Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package obs-service-go_modules for 
openSUSE:Factory checked in at 2025-05-22 16:55:58
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/obs-service-go_modules (Old)
 and      /work/SRC/openSUSE:Factory/.obs-service-go_modules.new.2732 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "obs-service-go_modules"

Thu May 22 16:55:58 2025 rev:16 rq:1279150 version:0.6.8

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/obs-service-go_modules/obs-service-go_modules.changes
    2025-04-20 20:04:33.828569934 +0200
+++ 
/work/SRC/openSUSE:Factory/.obs-service-go_modules.new.2732/obs-service-go_modules.changes
  2025-05-22 16:56:09.460105955 +0200
@@ -1,0 +2,17 @@
+Thu May 22 04:46:05 UTC 2025 - Jeff Kowalczyk <jkowalc...@suse.com>
+
+- Update to version 0.6.8:
+  * Implement go mod edit -replace using _service params refs #57
+  * cmd_go_mod() use list for arg cmd and new arg subcmd refs #57
+
+-------------------------------------------------------------------
+Wed May 21 04:07:39 UTC 2025 - Jeff Kowalczyk <jkowalc...@suse.com>
+
+- Update to version 0.6.7:
+  * archive_autodetect() match archive files before dir refs #66 #69 #73
+  * Ensure some level of compatibility with older libarchive
+  * archive_autodetect docstring add .obscpio to format list
+  * Format with python black
+  * Fix using go.mod of toplevel
+
+-------------------------------------------------------------------

Old:
----
  obs-service-go_modules-0.6.6.tar.gz

New:
----
  obs-service-go_modules-0.6.8.tar.gz

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

Other differences:
------------------
++++++ obs-service-go_modules.spec ++++++
--- /var/tmp/diff_new_pack.uidhJG/_old  2025-05-22 16:56:09.864123082 +0200
+++ /var/tmp/diff_new_pack.uidhJG/_new  2025-05-22 16:56:09.864123082 +0200
@@ -37,7 +37,7 @@
 %define use_test   test
 %endif
 Name:           obs-service-%{service}
-Version:        0.6.6
+Version:        0.6.8
 Release:        0
 Summary:        An OBS source service: Download, verify and vendor Go module 
dependencies
 License:        GPL-2.0-or-later

++++++ _service ++++++
--- /var/tmp/diff_new_pack.uidhJG/_old  2025-05-22 16:56:09.892124269 +0200
+++ /var/tmp/diff_new_pack.uidhJG/_new  2025-05-22 16:56:09.896124438 +0200
@@ -3,7 +3,7 @@
     <param 
name="url">https://github.com/openSUSE/obs-service-go_modules.git</param>
     <param name="scm">git</param>
     <param name="exclude">.git</param>
-    <param name="revision">v0.6.6</param>
+    <param name="revision">v0.6.8</param>
     <param name="versionformat">@PARENT_TAG@</param>
     <param name="changesgenerate">enable</param>
     <param name="versionrewrite-pattern">v(.*)</param>

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.uidhJG/_old  2025-05-22 16:56:09.916125286 +0200
+++ /var/tmp/diff_new_pack.uidhJG/_new  2025-05-22 16:56:09.920125456 +0200
@@ -1,6 +1,6 @@
 <servicedata>
 <service name="tar_scm">
                 <param 
name="url">https://github.com/openSUSE/obs-service-go_modules.git</param>
-              <param 
name="changesrevision">a9bf055557cf024478744fbd7e8621fd03cb2e87</param></service></servicedata>
+              <param 
name="changesrevision">27262b8fa611ffa96f764933b9088660de6a6cae</param></service></servicedata>
 (No newline at EOF)
 

++++++ obs-service-go_modules-0.6.6.tar.gz -> 
obs-service-go_modules-0.6.8.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/obs-service-go_modules-0.6.6/README.md 
new/obs-service-go_modules-0.6.8/README.md
--- old/obs-service-go_modules-0.6.6/README.md  2025-04-13 19:12:30.000000000 
+0200
+++ new/obs-service-go_modules-0.6.8/README.md  2025-05-22 06:37:03.000000000 
+0200
@@ -245,6 +245,116 @@
 
 Persistent state for changelog generation is stored in `_servicedata`.
 
