Plan ILIB-WP-0003: unattended OpenBao AppRole lane for the library mailbox.

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

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 1170398@bnt-lap001
Assistant-Session: 622cd705-cb31-4322-ba08-dd42e44fa583
This commit is contained in:
tegwick 2026-10-05 11:42:07 +02:00
parent d05d6ed35b
commit 15df3d7e52
2 changed files with 151 additions and 1 deletions

View file

@ -158,7 +158,8 @@ Done 2026-10-05: `run-due` runs under a lock. The systemd units are in `ops/syst
```task
id: ILIB-WP-0002-T07
status: todo
status: wait
blocking_reason: "Needs the unattended OpenBao AppRole lane (ILIB-WP-0003)."
priority: high
state_hub_task_id: "1e2ab60c-86ef-5e1c-9b94-1f9f1b3182ba"
```
@ -195,3 +196,7 @@ version 2.
2026-10-05: the founder reports that the entry was created and `IMAP_PASSWORD`
was added. This is not yet verified natively. A live read-only scan is still
needed for acceptance.
2026-10-05: the founder rejected an env file as a credential cache. The live
credential now comes from an ops-mason AppRole lane, fetched on every run
(ILIB-WP-0003). This task completes with ILIB-WP-0003-T06.

View file

@ -0,0 +1,145 @@
---
id: ILIB-WP-0003
type: workplan
title: "Read the library IMAP credential unattended from OpenBao"
domain: infotech
repo: inbound-library
status: active
flavor: implementation
owner: claude
topic_slug: custodian
created: "2026-10-05"
updated: "2026-10-05"
---
# Read the library IMAP credential unattended from OpenBao
The timer must read `library@coulomb.social` without an operator and without a
copy of the password cached on disk. The ecosystem already has the pieces; this
workplan uses them and does not build new infrastructure.
- **ops-mason** builds OpenBao AppRoles, policies and KV path structure from a
construction plan (`plans/<id>.md`). The plan goes from draft to reviewed, then
to approved (by the founder, from its executive summary), then built, then
catalogued. The build refuses to run unless the approved spec digest matches
the execution inputs. AppRole credentials go to private, exclusive files, and
the build is written to ops-mason's own audit trail. `AppRoleKVSpec` already
generates this shape.
- **ops-warden** routes to the lane through a pointer-only catalog entry
(`registry/routing/catalog.yaml`). It never holds the value.
- Precedents: `rein-openweights-openrouter-approle` and
`agent-harness-binky-mail` (an unattended AppRole on the workstation), and
`rein-aharness/mailscan.py` (an AppRole login followed by an IMAP scan).
Audit trail: the approved construction plan holds the decision and its reasoning,
and the approved digest binds that decision to what was built. ops-mason's build
evidence and audit log record the execution. The warden catalog commit records
the routing. The KV entry `platform/workloads/inbound-library/imap` itself was
created by `railiance-platform/scripts/inbound_library_imap_entry.py`
(docs/inbound-library-imap-custody.md).
## Draft the ops-mason construction plan
```task
id: ILIB-WP-0003-T01
status: todo
priority: high
```
Write `ops-mason/plans/inbound-library-imap-approle.md`, with demand source
ILIB-WP-0002-T07 and `credential_type: openbao-approle-kv`. Proposed shape:
- policy `workload-kv-read-inbound-library-imap`, read only, on
`platform/data/workloads/inbound-library/imap`;
- AppRole `inbound-library`, following the precedent: `token_ttl` 15m,
`token_max_ttl` 30m, and an explicitly bounded `token_num_uses`;
- delivery to `~/.local/inbound-library/approle/` (`role_id`, `secret_id`);
- `secret_id_ttl` to be decided in review.
Include the section 2 existing-structure survey (live `bao` policy, auth and
secrets lists, and the warden catalog), the phase 2 self-review, and the build
spec with its digest.
Acceptance: the plan reaches status `reviewed` and its executive summary is
rendered.
## Founder approval
```task
id: ILIB-WP-0003-T02
status: todo
priority: high
```
The founder decides from the executive summary. The plan then records
`approved_by`, `approved_at` and `approved_spec_sha256`.
Acceptance: the plan is `approved`. The digest matches the build spec.
## Build the lane
```task
id: ILIB-WP-0003-T03
status: todo
priority: high
```
Run the ops-mason AppRole builder from the approved plan, in an attended
platform-admin session. It creates the policy and the AppRole and delivers
`role_id` and `secret_id` to private files. Then record capabilities-safe
evidence: the lane token can read the path, a default-policy token is denied,
and no value is printed. Append section 6 with the build result.
Acceptance: the plan is `built`, and the evidence is in ops-mason
`docs/evidence/`.
## Fetch the credential on every run
```task
id: ILIB-WP-0003-T04
status: todo
priority: high
```
In `inbound_library`, add a standard-library OpenBao client:
- an AppRole login using the delivered files;
- one KV v2 read of `IMAP_USERNAME`, `IMAP_PASSWORD`, `IMAP_HOST`, `IMAP_PORT`
and `IMAP_FOLDER`;
- values held in memory for one run only, never logged, never written to disk.
The bao address, the AppRole directory and the KV path go in
`config/library.json`. The environment variables remain only as an explicit
override for tests. When OpenBao is unreachable, `run-due` reports
`credential_unavailable`, and matching and notices still run. Remove the
`EnvironmentFile` from the service unit.
Acceptance: the tests use a fake OpenBao (login, read, denied, unreachable).
No secret appears in any output.
## Route the lane in ops-warden
```task
id: ILIB-WP-0003-T05
status: todo
priority: medium
```
ops-mason proposes a pointer-only catalog entry `inbound-library-imap-approle`
(`warden_executes: false`) and a playbook, modelled on
`rein-openweights-openrouter-approle`.
Acceptance: `warden access` resolves the need to this lane.
## Live verification
```task
id: ILIB-WP-0003-T06
status: todo
priority: high
```
Install the timer and trigger one run through systemd. The journal must show an
AppRole login and a read-only scan of `library@coulomb.social`, with no secret
in the output. This also completes ILIB-WP-0002-T07.
Acceptance: one real mail is retained with provenance. No mailbox state changes,
and no credential file exists other than the AppRole delivery.