fix(pipeline): escape dynamic edge properties as JSON - #1065
Conversation
a88ccc4 to
67433fc
Compare
|
Thanks for the focused JSON escaping fix. This is a high-priority 0.9.1-rc graph-correctness PR. Review will verify that dynamic edge properties are escaped identically in sequential and parallel paths and that quotes, backslashes, control characters, and non-ASCII values remain valid round-trip JSON. |
Add cbm_pipeline_set_version() to stamp a version label (e.g. '28.0', '30.0') on every node emitted during indexing. Versioned runs bypass the incremental path so both versions accumulate side-by-side in the graph. Add diff_versions MCP tool: given a project, from_version, and to_version, returns added and removed node names (default label: Class, limit 500 per side) using OPTIONAL MATCH anti-join queries. Also auto-derives version from trailing numeric path segment in index_repository (e.g. /exports/MyApp/28.0 → version='28.0') when the version param is omitted. Refs DeusData#1065 Signed-off-by: Thomas Dyar <tdyar@intersystems.com>
Add cbm_pipeline_set_version() to stamp a version label (e.g. '28.0', '30.0') on every node emitted during indexing. Versioned runs bypass the incremental path so both versions accumulate side-by-side in the graph. Add diff_versions MCP tool: given a project, from_version, and to_version, returns added and removed node names (default label: Class, limit 500 per side) using OPTIONAL MATCH anti-join queries. Also auto-derives version from trailing numeric path segment in index_repository (e.g. /exports/MyApp/28.0 → version='28.0') when the version param is omitted. Refs DeusData#1065 Signed-off-by: Thomas Dyar <tdyar@intersystems.com>
Add cbm_pipeline_set_version() to stamp a version label (e.g. '28.0', '30.0') on every node emitted during indexing. Versioned runs bypass the incremental path so both versions accumulate side-by-side in the graph. Add diff_versions MCP tool: given a project, from_version, and to_version, returns added and removed node names (default label: Class, limit 500 per side) using OPTIONAL MATCH anti-join queries. Also auto-derives version from trailing numeric path segment in index_repository (e.g. /exports/MyApp/28.0 → version='28.0') when the version param is omitted. Refs DeusData#1065 Signed-off-by: Thomas Dyar <tdyar@intersystems.com>
|
The fix is correct and I want to land it — escaping parser-derived strings through The test as written is a vacuous guard. I verified it: reverting both production changes (the To make it a genuine reproduce-first guard, the fixture needs a value that actually breaks JSON when unescaped — e.g. an import whose Could you add that? Once the test is RED-without-the-fix I'll merge immediately — the production change is already good. Thanks for closing a real JSON-corruption gap. |
6392ffb to
f809e98
Compare
|
Thanks — addressed. The fixture now includes a GraphQL operation with a literal double quote ( I also cleaned the branch onto current |
f809e98 to
4811126
Compare
|
Thanks for addressing the vacuous regression and for cleaning the branch. Current head |
Add cbm_pipeline_set_version() to stamp a version label (e.g. '28.0', '30.0') on every node emitted during indexing. Versioned runs bypass the incremental path so both versions accumulate side-by-side in the graph. Add diff_versions MCP tool: given a project, from_version, and to_version, returns added and removed node names (default label: Class, limit 500 per side) using OPTIONAL MATCH anti-join queries. Also auto-derives version from trailing numeric path segment in index_repository (e.g. /exports/MyApp/28.0 → version='28.0') when the version param is omitted. Refs DeusData#1065 Signed-off-by: Thomas Dyar <tdyar@intersystems.com>
542bb6c to
0ab6f1d
Compare
Add cbm_pipeline_set_version() to stamp a version label (e.g. '28.0', '30.0') on every node emitted during indexing. Versioned runs bypass the incremental path so both versions accumulate side-by-side in the graph. Add diff_versions MCP tool: given a project, from_version, and to_version, returns added and removed node names (default label: Class, limit 500 per side) using OPTIONAL MATCH anti-join queries. Also auto-derives version from trailing numeric path segment in index_repository (e.g. /exports/MyApp/28.0 → version='28.0') when the version param is omitted. Refs DeusData#1065 Signed-off-by: Thomas Dyar <tdyar@intersystems.com>
|
Thank you for this — the production fix is exactly right and we want it. One problem with the regression test, and then it merges. What is correct. Both sites interpolated parser-derived text straight into JSON You reused I tried to break it and could not. Bare quote, trailing backslash, control characters, embedded NUL, and a crafted-length truncation attack are all contained post-fix. The round trip is clean too: encoded once, bound verbatim through the parameterised The problem: the regression test passes with and without your fix. The fixture uses a multiline triple-quoted Python string. That operation never reaches The same applies to the mechanism described in the PR body: a multiline operation producing malformed JSON is end-to-end unreachable. The genuinely reachable vector is a bare double quote on a single line — which is a better bug than the one you described, and your fix already handles it. The change I would like, and then this goes in: return gql('query GetUser { user(name: "quoted") { id name } }')A single-quoted Python string, so the inner double quote survives extraction, and every character is ≥ 0x20 so validation passes it through. Pre-fix that emits Please confirm it fails with the production hunks reverted before pushing. That revert-check is the whole point of the exercise here — a green test that would also be green without the fix tells us nothing later. Two smaller notes, neither blocking:
One thing I noticed while reviewing that is not yours: |
Escape import aliases and GraphQL operation strings before serializing edge properties, preventing raw control characters and quotes from producing malformed JSON. Add a reachable single-line GraphQL regression fixture and assert that emitted edge properties remain valid JSON. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: tmonestudio <tmonestudio@users.noreply.github.com>
0ab6f1d to
2d6766f
Compare
|
Updated as requested. The fixture now uses the reachable single-line, single-quoted Python form, so the embedded double quote reaches I also ran the explicit sensitivity check before pushing the final branch:
The PR is now rebased on current |
What does this PR do?
Prevents malformed JSON in edge properties when parser-derived values contain JSON-significant characters.
Two edge builders serialized dynamic strings directly:
local_namewithout escaping (defence-in-depth; import aliases are identifier-shaped);The reachable GraphQL reproduction is a single-line, single-quoted Python string whose operation contains a bare double quote.
Fix
Use the existing
cbm_json_escapehelper for both dynamic values before formatting the properties object.The regression fixture keeps the whole-table
json_valid(properties)invariant and now passes an embedded quote through extraction toemit_graphql_edge.Validation
contract_edge_parallel_service_edgesreportsinvalid_props == 1.Checklist
git commit -s)