Commit Graph

794 Commits

Author SHA1 Message Date
adlee-was-taken
1ce37f714e fix(ext): org writes refresh + re-sync the cached org manifest (visible after add/update/delete)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LKBbrAjmpVXMEK15pNi3Ha
2026-06-27 14:34:27 -04:00
adlee-was-taken
61fbafaa30 feat(ext): org write UI — collection picker, edit/delete, offline-gated across all 7 item types
- Add write-routing.ts: writesEnabled(), messageForAdd/Update/Delete(),
  collectionPickerHtml(), selectedCollectionSlug() — shared helpers that
  route to personal or org SW messages by context, gate on orgOffline.
- Un-hide edit/trash buttons in all 7 type-module detail views; render
  them disabled when writesEnabled() is false (org offline).
- Add if (!writesEnabled()) return guard to edit/trash click handlers and
  keyboard 'e'/'d' shortcuts across all 7 modules.
- Route delete through messageForDelete() in all 7 modules (personal →
  delete_item, org → org_delete_item).
- Insert collectionPickerHtml() into add forms across all 7 modules;
  route save through messageForAdd/Update() using selectedCollectionSlug().
- Un-gate '+ new' button and keyhint in item-list.ts: shows when
  writesEnabled() (personal always; org when online); hides when offline.
- Fix pre-existing error-copy gap: add org_offline and
  collection_not_granted entries (Task 3 SW handlers emitted these codes
  without corresponding user-facing copy).
- Tests: write-routing.test.ts (21 tests, truth-table + route assertions);
  org-write-ui.test.ts (13 tests, collection picker / personal unchanged /
  offline disable / org_delete_item routing). Updated item-list.test.ts
  and detail-read-only.test.ts to reflect new online-org behavior.
2026-06-27 14:20:39 -04:00
adlee-was-taken
50a05affcb feat(ext/sw): org_add/update/delete_item — signed commits via commitSigned + manifest landmine guard
Implements Task 3 of v0.9.0 Plan C: three org-write SW handlers in org-handlers.ts.
Each handler decrypts the FULL manifest via org_manifest_decrypt (unfiltered) before
mutating it — never state.manifest (filtered) — preventing silent wipe of ungranted
collection entries on re-encrypt. Grant checked before any network call for add;
checked post-lookup for update/delete. Delete is manifest-only (soft-delete via
trashed_at); item blob stays on disk. All three return org_offline when offline.
Commit signer built from get_device_info + rawSign wrapping sign_for_git output.

Wired: PopupMessage union + POPUP_ONLY_TYPES (messages.ts) + dispatch (popup-only.ts).
Tests: 7/7 org-write.test.ts (RED→GREEN); full SW suite 210/210; tsc clean.
2026-06-27 13:54:53 -04:00
adlee-was-taken
e0dd5590bc Merge remote-tracking branch 'origin/main' into feature/v0.9.0-dev-c-org-write 2026-06-27 13:42:49 -04:00
adlee-was-taken
a530e4423b merge: feature/v0.9.0-dev-b-org-read-ui (v0.9.0 Dev-B org read UI + add-org config flow) 2026-06-27 13:40:16 -04:00
adlee-was-taken
39fe7bf6e2 Merge remote-tracking branch 'origin/main' into feature/v0.9.0-dev-b-org-read-ui
# Conflicts:
#	extension/src/shared/error-copy.ts
2026-06-27 13:35:18 -04:00
adlee-was-taken
33dd018ea6 merge: feature/v0.9.0-dev-a-org-foundation (v0.9.0 Dev-A org foundation: SW+WASM, device-key persist/restore, org read) 2026-06-27 13:25:55 -04:00
adlee-was-taken
7c6e6fe32a feat(ext): org error-copy entries for ERROR_COPY coverage gate
The full-suite meta-test (src/shared/__tests__/error-copy.test.ts) requires a
user-facing ERROR_COPY entry for every literal 'ok: false, error: <code>' the SW
returns. The org handlers added org_not_configured (literal) with no copy → RED.
Add org_not_configured plus copy for the org codes that reach the popup via
thrown err.message (not_an_org_member, device_key_unavailable, not_in_org_context,
org_switch_failed). item_not_found already had an entry. (Dev-B added some of
these independently; B reconciles the wording when it syncs main post-merge.)

Full extension vitest: 70 files / 478 tests green (incl. error-copy 3/3).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014s527M917W47LDrfQ4t47g
2026-06-27 13:15:21 -04:00
adlee-was-taken
cc4d4e8f36 fix(ext): enforce org read-only in detail/drawer + context-aware vault drawer + escape switcher options 2026-06-27 12:52:36 -04:00
adlee-was-taken
59b0fcd985 feat(ext): add-org form + switcher trigger (org_add_config UI)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W3b8DA2mXmLWkd4zDbHXHg
2026-06-27 12:28:24 -04:00
adlee-was-taken
11e3aa41d1 feat(ext/sw): org_add_config message + handler (device-local org config write)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W3b8DA2mXmLWkd4zDbHXHg
2026-06-27 12:23:57 -04:00
adlee-was-taken
e370b06f85 feat(ext): org collection facet + collection filter in the vault sidebar
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W3b8DA2mXmLWkd4zDbHXHg
2026-06-27 12:17:36 -04:00
adlee-was-taken
dd0b415cdf refactor(ext): load org entries in the shared switcher (works in popup + vault tab)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W3b8DA2mXmLWkd4zDbHXHg
2026-06-27 12:01:06 -04:00
adlee-was-taken
c327c21fdc feat(ext): list/detail load + render org items in org context (normalized, read-only) 2026-06-27 11:47:50 -04:00
adlee-was-taken
183a3f0a81 fix(ext): ERROR_COPY entries for org context errors (read-UI surfacing)
A's org foundation returns org_not_configured (ok:false) plus thrown not_an_org_member /
device_key_unavailable, none of which had user-facing copy — they would render as the raw
code. Add friendly copy (org_not_configured ties into the add-org flow) and a focused test;
fixes the ERROR_COPY-coverage test that the foundation merge left red.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W3b8DA2mXmLWkd4zDbHXHg
2026-06-27 11:37:42 -04:00
adlee-was-taken
37fb76ab97 feat(ext): org context switcher (popup header + vault sidebar) + offline read-only banner 2026-06-27 11:31:20 -04:00
adlee-was-taken
eae07e778b merge: origin/main (Dev-E keyfile-ext + D-minors) into org-foundation
A-vs-E keep-both integration in 3 security-sensitive SW files:
- shared/messages.ts: kept E's attach_vault keyfile second-factor fields
  (secondFactor/referenceImageBytes?/keyfileBytes?) AND my 4 org message types.
- vault.ts: registerDeviceAndPersistConfig auto-merged to take BOTH E's
  factorStorage (image|keyfile) AND my handle (Task 4.5 device-key persist);
  both create/attach call sites pass (factorStorage, deviceName, h) so each
  flow does E secret-gen AND my register+persist in one coherent path.
- router/popup-only.ts: took E's 'unlock' -> handleUnlock refactor and moved my
  device-key restore + migration into handleUnlock's shared tail (after
  setCurrent, before manifest fetch) so it runs for both image + keyfile unlock.
- keyfile-unlock.test.ts: makeWasm mock gains persist_device_key + restore_device_key
  stubs (the merged create/attach/unlock flow now calls them) — no assertion weakened.

Gates: SW vitest 175/175 (18 files); cargo core+wasm 243/0; wasm32 build clean;
clippy -D warnings clean; build:all clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014s527M917W47LDrfQ4t47g
2026-06-27 11:22:17 -04:00
adlee-was-taken
aceeb30af9 feat(ext): PopupState org fields + context-aware message helper org branches 2026-06-27 11:21:31 -04:00
adlee-was-taken
7913e3ad84 fix(ext/sw): free org handle on openOrg error path (no org-key leak past lock)
Security review I1: openOrg's org_unwrap_key inserts the org master key into the
WASM session at step 7, but on the non-cached manifest-error path the handle was
never returned / registered via session.setOrg — so session.clearAll() (lock +
inactivity timeout) could not see it, and the org key would outlive a failed open
(GC-backstopped, non-deterministic). Triggers on a corrupt manifest.enc or a
first-switch network error with no cache. Free the handle before rethrowing.
Adds a test asserting the error path frees the handle.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014s527M917W47LDrfQ4t47g
2026-06-27 11:05:58 -04:00
adlee-was-taken
8b97ebc01a Merge remote-tracking branch 'origin/main' into feature/v0.9.0-dev-c-org-write 2026-06-27 11:04:23 -04:00
adlee-was-taken
7932703bc1 docs(status): keyfile track complete (D+minors+E merged); org track in progress (A I1-fix gated, B building+config-add, C held)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013Hc6Rvdz3DxLucqNtPE2iP
2026-06-27 11:04:09 -04:00
adlee-was-taken
72988eb481 Merge remote-tracking branch 'origin/feature/v0.9.0-dev-a-org-foundation' into feature/v0.9.0-dev-b-org-read-ui 2026-06-26 23:06:29 -04:00
adlee-was-taken
2ff5e5b584 merge: feature/v0.9.0-dev-e-keyfile-ext (v0.9.0 Dev-E keyfile extension + positioning) 2026-06-26 22:57:45 -04:00
adlee-was-taken
7a6cfb5659 test(ext/sw): cover handleUnlock keyfile error paths (forward-compat guard, invalid_key_file, key-file-not-set) 2026-06-26 22:51:10 -04:00
adlee-was-taken
98861218f9 docs(formats): pin KdfParams citation to crypto.rs:180 (line shifted post-merge) 2026-06-26 22:48:03 -04:00
adlee-was-taken
f9b8f3821d feat(ext/sw): org_switch + org read messages (grant-filtered, offline-aware, cache cleared on lock)
Wires 4 SW messages to the org-vault.ts read functions (Task 5b):
- org_switch: opens org vault via openOrg(), caches OrgHandleState, sets
  session context; switching to 'personal' resets context without openOrg.
  Offline-aware: if openOrg throws a network error and a prior cached state
  exists, reuses it read-only (offline:true) via exported isNetworkError.
- org_list_items: returns cached, grant-filtered OrgManifestEntry[] (not
  personal ManifestEntry[]) via listOrgItems(requireCurrentOrgState()).
- org_get_item: decrypts a single org item via getOrgItem.
- org_list_collections: returns granted Collection[] via listOrgCollections.

Three-place rule satisfied for all 4 messages:
1. messages.ts PopupMessage union (4 variants)
2. messages.ts POPUP_ONLY_TYPES (4 entries)
3. popup-only.ts switch (4 case arms)

Cache lifecycle / use-after-free guard:
- clearOrgCache() added to org-handlers.ts; exports.
- Called in popup-only.ts 'lock' handler (before session.clearCurrent).
- Called in index.ts inactivity-timer onExpired (before clearCurrent).

Plan doc fixes:
- Line ~410: org_list_items return type corrected to OrgManifestEntry[].
- Line ~47: org_unwrap_key signature updated (no device_private_key_base64
  param — reads DEVICE_STATE internally).

9 new tests in org-handlers.test.ts (TDD: all watched fail before passing).
Full SW suite: 167 tests (17 files) green. build:all type-checks clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014s527M917W47LDrfQ4t47g
2026-06-26 22:45:09 -04:00
adlee-was-taken
df3aa319e7 Merge remote-tracking branch 'origin/main' into feature/v0.9.0-dev-e-keyfile-ext 2026-06-26 22:33:45 -04:00
adlee-was-taken
2eb49ac217 feat(ext/sw): org-vault read core (openOrg, grant-filtered list, collection-scoped get, offline)
- Add extension/src/service-worker/org-vault.ts: openOrg (members.json fingerprint
  match → org_unwrap_key → org_manifest_decrypt_filtered), listOrgItems, getOrgItem
  (collection-scoped path: items/<collection>/<id>.enc), listOrgCollections (grants filter).
- Add OrgMember, OrgMembers, CollectionDef, OrgCollections, Collection types to shared/types.ts
  (mirrors relicario-core org.rs shapes).
- Add 8-test suite covering: fingerprint match, not_an_org_member, listOrgItems passthrough,
  collection-scoped item path, listOrgCollections grant filter, storage.set never called,
  offline fallback (TypeError → cached manifest), offline with no cache → rethrow.
- Fix plan doc line ~326: wasm.manifest_decrypt → wasm.org_manifest_decrypt_filtered.

Gate results: 158/158 SW tests pass; npm run build:all clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014s527M917W47LDrfQ4t47g
2026-06-26 22:30:39 -04:00
adlee-was-taken
73877bad78 docs: pin keyfile.rs/second_factor citations; state the second factor is never pushed to the remote 2026-06-26 22:24:57 -04:00
adlee-was-taken
288956c089 feat(core,wasm): filter_by_collections single-source + org_manifest_decrypt_filtered
Add OrgManifest::filter_by_collections(&[String]) as the single source of
grant-filter logic. Refactor filter_for_member to delegate to it (no
duplicated loop). Add org_manifest_decrypt_filtered WASM binding that
decrypts + filters in core so ungranted entries never cross to JS (phase-1
SOFT/UX filter; per-collection crypto isolation is phase-2). Declare the
binding in extension/src/wasm.d.ts. Vec<String> compiled cleanly for
wasm32-unknown-unknown.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014s527M917W47LDrfQ4t47g
2026-06-26 22:19:55 -04:00
adlee-was-taken
201bf05adc feat(ext/setup+sw): attach via key file when the vault uses one (probe second_factor, .relkey picker, handleAttachVault keyfile branch)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014THSV6cA4Gxa7bxFfisHBB
2026-06-26 22:19:41 -04:00
adlee-was-taken
0d56b3333b feat(ext/sw): persist device key at register, restore at unlock (+ migration)
- Add `persistDeviceKey(w, handle)` to vault.ts: calls
  `w.persist_device_key(handle)` and stores the ciphertext as base64
  in chrome.storage.local `device_key_enc`.
- Wire into `registerDeviceAndPersistConfig` (create + attach flows)
  so the key is persisted immediately after every `register_device`.
- Wire into `register_this_device` handler via `session.requireCurrent()`.
- Restore at unlock: if `device_key_enc` present, call
  `w.restore_device_key(handle, blob)`; failure is caught + logged but
  must not block unlock.
- Migration for pre-4.5b installs (absent `device_key_enc`): re-register,
  persist new key, addDevice to remote (best-effort, must not block).
  New device identity — org members must be re-granted to new pubkey.
- 4 new tests in device-key-persist.test.ts; existing 146 tests updated
  and kept green; router.test.ts register_this_device stub extended.
2026-06-26 22:13:50 -04:00
adlee-was-taken
2f7a034a1b feat(ext/setup): download the generated .relkey at finish + skip carrier gate in keyfile mode
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014THSV6cA4Gxa7bxFfisHBB
2026-06-26 22:07:14 -04:00
adlee-was-taken
e6ec210736 fix(wasm): zeroize transient device-private-key copy in export_state_bytes
Review fix (Important secret-hygiene finding): export_state_bytes built a
PersistedDeviceState via state.signing_private.as_str().to_owned(), creating
non-zeroized heap copies of the device ed25519 private keys (signing + deploy)
that lingered as plaintext residue after the struct dropped.

- Cargo.toml: enable zeroize "derive" feature (zeroize_derive already in lock tree)
- device.rs: PersistedDeviceState now derives Zeroize + ZeroizeOnDrop, wiping all
  String fields on every drop path (success, serde_json::to_vec ? error path, panic)
- device.rs: import_state_bytes uses std::mem::take per field (ZeroizeOnDrop adds a
  Drop impl, so fields can no longer be moved out — E0509); mem::take transfers the
  heap buffers without copying, leaving empty Strings the drop-zeroize no-ops
- doc-comments updated to describe the ZeroizeOnDrop / mem::take hygiene

Hygiene-only; no behavior change. Gates: cargo test -p relicario-wasm 15/15,
clippy -D warnings clean, build --target wasm32-unknown-unknown clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014s527M917W47LDrfQ4t47g
2026-06-26 22:01:00 -04:00
adlee-was-taken
d3f46389e4 feat(ext/sw): unlock resolves second factor from params hint (keyfile branch)
Extract handleUnlock from popup-only.ts handle() switch, add keyfile branch
(keyfile_decode + unlock_with_secret), forward-compat guard for unknown
second_factor values, loadKeyfileBase64 helper, loadSetupState isConfigured
fix for keyfile vaults. Register error copy for three new error codes.
Un-skip Task 4 TDD test — 440/440 green, build clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014THSV6cA4Gxa7bxFfisHBB
2026-06-26 21:59:17 -04:00
adlee-was-taken
2262272b20 merge: fix/v0.9.0-keyfile-minors (v0.9.0 Dev-D keyfile security-review minors) 2026-06-26 21:54:05 -04:00
adlee-was-taken
be619f8ed0 feat(wasm): persist/restore device key under master key; org_unwrap_key reads DEVICE_STATE
- device.rs: add PersistedDeviceState (serde mirror), export_state_bytes
  (plaintext JSON in Zeroizing<Vec<u8>>, NOT a wasm_bindgen export),
  import_state_bytes (repopulates DEVICE_STATE with Zeroizing<String> keys),
  signing_seed (extracts ed25519 seed via core::device::extract_ed25519_seed)
- lib.rs: add persist_device_key (#[wasm_bindgen], encrypts state bytes under
  master key via relicario_core::crypto::encrypt; ciphertext only reaches JS),
  restore_device_key (#[wasm_bindgen], decrypts inside WASM then calls
  import_state_bytes; plaintext never leaves WASM)
- lib.rs: refactor org_unwrap_key to drop device_private_openssh param; reads
  seed from DEVICE_STATE via device::signing_seed()
- lib.rs: update org_unwrap_key_yields_a_session_that_decrypts_org_blobs to
  new signature (register_device first, use signing_pub for wrap_org_key)
- lib.rs: add device_persist_tests module (4 tests: round-trip, org-unwrap
  post-restore, ciphertext-not-plaintext, no-device-error)
- lib.rs: add DEVICE_TEST_LOCK static to serialize DEVICE_STATE-touching tests
- lib.rs: add #[derive(Debug)] to SessionHandle
- wasm.d.ts: update org_unwrap_key sig; declare persist_device_key +
  restore_device_key

All gates: cargo test -p relicario-wasm (15/15), cargo test -p relicario-core
(no regression), cargo build --target wasm32-unknown-unknown (clean), clippy
-D warnings (clean).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014s527M917W47LDrfQ4t47g
2026-06-26 21:53:24 -04:00
adlee-was-taken
5cc16ddffb feat(ext/sw): create_vault key-file mode (generate secret, unlock_with_secret, store keyfileBase64)
- Add KEYFILE_PARAMS_JSON const (same KDF params as default + second_factor:"keyfile" hint)
- Generalize registerDeviceAndPersistConfig: takes factorStorage union instead of
  referenceImageBytes Uint8Array; spreads { imageBase64 } or { keyfileBase64 } into
  chrome.storage.local.set so exactly one factor key is present
- Branch handleCreateVault on msg.secondFactor === 'keyfile': skip carrier-image
  guards and embed_image_secret; call unlock_with_secret + keyfile_encode; share
  the file-write / device-registration / session tail with the image path
- Update handleAttachVault call to registerDeviceAndPersistConfig to pass
  { imageBase64: uint8ArrayToBase64(referenceImageBytes) }
- Relax carrierImageBytes to optional in messages.ts create_vault request type
- Skip Task-4 describe block in keyfile-unlock.test.ts (un-skip in Task 4)

TDD: Task-2 test RED → GREEN; Task-4 describe.skipped; full suite 439 passed/1 skipped; build clean

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014THSV6cA4Gxa7bxFfisHBB
2026-06-26 21:49:09 -04:00
adlee-was-taken
b2bed1c50e fix(core): zeroize keyfile_encode output + lock-in tests for backup-keyfile-error and malformed-vs-wrong unlock
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01McMF5pUJbCMricmFEnf2sG
2026-06-26 21:45:14 -04:00
adlee-was-taken
ce141480b9 merge: origin/main (Dev-D keyfile, d649203) into org-foundation
Additive conflict in extension/src/wasm.d.ts resolved by keeping BOTH the
org_* declarations (org_unwrap_key/org_manifest_decrypt/org_manifest_encrypt)
and the keyfile_* declarations (unlock_with_secret/keyfile_encode/keyfile_decode).
Rust lib.rs (core + wasm) auto-merged cleanly with both feature sets.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014s527M917W47LDrfQ4t47g
2026-06-26 21:35:56 -04:00
adlee-was-taken
6970893713 Merge remote-tracking branch 'origin/main' into feature/v0.9.0-dev-e-keyfile-ext 2026-06-26 21:35:39 -04:00
adlee-was-taken
956ab6886a Merge remote-tracking branch 'origin/main' into feature/v0.9.0-dev-c-org-write 2026-06-26 21:35:17 -04:00
adlee-was-taken
478dc88296 Merge remote-tracking branch 'origin/main' into feature/v0.9.0-dev-b-org-read-ui 2026-06-26 21:34:03 -04:00
adlee-was-taken
2c5af671d0 docs(coordination): v0.9.0 dev resume prompts after ~21h stall (D merged; A/B/C/E resume)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013Hc6Rvdz3DxLucqNtPE2iP
2026-06-26 21:29:56 -04:00
adlee-was-taken
d649203335 docs(status): Dev-D keyfile core/cli/wasm merged (588495f); keyfile-minors follow-up tracked
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013Hc6Rvdz3DxLucqNtPE2iP
2026-06-26 00:45:50 -04:00
adlee-was-taken
588495fd7b merge: feature/v0.9.0-dev-d-keyfile-core (v0.9.0 Dev-D keyfile core/cli/wasm) 2026-06-26 00:39:55 -04:00
adlee-was-taken
13512ed9bf docs: record v0.9.0 org-write spike decision + device-key prereq (PM)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013Hc6Rvdz3DxLucqNtPE2iP
2026-06-26 00:39:54 -04:00
adlee-was-taken
22068136dc docs(plan-c): mark Task 2 (universal commitSigned) DONE + security-clean
Universal isomorphic-git receive-pack push path shipped & verified: sshsig.ts +
mem-fs.ts + git-push.ts + commitSigned on GitHost/Gitea/GitHub. Full SW suite
163/163, build:all bundles isomorphic-git into the SW, /security-review clean.
Tasks 3-5 remain HELD on Dev-A + Dev-B merge.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LKBbrAjmpVXMEK15pNi3Ha
2026-06-26 00:30:23 -04:00
adlee-was-taken
110f02e4e3 refactor(cli): drop unused param from resolve_second_factor_secret (simplify pass)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01McMF5pUJbCMricmFEnf2sG
2026-06-26 00:19:55 -04:00
adlee-was-taken
d942650f9f fix(ext/sw): model isomorphic-git PushResult correctly; test the real push-rejection throw
PushResult has a singular `error: string | null` and a `refs` map — there
is no top-level `errors: string[]`. Replace the fabricated type and the
`errors`-based rejection guard with a correct PushResultRuntime type and a
belt-and-suspenders refsOk check. The real rejection path is a thrown
GitPushError (isomorphic-git throws, never returns, when a hook declines);
replace the single fiction-testing test with (a) a throw-path test that mocks
push to reject with a GitPushError and (b) a defensive non-throwing test that
mocks push to resolve { ok: false, error: 'unpack failed' }.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LKBbrAjmpVXMEK15pNi3Ha
2026-06-26 00:19:34 -04:00