Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package hawk2 for openSUSE:Factory checked 
in at 2026-06-23 17:42:35
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/hawk2 (Old)
 and      /work/SRC/openSUSE:Factory/.hawk2.new.1956 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "hawk2"

Tue Jun 23 17:42:35 2026 rev:43 rq:1361315 version:2.7.0+git.1781190752.ede285d7

Changes:
--------
--- /work/SRC/openSUSE:Factory/hawk2/hawk2.changes      2026-06-12 
19:26:08.078697432 +0200
+++ /work/SRC/openSUSE:Factory/.hawk2.new.1956/hawk2.changes    2026-06-23 
17:45:21.755703501 +0200
@@ -1,0 +2,7 @@
+Tue Jun 23 09:06:57 UTC 2026 - Aleksei Burlakov <[email protected]>
+
+- bump nokogiri-1.19.2 --> 1.19.4 
(bsc#1268688,bsc#1268693,bsc#1268698,bsc#1268703,
+  
bsc#1268712,bsc#1268713,bsc#1268718,bsc#1268723,bsc#1268729,bsc#1268733,bsc#1268738)
+  * nokogiri-1.19.4.gem 
+
+-------------------------------------------------------------------

Old:
----
  nokogiri-1.19.2.gem

New:
----
  nokogiri-1.19.4.gem

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ hawk2.spec ++++++
--- /var/tmp/diff_new_pack.oynHPb/_old  2026-06-23 17:45:25.519834678 +0200
+++ /var/tmp/diff_new_pack.oynHPb/_new  2026-06-23 17:45:25.523834817 +0200
@@ -101,7 +101,7 @@
 Source53:       net-protocol-0.2.2.gem
 Source54:       net-smtp-0.5.1.gem
 Source55:       nio4r-2.7.5.gem
-Source56:       nokogiri-1.19.2.gem
+Source56:       nokogiri-1.19.4.gem
 Source57:       ostruct-0.6.3.gem
 Source58:       po_to_json-3.0.2.gem
 Source59:       pp-0.6.3.gem
@@ -418,8 +418,8 @@
 %exclude 
%{install_gem_path}/gems/mini_portile2-2.8.9/test/assets/test-cmake-1.0/hello.c
 %exclude %{install_gem_path}/gems/nio4r-2.7.5/ext/libev/*
 %exclude %{install_gem_path}/gems/nio4r-2.7.5/ext/nio4r/*
-%exclude %{install_gem_path}/gems/nokogiri-1.19.2/ext/nokogiri/*
-%exclude %{install_gem_path}/gems/nokogiri-1.19.2/gumbo-parser/src/*
+%exclude %{install_gem_path}/gems/nokogiri-1.19.4/ext/nokogiri/*
+%exclude %{install_gem_path}/gems/nokogiri-1.19.4/gumbo-parser/src/*
 %exclude %{install_gem_path}/gems/prism-1.9.0/ext/*
 %exclude %{install_gem_path}/gems/prism-1.9.0/include/*
 %exclude %{install_gem_path}/gems/prism-1.9.0/src/*

++++++ gemfile-lock.patch ++++++
--- /var/tmp/diff_new_pack.oynHPb/_old  2026-06-23 17:45:25.887847503 +0200
+++ /var/tmp/diff_new_pack.oynHPb/_new  2026-06-23 17:45:25.895847782 +0200
@@ -188,7 +188,7 @@
 +    net-smtp (0.5.1)
 +      net-protocol
 +    nio4r (2.7.5)
-+    nokogiri (1.19.2)
++    nokogiri (1.19.4)
 +      mini_portile2 (~> 2.8.2)
 +      racc (~> 1.4)
 +    ostruct (0.6.3)
@@ -369,7 +369,7 @@
 +  net-protocol (0.2.2) 
sha256=aa73e0cba6a125369de9837b8d8ef82a61849360eba0521900e2c3713aa162a8
 +  net-smtp (0.5.1) 
sha256=ed96a0af63c524fceb4b29b0d352195c30d82dd916a42f03c62a3a70e5b70736
 +  nio4r (2.7.5) 
sha256=6c90168e48fb5f8e768419c93abb94ba2b892a1d0602cb06eef16d8b7df1dca1
-+  nokogiri (1.19.2) 
sha256=38fdd8b59db3d5ea9e7dfb14702e882b9bf819198d5bf976f17ebce12c481756
++  nokogiri (1.19.4) 
sha256=50c951611c92bca05c51411aef45f1cbc50f2821c4802758c5c6d34696533ab5
 +  ostruct (0.6.3) 
sha256=95a2ed4a4bd1d190784e666b47b2d3f078e4a9efda2fccf18f84ddc6538ed912
 +  po_to_json (3.0.2) 
sha256=31dd7810c3ada8965a2deff74210835d03f41de1de4680822a578a78822fe904
 +  pp (0.6.3) 
sha256=2951d514450b93ccfeb1df7d021cae0da16e0a7f95ee1e2273719669d0ab9df6

++++++ nokogiri-1.19.2.gem -> nokogiri-1.19.4.gem ++++++
Binary files old/checksums.yaml.gz and new/checksums.yaml.gz differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ext/nokogiri/nokogiri.c new/ext/nokogiri/nokogiri.c
--- old/ext/nokogiri/nokogiri.c 1980-01-02 01:00:00.000000000 +0100
+++ new/ext/nokogiri/nokogiri.c 1980-01-02 01:00:00.000000000 +0100
@@ -203,9 +203,6 @@
   rb_const_set(mNokogiri, rb_intern("LIBXSLT_COMPILED_VERSION"), 
NOKOGIRI_STR_NEW2(LIBXSLT_DOTTED_VERSION));
   rb_const_set(mNokogiri, rb_intern("LIBXSLT_LOADED_VERSION"), 
NOKOGIRI_STR_NEW2(xsltEngineVersion));
 
-  rb_const_set(mNokogiri, rb_intern("LIBXML_ZLIB_ENABLED"),
-               xmlHasFeature(XML_WITH_ZLIB) == 1 ? Qtrue : Qfalse);
-
 #ifdef NOKOGIRI_PACKAGED_LIBRARIES
   rb_const_set(mNokogiri, rb_intern("PACKAGED_LIBRARIES"), Qtrue);
 #  ifdef NOKOGIRI_PRECOMPILED_LIBRARIES
@@ -228,6 +225,12 @@
   rb_const_set(mNokogiri, rb_intern("LIBXML_ICONV_ENABLED"), Qfalse);
 #endif
 
+  rb_const_set(mNokogiri, rb_intern("LIBXML_ZLIB_ENABLED"),
+               xmlHasFeature(XML_WITH_ZLIB) == 1 ? Qtrue : Qfalse);
+
+  rb_const_set(mNokogiri, rb_intern("LIBXML_HTTP_ENABLED"),
+               xmlHasFeature(XML_WITH_HTTP) == 1 ? Qtrue : Qfalse);
+
 #ifdef NOKOGIRI_OTHER_LIBRARY_VERSIONS
   rb_const_set(mNokogiri, rb_intern("OTHER_LIBRARY_VERSIONS"), 
NOKOGIRI_STR_NEW2(NOKOGIRI_OTHER_LIBRARY_VERSIONS));
 #endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ext/nokogiri/nokogiri.h new/ext/nokogiri/nokogiri.h
--- old/ext/nokogiri/nokogiri.h 1980-01-02 01:00:00.000000000 +0100
+++ new/ext/nokogiri/nokogiri.h 1980-01-02 01:00:00.000000000 +0100
@@ -181,8 +181,17 @@
 int noko_io_write(void *ctx, char *buffer, int len);
 int noko_io_close(void *ctx);
 
-#define Noko_Node_Get_Struct(obj,type,sval) ((sval) = (type*)DATA_PTR(obj))
-#define Noko_Namespace_Get_Struct(obj,type,sval) ((sval) = 
(type*)DATA_PTR(obj))
+static inline void *
+_noko_data_ptr(VALUE rb_object)
+{
+  void *c_data = DATA_PTR(rb_object);
+  if (c_data == NULL) {
+    rb_raise(rb_eRuntimeError, "Uninitialized %" PRIsVALUE " struct (null data 
pointer)", rb_obj_class(rb_object));
+  }
+  return c_data;
+}
+#define Noko_Node_Get_Struct(obj,type,sval) ((sval) = 
(type*)_noko_data_ptr(obj))
+#define Noko_Namespace_Get_Struct(obj,type,sval) ((sval) = 
(type*)_noko_data_ptr(obj))
 
 VALUE noko_xml_node_wrap(VALUE klass, xmlNodePtr node) ;
 VALUE noko_xml_node_wrap_node_set_result(xmlNodePtr node, VALUE node_set) ;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ext/nokogiri/xml_attr.c new/ext/nokogiri/xml_attr.c
--- old/ext/nokogiri/xml_attr.c 1980-01-02 01:00:00.000000000 +0100
+++ new/ext/nokogiri/xml_attr.c 1980-01-02 01:00:00.000000000 +0100
@@ -10,37 +10,42 @@
  * (e.g., a HTML boolean attribute).
  */
 static VALUE
-set_value(VALUE self, VALUE content)
+noko_xml_attr_set_value(VALUE self, VALUE content)
 {
   xmlAttrPtr attr;
-  xmlChar *value;
-  xmlNode *cur;
 
   Noko_Node_Get_Struct(self, xmlAttr, attr);
 
-  if (attr->children) {
-    xmlFreeNodeList(attr->children);
+  {
+    /* Unlink and pin any wrapped children */
+    xmlNode *cur = attr->children;
+    xmlNode *next;
+
+    while (cur) {
+      next = cur->next;
+      if (cur->_private) {
+        xmlUnlinkNode(cur);
+        noko_xml_document_pin_node(cur);
+      }
+      cur = next;
+    }
   }
-  attr->children = attr->last = NULL;
 
   if (content == Qnil) {
-    return content;
-  }
-
-  value = xmlEncodeEntitiesReentrant(attr->doc, (unsigned char 
*)StringValueCStr(content));
-  if (xmlStrlen(value) == 0) {
-    attr->children = xmlNewDocText(attr->doc, value);
+    xmlNodeSetContent((xmlNodePtr)attr, NULL); /* Clear any remaining 
unwrapped children. */
   } else {
-    attr->children = xmlStringGetNodeList(attr->doc, value);
-  }
-  xmlFree(value);
+    xmlChar *value = xmlEncodeEntitiesReentrant(attr->doc, (unsigned char 
*)StringValueCStr(content));
+
+    if (xmlStrlen(value) == 0) {
+      xmlNodeSetContent((xmlNodePtr)attr, NULL); /* Clear any remaining 
unwrapped children. */
 
-  for (cur = attr->children; cur; cur = cur->next) {
-    cur->parent = (xmlNode *)attr;
-    cur->doc = attr->doc;
-    if (cur->next == NULL) {
-      attr->last = cur;
+      /* Preserve empty-string attributes as `foo=""` and not boolean `foo` */
+      attr->children = attr->last = xmlNewDocText(attr->doc, value);
+      attr->children->parent = (xmlNode *)attr;
+    } else {
+      xmlNodeSetContent((xmlNodePtr)attr, value);
     }
+    xmlFree(value);
   }
 
   return content;
@@ -53,7 +58,7 @@
  * Create a new Attr element on the +document+ with +name+
  */
 static VALUE
-new (int argc, VALUE *argv, VALUE klass)
+noko_xml_attr__new(int argc, VALUE *argv, VALUE klass)
 {
   xmlDocPtr xml_doc;
   VALUE document;
@@ -97,7 +102,7 @@
    */
   cNokogiriXmlAttr = rb_define_class_under(mNokogiriXml, "Attr", 
cNokogiriXmlNode);
 
-  rb_define_singleton_method(cNokogiriXmlAttr, "new", new, -1);
+  rb_define_singleton_method(cNokogiriXmlAttr, "new", noko_xml_attr__new, -1);
 
-  rb_define_method(cNokogiriXmlAttr, "value=", set_value, 1);
+  rb_define_method(cNokogiriXmlAttr, "value=", noko_xml_attr_set_value, 1);
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ext/nokogiri/xml_document.c 
new/ext/nokogiri/xml_document.c
--- old/ext/nokogiri/xml_document.c     1980-01-02 01:00:00.000000000 +0100
+++ new/ext/nokogiri/xml_document.c     1980-01-02 01:00:00.000000000 +0100
@@ -255,12 +255,6 @@
 
   c_document = noko_xml_document_unwrap(self);
 
-  c_current_root = xmlDocGetRootElement(c_document);
-  if (c_current_root) {
-    xmlUnlinkNode(c_current_root);
-    noko_xml_document_pin_node(c_current_root);
-  }
-
   if (!NIL_P(rb_new_root)) {
     if (!rb_obj_is_kind_of(rb_new_root, cNokogiriXmlNode)) {
       rb_raise(rb_eArgError,
@@ -270,13 +264,23 @@
 
     Noko_Node_Get_Struct(rb_new_root, xmlNode, c_new_root);
 
-    /* If the new root's document is not the same as the current document,
-     * then we need to dup the node in to this document. */
-    if (c_new_root->doc != c_document) {
-      c_new_root = xmlDocCopyNode(c_new_root, c_document, 1);
-      if (!c_new_root) {
-        rb_raise(rb_eRuntimeError, "Could not reparent node (xmlDocCopyNode)");
-      }
+    if (c_new_root->type != XML_ELEMENT_NODE) {
+      rb_raise(rb_eTypeError, "root must be a Nokogiri::XML::Element");
+    }
+  }
+
+  c_current_root = xmlDocGetRootElement(c_document);
+  if (c_current_root) {
+    xmlUnlinkNode(c_current_root);
+    noko_xml_document_pin_node(c_current_root);
+  }
+
+  /* If the new root's document is not the same as the current document,
+   * then we need to dup the node in to this document. */
+  if (c_new_root && c_new_root->doc != c_document) {
+    c_new_root = xmlDocCopyNode(c_new_root, c_document, 1);
+    if (!c_new_root) {
+      rb_raise(rb_eRuntimeError, "Could not reparent node (xmlDocCopyNode)");
     }
   }
 
@@ -317,12 +321,13 @@
 set_encoding(VALUE self, VALUE encoding)
 {
   xmlDocPtr doc = noko_xml_document_unwrap(self);
+  xmlChar *new_encoding = xmlStrdup((xmlChar *)StringValueCStr(encoding));
 
   if (doc->encoding) {
     xmlFree(DISCARD_CONST_QUAL_XMLCHAR(doc->encoding));
   }
 
-  doc->encoding = xmlStrdup((xmlChar *)StringValueCStr(encoding));
+  doc->encoding = new_encoding;
 
   return encoding;
 }
@@ -708,6 +713,9 @@
 {
   xmlDocPtr c_document;
   TypedData_Get_Struct(rb_document, xmlDoc, &xml_doc_type, c_document);
+  if (c_document == NULL) {
+    rb_raise(rb_eRuntimeError, "Uninitialized %" PRIsVALUE " struct (null data 
pointer)", rb_obj_class(rb_document));
+  }
   return c_document;
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ext/nokogiri/xml_node.c new/ext/nokogiri/xml_node.c
--- old/ext/nokogiri/xml_node.c 1980-01-02 01:00:00.000000000 +0100
+++ new/ext/nokogiri/xml_node.c 1980-01-02 01:00:00.000000000 +0100
@@ -971,6 +971,10 @@
   xmlDocPtr c_new_parent_doc;
   VALUE rb_node_cache;
 
+  if (!rb_obj_is_kind_of(rb_other, cNokogiriXmlNode)) {
+    rb_raise(rb_eTypeError, "argument must be a kind of Nokogiri::XML::Node");
+  }
+
   Noko_Node_Get_Struct(rb_other, xmlNode, c_other);
   c_level = (int)NUM2INT(rb_level);
   c_new_parent_doc = noko_xml_document_unwrap(rb_new_parent_doc);
@@ -2150,25 +2154,20 @@
 
 
 /*
- * call-seq:
- *   process_xincludes(flags)
- *
- * Loads and substitutes all xinclude elements below the node. The
- * parser context will be initialized with +flags+.
+ * Run XInclude substitution over the tree rooted at +c_node+, with the parser 
context initialized
+ * from +c_flags+. Collects libxml2's structured errors and raises 
Nokogiri::XML::SyntaxError (or
+ * RuntimeError) on failure.
  */
-static VALUE
-noko_xml_node__process_xincludes(VALUE rb_node, VALUE rb_flags)
+static void
+_noko_xml_node_process_xinclude_subtree(xmlNodePtr c_node, int c_flags)
 {
   int status ;
-  xmlNodePtr c_node;
   VALUE rb_errors = rb_ary_new();
   libxmlStructuredErrorHandlerState handler_state;
 
-  Noko_Node_Get_Struct(rb_node, xmlNode, c_node);
-
   noko__structured_error_func_save_and_set(&handler_state, (void *)rb_errors, 
noko__error_array_pusher);
 
-  status = xmlXIncludeProcessTreeFlags(c_node, (int)NUM2INT(rb_flags));
+  status = xmlXIncludeProcessTreeFlags(c_node, c_flags);
 
   noko__structured_error_func_restore(&handler_state);
 
@@ -2181,11 +2180,77 @@
       rb_raise(rb_eRuntimeError, "Could not perform xinclude substitution");
     }
   }
+}
+
+
+/*
+ * Whether +c_node+ is an <xi:include> element in either the 2001 or 2003 
XInclude namespace.
+ */
+static int
+_noko_xml_node_xinclude_element_p(xmlNodePtr c_node)
+{
+  return c_node->type == XML_ELEMENT_NODE
+         && xmlStrEqual(c_node->name, XINCLUDE_NODE)
+         && c_node->ns != NULL
+         && (xmlStrEqual(c_node->ns->href, XINCLUDE_NS) || 
xmlStrEqual(c_node->ns->href, XINCLUDE_OLD_NS));
+}
+
+
+/*
+ * call-seq:
+ *   process_xincludes(flags)
+ *
+ * Loads and substitutes all xinclude elements below the node. The
+ * parser context will be initialized with +flags+.
+ */
+static VALUE
+noko_xml_node__process_xincludes(VALUE rb_node, VALUE rb_flags)
+{
+  xmlNodePtr c_node;
+
+  Noko_Node_Get_Struct(rb_node, xmlNode, c_node);
+
+  if (c_node->parent == NULL && _noko_xml_node_xinclude_element_p(c_node)) {
+    rb_raise(rb_eRuntimeError, "cannot process XInclude on an unlinked 
<xi:include> node");
+  }
+
+  _noko_xml_node_process_xinclude_subtree(c_node, (int)NUM2INT(rb_flags));
 
   return rb_node;
 }
 
 
+/*
+ * Process this single <xi:include> node, substituting an unwrapped copy of it 
in its place so
+ * that libxml2 frees the copy. This node is unlinked and pinned to the 
document, so any Ruby
+ * wrapper for it (or for its descendants or namespaces) keeps pointing at 
valid memory. The
+ * parser context is initialized with +flags+.
+ */
+static VALUE
+noko_xml_node__safe_process_xinclude(VALUE rb_node, VALUE rb_flags)
+{
+  xmlNodePtr c_node, c_copy;
+
+  Noko_Node_Get_Struct(rb_node, xmlNode, c_node);
+
+  if (c_node->parent == NULL) {
+    rb_raise(rb_eRuntimeError, "cannot process XInclude on an unlinked 
<xi:include> node");
+  }
+
+  c_copy = xmlDocCopyNode(c_node, c_node->doc, 1);
+  if (c_copy == NULL) {
+    rb_raise(rb_eRuntimeError, "Could not copy node for xinclude 
substitution");
+  }
+
+  xmlReplaceNode(c_node, c_copy);
+  noko_xml_document_pin_node(c_node);
+
+  _noko_xml_node_process_xinclude_subtree(c_copy, (int)NUM2INT(rb_flags));
+
+  return Qnil;
+}
+
+
 /* TODO: DOCUMENT ME */
 static VALUE
 in_context(VALUE self, VALUE _str, VALUE _options)
@@ -2286,9 +2351,7 @@
 VALUE
 rb_xml_node_data_ptr_eh(VALUE self)
 {
-  xmlNodePtr c_node;
-  Noko_Node_Get_Struct(self, xmlNode, c_node);
-  return c_node ? Qtrue : Qfalse;
+  return DATA_PTR(self) ? Qtrue : Qfalse;
 }
 
 VALUE
@@ -2438,6 +2501,7 @@
   rb_define_method(cNokogiriXmlNode, "unlink", unlink_node, 0);
 
   rb_define_protected_method(cNokogiriXmlNode, "initialize_copy_with_args", 
rb_xml_node_initialize_copy_with_args, 3);
+  rb_define_protected_method(cNokogiriXmlNode, "safe_process_xinclude", 
noko_xml_node__safe_process_xinclude, 1);
 
   rb_define_private_method(cNokogiriXmlNode, "add_child_node", add_child, 1);
   rb_define_private_method(cNokogiriXmlNode, "add_next_sibling_node", 
add_next_sibling, 1);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ext/nokogiri/xml_node_set.c 
new/ext/nokogiri/xml_node_set.c
--- old/ext/nokogiri/xml_node_set.c     1980-01-02 01:00:00.000000000 +0100
+++ new/ext/nokogiri/xml_node_set.c     1980-01-02 01:00:00.000000000 +0100
@@ -304,7 +304,7 @@
 
   TypedData_Get_Struct(rb_self, xmlNodeSet, &xml_node_set_type, c_self);
 
-  if (offset >= c_self->nodeNr || abs((int)offset) > c_self->nodeNr) {
+  if (offset >= c_self->nodeNr || offset < -c_self->nodeNr) {
     return Qnil;
   }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ext/nokogiri/xml_xpath_context.c 
new/ext/nokogiri/xml_xpath_context.c
--- old/ext/nokogiri/xml_xpath_context.c        1980-01-02 01:00:00.000000000 
+0100
+++ new/ext/nokogiri/xml_xpath_context.c        1980-01-02 01:00:00.000000000 
+0100
@@ -12,6 +12,15 @@
 static const xmlChar *NOKOGIRI_BUILTIN_URI = (const xmlChar 
*)"https://www.nokogiri.org/default_ns/ruby/builtins";;
 
 static void
+_noko_xml_xpath_context_dmark(void *data)
+{
+  xmlXPathContextPtr c_context = data;
+  if (c_context->doc && DOC_RUBY_OBJECT_TEST(c_context->doc)) {
+    rb_gc_mark(DOC_RUBY_OBJECT(c_context->doc));
+  }
+}
+
+static void
 _noko_xml_xpath_context_dfree(void *data)
 {
   xmlXPathContextPtr c_context = data;
@@ -21,9 +30,10 @@
 static const rb_data_type_t _noko_xml_xpath_context_type = {
   .wrap_struct_name = "xmlXPathContext",
   .function = {
+    .dmark = _noko_xml_xpath_context_dmark,
     .dfree = _noko_xml_xpath_context_dfree,
   },
-  .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+  .flags = RUBY_TYPED_FREE_IMMEDIATELY,
 };
 
 /* find a CSS class in an HTML element's `class` attribute */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ext/nokogiri/xslt_stylesheet.c 
new/ext/nokogiri/xslt_stylesheet.c
--- old/ext/nokogiri/xslt_stylesheet.c  1980-01-02 01:00:00.000000000 +0100
+++ new/ext/nokogiri/xslt_stylesheet.c  1980-01-02 01:00:00.000000000 +0100
@@ -133,6 +133,35 @@
   return rval ;
 }
 
+
+/*
+ * Build the C-string params array passed to xsltApplyStylesheet.
+ *
+ * Note: params[j] is a raw pointer into a Ruby string's buffer, and we do not 
pin the underlying
+ * VALUEs against GC compaction. This is safe (despite not pinning the VALUEs) 
because libxslt fully
+ * processes params (interning names, evaluating values) before template 
execution begins, and Ruby
+ * callbacks can only run during template execution. By the time GC compaction 
is reachable, libxslt
+ * no longer reads params[].
+ */
+typedef struct {
+  VALUE rb_param;
+  long param_len;
+  const char **params;
+} build_xslt_params_args_t;
+
+static VALUE
+build_xslt_params(VALUE args_ptr)
+{
+  build_xslt_params_args_t *args = (build_xslt_params_args_t *)args_ptr;
+
+  for (long j = 0; j < args->param_len; j++) {
+    VALUE entry = rb_ary_entry(args->rb_param, j);
+    args->params[j] = StringValueCStr(entry);
+  }
+
+  return Qnil;
+}
+
 /*
  * call-seq:
  *   transform(document)
@@ -254,7 +283,7 @@
   xmlDocPtr c_result_document ;
   nokogiriXsltStylesheetTuple *wrapper;
   const char **params ;
-  long param_len, j ;
+  long param_len ;
   int parse_error_occurred ;
   int defensive_copy_p = 0;
 
@@ -277,10 +306,17 @@
 
   param_len = RARRAY_LEN(rb_param);
   params = ruby_xcalloc((size_t)param_len + 1, sizeof(char *));
-  for (j = 0 ; j < param_len ; j++) {
-    VALUE entry = rb_ary_entry(rb_param, j);
-    const char *ptr = StringValueCStr(entry);
-    params[j] = ptr;
+  {
+    // populate params under rb_protect so that a raise from StringValueCStr
+    // (e.g. on a null byte) does not leak the params allocation.
+    build_xslt_params_args_t args = { rb_param, param_len, params };
+    int state = 0;
+
+    rb_protect(build_xslt_params, (VALUE)&args, &state);
+    if (state) {
+      ruby_xfree(params);
+      rb_jump_tag(state);
+    }
   }
   params[param_len] = 0 ;
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/nokogiri/css/tokenizer.rb 
new/lib/nokogiri/css/tokenizer.rb
--- old/lib/nokogiri/css/tokenizer.rb   1980-01-02 01:00:00.000000000 +0100
+++ new/lib/nokogiri/css/tokenizer.rb   1980-01-02 01:00:00.000000000 +0100
@@ -1,7 +1,7 @@
 # frozen_string_literal: true
 #--
 # DO NOT MODIFY!!!!
-# This file is automatically generated by rex 1.0.7
+# This file is automatically generated by rex 1.0.8
 # from lexical definition file "lib/nokogiri/css/tokenizer.rex".
 #++
 
@@ -63,13 +63,13 @@
                   when (text = @ss.scan(/has\([\s]*/))
                      action { [:HAS, text] }
 
-                  when (text = 
@ss.scan(/-?([_A-Za-z]|[^\0-\177]|(\\[0-9A-Fa-f]{1,6}(\r\n|[\s])?|\\[^\n\r\f0-9A-Fa-f]))([_A-Za-z0-9-]|[^\0-\177]|(\\[0-9A-Fa-f]{1,6}(\r\n|[\s])?|\\[^\n\r\f0-9A-Fa-f]))*\([\s]*/))
+                  when (text = 
@ss.scan(/-?(?>[_A-Za-z]|[^\0-\177]|(\\[0-9A-Fa-f]{1,6}(\r\n|[\s])?|\\[^\n\r\f0-9A-Fa-f]))(?>[_A-Za-z0-9-]|[^\0-\177]|(\\[0-9A-Fa-f]{1,6}(\r\n|[\s])?|\\[^\n\r\f0-9A-Fa-f]))*\([\s]*/))
                      action { [:FUNCTION, text] }
 
-                  when (text = 
@ss.scan(/-?([_A-Za-z]|[^\0-\177]|(\\[0-9A-Fa-f]{1,6}(\r\n|[\s])?|\\[^\n\r\f0-9A-Fa-f]))([_A-Za-z0-9-]|[^\0-\177]|(\\[0-9A-Fa-f]{1,6}(\r\n|[\s])?|\\[^\n\r\f0-9A-Fa-f]))*/))
+                  when (text = 
@ss.scan(/-?(?>[_A-Za-z]|[^\0-\177]|(\\[0-9A-Fa-f]{1,6}(\r\n|[\s])?|\\[^\n\r\f0-9A-Fa-f]))(?>[_A-Za-z0-9-]|[^\0-\177]|(\\[0-9A-Fa-f]{1,6}(\r\n|[\s])?|\\[^\n\r\f0-9A-Fa-f]))*/))
                      action { [:IDENT, text] }
 
-                  when (text = 
@ss.scan(/\#([_A-Za-z0-9-]|[^\0-\177]|(\\[0-9A-Fa-f]{1,6}(\r\n|[\s])?|\\[^\n\r\f0-9A-Fa-f]))+/))
+                  when (text = 
@ss.scan(/\#(?>[_A-Za-z0-9-]|[^\0-\177]|(\\[0-9A-Fa-f]{1,6}(\r\n|[\s])?|\\[^\n\r\f0-9A-Fa-f]))+/))
                      action { [:HASH, text] }
 
                   when (text = @ss.scan(/[\s]*~=[\s]*/))
@@ -132,7 +132,7 @@
                   when (text = @ss.scan(/[\s]+/))
                      action { [:S, text] }
 
-                  when (text = 
@ss.scan(/("([^\n\r\f"]|(\n|\r\n|\r|\f)|[^\0-\177]|(\\[0-9A-Fa-f]{1,6}(\r\n|[\s])?|\\[^\n\r\f0-9A-Fa-f]))*(?<!\\)(?:\\{2})*"|'([^\n\r\f']|(\n|\r\n|\r|\f)|[^\0-\177]|(\\[0-9A-Fa-f]{1,6}(\r\n|[\s])?|\\[^\n\r\f0-9A-Fa-f]))*(?<!\\)(?:\\{2})*')/))
+                  when (text = 
@ss.scan(/("(?>[^\n\r\f"\\]|\\?(\n|\r\n|\r|\f)|[^\0-\177]|(\\[0-9A-Fa-f]{1,6}(\r\n|[\s])?|\\[^\n\r\f0-9A-Fa-f]))*"|'(?>[^\n\r\f'\\]|\\?(\n|\r\n|\r|\f)|[^\0-\177]|(\\[0-9A-Fa-f]{1,6}(\r\n|[\s])?|\\[^\n\r\f0-9A-Fa-f]))*')/))
                      action { [:STRING, text] }
 
                   when (text = @ss.scan(/./))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/nokogiri/css/tokenizer.rex 
new/lib/nokogiri/css/tokenizer.rex
--- old/lib/nokogiri/css/tokenizer.rex  1980-01-02 01:00:00.000000000 +0100
+++ new/lib/nokogiri/css/tokenizer.rex  1980-01-02 01:00:00.000000000 +0100
@@ -11,13 +11,13 @@
   unicode   \\[0-9A-Fa-f]{1,6}(\r\n|[\s])?
 
   escape    ({unicode}|\\[^\n\r\f0-9A-Fa-f])
-  nmchar    ([_A-Za-z0-9-]|{nonascii}|{escape})
-  nmstart   ([_A-Za-z]|{nonascii}|{escape})
+  nmchar    (?>[_A-Za-z0-9-]|{nonascii}|{escape})
+  nmstart   (?>[_A-Za-z]|{nonascii}|{escape})
   name      {nmstart}{nmchar}*
   ident     -?{name}
   charref   {nmchar}+
-  string1   "([^\n\r\f"]|{nl}|{nonascii}|{escape})*(?<!\\)(?:\\{2})*"
-  string2   '([^\n\r\f']|{nl}|{nonascii}|{escape})*(?<!\\)(?:\\{2})*'
+  string1   "(?>[^\n\r\f"\\]|\\?{nl}|{nonascii}|{escape})*"
+  string2   '(?>[^\n\r\f'\\]|\\?{nl}|{nonascii}|{escape})*'
   string    ({string1}|{string2})
 
 rule
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/nokogiri/version/constant.rb 
new/lib/nokogiri/version/constant.rb
--- old/lib/nokogiri/version/constant.rb        1980-01-02 01:00:00.000000000 
+0100
+++ new/lib/nokogiri/version/constant.rb        1980-01-02 01:00:00.000000000 
+0100
@@ -2,5 +2,5 @@
 
 module Nokogiri
   # The version of Nokogiri you are using
-  VERSION = "1.19.2"
+  VERSION = "1.19.4"
 end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/nokogiri/version/info.rb 
new/lib/nokogiri/version/info.rb
--- old/lib/nokogiri/version/info.rb    1980-01-02 01:00:00.000000000 +0100
+++ new/lib/nokogiri/version/info.rb    1980-01-02 01:00:00.000000000 +0100
@@ -53,6 +53,14 @@
       defined?(Nokogiri::LIBXML_ICONV_ENABLED) && 
Nokogiri::LIBXML_ICONV_ENABLED
     end
 
+    def libxml2_has_zlib?
+      defined?(Nokogiri::LIBXML_ZLIB_ENABLED) && Nokogiri::LIBXML_ZLIB_ENABLED
+    end
+
+    def libxml2_has_http?
+      defined?(Nokogiri::LIBXML_HTTP_ENABLED) && Nokogiri::LIBXML_HTTP_ENABLED
+    end
+
     def libxslt_has_datetime?
       defined?(Nokogiri::LIBXSLT_DATETIME_ENABLED) && 
Nokogiri::LIBXSLT_DATETIME_ENABLED
     end
@@ -145,6 +153,8 @@
             end
             libxml["memory_management"] = Nokogiri::LIBXML_MEMORY_MANAGEMENT
             libxml["iconv_enabled"] = libxml2_has_iconv?
+            libxml["zlib_enabled"] = libxml2_has_zlib?
+            libxml["http_enabled"] = libxml2_has_http?
             libxml["compiled"] = compiled_libxml_version.to_s
             libxml["loaded"] = loaded_libxml_version.to_s
           end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/nokogiri/xml/document.rb 
new/lib/nokogiri/xml/document.rb
--- old/lib/nokogiri/xml/document.rb    1980-01-02 01:00:00.000000000 +0100
+++ new/lib/nokogiri/xml/document.rb    1980-01-02 01:00:00.000000000 +0100
@@ -85,8 +85,9 @@
             read_memory(string_or_io, url, encoding, options.to_i)
           end
 
-          # do xinclude processing
-          doc.do_xinclude(options) if options.xinclude?
+          # do xinclude processing; the document is freshly parsed and 
unexposed to Ruby, so the
+          # defensive copy is unnecessary
+          doc.do_xinclude(options, safe_copy: false) if options.xinclude?
 
           doc
         end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/nokogiri/xml/node.rb new/lib/nokogiri/xml/node.rb
--- old/lib/nokogiri/xml/node.rb        1980-01-02 01:00:00.000000000 +0100
+++ new/lib/nokogiri/xml/node.rb        1980-01-02 01:00:00.000000000 +0100
@@ -523,16 +523,67 @@
         set_namespace(ns)
       end
 
+      XINCLUDE_NAMESPACES = {
+        "xi2001" => "http://www.w3.org/2001/XInclude";,
+        "xi2003" => "http://www.w3.org/2003/XInclude";,
+      }.freeze
+      private_constant :XINCLUDE_NAMESPACES
+
+      # Every top-level <xi:include> in the subtree, in either XInclude 
namespace, excluding
+      # includes nested inside another include's fallback (libxml2 only 
expands those if the
+      # parent include fails).
+      XINCLUDE_QUERY =
+        "descendant-or-self::xi2001:include[not(ancestor::xi2001:include) and 
not(ancestor::xi2003:include)] | " \
+        "descendant-or-self::xi2003:include[not(ancestor::xi2001:include) and 
not(ancestor::xi2003:include)]"
+      private_constant :XINCLUDE_QUERY
+
       ###
-      # Do xinclude substitution on the subtree below node. If given a block, a
-      # Nokogiri::XML::ParseOptions object initialized from +options+, will be
-      # passed to it, allowing more convenient modification of the parser 
options.
-      def do_xinclude(options = XML::ParseOptions::DEFAULT_XML)
+      # :call-seq:
+      #   do_xinclude(options = ParseOptions::DEFAULT_XML, safe_copy: true) → 
self
+      #   do_xinclude(options = ParseOptions::DEFAULT_XML, safe_copy: true) { 
|options| ... } → self
+      #
+      # Do XInclude substitution on the subtree below this node, replacing 
each +<xi:include>+ with
+      # the content it references.
+      #
+      # [Parameters]
+      # - +options+ (Nokogiri::XML::ParseOptions) The parser options for the 
substitution. (default
+      #   +ParseOptions::DEFAULT_XML+)
+      #
+      # [Optional Keyword Arguments]
+      # - +safe_copy:+ (Boolean) Operate on a defensive copy of each 
+<xi:include>+ element, to
+      #   prevent libxml2 from freeing memory that is bound to live Ruby 
objects. (default +true+)
+      #
+      #   When +true+, each +<xi:include>+ is processed on an unwrapped copy 
of itself, so libxml2
+      #   frees the copy while the original node is unlinked from the document 
and kept alive. This
+      #   prevents a use-after-free when the +<xi:include>+ node, or any of 
its descendants or
+      #   namespaces, has already been exposed to Ruby; as a consequence such 
a wrapped node ends up
+      #   detached from the document rather than removed or converted in place.
+      #
+      #   When +false+, the document is processed in place. This is faster but 
only safe when nothing
+      #   in the subtree has been exposed to Ruby (for example, immediately 
after parsing), which is
+      #   why Document.parse uses it.
+      #
+      #   This option has no effect on the pure-Java backend, which performs 
XInclude substitution
+      #   during parsing.
+      #
+      # [Yields]
+      #   If a block is given, a Nokogiri::XML::ParseOptions object 
initialized from +options+ is
+      #   yielded to it, which can be configured before substitution.
+      #
+      # [Returns] +self+ (Nokogiri::XML::Node)
+      def do_xinclude(options = XML::ParseOptions::DEFAULT_XML, safe_copy: 
true)
         options = Nokogiri::XML::ParseOptions.new(options) if Integer === 
options
         yield options if block_given?
 
-        # call c extension
-        process_xincludes(options.to_i)
+        if safe_copy && Nokogiri.uses_libxml?
+          xpath(XINCLUDE_QUERY, XINCLUDE_NAMESPACES).each do |include_node|
+            include_node.safe_process_xinclude(options.to_i)
+          end
+        else
+          process_xincludes(options.to_i)
+        end
+
+        self
       end
 
       alias_method :next, :next_sibling
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/nokogiri/xml/parse_options.rb 
new/lib/nokogiri/xml/parse_options.rb
--- old/lib/nokogiri/xml/parse_options.rb       1980-01-02 01:00:00.000000000 
+0100
+++ new/lib/nokogiri/xml/parse_options.rb       1980-01-02 01:00:00.000000000 
+0100
@@ -76,12 +76,12 @@
       #
       # ⚠ This option enables entity substitution, contrary to what the name 
implies.
       #
-      # ⚠ <b>It is UNSAFE to set this option</b> when parsing untrusted 
documents.
+      # 🛡 <b>It is UNSAFE to set this option</b> when parsing untrusted 
documents.
       NOENT       = 1 << 1
 
       # Load external subsets. On by default for XSLT::Stylesheet.
       #
-      # ⚠ <b>It is UNSAFE to set this option</b> when parsing untrusted 
documents.
+      # 🛡 <b>It is UNSAFE to set this option</b> when parsing untrusted 
documents.
       DTDLOAD     = 1 << 2
 
       # Default DTD attributes. On by default for XSLT::Stylesheet.
@@ -111,7 +111,7 @@
       # Forbid network access. On by default for XML::Document, 
XML::DocumentFragment,
       # HTML4::Document, HTML4::DocumentFragment, XSLT::Stylesheet, and 
XML::Schema.
       #
-      # ⚠ <b>It is UNSAFE to unset this option</b> when parsing untrusted 
documents.
+      # 🛡 <b>It is UNSAFE to unset this option</b> when parsing untrusted 
documents.
       NONET       = 1 << 11
 
       # Do not reuse the context dictionary. Off by default.
@@ -128,8 +128,7 @@
 
       # Compact small text nodes. Off by default.
       #
-      # ⚠ No modification of the DOM tree is allowed after parsing. libxml2 
may crash if you try to
-      # modify the tree.
+      # ⚠ No modification of the DOM tree is allowed after parsing.
       COMPACT     = 1 << 16
 
       # Parse using XML-1.0 before update 5. Off by default
@@ -140,7 +139,7 @@
 
       # Relax any hardcoded limit from the parser. Off by default.
       #
-      # ⚠ <b>It is UNSAFE to set this option</b> when parsing untrusted 
documents.
+      # 🛡 <b>It is UNSAFE to set this option</b> when parsing untrusted 
documents.
       HUGE        = 1 << 19
 
       # Support line numbers up to <code>long int</code> (default is a 
<code>short int</code>). On
@@ -151,7 +150,12 @@
       # The options mask used by default for parsing XML::Document and 
XML::DocumentFragment
       DEFAULT_XML  = RECOVER | NONET | BIG_LINES
 
-      # The options mask used by default used for parsing XSLT::Stylesheet
+      # Shorthand options mask useful for parsing XSLT stylesheets:
+      # sets RECOVER, NONET, NOENT, DTDLOAD, DTDATTR, NOCDATA, BIG_LINES.
+      #
+      # 🛡 This option set includes `NOENT` and `DTDLOAD` which are unsafe for 
untrusted
+      # documents. <b>Do not parse untrusted XSLT stylesheets.</b> See 
Nokogiri::XSLT for more
+      # information.
       DEFAULT_XSLT = RECOVER | NONET | NOENT | DTDLOAD | DTDATTR | NOCDATA | 
BIG_LINES
 
       # The options mask used by default used for parsing HTML4::Document and 
HTML4::DocumentFragment
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/nokogiri/xml/sax/document.rb 
new/lib/nokogiri/xml/sax/document.rb
--- old/lib/nokogiri/xml/sax/document.rb        1980-01-02 01:00:00.000000000 
+0100
+++ new/lib/nokogiri/xml/sax/document.rb        1980-01-02 01:00:00.000000000 
+0100
@@ -39,7 +39,7 @@
       # of ParserContext#replace_entities. (Recall that the default value of
       # ParserContext#replace_entities is `false`.)
       #
-      # ⚠ <b>It is UNSAFE to set ParserContext#replace_entities to `true`</b> 
when parsing untrusted
+      # 🛡 <b>It is UNSAFE to set ParserContext#replace_entities to `true`</b> 
when parsing untrusted
       # documents.
       #
       # 💡 For more information on entity types, see [Wikipedia's page on
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/nokogiri/xslt/stylesheet.rb 
new/lib/nokogiri/xslt/stylesheet.rb
--- old/lib/nokogiri/xslt/stylesheet.rb 1980-01-02 01:00:00.000000000 +0100
+++ new/lib/nokogiri/xslt/stylesheet.rb 1980-01-02 01:00:00.000000000 +0100
@@ -3,15 +3,20 @@
 module Nokogiri
   module XSLT
     ###
-    # A Stylesheet represents an XSLT Stylesheet object.  Stylesheet creation
-    # is done through Nokogiri.XSLT.  Here is an example of transforming
-    # an XML::Document with a Stylesheet:
+    # A Stylesheet represents an XSLT Stylesheet object. Stylesheet creation 
is done through
+    # Nokogiri::XSLT.parse (or the convenience method Nokogiri.XSLT). Here is 
an example of
+    # transforming an XML::Document with a Stylesheet:
     #
     #   doc   = Nokogiri::XML(File.read('some_file.xml'))
     #   xslt  = Nokogiri::XSLT(File.read('some_transformer.xslt'))
     #
     #   xslt.transform(doc) # => Nokogiri::XML::Document
     #
+    # 🛡 <b>This class does not support execution of untrusted stylesheets.</b> 
An untrusted
+    # stylesheet may consume a large amount of CPU, memory, or other system 
resources during
+    # transformation, and IO and file access are not restricted. See 
Nokogiri::XSLT for more
+    # information about the security implications of untrusted stylesheets.
+    #
     # Many XSLT transformations include serialization behavior to emit a 
non-XML document. For these
     # cases, please take care to invoke the #serialize method on the result of 
the transformation:
     #
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/nokogiri/xslt.rb new/lib/nokogiri/xslt.rb
--- old/lib/nokogiri/xslt.rb    1980-01-02 01:00:00.000000000 +0100
+++ new/lib/nokogiri/xslt.rb    1980-01-02 01:00:00.000000000 +0100
@@ -10,8 +10,14 @@
   end
 
   ###
-  # See Nokogiri::XSLT::Stylesheet for creating and manipulating
-  # Stylesheet object.
+  # See Nokogiri::XSLT::Stylesheet for creating and manipulating Stylesheet 
objects.
+  #
+  # 🛡 <b>Do not use this module for untrusted stylesheet documents.</b> 
libxslt does not support
+  # safely processing untrusted stylesheets. Untrusted stylesheets may access 
the file system and
+  # network, consume large amounts of CPU, memory, or other system resources, 
and IO and file
+  # access are not restricted. Additionally, the stylesheet is parsed by 
libxml2 with +NOENT+ and
+  # +DTDLOAD+ enabled (see ParseOptions::DEFAULT_XSLT), meaning that 
<b>external entities will be
+  # resolved and external subsets will be loaded</b> during parsing.
   module XSLT
     class << self
       # :call-seq:
@@ -20,6 +26,9 @@
       #
       # Parse the stylesheet in +xsl+, registering optional +modules+ as 
custom class handlers.
       #
+      # 🛡 <b>Do not pass untrusted stylesheet content to this method.</b> See 
Nokogiri::XSLT for more
+      # information.
+      #
       # [Parameters]
       # - +xsl+ (String) XSL content to be parsed into a stylesheet
       # - +modules+ (Hash<String ⇒ Class>) A hash of URI-to-handler relations 
for linking a
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/metadata new/metadata
--- old/metadata        1980-01-02 01:00:00.000000000 +0100
+++ new/metadata        1980-01-02 01:00:00.000000000 +0100
@@ -1,7 +1,7 @@
 --- !ruby/object:Gem::Specification
 name: nokogiri
 version: !ruby/object:Gem::Version
-  version: 1.19.2
+  version: 1.19.4
 platform: ruby
 authors:
 - Mike Dalessio
@@ -301,7 +301,7 @@
     - !ruby/object:Gem::Version
       version: '0'
 requirements: []
-rubygems_version: 4.0.3
+rubygems_version: 4.0.6
 specification_version: 4
 summary: Nokogiri (鋸) makes it easy and painless to work with XML and HTML 
from Ruby.
 test_files: []

Reply via email to