Skip to content

Split template injection validator by responsibility#26580

Merged
pelikhan merged 4 commits intomainfrom
copilot/split-template-injection-validation
Apr 16, 2026
Merged

Split template injection validator by responsibility#26580
pelikhan merged 4 commits intomainfrom
copilot/split-template-injection-validation

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 16, 2026

pkg/workflow/template_injection_validation.go had grown past the validator size guideline and mixed traversal/detection logic with utility + error-formatting concerns. This PR performs a pure intra-package split to isolate helpers while preserving behavior.

  • Validation core stays in template_injection_validation.go

    • Retains only the 3 entry points:
      • hasUnsafeExpressionInRunContent
      • validateNoTemplateInjection
      • validateNoTemplateInjectionFromParsed
    • File is now under the requested threshold (224 lines).
  • Helper/utility logic moved to template_injection_utils.go

    • Moved functions:
      • extractRunBlocks
      • removeHeredocContent
      • extractRunSnippet
      • detectExpressionContext
      • formatTemplateInjectionError
    • Includes supporting types/regex data used by those helpers (e.g., heredoc pattern struct and violation type), unchanged in behavior.
  • No functional changes

    • Same workflow package, same call graph, same error formatting and detection semantics.
    • Existing tests that exercise template-injection behavior continue to target the same function boundaries.
