The Unlock variant had a single field used as the
mnemonic, with no way to convey the BIP39 password extension (25th word).
The actor handler silently passed for the passphrase, making it
impossible to unlock with a BIP39 passphrase via irpc.
Split into + to match
the spec and SecretServiceHandle::unlock() signature.
Update secret-service.md to reflect the actual alknet-secret implementation:
- Fix dependency names/versions: secp256k1 (not libsecp256k1), version 0.29,
add tokio/irpc-derive/hmac/rand, use workspace refs
- Add SecretServiceActor and CacheConfig to public API
- Add ethereum.rs module to crate structure, fix test_vectors.rs filename
- DerivedKey is move-only (not Clone), matching the stronger security impl
- Update BIP39 pseudocode to actual derive_path_from_seed() API
- Document derive_password_string() convenience method
- Document SecretServiceActor::spawn() in irpc integration model
- Update Unlock variant to target state: { mnemonic, passphrase: Option }
- Add implementation gap note pointing to unlock-passphrase-gap task
Add tasks/integration/phase3/secret-service/unlock-passphrase-gap.md:
- Fix Unlock protocol variant to carry both mnemonic and BIP39 passphrase
- Currently the irpc message only has passphrase: String (used as mnemonic)
- The handle supports both parameters but the protocol can't convey them
- Add irpc (0.16) and irpc-derive (0.16) as workspace dependencies
- Add irpc, irpc-derive, and secp256k1 (optional) to alknet-secret Cargo.toml
- Clarify encryption-salt-kdf task: Option B (document salt as reserved) is the
chosen path per spec update, removing Option A acceptance criteria
- Update irpc-secret-protocol-integration task with concrete irpc crate details:
real crate on crates.io v0.16, #[rpc_requests] macro, workspace config,
AuthProtocol pattern reference, DerivedKey serialization considerations
- Fix secp256k1-ethereum-derivation task: correct crate name is secp256k1
(not libsecp256k1), add version pin 0.29
9 atomic tasks for alknet-secret spec conformance and gap closure,
derived from architect's implementation review. Dependencies form
a 5-generation graph starting with spec update, then parallel
implementation tasks, ending with a review gate.
Tasks address: DerivedKey zeroize security, key caching with TTL,
irpc protocol integration, password derivation, secp256k1/Ethereum
derivation, encryption salt/KDF, crypto test vectors, and final
spec conformance review.
Task 1 (stream-interface-message-interface-split):
- Document that TransportKind::Dns EXISTS and must be removed (was incorrectly described as 'never added')
- Document that TransportKind::WebTransport has { host: String } and must be changed to { server_name: Option<String> }
- Document that ListenerConfig is a flat struct, not an enum, and must be restructured per ADR-035
- Move ListenerConfig restructuring, InterfaceConfig rename, and TransportKind cleanup into task 1 to avoid overlap with task 2
- Add HttpListenerConfig/DnsListenerConfig/StreamInterfaceKind/MessageInterfaceKind to task 1 scope
Task 2 (listenconfig-http-dns-stubs):
- Remove work now covered by task 1 (InterfaceConfig rename, TransportKind changes, ListenerConfig enum creation)
- Focus on wiring the new enum form into Server/ServeOptions/StaticConfig, adding constructors, validation, and accept loop stubs
Phase 2 completes the interface-to-protocol bridge and adds core types
that external crates depend on. The 8 tasks are organized into 5
generations with clear dependencies:
- Gen 1: StreamInterface/MessageInterface trait split (must go first)
- Gen 2: SshSession bridge, RawFraming impl, CredentialProvider (parallel)
- Gen 3: API keys in DynamicConfig (depends on CredentialProvider)
- Gen 4: ListenerConfig HTTP/DNS stubs + axum scaffold
- Gen 5: Review gate before Phase 3
Key design decisions:
- 2.4a/2.4b split: SecretStoreCredentialProvider deferred to Phase 3
- API keys (2.6) must land before axum scaffold (2.7)
- ListenerConfig (2.5) must land before axum scaffold (2.7)
- Gen 2 tasks are parallelizable (separate modules)
Add doc comments and TODO markers to SshSession::recv() and send()
explicitly marking them as Phase 1 stubs. Notes that call protocol
event bridging from SSH channels is planned for Phase 2/3.
New Phase 1 modules should follow the existing pattern of referencing
ADR numbers in module-level doc comments for discoverability, matching
the style in transport/mod.rs.
ForwardingAction, TargetPattern, ForwardingRule, OperationType,
InterfaceConfig, InterfaceKind, DynamicConfig, and CallError are all
likely to gain variants/fields in future phases. Marking them
#[non_exhaustive] now prevents downstream breakage when new
variants/fields are added. Added constructor methods for types that
are constructed from other crates.
parse_proxy_config was using expect()/unwrap()/panic!() which would
crash the process on malformed proxy config strings instead of
returning a descriptive error. Now returns ConfigError::ProxyConfigInvalid
with the specific issue (bad scheme, bad address). Added tests for
invalid scheme, invalid address, and end-to-end from_serve_options.
NapiServerHandler was bypassing IdentityProvider, calling
config.auth.authenticate_publickey() directly, which meant no Identity
was stored on the session and per-identity forwarding rules could not
match. It also skipped ForwardingPolicy::check() entirely, defeating
forwarding access control for NAPI-served tunnels. Both are now
consistent with ServerHandler and SshHandler behavior.
Review found Phase 1 approved with minor issues. Created cleanup tasks:
- napi-identity-provider-wiring (bug: NAPI bypasses IdentityProvider)
- panic-free-static-config (code smell: panic/unwrap in production path)
- non-exhaustive-public-api (future-proofing public API types)
- adr-doc-comments (doc convention: ADR references in new modules)
- ssh-session-recv-stub-doc (documentation: mark stubs as planned)
Phase 1 of the integration plan modifies alknet-core to support the
architectural changes from Phase 0 ADRs and specs. Decomposed into
dependency-ordered tasks across config split, identity, forwarding
policy, OperationEnv, interface abstraction, and NAPI reload API.
Critical path: config-split → identity → forwarding → wire-into-handler
→ interface-trait → ssh-interface-extraction → review.
Two highest-risk tasks (interface-trait-definition, ssh-interface-extraction)
are split from §1.8 per the integration plan's note that it may need
sub-phases. OperationEnv is split into types and runtime per Phase 1
local-dispatch-only constraint.
The remaining task descriptions implied that downstream concerns
(StorageIdentityProvider, irpc service layer, agent services, multi-node
deployment) already exist. Updated to clearly distinguish:
- spec-update-server: Phase 1 ships ConfigIdentityProvider, not irpc auth
- spec-update-call-protocol: Phase 1 is local dispatch only; irpc and remote
dispatch are contracted for later. Agent services are downstream concerns.
- spec-update-overview: Note which crates exist now vs which are Phase 2+ contracts
- review-spec-foundation: Add phase boundary check to acceptance criteria
Add 10 new tasks under tasks/architecture/ for Phase 0a (ADR writing):
- 9 ADR tasks (026-034) with dependency-ordered structure
- 1 review checkpoint task before Phase 0b spec writing
ADR dependency graph (3 generations):
Gen 1 (parallel): 026, 029, 030, 031, 032, 034
Gen 2 (depends on 029): 027, 028
Gen 3 (depends on 027+028): 033
Gen 4: review checkpoint
Also mark all 34 prior implementation tasks as completed — they
were finished but still showing as pending in the taskgraph.
Add AcmeCertProvider with domain-based and IP-based modes using rustls-acme.
AcmeTlsAcceptor::bind_acme() and TlsAcceptor::bind_acme() provide ACME-integrated
TLS acceptance with automatic cert renewal via background tokio task.
Feature-gated behind 'acme' (implies 'tls'). Unit tests for config construction;
integration test for LE staging marked #[ignore].