# Secure Storage Spike

Chanora proof-of-concept. **Not product code.**

| Field | Value |
|---|---|
| PoC name | `secure-storage-spike` |
| PoC plan | [`docs/architecture/proof-of-concept-plan.md`](../../docs/architecture/proof-of-concept-plan.md) §2 |
| Purpose | Prove platform secure storage behaviour |
| Exit criterion | "Secret write/read/delete works through platform secure storage" |
| Authority | ADR-006 (`SecureStore trait + per-platform adapters`), SDD-078, SRS-091..095, SysRS-158..162 |
| Audit refs | `docs/security/secure-storage-audit-report.md` SS-AUD-001..006 / SS-TC-003 |

## What it proves

- A typed `SecretStorageRepository` trait that the rest of the Rust core
  can depend on without backend leakage (SAD-067).
- A Linux adapter selecting between two equivalent backends per
  SysRS-162 ("Secret Service, libsecret, **or equivalent**"):
  - **Secret Service / libsecret** (gnome-keyring, kwallet, KeePassXC, …).
  - **Kernel keyutils** (`add_key(2)` / `request_key(2)`) — used when no
    D-Bus session or unlocked Secret Service collection is available.
- A typed `SecureStoreError` with `NotFound` / `Unavailable` / `Backend`
  arms, satisfying SS-AUD-005 (safe error mapping).
- A `Secret` newtype with redacting `Debug` / `Display` and
  zero-on-drop, satisfying SS-AUD-003 defence-in-depth.
- A miniature `LocalDatabaseRepository` (rusqlite, bundled) that holds
  only **references** to secret names — proving the SAD-067 separation
  empirically (SS-AUD-001, SS-AUD-002).

## Layout

```text
secure-storage-spike/
  src/
    lib.rs              # crate root + re-exports
    secret.rs           # SecretStorageRepository trait, Secret type, Linux adapter
    sqlite_repo.rs      # LocalDatabaseRepository (non-secret state only)
    test_logger.rs      # in-memory log capture for SS-AUD-003
    main.rs             # secure-storage-cli driver (SS round-trip)
  tests/
    audit.rs            # SS-AUD-001/002/003/005/006 + SS-TC-003
  Cargo.toml
```

## Reproduce

Requires Rust stable (developed against 1.95). Linux only — non-Linux
adapters are out of scope for this spike. `cargo` needs network access
on first build.

```bash
# Run the audit test suite (uses kernel keyutils backend; hermetic).
keyctl session - cargo test --tests

# Run the CLI driver. It prefers Secret Service and falls back to
# keyutils if the default collection is locked. Either path satisfies
# SysRS-053 / SysRS-162.
keyctl session - cargo run --bin secure-storage-cli
```

> **Why `keyctl session -`?**
> The Linux kernel session keyring is inherited from the calling process.
> Cargo's test/run wrappers often inherit an expired or empty
> `_ses` keyring from non-interactive shells. `keyctl session -` creates
> a fresh session keyring before invoking the command, guaranteeing a
> valid backend for keyutils. Interactive desktop sessions normally do
> not need this wrapper.

## Scope boundaries

This spike is intentionally narrow. Out of scope:

- **Windows / macOS / iOS / Android adapters.** SS-TC-001/002/004/005
  remain unverified. The trait is shaped to accommodate them but no
  code is shipped here.
- **SS-AUD-004 (diagnostic export redaction).** Owned by the
  `diagnostics-redaction-spike`.
- **SS-AUD-007 (per-platform documentation).** Doc-only check; lives
  in the audit report itself.
- **SS-AUD-008 (migration / import).** No migration paths exist yet.
- **Encryption at rest** beyond what the platform backend provides.
- **Constant-time secret comparison.** `Secret::eq` is best-effort.
- **Threading / async semantics.** Trait is `Send + Sync` but no
  concurrent stress is exercised.

## Verification log

See `VERIFICATION.md` in this directory.
