From a7f4582af5ef91ba5477ea0957fdbf982430d745 Mon Sep 17 00:00:00 2001 From: topcoder1 Date: Sun, 24 May 2026 13:46:44 -0700 Subject: [PATCH] fix(claude-automerge): catch oauth2/* and main.go in risk-tier globs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The auth alternation `(auth|login|session|oauth|sso)` required the literal segment "oauth" — `internal/oauth2/server.go` slipped through because "oauth2" ≠ "oauth" under `(/|$)` anchoring. Go service entrypoints (`main.go` at any depth) had no pattern at all. Add `oauth2` to the alternation and a new `(^|/)main\.go$` pattern. Mirror both into the selftest with 6 new RISKY cases (oauth2 + main.go variants under common Go layouts) and 5 new SAFE cases (`main_test.go`, `mainview.go`, `oauth2helper.go`, `oauth2.md` doc — all substrings that must NOT match). Why: 2026-05-24 burn on whois-api-llc/wxa-mcp-server. PRs #193 (rename + main.go) and #197 (template.URL drop in internal/oauth2/server.go) had auto-merge enabled automatically by app/github-actions despite touching the oauth implementation. PR #194 — which touched internal/auth/ — was correctly blocked, confirming the `auth` segment match worked and only the `oauth2` + `main.go` paths leaked. Auto-merge rationale: in the manual-merge category (touches .github/workflows/**). Risk-tier path-scan will correctly block this PR on the new patterns themselves; manual click-merge required. Codex pre-review: not run — diff is purely additive regex + test cases (under ~30 LOC). Selftest exercises 41 RISKY + 16 SAFE paths and all pass; the regression surface is covered by the test, not the model. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/claude-author-automerge.yml | 12 ++++++++++-- selftest/test_automerge_risk_patterns.sh | 15 ++++++++++++++- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/.github/workflows/claude-author-automerge.yml b/.github/workflows/claude-author-automerge.yml index 7526143..f5a8f7c 100644 --- a/.github/workflows/claude-author-automerge.yml +++ b/.github/workflows/claude-author-automerge.yml @@ -9,10 +9,17 @@ name: Claude-author Auto-merge (reusable) # repo-specific block path without us having to keep a parallel regex). # # 2. Touching any risk-tier path category from the global CLAUDE.md policy: -# - auth / login / session / oauth / sso +# - auth / login / session / oauth / oauth2 / sso # - secrets / env files / keychain / credentials # - DB migrations / SQL files # - billing / payment / pricing / invoice +# - Go service entrypoints (main.go at any depth — wires routes, +# middleware, secrets loading, DB init; touching it can change +# auth or transport behavior. Lesson 2026-05-24 from +# whois-api-llc/wxa-mcp-server#193 + #197 where Claude PRs +# modifying main.go + internal/oauth2/ auto-merged because the +# `oauth` alternation didn't catch `oauth2` and main.go had no +# pattern at all.) # - production infra: Dockerfile, docker-compose, .github/workflows, # .github/risk-paths.yml, .github/CODEOWNERS, infra/iam/, infra # subdirs (deploy/terraform/pulumi/k8s/cloudformation/ansible/ @@ -252,7 +259,7 @@ jobs: # Risk-tier glob patterns (kept in sync with global CLAUDE.md policy). # If you add a category, also update install-automerge-policy.sh and # the CLAUDE.md policy block. - patterns='^(.*/)?(auth|login|session|oauth|sso)(/|$) + patterns='^(.*/)?(auth|login|session|oauth|oauth2|sso)(/|$) ^(.*/)?secrets(/|$) ^(.*/)?\.env($|\..*) ^(.*/)?keychain.* @@ -260,6 +267,7 @@ jobs: ^(.*/)?migrations(/|$) .*\.sql$ ^(.*/)?(billing|payment[s]?|pricing|invoice[s]?)(/|$) + (^|/)main\.go$ (^|/)Dockerfile(\..*)?$ ^docker-compose.*\.ya?ml$ ^\.github/workflows/.* diff --git a/selftest/test_automerge_risk_patterns.sh b/selftest/test_automerge_risk_patterns.sh index 08bb310..2e03e14 100755 --- a/selftest/test_automerge_risk_patterns.sh +++ b/selftest/test_automerge_risk_patterns.sh @@ -12,7 +12,7 @@ set -euo pipefail # Mirror the patterns block from .github/workflows/claude-author-automerge.yml. # Keep these in lock-step — if you edit one, edit the other. -patterns='^(.*/)?(auth|login|session|oauth|sso)(/|$) +patterns='^(.*/)?(auth|login|session|oauth|oauth2|sso)(/|$) ^(.*/)?secrets(/|$) ^(.*/)?\.env($|\..*) ^(.*/)?keychain.* @@ -20,6 +20,7 @@ patterns='^(.*/)?(auth|login|session|oauth|sso)(/|$) ^(.*/)?migrations(/|$) .*\.sql$ ^(.*/)?(billing|payment[s]?|pricing|invoice[s]?)(/|$) +(^|/)main\.go$ (^|/)Dockerfile(\..*)?$ ^docker-compose.*\.ya?ml$ ^\.github/workflows/.* @@ -52,6 +53,13 @@ matches() { # Cases the regex MUST flag as risky (manual click-merge). RISKY=( "src/auth/login.py" + "internal/auth/security.go" # auth segment, Go layout + "internal/oauth2/server.go" # oauth2 alternation — wxa-mcp-server#193/#197 gap (2026-05-24) + "internal/oauth2/handler.go" + "pkg/oauth2/token.go" + "main.go" # Go entrypoint at root — wxa-mcp-server#193 gap + "cmd/server/main.go" # Go entrypoint under cmd/ + "cmd/wxa-mcp-server/main.go" "secrets/api-keys.json" ".env.production" "src/keychain_helpers.py" @@ -92,6 +100,11 @@ SAFE=( "src/wxa_vpn/api/routes.py" "tests/test_anything.py" "docs/data-dictionary.md" + "main_test.go" # adjacent to main.go but a test file + "internal/foo/main_test.go" + "internal/oauth2.md" # doc file mentioning oauth2 — pattern needs trailing / or end + "cmd/server/mainview.go" # starts with "main" but not the literal main.go + "src/oauth2helper.go" # oauth2 substring but not a path segment "scripts/run_analysis.py" "infra/crontabs/wxa-scanner.crontab" # cron schedule — wxa_vpn#439 case "infra/crontabs/wxa-scanner-active.crontab"