Tracks the school content-filter browser extensions Civil Proxy has to work around, and watches for the moment one of their developers ships a change that specifically reacts to Civil.
extensions.json lists every tracked extension: its Chrome Web Store (or
vendor-hosted) id, its update endpoint, and the last version this repo has
seen. A scheduled workflow
(Monday and Thursday) asks each endpoint what's current using Chrome's own
extension-autoupdate protocol. When a version has moved:
- Downloads the new
.crxand unpacks it. - Runs every
.js/.tmpfile through the same Zig deobfuscator Civil Proxy uses — string-array inlining, constant folding, dead-branch pruning — so the diff in the next step is a diff of readable code, not two different obfuscator outputs that happen to be semantically identical. - Diffs each changed file against the last snapshot (
extensions/<name>/deobfuscated/, gitignored — carried between runs in the Actions cache rather than committed, since twenty-eight vendor bundles rewritten twice a week would bury every real change under regenerated output) and scans the added lines for anything that matches a signature pulled from Civil's ownmisc/filters/filterBlockerMiddleware.ts— a vendor telemetry domain Civil blocks, or a header/event name Civil defined. - If anything matches,
CHANGES_NEEDED.mdgets a section for that extension: what changed, and where in Civil's source it matters. A section disappears on its own once a later release stops tripping the signature that flagged it.
There's no separate first-run/bootstrap step. The first time an extension is checked, there's nothing to diff against yet, so step 3 just records the baseline — nothing is flagged, which is correct: a vendor's code referencing its own domain for the first time you look isn't news. Real detection starts on the next check, once there's an actual change to compare.
All 28 tracked extensions resolve to a real extension id. 21 came from the
Chrome Web Store's own _metadata/verified_contents.json (present in any
extension actually installed from the store). The other 7 use a
vendor-hosted, non-Web-Store update endpoint with no such metadata — those
were resolved by querying the endpoint directly and reading the real appid
back out of its response XML (each one verified against the extension's
locally-recorded version, and Securly's additionally cross-checked against
SECURLY_EXTENSION_ID already hardcoded in Civil's own
src/lib/filterCheckVendors.ts). See tools/README.md for the rest of
what's deliberately out of scope and why.
cd tools
zig build test # unit tests — no network needed
zig build
zig build run -- check --civil-dir /path/to/a/Civil/checkoutNeeds Zig 0.16.0 specifically — the
toolchain snapshot this was built against had a parser regression that broke
on Type{val} ** N syntax; 0.16.0 stable does not have it.