@@ -3,6 +3,7 @@ package main
33import (
44 "io/fs"
55 "os"
6+ "path/filepath"
67 "regexp"
78 "strconv"
89 "strings"
@@ -14,24 +15,34 @@ import (
1415// renders deterministic Kubernetes output from normalized inputs; how that
1516// output is transported, reviewed, or reconciled belongs to a separate
1617// promotion driver, not here. Each entry is matched case-insensitively.
18+ //
19+ // Patterns target the tokens these concepts actually carry in Go source and
20+ // Kubernetes manifests — import paths, API groups, resource kinds, and
21+ // process invocations — not the plain-English word, which real integrations
22+ // never emit. "flux" appears only as "fluxcd" (the module path and the
23+ // *.toolkit.fluxcd.io API groups); Git integration arrives as the go-git
24+ // library or an exec of the git binary, never as the prose "git clone".
1725var transportOwnershipPatterns = []* regexp.Regexp {
1826 regexp .MustCompile (`(?i)gitops` ),
1927 regexp .MustCompile (`(?i)repourl` ),
2028 regexp .MustCompile (`(?i)targetrevision` ),
2129 regexp .MustCompile (`(?i)appproject` ),
2230 regexp .MustCompile (`(?i)argocd` ),
2331 regexp .MustCompile (`(?i)argoproj` ),
24- regexp .MustCompile (`(?i)\bflux\b ` ),
32+ regexp .MustCompile (`(?i)fluxcd ` ),
2533 regexp .MustCompile (`(?i)kubeconfig` ),
2634 regexp .MustCompile (`(?i)reconcil` ),
35+ regexp .MustCompile (`(?i)go-git` ),
36+ regexp .MustCompile (`(?i)exec\.Command(?:Context)?\([^"]*"git"` ),
2737 regexp .MustCompile (`(?i)\bgit\s+(clone|push|commit|checkout|fetch|remote|tag|init|pull)\b` ),
2838 regexp .MustCompile (`(?i)\bpull\s+request\b` ),
2939 regexp .MustCompile (`(?i)kind:\s*Application\b` ),
3040 regexp .MustCompile (`(?i)kind:\s*AppProject\b` ),
41+ regexp .MustCompile (`(?i)kind:\s*GitRepository\b` ),
3142}
3243
33- // scan reports every line in content that matches a forbidden pattern,
34- // formatted as "<name>:<line>: <trimmed source>".
44+ // scanTransportOwnership reports every line in content that matches a
45+ // forbidden pattern, formatted as "<name>:<line>: <trimmed source>".
3546func scanTransportOwnership (name , content string ) []string {
3647 var hits []string
3748 for i , line := range strings .Split (content , "\n " ) {
@@ -45,22 +56,49 @@ func scanTransportOwnership(name, content string) []string {
4556 return hits
4657}
4758
59+ // isIgnoredSourceDir reports whether a directory is excluded from a module's
60+ // compiled runtime source. This mirrors the Go toolchain's own rule:
61+ // directories named "testdata" and those beginning with "." or "_" are never
62+ // built.
63+ func isIgnoredSourceDir (name string ) bool {
64+ return name == "testdata" || strings .HasPrefix (name , "." ) || strings .HasPrefix (name , "_" )
65+ }
66+
67+ // runtimeGoFiles returns every compiled runtime Go file under root: all
68+ // non-test .go files, recursively, excluding toolchain-ignored directories.
69+ // Test files are excluded because boundary guards (this file included) name
70+ // the forbidden concepts as data.
71+ func runtimeGoFiles (root string ) ([]string , error ) {
72+ var files []string
73+ err := filepath .WalkDir (root , func (path string , d fs.DirEntry , err error ) error {
74+ if err != nil {
75+ return err
76+ }
77+ if d .IsDir () {
78+ if path != root && isIgnoredSourceDir (d .Name ()) {
79+ return fs .SkipDir
80+ }
81+ return nil
82+ }
83+ if strings .HasSuffix (path , ".go" ) && ! strings .HasSuffix (path , "_test.go" ) {
84+ files = append (files , path )
85+ }
86+ return nil
87+ })
88+ return files , err
89+ }
90+
4891// TestRuntimeSourceIsTransportNeutral enforces the manifest-bundle boundary
4992// on this plugin's runtime source: it must not integrate with Git
5093// repositories, GitHub/pull requests, Argo CD/Flux reconcilers, kubeconfig,
5194// or own reconciliation objects (repoURL, targetRevision, Application,
52- // AppProject). Test files are excluded — this guard itself names the
53- // forbidden concepts.
95+ // AppProject). The scan is recursive so a future subpackage cannot escape it.
5496func TestRuntimeSourceIsTransportNeutral (t * testing.T ) {
55- entries , err := os . ReadDir ("." )
97+ files , err := runtimeGoFiles ("." )
5698 if err != nil {
57- t .Fatalf ("read package dir : %v" , err )
99+ t .Fatalf ("enumerate runtime source : %v" , err )
58100 }
59- for _ , e := range entries {
60- name := e .Name ()
61- if e .IsDir () || ! strings .HasSuffix (name , ".go" ) || strings .HasSuffix (name , "_test.go" ) {
62- continue
63- }
101+ for _ , name := range files {
64102 src , err := os .ReadFile (name )
65103 if err != nil {
66104 t .Fatalf ("read %s: %v" , name , err )
@@ -73,8 +111,8 @@ func TestRuntimeSourceIsTransportNeutral(t *testing.T) {
73111
74112// TestOwnedManifestsAreTransportNeutral enforces the same boundary on the
75113// plugin-owned deployment templates: they carry only workload/resources,
76- // never reconciliation control-plane objects (Argo Application/AppProject)
77- // or repository source bindings (repoURL, targetRevision).
114+ // never reconciliation control-plane objects (Argo Application/AppProject,
115+ // Flux GitRepository) or repository source bindings (repoURL, targetRevision).
78116func TestOwnedManifestsAreTransportNeutral (t * testing.T ) {
79117 err := fs .WalkDir (deploymentFS , "." , func (path string , d fs.DirEntry , err error ) error {
80118 if err != nil {
@@ -96,3 +134,85 @@ func TestOwnedManifestsAreTransportNeutral(t *testing.T) {
96134 t .Fatalf ("walk deployment templates: %v" , err )
97135 }
98136}
137+
138+ // TestScanTransportOwnershipDetectsRealVectors pins the detector to the forms
139+ // transport ownership actually takes in Go source and manifests — library
140+ // imports, API groups, resource kinds, and process invocations — and to a set
141+ // of benign lines that must not trip it.
142+ func TestScanTransportOwnershipDetectsRealVectors (t * testing.T ) {
143+ forbidden := []string {
144+ `_ "github.com/fluxcd/pkg/apis/meta"` ,
145+ `apiVersion: source.toolkit.fluxcd.io/v1` ,
146+ `kind: GitRepository` ,
147+ `_ "github.com/argoproj/argo-cd/v2/pkg/apis"` ,
148+ `import gogit "github.com/go-git/go-git/v5"` ,
149+ `r, _ := exec.Command("git", "clone", url).Output()` ,
150+ `out, _ := exec.CommandContext(ctx, "git", "push").CombinedOutput()` ,
151+ `kind: Application` ,
152+ `spec: { repoURL: https://example.com, targetRevision: main }` ,
153+ `// reconcile the cluster state` ,
154+ }
155+ for _ , line := range forbidden {
156+ if hits := scanTransportOwnership ("x.go" , line ); hits == nil {
157+ t .Errorf ("expected forbidden line to be flagged: %q" , line )
158+ }
159+ }
160+
161+ benign := []string {
162+ `import _ "github.com/codefly-dev/core/agents/services"` ,
163+ `s.Wool.Debug("git status is clean")` ,
164+ `kind: Deployment` ,
165+ `kind: Service` ,
166+ `newTag: {{.Image.Tag}}` ,
167+ `// influx of requests handled by the digit parser` ,
168+ }
169+ for _ , line := range benign {
170+ if hits := scanTransportOwnership ("x.go" , line ); hits != nil {
171+ t .Errorf ("benign line falsely flagged: %q -> %v" , line , hits )
172+ }
173+ }
174+ }
175+
176+ // TestRuntimeGoFilesRecursesAndFilters proves the enumerator descends into
177+ // subpackages (so no future package escapes the boundary check) while
178+ // excluding test files and toolchain-ignored directories.
179+ func TestRuntimeGoFilesRecursesAndFilters (t * testing.T ) {
180+ root := t .TempDir ()
181+ write := func (rel string ) {
182+ p := filepath .Join (root , rel )
183+ if err := os .MkdirAll (filepath .Dir (p ), 0o755 ); err != nil {
184+ t .Fatal (err )
185+ }
186+ if err := os .WriteFile (p , []byte ("package p\n " ), 0o644 ); err != nil {
187+ t .Fatal (err )
188+ }
189+ }
190+ write ("top.go" )
191+ write ("sub/pkg/deep.go" )
192+ write ("sub/pkg/deep_test.go" )
193+ write ("testdata/fixture.go" )
194+ write (".hidden/skip.go" )
195+
196+ files , err := runtimeGoFiles (root )
197+ if err != nil {
198+ t .Fatalf ("runtimeGoFiles: %v" , err )
199+ }
200+ got := map [string ]bool {}
201+ for _ , f := range files {
202+ rel , _ := filepath .Rel (root , f )
203+ got [filepath .ToSlash (rel )] = true
204+ }
205+
206+ want := []string {"top.go" , "sub/pkg/deep.go" }
207+ for _ , w := range want {
208+ if ! got [w ] {
209+ t .Errorf ("expected %s to be scanned, got %v" , w , files )
210+ }
211+ }
212+ excluded := []string {"sub/pkg/deep_test.go" , "testdata/fixture.go" , ".hidden/skip.go" }
213+ for _ , e := range excluded {
214+ if got [e ] {
215+ t .Errorf ("%s should have been excluded from the scan" , e )
216+ }
217+ }
218+ }
0 commit comments