From 30bd2403f426c84f8f83f412ca8a103d942d2938 Mon Sep 17 00:00:00 2001 From: Lang-Akshay Date: Mon, 10 Aug 2026 16:00:23 +0100 Subject: [PATCH 1/9] feat:added make pre-commit Signed-off-by: Lang-Akshay --- .dockerignore | 1 - .gitattributes | 4 + .github/workflows/docker_image_ci.yaml | 13 +- .gitignore | 3 + .pre-commit-config.yaml | 131 +++++ .secrets.baseline | 456 ++++++++++++++++++ Makefile | 146 +++++- ...ontextforge.intermediate.ca-chain.cert.pem | 1 - assets/tls_certificate.pem | 2 +- docker/docker-compose-local.yaml | 19 +- docker/mcp_conformance.Dockerfile | 2 +- docker/mcp_counter.Dockerfile | 2 +- ...gateway-performance-report-2026-05-01.html | 26 +- schemas/user.json | 2 +- schemas/user_config.json | 2 +- .../git/resolve-secrets-baseline-conflict.sh | 101 ++++ 16 files changed, 872 insertions(+), 39 deletions(-) create mode 100644 .gitattributes create mode 100644 .secrets.baseline create mode 100755 scripts/git/resolve-secrets-baseline-conflict.sh diff --git a/.dockerignore b/.dockerignore index 88bd6630..89532539 100644 --- a/.dockerignore +++ b/.dockerignore @@ -2,4 +2,3 @@ target/ assets/ resources/ releases/ - diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..7317a71d --- /dev/null +++ b/.gitattributes @@ -0,0 +1,4 @@ +# Tell git to use the secrets-baseline merge driver for .secrets.baseline +# so merge conflicts produce a regenerated JSON instead of conflict markers. +# Register the driver with: make configure-git +.secrets.baseline merge=secrets-baseline diff --git a/.github/workflows/docker_image_ci.yaml b/.github/workflows/docker_image_ci.yaml index 62b15ef9..1869a957 100644 --- a/.github/workflows/docker_image_ci.yaml +++ b/.github/workflows/docker_image_ci.yaml @@ -4,10 +4,10 @@ on: push: branches: [ "main" ] # tags: ["2.0.0"] - + env: IMAGE_NAME: contextforge-data-plane - + jobs: build: @@ -15,24 +15,23 @@ jobs: permissions: packages: write contents: read - steps: + steps: - uses: actions/checkout@v5 - name: Set version id: set_version run: | - CF_VERSION=$(grep -m 1 '^version' Cargo.toml | sed 's/version\s*=\s*"\(.*\)"/\1/') + CF_VERSION=$(grep -m 1 '^version' Cargo.toml | sed 's/version\s*=\s*"\(.*\)"/\1/') echo "CF_VERSION=${CF_VERSION}" >> "${GITHUB_ENV}" - name: Show version run: echo "${CF_VERSION}" - - name: Build the Docker image + - name: Build the Docker image run: docker build . --file docker/Dockerfile --tag "${IMAGE_NAME}:latest" - name: Log in to registry run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u "${{ github.actor }}" --password-stdin - name: Push image - run: | + run: | IMAGE_ID="ghcr.io/${{ github.repository_owner }}/${IMAGE_NAME}" docker tag "${IMAGE_NAME}:latest" "${IMAGE_ID}:v${CF_VERSION}" docker tag "${IMAGE_NAME}:latest" "${IMAGE_ID}:latest" docker push "${IMAGE_ID}:v${CF_VERSION}" docker push "${IMAGE_ID}:latest" - diff --git a/.gitignore b/.gitignore index bea63b88..cd00f559 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,9 @@ contextforge-data-plane.log.* # Generated by mdBook (wiki) _context/wiki/book/ +# pre-commit tool cache (hook virtualenvs and temp files) +.cache/ + # RustRover # JetBrains specific template is maintained in a separate JetBrains.gitignore that can # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 7fb2ce4a..f2495fe2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,4 +1,135 @@ +# ----------------------------------------------------------------------------- +# Pre-commit Configuration — contextforge-data-plane (Rust) +# ----------------------------------------------------------------------------- +# Install: +# uv tool install pre-commit +# pre-commit install +# pre-commit run --all-files +# +# Update hook revisions: +# pre-commit autoupdate +# +# Skip all checks for one commit: +# git commit -m "…" --no-verify +# +# NOTE: Formatters (cargo fmt) modify files and need re-staging. +# ----------------------------------------------------------------------------- + +exclude: 'Cargo\.lock$|\.lock$|target/' +fail_fast: true + repos: + # --------------------------------------------------------------------------- + # Security — private keys and large accidental blobs + # --------------------------------------------------------------------------- + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: cef0300fd0fc4d2a87a85fa2093c6b283ea36f4b # v5.0.0 + hooks: + - id: detect-private-key + name: Detect Private Key + exclude: 'assets/|tests/|crates/plugins/cpex-secrets-detection/' + + - id: check-added-large-files + name: Check Added Large Files + stages: [pre-commit, pre-push, manual] + + - id: check-merge-conflict + name: Check Merge Conflicts + types: [text] + + # --------------------------------------------------------------------------- + # File quality — whitespace, encoding, line endings, format syntax + # --------------------------------------------------------------------------- + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: cef0300fd0fc4d2a87a85fa2093c6b283ea36f4b # v5.0.0 + hooks: + - id: end-of-file-fixer + name: Fix End of Files + types: [text] + stages: [pre-commit, pre-push, manual] + + - id: trailing-whitespace + name: Trim Trailing Whitespace + types: [text] + stages: [pre-commit, pre-push, manual] + + - id: fix-byte-order-marker + name: Fix UTF-8 Byte Order Marker + types: [text] + + - id: mixed-line-ending + name: Mixed Line Ending + types: [text] + args: [--fix=lf] + + - id: check-case-conflict + name: Check Case Conflicts + + - id: check-symlinks + name: Check Symlinks + types: [symlink] + + - id: check-toml + name: Check TOML + types: [toml] + + - id: check-yaml + name: Check YAML + types: [yaml] + + - id: check-json + name: Check JSON + types: [json] + + # --------------------------------------------------------------------------- + # Unicode hygiene — BiDi controls can hide malicious code + # --------------------------------------------------------------------------- + - repo: https://github.com/sirosen/texthooks + rev: c1a669453f31baa33e32761cb670aa1f10141937 # v0.6.8 + hooks: + - id: forbid-bidi-controls + name: Forbid BiDi Unicode Controls + + # --------------------------------------------------------------------------- + # AI / placeholder guards (local) + # --------------------------------------------------------------------------- + - repo: local + hooks: + - id: forbid-content-reference + name: Forbid :contentReference + entry: ':contentReference' + language: pygrep + types: [text] + exclude: ^\.pre-commit-config\.yaml$ + + - id: forbid-oai-citations + name: Forbid OpenAI Citations + entry: '\[oaicite:\?\?\d+\]' + language: pygrep + types: [text] + exclude: ^\.pre-commit-config\.yaml$ + + - id: forbid-ai-stock-phrases + name: Forbid AI Stock Phrases + entry: '(?i)(as an ai language model|i am an ai developed by|my knowledge cutoff|my training data)' + language: pygrep + types: [text] + exclude: ^\.pre-commit-config\.yaml$ + + # --------------------------------------------------------------------------- + # Secret scanning — IBM hardened fork + # --------------------------------------------------------------------------- + - repo: https://github.com/ibm/detect-secrets + rev: 076672a9a01abdfc7ecee2e7d14f08cdccb73976 # 0.13.1+ibm.64.dss + hooks: + - id: detect-secrets + name: IBM Detect Secrets + args: ['--baseline', '.secrets.baseline', --use-all-plugins, --fail-on-unaudited] + types: [text] + + # --------------------------------------------------------------------------- + # Rust — format check, lint, supply-chain, test, build + # --------------------------------------------------------------------------- - repo: local hooks: - id: cargo-fmt diff --git a/.secrets.baseline b/.secrets.baseline new file mode 100644 index 00000000..005ab756 --- /dev/null +++ b/.secrets.baseline @@ -0,0 +1,456 @@ +{ + "exclude": { + "files": "Cargo\\.lock$|\\.lock$|target/", + "lines": null + }, + "generated_at": "2026-08-10T14:19:39Z", + "plugins_used": [ + { + "name": "AWSKeyDetector" + }, + { + "name": "ArtifactoryDetector" + }, + { + "name": "AzureStorageKeyDetector" + }, + { + "base64_limit": 4.5, + "name": "Base64HighEntropyString" + }, + { + "name": "BasicAuthDetector" + }, + { + "name": "BoxDetector" + }, + { + "name": "CloudantDetector" + }, + { + "ghe_instance": "github.ibm.com", + "name": "GheDetector" + }, + { + "name": "GitHubTokenDetector" + }, + { + "hex_limit": 3, + "name": "HexHighEntropyString" + }, + { + "name": "IbmCloudIamDetector" + }, + { + "name": "IbmCosHmacDetector" + }, + { + "name": "JwtTokenDetector" + }, + { + "keyword_exclude": null, + "name": "KeywordDetector" + }, + { + "name": "MailchimpDetector" + }, + { + "name": "NpmDetector" + }, + { + "name": "PrivateKeyDetector" + }, + { + "name": "SlackDetector" + }, + { + "name": "SoftlayerDetector" + }, + { + "name": "SquareOAuthDetector" + }, + { + "name": "StripeDetector" + }, + { + "name": "TwilioKeyDetector" + } + ], + "results": { + "Test-Suite.md": [ + { + "hashed_secret": "bc2f74c22f98f7b6ffbc2f67453dbfa99bce9a32", + "is_verified": false, + "line_number": 106, + "type": "Secret Keyword", + "verified_result": null, + "is_secret": false + } + ], + "assets/contextforgeCA/contextforge-client.key.pem": [ + { + "hashed_secret": "1348b145fa1a555461c1b790a2f66614781091e9", + "is_verified": false, + "line_number": 1, + "type": "Private Key", + "verified_result": null, + "is_secret": false + } + ], + "assets/contextforgeCA/contextforge-server.key.pem": [ + { + "hashed_secret": "1348b145fa1a555461c1b790a2f66614781091e9", + "is_verified": false, + "line_number": 1, + "type": "Private Key", + "verified_result": null, + "is_secret": false + } + ], + "assets/contextforgeCA/contextforge.ca.key.pem": [ + { + "hashed_secret": "1348b145fa1a555461c1b790a2f66614781091e9", + "is_verified": false, + "line_number": 1, + "type": "Private Key", + "verified_result": null, + "is_secret": false + } + ], + "assets/contextforgeCA/contextforge.intermediate.key.pem": [ + { + "hashed_secret": "1348b145fa1a555461c1b790a2f66614781091e9", + "is_verified": false, + "line_number": 1, + "type": "Private Key", + "verified_result": null, + "is_secret": false + } + ], + "assets/jwt.key": [ + { + "hashed_secret": "be4fc4886bd949b369d5e092eb87494f12e57e5b", + "is_verified": false, + "line_number": 1, + "type": "Private Key", + "verified_result": null, + "is_secret": false + } + ], + "assets/tls_key.pem": [ + { + "hashed_secret": "1348b145fa1a555461c1b790a2f66614781091e9", + "is_verified": false, + "line_number": 1, + "type": "Private Key", + "verified_result": null, + "is_secret": false + } + ], + "crates/contextforge-data-plane-lib/src/common.rs": [ + { + "hashed_secret": "4a4645604f0b9e29503be96a87f6f47a6e4a7890", + "is_verified": false, + "line_number": 154, + "type": "Secret Keyword", + "verified_result": null, + "is_secret": false + }, + { + "hashed_secret": "427f5e1b530d4a544883308d876a11d724060c86", + "is_verified": false, + "line_number": 157, + "type": "Secret Keyword", + "verified_result": null, + "is_secret": false + }, + { + "hashed_secret": "bfc6000db1195a9522813fc405c666dd4ce669ad", + "is_verified": false, + "line_number": 250, + "type": "Secret Keyword", + "verified_result": null, + "is_secret": false + } + ], + "crates/contextforge-data-plane-lib/src/telemetry.rs": [ + { + "hashed_secret": "0a24796d4c71ce722a92f450f69dc36c60b21de4", + "is_verified": false, + "line_number": 87, + "type": "Hex High Entropy String", + "verified_result": null, + "is_secret": false + } + ], + "crates/contextforge-data-plane-lib/tests/support/client.rs": [ + { + "hashed_secret": "a453c8b2640819a451ce875ac1e04d0dbab7b403", + "is_verified": false, + "line_number": 12, + "type": "Secret Keyword", + "verified_result": null, + "is_secret": false + } + ], + "crates/contextforge-data-plane-lib/tests/support/mod.rs": [ + { + "hashed_secret": "a453c8b2640819a451ce875ac1e04d0dbab7b403", + "is_verified": false, + "line_number": 17, + "type": "Secret Keyword", + "verified_result": null, + "is_secret": false + } + ], + "crates/contextforge-data-plane/Cargo.toml": [ + { + "hashed_secret": "58e7dc38ba3a7d4a720006d2f3cc4cda774d89dc", + "is_verified": false, + "line_number": 19, + "type": "Hex High Entropy String", + "verified_result": null, + "is_secret": false + } + ], + "crates/plugins/cpex-secrets-detection/src/lib.rs": [ + { + "hashed_secret": "86de8c52637ec530fe39b0a8471da9b8764d5242", + "is_verified": false, + "line_number": 609, + "type": "AWS Access Key", + "verified_result": null, + "is_secret": false + } + ], + "crates/plugins/cpex-secrets-detection/src/scanner.rs": [ + { + "hashed_secret": "9249e2590f5d19742260cb5296cb76fe0677f147", + "is_verified": false, + "line_number": 238, + "type": "Secret Keyword", + "verified_result": null, + "is_secret": false + }, + { + "hashed_secret": "199da8f71b7dced64f82cf6e96483134cace9b14", + "is_verified": false, + "line_number": 239, + "type": "Secret Keyword", + "verified_result": null, + "is_secret": false + }, + { + "hashed_secret": "c0026c4c848882618c987859077ffbae92130625", + "is_verified": false, + "line_number": 242, + "type": "Secret Keyword", + "verified_result": null, + "is_secret": false + }, + { + "hashed_secret": "078553dc10635837abb80f404302c70cba91b879", + "is_verified": false, + "line_number": 278, + "type": "Base64 High Entropy String", + "verified_result": null, + "is_secret": false + }, + { + "hashed_secret": "e175c6f5f2a92e8623bd9a4820edb4e8c1b0fd10", + "is_verified": false, + "line_number": 278, + "type": "GitHub Token", + "verified_result": null, + "is_secret": false + }, + { + "hashed_secret": "97d99a51e5ac827bb36fe6273facfda35245917a", + "is_verified": false, + "line_number": 279, + "type": "Base64 High Entropy String", + "verified_result": null, + "is_secret": false + }, + { + "hashed_secret": "be4fc4886bd949b369d5e092eb87494f12e57e5b", + "is_verified": false, + "line_number": 282, + "type": "Private Key", + "verified_result": null, + "is_secret": false + }, + { + "hashed_secret": "b1775a785f09a6ebaf2dc33d6eaeb98974d9cdb8", + "is_verified": false, + "line_number": 284, + "type": "Hex High Entropy String", + "verified_result": null, + "is_secret": false + }, + { + "hashed_secret": "eae9124e42e2ef05ba727bd1a1c0c6fa61a05b9e", + "is_verified": false, + "line_number": 302, + "type": "Secret Keyword", + "verified_result": null, + "is_secret": false + }, + { + "hashed_secret": "86de8c52637ec530fe39b0a8471da9b8764d5242", + "is_verified": false, + "line_number": 401, + "type": "AWS Access Key", + "verified_result": null, + "is_secret": false + }, + { + "hashed_secret": "9d7235fe33b6612ed7ebca4b63afd00d4adf5d66", + "is_verified": false, + "line_number": 410, + "type": "Secret Keyword", + "verified_result": null, + "is_secret": false + }, + { + "hashed_secret": "27a39044bff80a4c196689dfa8dcf129cb27fef8", + "is_verified": false, + "line_number": 431, + "type": "Base64 High Entropy String", + "verified_result": null, + "is_secret": false + } + ], + "crates/plugins/cpex-secrets-detection/tests/plugin_manager.rs": [ + { + "hashed_secret": "436da7d4d22c39c0165ab0d5b40073d0f2fc11c5", + "is_verified": false, + "line_number": 197, + "type": "AWS Access Key", + "verified_result": null, + "is_secret": false + }, + { + "hashed_secret": "8b4510a576d82f38bd2730436bf5e20c4e15b30e", + "is_verified": false, + "line_number": 198, + "type": "AWS Access Key", + "verified_result": null, + "is_secret": false + }, + { + "hashed_secret": "e4ea017859bcad962c8ab551fe29da9147877eee", + "is_verified": false, + "line_number": 199, + "type": "AWS Access Key", + "verified_result": null, + "is_secret": false + }, + { + "hashed_secret": "86de8c52637ec530fe39b0a8471da9b8764d5242", + "is_verified": false, + "line_number": 268, + "type": "AWS Access Key", + "verified_result": null, + "is_secret": false + } + ], + "docker/docker-compose-langfuse.yaml": [ + { + "hashed_secret": "cb1fde0682fbd1ac0faf2a9f297167ac9d06434b", + "is_verified": false, + "line_number": 16, + "type": "Secret Keyword", + "verified_result": null, + "is_secret": false + }, + { + "hashed_secret": "cb58df830a45cc33df1a313e616ecad78cd796c5", + "is_verified": false, + "line_number": 77, + "type": "Secret Keyword", + "verified_result": null, + "is_secret": false + }, + { + "hashed_secret": "2e0c522bfe4e7885492862df2e0b987c0ca02623", + "is_verified": false, + "line_number": 100, + "type": "Secret Keyword", + "verified_result": null, + "is_secret": false + }, + { + "hashed_secret": "d9d007c8de197b3f36a3a0ba4f13c0f7df175d5a", + "is_verified": false, + "line_number": 255, + "type": "Secret Keyword", + "verified_result": null, + "is_secret": false + } + ], + "docker/docker-compose.yml": [ + { + "hashed_secret": "2a8bfc0ce436d55ca907d0162989481bcb7677b4", + "is_verified": false, + "line_number": 189, + "type": "Secret Keyword", + "verified_result": null, + "is_secret": false + }, + { + "hashed_secret": "fdda45b7f6d2ead95d9991fc4678640c3bab0d84", + "is_verified": false, + "line_number": 363, + "type": "Secret Keyword", + "verified_result": null, + "is_secret": false + }, + { + "hashed_secret": "093d378410a5cfa4bd5088f3fef62fbdb8a95665", + "is_verified": false, + "line_number": 369, + "type": "Secret Keyword", + "verified_result": null, + "is_secret": false + }, + { + "hashed_secret": "c3de40d5e3fc71ed62771c2127a8e42585026c97", + "is_verified": false, + "line_number": 371, + "type": "Secret Keyword", + "verified_result": null, + "is_secret": false + }, + { + "hashed_secret": "4d4acd9b084d13f5fdb23807d857e1c48a1cfd0f", + "is_verified": false, + "line_number": 460, + "type": "Secret Keyword", + "verified_result": null, + "is_secret": false + }, + { + "hashed_secret": "bd0160c2cf35d950843c88f3be2b9412ed71f485", + "is_verified": false, + "line_number": 495, + "type": "Secret Keyword", + "verified_result": null, + "is_secret": false + }, + { + "hashed_secret": "293324f6824bb3a6db5c4dc42a60ddd4a9851c99", + "is_verified": false, + "line_number": 658, + "type": "Hex High Entropy String", + "verified_result": null, + "is_secret": false + } + ] + }, + "version": "0.13.1+ibm.64.dss", + "word_list": { + "file": null, + "hash": null + } +} diff --git a/Makefile b/Makefile index 89645fb5..c2145de8 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,28 @@ +<<<<<<< HEAD .PHONY: help docker-prod compose-up compose-down docs-serve +======= +SERVICES ?= nginx control-plane redis postgres pgbouncer data-plane fast_time_server register_fast_time +ARGS ?= + +# 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 + +# Files excluded from secret scanning (lock files generated by tooling). +DETECT_SECRETS_EXCLUDE := '(?x)(Cargo\.lock$$|\.lock$$)|^\.secrets\.baseline$$' + +.PHONY: help \ + docker-prod compose-up compose-down docs-serve \ + fmt fmt-check lint deny \ + pre-commit install-pre-commit-hooks configure-git \ + secrets-scan secrets-scan-all secrets-audit secrets-baseline +>>>>>>> 7aaeb99 (feat:added make pre-commit) help: ## Show this help - @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-15s\033[0m %s\n", $$1, $$2}' + @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-22s\033[0m %s\n", $$1, $$2}' + +# --------------------------------------------------------------------------- +# Docker +# --------------------------------------------------------------------------- docker-prod: ## Build production Docker image (contextforge-data-plane:latest) from docker/Dockerfile docker build -t contextforge-data-plane:latest -f docker/Dockerfile . @@ -11,10 +32,131 @@ compose-up: ## Launch stack: nginx, control plane, redis, postgres, pgbouncer, d echo "Image contextforge-data-plane:latest not found. Run 'make docker-prod' first."; \ exit 1; \ } - docker compose -f docker/docker-compose.yml up -d nginx control-plane redis postgres pgbouncer data-plane fast_time_server register_fast_time + docker compose -f docker/docker-compose.yml up -d $(SERVICES) $(ARGS) +<<<<<<< HEAD compose-down: ## Tear down the stack docker compose -f docker/docker-compose.yml stop nginx control-plane redis postgres pgbouncer data-plane fast_time_server register_fast_time docs-serve: ## Serve the wiki book locally at http://127.0.0.1:3000 mdbook serve _context/wiki --hostname 127.0.0.1 --port 3000 --open +======= +testing-down: ## Tear down the testing stack + docker compose -f docker/docker-compose.yml stop $(SERVICES) $(ARGS) +compose-down: ## Tear down the stack + docker compose -f docker/docker-compose.yml stop $(SERVICES) $(ARGS) + +docs-serve: ## Serve the wiki book locally at http://127.0.0.1:3000 + mdbook serve _context/wiki --hostname 127.0.0.1 --port 3000 --open + +# --------------------------------------------------------------------------- +# Rust format & lint +# --------------------------------------------------------------------------- + +fmt: ## Format Rust code with rustfmt (modifies files) + cargo fmt --all + +fmt-check: ## Check Rust formatting without modifying files + cargo fmt --all --check + +lint: ## Lint Rust code with clippy (warnings → errors) + cargo clippy --locked --workspace --all-targets -- -D warnings + +deny: ## Run cargo-deny supply-chain checks (advisories + licenses) + cargo deny check advisories licenses + +# --------------------------------------------------------------------------- +# pre-commit +# --------------------------------------------------------------------------- + +install-pre-commit-hooks: ## Install pre-commit git hooks into .git/hooks + @if ! command -v pre-commit >/dev/null 2>&1; then \ + echo "pre-commit not found. Install it with one of:"; \ + echo " uv tool install pre-commit"; \ + echo " brew install pre-commit"; \ + exit 1; \ + fi + pre-commit install + @echo "✅ pre-commit hooks installed" + +pre-commit: ## Run all pre-commit hooks against every file + @if ! command -v pre-commit >/dev/null 2>&1; then \ + echo "pre-commit not found. Install it with one of:"; \ + echo " uv tool install pre-commit"; \ + echo " brew install pre-commit"; \ + exit 1; \ + fi + @mkdir -p .cache/pre-commit-home .cache/tmp + PRE_COMMIT_HOME='$(CURDIR)/.cache/pre-commit-home' \ + TMPDIR='$(CURDIR)/.cache/tmp' \ + pre-commit run --config .pre-commit-config.yaml --all-files --show-diff-on-failure + +# --------------------------------------------------------------------------- +# Secret scanning (IBM detect-secrets hardened fork) +# --------------------------------------------------------------------------- + +secrets-scan: ## Scan changed files and update .secrets.baseline in place + @if ! command -v detect-secrets >/dev/null 2>&1 && ! command -v uv >/dev/null 2>&1; then \ + echo "detect-secrets not found. Install it with:"; \ + echo " uv tool install '$(DETECT_SECRETS_SPEC)'"; \ + exit 1; \ + fi + @if command -v detect-secrets >/dev/null 2>&1; then \ + detect-secrets scan --update .secrets.baseline --use-all-plugins \ + --exclude-files $(DETECT_SECRETS_EXCLUDE); \ + else \ + uv tool run --from '$(DETECT_SECRETS_SPEC)' detect-secrets scan \ + --update .secrets.baseline --use-all-plugins \ + --exclude-files $(DETECT_SECRETS_EXCLUDE); \ + fi + @echo "📊 Findings report:" + @if command -v detect-secrets >/dev/null 2>&1; then \ + detect-secrets audit --report .secrets.baseline; \ + else \ + uv tool run --from '$(DETECT_SECRETS_SPEC)' detect-secrets audit --report .secrets.baseline; \ + fi + +secrets-scan-all: ## Full-tree scan — regenerate .secrets.baseline from scratch + @if ! command -v detect-secrets >/dev/null 2>&1 && ! command -v uv >/dev/null 2>&1; then \ + echo "detect-secrets not found. Install it with:"; \ + echo " uv tool install '$(DETECT_SECRETS_SPEC)'"; \ + exit 1; \ + fi + @if command -v detect-secrets >/dev/null 2>&1; then \ + detect-secrets scan \ + --use-all-plugins \ + --exclude-files $(DETECT_SECRETS_EXCLUDE) \ + > .secrets.baseline; \ + else \ + uv tool run --from '$(DETECT_SECRETS_SPEC)' detect-secrets scan \ + --use-all-plugins \ + --exclude-files $(DETECT_SECRETS_EXCLUDE) \ + > .secrets.baseline; \ + fi + @echo "✅ .secrets.baseline regenerated — audit new findings with: make secrets-audit" + +secrets-audit: ## Interactive audit of unreviewed findings in .secrets.baseline + @if command -v detect-secrets >/dev/null 2>&1; then \ + detect-secrets audit .secrets.baseline; \ + else \ + uv tool run --from '$(DETECT_SECRETS_SPEC)' detect-secrets audit .secrets.baseline; \ + fi + +secrets-baseline: ## Alias for secrets-scan-all (initial baseline creation) + @$(MAKE) --no-print-directory secrets-scan-all + +# --------------------------------------------------------------------------- +# Git configuration +# --------------------------------------------------------------------------- + +configure-git: install-pre-commit-hooks ## Configure git hooks + merge driver for .secrets.baseline + @echo "🔀 Configuring git merge driver for .secrets.baseline..." + @common_dir=$$(git rev-parse --git-common-dir); \ + mkdir -p "$$common_dir/git-drivers"; \ + cp scripts/git/resolve-secrets-baseline-conflict.sh "$$common_dir/git-drivers/"; \ + chmod +x "$$common_dir/git-drivers/resolve-secrets-baseline-conflict.sh"; \ + git config merge.secrets-baseline.name "Regenerate .secrets.baseline via detect-secrets-scan"; \ + git config merge.secrets-baseline.driver \ + "$$common_dir/git-drivers/resolve-secrets-baseline-conflict.sh %O %A %B %P" + @echo "✅ Git merge driver configured for .secrets.baseline" +>>>>>>> 7aaeb99 (feat:added make pre-commit) diff --git a/assets/contextforgeCA/contextforge.intermediate.ca-chain.cert.pem b/assets/contextforgeCA/contextforge.intermediate.ca-chain.cert.pem index 500c32b9..ec2af56f 100644 --- a/assets/contextforgeCA/contextforge.intermediate.ca-chain.cert.pem +++ b/assets/contextforgeCA/contextforge.intermediate.ca-chain.cert.pem @@ -65,4 +65,3 @@ FUBoyJBRzE9DKZ/PLrqKQcXCTzYOJjToxLiwCzBZLyQD8dPoIrkT9avWfX6/rFKs 3gD9U4UCBXdJdE2qnKCE1Sj86Cr2/rHf742gEMqraOHko8zzQ1YaBUObNNdqs0U0 7Be9DRVVNItXDV0SuCuZdCw6YCZtoI8+0l/NWpg61i0= -----END CERTIFICATE----- - diff --git a/assets/tls_certificate.pem b/assets/tls_certificate.pem index fc236a02..a4c99947 100644 --- a/assets/tls_certificate.pem +++ b/assets/tls_certificate.pem @@ -14,4 +14,4 @@ y+CPxfq7Xl2uq6RqUFFnaVDZUmZGt0EofHvzpQKU29vGOjKoalIujoOj0sVyH7qK k26z9teDlU/wHHOElLHZaGwRPv7M5pWo5x2y5EnfTxwpi5Ic5mu0gaE3Xa6qlcu5 WcFVEd8NVFDYfxN1A52JRjyfpYrjcaPCOAzFrJERGMPtHSkyfd0djihvW75cpf64 CWeNQYqqf13rr1sg727cTXd65BRkhKFSb7A8QNf2e1m2vips2Q== ------END CERTIFICATE----- \ No newline at end of file +-----END CERTIFICATE----- diff --git a/docker/docker-compose-local.yaml b/docker/docker-compose-local.yaml index a8b60ded..00243505 100644 --- a/docker/docker-compose-local.yaml +++ b/docker/docker-compose-local.yaml @@ -1,6 +1,6 @@ #version: "3.9" # Supported by both podman-compose and Docker Compose v2+ name: contextforge-data-plane-local - + networks: contextforge-data-plane-net: # Single user-defined bridge network keeps traffic private @@ -22,7 +22,7 @@ services: - RUST_LOG=warn - MCP_SERVER_BIND_ADDRESS=0.0.0.0:5555 - MCP_SERVER_ALLOWED_HOSTS=127.0.0.1,9.85.219.104,192.168.1.14 - + sysctls: - net.ipv4.tcp_fin_timeout=15 - net.ipv4.ip_local_port_range=1024 65535 @@ -35,7 +35,7 @@ services: redis: condition: service_started - deploy: + deploy: resources: limits: cpus: '${GATEWAY_CPU_LIMIT:-8}' @@ -54,7 +54,7 @@ services: environment: - RUST_LOG=warn - PORT=5556 - + sysctls: - net.ipv4.tcp_fin_timeout=15 - net.ipv4.ip_local_port_range=1024 65535 @@ -67,17 +67,17 @@ services: redis: condition: service_started - deploy: + deploy: resources: limits: cpus: '${GATEWAY_CPU_LIMIT:-8}' memory: ${GATEWAY_MEM_LIMIT:-8G} reservations: cpus: '${GATEWAY_CPU_RESERVATION:-4}' - memory: ${GATEWAY_MEM_RESERVATION:-4G} + memory: ${GATEWAY_MEM_RESERVATION:-4G} + - @@ -120,9 +120,9 @@ services: ports: - "6379:6379" # expose only if you want host access - "16379:16379" # expose only if you want host access - volumes: + volumes: - ../assets/contextforgeCA/:/tls_config:z - + networks: [contextforge-data-plane-net] deploy: @@ -133,4 +133,3 @@ services: reservations: cpus: '1' memory: 1G - diff --git a/docker/mcp_conformance.Dockerfile b/docker/mcp_conformance.Dockerfile index a53d268c..ed28c4ca 100644 --- a/docker/mcp_conformance.Dockerfile +++ b/docker/mcp_conformance.Dockerfile @@ -8,7 +8,7 @@ git config --global http.sslVerify false git clone https://github.com/contextforge-gateway-rs/mcp-rust-sdk.git rust-sdk EOF WORKDIR /tmp/rust-sdk -RUN git checkout enabling_propagation_of_new_session_id_2 +RUN git checkout enabling_propagation_of_new_session_id_2 WORKDIR /tmp/rust-sdk/conformance RUN \ diff --git a/docker/mcp_counter.Dockerfile b/docker/mcp_counter.Dockerfile index f5f9af6e..d90d7acc 100644 --- a/docker/mcp_counter.Dockerfile +++ b/docker/mcp_counter.Dockerfile @@ -8,7 +8,7 @@ git config --global http.sslVerify false git clone https://github.com/contextforge-gateway-rs/mcp-rust-sdk.git rust-sdk EOF WORKDIR /tmp/rust-sdk -RUN git checkout enabling_propagation_of_new_session_id_2 +RUN git checkout enabling_propagation_of_new_session_id_2 WORKDIR /tmp/rust-sdk/examples/servers RUN \ diff --git a/reports/cf-gateway-performance-report-2026-05-01.html b/reports/cf-gateway-performance-report-2026-05-01.html index 55589b5c..b7506749 100644 --- a/reports/cf-gateway-performance-report-2026-05-01.html +++ b/reports/cf-gateway-performance-report-2026-05-01.html @@ -235,7 +235,7 @@

