Commit Graph

4 Commits

Author SHA1 Message Date
funman300 fc411bb6f1 scripts: require one certificate across the whole FIFA-facing TLS stack
Two live gates were lost to a second variable I had been asked to eliminate.
The Rust redirector was pointed at the repo's fifa17-recon/tools/redir_cert.pem
(fingerprint F9:16:1A...), while the running container serves a different cert
baked into its image (E7:F9:46...) which the Python redirector, roster and the
rest of the stack all share. So the A/B compared TLS implementation AND
certificate identity at once.

FIFA 17's ProtoSSL caches the server certificate for a backend. The redirector
is the first TLS connection of a session, so its cert becomes the one the client
expects; the next service presenting a different cert fails its handshake. That
is why the redirect itself always succeeded and the failure surfaced later, on
the roster fetch -- "An error occurred downloading the FUT Squad Update".

It stayed invisible because Python's socketserver swallows it: a handshake
failure at accept() raises ssl.SSLError, which subclasses OSError and is
discarded by _handle_request_noblock. No request log, no stderr. Every server
looked healthy while the client could not talk to any of them.

Confirmed on the wire: tls-observe in front of the roster server captured four
ClientHellos from the client, correct SNI and the same 8 static-RSA suites it
offers the redirector, none of which produced a request.

The check is mutation-tested against the real bug: with a redirector started on
the stale repo cert it exits 1 and names the mismatch.
2026-08-11 04:38:23 +00:00
funman300 5bc39e902d tooling: observe client connection ATTEMPTS; make the build guard reject bad args
openfut-observe.sh answers the one question no server log can: when a gate
fails and a service logged nothing, did the client try and fail, or never try?
Both look like silence. Two redirector gates were lost to that ambiguity --
"roster server logged nothing" was equally consistent with a broken roster
service, a wrong roster URL, and a client that never asked.

Built on iptables packet counters because this box has no tcpdump, no
conntrack, and no readable kernel log. That last one is verified rather than
assumed: an initial LOG-based version installed correctly and its rules matched
(counters proved it), but the output went nowhere -- journalctl -k has no
entries and dmesg is empty. Counters are also lower volume and record only SYNs,
so no payload can be captured even in principle.

Validated against the live client, not a loopback stand-in: an initial
self-test using this host's own address counted almost nothing, because
locally-generated packets never traverse PREROUTING. Against the real remote
client it counts 8081 at ~4/min, matching the roster server's own log.

Known gap, recorded rather than hidden: the catch-all TOTAL runs well above the
sum of the named ports, so the client makes steady background attempts to ports
not tracked here. It is present during a working session, so it is not the
failure signature, and it is not chased further here.

verify-build-identity.sh now rejects an argument that is not a commit hash.
Passing the binary path instead of its stamp previously produced a plausible
"REFUSING: binary was built from ./target/release/... but HEAD is <sha>", which
reads as a real stale-build finding rather than a caller mistake -- and a
safeguard that cries wolf is one people learn to route around. Usage error is
now exit 2, distinct from a genuine stale build (1) and success (0).
2026-08-11 04:22:40 +00:00
funman300 c03702707b redirector: commit stamp + shared build-identity verifier that REFUSES
The binary records only the commit it was built from -- no dirty-tree flag.
Cargo will not re-run a build script because another crate's source changed, so
a compiled-in 'clean' claim can be stale and is not a safeguard; that was
verified on the Blaze host.

scripts/verify-build-identity.sh establishes both facts at LAUNCH, where they
cannot go stale: the stamped commit equals HEAD, and the migration crates are
clean. It REFUSES rather than warns, because for a migration gate a warning on
stderr is something to scroll past.

--identity prints the stamp without valid configuration. The launcher must be
able to establish which commit a binary came from BEFORE deciding whether to
run it; requiring a correct environment first would invert the check.

redirector.sh mirrors sidecar.sh: refuses to start with an orphan present or
the port busy, matches the resolved executable rather than the command line
(pgrep -f matches any shell mentioning the name), and stop PROVES the process
is gone and the port free.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-11 03:46:07 +00:00
funman300 8f5f54833f ci: tripwire against lab addresses creeping back into tracked source
Cheap insurance, explicitly not the real check -- the semantic tests in
deployment_config.rs are what prove propagation, using two TEST-NET addresses
and bind != advertise. This grep only stops the lab subnet reappearing months
from now when the reasoning has been forgotten.

Deployment config legitimately contains real addresses and lives in gitignored
files, so it is never scanned. The frozen baseline doc is allowlisted BY PATH:
it records what a past deployment actually was, and rewriting it would falsify
the record.

Also swapped the lab IP for a TEST-NET placeholder in the usage examples and
error messages of compose/entrypoint/client_arm. Those were already correct
architecture -- every one requires the address via ${VAR:?} -- but using the
real lab IP as the example is the same 'happens to match our lab' smell, and
placeholders keep the tripwire allowlist near-empty.

Mutation-tested: adding a lab address to a source file makes it exit 1.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-11 02:59:41 +00:00