From 0bd15dbf82befd1b062c38bf716818f6c7446cad Mon Sep 17 00:00:00 2001 From: lucarlig Date: Mon, 7 Sep 2026 13:57:32 +0100 Subject: [PATCH 1/4] build: keep testing helpers out of production images Signed-off-by: lucarlig --- .github/workflows/ci.yml | 2 +- .secrets.baseline | 22 ++++-------- Makefile | 33 +++++++++-------- README.md | 22 ++++++++---- _context/wiki/architecture.md | 6 +++- _context/wiki/config.md | 21 ++++++----- _context/wiki/deployment.md | 28 +++++++++++++-- _context/wiki/getting-started.md | 27 +++++++++----- _context/wiki/index.md | 2 +- _context/wiki/security.md | 21 +++++++---- _context/wiki/testing.md | 20 +++++++++-- crates/contextforge-data-plane-lib/Cargo.toml | 1 + crates/contextforge-data-plane/Cargo.toml | 1 + docker/Dockerfile | 4 ++- docker/docker-compose.yml | 35 ++++--------------- 15 files changed, 148 insertions(+), 97 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 923a5697..48acbc67 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -81,7 +81,7 @@ jobs: ref: ${{ github.event.pull_request.head.sha || github.sha }} - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2.9.1 - - name: Build the workspace + - name: Build the workspace for conformance testing (includes with_tools) run: cargo build --locked --workspace --all-features - name: Strip the conformance binary diff --git a/.secrets.baseline b/.secrets.baseline index 2cd6744a..05731c8e 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -3,7 +3,7 @@ "files": "(?x)(Cargo\\.lock$|\\.lock$)|^\\.secrets\\.baseline$|^.secrets.baseline$", "lines": null }, - "generated_at": "2026-09-04T15:25:27Z", + "generated_at": "2026-09-07T12:56:51Z", "plugins_used": [ { "name": "AWSKeyDetector" @@ -382,19 +382,11 @@ } ], "docker/docker-compose.yml": [ - { - "hashed_secret": "2a8bfc0ce436d55ca907d0162989481bcb7677b4", - "is_secret": false, - "is_verified": false, - "line_number": 189, - "type": "Secret Keyword", - "verified_result": null - }, { "hashed_secret": "fdda45b7f6d2ead95d9991fc4678640c3bab0d84", "is_secret": false, "is_verified": false, - "line_number": 363, + "line_number": 342, "type": "Secret Keyword", "verified_result": null }, @@ -402,7 +394,7 @@ "hashed_secret": "093d378410a5cfa4bd5088f3fef62fbdb8a95665", "is_secret": false, "is_verified": false, - "line_number": 369, + "line_number": 348, "type": "Secret Keyword", "verified_result": null }, @@ -410,7 +402,7 @@ "hashed_secret": "c3de40d5e3fc71ed62771c2127a8e42585026c97", "is_secret": false, "is_verified": false, - "line_number": 371, + "line_number": 350, "type": "Secret Keyword", "verified_result": null }, @@ -418,7 +410,7 @@ "hashed_secret": "4d4acd9b084d13f5fdb23807d857e1c48a1cfd0f", "is_secret": false, "is_verified": false, - "line_number": 460, + "line_number": 439, "type": "Secret Keyword", "verified_result": null }, @@ -426,7 +418,7 @@ "hashed_secret": "bd0160c2cf35d950843c88f3be2b9412ed71f485", "is_secret": false, "is_verified": false, - "line_number": 495, + "line_number": 474, "type": "Secret Keyword", "verified_result": null }, @@ -434,7 +426,7 @@ "hashed_secret": "293324f6824bb3a6db5c4dc42a60ddd4a9851c99", "is_secret": false, "is_verified": false, - "line_number": 658, + "line_number": 637, "type": "Hex High Entropy String", "verified_result": null } diff --git a/Makefile b/Makefile index 24a82517..54253405 100644 --- a/Makefile +++ b/Makefile @@ -5,18 +5,19 @@ CF_INTEGRATION ?= cf-integration CF_INTEGRATION_DIR ?= $(CURDIR)/.integration CF_DATAPLANE_REPO ?= $(CURDIR) CF_DATAPLANE_REF ?= $(shell git -C "$(CF_DATAPLANE_REPO)" rev-parse HEAD) +CF_DATAPLANE_IMAGE ?= contextforge-data-plane:conformance CONFORMANCE_BASELINE_DIR := $(CURDIR)/tests/conformance/baselines # IBM detect-secrets hardened fork — pinned to the same commit used in mcp-context-forge. DETECT_SECRETS_SPEC ?= git+https://github.com/ibm/detect-secrets.git@076672a9a01abdfc7ecee2e7d14f08cdccb73976 DETECT_SECRETS_EXCLUDE := '(?x)(Cargo\.lock$$|\.lock$$)|^\.secrets\.baseline$$' -.PHONY: help docker-prod compose-up compose-down conformance conformance-bless docs-serve pre-commit secrets-scan-all configure-git +.PHONY: help docker-prod compose-up compose-down conformance-image conformance conformance-bless docs-serve pre-commit secrets-scan-all configure-git help: ## Show available commands @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-22s\033[0m %s\n", $$1, $$2}' -docker-prod: ## Build production Docker image (contextforge-data-plane:latest) from docker/Dockerfile +docker-prod: ## Build production Docker image with plugins and without testing-only with_tools docker build -t $(IMAGE_NAME) -f docker/Dockerfile . compose-up: ## Launch stack: nginx, control plane, redis, postgres, pgbouncer, dataplane, fast_time_server @@ -29,7 +30,7 @@ compose-up: ## Launch stack: nginx, control plane, redis, postgres, pgbouncer, d compose-down: ## Tear down the stack docker compose -f docker/docker-compose.yml stop $(SERVICES) $(ARGS) -conformance: ## Run strict modern MCP conformance against the committed data-plane HEAD +conformance-image: ## Prepare a testing-only conformance image from the committed data-plane ref @if ! command -v "$(CF_INTEGRATION)" >/dev/null 2>&1; then \ echo "cf-integration not found: install its published binary with cargo binstall or set CF_INTEGRATION to its path."; \ exit 1; \ @@ -38,9 +39,19 @@ conformance: ## Run strict modern MCP conformance against the committed data-pla echo "Tracked data-plane changes are not committed; commit or stash them before conformance."; \ exit 1; \ fi + @if [ -n "$(CF_DATAPLANE_REF)" ]; then \ + git -C "$(CF_DATAPLANE_REPO)" archive "$(CF_DATAPLANE_REF)" | \ + docker build -t "$(CF_DATAPLANE_IMAGE)" -f docker/Dockerfile \ + --label org.opencontainers.image.revision="$$(git -C "$(CF_DATAPLANE_REPO)" rev-parse "$(CF_DATAPLANE_REF)")" \ + --build-arg CARGO_FEATURES=plugins,with_tools -; \ + fi + +conformance: conformance-image ## Run strict modern MCP conformance against the committed data-plane HEAD @CF_INTEGRATION_DIR="$(CF_INTEGRATION_DIR)" \ CF_DATAPLANE_REPO="$(CF_DATAPLANE_REPO)" \ - CF_DATAPLANE_REF="$(CF_DATAPLANE_REF)" \ + CF_DATAPLANE_REF="" \ + CF_DATAPLANE_IMAGE="$(CF_DATAPLANE_IMAGE)" \ + CF_DATAPLANE_PULL_POLICY=never \ "$(CF_INTEGRATION)" conformance run \ --client-era modern \ --server-era modern \ @@ -49,18 +60,12 @@ conformance: ## Run strict modern MCP conformance against the committed data-pla --baseline-dir "$(CONFORMANCE_BASELINE_DIR)" \ --output-dir "$(CF_INTEGRATION_DIR)/reports" -conformance-bless: ## Run strict modern conformance and atomically update its baselines - @if ! command -v "$(CF_INTEGRATION)" >/dev/null 2>&1; then \ - echo "cf-integration not found: install its published binary with cargo binstall or set CF_INTEGRATION to its path."; \ - exit 1; \ - fi - @if [ -n "$$(git -C "$(CF_DATAPLANE_REPO)" status --porcelain --untracked-files=no)" ]; then \ - echo "Tracked data-plane changes are not committed; commit or stash them before conformance."; \ - exit 1; \ - fi +conformance-bless: conformance-image ## Run strict modern conformance and atomically update its baselines @CF_INTEGRATION_DIR="$(CF_INTEGRATION_DIR)" \ CF_DATAPLANE_REPO="$(CF_DATAPLANE_REPO)" \ - CF_DATAPLANE_REF="$(CF_DATAPLANE_REF)" \ + CF_DATAPLANE_REF="" \ + CF_DATAPLANE_IMAGE="$(CF_DATAPLANE_IMAGE)" \ + CF_DATAPLANE_PULL_POLICY=never \ "$(CF_INTEGRATION)" conformance run \ --client-era modern \ --server-era modern \ diff --git a/README.md b/README.md index 8dad5f3d..2f4afbfb 100644 --- a/README.md +++ b/README.md @@ -14,10 +14,16 @@ Build the production image and start the supported control-plane + data-plane test stack: ```bash +export CONTEXTFORGE_DATA_PLANE_JWKS_URL=https://your-issuer.example/.well-known/jwks.json make docker-prod make compose-up ``` +Replace the example JWKS URL with the HTTPS endpoint for the issuer of your +control-plane tokens. The production image includes the plugin factories and +`/contextforge-rs/health`; it does not include `with_tools`. That feature is for +testing only and enables unauthenticated token, JWKS, and config helpers. + The stack uses the current `fast_time_server` backend and exercises config publication through the external ContextForge control plane. See [getting-started.md](_context/wiki/getting-started.md) for the complete smoke @@ -72,29 +78,31 @@ cargo run --release \ --address 0.0.0.0:8001 \ --redis-port 6379 \ --redis-address 127.0.0.1 \ - --token-verification-public-key assets/jwt.key.pub \ - --token-verification-private-key assets/jwt.key \ + --jwks-url "$CONTEXTFORGE_DATA_PLANE_JWKS_URL" \ --number-of-cpus 16 \ --redis-mode=plain-text \ --upstream-connection-mode=plain-text-or-tls \ --runtime-plugins-enabled true ``` +### Testing-Only Bootstrap Helpers + +For local testing, explicitly enable `with_tools` and use its local JWKS +endpoint. Never enable this feature or use `--all-features` in production. ```bash -cargo run --features contextforge-data-plane-lib/with_tools \ +cargo run -p contextforge-data-plane --features with_tools \ -- \ ---address 0.0.0.0:8080 \ +--address 127.0.0.1:8080 \ --redis-address 127.0.0.1 \ --redis-port 6379 \ --redis-mode plain-text \ --token-verification-private-key ./assets/jwt.key \ ---token-verification-public-key ./assets/jwt.key.pub \ +--jwks-url http://127.0.0.1:8080/contextforge-rs/admin/.well-known/jwks.json \ --upstream-connection-mode plain-text-or-tls \ ---tls-address 0.0.0.0:8443 \ +--tls-address 127.0.0.1:8443 \ --server-private-key ./assets/tls_key.pem \ --server-certificate ./assets/tls_certificate.pem ---runtime-plugins-enabled true ``` ## Tracing and Metrics diff --git a/_context/wiki/architecture.md b/_context/wiki/architecture.md index e36a668d..e2cab091 100644 --- a/_context/wiki/architecture.md +++ b/_context/wiki/architecture.md @@ -105,7 +105,11 @@ Order is invariant: auth/config before backend selection; request plugins before | `gateway/session_store/` | Local and Redis user session storage | | `user_config_store/` | `UserConfigStore` trait, Redis-backed store | | `transports/` | Downstream TCP and TLS listener setup | -| `tools.rs` | Local bootstrap helpers (`with_tools` feature only) | +| `tools.rs` | Testing-only token, JWKS, and config helpers (`with_tools` feature) | + +`Gateway::into_router` registers `/contextforge-rs/health` in every build, +outside the MCP authentication and config layers. Health remains covered by the +outer HTTP tracing and metrics layers. ## State Ownership diff --git a/_context/wiki/config.md b/_context/wiki/config.md index 10d57bf2..dade1d68 100644 --- a/_context/wiki/config.md +++ b/_context/wiki/config.md @@ -6,7 +6,7 @@ --redis-address --redis-port --redis-mode ``` -Plus at least: `--address` or `--tls-address`, `--token-verification-public-key` or `--token-verification-secret`. +Plus `--jwks-url` and at least one listener: `--address` or `--tls-address`. ## Complete CLI and Environment Reference @@ -30,9 +30,9 @@ Origin and Host settings retain the explicitly configured | `--tls-address ` | `CONTEXTFORGE_DATA_PLANE_TLS_ADDRESS` | Optional | TLS listener; requires server certificate and key. | | `--server-certificate ` | `CONTEXTFORGE_DATA_PLANE_TLS_SERVER_CERTIFICATE` | With `--tls-address` | PEM certificate chain for downstream TLS. | | `--server-private-key ` | `CONTEXTFORGE_DATA_PLANE_TLS_SERVER_PRIVATE_KEY` | With `--tls-address` | PEM private key for downstream TLS. | -| `--token-verification-public-key ` | `CONTEXTFORGE_DATA_PLANE_TOKEN_VERIFICATION_PUBLIC_KEY` | For RSA tokens | Verifies `RS256`, `RS384`, and `RS512` tokens. | -| `--token-verification-secret ` | `CONTEXTFORGE_DATA_PLANE_TOKEN_SECRET` | For HMAC tokens | Verifies `HS256`, `HS384`, and `HS512` tokens. | -| `--token-verification-private-key ` | `CONTEXTFORGE_DATA_PLANE_TOKEN_VERIFICATION_PRIVATE_KEY` | Required when built with `with_tools` | Signs tokens for the optional local bootstrap helper. | +| `--jwks-url ` | `CONTEXTFORGE_DATA_PLANE_JWKS_URL` | Required | Token issuer's HTTPS JWKS endpoint; HTTP is allowed only on loopback for testing. | +| `--jwks-ca-cert-path ` | `CONTEXTFORGE_DATA_PLANE_JWKS_CA_PATH` | Optional | PEM trust bundle for the JWKS endpoint. | +| `--token-verification-private-key ` | None (CLI only) | Required when built with `with_tools` | Signs tokens for testing-only bootstrap helpers. Never use this feature in production. | ### MCP request validation @@ -250,17 +250,18 @@ docker compose -f docker/docker-compose-local.yaml exec -T redis \ }' ``` -Build and run with demo factories and runtime execution enabled: +For local testing only, build and run with demo factories, testing-only +`with_tools` helpers, and runtime execution enabled: ```bash cargo run -p contextforge-data-plane \ - --features 'contextforge-data-plane-lib/with_tools,test-plugins' \ + --features 'with_tools,test-plugins' \ --bin contextforge-data-plane -- \ --address 127.0.0.1:8001 \ --redis-address 127.0.0.1 \ --redis-port 6379 \ --redis-mode plain-text \ - --token-verification-public-key assets/jwt.key.pub \ + --jwks-url http://127.0.0.1:8001/contextforge-rs/admin/.well-known/jwks.json \ --token-verification-private-key assets/jwt.key \ --upstream-connection-mode plain-text-or-tls \ --runtime-plugins-enabled true @@ -387,13 +388,15 @@ docker compose \ up -d ``` -Run the gateway with export enabled (RUST_TRACE_LOG=debug required for trace export): +Run the gateway with export enabled (RUST_TRACE_LOG=debug required for trace +export). Set `CONTEXTFORGE_DATA_PLANE_JWKS_URL` to your token issuer's HTTPS JWKS +endpoint; this command does not enable testing helpers. ```bash RUST_TRACE_LOG=debug \ cargo run --release --bin contextforge-data-plane -- \ --address 0.0.0.0:8001 \ --redis-port 6379 --redis-address 127.0.0.1 --redis-mode=plain-text \ - --token-verification-public-key assets/jwt.key.pub \ + --jwks-url "$CONTEXTFORGE_DATA_PLANE_JWKS_URL" \ --number-of-cpus 4 \ --upstream-connection-mode=plain-text-or-tls \ --enable-open-telemetry true \ diff --git a/_context/wiki/deployment.md b/_context/wiki/deployment.md index 876b3026..b5b2f630 100644 --- a/_context/wiki/deployment.md +++ b/_context/wiki/deployment.md @@ -12,13 +12,34 @@ 3. Redis reachable; TLS/mTLS across trust zones; write access restricted to the control plane; `DATAPLANE_PUBLISHER=true` on the control plane. 4. Upstream connection mode matches backend URL schemes. 5. One replica per `Mcp-session-id` (single replica or sticky routing). -6. `with_tools` feature **disabled** in the production build. +6. `with_tools` feature **disabled** in the production build; it is for testing only. 7. Telemetry export pointed at the collector. 8. System limits raised: `nofile 65535`, TCP tuning (`tcp_fin_timeout=15`, widened local port range). ## Health Endpoint -**`/contextforge-rs/health` is a `with_tools` bootstrap helper only.** Production builds compile it out. Use TCP-level liveness checks or the exported metrics until a real health endpoint exists. +`GET /contextforge-rs/health` is available in every build, including production +builds without `with_tools`. It returns HTTP `200` with +`{"status": "healthy"}` and does not require authentication. The reference nginx +configuration also exposes it at `/health`. + +Use it for HTTP liveness checks. It reports that the HTTP server is responding; +it does not check Redis, JWKS availability, or backend readiness. + +## Production Builds + +```bash +make docker-prod +# Equivalent native build: +cargo build --locked --release -p contextforge-data-plane --features plugins +``` + +`make docker-prod`, direct builds of `docker/Dockerfile`, and the image publishing +workflow all compile the production plugin factories without `with_tools`. +Do not use `--all-features` for production artifacts: it also enables testing +helpers and demo plugins. Configure `--jwks-url` (or +`CONTEXTFORGE_DATA_PLANE_JWKS_URL`) with the HTTPS JWKS endpoint for the token +issuer; the dataplane does not need a token-signing private key. ## nginx Front-Door Routing @@ -72,7 +93,8 @@ Both default to ~60s. For functional tests, shorten the publisher interval and d | --- | --- | | JWT revocation | None. A leaked token is valid until `exp`. Rotate the key and restart to invalidate. | | CORS / Origin | CORS response headers are permissive. `mcp_origin_layer` validates Origin before authentication, and RMCP validates Host at the MCP service boundary. Configure both `--mcp-allowed-hosts` and `--mcp-allowed-origins` for production. | -| Local bootstrap routes | `/contextforge-rs/admin/tokens/{user}`, `/admin/userconfigs/{user}`, `/health` are **outside auth middleware — unauthenticated by design.** Only exist with `with_tools`. Production builds must not enable `with_tools`. | +| Testing helpers | The token, JWKS, and user-config routes under `/contextforge-rs/admin/` are unauthenticated and exist only with `with_tools`. The feature is for testing only and must never be enabled in production. | +| Health | `/contextforge-rs/health` is unauthenticated and available in every build. It checks HTTP liveness only. | | Redis trust | Whoever can write Redis controls routing (arbitrary backend URLs receive caller traffic) AND which registered plugin hooks execute on payloads. Protect with TLS/mTLS and restrict write access to the control plane. | | Downstream TLS | Optional. Plain HTTP is acceptable only behind a trusted front door on a private network. Identity is always the bearer JWT, not mTLS. | | Plugin code | Fully trusted, in-process. Redis config activates compiled-in factories only — it cannot inject new Rust code. | diff --git a/_context/wiki/getting-started.md b/_context/wiki/getting-started.md index 47983e2f..e748bf33 100644 --- a/_context/wiki/getting-started.md +++ b/_context/wiki/getting-started.md @@ -3,10 +3,16 @@ ## Full Docker Stack ```bash -make docker-prod # build contextforge-data-plane:latest from docker/Dockerfile +export CONTEXTFORGE_DATA_PLANE_JWKS_URL=https://your-issuer.example/.well-known/jwks.json +make docker-prod # production plugins and health endpoint; no testing helpers make compose-up # start nginx, Python control/built-in components, Redis, Postgres, external dataplane, fast_time_server ``` +Replace the example JWKS URL with the HTTPS endpoint serving the signing keys +for the tokens issued by your control plane. Compose passes it to the dataplane +through `CONTEXTFORGE_DATA_PLANE_JWKS_URL`. Production images do not contain the +testing-only `with_tools` helpers or need token-signing private keys. + Wait for `register_fast_time` to finish, then allow ~60s config propagation: ```bash @@ -17,7 +23,8 @@ docker compose -f docker/docker-compose.yml logs -f register_fast_time | Resource | URL | | --- | --- | | MCP endpoint | `http://localhost:8080/contextforge-rs/servers/{virtual_host_id}/mcp` | -| Bearer token | `GET http://localhost:8080/contextforge-rs/admin/tokens/admin@example.com` | +| Bearer token | Issue through the control plane; the production dataplane has no token helper. | +| Health | `http://localhost:8080/health` (also `/contextforge-rs/health`) | | fast_time_server virtual host id | `b8e3f1a2c4d5e6f7a1b2c3d4e5f6a7b8` | > **Critical**: `/contextforge-rs` prefix → ContextForge external dataplane. @@ -35,8 +42,9 @@ make conformance This runs the modern client and modern server eras through the committed external-dataplane `HEAD`, including fixture-direct server comparison and the -scoped client suite. Use `make conformance-bless` to replace all selected -baselines transactionally after a fully successful run. Generated checkouts, +scoped client suite. It builds a separate testing-only image with `with_tools` +for the harness's bootstrap JWKS endpoint. Use `make conformance-bless` to +replace all selected baselines transactionally after a fully successful run. Generated checkouts, results, reports, and logs stay under `.integration/`. ## Local Cargo Dev Workflow @@ -54,17 +62,19 @@ docker compose -f docker/docker-compose-local.yaml ps redis gateway-one gateway- | `gateway-one` | `http://127.0.0.1:5555/mcp` | MCP Rust SDK counter fixture. | | `gateway-two` | `http://127.0.0.1:5556/mcp` | MCP Rust SDK conformance fixture. | -Run the binary with bootstrap helpers: +Run the binary with bootstrap helpers **for local testing only**. `with_tools` +enables unauthenticated token, JWKS, and config routes. It must never be enabled +in production, and it is not needed for `/contextforge-rs/health`. ```bash cargo run -p contextforge-data-plane \ - --features contextforge-data-plane-lib/with_tools \ + --features with_tools \ --bin contextforge-data-plane -- \ --address 127.0.0.1:8001 \ --redis-address 127.0.0.1 \ --redis-port 6379 \ --redis-mode plain-text \ - --token-verification-public-key assets/jwt.key.pub \ + --jwks-url http://127.0.0.1:8001/contextforge-rs/admin/.well-known/jwks.json \ --token-verification-private-key assets/jwt.key \ --upstream-connection-mode plain-text-or-tls \ --number-of-cpus 4 @@ -76,8 +86,9 @@ The client-facing route is `http://127.0.0.1:8001/contextforge-rs/servers/{virtu ```bash USER_ID=11111111-1111-1111-1111-111111111111 +TENANT_ID=team_awesome TOKEN=$(curl --silent --show-error \ - --url "http://127.0.0.1:8001/contextforge-rs/admin/tokens/${USER_ID}?email=admin@example.com") + --url "http://127.0.0.1:8001/contextforge-rs/admin/tokens/${TENANT_ID}/${USER_ID}?email=admin@example.com") ``` ### Seed runtime configuration diff --git a/_context/wiki/index.md b/_context/wiki/index.md index d3f8b6a3..33d452a8 100644 --- a/_context/wiki/index.md +++ b/_context/wiki/index.md @@ -16,7 +16,7 @@ then follow only the links that are relevant. | [mcp-capability-allocation.md](mcp-capability-allocation.md) | Tentative ContextForge 2.0 target topology, ownership, state model, Phase 1-4 roadmap, and Phase 3 flows | | [failure-modes.md](failure-modes.md) | HTTP/MCP/routing/backend/plugin failure table — exact HTTP codes and JSON-RPC errors | | [config.md](config.md) | Key CLI flags, JWT claims, UserConfig shape, plugin config, telemetry debugging, startup validation, local observability stack | -| [deployment.md](deployment.md) | External-dataplane deployment checklist, health endpoint caveat, nginx routing, TLS choices, session affinity, Redis availability, image pinning | +| [deployment.md](deployment.md) | External-dataplane production builds, health endpoint, deployment checklist, nginx routing, TLS choices, session affinity, Redis availability, image pinning | | [security.md](security.md) | Trust boundaries among the control plane, built-in dataplane, and external dataplane; Origin/Host validation; transport security; secrets handling | | [performance.md](performance.md) | Control-plane Locust load runs, benchmark settings, and built-in-dataplane baseline | | [testing.md](testing.md) | Workspace checks, in-repo integration tests, full-stack harness lanes, settings, and control-plane baseline | diff --git a/_context/wiki/security.md b/_context/wiki/security.md index ff261aa5..e39859eb 100644 --- a/_context/wiki/security.md +++ b/_context/wiki/security.md @@ -108,14 +108,23 @@ unchanged, while RMCP regenerates method, routed-name, and protocol-version headers. If a plugin later changes an annotated argument, the original header remains and the upstream server may reject the mismatch. -## Local Bootstrap Helpers (`with_tools`) +## Testing-Only Bootstrap Helpers (`with_tools`) -The `contextforge-data-plane-lib/with_tools` feature compiles in: -- `/contextforge-rs/admin/tokens/{user}` -- `/contextforge-rs/admin/userconfigs/{user}` -- `/contextforge-rs/health` +The `with_tools` feature is **for testing only**. It compiles in these +unauthenticated helpers: -These routes are registered **outside the authentication middleware** — unauthenticated by design. They exist only for local bootstrap. **Production builds must not enable this feature.** In a real deployment the control plane mints tokens and writes config. +- `GET` and `POST /contextforge-rs/admin/tokens/{tenant_id}/{user_id}` +- `GET /contextforge-rs/admin/.well-known/jwks.json` +- `POST /contextforge-rs/admin/userconfigs/{user_id}` + +These routes are registered **outside the authentication middleware**. +**Production builds must not enable this feature**, including indirectly through +`--all-features`. Production token issuance and configuration publication belong +to the control plane and identity provider. + +`/contextforge-rs/health` is separate from these helpers. It is unauthenticated +and available in every build, including production. It reports HTTP liveness +without accessing authentication, runtime configuration, or MCP backends. ## Secrets Handling diff --git a/_context/wiki/testing.md b/_context/wiki/testing.md index a8b85662..db5f8b23 100644 --- a/_context/wiki/testing.md +++ b/_context/wiki/testing.md @@ -20,6 +20,15 @@ cargo shear --check-test-targets --deny-warnings --locked Use `cargo test` when nextest is unavailable. For wiki changes, also run `mdbook build _context/wiki` and `mdbook test _context/wiki`. +`with_tools` is for testing only. It provides unauthenticated token, JWKS, and +user-config helpers for local fixtures. The all-features test commands, local +conformance image, and CI conformance artifact deliberately include it; +production builds must omit it and must not use `--all-features`. +`/contextforge-rs/health` is available without +this feature. See [Deployment](deployment.md#production-builds) for production +build commands and [Getting Started](getting-started.md#local-cargo-dev-workflow) +for local testing. + New protocol-sensitive tests target MCP `2026-07-28`, connect through `server/discover`, and send the required per-request client metadata. A small `compatibility` module retains the active `2025-11-25`/`initialize` cases until @@ -90,9 +99,14 @@ cargo binstall cf-integration@0.3.1 --no-confirm make conformance ``` -The Make target tests the committed data-plane `HEAD`. It rejects tracked -uncommitted changes because the CLI clones the selected repository and commit -into `.integration/`. To use another local CLI binary: +The Make target tests the committed data-plane `HEAD` and rejects tracked +uncommitted changes. Its `conformance-image` prerequisite builds a Git archive of +`CF_DATAPLANE_REF` from `CF_DATAPLANE_REPO` with +`--build-arg CARGO_FEATURES=plugins,with_tools`. It passes the resulting local +image to the harness with pulling and source rebuilds disabled. The default tag +is `contextforge-data-plane:conformance`, separate from the production image. +CI supplies its prebuilt test image with `CF_DATAPLANE_REF` empty, which skips +the local image build. To use another local CLI binary: ```bash CF_INTEGRATION=/path/to/cf-integration \ diff --git a/crates/contextforge-data-plane-lib/Cargo.toml b/crates/contextforge-data-plane-lib/Cargo.toml index 7545201d..9f19af58 100644 --- a/crates/contextforge-data-plane-lib/Cargo.toml +++ b/crates/contextforge-data-plane-lib/Cargo.toml @@ -51,6 +51,7 @@ cel = "0.14.4" [features] default = [] +# Testing only: unauthenticated token, JWKS, and config helpers. Health is always available. with_tools = [] diff --git a/crates/contextforge-data-plane/Cargo.toml b/crates/contextforge-data-plane/Cargo.toml index e8096061..f7177d56 100644 --- a/crates/contextforge-data-plane/Cargo.toml +++ b/crates/contextforge-data-plane/Cargo.toml @@ -37,6 +37,7 @@ rustls.workspace = true [features] plugins = ["dep:cpex-secrets-detection"] test-plugins = ["dep:cpex-payload-marker", "dep:cpex-text-prefixer", "dep:cpex-tool-namespace"] +# Testing only: unauthenticated token, JWKS, and config helpers. Never enable in production. with_tools = ["contextforge-data-plane-lib/with_tools"] [dev-dependencies] diff --git a/docker/Dockerfile b/docker/Dockerfile index 6005f0ab..054c8ff6 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -7,13 +7,15 @@ apt install -y ca-certificates protobuf-compiler EOF COPY . . +# Production by default. Only test image builds may add with_tools. +ARG CARGO_FEATURES=plugins RUN --mount=type=cache,id=cargo,target=/usr/local/cargo/registry,sharing=locked \ --mount=type=cache,id=cargo-git,target=/usr/local/cargo/git,sharing=locked \ cargo fetch --locked RUN --mount=type=cache,id=cargo,target=/usr/local/cargo/registry,sharing=locked \ --mount=type=cache,id=cargo-git,target=/usr/local/cargo/git,sharing=locked \ --mount=type=cache,id=contextforge-data-plane-target,target=/app/target,sharing=locked \ - cargo build --release --features "contextforge-data-plane-lib/with_tools contextforge-data-plane/plugins" \ + cargo build --locked --release -p contextforge-data-plane --features "$CARGO_FEATURES" \ && mkdir -p /out \ && cp /app/target/release/contextforge-data-plane /out/contextforge-data-plane diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 918e3aaf..e8d95a31 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -74,8 +74,8 @@ services: - CONTEXTFORGE_DATA_PLANE_REDIS_PORT=6379 - CONTEXTFORGE_DATA_PLANE_REDIS_CONNECTION_MODE=plain-text - CONTEXTFORGE_DATA_PLANE_UPSTREAM_CONNECTION_MODE=plain-text-or-tls - - CONTEXTFORGE_DATA_PLANE_TOKEN_VERIFICATION_PUBLIC_KEY=/keys/jwt.key.pub - - CONTEXTFORGE_DATA_PLANE_TOKEN_VERIFICATION_PRIVATE_KEY=/keys/jwt.key + # Set the HTTPS JWKS endpoint for the token issuer in the host environment. + - CONTEXTFORGE_DATA_PLANE_JWKS_URL - RUST_LOG=debug sysctls: @@ -93,7 +93,7 @@ services: condition: service_healthy healthcheck: - ## Uncomment for HTTP healthcheck + # Health is available in production builds without with_tools. test: [ "CMD", @@ -122,13 +122,6 @@ services: cpus: '${GATEWAY_CPU_RESERVATION:-1}' memory: ${GATEWAY_MEM_RESERVATION:-512M} - # ────────────────────────────────────────────────────────────────────── - # Volume Mounts - # ────────────────────────────────────────────────────────────────────── - # Mount catalog configuration and SSL certificates - volumes: - - ../assets/:/keys:z # mount catalog configuration - contextforge-data-plane-one: image: ${IMAGE_LOCAL:-contextforge-data-plane:latest} container_name: contextforge-data-plane-one @@ -141,8 +134,8 @@ services: - CONTEXTFORGE_DATA_PLANE_REDIS_PORT=6379 - CONTEXTFORGE_DATA_PLANE_REDIS_CONNECTION_MODE=plain-text - CONTEXTFORGE_DATA_PLANE_UPSTREAM_CONNECTION_MODE=plain-text-or-tls - - CONTEXTFORGE_DATA_PLANE_TOKEN_VERIFICATION_PUBLIC_KEY=/keys/jwt.key.pub - - CONTEXTFORGE_DATA_PLANE_TOKEN_VERIFICATION_PRIVATE_KEY=/keys/jwt.key + # Set the HTTPS JWKS endpoint for the token issuer in the host environment. + - CONTEXTFORGE_DATA_PLANE_JWKS_URL - RUST_LOG=debug sysctls: @@ -166,13 +159,6 @@ services: cpus: '${GATEWAY_CPU_RESERVATION:-1}' memory: ${GATEWAY_MEM_RESERVATION:-512M} - # ────────────────────────────────────────────────────────────────────── - # Volume Mounts - # ────────────────────────────────────────────────────────────────────── - # Mount catalog configuration and SSL certificates - volumes: - - ../assets/:/keys:z # mount catalog configuration - contextforge-data-plane-two: image: ${IMAGE_LOCAL:-contextforge-data-plane:latest} container_name: contextforge-data-plane-two @@ -185,8 +171,8 @@ services: - CONTEXTFORGE_DATA_PLANE_REDIS_PORT=6379 - CONTEXTFORGE_DATA_PLANE_REDIS_CONNECTION_MODE=plain-text - CONTEXTFORGE_DATA_PLANE_UPSTREAM_CONNECTION_MODE=plain-text-or-tls - - CONTEXTFORGE_DATA_PLANE_TOKEN_VERIFICATION_PUBLIC_KEY=/keys/jwt.key.pub - - CONTEXTFORGE_DATA_PLANE_TOKEN_VERIFICATION_PRIVATE_KEY=/keys/jwt.key + # Set the HTTPS JWKS endpoint for the token issuer in the host environment. + - CONTEXTFORGE_DATA_PLANE_JWKS_URL - RUST_LOG=debug sysctls: @@ -210,13 +196,6 @@ services: cpus: '${GATEWAY_CPU_RESERVATION:-1}' memory: ${GATEWAY_MEM_RESERVATION:-512M} - # ────────────────────────────────────────────────────────────────────── - # Volume Mounts - # ────────────────────────────────────────────────────────────────────── - # Mount catalog configuration and SSL certificates - volumes: - - ../assets/:/keys:z # mount catalog configuration - mcp-counter-tool-one: image: ghcr.io/mcp-counter-tool:latest container_name: mcp-counter-tool-one From e4e5a09713b46b2797a7eaa4512a793797aeb334 Mon Sep 17 00:00:00 2001 From: lucarlig Date: Mon, 7 Sep 2026 16:18:04 +0100 Subject: [PATCH 2/4] Use production feature selection for conformance with cf-integration 0.3.2 Signed-off-by: lucarlig --- .github/workflows/ci.yml | 4 ++-- .github/workflows/conformance.yml | 4 ++-- Makefile | 31 +++++++++++++------------------ _context/wiki/getting-started.md | 7 ++++--- _context/wiki/testing.md | 28 ++++++++++++++-------------- docker/Dockerfile | 5 ++--- 6 files changed, 37 insertions(+), 42 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 48acbc67..a4e7bd45 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -81,8 +81,8 @@ jobs: ref: ${{ github.event.pull_request.head.sha || github.sha }} - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2.9.1 - - name: Build the workspace for conformance testing (includes with_tools) - run: cargo build --locked --workspace --all-features + - name: Build the production binary for conformance testing + run: cargo build --locked -p contextforge-data-plane --features plugins - name: Strip the conformance binary run: strip target/debug/contextforge-data-plane diff --git a/.github/workflows/conformance.yml b/.github/workflows/conformance.yml index 6654fd94..64cc7e8a 100644 --- a/.github/workflows/conformance.yml +++ b/.github/workflows/conformance.yml @@ -62,8 +62,8 @@ jobs: with: tool: cargo-binstall - - name: Install cf-integration 0.3.1 binary - run: cargo binstall cf-integration@0.3.1 --no-confirm + - name: Install cf-integration 0.3.2 binary + run: cargo binstall cf-integration@0.3.2 --no-confirm - name: Prepare the exact data-plane image env: diff --git a/Makefile b/Makefile index 54253405..2f8d118b 100644 --- a/Makefile +++ b/Makefile @@ -5,14 +5,13 @@ CF_INTEGRATION ?= cf-integration CF_INTEGRATION_DIR ?= $(CURDIR)/.integration CF_DATAPLANE_REPO ?= $(CURDIR) CF_DATAPLANE_REF ?= $(shell git -C "$(CF_DATAPLANE_REPO)" rev-parse HEAD) -CF_DATAPLANE_IMAGE ?= contextforge-data-plane:conformance CONFORMANCE_BASELINE_DIR := $(CURDIR)/tests/conformance/baselines # IBM detect-secrets hardened fork — pinned to the same commit used in mcp-context-forge. DETECT_SECRETS_SPEC ?= git+https://github.com/ibm/detect-secrets.git@076672a9a01abdfc7ecee2e7d14f08cdccb73976 DETECT_SECRETS_EXCLUDE := '(?x)(Cargo\.lock$$|\.lock$$)|^\.secrets\.baseline$$' -.PHONY: help docker-prod compose-up compose-down conformance-image conformance conformance-bless docs-serve pre-commit secrets-scan-all configure-git +.PHONY: help docker-prod compose-up compose-down conformance conformance-bless docs-serve pre-commit secrets-scan-all configure-git help: ## Show available commands @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-22s\033[0m %s\n", $$1, $$2}' @@ -30,7 +29,7 @@ compose-up: ## Launch stack: nginx, control plane, redis, postgres, pgbouncer, d compose-down: ## Tear down the stack docker compose -f docker/docker-compose.yml stop $(SERVICES) $(ARGS) -conformance-image: ## Prepare a testing-only conformance image from the committed data-plane ref +conformance: ## Run strict modern MCP conformance against the committed data-plane HEAD @if ! command -v "$(CF_INTEGRATION)" >/dev/null 2>&1; then \ echo "cf-integration not found: install its published binary with cargo binstall or set CF_INTEGRATION to its path."; \ exit 1; \ @@ -39,19 +38,9 @@ conformance-image: ## Prepare a testing-only conformance image from the committe echo "Tracked data-plane changes are not committed; commit or stash them before conformance."; \ exit 1; \ fi - @if [ -n "$(CF_DATAPLANE_REF)" ]; then \ - git -C "$(CF_DATAPLANE_REPO)" archive "$(CF_DATAPLANE_REF)" | \ - docker build -t "$(CF_DATAPLANE_IMAGE)" -f docker/Dockerfile \ - --label org.opencontainers.image.revision="$$(git -C "$(CF_DATAPLANE_REPO)" rev-parse "$(CF_DATAPLANE_REF)")" \ - --build-arg CARGO_FEATURES=plugins,with_tools -; \ - fi - -conformance: conformance-image ## Run strict modern MCP conformance against the committed data-plane HEAD @CF_INTEGRATION_DIR="$(CF_INTEGRATION_DIR)" \ CF_DATAPLANE_REPO="$(CF_DATAPLANE_REPO)" \ - CF_DATAPLANE_REF="" \ - CF_DATAPLANE_IMAGE="$(CF_DATAPLANE_IMAGE)" \ - CF_DATAPLANE_PULL_POLICY=never \ + CF_DATAPLANE_REF="$(CF_DATAPLANE_REF)" \ "$(CF_INTEGRATION)" conformance run \ --client-era modern \ --server-era modern \ @@ -60,12 +49,18 @@ conformance: conformance-image ## Run strict modern MCP conformance against the --baseline-dir "$(CONFORMANCE_BASELINE_DIR)" \ --output-dir "$(CF_INTEGRATION_DIR)/reports" -conformance-bless: conformance-image ## Run strict modern conformance and atomically update its baselines +conformance-bless: ## Run strict modern conformance and atomically update its baselines + @if ! command -v "$(CF_INTEGRATION)" >/dev/null 2>&1; then \ + echo "cf-integration not found: install its published binary with cargo binstall or set CF_INTEGRATION to its path."; \ + exit 1; \ + fi + @if [ -n "$$(git -C "$(CF_DATAPLANE_REPO)" status --porcelain --untracked-files=no)" ]; then \ + echo "Tracked data-plane changes are not committed; commit or stash them before conformance."; \ + exit 1; \ + fi @CF_INTEGRATION_DIR="$(CF_INTEGRATION_DIR)" \ CF_DATAPLANE_REPO="$(CF_DATAPLANE_REPO)" \ - CF_DATAPLANE_REF="" \ - CF_DATAPLANE_IMAGE="$(CF_DATAPLANE_IMAGE)" \ - CF_DATAPLANE_PULL_POLICY=never \ + CF_DATAPLANE_REF="$(CF_DATAPLANE_REF)" \ "$(CF_INTEGRATION)" conformance run \ --client-era modern \ --server-era modern \ diff --git a/_context/wiki/getting-started.md b/_context/wiki/getting-started.md index e748bf33..78e5d8bf 100644 --- a/_context/wiki/getting-started.md +++ b/_context/wiki/getting-started.md @@ -36,14 +36,15 @@ Teardown: `make compose-down` (stops containers; volumes kept). ## cf-integration Conformance ```bash -cargo binstall cf-integration@0.1.0 --no-confirm +cargo binstall cf-integration@0.3.2 --no-confirm make conformance ``` This runs the modern client and modern server eras through the committed external-dataplane `HEAD`, including fixture-direct server comparison and the -scoped client suite. It builds a separate testing-only image with `with_tools` -for the harness's bootstrap JWKS endpoint. Use `make conformance-bless` to +scoped client suite. It uses the production build without `with_tools`; the +harness owns test JWT signing, loopback JWKS, and Redis fixture publication. +Use `make conformance-bless` to replace all selected baselines transactionally after a fully successful run. Generated checkouts, results, reports, and logs stay under `.integration/`. diff --git a/_context/wiki/testing.md b/_context/wiki/testing.md index db5f8b23..b9e9a28e 100644 --- a/_context/wiki/testing.md +++ b/_context/wiki/testing.md @@ -21,9 +21,9 @@ cargo shear --check-test-targets --deny-warnings --locked Use `cargo test` when nextest is unavailable. For wiki changes, also run `mdbook build _context/wiki` and `mdbook test _context/wiki`. `with_tools` is for testing only. It provides unauthenticated token, JWKS, and -user-config helpers for local fixtures. The all-features test commands, local -conformance image, and CI conformance artifact deliberately include it; -production builds must omit it and must not use `--all-features`. +user-config helpers for local fixtures. The all-features unit test commands +include it. Production builds and conformance images omit it and must not use +`--all-features`. The harness owns conformance authentication and Redis setup. `/contextforge-rs/health` is available without this feature. See [Deployment](deployment.md#production-builds) for production build commands and [Getting Started](getting-started.md#local-cargo-dev-workflow) @@ -90,23 +90,23 @@ so changes to `main` do not invalidate the artifact. It runs the modern client and modern server eras through the external dataplane in standalone mode. This starts Redis, the dataplane, nginx, and the official fixture without the control plane. The harness discovers the fixture's tools, resources, templates, and -prompts and publishes their routes and actual tool schemas through the -dataplane serializer. Selecting that lane also runs the fixture-direct server -leg and the scoped external-dataplane client leg: +prompts and publishes their routes and actual tool schemas directly to Redis +as named MessagePack maps. Its own auth service signs test JWTs and serves +loopback JWKS; the production dataplane receives no signing key. Selecting that +lane also runs the fixture-direct server leg and the scoped external-dataplane +client leg: ```bash -cargo binstall cf-integration@0.3.1 --no-confirm +cargo binstall cf-integration@0.3.2 --no-confirm make conformance ``` The Make target tests the committed data-plane `HEAD` and rejects tracked -uncommitted changes. Its `conformance-image` prerequisite builds a Git archive of -`CF_DATAPLANE_REF` from `CF_DATAPLANE_REPO` with -`--build-arg CARGO_FEATURES=plugins,with_tools`. It passes the resulting local -image to the harness with pulling and source rebuilds disabled. The default tag -is `contextforge-data-plane:conformance`, separate from the production image. -CI supplies its prebuilt test image with `CF_DATAPLANE_REF` empty, which skips -the local image build. To use another local CLI binary: +uncommitted changes. The harness builds `CF_DATAPLANE_REF` from +`CF_DATAPLANE_REPO` using the production Dockerfile with `plugins` and without +`with_tools`. CI supplies a prebuilt production binary in its conformance image +and sets `CF_DATAPLANE_REF` empty to skip the source build. To use another local +CLI binary: ```bash CF_INTEGRATION=/path/to/cf-integration \ diff --git a/docker/Dockerfile b/docker/Dockerfile index 054c8ff6..05fd82e2 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -7,15 +7,14 @@ apt install -y ca-certificates protobuf-compiler EOF COPY . . -# Production by default. Only test image builds may add with_tools. -ARG CARGO_FEATURES=plugins +# Production builds exclude the testing-only with_tools feature. RUN --mount=type=cache,id=cargo,target=/usr/local/cargo/registry,sharing=locked \ --mount=type=cache,id=cargo-git,target=/usr/local/cargo/git,sharing=locked \ cargo fetch --locked RUN --mount=type=cache,id=cargo,target=/usr/local/cargo/registry,sharing=locked \ --mount=type=cache,id=cargo-git,target=/usr/local/cargo/git,sharing=locked \ --mount=type=cache,id=contextforge-data-plane-target,target=/app/target,sharing=locked \ - cargo build --locked --release -p contextforge-data-plane --features "$CARGO_FEATURES" \ + cargo build --locked --release -p contextforge-data-plane --features plugins \ && mkdir -p /out \ && cp /app/target/release/contextforge-data-plane /out/contextforge-data-plane From 7f1961c5e8cb3d888191b79589b36e2101d9c340 Mon Sep 17 00:00:00 2001 From: lucarlig Date: Tue, 8 Sep 2026 14:56:35 +0100 Subject: [PATCH 3/4] Pin the containerized harness for production conformance Signed-off-by: lucarlig --- .github/workflows/conformance.yml | 17 +++++++---------- Makefile | 4 ++-- _context/wiki/getting-started.md | 8 +++++++- _context/wiki/testing.md | 8 ++++---- 4 files changed, 20 insertions(+), 17 deletions(-) diff --git a/.github/workflows/conformance.yml b/.github/workflows/conformance.yml index 64cc7e8a..465cbac6 100644 --- a/.github/workflows/conformance.yml +++ b/.github/workflows/conformance.yml @@ -11,6 +11,7 @@ concurrency: env: CARGO_TERM_COLOR: always + CF_INTEGRATION_REV: 957eeb1a846c2d44c417707e45d2673a746805f2 # pragma: allowlist secret (public Git revision) jobs: conformance: @@ -58,12 +59,13 @@ jobs: persist-credentials: false ref: ${{ steps.revision.outputs.head_sha }} - - uses: taiki-e/install-action@v2.75.27 - with: - tool: cargo-binstall + - uses: dtolnay/rust-toolchain@1.97.0 - - name: Install cf-integration 0.3.2 binary - run: cargo binstall cf-integration@0.3.2 --no-confirm + - name: Install the pinned cf-integration revision + run: >- + cargo install --locked + --git https://github.com/contextforge-org/contextforge-dev-tools + --rev "$CF_INTEGRATION_REV" cf-integration - name: Prepare the exact data-plane image env: @@ -74,11 +76,6 @@ jobs: --binary contextforge-data-plane --image contextforge-data-plane:conformance - - name: Install Node.js 22 - uses: actions/setup-node@v6.5.0 - with: - node-version: 22 - - name: Run strict modern conformance id: conformance env: diff --git a/Makefile b/Makefile index 2f8d118b..bdc8b97d 100644 --- a/Makefile +++ b/Makefile @@ -31,7 +31,7 @@ compose-down: ## Tear down the stack conformance: ## Run strict modern MCP conformance against the committed data-plane HEAD @if ! command -v "$(CF_INTEGRATION)" >/dev/null 2>&1; then \ - echo "cf-integration not found: install its published binary with cargo binstall or set CF_INTEGRATION to its path."; \ + echo "cf-integration not found: follow _context/wiki/getting-started.md or set CF_INTEGRATION to its path."; \ exit 1; \ fi @if [ -n "$$(git -C "$(CF_DATAPLANE_REPO)" status --porcelain --untracked-files=no)" ]; then \ @@ -51,7 +51,7 @@ conformance: ## Run strict modern MCP conformance against the committed data-pla conformance-bless: ## Run strict modern conformance and atomically update its baselines @if ! command -v "$(CF_INTEGRATION)" >/dev/null 2>&1; then \ - echo "cf-integration not found: install its published binary with cargo binstall or set CF_INTEGRATION to its path."; \ + echo "cf-integration not found: follow _context/wiki/getting-started.md or set CF_INTEGRATION to its path."; \ exit 1; \ fi @if [ -n "$$(git -C "$(CF_DATAPLANE_REPO)" status --porcelain --untracked-files=no)" ]; then \ diff --git a/_context/wiki/getting-started.md b/_context/wiki/getting-started.md index 78e5d8bf..5640f90a 100644 --- a/_context/wiki/getting-started.md +++ b/_context/wiki/getting-started.md @@ -35,8 +35,14 @@ Teardown: `make compose-down` (stops containers; volumes kept). ## cf-integration Conformance +Install the same harness revision pinned by the conformance workflow (Rust +1.97 is required to build it). Official conformance packages and their Node/npm +runtime are installed only inside Docker images. + ```bash -cargo binstall cf-integration@0.3.2 --no-confirm +cargo +1.97.0 install --locked \ + --git https://github.com/contextforge-org/contextforge-dev-tools \ + --rev 957eeb1a846c2d44c417707e45d2673a746805f2 cf-integration make conformance ``` diff --git a/_context/wiki/testing.md b/_context/wiki/testing.md index b9e9a28e..7f4ece90 100644 --- a/_context/wiki/testing.md +++ b/_context/wiki/testing.md @@ -96,10 +96,10 @@ loopback JWKS; the production dataplane receives no signing key. Selecting that lane also runs the fixture-direct server leg and the scoped external-dataplane client leg: -```bash -cargo binstall cf-integration@0.3.2 --no-confirm -make conformance -``` +Install the pinned harness revision from +[Getting Started](getting-started.md#cf-integration-conformance), then run +`make conformance`. CI installs that same revision; conformance and Inspector +install and run Node/npm only inside Docker images. The Make target tests the committed data-plane `HEAD` and rejects tracked uncommitted changes. The harness builds `CF_DATAPLANE_REF` from From 5a1dc130682b7f9d015c51a21528a8bfa9b68dcd Mon Sep 17 00:00:00 2001 From: lucarlig Date: Tue, 8 Sep 2026 16:30:48 +0100 Subject: [PATCH 4/4] Restore cf-integration 0.3.2 release installation Signed-off-by: lucarlig --- .github/workflows/conformance.yml | 12 +++++------- Makefile | 4 ++-- _context/wiki/getting-started.md | 7 ++----- _context/wiki/testing.md | 4 ++-- 4 files changed, 11 insertions(+), 16 deletions(-) diff --git a/.github/workflows/conformance.yml b/.github/workflows/conformance.yml index 465cbac6..74e0d6cb 100644 --- a/.github/workflows/conformance.yml +++ b/.github/workflows/conformance.yml @@ -11,7 +11,6 @@ concurrency: env: CARGO_TERM_COLOR: always - CF_INTEGRATION_REV: 957eeb1a846c2d44c417707e45d2673a746805f2 # pragma: allowlist secret (public Git revision) jobs: conformance: @@ -59,13 +58,12 @@ jobs: persist-credentials: false ref: ${{ steps.revision.outputs.head_sha }} - - uses: dtolnay/rust-toolchain@1.97.0 + - uses: taiki-e/install-action@v2.75.27 + with: + tool: cargo-binstall - - name: Install the pinned cf-integration revision - run: >- - cargo install --locked - --git https://github.com/contextforge-org/contextforge-dev-tools - --rev "$CF_INTEGRATION_REV" cf-integration + - name: Install cf-integration 0.3.2 binary + run: cargo binstall cf-integration@0.3.2 --no-confirm - name: Prepare the exact data-plane image env: diff --git a/Makefile b/Makefile index bdc8b97d..2f8d118b 100644 --- a/Makefile +++ b/Makefile @@ -31,7 +31,7 @@ compose-down: ## Tear down the stack conformance: ## Run strict modern MCP conformance against the committed data-plane HEAD @if ! command -v "$(CF_INTEGRATION)" >/dev/null 2>&1; then \ - echo "cf-integration not found: follow _context/wiki/getting-started.md or set CF_INTEGRATION to its path."; \ + echo "cf-integration not found: install its published binary with cargo binstall or set CF_INTEGRATION to its path."; \ exit 1; \ fi @if [ -n "$$(git -C "$(CF_DATAPLANE_REPO)" status --porcelain --untracked-files=no)" ]; then \ @@ -51,7 +51,7 @@ conformance: ## Run strict modern MCP conformance against the committed data-pla conformance-bless: ## Run strict modern conformance and atomically update its baselines @if ! command -v "$(CF_INTEGRATION)" >/dev/null 2>&1; then \ - echo "cf-integration not found: follow _context/wiki/getting-started.md or set CF_INTEGRATION to its path."; \ + echo "cf-integration not found: install its published binary with cargo binstall or set CF_INTEGRATION to its path."; \ exit 1; \ fi @if [ -n "$$(git -C "$(CF_DATAPLANE_REPO)" status --porcelain --untracked-files=no)" ]; then \ diff --git a/_context/wiki/getting-started.md b/_context/wiki/getting-started.md index 5640f90a..515c6425 100644 --- a/_context/wiki/getting-started.md +++ b/_context/wiki/getting-started.md @@ -35,14 +35,11 @@ Teardown: `make compose-down` (stops containers; volumes kept). ## cf-integration Conformance -Install the same harness revision pinned by the conformance workflow (Rust -1.97 is required to build it). Official conformance packages and their Node/npm +Install the same harness version used by CI. Official conformance packages and their Node/npm runtime are installed only inside Docker images. ```bash -cargo +1.97.0 install --locked \ - --git https://github.com/contextforge-org/contextforge-dev-tools \ - --rev 957eeb1a846c2d44c417707e45d2673a746805f2 cf-integration +cargo binstall cf-integration@0.3.2 --no-confirm make conformance ``` diff --git a/_context/wiki/testing.md b/_context/wiki/testing.md index 7f4ece90..ee0d3ede 100644 --- a/_context/wiki/testing.md +++ b/_context/wiki/testing.md @@ -96,9 +96,9 @@ loopback JWKS; the production dataplane receives no signing key. Selecting that lane also runs the fixture-direct server leg and the scoped external-dataplane client leg: -Install the pinned harness revision from +Install the pinned harness version from [Getting Started](getting-started.md#cf-integration-conformance), then run -`make conformance`. CI installs that same revision; conformance and Inspector +`make conformance`. CI installs that same version; conformance and Inspector install and run Node/npm only inside Docker images. The Make target tests the committed data-plane `HEAD` and rejects tracked