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: |
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 |
|
Thank you for addressing the earlier review points, adding the RED/GREEN sensitivity evidence, and rebasing the branch. I have recorded the update and returned the current diff to the maintainer review queue. A complete review may still take a little time while the community queue is full. |
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>
dd2e9cb to
283321f
Compare
|
Rebased this PR onto current upstream
Local GCC 15 required suppressing two unrelated warnings-as-errors in existing daemon tests ( |
|
CI update: all 34 checks on |
|
Thank you @tmonestudio for rebasing and reporting the pinned verification. The current head This is recorded back in the maintainer review queue. The queue is still full, so the final code review may take some time, but no additional triage information is needed from you right now. |
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)