3. Development: Protect the Customer Repository

Delivery stage: Development environment New problem: How can Forge execute customer code without seeing unrelated source, developer credentials, or an unrestricted network? Deliverable: A tested Sandbox boundary and disposable workspace design. Working lab: code/02

The question behind the word

ByteCraft's design partner is willing to provide a small private repository, but only after the team explains where the code will live and who can access it. After the local lab, Maya says, "Forge runs in a sandbox now."

Lina asks a deceptively simple question:

What exactly is the sandbox protecting, and what is it not protecting?

A sandbox is not a magic label. For Forge, it must protect private source code, separate the Agent from credentials, restrict network destinations, and leave enough evidence to explain a failed or malicious action. If the team cannot name those boundaries, it cannot test them.

This chapter pauses the feature work and opens the sandbox layer by layer.

karsSandbox is the unit of work

In kars, one karsSandbox represents one Agent workload. It connects:

  • a runtime such as OpenClaw, Hermes, an adapter, or BYO;
  • a required InferencePolicy;
  • sandbox isolation and security settings;
  • network policy and optional approvals;
  • generated Kubernetes resources;
  • reconciliation status and conditions.

The custom resource is the desired-state contract. The running pod is one result of that contract. Editing the pod directly does not redefine the sandbox; the controller may replace it during reconciliation.

For the Forge story, one sandbox means one bounded execution context for one development role. It does not mean every developer, repository, and Agent should share one long-lived workspace.

Open the production-shaped pod

In local Kubernetes and AKS, the important pod shape is:

karsSandbox: forge
└── Pod
    ├── init: egress-guard  UID 0, NET_ADMIN during initialization
    ├── openclaw           UID 1000
    └── inference-router  UID 1001

Agent container technical anatomy

The openclaw container is intentionally treated as the least-trusted container in the Pod. The KARS Controller derives it from the KarsSandbox.spec.runtime and spec.sandbox contract rather than asking the application to hard-code its own security settings.

Kubernetes/runtime detail Forge configuration Result inside the Agent container
runAsNonRoot / runtime UID true / UID 1000 The Agent cannot depend on root ownership
readOnlyRootFilesystem true Image layers, binaries, and system configuration are not writable
allowPrivilegeEscalation false Setuid or process transitions cannot add privilege
Linux capabilities Drop ALL No ambient network, mount, or process-management capability
Writable paths /sandbox, /tmp State and caches have explicit disposal boundaries
Volumes No hostPath or Docker socket The Agent cannot reach the developer home or container daemon
Service account automountServiceAccountToken: false No implicit Kubernetes API bearer token appears in the filesystem
Provider environment No GitHub/Copilot token reference Prompt-injected code cannot read the model credential from env
Repository access No checkout mounted in this Pod Reads and writes cross the Router to the bounded workspace MCP service
Network namespace Shared with Router; UID-aware egress controls Loopback is available, independent external egress is not
Operator access Exec Admission Policy Normal pods/exec and attach paths into the Agent runtime are denied

The container still has meaningful capability: it can run OpenClaw, keep conversation state in approved writable paths, call 127.0.0.1:8443, and ask for governed tools. Sandboxing does not mean an empty process. It means every side effect beyond that runtime envelope crosses a separately enforced boundary.

What kars provides and what the platform still owns

KARS provides the runtime adapter, Controller reconciliation, Router sidecar, UID separation, sandbox security context, Egress Guard integration, NetworkPolicy intent, policy references, Conditions, and exec admission boundary. The platform team still owns the correctness of images, MCP implementations, Secret selection, allowed endpoints, writable data, and any external system that consumes Agent-produced artifacts.

This division is the practical advantage for ByteCraft: security controls are not reimplemented inside OpenClaw, but KARS also does not pretend that an unsafe tool server or incorrectly mounted Secret becomes safe merely because it runs next to a Router.

egress-guard

The init container installs network rules so the Agent UID can reach the router on loopback but cannot establish an independent external path. It is a safety net, not the policy decision point.

agent

Forge and its OpenClaw runtime execute as UID 1000. In the code/01 implementation, OpenClaw does not mount the repository directly. It calls the local router, which mediates access to the separate workspace MCP service. OpenClaw owns neither provider credentials nor direct egress.

inference-router

The Rust router executes as UID 1001. Its model-facing HTTP endpoint uses port 8443; its forward-proxy path uses port 8444. It evaluates policy, budget, identity, egress, governance, and audit behavior.

The UID split matters: code interpreted or executed by Forge does not run as the same operating-system user as the router holding external authority.

Five boundaries around one code change

Maya assigns Forge a workspace containing issue #482. The team follows the task through five boundaries.

1. Process boundary

Forge runs as a non-root Agent process. The router runs under a different UID. A command executed by the development Agent should not be able to inspect the router's process environment or credential material.

This is stronger in local Kubernetes and AKS than in single-container Docker development, where Agent and router are co-located and UID/network separation is not production-equivalent.

2. Filesystem boundary

The Agent receives only the runtime files required for the task. A good development sandbox uses an ephemeral checkout or worktree at a pinned revision and does not mount a developer's home directory, SSH directory, global Git credential store, or unrelated repositories.

Forge applies a stronger split. The hardened forge-workspace-mcp Pod owns the fixed-revision repository in a size-limited emptyDir; the OpenClaw Pod has no repository or hostPath mount. The MCP Deployment also disables automatic service-account token mounting and exposes only seven bounded tools.

kars defines the runtime sandbox, but the platform team still owns careful volume and secret design. A NetworkPolicy cannot protect a Secret that was mounted directly into the Agent container.

3. Network boundary