+## Updating dependencies during vendoring
+
+When a CVE or bug is reported for a dependency of a Go application, the best
+course of action is a pull request to the upstream project to use a newer fixed
+version of that dependency, and an accompanying tagged release. govulncheck
+output indicates the fixed version of the vulnerable dependency to use.
+
+On occasion, the upstream project may be slow to accept the update pull request
+or tag a release. If the vulnerability is severe and applicable to the packaged
+Go application, package maintainers can at their option temporarily vendor a
+newer fixed version of the dependency.
+
+In Long Term Support (LTS) scenarios, an dependency of an upstream project may
+be inactive, archived, removed, or explicitly marked EOL. In these cases it is
+appropriate to vendor a newer fixed version of dependency from a different
+repository URL or local file path.
+
+## Update a Go module with `go mod edit -replace`
+
+To replace a specific module with a newer fixed version,
+`obs-service-go_modules` supports the command
+`go mod edit -replace module=replacement`.
+This method is recommended, as the replace statement is explicitly written in
+`go.mod` and recorded in the `debug/buildinfo` metadata. Alternative methods of
+updating such as `go get` do not highlight the changed versions or the
+divergence from upstream pinned versions. Upstream projects do occasionally use
+replace statements in their pristine `go.mod` files.
+
+### Example replace to fix CVEs in dependencies
+
+Scenario: A packaged Go application has gone a long time since a tagged
+release. GitHub dependabot makes regular dependency update PRs to the upstream
+`main` branch, but no releases have been tagged. Two CVEs are detected against
+the most recent tagged release, as per `govulncheck` run in the local git 
clone:
+
+```
+govulncheck .
+=== Symbol Results ===
+
+Vulnerability #1: GO-2025-3485
+    DoS in go-jose Parsing in github.com/go-jose/go-jose
+  More info: https://pkg.go.dev/vuln/GO-2025-3485
+  Module: github.com/go-jose/go-jose/v3
+    Found in: github.com/go-jose/go-jose/v3@v3.0.3
+    Fixed in: github.com/go-jose/go-jose/v3@v3.0.4
+    Example traces found:
+      #1: pkg/attestation/attestation.go:145:35: attestation.signAttestation 
calls sign.SignerFromKeyOpts, which eventually calls jose.ParseSigned
+
+  Module: github.com/go-jose/go-jose/v4
+    Found in: github.com/go-jose/go-jose/v4@v4.0.2
+    Fixed in: github.com/go-jose/go-jose/v4@v4.0.5
+    Example traces found:
+      #1: pkg/attestation/attestation.go:145:35: attestation.signAttestation 
calls sign.SignerFromKeyOpts, which eventually calls jose.ParseSignedCompact
+
+Your code is affected by 1 vulnerability from 1 module.
+This scan also found 6 vulnerabilities in packages you import and 2
+vulnerabilities in modules you require, but your code doesn't appear to call
+these vulnerabilities.
+Use '-show verbose' for more details.
+```
+
+Mitigation: Add two replace entries to `_service` as indicated by the CVE 
report
+`fixed in` field:
+
+```
+<service name="go_modules" mode="manual">
+  <param 
name="replace">github.com/go-jose/go-jose/v3=github.com/go-jose/go-jose/v3@v3.0.4</param>
+  <param 
name="replace">github.com/go-jose/go-jose/v4=github.com/go-jose/go-jose/v4@v4.0.5</param>
+</service>
+```
+
+Next, run the source service to vendor dependencies as usual.
+
+`vendor.tar.gz` now contains the original dependencies pinned by upstream
+`go.mod`, with the addition of updates to two dependencies as shown above. To
+ensure the vendoring remains consistent, `vendor.tar.gz` also contains modified
+go.mod and go.sum lock files. These two files are the only diff against 
pristine
+upstream sources that will be neeeded in most uses of replace.
+
+Running govulncheck on the updated vendored dependencies shows the two CVEs 
have
+been cleared:
+
+```
+govulncheck .
+=== Symbol Results ===
+
+No vulnerabilities found.
+
+Your code is affected by 0 vulnerabilities.
+This scan also found 5 vulnerabilities in packages you import and 2
+vulnerabilities in modules you require, but your code doesn't appear to call
+these vulnerabilities.
+Use '-show verbose' for more details.
+```
+
+The use of `replace` can be observed in the modified `go.mod`, or the built
+binary:
+
+```
+go version -m <BINARYNAME> |grep jose
+        dep     github.com/go-jose/go-jose/v3   v3.0.3
+        =>      github.com/go-jose/go-jose/v3   v3.0.4
+        dep     github.com/go-jose/go-jose/v4   v4.0.2
+        =>      github.com/go-jose/go-jose/v4   v4.0.5
+```
+
+As soon as the Go application upstream tags a newer release, remove the replace
+parameters from `_service` to return to pristine upstream sources and receive
+further updates to the dependency.
+
 ## Transition note
 
 Until such time as `obs-service-go_modules` is available on
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/obs-service-go_modules-0.6.6/go_modules 
new/obs-service-go_modules-0.6.8/go_modules
--- old/obs-service-go_modules-0.6.6/go_modules 2025-04-13 19:12:30.000000000 
+0200
+++ new/obs-service-go_modules-0.6.8/go_modules 2025-05-22 06:37:03.000000000 
+0200
@@ -122,6 +122,7 @@
     - .tar.lz
     - .tar.xz
     - .tar.zst