Request Metrics

sampling: 'lttb', data: [["2026-05-01 11:14:35",1]], }, - + ] }); @@ -324,7 +324,7 @@

Request Metrics

- +

Response Time Metrics

@@ -468,7 +468,7 @@

Response Time Metrics

sampling: 'lttb', data: [["2026-05-01 11:14:35",11.0]], }, - + ] }); @@ -542,7 +542,7 @@

Response Time Metrics

- +

Status Code Metrics

@@ -628,7 +628,7 @@

Transaction Metrics

nameGap: 45, type: 'value' }, - + series: [ { name: 'Total', @@ -696,7 +696,7 @@

Transaction Metrics

}, data: [["2026-05-01 11:14:34",76],["2026-05-01 11:14:35",275],["2026-05-01 11:14:36",273],["2026-05-01 11:14:37",272],["2026-05-01 11:14:38",267],["2026-05-01 11:14:39",269],["2026-05-01 11:14:40",267],["2026-05-01 11:14:41",264],["2026-05-01 11:14:42",252],["2026-05-01 11:14:43",244],["2026-05-01 11:14:44",240],["2026-05-01 11:14:45",241],["2026-05-01 11:14:46",231],["2026-05-01 11:14:47",195],["2026-05-01 11:14:48",196],["2026-05-01 11:14:49",230],["2026-05-01 11:14:50",239],["2026-05-01 11:14:51",240],["2026-05-01 11:14:52",239],["2026-05-01 11:14:53",212],["2026-05-01 11:14:54",171],["2026-05-01 11:14:55",240],["2026-05-01 11:14:56",238],["2026-05-01 11:14:57",238],["2026-05-01 11:14:58",157],["2026-05-01 11:14:59",208],["2026-05-01 11:15:00",240],["2026-05-01 11:15:01",240],["2026-05-01 11:15:02",227],["2026-05-01 11:15:03",144],["2026-05-01 11:15:04",239],["2026-05-01 11:15:05",176],["2026-05-01 11:15:06",190],["2026-05-01 11:15:07",235],["2026-05-01 11:15:08",153],["2026-05-01 11:15:09",233],["2026-05-01 11:15:10",236],["2026-05-01 11:15:11",152],["2026-05-01 11:15:12",222],["2026-05-01 11:15:13",236],["2026-05-01 11:15:14",179],["2026-05-01 11:15:15",201],["2026-05-01 11:15:16",231],["2026-05-01 11:15:17",179],["2026-05-01 11:15:18",227],["2026-05-01 11:15:19",210],["2026-05-01 11:15:20",187],["2026-05-01 11:15:21",226],["2026-05-01 11:15:22",236],["2026-05-01 11:15:23",198],["2026-05-01 11:15:24",176],["2026-05-01 11:15:25",238],["2026-05-01 11:15:26",173],["2026-05-01 11:15:27",195],["2026-05-01 11:15:28",235],["2026-05-01 11:15:29",191],["2026-05-01 11:15:30",210],["2026-05-01 11:15:31",220],["2026-05-01 11:15:32",160],["2026-05-01 11:15:33",229],["2026-05-01 11:15:34",234],["2026-05-01 11:15:35",164],["2026-05-01 11:15:36",218],["2026-05-01 11:15:37",245],["2026-05-01 11:15:38",237],["2026-05-01 11:15:39",238],["2026-05-01 11:15:40",190],["2026-05-01 11:15:41",230],["2026-05-01 11:15:42",236],["2026-05-01 11:15:43",239],["2026-05-01 11:15:44",238],["2026-05-01 11:15:45",240],["2026-05-01 11:15:46",193],["2026-05-01 11:15:47",192],["2026-05-01 11:15:48",236],["2026-05-01 11:15:49",239],["2026-05-01 11:15:50",236],["2026-05-01 11:15:51",136],["2026-05-01 11:15:52",236],["2026-05-01 11:15:53",239],["2026-05-01 11:15:54",239],["2026-05-01 11:15:55",125],["2026-05-01 11:15:56",238],["2026-05-01 11:15:57",240],["2026-05-01 11:15:58",240],["2026-05-01 11:15:59",152],["2026-05-01 11:16:00",213],["2026-05-01 11:16:01",240],["2026-05-01 11:16:02",239],["2026-05-01 11:16:03",195],["2026-05-01 11:16:04",173],["2026-05-01 11:16:05",239],["2026-05-01 11:16:06",240],["2026-05-01 11:16:07",230],["2026-05-01 11:16:08",138],["2026-05-01 11:16:09",238],["2026-05-01 11:16:10",216],["2026-05-01 11:16:11",152],["2026-05-01 11:16:12",235],["2026-05-01 11:16:13",178],["2026-05-01 11:16:14",216],["2026-05-01 11:16:15",213],["2026-05-01 11:16:16",163],["2026-05-01 11:16:17",209],["2026-05-01 11:16:18",168],["2026-05-01 11:16:19",227],["2026-05-01 11:16:20",214],["2026-05-01 11:16:21",172],["2026-05-01 11:16:22",228],["2026-05-01 11:16:23",230],["2026-05-01 11:16:24",139],["2026-05-01 11:16:25",152],["2026-05-01 11:16:26",206],["2026-05-01 11:16:27",151],["2026-05-01 11:16:28",145],["2026-05-01 11:16:29",215],["2026-05-01 11:16:30",140],["2026-05-01 11:16:31",185],["2026-05-01 11:16:32",167],["2026-05-01 11:16:33",141],["2026-05-01 11:16:34",228],["2026-05-01 11:16:35",137],["2026-05-01 11:16:36",186],["2026-05-01 11:16:37",171],["2026-05-01 11:16:38",204],["2026-05-01 11:16:39",175],["2026-05-01 11:16:40",135],["2026-05-01 11:16:41",225],["2026-05-01 11:16:42",131],["2026-05-01 11:16:43",236],["2026-05-01 11:16:44",237],["2026-05-01 11:16:45",130],["2026-05-01 11:16:46",237],["2026-05-01 11:16:47",156],["2026-05-01 11:16:48",209],["2026-05-01 11:16:49",238],["2026-05-01 11:16:50",167],["2026-05-01 11:16:51",214],["2026-05-01 11:16:52",238],["2026-05-01 11:16:53",148],["2026-05-01 11:16:54",215],["2026-05-01 11:16:55",239],["2026-05-01 11:16:56",121],["2026-05-01 11:16:57",240],["2026-05-01 11:16:58",159],["2026-05-01 11:16:59",204],["2026-05-01 11:17:00",237],["2026-05-01 11:17:01",134],["2026-05-01 11:17:02",232],["2026-05-01 11:17:03",239],["2026-05-01 11:17:04",121],["2026-05-01 11:17:05",240],["2026-05-01 11:17:06",229],["2026-05-01 11:17:07",131],["2026-05-01 11:17:08",240],["2026-05-01 11:17:09",133],["2026-05-01 11:17:10",227],["2026-05-01 11:17:11",240],["2026-05-01 11:17:12",125],["2026-05-01 11:17:13",237],["2026-05-01 11:17:14",239],["2026-05-01 11:17:15",124],["2026-05-01 11:17:16",238],["2026-05-01 11:17:17",132],["2026-05-01 11:17:18",229],["2026-05-01 11:17:19",125],["2026-05-01 11:17:20",218],["2026-05-01 11:17:21",149],["2026-05-01 11:17:22",225],["2026-05-01 11:17:23",155],["2026-05-01 11:17:24",196],["2026-05-01 11:17:25",163],["2026-05-01 11:17:26",138],["2026-05-01 11:17:27",225],["2026-05-01 11:17:28",136],["2026-05-01 11:17:29",226],["2026-05-01 11:17:30",135],["2026-05-01 11:17:31",147],["2026-05-01 11:17:32",216],["2026-05-01 11:17:33",148],["2026-05-01 11:17:34",215],["2026-05-01 11:17:35",165],["2026-05-01 11:17:36",214],["2026-05-01 11:17:37",163],["2026-05-01 11:17:38",213],["2026-05-01 11:17:39",166],["2026-05-01 11:17:40",214],["2026-05-01 11:17:41",151],["2026-05-01 11:17:42",216],["2026-05-01 11:17:43",143],["2026-05-01 11:17:44",232],["2026-05-01 11:17:45",142],["2026-05-01 11:17:46",223],["2026-05-01 11:17:47",142],["2026-05-01 11:17:48",224],["2026-05-01 11:17:49",232],["2026-05-01 11:17:50",155],["2026-05-01 11:17:51",232],["2026-05-01 11:17:52",230],["2026-05-01 11:17:53",150],["2026-05-01 11:17:54",229],["2026-05-01 11:17:55",226],["2026-05-01 11:17:56",150],["2026-05-01 11:17:57",232],["2026-05-01 11:17:58",200],["2026-05-01 11:17:59",168],["2026-05-01 11:18:00",240],["2026-05-01 11:18:01",124],["2026-05-01 11:18:02",238],["2026-05-01 11:18:03",240],["2026-05-01 11:18:04",124],["2026-05-01 11:18:05",238],["2026-05-01 11:18:06",213],["2026-05-01 11:18:07",151],["2026-05-01 11:18:08",239],["2026-05-01 11:18:09",144],["2026-05-01 11:18:10",217],["2026-05-01 11:18:11",240],["2026-05-01 11:18:12",123],["2026-05-01 11:18:13",238],["2026-05-01 11:18:14",240],["2026-05-01 11:18:15",127],["2026-05-01 11:18:16",236],["2026-05-01 11:18:17",237],["2026-05-01 11:18:18",127],["2026-05-01 11:18:19",238],["2026-05-01 11:18:20",225],["2026-05-01 11:18:21",139],["2026-05-01 11:18:22",199],["2026-05-01 11:18:23",163],["2026-05-01 11:18:24",151],["2026-05-01 11:18:25",209],["2026-05-01 11:18:26",148],["2026-05-01 11:18:27",217],["2026-05-01 11:18:28",149],["2026-05-01 11:18:29",218],["2026-05-01 11:18:30",149],["2026-05-01 11:18:31",226],["2026-05-01 11:18:32",142],["2026-05-01 11:18:33",214],["2026-05-01 11:18:34",149],["2026-05-01 11:18:35",165],["2026-05-01 11:18:36",198],["2026-05-01 11:18:37",144],["2026-05-01 11:18:38",224],["2026-05-01 11:18:39",138],["2026-05-01 11:18:40",227],["2026-05-01 11:18:41",167],["2026-05-01 11:18:42",210],["2026-05-01 11:18:43",167],["2026-05-01 11:18:44",205],["2026-05-01 11:18:45",233],["2026-05-01 11:18:46",153],["2026-05-01 11:18:47",220],["2026-05-01 11:18:48",144],["2026-05-01 11:18:49",231],["2026-05-01 11:18:50",133],["2026-05-01 11:18:51",236],["2026-05-01 11:18:52",125],["2026-05-01 11:18:53",239],["2026-05-01 11:18:54",141],["2026-05-01 11:18:55",226],["2026-05-01 11:18:56",236],["2026-05-01 11:18:57",134],["2026-05-01 11:18:58",239],["2026-05-01 11:18:59",170],["2026-05-01 11:19:00",192],["2026-05-01 11:19:01",239],["2026-05-01 11:19:02",131],["2026-05-01 11:19:03",232],["2026-05-01 11:19:04",237],["2026-05-01 11:19:05",124],["2026-05-01 11:19:06",239],["2026-05-01 11:19:07",235],["2026-05-01 11:19:08",138],["2026-05-01 11:19:09",229],["2026-05-01 11:19:10",190],["2026-05-01 11:19:11",186],["2026-05-01 11:19:12",235],["2026-05-01 11:19:13",182],["2026-05-01 11:19:14",186],["2026-05-01 11:19:15",238],["2026-05-01 11:19:16",150],["2026-05-01 11:19:17",212],["2026-05-01 11:19:18",240],["2026-05-01 11:19:19",127],["2026-05-01 11:19:20",238],["2026-05-01 11:19:21",235],["2026-05-01 11:19:22",128],["2026-05-01 11:19:23",239],["2026-05-01 11:19:24",234],["2026-05-01 11:19:25",129],["2026-05-01 11:19:26",237],["2026-05-01 11:19:27",123],["2026-05-01 11:19:28",208],["2026-05-01 11:19:29",152],["2026-05-01 11:19:30",174],["2026-05-01 11:19:31",192],["2026-05-01 11:19:32",152],["2026-05-01 11:19:33",209],["2026-05-01 11:19:34",151],["2026-05-01 11:19:35",221],["2026-05-01 11:19:36",148],["2026-05-01 11:19:37",229],["2026-05-01 11:19:38",139],["2026-05-01 11:19:39",188],["2026-05-01 11:19:40",181],["2026-05-01 11:19:41",167],["2026-05-01 11:19:42",199],["2026-05-01 11:19:43",205],["2026-05-01 11:19:44",165],["2026-05-01 11:19:45",141],["2026-05-01 11:19:46",220],["2026-05-01 11:19:47",131],["2026-05-01 11:19:48",230],["2026-05-01 11:19:49",136],["2026-05-01 11:19:50",227],["2026-05-01 11:19:51",175],["2026-05-01 11:19:52",198],["2026-05-01 11:19:53",167],["2026-05-01 11:19:54",205],["2026-05-01 11:19:55",221],["2026-05-01 11:19:56",167],["2026-05-01 11:19:57",177],["2026-05-01 11:19:58",186],["2026-05-01 11:19:59",238],["2026-05-01 11:20:00",165],["2026-05-01 11:20:01",209],["2026-05-01 11:20:02",222],["2026-05-01 11:20:03",185],["2026-05-01 11:20:04",203],["2026-05-01 11:20:05",231],["2026-05-01 11:20:06",173],["2026-05-01 11:20:07",218],["2026-05-01 11:20:08",219],["2026-05-01 11:20:09",164],["2026-05-01 11:20:10",214],["2026-05-01 11:20:11",195],["2026-05-01 11:20:12",197],["2026-05-01 11:20:13",235],["2026-05-01 11:20:14",192],["2026-05-01 11:20:15",195],["2026-05-01 11:20:16",229],["2026-05-01 11:20:17",207],["2026-05-01 11:20:18",172],["2026-05-01 11:20:19",229],["2026-05-01 11:20:20",166],["2026-05-01 11:20:21",206],["2026-05-01 11:20:22",239],["2026-05-01 11:20:23",127],["2026-05-01 11:20:24",235],["2026-05-01 11:20:25",239],["2026-05-01 11:20:26",131],["2026-05-01 11:20:27",236],["2026-05-01 11:20:28",187],["2026-05-01 11:20:29",177],["2026-05-01 11:20:30",240],["2026-05-01 11:20:31",122],["2026-05-01 11:20:32",205],["2026-05-01 11:20:33",155],["2026-05-01 11:20:34",155],["2026-05-01 11:20:35",211],["2026-05-01 11:20:36",153],["2026-05-01 11:20:37",220],["2026-05-01 11:20:38",154],["2026-05-01 11:20:39",208],["2026-05-01 11:20:40",166],["2026-05-01 11:20:41",203],["2026-05-01 11:20:42",164],["2026-05-01 11:20:43",210],["2026-05-01 11:20:44",163],["2026-05-01 11:20:45",225],["2026-05-01 11:20:46",144],["2026-05-01 11:20:47",201],["2026-05-01 11:20:48",180],["2026-05-01 11:20:49",204],["2026-05-01 11:20:50",160],["2026-05-01 11:20:51",182],["2026-05-01 11:20:52",186],["2026-05-01 11:20:53",229],["2026-05-01 11:20:54",132],["2026-05-01 11:20:55",159],["2026-05-01 11:20:56",208],["2026-05-01 11:20:57",207],["2026-05-01 11:20:58",160],["2026-05-01 11:20:59",203],["2026-05-01 11:21:00",188],["2026-05-01 11:21:01",219],["2026-05-01 11:21:02",147],["2026-05-01 11:21:03",222],["2026-05-01 11:21:04",162],["2026-05-01 11:21:05",219],["2026-05-01 11:21:06",238],["2026-05-01 11:21:07",142],["2026-05-01 11:21:08",223],["2026-05-01 11:21:09",164],["2026-05-01 11:21:10",215],["2026-05-01 11:21:11",235],["2026-05-01 11:21:12",131],["2026-05-01 11:21:13",235],["2026-05-01 11:21:14",240],["2026-05-01 11:21:15",137],["2026-05-01 11:21:16",235],["2026-05-01 11:21:17",234],["2026-05-01 11:21:18",161],["2026-05-01 11:21:19",220],["2026-05-01 11:21:20",230],["2026-05-01 11:21:21",224],["2026-05-01 11:21:22",183],["2026-05-01 11:21:23",230],["2026-05-01 11:21:24",221],["2026-05-01 11:21:25",149],["2026-05-01 11:21:26",240],["2026-05-01 11:21:27",177],["2026-05-01 11:21:28",184],["2026-05-01 11:21:29",239],["2026-05-01 11:21:30",124],["2026-05-01 11:21:31",238],["2026-05-01 11:21:32",223],["2026-05-01 11:21:33",138],["2026-05-01 11:21:34",239],["2026-05-01 11:21:35",148],["2026-05-01 11:21:36",213],["2026-05-01 11:21:37",121],["2026-05-01 11:21:38",239],["2026-05-01 11:21:39",128],["2026-05-01 11:21:40",212],["2026-05-01 11:21:41",150],["2026-05-01 11:21:42",179],["2026-05-01 11:21:43",204],["2026-05-01 11:21:44",187],["2026-05-01 11:21:45",199],["2026-05-01 11:21:46",206],["2026-05-01 11:21:47",157],["2026-05-01 11:21:48",152],["2026-05-01 11:21:49",213],["2026-05-01 11:21:50",165],["2026-05-01 11:21:51",200],["2026-05-01 11:21:52",175],["2026-05-01 11:21:53",197],["2026-05-01 11:21:54",223],["2026-05-01 11:21:55",151],["2026-05-01 11:21:56",151],["2026-05-01 11:21:57",220],["2026-05-01 11:21:58",206],["2026-05-01 11:21:59",158],["2026-05-01 11:22:00",141],["2026-05-01 11:22:01",224],["2026-05-01 11:22:02",200],["2026-05-01 11:22:03",166],["2026-05-01 11:22:04",159],["2026-05-01 11:22:05",218],["2026-05-01 11:22:06",219],["2026-05-01 11:22:07",142],["2026-05-01 11:22:08",144],["2026-05-01 11:22:09",219],["2026-05-01 11:22:10",225],["2026-05-01 11:22:11",150],["2026-05-01 11:22:12",230],["2026-05-01 11:22:13",155],["2026-05-01 11:22:14",219],["2026-05-01 11:22:15",233],["2026-05-01 11:22:16",130],["2026-05-01 11:22:17",237],["2026-05-01 11:22:18",125],["2026-05-01 11:22:19",238],["2026-05-01 11:22:20",239],["2026-05-01 11:22:21",124],["2026-05-01 11:22:22",239],["2026-05-01 11:22:23",183],["2026-05-01 11:22:24",180],["2026-05-01 11:22:25",238],["2026-05-01 11:22:26",123],["2026-05-01 11:22:27",239],["2026-05-01 11:22:28",239],["2026-05-01 11:22:29",129],["2026-05-01 11:22:30",237],["2026-05-01 11:22:31",236],["2026-05-01 11:22:32",128],["2026-05-01 11:22:33",239],["2026-05-01 11:22:34",234],["2026-05-01 11:22:35",138],["2026-05-01 11:22:36",231],["2026-05-01 11:22:37",223],["2026-05-01 11:22:38",151],["2026-05-01 11:22:39",235],["2026-05-01 11:22:40",126],["2026-05-01 11:22:41",239],["2026-05-01 11:22:42",137],["2026-05-01 11:22:43",224],["2026-05-01 11:22:44",155],["2026-05-01 11:22:45",207],["2026-05-01 11:22:46",164],["2026-05-01 11:22:47",223],["2026-05-01 11:22:48",138],["2026-05-01 11:22:49",229],["2026-05-01 11:22:50",133],["2026-05-01 11:22:51",238],["2026-05-01 11:22:52",129],["2026-05-01 11:22:53",220],["2026-05-01 11:22:54",151],["2026-05-01 11:22:55",227],["2026-05-01 11:22:56",148],["2026-05-01 11:22:57",200],["2026-05-01 11:22:58",163],["2026-05-01 11:22:59",198],["2026-05-01 11:23:00",162],["2026-05-01 11:23:01",172],["2026-05-01 11:23:02",190],["2026-05-01 11:23:03",240],["2026-05-01 11:23:04",226],["2026-05-01 11:23:05",173],["2026-05-01 11:23:06",216],["2026-05-01 11:23:07",239],["2026-05-01 11:23:08",191],["2026-05-01 11:23:09",207],["2026-05-01 11:23:10",231],["2026-05-01 11:23:11",159],["2026-05-01 11:23:12",221],["2026-05-01 11:23:13",233],["2026-05-01 11:23:14",174],["2026-05-01 11:23:15",235],["2026-05-01 11:23:16",239],["2026-05-01 11:23:17",238],["2026-05-01 11:23:18",225],["2026-05-01 11:23:19",155],["2026-05-01 11:23:20",235],["2026-05-01 11:23:21",240],["2026-05-01 11:23:22",239],["2026-05-01 11:23:23",155],["2026-05-01 11:23:24",222],["2026-05-01 11:23:25",232],["2026-05-01 11:23:26",238],["2026-05-01 11:23:27",228],["2026-05-01 11:23:28",196],["2026-05-01 11:23:29",209],["2026-05-01 11:23:30",234],["2026-05-01 11:23:31",236],["2026-05-01 11:23:32",212],["2026-05-01 11:23:33",171],["2026-05-01 11:23:34",238],["2026-05-01 11:23:35",234],["2026-05-01 11:23:36",239],["2026-05-01 11:23:37",190],["2026-05-01 11:23:38",186],["2026-05-01 11:23:39",238],["2026-05-01 11:23:40",240],["2026-05-01 11:23:41",175],["2026-05-01 11:23:42",192],["2026-05-01 11:23:43",240],["2026-05-01 11:23:44",215],["2026-05-01 11:23:45",150],["2026-05-01 11:23:46",236],["2026-05-01 11:23:47",157],["2026-05-01 11:23:48",234],["2026-05-01 11:23:49",226],["2026-05-01 11:23:50",151],["2026-05-01 11:23:51",228],["2026-05-01 11:23:52",237],["2026-05-01 11:23:53",143],["2026-05-01 11:23:54",225],["2026-05-01 11:23:55",213],["2026-05-01 11:23:56",189],["2026-05-01 11:23:57",235],["2026-05-01 11:23:58",227],["2026-05-01 11:23:59",166],["2026-05-01 11:24:00",235],["2026-05-01 11:24:01",230],["2026-05-01 11:24:02",181],["2026-05-01 11:24:03",212],["2026-05-01 11:24:04",232],["2026-05-01 11:24:05",161],["2026-05-01 11:24:06",214],["2026-05-01 11:24:07",234],["2026-05-01 11:24:08",190],["2026-05-01 11:24:09",221],["2026-05-01 11:24:10",211],["2026-05-01 11:24:11",184],["2026-05-01 11:24:12",193],["2026-05-01 11:24:13",223],["2026-05-01 11:24:14",160],["2026-05-01 11:24:15",144],["2026-05-01 11:24:16",213],["2026-05-01 11:24:17",183],["2026-05-01 11:24:18",192],["2026-05-01 11:24:19",141],["2026-05-01 11:24:20",221],["2026-05-01 11:24:21",173],["2026-05-01 11:24:22",211],["2026-05-01 11:24:23",222],["2026-05-01 11:24:24",142],["2026-05-01 11:24:25",230],["2026-05-01 11:24:26",132],["2026-05-01 11:24:27",238],["2026-05-01 11:24:28",204],["2026-05-01 11:24:29",161],["2026-05-01 11:24:30",237],["2026-05-01 11:24:31",128],["2026-05-01 11:24:32",237],["2026-05-01 11:24:33",157],["2026-05-01 11:24:34",204],["2026-05-01 11:24:35",119]], }, - + ] }); @@ -802,7 +802,7 @@

Scenario Metrics

nameGap: 45, type: 'value' }, - + series: [ { name: 'Total', @@ -870,7 +870,7 @@

Scenario Metrics

}, data: [["2026-05-01 11:14:35",230],["2026-05-01 11:14:36",273],["2026-05-01 11:14:37",272],["2026-05-01 11:14:38",267],["2026-05-01 11:14:39",269],["2026-05-01 11:14:40",267],["2026-05-01 11:14:41",264],["2026-05-01 11:14:42",252],["2026-05-01 11:14:43",244],["2026-05-01 11:14:44",240],["2026-05-01 11:14:45",241],["2026-05-01 11:14:46",231],["2026-05-01 11:14:47",195],["2026-05-01 11:14:48",196],["2026-05-01 11:14:49",230],["2026-05-01 11:14:50",239],["2026-05-01 11:14:51",240],["2026-05-01 11:14:52",239],["2026-05-01 11:14:53",212],["2026-05-01 11:14:54",171],["2026-05-01 11:14:55",240],["2026-05-01 11:14:56",238],["2026-05-01 11:14:57",238],["2026-05-01 11:14:58",157],["2026-05-01 11:14:59",208],["2026-05-01 11:15:00",240],["2026-05-01 11:15:01",240],["2026-05-01 11:15:02",227],["2026-05-01 11:15:03",144],["2026-05-01 11:15:04",239],["2026-05-01 11:15:05",176],["2026-05-01 11:15:06",190],["2026-05-01 11:15:07",235],["2026-05-01 11:15:08",153],["2026-05-01 11:15:09",233],["2026-05-01 11:15:10",236],["2026-05-01 11:15:11",152],["2026-05-01 11:15:12",222],["2026-05-01 11:15:13",236],["2026-05-01 11:15:14",179],["2026-05-01 11:15:15",201],["2026-05-01 11:15:16",231],["2026-05-01 11:15:17",179],["2026-05-01 11:15:18",227],["2026-05-01 11:15:19",210],["2026-05-01 11:15:20",187],["2026-05-01 11:15:21",226],["2026-05-01 11:15:22",236],["2026-05-01 11:15:23",198],["2026-05-01 11:15:24",176],["2026-05-01 11:15:25",238],["2026-05-01 11:15:26",173],["2026-05-01 11:15:27",195],["2026-05-01 11:15:28",235],["2026-05-01 11:15:29",191],["2026-05-01 11:15:30",210],["2026-05-01 11:15:31",220],["2026-05-01 11:15:32",160],["2026-05-01 11:15:33",229],["2026-05-01 11:15:34",234],["2026-05-01 11:15:35",164],["2026-05-01 11:15:36",218],["2026-05-01 11:15:37",245],["2026-05-01 11:15:38",237],["2026-05-01 11:15:39",238],["2026-05-01 11:15:40",190],["2026-05-01 11:15:41",230],["2026-05-01 11:15:42",236],["2026-05-01 11:15:43",239],["2026-05-01 11:15:44",238],["2026-05-01 11:15:45",240],["2026-05-01 11:15:46",193],["2026-05-01 11:15:47",192],["2026-05-01 11:15:48",236],["2026-05-01 11:15:49",239],["2026-05-01 11:15:50",236],["2026-05-01 11:15:51",136],["2026-05-01 11:15:52",236],["2026-05-01 11:15:53",239],["2026-05-01 11:15:54",239],["2026-05-01 11:15:55",125],["2026-05-01 11:15:56",238],["2026-05-01 11:15:57",240],["2026-05-01 11:15:58",240],["2026-05-01 11:15:59",152],["2026-05-01 11:16:00",213],["2026-05-01 11:16:01",240],["2026-05-01 11:16:02",239],["2026-05-01 11:16:03",195],["2026-05-01 11:16:04",173],["2026-05-01 11:16:05",239],["2026-05-01 11:16:06",240],["2026-05-01 11:16:07",230],["2026-05-01 11:16:08",138],["2026-05-01 11:16:09",238],["2026-05-01 11:16:10",216],["2026-05-01 11:16:11",152],["2026-05-01 11:16:12",235],["2026-05-01 11:16:13",178],["2026-05-01 11:16:14",216],["2026-05-01 11:16:15",213],["2026-05-01 11:16:16",163],["2026-05-01 11:16:17",209],["2026-05-01 11:16:18",168],["2026-05-01 11:16:19",227],["2026-05-01 11:16:20",214],["2026-05-01 11:16:21",172],["2026-05-01 11:16:22",228],["2026-05-01 11:16:23",230],["2026-05-01 11:16:24",139],["2026-05-01 11:16:25",152],["2026-05-01 11:16:26",206],["2026-05-01 11:16:27",151],["2026-05-01 11:16:28",145],["2026-05-01 11:16:29",215],["2026-05-01 11:16:30",140],["2026-05-01 11:16:31",185],["2026-05-01 11:16:32",167],["2026-05-01 11:16:33",141],["2026-05-01 11:16:34",228],["2026-05-01 11:16:35",137],["2026-05-01 11:16:36",186],["2026-05-01 11:16:37",171],["2026-05-01 11:16:38",204],["2026-05-01 11:16:39",175],["2026-05-01 11:16:40",135],["2026-05-01 11:16:41",225],["2026-05-01 11:16:42",131],["2026-05-01 11:16:43",236],["2026-05-01 11:16:44",237],["2026-05-01 11:16:45",130],["2026-05-01 11:16:46",237],["2026-05-01 11:16:47",156],["2026-05-01 11:16:48",209],["2026-05-01 11:16:49",238],["2026-05-01 11:16:50",167],["2026-05-01 11:16:51",214],["2026-05-01 11:16:52",238],["2026-05-01 11:16:53",148],["2026-05-01 11:16:54",215],["2026-05-01 11:16:55",239],["2026-05-01 11:16:56",121],["2026-05-01 11:16:57",240],["2026-05-01 11:16:58",159],["2026-05-01 11:16:59",204],["2026-05-01 11:17:00",237],["2026-05-01 11:17:01",134],["2026-05-01 11:17:02",232],["2026-05-01 11:17:03",239],["2026-05-01 11:17:04",121],["2026-05-01 11:17:05",240],["2026-05-01 11:17:06",229],["2026-05-01 11:17:07",131],["2026-05-01 11:17:08",240],["2026-05-01 11:17:09",134],["2026-05-01 11:17:10",226],["2026-05-01 11:17:11",240],["2026-05-01 11:17:12",125],["2026-05-01 11:17:13",237],["2026-05-01 11:17:14",239],["2026-05-01 11:17:15",124],["2026-05-01 11:17:16",238],["2026-05-01 11:17:17",132],["2026-05-01 11:17:18",229],["2026-05-01 11:17:19",125],["2026-05-01 11:17:20",218],["2026-05-01 11:17:21",149],["2026-05-01 11:17:22",225],["2026-05-01 11:17:23",155],["2026-05-01 11:17:24",196],["2026-05-01 11:17:25",163],["2026-05-01 11:17:26",138],["2026-05-01 11:17:27",225],["2026-05-01 11:17:28",136],["2026-05-01 11:17:29",226],["2026-05-01 11:17:30",135],["2026-05-01 11:17:31",147],["2026-05-01 11:17:32",216],["2026-05-01 11:17:33",148],["2026-05-01 11:17:34",215],["2026-05-01 11:17:35",165],["2026-05-01 11:17:36",214],["2026-05-01 11:17:37",163],["2026-05-01 11:17:38",213],["2026-05-01 11:17:39",166],["2026-05-01 11:17:40",214],["2026-05-01 11:17:41",151],["2026-05-01 11:17:42",216],["2026-05-01 11:17:43",143],["2026-05-01 11:17:44",232],["2026-05-01 11:17:45",142],["2026-05-01 11:17:46",223],["2026-05-01 11:17:47",142],["2026-05-01 11:17:48",224],["2026-05-01 11:17:49",232],["2026-05-01 11:17:50",155],["2026-05-01 11:17:51",232],["2026-05-01 11:17:52",230],["2026-05-01 11:17:53",150],["2026-05-01 11:17:54",229],["2026-05-01 11:17:55",226],["2026-05-01 11:17:56",150],["2026-05-01 11:17:57",232],["2026-05-01 11:17:58",200],["2026-05-01 11:17:59",168],["2026-05-01 11:18:00",240],["2026-05-01 11:18:01",124],["2026-05-01 11:18:02",238],["2026-05-01 11:18:03",240],["2026-05-01 11:18:04",124],["2026-05-01 11:18:05",238],["2026-05-01 11:18:06",213],["2026-05-01 11:18:07",151],["2026-05-01 11:18:08",239],["2026-05-01 11:18:09",144],["2026-05-01 11:18:10",217],["2026-05-01 11:18:11",240],["2026-05-01 11:18:12",123],["2026-05-01 11:18:13",238],["2026-05-01 11:18:14",240],["2026-05-01 11:18:15",127],["2026-05-01 11:18:16",236],["2026-05-01 11:18:17",237],["2026-05-01 11:18:18",127],["2026-05-01 11:18:19",238],["2026-05-01 11:18:20",225],["2026-05-01 11:18:21",139],["2026-05-01 11:18:22",199],["2026-05-01 11:18:23",163],["2026-05-01 11:18:24",151],["2026-05-01 11:18:25",209],["2026-05-01 11:18:26",148],["2026-05-01 11:18:27",217],["2026-05-01 11:18:28",149],["2026-05-01 11:18:29",218],["2026-05-01 11:18:30",149],["2026-05-01 11:18:31",226],["2026-05-01 11:18:32",142],["2026-05-01 11:18:33",214],["2026-05-01 11:18:34",149],["2026-05-01 11:18:35",165],["2026-05-01 11:18:36",198],["2026-05-01 11:18:37",144],["2026-05-01 11:18:38",224],["2026-05-01 11:18:39",138],["2026-05-01 11:18:40",227],["2026-05-01 11:18:41",167],["2026-05-01 11:18:42",210],["2026-05-01 11:18:43",167],["2026-05-01 11:18:44",205],["2026-05-01 11:18:45",233],["2026-05-01 11:18:46",153],["2026-05-01 11:18:47",220],["2026-05-01 11:18:48",144],["2026-05-01 11:18:49",231],["2026-05-01 11:18:50",133],["2026-05-01 11:18:51",236],["2026-05-01 11:18:52",125],["2026-05-01 11:18:53",239],["2026-05-01 11:18:54",141],["2026-05-01 11:18:55",226],["2026-05-01 11:18:56",236],["2026-05-01 11:18:57",134],["2026-05-01 11:18:58",239],["2026-05-01 11:18:59",170],["2026-05-01 11:19:00",192],["2026-05-01 11:19:01",239],["2026-05-01 11:19:02",131],["2026-05-01 11:19:03",232],["2026-05-01 11:19:04",237],["2026-05-01 11:19:05",124],["2026-05-01 11:19:06",239],["2026-05-01 11:19:07",235],["2026-05-01 11:19:08",138],["2026-05-01 11:19:09",229],["2026-05-01 11:19:10",190],["2026-05-01 11:19:11",186],["2026-05-01 11:19:12",235],["2026-05-01 11:19:13",182],["2026-05-01 11:19:14",186],["2026-05-01 11:19:15",238],["2026-05-01 11:19:16",150],["2026-05-01 11:19:17",212],["2026-05-01 11:19:18",240],["2026-05-01 11:19:19",127],["2026-05-01 11:19:20",238],["2026-05-01 11:19:21",235],["2026-05-01 11:19:22",128],["2026-05-01 11:19:23",239],["2026-05-01 11:19:24",234],["2026-05-01 11:19:25",129],["2026-05-01 11:19:26",237],["2026-05-01 11:19:27",123],["2026-05-01 11:19:28",208],["2026-05-01 11:19:29",152],["2026-05-01 11:19:30",174],["2026-05-01 11:19:31",192],["2026-05-01 11:19:32",152],["2026-05-01 11:19:33",209],["2026-05-01 11:19:34",151],["2026-05-01 11:19:35",221],["2026-05-01 11:19:36",148],["2026-05-01 11:19:37",229],["2026-05-01 11:19:38",139],["2026-05-01 11:19:39",188],["2026-05-01 11:19:40",181],["2026-05-01 11:19:41",167],["2026-05-01 11:19:42",199],["2026-05-01 11:19:43",205],["2026-05-01 11:19:44",165],["2026-05-01 11:19:45",141],["2026-05-01 11:19:46",220],["2026-05-01 11:19:47",131],["2026-05-01 11:19:48",230],["2026-05-01 11:19:49",136],["2026-05-01 11:19:50",227],["2026-05-01 11:19:51",175],["2026-05-01 11:19:52",198],["2026-05-01 11:19:53",167],["2026-05-01 11:19:54",205],["2026-05-01 11:19:55",221],["2026-05-01 11:19:56",167],["2026-05-01 11:19:57",177],["2026-05-01 11:19:58",186],["2026-05-01 11:19:59",238],["2026-05-01 11:20:00",165],["2026-05-01 11:20:01",209],["2026-05-01 11:20:02",222],["2026-05-01 11:20:03",185],["2026-05-01 11:20:04",203],["2026-05-01 11:20:05",231],["2026-05-01 11:20:06",173],["2026-05-01 11:20:07",218],["2026-05-01 11:20:08",219],["2026-05-01 11:20:09",164],["2026-05-01 11:20:10",214],["2026-05-01 11:20:11",195],["2026-05-01 11:20:12",197],["2026-05-01 11:20:13",235],["2026-05-01 11:20:14",192],["2026-05-01 11:20:15",195],["2026-05-01 11:20:16",229],["2026-05-01 11:20:17",207],["2026-05-01 11:20:18",172],["2026-05-01 11:20:19",229],["2026-05-01 11:20:20",166],["2026-05-01 11:20:21",206],["2026-05-01 11:20:22",239],["2026-05-01 11:20:23",127],["2026-05-01 11:20:24",235],["2026-05-01 11:20:25",239],["2026-05-01 11:20:26",131],["2026-05-01 11:20:27",236],["2026-05-01 11:20:28",187],["2026-05-01 11:20:29",177],["2026-05-01 11:20:30",240],["2026-05-01 11:20:31",122],["2026-05-01 11:20:32",205],["2026-05-01 11:20:33",155],["2026-05-01 11:20:34",155],["2026-05-01 11:20:35",211],["2026-05-01 11:20:36",153],["2026-05-01 11:20:37",220],["2026-05-01 11:20:38",154],["2026-05-01 11:20:39",208],["2026-05-01 11:20:40",166],["2026-05-01 11:20:41",203],["2026-05-01 11:20:42",164],["2026-05-01 11:20:43",210],["2026-05-01 11:20:44",163],["2026-05-01 11:20:45",225],["2026-05-01 11:20:46",144],["2026-05-01 11:20:47",201],["2026-05-01 11:20:48",180],["2026-05-01 11:20:49",204],["2026-05-01 11:20:50",160],["2026-05-01 11:20:51",182],["2026-05-01 11:20:52",186],["2026-05-01 11:20:53",229],["2026-05-01 11:20:54",132],["2026-05-01 11:20:55",159],["2026-05-01 11:20:56",208],["2026-05-01 11:20:57",207],["2026-05-01 11:20:58",160],["2026-05-01 11:20:59",203],["2026-05-01 11:21:00",188],["2026-05-01 11:21:01",219],["2026-05-01 11:21:02",147],["2026-05-01 11:21:03",222],["2026-05-01 11:21:04",162],["2026-05-01 11:21:05",219],["2026-05-01 11:21:06",238],["2026-05-01 11:21:07",142],["2026-05-01 11:21:08",223],["2026-05-01 11:21:09",164],["2026-05-01 11:21:10",215],["2026-05-01 11:21:11",235],["2026-05-01 11:21:12",131],["2026-05-01 11:21:13",235],["2026-05-01 11:21:14",240],["2026-05-01 11:21:15",137],["2026-05-01 11:21:16",235],["2026-05-01 11:21:17",234],["2026-05-01 11:21:18",161],["2026-05-01 11:21:19",220],["2026-05-01 11:21:20",230],["2026-05-01 11:21:21",224],["2026-05-01 11:21:22",183],["2026-05-01 11:21:23",230],["2026-05-01 11:21:24",221],["2026-05-01 11:21:25",149],["2026-05-01 11:21:26",240],["2026-05-01 11:21:27",177],["2026-05-01 11:21:28",184],["2026-05-01 11:21:29",239],["2026-05-01 11:21:30",124],["2026-05-01 11:21:31",238],["2026-05-01 11:21:32",223],["2026-05-01 11:21:33",138],["2026-05-01 11:21:34",239],["2026-05-01 11:21:35",148],["2026-05-01 11:21:36",213],["2026-05-01 11:21:37",121],["2026-05-01 11:21:38",239],["2026-05-01 11:21:39",128],["2026-05-01 11:21:40",212],["2026-05-01 11:21:41",150],["2026-05-01 11:21:42",179],["2026-05-01 11:21:43",204],["2026-05-01 11:21:44",187],["2026-05-01 11:21:45",199],["2026-05-01 11:21:46",206],["2026-05-01 11:21:47",157],["2026-05-01 11:21:48",152],["2026-05-01 11:21:49",213],["2026-05-01 11:21:50",165],["2026-05-01 11:21:51",200],["2026-05-01 11:21:52",175],["2026-05-01 11:21:53",197],["2026-05-01 11:21:54",223],["2026-05-01 11:21:55",151],["2026-05-01 11:21:56",151],["2026-05-01 11:21:57",220],["2026-05-01 11:21:58",206],["2026-05-01 11:21:59",158],["2026-05-01 11:22:00",141],["2026-05-01 11:22:01",224],["2026-05-01 11:22:02",200],["2026-05-01 11:22:03",166],["2026-05-01 11:22:04",159],["2026-05-01 11:22:05",218],["2026-05-01 11:22:06",219],["2026-05-01 11:22:07",142],["2026-05-01 11:22:08",144],["2026-05-01 11:22:09",219],["2026-05-01 11:22:10",225],["2026-05-01 11:22:11",150],["2026-05-01 11:22:12",230],["2026-05-01 11:22:13",155],["2026-05-01 11:22:14",219],["2026-05-01 11:22:15",233],["2026-05-01 11:22:16",130],["2026-05-01 11:22:17",237],["2026-05-01 11:22:18",125],["2026-05-01 11:22:19",238],["2026-05-01 11:22:20",239],["2026-05-01 11:22:21",124],["2026-05-01 11:22:22",239],["2026-05-01 11:22:23",183],["2026-05-01 11:22:24",180],["2026-05-01 11:22:25",238],["2026-05-01 11:22:26",123],["2026-05-01 11:22:27",239],["2026-05-01 11:22:28",239],["2026-05-01 11:22:29",129],["2026-05-01 11:22:30",237],["2026-05-01 11:22:31",236],["2026-05-01 11:22:32",128],["2026-05-01 11:22:33",239],["2026-05-01 11:22:34",234],["2026-05-01 11:22:35",138],["2026-05-01 11:22:36",231],["2026-05-01 11:22:37",223],["2026-05-01 11:22:38",151],["2026-05-01 11:22:39",235],["2026-05-01 11:22:40",126],["2026-05-01 11:22:41",239],["2026-05-01 11:22:42",137],["2026-05-01 11:22:43",224],["2026-05-01 11:22:44",155],["2026-05-01 11:22:45",207],["2026-05-01 11:22:46",164],["2026-05-01 11:22:47",223],["2026-05-01 11:22:48",138],["2026-05-01 11:22:49",229],["2026-05-01 11:22:50",133],["2026-05-01 11:22:51",238],["2026-05-01 11:22:52",129],["2026-05-01 11:22:53",220],["2026-05-01 11:22:54",151],["2026-05-01 11:22:55",227],["2026-05-01 11:22:56",148],["2026-05-01 11:22:57",200],["2026-05-01 11:22:58",163],["2026-05-01 11:22:59",198],["2026-05-01 11:23:00",162],["2026-05-01 11:23:01",172],["2026-05-01 11:23:02",190],["2026-05-01 11:23:03",240],["2026-05-01 11:23:04",226],["2026-05-01 11:23:05",173],["2026-05-01 11:23:06",216],["2026-05-01 11:23:07",239],["2026-05-01 11:23:08",191],["2026-05-01 11:23:09",207],["2026-05-01 11:23:10",231],["2026-05-01 11:23:11",159],["2026-05-01 11:23:12",221],["2026-05-01 11:23:13",233],["2026-05-01 11:23:14",174],["2026-05-01 11:23:15",235],["2026-05-01 11:23:16",239],["2026-05-01 11:23:17",238],["2026-05-01 11:23:18",225],["2026-05-01 11:23:19",155],["2026-05-01 11:23:20",235],["2026-05-01 11:23:21",240],["2026-05-01 11:23:22",239],["2026-05-01 11:23:23",155],["2026-05-01 11:23:24",222],["2026-05-01 11:23:25",232],["2026-05-01 11:23:26",238],["2026-05-01 11:23:27",228],["2026-05-01 11:23:28",196],["2026-05-01 11:23:29",209],["2026-05-01 11:23:30",234],["2026-05-01 11:23:31",236],["2026-05-01 11:23:32",212],["2026-05-01 11:23:33",171],["2026-05-01 11:23:34",238],["2026-05-01 11:23:35",234],["2026-05-01 11:23:36",239],["2026-05-01 11:23:37",190],["2026-05-01 11:23:38",186],["2026-05-01 11:23:39",238],["2026-05-01 11:23:40",240],["2026-05-01 11:23:41",175],["2026-05-01 11:23:42",192],["2026-05-01 11:23:43",240],["2026-05-01 11:23:44",215],["2026-05-01 11:23:45",150],["2026-05-01 11:23:46",236],["2026-05-01 11:23:47",157],["2026-05-01 11:23:48",234],["2026-05-01 11:23:49",226],["2026-05-01 11:23:50",151],["2026-05-01 11:23:51",228],["2026-05-01 11:23:52",237],["2026-05-01 11:23:53",143],["2026-05-01 11:23:54",225],["2026-05-01 11:23:55",213],["2026-05-01 11:23:56",189],["2026-05-01 11:23:57",235],["2026-05-01 11:23:58",227],["2026-05-01 11:23:59",166],["2026-05-01 11:24:00",235],["2026-05-01 11:24:01",230],["2026-05-01 11:24:02",181],["2026-05-01 11:24:03",212],["2026-05-01 11:24:04",232],["2026-05-01 11:24:05",161],["2026-05-01 11:24:06",214],["2026-05-01 11:24:07",234],["2026-05-01 11:24:08",190],["2026-05-01 11:24:09",221],["2026-05-01 11:24:10",211],["2026-05-01 11:24:11",184],["2026-05-01 11:24:12",193],["2026-05-01 11:24:13",223],["2026-05-01 11:24:14",160],["2026-05-01 11:24:15",144],["2026-05-01 11:24:16",213],["2026-05-01 11:24:17",183],["2026-05-01 11:24:18",192],["2026-05-01 11:24:19",141],["2026-05-01 11:24:20",221],["2026-05-01 11:24:21",173],["2026-05-01 11:24:22",211],["2026-05-01 11:24:23",222],["2026-05-01 11:24:24",142],["2026-05-01 11:24:25",230],["2026-05-01 11:24:26",132],["2026-05-01 11:24:27",238],["2026-05-01 11:24:28",204],["2026-05-01 11:24:29",161],["2026-05-01 11:24:30",237],["2026-05-01 11:24:31",128],["2026-05-01 11:24:32",237],["2026-05-01 11:24:33",157],["2026-05-01 11:24:34",204],["2026-05-01 11:24:35",119]], }, - + ] }); @@ -962,7 +962,7 @@

