HOMELAB-1669: fix(agent-sandbox-mcp): pin sandbox-mcp image digest + align pod label with contract §5 #524

Merged
aaron merged 2 commits from epic/LD1 into live 2026-09-30 04:19:01 +00:00
Owner

What

Replaces the placeholder tag in core/manifests/agent-sandbox-mcp/deployment.yaml with the digest-pinned reference published by the live build of PR #523 (agent-sandbox-mcp is the last piece of the LD1.1 MCP spike; nothing syncs this module yet, so the change is inert in a cluster — the ArgoCD Application that reads it is the second PR of this ticket, in prod).

The pin is harbor.aaron.reynoza.org/lab-director/sandbox-mcp:v1.0.4@sha256:1ebd59688fd6da8f6a5dd4e04c38c8e1160fc21f959f55becf7f2d74547842c4. Both halves are deliberate: the v1.0.4 alias tag keeps the reference readable and crane/docker commands re-derivable, while the digest is the half Kubernetes resolves — .forgejo/workflows/mcp-server-image-build.yaml republishes the v1.0.4 and latest aliases on every later live build, so the bare tag would move under a synced Deployment.

Re-derived rather than copied from the ticket, and confirmed to be this image (crane config: entrypoint uvicorn k8s_agent_sandbox_mcp_server.app:app --host 0.0.0.0 --port 8000, USER 65532:65532, org.opencontainers.image.version=v1.0.4, source Homelab/infra-core):

crane digest harbor.aaron.reynoza.org/lab-director/sandbox-mcp:v1.0.4
# sha256:1ebd59688fd6da8f6a5dd4e04c38c8e1160fc21f959f55becf7f2d74547842c4

Comment/doc corrections

The pin makes four existing statements false, so they are corrected in the same PR rather than left as contradicted claims: the deployment.yaml pin comment, the kustomization.yaml header line ("which is why deployment.yaml carries a placeholder tag rather than a digest"), and the README's Pin table, "Deployment order" step 5 and "Digest pin" entry under "Left out on purpose" — all of which described the pin as the prod wiring ticket's job. The README's Pin section now carries the crane digest re-derivation command, and "Verify" gained a digest-pin assertion.

Verify

kubectl kustomize core/manifests/agent-sandbox-mcp | grep -c '^kind:'   # 5, unchanged
kubectl kustomize core/manifests/agent-sandbox-mcp | grep 'image:'      # the digest-pinned ref, once
yamllint -d relaxed core/manifests/agent-sandbox-mcp/                   # exit 0, no new warnings

No new yamllint warnings: the single remaining line-length warning is pre-existing (the SDK-finding comment), and the long image line is a single unbreakable token, which yamllint's allow-non-breakable-words permits.

Class B by the landing taxonomy: a module that nothing synchronises, so no cluster state can change from this PR. Digest-pinning review target: confirm the digest above against Harbor and that the tag+digest form is the intended convention for this image.

Second commit in this PR: pod label alignment (contract §5) — scope note

Found while wiring the ArgoCD side, and it is the difference between "wired" and "working", so it is fixed here rather than left as a trap
for the LD1.2 live smoke. Say the word if you want it split out: it is one self-contained commit (f3228e5) and cherry-picks cleanly.

The seat's NetworkPolicy admits exactly one ingress caller — pods labelled app.kubernetes.io/name: agent-sandbox-mcp in
agent-sandbox-system (contract §5 ingress: "everything else denied") — and prod/manifests/agent-sandbox/seat-template.yaml enforces
exactly that selector (networkPolicyManagement: Managed + the custom policy). The MCP Deployment's pod template carried only
app: agent-sandbox-mcp, so the rendered pod labels were {app: agent-sandbox-mcp}.

Effect had it shipped: the server reaches the apiserver fine, so create_sandbox, delete_sandbox and get_sandbox_status work — but
every call that talks to a seat's runtime sidecar at <podIP>:8888 (execute_command, upload_file, download_file, list_files,
file_exists) is denied and times out. That is exactly the end-to-end exec this ticket exists to prove, and it would have read as an
MCP/SDK bug rather than a label typo.

Fixed in this module, not in the seat template: app.kubernetes.io/name is the ratified contract value and the convention the rest of
infra-core/prod follows, and the alternative would edit a ratified contract to match a module. app: agent-sandbox-mcp stays — the
Service selects on it and the Deployment's selector is immutable, so this applies in place with no recreate (additive for both).

Verify: still 5 objects; pod labels carry both; Service and Deployment selectors unchanged; README "Verify" now asserts the pod label so
this cannot regress silently.

