Skip to content

Latest commit

 

History

History
155 lines (115 loc) · 11.4 KB

ARCHITECTURE.md

File metadata and controls

155 lines (115 loc) · 11.4 KB

Architecture

Bird's-eye view of the Honmoon monorepo. Describes structure and intent, not implementation detail. For product context see .please/docs/knowledge/.

System Overview

Purpose: Honmoon is a policy-based firewall gateway that intercepts an AI agent's network traffic and applies policy (allow / deny / pause) before requests reach their destination.

Primary users: AI agents (sandboxed clients of the gateway), the developers/security teams who write policy, and AI coding agents that maintain this repo.

Core workflow:

  1. An agent's outbound request enters the data plane (process wrapper, gateway, or tunnel).
  2. The proxy extracts protocol Facts (domain, and later HTTP/SQL/K8s) at the wire level.
  3. The policy engine evaluates the facts → a Verdict; the request is allowed, blocked, or held for human approval, and the decision is recorded to the audit log.

Key constraints: Fail closed (default deny). The data plane is performance- and safety-critical (Rust). Auditability is a hard requirement — the traffic-inspecting code must remain open source.

Dependency Layers

Dependencies flow downward only. Lower layers must not import upper layers.

┌─────────────────────────────────────────────────────────────┐
│  Interface Layer    honmoon-cli (run/gateway/join),           │
│                     @honmoon/api (audit query, Bun.serve),    │
│                     @honmoon/cli, @honmoon/dashboard (React)  │
├─────────────────────────────────────────────────────────────┤
│  Application Layer  honmoon-proxy (CONNECT egress proxy +     │
│                     approval registry + parsers),             │
│                     honmoon-mgmt (axum management API +        │
│                     embedded dashboard)                       │
├─────────────────────────────────────────────────────────────┤
│  Domain Layer       honmoon-core (Policy/Verdict/Facts/CEL +  │
│                     audit log), @honmoon/policy (types+Schema)│
├─────────────────────────────────────────────────────────────┤
│  Infrastructure     tokio sockets, axum, rust-embed, Bun,     │
│                     (Phase 2+) Pingora/TLS, (planned) D1/DO   │
└─────────────────────────────────────────────────────────────┘

Invariant: honmoon-core is transport-agnostic — it has no tokio or networking dependency. The proxy feeds it Facts and consumes a Verdict.

Entry Points

For understanding the data plane (the firewall itself):

  • crates/honmoon-cli/src/main.rs — CLI dispatch for run / gateway / join. gateway runs the proxy + management API on one runtime. Start here.
  • crates/honmoon-proxy/src/gateway.rs — the CONNECT proxy; where requests meet policy via decide_explained(), get audited, and (for pause) held.
  • crates/honmoon-proxy/src/approval.rs — ApprovalRegistry: holds paused requests and wakes them on resolve.
  • crates/honmoon-mgmt/src/lib.rs — axum management API (audit query, approval queue, policy) + the embedded dashboard (rust-embed).
  • crates/honmoon-core/src/engine.rs — decide() / decide_explained() / decide_pii_audit_only() (detect mode, PII-caused verdicts held back): CEL rule evaluation + egress matching.
  • crates/honmoon-core/src/audit.rs — AuditLog (bounded in-memory ring + optional JSONL sink), AuditEvent, Decision.
  • crates/honmoon-core/src/protocols.rs — wire parsers (parse_postgres_query, parse_sql, parse_k8s_request) → SQL/K8s facts.
  • crates/honmoon-core/src/lib.rs — the policy model (Policy, Egress, Rule, Verdict, Facts, HttpFacts, SqlFacts, K8sFacts).

For understanding the control plane and UI:

  • packages/api/src/audit.ts — durable JSONL audit-log query layer; src/index.ts serves it (Bun.serve).
  • packages/policy/src/index.ts + schema/policy.schema.json — policy types (incl. the AuditEvent/PendingApproval runtime model) and validation.
  • apps/dashboard/src/App.tsx — dashboard SPA shell; src/api.ts talks to the management API; views in src/components/.

For understanding policy authoring:

  • policies/agent.yaml — example policy (egress allow/deny + CEL protocol rules).

Module Reference

Module Purpose Key Files Depends On Depended By
crates/honmoon-core/ Policy model + decision engine (decide()/decide_explained()/decide_pii_audit_only()): CEL rules + egress matching; audit (AuditLog/AuditEvent); protocols (PostgreSQL/K8s parsers); content-aware detection + redaction: pii (Tier-1 PII), secret_detect (API keys/tokens), redact (joins both into the reversible secret_tokenizer) src/lib.rs, src/engine.rs, src/audit.rs, src/protocols.rs, src/pii.rs, src/secret_detect.rs, src/redact.rs, src/secret_tokenizer/ serde, serde_json, serde_yaml, thiserror, time, cel, regex, aho-corasick, hmac, sha2 honmoon-proxy, honmoon-mgmt, honmoon-cli
crates/honmoon-proxy/ CONNECT egress proxy (gateway); builds Facts, audits decisions, holds paused requests (approval); GatewayState shared with the management API src/gateway.rs, src/approval.rs honmoon-core, tokio, tracing honmoon-mgmt, honmoon-cli
crates/honmoon-mgmt/ axum management API (audit query, approval queue, policy) + embedded dashboard (rust-embed) src/lib.rs, build.rs honmoon-core, honmoon-proxy, axum, rust-embed, tokio honmoon-cli
crates/honmoon-cli/ honmoon binary — run/gateway/join; gateway runs proxy + management API; policy validate loads a policy through the same loader and exits, binding nothing; hook is the Claude Code plugin's command-transport backend (stdin hook JSON → honmoon-core redaction → stdout verdict) src/main.rs, src/hook.rs honmoon-core, honmoon-proxy, honmoon-mgmt, tokio, clap, serde_json, hmac, sha2 — (binary)
packages/claude-plugin/ Claude Code plugin (.claude-plugin/plugin.json + hooks/hooks.json): PreToolUse/PostToolUse/UserPromptSubmit command hooks that shell out to honmoon hook for client-side secret/PII redaction (transcript hygiene) .claude-plugin/plugin.json, hooks/hooks.json, scripts/redact.sh honmoon binary (runtime, via PATH/HONMOON_BIN) — (Claude Code plugin)
packages/policy/ TS policy types + runtime decision model + JSON Schema src/index.ts, schema/ — @honmoon/cli, @honmoon/api, @honmoon/dashboard
packages/cli/ honmoonctl control-plane CLI src/index.ts @honmoon/policy — (binary)
packages/api/ Durable JSONL audit-log query API (Bun.serve) src/index.ts, src/audit.ts @honmoon/policy —
apps/dashboard/ React SPA (overview/audit/policy/approvals) src/App.tsx, src/components/, vite.config.ts @honmoon/policy embedded in honmoon-mgmt

Architecture Invariants

Fail closed: The default egress verdict is deny. Absence of a matching allow/deny entry must never silently allow a request. Violating this turns the firewall into a no-op.

Data plane stays open source: Any component that inspects traffic or credentials (crates/*) must remain Apache-2.0 (or equivalent OSS). Monetization happens in the control/cloud plane only. Gating the data plane breaks the trust that drives adoption.

honmoon-core is transport-agnostic: Do NOT give honmoon-core an async runtime, a socket, or a network client. It can then be embedded anywhere and unit-tested without a runtime. Transport/proxy code stays in honmoon-proxy / honmoon-cli.

Transport-agnostic is not I/O-free, and issue #166 settled the difference rather than pretending it away: audit.rs opens and appends to one file, the operator's JSONL audit sink, and the hardening around that open stays in the crate because it enforces an invariant of AuditLog itself. That is the only file the crate touches, an environment read or a second file is still forbidden, and crates/AGENTS.md states the boundary in full.

Dual policy model stays in sync: The Rust model (honmoon-core) and the TS model (@honmoon/policy) describe the same policy. Changes to one must update the other (tracked as TD-001). The JSON Schema is the intended future single source of truth.

No decryption surprises: Extract only declared protocol Facts at the wire level. Do NOT add deep packet inspection that decrypts payloads beyond what policy needs and documents.

Cross-Cutting Concerns

Error handling: Rust libraries use thiserror (honmoon_core::Error); the binary uses anyhow. Unimplemented modes currently bail! with an explicit message rather than failing open.

Logging: Rust uses tracing + tracing-subscriber (controlled by RUST_LOG env filter). TS uses console/Bun logging for now.

Testing: Rust unit tests live inline (#[cfg(test)]) — cargo test --workspace. TS uses bun test. Target >80% coverage for new code (see .please/docs/knowledge/workflow.md).

Configuration: Policy is YAML (policies/*.yaml), validated by packages/policy/schema/policy.schema.json. Workspace deps are pinned centrally in the root Cargo.toml ([workspace.dependencies]); JS workspaces are declared in the root package.json.

Quality Notes

Well-tested: honmoon-core (policy parsing, audit log), honmoon-proxy (domain matching, CONNECT parsing, approval registry + hermetic egress test in tests/egress.rs), honmoon-mgmt (pause→approve/deny→tunnel/403 end-to-end in tests/e2e.rs), @honmoon/api (audit query). Safe to extend.

Fragile / incomplete: honmoon run does not yet sandbox the child's network namespace — it only sets proxy env vars, so a child that ignores them escapes the policy. honmoon join is a stub (bail!). SQL/K8s parsing exists and is tested in honmoon-core::protocols, but is not yet fed by a live inline TCP relay (TD-006); over CONNECT only http.host-based pause rules fire today. TLS termination / HTTP body inspection are unbuilt. The dashboard's policy editor is read-only (live hot-reload is Phase 5). @honmoon/api query is read-only; interactive approvals are served by the in-process management API (honmoon-mgmt), which must share the data plane's runtime.

Technical debt: TD-001 (duplicated Rust/TS policy model), TD-002 (serde_yaml deprecated). Tracked in .please/docs/tracks/tech-debt-tracker.md.


Last updated: 2026-06-23

Key ADRs:

  • ADR-0002: Phase 1 CONNECT egress proxy on raw tokio; defer Pingora to the TLS-inspection phase.
  • ADR-0001: Adopt Pingora (superseded by 0002).
  • Candidates not yet recorded: CEL over HCL, Rust data plane + Bun control plane, open-core boundary.