Skip to content

[pkg firewall] Vscode firewall tests - #23

Draft
dekkagaijin wants to merge 2 commits into
mainfrom
vscode-firewall-tests
Draft

[pkg firewall] Vscode firewall tests#23
dekkagaijin wants to merge 2 commits into
mainfrom
vscode-firewall-tests

Conversation

@dekkagaijin

Copy link
Copy Markdown
Contributor

No description provided.

dekkagaijin and others added 2 commits August 6, 2026 16:41
Routes VS Code and VS Code Insiders extension traffic through the Endor Package
Firewall on macOS, Linux and Windows, by patching the extensionsGallery object in
product.json.

Why product.json and not the ExtensionGalleryServiceUrl enterprise policy — that
policy looks like the obvious fit, but (a) it expects the URL to return an
IExtensionGalleryManifest document rather than a marketplace API root, (b) VS Code
gates it behind a signed-in GitHub account holding a Copilot Business/Enterprise
seat, and a failed gate disables the Extensions view entirely, and (c) it is never
consulted by `code --install-extension`. Details and what would unblock it are in
package-firewall/docs/vscode-enterprise-policy.md.

The patch sets one key and removes one:

  serviceUrl            -> the firewall's /firewall/vscode/_ak/<token> endpoint;
                           VS Code derives both /extensionquery and
                           /vscode/{publisher}/{name}/latest from it
  extensionUrlTemplate  -> removed. It is the fallback VS Code uses when the
                           resource API returns 5xx; left in place, a firewall
                           outage would silently resolve versions straight from
                           www.vscode-unpkg.net. Removing it redirects that
                           failure into the firewall's own extensionquery.

controlUrl (Microsoft's malicious-extension revocation list), resourceUrlTemplate,
itemUrl, publisherUrl, nlsBaseUrl, mcpUrl and accessSKUs are deliberately left
alone, and the writer merges key-by-key so keys added by future VS Code versions
survive.

Because product.json is JSON it can carry neither a sentinel comment nor an env-var
reference, so the managed marker is a top-level key that also stores the original
extensionsGallery verbatim — removal restores it byte-for-byte. Re-running is a
no-op when current; a rotated credential is detected as stale and triggers
restore-then-patch, so the captured original is never lost.

VS Code replaces product.json on every update (monthly for stable, nightly for
Insiders), so an update watcher re-applies the patch: launchd WatchPaths on macOS,
a systemd .path/.timer pair (or hourly cron) on Linux, a Scheduled Task on Windows.
The remaining race is made countable via repatch_count rather than left invisible.

New prerequisites, called out in the READMEs:

  - macOS Ventura+ needs the App Management (SystemPolicyAppBundles) TCC grant for
    the MDM agent; root is not exempt. The script detects EPERM and says so.
  - The gallery token lands in world-readable product.json and cannot not — VS Code
    offers no indirection. Use a dedicated, separately revocable API key.
  - Extension downloads still come from Microsoft's CDN by design, so *.vsassets.io
    and *.vscode-unpkg.net must stay reachable.
  - codesign --verify will report the bundle as modified. Expected; do not re-sign.

endor-vscode.* is deliberately not folded into endor-all.*: it is the only script
that writes inside an application bundle and the only one installing a persistent
daemon.

Also fixes stale documentation predating the user-attribution change: the
placeholder tables conflated generation-time and install-time tokens, and both
READMEs still described pip/uv/go credentials as env-var references.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
321 assertions across 7 suites covering the JSON editing primitives, the
patch/restore lifecycle, the update watcher, and the generated scripts end to
end. `cd package-firewall/tests && ./run-all.sh`.

VS Code is the first ecosystem worth testing. The others append a
sentinel-delimited block to a file nothing else rewrites; product.json is JSON
(so the marker has to be a JSON key carrying the byte-exact original), it lives
inside a signed bundle that every update replaces wholesale, and two
independent implementations plus a node fallback on each side must produce
interchangeable output. Each of those is a place to get byte-level fidelity
wrong in a way no review catches.

These caught six real bugs during development, all fixed before the ecosystem
landed:

  - a gawk-only for-init that BSD awk rejects outright
  - trailing-newline fidelity: shipped product.json has none, awk always adds
    one, which alone made byte-exact restore impossible
  - the node writer's pretty-printed marker being unreadable by the
    single-line marker parser, silently breaking restore on that path
  - set -e aborting the generated script on the benign "already current" return
  - PowerShell's ConvertFrom-Json accepting trailing commas, precisely the
    malformation the comma rewrite can produce
  - the PS template recomputing the attributed token in repatch mode, where no
    console user exists, minting a token attributed to nobody

Purely additive: no product code changes. The generators write to
out/<namespace> with no override, so the e2e suites copy the working tree to a
temp directory and generate there, leaving the checkout clean.

Target is a synthetic fixtures/product.json rather than an installed one, so
assertions like "16 accessSKUs" don't start failing on VS Code's release
schedule. Both lib suites additionally patch and restore whichever real
product.json is present, asserting nothing version-specific. Neither e2e suite
will execute until it has verified that install discovery is redirected into
its sandbox.

Windows-only surfaces — Scheduled Task registration and %ProgramFiles% /
AppData discovery — are reported as skipped, never as passed. They still need a
Windows box.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@dekkagaijin
dekkagaijin force-pushed the vscode-firewall-tests branch from d89ad93 to 054118c Compare August 6, 2026 23:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant