[GH-ISSUE #3955] [Bug] Version comparison accepts managed static facts with runtime locations #1563

Closed
opened 2026-10-16 21:07:11 +00:00 by bsakaguchi · 1 comment
Owner

Originally created by @coygeek on GitHub (Oct 15, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/3955

Before submitting

  • I searched the open and closed issues for a related report.
  • I removed credentials, tokens, private paths, and sensitive target data.

Area

Evidence, artifacts, or reconstruction

Observed behavior

rea compare-application-versions accepts caller-supplied managed projection Evidence containing an observed, exact managed-static-analysis fact at a runtime location. Its successful comparison returns that same contradictory fact in the change graph. The graph contract forbids static authorities from claiming runtime locations. The equivalent AST static-analysis input is rejected.

Reproduction

Run the following from the baseline checkout with its dependencies installed and runtime built. It creates a one-method graph, generates all semantic commitments for each input, wraps each graph in two distinct managed projection Evidence records, and invokes the public comparison CLI. The fixture uses an isolated home directory and synthetic digest values; it does not read an assembly or obtain runtime observations.

fixture_dir="$(mktemp -d)"
mkdir -p "$fixture_dir/home"
HOME="$fixture_dir/home" node --input-type=module - "$fixture_dir" <<'NODE'
import { writeFileSync } from 'node:fs';
import { resolve } from 'node:path';
import { spawnSync } from 'node:child_process';
import { createJavaScriptApplicationNode } from './dist/domain/javascript/javascriptApplicationGraph.js';
import { digestCanonicalValue } from './dist/domain/canonicalDigest.js';
import { createEvidence } from './dist/domain/evidence.js';

const output = process.argv[2];
const sha = '1'.repeat(64);
const link = `ev_${'2'.repeat(64)}`;
const coverage = { status: 'complete', truncated: false, omitted_count: 0, limits: [] };
for (const authority of ['managed-static-analysis', 'ast-static-analysis', 'passive-cdp-runtime']) {
  const node = createJavaScriptApplicationNode({
    kind: 'managed-method',
    identity: {
      strategy: 'artifact-local-key', stability: 'artifact-version',
      artifact_sha256: sha, namespace: 'managed-method', key: 'Example.Main'
    },
    observations: [{ label: 'Example.Main', properties: {}, evidence: {
      authority, state: 'observed', confidence: 'exact',
      artifact: { available: true, artifact_id: `art_${sha}`, sha256: sha },
      location: { available: true, value: {
        kind: 'runtime', capture_sha256: '3'.repeat(64),
        target_key: 'target', frame_key: null, script_key: null
      } },
      extractor: { name: 'fixture', version: '1', operation: 'fixture', executable_sha256: null },
      coverage, limitations: [], evidence_ids: [link]
    } }]
  });
  const content = {
    schema: 'JavaScriptApplicationGraph', root_node_ids: [node.node_id],
    nodes: [node], edges: [], coverage, limitations: []
  };
  const graph = {
    ...content,
    graph_id: `jag_${digestCanonicalValue(content, 'JavaScript Application Graph')}`
  };
  const result = {
    projection_id: `magp_${'4'.repeat(64)}`, root_artifact_sha256: sha,
    source_evidence: {
      managed_artifact_evidence_id: null,
      managed_members_evidence_id: link,
      managed_native_boundaries_evidence_id: null
    },
    summary: {
      graph_nodes: 1, graph_edges: 0, assemblies: 0, modules: 0, types: 0,
      methods: 1, fields: 0, pinvoke_imports: 0, native_implementations: 0
    },
    graph, coverage: { status: 'complete-within-inputs' },
    evidence_links: [link], limitations: []
  };
  const envelope = side => createEvidence(undefined, {
    id: 'rea-dotnet-workflows', name: 'REA managed-code workflows', version: '1'
  }, {
    predicateType: 'rea.managed-application-graph',
    operation: 'project_managed_application_graph', parameters: { side },
    result, confidence: 'inferred', authority: 'analyst-inference', evidenceLinks: [link]
  });
  const input = resolve(output, `${authority}.json`);
  writeFileSync(input, JSON.stringify({ left: envelope('left'), right: envelope('right') }));
  const run = spawnSync(process.execPath, [
    'scripts/rea.mjs', 'compare-application-versions', input, '--json'
  ], { encoding: 'utf8', timeout: 30000, env: { ...process.env, REA_LOG_LEVEL: 'silent' } });
  if (run.error) throw run.error;
  const response = JSON.parse(run.stdout);
  const fact = response.normalized_result?.graph.nodes[0]?.observations[0]?.evidence;
  console.log(JSON.stringify({
    authority, exit: run.status, summary: response.normalized_result?.summary,
    retained_authority: fact?.authority, retained_location: fact?.location.value?.kind,
    code: response.code, issues: response.details?.issues
  }));
}
NODE

Expected behavior

The comparison must reject the managed static fact's runtime location as invalid input, just as it rejects the AST static fact's runtime location. Managed inspection supplies static metadata rather than observations of CLR execution. A genuine runtime-authority fact with runtime coordinates must remain admissible, and managed facts with valid static coordinates must remain usable.

Impact and scope

A bounded input-validation defect allows contradictory provenance coordinates into a successful, validated comparison graph. The returned authority remains managed static analysis. No severe incident, execution claim from a real producer, or security boundary crossing was established.

Workaround: A caller could potentially validate authority/location combinations before submitting Evidence, but no existing external validation workflow was tested. The comparison command itself accepts the contradictory combination.

Assessment: P2.

REA version

rea 6.5.0 at source commit 4692bb3330

Runtime and platform

Node 24.18.0; macOS arm64

Target and artifact context

Synthetic authenticated managed projection Evidence containing a one-method graph. No assembly inspection or runtime observation was performed.

Interface

CLI

Earliest failure stage

Request parsing or validation

Relevant output or evidence

Observed one CLI invocation for each case. The managed static input exited 0 and returned {"unchanged":1,"added":0,"removed":0,"changed":0,"unknown":0}. Its returned graph retained authority: "managed-static-analysis", state: "observed", confidence: "exact", and location.value.kind: "runtime".

The AST static control exited 1 with code invalid_request, category invalid_input, and the message Static and native authorities cannot claim a runtime location at left.normalized_result.graph.nodes[0].observations[0].evidence.location. The passive CDP runtime control exited 0. These controls distinguish the missing managed-authority check from an invalid envelope, a mismatched commitment, or general rejection of runtime locations.

The observed defect concerns validation and propagation of supplied Evidence. No real assembly analysis, runtime capture, or MCP execution was performed, and this reproduction does not establish that the normal managed projection producer emits contradictory locations.

The existing focused graph test passed when run with npx vitest run src/domain/javascript/javascriptApplicationGraph.test.ts -t 'prevents static authorities from claiming runtime locations': one passed, 18 skipped. Its static-location exclusion case covers AST authority, which also rejects the runtime location through the public CLI control.

Typed outcome or recovery expected

Rerun the fixture through the public CLI. The managed static case must return an invalid-input diagnostic identifying the runtime location instead of a successful comparison graph containing that fact. The AST static case must continue to reject its runtime location, and the passive CDP runtime case must continue to succeed. Also confirm that a managed static fact using valid artifact or source coordinates still compares successfully, so restoration preserves supported managed analysis.

Additional context

Freshness checked against origin/main at 22ec8bdb2f. The cited failing implementation files are unchanged from the reproduced baseline; this is a source freshness check, not a runtime rerun on that revision.

Originally created by @coygeek on GitHub (Oct 15, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/3955 ### Before submitting - [x] I searched the open and closed issues for a related report. - [x] I removed credentials, tokens, private paths, and sensitive target data. ### Area Evidence, artifacts, or reconstruction ### Observed behavior `rea compare-application-versions` accepts caller-supplied managed projection Evidence containing an observed, exact `managed-static-analysis` fact at a runtime location. Its successful comparison returns that same contradictory fact in the change graph. The graph contract forbids static authorities from claiming runtime locations. The equivalent AST static-analysis input is rejected. ### Reproduction Run the following from the baseline checkout with its dependencies installed and runtime built. It creates a one-method graph, generates all semantic commitments for each input, wraps each graph in two distinct managed projection Evidence records, and invokes the public comparison CLI. The fixture uses an isolated home directory and synthetic digest values; it does not read an assembly or obtain runtime observations. ```sh fixture_dir="$(mktemp -d)" mkdir -p "$fixture_dir/home" HOME="$fixture_dir/home" node --input-type=module - "$fixture_dir" <<'NODE' import { writeFileSync } from 'node:fs'; import { resolve } from 'node:path'; import { spawnSync } from 'node:child_process'; import { createJavaScriptApplicationNode } from './dist/domain/javascript/javascriptApplicationGraph.js'; import { digestCanonicalValue } from './dist/domain/canonicalDigest.js'; import { createEvidence } from './dist/domain/evidence.js'; const output = process.argv[2]; const sha = '1'.repeat(64); const link = `ev_${'2'.repeat(64)}`; const coverage = { status: 'complete', truncated: false, omitted_count: 0, limits: [] }; for (const authority of ['managed-static-analysis', 'ast-static-analysis', 'passive-cdp-runtime']) { const node = createJavaScriptApplicationNode({ kind: 'managed-method', identity: { strategy: 'artifact-local-key', stability: 'artifact-version', artifact_sha256: sha, namespace: 'managed-method', key: 'Example.Main' }, observations: [{ label: 'Example.Main', properties: {}, evidence: { authority, state: 'observed', confidence: 'exact', artifact: { available: true, artifact_id: `art_${sha}`, sha256: sha }, location: { available: true, value: { kind: 'runtime', capture_sha256: '3'.repeat(64), target_key: 'target', frame_key: null, script_key: null } }, extractor: { name: 'fixture', version: '1', operation: 'fixture', executable_sha256: null }, coverage, limitations: [], evidence_ids: [link] } }] }); const content = { schema: 'JavaScriptApplicationGraph', root_node_ids: [node.node_id], nodes: [node], edges: [], coverage, limitations: [] }; const graph = { ...content, graph_id: `jag_${digestCanonicalValue(content, 'JavaScript Application Graph')}` }; const result = { projection_id: `magp_${'4'.repeat(64)}`, root_artifact_sha256: sha, source_evidence: { managed_artifact_evidence_id: null, managed_members_evidence_id: link, managed_native_boundaries_evidence_id: null }, summary: { graph_nodes: 1, graph_edges: 0, assemblies: 0, modules: 0, types: 0, methods: 1, fields: 0, pinvoke_imports: 0, native_implementations: 0 }, graph, coverage: { status: 'complete-within-inputs' }, evidence_links: [link], limitations: [] }; const envelope = side => createEvidence(undefined, { id: 'rea-dotnet-workflows', name: 'REA managed-code workflows', version: '1' }, { predicateType: 'rea.managed-application-graph', operation: 'project_managed_application_graph', parameters: { side }, result, confidence: 'inferred', authority: 'analyst-inference', evidenceLinks: [link] }); const input = resolve(output, `${authority}.json`); writeFileSync(input, JSON.stringify({ left: envelope('left'), right: envelope('right') })); const run = spawnSync(process.execPath, [ 'scripts/rea.mjs', 'compare-application-versions', input, '--json' ], { encoding: 'utf8', timeout: 30000, env: { ...process.env, REA_LOG_LEVEL: 'silent' } }); if (run.error) throw run.error; const response = JSON.parse(run.stdout); const fact = response.normalized_result?.graph.nodes[0]?.observations[0]?.evidence; console.log(JSON.stringify({ authority, exit: run.status, summary: response.normalized_result?.summary, retained_authority: fact?.authority, retained_location: fact?.location.value?.kind, code: response.code, issues: response.details?.issues })); } NODE ``` ### Expected behavior The comparison must reject the managed static fact's runtime location as invalid input, just as it rejects the AST static fact's runtime location. Managed inspection supplies static metadata rather than observations of CLR execution. A genuine runtime-authority fact with runtime coordinates must remain admissible, and managed facts with valid static coordinates must remain usable. ### Impact and scope A bounded input-validation defect allows contradictory provenance coordinates into a successful, validated comparison graph. The returned authority remains managed static analysis. No severe incident, execution claim from a real producer, or security boundary crossing was established. Workaround: A caller could potentially validate authority/location combinations before submitting Evidence, but no existing external validation workflow was tested. The comparison command itself accepts the contradictory combination. Assessment: P2. ### REA version rea 6.5.0 at source commit 4692bb33300c7cb77b095b6cc0c33da861c1b860 ### Runtime and platform Node 24.18.0; macOS arm64 ### Target and artifact context Synthetic authenticated managed projection Evidence containing a one-method graph. No assembly inspection or runtime observation was performed. ### Interface CLI ### Earliest failure stage Request parsing or validation ### Relevant output or evidence Observed one CLI invocation for each case. The managed static input exited 0 and returned `{"unchanged":1,"added":0,"removed":0,"changed":0,"unknown":0}`. Its returned graph retained `authority: "managed-static-analysis"`, `state: "observed"`, `confidence: "exact"`, and `location.value.kind: "runtime"`. The AST static control exited 1 with code `invalid_request`, category `invalid_input`, and the message `Static and native authorities cannot claim a runtime location` at `left.normalized_result.graph.nodes[0].observations[0].evidence.location`. The passive CDP runtime control exited 0. These controls distinguish the missing managed-authority check from an invalid envelope, a mismatched commitment, or general rejection of runtime locations. The observed defect concerns validation and propagation of supplied Evidence. No real assembly analysis, runtime capture, or MCP execution was performed, and this reproduction does not establish that the normal managed projection producer emits contradictory locations. - Expected source: [docs/javascript-application-graph.md:145](https://github.com/morluto/rea/blob/4692bb33300c7cb77b095b6cc0c33da861c1b860/docs/javascript-application-graph.md#L145) prohibits runtime locations for static/native authorities; [docs/managed-code-analysis.md:611](https://github.com/morluto/rea/blob/4692bb33300c7cb77b095b6cc0c33da861c1b860/docs/managed-code-analysis.md#L611) states the managed runtime behavior boundary; [src/domain/javascript/javascriptApplicationEvidenceSchemas.ts:21](https://github.com/morluto/rea/blob/4692bb33300c7cb77b095b6cc0c33da861c1b860/src/domain/javascript/javascriptApplicationEvidenceSchemas.ts#L21) admits the managed authority. - Failure source: The executed CLI reproduction above returns the managed static fact with runtime coordinates in its comparison graph. Source-derived explanation: [src/domain/javascript/javascriptApplicationGraph.ts:151](https://github.com/morluto/rea/blob/4692bb33300c7cb77b095b6cc0c33da861c1b860/src/domain/javascript/javascriptApplicationGraph.ts#L151) checks runtime locations against four authorities without including managed static analysis; [src/domain/managed/managedApplicationGraph.ts:82](https://github.com/morluto/rea/blob/4692bb33300c7cb77b095b6cc0c33da861c1b860/src/domain/managed/managedApplicationGraph.ts#L82) delegates to that graph validator; [src/application/javascript/JavaScriptApplicationEvidenceGraph.ts:110](https://github.com/morluto/rea/blob/4692bb33300c7cb77b095b6cc0c33da861c1b860/src/application/javascript/JavaScriptApplicationEvidenceGraph.ts#L110) and its managed branch at line 215 admit the corresponding Evidence through the comparison workflow. The existing focused graph test passed when run with `npx vitest run src/domain/javascript/javascriptApplicationGraph.test.ts -t 'prevents static authorities from claiming runtime locations'`: one passed, 18 skipped. Its static-location exclusion case covers AST authority, which also rejects the runtime location through the public CLI control. ### Typed outcome or recovery expected Rerun the fixture through the public CLI. The managed static case must return an invalid-input diagnostic identifying the runtime location instead of a successful comparison graph containing that fact. The AST static case must continue to reject its runtime location, and the passive CDP runtime case must continue to succeed. Also confirm that a managed static fact using valid artifact or source coordinates still compares successfully, so restoration preserves supported managed analysis. ### Additional context Freshness checked against origin/main at 22ec8bdb2f7d4626587f23b1eed4a207df600386. The cited failing implementation files are unchanged from the reproduced baseline; this is a source freshness check, not a runtime rerun on that revision.
Author
Owner

@coygeek commented on GitHub (Oct 24, 2026):

Checked the reported fix on main at d87e73f2db.

The shared graph validator now includes managed-static-analysis among authorities forbidden from runtime coordinates. The managed graph delegates to that schema before version comparison, so the previously accepted contradictory observation is rejected at the same boundary as AST static facts. The regression parameterizes AST and managed authorities with a runtime location and requires rejection.

Implementation: javascriptApplicationGraph.ts, javascriptApplicationGraph.test.ts.

The relevant regression checks in javascriptApplicationGraph.test.ts passed in the focused test run on this revision. This closure is based on the current source and those checks; provider fixtures do not establish a real-engine run. Closing as completed on main.

<!-- gh-comment-id:6380734922 --> @coygeek commented on GitHub (Oct 24, 2026): Checked the reported fix on `main` at d87e73f2db50be72d33a4b3c7199af35518b441c. The shared graph validator now includes managed-static-analysis among authorities forbidden from runtime coordinates. The managed graph delegates to that schema before version comparison, so the previously accepted contradictory observation is rejected at the same boundary as AST static facts. The regression parameterizes AST and managed authorities with a runtime location and requires rejection. Implementation: [javascriptApplicationGraph.ts](https://github.com/morluto/rea/blob/d87e73f2db50be72d33a4b3c7199af35518b441c/src/domain/javascript/javascriptApplicationGraph.ts#L158), [javascriptApplicationGraph.test.ts](https://github.com/morluto/rea/blob/d87e73f2db50be72d33a4b3c7199af35518b441c/src/domain/javascript/javascriptApplicationGraph.test.ts#L889). The relevant regression checks in [javascriptApplicationGraph.test.ts](https://github.com/morluto/rea/blob/d87e73f2db50be72d33a4b3c7199af35518b441c/src/domain/javascript/javascriptApplicationGraph.test.ts) passed in the focused test run on this revision. This closure is based on the current source and those checks; provider fixtures do not establish a real-engine run. Closing as completed on main.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#1563
No description provided.