Skip to content

feat(admin): deedkit admin key list and label; messaging and calendar key inventories (ANYM-494) - #281

Merged
egerev merged 4 commits into
mainfrom
feat/admin-cli-keys
Oct 24, 2026
Merged

egerev merged 4 commits into
mainfrom
feat/admin-cli-keys

Conversation

@egerev

@egerev egerev commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

Summary

deedkit admin key list (ANYM-494): one read-only view of every agent key. It shows one row per gateway principal with its messaging, calendar and calls credentials (public ID, expiry, live | revoked | expired | missing, unknown when a backend is unavailable) and the findings where the stores disagree. deedkit admin key label keeps labels in a private 0600 admin file that no service reads, so the policy schema stays the same.

  • messaging: list-keys --all (every key, public fields) and key-info --key-file (one token per line, max 100 / 64 KiB, input order, never a digest)
  • calendar: list-agents and agent-info --key-file (same contract)
  • scripts/deedkit_admin.py (new, stdlib only). scripts/deedkit.py admin routes to it. Template: deploy/admin.example.json
  • Docs: ACCESS.md (Key inventory), services/calendar/docs/SERVICE.md, docs/operations/production.md (Admin CLI)

Design choices:

  • messaging created_at = the earliest operator issue_key audit row, found by one aggregate scan of audit_log (there is no key_id index). It is null when no such row exists. The scan is bounded by the existing 5 s messaging statement timeout; on a very large audit_log the inventory call times out and only that backend's unbound_key findings are lost (backend_unavailable), the per-key lookups stay. No index is added here.
  • Findings cover every gateway principal, disabled and expired too. unbound_key covers every backend key no principal holds and carries its status. credential_pin_mismatch when a key file does not match the policy's key_sha256 (content-free). With --principal, backend_unavailable of a used backend stays, so --strict fails.
  • Key files reach the operator commands on stdin (--key-file /dev/stdin), never in argv or env. The calls registry is matched by sha256 in memory.
  • On a timeout or interrupt the CLI stops its own uniquely named container (docker stop, 30 s bound); calendar list-agents/agent-info run with a 5 s statement timeout. The one-shot container's stdout (public IDs only) sits in its Docker log until run --rm removes it (production.md).

Deployed-version compatibility: the host CLI needs messaging and calendar images built from this PR (the c4a7285 images lack list-keys --all, key-info, list-agents, agent-info). Until those are deployed it reports backend_unavailable. No schema, policy format, gateway or production.py change.

Spec

