Skip to content

feat: safe update mode enforcement for secrets and actions (#safe-update)#24968

Open
Copilot wants to merge 13 commits intomainfrom
copilot/update-compiler-safe-update-mode
Open

feat: safe update mode enforcement for secrets and actions (#safe-update)#24968
Copilot wants to merge 13 commits intomainfrom
copilot/update-compiler-safe-update-mode

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 6, 2026

Summary

Introduces safe update mode in the compiler to prevent unauthorized addition of secret consumption and unapproved action changes in workflows. When enabled, the compiler compares previously recorded secrets and actions (from a gh-aw-manifest header in the lock file) against newly detected ones and rejects unsafe changes.

Changes

New files

  • pkg/workflow/safe_update_manifest.goGHAWManifest struct (version, secrets, actions) with JSON parse/serialize/extract helpers
  • pkg/workflow/safe_update_enforcement.goEnforceSafeUpdate function implementing the diff-based secret and action policy
  • pkg/workflow/safe_update_manifest_test.go — Tests for manifest parsing, serialization, normalization
  • pkg/workflow/safe_update_enforcement_test.go — Tests for enforcement logic, action violation detection, and effectiveSafeUpdate

Modified files

  • pkg/constants/feature_constants.go — Added SafeUpdateFeatureFlag = "safe-update" constant
  • pkg/gitutil/gitutil.go — Added ReadFileFromHEAD(filePath string) to read a file's content from the last git commit (git show HEAD:<relpath>) rather than the working tree
  • pkg/workflow/compiler_types.go — Added safeUpdate bool field, WithSafeUpdate option, SetSafeUpdate method
  • pkg/workflow/compiler_yaml.go — Updated effectiveSafeUpdate to check CLI flag and feature flag; embed # gh-aw-manifest: {...} in lock file header; generateYAML now returns collected body secrets and action refs (eliminates duplicate scan)
  • pkg/workflow/compiler.go — Reads lock file manifest before recompilation (from git HEAD in dev mode, from filesystem in release/action modes); calls EnforceSafeUpdate after YAML generation; updated generateAndValidateYAML to propagate body secrets and action refs
  • pkg/workflow/compiler_string_api.go — Updated to handle new generateAndValidateYAML return signature
  • pkg/cli/compile_config.go — Added SafeUpdate bool field
  • pkg/cli/compile_compiler_setup.go — Pass SafeUpdate from config to compiler
  • cmd/gh-aw/main.go — Added --safe-update flag; wire to CompileConfig

Behavior

Safe update mode can be enabled via the --safe-update CLI flag, the GH_AW_FEATURES=safe-update environment variable, or the workflow frontmatter features: safe-update: true section.

Scenario Behavior
First compile (no lock file committed) Treated as empty manifest; all non-GITHUB_TOKEN secrets and non-actions/* actions rejected
Default (no --safe-update flag or feature flag) No enforcement; any secrets or actions allowed
--safe-update CLI flag or features: safe-update: true Enforce; reject new non-GITHUB_TOKEN secrets and unapproved action changes
secrets.GITHUB_TOKEN Always allowed regardless of manifest
actions/* actions (GitHub Actions org) Always allowed — never flagged as added or removed
Previously-recorded secret Allowed
New restricted secret Compilation rejected with actionable error
New unapproved action (non-actions/* repo not in manifest) Compilation rejected with actionable error
Previously-approved non-actions/* action removed Compilation rejected with actionable error
SHA/version change on approved action repo Allowed (pin updates don't require re-approval)

Tamper Prevention

The manifest baseline source depends on the compiler's action mode:

  • Dev mode (local development): the lock file is read from the last git commit (git show HEAD:<lockfile>) rather than the working tree. This prevents a local agent from modifying the .lock.yml on disk before invoking the compiler to forge an approved manifest and bypass enforcement. If the lock file has never been committed, enforcement proceeds with an empty manifest (principle of least privilege).
  • Release/action mode (GitHub Actions runner): the lock file is read from the filesystem. The working tree in a GitHub Actions runner is already a trusted checkout, so filesystem access is sufficient and avoids any dependency on git availability in the runner environment.

Manifest format

# gh-aw-manifest: {"version":1,"secrets":["secrets.GITHUB_TOKEN","secrets.MY_SECRET"],"actions":[{"repo":"my-org/my-action","sha":"abc123","version":"v1"}]}

The manifest line is embedded immediately after # gh-aw-metadata: in generated lock files and updated on every successful compilation.

Error output

When violations are detected, the error clearly labels each category:

safe update mode rejected compilation: unapproved changes were introduced

New restricted secret(s):
  - secrets.MY_SECRET

New unapproved action(s):
  - evil-org/steal-secrets

Previously-approved action(s) removed:
  - my-org/setup-tool

Remediation options:
  1. Use an interactive agentic flow (e.g. Copilot CLI) to review and approve the changes.
  2. Remove the --safe-update flag to allow the change.
  3. Revert the unapproved changes from your workflow if they were added unintentionally.

Copilot AI and others added 3 commits April 6, 2026 22:07
- Add GHAW manifest (version, secrets, actions) to lock file header
- Parse manifest from existing lock files before recompilation
- Enforce safe update mode: reject new restricted secrets vs manifest
- Allow secrets.GITHUB_TOKEN always; all others must be in manifest
- Add safeUpdate field to Compiler struct with CLI override semantics
- Add safe-update frontmatter field to FrontmatterConfig
- Add --safe-update flag to compile command
- Add SafeUpdate field to CompileConfig
- Integrate enforcement into CompileWorkflowData flow
- Add tests for manifest parsing, enforcement, effectiveSafeUpdate"

Agent-Logs-Url: https://github.com/github/gh-aw/sessions/9c7b0f2f-b244-44b5-9b0b-d9a9009a9d89

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
- Change generateYAML and generateAndValidateYAML to return collected body
  secrets alongside YAML content, eliminating duplicate CollectSecretReferences scan
- Update all call sites in test files to use new 3-return-value signature
- Fix typo: 'Normalise' -> 'Normalize' in comment
- Body secrets improve enforcement accuracy (only workflow body, not header JSON)"

Agent-Logs-Url: https://github.com/github/gh-aw/sessions/9c7b0f2f-b244-44b5-9b0b-d9a9009a9d89

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
- Improve GHAW manifest serialization failure log message with impact context
- Improve GHAW manifest parse failure log message with behavior description
- Simplify buildSafeUpdateError using fmt.Errorf with Join instead of strings.Builder"

Agent-Logs-Url: https://github.com/github/gh-aw/sessions/9c7b0f2f-b244-44b5-9b0b-d9a9009a9d89

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copy link
Copy Markdown
Collaborator

@pelikhan pelikhan left a comment

Choose a reason for hiding this comment

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

@copilot the compiler is safe update mode should not allow to set the safe update field to true.

var safeUpdateManifestLog = logger.New("workflow:safe_update_manifest")

// ghawManifestPattern matches a "# GHAW manifest: {...}" line in a lock file header.
var ghawManifestPattern = regexp.MustCompile(`#\s*GHAW manifest:\s*(\{.+\})`)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@copilot use gh-aw-manifest: instead of GHAW

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done in commit 0f5648f. Renamed all occurrences from # GHAW manifest: to # gh-aw-manifest:, including the regex pattern, log messages, and error strings.

- Rename '# GHAW manifest:' header to '# gh-aw-manifest:' per review
- Remove SafeUpdate *bool from FrontmatterConfig; safe update can only be
  enabled via CLI --safe-update flag (not frontmatter)
- Simplify effectiveSafeUpdate to only check compiler CLI flag
- Update remediation error message to remove frontmatter reference
- Update tests for effectiveSafeUpdate and manifest extraction"

Agent-Logs-Url: https://github.com/github/gh-aw/sessions/ef674059-8bd8-421d-8740-2382d729353c

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 7, 2026

@copilot the compiler is safe update mode should not allow to set the safe update field to true.

Done in commit 0f5648f. Removed SafeUpdate *bool from FrontmatterConfig and simplified effectiveSafeUpdate to only check the CLI flag (c.safeUpdate). Safe update mode can now only be enabled via --safe-update on the CLI — frontmatter cannot enable it.

@pelikhan
Copy link
Copy Markdown
Collaborator

pelikhan commented Apr 7, 2026

@copilot adding or remove custom actions that are not approved is also tagged as an error in safe-update mode

@pelikhan
Copy link
Copy Markdown
Collaborator

pelikhan commented Apr 7, 2026

@copilot if there is no prior manifest, and no prior lock file, dissallow any secrets usage.

Copilot AI and others added 2 commits April 7, 2026 01:41
- EnforceSafeUpdate now accepts actionRefs []string in addition to secretNames
- New collectActionViolations function detects added/removed action repos
  (uses repo as key; SHA/version changes to approved repos are permitted)
- buildSafeUpdateError extended to report secret, added-action and removed-action
  violations in separate clearly-labelled sections
- generateYAML now returns (yaml, secrets, actions, error) to propagate action
  refs without a second scan
- generateAndValidateYAML updated to match; compiler_string_api.go updated
- All test call sites updated; new test cases added for action enforcement"

Agent-Logs-Url: https://github.com/github/gh-aw/sessions/d8dde9af-177a-43c4-9ad8-bb638163c532

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 7, 2026

@copilot adding or remove custom actions that are not approved is also tagged as an error in safe-update mode

Done in commit 9b72aff. Safe-update mode now also enforces action changes:

  • New unapproved action (repo not in the previous manifest) → compilation rejected
  • Previously-approved action removed (repo in the previous manifest but gone from the new compilation) → compilation rejected
  • SHA/version change on an already-approved repo → allowed (version pin updates don't require re-approval)

The error message clearly labels each category:

safe update mode rejected compilation: unapproved changes were introduced

New unapproved action(s):
  - evil-org/steal-secrets

Previously-approved action(s) removed:
  - actions/setup-node

Remediation options:
  1. Use an interactive agentic flow (e.g. Copilot CLI) to review and approve the changes.
  ...

Action refs are now returned alongside secrets from generateYAML (no extra scan needed).

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 GO111MODULE 64/bin/go git rev-�� --show-toplevel 2343503/b400/impGOPROXY /usr/bin/git che/go-build/b7/git GOPROXY 64/bin/go git (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 -json GO111MODULE /opt/hostedtoolcache/go/1.25.8/x64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE /snap/bin/bash GOINSECURE GOMOD GOMODCACHE bash (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 -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)
  • 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 -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE sh -c npx prettier --cGOINSECURE GOPROXY 64/bin/go GOSUMDB GOWORK 64/bin/go sh (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha -json GO111MODULE /usr/bin/git GOINSECURE GOMOD GOMODCACHE git rev-�� --show-toplevel GOPROXY /usr/bin/git GOSUMDB GOWORK 64/bin/go git (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha --show-toplevel go /usr/bin/git -json GO111MODULE 64/bin/go git rev-�� --show-toplevel go /usr/bin/git -json GO111MODULE 64/bin/go git (http block)
  • https://api.github.com/repos/actions/checkout/git/ref/tags/v6
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq .object.sha -json GO111MODULE /opt/hostedtoolcache/go/1.25.8/x64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE /opt/hostedtoolcache/go/1.25.8/x64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq .object.sha --show-toplevel /opt/hostedtoolcache/go/1.25.8/xGO111MODULE /usr/bin/git /tmp/go-build198git -trimpath 64/bin/go git rev-�� --show-toplevel go /usr/bin/git athSetup_GorootOgit GO111MODULE 64/bin/go 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 -json GO111MODULE /opt/hostedtoolcache/go/1.25.8/x64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE /opt/hostedtoolcache/go/1.25.8/x64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq .object.sha --show-toplevel /opt/hostedtoolcache/go/1.25.8/xGO111MODULE /usr/bin/git /tmp/go-build198git -trimpath 64/bin/go git rev-�� --show-toplevel go /usr/bin/git -json GO111MODULE 64/bin/go git (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 -json GO111MODULE /opt/hostedtoolcache/go/1.25.8/x64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE /opt/hostedtoolcache/go/1.25.8/x64/bin/go GOINSECURE GOMOD GOMODCACHE go (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 -json GO111MODULE /opt/hostedtoolcache/go/1.25.8/x64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE /opt/hostedtoolcache/go/1.25.8/x64/bin/go GOINSECURE GOMOD GOMODCACHE go (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 -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (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 -json GO111MODULE /opt/hostedtoolcache/go/1.25.8/x64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE /opt/hostedtoolcache/go/1.25.8/x64/bin/go GOINSECURE GOMOD GOMODCACHE go (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 -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (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 -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (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 --show-toplevel GOPROXY /usr/bin/git GOSUMDB GOWORK 64/bin/go git rev-�� --show-toplevel go /usr/bin/git -json GO111MODULE 64/bin/go 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 GOSUMDB GOWORK 64/bin/go GOINSECURE GOMOD erignore go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE 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 GOSUMDB GOWORK 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 changed the title feat: safe update mode enforcement for secrets (#safe-update) feat: safe update mode enforcement for secrets and actions (#safe-update) Apr 7, 2026
…ists

When --safe-update is active and there is no existing lock file (nil manifest),
treat the manifest as empty rather than skipping enforcement. This ensures that
any non-GITHUB_TOKEN secrets and any custom actions are rejected on the very
first compilation, matching the principle of least privilege.

Agent-Logs-Url: https://github.com/github/gh-aw/sessions/a2834c03-20e6-4967-bf03-06e41c3f905f

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 7, 2026

@copilot if there is no prior manifest, and no prior lock file, dissallow any secrets usage.

Done in commit eb89621. When --safe-update is active and there is no prior lock file (nil manifest), the manifest is now treated as empty rather than skipping enforcement. This means the first compilation will reject any non-GITHUB_TOKEN secrets and any custom action refs, following the principle of least privilege.

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 (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 prettier --write /opt/hostedtoolcache/node/24.14.1/x64/bin/npm **/*.ts **/*.json --ignore-path npm run format:pkg-json --silent /snap/bin/bash tierignore (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 se 477704/b121/vet.cfg ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet (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 ath ../../../.pr**/*.json (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha --write ../../../**/*.json /usr/bin/git --ignore-path ../../../.prettirev-parse (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha --show-toplevel 64/pkg/tool/linux_amd64/vet /usr/bin/git _QdOprojJ (http block)
  • https://api.github.com/repos/actions/checkout/git/ref/tags/v6
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq .object.sha te &#39;../../../**/*.json&#39; &#39;!../../../pkg/workflow/js/**/*.json&#39; --ignore-path ../../../.prettieriggit -buildtags /opt/hostedtoolcache/go/1.25.8/x64/bin/gofmt -errorsas -ifaceassert -nilfunc /opt/hostedtoolcache/go/1.25.8/x64/bin/gofmt -l -w actions/setup/js/node_modules/flatted/golang/pkg/flatted/flatted.go /home/REDACTED/.local/bin/node cmd/gh-aw/capitagit cmd/gh-aw/commanrev-parse cmd/gh-aw/format--show-toplevel node (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq .object.sha te &#39;../../../**/*.json&#39; &#39;!../../../pkg/workflow/js/**/*.json&#39; --ignore-path ../../../.prettieriggit -buildtags /home/REDACTED/go/bin/node -errorsas -ifaceassert -nilfunc node /opt�� run format:cjs /home/node_modules/.bin/sh (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq .object.sha --show-toplevel 64/pkg/tool/linux_amd64/compile /usr/bin/git _.a (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 te &#39;../../../**/*.json&#39; &#39;!../../../pkg/workflow/js/**/*.json&#39; --ignore-path ../../../.prettieriggit -buildtags /home/REDACTED/.local/bin/bash -errorsas -ifaceassert -nilfunc bash --no�� --noprofile -tests /home/REDACTED/node_modules/.bin/node (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq .object.sha te &#39;../../../**/*.json&#39; &#39;!../../../pkg/workflow/js/**/*.json&#39; --ignore-path ../../../.prettieriggit -buildtags /home/REDACTED/work/_temp/uv-python-dir/node -errorsas -ifaceassert -nilfunc node /opt�� run format:cjs /home/REDACTED/work/gh-aw/node_modules/.bin/sh (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq .object.sha te &#39;../../../**/*.json&#39; &#39;!../../../pkg/workflow/js/**/*.json&#39; --ignore-path ../../../.prettieriggit -buildtags /opt/hostedtoolcache/node/24.14.1/x64/bin/node -errorsas -ifaceassert -nilfunc node /opt�� run format:cjs /opt/hostedtoolcache/node/24.14.1/x64/lib/node_modules/npm/node_modules/@npmcli/run-script/lib/n--show-toplevel (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 te &#39;../../../**/*.json&#39; &#39;!../../../pkg/workflow/js/**/*.json&#39; --ignore-path ../../../.prettieriggit -buildtags /bin/sh -errorsas -ifaceassert -nilfunc /bin/sh -c cd actions/setup/js &amp;&amp; npm run format:cjs --silent &gt;/dev/null 2&gt;&amp;1 -tests /home/REDACTED/.npm/_npx/b388654678d519d9/node_modules/.bin/sh (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 te &#39;../../../**/*.json&#39; &#39;!../../../pkg/workflow/js/**/*.json&#39; --ignore-path ../../../.prettieriggit stants_integration_test.go /bin/sh (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 get --local tions/setup/js/node_modules/.bin/prettier gpg.program (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 te &#39;../../../**/*.json&#39; &#39;!../../../pkg/workflow/js/**/*.json&#39; --ignore-path ../../../.prettieriggit /tmp/go-build141477704/b243/vet.cfg /usr/local/.ghcup/bin/bash (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 get --local bin/node commit.gpgsign (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 get --local de_modules/.bin/node commit.gpgsign (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 --show-toplevel (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 ignore-path ../../../.prettierignore (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 ignore-path ../../../.prettierignore (http block)

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

@pelikhan
Copy link
Copy Markdown
Collaborator

pelikhan commented Apr 7, 2026

@copilot

  • add features flag to enable this
  • @actions/* are allowed

…rom enforcement

- Add SafeUpdateFeatureFlag constant ("safe-update") to pkg/constants/feature_constants.go
- Update effectiveSafeUpdate to check isFeatureEnabled(SafeUpdateFeatureFlag) in addition
  to the CLI --safe-update flag, allowing safe-update to be enabled via the
  frontmatter features section or GH_AW_FEATURES env var
- Exempt actions/* repos (GitHub Actions org) from action violation checks:
  adding or removing actions/checkout, actions/setup-node etc. is always allowed
- Update tests to cover feature-flag activation and actions/* exemption

Agent-Logs-Url: https://github.com/github/gh-aw/sessions/295f5415-166c-4ec6-8a31-72b95c074c46

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 7, 2026

@copilot

  • add features flag to enable this...

Done in commit ee3ad48:

  • Feature flag: Added SafeUpdateFeatureFlag = "safe-update" to pkg/constants/feature_constants.go. effectiveSafeUpdate now checks isFeatureEnabled(SafeUpdateFeatureFlag, workflowData) in addition to the CLI --safe-update flag, so safe-update mode can be enabled via features: safe-update: true in workflow frontmatter or the GH_AW_FEATURES=safe-update env var.

  • actions/* exemption: Actions from the actions/ GitHub org are now always trusted. Adding actions/checkout, actions/setup-node, etc. (whether or not they appear in the prior manifest) will never be flagged — and removing them from the manifest is also not flagged.

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 (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 npx prettier --write &#39;**/*.cjs&#39; &#39;**/*.ts&#39; &#39;**/*.json&#39; --ignore-path ../../../.pr**/*.json -tests /home/REDACTED/node_modules/.bin/node (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 .js&#39; --ignore-path .prettierignore --log-level=error HEAD de_modules/.bin/node (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 ath ../../../.pr**/*.json (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha &#34;prettier&#34; --write &#39;../../../**/*.json&#39; &#39;!../../../pkg/workflow/js/**/*.json&#39; --ignore-path ../.git (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha --show-toplevel 64/pkg/tool/linux_amd64/vet /usr/bin/git --get-regexp cfg es/.bin/sh git rev-�� --show-toplevel 64/pkg/tool/linux_amd64/vet /usr/bin/git ../pkg/workflow/git cfg 64/pkg/tool/linu--show-toplevel git (http block)
  • https://api.github.com/repos/actions/checkout/git/ref/tags/v6
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq .object.sha te &#39;../../../**/*.json&#39; &#39;!../../../pkg/workflow/js/**/*.json&#39; --ignore-path ../../../.prettieriggit -buildtags /home/REDACTED/.local/bin/bash -errorsas -ifaceassert -nilfunc bash --no�� --noprofile -tests /home/node_modules/.bin/node (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq .object.sha te &#39;../../../**/*.json&#39; &#39;!../../../pkg/workflow/js/**/*.json&#39; --ignore-path ../../../.prettieriggit -buildtags /usr/bin/bash -errorsas -ifaceassert -nilfunc bash --no�� --noprofile -tests /bin/sh (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq .object.sha --show-toplevel (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 te &#39;../../../**/*.json&#39; &#39;!../../../pkg/workflow/js/**/*.json&#39; --ignore-path ../../../.prettieriggit k/gh-aw/gh-aw/pkg/workflow/import_schema_test.go /opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/vet (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq .object.sha te &#39;../../../**/*.json&#39; &#39;!../../../pkg/workflow/js/**/*.json&#39; --ignore-path ../../../.prettieriggit /tmp/go-build889456437/b267/vet.cfg /usr/local/sbin/bash (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq .object.sha te &#39;../../../**/*.json&#39; &#39;!../../../pkg/workflow/js/**/*.json&#39; --ignore-path ../../../.prettieriggit -buildtags /bin/sh -errorsas -ifaceassert -nilfunc /bin/sh -c echo &#34;��� Formatting Go code...&#34; -tests /home/REDACTED/work/_temp/uv-python-dir/node (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 te &#39;../../../**/*.json&#39; &#39;!../../../pkg/workflow/js/**/*.json&#39; --ignore-path ../../../.prettieriggit /tmp/go-build889456437/b266/vet.cfg /usr/local/.ghcup/bin/bash (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 te &#39;../../../**/*.json&#39; &#39;!../../../pkg/workflow/js/**/*.json&#39; --ignore-path ../../../.prettieriggit -buildtags /home/REDACTED/.cargo/bin/bash -errorsas -ifaceassert -nilfunc bash --no�� --noprofile -tests /opt/hostedtoolcache/node/24.14.1/x64/lib/node_modules/npm/node_modules/@npmcli/run-script/lib/n--show-toplevel (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 --local cfg 1/x64/bin/sh (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 te &#39;../../../**/*.json&#39; &#39;!../../../pkg/workflow/js/**/*.json&#39; --ignore-path ../../../.prettieriggit /tmp/go-build889456437/b244/vet.cfg /opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/vet (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 _.a credential.helper tions/node_modules/.bin/node (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 --local credential.helper tions/setup/js/node_modules/.bin/node (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 --show-toplevel (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 ignore-path ../../../.prettierignore (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 ignore-path ../../../.prettierignore /deps.go x_amd64/compile (http block)

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

@pelikhan
Copy link
Copy Markdown
Collaborator

pelikhan commented Apr 7, 2026

@copilot read the lock.yml previous version from the previous commit in git/github to avoid local tampering

Add gitutil.ReadFileFromHEAD() that runs `git show HEAD:<relpath>` to
retrieve a file's content from the last committed revision rather than
the working tree.

In safe update mode, the compiler now uses the committed lock file as
the manifest baseline instead of os.ReadFile(). This prevents a local
agent from tampering with the .lock.yml file on disk before invoking the
compiler in order to forge a manifest that approves new secrets or actions.

Agent-Logs-Url: https://github.com/github/gh-aw/sessions/ac0875c5-6338-4dee-8b1c-8aa6707ab111

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 7, 2026

@copilot read the lock.yml previous version from the previous commit in git/github to avoid local tampering

Done in commit e7c9a1c.

Added gitutil.ReadFileFromHEAD(filePath string) to pkg/gitutil/gitutil.go. It runs git show HEAD:<relpath> to retrieve the file's content from the last committed revision rather than the working tree.

The compiler now uses this in safe update mode: gitutil.ReadFileFromHEAD(lockFile) is called to obtain the manifest baseline. If the lock file hasn't been committed yet (new workflow), the call returns an error and enforcement proceeds with a nil/empty manifest as before. This prevents a local agent from modifying the .lock.yml on disk before invoking the compiler to forge an approval.

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 8611877/b012/vetrev-parse .cfg git rev-�� st-runs/20260407-030909-13382/runtime-import-path-test2183290601/my-github-project/.github/workfgit ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet /usr/bin/git st2970363239/tesgit 8611877/b151/vetshow .cfg 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 infocmp bin/bash git rev-�� st-runs/20260407-031133-19963/runtime-import-path-test67124322/my-github-project/.github/workflogit node /usr/bin/git -031133-19963/ougit git k/gh-aw/gh-aw/acHEAD:../../../../../tmp/gh-aw-test-runs/20260407-031133-19963/test-796743753/test-push-to-pull-request-branch-labels.lock.yml git (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 ncurrent-test2923198944/workflow-13.lock.yml (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/ai-inference/git/ref/tags/v1 --jq .object.sha --show-toplevel git /usr/bin/git lock.yml git 1/x64/bin/node git rev-�� st-runs/20260407-031133-19963/job-manager-state-test1415954860/test.lock.yml git /usr/bin/git util/gitutil.go git _modules/.bin/noinstall 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 se 8611877/b209/vet.cfg b95dd3cd39d53014252684935be949656708c912b973a09ac7f39252eaf842e1-d .prettierignore --log-level=errorev-parse (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v3 --jq .object.sha te &#39;**/*.cjs&#39; &#39;**/*.ts&#39; &#39;**/*.json&#39; --ignore-path ../../../.prettierignore git ache/node/24.14.1/x64/lib/node_modules/npm/node_modules/@npmcli/run-script/lib/node-gyp-bin/sh w.lock.yml git /usr/bin/git git comm�� rite &#39;../../../**/*.json&#39; &#39;!../../../pkg/workflow/js/**/*.json&#39; --ignore-path feat: read lock file manifest from git HEAD to prevent local tam../../../.prettierignore /home/REDACTED/.config/composer/vendor/bin/git --show-toplevel git /usr/bin/git 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 ../pkg/workflow/-errorsas r x_amd64/vet (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha pilot-log-parsing-test1842770964/test-copilot-log-parsing.lock.yml x_amd64/vet /usr/bin/git -branch-test9484tr --local x_amd64/vet git rev-�� --show-toplevel x_amd64/vet /usr/bin/git *.json&#39; &#39;!../../git user.email 64/pkg/tool/linu--show-toplevel git (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha heckout/git/ref/tags/v6 /opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/vet /usr/bin/git 21622112/test-wogit /tmp/go-build314rev-parse /opt/hostedtoolc--show-toplevel n-continued&#34; show�� HEAD:../../../../../tmp/gh-aw-test-runs/20260407-030909-13382/concurrent-test2923198944/workflowgit /opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/vet /usr/bin/git test-no-assigneegit -buildtags /usr/bin/sed git (http block)
  • https://api.github.com/repos/actions/checkout/git/ref/tags/v6
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq .object.sha st-pr-expires-3421622112/test-workflow.lock.yml (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq .object.sha --show-toplevel (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq .object.sha ing-test3681731705/skip-if-check-failing-null-workflow.lock.yml /opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/vet /usr/bin/git -pat-workflow.logit /tmp/go-build314rev-parse 8487314/b250/vet--show-toplevel git rev-�� --show-toplevel /opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/vet ache/node/24.14.1/x64/bin/node -unreachable=falgit /tmp/go-build314rev-parse /opt/hostedtoolc--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 --show-toplevel -tests /usr/bin/git 54086605/commandgit (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq .object.sha --show-toplevel (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq .object.sha cret-redaction-test721282583/test-workflow.lock.yml /opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/vet /usr/bin/git -30.lock.yml /tmp/go-build314rev-parse 8487314/b258/vet--show-toplevel git rev-�� /../tmp/compute-text-context-test2260613474/discussion_trigger_without_explicit_usage.lock.yml /opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/vet /usr/bin/git ml /tmp/go-build314rev-parse /opt/hostedtoolc--show-toplevel git (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 --show-toplevel (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/setup-go/git/ref/tags/v4 --jq .object.sha HEAD:../../../../../tmp/gh-aw-test-runs/20260407-031133-19963/aw-info-order-test1363092991/test-git git /usr/bin/git o git /usr/bin/git git rev-�� --show-toplevel git /usr/bin/git h ../../../.pretgit git /usr/bin/git 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 2355/test.lock.yml (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/setup-node/git/ref/tags/v4 --jq .object.sha 73494/test.lock.yml git /usr/bin/git o git /sh git rev-�� --show-toplevel git /usr/bin/git h ../../../.pretgit git -main/dist/gh-gp--show-toplevel 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 te &#39;../../../**/*.json&#39; &#39;!../../../pkg/workflow/-errorsas .cfg ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/upload-artifact/git/ref/tags/v4 --jq .object.sha celain --ignore-submodules | head -n 10 git /opt/hostedtoolcache/node/24.14.1/x64/bin/node ation-test280328git find /usr/bin/gh node tion�� -031133-19963/workflow-event-aware-command-test317681013/command-with-schedule.lock.yml gh son ignore --jq /usr/bin/git node (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 --show-toplevel -goversion /usr/bin/git -c=4 -nolocalimports -importcfg git rev-�� mpiler-edge-case4019542072/test.lock.yml /home/REDACTED/work/gh-aw/gh-aw/pkg/workflow/import_schema_test.go /usr/bin/git th .prettierignogit (http block)
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw-actions/git/ref/tags/v0.1.2 --jq .object.sha -031133-19963/missing-fields-test2187563716/test.lock.yml git /usr/bin/git --show-toplevel git /usr/bin/git git rev-�� mpiler-edge-case2319206886/test.lock.yml git /usr/bin/git ath ../../../.prgit git /usr/bin/git 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 10 on ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet /../../.prettiergit erignore (http block)
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw-actions/git/ref/tags/v1.0.0 --jq .object.sha */*.json&#39; &#39;!../../../pkg/workflow/js/**/*.json&#39; --ignore-path file manifest from git HEAD to prevent local tam../../../.prettierignore 64/pkg/tool/linux_amd64/compile st-workflow.lockgit /opt/hostedtoolcrev-parse /usr/bin/git 64/pkg/tool/linux_amd64/compile js/f�� g_.a git ache/go/1.25.8/x64/bin/node nore git /usr/bin/git node (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 git status --porcelain --ignore-submodules | hea--log-target on 64/pkg/tool/linux_amd64/cgo /../../.prettiergit erignore (http block)
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw-actions/git/ref/tags/v1.2.3 --jq .object.sha */*.json&#39; &#39;!../../../pkg/workflow/js/**/*.json&#39; --ignore-path file manifest from git HEAD to prevent local tam../../../.prettierignore 64/pkg/tool/linux_amd64/compile --show-toplevel gcc /usr/bin/git 64/pkg/tool/linux_amd64/compile js/f�� g_.a git cal/bin/node nore flow_test /usr/bin/git node (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 -030909-13382/concurrent-test2923198944/workflow-35.lock.yml x_amd64/vet /usr/bin/git --local committer.email 64/pkg/tool/linu-b git rev-�� --show-toplevel 64/pkg/tool/linux_amd64/vet /usr/bin/git te &#39;**/*.cjs&#39; &#39;*git .cfg k/gh-aw/node_mod--show-toplevel git (http block)
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v0.47.4 --jq .object.sha -031133-19963/concurrent-test2125582242/workflow-42.lock.yml git /usr/bin/git --show-toplevel git ate-mode git rev-�� --show-toplevel git /usr/bin/git --show-toplevel git ache/node/24.14.--show-toplevel 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 (http block)
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v1.0.0 --jq .object.sha ignore-path ../../../.prettierignore git /usr/bin/git 43661600/withoutsh 64/pkg/tool/linu-c /usr/bin/git git rev-�� --show-toplevel git /usr/bin/git --show-toplevel 64/pkg/tool/linu/opt/hostedtoolcache/node/24.14.1/x64/bin/npx /usr/bin/git git (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 (http block)
    • Triggering command: /usr/bin/gh gh api /repos/nonexistent/action/git/ref/tags/v999.999.999 --jq .object.sha ignore-path ../../../.prettierignore git /usr/bin/git --show-toplevel 64/pkg/tool/linu-c /usr/bin/git git rev-�� --show-toplevel git /usr/bin/git onStep3553383684node 64/pkg/tool/linu/opt/hostedtoolcache/node/24.14.1/x64/bin/npx /usr/bin/git git (http block)

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

…g in log message

Agent-Logs-Url: https://github.com/github/gh-aw/sessions/ac0875c5-6338-4dee-8b1c-8aa6707ab111

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
@pelikhan
Copy link
Copy Markdown
Collaborator

pelikhan commented Apr 7, 2026

@copilot gate this feature to dev mode only for the compiler.

In dev mode (local development) the compiler reads the lock file manifest
from git HEAD to prevent a local agent from forging an approval by
modifying the .lock.yml before invoking the compiler.

In release/action modes the compiler runs inside a GitHub Actions runner
whose working tree is already a trusted checkout, so the lock file is
read directly from the filesystem — avoiding any dependency on git
availability in the runner environment.

Agent-Logs-Url: https://github.com/github/gh-aw/sessions/d5256d85-7fbe-4e3e-b3d9-b7bc6782fe9d

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 7, 2026

@copilot gate this feature to dev mode only for the compiler.

Done in commit 2896b9d. The ReadFileFromHEAD path is now gated behind c.actionMode.IsDev(). In dev mode, the manifest baseline is read from git show HEAD:<lockfile> to prevent local tampering. In release/action modes the lock file is read from the filesystem as before, since the GitHub Actions runner's working tree is already a trusted checkout.

…non-dev mode)

Agent-Logs-Url: https://github.com/github/gh-aw/sessions/d5256d85-7fbe-4e3e-b3d9-b7bc6782fe9d

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
@pelikhan pelikhan marked this pull request as ready for review April 7, 2026 03:38
Copilot AI review requested due to automatic review settings April 7, 2026 03:38
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

Adds a “safe update mode” to the workflow compiler that records an allowlist-style manifest (secrets + external actions) into lock files and, when enabled, rejects compilations that introduce new restricted secret usage or unapproved action repo additions/removals relative to the previously recorded manifest.

Changes:

  • Embed a # gh-aw-manifest: {...} JSON header in generated .lock.yml files and add helpers to parse/serialize it.
  • Add safe-update enforcement that diffs newly-detected secrets/actions against the previous manifest (with a tamper-resistant baseline in dev mode by reading from git HEAD).
  • Wire safe-update enabling via CLI/config and update compiler APIs/tests for new return values from YAML generation.
Show a summary per file
File Description
pkg/workflow/compiler_types.go Adds safeUpdate state + option/setter; (docs need alignment with actual enablement behavior).
pkg/gitutil/gitutil.go Adds ReadFileFromHEAD used to load committed lockfile content as a baseline in dev mode.
pkg/gitutil/gitutil_test.go Adds unit tests for ReadFileFromHEAD.
pkg/constants/feature_constants.go Introduces SafeUpdateFeatureFlag constant.
pkg/cli/compile_config.go Adds SafeUpdate to compile configuration.
pkg/cli/compile_compiler_setup.go Propagates SafeUpdate config into compiler setup and logs enablement.
cmd/gh-aw/main.go Adds --safe-update CLI flag wiring.
pkg/workflow/*_test.go (multiple) Updates tests for the new generateYAML / generateAndValidateYAML return signature.
.github/workflows/*.lock.yml (many) Inserts # gh-aw-manifest: ... header line into generated lock files.

Copilot's findings

Tip

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

Comments suppressed due to low confidence (1)

pkg/gitutil/gitutil.go:122

  • ReadFileFromHEAD uses cmd.Output() and then wraps any git error as "file not found in HEAD commit", which can mask other failures (e.g., git not available, invalid ref, permissions) and drops stderr. Using CombinedOutput (or capturing stderr) and returning a more accurate error message based on the failure would make debugging much easier.
  • Files reviewed: 207/207 changed files
  • Comments generated: 6

Comment on lines +161 to +165
// SetSafeUpdate configures whether to enforce safe update mode (reject newly introduced secrets).
// Safe update mode can only be enabled via the CLI; frontmatter cannot enable it.
func (c *Compiler) SetSafeUpdate(safeUpdate bool) {
c.safeUpdate = safeUpdate
}
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

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

SetSafeUpdate’s doc comment says safe update mode can only be enabled via the CLI and that frontmatter cannot enable it, but effectiveSafeUpdate() enables it via GH_AW_FEATURES and frontmatter features (features: safe-update: true). Please update this comment (or the behavior) so the API docs match the actual precedence rules.

Copilot uses AI. Check for mistakes.
Comment on lines +35 to +38
// WithSafeUpdate configures whether to enforce safe update mode (reject newly introduced secrets)
func WithSafeUpdate(safeUpdate bool) CompilerOption {
return func(c *Compiler) { c.safeUpdate = safeUpdate }
}
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

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

The WithSafeUpdate comment mentions only rejecting newly introduced secrets, but safe update enforcement also blocks unapproved action additions/removals. Consider updating the comment to mention actions too (or rename to reflect the broader policy) to avoid misleading callers.

Copilot uses AI. Check for mistakes.
Comment on lines +107 to +113
// git show requires the path to be relative to the repository root and to use
// forward slashes even on Windows.
relPath, err := filepath.Rel(gitRoot, absPath)
if err != nil {
return "", fmt.Errorf("cannot compute path of %q relative to git root %q: %w", absPath, gitRoot, err)
}
relPath = filepath.ToSlash(relPath)
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

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

ReadFileFromHEAD computes relPath via filepath.Rel(gitRoot, absPath) but doesn’t validate that the resulting path stays within the repo (e.g., relPath starting with ".." when filePath is outside gitRoot). Add a guard to reject paths outside the repository before passing them to git show.

This issue also appears on line 117 of the same file.

Copilot uses AI. Check for mistakes.
compileCmd.Flags().Bool("fail-fast", false, "Stop at the first validation error instead of collecting all errors")
compileCmd.Flags().Bool("no-check-update", false, "Skip checking for gh-aw updates")
compileCmd.Flags().String("schedule-seed", "", "Override the repository slug (owner/repo) used as seed for fuzzy schedule scattering (e.g. 'github/gh-aw'). Bypasses git remote detection entirely. Use this when your git remote is not named 'origin' and you have multiple remotes configured")
compileCmd.Flags().Bool("safe-update", false, "Enforce safe update mode: reject compilations that introduce new restricted secrets not present in the existing GHAW manifest. CLI override always takes precedence over frontmatter safe-update field")
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

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

The --safe-update flag help text says the CLI override always takes precedence over frontmatter safe-update, but the implementation only provides an enabling flag (frontmatter/features can still enable safe update when the CLI flag is not set). Consider rewording to something like “CLI flag forces safe update on (cannot be disabled by frontmatter)” to match behavior.

Copilot uses AI. Check for mistakes.
Comment on lines 28 to 32
Stats bool // Display statistics table sorted by file size
FailFast bool // Stop at first error instead of collecting all errors
ScheduleSeed string // Override repository slug used for fuzzy schedule scattering (e.g. owner/repo)
SafeUpdate bool // Enforce safe update mode: reject compilations that introduce new restricted secrets
}
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

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

The SafeUpdate field comment mentions only “restricted secrets”, but safe update mode also enforces an action allowlist policy (added/removed unapproved actions). Update this comment so CLI config accurately reflects what enabling this flag does.

Copilot uses AI. Check for mistakes.
Comment on lines +159 to +163
// Set safe update flag: when enabled via CLI it overrides any frontmatter setting
compiler.SetSafeUpdate(config.SafeUpdate)
if config.SafeUpdate {
compileCompilerSetupLog.Print("Safe update mode enabled: compilations introducing new restricted secrets will be rejected")
}
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

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

The log message for enabling safe update mentions only “new restricted secrets”, but enforcement also rejects unapproved action additions/removals. Consider updating the message so users aren’t surprised when action changes are blocked too.

Copilot uses AI. Check for mistakes.
@pelikhan
Copy link
Copy Markdown
Collaborator

pelikhan commented Apr 7, 2026

@copilot review comments

…g/help text

- compiler_types.go: fix WithSafeUpdate and SetSafeUpdate doc comments to
  mention action enforcement and accurate enabling paths (CLI/env/frontmatter)
- gitutil.go: add path-traversal guard in ReadFileFromHEAD — reject paths
  whose relative form starts with ".." (outside repository root)
- main.go: reword --safe-update flag help text to describe additive enabling
  semantics and mention action allowlist enforcement
- compile_config.go: extend SafeUpdate field comment to mention actions
- compile_compiler_setup.go: update log message to mention action enforcement

Agent-Logs-Url: https://github.com/github/gh-aw/sessions/ce9fbee6-0a8b-49f6-b289-d275925870c0

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 7, 2026

@copilot review comments

Done in commit e73e17a. Addressed all 6 review comments:

  • Fixed WithSafeUpdate / SetSafeUpdate doc comments (action enforcement + accurate enabling paths)
  • Added path-traversal guard in ReadFileFromHEAD (reject ..-prefixed relative paths)
  • Rewrote --safe-update flag help text (additive semantics, mentions action enforcement)
  • Updated SafeUpdate field comment and log message to mention action allowlist enforcement

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.

3 participants