From c9b618c08e57dc3eb6347009975b04aa6eca6ab6 Mon Sep 17 00:00:00 2001 From: Antoine Toussaint <312536060+antoinetoussaint-byte@users.noreply.github.com> Date: Tue, 27 Oct 2026 16:10:42 -0400 Subject: [PATCH 1/2] fix(manifest-guard): retain Go binding declaration coverage --- actions/manifest-ownership-scan/scan.sh | 7 ++++--- actions/manifest-ownership-scan/scan_test.sh | 20 +++++++++++++++++++ .../testdata/go-declarations/source.go | 13 ++++++++++++ docs/manifest-guard.md | 3 +++ 4 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 actions/manifest-ownership-scan/testdata/go-declarations/source.go diff --git a/actions/manifest-ownership-scan/scan.sh b/actions/manifest-ownership-scan/scan.sh index 7cf1f7f..d6a1701 100755 --- a/actions/manifest-ownership-scan/scan.sh +++ b/actions/manifest-ownership-scan/scan.sh @@ -67,9 +67,10 @@ PATTERNS=( # catch it. A plain READ (`req.Revision == ""`) stays allowed: reading a # released contract field owns neither the type nor a binding. The explicit # spellings and refs/heads/ stay matched wherever they appear. - "Repository branch binding::(^|[^[:alnum:]_])(repoBranch|repositoryBranch|repository_branch|repository-branch|gitBranch|git_branch|git-branch)([^[:alnum:]_]|$)|refs/heads/|^[[:space:]]*(-[[:space:]]*)?[\"']?branch[\"']?[[:space:]]*(:|=[^=])|^[[:space:]]*branch[[:space:]]+[^[:space:]]|[\"']branch[\"'][[:space:]]*:|:[\"']branch[\"']|[.>]branch[[:space:]]*=[^=]|[{,][[:space:]]*branch[[:space:]]*:|(set|with)_?branch[[:space:]]*\\(" - # Same rule as Branch above, including the allowed selector read. - "Repository revision binding::(^|[^[:alnum:]_])(targetRevision|repoRevision|repositoryRevision|repository_revision|repository-revision|gitRevision|git_revision|git-revision)([^[:alnum:]_]|$)|^[[:space:]]*(-[[:space:]]*)?[\"']?revision[\"']?[[:space:]]*(:|=[^=])|^[[:space:]]*revision[[:space:]]+[^[:space:]]|[\"']revision[\"'][[:space:]]*:|:[\"']revision[\"']|[.>]revision[[:space:]]*=[^=]|[{,][[:space:]]*revision[[:space:]]*:|(set|with)_?revision[[:space:]]*\\(" + "Repository branch binding::(^|[^[:alnum:]_])(repoBranch|repositoryBranch|repository_branch|repository-branch|gitBranch|git_branch|git-branch)([^[:alnum:]_]|$)|refs/heads/|^[[:space:]]*(-[[:space:]]*)?[\"']?branch[\"']?[[:space:]]*(:|=[^=])|(^|[{;])[[:space:]]*((var|const)[[:space:]]+)?branch[[:space:]]+[^[:space:]]|[\"']branch[\"'][[:space:]]*:|:[\"']branch[\"']|[.>]branch[[:space:]]*=[^=]|[{,][[:space:]]*branch[[:space:]]*:|(set|with)_?branch[[:space:]]*\\(" + # Same rule as Branch above, including var/const and inline fields, + # while preserving the allowed selector read. + "Repository revision binding::(^|[^[:alnum:]_])(targetRevision|repoRevision|repositoryRevision|repository_revision|repository-revision|gitRevision|git_revision|git-revision)([^[:alnum:]_]|$)|^[[:space:]]*(-[[:space:]]*)?[\"']?revision[\"']?[[:space:]]*(:|=[^=])|(^|[{;])[[:space:]]*((var|const)[[:space:]]+)?revision[[:space:]]+[^[:space:]]|[\"']revision[\"'][[:space:]]*:|:[\"']revision[\"']|[.>]revision[[:space:]]*=[^=]|[{,][[:space:]]*revision[[:space:]]*:|(set|with)_?revision[[:space:]]*\\(" 'Git library::github\.com/(go-git/go-git|libgit2/git2go|src-d/go-git)/|org\.eclipse\.jgit|git2::Repository|simple-git|isomorphic-git|nodegit|GitPython|dulwich' 'GitHub API client::github\.com/google/go-github/|github\.com/shurcooL/githubv4|github\.NewClient|@octokit/|PyGithub|githubkit|octocrab' 'Pull request operation::PullRequest|pull_request|pull-request|pulls\.(Create|Edit|List|Merge)' diff --git a/actions/manifest-ownership-scan/scan_test.sh b/actions/manifest-ownership-scan/scan_test.sh index 76b8e99..e2b820b 100755 --- a/actions/manifest-ownership-scan/scan_test.sh +++ b/actions/manifest-ownership-scan/scan_test.sh @@ -134,6 +134,26 @@ else done fi +# Go declarations are bindings even with var/const prefixes or inline fields. +# Prose and contract reads above must remain clean under the same matcher. +if out="$(SCAN_ROOT="$here/testdata/go-declarations" bash "$scan" 2>&1)"; then + fail "Go binding declarations should fail but passed" +else + for expectation in \ + "[Repository branch binding] source.go:4:" \ + "[Repository revision binding] source.go:5:" \ + "[Repository branch binding] source.go:9:" \ + "[Repository revision binding] source.go:10:" \ + "[Repository branch binding] source.go:13:" \ + "[Repository revision binding] source.go:13:"; do + if grep -qF "$expectation" <<<"$out"; then + pass "Go declaration reported: $expectation" + else + fail "Go declaration missed: $expectation"$'\n'"$out" + fi + done +fi + # Excluded paths must not be the reason a dirty tree fails: prove the release # workflow's git@github.com and the fixture's argoproj.io are never reported # for the clean tree. diff --git a/actions/manifest-ownership-scan/testdata/go-declarations/source.go b/actions/manifest-ownership-scan/testdata/go-declarations/source.go new file mode 100644 index 0000000..3c9da8d --- /dev/null +++ b/actions/manifest-ownership-scan/testdata/go-declarations/source.go @@ -0,0 +1,13 @@ +package runtime + +func variables() { + var Branch = "main" + var Revision = "HEAD" + _, _ = Branch, Revision +} +func constants() { + const Branch = "main" + const Revision = "HEAD" + _, _ = Branch, Revision +} +type Inline struct { Branch string; Revision string } diff --git a/docs/manifest-guard.md b/docs/manifest-guard.md index ad2a163..957282f 100644 --- a/docs/manifest-guard.md +++ b/docs/manifest-guard.md @@ -19,6 +19,9 @@ The guard does two things: ownership concepts: Git operations and remotes, repository URL/branch/ revision bindings, pull requests, GitHub clients, Argo/Flux clients and API groups, `Application`, `AppProject`, `repoURL`, and `targetRevision`. + Branch/revision binding includes Go `var`/`const` declarations and inline + struct fields; plain released-contract field reads and comment prose remain + allowed. Exclusions are **path-based only**. Repository automation (`.github/`, `.coderabbit.yaml`, and conventional publish/release script directories) and From 3a1e9063dac195791712ea73c439511d2107257a Mon Sep 17 00:00:00 2001 From: Antoine Toussaint <312536060+antoinetoussaint-byte@users.noreply.github.com> Date: Tue, 27 Oct 2026 16:14:29 -0400 Subject: [PATCH 2/2] fix(manifest-guard): distinguish Go declarations from punctuated prose --- actions/manifest-ownership-scan/scan.sh | 4 ++-- actions/manifest-ownership-scan/scan_test.sh | 4 +++- .../testdata/go-declarations/source.go | 1 + .../testdata/runtime-prose/runtime.go | 5 +++++ 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/actions/manifest-ownership-scan/scan.sh b/actions/manifest-ownership-scan/scan.sh index d6a1701..a0171bf 100755 --- a/actions/manifest-ownership-scan/scan.sh +++ b/actions/manifest-ownership-scan/scan.sh @@ -67,10 +67,10 @@ PATTERNS=( # catch it. A plain READ (`req.Revision == ""`) stays allowed: reading a # released contract field owns neither the type nor a binding. The explicit # spellings and refs/heads/ stay matched wherever they appear. - "Repository branch binding::(^|[^[:alnum:]_])(repoBranch|repositoryBranch|repository_branch|repository-branch|gitBranch|git_branch|git-branch)([^[:alnum:]_]|$)|refs/heads/|^[[:space:]]*(-[[:space:]]*)?[\"']?branch[\"']?[[:space:]]*(:|=[^=])|(^|[{;])[[:space:]]*((var|const)[[:space:]]+)?branch[[:space:]]+[^[:space:]]|[\"']branch[\"'][[:space:]]*:|:[\"']branch[\"']|[.>]branch[[:space:]]*=[^=]|[{,][[:space:]]*branch[[:space:]]*:|(set|with)_?branch[[:space:]]*\\(" + "Repository branch binding::(^|[^[:alnum:]_])(repoBranch|repositoryBranch|repository_branch|repository-branch|gitBranch|git_branch|git-branch)([^[:alnum:]_]|$)|refs/heads/|^[[:space:]]*(-[[:space:]]*)?[\"']?branch[\"']?[[:space:]]*(:|=[^=])|^[[:space:]]*branch[[:space:]]+[^[:space:]]|(^|[{;])[[:space:]]*(var|const)[[:space:]]+branch[[:space:]]+[^[:space:]]|^[[:space:]]*type[[:space:]]+[[:alnum:]_]+[[:space:]]+struct[[:space:]]*[{]([^}]*;)?[[:space:]]*branch[[:space:]]+[^[:space:]]|[\"']branch[\"'][[:space:]]*:|:[\"']branch[\"']|[.>]branch[[:space:]]*=[^=]|[{,][[:space:]]*branch[[:space:]]*:|(set|with)_?branch[[:space:]]*\\(" # Same rule as Branch above, including var/const and inline fields, # while preserving the allowed selector read. - "Repository revision binding::(^|[^[:alnum:]_])(targetRevision|repoRevision|repositoryRevision|repository_revision|repository-revision|gitRevision|git_revision|git-revision)([^[:alnum:]_]|$)|^[[:space:]]*(-[[:space:]]*)?[\"']?revision[\"']?[[:space:]]*(:|=[^=])|(^|[{;])[[:space:]]*((var|const)[[:space:]]+)?revision[[:space:]]+[^[:space:]]|[\"']revision[\"'][[:space:]]*:|:[\"']revision[\"']|[.>]revision[[:space:]]*=[^=]|[{,][[:space:]]*revision[[:space:]]*:|(set|with)_?revision[[:space:]]*\\(" + "Repository revision binding::(^|[^[:alnum:]_])(targetRevision|repoRevision|repositoryRevision|repository_revision|repository-revision|gitRevision|git_revision|git-revision)([^[:alnum:]_]|$)|^[[:space:]]*(-[[:space:]]*)?[\"']?revision[\"']?[[:space:]]*(:|=[^=])|^[[:space:]]*revision[[:space:]]+[^[:space:]]|(^|[{;])[[:space:]]*(var|const)[[:space:]]+revision[[:space:]]+[^[:space:]]|^[[:space:]]*type[[:space:]]+[[:alnum:]_]+[[:space:]]+struct[[:space:]]*[{]([^}]*;)?[[:space:]]*revision[[:space:]]+[^[:space:]]|[\"']revision[\"'][[:space:]]*:|:[\"']revision[\"']|[.>]revision[[:space:]]*=[^=]|[{,][[:space:]]*revision[[:space:]]*:|(set|with)_?revision[[:space:]]*\\(" 'Git library::github\.com/(go-git/go-git|libgit2/git2go|src-d/go-git)/|org\.eclipse\.jgit|git2::Repository|simple-git|isomorphic-git|nodegit|GitPython|dulwich' 'GitHub API client::github\.com/google/go-github/|github\.com/shurcooL/githubv4|github\.NewClient|@octokit/|PyGithub|githubkit|octocrab' 'Pull request operation::PullRequest|pull_request|pull-request|pulls\.(Create|Edit|List|Merge)' diff --git a/actions/manifest-ownership-scan/scan_test.sh b/actions/manifest-ownership-scan/scan_test.sh index e2b820b..a80f734 100755 --- a/actions/manifest-ownership-scan/scan_test.sh +++ b/actions/manifest-ownership-scan/scan_test.sh @@ -145,7 +145,9 @@ else "[Repository branch binding] source.go:9:" \ "[Repository revision binding] source.go:10:" \ "[Repository branch binding] source.go:13:" \ - "[Repository revision binding] source.go:13:"; do + "[Repository revision binding] source.go:13:" \ + "[Repository branch binding] source.go:14:" \ + "[Repository revision binding] source.go:14:"; do if grep -qF "$expectation" <<<"$out"; then pass "Go declaration reported: $expectation" else diff --git a/actions/manifest-ownership-scan/testdata/go-declarations/source.go b/actions/manifest-ownership-scan/testdata/go-declarations/source.go index 3c9da8d..1d35904 100644 --- a/actions/manifest-ownership-scan/testdata/go-declarations/source.go +++ b/actions/manifest-ownership-scan/testdata/go-declarations/source.go @@ -11,3 +11,4 @@ func constants() { _, _ = Branch, Revision } type Inline struct { Branch string; Revision string } +func inline() { var Branch = "main"; var Revision = "HEAD"; _, _ = Branch, Revision } diff --git a/actions/manifest-ownership-scan/testdata/runtime-prose/runtime.go b/actions/manifest-ownership-scan/testdata/runtime-prose/runtime.go index fff74bf..1432f27 100644 --- a/actions/manifest-ownership-scan/testdata/runtime-prose/runtime.go +++ b/actions/manifest-ownership-scan/testdata/runtime-prose/runtime.go @@ -13,3 +13,8 @@ func installsLinkedPackages(container bool) bool { } return true } + +// Select a path; branch selection depends on the input. +// Update the plan; revision history remains available. +// Explain the choice { branch selection depends on the input. +// Explain the choice { revision history remains available.