docs(org): complete A5 living-docs sweep (item CRUD merged) + dead_code cleanup
Extends the A5 pre-stage now that dev-b's full B-stream (item CRUD + all 19 org subcommands) merged to main (7392795). Living docs: - FORMATS/CRYPTO/SECURITY/DESIGN: flip the item-CRUD "pending Dev-B" markers to shipped; SECURITY audit vocabulary moves item-* actions to live. - crates/relicario-cli/ARCHITECTURE.md: full 19-subcommand surface (12 admin + 7 item CRUD), accurate OrgAddKind scope (Login/SecureNote/Identity). - STATUS.md: enterprise-org-vault landed section (merged7392795) + tracked follow-ups + honest known-limitations; correct spec citation. - ROADMAP.md: backend-complete row + phase-2 follow-ups. - CHANGELOG.md: finalize the enterprise-org-vault Unreleased section (item CRUD into Added; Card/Key/Document/Totp + extension + phase-2 into Deferred). Code (PM-directed dead_code fixes): wire device::current_device_seed by removing the identical duplicate private fn in org_session.rs (de-dup); #[allow(dead_code)] + justification on org_session org_meta_path/load_meta (API completeness, no command consumes org.json yet). Also silence a 3rd pre-existing test-only warning (unused relicario() helper in tests/org_init_signing.rs). Honest deferrals kept explicit throughout: Card/Key/Document/Totp org add/edit parity, extension org switch/read (Dev-D) + writes, phase-2 (SSO/LDAP, read audit, per-collection subkeys, HTTP plane). Full workspace cargo test green, zero warnings. All cited code constants pinned file:line. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TJo44YM3UbBjro2fG6NrKy
This commit is contained in:
49
CHANGELOG.md
49
CHANGELOG.md
@@ -1,14 +1,12 @@
|
||||
# Changelog
|
||||
|
||||
## Unreleased — enterprise org vault (in progress)
|
||||
## Unreleased — enterprise org vault
|
||||
|
||||
Git-native multi-user **org vaults**: a separate org git repository alongside each
|
||||
member's personal vault, with a 256-bit org master key ECIES-wrapped per member to
|
||||
their ed25519 device key, collection-scoped item storage, role-based access, and a
|
||||
signature-verifying pre-receive hook that makes least-privilege server-enforced.
|
||||
Tracked under `docs/superpowers/plans/2026-06-06-enterprise-org-vault.md`. Entries
|
||||
below cover the **already-merged** core (A) + server (C) + CLI admin work; item CRUD
|
||||
and extension parity land subsequently.
|
||||
signature-verifying pre-receive hook that makes least-privilege enforcement
|
||||
server-side. Tracked under `docs/superpowers/plans/2026-06-06-enterprise-org-vault.md`.
|
||||
|
||||
### Added
|
||||
- **relicario-core `org` module** (`crates/relicario-core/src/org.rs`): org types
|
||||
@@ -17,22 +15,39 @@ and extension parity land subsequently.
|
||||
key wrap/unwrap (`generate_org_key`, `wrap_org_key`, `unwrap_org_key`) — ed25519→
|
||||
X25519 via RFC 7748 clamp, domain-separated `SHA-256(dh || eph_pk || rcpt_pk)` KDF,
|
||||
XChaCha20-Poly1305 inner cipher, all key material in `Zeroizing`. Adds
|
||||
`encrypt_org_manifest` / `decrypt_org_manifest` vault wrappers. New dependency
|
||||
`x25519-dalek 2` (`static_secrets`).
|
||||
- **relicario-server org mode**: `verify-org-commit` (signature verification against
|
||||
`members.json`, path-scoped role/grant authorization, owner-only elevation judged
|
||||
on the signer's pre-commit role, schema-version monotonicity) and
|
||||
`generate-org-hook`; new `[lib]` target (`classify_path`, `extract_schema_version`).
|
||||
`encrypt_org_manifest` / `decrypt_org_manifest` vault wrappers. New dependencies:
|
||||
`x25519-dalek 2` (`static_secrets`) in core, `ssh-key 0.6` in core and CLI.
|
||||
- **relicario-server org mode**: `verify-org-commit` (commit-signature verification
|
||||
against `members.json` ed25519 keys, path-scoped role/grant authorization,
|
||||
owner-only elevation judged on the signer's pre-commit role, schema-version
|
||||
monotonicity) and `generate-org-hook`; new `[lib]` target (`classify_path`,
|
||||
`extract_schema_version`). Audit trail on every push carries verified-signer
|
||||
attribution; commits whose signer cannot be matched are flagged `TAMPERED`.
|
||||
- **relicario-cli org admin commands**: `org init`, `add-member` / `remove-member` /
|
||||
`set-role` (owner-only escalation guard), `create-collection` / `grant` / `revoke`,
|
||||
`rotate-key` (re-encrypts every item blob + manifest under a fresh key),
|
||||
`status` / `audit` (verified-signer attribution + `TAMPERED` flag). Org commits are
|
||||
signed (`org_git_run` preserves signing). New `ssh-key` dependency in the CLI.
|
||||
`rotate-key` (re-encrypts every item blob + manifest under a fresh org key),
|
||||
`transfer-ownership`, `delete-org` (local tombstone; hook blocks pushing a
|
||||
protected-file deletion), `status` / `audit`. Org commits are signed
|
||||
(`org_git_run` preserves signing).
|
||||
- **relicario-cli org item CRUD**: `org add` (Login, SecureNote, Identity — each
|
||||
collection-scoped and grant-enforced), `org get <query> [--show]` (secrets masked
|
||||
by default; renders Login/SecureNote/Identity/Card/Document/Totp), `org list
|
||||
[--trashed]` (manifest filtered to your collection grants), `org edit <query>`
|
||||
(flag-driven field updates for login/note/identity fields), `org rm` / `org restore`
|
||||
/ `org purge` (soft-delete lifecycle). Audit actions emitted: `item-create`,
|
||||
`item-update`, `item-delete`, `item-restore`, `item-purge`.
|
||||
|
||||
### TODO (pending merge)
|
||||
- CLI item CRUD: `org add` / `get` / `list` / `edit` / `rm` / `restore` / `purge`,
|
||||
and the final `Commands::Org` wiring in `main.rs` (Dev-B B9–B14).
|
||||
### Deferred
|
||||
- `org add` / `org edit` parity for Card, SshKey, Document, and Totp item types
|
||||
(only Login, SecureNote, Identity supported today; `org get` and `org list` can
|
||||
display all types already present in the vault).
|
||||
- Extension org switch + read-only browse parity (Dev-D follow-up).
|
||||
- Extension org writes.
|
||||
- Phase-2 features: SSO/LDAP provisioning, read audit trail, per-collection subkeys
|
||||
(the current shared org master key scopes *writes* via the hook and *read access*
|
||||
via manifest filtering, but does not cryptographically isolate collections from one
|
||||
another — a member who obtains the org key can decrypt any blob), HTTP management
|
||||
plane.
|
||||
|
||||
## v0.7.0 — 2026-06-01
|
||||
|
||||
|
||||
@@ -164,7 +164,7 @@ The enterprise org vault is a **second git repository** alongside each member's
|
||||
- **relicario-server** gains an **org mode**: a new `[lib]` target (`classify_path`, `extract_schema_version`) plus the `verify-org-commit` and `generate-org-hook` subcommands — a signature-verifying, path-scoped pre-receive hook (see `docs/SECURITY.md`).
|
||||
- **extension** org switch + read parity is a tracked follow-up (Dev-D) — `TODO (extension follow-up)`.
|
||||
|
||||
Status: core (A) + server hook (C) merged; CLI admin/rotate/status-audit merged; CLI item-CRUD + the final command wiring are `TODO (pending Dev-B B9–B14)`.
|
||||
Status: the backend is complete on `main` — core (A) org module, server hook (C), and the full CLI (all 19 `org` subcommands incl. item CRUD) are merged. Deferred: `org add`/`edit` parity for Card/Key/Document/Totp (Login/SecureNote/Identity ship today), and the extension org switch + read parity (`TODO (extension follow-up)`, Dev-D).
|
||||
|
||||
## Build matrix
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
| Version | Highlights |
|
||||
|---|---|
|
||||
| *(untagged, 2026-06-20)* | **Enterprise org vault — backend complete** (`7392795`): relicario-core `org` module (ECIES X25519 key wrap/unwrap, `OrgRole`/`OrgMember`/`OrgManifest` types, `filter_for_member`, `schema_version: 1`); relicario-server org hook (`verify-org-commit`: signature verification, path-scoped authz, `enforce_owner_only_elevation` on parent role, `enforce_schema_monotonicity`, `generate-org-hook`, new `[lib]` target); relicario-cli — all 19 `relicario org` subcommands: init, add-member/remove-member/set-role, create-collection/grant/revoke, rotate-key (re-encrypts all blobs), transfer-ownership, delete-org, status, audit, and item CRUD (add/get/list/edit/rm/restore/purge). **Not yet shipped:** `org add`/`edit` for Card/SshKey/Document/Totp; extension org parity (Dev-D); phase 2 (SSO/LDAP, read audit, per-collection subkeys, HTTP plane). |
|
||||
| v0.7.0 *(2026-06-01)* | Extension restructure (Plan C) complete — Phases 3/4/6 merged via 3 parallel worktree streams under PM coordination: setup wizard crypto migrated into the SW (`create_vault`/`attach_vault`; `setup.ts` 1230→58 LOC + step registry); `vault.ts` split 1037→194 LOC into 5 focused + 2 support modules; `vault_locked` intercept lifted into `shared/state.ts`; `get_vault_status` SW message + sidebar status indicator closing the last `relicario status` CLI/extension parity gap |
|
||||
| v0.6.0 *(2026-05-30)* | Security audit fixes; device authentication; backup/restore + LastPass import; fullscreen UX Phases 1+2A+2B; v0.5.1 Streams A/B/C (3-column vault layout + bottom-sheet picker + toast system; left-nav settings; Recovery QR end-to-end + setup wizard Style C); 1C-γ (attachments + Document type + device registration + trash + field history); Plan B multi-stream refactor (commands/ split, prompt_or_flag, core/WASM seam); vault-tab management surfaces revamp (settings synced/local split, devices fingerprint, trash purge countdown, field-history polish, item-history-index, `#history/<id>` routing); doc-structure redesign (rename to DESIGN/CRYPTO/docs/FORMATS, scope headers + Next: footers); GPL-3.0-or-later license |
|
||||
| v0.2.0 | Typed-item rewrite (Plans 1A/1B/1C-α/β₁/β₂) |
|
||||
@@ -15,14 +16,19 @@ See `CHANGELOG.md` for tagged-release detail and `STATUS.md` for the per-train c
|
||||
|
||||
## Up next
|
||||
|
||||
All three 2026-05-04 architecture-review specs are now shipped (CLI restructure = Plan B Cycles 1+2; security polish = Stream A Cycle 1; extension restructure = Plan C Phases 1–6, completed v0.7.0 2026-06-01). The next committed item is:
|
||||
All three 2026-05-04 architecture-review specs are shipped; enterprise org vault backend is shipped (2026-06-20). Pending items in rough priority order:
|
||||
|
||||
- **Org-vault item-type parity** — `org add`/`edit` support for Card, SshKey, Document, Totp (Login/SecureNote/Identity ship today)
|
||||
- **Extension org parity — read** — org switch + collection-filtered browse in the popup/vault tab (Dev-D, deferred)
|
||||
- **Extension org parity — write** — `org add`/`edit`/`rm` from the extension
|
||||
- **Phase 4: command palette** — ⌘K global search + action dispatch across the vault tab (no spec yet)
|
||||
|
||||
## Medium-term
|
||||
|
||||
_(promote here once specced)_
|
||||
|
||||
- **Org vault phase 2** — SSO/LDAP federation, read audit log, per-collection subkeys (true cryptographic scope separation per collection), HTTP management plane
|
||||
|
||||
## Long-term / backlog
|
||||
|
||||
- **Relay server** — encrypted WebSocket relay for multi-device sync without a shared git server
|
||||
|
||||
34
STATUS.md
34
STATUS.md
@@ -98,6 +98,30 @@ Plan: `docs/superpowers/plans/2026-05-24-vault-tab-management-surfaces-revamp.md
|
||||
- Item-history-index pane — top-level "items with history" list (`32e1632`)
|
||||
- Sidebar slot wiring + `#history/<id>` route with `#field-history/<id>` legacy normalization (`88d7228`)
|
||||
|
||||
### Enterprise org vault — core + server hook + CLI (merged 2026-06-20, `7392795`)
|
||||
|
||||
Spec: `docs/superpowers/specs/2026-06-06-relicario-enterprise-org-vault-design.md`; plan: `docs/superpowers/plans/2026-06-06-enterprise-org-vault.md`
|
||||
|
||||
**relicario-core org module** (`crates/relicario-core/src/org.rs`): `OrgId`, `MemberId`, `OrgRole` (Owner/Admin/Member), `OrgMember`, `OrgMembers`/`OrgCollections`/`OrgMeta`/`OrgManifest`/`OrgManifestEntry` (all `schema_version: 1`); `generate_org_key`; ECIES X25519 key wrap/unwrap (`wrap_org_key` / `unwrap_org_key`) — ed25519→X25519 conversion via `SHA-512(seed)[..32]` + RFC 7748 clamp, ephemeral DH, `SHA-256(dh_shared || ephemeral_pk || recipient_pk)` wrap key, inner cipher delegated to `crate::crypto::encrypt` (XChaCha20-Poly1305, no Argon2id in org path); `OrgManifest::filter_for_member` for collection-scoped manifest views. Vault wrappers: `encrypt_org_manifest` / `decrypt_org_manifest` in `vault.rs`. 5 acceptance tests in `crates/relicario-core/tests/org.rs` incl. wrap/unwrap round-trip, revoke-after-rotation, manifest filter, and an RFC 8032 ed25519→X25519 known-answer vector.
|
||||
|
||||
**relicario-server org hook** (`crates/relicario-server/src/{lib.rs,main.rs}`): pure `classify_path` / `extract_schema_version` in new `lib.rs` target; `verify_org_commit` — commit-signature verification against `members.json` ed25519 keys, path-scoped authorization (protected JSON → owner/admin only; `items/<slug>/…` → slug in signer's grants), `enforce_owner_only_elevation` (parent-role check; guards against privilege self-escalation), `enforce_schema_monotonicity` (schema_version must not decrease; merge commits rejected; genesis allowed); `generate-org-hook` subcommand emits a wrapper script. New `[lib]` target added to `relicario-server` crate.
|
||||
|
||||
**relicario-cli — all 19 `relicario org` subcommands** (`crates/relicario-cli/src/{org_session.rs,commands/org.rs,device.rs}`): `org_session.rs` provides `UnlockedOrgVault` (org key in `Zeroizing`), collection-scoped `item_path`, fingerprint-based member match, `atomic_write`, `org_git_run` (signed commits — does NOT suppress `commit.gpgsign`).
|
||||
|
||||
Admin/lifecycle commands: `init` (structure + wrap + `configure_git_signing` + signed bootstrap commit), `add-member` / `remove-member` / `set-role` (owner-only escalation guard), `create-collection` / `grant` / `revoke`, `rotate-key` (fresh key + re-wrap all members + re-encrypt every `items/<slug>/<id>.enc` blob + manifest, concurrent-rotation abort, `Relicario-Action: key-rotate`), `transfer-ownership`, `delete-org`, `status`, `audit` (verified-signer attribution + TAMPERED flag).
|
||||
|
||||
Item CRUD commands (B9–B14): `org add` (`OrgAddKind`: Login/SecureNote/Identity; card/key/document/totp deferred — see below), `org get <query> [--show]`, `org list [--trashed]`, `org edit <query> [--title/--username/…]`, `org rm`, `org restore`, `org purge`. All ops are collection-scoped + grant-enforced; audit trail emits `item-create` / `item-update` / `item-delete` / `item-restore` / `item-purge`.
|
||||
|
||||
**A5 doc-fix** (`enforce_owner_only_elevation` parent-role close, `519e503`) and this living-docs sweep also landed.
|
||||
|
||||
**Tracked follow-ups (deferred, not shipped):**
|
||||
- `org add` / `org edit` parity for Card, SshKey, Document, Totp item types (Login/SecureNote/Identity only today; `get`/`list` can display all types if present)
|
||||
- Extension org-vault switch + read parity (Dev-D deferred)
|
||||
- Extension org write operations
|
||||
- Phase 2: SSO/LDAP federation, read audit log, per-collection subkeys (true cryptographic scope separation), HTTP management plane
|
||||
|
||||
**Known limitations (by design in phase 1):** shared org master key — reads are not cryptographically scoped per collection (hook scopes writes; client filters manifest); no read audit (git records writes only); `delete-org` is a local tombstone only (hook rejects protected-file deletion on push).
|
||||
|
||||
### Extension restructure — Plan C Phases 3, 4, 6 (merged 2026-05-31 → 06-01, v0.7.0)
|
||||
|
||||
Spec: `docs/superpowers/specs/2026-05-04-extension-restructure-design.md`
|
||||
@@ -143,6 +167,12 @@ Per the 2026-05-30 post-v0.6.0 audit of the three 2026-05-04 architecture-review
|
||||
- **Security polish** (`2026-05-04-security-polish-design.md`) — *already shipped* as Stream A Cycle 1 (`89090a8`) plus follow-ups (`0c9387f` start.sh fourth window, `229e483` recovery_qr.rs docs). All four phases done.
|
||||
- **Extension restructure** (`2026-05-04-extension-restructure-design.md`, plan `docs/superpowers/plans/2026-05-30-extension-restructure.md`) — ✅ **COMPLETE** (all six phases merged; see the dated landing section above). Phases 1/2/5 merged 2026-05-30; Phases 3/4/6 merged 2026-05-31 → 06-01. Final tree: 423/423 vitest, build:all clean. v0.7.0 versions bumped; tag pending.
|
||||
|
||||
Beyond extension restructure, ROADMAP medium-term holds Phase 4 command palette (no spec yet). Long-term: relay server, mobile.
|
||||
**Enterprise org vault** — ✅ **COMPLETE (backend)** — all 19 CLI subcommands + core + server hook merged `7392795` 2026-06-20. Deferred follow-ups tracked in the landing section above.
|
||||
|
||||
See `ROADMAP.md` for the longer arc and `CHANGELOG.md` for tagged-release history (current head: `v0.6.0`; the `v0.7.0` entry covers this extension-restructure completion).
|
||||
Pending org-vault follow-ups (in rough priority order):
|
||||
- `org add`/`edit` parity for Card, SshKey, Document, Totp
|
||||
- Extension org switch + read parity (Dev-D)
|
||||
- Extension org write operations
|
||||
- **Phase 4: command palette** — ⌘K global search + action dispatch across the vault tab (no spec yet)
|
||||
|
||||
Long-term: relay server, mobile. See `ROADMAP.md` for the longer arc and `CHANGELOG.md` for tagged-release history (current head: `v0.6.0`; the `v0.7.0` entry covers extension-restructure completion).
|
||||
|
||||
@@ -74,26 +74,43 @@ under `src/commands/`. Each source file has one job.
|
||||
- **`src/org_session.rs`** — `UnlockedOrgVault`, the org-vault analogue of
|
||||
`session.rs`. Holds the org master key in `Zeroizing<[u8; 32]>` for one CLI
|
||||
invocation, recovered by unwrapping `keys/<member-id>.enc` with the device
|
||||
ed25519 seed (`relicario_core::unwrap_org_key`). Owns the **collection-scoped**
|
||||
`item_path` (`items/<collection-slug>/<id>.enc` — the leading slug is what the
|
||||
pre-receive hook authorizes against, never decrypting), fingerprint-based
|
||||
member matching (`relicario_core::fingerprint`, tolerant of OpenSSH
|
||||
whitespace/comment differences), `atomic_write`, and `org_git_run`. Note
|
||||
`org_git_run` runs **bare git** — unlike `helpers::git_run` it does NOT inject
|
||||
ed25519 seed. `open_org_vault` calls `crate::device::current_device_seed()`
|
||||
directly (`device.rs`) — a duplicate private fn that previously existed in
|
||||
`org_session.rs` was removed during the A5 sweep (implementations were
|
||||
identical). Owns the **collection-scoped** `item_path`
|
||||
(`items/<collection-slug>/<id>.enc` — the leading slug is what the pre-receive
|
||||
hook authorizes against, never decrypting), fingerprint-based member matching
|
||||
(`relicario_core::fingerprint`, tolerant of OpenSSH whitespace/comment
|
||||
differences), `atomic_write`, and `org_git_run`. Note `org_git_run` runs
|
||||
**bare git** — unlike `helpers::git_run` it does NOT inject
|
||||
`commit.gpgsign=false`, because org commits MUST be signed (the hook verifies
|
||||
every commit's signature); signing config is established by
|
||||
`configure_git_signing` during `org init`.
|
||||
|
||||
- **`src/commands/org.rs`** — the `relicario org` subcommand surface. Merged:
|
||||
`init`, `add-member` / `remove-member` / `set-role` (owner-only escalation
|
||||
guard), `create-collection` / `grant` / `revoke`, `rotate-key`
|
||||
(`run_rotate_key`, `commands/org.rs:332` — fresh key, re-wrap for all members,
|
||||
re-encrypt every item blob + manifest under the new key, concurrent-rotation
|
||||
abort), and `status` / `audit` (verified-signer attribution + `TAMPERED`
|
||||
flag). **TODO (pending Dev-B B9–B14):** the item-CRUD commands (`org add` /
|
||||
`get` / `list` / `edit` / `rm` / `restore` / `purge`) and the final
|
||||
`Commands::Org` wiring in `main.rs`. `device.rs` gains
|
||||
`current_device_seed` / `current_device_pubkey` helpers for the ECIES unwrap.
|
||||
- **`src/commands/org.rs`** — the `relicario org` subcommand surface. Full
|
||||
19-subcommand surface is merged and wired via `Commands::Org` in `main.rs`.
|
||||
|
||||
*Admin / lifecycle (12):* `init` (structure + wrap + `configure_git_signing` +
|
||||
signed bootstrap commit), `add-member` / `remove-member` / `set-role`
|
||||
(owner-only escalation guard), `create-collection` / `grant` / `revoke`,
|
||||
`rotate-key` (`run_rotate_key`, `commands/org.rs:332` — fresh key, re-wrap for
|
||||
all members, re-encrypt every item blob + manifest under the new key,
|
||||
concurrent-rotation abort), `transfer-ownership`, `delete-org`, `status` /
|
||||
`audit` (verified-signer attribution + `TAMPERED` flag).
|
||||
|
||||
*Item CRUD (7):* `org add` creates typed items via `OrgAddKind`
|
||||
(`commands/org.rs:749`) — **Login / SecureNote / Identity only**; Card /
|
||||
SshKey / Document / Totp creation is a deferred follow-up. `get` / `list` can
|
||||
display any item type if present. `org get <query> [--show]` masks secrets
|
||||
unless `--show`; `org list [--trashed]` filters by the caller's collection
|
||||
grants; `org edit <query>` is flag-driven (blank flags keep current values);
|
||||
`org rm` soft-deletes, `org restore` undoes, `org purge` permanently removes
|
||||
the encrypted blob. All item ops are collection-scoped and grant-enforced. The
|
||||
audit trail emits `item-create` / `item-update` / `item-delete` /
|
||||
`item-restore` / `item-purge`.
|
||||
|
||||
Deferred: Card / SshKey / Document / Totp `org add` / `edit` parity;
|
||||
extension org reads and writes (Dev-D).
|
||||
|
||||
- **`src/helpers.rs`** (`helpers.rs:1-101`) — pure, no-state plumbing:
|
||||
`find_vault_dir_from` (`helpers.rs:14-28`) walks up parent directories
|
||||
|
||||
@@ -39,8 +39,14 @@ impl UnlockedOrgVault {
|
||||
}
|
||||
pub fn members_path(&self) -> PathBuf { self.root.join("members.json") }
|
||||
pub fn collections_path(&self) -> PathBuf { self.root.join("collections.json") }
|
||||
// OrgMeta accessors — part of the UnlockedOrgVault path/loader API surface
|
||||
// (parallel to members_path/collections_path + load_members), retained for
|
||||
// completeness. No command consumes org.json yet; surfacing the org
|
||||
// name/id in `org status` is a tracked follow-up, so allow until then.
|
||||
#[allow(dead_code)]
|
||||
pub fn org_meta_path(&self) -> PathBuf { self.root.join("org.json") }
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn load_meta(&self) -> Result<OrgMeta> {
|
||||
let s = fs::read_to_string(self.org_meta_path()).context("read org.json")?;
|
||||
Ok(serde_json::from_str(&s).context("parse org.json")?)
|
||||
@@ -185,7 +191,7 @@ pub fn open_org_vault(dir_flag: Option<&std::path::Path>) -> Result<UnlockedOrgV
|
||||
fs::read(&key_path).with_context(|| format!("read {}", key_path.display()))?;
|
||||
|
||||
// Recover the device ed25519 seed and unwrap.
|
||||
let seed = current_device_seed()?;
|
||||
let seed = crate::device::current_device_seed()?;
|
||||
let org_key = relicario_core::unwrap_org_key(&wrapped, &seed)?;
|
||||
|
||||
Ok(UnlockedOrgVault { root, org_key })
|
||||
@@ -202,27 +208,6 @@ fn current_device_fingerprint() -> Result<String> {
|
||||
}
|
||||
|
||||
/// Recover the active device's ed25519 seed (the 32-byte private scalar source)
|
||||
/// from its OpenSSH `signing.key`, for ECIES unwrap.
|
||||
fn current_device_seed() -> Result<Zeroizing<[u8; 32]>> {
|
||||
let name = crate::device::current_device()?
|
||||
.ok_or_else(|| anyhow::anyhow!("no active device — run `relicario device add` first"))?;
|
||||
let key_pem = crate::device::load_signing_key(&name)?;
|
||||
let private = ssh_key::PrivateKey::from_openssh(key_pem.as_str())
|
||||
.map_err(|e| anyhow::anyhow!("parse device signing key: {e}"))?;
|
||||
let ed = private
|
||||
.key_data()
|
||||
.ed25519()
|
||||
.ok_or_else(|| anyhow::anyhow!("device signing key is not ed25519"))?;
|
||||
// Ed25519PrivateKey derefs to its 32-byte seed.
|
||||
let seed_bytes: &[u8] = ed.private.as_ref();
|
||||
if seed_bytes.len() != 32 {
|
||||
anyhow::bail!("ed25519 seed has wrong length: {}", seed_bytes.len());
|
||||
}
|
||||
let mut seed = Zeroizing::new([0u8; 32]);
|
||||
seed.copy_from_slice(seed_bytes);
|
||||
Ok(seed)
|
||||
}
|
||||
|
||||
pub(crate) fn atomic_write(path: &Path, data: &[u8]) -> Result<()> {
|
||||
let mut tmp = path.as_os_str().to_owned();
|
||||
tmp.push(".tmp");
|
||||
|
||||
@@ -3,6 +3,10 @@ use std::path::Path;
|
||||
use std::process::Command;
|
||||
use tempfile::TempDir;
|
||||
|
||||
// Base runner kept as the documented counterpart to relicario_with_git_identity
|
||||
// below (every test in this file needs the git identity, so only the _with_
|
||||
// variant is currently called).
|
||||
#[allow(dead_code)]
|
||||
fn relicario(config_home: &Path, args: &[&str]) -> std::process::Output {
|
||||
Command::new(env!("CARGO_BIN_EXE_relicario"))
|
||||
.env("XDG_CONFIG_HOME", config_home)
|
||||
|
||||
@@ -272,7 +272,7 @@ a local clone of the repo cannot decrypt any item written after the rotation, be
|
||||
those blobs are sealed under a key they never received. Without re-encryption, all
|
||||
pre-rotation blobs would remain readable to the former member indefinitely.
|
||||
|
||||
> **TODO (pending Dev-B B9–B14):** item-CRUD commands (`org add`/`get`/`list`/`edit`/`rm`/`restore`/`purge`) and the final `Commands::Org` wiring in `main.rs` are not yet merged.
|
||||
The item-CRUD commands (`org add`/`get`/`list`/`edit`/`rm`/`restore`/`purge`) that read and write these blobs are merged and wired into `main.rs`; each operates under the org master key recovered by `unwrap_org_key`.
|
||||
|
||||
## imgsecret DCT Embedding
|
||||
|
||||
|
||||
@@ -121,9 +121,9 @@ Contrast with the personal vault manifest: `Manifest` uses `MANIFEST_SCHEMA_VERS
|
||||
|
||||
Standard `.enc` blob (see **Encrypted blob** above), encrypted under the org master key. The blob itself does **not** name its collection — the directory path segment carries the slug. This allows the pre-receive hook (`relicario-server`) to authorize a write by path segment without decrypting the blob.
|
||||
|
||||
**TODO (pending Dev-B B9–B14):** CLI commands for creating, reading, editing, and deleting org items (`org add` / `get` / `list` / `edit` / `rm` / `restore` / `purge`) are not yet wired in `main.rs`.
|
||||
These blobs are written and read by the `relicario org` item commands (`org add` / `get` / `list` / `edit` / `rm` / `restore` / `purge`), all collection-scoped and grant-enforced. `org add` currently creates Login / SecureNote / Identity items; `get` / `list` display any item type present.
|
||||
|
||||
**TODO (extension follow-up):** extension UI for browsing and editing org vault items.
|
||||
**TODO (extension follow-up):** extension UI for browsing and editing org vault items. **Deferred:** `org add` / `edit` parity for Card / Key / Document / Totp item types.
|
||||
|
||||
## Item IDs and Field IDs
|
||||
|
||||
|
||||
@@ -154,13 +154,13 @@ the cryptographically verified signer.
|
||||
|
||||
Actions live in two groups:
|
||||
|
||||
- **Live (merged A + C streams):** `member-add`, `member-remove`,
|
||||
- **Membership / collections / lifecycle:** `member-add`, `member-remove`,
|
||||
`member-role-change`, `collection-create`, `collection-grant`,
|
||||
`collection-revoke`, `key-rotate`, `org-init`, `ownership-transfer`,
|
||||
`org-delete`.
|
||||
- **TODO (pending Dev-B B9–B13):** `item-create`, `item-update`,
|
||||
`item-delete`, `item-restore`, `item-purge` — the emitter code lands with
|
||||
the item-CRUD command stream.
|
||||
- **Item CRUD:** `item-create`, `item-update`, `item-delete` (soft-delete /
|
||||
trash), `item-restore`, `item-purge` — emitted by the `org add` / `edit` /
|
||||
`rm` / `restore` / `purge` commands.
|
||||
|
||||
### Honest limitations
|
||||
|
||||
|
||||
Reference in New Issue
Block a user