add 0032/SESSION-0032.0-TRANSCRIPT-2026-05-28T18-52--2026-05-28T19-13.md + replace placeholder/variant SESSION-0032.0-TRANSCRIPT-2026-05-28T18-52--INPROGRESS.md

This commit is contained in:
Ben Stull
2026-05-28 19:15:58 -07:00
parent 073db8a8e3
commit fca17122fc
2 changed files with 249 additions and 48 deletions
@@ -0,0 +1,249 @@
# Session 0032.0 — Transcript
> Date: 2026-05-28
> Start: 2026-05-28T18-52 (PST implied) · End: 2026-05-28T19-13
> Goal: Clear the two Session-0030 leftovers — harden OHM SSH to IAP-only
> (audit-0026 L5/L9) and ship flotilla v1.2.0 — plus the minor leftovers
> (audit I3/I4 as rfc-app v0.28.0, and the orphaned VM db files).
>
> Outcome: **All four tasks landed. OHM SSH is now IAP-only (L5 closed,
> L9 residue retired); the VM was re-verified healthy end-to-end through
> flotilla's own SSH path. flotilla v1.2.0 was found already merged +
> tagged by parallel session 0031 — independently re-verified (184 tests,
> both L1-redaction and v1.2.0 verbs coexist), no new PR needed. Orphaned
> `ohm-app.db\r*` files deleted (confirmed orphaned). rfc-app v0.28.0
> (audit I3 + I4) opened as PR #2 for the operator to merge + tag +
> deploy.**
---
## Plan / TODO
- [x] Claim session ID (→ 0032), read SESSION-PROTOCOL.md + audit-0026.
- [x] Task 2 — flotilla v1.2.0 merge (turned out: already done by 0031; verify).
- [x] Task 1 — IAP SSH hardening (additive → verify → delete → flip → re-verify).
- [x] Task 4 — rm orphaned VM db files (confirm orphaned first).
- [x] Task 3 — rfc-app v0.28.0 (audit I3 + I4) as a PR.
- [x] Finalize + publish transcript (this file).
---
## Pre-session state
- **flotilla** (`/Users/benstull/projects/wiggleverse/ohm-rfc-app-flotilla`):
local `main` == `origin/main` == `ef34ffe` (already the v1.2.0 merge
commit), tag `v1.2.0` present locally + on remote (`cae3fda``ef34ffe`).
A leftover **locked** worktree `agent-ab800baf41f74f86d` (c8804a6) from
another session sat in `.claude/worktrees/`.
- **rfc-app** (`/Users/benstull/git/rfc-app`): `main` == `fe044ed`
(Release v0.27.0 merge), clean. Latest tag `v0.27.0`.
- **OHM live**: HTTP 200, `version=0.27.0`, `status=ok`. ohm-rfc pin =
`0.27.0`.
- **GCP** `wiggleverse-ohm`: firewall had `default-allow-ssh` (0.0.0.0/0
→ tcp:22), no `default-allow-rdp`. IAP API **not** enabled. `ben.stull`
= `roles/owner` + secretmanager admin/accessor; no IAP binding.
- **Other live sessions** at claim time (from `claim-session-id.sh`):
`0026.0` and `0027.0` still `--INPROGRESS`. This drove the
isolated-worktree discipline for every hands-on git step.
---
## Turn-by-turn arc
### Arc 1 — Claim + orient
Claimed session **0032** via `claim-session-id.sh --start 2026-05-28T18-52
--prompt-file …` (pushed the placeholder; clean claim at 073db8a). Read
`SESSION-PROTOCOL.md` and `SECURITY-AUDIT-0026-2026-05-28.md` end to end.
Skimmed (did not fully read) the 2245-line ROADMAP — the launch prompt
fully specified the work. Relevant audit findings: **L5** (SSH+RDP world-
open), **L9** (`ssh.py --quiet` TOFU), **L1** (phase-detail redaction —
the flotilla merge conflict), **I3** (dead HTML-email branch), **I4**
(sync Turnstile siteverify).
### Arc 2 — Task 2: flotilla v1.2.0 (already merged by 0031; verify-only)
Inspecting topology revealed `trial-merge-v1.2.0` is fully contained in
`main`; `main` == `origin/main` == `ef34ffe` == tag `v1.2.0`, all pushed.
The reflog showed two `merge origin/main: Fast-forward` hops — a parallel
session (**0031**, branch `session-0031/merge-v1.2.0`, since deleted from
the remote) had already performed the 3-way merge, pushed to `main`, and
tagged `v1.2.0`. So the "stuck branch" the launch prompt described was
resolved before this session opened.
Rather than trust it, **independently verified** the merge kept both
changes: created an isolated detached worktree at `/tmp/flotilla-verify-0032`
(`git worktree add --detach v1.2.0`) with its own venv, `pip install -e .`
+ pytest. Confirmed in `deploy.py` `_PhaseRunner.run` that **all three**
detail paths — `_PhaseFailure` (line 251), `ssh.SshError` (275), and the
success path (285) — apply `self._redact(...)` (the **L1** live-redaction),
*and* the v1.2.0 `except ssh.SshError` robustness branch + preflight probe
are present. The L1 redaction test (`test_deploy.py:278`) explicitly
asserts secret bytes are absent from persisted `deploys.phases` detail and
iterates every phase. **184 tests passed.** Removed the verify worktree.
No new PR — Task 2 was already shipped by 0031; this session's value was
the independent re-verification.
### Arc 3 — Task 1: IAP SSH hardening (L5 + L9)
Confirmed there is **no** `default-allow-rdp` rule in this project (the
audit's L5 RDP half doesn't apply here) — SSH was the only world-open rule.
Did the additive steps first (none remove access):
1. `gcloud services enable iap.googleapis.com` (was disabled).
2. Created firewall rule **`allow-iap-ssh`** (INGRESS, ALLOW tcp:22,
source `35.235.240.0/20`).
3. Granted `ben.stull@wiggleverse.org` **`roles/iap.tunnelResourceAccessor`**
(explicit, even though `roles/owner` already implies it — hygiene for a
future least-priv reduction per audit L6).
**Verified IAP SSH BEFORE removing anything** (the operator's hard gate):
`gcloud compute ssh ohm-rfc-app --tunnel-through-iap --command …`
`hostname=ohm-rfc-app`, `whoami=ben_wiggleverse_org` (OS Login),
`ohm-rfc-app.service active`. Only then **deleted `default-allow-ssh`**
(0.0.0.0/0). SSH ingress is now IAP-only.
Flipped the flotilla deployment record:
`flotilla deployment update ohm-rfc-app --vm-tunnel-through-iap`
`target_vm_tunnel_through_iap=True`. **Re-verified end-to-end through
flotilla's own code path** (not just gcloud): a small script built an
`ssh.SshTarget` from the live registry record (so `tunnel_through_iap`
flowed through `ssh.py`, which appends `--tunnel-through-iap` at line 90)
and ran `ssh.run_remote(...)` → returncode 0, `service active`. A real
`flotilla deploy` would now succeed via IAP. `flotilla deploy status`
HTTP 200 v0.27.0 ok (HTTP path unaffected). **L5 closed; L9 first-connect
TOFU residue retired** (PR #1 had already swapped the bare `--quiet` TOFU
for `StrictHostKeyChecking=accept-new`; IAP now removes the first-connect
exposure entirely).
### Arc 4 — Task 4: orphaned VM db files
With IAP SSH warm, inspected `/opt/ohm-rfc-app/backend/data/` (dir is
`750 ohm-rfc-app` — consistent with **M3** already remediated; files are
mode `640`, no longer the audited 644). The data dir held the live trio
(`ohm-app.db` / `-shm` / `-wal`, May 29, held open by the service MainPID
3287 per `/proc/<pid>/fd`) plus three stale files dated May 28 04:01.
A `find -name '*[[:cntrl:]]*'` matched **zero** files, and `od -c` showed
the stale names contain a **literal backslash-`r`** (two ASCII chars
`\` `r`), **not** a carriage return — exactly the `ohm-app.db\r*` the
launch prompt named. Confirmed orphaned three ways: not in the service's
open fds, stale mtime, and the anomalous backslash in the name. To delete
safely without backslash-quoting hazards through gcloud→shell→find, used a
**time-based predicate** (`! -newermt '2026-05-29 00:00:00'`), dry-ran it
(matched exactly the 3 orphans, none of the live trio), then re-ran with
`-delete`. Re-listed: only the live trio remains. `deploy status` → 200 ok.
### Arc 5 — Task 3: rfc-app v0.28.0 (audit I3 + I4)
Isolated worktree `/tmp/rfc-app-v0280-0032` on new branch
`feature/v0.28.0-email-turnstile-async` (own venv from
`backend/requirements.txt` + pytest). Baselined the turnstile (5) and
email_envelope (15) tests green first.
- **I3** — `email_envelope.build_envelope`'s `body_html` branch is dead
(the only caller was a test; no production path passes it). Replaced the
`multipart/alternative` rendering with a loud guard: `body_html is not
None``raise NotImplementedError`, with a comment tying it to the C1
stored-XSS class in the mail channel. Kept the arg for documented future
symmetry. Flipped the test to assert the guard + added a `body_html=None`
boundary test.
- **I4** — made `turnstile.verify_token` `async`, awaiting
`httpx.AsyncClient`. **Dead end:** first cut had the test monkeypatch the
global `httpx.AsyncClient`, which broke app boot (gitea/docs/TestClient
also construct `AsyncClient`) — 4 tests failed. Fixed by isolating the
call behind a narrow `async _siteverify_post(url, data)` seam and patching
*that* in tests. Updated the sole caller (`main.py`) to `await`. Added a
coroutine-contract unit test.
Bumped `VERSION`→0.28.0 + mirrored `frontend/package.json`; wrote the
CHANGELOG entry (no-op upgrade steps). **Full backend suite: 365 passed.**
Committed as `Release v0.28.0`, pushed the branch, and opened **PR #2**
(`ben.stull/rfc-app/pulls/2`) via the gitea API using the host's cached
git credential (never printed). Removed the worktree.
---
## Cut state (end of session)
| | |
| --- | --- |
| flotilla | `main`/`origin/main` = `ef34ffe`, tag `v1.2.0` (merged+tagged by session 0031; re-verified here, 184 tests). No change this session. |
| rfc-app | `main` = `fe044ed` (v0.27.0). Branch `feature/v0.28.0-email-turnstile-async` = `79a447c` pushed; **PR #2 open** (awaiting operator merge+tag+deploy). |
| OHM live | `deploys` unchanged, **HTTP 200 v0.27.0 status=ok** before and after all infra changes. |
| ohm-rfc pin | `0.27.0` (unchanged; bumps to 0.28.0 only after the operator deploys PR #2). |
| GCP firewall | `default-allow-ssh` **deleted**; `allow-iap-ssh` (35.235.240.0/20→tcp:22) added. SSH is IAP-only. |
| GCP IAM | `ben.stull` granted `roles/iap.tunnelResourceAccessor`; IAP API enabled. |
| flotilla record | `ohm-rfc-app.target_vm_tunnel_through_iap = True`. |
| VM data dir | orphaned `ohm-app.db\r*` (×3) deleted; live trio intact, mode 640. |
| Ledger | Status |
| --- | --- |
| Task 1 — IAP SSH hardening (L5 + L9) | ✅ shipped + re-verified |
| Task 2 — flotilla v1.2.0 | ✅ (shipped by 0031; independently re-verified) |
| Task 3 — rfc-app v0.28.0 (I3 + I4) | 🟡 PR #2 open — operator merges + tags + deploys |
| Task 4 — orphaned VM db files | ✅ deleted |
---
## §19.2 / process candidates surfaced
1. **No lightweight SSH-only flotilla verb.** Re-verifying the deploy SSH
path end-to-end required a hand-rolled `ssh.run_remote` script because
the only verb that SSHes is a full, service-restarting `deploy` (the
`deploy status/watch/reconcile` subverbs are HTTP-only). A
`flotilla deploy preflight` / `ssh-check <deployment>` verb (read-only
remote probe through the configured SSH path) would make IAP-style
cutovers and connectivity checks first-class instead of ad-hoc.
2. **Parallel-session merge already done.** Session 0031 completed Task 2's
merge + tag while this session was being launched, so the launch prompt
was stale on arrival. Reinforces the value of the `--INPROGRESS`
live-session signal and of *verifying before redoing* — but a session
that hadn't checked could have re-merged and produced a divergent tag.
---
## What lands on the operator's plate
1. **Merge + tag + deploy rfc-app v0.28.0** — review PR #2
(`ben.stull/rfc-app/pulls/2`), merge, `git tag v0.28.0`, then
`flotilla deploy ohm-rfc-app` (now over IAP) and bump
`ohm-rfc/.rfc-app-version` to `0.28.0`. No migration/secret/overlay
change; plain code deploy.
2. **IAP is now load-bearing for all VM access.** Any manual SSH MUST use
`--tunnel-through-iap`; the operator keeps `roles/iap.tunnelResourceAccessor`.
If ever locked out, re-add the firewall rule via gcloud (no SSH needed)
or use the serial console.
3. **Leftover locked flotilla worktree** `agent-ab800baf41f74f86d` in
`.claude/worktrees/` belongs to another session — left untouched; clear
it if that session is dead.
---
## Prompt the operator can paste into the next Claude Code session
```
OHM driver session. This session reserves its own ID at start
(claim-session-id.sh) — the number below is advisory.
State as of session 0032 (2026-05-28):
- OHM live = rfc-app v0.27.0, HTTP 200 ok. ohm-rfc pin = 0.27.0.
- OHM VM SSH is now IAP-ONLY (audit-0026 L5 closed, L9 residue retired).
Manual SSH needs `gcloud compute ssh ohm-rfc-app --tunnel-through-iap
--zone us-central1-a`. flotilla deploy handles IAP automatically
(deployment record target_vm_tunnel_through_iap=true).
- flotilla v1.2.0 is merged + tagged (done by session 0031, re-verified
by 0032).
Open item:
- rfc-app v0.28.0 (audit-0026 I3 dead-HTML-email guard + I4 async Turnstile
siteverify) is PR #2 (ben.stull/rfc-app/pulls/2), backend suite 365 green,
no-op upgrade. If not yet merged: review + merge + `git tag v0.28.0` +
`flotilla deploy ohm-rfc-app` + bump ohm-rfc/.rfc-app-version to 0.28.0.
Then pick up the ROADMAP (~/git/ohm-rfc/ROADMAP.md) — the audit-0026
Critical/High/Medium remediations already shipped in v0.27.0; remaining
audit items are the Low/Info tail. Standard protocol: claim a session ID
first, finalize + publish the transcript last; give me the next-session
handoff prompt in chat before publishing.
```
@@ -1,48 +0,0 @@
# Session 0032.0 — Transcript
> Date: 2026-05-28
> Start: 2026-05-28T18-52 (PST implied)
> Status: **PLACEHOLDER — claimed at session start; finalized at session end.**
>
> This file reserves session ID 0032. The driver replaces this body
> with the full transcript before publishing, and renames the file to
> its final SESSION-0032.0-TRANSCRIPT-2026-05-28T18-52--<end>.md form.
---
## Launch prompt
```
OHM driver session. Two infra/cleanup threads left over from Session 0030
(which fully remediated security-audit-0026 and shipped rfc-app v0.27.0 +
flotilla PR #1 — all live on prod; see SESSION-0030.0 transcript in
ohm-session-history for context).
Task 1 — Harden OHM SSH via IAP (§19.2; closes audit-0026 L5 + retires the
L9 first-connect-TOFU residue):
- Project wiggleverse-ohm, VM ohm-rfc-app, zone us-central1-a.
- Add an IAP firewall rule (source 35.235.240.0/20 → tcp:22), grant the
operator roles/iap.tunnelResourceAccessor.
- VERIFY `gcloud compute ssh ohm-rfc-app --tunnel-through-iap` works
BEFORE removing anything.
- Only then delete the `default-allow-ssh` 0.0.0.0/0 rule, and flip the
flotilla deployment to IAP: set tunnel_through_iap=true on the
deployment record + confirm the deploy ssh path uses --tunnel-through-iap.
- Re-verify a deploy/ssh still works end-to-end after the cutover.
Task 2 — Resolve the stuck `trial-merge-v1.2.0` branch in the flotilla repo
to ship flotilla v1.2.0 (session 0028's PR):
- It conflicts with the L1 redaction change in `_PhaseRunner.run`
(deploy.py) — both edited the same block. Do a proper 3-way merge that
KEEPS BOTH: the live-redaction wrapping of phase detail AND v1.2.0's
deploy-robustness / record-maintenance verbs.
- IMPORTANT: do the merge in an ISOLATED git worktree with its own venv,
NOT the shared flotilla checkout.
- Ship as a PR (operator merges + tags), matching the repo convention.
Minor leftovers if time: audit-0026 I3 (dead text/html email branch in
email_envelope.py) and I4 (turnstile.py siteverify async) — small v0.28.0.
And VM: sudo rm orphaned /opt/ohm-rfc-app/backend/data/ohm-app.db\r* files
once confirmed orphaned.
```