Skip to content

Commit 858a727

Browse files
committed
fix: block indirect dependencies when directly imported
Previously, gomodguard would not block indirect dependencies if they were directly imported in the code without running `go mod tidy`. This fix ensures that all imports, including indirect dependencies, are checked against the allow and block lists. Fixes: GH-59
1 parent 7cf3bf4 commit 858a727

File tree

12 files changed

+224
-10
lines changed

12 files changed

+224
-10
lines changed

_example/allOptions/blocked_example.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package gomodguard
1+
package example
22

33
import (
44
"os"

_example/emptyAllowList/blocked_example_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package example2
1+
package example
22

33
import (
44
"testing"

_example/emptyAllowList/go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
module github.com/ryancurrah/example/example2
1+
module github.com/ryancurrah/example
22

33
go 1.21
44

_example/indirectDep/.gomodguard.yaml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
allowed:
2+
modules: # List of allowed modules
3+
- gopkg.in/yaml.v3
4+
- github.com/go-xmlfmt/xmlfmt
5+
- github.com/Masterminds/semver
6+
- github.com/ryancurrah/gomodguard
7+
domains: # List of allowed module domains
8+
- golang.org
9+
10+
blocked:
11+
modules: # List of blocked modules
12+
- github.com/gofrs/uuid:
13+
recommendations:
14+
- github.com/ryancurrah/gomodguard
15+
reason: "testing module is blocked when it is an indirect dependency."
16+
17+
versions:
18+
- github.com/mitchellh/go-homedir:
19+
version: "<= 1.1.0"
20+
reason: "testing if blocked version constraint works."
21+
22+
local_replace_directives: true

_example/indirectDep/go.mod

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
module github.com/ryancurrah/example
2+
3+
go 1.15
4+
5+
require (
6+
github.com/mitchellh/go-homedir v1.1.0
7+
github.com/ryancurrah/gomodguard v1.1.0
8+
)
9+
10+
require (
11+
github.com/gofrs/uuid v3.3.0+incompatible // indirect
12+
github.com/uudashr/go-module v0.0.0-20200529023307-c90a4239ad70 // indirect
13+
)
14+
15+
replace github.com/ryancurrah/gomodguard => ../

_example/indirectDep/go.sum

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
2+
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
3+
github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b h1:khEcpUM4yFcxg4/FHQWkvVRmgijNXRfzkIDHh23ggEo=
4+
github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM=
5+
github.com/gofrs/uuid v3.3.0+incompatible h1:8K4tyRfvU1CYPgJsveYFQMhpFd/wXNM7iK6rR7UHz84=
6+
github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
7+
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
8+
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
9+
github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d h1:CdDQnGF8Nq9ocOS/xlSptM1N3BbrA6/kmaep5ggwaIA=
10+
github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d/go.mod h1:3OzsM7FXDQlpCiw2j81fOmAwQLnZnLGXVKUzeKQXIAw=
11+
github.com/uudashr/go-module v0.0.0-20200529023307-c90a4239ad70 h1:t/4GlAfaNAVbh8GqZmHl96pFwlaw7+DAwp2OjUMOxgw=
12+
github.com/uudashr/go-module v0.0.0-20200529023307-c90a4239ad70/go.mod h1:P6Nk1sQWL6jcdBIxnLVlqCsOl0arao7gg7sPoM6gx4A=
13+
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
14+
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
15+
golang.org/x/mod v0.4.0 h1:8pl+sMODzuvGJkmj2W4kZihvVb5mKm8pB/X44PIQHv8=
16+
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
17+
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
18+
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
19+
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
20+
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
21+
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
22+
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
23+
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
24+
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
25+
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA=
26+
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
27+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
28+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
29+
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
30+
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package gomodguard
2+
3+
import (
4+
"os"
5+
6+
"github.com/gofrs/uuid"
7+
"github.com/mitchellh/go-homedir"
8+
"github.com/ryancurrah/gomodguard"
9+
module "github.com/uudashr/go-module"
10+
)
11+
12+
func aBlockedImport() { //nolint: deadcode,unused
13+
b, err := os.ReadFile("go.mod")
14+
if err != nil {
15+
panic(err)
16+
}
17+
18+
mod, err := module.Parse(b)
19+
if err != nil {
20+
panic(err)
21+
}
22+
23+
_ = mod
24+
25+
_ = uuid.Must(uuid.NewV4())
26+
27+
var blockedModule gomodguard.BlockedModule
28+
blockedModule.Set("some.com/module/name")
29+
30+
_, _ = homedir.Expand("~/something")
31+
}

_example/invalidConstraint/blocked_example_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package example2
1+
package example
22

33
import (
44
"errors"

_example/invalidConstraint/go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
module github.com/ryancurrah/example/example3
1+
module github.com/ryancurrah/example
22

33
go 1.21
44

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module github.com/ryancurrah/gomodguard
22

3-
go 1.22.0
3+
go 1.24
44

55
require (
66
github.com/Masterminds/semver/v3 v3.3.1

processor.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -146,10 +146,6 @@ func (p *Processor) SetBlockedModules() { //nolint:funlen
146146
replacedModules := p.Modfile.Replace
147147

148148
for i := range lintedModules {
149-
if lintedModules[i].Indirect {
150-
continue // Do not lint indirect modules.
151-
}
152-
153149
lintedModuleName := strings.TrimSpace(lintedModules[i].Mod.Path)
154150
lintedModuleVersion := strings.TrimSpace(lintedModules[i].Mod.Version)
155151

processor_internal_test.go

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,3 +385,123 @@ func TestProcessorSetBlockedModulesWithInvalidVersionConstraint(t *testing.T) {
385385
processor.blockedModulesFromModFile["github.com/gin-gonic/gin"],
386386
)
387387
}
388+
389+
func TestProcessorSetBlockedModulesWithIndirectDependency(t *testing.T) {
390+
tests := []struct {
391+
name string
392+
config *Configuration
393+
modfile *modfile.File
394+
wantBlockedModules map[string][]string
395+
}{
396+
{
397+
name: "module is specifically blocked",
398+
config: &Configuration{
399+
Allowed: Allowed{
400+
Modules: []string{
401+
"gopkg.in/yaml.v3",
402+
"github.com/go-xmlfmt/xmlfmt",
403+
"github.com/Masterminds/semver/v3",
404+
"github.com/ryancurrah/gomodguard",
405+
},
406+
Domains: []string{
407+
"golang.org",
408+
},
409+
},
410+
Blocked: Blocked{
411+
Modules: BlockedModules{
412+
{
413+
"github.com/indirect/dependency": BlockedModule{
414+
Recommendations: []string{"github.com/recommended/module"},
415+
Reason: "Indirect dependencies should not be directly imported.",
416+
},
417+
},
418+
},
419+
},
420+
},
421+
modfile: &modfile.File{
422+
Module: &modfile.Module{
423+
Mod: module.Version{
424+
Path: "github.com/ryancurrah/gomodguard",
425+
Version: "v1.0.0",
426+
},
427+
},
428+
Require: []*modfile.Require{
429+
{
430+
Indirect: true, // Mark this dependency as indirect
431+
Mod: module.Version{
432+
Path: "github.com/indirect/dependency",
433+
Version: "v1.0.0",
434+
},
435+
},
436+
},
437+
},
438+
wantBlockedModules: map[string][]string{
439+
"github.com/indirect/dependency": {
440+
"import of package `%s` is blocked because the module is in the blocked modules list. " +
441+
"`github.com/recommended/module` is a recommended module. Indirect dependencies should not be directly imported.",
442+
},
443+
},
444+
},
445+
{
446+
name: "module is implicitly blocked (not in allowed list)",
447+
config: &Configuration{
448+
Allowed: Allowed{
449+
Modules: []string{
450+
"gopkg.in/yaml.v3",
451+
"github.com/go-xmlfmt/xmlfmt",
452+
"github.com/Masterminds/semver/v3",
453+
"github.com/ryancurrah/gomodguard",
454+
},
455+
Domains: []string{
456+
"golang.org",
457+
},
458+
},
459+
Blocked: Blocked{
460+
Modules: BlockedModules{},
461+
},
462+
},
463+
modfile: &modfile.File{
464+
Module: &modfile.Module{
465+
Mod: module.Version{
466+
Path: "github.com/ryancurrah/gomodguard",
467+
Version: "v1.0.0",
468+
},
469+
},
470+
Require: []*modfile.Require{
471+
{
472+
Indirect: true, // Mark this dependency as indirect
473+
Mod: module.Version{
474+
Path: "github.com/indirect/dependency",
475+
Version: "v1.0.0",
476+
},
477+
},
478+
},
479+
},
480+
wantBlockedModules: map[string][]string{
481+
"github.com/indirect/dependency": {
482+
"import of package `%s` is blocked because the module is not in the allowed modules list.",
483+
},
484+
},
485+
},
486+
}
487+
488+
for _, tt := range tests {
489+
t.Run(tt.name, func(t *testing.T) {
490+
processor := &Processor{
491+
Config: tt.config,
492+
Modfile: tt.modfile,
493+
}
494+
495+
processor.SetBlockedModules()
496+
497+
// Assert number of blocked modules
498+
assert.Equal(t, len(tt.wantBlockedModules), len(processor.blockedModulesFromModFile))
499+
500+
// Assert blocked modules and reasons
501+
for blockedModule, wantReasons := range tt.wantBlockedModules {
502+
gotReasons := processor.blockedModulesFromModFile[blockedModule]
503+
assert.Equal(t, wantReasons, gotReasons)
504+
}
505+
})
506+
}
507+
}

0 commit comments

Comments
 (0)