Files
obsidian-vault/personal/projects/archive/execution-broker-repo-cleanup-2026-10-16/docs/deployment.md
T

14 KiB
Executable File

Архив исходника Broker

Историческая копия до очистки репозитория 2026-10-16. Источник: mallexxx/execution-broker, commit ae92c15d31c8396789765cebf82f7971d6f4cb12, файл docs/deployment.md. Старые статусы и deployment pins ниже не заменяют актуальную personal/projects/balda/execution-broker.


Deployment profiles

Keep configuration and token files outside Git. scripts/init-deployment.py creates a fresh smoke-only configuration and refuses to overwrite it. The Compose stack owns separate Broker, projection, and Beads volumes. Beads v1.3.0 runs embedded Dolt inside the Prism sidecar; it is not an external shared Dolt server. Do not attach another Beads writer to this workspace.

Linux coding workers

Build an operator-reviewed image containing execution-runner, the pinned broker-callee, Git, provider CLI binaries and the read-only workflow pack. Use deploy/Dockerfile.runner as the minimal contract. The image must have a /state directory owned by UID/GID 65532 and /etc/execution-runner/config.json. It must run sleep infinity as its entry command so the gateway can invoke RPC. Do not bake live credentials into image layers.

Allowlist prism/story on both Broker and Runner with the exact whole-pack digest in workflows.version and an agent profile such as codex-default. Runner's agent_environment maps profile IDs to explicitly injected environment values. It does not inherit the host process environment. Use a worker profile's credentials_file for an operator-issued lease. Broker pins the lease at admission and delivers it only over the private worker transport. Runner checks repository/profile and expiry, uses the Git token only in the fetch process environment (never argv, Git config files or Callee's environment), and exports only the selected provider environment. No host home directory is copied. Actual provider login and token issuance belong to the operator/secret manager; private repository and real provider acceptance require those credentials.

The bundled Prism pack uses fresh Codex sessions for specification, design and breakdown, followed by up to three implement, verify and review cycles in one disposable worker. A deterministic router requires the exact approval answer approved before mutation. The final quality gate records failure evidence after the repair limit. Callee remains responsible for workflow policy. Agent profile selection is an allowlist/environment boundary; this pack itself pins its provider to Codex.

Docker images must be configured as registry/image@sha256:… or a local immutable sha256:… image ID. Broker has no socket. The separate gateway is a trusted administrative component with the Docker socket and only creates fixed, restricted workers: no host binds, non-root, read-only rootfs, cap-drop ALL, no-new-privileges, 256 PIDs, 4 GiB RAM, two CPUs. Docker workers are not a VM security boundary for hostile multi-tenant code. Configure Docker-host network/firewall policy to restrict worker egress; default bridge networking alone does not isolate the host LAN.

Broker persists the selected Linux image in each private acquisition handle; Gateway rejects a missing or different pin before allocating a container. Upgrade Broker and Gateway together, align their static image IDs and rebuild the workflow pack before admitting new runs. Dynamic builds persist the resolved immutable image ID as well. Docker socket paths and daemon groups are rejected in worker profiles; container builds require an independently isolated builder.

Nested Linux sandbox

Some provider CLIs need user/mount namespaces inside their worker. For those profiles the gateway accepts the operator setting "container_sandbox": "nested-v1". Requests cannot select or modify it. The gateway image bundles the corresponding seccomp policy under /opt/execution-broker/docker-sandbox/nested-v1/. The Docker host must first load the exact apparmor.profile as execution-broker-codex-sandbox-v1, using its AppArmor service or the distribution's apparmor_parser. Install it as a separate profile; preserve docker-default and the host's unprivileged-user-namespace restrictions. Missing policy files or a missing AppArmor profile cause worker creation to fail. An empty setting retains Docker's defaults.

The versioned policy derives from Moby's default profiles and enables namespace, mount and pivot-root operations required by bubblewrap. Workers retain non-root UID, empty outer capabilities, no-new-privileges, read-only root, private state, Docker's masked/read-only system paths, AF_ALG denial and resource limits. Never replace either policy with unconfined, disable system-path guards, or enable a provider's full-access mode to make a check pass. Codex can use its own /proc mount fallback while retaining Docker's inherited proc guards and a separate PID namespace. Qualify the exact kernel, Docker, provider and both security profiles with a real Story and attempted read-only writes before enabling new admissions. Do not remove a loaded profile while a worker still uses it.

Virfield macOS workers

Virfield v2 must have a ready, approved template and independent lease cleanup.

The operator's macos27 path passed production reacceptance on 2026-10-16 with installed Virfield 8bfff9f, the corrected Runner package and reviewer-deny workflow. The support matrix records its tests, artifacts, credential settlement and cleanup. Qualify each different deployment with its own fresh worker. A ready template is not fresh worker evidence.

Configure a Broker worker:

{
  "runtime_class": "macos-vm",
  "endpoint": "http://host.docker.internal:7780",
  "token_file": "/run/secrets/virfield_token",
  "template": "macos27",
  "ssh_route": "tunnel",
  "ssh_tunnel_host": "host.docker.internal",
  "bootstrap_file": "/opt/execution-broker/assets/macos-bootstrap.tar.gz",
  "limit": 2
}

Mount the API token and bootstrap archive read-only into the Broker container. With Colima, use the lease-bound Virfield tunnel and the explicit Docker host alias shown above: the guest's IP may be unreachable from Docker. ssh_tunnel_host rewrites only a numeric loopback address returned by the authenticated API, preserving its lease-specific port and guest SSH host-key pin. The host alias must resolve and reach host loopback listeners from the Broker network; no guest or host listener is exposed on all interfaces. For a native Broker on the Mac, omit ssh_tunnel_host. Use ssh_route: direct only when the Docker network can reach the guest's IP/SSH port, and omit the tunnel override. Do not disable SSH pinning or MCP DNS-rebinding protections to work around routing. Broker uses the authenticated REST API.

A ready image can preinstall Runner/Callee/config, or an operator can package a credential-free bootstrap:

make build
./scripts/build-callee.sh "$PWD/.build/bin/broker-callee"
python3 scripts/build-macos-bootstrap.py \
  --runner .build/bin/execution-runner --callee .build/bin/broker-callee \
  --repository https://github.com/baldaworks/callee.git \
  --output .build/macos-bootstrap.tar.gz

Bootstrap uses the per-lease SSH identity and pinned guest host key. Its digest is persisted before acquisition. Installation runs only inside the disposable leased VM and requires that guest account's noninteractive sudo. A failed bootstrap retains its lease for cleanup; it never modifies a golden image. The bootstrap shown contains only the smoke workflow. Install authorized provider binaries/credentials and a reviewed Runner config before enabling coding profiles. VM checkout is on guest-local disk, never a mutable host shared folder.

Managed hosts

The proposed host permissions, SSH tooling, VM cache, iPad deployment and Balda integrations are tracked in the work plan.

Install execution-host-runner under a dedicated service identity. Keep its configuration/plan writable only by the administrator. A plan lists a fixed host, identity and ordered operation objects with absolute preflight, apply, verify, rollback argv. Requests cannot supply new commands. Preflight commands must actually be read-only: this is an operator obligation, not something the executable can infer.

Generate an operator signing key outside Balda/Broker/host-runner:

executionctl -operation keygen -approval-key /secure/operator/approval.key

Configure the host profile's host_id and approval_key_file (the .pub file) on Broker and host-runner. Start host-runner with --config, --plan, and --profile. Use TLS/authenticated private networking for a remote host; the built-in plain HTTP listener is intended behind that transport. deploy/execution-host-runner.service and .plist are templates and are not installed automatically.

Call execution_remote_plan, review the returned exact Plan and digest, save the plan object to a file, and sign it only after human approval:

executionctl -operation approve-plan -approval-key /secure/operator/approval.key \
  -plan-file reviewed-plan.json -story-id eb-example -chat-id CHAT -topic-id TOPIC \
  -ttl-seconds 900 -out approval.json

Pass approval.json's capability to the matching run with a shorter run TTL (for example 600 seconds). A capability binds nonce, host, OS identity, ordered operations, plan SHA, Story, chat/topic and expiry; it cannot authorize a second run. The signer is intentionally unavailable through MCP. Automatic capability minting from a model-provided approved string would erase the human authorization boundary.

All operations preflight before the first mutation. Verify failure rolls back started operations in reverse order, within the original deadline. An interrupted/expired rollback is reported as requiring manual action. Service restart marks uncertain mutations remote_outcome_unknown; it never automatically replays them. Only one mutation plan runs on a host at a time.

Credential lease file

Set credentials_file to an absolute private path on the Broker for the selected worker profile. Mount it as a read-only secret. A run request cannot supply this path or secret material. Example structure (replace the expiry with a time covering the intended run, at most 24 hours from now):

{
  "repository": "https://github.com/example/project.git",
  "agent_profile": "codex-default",
  "expires_at": "REPLACE_WITH_RFC3339_EXPIRY",
  "environment": {"PROVIDER_CREDENTIAL_VARIABLE": "OPERATOR_ISSUED_SCOPED_VALUE"},
  "git_token": "OPTIONAL_REPOSITORY_SCOPED_TOKEN"
}

The provider's actual accepted credential variable comes from its reviewed image/profile. Git HTTPS authentication uses Basic x-access-token:TOKEN; configure a compatible repository provider/token. Redirects are disabled. Omit git_token for public repositories. Runtime requests cannot choose additional credential files or profiles. The metadata does not issue or cryptographically attenuate a provider token: the issuer must enforce the same repository, permission and time scope. Broker/Runner validate metadata and execution lifetime; the external provider must revoke/expire the credential as promised.

Known provider/Git secret values are redacted from event summaries, Human questions, result text and exported Callee logs. Source patches and arbitrary build archives remain reviewable outputs, not a guaranteed secret-sanitization boundary. Private lease material is erased from active state after confirmed cleanup; encrypted backups and SQLite storage can still retain historical bytes and need normal secure retention controls.

Workflow completion policy

prism/story runs fresh sequential roles. Specify/design/breakdown/reviewer use the Codex read-only sandbox argument. The operator must verify that the installed provider bridge supports and enforces that argument before enabling the profile. Docker coding requires separate provider sandbox acceptance; see Codex runtime. The final Script quality gate requires strict JSON reports from both reviewer and verifier, status passed, no unresolved findings, and at least one executed verification command. Commands must exit zero unless the check declares an expected_exit_code; expected nonzero exits require observed behavior evidence. ACP can concatenate assistant progress text before the final JSON object. The gate accepts that preamble, preserves the complete raw output in quality.json, and validates the first JSON object without skipping an earlier report. Competing objects, trailing content, failed, malformed or unexecuted reports fail the workflow. This validates reports; it does not independently prove that a model told the truth about evidence. Human/operator review of artifacts remains necessary for release approval.

The adapter currently rejects all Parallel nodes before starting work because it has no per-writer worktree allocator. This safely prevents shared-checkout concurrent mutation; parallel read-only roles and worktree fan-out are not yet advertised as supported. Parallel Stories still use separate workers and remain supported.

Persistent macOS OAuth

For reusable OAuth, configure the separate host issuer described in credentials and include compose.credentials.yaml. A macos-codex profile uses credential_endpoint plus credential_token_file instead of a static credentials_file. The runner receives .codex/auth.json in its private HOME; successful and failed terminal workflows checkpoint it before release. Neither golden image nor bootstrap contains login credentials. A prism/story run has a design approval gate but no per-VM login gate. The CLI enrollment workflow oauth/story is reserved for first login/re-enrollment.

Coordinated backup and restore

Use the stack recovery runbook for Balda, Broker, Prism, Beads, gateway, configuration and vault snapshots. A Broker-only SQLite backup does not cover this stack.