Add offline TLS identity verification #6
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "issue/5-offline-tls-check"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Scope
Add optional
make tls-checkfor existing operator-supplied certificate/key material. It reads Compose-resolved router arguments and bind source, then performs a bounded in-memory, hostname-verifying TLS handshake using host default trust. It does not provision certificates, establish trust, affectmake up, or close #5. It cannot prove container or browser trust, container key access, deployed startup, or first-admin authority.Validation
python3 -m unittest discover -s tests -v: 16 tests passed on Docker Desktop/WSL2. Includes fixture verification, untrusted CA, wrong hostname, bad/encrypted key, ambiguous and abbreviated arguments, explicit trust-override positive controls, and existing preflight tests.docker compose --env-file .env.example -f compose.yaml config --quietpassed;git diff --checkpassed.Review and limitations
Fresh GPT-6.1 Sol High security review of
57670dfidentified two issues; follow-upd264df43f1467bccb720c44e9194edc5e02ca276addresses both. The independent follow-up COMMENT review found no new actionable findings; these automated reviews are not human approval or merge authorization. No disposable Windows account/VM was established, so native Windows browser and Schannel leaf-trust, consent and removal remain unverified. Secure first-admin authority and atomicity tracked in Creatidy/scarcity-router#242. This PR does not close #5.Automated fresh independent security review by GPT-6.1 Sol High. This is a COMMENT, not an approval or merge authorization.
Exact reviewed comparison:
c8fd679e02e870e0545a082edd10c864d6a1d4ba57670dfcc4e32b17f8ec1696960ff95ec7fb54ebCanonical Forgejo PR metadata and the local clean checkout matched those revisions; I rechecked before posting. I independently inspected the diff and relevant pinned Scarcity Router source contracts, rather than relying on prior review conclusions.
Findings
[P2] Ambiguity detection does not match SR's accepted option syntax (
scripts/tls_check.py:24-28). The checker only counts exact full option names, but the documented SR revision209f7d39f3ecebbd1b98b11d7c44c63192fe50a4constructs a defaultargparse.ArgumentParserinscarcity_router/control_server.py:70-87, with abbreviation enabled and last-value-wins options. A command containing the existing--tls-reload-hostname=example.testfollowed by--tls-reload-host=wrong.testpassesrouter_identity()asexample.test, while SR interprets its effective hostname aswrong.test. The same discrepancy applies to appended--tls-cert=...and--tls-key=.... I reproduced the hostname case through real Compose JSON rendering in a disposable project, then successfully handshook the fixture for the checker's hostname; the upstream-equivalent argument parsing selected the other hostname. This requires a command extension in the Compose file; the untouched committed command does not contain these aliases, and this is not environment-to-shell injection. Nevertheless it defeats the new ambiguity guard and can produce a pass for a different identity from the router's effective arguments. Reject unhandled TLS abbreviations/overrides, or otherwise match the pinned parser's effective argument semantics, and add a regression case.[P3] The default-trust integration test can pass without testing trust (
tests/test_tls_check.py:109-113). Any nonzero result containingTLS check failedsatisfies the assertions, including Docker/Compose absence, malformed interpolation, or another failure before context construction. I confirmed that supplying a synthetic unrelated Compose-failure result makes this test pass. Thus a green test does not prove that the fixture would succeed if its root were accepted, or that removing the environment-override protection would make the test fail. Add a controlled positive-path counterpart and distinguish an unavailable dependency from an actual certificate-verification rejection; also cover a genuinely populated/hashedSSL_CERT_DIR, not onlySSL_CERT_FILE.Verified behavior
git diff --checkpassed; the worktree remained unchanged.Limits and claims
The README and PR correctly limit this to an optional offline, host-side check: no container/browser trust, deployed startup, authenticated onboarding, first-admin authority, or production readiness is established. Host defaults may contain locally installed roots and are not proof of public-CA provenance. The handshake's iteration/traffic bound is not an end-to-end wall-clock or memory bound on certificate-file loading and subprocess output capture. Windows/Schannel behavior, revocation checking, container access, and deployment were not validated in this review. Positive handshakes used generated test-only trust, not modifications to the host trust store.
No repository files were modified, no containers were started, no production credentials were accessed, and no approval, merge, release, or deployment was performed.
Security review disposition: follow-up commit
d264df4rejects noncanonical, split, abbreviated, duplicate and unknown router options rather than guessing SR argparse behavior. Trust-override coverage now has Compose-render and trusted-handshake positive controls, checks both SSL_CERT_FILE and a populated hashed SSL_CERT_DIR, and verifies the rejection actually reaches certificate verification.python3 -m unittest discover -s tests -v: 16 passed;git diff --check: clean. Independent follow-up verification of this head is requested. This remains an optional host-only check, not trust provisioning or local onboarding acceptance.Automated independent follow-up security review by GPT-6.1 Sol High, verifying the fixes to my review #737. This is a COMMENT, not an approval or merge/deployment authorization.
Exact revisions:
c8fd679e02e870e0545a082edd10c864d6a1d4ba57670dfcc4e32b17f8ec1696960ff95ec7fb54ebd264df43f1467bccb720c44e9194edc5e02ca276I checked the follow-up diff against the previously reviewed head and its relationship to the original base. Canonical PR metadata and the clean local checkout matched the follow-up head immediately before posting.
Findings and disposition
Both findings from review #737 are resolved. No new actionable security findings or regressions were found in the follow-up diff.
Original P2, argument ambiguity: resolved (
scripts/tls_check.py:23-37). The checker now requires exactly the six known, full-name, equals-form options, with nonempty values and no duplicates. Unknown options, abbreviations, split forms, terminators, missing options, and positional tokens fail closed. This prevents the prior mismatch with SR's abbreviation-enabled, last-value-wins argparse behavior without pretending to implement a general upstream parser. I independently exercised 156 abbreviated-option cases, all rejected, and all 720 orderings of the valid six-option command, all accepted. The README explicitly documents the narrow command contract and the need to review checker changes alongside command extensions.Original P3, false-green trust test: resolved (
tests/test_tls_check.py:139-176). The test now requires successful real Compose rendering, validates the extracted identity, verifies the fixture with explicit test trust, and exercises positive controls in which the environment override is restored immediately before context creation. The negative control must demonstrate an actualSSLCertVerificationError, rather than just a generic command failure. BothSSL_CERT_FILEand a genuinely hashedSSL_CERT_DIRare covered. I independently confirmed that each override can trust the generated fixture, that the realmain()removes both override variables before constructing its context and rejects that fixture, and that the unrelated Compose-failure result which previously produced a false green now fails the test.Verification
PYTHONDONTWRITEBYTECODE=1 TMPDIR=/tmp/kilo python3 -m unittest discover -s tests -v: 16 tests passed, including all 9 existing preflight tests.git diff --checkpassed for both the complete PR comparison and the follow-up comparison.The TLS handshake implementation, trust-override protection, fixed subprocess argv, output suppression, and Makefile behavior are otherwise unchanged from the original review. The updated README accurately adds that certificate-file loading and captured Compose output are outside the handshake limits, and that revocation status is not established. Host roots still do not establish container/browser trust or public-CA provenance; native Windows/Schannel, deployed startup, container file access, authentication/first-admin authority, and production readiness remain unverified. These fixes do not close issue #5 or establish installation acceptance.
No repository files were modified, no containers were started, and no approval, merge, release, or deployment was performed.
Integration update: merged canonical main (
bed7e1760115a755ed5853a8207484b413c21ec7, PR #7) into this branch asa658d6e18bc5618bd4ef5e85ae948535cc05843f. The only conflict was the Makefile.PHONYline; all targets are retained. README merged automatically plus a clarification thattls-checkis not a prerequisite for local self-signed leaves. Both reviewed TLS implementations and tests are byte-for-byte unchanged from their reviewed heads; canonical Compose andtls_preflight.pyare unchanged. CombinedFOUNDRY_TEST_SR_IMAGE=examples-scarcity-router:latest PYTHONDONTWRITEBYTECODE=1 python3 -m unittest discover -s tests -v: 26 passed, including actual isolated Docker runtime tests. Example Compose config andgit diff --cached --checkpassed. The local test image's source provenance is unverified; prior PR #7 tests against source-pinned SR are documented separately. No new security behavior was introduced by the conflict resolution.