Repository navigation
Support issue artifacts in create-issue safe outputs - #75323
Conversation
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Add a per-issue artifact cap with non-positive values disabling attachments. Preserve the requested max-isssue-artifacts spelling as an alias. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Enforce UTF-8 byte limits before creation and attachment without silently truncating artifacts. Update schemas, tool constraints, documentation, and generated locks. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Include issue_artifacts.cjs in the safe-outputs deployment bundle and exercise artifact normalization from the deployed files. Regenerate nine WASM compiler golden fixtures for the issue artifact limits and validation schema. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅
|
|
✅ PR Specification Reviewer completed successfully!
|
|
✅ Test Quality Sentinel completed test quality analysis. Test Quality SentinelOutcome: The agent completed and reported no action. A no-op output alone does not verify that all required work was completed or that publication was possible. Agent messages are omitted from this comment. The category uses structured run status, not interpretation of agent prose.
|
|
❌ Design Decision Gate 🏗️ failed to deliver outputs during design decision gate check.
|
|
✅ Ponytail Reviewer completed successfully!
|
|
✅ PR Code Quality Reviewer completed the code quality review.
|
There was a problem hiding this comment.
Reviewed PR head 40486df760d2c43e373772308ad5d0e23add7d1f against Safe Outputs Specification v1.29.17, especially §7.1 Issue Artifact Requirements 4 and Files and Paths, plus the security architecture privilege/content-integrity boundaries. Static review only; no tests or conformance scripts were run.
Blocking findings (already covered by existing inline comments, so no duplicate inline comments were emitted):
-
embedded_htmlbypasses sanitization (existing comment 4489544474,actions/setup/js/issue_artifacts.cjs:153). Wrapping the body in a fenced code block makessanitizeContenttreat the entire HTML payload as inert, then the fence is stripped and the raw payload is published. This violates §7.1 Issue Artifact Requirements 4, which requires content policies to be applied while preserving HTML source. Sanitize the HTML body itself (or otherwise apply the same non-code policies without allowing the wrapper to suppress them) and add regression coverage for commands, URLs, template delimiters, and XML content. -
Agent-controlled paths can disclose sensitive workspace or
/tmpfiles (existing comment 4489675788,actions/setup/js/safe_outputs_handlers.cjs:2237). The MCP handler reads any model-selected regular file under those broad roots and publishes its contents through an issue artifact. Symlink/hard-link and size guards prevent traversal, but do not prevent intentional disclosure of credentials or other sensitive files. The new Files and Paths contract explicitly permits this behavior, so the contract and implementation need a maintainer-approved security decision; do not treat the current spec addition as sufficient authorization to weaken the broader untrusted-agent data-boundary guarantees.
Coverage limit: the prefetched patch and local source were inspected; generated lock changes were not individually reviewed. No specification synchronization was performed because the artifact security behavior remains unresolved.
Generated by PR Specification Reviewer for #75323 · copilot · gpt50 · ~4 AIC · ⌖ ~1 AIC · ⊞ 1.6K
Comment /review-specs to run again
|
Warning The 🏗️ Design Decision Gate — ADR RequiredThis PR adds 413 new lines of core business logic (more than the 100-line threshold) in 📄 Draft ADR committed:
Decision captured in the draft: The unprivileged safeoutputs MCP backend reads artifact 📋 What to do next
Once the ADR is linked in the PR body, this gate will run again and check that the implementation matches the decision. ❓ Why ADRs Matter
ADRs create a searchable, permanent record of why the codebase looks the way it does. Future contributors (and your future self) will thank you. 📋 Michael Nygard ADR Format ReferenceAn ADR must contain these four sections to be considered complete:
All ADRs are stored in
|
There was a problem hiding this comment.
What this change does: This adds typed, bounded issue-artifact inputs to create_issue, including guarded path ingestion, sanitization, staged previews, and post-creation attachment. It also wires compiler limits and documents the body-only custom-job helper.
Should fix:
-
The schema parity test is duplicated (
actions/setup/js/issue_artifacts.test.cjs:L30)- What this is: The new test compares the runtime and compiler copies of the artifact schema.
- Problem:
TestSafeOutputsToolsJSONInSyncinpkg/workflow/safe_outputs_tools_test.goalready compares every tool object in both copies, so this lookup and equality assertion add a second parity check. - Fix: Remove the compiler lookup and
expect(runtime).toEqual(compiler), keeping the focused runtime-shape assertions in this test. - If we skip it: Schema changes require maintaining two parity tests.
Not checked: correctness, security, and performance issues, per the requested review scope.
Verdict: fix 1 first.
Lean: -3 lines possible.
Generated by ✂️ Ponytail Reviewer for #75323 · codex · routed: gpt56 max · ~8 AIC · ⌖ ~1 AIC · ⊞ 118
Comment /ponytail to run again
There was a problem hiding this comment.
Review complete. I found no additional actionable issues beyond the existing review comments on the changed code. The specialist pass produced no parseable findings, so it was treated as unavailable; no tests were run per the static-review instructions.
🔎 Code quality review by PR Code Quality Reviewer · copilot · gpt50 · ~7 AIC · ⌖ ~1 AIC · ⊞ 1.6K
Comment /review to run again
There was a problem hiding this comment.
Skills-Based Review 🧠
Applied /diagnosing-bugs, /tdd, and /codebase-design. Requesting changes on one correctness gap in the attachment failure path.
📋 Key Themes & Highlights
Key Themes
- Partial-failure path skips post-create steps (
create_issue.cjs:1350): an attachment error returns before copilot assignment and sub-issue linking, even though the issue exists. See the inline comment. - Readability of the body/path check (
issue_artifacts.cjs:66): correct, but easy to misread. - Already raised by the bot, not repeated here: the
embedded_htmlsynthetic fence (issue_artifacts.cjs:153) and the model-controlled path-read surface (safe_outputs_handlers.cjs:2237). Both still need a decision from the author.
Positive Highlights
- ✅ Fence length is derived from the longest backtick run in the source, so the source cannot escape the synthetic fence.
- ✅ Size limits reject oversized bodies instead of truncating them, and UTF-8 bytes are counted correctly.
- ✅ Staged previews perform no writes, and same-day grouping is bypassed for artifact issues. Both are covered by tests.
- ✅ The
max_issue_artifact_sizeinteger path is validated by the schema (minimum: 1).
@copilot please address the review comments above.
🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · copilot · routed: haiku55 xhigh · ~8 AIC · ⌖ ~1 AIC · ⊞ 5.4K
Comment /matt to run again
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved artifact-handling flaws can expose sensitive workspace or temporary files and allow embedded HTML to bypass configured URL-domain restrictions.
2 open issues
What changed in this PR
Adds issue-artifact support to create_issue and the custom-job createIssue helper, including inline content, MCP file-path ingestion, and configurable attachment limits.
Changes:
- Adds artifact schemas, shared types, count/size limits, and compiler configuration.
- Integrates file ingestion, sanitization, attachment handling, and partial-failure reporting.
- Updates documentation, tests, WASM fixtures, and generated workflow locks.
This pull request requires changes.
Outstanding review comments:
- Critical —
actions/setup/js/safe_outputs_handlers.cjs:2236: Path ingestion can publish sensitive workspace or/tmpfiles without the existing upload-source denylist. Apply those exclusions and consider narrowing the permitted temporary directory. - Critical —
actions/setup/js/safe_outputs_tools.json:144: Underallowed-or-code-region, temporary code fencing exemptsembedded_htmlURLs from domain filtering before the fences are removed for rendered publication. - Moderate —
actions/setup/js/create_issue.cjs:1347: Attachment failure returns early, skipping Copilot assignment, closing older issues, and parent/group linking. Continue those lifecycle steps while preserving the partial-failure result. - Moderate —
actions/setup/js/issue_artifacts.cjs:155: Invalid or sanitized non-URL bodies can pass validation aslinkartifacts. Require a single HTTPS URL after sanitization, before creating the issue. - Nit —
docs/src/content/docs/reference/custom-safe-outputs.md:345: Link toupload-artifactfor binary files and downloadable originals rather than issue-artifact path ingestion.
| File | Description |
|---|---|
pkg/workflow/tool_description_enhancer.go |
Describes artifact limits and disabled state. |
pkg/workflow/testdata/TestWasmGolden_CompileFixtures/with-imports.golden |
Refreshes imported-workflow artifact expectations. |
pkg/workflow/testdata/TestWasmGolden_CompileFixtures/playwright-cli-mode.golden |
Refreshes Playwright artifact expectations. |
pkg/workflow/testdata/TestWasmGolden_CompileFixtures/basic-copilot.golden |
Refreshes basic Copilot artifact expectations. |
pkg/workflow/testdata/TestWasmGolden_AllEngines/pi.golden |
Refreshes Pi artifact expectations. |
pkg/workflow/testdata/TestWasmGolden_AllEngines/gemini.golden |
Refreshes Gemini artifact expectations. |
pkg/workflow/testdata/TestWasmGolden_AllEngines/copilot.golden |
Refreshes Copilot artifact expectations. |
pkg/workflow/testdata/TestWasmGolden_AllEngines/codex.golden |
Refreshes Codex artifact expectations. |
pkg/workflow/testdata/TestWasmGolden_AllEngines/claude.golden |
Refreshes Claude artifact expectations. |
pkg/workflow/safe_outputs_validation_config.go |
Preserves optional artifact arrays for handler validation. |
pkg/workflow/safe_outputs_max_validation.go |
Propagates artifact-size parsing errors. |
pkg/workflow/safe_outputs_handler_registry_issues.go |
Emits runtime artifact limits. |
pkg/workflow/safe_output_validation_config_test.go |
Checks artifact-array validation metadata. |
pkg/workflow/js/safe_outputs_tools.json |
Adds compiler-side artifact input schema. |
pkg/parser/schemas/main_workflow_schema.json |
Defines artifact count and size options. |
pkg/parser/schema_test.go |
Tests option types, sizes, and misspellings. |
docs/src/content/docs/reference/custom-safe-outputs.md |
Documents helper artifacts and file transport. |
actions/setup/setup.sh |
Deploys the issue-artifact runtime helper. |
actions/setup/js/types/safe-outputs.d.ts |
Defines input, normalized, and created artifact types. |
actions/setup/js/types/safe-outputs-config.d.ts |
Types frontmatter artifact limits. |
actions/setup/js/types/handler-factory.d.ts |
Types compiled artifact limits. |
actions/setup/js/symlink_guard.cjs |
Shares workspace-or-/tmp path validation. |
actions/setup/js/setup_sh_file_lists.test.cjs |
Checks deployed artifact-helper availability. |
actions/setup/js/safe_outputs_tools.json |
Adds runtime artifact input schema. |
actions/setup/js/safe_outputs_mcp_schema_validation.test.cjs |
Tests mutually exclusive body/path sources. |
actions/setup/js/safe_outputs_mcp_large_content.test.cjs |
Adds Linux stdio-MCP file-ingestion coverage. |
actions/setup/js/safe_outputs_handlers.cjs |
Resolves artifact paths before recording issue requests. |
.github/workflows/windows.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/windows-grower.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/weekly-network-domains-audit.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/video-analyzer.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/super-linter.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/squad-plan.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/smoke-work-queue.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/smoke-work-queue-worker.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/smoke-security-alerts.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/smoke-pi-sub-agents.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/smoke-pi-routed.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/smoke-pi-routed-claude.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/smoke-pi-auto.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/smoke-otel-backends.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/smoke-github-codex.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/smoke-copilot-sub-agents.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/smoke-copilot-small.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/smoke-copilot-sdk.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/smoke-copilot-sdk-routed.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/smoke-copilot-routed.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/smoke-copilot-routed-steering.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/smoke-copilot-routed-claude.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/smoke-copilot-dynamic-workflow.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/smoke-codex-routed.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/smoke-codex-routed-openai.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/smoke-codex-bare-auto.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/smoke-codex-auto.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/smoke-claude-routed.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/smoke-claude-routed-anthropic.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/smoke-claude-dynamic.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/smoke-claude-copilot.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/smoke-claude-copilot-auto.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/smoke-claude-auto.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/smoke-azure-pi.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/smoke-azure-codex.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/sighthound-security-scan.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/refactoring-cadence.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/plan.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/objective-impact-report.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/notion-issue-summary.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/hippo-embed.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/gpclean.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/go-pattern-detector.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/firewall.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/feature-grower.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/example-permissions-warning.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/example-failure-category-filter.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/dev.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/designer-drift-audit.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/deployment-incident-monitor.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/daily-work-queues-report.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/daily-windows-terminal-integration-builder.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/daily-team-status.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/daily-model-resolution.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/daily-max-ai-credits-test.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/daily-file-diet.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/daily-credit-limit-test.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/daily-cache-strategy-analyzer.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/daily-byok-ollama-test.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/daily-action-setup-security-audit.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/codex-github-remote-mcp-test.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/cli-consistency-checker.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/bot-detection.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/agent-persona-explorer.lock.yml |
Refreshes artifact defaults and validation. |
.github/workflows/ace-editor.lock.yml |
Refreshes artifact defaults and validation. |
Review effort: Max (auto)
Address review feedback with shared sensitive-path exclusions, strict rendered HTML sanitization, continued assignment and parent linkage after artifact errors, focused regressions, and ADR-75323. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
In response to the skills review notice: this completion notice contains no actionable finding, so no repository change is needed. |
|
In response to the specification review notice: there is no actionable finding in this completion notice, so no repository change is needed. |
|
In response to the test quality notice: reported_no_action is not proof of verification or publication, and this notice requests no code change. The review fixes were validated separately with focused suites and a real Linux stdio-MCP ingestion check. |
|
In response to the design gate delivery notice: the logs confirm safe_outputs failed because its token could not read branch protection, although the agent completed and its explanatory comment was published. Added and linked the missing ADR through this authorized local PR update without changing permissions or bypassing the workflow's protection check. |
|
In response to the Ponytail review notice: this successful completion notice contains no actionable finding, so no repository change is needed. |
|
In response to the code quality notice: the notice itself requests no change. The separate actionable clarity and post-create failure comments have been addressed with focused regressions. |
|
In response to the ADR requirement: accepted the documentation requirement, but the claimed committed draft was absent after the blocked workflow push. Added and linked ADR-75323, covering the final constrained read policy, strict HTML filtering, alternatives, limits, and partial-publication behavior. |
|
Copilot assignment requested for the following outstanding work:
Once you start work, post this work summary as a PR comment without the leading Copilot mention, including the Sous-chef head, work, and state lines below, to record that the assignment is running. Apply the necessary fixes on this PR's existing branch, reply to each listed review thread and resolve it when addressed. Ignore feedback already answered or resolved; stop when only human review or CI remains. Do not merge or trigger CI. Sous-chef requested-head: 40486df
|
Preserve both safe-output specification revisions and recompile merged workflows. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Merged latest |
|
🎉 This pull request is included in a new release. Release: |

