feat: A.I.R. API layer — VaultNode operational stack#2
Conversation
- main.py: FastAPI app with lifespan DB pool, full interdiction logic wired to asyncpg. /event validates state transitions against ratified workflows, flags incidents on unauthorized transitions. - schema.sql: Five-table Postgres ledger (agents, sessions, workflows, events, incidents). Authoritative init script. - docker-compose.yml: Postgres 15-alpine container, schema mounted as init script, credentials sourced from .env (never hardcoded). - requirements.txt: Pinned deps — FastAPI 0.111, asyncpg 0.29, pydantic-settings 2.2. - .env.example: Credential template, safe to commit. - .gitignore: .env blocked from remote. CAGE: 17TJ5 | UEI: SVZVXPTM9AF4 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 27817fffd7
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| event.session_id, | ||
| ) | ||
|
|
||
| if row: |
There was a problem hiding this comment.
Reject events when no workflow is found
The interdiction check only runs inside if row, so when a session exists but has no matching workflow, the request skips validation and still inserts into events as "authorized." This creates a straightforward bypass where unratified sessions can commit transitions without incident logging, which undermines the core enforcement path described by this endpoint.
Useful? React with 👍 / 👎.
| valid_next = definition.get(event.state_before, []) | ||
| if event.state_after not in valid_next: | ||
| # Unauthorized transition — generate incident | ||
| incident_id = f"INC-{event.session_id}-{event.action}" |
There was a problem hiding this comment.
Make incident IDs unique per violation
Incident IDs are derived only from session_id and action, but inserts use ON CONFLICT (id) DO NOTHING, so multiple unauthorized transitions with the same action in one session are silently discarded after the first one. In practice this drops evidence of repeated drift and leaves the incidents ledger incomplete for exactly the cases this service is meant to audit.
Useful? React with 👍 / 👎.
A.I.R. — VaultNode Operational Stack
CAGE: 17TJ5 | UEI: SVZVXPTM9AF4
Summary
main.py— FastAPI app withlifespanDB pool (asyncpg). Full interdiction logic:/eventvalidates state transitions against ratified workflows, flagsincidentson unauthorized transitions, commits authorized events to ledger.schema.sql— Five-table Postgres ledger:agents,sessions,workflows,events,incidents. Authoritative init script mounted at container startup.docker-compose.yml— Postgres 15-alpine, schema mounted as init script, credentials from.envonly.requirements.txt— Pinned: FastAPI 0.111, asyncpg 0.29, pydantic-settings 2.2, uvicorn 0.29..env.example— Credential template, safe to commit..gitignore—.envpermanently blocked from remote.Architecture Notes
@app.on_event("startup")deprecated path avoided —lifespancontext manager used instead.Test plan
cp .env.example .env— populate passworddocker-compose up -d— verify Postgres init against schema.sqlpip install -r requirements.txt && uvicorn main:app --reload/workflow/event/incidentsmaster🤖 Generated with Claude Code