@@ -45,32 +45,57 @@ const BINARY_AUTH_TOKEN_ENV = 'SONAR_SECRETS_TOKEN';
4545const SCAN_TIMEOUT_MS = 30000 ;
4646const STDIN_READ_TIMEOUT_MS = 5000 ;
4747
48+ export const EXIT_CODE_SECRETS_FOUND = 51 ;
49+
50+ /**
51+ * Run sonar-secrets binary on the given files. Returns the full spawn result.
52+ * Kills the child process on timeout.
53+ */
54+ export async function runSecretsBinary (
55+ binaryPath : string ,
56+ files : string [ ] ,
57+ auth : ResolvedAuth ,
58+ ) : Promise < SpawnResult > {
59+ let killChild : ( ( ) => void ) | undefined ;
60+ let timeoutId : ReturnType < typeof setTimeout > | undefined ;
61+ try {
62+ return await Promise . race ( [
63+ spawnProcess ( binaryPath , [ '--non-interactive' , ...files ] , {
64+ stdin : 'pipe' ,
65+ stdout : 'pipe' ,
66+ stderr : 'pipe' ,
67+ env : { [ BINARY_AUTH_URL_ENV ] : auth . serverUrl , [ BINARY_AUTH_TOKEN_ENV ] : auth . token } ,
68+ onSpawn : ( kill ) => {
69+ killChild = kill ;
70+ } ,
71+ } ) ,
72+ new Promise < never > ( ( _ , reject ) => {
73+ timeoutId = setTimeout ( ( ) => {
74+ killChild ?.( ) ;
75+ reject ( new Error ( `Scan timed out after ${ SCAN_TIMEOUT_MS } ms` ) ) ;
76+ } , SCAN_TIMEOUT_MS ) ;
77+ } ) ,
78+ ] ) ;
79+ } finally {
80+ clearTimeout ( timeoutId ) ;
81+ }
82+ }
83+
4884async function handleCheckCommand (
4985 options : AnalyzeSecretsOptions ,
5086 auth : ResolvedAuth ,
5187) : Promise < void > {
5288 validateScanOptions ( options ) ;
5389 const binaryPath = await installSecretsBinary ( ) ;
54- const { authUrl, authToken } = setupScanEnvironment ( binaryPath , auth ) ;
5590 const scanStartTime = Date . now ( ) ;
5691
5792 if ( options . stdin ) {
58- await performStdinScan ( binaryPath , authUrl , authToken , scanStartTime ) ;
93+ await performStdinScan ( binaryPath , auth , scanStartTime ) ;
5994 } else {
60- await performPathsScan ( binaryPath , options . paths ?? [ ] , authUrl , authToken , scanStartTime ) ;
95+ await performPathsScan ( binaryPath , options . paths ?? [ ] , auth , scanStartTime ) ;
6196 }
6297}
6398
64- interface ScanEnvironment {
65- binaryPath : string ;
66- authUrl ?: string ;
67- authToken ?: string ;
68- }
69-
70- function setupScanEnvironment ( binaryPath : string , auth : ResolvedAuth ) : ScanEnvironment {
71- return { binaryPath, authUrl : auth . serverUrl , authToken : auth . token } ;
72- }
73-
7499function validateScanOptions ( options : { paths ?: string [ ] ; stdin ?: boolean } ) : void {
75100 const hasPaths = ( options . paths ?. length ?? 0 ) > 0 ;
76101 if ( ! hasPaths && ! options . stdin ) {
@@ -84,11 +109,10 @@ function validateScanOptions(options: { paths?: string[]; stdin?: boolean }): vo
84109
85110async function performStdinScan (
86111 binaryPath : string ,
87- authUrl : string | undefined ,
88- authToken : string | undefined ,
112+ auth : ResolvedAuth ,
89113 scanStartTime : number ,
90114) : Promise < void > {
91- const result = await runScanFromStdin ( binaryPath , authUrl , authToken ) ;
115+ const result = await runScanFromStdin ( binaryPath , auth ) ;
92116 const scanDurationMs = Date . now ( ) - scanStartTime ;
93117
94118 const exitCode = result . exitCode ?? 1 ;
@@ -102,8 +126,7 @@ async function performStdinScan(
102126async function performPathsScan (
103127 binaryPath : string ,
104128 paths : string [ ] ,
105- authUrl : string | undefined ,
106- authToken : string | undefined ,
129+ auth : ResolvedAuth ,
107130 scanStartTime : number ,
108131) : Promise < void > {
109132 if ( paths . length === 0 ) {
@@ -116,7 +139,7 @@ async function performPathsScan(
116139 }
117140 }
118141
119- const result = await runScan ( binaryPath , paths , authUrl , authToken ) ;
142+ const result = await runSecretsBinary ( binaryPath , paths , auth ) ;
120143 const scanDurationMs = Date . now ( ) - scanStartTime ;
121144
122145 const exitCode = result . exitCode ?? 1 ;
@@ -127,41 +150,7 @@ async function performPathsScan(
127150 }
128151}
129152
130- async function runScan (
131- binaryPath : string ,
132- paths : string [ ] ,
133- authUrl : string | undefined ,
134- authToken : string | undefined ,
135- ) : Promise < SpawnResult > {
136- let timeoutId : ReturnType < typeof setTimeout > | undefined ;
137- try {
138- return await Promise . race ( [
139- spawnProcess ( binaryPath , [ '--non-interactive' , ...paths ] , {
140- stdin : 'pipe' ,
141- stdout : 'pipe' ,
142- stderr : 'pipe' ,
143- env : {
144- ...( authUrl && authToken
145- ? { [ BINARY_AUTH_URL_ENV ] : authUrl , [ BINARY_AUTH_TOKEN_ENV ] : authToken }
146- : { } ) ,
147- } ,
148- } ) ,
149- new Promise < never > ( ( _resolve , reject ) => {
150- timeoutId = setTimeout ( ( ) => {
151- reject ( new Error ( `Scan timed out after ${ SCAN_TIMEOUT_MS } ms` ) ) ;
152- } , SCAN_TIMEOUT_MS ) ;
153- } ) ,
154- ] ) ;
155- } finally {
156- clearTimeout ( timeoutId ) ;
157- }
158- }
159-
160- async function runScanFromStdin (
161- binaryPath : string ,
162- authUrl : string | undefined ,
163- authToken : string | undefined ,
164- ) : Promise < SpawnResult > {
153+ async function runScanFromStdin ( binaryPath : string , auth : ResolvedAuth ) : Promise < SpawnResult > {
165154 const { writeFileSync, unlinkSync } = await import ( 'node:fs' ) ;
166155 const { tmpdir } = await import ( 'node:os' ) ;
167156 const pathModule = await import ( 'node:path' ) ;
@@ -171,6 +160,7 @@ async function runScanFromStdin(
171160
172161 const tempFile = pathJoin ( tmpdir ( ) , `sonar-secrets-scan-${ Date . now ( ) } .tmp` ) ;
173162
163+ let killChild : ( ( ) => void ) | undefined ;
174164 let timeoutId : ReturnType < typeof setTimeout > | undefined ;
175165 try {
176166 writeFileSync ( tempFile , stdinData ) ;
@@ -179,14 +169,14 @@ async function runScanFromStdin(
179169 spawnProcess ( binaryPath , [ tempFile ] , {
180170 stdout : 'pipe' ,
181171 stderr : 'pipe' ,
182- env : {
183- ...( authUrl && authToken
184- ? { [ BINARY_AUTH_URL_ENV ] : authUrl , [ BINARY_AUTH_TOKEN_ENV ] : authToken }
185- : { } ) ,
172+ env : { [ BINARY_AUTH_URL_ENV ] : auth . serverUrl , [ BINARY_AUTH_TOKEN_ENV ] : auth . token } ,
173+ onSpawn : ( kill ) => {
174+ killChild = kill ;
186175 } ,
187176 } ) ,
188177 new Promise < never > ( ( _resolve , reject ) => {
189178 timeoutId = setTimeout ( ( ) => {
179+ killChild ?.( ) ;
190180 reject ( new Error ( `Scan timed out after ${ SCAN_TIMEOUT_MS } ms` ) ) ;
191181 } , SCAN_TIMEOUT_MS ) ;
192182 } ) ,
@@ -270,8 +260,6 @@ function displayScanResults(scanResult: {
270260 } ) ;
271261}
272262
273- const EXIT_CODE_SECRETS_FOUND = 51 ;
274-
275263function handleScanFailure (
276264 result : { exitCode : number | null ; stderr : string ; stdout : string } ,
277265 scanDurationMs : number ,
0 commit comments