[pkg firewall] add the VS Code product.json patch lifecycle - #26
Open
dekkagaijin wants to merge 1 commit into
Open
[pkg firewall] add the VS Code product.json patch lifecycle#26dekkagaijin wants to merge 1 commit into
dekkagaijin wants to merge 1 commit into
Conversation
Second code chunk. Builds on the JSON primitives to give discovery, a
three-state machine, and patch/restore. Still nothing calls it — the generator
wiring is a later change — so this can be reviewed as the state machine it is.
vscode_install_paths stable and Insiders, macOS/Linux
vscode_edition_label from nameLong, so output names the edition
vscode_is_readonly_install snap/flatpak by path prefix
vscode_can_write probes without modifying
vscode_node_bin VS Code's own Electron, via CFBundleExecutable
vscode_managed_state unmanaged | current | stale
vscode_marker_field reads the marker, single-line or pretty-printed
vscode_patch / vscode_unpatch
vscode_patch_via_node / vscode_unpatch_via_node
The patch is one key set and one key removed:
serviceUrl -> the firewall's gallery URL. VS Code derives both
${serviceUrl}/extensionquery and
${serviceUrl}/vscode/{publisher}/{name}/latest from it.
extensionUrlTemplate -> removed. It is the fallback when the resource API
returns 5xx. Left in place, a firewall outage
silently resolves versions from www.vscode-unpkg.net,
bypassing the firewall exactly when it is unhealthy.
Removed, that failure retries our own extensionquery
and fails the install if that also fails.
controlUrl (Microsoft's malicious-extension revocation list), resourceUrlTemplate,
itemUrl, publisherUrl, nlsBaseUrl, mcpUrl and accessSKUs are left alone, and the
merge is key-level, so keys future VS Code versions add survive untouched.
Three states, because credentials rotate:
unmanaged marker absent -> capture the original, then patch
current marker + expected line -> no write at all
stale marker but not current -> restore first, *then* patch
Never patching on top of a patch is the invariant that lets credentials rotate
indefinitely without the captured original drifting.
Failure modes are loud rather than silent, because a silent no-op is
indistinguishable from success in an MDM log:
- An unwritable product.json on macOS almost always means the missing App
Management (TCC) grant, and says so. Root is not exempt from that gate.
- snap/flatpak installs are refused by path prefix, not by [[ -w ]] — under
root that test returns true on a read-only mount.
- Not line-oriented (repackaged, minified) falls back to VS Code's own bundled
Electron as node. Never hardcodes "Electron": stable ships "Code".
- --dry-run redacts the _ak token. A deliberate deviation from the other
ecosystems, which echo full credentialed URLs: this one is a bearer
credential in a URL path, and MDM consoles retain output for more people
than can read product.json.
Tests: 60 assertions covering the full state machine, both writer paths, the
EPERM/TCC message, the snap refusal, dry-run redaction, and byte-exact restore
after two patch cycles. Also patches and restores whichever real product.json is
installed on the machine, asserting nothing version-specific.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
dekkagaijin
force-pushed
the
vscode-fw-3-lifecycle
branch
from
August 6, 2026 16:10
1124b90 to
1f2193e
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Merge after #25
Second code chunk. Builds on the JSON primitives to give discovery, a three-state machine, and patch/restore. Still nothing calls it — the generator wiring is a later change — so this can be reviewed as the state machine it is.
vscode_install_paths stable and Insiders, macOS/Linux
vscode_edition_label from nameLong, so output names the edition
vscode_is_readonly_install snap/flatpak by path prefix
vscode_can_write probes without modifying
vscode_node_bin VS Code's own Electron, via CFBundleExecutable
vscode_managed_state unmanaged | current | stale
vscode_marker_field reads the marker, single-line or pretty-printed
vscode_patch / vscode_unpatch
vscode_patch_via_node / vscode_unpatch_via_node
The patch is one key set and one key removed:
serviceUrl -> the firewall's gallery URL. VS Code derives both
${serviceUrl}/extensionquery and
${serviceUrl}/vscode/{publisher}/{name}/latest from it.
extensionUrlTemplate -> removed. It is the fallback when the resource API
returns 5xx. Left in place, a firewall outage
silently resolves versions from www.vscode-unpkg.net,
bypassing the firewall exactly when it is unhealthy.
Removed, that failure retries our own extensionquery
and fails the install if that also fails.
controlUrl (Microsoft's malicious-extension revocation list), resourceUrlTemplate, itemUrl, publisherUrl, nlsBaseUrl, mcpUrl and accessSKUs are left alone, and the merge is key-level, so keys future VS Code versions add survive untouched.
Three states, because credentials rotate:
unmanaged marker absent -> capture the original, then patch
current marker + expected line -> no write at all
stale marker but not current -> restore first, then patch
Never patching on top of a patch is the invariant that lets credentials rotate indefinitely without the captured original drifting.
Failure modes are loud rather than silent, because a silent no-op is indistinguishable from success in an MDM log:
Tests: 60 assertions covering the full state machine, both writer paths, the EPERM/TCC message, the snap refusal, dry-run redaction, and byte-exact restore after two patch cycles. Also patches and restores whichever real product.json is installed on the machine, asserting nothing version-specific.
https://endorlabs.atlassian.net/browse/LM-452