Skip to content

Commit 53460cf

Browse files
committed
Merge remote-tracking branch 'origin/main' into pr771-merge
2 parents 44ea2f2 + 8f154ce commit 53460cf

162 files changed

Lines changed: 18380 additions & 743 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/dependabot-auto-merge.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ jobs:
3535
steps:
3636
- name: Fetch Dependabot metadata
3737
id: meta
38-
uses: dependabot/fetch-metadata@v2
38+
uses: dependabot/fetch-metadata@v3
3939
with:
4040
github-token: ${{ secrets.GITHUB_TOKEN }}
4141

.github/workflows/eval.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,17 @@ jobs:
5858
go-version: "1.25"
5959
cache: true
6060

61+
# Spec 076 / US3 (FR-013, SC-006): pure-Go, offline regression gate over the
62+
# labeled detect corpus. It runs the production detect.Engine and fails the
63+
# build if malicious recall drops below 0.90 or the hard-negative
64+
# false-positive rate climbs above 0.05. No mcp-eval/Python needed — runs
65+
# first so a detector regression fails fast.
66+
- name: Run Spec-076 detect-engine gate (offline, blocking)
67+
run: |
68+
go run ./cmd/scan-eval \
69+
--corpus specs/065-evaluation-foundation/datasets/detect_corpus_v1.json \
70+
--gate --min-recall 0.90 --max-fp 0.05
71+
6172
- name: Checkout mcp-eval (public, pinned)
6273
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
6374
with:

.github/workflows/native-tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ jobs:
9696
timeout-minutes: 5
9797
steps:
9898
- uses: actions/checkout@v6
99-
- uses: actions/setup-python@v5
99+
- uses: actions/setup-python@v6
100100
with:
101101
python-version: '3.12'
102102
- name: Web <-> native settings catalog parity

.github/workflows/roadmap.yml

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
name: roadmap
2+
3+
# Keep ROADMAP.md in sync with roadmap.yaml and the per-spec tasks.md badges.
4+
# ROADMAP.md is a generated file (scripts/gen-roadmap.py); this canary fails the
5+
# build if it is stale so the roadmap never silently drifts. Regenerate locally
6+
# with `python3 scripts/gen-roadmap.py` and commit the result.
7+
8+
on:
9+
pull_request:
10+
paths:
11+
- 'roadmap.yaml'
12+
- 'ROADMAP.md'
13+
- 'scripts/gen-roadmap.py'
14+
- 'specs/**/tasks.md'
15+
- '.github/workflows/roadmap.yml'
16+
push:
17+
branches: [main, next]
18+
paths:
19+
- 'roadmap.yaml'
20+
- 'ROADMAP.md'
21+
- 'scripts/gen-roadmap.py'
22+
- 'specs/**/tasks.md'
23+
- '.github/workflows/roadmap.yml'
24+
25+
permissions:
26+
contents: read
27+
pull-requests: read
28+
29+
jobs:
30+
roadmap-check:
31+
name: roadmap-up-to-date
32+
runs-on: ubuntu-latest
33+
timeout-minutes: 5
34+
steps:
35+
- uses: actions/checkout@v6
36+
- uses: actions/setup-python@v5
37+
with:
38+
python-version: '3.12'
39+
- name: Install PyYAML
40+
run: pip install pyyaml
41+
- name: Verify ROADMAP.md is up to date
42+
run: python3 scripts/gen-roadmap.py --check
43+
# Non-blocking: report roadmap.yaml drift vs live GitHub PR state, dangling
44+
# spec: links, and status sanity. `gh` is preinstalled on GitHub runners;
45+
# GH_TOKEN authenticates it. continue-on-error so drift is surfaced in the
46+
# log without failing the build (roadmap.yaml is hand-maintained).
47+
- name: Cross-check roadmap.yaml vs GitHub (advisory)
48+
continue-on-error: true
49+
env:
50+
GH_TOKEN: ${{ github.token }}
51+
run: python3 scripts/gen-roadmap.py --check-github
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
name: Sandbox Integration Tests
2+
3+
# MCP-34.5 / MCP-3236: Prove sandbox isolation works on Linux (Landlock LSM).
4+
# ubuntu-latest == Ubuntu 24.04, kernel 6.8 — Landlock ABI ≥ 3 available.
5+
# These tests are also covered by unit-tests.yml; this job surfaces them
6+
# explicitly and adds the server-startup probe so CI shows dedicated evidence.
7+
8+
on:
9+
push:
10+
branches: ["*"]
11+
paths:
12+
- "internal/sandbox/**"
13+
- "internal/upstream/core/sandbox*.go"
14+
- "internal/security/scanner/**"
15+
- "internal/upstream/core/**"
16+
- ".github/workflows/sandbox-integration.yml"
17+
pull_request:
18+
branches: ["*"]
19+
paths:
20+
- "internal/sandbox/**"
21+
- "internal/upstream/core/sandbox*.go"
22+
- "internal/security/scanner/**"
23+
- "internal/upstream/core/**"
24+
- ".github/workflows/sandbox-integration.yml"
25+
workflow_dispatch:
26+
27+
jobs:
28+
sandbox-integration:
29+
name: Sandbox Integration (Linux / Landlock)
30+
runs-on: ubuntu-latest
31+
32+
env:
33+
GO111MODULE: "on"
34+
35+
steps:
36+
- name: Checkout code
37+
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
38+
39+
- name: Set up Go
40+
uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.6.0
41+
with:
42+
go-version: "1.25"
43+
cache: true
44+
45+
- name: Download dependencies
46+
run: go mod download
47+
48+
# Confirm the kernel supports Landlock before running enforcement tests.
49+
- name: Check Landlock availability
50+
run: |
51+
uname -r
52+
if grep -qi landlock /proc/kallsyms 2>/dev/null || \
53+
cat /proc/sys/kernel/landlock/abi 2>/dev/null | grep -q "[1-9]"; then
54+
echo "Landlock available"
55+
else
56+
# ubuntu 24.04 exposes ABI via a prctl probe — let the Go test skip logic handle it
57+
echo "Landlock probe inconclusive — Go tests will auto-skip if unavailable"
58+
fi
59+
60+
# 1. sandbox package: Landlock enforcement (TestLandlockEnforcesFilesystemAllowlist),
61+
# wrap/encode round-trip, rlimit constants.
62+
- name: Run sandbox package tests
63+
run: go test -v -race ./internal/sandbox/...
64+
65+
# 2. upstream/core: wrapWithSandbox full re-exec integration
66+
# (TestSandboxWrapper_EndToEnd, TestSandboxWrapper_FailClosed, spec builders).
67+
- name: Run upstream/core sandbox tests
68+
run: go test -v -race -run "Sandbox|sandbox|buildSandbox" ./internal/upstream/core/...
69+
70+
# 3. scanner/engine: degradation under sandbox/none isolation mode
71+
# (TestEngineResolveScannersSkipsDockerUnderSandbox, TestEngineEffectiveIsolationMode).
72+
- name: Run scanner isolation-mode tests
73+
run: go test -v -race -run "Sandbox|sandbox|IsolationMode|isolation" ./internal/security/scanner/...
74+
75+
# 4. Full sandbox + scanner test set with race detector.
76+
- name: Run all sandbox-related tests (race)
77+
run: |
78+
go test -race \
79+
./internal/sandbox/... \
80+
./internal/upstream/core/... \
81+
./internal/security/scanner/...
82+
83+
# 5. Build the binary (proves sandbox code compiles on linux/amd64).
84+
- name: Build mcpproxy binary
85+
run: go build -v -o mcpproxy ./cmd/mcpproxy
86+
87+
# 6. Server startup probe: start mcpproxy with isolation.mode=sandbox,
88+
# verify it starts healthy, check the upstream list (no stdio servers
89+
# configured so no wrapWithSandbox is called — this proves the binary
90+
# starts cleanly under this config, not sandbox enforcement itself).
91+
- name: Start mcpproxy with isolation.mode=sandbox (startup probe)
92+
run: |
93+
mkdir -p /tmp/mcp3236-ci
94+
cat > /tmp/mcp3236-ci/mcp_config.json <<'EOF'
95+
{
96+
"listen": "127.0.0.1:19237",
97+
"api_key": "qa-sandbox-ci-test",
98+
"enable_web_ui": false,
99+
"docker_isolation": { "mode": "sandbox" },
100+
"mcpServers": []
101+
}
102+
EOF
103+
MCPPROXY_DATA_DIR=/tmp/mcp3236-ci ./mcpproxy serve \
104+
--config /tmp/mcp3236-ci/mcp_config.json \
105+
--log-level=debug \
106+
> /tmp/mcp3236-ci/server.log 2>&1 &
107+
SERVER_PID=$!
108+
echo "SERVER_PID=$SERVER_PID" >> "$GITHUB_ENV"
109+
# Wait for server to be ready
110+
for i in $(seq 1 20); do
111+
if curl -sf -H "X-API-Key: qa-sandbox-ci-test" \
112+
http://127.0.0.1:19237/api/v1/status > /dev/null 2>&1; then
113+
echo "Server ready after ${i}s"
114+
break
115+
fi
116+
sleep 1
117+
done
118+
119+
- name: Verify server health under sandbox config
120+
run: |
121+
# Use the dedicated readiness endpoint (/readyz returns 200 once the
122+
# server has completed startup) — structure-independent, unlike parsing
123+
# the /api/v1/status JSON. The server serves HTTP before it's ready, so
124+
# poll up to 30s.
125+
READY=0
126+
for i in $(seq 1 30); do
127+
if curl -sf http://127.0.0.1:19237/readyz > /dev/null 2>&1; then
128+
READY=1; echo "Server ready (/readyz 200) after ${i}s"; break
129+
fi
130+
sleep 1
131+
done
132+
echo "--- /readyz body ---"; curl -s http://127.0.0.1:19237/readyz || true; echo
133+
echo "--- /api/v1/status ---"
134+
curl -sf -H "X-API-Key: qa-sandbox-ci-test" http://127.0.0.1:19237/api/v1/status | python3 -m json.tool || true
135+
if [ "$READY" != "1" ]; then
136+
echo "ERROR: /readyz did not return 200 within 30s"
137+
cat /tmp/mcp3236-ci/server.log
138+
exit 1
139+
fi
140+
# Prove the server actually resolved SANDBOX mode (the global key is
141+
# docker_isolation.mode — a wrong key silently falls back to "none",
142+
# which would make this probe vacuous).
143+
if ! grep -i "isolation_mode" /tmp/mcp3236-ci/server.log | grep -qi "sandbox"; then
144+
echo "ERROR: server did not start in sandbox mode (expected isolation_mode=sandbox)"
145+
grep -i "isolation_mode" /tmp/mcp3236-ci/server.log || echo "(no isolation_mode log line found)"
146+
exit 1
147+
fi
148+
echo "Server healthy (/readyz) and confirmed isolation_mode=sandbox"
149+
150+
- name: macOS/non-Linux graceful-degrade probe (build check)
151+
run: |
152+
# Cross-compile for darwin to prove the no-op path compiles cleanly.
153+
GOOS=darwin GOARCH=arm64 go build -o /dev/null ./internal/sandbox/... 2>&1 || true
154+
GOOS=darwin GOARCH=arm64 go build -o /dev/null ./internal/upstream/core/ 2>&1 || true
155+
echo "Cross-compile probe done (darwin build tags: sandbox_other.go path)"
156+
157+
- name: Stop server
158+
if: always()
159+
run: |
160+
if [ -n "$SERVER_PID" ]; then kill "$SERVER_PID" 2>/dev/null || true; fi
161+
cat /tmp/mcp3236-ci/server.log 2>/dev/null || true
162+
163+
- name: Upload server log
164+
if: always()
165+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
166+
with:
167+
name: sandbox-server-log
168+
path: /tmp/mcp3236-ci/server.log
169+
retention-days: 7

.github/workflows/unit-tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ jobs:
173173
cp -r frontend/dist web/frontend/
174174
175175
- name: golangci-lint
176-
uses: golangci/golangci-lint-action@9fae48acfc02a90574d7c304a1758ef9895495fa # v7.0.1
176+
uses: golangci/golangci-lint-action@82606bf257cbaff209d206a39f5134f0cfbfd2ee # v9.2.1
177177
with:
178178
version: v2.6.2
179179
args: --config .github/.golangci.yml --timeout=5m

.pre-commit-config.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,13 @@ repos:
2525
stages: [pre-push]
2626
pass_filenames: false
2727

28+
- id: roadmap-verify
29+
name: Verify ROADMAP.md is up to date
30+
entry: python3 scripts/gen-roadmap.py --check
31+
language: system
32+
pass_filenames: false
33+
files: '^(roadmap\.yaml|ROADMAP\.md|scripts/gen-roadmap\.py|specs/.*/tasks\.md)$'
34+
2835
- id: go-build
2936
name: go build
3037
entry: go build -o /dev/null ./cmd/mcpproxy

CLAUDE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,4 +157,5 @@ tail -f ~/Library/Logs/mcpproxy/main.log # main log (macOS; Linux: ~/.mcpproxy/
157157
- **Windows installer**: [docs/github-actions-windows-wix-research.md](docs/github-actions-windows-wix-research.md). **Prerelease** (`next` branch + `v*-rc.*` tags, opt-in, off stable channels): [docs/prerelease-builds.md](docs/prerelease-builds.md).
158158

159159
## Recent Changes
160+
- 077-scanner-simplification: Added Go 1.24 (backend/core), TypeScript 5.9 / Vue 3.5 (frontend Web UI) + Existing only — `internal/security/detect` (stdlib + `golang.org/x/text/unicode/norm`, already an indirect dep), `internal/security/scanner`, BBolt (scanner records + tool approvals), Bleve (index, untouched), zap (logging). **No new third-party dependency.**
160161
- 076-deterministic-tool-scanner: Added Go 1.24 + stdlib only for detection (`unicode`, `unicode/utf8`, `encoding/base64`, `encoding/hex`, `regexp`); `golang.org/x/text/unicode/norm` (already an indirect dep via x/text) for NFKC; existing `internal/security/patterns/`, `internal/security/scanner/`, `internal/runtime/tool_quarantine.go`. No new third-party dependency.

0 commit comments

Comments
 (0)