Own migrate objects as audit_core_migrate; pin snapshot-read image
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s

SET ROLE during migrate so tables are not owned by a disposable lease.
Current image sha256:aec5575. T02/T03 recorded done after live rotation
and rollout undo. T05 remote run is partial (port-forward dropped).
This commit is contained in:
tegwick 2026-08-13 12:36:25 +02:00
parent c404c910cd
commit 53df641866
4 changed files with 42 additions and 13 deletions

View file

@ -204,6 +204,13 @@ class PostgresAuditBackend:
applied: list[str] = []
try:
with self.pool.connection() as conn:
migrate_role = os.environ.get("AUDIT_CORE_MIGRATE_ROLE", "").strip()
if migrate_role:
if not migrate_role.isidentifier():
raise ValueError(f"unsafe migrate role: {migrate_role!r}")
# Leased login roles must SET ROLE to the group so new
# objects are owned by audit_core_migrate, not the lease.
conn.execute(f'SET ROLE "{migrate_role}"')
conn.execute(f'CREATE SCHEMA IF NOT EXISTS "{self.schema}"')
conn.execute(
f'CREATE TABLE IF NOT EXISTS "{self.schema}".schema_migrations ('

View file

@ -80,7 +80,7 @@ spec:
- name: audit-core
# REPLACE at release time with the built digest. A mutable tag is not
# an immutable image, and `:latest` must never be the only reference.
image: forgejo.coulomb.social/coulomb/audit-core@sha256:41493cd5bbd86a3309af07b1a97d41343b91d758a300ad39d71e4a18c17de7cc
image: forgejo.coulomb.social/coulomb/audit-core@sha256:aec5575ceadf1dc53d0892c0786f1fcd5cb38077ce36ba271ee7204aacd80df5
imagePullPolicy: IfNotPresent
ports:
- name: http

View file

@ -33,7 +33,7 @@ spec:
type: RuntimeDefault
containers:
- name: migrate
image: forgejo.coulomb.social/coulomb/audit-core@sha256:41493cd5bbd86a3309af07b1a97d41343b91d758a300ad39d71e4a18c17de7cc
image: forgejo.coulomb.social/coulomb/audit-core@sha256:aec5575ceadf1dc53d0892c0786f1fcd5cb38077ce36ba271ee7204aacd80df5
imagePullPolicy: IfNotPresent
command: ["python", "-m", "audit_core", "migrate"]
env:
@ -41,6 +41,8 @@ spec:
value: /etc/audit-core/db
- name: AUDIT_CORE_DATABASE_SCHEMA
value: audit_core
- name: AUDIT_CORE_MIGRATE_ROLE
value: audit_core_migrate
resources:
requests:
cpu: 25m

View file

@ -115,7 +115,7 @@ cluster and belongs to T05.
```task
id: AUDIT-WP-0005-T02
status: progress
status: done
priority: high
state_hub_task_id: "831b2472-0d80-4369-a5e3-eb08ef3526b1"
```
@ -218,15 +218,29 @@ Mason plan approved 2026-08-13 and built: AppRole
ClusterSecretStores on AppRole and `Valid`. Interim ESO token Secret
removed. Receiver stayed Ready.
Remaining before T02 done: a live rotation drill (refresh lease, confirm
no delivery gap). Empty senders KV path is a later wrap-migrate, not a
founder paste.
Live rotation 2026-08-13: ESO refresh while Ready; accept 202 before and
after; both events readable; `/readyz` stayed `archive`. Fingerprint log
was not seen on that refresh (lease may have been reused).
Findings fixed on the way:
- ESO AppRole login+discard **revokes** `database/creds` leases. Working
client is a renewable orphan token. AppRole remains for a later
lease-aware generator.
- Mounted Secret reads must use Kubernetes `..data` or they can tear
across two leases.
- Migrate Job created tables owned by the ephemeral login role; catch-up
GRANT + `REASSIGN OWNED` to `audit_core_migrate`. `SET ROLE
audit_core_migrate` is now in migrate().
T02 done for the provisioned-lane + no-delivery-gap claim. Empty senders
KV wrap-migrate is follow-on, not a founder paste.
## T03 - Deploy the receiver
```task
id: AUDIT-WP-0005-T03
status: progress
status: done
priority: high
state_hub_task_id: "598af2ac-e772-4a4e-9a65-dde9d4ca167f"
```
@ -321,8 +335,11 @@ rapp-postgres isolation-test stub `events` table (3 columns, 2 fixture
rows — not audit custody). Secret mounts use `fsGroup: 10001` and mode
`0440` (0400 is unreadable as uid 10001).
Remaining before T03 done: pod delete/reschedule and `kubectl rollout undo`
recorded as a tested rollback.
Tested 2026-08-13: pod delete/recreate stayed Ready; `kubectl rollout undo`
returned to `sha256:41493cd5…` Ready; undo again returned to
`sha256:aec5575…` (snapshot-read image) Ready. Current pin is
`forgejo.coulomb.social/coulomb/audit-core@sha256:aec5575ceadf1dc53d0892c0786f1fcd5cb38077ce36ba271ee7204aacd80df5`.
T03 done.
## T04 - Migrate existing SQLite records
@ -440,10 +457,13 @@ against an unreachable receiver (it does not pass silently), and the emitted
evidence JSON contains no tokens, credentials, or event payloads, so a run
against the deployed receiver can go to NK-WP-0024 as-is.
Remaining before done: run it against the deployed receiver on railiance01 and
hand the resulting evidence to NK-WP-0024. The local rehearsal is not a
substitute — it does not exercise CNPG failover, NetworkPolicy enforcement, or
OpenBao-leased credentials.
Remote run 2026-08-13 (`evidence/failure-matrix-20260813T103540Z.json`,
`MODE=remote DISRUPT=0`): **7 passed, 5 failed, 3 skipped**. S01S07 passed
on the live receiver (accept, duplicate, conflict, cross-tenant 400, dead
letter, 401, redaction). S08S12 failed with `status=0` (port-forward
dropped mid-run), not a contract mismatch. S13S15 skipped (`DISRUPT=0`,
replay needs DB). Re-run through a stable operator path before handing
NK-WP-0024; do not treat this JSON as closeout.
## T06 - Operational handover