## What Replaces the placeholder tag in `core/manifests/agent-sandbox-mcp/deployment.yaml` with the digest-pinned reference published by the `live` build of PR #523 (`agent-sandbox-mcp` is the last piece of the LD1.1 MCP spike; nothing syncs this module yet, so the change is inert in a cluster — the ArgoCD Application that reads it is the second PR of this ticket, in `prod`). The pin is `harbor.aaron.reynoza.org/lab-director/sandbox-mcp:v1.0.4@sha256:1ebd59688fd6da8f6a5dd4e04c38c8e1160fc21f959f55becf7f2d74547842c4`. Both halves are deliberate: the `v1.0.4` alias tag keeps the reference readable and `crane`/`docker` commands re-derivable, while the digest is the half Kubernetes resolves — `.forgejo/workflows/mcp-server-image-build.yaml` republishes the `v1.0.4` and `latest` aliases on every later `live` build, so the bare tag would move under a synced Deployment. Re-derived rather than copied from the ticket, and confirmed to be *this* image (`crane config`: entrypoint `uvicorn k8s_agent_sandbox_mcp_server.app:app --host 0.0.0.0 --port 8000`, `USER 65532:65532`, `org.opencontainers.image.version=v1.0.4`, source `Homelab/infra-core`): ```bash crane digest harbor.aaron.reynoza.org/lab-director/sandbox-mcp:v1.0.4 # sha256:1ebd59688fd6da8f6a5dd4e04c38c8e1160fc21f959f55becf7f2d74547842c4 ``` ## Comment/doc corrections The pin makes four existing statements false, so they are corrected in the same PR rather than left as contradicted claims: the `deployment.yaml` pin comment, the `kustomization.yaml` header line ("which is why deployment.yaml carries a placeholder tag rather than a digest"), and the README's Pin table, "Deployment order" step 5 and "Digest pin" entry under "Left out on purpose" — all of which described the pin as the prod wiring ticket's job. The README's Pin section now carries the `crane digest` re-derivation command, and "Verify" gained a digest-pin assertion. ## Verify ```bash kubectl kustomize core/manifests/agent-sandbox-mcp | grep -c '^kind:' # 5, unchanged kubectl kustomize core/manifests/agent-sandbox-mcp | grep 'image:' # the digest-pinned ref, once yamllint -d relaxed core/manifests/agent-sandbox-mcp/ # exit 0, no new warnings ``` No new yamllint warnings: the single remaining `line-length` warning is pre-existing (the SDK-finding comment), and the long image line is a single unbreakable token, which `yamllint`'s `allow-non-breakable-words` permits. Class B by the landing taxonomy: a module that nothing synchronises, so no cluster state can change from this PR. Digest-pinning review target: confirm the digest above against Harbor and that the tag+digest form is the intended convention for this image. ## Second commit in this PR: pod label alignment (contract §5) — scope note Found while wiring the ArgoCD side, and it is the difference between "wired" and "working", so it is fixed here rather than left as a trap for the LD1.2 live smoke. Say the word if you want it split out: it is one self-contained commit (`f3228e5`) and cherry-picks cleanly. The seat's NetworkPolicy admits **exactly one** ingress caller — pods labelled `app.kubernetes.io/name: agent-sandbox-mcp` in `agent-sandbox-system` (contract §5 ingress: "everything else denied") — and `prod/manifests/agent-sandbox/seat-template.yaml` enforces exactly that selector (`networkPolicyManagement: Managed` + the custom policy). The MCP Deployment's pod template carried only `app: agent-sandbox-mcp`, so the rendered pod labels were `{app: agent-sandbox-mcp}`. Effect had it shipped: the server reaches the apiserver fine, so `create_sandbox`, `delete_sandbox` and `get_sandbox_status` work — but every call that talks to a seat's runtime sidecar at `<podIP>:8888` (`execute_command`, `upload_file`, `download_file`, `list_files`, `file_exists`) is denied and times out. That is exactly the end-to-end exec this ticket exists to prove, and it would have read as an MCP/SDK bug rather than a label typo. Fixed in this module, not in the seat template: `app.kubernetes.io/name` is the ratified contract value and the convention the rest of `infra-core`/`prod` follows, and the alternative would edit a ratified contract to match a module. `app: agent-sandbox-mcp` stays — the Service selects on it and the Deployment's selector is immutable, so this applies in place with no recreate (additive for both). Verify: still 5 objects; pod labels carry both; Service and Deployment selectors unchanged; README "Verify" now asserts the pod label so this cannot regress silently.
HOMELAB-1669: fix(agent-sandbox-mcp): pin sandbox-mcp image digest
Some checks failed
0/0 projects applied successfully.
CI Review / receiver-test (pull_request) Successful in 4s
CI Review / helm-validate (pull_request) Successful in 7s
Lint & Validate / shellcheck (pull_request) Successful in 5s
Lint & Validate / yaml-lint (pull_request) Successful in 10s
Lint & Validate / terraform-validate (pull_request) Has been cancelled
2266a8c27d
Replace the placeholder tag with the digest-pinned reference published by the
live build of PR #523:

  harbor.aaron.reynoza.org/lab-director/sandbox-mcp:v1.0.4@sha256:1ebd5968…