+    - .obscpio
     Returns str with filename of the archive or subdirectory
     """
     log.info("Autodetecting archive since no archive param provided in 
_service")
@@ -134,11 +135,11 @@
     spec = specs[0]
     c_exts = ("gz", "xz", "zst", "lz", "bz2")
     for pattern in (
-        [spec.stem]
-        + [f"{spec.stem}*.tar.{c_ext}" for c_ext in c_exts]
+        [f"{spec.stem}*.tar.{c_ext}" for c_ext in c_exts]
         + [f"{spec.stem}*.obscpio"]
         + [f"_service:*:{spec.stem}*tar.{c_ext}" for c_ext in c_exts]
         + [f"_service:*:{spec.stem}*obscpio"]
+        + [spec.stem]
     ):
         log.debug(f"Trying to find archive name with pattern {pattern}")
         matches = sorted(spec.parent.glob(pattern), reverse=True)
@@ -193,28 +194,49 @@
     os.chdir(cwd)
 
 
-def cmd_go_mod(cmd, moddir):
+def cmd_go_mod(subcmd, moddir):
     """Execute go mod subcommand using subprocess.run().
     Capture both stderr and stdout as text.
     Log as info or error in this function body.
     Return CompletedProcess object to caller for control flow.
     """
-    log.info(f"go mod {cmd}")
+    cmd = ["go", "mod"]
+    cmd.extend(subcmd)
+    log.info(" ".join(cmd))
     # subprocess.run() returns CompletedProcess cp
     if sys.version_info >= (3, 7):
-        cp = run(["go", "mod", cmd], cwd=moddir, capture_output=True, 
text=True)
+        cp = run(cmd, cwd=moddir, capture_output=True, text=True)
     else:
-        cp = run(["go", "mod", cmd], cwd=moddir)
+        cp = run(cmd, cwd=moddir)
     if cp.returncode:
         log.error(cp.stderr.strip())
     return cp
 
 
+def replace_modules(replace, go_mod_dir):
+    """Replace one or more modules
+    Parameter replace is a list of strings: 'module=replacement'
+    Returns boolean indicating go.mod and go.sum are modified
+    """
+    log.info(f"Replacing {len(replace)} modules")
+    for r in replace:
+        cp = cmd_go_mod(["edit", "-replace", r], go_mod_dir)
+        if cp.returncode:
+            log.error(f"go mod edit -replace={r} failed")
+            exit(1)
+    # run go mod tidy to update go.mod and go.sum
+    cp = cmd_go_mod(["tidy"], go_mod_dir)
+    if cp.returncode:
+        log.error("go mod tidy failed")
+        exit(1)
+    return True
+
+
 def sanitize_subdir(basedir, subdir):
     ret = os.path.normpath(subdir)
     if basedir == os.path.commonpath([basedir, ret]):
         return ret
-    log.error("Invalid path: {ret} not subdir of {basedir}")
+    log.error(f"Invalid path: {ret} not subdir of {basedir}")
     exit(1)
 
 
@@ -231,11 +253,18 @@
     parser.add_argument("--basename")
     parser.add_argument("--vendorname", default=DEFAULT_VENDOR_STEM)
     parser.add_argument("--subdir")
+    parser.add_argument(
+        "--replace",
+        action="append",
+        help="go mod edit replace argument: 'module=replacement'. Can be used 
multiple times.",
+    )
     args = parser.parse_args()
 
     outdir = args.outdir
     subdir = args.subdir
 
+    replace = args.replace
+
     archive_args = get_archive_parameters(args)
     vendor_tarname = f"{archive_args['vendorname']}.{archive_args['ext']}"
     if args.archive:
@@ -262,6 +291,7 @@
             or basename_from_archive(archive)
             or basename_from_archive_name(archive)
         )
+        basename = basename.split("/")[-1]
         if subdir:
             go_mod_path = sanitize_subdir(
                 tempdir, os.path.join(tempdir, basename, subdir, "go.mod")
@@ -277,6 +307,12 @@
             log.error(f"File go.mod not found under {os.path.join(tempdir, 
basename)}")
             exit(1)
 
+        modified = False  # sentinel value indicating go.mod and go.sum 
modification
+        if args.replace:
+            # replace one or more modules
+            # go.mod and go.sum will be modified and should be included in 
vendor archive
+            modified = replace_modules(replace, go_mod_dir)
+
         if args.strategy == "vendor":
             # go subcommand sequence:
             # - go mod download
@@ -287,7 +323,7 @@
             #   (validates checksums)
 
             # return value cp is type subprocess.CompletedProcess
-            cp = cmd_go_mod("download", go_mod_dir)
+            cp = cmd_go_mod(["download"], go_mod_dir)
             if cp.returncode:
                 if "invalid version" in cp.stderr:
                     log.warning(
@@ -300,12 +336,12 @@
                     log.error("go mod download failed")
                     exit(1)
 
-            cp = cmd_go_mod("vendor", go_mod_dir)
+            cp = cmd_go_mod(["vendor"], go_mod_dir)
             if cp.returncode:
                 log.error("go mod vendor failed")
                 exit(1)
 
-            cp = cmd_go_mod("verify", go_mod_dir)
+            cp = cmd_go_mod(["verify"], go_mod_dir)
             if cp.returncode:
                 log.error("go mod verify failed")
                 exit(1)
@@ -330,7 +366,24 @@
                 archive_args["compression"],
                 options=",".join(options),
             ) as new_archive:
-                new_archive.add_files(vendor_dir, mtime=mtime, ctime=mtime, 
atime=mtime)
+                try:
+                    new_archive.add_files(
+                        vendor_dir, mtime=mtime, ctime=mtime, atime=mtime
+                    )
+                    if modified:
+                        new_archive.add_files(
+                            "go.mod", mtime=mtime, ctime=mtime, atime=mtime
+                        )
+                        new_archive.add_files(
+                            "go.sum", mtime=mtime, ctime=mtime, atime=mtime
+                        )
+                except (
+                    TypeError
+                ):  # If using old libarchive fallback to old non reproducible 
behavior
+                    log.warning(
+                        "python libarchive is too old, unable to produce 
reproducible output"
+                    )
+                    new_archive.add_files(vendor_dir)
             os.chdir(cwd)
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/obs-service-go_modules-0.6.6/go_modules.service 
new/obs-service-go_modules-0.6.8/go_modules.service
--- old/obs-service-go_modules-0.6.6/go_modules.service 2025-04-13 
19:12:30.000000000 +0200
+++ new/obs-service-go_modules-0.6.8/go_modules.service 2025-05-22 
06:37:03.000000000 +0200
@@ -19,4 +19,7 @@
   <parameter name="vendorname">
     <description>Specify the name for the generated vendor tarball. Default: 
vendor</description>
   </parameter>
+  <parameter name="replace">
+    <description>Specify a module name and its replacement to be updated at 
vendoring time. Syntax must be a valid expression input to go mod edit 
-replace, e.g. 
github.com/go-jose/go-jose/v4=github.com/go-jose/go-jose/v4@v4.0.5. Can be used 
multiple times. Default: None.</description>
+  </parameter>
 </service>

Reply via email to