Spec: ANYM-494
Delivers: ANYM-494
Change path: AUTO+review (signal grep: only comment and test words such as secret and store.revoke; no section-2 item: no role SQL, permissions, compose, migration or ruleset)
Spec impact:

  • ANYM-10: keeps (additive read commands; existing behaviour unchanged) — Scoped agent credentials [anchor only] (flagged)
  • ANYM-11: keeps (additive read commands; existing behaviour unchanged) — Issue an account-scoped agent key [anchor only] (flagged)
  • ANYM-12: keeps (additive read commands; existing behaviour unchanged) — Narrow a principal's accounts, chats and permissions [anchor only] (flagged)
  • ANYM-13: keeps (additive read commands; existing behaviour unchanged) — Revoke an agent key [anchor only] (flagged)
  • ANYM-14: keeps (additive read commands; existing behaviour unchanged) — Authorize every request against current principal and key permissions [anchor only] (flagged)
  • ANYM-15: keeps (additive read commands; existing behaviour unchanged) — Content-free append-only audit log [anchor only] (flagged)
  • ANYM-18: keeps (additive read commands; existing behaviour unchanged) — Record a review of a message revision [anchor only]
  • ANYM-19: keeps (additive read commands; existing behaviour unchanged) — Read reviews with visibility and staleness [anchor only]
  • ANYM-21: keeps (additive read commands; existing behaviour unchanged) — MCP and REST agent gateway [anchor only] (flagged)
  • ANYM-24: keeps (additive read commands; existing behaviour unchanged) — Discover the caller's capabilities [anchor only] (flagged)
  • ANYM-30: keeps (additive read commands; existing behaviour unchanged) — anymsg command line entry point [anchor only] (flagged)
  • ANYM-34: keeps (additive read commands; existing behaviour unchanged) — Filter messages by account, chat, sender, time and direction [anchor only]
  • ANYM-37: keeps (additive read commands; existing behaviour unchanged) — Page through a chat's messages [anchor only] (flagged)
  • ANYM-38: keeps (additive read commands; existing behaviour unchanged) — Open a message with its surrounding context [anchor only] (flagged)
  • ANYM-39: keeps (additive read commands; existing behaviour unchanged) — Resolve a provider chat/message reference [anchor only]
  • ANYM-41: keeps (additive read commands; existing behaviour unchanged) — List visible chats [anchor only] (flagged)
  • ANYM-48: keeps (additive read commands; existing behaviour unchanged) — Pull message changes for a named consumer [anchor only] (flagged)
  • ANYM-49: keeps (additive read commands; existing behaviour unchanged) — Acknowledge processed updates [anchor only] (flagged)
  • ANYM-51: keeps (additive read commands; existing behaviour unchanged) — Get sync status per account and chat [anchor only] (flagged)
  • ANYM-56: keeps (additive read commands; existing behaviour unchanged) — Request a download grant for an attachment [anchor only] (flagged)
  • ANYM-57: keeps (additive read commands; existing behaviour unchanged) — Download bytes through a grant [anchor only] (flagged)
  • ANYM-59: keeps (additive read commands; existing behaviour unchanged) — Search files by name and content [anchor only] (flagged)
  • ANYM-65: keeps (additive read commands; existing behaviour unchanged) — Media storage admission and pause [anchor only] (flagged)
  • ANYM-80: keeps (additive read commands; existing behaviour unchanged) — Register an account with include/exclude/discover policy [anchor only]
  • ANYM-98: keeps (additive read commands; existing behaviour unchanged) — Replay a JSONL envelope file into the archive from the operator CLI [anchor only] (flagged)
  • ANYM-119: keeps (additive read commands; existing behaviour unchanged) — Create a consistent snapshot with a per-table manifest [anchor only] (flagged)
  • ANYM-121: keeps (additive read commands; existing behaviour unchanged) — Quarantine a restored database so it cannot collect, send or accept old keys [anchor only] (flagged)
  • ANYM-129: keeps (additive read commands; existing behaviour unchanged) — Install, migrate and serve the archive [anchor only] (flagged)
  • ANYM-130: keeps (additive read commands; existing behaviour unchanged) — Apply checksummed, serialized schema migrations [anchor only] (flagged)
  • ANYM-131: keeps (additive read commands; existing behaviour unchanged) — Initialise with synthetic demo accounts for a no-data trial [anchor only] (flagged)
  • ANYM-132: keeps (additive read commands; existing behaviour unchanged) — Serve the gateway with conservative network defaults [anchor only] (flagged)
  • ANYM-133: keeps (additive read commands; existing behaviour unchanged) — Run administration only from a local operator container [anchor only] (flagged)
  • ANYM-155: keeps (additive read commands; existing behaviour unchanged) — Publish original attachment readiness with occurrence provenance [anchor only] (flagged)
  • ANYM-174: keeps (additive read commands; existing behaviour unchanged) — Set an individual credential's permission ceiling [anchor only] (flagged)
  • ANYM-175: keeps (additive read commands; existing behaviour unchanged) — Opt-in idempotent text sending [anchor only] (flagged)
  • ANYM-176: keeps (additive read commands; existing behaviour unchanged) — Preview and persist formatted message intent [anchor only] (flagged)
  • ANYM-177: keeps (additive read commands; existing behaviour unchanged) — Explicitly permitted reviewed messenger operations [anchor only] (flagged)
  • ANYM-182: keeps (additive read commands; existing behaviour unchanged) — Durable key-owned passive subscriptions [anchor only] (flagged)
  • ANYM-186: keeps (additive read commands; existing behaviour unchanged) — Independent file readiness and processing failure events [anchor only] (flagged)
  • ANYM-196: keeps (additive read commands; existing behaviour unchanged) — Qualified conversation ordering and bound traversal [anchor only] (flagged)
  • ANYM-214: keeps (additive read commands; existing behaviour unchanged) — Explicit bounded original-download requests [anchor only] (flagged)
  • ANYM-217: keeps (additive read commands; existing behaviour unchanged) — Explicit scoped subscription consumption [anchor only] (flagged)
  • ANYM-218: keeps (additive read commands; existing behaviour unchanged) — Operator-registered signed subscription hints [anchor only] (flagged)
  • ANYM-219: keeps (additive read commands; existing behaviour unchanged) — Private principal-owned agent feedback [anchor only] (flagged)
  • ANYM-269: keeps (additive read commands; existing behaviour unchanged) — Awaiting-reply list_chats rows state each fact once, list 25 rows by default and stay within a size guard [anchor only] (flagged)
  • ANYM-274: keeps (additive read commands; existing behaviour unchanged) — A forwarded message carries its origin author, chat and time, and is never presented as the forwarder's own words [anchor only] (flagged)
  • ANYM-368: keeps (additive read commands; existing behaviour unchanged) — Provider events become agenda occurrences with explicit instants, stable refs and bounded recurrence expansion [anchor only] (flagged)
  • ANYM-371: keeps (additive read commands; existing behaviour unchanged) — Calendar REST and MCP requests are authenticated per call and share one argument, error and time-input contract, plan ev [anchor only] (flagged)
  • ANYM-372: keeps (additive read commands; existing behaviour unchanged) — Service storage keeps family membership, account identity, secrets and imported calendar timezones consistent [anchor only] (flagged)
  • ANYM-494: delivers — The owner sees every agent key in one list [named (Delivers)]
  • Unanchored: 3 file(s); sync B anchors them to ANYM-494: deploy/admin.example.json, scripts/deedkit.py, scripts/deedkit_admin.py
  • symbols: header-only: ACCESS.md, deploy/admin.example.json, docs/operations/production.md, services/calendar/docs/SERVICE.md
    Settle text: none
    Not built here: [open: live] one deedkit admin key list on production (after deploy, read-only).

