feat: Add NEAR key management with transaction signing and policy engine

Implements hybrid-custody NEAR key management where the agent holds scoped
function-call keys for routine operations while high-value operations require
explicit user approval through the existing channel approval flow.

Core infrastructure:
- Ed25519 key generation/import via ed25519-dalek (not near-crypto)
- AES-256-GCM encrypted storage via existing SecretsStore
- Hand-rolled borsh-serializable NEAR transaction types
- NEP-413 intent signing and MPC chain signature support
- Configurable policy engine with transaction analysis pipeline
- Daily spend tracking with automatic midnight UTC reset
- Encrypted backup/restore with Argon2id KDF
- CLI subcommands: generate, import, list, info, remove, export, policy, backup, restore
- NEAR ed25519 secret key leak detection (Critical/Block)
- WASM sign-payload host function (keys never enter WASM memory)
- KeyManager wired into AgentDeps for agent-wide access

Security invariants: private keys never reach the LLM or WASM boundary,
signing happens in host Rust code with Zeroize on drop, every transaction
is analyzed before signing, most-restrictive policy rule wins.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
This commit is contained in:
Illia Polosukhin
2026-02-09 16:24:47 -08:00
co-authored by Claude Opus 4.6
parent a35db4d32d
commit 2e62d71567
26 changed files with 5497 additions and 5 deletions
+26
View File
@@ -98,6 +98,32 @@ interface host {
///
/// Returns true if the secret exists and is accessible to this tool.
secret-exists: func(name: string) -> bool;
// ==================== Signing Capability ====================
/// Result of a payload signing request.
record sign-result {
/// Base64-encoded signature bytes (set on success).
signature: option<string>,
/// Error message (set on failure).
error: option<string>,
/// True if user approval is needed before signing can proceed.
approval-pending: bool,
}
/// Sign a payload using a NEAR key managed by the host (if capability granted).
///
/// Security:
/// - Private keys NEVER enter WASM memory; signing happens in host code only
/// - Only key labels declared in the tool's signing capability can be used
/// - Rate-limited per execution
/// - Subject to the host's transaction policy (may require user approval)
///
/// The payload should be base64-encoded bytes to sign.
/// The context-json is optional metadata about what's being signed (for policy display).
///
/// Returns sign-result with either signature or error/approval-pending.
sign-payload: func(key-label: string, payload: string, context-json: string) -> sign-result;
}
/// Tool interface that sandboxed tools must implement.