Skip to content

[pkg firewall] JSON editing utilities - #25

Open
dekkagaijin wants to merge 2 commits into
vscode-fw-1-policy-findingsfrom
vscode-fw-2-json-primitives
Open

[pkg firewall] JSON editing utilities#25
dekkagaijin wants to merge 2 commits into
vscode-fw-1-policy-findingsfrom
vscode-fw-2-json-primitives

Conversation

@dekkagaijin

@dekkagaijin dekkagaijin commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Merge after #24

First code chunk of the VS Code ecosystem. TBH I'm not sure we shouldn't just require jq to be installed (and use powershell's json utilities on Windows), but here's what Claude came up with. Nothing calls these yet, they are added with their tests so the byte-fidelity properties can be reviewed on their own (ahead of the lifecycle that uses them).

VS Code's product.json is the only config target here that is JSON, so it can carry neither a '#' sentinel nor an ${ENDOR_*} reference, and it must be edited in place with byte-exact restore. That rules out reserialization, and there is no jq or python3 guarantee on a stock macOS or a minimal Linux image, so these are line-oriented awk editors over the depth-1 object. plutil is not an option either: it reorders every top-level key and minifies, and plutil -lint does not even validate JSON.

endor_b64url / endor_b64d base64url on stdin, matching endor_b64
endor_redact_ak strip the _ak/ path segment
endor_file_has_final_newline
endor_replace_contents_inplace preserves inode, mode, owner and the
source's final-newline state
endor_json_top_string depth-1 scalar, ignoring nested keys
endor_json_extract_top_object raw lines of a depth-1 object
endor_json_merge_object_keys key-level set and delete, commas recomputed
endor_json_replace_top_object verbatim splice-back, for restore
endor_json_insert_top_line / endor_json_remove_top_key
endor_json_validate

Two properties are the whole point, and both are asserted:

  • An edit touches only the keys it claims to. The patch is one key set and one removed; the diff against a pristine file is 3 lines, not a reserialized 2963.
  • Restore is byte-exact. Shipped product.json has no final newline while awk always emits one, so the newline state is normalised back on write — otherwise every patch would dirty the last line and no restore could ever match.

Deleting or appending the last entry in an object must not leave a trailing comma, so the merge recomputes entry-terminating commas rather than editing lines in isolation. On input it cannot handle (minified, not line-oriented) each editor declines with a non-zero return and leaves the file untouched, rather than guessing.

endor_json_validate also rejects trailing commas structurally: node is not always resolvable, and a trailing comma is precisely the malformation a bad comma rewrite produces.

Tests: 43 assertions against a synthetic tests/fixtures/product.json — shaped like a shipped one (tab-indented, LF, no final newline, extensionsGallery at depth 1) but not tied to a VS Code build, so assertions like "16 accessSKUs" don't start failing on VS Code's release schedule. Also covers 4-space indentation, a sole-entry delete, and minified input.

https://endorlabs.atlassian.net/browse/LM-452

First code chunk of the VS Code ecosystem. Nothing calls these yet — they are
added with their tests so the byte-fidelity properties can be reviewed on their
own, ahead of the lifecycle that uses them.

VS Code's product.json is the only config target here that is JSON, so it can
carry neither a '#' sentinel nor an ${ENDOR_*} reference, and it must be edited
in place with byte-exact restore. That rules out reserialization, and there is
no jq or python3 guarantee on a stock macOS or a minimal Linux image, so these
are line-oriented awk editors over the depth-1 object. plutil is not an option
either: it reorders every top-level key and minifies, and `plutil -lint` does
not even validate JSON.

  endor_b64url / endor_b64d          base64url on stdin, matching endor_b64
  endor_redact_ak                    strip the _ak/<token> path segment
  endor_file_has_final_newline
  endor_replace_contents_inplace     preserves inode, mode, owner and the
                                     source's final-newline state
  endor_json_top_string              depth-1 scalar, ignoring nested keys
  endor_json_extract_top_object      raw lines of a depth-1 object
  endor_json_merge_object_keys       key-level set and delete, commas recomputed
  endor_json_replace_top_object      verbatim splice-back, for restore
  endor_json_insert_top_line / endor_json_remove_top_key
  endor_json_validate

Two properties are the whole point, and both are asserted:

  - An edit touches only the keys it claims to. The patch is one key set and one
    removed; the diff against a pristine file is 3 lines, not a reserialized
    2963.
  - Restore is byte-exact. Shipped product.json has no final newline while awk
    always emits one, so the newline state is normalised back on write —
    otherwise every patch would dirty the last line and no restore could ever
    match.

Deleting or appending the last entry in an object must not leave a trailing
comma, so the merge recomputes entry-terminating commas rather than editing
lines in isolation. On input it cannot handle (minified, not line-oriented) each
editor declines with a non-zero return and leaves the file untouched, rather
than guessing.

endor_json_validate also rejects trailing commas structurally: node is not
always resolvable, and a trailing comma is precisely the malformation a bad
comma rewrite produces.

Tests: 43 assertions against a synthetic tests/fixtures/product.json — shaped
like a shipped one (tab-indented, LF, no final newline, extensionsGallery at
depth 1) but not tied to a VS Code build, so assertions like "16 accessSKUs"
don't start failing on VS Code's release schedule. Also covers 4-space
indentation, a sole-entry delete, and minified input.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@dekkagaijin
dekkagaijin force-pushed the vscode-fw-2-json-primitives branch from d41d530 to 20b8435 Compare August 6, 2026 16:10
The harness is sourced, so the constants it defines are read by the suites
and never by the file itself, which shellcheck cannot see from a single-file
lint. Declare that once at the top rather than per variable.

REPO_DIR and FIXTURE_LINES had no reader at all; the 74-line fact is already
recorded in tests/README.md.

run-all.sh runs without -e, so an unguarded cd would have let suite discovery
glob the caller's directory instead of failing.
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