The tag is kept alongside the digest so the reference stays readable and
`crane digest` commands stay re-derivable; the digest is what Kubernetes
resolves, and the `v1.0.4`/`latest` aliases are republished by every later
`live` build of mcp-server-image-build.yaml, so the tag alone is not a pin.

Re-derived, not copied:

  $ crane digest harbor.aaron.reynoza.org/lab-director/sandbox-mcp:v1.0.4
  sha256:1ebd59688fd6da8f6a5dd4e04c38c8e1160fc21f959f55becf7f2d74547842c4

`crane config` confirms the digest is the agent-sandbox MCP server image
(entrypoint uvicorn k8s_agent_sandbox_mcp_server.app:app, USER 65532:65532,
label org.opencontainers.image.version=v1.0.4, built from this repo).

Docs/comment corrections that the pin makes true or false:
- deployment.yaml: the pin comment now states the pin, its origin and the
  re-derivation path instead of describing a placeholder.
- kustomization.yaml: dropped "which is why deployment.yaml carries a
  placeholder tag rather than a digest" — that clause is now false.
- README.md: the Pin table, the pin-style paragraph, Deployment order step 5
  and the "Digest pin" entry under "Left out on purpose" all described the pin
  as the prod wiring's job; they now describe the pin that exists. Added the
  `crane digest` re-derivation to the Pin section and a digest-pin assertion to
  "Verify".

Nothing syncs this module yet, so this change is inert until the ArgoCD
Application lands (prod PR, same ticket). Render check: 5 objects, unchanged.

Verify:
- kubectl kustomize core/manifests/agent-sandbox-mcp -> 5 objects
- rendered image reference is the digest-pinned one (grep -c == 1)
- yamllint -d relaxed core/manifests/agent-sandbox-mcp/ -> exit 0, no new
  warnings (the one remaining line-length warning is pre-existing, in the
  SDK finding comment)
HOMELAB-1669: fix(agent-sandbox-mcp): label pod for the seat NetworkPolicy
All checks were successful
CI Review / receiver-test (pull_request) Successful in 4s
CI Review / helm-validate (pull_request) Successful in 7s
Lint & Validate / shellcheck (pull_request) Successful in 4s
0/0 projects applied successfully.
Lint & Validate / yaml-lint (pull_request) Successful in 12s
Lint & Validate / terraform-validate (pull_request) Successful in 2m45s
f3228e5a07
The seat's NetworkPolicy admits exactly one ingress caller — pods labelled
`app.kubernetes.io/name: agent-sandbox-mcp` in `agent-sandbox-system` — but the
MCP Deployment's pod template carried only `app: agent-sandbox-mcp`.

Evidence (all three read, not assumed):

  * contract §5, "ingress": `from namespaceSelector agent-sandbox-system +
    podSelector app.kubernetes.io/name: agent-sandbox-mcp, port 8888/TCP only`,
    with "everything else denied".
  * prod `manifests/agent-sandbox/seat-template.yaml` enforces exactly that
    (`networkPolicyManagement: Managed` plus the custom `spec.networkPolicy`),
    so the selector is live, not documentation.
  * this module rendered `pod labels = {app: agent-sandbox-mcp}` only.

Consequence if left as-is: the server still reaches the apiserver, so
`create_sandbox` / `delete_sandbox` / `get_sandbox_status` work, but every call
that talks to a seat's runtime sidecar at `<podIP>:8888` — `execute_command`,
`upload_file`, `download_file`, `list_files`, `file_exists` — is denied and
times out. That is precisely the end-to-end exec HOMELAB-1669 exists to prove,
so the failure would have looked like an MCP/SDK bug in LD1.2 rather than a
label typo.

Fix in this module rather than in the seat template: `app.kubernetes.io/name`
is the ratified contract value, it is the convention every other module in this
repo follows, and the alternative (loosening the prod selector to `app`) would
edit a ratified contract to match a module.

`app: agent-sandbox-mcp` is kept: the Service selects on it and the Deployment's
selector is immutable, so the change applies in place with no recreate. Adding
the label is additive for both.

Verify:
- kubectl kustomize core/manifests/agent-sandbox-mcp -> still 5 objects
- pod labels now carry both; Service selector and Deployment selector unchanged
- README "Verify" gained the assertion that keeps this from regressing
aaron changed title from HOMELAB-1669: fix(agent-sandbox-mcp): pin sandbox-mcp image digest to HOMELAB-1669: fix(agent-sandbox-mcp): pin sandbox-mcp image digest + align pod label with contract §5 2026-09-30 04:15:30 +00:00
aaron merged commit a82c8282b6 into live 2026-09-30 04:19:01 +00:00
Sign in to join this conversation.
No reviewers
No labels
operator-review
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Homelab/infra-core!524
No description provided.