Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,7 @@ htmlcov/
.coverage.*
coverage.xml
*.cover

# Runtime artifacts
*.db
audit.db
23 changes: 14 additions & 9 deletions src/cmcp_runtime/mcp/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,15 +206,20 @@ async def _handle_mcp(self, request: Request) -> Response:
"""Handle MCP JSON-RPC 2.0 calls."""
# DOS-001: reject oversized requests before parsing to prevent OOM
content_length = request.headers.get("content-length")
if content_length and int(content_length) > self._max_request_bytes:
return JSONResponse(
{
"jsonrpc": "2.0",
"error": {"code": -32600, "message": "Request body too large"},
"id": None,
},
status_code=413,
)
if content_length:
try:
cl = int(content_length)
except ValueError:
return JSONResponse({"error": "invalid Content-Length"}, status_code=400)
if cl > self._max_request_bytes:
return JSONResponse(
{
"jsonrpc": "2.0",
"error": {"code": -32600, "message": "Request body too large"},
"id": None,
},
status_code=413,
)
try:
body = await request.body()
if len(body) > self._max_request_bytes:
Expand Down
6 changes: 6 additions & 0 deletions src/cmcp_verify/opaque.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,12 @@ def verify_opaque_measurement(
result.details["hint"] = "raw_evidence not provided; cannot verify with Opaque"
return result

if not endpoint or not endpoint.startswith("https://"):
raise ValueError(
f"Opaque attestation endpoint must use https://. Got: {endpoint!r}. "
"Set CMCP_OPAQUE_ATTESTATION_ENDPOINT to a valid https:// URL."
)

# POST raw_evidence (base64-encoded) to the Opaque attestation endpoint
payload = json.dumps({
"measurement": measurement,
Expand Down
4 changes: 2 additions & 2 deletions tests/unit/test_low_batch_186_187_191_194.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ def test_redact_auth_headers_no_auth_unchanged():

def test_opaque_api_key_not_logged_on_failure(monkeypatch, caplog):
"""HW-008: OPAQUE_API_KEY value must not appear in log output on failure."""
monkeypatch.setenv("CMCP_OPAQUE_ATTESTATION_ENDPOINT", "https://attest.opaque.co/v1/verify")
monkeypatch.setenv("CMCP_OPAQUE_ATTESTATION_ENDPOINT", "https://attest.example.com/v1/verify")
monkeypatch.setenv("OPAQUE_API_KEY", "sk-supersecret-key-do-not-log")
import cmcp_verify.opaque as opaque_mod
importlib.reload(opaque_mod)
Expand All @@ -211,7 +211,7 @@ def mock_urlopen(req, timeout=None):
opaque_mod.verify_opaque_measurement(
"sha384:" + "a" * 96,
b"\x00" * 64,
opaque_endpoint="https://attest.opaque.co/v1/verify",
opaque_endpoint="https://attest.example.com/v1/verify",
)
auth = captured.get("headers", {}).get("authorization")
assert auth == "Bearer test-api-key-12345"
8 changes: 4 additions & 4 deletions tests/unit/test_tdx_opaque_verify.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ def test_opaque_no_endpoint_configured(monkeypatch):


def test_opaque_no_raw_evidence_fails_closed(monkeypatch):
monkeypatch.setenv("CMCP_OPAQUE_ATTESTATION_ENDPOINT", "https://attest.opaque.co/v1/verify")
monkeypatch.setenv("CMCP_OPAQUE_ATTESTATION_ENDPOINT", "https://attest.example.com/v1/verify")
result = verify_opaque_measurement("sha384:" + "a" * 96, None)
assert result.verified is False
assert result.failure_reason == "no_raw_evidence"
Expand All @@ -121,7 +121,7 @@ def test_opaque_endpoint_returns_verified(monkeypatch):
result = verify_opaque_measurement(
"sha384:" + "a" * 96,
b"\x00" * 64,
opaque_endpoint="https://attest.opaque.co/v1/verify",
opaque_endpoint="https://attest.example.com/v1/verify",
)

assert result.verified
Expand All @@ -140,7 +140,7 @@ def test_opaque_endpoint_returns_unverified(monkeypatch):
result = verify_opaque_measurement(
"sha384:" + "a" * 96,
b"\x00" * 64,
opaque_endpoint="https://attest.opaque.co/v1/verify",
opaque_endpoint="https://attest.example.com/v1/verify",
)

assert not result.verified
Expand All @@ -154,7 +154,7 @@ def test_opaque_network_error(monkeypatch):
result = verify_opaque_measurement(
"sha384:" + "a" * 96,
b"\x00" * 64,
opaque_endpoint="https://attest.opaque.co/v1/verify",
opaque_endpoint="https://attest.example.com/v1/verify",
)

assert result.verified
Expand Down
Loading