Skip to content

Commit ee7d045

Browse files
CLI-56: Adjust secret scan to sonar-secrets binary protocol changes
Pass --non-interactive flag to skip interactive auth prompt when running file scans (binary hangs on open stdin waiting for user input otherwise). Remove exit-code remap (1 -> 51): sonar-secrets v2.41 now returns 51 directly when secrets are found; exit 1 means a generic error. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 1ca41e1 commit ee7d045

File tree

2 files changed

+37
-7
lines changed

2 files changed

+37
-7
lines changed

src/commands/secret-scan.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ async function runScan(
190190
authToken: string | undefined
191191
): Promise<{ exitCode: number | null; stdout: string; stderr: string }> {
192192
return Promise.race([
193-
spawnProcess(binaryPath, [file], {
193+
spawnProcess(binaryPath, ['--non-interactive', file], {
194194
stdin: 'pipe',
195195
stdout: 'pipe',
196196
stderr: 'pipe',
@@ -342,8 +342,7 @@ function handleScanFailure(
342342
print(result.stdout);
343343
}
344344
blank();
345-
// Binary exit 1 = secrets found — remap to 51 so hooks can distinguish from generic errors
346-
process.exit(exitCode === 1 ? SECRET_SCAN_POSITIVE_EXIT_CODE : exitCode);
345+
process.exit(exitCode);
347346
}
348347

349348
function handleScanError(err: unknown): void {

tests/unit/secret-scan.test.ts

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,23 @@ describe('secretCheckCommand: runs without authentication', () => {
121121
expect(spawnCall[2].env['SONAR_SECRETS_AUTH_URL']).toBe(SONARCLOUD_URL);
122122
expect(spawnCall[2].env['SONAR_SECRETS_TOKEN']).toBe(TEST_TOKEN);
123123
});
124+
125+
it('passes --non-interactive as first arg to binary for file scan', async () => {
126+
spawnSpy.mockResolvedValue({
127+
exitCode: 0,
128+
stdout: JSON.stringify({ issues: [] }),
129+
stderr: '',
130+
});
131+
const existsSpy = mockBinaryExists();
132+
try {
133+
await secretCheckCommand({ file: 'src/index.ts' });
134+
} finally {
135+
existsSpy.mockRestore();
136+
}
137+
138+
const spawnCall = spawnSpy.mock.calls[0];
139+
expect(spawnCall[1][0]).toBe('--non-interactive');
140+
});
124141
});
125142

126143
// ─── Successful scan paths ────────────────────────────────────────────────────
@@ -221,9 +238,9 @@ describe('secretCheckCommand: successful scan', () => {
221238
// ─── Failed scan paths ────────────────────────────────────────────────────────
222239

223240
describe('secretCheckCommand: scan failures', () => {
224-
it('exits 51 when binary exits 1 (secrets found)', async () => {
241+
it('exits 51 when binary exits 51 (secrets found)', async () => {
225242
await setupAuthenticatedState();
226-
spawnSpy.mockResolvedValue({ exitCode: 1, stdout: '', stderr: '' });
243+
spawnSpy.mockResolvedValue({ exitCode: 51, stdout: '', stderr: '' });
227244

228245
const existsSpy = mockBinaryExists(true);
229246
try {
@@ -237,6 +254,20 @@ describe('secretCheckCommand: scan failures', () => {
237254
expect(errors.some(m => m.includes('Scan failed'))).toBe(true);
238255
});
239256

257+
it('exits 1 when binary exits 1 (error, not secrets found)', async () => {
258+
await setupAuthenticatedState();
259+
spawnSpy.mockResolvedValue({ exitCode: 1, stdout: '', stderr: 'unexpected error' });
260+
261+
const existsSpy = mockBinaryExists(true);
262+
try {
263+
await secretCheckCommand({ file: 'src/index.ts' });
264+
} finally {
265+
existsSpy.mockRestore();
266+
}
267+
268+
expect(mockExit).toHaveBeenCalledWith(1);
269+
});
270+
240271
it('displays stderr when scan fails with error output', async () => {
241272
await setupAuthenticatedState();
242273
const stderrMsg = 'Connection refused to auth server';
@@ -368,9 +399,9 @@ describe('secretCheckCommand: stdin scan', () => {
368399
expect(mockExit).toHaveBeenCalledWith(0);
369400
});
370401

371-
it('exits 51 when binary exits 1 during stdin scan (secrets found)', async () => {
402+
it('exits 51 when binary exits 51 during stdin scan (secrets found)', async () => {
372403
await setupAuthenticatedState();
373-
spawnSpy.mockResolvedValue({ exitCode: 1, stdout: '', stderr: 'secret found' });
404+
spawnSpy.mockResolvedValue({ exitCode: 51, stdout: '', stderr: 'secret found' });
374405

375406
const existsSpy = mockBinaryExists(true);
376407
try {

0 commit comments

Comments
 (0)