The Agent sends controlled requests to 127.0.0.1:8443 or the documented proxy path. The egress guard and Kubernetes NetworkPolicy prevent an independent route; the router makes the actual policy decision.

This distinction is important:

  • Network controls answer, "Can this packet leave by another path?"
  • Router policy answers, "Is this model, tool, host, or action allowed?"

Defense in depth requires both.

4. Identity boundary

In production, the router uses Workload Identity or a per-sandbox Entra Agent ID, depending on deployment mode. Forge does not receive the resulting Azure credential.

Local Kubernetes reproduces the pod and network shape but uses a static provider credential for development. It is production-shaped infrastructure, not production identity.

5. Lifecycle and evidence boundary

The controller observes the karsSandbox, creates or updates resources, and reports conditions. The router records request-time decisions. When the task ends, the workspace can be discarded while audit evidence is exported independently.

Ephemeral execution reduces persistence risk, but deleting a pod before exporting evidence can also destroy useful incident context.

Inspect the sandbox rather than assuming

Start with the Forge deployment from Chapter 2, then use the executable lab:

cd code/02
make inspect

The script discovers the generated namespace and Pod from KarsSandbox/forge; it does not hard-code a Pod name. It exports:

  • the Sandbox desired state and Conditions;
  • the Pod specification and a compact UID/mount summary;
  • NetworkPolicy;
  • the workspace MCP Deployment;
  • the kars exec Admission Policy;
  • recent controller and router logs.

The output is written to .evidence/<UTC timestamp>/ outside Kubernetes, so it survives Pod reconciliation and workspace cleanup.

Normal operators also cannot assume interactive shell access:

kubectl -n kars-forge exec <forge-pod> -c openclaw -- id

kars rejects this request through kars-sandbox-exec-ban. The complete lab can temporarily enable the audited namespace break-glass label, run narrowly scoped read-only probes, and remove the label through a shell trap.

Test the boundaries with Forge

The fixture repository from code/01 is intentionally disposable. Never use a production checkout for these experiments.

Test Expected result
Inspect Forge and its assigned workspace Allowed through kars resources and bounded MCP tools
Read a developer home-directory Secret No host filesystem or home directory is mounted
Call the model through the router Allowed under inference policy
Reach an unknown host directly from OpenClaw Times out with HTTP 000
Write to /etc from OpenClaw Denied by the read-only root filesystem
Find a Copilot credential in OpenClaw No provider credential variable is present
Use ordinary kubectl exec on OpenClaw Denied by kars Admission Policy
Restart the Agent Controller returns workload to desired state
Reference a missing inference policy Degraded/InferencePolicyNotFound

Run the non-disruptive checks:

make test

Run the complete experiment, including short-lived break-glass probes and a Forge Pod replacement:

make test-full

The verified macOS arm64 run showed OpenClaw UID 1000, router UID 1001, denied root-filesystem writes, no provider credential in OpenClaw, blocked direct HTTPS, HTTP 200 through 127.0.0.1:8443, a missing-policy Degraded condition, and successful controller replacement of the deleted Forge Pod.

Before running, the lab enforces the Microsoft package sources used by code/01:

https://packagefeedproxy.microsoft.io/npm/
https://packagefeedproxy.microsoft.io/pypi/simple/
https://packagefeedproxy.microsoft.io/nuget/v3/index.json

Choose the right isolation level

kars uses secure sandbox defaults, including enhanced isolation, a strict seccomp profile, and default-deny networking. AKS can optionally use Kata/AMD SEV-SNP-backed confidential isolation for stronger workload separation.

Confidential isolation may be appropriate when Forge handles unreleased source or high-value build inputs. It does not replace least-privilege identity, signed images, tool policy, egress policy, or code review.

What the sandbox does not promise

The team adds these limitations to its threat model:

  • It does not prove a generated patch is correct.
  • It does not make untrusted code safe to merge.
  • It cannot protect a credential mounted into the Agent by mistake.
  • It does not turn Docker development mode into a production boundary.
  • It does not replace tenant-level RBAC, quotas, image policy, or audit export.
  • It cannot compensate for a policy that deliberately allows arbitrary shell and unrestricted egress.

The sandbox bounds authority. Tests, evaluation, review, and deployment policy still decide whether a change is acceptable.

Sandbox design record for Forge

Before continuing, the team records:

Workload: one Forge Builder task
Source: fixed-revision checkout in the workspace MCP Pod's emptyDir
Agent user: UID 1000
Router user: UID 1001
External path: router only
Credentials in Agent: none
OpenClaw writable scope: /sandbox and /tmp
Repository writes: bounded workspace MCP tools only
Lifecycle owner: kars controller
Evidence destination: code/02/.evidence, then an external audit store
Cleanup: export evidence before Pod or workspace removal

The next chapter turns this understood runtime boundary into a reviewable Kubernetes contract.

Definition of done

The development environment is ready when the disposable fixed-revision checkout is isolated in the workspace MCP Pod, OpenClaw has no repository mount or reusable Git/model credential, direct unknown egress fails, UID separation and exec restrictions are visible, controller reconciliation is proven, and exported evidence survives workspace cleanup.

Official references

Sandbox-escape checkpoint: remove ambient authority

The first containment checkpoint is structural. Forge may write only to /sandbox and /tmp; it receives no host mount, Docker socket, provider credential, or ambient Kubernetes service-account token. Normal exec into the Agent runtime is denied, while break-glass is explicit and audited.

Run the corresponding checks in code/02:

make test

This stage does not assume every prompt injection will be recognized. It removes the process-level primitives needed to turn a bad decision into host or cluster control.