potiuk opened a new pull request, #417:
URL: https://github.com/apache/airflow-steward/pull/417
## Summary
Real implementation behind the `--apply-permission-audit` flag of
`/setup-steward verify` check 8d (introduced in #415). The skill
previously described the audit + atomic-edit semantics abstractly;
this PR adds the actual CLI the skill calls.
## What
`tools/permission-audit/` — stdlib-only Python CLI, three subcommands:
- **`audit <path> [--families ...]`** — read a settings file, classify
`permissions.allow[]` against the forbidden + family-scoped
recommended lists, print structured JSON. Exit code `1` on any
forbidden hit so a shell caller can pipeline. The JSON-pointer
path (`.permissions.allow[<index>]`) returned per forbidden entry
lets the verify report point operators at the exact location.
- **`apply <path> [--add ...]... [--remove ...]... [--create-if-missing]`** —
atomic add/remove. POSIX `fcntl.flock` advisory exclusive lock on
the target file, re-parse under the lock, mutate, write to a sibling
temp file, `os.replace` into place. Concurrent
`setup-isolated-setup-install` writes (which touch
`sandbox.filesystem.*` on the same file) serialise without either
losing work. Unrelated top-level keys (`extraKnownMarketplaces`,
`hooks`, `permissions.deny`) are preserved verbatim.
- **`list-known`** — dump the canonical forbidden + recommended-by-family
lists for diff-friendly inspection.
## Why
Check 8d landed in #415 with the *spec*. Without an implementation
the skill's only option on a finding was to print the proposal and
ask the operator to hand-edit — a per-file JSON edit during which
concurrent `setup-isolated-setup-install` writes could silently
clobber unrelated keys. The atomic flock-guarded path closes that
race without changing the skill's user-facing contract.
The 6-entry merge I did manually on `airflow-s/.claude/settings.local.json`
+ `airflow-steward/.claude/settings.local.json` last session was exactly
the kind of edit this tool now mechanises — including the removal of
`Bash(uv run *)` and `Bash(python3 *)`, both arbitrary-code-execution
holes that had silently accumulated.
## Wiring
- `.pre-commit-config.yaml` — ruff + mypy + pytest gates on
`tools/permission-audit/**` (matches the `github-body-field` convention).
- `docs/labels-and-capabilities.md` — new tool row, `capability:setup`.
- `.claude/skills/setup-steward/verify.md` — check 8d's
*"Implementation"* paragraph now references the CLI with the concrete
`uv run --project` invocations.
## Test plan
- [ ] `uv run --project tools/permission-audit pytest` — 22 tests pass
(classification, family-scoping, duplicate JSON-pointer numbering, atomic
add/remove, no-op-rewrite skip, malformed-JSON detection)
- [ ] `permission-audit audit <path>` on a settings file with `Bash(uv run
*)` returns exit 1, JSON contains the `.permissions.allow[<index>]` pointer
- [ ] `permission-audit apply <path> --remove 'Bash(uv run *)' --add
'Bash(lychee *)'` mutates atomically; unrelated `extraKnownMarketplaces` /
`hooks` keys survive verbatim
- [ ] `permission-audit list-known` dumps both canonical lists as JSON
🤖 Generated with [Claude Code](https://claude.com/claude-code)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]