Commit Graph
3 Commits
Author SHA1 Message Date
mathiasandClaude Opus 5.5 a41f5abfba fix(hooks): file_write_branch clears only one exact-case key and a plain branch name
CI / Check / Test (push) Successful in 5s
CI / Tag release (push) Skipped
CI / Check / Test (pull_request) Successful in 5s
CI / Tag release (pull_request) Skipped
Round-2 review of skills#52 committed to main through gitea-mcp with
{"branch":"feat/y8","Branch":"main"}: Go's encoding/json matches keys
case-insensitively and the last one wins, while the hook read only the
lowercase key. Same trick on content emptied a file.

The guard now asks unless exactly one key case-folds to "branch" and
one to "content", both spelled exactly, both strings. The branch is
cleared by shape ([A-Za-z0-9][A-Za-z0-9._/-]*, no "..", no refs/ prefix,
no trailing slash) instead of a blocklist, since refs/heads/main created
a second ref that wedged every API write to main. Whitespace-only
content asks.

11 new cases; 6 were red before the change, 5 pinned untested-but-correct
behaviour the reviewer's flips showed nothing covered.

Refs mathias/infra#508

Bump-Type: minor

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 22:19:00 +02:00
mathiasandClaude Opus 5.5 4a82206393 fix(hooks): close the five escapes the skills#52 review found
CI / Check / Test (push) Successful in 4s
CI / Tag release (push) Skipped
CI / Check / Test (pull_request) Successful in 5s
CI / Tag release (pull_request) Skipped
- Fail-closed path no longer needs jq: the ask JSON is a printf literal,
  and a host without jq asks instead of staying silent.
- A tool_name that is not a non-empty string asks (was: no opinion).
- Gate workflow_run_trigger, tag_create, release_create, and
  file_write_branch when it lands on main/master, has no branch, or
  empties a file (same effect as pr_merge / file_delete).
- Header claim narrowed: gitea-mcp spellings on any server name, not
  other servers' spellings of the same operation.
- Tests run the hook as hooks.json does (bash <path>), assert exit 0 on
  every case, and cover null/missing/wrong-type tool_name, last-segment
  verb parsing and a PATH without jq. 13 new cases were red first.

Refs mathias/infra#508

Bump-Type: minor

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 20:45:19 +02:00
mathiasandClaude Opus 5.5 9ba7cb2dcd feat(hooks): mcp-destructive-guard asks before irreversible MCP verbs
CI / Check / Test (push) Successful in 4s
CI / Tag release (push) Skipped
gitea-mcp authenticates by PAT pass-through, so an agent holds the
caller's full PAT scope, and repo_delete's confirm field is filled in by
the model. The infra-mcp README said client-side deny lists covered
destructive verbs; on 2026-10-01 none existed in any settings file.

PreToolUse hook on mcp__.*: repo_delete, file_delete, branch_delete,
pr_merge, tbd_ship, repo_update and repo_mirror_push get "ask". Matched
on the verb, not the server name, so the connector namespace or a
renamed registration cannot bypass it. Never emits allow; malformed
input fails closed.

Scope limit: MCP calls only. The Gitea REST API via Bash with the PAT
in env is not covered (recorded in infra ADR-0027).

Refs mathias/infra#508

Bump-Type: minor

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 20:37:46 +02:00