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.
6.7 KiB
id, name, status, depends_on, scope, risk, impact, level
| id | name | status | depends_on | scope | risk | impact | level | ||
|---|---|---|---|---|---|---|---|---|---|
| irpc-secret-protocol-integration | Wire SecretProtocol to irpc with local SecretServiceHandle and remote dispatch | pending |
|
moderate | medium | component | implementation |
Description
The SecretProtocol enum in protocol.rs currently has a placeholder SecretMessage = SecretProtocol type alias. The spec (after update) defines two dispatch paths:
- Local dispatch (in-process):
SecretServiceHandle— async methods that directly call intoSecretServiceInner. No serialization overhead. - Remote dispatch (in-cluster):
SecretProtocolirpc client — sendsSecretMessagevia mpsc (local node) or QUIC stream (remote worker). The service runs on a head node; workers request derived keys via irpc.
Per ADR-027, irpc is always a dependency in alknet-secret (not feature-gated). Per ADR-033, irpc is one dispatch backend for OperationEnv.
What needs to happen:
-
irpc crate integration: The
irpccrate needs to be added as a dependency toalknet-secret. The#[rpc_requests]macro must be applied toSecretProtocolto generateSecretMessagewith oneshot channels for the response types. -
SecretMessage definition: Replace
pub type SecretMessage = SecretProtocol;with the irpc-generated message type. Each variant gets aoneshot::Sender<T>for the response:DeriveEd25519 { path: String, tx: oneshot::Sender<DerivedKey> }→SecretMessage::DeriveEd25519DeriveEncryptionKey { path: String, tx: oneshot::Sender<DerivedKey> }DeriveEthereumKey { path: String, tx: oneshot::Sender<DerivedKey> }DerivePassword { path: String, length: usize, tx: oneshot::Sender<Vec<u8>> }Encrypt { plaintext: String, key_version: u32, tx: oneshot::Sender<EncryptedData> }Decrypt { encrypted: EncryptedData, tx: oneshot::Sender<String> }Lock { tx: oneshot::Sender<()> }Unlock { passphrase: String, tx: oneshot::Sender<()> }
Note: If the
irpccrate's#[rpc_requests]macro generates this automatically, use it. If irpc doesn't exist as a crate yet (it may still be in design), create theSecretMessageenum manually with the oneshot channels, following the pattern used byAuthProtocolin alknet-core. -
SecretServiceHandle dispatch: The
SecretServiceHandlemethods should dispatch through the irpc channel. When assembled locally, the handle sendsSecretMessagevariants to atokio::sync::mpscchannel; a task runsSecretServiceInnerand processes messages. This replaces the currentRwLock<SecretServiceInner>pattern with an actor-model pattern.OR keep the current
RwLock<SecretServiceInner>for local use and add a separateSecretServiceActorthat wraps the handle in an mpsc-based message loop. TheSecretServiceHandlestays as the primary local API. The actor is the irpc entry point.Prefer the simpler approach: Keep
SecretServiceHandlewithRwLockfor direct local use (current code). Add aSecretServiceActorthat:- Holds a
SecretServiceHandle - Runs a message loop: receives
SecretMessage, dispatches toSecretServiceHandlemethods, sends responses through oneshot channels - Can be spawned as a
tokio::taskfor in-process irpc - Exposes a
tokio::sync::mpsc::Sender<SecretMessage>as the client handle
- Holds a
-
irpc feature: Per ADR-027, irpc is always-on in alknet-secret. No feature flag needed. If the
irpccrate exists, depend on it directly. If not, theSecretMessagetype can be defined locally following the irpc pattern.
Current state: irpc is listed as "0.x" in the spec's dependencies but is not in Cargo.toml. The current code doesn't import irpc at all. Check whether the irpc crate exists in the workspace or if it needs to be defined locally.
Critical dependency: This task cannot proceed until we know the irpc crate's API. If it doesn't exist yet, we should define SecretMessage manually following the same pattern as AuthProtocol in alknet-core (which also uses irpc behind a feature flag).
Acceptance Criteria
irpcdependency added toCargo.toml(orSecretMessagedefined manually if irpc doesn't exist yet)SecretMessageenum defined with oneshot channels for eachSecretProtocolvariant's response typeSecretServiceActorstruct that wrapsSecretServiceHandleand processesSecretMessagevariantsSecretServiceActor::run()method that spawns a message loop as atokio::taskSecretServiceActor::handle(&self) -> mpsc::Sender<SecretMessage>returns a client handle for sending messages- Each
SecretMessagevariant dispatches to the correspondingSecretServiceHandlemethod SecretServiceHandleremains the primary local API (RwLock-based, unchanged for direct use)- Unit test:
SecretServiceActorprocessesSecretMessage::Unlockand responds successfully - Unit test:
SecretMessage::DeriveEd25519dispatched through actor returnsDerivedKey - Unit test:
SecretMessage::Lockclears state and subsequent derive calls fail protocol.rsupdated:SecretMessageis no longer a type alias, it's the irpc message typelib.rsre-exports updated to includeSecretServiceActorandSecretMessage
References
- docs/architecture/secret-service.md — irpc service section (after spec update)
- docs/architecture/decisions/027-crate-decomposition.md — ADR-027 (irpc always-on in alknet-secret)
- docs/architecture/decisions/033-operationenv-irpc-call-protocol.md — ADR-033 (irpc as dispatch backend)
- crates/alknet-secret/src/protocol.rs — Current SecretProtocol with placeholder SecretMessage
- crates/alknet-secret/src/service.rs — SecretServiceHandle and SecretService
- crates/alknet-core/src/auth/ — AuthProtocol pattern (reference for irpc integration)
Notes
This is the biggest gap identified by the architect. The spec says
#[rpc_requests]but that macro doesn't exist in the codebase yet. Check whetherirpcis a workspace crate or an external dependency.
If
irpcdoesn't exist yet, create a localSecretMessagetype following the same channel-based pattern that alknet-core uses for its irpc services. The key pattern is: each protocol variant has a corresponding message variant with aoneshot::Sender<Response>for the response. The service actor receives messages, processes them, and sends responses.
The
SecretServiceHandlewithRwLockshould remain as the primary local API. It's simpler, faster, and works well for single-process use. TheSecretServiceActorwraps it for irpc dispatch. This two-API pattern matches the spec's "minimal deployment (local handle) vs production deployment (irpc service)" distinction.
Summary
To be filled on completion