fix(stage-1a): refuse to serve when MCP requirements cannot be read

entrypoint.sh discarded the exit status of the python overlay builder, so
an unparseable /etc/agency/mcp-requirements.json started the server with
MCP servers that should have been disabled, contradicting the stage-1a
overlay requirement. The entrypoint now exits 64 naming the file.

Evidence: docs/evidence/1a/entrypoint-mcp-requirements-failclosed.log (a
container started with a malformed requirements file exits 64, is not
running, and its log names the file). The image was rebuilt and checks
02/03/04 pass against it.
This commit is contained in:
John Smith committed 2026-10-13 14:39:59 -04:00
1 parent 382aa7e1de
commit 3ccfd645b0
2 files changed
+26 -3

No files matched your search

@@ -0,0 +1,16 @@
Entrypoint fail-closed on an unparseable /etc/agency/mcp-requirements.json.
Sabotage/premise: the mounted requirements file is invalid JSON; before this
fix the python parse failure was silently swallowed and the server started
with servers that should have been disabled. Command and output:
$ printf '{ "mcpServers": { broken\n' > /tmp/opencode/badreq/mcp-requirements.json
$ docker run -d --name agency-spike-badreq -e OPENCODE_PASSWORD=<dummy> \
-e OPENCODE_API_KEY=<dummy> -v /tmp/opencode/badreq:/etc/agency:ro,z agency-base:2.0.26
$ docker inspect -f '{{.State.ExitCode}}/{{.State.Running}}' agency-spike-badreq
64/false
$ docker logs agency-spike-badreq
^^^^^^^^^^^^^^^^^^^^^^
json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes: line 1 column 19 (char 18)
entrypoint: refusing to start: cannot read MCP requirements from /etc/agency/mcp-requirements.json
Expected: exit code 64, not running, log names mcp-requirements.json.
+10 -3
View File
@@ -5,6 +5,8 @@
# 3. Disable MCP servers whose required variables are unset, via an
# OPENCODE_CONFIG_CONTENT overlay that carries each disabled server's
# complete config (a later config document replaces a server entry whole).
# A malformed requirements file refuses to start instead of serving
# with servers that should have been disabled.
# 4. Apply the fallbacks recorded under "Fallbacks in force" (none yet).
# 5. Serve OpenCode.
set -u
@@ -29,10 +31,12 @@ export OPENCODE_CONFIG_DIR
# MCP overlay: /etc/agency/mcp-requirements.json maps each server to its
# required variables plus its complete config. Servers with unmet
# requirements are republished here with "disabled": true.
# requirements are republished here with "disabled": true. A malformed
# requirements file is a configuration error: refuse to start rather than
# serve with servers that should have been disabled.
req_file="/etc/agency/mcp-requirements.json"
if [ -f "$req_file" ]; then
overlay=$(python3 - "$req_file" <<'PY'
if ! overlay=$(python3 - "$req_file" <<'PY'
import json, os, sys
with open(sys.argv[1]) as fh:
req = json.load(fh)
@@ -47,7 +51,10 @@ for name, entry in req.get("mcpServers", {}).items():
if disabled:
print(json.dumps({"mcp": {"servers": disabled}}))
PY
)
); then
echo "entrypoint: refusing to start: cannot read MCP requirements from $req_file" >&2
exit 64
fi
if [ -n "$overlay" ]; then
export OPENCODE_CONFIG_CONTENT="$overlay"
fi