Skip to content

feat(security-guard): name the vetted route when a gh api write is blocked - #2057

Merged
potiuk merged 1 commit into
apache:mainfrom
potiuk:guard-point-to-vetted-ops
Nov 10, 2026
Merged

potiuk merged 1 commit into
apache:mainfrom
potiuk:guard-point-to-vetted-ops

Conversation

@potiuk

@potiuk potiuk commented Nov 10, 2026

Copy link
Copy Markdown
Member

Summary

The public-surface guard blocks a gh api write whose text holds one of its forbidden terms. Its message says only that a maintainer can set the environment bypass. For two private surfaces, GHSA discussion comments and tracker comment edits, a vetted-ops operation already does the same write, but nothing in the block message points to it. An agent running issue-sync then stalls, or hands the step back to the operator as a manual paste.

The block decision is unchanged: every command this guard blocked before is still blocked. When the blocked endpoint has a vetted route, the reason now names it:

  • a comment post on a GHSA → the GHSA comment-post operation;
  • a tracker comment edit → comment-update;
  • a tracker comment post → issue-comment;
  • GHSA record fields, and edits or deletes of existing GHSA comments → no vetted operation, so the message says to use the web UI.

Each hint also says the operation has to be in the caller's [callers] list in the adopter's .apache-magpie-overrides/tools/vetted-ops/config.toml, that adding it is a maintainer's change, and that the body file goes under ~/.cache/apache-magpie/vetted-ops-bodies/. The issue-sync skill's GHSA page says the same in the two places that offered plain gh api as the alternative.

Why

This came up on a real sync run. The sync caller could read GHSA comments but not post them. The plain gh api post was blocked, and the block named neither the operation nor the grant, so the reply went back to the operator to paste by hand. Setting the assigned ID on a GHSA hit the same block, and no vetted operation exists for record fields.

Follow-up, not in this PR

A vetted operation for GHSA record fields would close the remaining gap. It needs a key allowlist that refuses state and the collaborator fields, because publishing is permanent and public. That makes it more than a one-line _register, so it is left for a separate PR.

Tests

  • claude plugin test plugins/magpie-security: 165 pass, including six new cases.
  • claude plugin validate --strict plugins/magpie-security: passed.
  • prek on the changed files: passed.

🤖 Generated with Claude Code

…ocked

The public-surface guard blocks `gh api` writes whose text holds one of
its forbidden terms, and its message only says to ask a maintainer for
the environment bypass. For GHSA discussion comments and tracker
comment edits a vetted-ops operation already does the same write, but
nothing in the block points there, so an agent stalls or hands the
step back to the operator.

The block decision is unchanged. When the blocked endpoint has a
vetted route, the reason now names it, with the exact op:

- POST to a GHSA comments endpoint -> the GHSA comment op
- PATCH .../issues/comments/<id> -> comment-update
- POST .../issues/<N>/comments -> issue-comment

and says the op must be in the caller's `[callers]` list in the
adopter's vetted-ops config, which a maintainer adds. GHSA record field
edits and GHSA comment edits have no vetted op; the reason says to use
the web UI. The issue-sync GHSA reference says the same.

Generated-by: Claude Opus 5
@potiuk
potiuk enabled auto-merge (squash) November 10, 2026 17:30
@github-actions github-actions Bot added family:security security-* skills capability:intake Import external signal + sync tracker state labels Nov 10, 2026
@potiuk
potiuk merged commit f370343 into apache:main Nov 10, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

capability:intake Import external signal + sync tracker state family:security security-* skills

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant