From 77787798e02684cf10efe458ff8440002a7ac432 Mon Sep 17 00:00:00 2001 From: Lakshman Patel Date: Sat, 22 Aug 2026 08:24:45 +0530 Subject: [PATCH] feat: adopt codex status transparency and audit plan --- cmd/status_snapshot.go | 15 +++++- cmd/status_snapshot_test.go | 13 ++++++ docs/plans/codex-adoption-plan.md | 77 +++++++++++++++++++++++++++++++ internal/status/snapshot.go | 1 + 4 files changed, 104 insertions(+), 2 deletions(-) create mode 100644 docs/plans/codex-adoption-plan.md diff --git a/cmd/status_snapshot.go b/cmd/status_snapshot.go index fdc2262d..0b133052 100644 --- a/cmd/status_snapshot.go +++ b/cmd/status_snapshot.go @@ -8,6 +8,7 @@ import ( hawkconfig "github.com/GrayCodeAI/hawk/internal/config" "github.com/GrayCodeAI/hawk/internal/engine" "github.com/GrayCodeAI/hawk/internal/plugin" + "github.com/GrayCodeAI/hawk/internal/sandbox" "github.com/GrayCodeAI/hawk/internal/status" "github.com/spf13/cobra" ) @@ -48,6 +49,12 @@ func buildStatusSnapshot() status.Snapshot { snapshot.Provider = strings.TrimSpace(settings.Provider) } snapshot.Permission.SandboxMode = settings.Sandbox + // Resolve the native confinement backend the way execution would, so the + // snapshot shows the real isolation technology (seatbelt/landlock/docker…) + // rather than only the requested policy label. + if sel := sandbox.SelectSandbox(sandbox.IsolationDefault, snapshot.Workspace); sel.Backend != "" { + snapshot.Permission.SandboxBackend = sel.Backend + } snapshot.Permission.EffectiveRules = len(settings.AllowedTools) + len(settings.DisallowedTools) + len(settings.AutoAllow) if settings.AutonomyExplicit { snapshot.Permission.AutonomyTier = fmt.Sprintf("%d", settings.Autonomy) @@ -74,9 +81,13 @@ func buildStatusSnapshot() status.Snapshot { } func formatStatusSnapshot(s status.Snapshot) string { - return fmt.Sprintf("Hawk status\nSchema: %s\nWorkspace: %s\nGit branch: %s\nProvider: %s\nModel: %s\nAutonomy tier: %s\nSandbox: %s\nPermission rules: %d\nMCP: %d configured (%s)\nSkills: %d (%s)\nSecrets redacted: %t\n", + backend := "" + if s.Permission.SandboxBackend != "" { + backend = " (" + s.Permission.SandboxBackend + ")" + } + return fmt.Sprintf("Hawk status\nSchema: %s\nWorkspace: %s\nGit branch: %s\nProvider: %s\nModel: %s\nAutonomy tier: %s\nSandbox: %s%s\nPermission rules: %d\nMCP: %d configured (%s)\nSkills: %d (%s)\nSecrets redacted: %t\n", s.SchemaVersion, s.Workspace, s.GitBranch, s.Provider, s.Model, - s.Permission.AutonomyTier, s.Permission.SandboxMode, + s.Permission.AutonomyTier, s.Permission.SandboxMode, backend, s.Permission.EffectiveRules, s.MCP.Configured, s.MCP.State, s.Skills.Configured, s.Skills.State, s.Permission.SecretRedacted) } diff --git a/cmd/status_snapshot_test.go b/cmd/status_snapshot_test.go index d7cdcfff..ed8ad8d0 100644 --- a/cmd/status_snapshot_test.go +++ b/cmd/status_snapshot_test.go @@ -3,6 +3,8 @@ package cmd import ( "strings" "testing" + + "github.com/GrayCodeAI/hawk/internal/sandbox" ) func TestFormatStatusSnapshot(t *testing.T) { @@ -14,3 +16,14 @@ func TestFormatStatusSnapshot(t *testing.T) { } } } + +func TestStatusSnapshotReportsNativeSandboxBackend(t *testing.T) { + want := sandbox.SelectSandbox(sandbox.IsolationDefault, ".").Backend + got := buildStatusSnapshot().Permission.SandboxBackend + if got != want { + t.Fatalf("sandbox backend = %q, want selector result %q", got, want) + } + if want == "" { + t.Skip("no sandbox backend on this platform") + } +} diff --git a/docs/plans/codex-adoption-plan.md b/docs/plans/codex-adoption-plan.md new file mode 100644 index 00000000..18d73075 --- /dev/null +++ b/docs/plans/codex-adoption-plan.md @@ -0,0 +1,77 @@ +# OpenAI Codex CLI Adoption Plan + +Status: Audited. Core ideas already implemented natively in hawk; remaining +deltas recorded as future RFCs. + +Source: `https://github.com/openai/codex` (Apache-2.0, Rust workspace +`codex-rs`, ~100 crates) + +## Executive Decision + +The audit found that every codex-rs capability relevant to hawk's security and +runtime model already has a native Go implementation, several of them deeper +than codex's equivalents because they build on hawk's ecosystem submodules. +No second runtime, sandbox layer, or policy engine was created. + +One small transparency improvement was adopted: the resolved native sandbox +backend (seatbelt / landlock / docker / …) is now reported in the unified +status snapshot alongside the requested policy label. + +Three codex ideas are deliberately deferred as future RFCs; see +[Deliberately Deferred](#deliberately-deferred). + +## Capability Audit + +| codex-rs crate/concept | hawk implementation | Decision | +|---|---|---| +| `core` agent loop | `internal/engine` | Keep hawk | +| `tui`, `ansi-escape`, `terminal-detection` | Bubble Tea/Lipgloss TUI | Keep hawk | +| `rollout`, `thread-store`, `history` JSONL sessions with resume/fork | `internal/session` JSONL + WAL + named checkpoints + fork + recovery + handover | Keep hawk (richer) | +| `app-server-daemon`, `app-server-protocol` (JSON-RPC for IDE/desktop) | `internal/daemon` HTTP/SSE on 4590 + `internal/acp` | Keep hawk | +| `mcp-server`, `codex-mcp`, `rmcp-client`, `connectors` | `internal/mcp` client+server, `external/hawk-mcpkit` scaffolding | Keep hawk | +| `skills`, `plugin`, `hooks` | community skill registry + structural validator, plugins, expanded lifecycle hook events | Keep hawk | +| `login`, `keyring-store`, `aws-auth` | eyrie credential store in OS keychain across 28 providers | Keep hawk (broader) | +| `model-provider(-info)`, `models-manager`, `ollama`, `lmstudio` | `external/eyrie` adapters, catalog, cascade routing | Keep hawk (much broader) | +| `memories`, `agent-graph-store`, `context-fragments` | `external/yaad` graph memory; eventlog/graphjournal projections | Keep hawk | +| `apply-patch`, `file-search`, `file-watcher`, `git-utils` | edit tools, codegraph, git tooling, watcher hooks | Keep hawk | +| `external-agent-migration` | trace reads Claude Code / Codex / Gemini CLI / OpenCode / Cursor sessions | Parity | +| **`linux-sandbox`** (Landlock + seccomp-bpf) | `internal/sandbox/landlock.go`, `seccomp.go` — raw syscalls and BPF filter, no external tools | Already implemented | +| **macOS Seatbelt** | `internal/sandbox/seatbelt.go` — SBPL profile generator with per-policy read/write/process/network rules | Already implemented | +| Windows confinement | `internal/sandbox/windows_acl.go` | Already implemented | +| **`bwrap`**, nsjail, container fallbacks | `selector.go` orders landlock > nsjail > bwrap > docker per platform | Already implemented | +| **`network-proxy`** (egress through inspectable proxy) | `internal/sandbox/netproxy.go` + egress tests | Already implemented | +| **`execpolicy`** (structured pre-exec command analysis) | `internal/sandbox/code_verifier.go` static analysis of generated code (blocked modules/functions/patterns incl. privilege escalation) plus permission-engine destructive-command hard block and user `NeverAllow` ceiling | Covered by equivalent layers | +| **`shell-escalation`** (exact re-validated widening approval) | sandbox policy statements direct denial/escalation flow; `PermissionService.EscalatePermission` binds single-use opaque tokens to exact calls | Covered by equivalent layers | +| `sdk` (TS), `thread-manager-sample` | daemon REST/SSE API is the programmatic surface; Go SDK deferred until consumers require it | Deferred (matches fx plan) | + +### Adopted in this change + +- Status transparency: `hawk status` (text and `--json`) now resolves the + effective sandbox backend via `sandbox.SelectSandbox` and reports it as + `permission.sandbox_backend`, so operators can confirm real kernel-level + isolation (seatbelt on macOS, landlock/seccomp on Linux, ACL on Windows, + docker fallbacks) instead of only the strict/workspace/off label. + +## Deliberately Deferred + +- **Code Mode** (`code-mode`, `code-mode-runtime`, `v8-poc`): letting the model + author a short script that batches many tool calls into one sandboxed + execution. Promising token-cost lever, but it introduces an embedded JS + runtime and a new execution authority boundary. Requires its own threat + model (script capabilities, network/file scope, output trust) before any + implementation. Track as a standalone RFC. +- **Agent identity signing** (`agent-identity`): cryptographic identity for + agents and subagents woven into audit records. hawk's tamper-evident + security log covers integrity today; signed delegation chains are worth a + focused design once multi-org delegation exists. +- **Cloud tasks client** (`cloud-tasks*`): remote task queue integration. + Hawk Cloud already provides sync/review surfaces; a queue protocol would + duplicate that until a concrete consumer exists. + +## Verification + +- `go test ./...` full suite green. +- `make vet`, `make lint`, `hawk verify` green. +- Repo-owned markdown passes `markdownlint-cli2 '**/*.md'` (CI scope); + findings under `external/*` belong to the submodule repos and follow their + own contribution flow. diff --git a/internal/status/snapshot.go b/internal/status/snapshot.go index edd0c8fa..3fc01edf 100644 --- a/internal/status/snapshot.go +++ b/internal/status/snapshot.go @@ -36,6 +36,7 @@ type PermissionStatus struct { Mode string `json:"mode,omitempty"` AutonomyTier string `json:"autonomy_tier,omitempty"` SandboxMode string `json:"sandbox_mode,omitempty"` + SandboxBackend string `json:"sandbox_backend,omitempty"` EffectiveRules int `json:"effective_rules,omitempty"` SecretRedacted bool `json:"secret_values_redacted"` }