Commit Graph

678 Commits

Author SHA1 Message Date
adlee-was-taken
d8b23d421e refactor(cli): tidy item_build edit helpers (simplify pass)
- edit_secure_note / edit_key now call the module's resolve_secret_multiline
  instead of open-coding the eprintln-hint + read-to-EOF pattern (the helper
  exists precisely to centralize this; build_secure_note/build_key already use it).
- drop redundant fn-local imports: `use zeroize::Zeroizing;` from the five edit_*
  helpers and the re-imported `TotpAlgorithm` from edit_login/build_login
  (all covered by module-level imports; leftover from the verbatim A2/A3 move).
- build_login passes the password_stdin flag through to resolve_secret_line for
  consistency with build_card/build_totp (behavior identical — that branch is
  only reached when password_stdin is true).
- restore #[allow(clippy::too_many_arguments)] on build_totp (8 args; the old
  build_totp_item carried the same allow — signature is frozen for B/C).
2026-06-20 18:14:10 -04:00
adlee-was-taken
6eb1275710 feat(cli): --*-stdin secret flags for personal add (non-interactive secrets) 2026-06-20 17:56:45 -04:00
adlee-was-taken
751e4e9bb1 chore(cli): remove now-dead prompt/prompt_optional helpers
A3 routed personal `add` through the shared item_build builders, which use
prompt_secret / resolve_secret_*; the generic single-line prompt() and
prompt_optional() lost their last callers. read_required_line /
read_optional_line stay (used by prompt_or_flag*).
2026-06-20 17:40:52 -04:00
adlee-was-taken
65e23cfddc refactor(cli): personal add delegates to shared item_build builders 2026-06-20 17:35:18 -04:00
adlee-was-taken
b83643ee0a refactor(cli): move per-type edit helpers into shared item_build module 2026-06-20 17:27:05 -04:00
adlee-was-taken
154b984725 feat(cli): shared item_build module — secret resolution + type parsers 2026-06-20 17:21:43 -04:00
adlee-was-taken
517d52d517 docs(coordination): v0.8.1 PM + Dev-A/B/C/D kickoff prompts
4-stream manual-pane kickoff (no tmux automation): A foundation, B
Card/Key/Totp, C Document+attachments, D server hook. Each dev prompt
mandates a relay polling cadence (read inbox between every subagent;
HOLD/RESCOPE = interrupt) so PM directives are never missed. Gitea/git
merge mechanism; C<->D attachment-path coordination baked in.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L5JvzEse4xUxLZKhofyeCD
2026-06-20 17:10:26 -04:00
adlee-was-taken
3774047298 chore(salvage): snapshot org-vault tail uncommitted work before worktree cleanup
org_audit.rs (B8 verified-signer test) + the two uncommitted org.rs diffs
(item-CRUD B9-B13, status/audit B8) from the wf_22020aea first-run worktrees.
All superseded by v0.8.0 main; also committed on the -r2 branches. Kept so
nothing is lost when the stale worktrees are removed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L5JvzEse4xUxLZKhofyeCD
2026-06-20 16:58:28 -04:00
adlee-was-taken
f27dc72e96 docs(plan): v0.8.1 org item-type parity — 4-stream multi-agent plan
Dev-A shared item_build foundation + personal --*-stdin; Dev-B org
Card/Key/Totp; Dev-C org Document + attachment storage; Dev-D server
hook grant-scoping. TDD tasks with full code; A gates B/C, D independent.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L5JvzEse4xUxLZKhofyeCD
2026-06-20 16:48:46 -04:00
adlee-was-taken
b2f3739673 docs(spec): v0.8.1 org item-type parity (Card/Key/Document/Totp) design
Card/Key/Totp = CLI-only parity via shared item-build module; Document
adds org attachment storage + a relicario-server hook change that
grant-scopes attachment paths (closing the Unrestricted gap). Secrets
via interactive prompts + --*-stdin escape hatches. Four suggested dev
streams (A foundation, B Card/Key/Totp, C Document+attachments, D hook).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L5JvzEse4xUxLZKhofyeCD
2026-06-20 16:38:05 -04:00
adlee-was-taken
50b5c01291 release: v0.8.0 — enterprise org vault
Bump core/cli/wasm 0.7.0 -> 0.8.0; finalize CHANGELOG v0.8.0 header. Git-native multi-user org vaults (core org module + ECIES X25519 wrap, server signature-verifying pre-receive hook, CLI admin + item CRUD); 332/0 workspace tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RXpTHcQzw1n8qjYwZqruzQ
v0.8.0
2026-06-20 16:06:16 -04:00
adlee-was-taken
3871da383d merge(docs): A5 living-docs sweep — item-CRUD across FORMATS/CRYPTO/SECURITY/DESIGN/ARCHITECTURE, STATUS shipped, ROADMAP, CHANGELOG; dead_code de-dup 2026-06-20 15:57:38 -04:00
adlee-was-taken
44d61ae7a7 test(cli/org): add grant-denial + secure-note masking regression tests
Cover two authz gaps left by the B9-B14 org item-CRUD work:

1. Grant-DENIAL on the read/mutate-by-query commands. A second member
   added with their own device key but NOT granted `prod` is rejected by
   every one of `org get`, `edit`, `rm`, `restore`, and `purge`, and
   `org get` (with and without --show) leaks no plaintext. Previously
   only `org add` had a denial test. Also asserts the item is untouched
   afterward (owner still reads the original password/username).

2. SecureNote body masking: `org get <note>` prints `********` and not
   the body; `org get <note> --show` reveals it. Mirrors the existing
   Login-password masking assertions in org_items.rs.

New tests/org_authz.rs reuses the multi-member `Dev` harness pattern
from org_lifecycle.rs (one XDG config home + ed25519 device key per
member), so a second member joins with their own keypair.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RXpTHcQzw1n8qjYwZqruzQ
2026-06-20 15:55:25 -04:00
adlee-was-taken
0cd417ded7 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 (merged 7392795) + 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
2026-06-20 15:54:51 -04:00
adlee-was-taken
8bb1d779c4 docs(org): pre-stage A5 living-docs for merged core+server+CLI-admin (item-CRUD/extension TODO)
Pre-stages the A5 living-docs sweep for the already-merged A (relicario-core org
module) + C (relicario-server pre-receive hook) + CLI admin/rotate/status-audit
work, so the final A5 sweep (after Dev-B B9-B14 merges) is fast.

Adds org sections to docs/FORMATS.md (org repo wire formats + wrapped-key blob
layout), docs/CRYPTO.md (ECIES X25519 wrap/unwrap, no-Argon2id contrast, rotate
re-encryption), docs/SECURITY.md (signature-verifying hook, owner-only elevation,
audit vocabulary, honest limitations), DESIGN.md (org-master-key secrets row +
server org mode + deps), core/cli ARCHITECTURE.md (org module + org_session), and
an Unreleased CHANGELOG entry.

B item-CRUD (org add/get/list/edit/rm/restore/purge + main.rs wiring) and extension
parity are left as explicit TODO. STATUS/ROADMAP mark-shipped and
extension/ARCHITECTURE are deferred to the full A5 (track not yet landed; Dev-D
deferred). All cited code constants pinned with file:line per living-docs discipline.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TJo44YM3UbBjro2fG6NrKy
2026-06-20 15:23:27 -04:00
adlee-was-taken
739279515a merge(cli): dev-b B9-B14 — org item CRUD (add/get/list/edit/rm/restore/purge) + wire all 19 OrgCommands. Reviewed: authz+secrets clean; grant-denial regression test follow-up tracked 2026-06-20 15:13:59 -04:00
adlee-was-taken
6123d8b033 feat(cli/org): org rm/restore/purge trash lifecycle (collection-scoped) 2026-06-20 14:39:18 -04:00
adlee-was-taken
057a7defe5 feat(cli/org): org edit — flag-driven field update for login/note/identity 2026-06-20 14:12:46 -04:00
adlee-was-taken
2acd57a4a5 feat(cli/org): org get + list with per-member grant filtering 2026-06-20 14:08:22 -04:00
adlee-was-taken
87b1d166c2 feat(cli/org): org add — collection-scoped typed item create with grant guard 2026-06-20 14:00:21 -04:00
adlee-was-taken
6a16523ee0 feat(cli/org): wire Commands::Org admin subcommands + parse_org_role + transfer-ownership/delete-org 2026-06-20 13:50:11 -04:00
adlee-was-taken
519e503cbd docs(plan,spec): align enforce_owner_only_elevation to shipped parent-role authority
The plan's pre-receive-hook pseudocode judged owner-elevation authority on the
post-change `signer.role` (so a self-promoting Admin reads as Owner in the same
commit and self-authorizes the promotion — the exact escalation the gate exists
to stop). f249395 had fixed only the skip-predicate, leaving this final check
vulnerable. Align the plan's `enforce_owner_only_elevation` to the SHIPPED fix
(relicario-server/src/main.rs, aace6f1): derive `signer_may_manage_owners` from
`signer_parent = parent_role(signer.member_id)` (the signer's PRE-commit role;
None -> reject; genesis allowed) and gate on that, never the post-change role.

The spec was already policy-correct in prose ("a member-role-change granting
owner/admin must be signed by an owner") and did NOT carry the vulnerable
implementation detail; strengthened it with an explicit pre-commit-role note so
the design record pins the property and no one re-derives the vulnerable form.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TJo44YM3UbBjro2fG6NrKy
2026-06-20 13:45:04 -04:00
adlee-was-taken
cdb008c900 merge(cli): dev-b B7 (rotate-key) + B8 (status/audit) — reviewed; rotate re-encrypts all blobs, owner-only, concurrent-rotation abort 2026-06-20 13:40:36 -04:00
adlee-was-taken
053062effd feat(cli/org): status + audit (verified-signer attribution, TAMPERED flag, committer-date framing) 2026-06-20 13:24:35 -04:00
adlee-was-taken
3b6dbbe353 fix(cli/org): rotate-key writes member key blobs atomically (crash-safe) 2026-06-20 13:17:16 -04:00
adlee-was-taken
558da3bd75 feat(cli/org): rotate-key — re-encrypt every item blob + abort on concurrent rotation 2026-06-20 12:58:00 -04:00
adlee-was-taken
9c43f223f5 merge(cli): dev-b org stream B1-B6 — session, init, member/collection admin commands (dormant until B14 wiring) 2026-06-20 12:51:37 -04:00
adlee-was-taken
1c177871a7 feat(cli/org): create-collection, grant, revoke commands 2026-06-20 12:44:32 -04:00
adlee-was-taken
1ad8eb0918 feat(cli/org): add-member (owner-only escalation guard), remove-member, set-role 2026-06-20 12:38:48 -04:00
adlee-was-taken
aace6f132a harden(server): explicit verify-commit success gate + non-member/genesis hook tests
- verify_org_signer now rejects on a non-zero git verify-commit exit instead of
  relying on the stderr fingerprint regex alone (PM hardening note 1).
- org_hook_signed: add commit_signed_by_non_member_is_rejected (exercises the
  signature rejection path) and genesis_bootstrap_with_sole_owner_is_accepted.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 12:36:04 -04:00
adlee-was-taken
dbdb3f6ab0 refactor(cli/org): align org init main.rs wiring to OrgCommands + global --dir (B14-shaped) + assert org-init trailer 2026-06-20 12:33:07 -04:00
adlee-was-taken
7faedf8578 feat(cli/org): org init — structure + wrap + configure_git_signing + signed bootstrap commit 2026-06-20 10:27:08 -04:00
adlee-was-taken
ccb58d8bb5 feat(server): verify-org-commit — signature + path-scoped role/grant auth + owner-only elevation (parent-role authority) + schema monotonicity + generate-org-hook
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 10:21:15 -04:00
adlee-was-taken
570b0ddcd3 feat(cli/org): UnlockedOrgVault session (collection-scoped item_path, fingerprint match, signed org_git_run) 2026-06-20 09:48:15 -04:00
adlee-was-taken
7daedb33e0 feat(cli/org): org commands module stub + pub mod wiring 2026-06-20 09:43:43 -04:00
adlee-was-taken
17df315f0e feat(cli/device): current_device_seed + current_device_pubkey helpers
Read the active device's ed25519 seed/pubkey from
devices/<name>/signing.{key,pub}. Adds ssh-key (0.6) as a CLI dep
(already at 0.6.7 in the workspace lock via relicario-core) and
ed25519-dalek as a dev-dep for the round-trip test.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 09:43:43 -04:00
adlee-was-taken
2dd5d79f36 refactor(server): fold in PM review notes on classify_path
- classify_path now Rejects a collection slug containing '.' (mirrors
  OrgCollections::validate, plan L317, and item_path's documented contract,
  plan L990). Unreachable today since git normalizes './' away, but keeps the
  pre-receive hook self-defensive against path traversal.
- Rename test item_write_nested_slug_takes_leading_segment_only ->
  item_write_nested_slug_is_rejected (it asserts Rejected; old name misled).
- Add dotted_slug_is_rejected covering the new guard.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M5brcDrT35r5GaJySXD5ja
2026-06-20 00:04:39 -04:00
adlee-was-taken
675b7836e1 feat(server): lib target + pure org-hook helpers (classify_path, extract_schema_version) + unit tests 2026-06-20 00:04:39 -04:00
adlee-was-taken
743a46f3d5 test(core/org): full org lifecycle integration tests
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TJo44YM3UbBjro2fG6NrKy
2026-06-19 23:44:15 -04:00
adlee-was-taken
409ddce049 feat(core/org): encrypt/decrypt_org_manifest vault wrappers
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TJo44YM3UbBjro2fG6NrKy
2026-06-19 23:24:55 -04:00
adlee-was-taken
631608e6e5 refactor(core/org): drop unreachable unwrap in unwrap_org_key; assert hex in OrgId test
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TJo44YM3UbBjro2fG6NrKy
2026-06-19 23:14:27 -04:00
adlee-was-taken
ca4936cf95 feat(core/org): org types, manifest, and X25519 key wrap/unwrap (Zeroizing KDF)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TJo44YM3UbBjro2fG6NrKy
2026-06-19 23:07:13 -04:00
adlee-was-taken
da4dc44f80 feat(core/org): add x25519-dalek dep + stub org module
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TJo44YM3UbBjro2fG6NrKy
2026-06-19 22:51:27 -04:00
adlee-was-taken
f249395644 fix(plan/C1): close Admin→Owner escalation in enforce_owner_only_elevation
Spot-check of the new H-C1 hook code found the owner-only-elevation gate was
bypassable: it skipped any member ALREADY privileged in the parent, but since
Admin is also "privileged", an Admin→Owner promotion was skipped and accepted —
the exact escalation the gate exists to stop, and a failure of its own paired
test. Gate now skips only UNCHANGED roles (parent role == new role), so every
change into a privileged role (Member→Admin/Owner, Admin→Owner, new privileged
member) requires an owner signer.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 20:00:09 -04:00
adlee-was-taken
b655024320 docs(plan,spec): apply re-verification fixes (5 high + 5 med + 6 low)
Re-verification gate cleared all original criticals; these close the residual
defects the reassembly leaked back in:

HIGH:
- H-D1: add ssh-key dep to relicario-wasm; two-step PrivateKey::from; drop false note
- H-D2: org_open_with_registered_device unwraps inside WASM (DEVICE_STATE seed,
  session-only); device private key never crosses to JS
- H-D3: extension grant-filters the org manifest (members.json → member grants →
  filter_for_member) to honor the spec parity promise
- H-C1: hook diffs {commit}^:members.json, rejects owner/admin escalation unless
  signer is Owner; adds signed-commit hook test
- H-B4: reorder B4 tests to "org init --dir <path>" (subcommand-scoped global)

MEDIUM: trash=item-delete + item-restore vocabulary reconciled; real
transfer-ownership (demote caller unless --keep-owner); delete-org local-only
caveat in spec; pinned RFC8032 X25519 KAT.

LOW: org init honors RELICARIO_ORG_DIR; D3 VaultEntry type pinned; static_secrets
in File Map/Tech Stack; --format <table|json>; hook slug-in-collections check;
spec-mandated integration tests (TAMPERED, audit JSON, rotate race, remove→rotate
decrypt-denial).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 19:54:04 -04:00
adlee-was-taken
8c19e3cfda docs(plan): rewrite org-vault plan per review — 25 tasks, 4 streams
Corrects every critical/high finding from the adversarial review and adds the
two scope expansions (full item CRUD + extension parity):

- Device-key helpers built on the real devices/<name>/signing.{key,pub} layout
  + ssh-key CLI dep (was: invented ~/.config/relicario/device.key)
- Signature-verifying pre-receive hook on every commit + path-scoped write
  authz via items/<slug>/<id>.enc (was: bare %GF, unenforceable flat items)
- Org item CRUD (add/get/list/edit/rm/restore/purge), collection-scoped
- Audit attributed to verified signer + TAMPERED flag (was: spoofable trailers)
- rotate-key re-encrypts every item blob (was: manifest only)
- Zeroize KDF intermediates; fix ssh_key::PrivateKey::from test helpers
- Owner-only role-gating; fingerprint-based member matching; %x1e/%x1f audit
  parser framing; signed org commits via org_git_run
- Extension stream (WASM bindings + SW org session + switcher + 3 vitest tests)
- Stream-prefixed task IDs (A/B/C/D) with explicit cross-stream deps
- Living-docs task

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 19:22:09 -04:00
adlee-was-taken
21ed8d83b8 docs(spec): revise org-vault design per adversarial review
Path-scoped collection storage (items/<slug>/<id>.enc) for hook-enforceable
writes; signature-verifying pre-receive hook on every commit; audit actor from
verified signer (trailers advisory + TAMPERED flag); org item CRUD in scope;
rotate-key re-encrypts all items; transfer/delete-org; extension parity in
phase 1; living-docs impact section.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 18:50:21 -04:00
adlee-was-taken
ac6756e698 fix(workflow/release): parse string args 'action mode release-label' 2026-06-19 11:09:34 -04:00
adlee-was-taken
2543ed30f6 docs(plan): enterprise org vault implementation plan
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-06 21:22:15 -04:00
adlee-was-taken
2a6f6f1307 docs(spec): enterprise org vault design — git-native multi-user org
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-06 21:06:34 -04:00