Commit Graph

303 Commits

Author SHA1 Message Date
e63a36ede0 Implement PendingRequestMap for call protocol
Correlates call.responded events back to call.requested by request ID
(stream-agnostic per ADR-012). Manages Call (oneshot) and Subscribe
(mpsc) entries with timeout-based eviction and fail_all on connection
close. Unknown request IDs are silently discarded.
2026-06-23 14:23:49 +00:00
dabb0d8b68 tasks: mark vault/spec-sync-remove-drift completed 2026-06-23 14:17:39 +00:00
d0f633c71d docs(vault): remove drift tracking artifacts, bump vault docs to stable (task: vault/spec-sync-remove-drift)
Remove the Known Source Drift table from vault/README.md. Remove all 'known
drift'/'current source uses X' prose from Security Constraints in README,
encryption.md, service.md (constraint statements preserved). Remove stale
ADR-025/postcard notes in protocol.md. Bump all 5 vault doc frontmatter to
status: stable. Update architecture/README.md vault doc statuses to stable
and Current State to remove 'pending ADR-025/026 refactor' language.

Refs: docs/architecture/crates/vault/README.md (drift cleanup)
2026-06-23 14:17:10 +00:00
482901db74 tasks: mark core/config completed 2026-06-23 14:16:38 +00:00
323ee85d40 docs(vault): remove drift tracking artifacts, bump vault docs to stable
The vault spec-to-implementation sync is complete. Remove the drift
tracking tools that were only needed during sync:

- Remove the Known Source Drift table from vault/README.md
- Remove 'known drift' / 'current source uses X' prose from Security
  Constraints sections in vault/README.md, encryption.md, and service.md.
  The permanent constraint statements (OsRng for IVs, zeroized drop,
  no unwrap, etc.) are preserved.
- Remove the drift paragraph in encryption.md Key Versioning.
- Remove stale 'to be updated per ADR-025' / 'postcard tests to be
  removed' notes in protocol.md References.
- Bump status: draft -> stable in the frontmatter of all vault docs
  (README, mnemonic-derivation, encryption, service, protocol).
- Update architecture/README.md: vault doc status entries to stable,
  Current State paragraph reflects vault implementation complete (no
  'pending ADR-025/026 refactor' language).
2026-06-23 14:15:13 +00:00
da5646bf46 feat(core): implement StaticConfig, DynamicConfig, AuthPolicy, ApiKeyEntry, RateLimitConfig, ConfigReloadHandle, TlsIdentity, ConfigError (task: core/config)
Implement all configuration types in config.rs: StaticConfig (drain_timeout=2s
default), TlsIdentity (X509/RawKey[iroh-gated]/SelfSigned), DynamicConfig
(Clone/Debug/Default, ArcSwap-reloadable), AuthPolicy (String fingerprints, no
russh), ApiKeyEntry (5 fields), RateLimitConfig (100/5 defaults),
ConfigReloadHandle (reload/dynamic via ArcSwap), ConfigError (thiserror, all
variants). iroh_relay and RawKey feature-gated to iroh. 14 unit tests.

Refs: docs/architecture/crates/core/config.md
Implements: ADR-003, ADR-010

# Conflicts:
#	crates/alknet-core/src/config.rs
2026-06-23 14:14:51 +00:00
e98cfa77d8 Implement core/config: StaticConfig, DynamicConfig, AuthPolicy, ApiKeyEntry, RateLimitConfig, ConfigReloadHandle, TlsIdentity, ConfigError
- StaticConfig: immutable startup config (listen_addr, tls_identity, iroh_relay, drain_timeout=2s)
- TlsIdentity enum: X509, RawKey (iroh feature-gated), SelfSigned
- DynamicConfig: hot-reloadable via ArcSwap (auth + rate_limits), derives Clone/Debug/Default
- AuthPolicy: authorized_fingerprints (HashSet<String>), api_keys (Vec<ApiKeyEntry>) — no russh dep
- ApiKeyEntry: prefix/hash/scopes/description/expires_at
- RateLimitConfig: max_connections_per_ip=100, max_auth_attempts=5
- ConfigReloadHandle: reload() atomic swap, dynamic() load_full
- ConfigError: thiserror enum with all variants

14 unit tests covering defaults, construction, atomic reload swap, and error displays.
2026-06-23 14:11:07 +00:00
b93a85a280 tasks: mark vault/review-vault-sync and core/auth completed 2026-06-23 14:10:54 +00:00
a4b4d89d8f feat(core): implement AuthContext, Identity, AuthToken, IdentityProvider, ConfigIdentityProvider (task: core/auth)
Implement authentication types in auth.rs: AuthContext (Clone, 4 fields),
Identity (Clone, PartialEq), AuthToken, IdentityProvider trait (resolve_from_
fingerprint + resolve_from_token), ConfigIdentityProvider (reads from
ArcSwap<DynamicConfig> on every call — hot-reloadable). Fingerprint resolution
via authorized_fingerprints HashSet, token resolution via alk_ prefix + SHA-256
hash + expiry check. Also implemented minimal config.rs types (DynamicConfig,
AuthPolicy, ApiKeyEntry, RateLimitConfig, ConfigReloadHandle) needed by auth —
aligned with architecture docs for the parallel core/config task to extend.

27 unit tests pass; clippy clean.

Refs: docs/architecture/crates/core/auth.md
Implements: ADR-004, ADR-011
2026-06-23 14:10:06 +00:00
d7d879a3fa vault: spec-conformance fixes from review (task: vault/review-vault-sync)
Review of vault crate against all architecture specs. Fixed 5 deviations:
1. EncryptionKey: removed Clone (now move-only per spec), added redacting Debug
2. EncryptionKey::new made private (cfg(test)), added pub(crate) key_bytes()
3. encrypt/decrypt made pub(crate) per encryption.md, low-level crypto tests
   moved from integration to unit tests
4. CachedKey refactored to wrap DerivedKey with cached_at/last_accessed fields
   per service.md, with key_type()/private_key()/public_key() accessors
5. Mnemonic::to_seed() unwrap() eliminated by storing validated Bip39Mnemonic
   (enabled bip39 zeroize feature for proper zeroization)

All 10 drift items verified resolved. 105 tests pass; clippy clean.

Refs: docs/architecture/crates/vault/README.md (review checklist)
2026-06-23 14:09:36 +00:00
20b5c640ec tasks: mark call/protocol/wire-types completed 2026-06-23 14:08:50 +00:00
8dc842b1f4 feat(core): implement AuthContext, Identity, AuthToken, IdentityProvider, ConfigIdentityProvider (task: core/auth)
- auth.rs: Identity, AuthContext, AuthToken, IdentityProvider trait, ConfigIdentityProvider
- ConfigIdentityProvider reads from ArcSwap<DynamicConfig> on every call (hot-reloadable)
- Fingerprint resolution via authorized_fingerprints; token resolution via alk_ prefix + SHA-256 hash + expiry check
- config.rs: minimal DynamicConfig, AuthPolicy (with resolve methods), ApiKeyEntry, RateLimitConfig, ConfigReloadHandle required by auth
- Unit tests: fingerprint resolution (known/unknown/empty), token resolution (valid/expired/unknown/wrong-hash/non-alk), config reload changes results immediately
- Add sha2, hex deps to alknet-core
2026-06-23 14:08:33 +00:00
55404e52a3 feat(call): implement wire protocol types and framing (task: call/protocol/wire-types)
Implement EventEnvelope, ResponseEnvelope, CallError, FrameError, and
FrameFramedReader/FrameFramedWriter with 4-byte big-endian length-prefixed JSON
framing in protocol/wire.rs. Added ResponseEnvelope helpers (ok/error/not_found/
forbidden) and ResponseEnvelope→EventEnvelope conversion. 20 unit tests.

Refs: docs/architecture/crates/call/call-protocol.md
Implements: ADR-005, ADR-012, ADR-023
2026-06-23 14:08:03 +00:00
41f0fc7843 vault: spec-conformance fixes from review (task: vault/review-vault-sync)
- EncryptionKey: remove Clone (move-only per spec), add custom redacting
  Debug impl, make new() private (cfg(test)), add pub(crate) key_bytes()
  accessor, make encrypt/decrypt pub(crate) module-internal helpers
- CachedKey: refactor to wrap DerivedKey (per service.md) with cached_at
  and last_accessed fields; add key_type()/private_key()/public_key()
  accessors
- Mnemonic: store validated Bip39Mnemonic to eliminate unwrap() in
  to_seed(); enable bip39 zeroize feature so inner is zeroized on drop
- Fix clippy: remove unused import in drop_tracker tests, use struct
  init syntax instead of field reassignment with Default
- Move low-level EncryptionKey round-trip/wrong-key tests from
  integration tests to unit tests (encrypt/decrypt now pub(crate))
2026-06-23 14:07:24 +00:00
c9898566b9 Implement call protocol wire types and framing
Implements src/protocol/wire.rs with:
- EventEnvelope (type/id/payload, JSON wire format with leading-slash op ids)
- ResponseEnvelope and CallError (with optional typed details, ADR-023)
- ResponseEnvelope::ok/error/not_found/forbidden helpers
- ResponseEnvelope -> EventEnvelope conversion (Ok -> call.responded, Err -> call.error)
- FrameFramedReader / FrameFramedWriter: 4-byte big-endian length-prefixed JSON frames
- FrameError: Io, Json, ConnectionClosed, InvalidFrame
- 20 unit tests covering round-trip, large payloads, truncated frames, helpers

Builds on the call/crate-init skeleton. See
docs/architecture/crates/call/call-protocol.md and ADR-005/012/023.
2026-06-23 14:06:48 +00:00
e0ccdc28ac tasks: mark call/registry/operation-spec completed 2026-06-23 14:06:26 +00:00
6d536a3bf5 feat(call): implement OperationSpec, AccessControl, Visibility, ErrorDefinition (task: call/registry/operation-spec)
Implement operation specification types in registry/spec.rs: OperationSpec (with
path() returning /{name}, namespace derived from name), OperationType (Query,
Mutation, Subscription), Visibility (External, Internal), ErrorDefinition (ADR-023),
AccessControl::check returning AccessResult (AND/OR scope checks, resource checks,
None identity → 'authentication required', empty ACL → Allowed). 9 unit tests.

Refs: docs/architecture/crates/call/operation-registry.md
Implements: ADR-015, ADR-023
2026-06-23 14:04:42 +00:00
b46fc81dc5 Implement OperationSpec, AccessControl, Visibility, ErrorDefinition 2026-06-23 14:03:27 +00:00
669feab741 tasks: mark core/core-types completed 2026-06-23 13:54:28 +00:00
96938092ca feat(core): implement core types — ProtocolHandler, Connection, Capabilities (task: core/core-types)
Implement all core types in types.rs: ProtocolHandler trait (alpn + handle),
HandlerError (4 variants), Connection (quinn/iroh feature-gated enum dispatch,
OnceLock write-once identity, accept_bi/open_bi/close/remote_alpn/remote_addr),
BiStream trait, SendStream/RecvStream AsyncWrite/AsyncRead wrappers, StreamError,
From<StreamError> for HandlerError, Capabilities (Zeroize+ZeroizeOnDrop, immutable
builder API, Secret<String> wrapper, non-serializable), IdentityAlreadySet. Added
minimal Identity/AuthContext in auth.rs as foundation for the auth task.

Notable: quinn::Connection has no alpn() accessor so ALPN is stored separately
(from_quinn_with_alpn); iroh 0.35 types accessed via iroh::endpoint::*; iroh
Connection has no remote_address (returns None per spec).

Refs: docs/architecture/crates/core/core-types.md
Implements: ADR-002, ADR-007, ADR-014, ADR-022
2026-06-23 13:53:47 +00:00
8611935f1a feat(core): implement core types (ProtocolHandler, Connection, Capabilities)
Implements the foundational types in alknet-core/src/types.rs per the
core-types architecture (ADRs 002, 007, 014, 022):

- ProtocolHandler trait (alpn + async handle) with HandlerError
- Connection wrapping quinn/iroh via internal enum dispatch (feature-gated);
  write-once identity via OnceLock, IdentityAlreadySet on second set
- SendStream/RecvStream concrete wrappers implementing AsyncWrite/AsyncRead
- BiStream convenience trait
- StreamError with canonical From<StreamError> for HandlerError
- Capabilities: non-serializable, Zeroize + ZeroizeOnDrop, immutable builder
  API (new/with_api_key/with_http_token/get) backed by a Secret<String> wrapper
- Minimal Identity and AuthContext in auth.rs as the foundation the auth task
  extends

13 unit tests cover Capabilities (build/get/clone/zeroize/redaction) and
Connection::set_identity (once succeeds, twice errors). Verified across
feature combos (default, no-default, iroh-only): build, clippy -D warnings,
test, fmt --check all clean.

(task: core/core-types)
2026-06-23 13:49:12 +00:00
016c30691d tasks: mark call/crate-init completed 2026-06-23 13:47:49 +00:00
51f80e90bb feat(call): initialize alknet-call crate skeleton (task: call/crate-init)
Create crates/alknet-call with Cargo.toml (deps: alknet-core path, irpc workspace,
tokio, serde, serde_json, async-trait, tracing, thiserror, uuid, futures), src/lib.rs,
and module skeletons for registry (spec, context, registration, env, discovery) and
protocol (wire, pending, connection, adapter, abort). Added to workspace members.

Refs: docs/architecture/crates/call/README.md
Implements: ADR-003, ADR-005
2026-06-23 13:46:11 +00:00
e13a150d9f feat(call): initialize alknet-call crate skeleton (task: call/crate-init)
Create crates/alknet-call with Cargo.toml, lib.rs, and module skeletons
for the registry (spec, context, registration, env, discovery) and
protocol (wire, pending, connection, adapter, abort) subsystems. Add the
crate to the workspace members list. Depends on alknet-core (workspace
path), irpc (workspace dep), tokio, serde, serde_json, async-trait,
tracing, thiserror, uuid, and futures. Implements ProtocolHandler on
ALPN alknet/call per docs/architecture/crates/call.
2026-06-23 13:45:14 +00:00
968e3a09ee tasks: mark vault/key-versioning-rotation completed 2026-06-23 13:39:37 +00:00
9eab93100e vault: version-indexed encryption key paths, bump CURRENT_KEY_VERSION to 2, add rotate (task: vault/key-versioning-rotation)
Drift items #3, #9, #10: implement the version-indexed key rotation mechanism
(ADR-021). Bump CURRENT_KEY_VERSION to 2 (HD-derived per ADR-020). Add
encryption_path_for_version in derivation.rs, derive_encryption_key_for_version
+ version-aware encrypt/decrypt + rotate method on VaultServiceHandle. Each
version maps to a distinct derivation path; the blob carries its own version.

Refs: docs/architecture/crates/vault/README.md drift #3, #9, #10
Implements: ADR-020, ADR-021

# Conflicts:
#	crates/alknet-vault/src/derivation.rs
#	crates/alknet-vault/src/service.rs
2026-06-23 13:39:05 +00:00
25327b41d4 tasks: mark vault/remove-password-derivation, vault/unlock-new-zeroizing-return, vault/poisoned-lock-recovery completed 2026-06-23 13:36:49 +00:00
bc8e329f90 vault: replace unwrap() on RwLock with poisoned-lock recovery (task: vault/poisoned-lock-recovery)
Drift item #2: replace all .read().unwrap()/.write().unwrap() calls in
VaultServiceHandle with .unwrap_or_else(|e| e.into_inner()) to recover from
poisoned locks instead of bricking the vault. Added test_poisoned_lock_recovery
that poisons the lock via a panicking thread and verifies the vault remains
usable.

Refs: docs/architecture/crates/vault/README.md drift #2
Implements: ADR-025

# Conflicts:
#	crates/alknet-vault/src/service.rs
2026-06-23 13:35:53 +00:00
55d356cb4e feat(vault): version-indexed encryption key paths, CURRENT_KEY_VERSION=2, rotate method (ADR-021)
- Bump CURRENT_KEY_VERSION from 1 to 2 (v1 reserved for TS PBKDF2 legacy per ADR-020)
- Add derivation::encryption_path_for_version(version) -> m/74'/2'/0'/{version-2}', returns InvalidPath for version < 2
- Add VaultServiceHandle::derive_encryption_key_for_version(version), cached by path, returns InvalidPath for version < 2
- encrypt/decrypt now derive at encryption_path_for_version(key_version) instead of fixed PATHS::ENCRYPTION
- Add VaultServiceHandle::rotate(encrypted, to_version): decrypt old, re-encrypt new
- Update existing tests to use v2; add round-trip, rotation, partial-rotation, and invalid-version tests

Task: vault/key-versioning-rotation
2026-06-23 13:35:44 +00:00
ad1174b485 vault: change unlock_new return type to Zeroizing<String> (task: vault/unlock-new-zeroizing-return)
Drift item #8: the mnemonic phrase is the root of trust — it must not linger in
freed heap memory. Changed unlock_new return from String to Zeroizing<String>
(zeroized on drop). Existing tests work via Deref coercion.

Refs: docs/architecture/crates/vault/README.md drift #8
Implements: ADR-025 (resolves W7)
2026-06-23 13:33:55 +00:00
aec4bc9b87 refactor(vault): remove derive_password and site_password_path (task: vault/remove-password-derivation)
Drift item #7: remove the password-manager pattern (derive_password,
derive_password_string, site_password_path) — not relevant to an RPC system's
vault. Removed methods, path function, doc-table row, all tests, and the
now-unused base64 URL_SAFE_NO_PAD import.

Refs: docs/architecture/crates/vault/README.md drift #7
Implements: ADR-025 (resolves C9)
2026-06-23 13:33:36 +00:00
9045dd83d3 vault: replace RwLock unwrap with poisoned-lock recovery
Replace all .read().unwrap() and .write().unwrap() calls in
VaultServiceHandle methods with .unwrap_or_else(|e| e.into_inner())
so a panic while holding the lock does not brick the vault for all
subsequent operations. Add unit test that poisons the lock and
verifies the next call recovers.
2026-06-23 13:33:00 +00:00
685413dee4 vault: return Zeroizing<String> from unlock_new
Change unlock_new return type from String to Zeroizing<String>
so the generated mnemonic phrase is zeroized on drop and does not
linger in freed heap memory. Resolves drift item #8 / review W7.
2026-06-23 13:33:00 +00:00
06b715322a refactor(vault): remove derive_password and site_password_path (ADR-025)
Drop the password-manager pattern from alknet-vault (drift item #7,
ADR-025, resolves review #002 C9). Site-specific password derivation
is not relevant to an RPC system's vault.

Removed:
- derive_password method from VaultServiceHandle (service.rs)
- derive_password_string method from VaultServiceHandle (service.rs)
- site_password_path function from derivation.rs
- site-password derivation path row from derivation.rs doc table
- All password-derivation tests from service.rs and derivation.rs
- Now-unused base64 URL_SAFE_NO_PAD import from service.rs
2026-06-23 13:32:45 +00:00
1ac5585f84 tasks: mark vault/derivedkey-serialization completed 2026-06-23 13:32:35 +00:00
68d2068f36 vault: always-redact DerivedKey serialization, reject redacted payloads on deserialize (task: vault/derivedkey-serialization)
Drift item #5: replace DerivedKey's dual serialization behavior (JSON redacts,
binary preserves) with always-redact. Custom Serialize always redacts private_key
as "[REDACTED]"; custom Deserialize rejects "[REDACTED]" payloads with an
explicit error. Dropped the is_human_readable() branch that preserved bytes in
binary formats (postcard path removed by ADR-025). Debug impl already redacted.

Refs: docs/architecture/crates/vault/README.md drift #5
Implements: ADR-025 (resolves W8)
2026-06-23 13:31:19 +00:00
bd4c2bc268 vault: always-redact DerivedKey serialization, reject redacted payloads on deserialize
Replace derived Deserialize with a custom impl that rejects
private_key == b"[REDACTED]" with an explicit error, and make the
custom Serialize impl always redact (drop the human-readable-only
branch). Updates the redaction-rejection and debug-no-leak tests.

Resolves drift item #5 (ADR-025 dropped the postcard/remote path).
2026-06-23 13:30:21 +00:00
4078a8d8d5 tasks: mark vault/irpc-removal completed 2026-06-23 13:23:05 +00:00
7e3300e83a refactor(vault): remove irpc actor dispatch — direct method calls on VaultServiceHandle (task: vault/irpc-removal)
ADR-025 / drift item #4: remove the irpc-based actor dispatch from the vault
crate. VaultServiceHandle (Arc<std::sync::RwLock<>>) is now the sole synchronous
API. Removed: VaultProtocol enum, VaultServiceActor, VaultService wrapper,
Client<VaultProtocol> usage, irpc/irpc-derive/tokio deps, postcard dev-dep,
Serialize/Deserialize on VaultServiceError. lib.rs re-exports match the vault
README Public API. The vault is now local-only by construction with zero async
runtime dependency.

Refs: docs/architecture/crates/vault/README.md drift #4
Implements: ADR-025

# Conflicts:
#	Cargo.lock
2026-06-23 13:22:13 +00:00
9028fca302 refactor(vault): remove irpc actor dispatch — direct method calls on VaultServiceHandle (ADR-025)
Drop the irpc-based actor dispatch path from alknet-vault and convert to
direct method calls on VaultServiceHandle (drift item #4, ADR-025).

Removed:
- VaultProtocol enum with #[rpc_requests] derive from protocol.rs
- VaultServiceActor (mpsc + oneshot dispatch loop) from service.rs
- VaultService wrapper struct (only the handle is needed)
- Client<VaultProtocol> usage
- irpc, irpc-derive, tokio from [dependencies]
- postcard from [dev-dependencies]
- VaultMessage/VaultProtocol/VaultServiceActor re-exports from lib.rs
- Serialize/Deserialize derives from VaultServiceError
- postcard round-trip tests from protocol.rs
- actor tokio::test tests from service.rs

The vault now has zero async runtime dependency and zero RPC framework
dependency — it is local-only by construction. VaultServiceHandle is the
sole API: Arc<std::sync::RwLock<VaultServiceInner>> with synchronous
methods. lib.rs re-exports match the vault README Public API section.

Also fixes pre-existing clippy field_reassign_with_default warnings in
cache.rs tests so cargo clippy -- -D warnings passes.
2026-06-23 13:20:28 +00:00
e9d8896309 tasks: mark vault/cache-zeroization-test completed 2026-06-23 13:19:48 +00:00
f413719971 test(vault): add zeroization tests for cache eviction and clear (task: vault/cache-zeroization-test)
Drift item #6: verify HashMap::clear()/remove()/replace drop CachedKey values
triggering ZeroizeOnDrop. Adds drop_tracker module proving Drop semantics,
plus LRU eviction, TTL expiry, and clear() tests. The lock()-clears-cache
criterion is covered by existing test_lock_clears_all_cache_entries in service.rs.

Refs: docs/architecture/crates/vault/README.md drift #6
2026-06-23 13:18:52 +00:00
389a9e93f7 test(vault): add zeroization tests for cache eviction and clear
Adds tests verifying that HashMap::clear() and remove() drop CachedKey
values (triggering ZeroizeOnDrop), plus explicit tests for LRU eviction,
TTL expiry, and clear() removing all entries. Resolves drift item #6.

- drop_tracker module: proves HashMap::clear/remove/replace drop values
  via a Drop-flag instrumented type mirroring CachedKey's zeroize-on-drop
- test_lru_eviction_drops_evicted_cached_key: cache exceeds max_entries,
  oldest evicted
- test_ttl_expiry_evicts_entry_on_access: short TTL, wait, entry gone
- test_clear_removes_all_entries_and_empties_cache: empty after clear
- lock() clears cache already covered by test_lock_clears_all_cache_entries
2026-06-23 13:17:42 +00:00
ff50ccea09 tasks: mark core/crate-init completed 2026-06-23 13:14:06 +00:00
963f3d9532 feat(core): initialize alknet-core crate with module skeleton
Create crates/alknet-core with Cargo.toml (dependencies, feature flags
quinn/iroh), src/lib.rs declaring types/auth/config/endpoint modules, and
skeleton files for each module with doc comments and TODO markers. Add the
crate to the workspace members list.

Both quinn (default-on) and iroh (opt-in) are optional and can be active
simultaneously per ADR-010. Dual license MIT OR Apache-2.0 inherited from
the workspace.
2026-06-23 13:12:49 +00:00
6056492128 tasks: mark vault/osrng-iv-generation completed 2026-06-23 13:12:10 +00:00
3a48b11e8b vault: use OsRng for AES-GCM IV and salt generation (task: vault/osrng-iv-generation)
Drift item #1: replace rand::random() thread-local RNG with rand::rngs::OsRng
CSPRNG for security-critical IV (12-byte GCM nonce) and salt (32-byte) generation.

Refs: docs/architecture/crates/vault/README.md drift #1
Implements: ADR-020
2026-06-23 13:11:42 +00:00
f43246b978 vault: use OsRng for AES-GCM IV and salt generation
Replace rand::random() with rand::rngs::OsRng for cryptographic nonce
and salt generation in encryption.rs. rand::random() uses thread-local
RNG which may not be a CSPRNG on all platforms; OsRng reads from the
OS entropy source, preventing catastrophic IV reuse under AES-GCM.

Drift item #1 (security-critical).
2026-06-23 13:09:07 +00:00
098fd8b9b9 tasks: decompose vault, core, call crates into 28 atomic implementation tasks
Break down the three initial crates (alknet-vault, alknet-core, alknet-call)
into dependency-ordered task files for implementation agents.

Structure:
- tasks/vault/ (10 tasks) — drift fixes from ADR-025/026 refactor, review,
  spec sync. Vault is independent and can run fully in parallel with core/call.
- tasks/core/ (6 tasks) — crate init, core types, config, auth, endpoint,
  review. Core is foundational; call depends on it.
- tasks/call/ (12 tasks) — split into registry/ and protocol/ topic subdirs
  reflecting the two subsystems. CallAdapter is the merge point.

Key decisions:
- Drifts 3+9+10 grouped as one task (key-versioning-rotation) — the complete
  ADR-021 rotation feature that doesn't compile in pieces
- Reviews injected at end of each crate phase (vault, core, call)
- Vault spec-sync task removes the drift table and bumps doc status to stable
- ACME deferred in core/endpoint (noted as TODO; X509 manual certs for now)
- OperationEnv kept as a trait (load-bearing for ADR-024 layering)

Validated: 28 tasks, no cycles, 11 generations of parallel work.
Critical path runs through call (11 tasks). Vault completes by generation 4.
6 high-risk tasks identified (21%): irpc-removal, endpoint, operation-context,
operation-env, call-adapter, abort-cascade.
2026-06-23 12:41:47 +00:00
2e34590522 docs(architecture): resolve review #003 — type/API surface completeness
Review #003 found 11 critical, 14 warning, and 6 suggestion findings
after reviews #001 (governance/security) and #002 (cross-document
consistency/two-way-door audit) were resolved. The theme: types and
APIs that were *referenced* but never *defined*, and stale ADR sketches
that didn't match the now-updated spec docs.

Critical fixes (11):

- C1: DerivedKey #[derive(Deserialize)] contradicted the custom
  Deserialize that rejects "[REDACTED]" — dropped the derive, added
  explicit manual Serialize/Deserialize impls (protocol.md).
- C2: encrypt prose said "derived at PATHS::ENCRYPTION" but the
  signature takes key_version — updated to encryption_path_for_version
  (service.md).
- C3: derive_encryption_key returned DerivedKey, derive_encryption_key
  _for_version returned EncryptionKey (same cache) — unified on
  DerivedKey, defined CachedKey (service.md).
- C4: tokio vs std::sync::RwLock contradiction — specified
  std::sync::RwLock, dropped tokio from vault deps (ADR-018, ADR-025,
  service.md).
- C5: Missing drift rows in vault README — added #9 (key_version
  ignored) and #10 (rotate not implemented).
- C6: ADR-022 build_root_context and invoke() sketches omitted
  abort_policy (9 fields vs 10) — added the field to both sketches.
- C7: Capabilities type referenced 20+ times, never defined — added
  struct definition to core-types.md with Clone+Send+Sync, Zeroize,
  sealed builder API, immutability guard.
- C8: SessionOverlaySource on CallAdapter but never defined, crate
  violation (alknet-call can't depend on alknet-agent) — defined the
  trait in alknet-call (call-protocol.md), matching the IdentityProvider
  pattern.
- C9: CompositeOperationEnv dispatch fall-through was "a two-way door"
  — added contains() to OperationEnv trait, made the composite probe
  before dispatching, eliminating the sentinel ambiguity.
- C10: No API for Layer 2 (connection overlay) registration, CallConnection
  undefined — defined CallConnection struct + register_imported() API
  (call-protocol.md).
- C11: with_local signature diverged between two examples (4 args vs 5)
  — added capabilities as the 5th arg, made both examples consistent.

Warning fixes (14):

- W1: invoke_with_policy restructured as required method, invoke gets a
  default impl delegating to it — eliminates duplication across impls.
- W2: CachedKey defined (service.md).
- W3: EncryptionKey constructor/glue specified, added to re-export list.
- W4: Secp256k1ExtendedPrivKey defined, derive_ethereum_key glue shown.
- W5: encryption_path_for_version rejects version < 2 (v1 is TS PBKDF2).
- W6: Wire payload schemas for all event types + ResponseEnvelope →
  EventEnvelope conversion table (call-protocol.md).
- W7: Timeout section — deadline on OperationContext, composed calls
  inherit parent's deadline, CallAdapter::with_timeout().
- W8: Request ID generation spec — UUID v4 for composed calls, wire ID
  vs internal ID relationship for abort cascade.
- W9: unlock_new already-unlocked behavior specified (returns
  AlreadyUnlocked).
- W10: KeyType Serialize/Deserialize justification corrected (stale
  irpc reference removed).
- W11: OperationProvenance and CompositionAuthority defined inline in
  operation-registry.md (were only in ADR-022).
- W12: encrypt/decrypt free functions marked pub(crate), relationship
  to VaultServiceHandle methods stated.
- W13: rotate signature removed from encryption.md (it's a
  VaultServiceHandle method, not a free function).
- W14: CallAdapter::new() + with_session_source() + with_timeout()
  constructors shown.

Suggestion fixes (6): Seed: Clone note, VaultServiceInner invariant,
ExtendedPrivKey accessor signatures, CURRENT_KEY_VERSION location, ADR-018
stale actor text, derivation helpers re-export note.
2026-06-23 10:56:05 +00:00