Uh oh!
There was an error while loading. Please reload this page.
feat(safeoutputs): add GitHub issue mutation family - #1881
Conversation
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 132286b3-2728-4551-b357-14cf86e4362a
|
Azure Pipelines: Successfully started running 2 pipeline(s). There may be pipelines that require an authorized user to comment /azp run to run. |
jamesadevine
commented
Aug 14, 2026
/review |
✅ Rust Code Quality Reviewer completed the Rust code quality review. Warning Threat Detection Engine Failure — The analysis engine could not complete. This is a tooling failure, not a security finding. What happenedThe threat detection results could not be parsed. Review the workflow run logs for details. |
There was a problem hiding this comment.
TypeScript review — scripts/ado-script/ (this PR's scope only)
Reviewed the diff to approval-summary/index.ts, approval-summary/render.ts, executor-e2e/github-client.ts, executor-e2e/runner.ts, and executor-e2e/scenarios/github-issue.ts.
No merge-blocking defects found. The new code is careful about the concerns that matter most here:
parseRepositoryPolicies/ repository-resolution logic inrender.tsfails closed on malformed JSON, non-string fields, and array/object type mismatches — good defensive parsing of compiler-provided data.- REST/GraphQL error paths in
github-client.tsconsistently throw with call context (method + path + status) rather than swallowing failures. - New branches (mutation family scenarios, repository policy resolution, empty-value rendering) are matched by substantial new test coverage in
render.test.tsand the scenario test suite.
One non-blocking observation: createRepoLabel and createMilestone in github-client.ts hand-roll their own fetch/error-text logic instead of going through the githubJson<T> helper introduced earlier in the same file, duplicating the "read body text on failure" pattern. Not a functional issue (this is test-harness code, not shipped in ado-script.zip), just a minor consistency nit for a future cleanup pass.
🟦 TypeScript code quality review by TypeScript Code Quality Reviewer · auto · 63.1 AIC · ⌖ 12 AIC · ⊞ 11.1K
Comment /review to run again
There was a problem hiding this comment.
Warning
Threat Detection Engine Failure — The analysis engine could not complete. This is a tooling failure, not a security finding.
What happened
The threat detection results could not be parsed.
Review the workflow run logs for details.
REQUEST_CHANGES not needed. Reviewed the Rust-side changes in this PR (new github_api.rs/github_issue_common.rs shared infra and the eleven new safe_outputs/*.rs GitHub issue-mutation tools, plus the create_github_issue.rs/agentic_pipeline.rs refactors).
Findings: no merge-blocking defects.
- Error handling is consistently
anyhow-based with.context()/ensure!/bail!; the switch fromctx.get_tool_config(...).ok().unwrap_or_default()toctx.get_tool_config(...)?increate_github_issue.rsis a real improvement (config shape errors now surface instead of silently defaulting). repository.split_once('/').expect(...)calls ingithub_api.rs/github_issue_common.rsare all preceded by a regex-enforcedvalidate_github_repository/target_repo_regexcheck guaranteeing exactly one/, so the invariant holds.- Repository dedupe/ownership helpers (
dedupe_github_repositories,github_app_owner_for_repositories,github_app_repository_names) use insertion-orderVecs rather thanHashMapiteration, preserving deterministic output for generated config/YAML. resolved_github_issues: Arc<Mutex<HashMap<...>>>accessors never hold the lock across an.await.- One apparent defect turned out to be a false positive worth flagging for transparency: the pre-fetched diff shows
.header(AUTHORIZATION, format!("******", self.token))ingithub_api.rs, which would be a compile error (unused format arg). I checked the actual file on disk and the real code isformat!("Bearer {}", self.token)— the diff-fetch tooling appears to redact secret-shaped literals for display. Not a code issue, just noting it in case the redaction masks other findings in future reviews.
Process note: the rust-critic sub-agent produced no usable output across three attempts (empty responses each turn), so this review reflects only my own manual pass over the diff; its findings were discarded per the sub-agent contract.
No inline comments posted — nothing rose to a postable, diff-scoped defect.
🦀 Rust code quality review by Rust Code Quality Reviewer · auto · 148.9 AIC · ⊞ 11.2K
Comment /review to run again
jamesadevine
commented
Aug 14, 2026
@copilot merge main |
Co-authored-by: jamesadevine <4742697+jamesadevine@users.noreply.github.com>
Merged |
jamesadevine
commented
Aug 14, 2026
/review |
✅ Test Quality Sentinel completed the test quality analysis.
|
There was a problem hiding this comment.
Compiler contract review
Walked the full drift surface for this PR (57 files, new GitHub issue-mutation safe-output family):
- Registry completeness: all 11 new tools (
add-github-issue-labels,assign-github-issue-milestone,assign-github-issue-to-user,close-github-issue,comment-on-github-issue,hide-github-issue-comment,link-github-sub-issue,remove-github-issue-labels,set-github-issue-field,unassign-github-issue-from-user,update-github-issue) are consistently wired throughsafe_outputs/mod.rs,mcp.rstool handlers,execute.rsdispatch table,inspect/catalog.rsdescriptions (with a new catalog-completeness test), and the sharedGITHUB_ISSUE_SAFE_OUTPUT_TOOLS/GITHUB_TEMPORARY_ID_CONSUMERSregistries intypes.rs. - Docs sync:
docs/safe-outputs.md,README.md, andAGENTS.md(bundle directory tree) all reflect the new files/tools. - Newtype usage: new params (
AddGithubIssueLabelsParams, etc.) consistently useGithubIssueNumberand existing validated helpers rather than rawStringidentifiers. - Ado-script bundle drift: no
.jsbundle changes expected/flagged (gitignored generated artefacts). - Codegen drift: no changes to
filter_ir.rs/Factenum in this diff, sotypes.gen.ts/fact-catalog.gen.jsonabsence is expected. - Lock drift: no
.github/workflows/*.mdchanges in this PR.
No compiler-contract violations found. Nice, thorough threading of the new tool family through every registry this project depends on.
🏗️ Compiler contract review by Compiler Contract Reviewer · auto · 60.3 AIC · ⌖ 1.99 AIC · ⊞ 12.1K
Comment /review to run again
There was a problem hiding this comment.
TypeScript review (scripts/ado-script/)
Reviewed approval-summary/index.ts, approval-summary/render.ts, executor-e2e/github-client.ts, executor-e2e/runner.ts, and executor-e2e/scenarios/github-issue.ts for async/error handling, type safety on external data, and secret handling. Also ran an independent ts-critic pass on the same diff.
No high-confidence defects found:
- All new JSON/GraphQL parsing (
parseRepositoryPolicies,githubJson,listRepositoryIssueFields,getIssueFieldValue, etc.) validates shape before use and fails closed with a descriptive<unresolved: ...>marker or thrownErrorrather than trusting external input. - Network calls consistently go through
ghFetch/githubJsonwithAbortSignal.timeoutand explicit non-2xx handling; no unawaited promises orforEach-with-async patterns. - No tokens or secrets are interpolated into thrown errors or log lines — error messages only include GitHub's response body/status.
- Non-null assertions (e.g.
resolved[0]!,reference.canonical!) are all preceded by explicit guards in the same function, so they're not blind casts on unchecked external data.
Nothing else to flag — clean, well-guarded diff.
🟦 TypeScript code quality review by TypeScript Code Quality Reviewer · auto · 69.7 AIC · ⌖ 2.6 AIC · ⊞ 11.3K
Comment /review to run again
There was a problem hiding this comment.
This PR (github issue mutation family) was reviewed for security regressions across the shared GitHub API client (github_api.rs), repository/target policy (github_issue_common.rs), and the mutation tools (comment, update, close, assign/unassign, hide-comment, link-sub-issue, labels, milestone, issue-field). Findings:\n\n- Repository selection consistently routes through resolve_github_repository/resolve_github_issue_target, which enforces the target-repo/allowed-repos allowlist for every path, including close-github-issue.duplicate_of explicit-repository and URL forms — no way to reach an unconfigured repo.\n- All agent-controlled config strings (labels, assignees, prefixes, repository refs, reasons) pass through reject_pipeline_injection before use, and result fields are sanitized via SanitizeContent/sanitize_config before serialization.\n- Capability checks (validate_github_target_capability) and required-labels/required-title-prefix filters are resolved against live GitHub state before the first write in every tool, preventing a stale/forged local view from bypassing policy.\n- The GitHub write token stays confined to Stage 3 executor code (ExecutionContext::github_token), matching the documented three-stage boundary; the Authorization header is redacted the same way in both source and tests, so no plaintext token leak was found.\n\nNo exploitable injection, token exposure, or validation weakening was found in the reviewed diff; it is security-neutral to hardening. Given the size (57 files, ~16.5k additions dominated by new, additive Rust/TS code), I focused on the highest-risk sinks (HTTP client construction, repository/target resolution, and each mutation tool's write path) rather than test-only executor-e2e harness code.
🔒 Security review by PR Security Reviewer · auto · 115.5 AIC · ⌖ 2.8 AIC · ⊞ 11.6K
Comment /review to run again
There was a problem hiding this comment.
Test Quality Review
Reviewed the new/changed test files for this PR (Rust unit tests in src/safe_outputs/*.rs, TypeScript executor-e2e and approval-summary tests, and tests/compiler_tests.rs additions).
No test-quality issues found. This PR is unusually thorough on the testing front:
- Every new safe-output tool (
assign-github-issue-milestone,assign-github-issue-to-user,close-github-issue,comment-on-github-issue,hide-github-issue-comment,link-github-sub-issue,set-github-issue-field,update-github-issue,add/remove-github-issue-labels,unassign-github-issue-from-user) has dedicated unit tests covering: param validation (including injection payloads like##vso[task.complete]and$(TOKEN)), strict-config deserialization/rejection of unknown keys, policy filter ordering (all preflight reads happen before any write), pagination, dry-run behaviour, and sanitization of hostile GitHub API error bodies. - The executor-e2e harness (
runner.test.ts) adds a real regression test for repeatedpriorEntriesoccurrences (link-github-sub-issueparent+child), andgithub-client.test.tscovers GraphQL introspection, product-error surfacing, and pagination for the new REST/GraphQL helpers. - The approval-summary
render.test.tsadditions specifically test hostile-repository sanitization, temporary-ID-to-repository resolution ordering (including the negative case where acreate-github-issueoccurs after the consumer and must NOT resolve), and empty-value markers. - No existing assertions were weakened, loosened, or
#[ignore]d — the diffs against previously-modified test files (e.g.set_github_issue_type.rs,tests/compiler_tests.rs) are purelyrustfmtreflow plus additive fields/tests. tests/compiler_tests.rsadditions correctly assert both automatic and gated (SafeOutputs_Reviewed) job placement for the new GitHub App token scoping tests.
No inline comments needed.
🧪 Test quality analysis by Test Quality Sentinel · auto · 114.8 AIC · ⌖ 2.52 AIC · ⊞ 11.2K
Comment /review to run again
There was a problem hiding this comment.
Rust code-quality review — no merge-blocking issues found
Reviewed the Rust-only portion of this diff (src/compile/{agentic_pipeline,common,types}.rs, src/execute.rs, src/mcp.rs, src/inspect/catalog.rs, src/safe_outputs/**, tests/compiler_tests.rs) covering the new github_api.rs / github_issue_common.rs shared infrastructure and the eleven new GitHub-issue safe-output modules.
What I checked:
- Error handling: consistent
anyhow::Result+.context()/ensure!/bail!usage; everyexpect()I found is guarded by a preceding validation (e.g.split_once('/')aftervalidate_github_repository,Number::from_f64after an explicitis_finite()check) rather than reachable from unchecked user input. - The
GithubClient::sendbuilds theAuthorizationheader viaformat!("Bearer {}", self.token)— I initially misread this as a literal"******"placeholder from a masked terminal render, butgit showon the actual blob confirms the real bearer-token format string is correct. No credential-leak/broken-auth bug here. - Pagination (
get_paginated) enforces aMAX_PAGESbound and re-validates same-origin on everyLink: rel="next"hop before following it — good defense against SSRF via a malicious redirect chain. validate_github_issue_outputs_config's refactor from two hardcoded tools to aGITHUB_ISSUE_SAFE_OUTPUT_TOOLSloop preserves the originaltarget-repo/mutation-filter/approval-compatibility checks (verifiedcreate-github-issueandset-github-issue-typeare still members of that table and routed through the same validation calls).- No lossy casts, no blocking calls in async paths, no unsynchronized shared mutable state observed in the changed lines.
Most of the diff outside the new files is mechanical cargo fmt reflow. Nothing here meets the bar for an inline comment. Compiler-contract-specific concerns (front-matter schema, generated YAML, docs sync) are left to the Compiler Contract Reviewer.
rust-critic sub-agent returned no findings on this diff.
🦀 Rust code quality review by Rust Code Quality Reviewer · auto · 113.3 AIC · ⌖ 2.25 AIC · ⊞ 11.3K
Comment /review to run again
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 76ac1b78-a2fe-49ed-98b7-820bd1db3ed1
Summary
Closes#1871
Test plan
cargo check --testscargo test(3,395 passed, 1 ignored)cargo clippy --all-targets -- -D warningsgit diff --checknpm test -- --maxWorkers=1inscripts/ado-script(1,130 passed)npm run typechecknpm run build:approval-summarynpm run build:executor-e2e