diff --git a/deploy/mint/.env.example b/deploy/mint/.env.example index b805e5f..d601fec 100644 --- a/deploy/mint/.env.example +++ b/deploy/mint/.env.example @@ -19,3 +19,8 @@ JARVIS_APP_PORT=8011 # has run in warn for 7 days without the watchdog complaining; require makes unsigned or invalid a failure and never reports # success without a trust root. docs/SIGNING_RUNBOOK.md. # JARVIS_SIGNATURES=warn + +# MCP write tools (emr_remember / emr_upsert): draft-only, need user_requested=true, ledger key only (the recall key is refused). OFF unless this is exactly true. +# After changing it: cd deploy/mint && docker compose up -d --force-recreate --no-deps app +# JARVIS_MCP_WRITE_ENABLED=false + diff --git a/deploy/mint/docker-compose.yml b/deploy/mint/docker-compose.yml index bc9f683..889137d 100644 --- a/deploy/mint/docker-compose.yml +++ b/deploy/mint/docker-compose.yml @@ -85,9 +85,10 @@ services: JARVIS_HOST: 0.0.0.0 JARVIS_DATABASE_SCHEMA: jarvis JARVIS_PG_STORE: rows - # Private host: agents write through the REST API. MCP write tools stay off until you decide otherwise. + # Private host: agents write through the REST API. MCP write tools (emr_remember / emr_upsert: draft-only, user_requested, ledger key only; the recall key is refused) + # stay off until you set JARVIS_MCP_WRITE_ENABLED=true in deploy/mint/.env and recreate the app. The default is OFF, so a missing or empty value never opens writes. JARVIS_MEMORY_WRITE_ENABLED: "true" - JARVIS_MCP_WRITE_ENABLED: "false" + JARVIS_MCP_WRITE_ENABLED: ${JARVIS_MCP_WRITE_ENABLED:-false} JARVIS_CORS_ORIGINS: "http://127.0.0.1:${JARVIS_APP_PORT:-8011},http://localhost:${JARVIS_APP_PORT:-8011}" # Everything the app writes outside Postgres goes to the appdata volume (the image root is read-only). # The PUBLIC root keys the service verifies signatures against (read-only; empty until the key ceremony). No private key is ever diff --git a/tests/test_deploy_keys.py b/tests/test_deploy_keys.py index c299ece..b4c0870 100644 --- a/tests/test_deploy_keys.py +++ b/tests/test_deploy_keys.py @@ -221,3 +221,12 @@ def test_status_reports_the_app_copy(box): assert "app pepper copy: absent" in box.run("status").stdout (box.secrets / "key-pepper.app").write_text("x\n") assert "app pepper copy: present, identical" in box.run("status").stdout # the fake docker answers `same` + + +def test_the_mcp_write_flag_comes_from_the_env_file_and_defaults_to_off(): + """The compose file used to hard-code JARVIS_MCP_WRITE_ENABLED to "false" (compose environment beats secrets/app.env), so it could not be turned on without editing a tracked file on the box. + It is now ${JARVIS_MCP_WRITE_ENABLED:-false}: set in deploy/mint/.env, and an unset or empty value is OFF.""" + compose = (MINT / "docker-compose.yml").read_text() + lines = [l.strip() for l in compose.splitlines() if l.strip().startswith("JARVIS_MCP_WRITE_ENABLED")] + assert lines == ["JARVIS_MCP_WRITE_ENABLED: ${JARVIS_MCP_WRITE_ENABLED:-false}"] + assert "JARVIS_MCP_WRITE_ENABLED=false" in (MINT / ".env.example").read_text()