Tests

  • tests/test_deedkit_admin_list.py (33, synthetic stores and fake runners: rows, filters, every finding, --strict, labels outside service files, no secret in output; r1 regressions: disabled/expired principals, revoked/expired unbound keys, --principal keeps backend failures, missing calls registry, pin mismatch, no self-sharing, inventory failure keeps lookups, container stop on timeout/interrupt, oversized/changing private file). The 16 r1 regression cases fail on the pre-fix script and pass on 395113b (local run).
  • tests/test_admin_key_inventory.py (messaging, DB), services/calendar/tests/service/test_agent_inventory.py (calendar, DB): the new commands print no token, digest or hash

Review

  • r1: Astra (gpt-6-astra, access): CHANGES_REQUESTED, 1 blocking, 4 major, 4 minor. Fixed in 395113b: 1 blocking (findings suppressed for disabled/expired principals and non-live unbound keys), 2 (--principal --strict passed on a backend failure; missing calls registry), 3 (policy pin not checked), 4 (self-sharing), 5 (timeout cleanup, calendar statement timeout), 6 (lookups kept on inventory failure; scan bound stated above), 7 (private reader truncation), 8 (container log egress documented), 9 (packet: no product-context projection read; inputs were the card text and the diff).
  • r2: Astra (gpt-6-astra) scoped recheck of the blocking access finding: findings 1-9 CLOSED; 0 blocking, 0 major, 2 new minors (a malformed policy pin crashed the listing; a renamed test), both fixed in b0a237d (minors after the round cap, no further round).

Model: claude-opus-5-5 high

🤖 Generated with Claude Code

egerev and others added 4 commits October 24, 2026 17:03
…ll/key-info; calendar list-agents/agent-info (ANYM-494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: egerev <egor@gosync.ai>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: egerev <egor@gosync.ai>
…olicy pin, keeps backend-wide findings under --principal, stops its own container on timeout (ANYM-494)

Astra r1 findings 1-8: findings for disabled/expired principals and revoked/expired unbound keys;
credential_pin_mismatch; backend_unavailable kept with --principal and for a missing calls
registry; shared_credential needs two principals; docker stop of the invocation's container on
timeout/interrupt and a 5 s statement timeout on the calendar reads; a failed inventory keeps the
lookups; read_private refuses oversized or changed files; container log egress documented.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: egerev <egor@gosync.ai>
…ep the original test name (ANYM-494)

Astra r2 minors.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: egerev <egor@gosync.ai>
@egerev
egerev force-pushed the feat/admin-cli-keys branch from b0a237d to 2618168 Compare October 24, 2026 09:03
@egerev
egerev enabled auto-merge October 24, 2026 09:04
@egerev
egerev added this pull request to the merge queue Oct 24, 2026
Merged via the queue into main with commit b61f412 Oct 24, 2026
27 checks passed
@egerev
egerev deleted the feat/admin-cli-keys branch October 24, 2026 09:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant