* fix(#3020): verify graphify tool identity before reporting compatibility checkGraphifyVersion ran 'graphify --version' on PATH and trusted any plausible version string — a foreign binary named 'graphify' that happened to print a version would silently report compatible:true with no warning. Downstream graphify work would then proceed against the wrong tool and fail later in ways that looked like GSD defects. After getting a version from the binary, verify the graphifyy Python package via importlib.metadata. If the package cannot be confirmed, emit a warning naming the mismatch regardless of version-range compatibility. The compatible flag is now correctly false for unverified tools (it was previously read by nobody — the warning is what surfaces). * chore(#3020): backfill changeset PR number 3107 --------- Co-authored-by: sim <sim@local>
This commit is contained in:
@@ -604,9 +604,11 @@ describe('build', () => {
|
||||
});
|
||||
|
||||
test('returns compatible:true for version 0.4.0', () => {
|
||||
mock.method(childProcess, 'spawnSync', () => ({
|
||||
// #3020: command-aware mock — graphify --version returns the version,
|
||||
// python3 importlib.metadata confirms the graphifyy package.
|
||||
mock.method(childProcess, 'spawnSync', (cmd) => ({
|
||||
status: 0,
|
||||
stdout: '0.4.0\n',
|
||||
stdout: cmd === 'graphify' ? '0.4.0\n' : '0.4.0\n',
|
||||
stderr: '',
|
||||
error: undefined,
|
||||
signal: null,
|
||||
@@ -619,9 +621,9 @@ describe('build', () => {
|
||||
});
|
||||
|
||||
test('returns compatible:true for version 0.9.5', () => {
|
||||
mock.method(childProcess, 'spawnSync', () => ({
|
||||
mock.method(childProcess, 'spawnSync', (cmd) => ({
|
||||
status: 0,
|
||||
stdout: '0.9.5\n',
|
||||
stdout: cmd === 'graphify' ? '0.9.5\n' : '0.9.5\n',
|
||||
stderr: '',
|
||||
error: undefined,
|
||||
signal: null,
|
||||
@@ -633,9 +635,9 @@ describe('build', () => {
|
||||
});
|
||||
|
||||
test('returns compatible:false for version 0.3.0', () => {
|
||||
mock.method(childProcess, 'spawnSync', () => ({
|
||||
mock.method(childProcess, 'spawnSync', (cmd) => ({
|
||||
status: 0,
|
||||
stdout: '0.3.0\n',
|
||||
stdout: cmd === 'graphify' ? '0.3.0\n' : '0.3.0\n',
|
||||
stderr: '',
|
||||
error: undefined,
|
||||
signal: null,
|
||||
@@ -647,9 +649,9 @@ describe('build', () => {
|
||||
});
|
||||
|
||||
test('returns compatible:false for version 1.0.0', () => {
|
||||
mock.method(childProcess, 'spawnSync', () => ({
|
||||
mock.method(childProcess, 'spawnSync', (cmd) => ({
|
||||
status: 0,
|
||||
stdout: '1.0.0\n',
|
||||
stdout: cmd === 'graphify' ? '1.0.0\n' : '1.0.0\n',
|
||||
stderr: '',
|
||||
error: undefined,
|
||||
signal: null,
|
||||
@@ -688,19 +690,35 @@ describe('build', () => {
|
||||
assert.ok(result.warning.includes('Could not parse'));
|
||||
});
|
||||
|
||||
test('tries graphify --version first before python3', () => {
|
||||
test('#3020: warns when graphifyy package cannot be confirmed (foreign binary)', () => {
|
||||
// graphify --version succeeds with a plausible version, but python3
|
||||
// importlib.metadata cannot find the graphifyy package — identity unverified.
|
||||
mock.method(childProcess, 'spawnSync', (cmd) => {
|
||||
if (cmd === 'graphify') {
|
||||
return { status: 0, stdout: '0.4.3\n', stderr: '', error: undefined, signal: null };
|
||||
}
|
||||
// python3 importlib.metadata fails — package not found
|
||||
return { status: 1, stdout: '', stderr: 'PackageNotFoundError', error: undefined, signal: null };
|
||||
});
|
||||
|
||||
const result = checkGraphifyVersion();
|
||||
assert.strictEqual(result.version, '0.4.3');
|
||||
assert.strictEqual(result.compatible, false, 'foreign binary must not report compatible');
|
||||
assert.ok(result.warning && result.warning.includes('graphifyy'), 'warning must name the package mismatch');
|
||||
});
|
||||
|
||||
test('tries graphify --version first, then verifies identity via python3', () => {
|
||||
const calls = [];
|
||||
mock.method(childProcess, 'spawnSync', (cmd, args) => {
|
||||
calls.push({ cmd, args });
|
||||
return { status: 0, stdout: '0.4.3\n', stderr: '', error: undefined, signal: null };
|
||||
return { status: 0, stdout: cmd === 'graphify' ? '0.4.3\n' : '0.4.3\n', stderr: '', error: undefined, signal: null };
|
||||
});
|
||||
|
||||
checkGraphifyVersion();
|
||||
assert.strictEqual(calls.length, 1, 'exactly one spawnSync call — no python3 fallback');
|
||||
assert.strictEqual(calls[0].cmd, 'graphify');
|
||||
assert.strictEqual(calls.length, 2, 'graphify --version + python3 identity verification (#3020)');
|
||||
assert.strictEqual(calls[0].cmd, 'graphify', 'first call is graphify --version');
|
||||
assert.strictEqual(calls[1].cmd, 'python3', 'second call is python3 identity check (#3020)');
|
||||
assert.ok(calls[0].args.includes('--version'), 'graphify called with --version');
|
||||
const python3Calls = calls.filter(c => c.cmd === 'python3');
|
||||
assert.strictEqual(python3Calls.length, 0, 'no python3 fallback when graphify --version succeeds');
|
||||
});
|
||||
|
||||
test('falls back to python3 importlib.metadata when graphify --version fails', () => {
|
||||
|
||||
Reference in New Issue
Block a user