Commit Graph

34 Commits

Author SHA1 Message Date
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
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
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
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
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
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
80128a56e5 refactor: rename alknet-secret to alknet-vault
Rename the crate from alknet-secret to alknet-vault to better reflect its
purpose as a local key vault (seed management, key derivation, encryption)
rather than a network service.

Symbol renames:
- SecretService → VaultService
- SecretServiceHandle → VaultServiceHandle
- SecretServiceActor → VaultServiceActor
- SecretServiceError → VaultServiceError
- SecretProtocol → VaultProtocol
- SecretMessage → VaultMessage
- ServiceLocked → VaultLocked
- alknet_secret → alknet_vault (crate name)

Update ADR-008 with vault access pattern: the vault is a capability source,
not a service endpoint. The CLI injects derived/decrypted material into
operation contexts — handlers never hold vault references.
2026-06-16 11:10:07 +00:00
b5a4600d74 greenfield: clean slate for ALPN-as-service pivot
Delete old source crates (alknet-core, alknet, alknet-napi), old
architecture docs (ADRs, specs, open questions), old research docs
(phase2, event-sourcing, feasibility, etc.), old tasks, and obsolete
reference material (gitserver/MPL, honker, nats, rustfs, polyglot,
keystone, distributed-identity).

Keep: alknet-secret (standalone, compiles), pivot docs, iroh and ssh
references, rudolfs reference (MIT/Apache, fork candidate), ops docs,
sdd_process.md, and licenses.

Previous implementation preserved at /workspace/@alkdev/alknet-main/
for reference during porting.

Workspace compiles: cargo check + 14 tests pass for alknet-secret.
2026-06-15 12:08:08 +00:00
470473fbb9 feat(secret): wire SecretProtocol to irpc with SecretServiceActor
Apply #[rpc_requests(message = SecretMessage)] to SecretProtocol enum with
#[rpc(tx=oneshot::Sender<Result<T, SecretServiceError>>)] and #[wrap] attributes
on each variant. Add SecretServiceActor that wraps SecretServiceHandle and
processes SecretMessage variants via mpsc channel. Update DerivedKey
serialization to use is_human_readable() so postcard preserves private_key
bytes while JSON redacts them. Add Serialize/Deserialize to SecretServiceError
for irpc wire format compatibility. Add tokio dependency for actor runtime.
2026-06-10 07:41:53 +00:00
eae47c366b feat(alknet-secret): make DerivedKey zeroize-on-drop, non-Clone, with redacted serialization
Per ADR-038, DerivedKey.private_key now derives Zeroize with #[zeroize(drop)]
ensuring sensitive key material is zeroized before deallocation. DerivedKey
is now move-only (no Clone), and JSON/debug output redacts private_key as
"[REDACTED]". Deserialization still works for postcard/irpc wire format.

Also fixes clippy needless_borrows_for_generic_args in encryption.rs and
applies cargo fmt to existing code.
2026-06-10 06:16:38 +00:00
83ea66b5d1 chore: prep Phase 3 tasks and workspace for alknet-secret development
- 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
2026-06-10 05:57:27 +00:00
04e969982e feat(secret): add alknet-secret crate and architecture spec for Phase 3
Create the alknet-secret crate with BIP39 mnemonic generation, SLIP-0010
Ed25519 HD key derivation, AES-256-GCM encryption, and SecretProtocol
irpc service definition. This is Phase 3.1 from the integration plan.

Architecture changes:
- Promote secret-service.md to reviewed status with full spec format
  (crate structure, public API, security model, phase progression,
   ADR/OQ cross-references, wire format compatibility section)
- Add ADR-038 (seed lifecycle and memory security): zeroize for v1,
  mlock deferred to Phase B
- Add OQ-SEC-01 (mlock/VirtualLock for seed RAM) to open-questions.md
- Update README.md with ADR-038 and secret-service status

Crate structure:
- src/mnemonic.rs: BIP39 phrase generation, validation, seed derivation
- src/derivation.rs: SLIP-0010 HD key derivation, path constants (74')
- src/encryption.rs: AES-256-GCM encrypt/decrypt, EncryptedData type
- src/protocol.rs: SecretProtocol irpc enum, DerivedKey, KeyType
- src/service.rs: SecretServiceHandle with Unlock/Lock lifecycle
- 40 passing tests (unit + integration + doc)
2026-06-09 13:49:53 +00:00
d5d4b3c153 feat(core): add axum HTTP router scaffold with auth middleware and stealth handoff
Add http feature flag with axum, hyper, hyper-util, tower, and http-body-util
dependencies. Create http module with auth middleware (extracts Bearer token,
calls IdentityProvider::resolve_from_token, attaches Identity to extensions)
and router scaffold (default 404 fallback, no operational routes yet). Replace
send_fake_nginx_404 with axum router handoff when http feature is enabled;
fake 404 behavior preserved when http is disabled. Wire HttpInterface with
build_router() method and pass IdentityProvider through Server to handle_connection.
2026-06-09 11:27:27 +00:00
1f55844935 feat(core): add API keys to DynamicConfig.auth and extend IdentityProvider token resolution 2026-06-09 11:01:33 +00:00
88a875241a Add NAPI reload API for DynamicConfig and ForwardingPolicy
- Add reloadAuth(), reloadForwarding(), reloadAll() methods to AlknetServer
- Add NAPI type definitions: AuthConfigNapi, ForwardingPolicyConfig, ForwardingRuleConfig
- Refactor NapiServerHandler to use ArcSwap<DynamicConfig> for atomic config swaps
- Add ConfigReloadHandle::dynamic_arc() accessor for sharing ArcSwap between NAPI and accept loop
- Add ipnetwork dependency to alknet-napi for TargetPattern CIDR parsing
- Add builder functions for AuthPolicy and ForwardingPolicy from NAPI config types
- All swaps are atomic via ArcSwap per ADR-030
2026-06-07 15:30:38 +00:00
0d6f94c24c feat(core): implement OperationContext, OperationRegistry, and OperationSpec 2026-06-07 14:44:26 +00:00
ee1b3f3819 feat(core): implement StaticConfig/DynamicConfig split with ArcSwap hot-reload
Split alknet-core configuration into StaticConfig (immutable after startup)
and DynamicConfig (hot-reloadable at runtime via ArcSwap).

- Add StaticConfig struct in config/static_config.rs with all fields per ADR-030
- Add DynamicConfig struct with AuthPolicy, ForwardingPolicy, RateLimitConfig
- Add ForwardingPolicy with allow_all()/deny_all() defaults (ADR-031)
- Add ConfigReloadHandle with reload() method for runtime config updates
- Replace Arc<ServerAuthConfig> with Arc<ArcSwap<DynamicConfig>> in ServerHandler
- Add config_reload_handle() to Server for obtaining reload handles
- Add AuthPolicy with authenticate_publickey/authenticate_certificate methods
- All existing tests pass with the new config structure
- Default DynamicConfig produces identical behavior to current code
2026-06-07 14:03:46 +00:00
596c89ce24 refactor!: rebrand wraith to alknet
Rename all crates, CLI commands, constants, type names, doc comments,
and documentation from wraith to alknet. Includes wire-protocol changes:
ALPN wraith-ssh -> alknet-ssh, reserved destination prefix wraith- ->
alknet-, SSH auth username wraith -> alknet.
2026-06-05 10:04:32 +00:00
d85c882635 feat!: harden SSH server handler security
- Restrict auth methods to PUBLICKEY only (no none, password, hostbased,
  or keyboard-interactive advertised during negotiation)
- Log all denied channel types (session, x11, forwarded-tcpip) and
  dangerous request types (exec, shell, subsystem, pty, env, x11, agent)
- Explicitly reject all dangerous channel request handlers (exec, shell,
  subsystem, pty, env, x11, agent forwarding) with channel_failure
  responses instead of russh's default silent Ok(()) which leaves clients
  hanging and is a footgun if session channels are ever allowed
- Explicitly reject tcpip_forward, streamlocal_forward with logged warnings
- Log signal requests at debug level (harmless, no response needed)
- Override handlers in both core ServerHandler and NapiServerHandler
- Add tracing dependency to wraith-napi for security event logging
- Set preferred algorithms explicitly (russh::Preferred::DEFAULT which
  uses only modern KEX/cipher/MAC algorithms)
2026-06-03 09:04:01 +00:00
150b1f3ae5 feat(napi): add TLS and iroh transport support to serve() and connect() 2026-06-03 05:58:05 +00:00
0fdb6cd782 feat(napi): implement serve() function with WraithServer, WraithServerStream, and ConnectionInfo
Expose NAPI serve() per ADR-016. WraithServer provides close() and
onConnection(callback) for receiving SSH channel streams from
incoming connections. Each connection produces a WraithServerStream
(Duplex-like read/write/close) with ConnectionInfo (remoteAddr,
transportKind). Supports TCP transport with optional authorizedKeys
and certAuthority auth. TLS and iroh transports return helpful errors
indicating future support.
2026-06-02 20:05:13 +00:00
62d57dd477 Implement wraith serve CLI subcommand with clap
Add serve subcommand with all flags matching server.md CLI interface:
--key, --authorized-keys, --cert-authority, --transport, --listen,
--tls-cert, --tls-key, --acme-domain, --stealth, --proxy,
--iroh-relay, --max-connections-per-ip, --max-auth-attempts.

--key is required, --transport defaults to tcp, --listen defaults to
0.0.0.0:22. --stealth validates TLS transport. --acme-domain requires
acme feature flag. --transport iroh prints endpoint ID on startup.
Key inputs accept file paths. Errors reported to stderr with non-zero
exit code. Also adds acme feature flag and rustls-pemfile/rustls-pki-types
dependencies for TLS cert loading.
2026-06-02 12:28:37 +00:00
94feb5fdac feat(cli): implement wraith connect subcommand with clap derive
All CLI flags from client.md: --server, --peer, --transport (default tcp),
--identity, --socks5 (default 127.0.0.1:1080), --forward (repeatable),
--remote-forward (repeatable), --proxy, --iroh-relay, --tls-server-name,
--insecure. Env var defaults: WRAITH_SERVER, WRAITH_IDENTITY. Validates
--server required for tcp/tls, --peer required for iroh, --identity required.
Warns on --proxy with --transport tcp (ADR-019). Translates args to
ConnectOptions and calls ClientSession::new(opts).run().await. Errors to
stderr with non-zero exit.
2026-06-02 11:39:57 +00:00
243243a82f Implement NAPI connect() function — single SSH channel as duplex stream
- Add WraithConnectOptions struct with napi fields: server, peer, transport,
  identity (string path or Buffer), tlsServerName, insecure, irohRelay, proxy
- Add WraithStream napi class wrapping SSH channel read/write halves via
  ChannelStream::into_stream() + tokio::io::split()
- Implement connect() async function: transport creation (tcp, tls), SSH client
  connection, authenticate, open direct_tcpip channel, return WraithStream
- Identity field accepts file path (string) or in-memory key data (Buffer)
- All Rust errors marshalled to JavaScript exceptions with descriptive messages
- Add ForwardError enum to wraith-core (required by forward.rs)
- Enable tls, iroh features on wraith-core dependency
- 7 unit tests for key source resolution and address parsing
2026-06-02 11:10:42 +00:00
bf8233af61 fix: add rand dev-dep, install rustls CryptoProvider in TLS tests, fix iroh OsRng import 2026-06-02 10:32:29 +00:00
b3589a038e Merge remote-tracking branch 'origin/feat/transport/iroh-transport' into transport/trait-and-types
# Conflicts:
#	Cargo.lock
#	crates/wraith-core/Cargo.toml
2026-06-02 10:30:12 +00:00
c3f5f3f504 Implement IrohTransport and IrohAcceptor (feature-gated iroh)
Add iroh QUIC P2P transport using tokio::io::join for stream duplexing
per ADR-003. Default relay is n0's https://relay.iroh.network/ (ADR-009).
Proxy URL passed to Endpoint::builder (ADR-010). Integration test marked
#[ignore] for CI since it requires iroh relay connectivity.
2026-06-02 10:29:40 +00:00
b559e335d3 Implement server-side auth with ServerAuthConfig (Ed25519 keys + cert-authority) 2026-06-02 10:21:28 +00:00
eb032c87f1 Implement client-side SSH auth handler with ClientAuthConfig and ClientHandler 2026-06-02 10:03:56 +00:00
b4f4f2ed8c Implement SSH key material loading with KeySource, load_private_key, load_public_keys, and CertAuthorityEntry 2026-06-02 09:52:39 +00:00
dddc6d7a4c Define Transport trait, TransportAcceptor trait, TransportInfo, and TransportKind types 2026-06-02 09:17:50 +00:00
2bc15f1035 Initialize Cargo workspace with wraith-core, wraith, and wraith-napi crates
- Workspace root Cargo.toml with three crate members
- wraith-core: library with feature flags (tls, iroh, acme), core deps (russh, tokio, tracing, anyhow, thiserror, tokio-util), module skeleton (transport, client, server, auth, socks5, error)
- wraith: binary crate depending on wraith-core with clap derive
- wraith-napi: cdylib crate depending on wraith-core, napi, napi-derive
- .gitignore for target/ and node_modules/
2026-06-02 09:14:40 +00:00