From f0cb75ef360b4bb01e15bcbf984d2a48f44b54ed Mon Sep 17 00:00:00 2001 From: shrkz1 Date: Wed, 22 Apr 2026 15:56:29 +0200 Subject: [PATCH 1/5] Add MCP server to simple install compose --- docker-compose.simple-install.enterprise.yml | 4 +-- docker-compose.simple-install.yml | 37 ++++++++++++++++++-- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/docker-compose.simple-install.enterprise.yml b/docker-compose.simple-install.enterprise.yml index cdb0db2..882e44c 100644 --- a/docker-compose.simple-install.enterprise.yml +++ b/docker-compose.simple-install.enterprise.yml @@ -1,5 +1,5 @@ services: eramba: - image: ghcr.io/eramba/eramba-enterprise:3.x + image: ghcr.io/eramba/eramba-enterprise:martin-plan-setup-upgrades cron: - image: ghcr.io/eramba/eramba-enterprise:3.x + image: ghcr.io/eramba/eramba-enterprise:martin-plan-setup-upgrades diff --git a/docker-compose.simple-install.yml b/docker-compose.simple-install.yml index b54f002..50acfc6 100644 --- a/docker-compose.simple-install.yml +++ b/docker-compose.simple-install.yml @@ -24,7 +24,7 @@ services: - app_internal eramba: container_name: eramba - image: ghcr.io/eramba/eramba:3.x + image: ghcr.io/eramba/eramba:martin-plan-setup-upgrades restart: always ports: - 8443:443 @@ -65,7 +65,7 @@ services: - triggers_net cron: container_name: cron - image: ghcr.io/eramba/eramba:3.x + image: ghcr.io/eramba/eramba:martin-plan-setup-upgrades command: ["cron", "-f"] entrypoint: ["/docker-cron-entrypoint.sh"] restart: always @@ -102,7 +102,7 @@ services: - app_internal - triggers_net triggers_caddy: - image: ghcr.io/eramba/eramba-triggers:3.x + image: ghcr.io/eramba/eramba-triggers:martin-plan-setup-upgrades container_name: triggers_caddy entrypoint: - /app/iptables-entrypoint.sh @@ -124,6 +124,37 @@ services: timeout: 5s retries: 3 start_period: 10s + mcp_server: + image: ghcr.io/eramba/eramba-mcp-server:martin-plan-setup-upgrades + container_name: mcp_server + restart: always + ports: + - 13000:3000 + depends_on: + - eramba + environment: + MCP_TRANSPORT: http + PORT: 3000 + PUBLIC_ADDRESS: ${PUBLIC_ADDRESS} + MCP_PUBLIC_URL: ${MCP_PUBLIC_URL:-http://localhost:13000} + MCP_RESOURCE: ${MCP_RESOURCE:-http://localhost:13000/mcp} + ERAMBA_BASE_URL: https://eramba + ERAMBA_OAUTH_ISSUER: ${OAUTH2_ISSUER:-${PUBLIC_ADDRESS}} + ERAMBA_OAUTH_INTROSPECTION_URL: ${ERAMBA_OAUTH_INTROSPECTION_URL:-https://eramba/oauth2/introspect} + ERAMBA_OAUTH_INTROSPECTION_CLIENT_ID: ${OAUTH2_INTROSPECTION_CLIENT_ID:-} + ERAMBA_OAUTH_INTROSPECTION_CLIENT_SECRET: ${OAUTH2_INTROSPECTION_CLIENT_SECRET:-} + MCP_REQUIRED_SCOPE: ${OAUTH2_SCOPE:-eramba.full_access} + ERAMBA_INSECURE_TLS: 1 + ERAMBA_REQUEST_TIMEOUT_MS: 15000 + networks: + - app_internal + - host_access + healthcheck: + test: ["CMD-SHELL", "node -e \"fetch('http://127.0.0.1:3000/openapi.json').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))\""] + interval: 30s + timeout: 5s + retries: 3 + start_period: 10s volumes: app: data: From f577cb5ae8140d3f3757ab8e5666b48bef1d0c44 Mon Sep 17 00:00:00 2001 From: shrkz1 Date: Wed, 22 Apr 2026 16:05:10 +0200 Subject: [PATCH 2/5] Add public proxy for MCP simple install --- Caddyfile | 16 ++++++++++++++++ docker-compose.simple-install.yml | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 Caddyfile diff --git a/Caddyfile b/Caddyfile new file mode 100644 index 0000000..3066d9f --- /dev/null +++ b/Caddyfile @@ -0,0 +1,16 @@ +:80 { + # Keep Inspector local-only. Proxying the UI and its local bridge through the + # same public origin as Eramba/MCP makes OAuth and app rendering brittle. + @mcp path /mcp /openapi /openapi.json /.well-known/oauth-protected-resource /.well-known/oauth-protected-resource/mcp /.well-known/oauth-authorization-server /.well-known/openid-configuration + handle @mcp { + reverse_proxy {$MCP_UPSTREAM:mcp_server:3000} + } + + handle { + reverse_proxy {$ERAMBA_UPSTREAM:https://eramba:443} { + transport http { + tls_insecure_skip_verify + } + } + } +} diff --git a/docker-compose.simple-install.yml b/docker-compose.simple-install.yml index 50acfc6..5f8f4fe 100644 --- a/docker-compose.simple-install.yml +++ b/docker-compose.simple-install.yml @@ -155,6 +155,22 @@ services: timeout: 5s retries: 3 start_period: 10s + public_proxy: + container_name: public_proxy + image: caddy:2.8-alpine + ports: + - 8088:80 + volumes: + - ./Caddyfile:/etc/caddy/Caddyfile:ro + environment: + MCP_UPSTREAM: mcp_server:3000 + ERAMBA_UPSTREAM: https://eramba:443 + depends_on: + - eramba + - mcp_server + networks: + - app_internal + - host_access volumes: app: data: From 228a0b69301077a14b4ea8e8355d3337e0bd7b1e Mon Sep 17 00:00:00 2001 From: shrkz1 Date: Wed, 22 Apr 2026 16:10:58 +0200 Subject: [PATCH 3/5] Enable OAuth for MCP simple install --- docker-compose.simple-install.yml | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/docker-compose.simple-install.yml b/docker-compose.simple-install.yml index 5f8f4fe..ffd7d52 100644 --- a/docker-compose.simple-install.yml +++ b/docker-compose.simple-install.yml @@ -55,6 +55,15 @@ services: TRIGGER_RUNNER_SHARED_SECRET: ${TRIGGER_RUNNER_SHARED_SECRET} DOCKER_DEPLOYMENT: ${DOCKER_DEPLOYMENT} LDAPTLS_REQCERT: ${LDAPTLS_REQCERT} + OAUTH2_ENABLED: ${OAUTH2_ENABLED:-1} + OAUTH2_ISSUER: ${OAUTH2_ISSUER:-${PUBLIC_ADDRESS}} + OAUTH2_RESOURCE: ${OAUTH2_RESOURCE:-${PUBLIC_ADDRESS}/mcp} + OAUTH2_SCOPE: ${OAUTH2_SCOPE:-eramba.full_access} + OAUTH2_AUTH_CODE_TTL: ${OAUTH2_AUTH_CODE_TTL:-120} + OAUTH2_ACCESS_TOKEN_TTL: ${OAUTH2_ACCESS_TOKEN_TTL:-900} + OAUTH2_REFRESH_TOKEN_TTL: ${OAUTH2_REFRESH_TOKEN_TTL:-2592000} + OAUTH2_INTROSPECTION_CLIENT_ID: ${OAUTH2_INTROSPECTION_CLIENT_ID:-eramba-mcp-introspect} + OAUTH2_INTROSPECTION_CLIENT_SECRET: ${OAUTH2_INTROSPECTION_CLIENT_SECRET:-Replace-this-with-a-secret} links: - mysql - redis @@ -92,6 +101,15 @@ services: TRIGGER_RUNNER_SHARED_SECRET: ${TRIGGER_RUNNER_SHARED_SECRET} DOCKER_DEPLOYMENT: ${DOCKER_DEPLOYMENT} LDAPTLS_REQCERT: ${LDAPTLS_REQCERT} + OAUTH2_ENABLED: ${OAUTH2_ENABLED:-1} + OAUTH2_ISSUER: ${OAUTH2_ISSUER:-${PUBLIC_ADDRESS}} + OAUTH2_RESOURCE: ${OAUTH2_RESOURCE:-${PUBLIC_ADDRESS}/mcp} + OAUTH2_SCOPE: ${OAUTH2_SCOPE:-eramba.full_access} + OAUTH2_AUTH_CODE_TTL: ${OAUTH2_AUTH_CODE_TTL:-120} + OAUTH2_ACCESS_TOKEN_TTL: ${OAUTH2_ACCESS_TOKEN_TTL:-900} + OAUTH2_REFRESH_TOKEN_TTL: ${OAUTH2_REFRESH_TOKEN_TTL:-2592000} + OAUTH2_INTROSPECTION_CLIENT_ID: ${OAUTH2_INTROSPECTION_CLIENT_ID:-eramba-mcp-introspect} + OAUTH2_INTROSPECTION_CLIENT_SECRET: ${OAUTH2_INTROSPECTION_CLIENT_SECRET:-Replace-this-with-a-secret} links: - mysql - redis @@ -141,8 +159,8 @@ services: ERAMBA_BASE_URL: https://eramba ERAMBA_OAUTH_ISSUER: ${OAUTH2_ISSUER:-${PUBLIC_ADDRESS}} ERAMBA_OAUTH_INTROSPECTION_URL: ${ERAMBA_OAUTH_INTROSPECTION_URL:-https://eramba/oauth2/introspect} - ERAMBA_OAUTH_INTROSPECTION_CLIENT_ID: ${OAUTH2_INTROSPECTION_CLIENT_ID:-} - ERAMBA_OAUTH_INTROSPECTION_CLIENT_SECRET: ${OAUTH2_INTROSPECTION_CLIENT_SECRET:-} + ERAMBA_OAUTH_INTROSPECTION_CLIENT_ID: ${OAUTH2_INTROSPECTION_CLIENT_ID:-eramba-mcp-introspect} + ERAMBA_OAUTH_INTROSPECTION_CLIENT_SECRET: ${OAUTH2_INTROSPECTION_CLIENT_SECRET:-Replace-this-with-a-secret} MCP_REQUIRED_SCOPE: ${OAUTH2_SCOPE:-eramba.full_access} ERAMBA_INSECURE_TLS: 1 ERAMBA_REQUEST_TIMEOUT_MS: 15000 From bfb5ea91c52657e8d666caac99edb5a6fa9e89ca Mon Sep 17 00:00:00 2001 From: shrkz1 Date: Tue, 4 Aug 2026 11:54:18 +0200 Subject: [PATCH 4/5] fix: make MCP simple install production-ready --- .env | 3 +++ .github/workflows/Docker.yml | 30 +++++++++++++++++++++- Caddyfile | 4 ++- README.md | 4 +++ docker-compose.simple-install.yml | 34 ++++++++++--------------- tests/mcp-simple-install.bats | 42 +++++++++++++++++++++++++++++++ 6 files changed, 94 insertions(+), 23 deletions(-) create mode 100644 tests/mcp-simple-install.bats diff --git a/.env b/.env index 618af9f..d90c578 100644 --- a/.env +++ b/.env @@ -11,6 +11,9 @@ USE_PROXY_AUTH=0 PROXY_AUTH_USER= PROXY_AUTH_PASS= PUBLIC_ADDRESS=https://localhost:8443 +ERAMBA_MCP_IMAGE_TAG=3.x +OAUTH2_INTROSPECTION_CLIENT_ID=eramba-mcp-introspect +OAUTH2_INTROSPECTION_CLIENT_SECRET=Replace-this-with-a-unique-secret DOCKER_DEPLOYMENT=1 LDAPTLS_REQCERT=never TRIGGER_RUNNER_SHARED_SECRET=c86b1a9edd5fdad7f85c95775f42246d761c5486b9059b7db23efc69410b9eaf diff --git a/.github/workflows/Docker.yml b/.github/workflows/Docker.yml index 7999b77..34f1266 100644 --- a/.github/workflows/Docker.yml +++ b/.github/workflows/Docker.yml @@ -19,6 +19,9 @@ jobs: steps: - name: Check out the repo uses: actions/checkout@v3 + + - name: Check MCP simple-install contract + run: npx --yes bats@1.12.0 tests/mcp-simple-install.bats # # - name: Log in to GitHub Container Registry # uses: docker/login-action@v2 @@ -32,7 +35,7 @@ jobs: docker compose -f docker-compose.simple-install.yml down 2>&1 docker system prune --force --volumes --all - docker compose -f docker-compose.simple-install.yml up -d + ERAMBA_MCP_DEV_BEARER_TOKEN=ci-mcp-smoke-token docker compose -f docker-compose.simple-install.yml up -d - name: Wait for apache to start timeout-minutes: 5 @@ -46,6 +49,31 @@ jobs: exit 1 fi + - name: MCP protocol check + timeout-minutes: 5 + run: | + until curl --fail --silent --insecure https://localhost:8443/openapi.json >/dev/null; do + printf 'Waiting for MCP...\n' + sleep 2 + done + + curl --fail --silent --insecure https://localhost:8443/.well-known/oauth-protected-resource/mcp \ + | jq -e '.resource == "https://localhost:8443/mcp"' + + curl --fail --silent --insecure https://localhost:8443/mcp \ + -H 'Authorization: Bearer ci-mcp-smoke-token' \ + -H 'Content-Type: application/json' \ + -H 'Accept: application/json, text/event-stream' \ + --data '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"docker-ci","version":"1.0"}}}' \ + | jq -e '.result.protocolVersion == "2025-03-26"' + + curl --fail --silent --insecure https://localhost:8443/mcp \ + -H 'Authorization: Bearer ci-mcp-smoke-token' \ + -H 'Content-Type: application/json' \ + -H 'Accept: application/json, text/event-stream' \ + --data '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}' \ + | jq -e '.result.tools | length > 0' + - name: CMD Check run: | if docker exec -w /var/www/eramba/app/upgrade -u www-data eramba bin/cake current_config validate; then diff --git a/Caddyfile b/Caddyfile index 3066d9f..ada4b46 100644 --- a/Caddyfile +++ b/Caddyfile @@ -1,4 +1,6 @@ -:80 { +:443 { + tls /certs/mycert.crt /certs/mycert.key + # Keep Inspector local-only. Proxying the UI and its local bridge through the # same public origin as Eramba/MCP makes OAuth and app rendering brittle. @mcp path /mcp /openapi /openapi.json /.well-known/oauth-protected-resource /.well-known/oauth-protected-resource/mcp /.well-known/oauth-authorization-server /.well-known/openid-configuration diff --git a/README.md b/README.md index 72581bb..4989c14 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,7 @@ Welcome to eramba's official Github account, for Docker installs please review our website Learning Platform ([eramba.org](https://www.eramba.org/learning/courses/12/episodes/274)) under Docker Install. The bundled files in `apache/ssl/` are a branded local development certificate intended only for local or simple demo installs. It is signed by a local development CA and will only be trusted on machines where that CA has been installed. Replace it with your own CA-issued certificate and private key for any real deployment. + +Eramba and its MCP endpoint share the `PUBLIC_ADDRESS` origin. With the default configuration the application is available at `https://localhost:8443` and MCP at `https://localhost:8443/mcp`; issuer, resource, metadata, and OpenAPI URLs are derived automatically. Do not add separate public MCP URL variables. + +Before starting a real deployment, replace `OAUTH2_INTROSPECTION_CLIENT_SECRET` in `.env` with a unique random secret. `ERAMBA_MCP_IMAGE_TAG` defaults to the supported `3.x` MCP image stream and can be pinned when required. diff --git a/docker-compose.simple-install.yml b/docker-compose.simple-install.yml index 8ddf82a..bb9eec3 100644 --- a/docker-compose.simple-install.yml +++ b/docker-compose.simple-install.yml @@ -26,8 +26,6 @@ services: container_name: eramba image: ghcr.io/eramba/eramba:latest restart: always - ports: - - 8443:443 volumes: - data:/var/www/eramba/app/upgrade/data - app:/var/www/eramba @@ -56,14 +54,12 @@ services: DOCKER_DEPLOYMENT: ${DOCKER_DEPLOYMENT} LDAPTLS_REQCERT: ${LDAPTLS_REQCERT} OAUTH2_ENABLED: ${OAUTH2_ENABLED:-1} - OAUTH2_ISSUER: ${OAUTH2_ISSUER:-${PUBLIC_ADDRESS}} - OAUTH2_RESOURCE: ${OAUTH2_RESOURCE:-${PUBLIC_ADDRESS}/mcp} OAUTH2_SCOPE: ${OAUTH2_SCOPE:-eramba.full_access} OAUTH2_AUTH_CODE_TTL: ${OAUTH2_AUTH_CODE_TTL:-120} OAUTH2_ACCESS_TOKEN_TTL: ${OAUTH2_ACCESS_TOKEN_TTL:-900} OAUTH2_REFRESH_TOKEN_TTL: ${OAUTH2_REFRESH_TOKEN_TTL:-2592000} - OAUTH2_INTROSPECTION_CLIENT_ID: ${OAUTH2_INTROSPECTION_CLIENT_ID:-eramba-mcp-introspect} - OAUTH2_INTROSPECTION_CLIENT_SECRET: ${OAUTH2_INTROSPECTION_CLIENT_SECRET:-Replace-this-with-a-secret} + OAUTH2_INTROSPECTION_CLIENT_ID: ${OAUTH2_INTROSPECTION_CLIENT_ID:?Set OAUTH2_INTROSPECTION_CLIENT_ID in .env} + OAUTH2_INTROSPECTION_CLIENT_SECRET: ${OAUTH2_INTROSPECTION_CLIENT_SECRET:?Set OAUTH2_INTROSPECTION_CLIENT_SECRET in .env} links: - mysql - redis @@ -102,14 +98,12 @@ services: DOCKER_DEPLOYMENT: ${DOCKER_DEPLOYMENT} LDAPTLS_REQCERT: ${LDAPTLS_REQCERT} OAUTH2_ENABLED: ${OAUTH2_ENABLED:-1} - OAUTH2_ISSUER: ${OAUTH2_ISSUER:-${PUBLIC_ADDRESS}} - OAUTH2_RESOURCE: ${OAUTH2_RESOURCE:-${PUBLIC_ADDRESS}/mcp} OAUTH2_SCOPE: ${OAUTH2_SCOPE:-eramba.full_access} OAUTH2_AUTH_CODE_TTL: ${OAUTH2_AUTH_CODE_TTL:-120} OAUTH2_ACCESS_TOKEN_TTL: ${OAUTH2_ACCESS_TOKEN_TTL:-900} OAUTH2_REFRESH_TOKEN_TTL: ${OAUTH2_REFRESH_TOKEN_TTL:-2592000} - OAUTH2_INTROSPECTION_CLIENT_ID: ${OAUTH2_INTROSPECTION_CLIENT_ID:-eramba-mcp-introspect} - OAUTH2_INTROSPECTION_CLIENT_SECRET: ${OAUTH2_INTROSPECTION_CLIENT_SECRET:-Replace-this-with-a-secret} + OAUTH2_INTROSPECTION_CLIENT_ID: ${OAUTH2_INTROSPECTION_CLIENT_ID:?Set OAUTH2_INTROSPECTION_CLIENT_ID in .env} + OAUTH2_INTROSPECTION_CLIENT_SECRET: ${OAUTH2_INTROSPECTION_CLIENT_SECRET:?Set OAUTH2_INTROSPECTION_CLIENT_SECRET in .env} links: - mysql - redis @@ -143,25 +137,21 @@ services: retries: 3 start_period: 10s mcp_server: - image: ghcr.io/eramba/eramba-mcp-server:martin-plan-setup-upgrades + image: ghcr.io/eramba/eramba-mcp-server:${ERAMBA_MCP_IMAGE_TAG:-3.x} container_name: mcp_server restart: always - ports: - - 13000:3000 depends_on: - eramba environment: MCP_TRANSPORT: http PORT: 3000 PUBLIC_ADDRESS: ${PUBLIC_ADDRESS} - MCP_PUBLIC_URL: ${MCP_PUBLIC_URL:-http://localhost:13000} - MCP_RESOURCE: ${MCP_RESOURCE:-http://localhost:13000/mcp} - ERAMBA_BASE_URL: https://eramba - ERAMBA_OAUTH_ISSUER: ${OAUTH2_ISSUER:-${PUBLIC_ADDRESS}} - ERAMBA_OAUTH_INTROSPECTION_URL: ${ERAMBA_OAUTH_INTROSPECTION_URL:-https://eramba/oauth2/introspect} - ERAMBA_OAUTH_INTROSPECTION_CLIENT_ID: ${OAUTH2_INTROSPECTION_CLIENT_ID:-eramba-mcp-introspect} - ERAMBA_OAUTH_INTROSPECTION_CLIENT_SECRET: ${OAUTH2_INTROSPECTION_CLIENT_SECRET:-Replace-this-with-a-secret} + ERAMBA_BASE_URL: https://eramba:443 + ERAMBA_OAUTH_INTROSPECTION_URL: https://eramba:443/oauth2/introspect + ERAMBA_OAUTH_INTROSPECTION_CLIENT_ID: ${OAUTH2_INTROSPECTION_CLIENT_ID:?Set OAUTH2_INTROSPECTION_CLIENT_ID in .env} + ERAMBA_OAUTH_INTROSPECTION_CLIENT_SECRET: ${OAUTH2_INTROSPECTION_CLIENT_SECRET:?Set OAUTH2_INTROSPECTION_CLIENT_SECRET in .env} MCP_REQUIRED_SCOPE: ${OAUTH2_SCOPE:-eramba.full_access} + ERAMBA_MCP_DEV_BEARER_TOKEN: ${ERAMBA_MCP_DEV_BEARER_TOKEN:-} ERAMBA_INSECURE_TLS: 1 ERAMBA_REQUEST_TIMEOUT_MS: 15000 networks: @@ -177,9 +167,11 @@ services: container_name: public_proxy image: caddy:2.8-alpine ports: - - 8088:80 + - 8443:443 volumes: - ./Caddyfile:/etc/caddy/Caddyfile:ro + - ./apache/ssl/mycert.crt:/certs/mycert.crt:ro + - ./apache/ssl/mycert.key:/certs/mycert.key:ro environment: MCP_UPSTREAM: mcp_server:3000 ERAMBA_UPSTREAM: https://eramba:443 diff --git a/tests/mcp-simple-install.bats b/tests/mcp-simple-install.bats new file mode 100644 index 0000000..0bc49cf --- /dev/null +++ b/tests/mcp-simple-install.bats @@ -0,0 +1,42 @@ +#!/usr/bin/env bats + +setup() { + REPOSITORY_ROOT="$(cd "${BATS_TEST_DIRNAME}/.." && pwd)" + + run env -i PATH="$PATH" HOME="$HOME" docker compose \ + --project-directory "$REPOSITORY_ROOT" \ + --env-file "$REPOSITORY_ROOT/.env" \ + -f "$REPOSITORY_ROOT/docker-compose.simple-install.yml" \ + config --format json + + [ "$status" -eq 0 ] + COMPOSE_CONFIG="$output" +} + +@test "simple install keeps release app images and uses the MCP 3.x image" { + [ "$(jq -r '.services.eramba.image' <<<"$COMPOSE_CONFIG")" = "ghcr.io/eramba/eramba:latest" ] + [ "$(jq -r '.services.cron.image' <<<"$COMPOSE_CONFIG")" = "ghcr.io/eramba/eramba:latest" ] + [ "$(jq -r '.services.triggers_caddy.image' <<<"$COMPOSE_CONFIG")" = "ghcr.io/eramba/eramba-triggers:latest" ] + [ "$(jq -r '.services.mcp_server.image' <<<"$COMPOSE_CONFIG")" = "ghcr.io/eramba/eramba-mcp-server:3.x" ] +} + +@test "Caddy is the only published application edge" { + [ "$(jq -r '(.services.eramba.ports // []) | length' <<<"$COMPOSE_CONFIG")" -eq 0 ] + [ "$(jq -r '(.services.mcp_server.ports // []) | length' <<<"$COMPOSE_CONFIG")" -eq 0 ] + [ "$(jq -r '.services.public_proxy.ports | length' <<<"$COMPOSE_CONFIG")" -eq 1 ] + [ "$(jq -r '.services.public_proxy.ports[0] | "\(.published):\(.target)"' <<<"$COMPOSE_CONFIG")" = "8443:443" ] +} + +@test "MCP derives public metadata from PUBLIC_ADDRESS and introspects internally" { + [ "$(jq -r '.services.mcp_server.environment.PUBLIC_ADDRESS' <<<"$COMPOSE_CONFIG")" = "https://localhost:8443" ] + [ "$(jq -r '.services.mcp_server.environment.ERAMBA_OAUTH_INTROSPECTION_URL' <<<"$COMPOSE_CONFIG")" = "https://eramba:443/oauth2/introspect" ] + + for override in MCP_PUBLIC_URL MCP_RESOURCE ERAMBA_OAUTH_ISSUER OAUTH2_ISSUER OAUTH2_RESOURCE; do + [ "$(jq -r --arg name "$override" '.services.mcp_server.environment | has($name)' <<<"$COMPOSE_CONFIG")" = "false" ] + done +} + +@test "Caddy receives the bundled TLS certificate and key" { + [ "$(jq -r '[.services.public_proxy.volumes[].target] | index("/certs/mycert.crt") != null' <<<"$COMPOSE_CONFIG")" = "true" ] + [ "$(jq -r '[.services.public_proxy.volumes[].target] | index("/certs/mycert.key") != null' <<<"$COMPOSE_CONFIG")" = "true" ] +} From ff98f40f72abec617e12cc845a04257ba8efe308 Mon Sep 17 00:00:00 2001 From: shrkz1 Date: Tue, 4 Aug 2026 12:03:50 +0200 Subject: [PATCH 5/5] ci: authenticate private MCP image pulls --- .github/workflows/Docker.yml | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/.github/workflows/Docker.yml b/.github/workflows/Docker.yml index 34f1266..d2af0bb 100644 --- a/.github/workflows/Docker.yml +++ b/.github/workflows/Docker.yml @@ -5,6 +5,10 @@ on: branches: - '*' +permissions: + contents: read + packages: read + jobs: simple_install: name: Simple Installation [${{ matrix.build-type }}] @@ -22,14 +26,13 @@ jobs: - name: Check MCP simple-install contract run: npx --yes bats@1.12.0 tests/mcp-simple-install.bats - # - # - name: Log in to GitHub Container Registry - # uses: docker/login-action@v2 - # with: - # registry: ghcr.io - # username: ${{ github.actor }} - # password: ${{ secrets.TOKEN_INCREASED_PERMISSIONS }} + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} - name: Run Simple Install run: | docker compose -f docker-compose.simple-install.yml down 2>&1