Skip to content

fix: Prevent patch/bundle desynchronization in safe-outputs#36762

Merged
lpcox merged 4 commits into
mainfrom
fix/patch-bundle-desync-540
Jun 4, 2026
Merged

fix: Prevent patch/bundle desynchronization in safe-outputs#36762
lpcox merged 4 commits into
mainfrom
fix/patch-bundle-desync-540

Conversation

@lpcox
Copy link
Copy Markdown
Collaborator

@lpcox lpcox commented Jun 4, 2026

Summary

Prevents patch/bundle desynchronization in safe-outputs by pinning the branch ref to a SHA before transport artifact generation and verifying it hasn't changed after bundle creation (closes #540). Also fixes agent-injected metadata from leaking into privileged handlers by normalizing items before dispatch.

Changes

Security / Bug Fixes

  • actions/setup/js/safe_outputs_handlers.cjs — Added TOCTOU protection: pins the branch ref to a SHA before transport artifact generation and verifies the ref hasn't changed after bundle creation; aborts with a clear error if the ref was flipped concurrently. This closes the patch/bundle desynchronization window described in #540.

  • actions/setup/js/collect_ndjson_output.cjs — Fixed item processing to use normalizedItem (which strips infrastructure-only transport fields) instead of the raw item for known types, preventing agent-injected metadata from reaching privileged handlers.

Tests

  • actions/setup/js/safe_outputs_handlers.test.cjs — Updated test assertions to match the new "Failed to pin branch" and "Bundle transport requires branch pinning" error messages, replacing the previous patch-generation error messages.

Documentation / Tooling

  • .github/skills/agentic-workflows/SKILL.md — Added agentic-workflows-mcp.md and mcp-clis.md to the skill's file-loading list.

Impact

Area Impact Breaking
safe-outputs TOCTOU protection High No
Agent metadata isolation in NDJSON dispatch High No
Test coverage for new error messages Medium No
Skill reference file list Low No

Related

  • Closes #540 — patch/bundle desynchronization in safe-outputs
  • Improves bundle pinning guidance (commit a233d7860)

Generated by PR Description Updater for issue #36762 · sonnet46 1.2M ·

…540)

Three security fixes to prevent agents from bypassing file-protection
policy through transport artifact manipulation:

1. Strip infrastructure fields in validateItem():
   - Delete patch_path, bundle_path, base_commit, diff_size from
     normalizedItem in the validation engine
   - Push normalizedItem (not original item) in collect_ndjson_output.cjs
   - Prevents agents from injecting arbitrary file paths or size values
     through NDJSON output

2. Pin branch SHA in MCP handlers:
   - Resolve refs/heads/<branch> to a SHA once before generating artifacts
   - Pass pinnedSha to generateGitPatch so it uses the pinned commit
     directly (skipping show-ref verification)
   - Fail closed if pinnedSha generation encounters errors

3. TOCTOU verification after bundle generation:
   - After generating both patch and bundle, verify the branch ref still
     points to the pinned SHA
   - If the agent flipped the ref between operations, abort with an error
   - Applied to both create_pull_request and push_to_pull_request_branch

Includes 6 regression tests verifying infrastructure field stripping.

Refs: github/agentic-workflows#540

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 4, 2026 00:04
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 4, 2026

✅ smoke-ci: safeoutputs CLI comment + comment-memory run (26921046033)

Generated by 🧪 Smoke CI for issue #36762 ·

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 4, 2026

Comment Memory

CI lights the path
Green checks bloom at dawn
Quiet bots still sing

Note

This comment is managed by comment memory.

It stores persistent context for this thread in the code block at the top of this comment.
Edit only the text inside the backtick fences; workflow metadata and the footer are regenerated automatically.

Learn more about comment memory

Generated by 🧪 Smoke CI for issue #36762 ·

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

This PR hardens the safe-outputs pipeline against transport artifact manipulation by (1) stripping infrastructure-only fields during validation/ingestion, and (2) reducing patch/bundle desynchronization risk by pinning branch refs to a SHA and adding a post-generation TOCTOU check in the privileged handlers.

Changes:

  • Strip patch_path, bundle_path, base_commit, and diff_size from validateItem() normalized output and ensure ingestion uses normalizedItem.
  • Add branch SHA pinning + TOCTOU verification to create_pull_request and push_to_pull_request_branch handlers.
  • Add regression tests covering infrastructure field stripping.
Show a summary per file
File Description
actions/setup/js/safe_outputs_handlers.cjs Pins branch SHA before artifact generation and verifies ref stability after bundle generation.
actions/setup/js/safe_output_type_validator.cjs Deletes infrastructure-only fields from normalizedItem during validation.
actions/setup/js/collect_ndjson_output.cjs Ensures ingestion pushes normalizedItem (with stripped infra fields) rather than the raw item.
actions/setup/js/generate_git_patch.cjs Adds pinnedSha support to avoid dereferencing mutable refs during patch generation.
actions/setup/js/safe_output_type_validator.test.cjs Adds tests asserting infra field stripping behavior.

Copilot's findings

Tip

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

  • Files reviewed: 5/5 changed files
  • Comments generated: 4

Comment thread actions/setup/js/generate_git_patch.cjs Outdated
Comment on lines +140 to +143
// SECURITY: When pinnedSha is provided, use it directly as the tip commit instead
// of dereferencing refs/heads/<branchName>. This prevents TOCTOU races where the
// agent can flip the branch ref between patch and bundle generation.
const tipRef = options.pinnedSha || branchName;
Comment on lines +565 to +569
} catch (pinError) {
server.debug(`Failed to pin branch '${entry.branch}': ${getErrorMessage(pinError)}`);
// If we can't resolve the branch, let the downstream functions handle the error
pinnedSha = null;
}
Comment on lines +945 to +948
} catch (pinError) {
server.debug(`Failed to pin branch '${entry.branch}': ${getErrorMessage(pinError)}`);
pushPinnedSha = null;
}
Comment on lines +326 to +329
// SECURITY: Use normalizedItem (which only contains declared schema
// fields) instead of the original item, to prevent agent-injected
// infrastructure fields (patch_path, bundle_path, base_commit, diff_size)
// from reaching the privileged handler.
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 4, 2026

@copilot review all comments and address unresolved review feedback.
Please resolve the open SHA pinning and fail-closed bundle handling threads before the next check run.

Generated by 👨‍🍳 PR Sous Chef · gpt54mini 4M ·

@lpcox
Copy link
Copy Markdown
Collaborator Author

lpcox commented Jun 4, 2026

@copilot address review feedback

Copilot AI and others added 2 commits June 4, 2026 00:25
Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI commented Jun 4, 2026

@copilot address review feedback

Addressed. I pushed follow-up fixes in commits c658e05 and a233d78:

  • pinned SHA is now used consistently for downstream incremental diff-size calculations in generate_git_patch.cjs
  • bundle transport now fails closed when branch pinning fails in both handlers
  • the inaccurate normalizedItem security comment was corrected
  • related handler tests were updated and passing

@pelikhan
Copy link
Copy Markdown
Collaborator

pelikhan commented Jun 4, 2026

@lpcox you need to create draft PRs as the draft -> ready triggers PR reviewers.

@lpcox
Copy link
Copy Markdown
Collaborator Author

lpcox commented Jun 4, 2026

@copilot address the feedback #36762 (comment)

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 4, 2026

🚀 Smoke Antigravity MISSION COMPLETE! Antigravity has spoken. ✨

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 4, 2026

🎬 THE ENDSmoke Claude MISSION: ACCOMPLISHED! The hero saves the day! ✨

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 4, 2026

🚀 Smoke Gemini MISSION COMPLETE! Gemini has spoken. ✨

Testing safeoutputs CLI

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 4, 2026

🚀 Smoke Pi MISSION COMPLETE! Pi delivered. 🥧

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 4, 2026

✨ The prophecy is fulfilled... Smoke Codex has completed its mystical journey. The stars align. 🌟

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 4, 2026

✅ All tools validated successfully! Agent Container Smoke Test confirms agent container is ready.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 4, 2026

📰 BREAKING: Smoke Copilot is now investigating this pull request. Sources say the story is developing...

Copy link
Copy Markdown
Contributor

Copilot AI commented Jun 4, 2026

@copilot address the feedback #36762 (comment)

The linked feedback is about PR lifecycle (opening as draft, then marking ready), not code in this branch. There’s no repository code change to apply for this request. I can’t change PR draft/ready state from here, so this should be handled when creating/updating the PR.

Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
Copilot finished work on behalf of lpcox June 4, 2026 03:05
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 4, 2026

Smoke Test Results\n- GitHub MCP Testing: ✅\n- Web Fetch Testing: ✅\n- File Writing Testing: ✅\n- Bash Tool Testing: ✅\n- Build gh-aw: ❌\n\nOverall Status: FAIL

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • localhost

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "localhost"

See Network Configuration for more information.

Smoke Gemini — Powered by Gemini ·

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 4, 2026

Agent Container Tool Check

Tool Status Version
bash 5.2.21
sh available
git 2.54.0
jq 1.7
yq 4.53.2
curl 8.5.0
gh 2.92.0
node 24.16.0
python3 3.13.13
go 1.24.13
java 10.0.300 (.NET)
dotnet 10.0.300

Result: 12/12 tools available ✅

Overall Status: PASS

🔧 Tool validation by Agent Container Smoke Test · sonnet46 221.5K ·

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 4, 2026

Smoke test summary for PR #36762

  • GitHub MCP read: ✅
  • Serena symbol lookup: ✅
  • Playwright browser check: ✅
  • Web-fetch MCP check: ❌
  • Overall status: FAIL

Warning

Firewall blocked 6 domains

The following domains were blocked by the firewall during workflow execution:

  • accounts.google.com
  • android.clients.google.com
  • clients2.google.com
  • contentautofill.googleapis.com
  • safebrowsingohttpgateway.googleapis.com
  • www.google.com

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "accounts.google.com"
    - "android.clients.google.com"
    - "clients2.google.com"
    - "contentautofill.googleapis.com"
    - "safebrowsingohttpgateway.googleapis.com"
    - "www.google.com"

See Network Configuration for more information.

🔮 The oracle has spoken through Smoke Codex · gpt54mini 11.1M ·

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 4, 2026

Comment Memory

Signal in cold code
A browser lights the GitHub path
Tests settle like dust

Note

This comment is managed by comment memory.

It stores persistent context for this thread in the code block at the top of this comment.
Edit only the text inside the backtick fences; workflow metadata and the footer are regenerated automatically.

Learn more about comment memory

Warning

Firewall blocked 6 domains

The following domains were blocked by the firewall during workflow execution:

  • accounts.google.com
  • android.clients.google.com
  • clients2.google.com
  • contentautofill.googleapis.com
  • safebrowsingohttpgateway.googleapis.com
  • www.google.com

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "accounts.google.com"
    - "android.clients.google.com"
    - "clients2.google.com"
    - "contentautofill.googleapis.com"
    - "safebrowsingohttpgateway.googleapis.com"
    - "www.google.com"

See Network Configuration for more information.

🔮 The oracle has spoken through Smoke Codex · gpt54mini 11.1M ·

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 4, 2026

🧪 Smoke Test: Claude — Run 26927666920

Core #1#13: ✅ except #2 ⚠️ (mcpscripts-gh unavailable, used github_pr_query) and #3 ❌ (Serena find_symbol LSP EOF crash; activation ✅)
PR Review #14#20: ✅ all, except #20 ⚠️ (no safe PR to close)

Overall: PARTIALrun

Warning

Firewall blocked 6 domains

The following domains were blocked by the firewall during workflow execution:

  • accounts.google.com
  • android.clients.google.com
  • clients2.google.com
  • contentautofill.googleapis.com
  • safebrowsingohttpgateway.googleapis.com
  • www.google.com

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "accounts.google.com"
    - "android.clients.google.com"
    - "clients2.google.com"
    - "contentautofill.googleapis.com"
    - "safebrowsingohttpgateway.googleapis.com"
    - "www.google.com"

See Network Configuration for more information.

💥 [THE END] — Illustrated by Smoke Claude · opus48 5.3M ·

Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

💥 Automated smoke test review - all systems nominal!

Warning

Firewall blocked 6 domains

The following domains were blocked by the firewall during workflow execution:

  • accounts.google.com
  • android.clients.google.com
  • clients2.google.com
  • contentautofill.googleapis.com
  • safebrowsingohttpgateway.googleapis.com
  • www.google.com

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "accounts.google.com"
    - "android.clients.google.com"
    - "clients2.google.com"
    - "contentautofill.googleapis.com"
    - "safebrowsingohttpgateway.googleapis.com"
    - "www.google.com"

See Network Configuration for more information.

💥 [THE END] — Illustrated by Smoke Claude · opus48 5.3M

// never by the agent. If an agent injects these via NDJSON output, it could bypass
// file-protection policy (patch_path/bundle_path point to attacker-controlled files)
// or circumvent size limits (diff_size).
delete normalizedItem.patch_path;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Good defensive move stripping patch_path here — this prevents agent-injected infrastructure fields from reaching the handler. 👍

delete normalizedItem.patch_path;
delete normalizedItem.bundle_path;
delete normalizedItem.base_commit;
delete normalizedItem.diff_size;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Consider centralizing this list of stripped fields (patch_path, bundle_path, base_commit, diff_size) into a named constant for reuse and easier auditing.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 4, 2026

PR: fix: Prevent patch/bundle desynchronization in safe-outputs
Seen: Trim ambient prompt surface for smoke workflows and failure investigator
Seen: Remove agentic-workflows guide from prompt and move reference to .github/aw
1✅ 2❌ 3✅ 4✅ 5❌ 6✅ 7✅ 8✅ 9✅ 10✅ 11❌ 12✅ 13✅ 14❌ 15✅ 16✅
Overall: FAIL
Author: @lpcox Assignees: none

Warning

Firewall blocked 6 domains

The following domains were blocked by the firewall during workflow execution:

  • accounts.google.com
  • android.clients.google.com
  • clients2.google.com
  • contentautofill.googleapis.com
  • safebrowsingohttpgateway.googleapis.com
  • www.google.com

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "accounts.google.com"
    - "android.clients.google.com"
    - "clients2.google.com"
    - "contentautofill.googleapis.com"
    - "safebrowsingohttpgateway.googleapis.com"
    - "www.google.com"

See Network Configuration for more information.

📰 BREAKING: Report filed by Smoke Copilot · gpt54 5.9M ·

@lpcox lpcox merged commit eacfb51 into main Jun 4, 2026
9 of 13 checks passed
@lpcox lpcox deleted the fix/patch-bundle-desync-540 branch June 4, 2026 04:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants