[package]
name = "assay-vault"
version = "0.2.0"
categories = ["cryptography", "asynchronous", "database"]
edition = "2024"
keywords = ["vault", "secrets", "kv", "transit", "biscuit"]
license = "Apache-2.0"
repository = "https://github.com/developerinlondon/assay"
description = "Vault module for assay-engine: KV v2, transit, dynamic credentials, Bitwarden-aligned vaults + collections + items + folders, biscuit-attenuated share links, sealing (Shamir / cloud KMS / HSM), audit forwarding, and a Bitwarden-protocol compat shim. PG18 + SQLite, both first-class."

[features]
# Default builds: full vault meta-feature plus both backends. The
# fine-grained submodule flags exist so a slim downstream binary can
# opt out of individual surfaces without touching the engine wiring.
default = [
  "vault",
  "backend-postgres",
  "backend-sqlite",
]

# Meta-feature pulling every default-on submodule. Mirrors the shape
# of assay-auth's `auth` umbrella feature. PKCS#11-backed sealing
# (`vault-sealing-hsm`) is intentionally NOT in the umbrella — most
# operators don't have an HSM and the cryptoki dep is heavy.
vault = [
  "vault-kv",
  "vault-transit",
  "vault-collections",
  "vault-share",
  "vault-sealing-shamir",
  "vault-sealing-kms",
  "vault-audit-forwarding",
  "vault-bitwarden-compat",
  "vault-dynamic-postgres",
  "vault-dynamic-aws",
  "vault-dynamic-gcp",
  "vault-dynamic-kubernetes",
]

vault-kv = []
vault-transit = []
vault-collections = []
vault-share = ["dep:biscuit-auth"]
vault-sealing-shamir = ["dep:sharks"]
vault-sealing-kms = ["dep:reqwest", "dep:hmac", "dep:jsonwebtoken"]
# Opt-in: requires a PKCS#11 device and the `cryptoki` dep. Phase 2
# wires the actual implementation; Phase 0 just reserves the flag.
vault-sealing-hsm = []
vault-audit-forwarding = ["dep:reqwest", "dep:syslog", "dep:hmac"]
# BW-compat shim requires assay-auth's password + JWT surfaces — the
# `/identity/connect/token` route delegates to assay-auth's password
# verifier and JWT issuer.
vault-bitwarden-compat = ["assay-auth/auth-password", "assay-auth/auth-jwt"]
vault-dynamic-postgres = []
vault-dynamic-aws = ["dep:reqwest", "dep:hmac"]
vault-dynamic-gcp = ["dep:reqwest", "dep:jsonwebtoken"]
vault-dynamic-kubernetes = ["dep:reqwest"]

backend-postgres = ["dep:sqlx", "sqlx/postgres"]
backend-sqlite = ["dep:sqlx", "sqlx/sqlite"]

[dependencies]
assay-auth = { path = "../assay-auth", version = "0.3" }
assay-domain = { path = "../assay-domain", version = "0.2" }

# Phase 0 holds the dep set deliberately small: just what the schema
# bootstrap, ctx skeleton, and smoke test need. Subsequent phases
# (1: KV+transit, 2: sealing+audit, 3: collections, 4: share, 5:
# dynamic creds, 6: HA, 7: BW-compat) add their own crypto / HTTP
# / sigv4 / kms primitives behind their own feature gates.
anyhow = "1"
async-trait = "0.1"
chrono = { version = "0.4", default-features = false, features = ["std", "clock", "serde"] }
parking_lot = "0.12"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
thiserror = "2"
tracing = "0.1"
url = "2"
uuid = { version = "1", features = ["v4", "v7", "serde"] }

# Runtime — `rt` for spawn_blocking (syslog sink), `sync` for the
# parking_lot/RwLock-bridge primitives, `time` for sleeps in tests
# already covered by the dev tokio feature.
tokio = { version = "1", features = ["rt", "sync", "time"] }

# AEAD (AES-256-GCM-SIV) — RustCrypto. Misuse-resistant: the SIV mode
# survives nonce reuse, which matters for transit's deterministic
# per-version nonces. Used for the master KEK ↔ DEK envelope, KV
# at-rest, transit, and (Phase 3) collection-side item encryption.
aes-gcm-siv = "0.11"
data-encoding = "2"
rand = "0.9"
sha2 = "0.10"

# Shamir Secret Sharing for the init-unseal flow (plan 17 §S7).
# Galois-field-256 SSS, pure Rust, audited. ~50 KB on disk.
sharks = { version = "0.5", optional = true }

# Biscuit capability tokens for share-link semantics (plan 17 §S5).
# Already in the workspace via assay-auth; gated here on `vault-share`
# so a slim build without share links doesn't link biscuit twice.
biscuit-auth = { version = "6", optional = true }

# HTTP layer — axum 0.8, the version every other engine module already
# uses. assay-auth is in tree, so its types (AdminApiKeys) come from
# the existing path dep; no extra cost.
axum = "0.8"

# Webhook + S3 audit forwarding + KMS / dynamic-creds cloud calls all
# share this HTTP client. reqwest is already pulled by the engine;
# the cost here is only the optional feature gate.
reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls"], optional = true }

# AWS SigV4 signing — used by KMS auto-unseal (AwsKmsSeal), the AWS
# dynamic-creds provider (sts:AssumeRole + iam:CreateAccessKey), and
# the S3 audit sink. Implemented inline against `hmac` rather than
# pulling the full aws-sigv4 crate to keep the binary delta minimal
# (plan 17 §"Cost estimate" budgets ~150 KB for the AWS surface).
hmac = { version = "0.12", optional = true }

# JWT signing — used by GCP KMS auto-unseal + GCP dynamic-creds
# (service account impersonation). Already in tree via assay-auth.
jsonwebtoken = { version = "10", optional = true }

# RFC 5424 / 3164 syslog — TCP / UDP / UDS sinks for audit forwarding.
# ~50 KB, zero transitive deps.
syslog = { version = "7", optional = true }

sqlx = { version = "0.8", features = ["runtime-tokio-rustls", "any"], optional = true }

[dev-dependencies]
tempfile = "3"
tokio = { version = "1", features = ["full"] }