User Metrics

nameGap: 45, type: 'value' }, - + series: [ { name: 'Total', @@ -1030,17 +1030,17 @@

User Metrics

}, data: [["2026-05-01 11:14:32",120],["2026-05-01 11:14:33",120],["2026-05-01 11:14:34",120],["2026-05-01 11:14:35",120],["2026-05-01 11:14:36",120],["2026-05-01 11:14:37",120],["2026-05-01 11:14:38",120],["2026-05-01 11:14:39",120],["2026-05-01 11:14:40",120],["2026-05-01 11:14:41",120],["2026-05-01 11:14:42",120],["2026-05-01 11:14:43",120],["2026-05-01 11:14:44",120],["2026-05-01 11:14:45",120],["2026-05-01 11:14:46",120],["2026-05-01 11:14:47",120],["2026-05-01 11:14:48",120],["2026-05-01 11:14:49",120],["2026-05-01 11:14:50",120],["2026-05-01 11:14:51",120],["2026-05-01 11:14:52",120],["2026-05-01 11:14:53",120],["2026-05-01 11:14:54",120],["2026-05-01 11:14:55",120],["2026-05-01 11:14:56",120],["2026-05-01 11:14:57",120],["2026-05-01 11:14:58",120],["2026-05-01 11:14:59",120],["2026-05-01 11:15:00",120],["2026-05-01 11:15:01",120],["2026-05-01 11:15:02",120],["2026-05-01 11:15:03",120],["2026-05-01 11:15:04",120],["2026-05-01 11:15:05",120],["2026-05-01 11:15:06",120],["2026-05-01 11:15:07",120],["2026-05-01 11:15:08",120],["2026-05-01 11:15:09",120],["2026-05-01 11:15:10",120],["2026-05-01 11:15:11",120],["2026-05-01 11:15:12",120],["2026-05-01 11:15:13",120],["2026-05-01 11:15:14",120],["2026-05-01 11:15:15",120],["2026-05-01 11:15:16",120],["2026-05-01 11:15:17",120],["2026-05-01 11:15:18",120],["2026-05-01 11:15:19",120],["2026-05-01 11:15:20",120],["2026-05-01 11:15:21",120],["2026-05-01 11:15:22",120],["2026-05-01 11:15:23",120],["2026-05-01 11:15:24",120],["2026-05-01 11:15:25",120],["2026-05-01 11:15:26",120],["2026-05-01 11:15:27",120],["2026-05-01 11:15:28",120],["2026-05-01 11:15:29",120],["2026-05-01 11:15:30",120],["2026-05-01 11:15:31",120],["2026-05-01 11:15:32",120],["2026-05-01 11:15:33",120],["2026-05-01 11:15:34",120],["2026-05-01 11:15:35",120],["2026-05-01 11:15:36",120],["2026-05-01 11:15:37",120],["2026-05-01 11:15:38",120],["2026-05-01 11:15:39",120],["2026-05-01 11:15:40",120],["2026-05-01 11:15:41",120],["2026-05-01 11:15:42",120],["2026-05-01 11:15:43",120],["2026-05-01 11:15:44",120],["2026-05-01 11:15:45",120],["2026-05-01 11:15:46",120],["2026-05-01 11:15:47",120],["2026-05-01 11:15:48",120],["2026-05-01 11:15:49",120],["2026-05-01 11:15:50",120],["2026-05-01 11:15:51",120],["2026-05-01 11:15:52",120],["2026-05-01 11:15:53",120],["2026-05-01 11:15:54",120],["2026-05-01 11:15:55",120],["2026-05-01 11:15:56",120],["2026-05-01 11:15:57",120],["2026-05-01 11:15:58",120],["2026-05-01 11:15:59",120],["2026-05-01 11:16:00",120],["2026-05-01 11:16:01",120],["2026-05-01 11:16:02",120],["2026-05-01 11:16:03",120],["2026-05-01 11:16:04",120],["2026-05-01 11:16:05",120],["2026-05-01 11:16:06",120],["2026-05-01 11:16:07",120],["2026-05-01 11:16:08",120],["2026-05-01 11:16:09",120],["2026-05-01 11:16:10",120],["2026-05-01 11:16:11",120],["2026-05-01 11:16:12",120],["2026-05-01 11:16:13",120],["2026-05-01 11:16:14",120],["2026-05-01 11:16:15",120],["2026-05-01 11:16:16",120],["2026-05-01 11:16:17",120],["2026-05-01 11:16:18",120],["2026-05-01 11:16:19",120],["2026-05-01 11:16:20",120],["2026-05-01 11:16:21",120],["2026-05-01 11:16:22",120],["2026-05-01 11:16:23",120],["2026-05-01 11:16:24",120],["2026-05-01 11:16:25",120],["2026-05-01 11:16:26",120],["2026-05-01 11:16:27",120],["2026-05-01 11:16:28",120],["2026-05-01 11:16:29",120],["2026-05-01 11:16:30",120],["2026-05-01 11:16:31",120],["2026-05-01 11:16:32",120],["2026-05-01 11:16:33",120],["2026-05-01 11:16:34",120],["2026-05-01 11:16:35",120],["2026-05-01 11:16:36",120],["2026-05-01 11:16:37",120],["2026-05-01 11:16:38",120],["2026-05-01 11:16:39",120],["2026-05-01 11:16:40",120],["2026-05-01 11:16:41",120],["2026-05-01 11:16:42",120],["2026-05-01 11:16:43",120],["2026-05-01 11:16:44",120],["2026-05-01 11:16:45",120],["2026-05-01 11:16:46",120],["2026-05-01 11:16:47",120],["2026-05-01 11:16:48",120],["2026-05-01 11:16:49",120],["2026-05-01 11:16:50",120],["2026-05-01 11:16:51",120],["2026-05-01 11:16:52",120],["2026-05-01 11:16:53",120],["2026-05-01 11:16:54",120],["2026-05-01 11:16:55",120],["2026-05-01 11:16:56",120],["2026-05-01 11:16:57",120],["2026-05-01 11:16:58",120],["2026-05-01 11:16:59",120],["2026-05-01 11:17:00",120],["2026-05-01 11:17:01",120],["2026-05-01 11:17:02",120],["2026-05-01 11:17:03",120],["2026-05-01 11:17:04",120],["2026-05-01 11:17:05",120],["2026-05-01 11:17:06",120],["2026-05-01 11:17:07",120],["2026-05-01 11:17:08",120],["2026-05-01 11:17:09",120],["2026-05-01 11:17:10",120],["2026-05-01 11:17:11",120],["2026-05-01 11:17:12",120],["2026-05-01 11:17:13",120],["2026-05-01 11:17:14",120],["2026-05-01 11:17:15",120],["2026-05-01 11:17:16",120],["2026-05-01 11:17:17",120],["2026-05-01 11:17:18",120],["2026-05-01 11:17:19",120],["2026-05-01 11:17:20",120],["2026-05-01 11:17:21",120],["2026-05-01 11:17:22",120],["2026-05-01 11:17:23",120],["2026-05-01 11:17:24",120],["2026-05-01 11:17:25",120],["2026-05-01 11:17:26",120],["2026-05-01 11:17:27",120],["2026-05-01 11:17:28",120],["2026-05-01 11:17:29",120],["2026-05-01 11:17:30",120],["2026-05-01 11:17:31",120],["2026-05-01 11:17:32",120],["2026-05-01 11:17:33",120],["2026-05-01 11:17:34",120],["2026-05-01 11:17:35",120],["2026-05-01 11:17:36",120],["2026-05-01 11:17:37",120],["2026-05-01 11:17:38",120],["2026-05-01 11:17:39",120],["2026-05-01 11:17:40",120],["2026-05-01 11:17:41",120],["2026-05-01 11:17:42",120],["2026-05-01 11:17:43",120],["2026-05-01 11:17:44",120],["2026-05-01 11:17:45",120],["2026-05-01 11:17:46",120],["2026-05-01 11:17:47",120],["2026-05-01 11:17:48",120],["2026-05-01 11:17:49",120],["2026-05-01 11:17:50",120],["2026-05-01 11:17:51",120],["2026-05-01 11:17:52",120],["2026-05-01 11:17:53",120],["2026-05-01 11:17:54",120],["2026-05-01 11:17:55",120],["2026-05-01 11:17:56",120],["2026-05-01 11:17:57",120],["2026-05-01 11:17:58",120],["2026-05-01 11:17:59",120],["2026-05-01 11:18:00",120],["2026-05-01 11:18:01",120],["2026-05-01 11:18:02",120],["2026-05-01 11:18:03",120],["2026-05-01 11:18:04",120],["2026-05-01 11:18:05",120],["2026-05-01 11:18:06",120],["2026-05-01 11:18:07",120],["2026-05-01 11:18:08",120],["2026-05-01 11:18:09",120],["2026-05-01 11:18:10",120],["2026-05-01 11:18:11",120],["2026-05-01 11:18:12",120],["2026-05-01 11:18:13",120],["2026-05-01 11:18:14",120],["2026-05-01 11:18:15",120],["2026-05-01 11:18:16",120],["2026-05-01 11:18:17",120],["2026-05-01 11:18:18",120],["2026-05-01 11:18:19",120],["2026-05-01 11:18:20",120],["2026-05-01 11:18:21",120],["2026-05-01 11:18:22",120],["2026-05-01 11:18:23",120],["2026-05-01 11:18:24",120],["2026-05-01 11:18:25",120],["2026-05-01 11:18:26",120],["2026-05-01 11:18:27",120],["2026-05-01 11:18:28",120],["2026-05-01 11:18:29",120],["2026-05-01 11:18:30",120],["2026-05-01 11:18:31",120],["2026-05-01 11:18:32",120],["2026-05-01 11:18:33",120],["2026-05-01 11:18:34",120],["2026-05-01 11:18:35",120],["2026-05-01 11:18:36",120],["2026-05-01 11:18:37",120],["2026-05-01 11:18:38",120],["2026-05-01 11:18:39",120],["2026-05-01 11:18:40",120],["2026-05-01 11:18:41",120],["2026-05-01 11:18:42",120],["2026-05-01 11:18:43",120],["2026-05-01 11:18:44",120],["2026-05-01 11:18:45",120],["2026-05-01 11:18:46",120],["2026-05-01 11:18:47",120],["2026-05-01 11:18:48",120],["2026-05-01 11:18:49",120],["2026-05-01 11:18:50",120],["2026-05-01 11:18:51",120],["2026-05-01 11:18:52",120],["2026-05-01 11:18:53",120],["2026-05-01 11:18:54",120],["2026-05-01 11:18:55",120],["2026-05-01 11:18:56",120],["2026-05-01 11:18:57",120],["2026-05-01 11:18:58",120],["2026-05-01 11:18:59",120],["2026-05-01 11:19:00",120],["2026-05-01 11:19:01",120],["2026-05-01 11:19:02",120],["2026-05-01 11:19:03",120],["2026-05-01 11:19:04",120],["2026-05-01 11:19:05",120],["2026-05-01 11:19:06",120],["2026-05-01 11:19:07",120],["2026-05-01 11:19:08",120],["2026-05-01 11:19:09",120],["2026-05-01 11:19:10",120],["2026-05-01 11:19:11",120],["2026-05-01 11:19:12",120],["2026-05-01 11:19:13",120],["2026-05-01 11:19:14",120],["2026-05-01 11:19:15",120],["2026-05-01 11:19:16",120],["2026-05-01 11:19:17",120],["2026-05-01 11:19:18",120],["2026-05-01 11:19:19",120],["2026-05-01 11:19:20",120],["2026-05-01 11:19:21",120],["2026-05-01 11:19:22",120],["2026-05-01 11:19:23",120],["2026-05-01 11:19:24",120],["2026-05-01 11:19:25",120],["2026-05-01 11:19:26",120],["2026-05-01 11:19:27",120],["2026-05-01 11:19:28",120],["2026-05-01 11:19:29",120],["2026-05-01 11:19:30",120],["2026-05-01 11:19:31",120],["2026-05-01 11:19:32",120],["2026-05-01 11:19:33",120],["2026-05-01 11:19:34",120],["2026-05-01 11:19:35",120],["2026-05-01 11:19:36",120],["2026-05-01 11:19:37",120],["2026-05-01 11:19:38",120],["2026-05-01 11:19:39",120],["2026-05-01 11:19:40",120],["2026-05-01 11:19:41",120],["2026-05-01 11:19:42",120],["2026-05-01 11:19:43",120],["2026-05-01 11:19:44",120],["2026-05-01 11:19:45",120],["2026-05-01 11:19:46",120],["2026-05-01 11:19:47",120],["2026-05-01 11:19:48",120],["2026-05-01 11:19:49",120],["2026-05-01 11:19:50",120],["2026-05-01 11:19:51",120],["2026-05-01 11:19:52",120],["2026-05-01 11:19:53",120],["2026-05-01 11:19:54",120],["2026-05-01 11:19:55",120],["2026-05-01 11:19:56",120],["2026-05-01 11:19:57",120],["2026-05-01 11:19:58",120],["2026-05-01 11:19:59",120],["2026-05-01 11:20:00",120],["2026-05-01 11:20:01",120],["2026-05-01 11:20:02",120],["2026-05-01 11:20:03",120],["2026-05-01 11:20:04",120],["2026-05-01 11:20:05",120],["2026-05-01 11:20:06",120],["2026-05-01 11:20:07",120],["2026-05-01 11:20:08",120],["2026-05-01 11:20:09",120],["2026-05-01 11:20:10",120],["2026-05-01 11:20:11",120],["2026-05-01 11:20:12",120],["2026-05-01 11:20:13",120],["2026-05-01 11:20:14",120],["2026-05-01 11:20:15",120],["2026-05-01 11:20:16",120],["2026-05-01 11:20:17",120],["2026-05-01 11:20:18",120],["2026-05-01 11:20:19",120],["2026-05-01 11:20:20",120],["2026-05-01 11:20:21",120],["2026-05-01 11:20:22",120],["2026-05-01 11:20:23",120],["2026-05-01 11:20:24",120],["2026-05-01 11:20:25",120],["2026-05-01 11:20:26",120],["2026-05-01 11:20:27",120],["2026-05-01 11:20:28",120],["2026-05-01 11:20:29",120],["2026-05-01 11:20:30",120],["2026-05-01 11:20:31",120],["2026-05-01 11:20:32",120],["2026-05-01 11:20:33",120],["2026-05-01 11:20:34",120],["2026-05-01 11:20:35",120],["2026-05-01 11:20:36",120],["2026-05-01 11:20:37",120],["2026-05-01 11:20:38",120],["2026-05-01 11:20:39",120],["2026-05-01 11:20:40",120],["2026-05-01 11:20:41",120],["2026-05-01 11:20:42",120],["2026-05-01 11:20:43",120],["2026-05-01 11:20:44",120],["2026-05-01 11:20:45",120],["2026-05-01 11:20:46",120],["2026-05-01 11:20:47",120],["2026-05-01 11:20:48",120],["2026-05-01 11:20:49",120],["2026-05-01 11:20:50",120],["2026-05-01 11:20:51",120],["2026-05-01 11:20:52",120],["2026-05-01 11:20:53",120],["2026-05-01 11:20:54",120],["2026-05-01 11:20:55",120],["2026-05-01 11:20:56",120],["2026-05-01 11:20:57",120],["2026-05-01 11:20:58",120],["2026-05-01 11:20:59",120],["2026-05-01 11:21:00",120],["2026-05-01 11:21:01",120],["2026-05-01 11:21:02",120],["2026-05-01 11:21:03",120],["2026-05-01 11:21:04",120],["2026-05-01 11:21:05",120],["2026-05-01 11:21:06",120],["2026-05-01 11:21:07",120],["2026-05-01 11:21:08",120],["2026-05-01 11:21:09",120],["2026-05-01 11:21:10",120],["2026-05-01 11:21:11",120],["2026-05-01 11:21:12",120],["2026-05-01 11:21:13",120],["2026-05-01 11:21:14",120],["2026-05-01 11:21:15",120],["2026-05-01 11:21:16",120],["2026-05-01 11:21:17",120],["2026-05-01 11:21:18",120],["2026-05-01 11:21:19",120],["2026-05-01 11:21:20",120],["2026-05-01 11:21:21",120],["2026-05-01 11:21:22",120],["2026-05-01 11:21:23",120],["2026-05-01 11:21:24",120],["2026-05-01 11:21:25",120],["2026-05-01 11:21:26",120],["2026-05-01 11:21:27",120],["2026-05-01 11:21:28",120],["2026-05-01 11:21:29",120],["2026-05-01 11:21:30",120],["2026-05-01 11:21:31",120],["2026-05-01 11:21:32",120],["2026-05-01 11:21:33",120],["2026-05-01 11:21:34",120],["2026-05-01 11:21:35",120],["2026-05-01 11:21:36",120],["2026-05-01 11:21:37",120],["2026-05-01 11:21:38",120],["2026-05-01 11:21:39",120],["2026-05-01 11:21:40",120],["2026-05-01 11:21:41",120],["2026-05-01 11:21:42",120],["2026-05-01 11:21:43",120],["2026-05-01 11:21:44",120],["2026-05-01 11:21:45",120],["2026-05-01 11:21:46",120],["2026-05-01 11:21:47",120],["2026-05-01 11:21:48",120],["2026-05-01 11:21:49",120],["2026-05-01 11:21:50",120],["2026-05-01 11:21:51",120],["2026-05-01 11:21:52",120],["2026-05-01 11:21:53",120],["2026-05-01 11:21:54",120],["2026-05-01 11:21:55",120],["2026-05-01 11:21:56",120],["2026-05-01 11:21:57",120],["2026-05-01 11:21:58",120],["2026-05-01 11:21:59",120],["2026-05-01 11:22:00",120],["2026-05-01 11:22:01",120],["2026-05-01 11:22:02",120],["2026-05-01 11:22:03",120],["2026-05-01 11:22:04",120],["2026-05-01 11:22:05",120],["2026-05-01 11:22:06",120],["2026-05-01 11:22:07",120],["2026-05-01 11:22:08",120],["2026-05-01 11:22:09",120],["2026-05-01 11:22:10",120],["2026-05-01 11:22:11",120],["2026-05-01 11:22:12",120],["2026-05-01 11:22:13",120],["2026-05-01 11:22:14",120],["2026-05-01 11:22:15",120],["2026-05-01 11:22:16",120],["2026-05-01 11:22:17",120],["2026-05-01 11:22:18",120],["2026-05-01 11:22:19",120],["2026-05-01 11:22:20",120],["2026-05-01 11:22:21",120],["2026-05-01 11:22:22",120],["2026-05-01 11:22:23",120],["2026-05-01 11:22:24",120],["2026-05-01 11:22:25",120],["2026-05-01 11:22:26",120],["2026-05-01 11:22:27",120],["2026-05-01 11:22:28",120],["2026-05-01 11:22:29",120],["2026-05-01 11:22:30",120],["2026-05-01 11:22:31",120],["2026-05-01 11:22:32",120],["2026-05-01 11:22:33",120],["2026-05-01 11:22:34",120],["2026-05-01 11:22:35",120],["2026-05-01 11:22:36",120],["2026-05-01 11:22:37",120],["2026-05-01 11:22:38",120],["2026-05-01 11:22:39",120],["2026-05-01 11:22:40",120],["2026-05-01 11:22:41",120],["2026-05-01 11:22:42",120],["2026-05-01 11:22:43",120],["2026-05-01 11:22:44",120],["2026-05-01 11:22:45",120],["2026-05-01 11:22:46",120],["2026-05-01 11:22:47",120],["2026-05-01 11:22:48",120],["2026-05-01 11:22:49",120],["2026-05-01 11:22:50",120],["2026-05-01 11:22:51",120],["2026-05-01 11:22:52",120],["2026-05-01 11:22:53",120],["2026-05-01 11:22:54",120],["2026-05-01 11:22:55",120],["2026-05-01 11:22:56",120],["2026-05-01 11:22:57",120],["2026-05-01 11:22:58",120],["2026-05-01 11:22:59",120],["2026-05-01 11:23:00",120],["2026-05-01 11:23:01",120],["2026-05-01 11:23:02",120],["2026-05-01 11:23:03",120],["2026-05-01 11:23:04",120],["2026-05-01 11:23:05",120],["2026-05-01 11:23:06",120],["2026-05-01 11:23:07",120],["2026-05-01 11:23:08",120],["2026-05-01 11:23:09",120],["2026-05-01 11:23:10",120],["2026-05-01 11:23:11",120],["2026-05-01 11:23:12",120],["2026-05-01 11:23:13",120],["2026-05-01 11:23:14",120],["2026-05-01 11:23:15",120],["2026-05-01 11:23:16",120],["2026-05-01 11:23:17",120],["2026-05-01 11:23:18",120],["2026-05-01 11:23:19",120],["2026-05-01 11:23:20",120],["2026-05-01 11:23:21",120],["2026-05-01 11:23:22",120],["2026-05-01 11:23:23",120],["2026-05-01 11:23:24",120],["2026-05-01 11:23:25",120],["2026-05-01 11:23:26",120],["2026-05-01 11:23:27",120],["2026-05-01 11:23:28",120],["2026-05-01 11:23:29",120],["2026-05-01 11:23:30",120],["2026-05-01 11:23:31",120],["2026-05-01 11:23:32",120],["2026-05-01 11:23:33",120],["2026-05-01 11:23:34",120],["2026-05-01 11:23:35",120],["2026-05-01 11:23:36",120],["2026-05-01 11:23:37",120],["2026-05-01 11:23:38",120],["2026-05-01 11:23:39",120],["2026-05-01 11:23:40",120],["2026-05-01 11:23:41",120],["2026-05-01 11:23:42",120],["2026-05-01 11:23:43",120],["2026-05-01 11:23:44",120],["2026-05-01 11:23:45",120],["2026-05-01 11:23:46",120],["2026-05-01 11:23:47",120],["2026-05-01 11:23:48",120],["2026-05-01 11:23:49",120],["2026-05-01 11:23:50",120],["2026-05-01 11:23:51",120],["2026-05-01 11:23:52",120],["2026-05-01 11:23:53",120],["2026-05-01 11:23:54",120],["2026-05-01 11:23:55",120],["2026-05-01 11:23:56",120],["2026-05-01 11:23:57",120],["2026-05-01 11:23:58",120],["2026-05-01 11:23:59",120],["2026-05-01 11:24:00",120],["2026-05-01 11:24:01",120],["2026-05-01 11:24:02",120],["2026-05-01 11:24:03",120],["2026-05-01 11:24:04",120],["2026-05-01 11:24:05",120],["2026-05-01 11:24:06",120],["2026-05-01 11:24:07",120],["2026-05-01 11:24:08",120],["2026-05-01 11:24:09",120],["2026-05-01 11:24:10",120],["2026-05-01 11:24:11",120],["2026-05-01 11:24:12",120],["2026-05-01 11:24:13",120],["2026-05-01 11:24:14",120],["2026-05-01 11:24:15",120],["2026-05-01 11:24:16",120],["2026-05-01 11:24:17",120],["2026-05-01 11:24:18",120],["2026-05-01 11:24:19",120],["2026-05-01 11:24:20",120],["2026-05-01 11:24:21",120],["2026-05-01 11:24:22",120],["2026-05-01 11:24:23",120],["2026-05-01 11:24:24",120],["2026-05-01 11:24:25",120],["2026-05-01 11:24:26",120],["2026-05-01 11:24:27",120],["2026-05-01 11:24:28",120],["2026-05-01 11:24:29",120],["2026-05-01 11:24:30",120],["2026-05-01 11:24:31",120]], }, - + ] });
- - + + - \ No newline at end of file + diff --git a/schemas/user.json b/schemas/user.json index 0144f023..78176e5d 100644 --- a/schemas/user.json +++ b/schemas/user.json @@ -22,4 +22,4 @@ ] } } -} \ No newline at end of file +} diff --git a/schemas/user_config.json b/schemas/user_config.json index 4025f635..4afe3ab9 100644 --- a/schemas/user_config.json +++ b/schemas/user_config.json @@ -97,4 +97,4 @@ ] } } -} \ No newline at end of file +} diff --git a/scripts/git/resolve-secrets-baseline-conflict.sh b/scripts/git/resolve-secrets-baseline-conflict.sh new file mode 100755 index 00000000..c228eb8c --- /dev/null +++ b/scripts/git/resolve-secrets-baseline-conflict.sh @@ -0,0 +1,101 @@ +#!/usr/bin/env bash +# ----------------------------------------------------------------------------- +# Git merge driver for .secrets.baseline +# +# Registered in .gitattributes: +# .secrets.baseline merge=secrets-baseline +# +# Registered in git config (via `make configure-git`): +# git config merge.secrets-baseline.driver \ +# "scripts/git/resolve-secrets-baseline-conflict.sh %O %A %B %P" +# +# On conflict the driver discards both sides and regenerates the baseline +# from the working tree, preserving existing audit decisions (is_secret). +# This avoids JSON merge conflicts while keeping human audits intact. +# ----------------------------------------------------------------------------- +set -euo pipefail + +ANCESTOR="$1" # %O — common ancestor version +CURRENT="$2" # %A — current branch version (written back on success) +OTHER="$3" # %B — incoming branch version +BASENAME="$4" # %P — path of the file being merged + +DETECT_SECRETS_SPEC="git+https://github.com/ibm/detect-secrets.git@076672a9a01abdfc7ecee2e7d14f08cdccb73976" +EXCLUDE="'(?x)(Cargo\\.lock\$|\\.lock\$|target/)'" + +echo "🔀 secrets-baseline merge driver: regenerating $BASENAME from working tree..." + +# Merge existing audit decisions from both sides into a temp file so we +# can propagate is_secret=false/true for already-reviewed findings. +MERGED_AUDITS=$(mktemp) +trap 'rm -f "$MERGED_AUDITS"' EXIT + +# Combine is_secret decisions from ancestor + incoming into a lookup. +# Strategy: incoming wins over ancestor; current (working) wins over both. +python3 - "$ANCESTOR" "$CURRENT" "$OTHER" "$MERGED_AUDITS" <<'PYEOF' +import json, sys + +def load(path): + try: + with open(path) as f: + return json.load(f) + except Exception: + return {"results": {}} + +ancestor = load(sys.argv[1]) +current = load(sys.argv[2]) +other = load(sys.argv[3]) +out_path = sys.argv[4] + +# Build hash → is_secret map, later sources win +audits = {} +for baseline in (ancestor, other, current): + for _file, findings in baseline.get("results", {}).items(): + for f in findings: + h = f.get("hashed_secret") + if h and "is_secret" in f: + audits[h] = f["is_secret"] + +with open(out_path, "w") as f: + json.dump(audits, f) +PYEOF + +# Regenerate the baseline from the current working tree. +if command -v uv >/dev/null 2>&1; then + uv tool run --from "$DETECT_SECRETS_SPEC" detect-secrets scan \ + --use-all-plugins \ + --exclude-files "$EXCLUDE" \ + > "$CURRENT.new" +elif command -v detect-secrets >/dev/null 2>&1; then + detect-secrets scan \ + --use-all-plugins \ + --exclude-files "$EXCLUDE" \ + > "$CURRENT.new" +else + echo "❌ detect-secrets not found; install via: uv tool install git+https://github.com/ibm/detect-secrets.git@076672a9a01abdfc7ecee2e7d14f08cdccb73976" >&2 + exit 1 +fi + +# Re-apply audit decisions from the merged audits map. +python3 - "$CURRENT.new" "$MERGED_AUDITS" "$CURRENT" <<'PYEOF' +import json, sys + +with open(sys.argv[1]) as f: + baseline = json.load(f) +with open(sys.argv[2]) as f: + audits = json.load(f) + +for _file, findings in baseline.get("results", {}).items(): + for finding in findings: + h = finding.get("hashed_secret") + if h and h in audits: + finding["is_secret"] = audits[h] + +with open(sys.argv[3], "w") as f: + json.dump(baseline, f, indent=2) + f.write("\n") +PYEOF + +rm -f "$CURRENT.new" +echo "✅ $BASENAME regenerated and audit decisions preserved." +exit 0 From ff4c4c4cd4b20c28fa03a13267d66a18ca82c6ff Mon Sep 17 00:00:00 2001 From: Lang-Akshay Date: Mon, 10 Aug 2026 16:10:04 +0100 Subject: [PATCH 2/9] restored: Makefile changes - scope creep Signed-off-by: Lang-Akshay --- Makefile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Makefile b/Makefile index c2145de8..ec87eedb 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,10 @@ DETECT_SECRETS_EXCLUDE := '(?x)(Cargo\.lock$$|\.lock$$)|^\.secrets\.baseline$$' fmt fmt-check lint deny \ pre-commit install-pre-commit-hooks configure-git \ secrets-scan secrets-scan-all secrets-audit secrets-baseline +<<<<<<< HEAD >>>>>>> 7aaeb99 (feat:added make pre-commit) +======= +>>>>>>> a7bc99d (restored: Makefile changes - scope creep) help: ## Show this help @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-22s\033[0m %s\n", $$1, $$2}' @@ -159,4 +162,7 @@ configure-git: install-pre-commit-hooks ## Configure git hooks + merge driver fo git config merge.secrets-baseline.driver \ "$$common_dir/git-drivers/resolve-secrets-baseline-conflict.sh %O %A %B %P" @echo "✅ Git merge driver configured for .secrets.baseline" +<<<<<<< HEAD >>>>>>> 7aaeb99 (feat:added make pre-commit) +======= +>>>>>>> a7bc99d (restored: Makefile changes - scope creep) From ade29b23462e537de4ecfa4ac9ca97bcd4b498b0 Mon Sep 17 00:00:00 2001 From: Lang-Akshay Date: Mon, 10 Aug 2026 16:37:22 +0100 Subject: [PATCH 3/9] maketarget: removed unnecassry make targets Signed-off-by: Lang-Akshay --- .pre-commit-config.yaml | 2 +- .secrets.baseline | 144 ++++++++++++++-------------------------- Makefile | 23 +------ 3 files changed, 53 insertions(+), 116 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f2495fe2..20d04681 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -124,7 +124,7 @@ repos: hooks: - id: detect-secrets name: IBM Detect Secrets - args: ['--baseline', '.secrets.baseline', --use-all-plugins, --fail-on-unaudited] + args: ['--baseline', '.secrets.baseline', --use-all-plugins] types: [text] # --------------------------------------------------------------------------- diff --git a/.secrets.baseline b/.secrets.baseline index 005ab756..5ef0b52f 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -3,7 +3,7 @@ "files": "Cargo\\.lock$|\\.lock$|target/", "lines": null }, - "generated_at": "2026-08-10T14:19:39Z", + "generated_at": "2026-08-10T15:26:13Z", "plugins_used": [ { "name": "AWSKeyDetector" @@ -77,24 +77,13 @@ } ], "results": { - "Test-Suite.md": [ - { - "hashed_secret": "bc2f74c22f98f7b6ffbc2f67453dbfa99bce9a32", - "is_verified": false, - "line_number": 106, - "type": "Secret Keyword", - "verified_result": null, - "is_secret": false - } - ], "assets/contextforgeCA/contextforge-client.key.pem": [ { "hashed_secret": "1348b145fa1a555461c1b790a2f66614781091e9", "is_verified": false, "line_number": 1, "type": "Private Key", - "verified_result": null, - "is_secret": false + "verified_result": null } ], "assets/contextforgeCA/contextforge-server.key.pem": [ @@ -103,8 +92,7 @@ "is_verified": false, "line_number": 1, "type": "Private Key", - "verified_result": null, - "is_secret": false + "verified_result": null } ], "assets/contextforgeCA/contextforge.ca.key.pem": [ @@ -113,8 +101,7 @@ "is_verified": false, "line_number": 1, "type": "Private Key", - "verified_result": null, - "is_secret": false + "verified_result": null } ], "assets/contextforgeCA/contextforge.intermediate.key.pem": [ @@ -123,8 +110,7 @@ "is_verified": false, "line_number": 1, "type": "Private Key", - "verified_result": null, - "is_secret": false + "verified_result": null } ], "assets/jwt.key": [ @@ -133,8 +119,7 @@ "is_verified": false, "line_number": 1, "type": "Private Key", - "verified_result": null, - "is_secret": false + "verified_result": null } ], "assets/tls_key.pem": [ @@ -143,8 +128,7 @@ "is_verified": false, "line_number": 1, "type": "Private Key", - "verified_result": null, - "is_secret": false + "verified_result": null } ], "crates/contextforge-data-plane-lib/src/common.rs": [ @@ -153,24 +137,21 @@ "is_verified": false, "line_number": 154, "type": "Secret Keyword", - "verified_result": null, - "is_secret": false + "verified_result": null }, { "hashed_secret": "427f5e1b530d4a544883308d876a11d724060c86", "is_verified": false, "line_number": 157, "type": "Secret Keyword", - "verified_result": null, - "is_secret": false + "verified_result": null }, { "hashed_secret": "bfc6000db1195a9522813fc405c666dd4ce669ad", "is_verified": false, "line_number": 250, "type": "Secret Keyword", - "verified_result": null, - "is_secret": false + "verified_result": null } ], "crates/contextforge-data-plane-lib/src/telemetry.rs": [ @@ -179,8 +160,7 @@ "is_verified": false, "line_number": 87, "type": "Hex High Entropy String", - "verified_result": null, - "is_secret": false + "verified_result": null } ], "crates/contextforge-data-plane-lib/tests/support/client.rs": [ @@ -189,8 +169,7 @@ "is_verified": false, "line_number": 12, "type": "Secret Keyword", - "verified_result": null, - "is_secret": false + "verified_result": null } ], "crates/contextforge-data-plane-lib/tests/support/mod.rs": [ @@ -199,8 +178,7 @@ "is_verified": false, "line_number": 17, "type": "Secret Keyword", - "verified_result": null, - "is_secret": false + "verified_result": null } ], "crates/contextforge-data-plane/Cargo.toml": [ @@ -209,8 +187,7 @@ "is_verified": false, "line_number": 19, "type": "Hex High Entropy String", - "verified_result": null, - "is_secret": false + "verified_result": null } ], "crates/plugins/cpex-secrets-detection/src/lib.rs": [ @@ -219,8 +196,7 @@ "is_verified": false, "line_number": 609, "type": "AWS Access Key", - "verified_result": null, - "is_secret": false + "verified_result": null } ], "crates/plugins/cpex-secrets-detection/src/scanner.rs": [ @@ -229,96 +205,84 @@ "is_verified": false, "line_number": 238, "type": "Secret Keyword", - "verified_result": null, - "is_secret": false + "verified_result": null }, { "hashed_secret": "199da8f71b7dced64f82cf6e96483134cace9b14", "is_verified": false, "line_number": 239, "type": "Secret Keyword", - "verified_result": null, - "is_secret": false + "verified_result": null }, { "hashed_secret": "c0026c4c848882618c987859077ffbae92130625", "is_verified": false, "line_number": 242, "type": "Secret Keyword", - "verified_result": null, - "is_secret": false + "verified_result": null }, { "hashed_secret": "078553dc10635837abb80f404302c70cba91b879", "is_verified": false, "line_number": 278, "type": "Base64 High Entropy String", - "verified_result": null, - "is_secret": false + "verified_result": null }, { "hashed_secret": "e175c6f5f2a92e8623bd9a4820edb4e8c1b0fd10", "is_verified": false, "line_number": 278, "type": "GitHub Token", - "verified_result": null, - "is_secret": false + "verified_result": null }, { "hashed_secret": "97d99a51e5ac827bb36fe6273facfda35245917a", "is_verified": false, "line_number": 279, "type": "Base64 High Entropy String", - "verified_result": null, - "is_secret": false + "verified_result": null }, { "hashed_secret": "be4fc4886bd949b369d5e092eb87494f12e57e5b", "is_verified": false, "line_number": 282, "type": "Private Key", - "verified_result": null, - "is_secret": false + "verified_result": null }, { "hashed_secret": "b1775a785f09a6ebaf2dc33d6eaeb98974d9cdb8", "is_verified": false, "line_number": 284, "type": "Hex High Entropy String", - "verified_result": null, - "is_secret": false + "verified_result": null }, { "hashed_secret": "eae9124e42e2ef05ba727bd1a1c0c6fa61a05b9e", "is_verified": false, "line_number": 302, "type": "Secret Keyword", - "verified_result": null, - "is_secret": false + "verified_result": null }, { "hashed_secret": "86de8c52637ec530fe39b0a8471da9b8764d5242", "is_verified": false, "line_number": 401, "type": "AWS Access Key", - "verified_result": null, - "is_secret": false + "verified_result": null }, { "hashed_secret": "9d7235fe33b6612ed7ebca4b63afd00d4adf5d66", "is_verified": false, "line_number": 410, "type": "Secret Keyword", - "verified_result": null, - "is_secret": false + "verified_result": null }, { "hashed_secret": "27a39044bff80a4c196689dfa8dcf129cb27fef8", "is_verified": false, "line_number": 431, "type": "Base64 High Entropy String", - "verified_result": null, - "is_secret": false + "verified_result": null } ], "crates/plugins/cpex-secrets-detection/tests/plugin_manager.rs": [ @@ -327,32 +291,28 @@ "is_verified": false, "line_number": 197, "type": "AWS Access Key", - "verified_result": null, - "is_secret": false + "verified_result": null }, { "hashed_secret": "8b4510a576d82f38bd2730436bf5e20c4e15b30e", "is_verified": false, "line_number": 198, "type": "AWS Access Key", - "verified_result": null, - "is_secret": false + "verified_result": null }, { "hashed_secret": "e4ea017859bcad962c8ab551fe29da9147877eee", "is_verified": false, "line_number": 199, "type": "AWS Access Key", - "verified_result": null, - "is_secret": false + "verified_result": null }, { "hashed_secret": "86de8c52637ec530fe39b0a8471da9b8764d5242", "is_verified": false, "line_number": 268, "type": "AWS Access Key", - "verified_result": null, - "is_secret": false + "verified_result": null } ], "docker/docker-compose-langfuse.yaml": [ @@ -361,32 +321,28 @@ "is_verified": false, "line_number": 16, "type": "Secret Keyword", - "verified_result": null, - "is_secret": false + "verified_result": null }, { "hashed_secret": "cb58df830a45cc33df1a313e616ecad78cd796c5", "is_verified": false, "line_number": 77, "type": "Secret Keyword", - "verified_result": null, - "is_secret": false + "verified_result": null }, { "hashed_secret": "2e0c522bfe4e7885492862df2e0b987c0ca02623", "is_verified": false, "line_number": 100, "type": "Secret Keyword", - "verified_result": null, - "is_secret": false + "verified_result": null }, { "hashed_secret": "d9d007c8de197b3f36a3a0ba4f13c0f7df175d5a", "is_verified": false, "line_number": 255, "type": "Secret Keyword", - "verified_result": null, - "is_secret": false + "verified_result": null } ], "docker/docker-compose.yml": [ @@ -395,56 +351,58 @@ "is_verified": false, "line_number": 189, "type": "Secret Keyword", - "verified_result": null, - "is_secret": false + "verified_result": null }, { "hashed_secret": "fdda45b7f6d2ead95d9991fc4678640c3bab0d84", "is_verified": false, "line_number": 363, "type": "Secret Keyword", - "verified_result": null, - "is_secret": false + "verified_result": null }, { "hashed_secret": "093d378410a5cfa4bd5088f3fef62fbdb8a95665", "is_verified": false, "line_number": 369, "type": "Secret Keyword", - "verified_result": null, - "is_secret": false + "verified_result": null }, { "hashed_secret": "c3de40d5e3fc71ed62771c2127a8e42585026c97", "is_verified": false, "line_number": 371, "type": "Secret Keyword", - "verified_result": null, - "is_secret": false + "verified_result": null }, { "hashed_secret": "4d4acd9b084d13f5fdb23807d857e1c48a1cfd0f", "is_verified": false, "line_number": 460, "type": "Secret Keyword", - "verified_result": null, - "is_secret": false + "verified_result": null }, { "hashed_secret": "bd0160c2cf35d950843c88f3be2b9412ed71f485", "is_verified": false, "line_number": 495, "type": "Secret Keyword", - "verified_result": null, - "is_secret": false + "verified_result": null }, { "hashed_secret": "293324f6824bb3a6db5c4dc42a60ddd4a9851c99", "is_verified": false, "line_number": 658, "type": "Hex High Entropy String", - "verified_result": null, - "is_secret": false + "verified_result": null + } + ], + "scripts/git/resolve-secrets-baseline-conflict.sh": [ + { + "hashed_secret": "44ffd1bfb94772d5f91d528e7aca703990edbbd7", + "is_verified": false, + "line_number": 29, + "type": "Secret Keyword", + "verified_result": null } ] }, diff --git a/Makefile b/Makefile index ec87eedb..7e8e957c 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,3 @@ -<<<<<<< HEAD -.PHONY: help docker-prod compose-up compose-down docs-serve -======= SERVICES ?= nginx control-plane redis postgres pgbouncer data-plane fast_time_server register_fast_time ARGS ?= @@ -15,10 +12,6 @@ DETECT_SECRETS_EXCLUDE := '(?x)(Cargo\.lock$$|\.lock$$)|^\.secrets\.baseline$$' fmt fmt-check lint deny \ pre-commit install-pre-commit-hooks configure-git \ secrets-scan secrets-scan-all secrets-audit secrets-baseline -<<<<<<< HEAD ->>>>>>> 7aaeb99 (feat:added make pre-commit) -======= ->>>>>>> a7bc99d (restored: Makefile changes - scope creep) help: ## Show this help @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-22s\033[0m %s\n", $$1, $$2}' @@ -37,15 +30,6 @@ compose-up: ## Launch stack: nginx, control plane, redis, postgres, pgbouncer, d } docker compose -f docker/docker-compose.yml up -d $(SERVICES) $(ARGS) -<<<<<<< HEAD -compose-down: ## Tear down the stack - docker compose -f docker/docker-compose.yml stop nginx control-plane redis postgres pgbouncer data-plane fast_time_server register_fast_time - -docs-serve: ## Serve the wiki book locally at http://127.0.0.1:3000 - mdbook serve _context/wiki --hostname 127.0.0.1 --port 3000 --open -======= -testing-down: ## Tear down the testing stack - docker compose -f docker/docker-compose.yml stop $(SERVICES) $(ARGS) compose-down: ## Tear down the stack docker compose -f docker/docker-compose.yml stop $(SERVICES) $(ARGS) @@ -77,7 +61,7 @@ install-pre-commit-hooks: ## Install pre-commit git hooks into .git/hooks echo "pre-commit not found. Install it with one of:"; \ echo " uv tool install pre-commit"; \ echo " brew install pre-commit"; \ - exit 1; \ + echo " exit 1"; \ fi pre-commit install @echo "✅ pre-commit hooks installed" @@ -86,7 +70,6 @@ pre-commit: ## Run all pre-commit hooks against every file @if ! command -v pre-commit >/dev/null 2>&1; then \ echo "pre-commit not found. Install it with one of:"; \ echo " uv tool install pre-commit"; \ - echo " brew install pre-commit"; \ exit 1; \ fi @mkdir -p .cache/pre-commit-home .cache/tmp @@ -162,7 +145,3 @@ configure-git: install-pre-commit-hooks ## Configure git hooks + merge driver fo git config merge.secrets-baseline.driver \ "$$common_dir/git-drivers/resolve-secrets-baseline-conflict.sh %O %A %B %P" @echo "✅ Git merge driver configured for .secrets.baseline" -<<<<<<< HEAD ->>>>>>> 7aaeb99 (feat:added make pre-commit) -======= ->>>>>>> a7bc99d (restored: Makefile changes - scope creep) From 3e52596d3f3988264c0e9814576a87e902ec3363 Mon Sep 17 00:00:00 2001 From: Lang-Akshay Date: Mon, 10 Aug 2026 17:00:05 +0100 Subject: [PATCH 4/9] fixup: .gitignore Signed-off-by: Lang-Akshay --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index cd00f559..5efd0ef1 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,7 @@ _context/wiki/book/ # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ + + +# Personal dev tooling (wt worktree manager, etc.) +.config/ \ No newline at end of file From 696902cfdd9f7dde2dfb4999b31f285391755389 Mon Sep 17 00:00:00 2001 From: Lang-Akshay Date: Mon, 10 Aug 2026 17:04:26 +0100 Subject: [PATCH 5/9] fixup: endof line checked removed from pre-commit Signed-off-by: Lang-Akshay --- .pre-commit-config.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 20d04681..8df0d25b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -46,6 +46,7 @@ repos: - id: end-of-file-fixer name: Fix End of Files types: [text] + exclude: '^\.gitignore$' stages: [pre-commit, pre-push, manual] - id: trailing-whitespace From c48fead0d60620074294cdd865110f8b12b17e88 Mon Sep 17 00:00:00 2001 From: Lang-Akshay Date: Tue, 11 Aug 2026 11:55:44 +0100 Subject: [PATCH 6/9] fix: harden pre-commit and build config - Remove cargo bench --no-run hook (no benchmarks exist; was compiling full release profile for nothing) - Remove jobs=4 cap in .cargo/config.toml (let Cargo use all cores) - Add --fail-on-unaudited to detect-secrets hook - Audit all 45 baseline findings (is_secret: false) - Add IMAGE_NAME variable, help target, configure-git, secrets-update targets to Makefile; redirect CARGO_HOME for hermeticity - Fail-close the secrets-baseline merge driver on unaudited findings Signed-off-by: Lang-Akshay --- .cargo/config.toml | 1 - .pre-commit-config.yaml | 8 +-- .secrets.baseline | 72 ++++++++++++++++++- Makefile | 26 +++++-- .../git/resolve-secrets-baseline-conflict.sh | 24 +++++++ 5 files changed, 116 insertions(+), 15 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index 3c22e472..519f8bc8 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,5 +1,4 @@ [build] -jobs = 4 [http] timeout = 10 # timeout for each HTTP request, in seconds diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8df0d25b..5abf3e5a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -125,7 +125,7 @@ repos: hooks: - id: detect-secrets name: IBM Detect Secrets - args: ['--baseline', '.secrets.baseline', --use-all-plugins] + args: ['--baseline', '.secrets.baseline', '--use-all-plugins', '--fail-on-unaudited'] types: [text] # --------------------------------------------------------------------------- @@ -162,9 +162,3 @@ repos: entry: cargo build --locked --workspace language: system pass_filenames: false - - - id: cargo-bench-no-run - name: cargo bench --no-run - entry: cargo bench --locked --workspace --no-run - language: system - pass_filenames: false diff --git a/.secrets.baseline b/.secrets.baseline index 5ef0b52f..1f7bb805 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -1,9 +1,9 @@ { "exclude": { - "files": "Cargo\\.lock$|\\.lock$|target/", + "files": "Cargo\\.lock$|\\.lock$|target/|^.secrets.baseline$", "lines": null }, - "generated_at": "2026-08-10T15:26:13Z", + "generated_at": "2026-08-11T09:49:51Z", "plugins_used": [ { "name": "AWSKeyDetector" @@ -80,6 +80,7 @@ "assets/contextforgeCA/contextforge-client.key.pem": [ { "hashed_secret": "1348b145fa1a555461c1b790a2f66614781091e9", + "is_secret": false, "is_verified": false, "line_number": 1, "type": "Private Key", @@ -89,6 +90,7 @@ "assets/contextforgeCA/contextforge-server.key.pem": [ { "hashed_secret": "1348b145fa1a555461c1b790a2f66614781091e9", + "is_secret": false, "is_verified": false, "line_number": 1, "type": "Private Key", @@ -98,6 +100,7 @@ "assets/contextforgeCA/contextforge.ca.key.pem": [ { "hashed_secret": "1348b145fa1a555461c1b790a2f66614781091e9", + "is_secret": false, "is_verified": false, "line_number": 1, "type": "Private Key", @@ -107,6 +110,7 @@ "assets/contextforgeCA/contextforge.intermediate.key.pem": [ { "hashed_secret": "1348b145fa1a555461c1b790a2f66614781091e9", + "is_secret": false, "is_verified": false, "line_number": 1, "type": "Private Key", @@ -116,6 +120,7 @@ "assets/jwt.key": [ { "hashed_secret": "be4fc4886bd949b369d5e092eb87494f12e57e5b", + "is_secret": false, "is_verified": false, "line_number": 1, "type": "Private Key", @@ -125,6 +130,7 @@ "assets/tls_key.pem": [ { "hashed_secret": "1348b145fa1a555461c1b790a2f66614781091e9", + "is_secret": false, "is_verified": false, "line_number": 1, "type": "Private Key", @@ -134,6 +140,7 @@ "crates/contextforge-data-plane-lib/src/common.rs": [ { "hashed_secret": "4a4645604f0b9e29503be96a87f6f47a6e4a7890", + "is_secret": false, "is_verified": false, "line_number": 154, "type": "Secret Keyword", @@ -141,6 +148,7 @@ }, { "hashed_secret": "427f5e1b530d4a544883308d876a11d724060c86", + "is_secret": false, "is_verified": false, "line_number": 157, "type": "Secret Keyword", @@ -148,15 +156,43 @@ }, { "hashed_secret": "bfc6000db1195a9522813fc405c666dd4ce669ad", + "is_secret": false, "is_verified": false, "line_number": 250, "type": "Secret Keyword", "verified_result": null } ], + "crates/contextforge-data-plane-lib/src/layers/mcp_origin.rs": [ + { + "hashed_secret": "3e4e260fceb19ea97eb49fdcc922cc84f052b0f6", + "is_verified": false, + "line_number": 235, + "type": "Secret Keyword", + "verified_result": null, + "is_secret": false + }, + { + "hashed_secret": "2f3b648abbad8976facf96604c2f272845b2aa23", + "is_verified": false, + "line_number": 241, + "type": "Secret Keyword", + "verified_result": null, + "is_secret": false + }, + { + "hashed_secret": "af70e9cc80b554e84e780440cd8fe46092a7e6e5", + "is_verified": false, + "line_number": 255, + "type": "Secret Keyword", + "verified_result": null, + "is_secret": false + } + ], "crates/contextforge-data-plane-lib/src/telemetry.rs": [ { "hashed_secret": "0a24796d4c71ce722a92f450f69dc36c60b21de4", + "is_secret": false, "is_verified": false, "line_number": 87, "type": "Hex High Entropy String", @@ -166,6 +202,7 @@ "crates/contextforge-data-plane-lib/tests/support/client.rs": [ { "hashed_secret": "a453c8b2640819a451ce875ac1e04d0dbab7b403", + "is_secret": false, "is_verified": false, "line_number": 12, "type": "Secret Keyword", @@ -175,6 +212,7 @@ "crates/contextforge-data-plane-lib/tests/support/mod.rs": [ { "hashed_secret": "a453c8b2640819a451ce875ac1e04d0dbab7b403", + "is_secret": false, "is_verified": false, "line_number": 17, "type": "Secret Keyword", @@ -184,6 +222,7 @@ "crates/contextforge-data-plane/Cargo.toml": [ { "hashed_secret": "58e7dc38ba3a7d4a720006d2f3cc4cda774d89dc", + "is_secret": false, "is_verified": false, "line_number": 19, "type": "Hex High Entropy String", @@ -193,6 +232,7 @@ "crates/plugins/cpex-secrets-detection/src/lib.rs": [ { "hashed_secret": "86de8c52637ec530fe39b0a8471da9b8764d5242", + "is_secret": false, "is_verified": false, "line_number": 609, "type": "AWS Access Key", @@ -202,6 +242,7 @@ "crates/plugins/cpex-secrets-detection/src/scanner.rs": [ { "hashed_secret": "9249e2590f5d19742260cb5296cb76fe0677f147", + "is_secret": false, "is_verified": false, "line_number": 238, "type": "Secret Keyword", @@ -209,6 +250,7 @@ }, { "hashed_secret": "199da8f71b7dced64f82cf6e96483134cace9b14", + "is_secret": false, "is_verified": false, "line_number": 239, "type": "Secret Keyword", @@ -216,6 +258,7 @@ }, { "hashed_secret": "c0026c4c848882618c987859077ffbae92130625", + "is_secret": false, "is_verified": false, "line_number": 242, "type": "Secret Keyword", @@ -223,6 +266,7 @@ }, { "hashed_secret": "078553dc10635837abb80f404302c70cba91b879", + "is_secret": false, "is_verified": false, "line_number": 278, "type": "Base64 High Entropy String", @@ -230,6 +274,7 @@ }, { "hashed_secret": "e175c6f5f2a92e8623bd9a4820edb4e8c1b0fd10", + "is_secret": false, "is_verified": false, "line_number": 278, "type": "GitHub Token", @@ -237,6 +282,7 @@ }, { "hashed_secret": "97d99a51e5ac827bb36fe6273facfda35245917a", + "is_secret": false, "is_verified": false, "line_number": 279, "type": "Base64 High Entropy String", @@ -244,6 +290,7 @@ }, { "hashed_secret": "be4fc4886bd949b369d5e092eb87494f12e57e5b", + "is_secret": false, "is_verified": false, "line_number": 282, "type": "Private Key", @@ -251,6 +298,7 @@ }, { "hashed_secret": "b1775a785f09a6ebaf2dc33d6eaeb98974d9cdb8", + "is_secret": false, "is_verified": false, "line_number": 284, "type": "Hex High Entropy String", @@ -258,6 +306,7 @@ }, { "hashed_secret": "eae9124e42e2ef05ba727bd1a1c0c6fa61a05b9e", + "is_secret": false, "is_verified": false, "line_number": 302, "type": "Secret Keyword", @@ -265,6 +314,7 @@ }, { "hashed_secret": "86de8c52637ec530fe39b0a8471da9b8764d5242", + "is_secret": false, "is_verified": false, "line_number": 401, "type": "AWS Access Key", @@ -272,6 +322,7 @@ }, { "hashed_secret": "9d7235fe33b6612ed7ebca4b63afd00d4adf5d66", + "is_secret": false, "is_verified": false, "line_number": 410, "type": "Secret Keyword", @@ -279,6 +330,7 @@ }, { "hashed_secret": "27a39044bff80a4c196689dfa8dcf129cb27fef8", + "is_secret": false, "is_verified": false, "line_number": 431, "type": "Base64 High Entropy String", @@ -288,6 +340,7 @@ "crates/plugins/cpex-secrets-detection/tests/plugin_manager.rs": [ { "hashed_secret": "436da7d4d22c39c0165ab0d5b40073d0f2fc11c5", + "is_secret": false, "is_verified": false, "line_number": 197, "type": "AWS Access Key", @@ -295,6 +348,7 @@ }, { "hashed_secret": "8b4510a576d82f38bd2730436bf5e20c4e15b30e", + "is_secret": false, "is_verified": false, "line_number": 198, "type": "AWS Access Key", @@ -302,6 +356,7 @@ }, { "hashed_secret": "e4ea017859bcad962c8ab551fe29da9147877eee", + "is_secret": false, "is_verified": false, "line_number": 199, "type": "AWS Access Key", @@ -309,6 +364,7 @@ }, { "hashed_secret": "86de8c52637ec530fe39b0a8471da9b8764d5242", + "is_secret": false, "is_verified": false, "line_number": 268, "type": "AWS Access Key", @@ -318,6 +374,7 @@ "docker/docker-compose-langfuse.yaml": [ { "hashed_secret": "cb1fde0682fbd1ac0faf2a9f297167ac9d06434b", + "is_secret": false, "is_verified": false, "line_number": 16, "type": "Secret Keyword", @@ -325,6 +382,7 @@ }, { "hashed_secret": "cb58df830a45cc33df1a313e616ecad78cd796c5", + "is_secret": false, "is_verified": false, "line_number": 77, "type": "Secret Keyword", @@ -332,6 +390,7 @@ }, { "hashed_secret": "2e0c522bfe4e7885492862df2e0b987c0ca02623", + "is_secret": false, "is_verified": false, "line_number": 100, "type": "Secret Keyword", @@ -339,6 +398,7 @@ }, { "hashed_secret": "d9d007c8de197b3f36a3a0ba4f13c0f7df175d5a", + "is_secret": false, "is_verified": false, "line_number": 255, "type": "Secret Keyword", @@ -348,6 +408,7 @@ "docker/docker-compose.yml": [ { "hashed_secret": "2a8bfc0ce436d55ca907d0162989481bcb7677b4", + "is_secret": false, "is_verified": false, "line_number": 189, "type": "Secret Keyword", @@ -355,6 +416,7 @@ }, { "hashed_secret": "fdda45b7f6d2ead95d9991fc4678640c3bab0d84", + "is_secret": false, "is_verified": false, "line_number": 363, "type": "Secret Keyword", @@ -362,6 +424,7 @@ }, { "hashed_secret": "093d378410a5cfa4bd5088f3fef62fbdb8a95665", + "is_secret": false, "is_verified": false, "line_number": 369, "type": "Secret Keyword", @@ -369,6 +432,7 @@ }, { "hashed_secret": "c3de40d5e3fc71ed62771c2127a8e42585026c97", + "is_secret": false, "is_verified": false, "line_number": 371, "type": "Secret Keyword", @@ -376,6 +440,7 @@ }, { "hashed_secret": "4d4acd9b084d13f5fdb23807d857e1c48a1cfd0f", + "is_secret": false, "is_verified": false, "line_number": 460, "type": "Secret Keyword", @@ -383,6 +448,7 @@ }, { "hashed_secret": "bd0160c2cf35d950843c88f3be2b9412ed71f485", + "is_secret": false, "is_verified": false, "line_number": 495, "type": "Secret Keyword", @@ -390,6 +456,7 @@ }, { "hashed_secret": "293324f6824bb3a6db5c4dc42a60ddd4a9851c99", + "is_secret": false, "is_verified": false, "line_number": 658, "type": "Hex High Entropy String", @@ -399,6 +466,7 @@ "scripts/git/resolve-secrets-baseline-conflict.sh": [ { "hashed_secret": "44ffd1bfb94772d5f91d528e7aca703990edbbd7", + "is_secret": false, "is_verified": false, "line_number": 29, "type": "Secret Keyword", diff --git a/Makefile b/Makefile index 7e8e957c..7b2039c2 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,11 @@ SERVICES ?= nginx control-plane redis postgres pgbouncer data-plane fast_time_server register_fast_time ARGS ?= +IMAGE_NAME := contextforge-data-plane:latest + +SERVICES ?= nginx control-plane redis postgres pgbouncer data-plane fast_time_server register_fast_time +ARGS ?= + # 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 @@ -11,7 +16,7 @@ DETECT_SECRETS_EXCLUDE := '(?x)(Cargo\.lock$$|\.lock$$)|^\.secrets\.baseline$$' docker-prod compose-up compose-down docs-serve \ fmt fmt-check lint deny \ pre-commit install-pre-commit-hooks configure-git \ - secrets-scan secrets-scan-all secrets-audit secrets-baseline + secrets-scan secrets-scan-all secrets-audit secrets-baseline secrets-update help: ## Show this help @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-22s\033[0m %s\n", $$1, $$2}' @@ -21,11 +26,11 @@ help: ## Show this help # --------------------------------------------------------------------------- docker-prod: ## Build production Docker image (contextforge-data-plane:latest) from docker/Dockerfile - docker build -t contextforge-data-plane:latest -f docker/Dockerfile . + docker build -t $(IMAGE_NAME) -f docker/Dockerfile . compose-up: ## Launch stack: nginx, control plane, redis, postgres, pgbouncer, dataplane, fast_time_server - @docker image inspect contextforge-data-plane:latest >/dev/null 2>&1 || { \ - echo "Image contextforge-data-plane:latest not found. Run 'make docker-prod' first."; \ + @docker image inspect $(IMAGE_NAME) >/dev/null 2>&1 || { \ + echo "Image $(IMAGE_NAME) not found. Run 'make docker-prod' first."; \ exit 1; \ } docker compose -f docker/docker-compose.yml up -d $(SERVICES) $(ARGS) @@ -72,9 +77,10 @@ pre-commit: ## Run all pre-commit hooks against every file echo " uv tool install pre-commit"; \ exit 1; \ fi - @mkdir -p .cache/pre-commit-home .cache/tmp + @mkdir -p .cache/pre-commit-home .cache/tmp .cache/cargo PRE_COMMIT_HOME='$(CURDIR)/.cache/pre-commit-home' \ TMPDIR='$(CURDIR)/.cache/tmp' \ + CARGO_HOME='$(CURDIR)/.cache/cargo' \ pre-commit run --config .pre-commit-config.yaml --all-files --show-diff-on-failure # --------------------------------------------------------------------------- @@ -145,3 +151,13 @@ configure-git: install-pre-commit-hooks ## Configure git hooks + merge driver fo git config merge.secrets-baseline.driver \ "$$common_dir/git-drivers/resolve-secrets-baseline-conflict.sh %O %A %B %P" @echo "✅ Git merge driver configured for .secrets.baseline" + +secrets-update: ## Re-scan and update .secrets.baseline in place + @if command -v detect-secrets >/dev/null 2>&1; then \ + detect-secrets scan --update .secrets.baseline --use-all-plugins \ + --exclude-files $(DETECT_SECRETS_EXCLUDE); \ + else \ + uv tool run --from '$(DETECT_SECRETS_SPEC)' detect-secrets scan \ + --update .secrets.baseline --use-all-plugins \ + --exclude-files $(DETECT_SECRETS_EXCLUDE); \ + fi diff --git a/scripts/git/resolve-secrets-baseline-conflict.sh b/scripts/git/resolve-secrets-baseline-conflict.sh index c228eb8c..21459c4c 100755 --- a/scripts/git/resolve-secrets-baseline-conflict.sh +++ b/scripts/git/resolve-secrets-baseline-conflict.sh @@ -12,6 +12,8 @@ # On conflict the driver discards both sides and regenerates the baseline # from the working tree, preserving existing audit decisions (is_secret). # This avoids JSON merge conflicts while keeping human audits intact. +# The driver fails closed: if the regenerated baseline contains findings +# without an is_secret audit decision the merge is rejected. # ----------------------------------------------------------------------------- set -euo pipefail @@ -97,5 +99,27 @@ with open(sys.argv[3], "w") as f: PYEOF rm -f "$CURRENT.new" + +# Fail closed: reject unaudited findings introduced by the merge. +UNAUDITED=$(python3 - "$CURRENT" <<'PYEOF' +import json, sys +with open(sys.argv[1]) as f: + baseline = json.load(f) +count = sum( + 1 + for findings in baseline.get("results", {}).values() + for f in findings + if "is_secret" not in f +) +print(count) +PYEOF +) + +if [ "$UNAUDITED" -gt 0 ]; then + echo "❌ $BASENAME has $UNAUDITED unaudited finding(s) after merge. Audit them with:" >&2 + echo " detect-secrets audit $BASENAME" >&2 + exit 1 +fi + echo "✅ $BASENAME regenerated and audit decisions preserved." exit 0 From 8b7de59c000bdc953e28adbc2fd84b4ec6b19973 Mon Sep 17 00:00:00 2001 From: Lang-Akshay Date: Tue, 11 Aug 2026 13:19:51 +0100 Subject: [PATCH 7/9] feat: updated makefile to have selective target Signed-off-by: Lang-Akshay --- Makefile | 105 ++++--------------------------------------------------- 1 file changed, 6 insertions(+), 99 deletions(-) diff --git a/Makefile b/Makefile index 7b2039c2..cdc0725c 100644 --- a/Makefile +++ b/Makefile @@ -1,30 +1,16 @@ -SERVICES ?= nginx control-plane redis postgres pgbouncer data-plane fast_time_server register_fast_time -ARGS ?= - IMAGE_NAME := contextforge-data-plane:latest - SERVICES ?= nginx control-plane redis postgres pgbouncer data-plane fast_time_server register_fast_time ARGS ?= # 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 - -# Files excluded from secret scanning (lock files generated by tooling). DETECT_SECRETS_EXCLUDE := '(?x)(Cargo\.lock$$|\.lock$$)|^\.secrets\.baseline$$' -.PHONY: help \ - docker-prod compose-up compose-down docs-serve \ - fmt fmt-check lint deny \ - pre-commit install-pre-commit-hooks configure-git \ - secrets-scan secrets-scan-all secrets-audit secrets-baseline secrets-update +.PHONY: help docker-prod compose-up compose-down docs-serve pre-commit secrets-scan-all configure-git -help: ## Show this help +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 -# --------------------------------------------------------------------------- - docker-prod: ## Build production Docker image (contextforge-data-plane:latest) from docker/Dockerfile docker build -t $(IMAGE_NAME) -f docker/Dockerfile . @@ -41,40 +27,11 @@ compose-down: ## Tear down the stack docs-serve: ## Serve the wiki book locally at http://127.0.0.1:3000 mdbook serve _context/wiki --hostname 127.0.0.1 --port 3000 --open -# --------------------------------------------------------------------------- -# Rust format & lint -# --------------------------------------------------------------------------- - -fmt: ## Format Rust code with rustfmt (modifies files) - cargo fmt --all - -fmt-check: ## Check Rust formatting without modifying files - cargo fmt --all --check - -lint: ## Lint Rust code with clippy (warnings → errors) - cargo clippy --locked --workspace --all-targets -- -D warnings - -deny: ## Run cargo-deny supply-chain checks (advisories + licenses) - cargo deny check advisories licenses - -# --------------------------------------------------------------------------- -# pre-commit -# --------------------------------------------------------------------------- - -install-pre-commit-hooks: ## Install pre-commit git hooks into .git/hooks - @if ! command -v pre-commit >/dev/null 2>&1; then \ - echo "pre-commit not found. Install it with one of:"; \ - echo " uv tool install pre-commit"; \ - echo " brew install pre-commit"; \ - echo " exit 1"; \ - fi - pre-commit install - @echo "✅ pre-commit hooks installed" - pre-commit: ## Run all pre-commit hooks against every file @if ! command -v pre-commit >/dev/null 2>&1; then \ echo "pre-commit not found. Install it with one of:"; \ echo " uv tool install pre-commit"; \ + echo " brew install pre-commit"; \ exit 1; \ fi @mkdir -p .cache/pre-commit-home .cache/tmp .cache/cargo @@ -83,31 +40,6 @@ pre-commit: ## Run all pre-commit hooks against every file CARGO_HOME='$(CURDIR)/.cache/cargo' \ pre-commit run --config .pre-commit-config.yaml --all-files --show-diff-on-failure -# --------------------------------------------------------------------------- -# Secret scanning (IBM detect-secrets hardened fork) -# --------------------------------------------------------------------------- - -secrets-scan: ## Scan changed files and update .secrets.baseline in place - @if ! command -v detect-secrets >/dev/null 2>&1 && ! command -v uv >/dev/null 2>&1; then \ - echo "detect-secrets not found. Install it with:"; \ - echo " uv tool install '$(DETECT_SECRETS_SPEC)'"; \ - exit 1; \ - fi - @if command -v detect-secrets >/dev/null 2>&1; then \ - detect-secrets scan --update .secrets.baseline --use-all-plugins \ - --exclude-files $(DETECT_SECRETS_EXCLUDE); \ - else \ - uv tool run --from '$(DETECT_SECRETS_SPEC)' detect-secrets scan \ - --update .secrets.baseline --use-all-plugins \ - --exclude-files $(DETECT_SECRETS_EXCLUDE); \ - fi - @echo "📊 Findings report:" - @if command -v detect-secrets >/dev/null 2>&1; then \ - detect-secrets audit --report .secrets.baseline; \ - else \ - uv tool run --from '$(DETECT_SECRETS_SPEC)' detect-secrets audit --report .secrets.baseline; \ - fi - secrets-scan-all: ## Full-tree scan — regenerate .secrets.baseline from scratch @if ! command -v detect-secrets >/dev/null 2>&1 && ! command -v uv >/dev/null 2>&1; then \ echo "detect-secrets not found. Install it with:"; \ @@ -125,24 +57,10 @@ secrets-scan-all: ## Full-tree scan — regenerate .secrets.baseline from scratc --exclude-files $(DETECT_SECRETS_EXCLUDE) \ > .secrets.baseline; \ fi - @echo "✅ .secrets.baseline regenerated — audit new findings with: make secrets-audit" + @echo "✅ .secrets.baseline regenerated — audit new findings before committing" -secrets-audit: ## Interactive audit of unreviewed findings in .secrets.baseline - @if command -v detect-secrets >/dev/null 2>&1; then \ - detect-secrets audit .secrets.baseline; \ - else \ - uv tool run --from '$(DETECT_SECRETS_SPEC)' detect-secrets audit .secrets.baseline; \ - fi - -secrets-baseline: ## Alias for secrets-scan-all (initial baseline creation) - @$(MAKE) --no-print-directory secrets-scan-all - -# --------------------------------------------------------------------------- -# Git configuration -# --------------------------------------------------------------------------- - -configure-git: install-pre-commit-hooks ## Configure git hooks + merge driver for .secrets.baseline - @echo "🔀 Configuring git merge driver for .secrets.baseline..." +# Internal target used by .gitattributes; intentionally omitted from `make help`. +configure-git: @common_dir=$$(git rev-parse --git-common-dir); \ mkdir -p "$$common_dir/git-drivers"; \ cp scripts/git/resolve-secrets-baseline-conflict.sh "$$common_dir/git-drivers/"; \ @@ -150,14 +68,3 @@ configure-git: install-pre-commit-hooks ## Configure git hooks + merge driver fo git config merge.secrets-baseline.name "Regenerate .secrets.baseline via detect-secrets-scan"; \ git config merge.secrets-baseline.driver \ "$$common_dir/git-drivers/resolve-secrets-baseline-conflict.sh %O %A %B %P" - @echo "✅ Git merge driver configured for .secrets.baseline" - -secrets-update: ## Re-scan and update .secrets.baseline in place - @if command -v detect-secrets >/dev/null 2>&1; then \ - detect-secrets scan --update .secrets.baseline --use-all-plugins \ - --exclude-files $(DETECT_SECRETS_EXCLUDE); \ - else \ - uv tool run --from '$(DETECT_SECRETS_SPEC)' detect-secrets scan \ - --update .secrets.baseline --use-all-plugins \ - --exclude-files $(DETECT_SECRETS_EXCLUDE); \ - fi From cd391e1e59b93c8fa05c37077129ba401f94fc81 Mon Sep 17 00:00:00 2001 From: Lang-Akshay Date: Tue, 11 Aug 2026 13:22:29 +0100 Subject: [PATCH 8/9] chore: refresh secret baseline and docs whitespace Signed-off-by: Lang-Akshay --- .secrets.baseline | 16 ++++++++-------- _context/wiki/config.md | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.secrets.baseline b/.secrets.baseline index 1f7bb805..7cf529b9 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -3,7 +3,7 @@ "files": "Cargo\\.lock$|\\.lock$|target/|^.secrets.baseline$", "lines": null }, - "generated_at": "2026-08-11T09:49:51Z", + "generated_at": "2026-08-11T12:22:16Z", "plugins_used": [ { "name": "AWSKeyDetector" @@ -166,27 +166,27 @@ "crates/contextforge-data-plane-lib/src/layers/mcp_origin.rs": [ { "hashed_secret": "3e4e260fceb19ea97eb49fdcc922cc84f052b0f6", + "is_secret": false, "is_verified": false, "line_number": 235, "type": "Secret Keyword", - "verified_result": null, - "is_secret": false + "verified_result": null }, { "hashed_secret": "2f3b648abbad8976facf96604c2f272845b2aa23", + "is_secret": false, "is_verified": false, "line_number": 241, "type": "Secret Keyword", - "verified_result": null, - "is_secret": false + "verified_result": null }, { "hashed_secret": "af70e9cc80b554e84e780440cd8fe46092a7e6e5", + "is_secret": false, "is_verified": false, "line_number": 255, "type": "Secret Keyword", - "verified_result": null, - "is_secret": false + "verified_result": null } ], "crates/contextforge-data-plane-lib/src/telemetry.rs": [ @@ -468,7 +468,7 @@ "hashed_secret": "44ffd1bfb94772d5f91d528e7aca703990edbbd7", "is_secret": false, "is_verified": false, - "line_number": 29, + "line_number": 31, "type": "Secret Keyword", "verified_result": null } diff --git a/_context/wiki/config.md b/_context/wiki/config.md index efbd62f3..304c9a3c 100644 --- a/_context/wiki/config.md +++ b/_context/wiki/config.md @@ -156,8 +156,8 @@ RuntimePluginConfigDocument cpex: CpexConfig ``` -Supported: `cmf.tool_pre_invoke`, `cmf.tool_post_invoke` only. -Rejected: routing-based selection, plugin dirs, global policies, other hook types. +Supported: `cmf.tool_pre_invoke`, `cmf.tool_post_invoke` only. +Rejected: routing-based selection, plugin dirs, global policies, other hook types. Reload watcher: 10-minute interval. Invalid reload → runtime marked failed. ### Tool Call Hook Behavior From 578bb9dfd66ed3ea5ca452e6d2ef7a313feaae9c Mon Sep 17 00:00:00 2001 From: Lang-Akshay Date: Tue, 11 Aug 2026 15:45:35 +0100 Subject: [PATCH 9/9] commit change Signed-off-by: Lang-Akshay --- .../git/resolve-secrets-baseline-conflict.sh | 2 +- .../test-resolve-secrets-baseline-conflict.sh | 124 ++++++++++++++++++ 2 files changed, 125 insertions(+), 1 deletion(-) create mode 100755 scripts/git/test-resolve-secrets-baseline-conflict.sh diff --git a/scripts/git/resolve-secrets-baseline-conflict.sh b/scripts/git/resolve-secrets-baseline-conflict.sh index 21459c4c..72d3dc8e 100755 --- a/scripts/git/resolve-secrets-baseline-conflict.sh +++ b/scripts/git/resolve-secrets-baseline-conflict.sh @@ -23,7 +23,7 @@ OTHER="$3" # %B — incoming branch version BASENAME="$4" # %P — path of the file being merged DETECT_SECRETS_SPEC="git+https://github.com/ibm/detect-secrets.git@076672a9a01abdfc7ecee2e7d14f08cdccb73976" -EXCLUDE="'(?x)(Cargo\\.lock\$|\\.lock\$|target/)'" +EXCLUDE="(?x)(Cargo\.lock$|\.lock$|target/|^\.secrets\.baseline$)" echo "🔀 secrets-baseline merge driver: regenerating $BASENAME from working tree..." diff --git a/scripts/git/test-resolve-secrets-baseline-conflict.sh b/scripts/git/test-resolve-secrets-baseline-conflict.sh new file mode 100755 index 00000000..475c5a10 --- /dev/null +++ b/scripts/git/test-resolve-secrets-baseline-conflict.sh @@ -0,0 +1,124 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd) +PYTHON=$(command -v python3) +TMP_DIR=$(mktemp -d) +trap 'rm -rf "$TMP_DIR"' EXIT + +FAKE_BIN="$TMP_DIR/bin" +mkdir -p "$FAKE_BIN" + +cat > "$FAKE_BIN/detect-secrets" <<'FAKE_DETECT_SECRETS' +#!/usr/bin/env bash +set -euo pipefail + +exclude='' +while (($#)); do + if [[ "$1" == --exclude-files ]]; then + exclude=$2 + shift 2 + else + shift + fi +done + +python3 - "$exclude" <<'PY' +import json +import re +import sys + +exclude = sys.argv[1] +try: + excludes_baseline = re.search(exclude, ".secrets.baseline") is not None +except re.error as error: + print(error, file=sys.stderr) + raise + +results = {} +results["known.txt"] = [ + { + "type": "BasicAuthDetector", + "filename": "known.txt", + "hashed_secret": "known-audited-value", # pragma: allowlist secret + } +] +if not excludes_baseline: + results[".secrets.baseline"] = [ + { + "type": "BasicAuthDetector", + "filename": ".secrets.baseline", + "hashed_secret": "baseline-self-value", # pragma: allowlist secret + } + ] + +if __import__("os").environ.get("FAKE_SCAN_MODE") == "unaudited": + results["new-value.txt"] = [ + { + "type": "BasicAuthDetector", + "filename": "new-value.txt", + "hashed_secret": "new-unaudited-value", # pragma: allowlist secret + } + ] + +print(json.dumps({"results": results})) +PY +FAKE_DETECT_SECRETS +chmod +x "$FAKE_BIN/detect-secrets" + +python3 - "$TMP_DIR" <<'PY' +import json +import pathlib +import sys + +tmp_dir = pathlib.Path(sys.argv[1]) +baseline = { + "results": { + "known.txt": [ + { + "type": "BasicAuthDetector", + "filename": "known.txt", + "hashed_secret": "known-audited-value", # pragma: allowlist secret + "is_secret": False, + } + ] + } +} +for name in ("ancestor.json", "current.json", "other.json"): + (tmp_dir / name).write_text(json.dumps(baseline)) +PY + +PATH="$FAKE_BIN:$(dirname "$PYTHON"):/usr/bin:/bin" \ + FAKE_SCAN_MODE=clean \ + "$SCRIPT_DIR/resolve-secrets-baseline-conflict.sh" \ + "$TMP_DIR/ancestor.json" "$TMP_DIR/current.json" "$TMP_DIR/other.json" \ + .secrets.baseline + +python3 - "$TMP_DIR/current.json" <<'PY' +import json +import sys + +with open(sys.argv[1]) as stream: + baseline = json.load(stream) +assert ".secrets.baseline" not in baseline["results"] +assert baseline["results"]["known.txt"][0]["is_secret"] is False +PY + +if output=$(env PATH="$FAKE_BIN:$(dirname "$PYTHON"):/usr/bin:/bin" \ + FAKE_SCAN_MODE=unaudited \ + "$SCRIPT_DIR/resolve-secrets-baseline-conflict.sh" \ + "$TMP_DIR/ancestor.json" "$TMP_DIR/current.json" "$TMP_DIR/other.json" \ + .secrets.baseline 2>&1); then + printf 'merge driver accepted an unaudited finding\n%s\n' "$output" >&2 + exit 1 +fi + +case "$output" in + *"has 1 unaudited finding(s)"*) ;; + *) + printf 'merge driver rejected for the wrong reason\n%s\n' "$output" >&2 + exit 1 + ;; +esac + +echo "merge-driver regression checks passed"