fix(#337): Return error state from secret scanner on scan failures

- Add scanError field and scannedSuccessfully flag to SecretScanResult
- File read errors no longer falsely report as "clean"
- Callers can distinguish clean files from scan failures
- Update getScanSummary to track filesWithErrors count
- SecretsDetectedError now reports files that couldn't be scanned
- Add tests verifying error handling behavior for file access issues

Refs #337

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Jason Woltje
2026-02-05 15:30:06 -06:00
parent aa14b580b3
commit 6bb9846cde
3 changed files with 162 additions and 3 deletions

View File

@@ -207,6 +207,7 @@ export class SecretScannerService {
hasSecrets: allMatches.length > 0,
matches: allMatches,
count: allMatches.length,
scannedSuccessfully: true,
};
}
@@ -231,6 +232,7 @@ export class SecretScannerService {
hasSecrets: false,
matches: [],
count: 0,
scannedSuccessfully: true,
};
}
}
@@ -247,6 +249,7 @@ export class SecretScannerService {
hasSecrets: false,
matches: [],
count: 0,
scannedSuccessfully: true,
};
}
@@ -257,13 +260,16 @@ export class SecretScannerService {
// Scan content
return this.scanContent(content, filePath);
} catch (error) {
this.logger.error(`Failed to scan file ${filePath}: ${String(error)}`);
// Return empty result on error
const errorMessage = error instanceof Error ? error.message : String(error);
this.logger.warn(`Failed to scan file ${filePath}: ${errorMessage}`);
// Return error state - file could not be scanned, NOT clean
return {
filePath,
hasSecrets: false,
matches: [],
count: 0,
scannedSuccessfully: false,
scanError: errorMessage,
};
}
}
@@ -289,12 +295,14 @@ export class SecretScannerService {
totalFiles: number;
filesWithSecrets: number;
totalSecrets: number;
filesWithErrors: number;
bySeverity: Record<string, number>;
} {
const summary = {
totalFiles: results.length,
filesWithSecrets: results.filter((r) => r.hasSecrets).length,
totalSecrets: results.reduce((sum, r) => sum + r.count, 0),
filesWithErrors: results.filter((r) => !r.scannedSuccessfully).length,
bySeverity: {
critical: 0,
high: 0,