#1151332 dh-go: an installed copy of the package being built shadows its own go.mod

Package:
dh-go
Source:
dh-go
Submitter:
Juan Manuel Mendez Rey
Date:
2026-10-19 18:47:03 UTC
Severity:
normal
#1151332#5
Date:
2026-10-19 18:44:52 UTC
From:
To:
_get_go_module_dependencies() sends the module path through
auto_module_mappings before it reads go.mod. DH_GOPKG and the use targets go
through the same mapping. When the package being built declares a /vN module
path, and an older version of itself is installed at the directory without
the suffix, the mapping points the walk at the installed copy. The
requirements of the sources being built are then never followed, and the
modules they need end up neither replaced nor stubbed in go.work.

The mapping is mine, from commit 1ff68b9 for bug 1149023. It was tested from
the consumer side only, where the module being built and the mapped module
are never the same.

Reproducer, two native packages. Package one ships
usr/share/gocode/src/example.debian.org/walkstub/go.mod with the line
"module example.debian.org/walkstub/v2". Package two declares
XS-Go-Import-Path: example.debian.org/walkstub/v2, has the same module line
in its own go.mod, requires github.com/google/go-containerregistry v0.20.7,
build depends on package one, and prints _build/go.work after
dh_auto_configure. Both builds are sbuild runs in a clean sid chroot:

  package one installed   Checking dependencies of   go.work replace lines
  no                      362                        1548, auto/sdk stubbed
  yes                     2                          1495, auto/sdk missing

With package one installed the log shows the shadowing twice:

  Checking dependencies of example.debian.org/walkstub/v2
  ... installed at example.debian.org/walkstub

In a real package the build stops. golang-github-theupdateframework-go-tuf,
ported to dh-go with XS-Go-Import-Path github.com/theupdateframework/go-tuf/v2
while sid still ships the library at the path without the suffix, fails with

  github.com/google/go-containerregistry@v0.20.7 requires
  go.opentelemetry.io/auto/sdk@v1.1.0: module lookup disabled by GOPROXY=off

for a module that is in neither its go.mod nor its debian/rules. A circular build dependency is
what installs the old version, which is normal for a library that its own
reverse dependency needs to run the tests.

Please merge
https://salsa.debian.org/go-team/dh-go/-/merge_requests/6

The patch only follows the mapping when the build directory does not already
hold that module at its own path:
--- a/lib/Debian/Debhelper/Buildsystem/golang.pm
+++ b/lib/Debian/Debhelper/Buildsystem/golang.pm
@@
-    } elsif (exists $this->{auto_module_mappings}{$gomodule}) {
+    } elsif (exists $this->{auto_module_mappings}{$gomodule}
+        and not -e $this->get_buildpath("src/$gomodule/go.mod"))
+    {
         # A module can be installed at a path other than its module
         # path, e.g. github.com/foo/bar/v2 under github.com/foo/bar.
         # Its requirements must still be followed, otherwise they end
         # up neither replaced nor stubbed in go.work.
+        #
+        # Only follow the mapping when the build directory does not hold
+        # that module already. The sources of the package being built are
+        # copied to src/$DH_GOPKG, and an older version of the same module
+        # can be installed at another path. The mapping would then send the
+        # walk to the installed copy instead of the source being built.
         $gomodule = $this->{auto_module_mappings}{$gomodule};
         verbose_print("... installed at $gomodule");
     }

I also rebuilt every source that build depends on dh-go, 27 of them, in a
clean sid chroot with the patch in place. All 27 come back
"Status: successful", the eight with a -vN-dev binary among them. I took
go-sendxmpp from sid, 0.17.1-1, because the version in testing does not
build against the dependencies in sid with 1.69 either.

Verified with the same two packages: the shadowed build goes back to 362
dependency checks, 1548 replace lines and the stub. The case of bug 1149023
is unchanged, checked with a consumer package whose dependency is installed
at the path without the suffix and whose requirements only the mapping can
reach: the mapping is still followed and that requirement is still stubbed,
with 1.69 and with the patch.