Summary
Attach plans, links, notes, and HTML previews to newly created GitHub issues using the issue artifacts REST API.
ADR: ADR-75323: Resolve Issue Artifact Paths in the Unprivileged Safe-Outputs Backend
artifactsto the built-increate_issuetool and custom-jobcreateIssuehelper, supportinggeneric(default),plan,link, andembedded_html.bodyor an absolutepathper artifact. The unprivileged safeoutputs backend reads path-based UTF-8 content and records a body-only request, without loading or echoing the file into the agent's conversation. The privileged issue handler and custom-job helper reject unresolved paths./tmp/gh-aw/agent, excluding Git metadata, system directories, and HOME credential/configuration paths through the shared file-upload denylist. Reject links, non-regular files, invalid UTF-8, NUL bytes, empty content, and oversized files. Validate counts and all input shapes before opening sources; failures record no issue request or deduplication state.Configuration
max-issue-artifactsdefaults to 10; zero or negative integers disable attachments without disabling ordinary issue creation. Only the correctly spelled option is supported.max-issue-artifact-sizedefaults to 1 MB (1,048,576 bytes). It accepts integer bytes or human-friendly sizes such as512kband1.5mb; units are case-insensitive, use multiples of 1024, and must resolve to a positive whole-byte count. Limits apply independently to each artifact, including bounded file reads and sanitized/reference-resolved content; oversized content is rejected, not truncated.Path-based MCP example
After writing the file, the agent calls
create_issuewith:{ "title": "Implement parser caching", "body": "The implementation plan is attached.", "artifacts": [ { "type": "plan", "name": "Implementation plan", "path": "/tmp/gh-aw/agent/issue-plan.md" } ] }The backend reads the complete file into
bodybefore recording the request. No separate upload or custom-job file declaration is needed. Paths are literal: variables and globs are not expanded. General temporary runtime files are not allowed. Guarded reads require the Linux workflow runtime and fail closed elsewhere.Artifact requests bypass same-day comment grouping so attachments are not lost; existing issue deduplication remains. Attachment failures retain the already-created issue's identity and attachment count, without recreating or rolling back the issue. The trusted custom-job helper accepts inline content only and uses fixed default limits rather than inheriting built-in frontmatter settings.
Validation
.gitreads fail without appending requests. The Linux-only integration test remains skipped on the native macOS host.main; this update does not alter those files.