feat: add ward pkg brew - scoped brew wrapper with audit, parity with coily pkg brew #52

Closed
opened 2026-06-04 11:19:47 +00:00 by coilysiren · 0 comments
Owner

Problem

Board repos gated by ward have no audited brew path. Ward's own deny-recovery hints route brew to coily brew ..., but that couples a public ward-gated repo to coily, which public contributors don't have. Package management should be reachable through ward itself.

Goal

Add a ward pkg group with a brew subcommand at full parity with coily pkg brew (coily cmd/coily/brew.go):

  • Mirrors brew's argv shape: ward pkg brew <verb> [args...].
  • Scoping classes with --allow-untapped opt-out:
    • formula-scoped: install, uninstall, upgrade, reinstall, link, unlink, pin, unpin
    • tap-scoped: tap, untap
    • touch-everything: cleanup, autoremove, services cleanup
    • services formula-scoped: services start/stop/restart/run/kill
    • passthrough (read-only / unrecognized): update, search, info, list, deps, ...
  • Audit rows pkg.brew.* written to ~/.coily/audit/<repo>.jsonl via cli-guard config.DefaultAuditPath().
  • Reuses cli-guard verb, audit, egress, exitcode, shell; ward grows a minimal Runner (shell + audit writer), no coily import.

Out of scope

  • Other package managers (npm/pip/cargo/...) - follow-up once brew lands.
  • A ward release - tracked separately; the new verb ships in the next ward tag.

Context

First consumer is the public board repo otel-a2a-relay-ansible-debug (deps install). Relates to the ward-adopter wiring in cli-guard#74. Supersedes the "ward never grows ops verbs" note in older .ward/ward.yaml comments - that constraint moved to the future seed template, per the cli-guard reflow.

## Problem Board repos gated by `ward` have no audited brew path. Ward's own deny-recovery hints route `brew` to `coily brew ...`, but that couples a public ward-gated repo to coily, which public contributors don't have. Package management should be reachable through ward itself. ## Goal Add a `ward pkg` group with a `brew` subcommand at **full parity with `coily pkg brew`** (coily `cmd/coily/brew.go`): - Mirrors brew's argv shape: `ward pkg brew <verb> [args...]`. - Scoping classes with `--allow-untapped` opt-out: - formula-scoped: install, uninstall, upgrade, reinstall, link, unlink, pin, unpin - tap-scoped: tap, untap - touch-everything: cleanup, autoremove, services cleanup - services formula-scoped: services start/stop/restart/run/kill - passthrough (read-only / unrecognized): update, search, info, list, deps, ... - Audit rows `pkg.brew.*` written to `~/.coily/audit/<repo>.jsonl` via cli-guard `config.DefaultAuditPath()`. - Reuses cli-guard `verb`, `audit`, `egress`, `exitcode`, `shell`; ward grows a minimal `Runner` (shell + audit writer), no coily import. ## Out of scope - Other package managers (npm/pip/cargo/...) - follow-up once brew lands. - A ward release - tracked separately; the new verb ships in the next ward tag. ## Context First consumer is the public board repo `otel-a2a-relay-ansible-debug` (deps install). Relates to the ward-adopter wiring in cli-guard#74. Supersedes the "ward never grows ops verbs" note in older `.ward/ward.yaml` comments - that constraint moved to the future `seed` template, per the cli-guard reflow.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
coilyco-flight-deck/ward#52
No description provided.