feat: enforcement gateway v2 - agent-facing MCP server with human-only approval#58
feat: enforcement gateway v2 - agent-facing MCP server with human-only approval#58jessfortemnaturae8717 wants to merge 1 commit into
Conversation
…y approval This is a complete enforcement layer rewrite with the core invariant: "The agent proposes. The gateway enforces. RecourseOS verifies consequences." Key changes: - Agents receive gateway tools, never raw credentials - gateway_approve/reject removed (human-only control plane) - Terraform is plan-bound (plan_id verification, hash, TTL, approval) - kubectl split into operation-specific tools (get/logs vs apply/delete) - Shell sandboxed with explicit allow/escalate/block lists - Policy model: per-environment rules, protected namespaces New commands: - recourse gateway serve -e prod - recourse gateway doctor -e prod (28 self-tests) Trust boundary documented in README and docs/enforcement-gateway.md Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a1c56735fe
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if (options.policyFile && fs.existsSync(options.policyFile)) { | ||
| // TODO: Load from YAML |
There was a problem hiding this comment.
Load the policy file before serving requests
runGatewayMcpServer accepts --policy/policyFile, but this branch is a no-op, so the server always runs with defaults even when operators supply stricter production rules. That silently disables custom enforcement (protected namespaces, TTLs, shell blocks, etc.), which is a security/control-plane regression because callers believe policy overrides are active when they are not.
Useful? React with 👍 / 👎.
|
|
||
| // Run terraform plan | ||
| const planFile = path.join(cwd, `tfplan-${Date.now()}`); | ||
| const planResult = await runCommand('terraform', ['plan', '-out=' + planFile, ...extraArgs], cwd); |
There was a problem hiding this comment.
Honor workspace input when creating Terraform plans
gateway_terraform_plan accepts a workspace argument, but the plan command is executed without selecting or passing that workspace. As a result, plans run in whichever workspace is currently active, so the stored workspace metadata can be wrong and protections like workspace-specific approval policy can be bypassed unintentionally.
Useful? React with 👍 / 👎.
| const kubectlArgs = ['apply']; | ||
| if (file) kubectlArgs.push('-f', file); | ||
| if (namespace) kubectlArgs.push('-n', namespace); |
There was a problem hiding this comment.
Add stdin source flag for inline kubectl manifests
When gateway_kubectl_apply is called with manifest (and no file), the code writes YAML to stdin but never adds -f - to kubectl apply. In this path kubectl has no manifest source argument, so inline-manifest applies fail at runtime instead of executing the evaluated change.
Useful? React with 👍 / 👎.
| options: GatewayMcpServerOptions = {} | ||
| ): Promise<void> { | ||
| verbose = options.verbose ?? false; | ||
| currentEnvironment = options.environment ?? 'dev'; |
There was a problem hiding this comment.
Validate environment values before using policy maps
The server trusts options.environment and stores it directly in currentEnvironment without normalization/validation. If callers pass values like production (which the CLI help text suggests), later lookups such as policy.environments[currentEnvironment] become undefined and mutation handlers return runtime errors instead of enforceable decisions.
Useful? React with 👍 / 👎.
Summary
Complete enforcement layer rewrite with the core invariant:
gateway_approve/gateway_rejectremoved (human-only control plane)New Commands
Gateway Doctor Output
Trust Boundary
Test plan
npm run buildpassesrecourse gateway doctor -e prodpasses (28/28 tests)🤖 Generated with Claude Code