ops-mason/workplans/MASON-WP-0004-credential-inventory-descriptions.md
tegwick 28386d3b4c Rebuild Forgejo bundle from type 1.1; draft fluid-telegram custody descriptions
Bundle validates; ESO policy identical to applied CCR-2026-0041. Four
fluid-telegram entries drafted from the approved plan; email-connect asked
for its new path.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 327203@bnt-lap001
Assistant-Session: 55028ae3-4914-4bd1-8f5c-815f3527aef0
2026-10-10 15:12:56 +02:00

232 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
id: MASON-WP-0004
type: workplan
title: "Describe every stored credential so the store is navigable"
domain: infotech
repo: ops-mason
status: blocked
flavor: planning
owner: codex
topic_slug: custodian
created: "2026-08-28"
updated: "2026-10-03"
related:
- MASON-WP-0003
- NK-WP-0033
state_hub_workstream_id: "e5656747-a974-581a-a3d4-4e6bb7262f4c"
---
# Describe every stored credential so the store is navigable
## Goal
Give all 21 credential paths in `operators/` and `platform/workloads/` the five
`custom_metadata` fields the custody standard requires, so an operator can find
out what a credential is without reading it.
## Why this exists
`custody-inventory.py` reported 21 paths on 2026-08-28. Four carry descriptions
— the ones `MASON-WP-0003` touched. **Seventeen carry none.**
An undescribed credential is one nobody can identify without reading it, which
means orientation requires the very access the store exists to control. It also
means the two failure modes of the previous week stay available: no `used_by`
list, so a rotation misses a consumer the way privacyIDEA's resolver was missed
for four days; and no `on_loss` line, so recovery gets improvised under pressure
the way the LLDAP predecessor's did.
This is not urgent the way a broken login is urgent. It is the difference
between a secret store and a drawer of unmarked keys.
## What "described" means
Five fields, per `net-kingdom/docs/platform-root-custody.md`: `description`,
`owner`, `used_by`, `rotation`, `on_loss`. Metadata only — no path's value is
read, and `ops-mason-build` cannot read one.
## Establish owners before writing anything
```task
id: MASON-WP-0004-T01
status: done
decision_id: e9f44beb-ad15-4285-8996-1e66d312fe59
priority: medium
state_hub_task_id: "5bda75f2-f780-579e-9d44-cc4011662b9a"
```
Most of the seventeen predate this repository and ops-mason cannot invent what
they are for. Group them by mount prefix, propose an owning repo for each from
the ops-warden catalog and the paths themselves, and take the founder's ruling
on the ones that are genuinely unclear.
Guessing is the failure mode to avoid: a confidently wrong `used_by` is worse
than an empty one, because a rotation will trust it.
Acceptance: every one of the seventeen has a named owner, or is explicitly
listed as unknown with the question that would settle it.
2026-10-03: human gate routed to hub decision e9f44beb-ad15-4285-8996-1e66d312fe59 (D8: ops-mason plan approvals: unclear metadata paths and the live-survey plan) by CUST-WP-0075; resolving that decision raises C-40 here.
2026-10-09: live inventory under grant `claude-MASON-WP-0004-T01` (revoked
after): 49 paths, 45 undescribed (was 21/17 on 2026-08-28). Owner proposals in
`docs/credential-owner-proposals-2026-10-09.md`: 38 documented (owner from
catalog or CCR), 3 genuinely unclear (`activity-core/default/llm-connect-provider-secrets`,
`forgejo/forgejo-mailer`, `target-revenue/runtime-secrets`), and 4 undocumented
fluid-telegram entries under tenant `infotech` that conflict with the approved
MASON-WP-0005 plan (`coulomb`). Waiting on the founder's ruling for A and B.
2026-10-09 done: founder ruled. A: `coulomb` as approved, the four values move
there (MASON-WP-0005). B1: retire the duplicate `activity-core/default/...`
entry (founder-run delete via railiance-platform after a live no-grant check).
B2: `forgejo/forgejo-mailer` belongs to the new `rapp-forgejo` repo. B3:
`target-revenue/runtime-secrets` deferred as outdated. Every path now has a
proposed owner or an explicit reason, which is T01's acceptance.
## Describe the paths whose purpose is already documented
```task
id: MASON-WP-0004-T02
status: done
decision_id: 62aa95e4-3ccc-4867-8806-5e3db005b483
priority: medium
state_hub_task_id: "a6a944d7-21c5-5043-a78d-b3809de0ee64"
```
Several are covered by an existing ops-warden catalog entry, playbook, or
construction plan in `plans/` — `railiance/backup/*`, `rapp-qonto/*`,
`user-engine/runtime`, `reuse-surface/runtime-secrets` among them. For those the
five fields can be written from documents that already exist, with `rotation`
pointing at the real procedure rather than paraphrasing it.
Acceptance: `custody-inventory.py` reports these paths without a `!`, and each
`rotation` field names a document that exists.
2026-10-03: human gate routed to hub decision 62aa95e4-3ccc-4867-8806-5e3db005b483 (D1: Attended OpenBao provisioning window: one session clears the pending credential lanes) by CUST-WP-0075; resolving that decision raises C-40 here.
2026-10-09: drafted. `scripts/custody-describe.py draft` builds
`manifests/custody-descriptions.yaml` from the railiance-platform CCRs
(`target.purpose`, `delivery.target`, `lifecycle.rotate`), the ops-warden
catalog and the owner proposals, never from OpenBao; four ops-mason-sourced
entries were filled by hand from `plans/`. 29 of 38 have all five fields; 9
have gaps left empty on purpose (nextcloud x2, keycape-factor-issuer,
grafana-admin, smtp, and four `used_by`). Every entry is `review: draft`.
`apply` writes custom_metadata only, for `review: accepted` entries, silently
(`tests/test_custody_describe.py`, suite 157 passed). Founder run, after
review: `warden access openbao-platform-admin-login --exec -- sh -c 'python3
/home/worsch/ops-mason/scripts/custody-describe.py apply
/home/worsch/ops-mason/manifests/custody-descriptions.yaml >/dev/null 2>&1'`,
then read `~/.local/state/railiance/receipts/custody-describe.json`.
(First attempt 2026-10-09 refused by the wrapper because apply printed status
lines; nothing written, all entries were still drafts. apply is now silent.)
2026-10-09 founder runs 3-4: the wrapper has a temporary HOME and the admin
policy has no `patch` capability, so apply now writes its receipt under the
real home and falls back to metadata get + merged put. Run 4 receipt: 27 of 29
accepted entries `merged` (existing custom_metadata kept), 2 `failed put
http=400` (`core-hub/forgejo-source-read`, `secrets-engine/approval-client`):
`used_by` was 514 bytes, clipped by characters. Clipping is now by bytes; those
two need one more run.
2026-10-09 founder run 5: exit 0, receipt 29/29 accepted entries `merged`, 9
drafts `skipped`. Remaining for T02 acceptance: re-run custody-inventory under
a survey grant to confirm the 29 report without `!`. The 9 gaps go to owners
in T03.
2026-10-09 done: custody-inventory under grant `claude-MASON-WP-0004-T02`
(revoked after): 49 paths, 16 undescribed (from 45); none of the 29 accepted
paths is flagged, and the keycape entry kept its CCR-2026-0033 keys next to the
five new ones. Each `rotation` names an existing CCR file or document. The 16
left: the 9 drafts with gaps (T03), the four `infotech` fluid-telegram entries
(moving, MASON-WP-0005-T04), the retiring `activity-core/default` duplicate,
`forgejo/forgejo-mailer` (rapp-forgejo) and the deferred
`target-revenue/runtime-secrets`.
## Resolve the rest with their owners
```task
id: MASON-WP-0004-T03
status: wait
depends_on: [MASON-WP-0004-T01]
blocked_on: owners
blocking_reason: "Owners fill the gaps in manifests/custody-descriptions.yaml for the 9 draft entries (asked 2026-10-09)."
priority: low
state_hub_task_id: "fff26914-d854-5854-b350-d7241812fb04"
```
Blocked on T01. What remains after T02 are paths whose purpose is not written
down anywhere. Each needs its owner to answer three questions: what is this, what
breaks when it changes, and what do you do when it is lost.
A path whose owner cannot answer the third question is a finding in its own
right — it is a credential with no recovery story, and that is worth knowing
before it is lost rather than after.
Acceptance: `custody-inventory.py` exits 0 across both mounts, or the remainder
is a short list with a recorded reason each.
2026-10-09: asked railiance-platform (nextcloud x2, telemetry smtp,
grafana-admin, agent-harness deploy key, whynot-design npm-publish),
net-kingdom (keycape-factor-issuer) and key-cape (rapp-qonto keycape-client).
user-engine/runtime's `on_loss` is ops-mason's own to write from the
user-engine plan once its ESO rotation rehearsal is recorded.
2026-10-09: net-kingdom answered for `keycape-factor-issuer` (message
`75b48030`): four fields filled in the manifest; `rotation` stays empty because
no rotation document exists, a gap attributed to railiance-platform. The entry
stays a draft until that exists. railiance-platform retired the duplicate
`activity-core/default/llm-connect-provider-secrets` (message `af873813`), and
the four `infotech` fluid-telegram entries were moved to `coulomb`.
2026-10-10: answers filled into the manifest (still `review: draft`, awaiting
founder acceptance and an apply run): railiance-platform (message `3e490cd4`)
completed `operators/nextcloud/backup`, `railiance-telemetry/smtp`,
`telemetry/grafana-admin`, `agent-harness/forgejo-deploy-key` and
`whynot-design/npm-publish`; key-cape (message `40395cc2`) named the two readers
of `rapp-qonto/keycape-client` (the rapp-qonto runtime's transport is for
railiance-apps to name). Still open: `operators/nextcloud` (railiance-platform
is asking the founder what it holds), `keycape-factor-issuer` rotation
(railiance-platform gap) and `user-engine/runtime` on_loss (ops-mason, after
its rotation rehearsal).
2026-10-10: founder accepted the six and applied: 34 paths `merged`, 3 drafts
skipped. `operators/nextcloud/backup` failed with HTTP 403, under both the
admin wrapper and the founder's own session (`operator-custody`): metadata is
readable but neither patch nor put may write it. Asked railiance-platform
whether `operators/*` metadata is write-protected by design and who writes
descriptions there (message `6b08c40d`).
2026-10-10 inventory (same grant as WP-0009-T05): 49 paths, 11 undescribed.
New since the last run: the four fluid-telegram entries at the `coulomb` path
(moved, never described) and `email-connect/callers/user-engine`. Drafted the
fluid-telegram four from the approved plan (draft until fluid-telegram confirms,
message `da7e711c`); asked email-connect for its new path (message
`acb3ff22`).
## Make an undescribed path visible before it accumulates
```task
id: MASON-WP-0004-T04
status: wait
depends_on: [MASON-WP-0004-T03]
blocking_reason: "After T03. A scheduled --undescribed report needs an unattended metadata-read credential and a named reader; survey grants are human-minted and expire within an hour."
priority: low
state_hub_task_id: "9a0cea06-eb63-54ad-963d-db4ea79c7c66"
```
Blocked on T03. Seventeen accumulated because nothing ever looked. Wire
`custody-inventory.py --undescribed` into whatever already runs regularly
against this repo, so a new undescribed path is noticed in days rather than
discovered in a year.
The check must not fail a build for a path someone else owns; it reports, and
the report has a reader.
Acceptance: an undescribed path added today surfaces without anyone
remembering to look.
## Loose-end review — 2026-09-28
T01–T04 remain wait: no valid scoped metadata grant/current inventory or complete owner/recovery confirmations are available. Inventory failure handling and the private-tunnel defaults are fixed and tested; scheduled reporting still needs its reader and credential.
Evidence and precise resumption conditions: [review](../docs/evidence/2026-09-28-loose-end-review.md). Existing tasks retain all remaining obligations; no new task or workplan was opened.