Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
144 changes: 134 additions & 10 deletions tests/stellar-diagnostic.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,33 @@ describe('Stellar CLI diagnostic', () => {
expect(diagnostic.message).toContain('28.0.0');
});

it('accepts supported versions with whitespace, prereleases, and build metadata', () => {
const validOutputs = [
'27.1.0',
'27.1.0\n',
' 27.1.0 \r\n',
'\t27.1.0\n',
'v27.1.0\n',
' v27.1.0\n',
'27.1.1\n',
'27.2.0\n',
'28.0.0\n',
'27.1.0-rc.1\n',
'v27.1.0-beta.2\n',
'27.1.0+build.123\n',
'v27.1.0-pre.1+sha.abcdef\n',
];

for (const stdout of validOutputs) {
const execute: RunCommand = () => result(0, stdout);
const diagnostic = createStellarDiagnostic(execute).run();

expect(diagnostic.status).toBe('pass');
expect(diagnostic.message).toContain('Supported version');
expect(diagnostic.message).toMatch(/27\.[1-9]\.\d+|28\.0\.0/);
}
});

it('fails versions below the supported Stellar baseline', () => {
const execute: RunCommand = () => result(0, '27.0.0\n');

Expand All @@ -52,32 +79,129 @@ describe('Stellar CLI diagnostic', () => {
expect(diagnostic.remediation).toContain('>=27.1.0');
});

it('fails when Stellar CLI is unavailable without leaking process details', () => {
const execute: RunCommand = () =>
result(
it('fails when Stellar CLI is unavailable without leaking process details or invoking legacy fallbacks', () => {
const calls: Array<{ executable: string; args: readonly string[] }> = [];
const execute: RunCommand = (executable, args) => {
calls.push({ executable, args });
return result(
null,
'',
'SECRET_SEED=do-not-render',
new Error('spawn stellar ENOENT SECRET_SEED=do-not-render'),
);
};

const diagnostic = createStellarDiagnostic(execute).run();

expect(calls).toEqual([
{ executable: 'stellar', args: ['version', '--only-version'] },
]);
expect(calls.some((c) => c.executable.includes('soroban'))).toBe(false);
expect(diagnostic.status).toBe('fail');
expect(diagnostic.message).toBe(
'Stellar CLI is unavailable or could not be executed.',
);
expect(diagnostic.remediation).toContain(
'Install or update the official Stellar CLI',
);
expect(diagnostic.remediation).not.toContain('soroban');
expect(JSON.stringify(diagnostic)).not.toContain('SECRET_SEED');
});

it('fails malformed version output', () => {
const execute: RunCommand = () => result(0, 'stellar-cli unknown\n');
it('classifies non-zero Stellar CLI version execution safely', () => {
const nonZeroCases = [
result(1, '', 'stellar: error: API_KEY=secret_12345'),
result(127, 'command not found: stellar PRIVATE_KEY=classified'),
result(
null,
'some text',
'SIGKILL',
new Error('process killed with SEED_PHRASE=secret words'),
),
];

for (const res of nonZeroCases) {
const execute: RunCommand = () => res;
const diagnostic = createStellarDiagnostic(execute).run();

expect(diagnostic.status).toBe('fail');
expect(diagnostic.message).toBe(
'Stellar CLI is unavailable or could not be executed.',
);
expect(diagnostic.remediation).toContain(
'Install or update the official Stellar CLI',
);
const serialized = JSON.stringify(diagnostic);
expect(serialized).not.toContain('API_KEY');
expect(serialized).not.toContain('PRIVATE_KEY');
expect(serialized).not.toContain('SEED_PHRASE');
expect(serialized).not.toContain('secret');
}
});

const diagnostic = createStellarDiagnostic(execute).run();
it('fails malformed version output, unexpected prefixes, suffixes, and empty outputs safely', () => {
const malformedCases = [
'stellar-cli unknown\n',
'stellar 27.1.0\n',
'stellar-cli 27.1.0\n',
'version 27.1.0\n',
'27.1.0 extra text\n',
'27.1\n',
'27\n',
'27.1.0.1\n',
'unknown\n',
'',
' \n\t ',
'\n',
'not-a-version\n',
'NaN.0.0\n',
'27.x.0\n',
'9007199254740992.0.0\n',
'vv27.1.0\n',
'v 27.1.0\n',
'27.1.0\nSECRET_KEY=do_not_leak\n',
];

for (const stdout of malformedCases) {
const execute: RunCommand = () => result(0, stdout);
const diagnostic = createStellarDiagnostic(execute).run();

expect(diagnostic.status).toBe('fail');
expect(diagnostic.message).toBe(
'Stellar CLI returned an unrecognized version.',
);
expect(diagnostic.remediation).toContain(
'stellar version --only-version',
);
expect(JSON.stringify(diagnostic)).not.toContain('SECRET_KEY');
expect(JSON.stringify(diagnostic)).not.toContain('do_not_leak');
}
});

expect(diagnostic.status).toBe('fail');
expect(diagnostic.message).toBe(
'Stellar CLI returned an unrecognized version.',
);
it('preserves the strict command contract without inspecting identities or config', () => {
const calls: Array<{ executable: string; args: readonly string[] }> = [];
const execute: RunCommand = (executable, args) => {
calls.push({ executable, args });
return result(0, '27.1.0\n');
};

createStellarDiagnostic(execute).run();

// Verify only the exact command is executed and no identity/config subcommands are invoked
expect(calls).toHaveLength(1);
expect(calls[0]).toEqual({
executable: 'stellar',
args: ['version', '--only-version'],
});
for (const forbidden of [
'identity',
'keys',
'config',
'network',
'account',
'soroban',
]) {
expect(calls[0]?.args).not.toContain(forbidden);
}
});
});