// validation file now keeps orchestration only:
func validateNoTemplateInjectionFromParsed(workflow map[string]any) error {
	runBlocks := extractRunBlocks(workflow) // now defined in template_injection_utils.go
	// ... unchanged detection loop ...
	return formatTemplateInjectionError(violations) // now in utils file
}

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • https://api.github.com/graphql
    • Triggering command: /usr/bin/gh /usr/bin/gh api graphql -f query=query($owner: String!, $name: String!) { repository(owner: $owner, name: $name) { hasDiscussionsEnabled } } -f owner=github -f name=gh-aw pkg/mod/golang.orev-parse ache/go/1.25.8/x--show-toplevel git rev-�� --show-toplevel ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet /usr/bin/git /tmp/go-build285git -trimpath 1/x64/bin/node git (http block)
    • Triggering command: /usr/bin/gh /usr/bin/gh api graphql -f query=query($owner: String!, $name: String!) { repository(owner: $owner, name: $name) { hasDiscussionsEnabled } } -f owner=github -f name=gh-aw GO111MODULE .cfg git rev-�� --show-toplevel go /usr/bin/git CompiledOutput23git GO111MODULE ache/go/1.25.8/x--show-toplevel git (http block)
    • Triggering command: /usr/bin/gh /usr/bin/gh api graphql -f query=query($owner: String!, $name: String!) { repository(owner: $owner, name: $name) { hasDiscussionsEnabled } } -f owner=github -f name=gh-aw efaultBranchFromrev-parse k/gh-aw/gh-aw/ac--show-toplevel git rev-�� --show-toplevel go /usr/lib/git-core/git-remote-https CommaSeparatedCogit GO111MODULE /opt/hostedtoolc--show-toplevel /usr/lib/git-core/git-remote-https (http block)
  • https://api.github.com/orgs/test-owner/actions/secrets
    • Triggering command: /usr/bin/gh gh api /orgs/test-owner/actions/secrets --jq .secrets[].name -json GO111MODULE x_amd64/compile GOINSECURE GOMOD GOMODCACHE x_amd64/compile env -json GO111MODULE x_amd64/compile GOINSECURE GOMOD GOMODCACHE x_amd64/compile (http block)
    • Triggering command: /usr/bin/gh gh api /orgs/test-owner/actions/secrets --jq .secrets[].name -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
    • Triggering command: /usr/bin/gh gh api /orgs/test-owner/actions/secrets --jq .secrets[].name -json GO111MODULE 64/bin/go GOINSECURE GOMOD erignore go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/actions/ai-inference/git/ref/tags/v1
    • Triggering command: /usr/bin/gh gh api /repos/actions/ai-inference/git/ref/tags/v1 --jq [.object.sha, .object.type] | @tsv --show-toplevel x_amd64/compile /usr/bin/git tmatter-with-nesgit .cfg 64/pkg/tool/linu--show-toplevel /usr/bin/git remo�� -v 64/pkg/tool/linuTest commit /usr/bin/git ortcfg GO111MODULE 64/pkg/tool/linu--show-toplevel git (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/ai-inference/git/ref/tags/v1 --jq [.object.sha, .object.type] | @tsv --show-toplevel go /usr/bin/gh -json GO111MODULE 64/bin/go gh api --paginate repos/{owner}/{repo}/actions/runs/12346/artifacts /usr/bin/git .artifacts[].namgit GO111MODULE 64/bin/go git (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/ai-inference/git/ref/tags/v1 --jq [.object.sha, .object.type] | @tsv --git-dir go /usr/bin/git b/workflows GO111MODULE 64/bin/go git rev-�� --show-toplevel resolved$ /usr/bin/git itcustom_branch4git itcustom_branch4rev-parse ache/go/1.25.8/x--show-toplevel git (http block)
  • https://api.github.com/repos/actions/checkout/git/ref/tags/v3
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v3 --jq [.object.sha, .object.type] | @tsv /tmp/TestGuardPolicyMinIntegrityOnlymin-integrity_with_repos=pub-c=4 (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v3 --jq [.object.sha, .object.type] | @tsv /tmp/TestHashConsistency_GoAndJavaScript1810235438/001/test-simp.github/workflows/test.md -tests /usr/bin/gh ck 'scripts/**/*git GO111MODULE 64/bin/go gh api /repos/actions/github-script/git/ref/tags/v9 --jq /opt/hostedtoolcache/node/24.14.1/x64/bin/node led-with-body-cogit GO111MODULE 64/bin/go node (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v3 --jq [.object.sha, .object.type] | @tsv ons-test713143657 -tests /usr/bin/git l 010184299/001' 64/bin/go git -C /tmp/compile-instructions-test-1506387569/.github/workflows rev-parse om/myorg/repo.git -json GO111MODULE 64/bin/go git (http block)
  • https://api.github.com/repos/actions/checkout/git/ref/tags/v5
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq [.object.sha, .object.type] | @tsv ility-kit.md 0520629/b099/vet.cfg .cfg GOSUMDB GOWORK 64/bin/go ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet -o 1389/001/stability-test.md -trimpath ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet -p strings -lang=go1.25 ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq [.object.sha, .object.type] | @tsv --show-toplevel x_amd64/link /usr/bin/git 6095618/b181/_pkgit GO111MODULE 64/pkg/tool/linu--show-toplevel git rev-�� it/ref/tags/v4 Bc/pxJ9LMLW5bpRYmCL8sxl/jOx707g3-buildtags sv 35/001/test-simpgit 0520629/b037/vetrev-parse x_amd64/compile git (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq [.object.sha, .object.type] | @tsv --show-toplevel /opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linuremote2 /usr/bin/git licyBlockedUsersgit /tmp/go-build423rev-parse /opt/hostedtoolc--show-toplevel git rev-�� --show-toplevel /opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/vet /usr/bin/git -bool -buildtags /usr/lib/git-cor--show-toplevel git (http block)
  • https://api.github.com/repos/actions/github-script/git/ref/tags/v8
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq [.object.sha, .object.type] | @tsv --show-toplevel 64/pkg/tool/linux_amd64/compile /usr/bin/git g_.a 0520629/b050/vetcommit .cfg git rev-�� --show-toplevel ache/go/1.25.8/x64/pkg/tool/linuremote.origin.url /usr/bin/git 5636-32468/test-git 0520629/b230/vetrev-parse ache/go/1.25.8/x--show-toplevel git (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq [.object.sha, .object.type] | @tsv --show-toplevel 64/pkg/tool/linux_amd64/compile /usr/bin/git g_.a GO111MODULE ache/go/1.25.8/x-m git rev-�� --show-toplevel go /usr/bin/git dgL_xDIyf GO111MODULE ache/go/1.25.8/x--show-toplevel git (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq [.object.sha, .object.type] | @tsv --show-toplevel 64/pkg/tool/linux_amd64/vet /usr/bin/git -json GO111MODULE At,event,headBra-m git rev-�� --show-toplevel 64/pkg/tool/linux_amd64/vet /usr/bin/git -json GO111MODULE .cfg git (http block)
  • https://api.github.com/repos/actions/github-script/git/ref/tags/v9
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v9 --jq [.object.sha, .object.type] | @tsv -json GO111MODULE x_amd64/compile GOINSECURE GOMOD GOMODCACHE x_amd64/compile env -json GO111MODULE x_amd64/compile GOINSECURE GOMOD GOMODCACHE x_amd64/compile (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v9 --jq [.object.sha, .object.type] | @tsv -json 1.5.0/internal/mcpgodebug/mcpgodebug.go x_amd64/compile GOINSECURE GOMOD GOMODCACHE x_amd64/compile env -json GO111MODULE x_amd64/vet GOINSECURE jsonrpc2 GOMODCACHE x_amd64/vet (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v9 --jq [.object.sha, .object.type] | @tsv -json GO111MODULE x_amd64/compile GOINSECURE GOMOD GOMODCACHE x_amd64/compile abi/�� -json GO111MODULE x_amd64/vet GOINSECURE GOMOD GOMODCACHE x_amd64/vet (http block)
  • https://api.github.com/repos/actions/setup-go/git/ref/tags/v4
    • Triggering command: /usr/bin/gh gh api /repos/actions/setup-go/git/ref/tags/v4 --jq [.object.sha, .object.type] | @tsv remove myorg /usr/bin/git 288208/001 GO111MODULE x_amd64/vet git rev-�� --show-toplevel x_amd64/vet 0520629/b457/vet.cfg -json yZeOx_cnJ 64/pkg/tool/linu--show-toplevel git (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/setup-go/git/ref/tags/v4 --jq [.object.sha, .object.type] | @tsv 2496564/b458/workflow.test go 2496564/b458/importcfg.link b/workflows GO111MODULE 64/bin/go iwImYbf0iDSPO/IkekbXyWHooEiV9moA8t/Acu3xF--2uzjP_kkzeQL/cc4GKggiwImYbf0iDSPO init�� ry=1 go che/go-build/5d/5d1d90f152753455063e873cd613c140e96a3d11fd7d3e088b1b7f6f4e3e1c9e-d -json GO111MODULE x_amd64/link git (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/setup-go/git/ref/tags/v4 --jq [.object.sha, .object.type] | @tsv /tmp/gh-aw-test-runs/20260416-083255-80920/test-2899617859 rev-parse /usr/bin/git @{u} GO111MODULE 64/bin/go git rev-�� --show-toplevel h-aw.wasm; \ AFremote /usr/bin/git th .prettierignogit GO111MODULE 64/bin/go git (http block)
  • https://api.github.com/repos/actions/setup-node/git/ref/tags/v4
    • Triggering command: /usr/bin/gh gh api /repos/actions/setup-node/git/ref/tags/v4 --jq [.object.sha, .object.type] | @tsv 0520629/b458/_pkg_.a x_amd64/vet 0520629/b458=> g_.a X4Ap2OrxA x_amd64/vet git rev-�� r92o/MOnXGBEYub-2Hgbqr92o x_amd64/vet /usr/bin/git l 2>&1; then \ git GO111MODULE tartedAt,updated--show-toplevel git (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/setup-node/git/ref/tags/v4 --jq [.object.sha, .object.type] | @tsv v1.0.0 go /usr/bin/git -json GO111MODULE 64/bin/go git rev-�� --show-toplevel go /usr/bin/git -json GO111MODULE x_amd64/vet git (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/setup-node/git/ref/tags/v4 --jq [.object.sha, .object.type] | @tsv --show-toplevel go /usr/bin/git json' --ignore-pgit GO111MODULE 64/bin/go git rev-�� --git-dir go /usr/bin/git th .prettierignogit GO111MODULE 64/bin/go git (http block)
  • https://api.github.com/repos/actions/upload-artifact/git/ref/tags/v4
    • Triggering command: /usr/bin/gh gh api /repos/actions/upload-artifact/git/ref/tags/v4 --jq [.object.sha, .object.type] | @tsv sistency_GoAndJavaScript1538318835/001/test-simple-frontmatter.m-errorsas -trimpath ache/go/1.25.8/x64/pkg/tool/linux_amd64/compile -p main -lang=go1.25 ache/go/1.25.8/x64/pkg/tool/linux_amd64/compile -c 0520629/b454/_pkg_.a git-upload-pack '/tmp/TestParseDefaultBranchFromLsRemoteWithRealGitbranch_with_hyphen3422843600/rev-parse 0520629/b454=> go1.25.8 b/gh-aw/pkg/typerev-parse -nolocalimports git (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/upload-artifact/git/ref/tags/v4 --jq [.object.sha, .object.type] | @tsv runs/20260416-082119-66098/test-74463298/.github/workflows GO111MODULE /usr/bin/git GOINSECURE GOMOD GOMODCACHE git clon�� /tmp/TestParseDefaultBranchFromLsRemoteWithRealGitmaster_branch2492626239/001 /tmp/TestParseDefaultBranchFromLsRemoteWithRealGitmaster_branch2492626239/002/work /usr/bin/git GOSUMDB GOWORK 64/bin/go git (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/upload-artifact/git/ref/tags/v4 --jq [.object.sha, .object.type] | @tsv extensions.objectformat sh /usr/bin/git npx prettier --wgit git 64/bin/go git init�� --bare --initial-branch=master /usr/bin/git -json GO111MODULE 64/bin/go git (http block)
  • https://api.github.com/repos/github/gh-aw-actions/git/ref/tags/v0.1.2
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw-actions/git/ref/tags/v0.1.2 --jq [.object.sha, .object.type] | @tsv remove other /usr/bin/git ay_c1123812081/0git GO111MODULE x_amd64/vet git rev-�� --show-toplevel x_amd64/vet /usr/bin/infocmp g_.a GO111MODULE 64/pkg/tool/linu--show-toplevel infocmp (http block)
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw-actions/git/ref/tags/v0.1.2 --jq [.object.sha, .object.type] | @tsv /tmp/gh-aw-test-runs/20260416-082119-66098/test-2513483635 rev-parse 2496564/b464/vet.cfg @{u} GO111MODULE 64/bin/go git rev-�� --show-toplevel go /usr/bin/git -json GO111MODULE 64/bin/go git (http block)
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw-actions/git/ref/tags/v0.1.2 --jq [.object.sha, .object.type] | @tsv /tmp/gh-aw-test-runs/20260416-083255-80920/test-2899617859 status /usr/bin/git .github/workflowgit GO111MODULE 8b1b7f6f4e3e1c9e--show-toplevel git rev-�� --show-toplevel go /usr/bin/git y-test.md GO111MODULE 64/bin/go git (http block)
  • https://api.github.com/repos/github/gh-aw-actions/git/ref/tags/v1.0.0
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw-actions/git/ref/tags/v1.0.0 --jq [.object.sha, .object.type] | @tsv sistency_GoAndJavaScript1538318835/001/test-frontmatter-with-nested-objects.md -tests /usr/bin/git -json GO111MODULE x_amd64/compile git rev-�� --show-toplevel x_amd64/compile /usr/bin/git -json GO111MODULE x_amd64/compile git (http block)
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw-actions/git/ref/tags/v1.0.0 --jq [.object.sha, .object.type] | @tsv runs/20260416-082119-66098/test-2164965002/.github/workflows security /usr/bin/git OUTPUT -d 168.63.129.16 git init�� --bare --initial-branch=develop e/git ACCEPT GO111MODULE 64/bin/go e/git (http block)
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw-actions/git/ref/tags/v1.0.0 --jq [.object.sha, .object.type] | @tsv runs/20260416-083255-80920/test-953795916/.github/workflows node /usr/lib/git-core/git-upload-pack prettier --write 64/bin/go git-upload-pack /tmp�� ../../../.pretti-json l /usr/bin/git -json GO111MODULE 64/bin/go git (http block)
  • https://api.github.com/repos/github/gh-aw-actions/git/ref/tags/v1.2.3
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw-actions/git/ref/tags/v1.2.3 --jq [.object.sha, .object.type] | @tsv 0520629/b443/_pkg_.a -tests 0520629/b443=> -json b/gh-aw/pkg/stylrev-parse x_amd64/compile git init�� r-test1079381225/existing.md x_amd64/compile /usr/bin/git -json GO111MODULE x_amd64/compile 0520629/b443/importcfg (http block)
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw-actions/git/ref/tags/v1.2.3 --jq [.object.sha, .object.type] | @tsv runs/20260416-082119-66098/test-2164965002/.github/workflows security /bin/sh OUTPUT -d 168.63.129.16 /bin/sh -c git-upload-pack '/tmp/TestParseDefaultBranchFromLsRemoteWithRealGitmaster_branch2492626239/001' l /usr/bin/git ACCEPT GO111MODULE 64/bin/go git (http block)
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw-actions/git/ref/tags/v1.2.3 --jq [.object.sha, .object.type] | @tsv actions/setup-cli/install.sh node /usr/bin/git prettier --write 64/bin/go git ls-r�� --symref origin om/testowner/testrepo.git -json GO111MODULE 64/bin/go git (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/1/artifacts
    • Triggering command: /usr/bin/gh gh api --paginate repos/{owner}/{repo}/actions/runs/1/artifacts --jq .artifacts[].name GO111MODULE 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/vet env 3731900851 cQ7c/qW3Yktv_0Qvh00yucQ7c .cfg GOINSECURE g/x/net/http2/hprev-parse GOMODCACHE ache/go/1.25.8/x64/pkg/tool/linu-trimpath (http block)
    • Triggering command: /usr/bin/gh gh run download 1 --dir test-logs/run-1 .cfg 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD 6095618/b013/symuser.name 64/pkg/tool/linuTest User env 6095618/b254/_pkg_.a 7Ps3/Xuna8G_bMUX3GMM57Ps3 ache/go/1.25.8/x64/pkg/tool/linu-lang=go1.25 GOINSECURE GOMOD GOMODCACHE ache/go/1.25.8/x64/pkg/tool/linu-goversion (http block)
    • Triggering command: /usr/bin/gh gh api --paginate repos/{owner}/{repo}/actions/runs/1/artifacts --jq .artifacts[].name LsRemoteWithRealGitbranch_with_hyphen397646581/001' tions/setup/node_modules/.bin/sh GOINSECURE GOMOD GOMODCACHE go env ut4194082363/001 GO111MODULE ache/go/1.25.8/x64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/12345/artifacts
    • Triggering command: /usr/bin/gh gh api --paginate repos/{owner}/{repo}/actions/runs/12345/artifacts --jq .artifacts[].name .cfg 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/vet env 6095618/b202/_pkg_.a GO111MODULE ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD 6095618/b078/sym--get ache/go/1.25.8/xremote.origin.url (http block)
    • Triggering command: /usr/bin/gh gh run download 12345 --dir test-logs/run-12345 .cfg 64/pkg/tool/linux_amd64/vet GOINSECURE (http block)
    • Triggering command: /usr/bin/gh gh api --paginate repos/{owner}/{repo}/actions/runs/12345/artifacts --jq .artifacts[].name GO111MODULE ache/go/1.25.8/x64/bin/go GOINSECURE GOMOD GOMODCACHE go 1/x6�� y_with_explicit_repo3960452412/001 GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/12346/artifacts
    • Triggering command: /usr/bin/gh gh api --paginate repos/{owner}/{repo}/actions/runs/12346/artifacts --jq .artifacts[].name .cfg 64/pkg/tool/linux_amd64/vet GOINSECURE 6095618/b006/ GOMODCACHE 64/pkg/tool/linux_amd64/vet env 6095618/b200/_pkg_.a GO111MODULE ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet GOINSECURE 6095618/b006/asmconfig ache/go/1.25.8/x--get ache/go/1.25.8/xremote.origin.url (http block)
    • Triggering command: /usr/bin/gh gh run download 12346 --dir test-logs/run-12346 GO111MODULE 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/vet env 1993194114 go .cfg GOINSECURE GOMOD GOMODCACHE ache/go/1.25.8/x64/pkg/tool/linu-test.v=true (http block)
    • Triggering command: /usr/bin/gh gh api --paginate repos/{owner}/{repo}/actions/runs/12346/artifacts --jq .artifacts[].name GO111MODULE ache/go/1.25.8/x64/bin/go GOINSECURE GOMOD GOMODCACHE go 1/x6�� -json GO111MODULE ache/go/1.25.8/x64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/2/artifacts
    • Triggering command: /usr/bin/gh gh api --paginate repos/{owner}/{repo}/actions/runs/2/artifacts --jq .artifacts[].name GO111MODULE 64/pkg/tool/linux_amd64/vet GOINSECURE fips140 GOMODCACHE 64/pkg/tool/linutest@example.com env 3731900851 i2Jk/kxQktkbJrdZm0O72i2Jk 64/pkg/tool/linux_amd64/link GOINSECURE able GOMODCACHE 64/pkg/tool/linux_amd64/link (http block)
    • Triggering command: /usr/bin/gh gh run download 2 --dir test-logs/run-2 rg/x/text@v0.36.0/internal/tag/tag.go 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/vet env 6095618/b241/_pkg_.a V7o_/18xeupG6XnJInX8DV7o_ .cfg GOINSECURE t/internal/langurev-parse GOMODCACHE ache/go/1.25.8/x64/pkg/tool/linu-tests (http block)
    • Triggering command: /usr/bin/gh gh api --paginate repos/{owner}/{repo}/actions/runs/2/artifacts --jq .artifacts[].name GO111MODULE tions/node_modules/.bin/sh GOINSECURE GOMOD GOMODCACHE go env ut4194082363/001 GO111MODULE ache/go/1.25.8/x64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/3/artifacts
    • Triggering command: /usr/bin/gh gh api --paginate repos/{owner}/{repo}/actions/runs/3/artifacts --jq .artifacts[].name GO111MODULE 64/pkg/tool/linux_amd64/vet GOINSECURE fips140/sha3 GOMODCACHE 64/pkg/tool/linux_amd64/vet env 6095618/b223/_pkg_.a Ldjv/q8rDzC5dO2KyVIFwLdjv .cfg GOINSECURE GOMOD GOMODCACHE ache/go/1.25.8/x64/pkg/tool/linu-extld=gcc (http block)
    • Triggering command: /usr/bin/gh gh run download 3 --dir test-logs/run-3 rg/x/text@v0.36.0/internal/stringset/set.go 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD 6095618/b007/symabis 64/pkg/tool/linux_amd64/vet env 1618337691 6095618/b007/importcfg .cfg GOINSECURE /semver GOMODCACHE ache/go/1.25.8/x64/pkg/tool/linu-goversion (http block)
    • Triggering command: /usr/bin/gh gh api --paginate repos/{owner}/{repo}/actions/runs/3/artifacts --jq .artifacts[].name GO111MODULE de_modules/.bin/sh GOINSECURE GOMOD GOMODCACHE go env 2976/001/stability-test.md GO111MODULE 64/bin/bash GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/4/artifacts
    • Triggering command: /usr/bin/gh gh api --paginate repos/{owner}/{repo}/actions/runs/4/artifacts --jq .artifacts[].name GO111MODULE 64/pkg/tool/linu-nolocalimports GOINSECURE fips140/sha256 GOMODCACHE 64/pkg/tool/linu/tmp/go-build4230520629/b450/_testmain.go env 6095618/b226/_pkg_.a t2Bi/LbyKJAzlPTfrrG8ct2Bi .cfg GOINSECURE l GOMODCACHE ache/go/1.25.8/x64/pkg/tool/linu-importcfg (http block)
    • Triggering command: /usr/bin/gh gh run download 4 --dir test-logs/run-4 .cfg 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD 6095618/b013/sym--show-toplevel 64/pkg/tool/linux_amd64/vet env 1618337691/.github/workflows GO111MODULE 64/pkg/tool/linux_amd64/vet GOINSECURE g/x/net/http/httrev-parse GOMODCACHE 64/pkg/tool/linux_amd64/vet (http block)
    • Triggering command: /usr/bin/gh gh api --paginate repos/{owner}/{repo}/actions/runs/4/artifacts --jq .artifacts[].name GO111MODULE ules/.bin/sh GOINSECURE GOMOD GOMODCACHE go env */*.ts' '**/*.json' --ignore-path ../../../.prettierignore GO111MODULE 1/x64/bin/bash GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/5/artifacts
    • Triggering command: /usr/bin/gh gh api --paginate repos/{owner}/{repo}/actions/runs/5/artifacts --jq .artifacts[].name GO111MODULE 64/pkg/tool/linu-importcfg GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linuTest User env 3731900851 3cxW/IBlaqeSprCJhOYFQ3cxW 64/pkg/tool/linux_amd64/compile GOINSECURE g/x/text/secure/rev-parse GOMODCACHE 64/pkg/tool/linux_amd64/compile (http block)
    • Triggering command: /usr/bin/gh gh run download 5 --dir test-logs/run-5 .cfg 64/pkg/tool/linux_amd64/vet GOINSECURE hlite GOMODCACHE 64/pkg/tool/linux_amd64/vet env 1618337691/.github/workflows _zAe/m6K4S-499xrKjIdi_zAe ache/go/1.25.8/x64/pkg/tool/linu-test.short=true GOINSECURE g/x/net/http/httinit GOMODCACHE ache/go/1.25.8/x64/pkg/tool/linu/tmp/file-tracker-test4097742932/test2.lock.yml (http block)
    • Triggering command: /usr/bin/gh gh api --paginate repos/{owner}/{repo}/actions/runs/5/artifacts --jq .artifacts[].name GO111MODULE bin/sh GOINSECURE GOMOD GOMODCACHE go env mpiledOutput3736360712/001 GO111MODULE de/node/bin/bash GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/github/gh-aw/actions/workflows
    • Triggering command: /usr/bin/gh gh workflow list --json name,state,path -json GO111MODULE x_amd64/compile GOINSECURE GOMOD GOMODCACHE x_amd64/compile env -json 1.5.0/jsonrpc/jsonrpc.go x_amd64/compile GOINSECURE GOMOD GOMODCACHE x_amd64/compile (http block)
    • Triggering command: /usr/bin/gh gh run list --json databaseId,number,url,status,conclusion,workflowName,createdAt,startedAt,updatedAt,event,headBranch,headSha,displayTitle --workflow nonexistent-workflow-12345 --limit 100 GOMOD GOMODCACHE x_amd64/vet env -json .go x_amd64/vet GOINSECURE GOMOD GOMODCACHE x_amd64/vet (http block)
    • Triggering command: /usr/bin/gh gh run list --json databaseId,number,url,status,conclusion,workflowName,createdAt,startedAt,updatedAt,event,headBranch,headSha,displayTitle --workflow nonexistent-workflow-12345 --limit 6 6095618/b011/ GOMODCACHE 64/pkg/tool/linux_amd64/vet env 6095618/b176/_pkg_.a GO111MODULE x_amd64/link GOINSECURE fips140/nistec/frev-parse ache/go/1.25.8/x--show-toplevel x_amd64/link (http block)
  • https://api.github.com/repos/github/gh-aw/git/ref/tags/v0.47.4
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v0.47.4 --jq [.object.sha, .object.type] | @tsv --show-toplevel -extld=gcc /usr/bin/git gh-aw.wasm ($(dugit GO111MODULE ache/go/1.25.8/x--show-toplevel git rev-�� --show-toplevel ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet /usr/bin/git /tmp/go-build285ls pkg/mod/github.c-lh .cfg git (http block)
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v0.47.4 --jq [.object.sha, .object.type] | @tsv --show-toplevel go /usr/bin/git -json GO111MODULE ache/go/1.25.8/x--show-toplevel git rev-�� --show-toplevel go /usr/bin/git -json GO111MODULE ache/go/1.25.8/x/tmp/gh-aw/aw-feature-branch.patch git (http block)
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v0.47.4 --jq [.object.sha, .object.type] | @tsv --show-toplevel go /usr/bin/infocmp ithub/workflows GO111MODULE ache/go/1.25.8/x--show-toplevel infocmp -1 xterm-color go /usr/bin/git agentic-observabls GO111MODULE ache/node/24.14./tmp/gh-aw/aw-feature-branch.patch git (http block)
  • https://api.github.com/repos/github/gh-aw/git/ref/tags/v1.0.0
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v1.0.0 --jq [.object.sha, .object.type] | @tsv 6095618/b138/_pkg_.a .cfg 64/pkg/tool/linux_amd64/compile GOINSECURE e/jsonschema-go/init GOMODCACHE 64/pkg/tool/linux_amd64/compile (http block)
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v1.0.0 --jq [.object.sha, .object.type] | @tsv 3803463147/.github/workflows GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env 656697602 GO111MODULE ache/go/1.25.8/x64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v1.0.0 --jq [.object.sha, .object.type] | @tsv -json GO111MODULE de_modules/.bin/sh GOINSECURE GOMOD GOMODCACHE go env */*.ts' '**/*.json' --ignore-path ../../../.prettierignore GO111MODULE 64/pkg/tool/linux_amd64/compile GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/compile (http block)
  • https://api.github.com/repos/github/gh-aw/git/ref/tags/v1.2.3
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v1.2.3 --jq [.object.sha, .object.type] | @tsv -json GO111MODULE x_amd64/vet GOINSECURE GOMOD GOMODCACHE x_amd64/vet env /a.out GO111MODULE x_amd64/vet GOINSECURE 6wH48CcCan7n99te-C GOMODCACHE x_amd64/vet (http block)
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v1.2.3 --jq [.object.sha, .object.type] | @tsv re GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v1.2.3 --jq [.object.sha, .object.type] | @tsv run lint:cjs 64/bin/go GOSUMDB GOWORK 64/bin/go sh 9070�� "prettier" --check 'scripts/**/*GOINSECURE node 64/bin/go --write scripts/**/*.js 64/bin/go go (http block)
  • https://api.github.com/repos/github/gh-aw/git/ref/tags/v2.0.0
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v2.0.0 --jq [.object.sha, .object.type] | @tsv -json GO111MODULE x_amd64/compile GOINSECURE GOMOD GOMODCACHE x_amd64/compile 5828�� -json 17139bf8cde608df4 x_amd64/vet GOINSECURE GOMOD GOMODCACHE x_amd64/vet (http block)
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v2.0.0 --jq [.object.sha, .object.type] | @tsv -json GO111MODULE x_amd64/vet GOINSECURE GOMOD GOMODCACHE x_amd64/vet env g_.a poll/fd.go x_amd64/vet GOINSECURE GOMOD GOMODCACHE x_amd64/vet (http block)
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v2.0.0 --jq [.object.sha, .object.type] | @tsv -json GO111MODULE x_amd64/vet GOINSECURE GOMOD GOMODCACHE x_amd64/vet env g_.a GO111MODULE x_amd64/vet GOINSECURE GOMOD GOMODCACHE x_amd64/vet (http block)
  • https://api.github.com/repos/github/gh-aw/git/ref/tags/v3.0.0
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v3.0.0 --jq [.object.sha, .object.type] | @tsv -json GO111MODULE x_amd64/vet GOINSECURE GOMOD GOMODCACHE x_amd64/vet env -json GO111MODULE x_amd64/vet sm); \ wasm-optgit GOMOD GOMODCACHE x_amd64/vet (http block)
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v3.0.0 --jq [.object.sha, .object.type] | @tsv re GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go 5855�� -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v3.0.0 --jq [.object.sha, .object.type] | @tsv npx prettier --cGOSUMDB GOPROXY 64/bin/go GOSUMDB GOWORK 64/bin/go sh -c Gitmain_branch2839070236/001' Gitmain_branch2839070236/001' 64/bin/go --write scripts/**/*.js 64/bin/go go (http block)
  • https://api.github.com/repos/nonexistent/action/git/ref/tags/v999.999.999
    • Triggering command: /usr/bin/gh gh api /repos/nonexistent/action/git/ref/tags/v999.999.999 --jq [.object.sha, .object.type] | @tsv 6095618/b156/_pkg_.a 38wk/F3_s36TZU8RlNGu_38wk 64/pkg/tool/linux_amd64/link GOINSECURE contextprotocol/config GOMODCACHE 64/pkg/tool/linutest@example.com (http block)
    • Triggering command: /usr/bin/gh gh api /repos/nonexistent/action/git/ref/tags/v999.999.999 --jq [.object.sha, .object.type] | @tsv -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE ache/go/1.25.8/x64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
    • Triggering command: /usr/bin/gh gh api /repos/nonexistent/action/git/ref/tags/v999.999.999 --jq [.object.sha, .object.type] | @tsv -json GO111MODULE ache/go/1.25.8/x64/bin/go GOINSECURE GOMOD GOMODCACHE go env y_only_defaults_repo1512666037/001 GO111MODULE ache/go/1.25.8/x64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/nonexistent/repo/actions/runs/12345
    • Triggering command: /usr/bin/gh gh run view 12345 --repo nonexistent/repo --json status,conclusion GOINSECURE ntio/asm/cpu/armrev-parse GOMODCACHE 64/pkg/tool/linux_amd64/vet env 6095618/b161/_pkg_.a GO111MODULE 64/pkg/tool/linux_amd64/vet GOINSECURE th2 GOMODCACHE 64/pkg/tool/linux_amd64/vet (http block)
    • Triggering command: /usr/bin/gh gh run view 12345 --repo nonexistent/repo --json status,conclusion GOINSECURE GOMOD GOMODCACHE go tion�� -json GO111MODULE ache/go/1.25.8/x64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
    • Triggering command: /usr/bin/gh gh run view 12345 --repo nonexistent/repo --json status,conclusion GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE ache/go/1.25.8/x64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/owner/repo/actions/workflows
    • Triggering command: /usr/bin/gh gh workflow list --json name,state,path --repo owner/repo x_amd64/compile GOINSECURE GOMOD GOMODCACHE x_amd64/compile env -json GO111MODULE x_amd64/compile GOINSECURE GOMOD GOMODCACHE x_amd64/compile (http block)
    • Triggering command: /usr/bin/gh gh workflow list --json name,state,path --repo owner/repo x_amd64/compile GOINSECURE GOMOD GOMODCACHE x_amd64/compile env -json gset/set.go x_amd64/compile GOINSECURE GOMOD GOMODCACHE x_amd64/compile (http block)
    • Triggering command: /usr/bin/gh gh workflow list --json name,state,path --repo owner/repo 64/bin/go GOINSECURE GOMOD GOMODCACHE go env ath ../../../.pr**/*.json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/owner/repo/contents/file.md
    • Triggering command: /tmp/go-build4230520629/b400/cli.test /tmp/go-build4230520629/b400/cli.test -test.testlogfile=/tmp/go-build4230520629/b400/testlog.txt -test.paniconexit0 -test.v=true -test.parallel=4 -test.timeout=10m0s -test.run=^Test -test.short=true GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE x_amd64/compile GOINSECURE GOMOD GOMODCACHE x_amd64/compile (http block)
    • Triggering command: /tmp/go-build3881978530/b400/cli.test /tmp/go-build3881978530/b400/cli.test -test.testlogfile=/tmp/go-build3881978530/b400/testlog.txt -test.paniconexit0 -test.v=true -test.parallel=4 -test.timeout=10m0s -test.run=^Test -test.short=true --show-toplevel /opt/hostedtoolcenv /usr/bin/git go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
    • Triggering command: /tmp/go-build3972496564/b400/cli.test /tmp/go-build3972496564/b400/cli.test -test.testlogfile=/tmp/go-build3972496564/b400/testlog.txt -test.paniconexit0 -test.v=true -test.parallel=4 -test.timeout=10m0s -test.run=^Test -test.short=true GOINSECURE GOMOD ode-gyp-bin/node-json go env ck 'scripts/**/*GOINSECURE GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/test-owner/test-repo/actions/secrets
    • Triggering command: /usr/bin/gh gh api /repos/test-owner/test-repo/actions/secrets --jq .secrets[].name -json 4 x_amd64/compile GOINSECURE GOMOD GOMODCACHE x_amd64/compile env -json GO111MODULE x_amd64/compile GOINSECURE GOMOD GOMODCACHE x_amd64/compile (http block)
    • Triggering command: /usr/bin/gh gh api /repos/test-owner/test-repo/actions/secrets --jq .secrets[].name -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
    • Triggering command: /usr/bin/gh gh api /repos/test-owner/test-repo/actions/secrets --jq .secrets[].name -json GO111MODULE 64/bin/go GOINSECURE GOMOD erignore go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot AI and others added 3 commits April 16, 2026 07:52
This reverts commit 43c272b.

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Split template_injection_validation.go by responsibility Split template injection validator by responsibility Apr 16, 2026
Copilot AI requested a review from pelikhan April 16, 2026 08:42
@pelikhan pelikhan marked this pull request as ready for review April 16, 2026 13:47
Copilot AI review requested due to automatic review settings April 16, 2026 13:47
@pelikhan pelikhan merged commit 411beb2 into main Apr 16, 2026
52 checks passed
@pelikhan pelikhan deleted the copilot/split-template-injection-validation branch April 16, 2026 13:47
@github-actions github-actions Bot mentioned this pull request Apr 16, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Refactors the template-injection validator by splitting traversal/detection orchestration from helper utilities, keeping behavior and error formatting consistent while reducing file size.

Changes:

  • Trimmed template_injection_validation.go down to the three validator entry points and core orchestration logic.
  • Moved helper types/functions (run block extraction, heredoc stripping, snippet/context detection, error formatting) into new template_injection_utils.go.
Show a summary per file
File Description
pkg/workflow/template_injection_validation.go Keeps only the validation entry points and core scanning loop; removes helper implementations and the unused fmt import.
pkg/workflow/template_injection_utils.go Introduces a new utils file containing extracted helper functions/types used by the validator.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 2/2 changed files
  • Comments generated: 2

Comment on lines +122 to +143
// Group violations by context for clearer reporting
contextGroups := make(map[string][]TemplateInjectionViolation)
for _, v := range violations {
contextGroups[v.Context] = append(contextGroups[v.Context], v)
}

// Report violations grouped by context
for context, contextViolations := range contextGroups {
fmt.Fprintf(&builder, " %s context (%d occurrence(s)):\n", context, len(contextViolations))

// Show up to 3 examples per context to keep error message manageable
maxExamples := 3
for i, v := range contextViolations {
if i >= maxExamples {
fmt.Fprintf(&builder, " ... and %d more\n", len(contextViolations)-maxExamples)
break
}
fmt.Fprintf(&builder, " - %s\n", v.Expression)
fmt.Fprintf(&builder, " in: %s\n", v.Snippet)
}
builder.WriteString("\n")
}
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

formatTemplateInjectionError groups violations in a map[string][]... and then iterates the map, which yields nondeterministic context ordering in the resulting error message. This can make output harder to diff/compare across runs. Consider sorting the context keys (and optionally each group) before writing to the builder for stable, predictable formatting.

Copilot uses AI. Check for mistakes.
Comment on lines +73 to +78
// TemplateInjectionViolation represents a detected template injection risk
type TemplateInjectionViolation struct {
Expression string // The unsafe expression (e.g., "${{ github.event.issue.title }}")
Snippet string // Code snippet showing the violation context
Context string // Expression context (e.g., "github.event", "steps.*.outputs")
}
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TemplateInjectionViolation is exported (capitalized) but appears to be used only internally within the workflow package. If it is not intended to be part of the package’s public API, consider unexporting it (e.g., templateInjectionViolation) to reduce exposed surface area.

Copilot uses AI. Check for mistakes.
@github-actions
Copy link
Copy Markdown
Contributor

🏗️ Design Decision Gate — ADR Required

This PR makes significant changes to core business logic (166 new lines in pkg/workflow/) but does not have a linked Architecture Decision Record (ADR).

Note: This gate ran after the PR was already merged, so the branch is no longer available. The draft ADR below should be committed directly to main in a follow-up.

AI has analyzed the PR diff and generated a draft ADR to help get started:

📄 Draft ADR: docs/adr/26580-split-template-injection-validator-by-responsibility.md

View generated draft ADR
# ADR-26580: Split Template Injection Validator by Responsibility

**Date**: 2026-04-16
**Status**: Draft
**Deciders**: pelikhan, Copilot

---

## Part 1 — Narrative (Human-Friendly)

### Context

The `pkg/workflow/template_injection_validation.go` file had grown past the project's validator file size guideline following ADR-26385, which added the `hasUnsafeExpressionInRunContent` fast pre-flight scanner (~80 lines of custom parsing logic). The file mixed two distinct concerns: orchestration entry points that drive the detection flow, and helper utilities (YAML tree traversal, heredoc removal, snippet extraction, error formatting, supporting types) that back those entry points. The project applies a file size guideline to keep individual Go source files focused, navigable, and easy to review.

### Decision

We will split `template_injection_validation.go` into two files that remain in the same `workflow` package. The original file retains the three validation entry points — `hasUnsafeExpressionInRunContent`, `validateNoTemplateInjection`, and `validateNoTemplateInjectionFromParsed` — along with the shared compiled-regex variables, keeping it under the file size threshold. A new `template_injection_utils.go` file receives the supporting types and helper functions: `TemplateInjectionViolation`, `heredocPatterns`, `extractRunBlocks`, `removeHeredocContent`, `extractRunSnippet`, `detectExpressionContext`, and `formatTemplateInjectionError`. No behavioral changes are made; the split is purely structural within the existing package boundary.

### Alternatives Considered

#### Alternative 1: Keep everything in one file

Retaining the single-file layout is the simplest option and avoids any cognitive overhead of locating related code across files. However, the file had already exceeded the project size guideline and mixed orchestration logic with utility/formatting concerns, making it harder to navigate and review. Rejected because the maintenance cost of a growing, mixed-concern file outweighs the simplicity of a single file.

#### Alternative 2: Extract helpers into a separate sub-package

Moving the utilities to a dedicated sub-package (e.g., `pkg/workflow/internal/tiutil`) would create a hard encapsulation boundary. However, both the entry points and the helpers are consumed exclusively within the `workflow` package; exporting all shared types across the package boundary would add boilerplate for no practical benefit. Rejected because intra-package separation achieves the readability goal with far less ceremony.

#### Alternative 3: Inline helpers at their only call site

Eliminating the named helper functions and inlining their bodies at the single point of use would reduce file count. However, helpers such as `removeHeredocContent` and `formatTemplateInjectionError` are substantial enough that inlining would produce hard-to-read validation functions. Rejected because it trades a small structural concern for a larger readability regression.

### Consequences

#### Positive
- `template_injection_validation.go` is brought below the validator file size guideline (224 lines post-split).
- Each file has a single, clearly stated responsibility: orchestration/detection entry points vs. utility types and helper functions.
- Future contributors can find the core validation logic without scrolling through supporting utility code.

#### Negative
- The relationship between the two files is implicit; a reader encountering an unfamiliar helper call must know to look in `template_injection_utils.go`.
- When the detection strategy changes substantially, both files may need coordinated updates.

#### Neutral
- No API surface changes; both files remain in the `workflow` package.
- Existing tests continue to target the same function boundaries without modification.

What to do next

  1. Review the draft ADR — the content above was generated from the PR diff
  2. Complete any missing context — refine the decision rationale and alternatives if needed
  3. Commit the finalized ADR to docs/adr/26580-split-template-injection-validator-by-responsibility.md on main
  4. Update PR body or commit message to reference the ADR for future traceability

Why ADRs Matter

"AI made me procrastinate on key design decisions. Because refactoring was cheap, I could always say 'I'll deal with this later.' Deferring decisions corroded my ability to think clearly."

ADRs create a searchable, permanent record of why the codebase looks the way it does. Even structural/refactoring decisions like this one answer future questions about why template_injection_utils.go exists alongside template_injection_validation.go.


📋 Michael Nygard ADR Format Reference

An ADR must contain these four sections to be considered complete:

  • Context — What is the problem? What forces are at play?
  • Decision — What did you decide? Why?
  • Alternatives Considered — What else could have been done?
  • Consequences — What are the trade-offs (positive and negative)?

All ADRs are stored in docs/adr/ as Markdown files numbered by PR number (e.g., 26580-split-template-injection-validator-by-responsibility.md for PR #26580).

References: §24513892046

Note

🔒 Integrity filter blocked 1 item

The following item were blocked because they don't meet the GitHub integrity level.

To allow these resources, lower min-integrity in your GitHub frontmatter:

tools:
  github:
    min-integrity: approved  # merged | approved | unapproved | none

🏗️ ADR gate enforced by Design Decision Gate 🏗️ · ● 212.3K ·

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[plan] Split template_injection_validation.go by responsibility

3 participants