Implement WP-0022 audit trail and WP-0023 INTENT–SCOPE closeout
Add unified metadata-only audit.jsonl with secret-material guard, instrument sign/access/worker paths, and expose warden activity CLI. Surface broker hint when VAULT_TOKEN is unset, refresh INTENT/SCOPE docs, and add production integration checklists plus catalog lane promotion playbook.
This commit is contained in:
parent
f47d632d8e
commit
d6088e4e16
18 changed files with 875 additions and 59 deletions
|
|
@ -39,6 +39,11 @@ worker_app = typer.Typer(
|
|||
no_args_is_help=True,
|
||||
)
|
||||
app.add_typer(worker_app, name="worker")
|
||||
activity_app = typer.Typer(
|
||||
help="Unified metadata-only audit view (WARDEN-WP-0022)",
|
||||
no_args_is_help=True,
|
||||
)
|
||||
app.add_typer(activity_app, name="activity")
|
||||
|
||||
console = Console()
|
||||
err = Console(stderr=True)
|
||||
|
|
@ -1237,6 +1242,55 @@ def worker_approve(
|
|||
raise typer.Exit(1)
|
||||
|
||||
|
||||
@activity_app.callback(invoke_without_command=True)
|
||||
def activity_show(
|
||||
days: Annotated[int, typer.Option("--days", help="Look back N days")] = 7,
|
||||
kind: Annotated[
|
||||
Optional[str],
|
||||
typer.Option("--kind", help="Filter: sign, access, worker, hub"),
|
||||
] = None,
|
||||
output_json: Annotated[bool, typer.Option("--json", help="Output JSON")] = False,
|
||||
include_hub: Annotated[
|
||||
bool, typer.Option("--hub", help="Include State Hub progress notes")
|
||||
] = False,
|
||||
) -> None:
|
||||
"""Show what ops-warden did recently (metadata only — no secret values)."""
|
||||
from warden.audit import collect_activity, fetch_hub_notes
|
||||
|
||||
cfg = _load_cfg()
|
||||
kinds = {kind} if kind else None
|
||||
events = collect_activity(cfg.state_dir, days=days, kinds=kinds)
|
||||
if include_hub and (kinds is None or "hub" in kinds):
|
||||
events.extend(fetch_hub_notes(days=days))
|
||||
events.sort(key=lambda e: str(e.get("ts", "")))
|
||||
|
||||
if output_json:
|
||||
print(json.dumps(events, indent=2))
|
||||
return
|
||||
|
||||
if not events:
|
||||
console.print(f"No activity in the last {days} day(s).")
|
||||
return
|
||||
|
||||
table = Table(title=f"ops-warden activity (last {days} days)")
|
||||
table.add_column("When", style="dim")
|
||||
table.add_column("Kind")
|
||||
table.add_column("Action")
|
||||
table.add_column("Subject")
|
||||
table.add_column("Target")
|
||||
table.add_column("Outcome")
|
||||
for event in events:
|
||||
table.add_row(
|
||||
str(event.get("ts", ""))[:19],
|
||||
str(event.get("kind", "")),
|
||||
str(event.get("action", "")),
|
||||
str(event.get("subject", ""))[:24],
|
||||
str(event.get("target", ""))[:28],
|
||||
str(event.get("outcome", "")),
|
||||
)
|
||||
console.print(table)
|
||||
|
||||
|
||||
@worker_app.command("status")
|
||||
def worker_status_cmd() -> None:
|
||||
"""Show worker state: pending drafts, triage count, last digest, timer status."""
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue