Repository navigation
Test the secret-path gate the README's security model rests on - #3
Merged
Merged
Conversation
server.py states the whole security model in its docstring: the transport is
mounted at an unguessable URL path, and that path is the gate because ChatGPT's
connectors cannot send an Authorization header. Nothing tested it. A gate that
quietly stops gating looks exactly like one that works, and this server is
deliberately exposed through an ngrok tunnel.
tests/test_secret_path_gate.py drives SecretPathAuth as plain ASGI middleware
with a stub downstream app -- no uvicorn, no COM, no AutoCAD. 14 cases:
- the exact secret path and paths beneath it pass through;
- unrelated paths, the root, and the secret appearing later in the path 404;
- `/<secret>x`, `/<secret>-extra` and `/<secret>.json` 404. A bare
startswith(prefix) check would admit all three and turn the secret into a
guessable stem, so this is the case worth pinning down;
- non-http scopes (lifespan, websocket) pass without being path-checked;
- a wrong bearer is 401, a right one passes, a missing one passes by design;
- a wrong bearer on a wrong path is still 404, so a bad path cannot be used
to probe the token.
tests/test_config.py gains 8 cases for _load_or_create_secret. The connector
URLs pasted into ChatGPT and Manus embed the secret path, so if a restart
regenerated it every connector would start 404ing with no obvious cause:
generated once and written, reused on the next start, read back without the
trailing newline, blank file replaced, env override wins and writes no file,
override beats a stored secret, generated values do not repeat, and MCP_PATH
derives from the secret.
The tests were checked against deliberately broken copies rather than just run
green. Replacing the prefix check with a bare startswith fails 4; removing the
bearer check fails 2; skipping the path check entirely fails 8; dropping the
.secret reuse fails 2; ignoring the env override fails 3.
The repo had no CI, so none of this would run on its own. The workflow uses
windows-latest -- config and tools deal in Windows paths and server imports
pywin32 -- and adds compileall and a PowerShell parse check. Actions are pinned
by SHA, matching helios-llm-orchestrator.
No production code changes in this commit.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Tests for the request gate and for secret-path persistence, plus the repo's first CI workflow. No production code changes —
server.pyandconfig.pyare untouched.tests/test_secret_path_gate.py— 14 new cases forserver.SecretPathAuthtests/test_config.py— 8 new cases forconfig._load_or_create_secret.github/workflows/ci.yml— newWhy
server.pystates the entire security model in its module docstring:That is asserted, and it was never tested. This server is deliberately exposed through an ngrok tunnel, so the path check is the only thing standing between the open internet and a COM handle on AutoCAD. A gate that quietly stops gating looks exactly like one that works.
The case most worth pinning down is prefix confusion. The current check is correct:
but the natural "simplification" to a bare
path.startswith(self.prefix)would admit/<secret>x,/<secret>-extraand/<secret>.json— turning the secret from a password into a guessable stem. Nothing would have caught that.Secret persistence matters for a less dramatic but more likely failure: the connector URLs pasted into ChatGPT and Manus embed the secret path. If a restart regenerated it, every connector would start 404ing with no obvious cause.
Coverage
SecretPathAuth— driven as plain ASGI middleware with a stub downstream app, so no uvicorn, no COM, no AutoCAD:/, and the secret appearing later in the path → 404/<secret>x,/<secret>-extra,/<secret>.json→ 404Bearerscheme → 401; surrounding whitespace tolerated_load_or_create_secret— generated once and written; reused on the next start; read back without the trailing newline; blank file replaced; env override wins and writes no file; override beats a stored secret; generated values do not repeat across 5 runs;MCP_PATHderives from the secret.How it was verified
python -m unittest discover -s tests -t .→ 37 tests, OK (Python 3.13, Windows).These are new tests for existing correct code, so "fails on the old code" does not apply directly. Instead each was checked against a deliberately broken copy, rather than just run green:
startswith(self.prefix).secretreuse removedserver.pyandconfig.pywere restored byte-identical afterwards (git diffclean).Every CI step was also dry-run locally:
pip install -r requirements.txtdeps already present,compileallclean, the test suite green, and the PowerShell parse step run in a real PowerShell —ok: run.ps1,ok: start_ngrok.ps1. Both pinned action SHAs were confirmed to be exactly the currentv4/v5tags via the GitHub API.What was not verified
tools.pyandacad.pyare only byte-compiled, not exercised.build_app()is never called, so the real FastMCP transport, the/healthroute, and uvicorn's own request handling are out of scope here.windows-latestyet — this is the first workflow in the repo. Local verification was Windows 11 / Python 3.13, which is the same shape.Follow-ups, not folded in
!=, which is not timing-safe;hmac.compare_digestwould be better. Left out deliberately — it is a behaviour-identical hardening change, so no test can fail on the old code, and mixing it in would make this PR two things. Happy to send it separately.LICENSEfile. That is the owner's choice, not mine to make.