openalice-vault
Architecture rating
JWT-gated identity surface + per-owner rate-limit (600 RPM default); RLS+FORCE on all 5 tables with SET LOCAL app.owner_id (injection-safe set_config); 0600 Ed25519 keyfile with perm check + zeroize-on-drop KMS; AAD-bound XChaCha20 bundle seal AND AES-256-GCM DEK wrap (transplant-reject tested); BlobStore rejects path traversal (3 test vectors); prod-secret boot guard panics on shipped dev defaults; cargo-deny gates advisories+licenses+sources; security-headers + normalize_errors middleware; internal error detail never leaked to client.
5-table schema with FK constraints (vault_versions/dek_meta/consent_records → identities), CHECK constraints on subject_kind + status enums, UNIQUE (identity_id,version); RLS owner policies on all 5 tables with idempotent FORCE toggle helpers and NOSUPERUSER/NOBYPASSRLS prerequisite documented; owner_user_id denormalized onto every child (no JOIN for policy eval); crypto-shred = NULL wrapped_dek + shredded_at + zero-overwrite blob delete (GDPR erasure); versioned migrations (0001_init + 0002_audit_signed_at binding timestamp into signed surface); UUIDv7 PKs.
~63 tests (55 inline unit + 8 DB-gated acceptance): crypto paths deeply covered (seal/open roundtrip, AAD-transplant rejection at both DEK-wrap and bundle-seal layers, tampered ciphertext, wrong key, nonce uniqueness); audit hash-chain tested for valid/tampered-core/tampered-timestamp/removed/reordered/forged-key; acceptance tests cover full seal→verify→shred lifecycle, RLS cross-owner isolation (alice vs mallory), version chaining with parent_hash, revoke-without-erasure, mandate-gated instantiation; boot-guard + vault-mode unit tests. Gap: no HTTP-level handler integration tests (api/mod.rs handlers untested at the HTTP boundary), acceptance gated behind TEST_DATABASE_URL.
Shares openalice-axum-common for CORS, rate-limit (TenantRateLimit), AuthUser/JwtVerifier, tracing init, HTTP metrics, security-headers, normalize_errors, shutdown, internal_client — mirrors openalice-tenants skeleton explicitly; consistent middleware layer ordering documented in router.rs; uniform {error:{code,message}} envelope; rustls-only posture (sqlx + reqwest); cargo-deny with org-standard config. Gaps: 85 missing docstrings, 7 god-module flags, duplicate error types (api::ApiError vs error::AppError both do status→JSON mapping).
Prometheus /metrics endpoint with HTTP latency+count middleware (bounded cardinality via MatchedPath); /health returns 200/503 with dep status JSON (postgres: ok/down); structured tracing with env-filter + OTEL span export when OTEL_EXPORTER_OTLP_ENDPOINT set; W3C traceparent propagation (propagate_incoming); INFO-level request spans. Missing: no custom business metrics (seal/shred counts), health probe doesn't report crypto subsystem readiness, no separate readiness vs liveness probe.
Graceful shutdown via with_graceful_shutdown(shutdown_signal()); pool acquire_timeout 5s (4..20 conns); boot-guard pattern — absent signing key or master key degrades to 503 on identity endpoints while /health stays live; kill switch (off/on/shadow) for incident response; blob write-before-insert prevents dangling rows; SET LOCAL tx-scoped owner context never leaks across pooled connections; idempotent RLS toggle. Gaps: no retry/backoff on transient DB errors, no explicit request-level timeout, no idempotency keys on create/seal (client retry could duplicate).
Excellent inline module docs (//! blocks on every module explaining purpose, security invariants, Alex §13 decisions, milestone scope); 2 @feature annotations (rate-limit, identity-custodian); migrations carry detailed schema/RLS design comments; cargo-deny thoroughly commented. Gaps: no README (Atlas readme_excerpt empty), no OpenAPI/Swagger spec, 85 missing function-level docstrings per inspector, only 2 registered features vs the full lifecycle surface, no architecture diagram.
source · auto-grader-2026-06-17
Code composition
tokei · loc- Rust93.4%
- TOML3.0%
- SQL2.9%
- Dockerfile0.7%
- Rust93.4%
- TOML3.0%
- SQL2.9%
- Dockerfile0.7%
- Rust93.4%· 3,309
- TOML3.0%· 108
- SQL2.9%· 102
- Dockerfile0.7%· 24
| Language | % code | code | comments | blanks | files |
|---|---|---|---|---|---|
| Rust | 93.4% | 3,309 | 199 | 373 | 24 |
| TOML | 3.0% | 108 | 74 | 12 | 2 |
| SQL | 2.9% | 102 | 69 | 19 | 2 |
| Dockerfile | 0.7% | 24 | 20 | 12 | 1 |
| Markdown | 0.0% | 0 | 115 | 22 | 1 |
Telemetry ribbon · last 90 days
7 eventsvault/crate
1 feature- vault.crate.identity-custodiansrc/lib.rs:3Rust/Axum service (port 3992) that seals, versions, and crypto-shreds per-owner *identities* — NOT a generic secrets store. Each identity is a signed, content-addressed bundle (manifest + encrypted blob), wrapped by a per-identity Data Encryption Key (DEK) that itself is KEK-wrapped. Crypto shred = drop the wrapped DEK → the blob is permanently unreadable. Owner isolation is enforced by Postgres Row-Level Security keyed on `app.owner_id` (see [`db`]); the app role MUST be NOSUPERUSER NOBYPASSRLS for FORCE RLS to bite (applied at boot via `VAULT_RLS_ENFORCE`). M1.1 ships the COMPILING skeleton: HTTP wire surface (health + 501-stub identity routes), the owner-scoped DB/RLS plumbing, and the schema. The crypto / bundle / store / audit / consent / api modules are STUBS — Tycho implements them in M1.2+.
vault/middleware
1 feature- vault.middleware.rate-limitsrc/main.rs:3Per-owner token-bucket rate limiter on /v1/identities/* (default 600 req/min ≈ 10 RPS, overridable via VAULT_RATE_LIMIT_PER_MINUTE). Guards against a runaway agent loop abusing a single owner's bearer while staying invisible to normal interactive use. Provided by openalice-axum-common::rate_limit. default-rpm: 600 Routes are split into: * `/health` — Traefik liveness probe. * `/metrics` — Prometheus scrape. * `/v1/identities/*` — owner-facing identity lifecycle (create, seal, versions, export, crypto-shred). M1.1: 501 stubs (see `router`). The identity handlers (crypto/store/audit-backed) land in M1.2+; for now they stub-respond 501 so the wire surface + RLS scaffold ship first.