fix: make security fixtures fail closed

This commit is contained in:
DongHyeonka
2026-08-02 05:40:58 +09:00
parent 76d0ab0f62
commit 100a3bb6ba
8 changed files with 374 additions and 83 deletions
+59
View File
@@ -0,0 +1,59 @@
import { normalizeRepositoryRelativePath } from "./repository-file-inventory.ts";
export function parseSecretScanIncludedPaths(
value: unknown,
): readonly string[] | null {
if (value === undefined) return null;
if (
!Array.isArray(value) ||
value.length === 0 ||
value.some(
(entry) =>
typeof entry !== "string" ||
entry.length === 0 ||
entry.trim() !== entry,
)
) {
throw new TypeError(
"includedPaths must be a non-empty array of repository-relative POSIX paths",
);
}
const normalized = value.map((entry) =>
normalizeRepositoryRelativePath(entry as string, "included path"),
);
if (new Set(normalized).size !== normalized.length) {
throw new TypeError("includedPaths must not contain duplicate paths");
}
return Object.freeze(normalized);
}
export function selectIncludedInventoryFiles(
inventoryFiles: readonly string[],
includedPaths: readonly string[] | null,
): readonly string[] {
if (includedPaths === null) return Object.freeze([...inventoryFiles]);
const validatedIncludedPaths = parseSecretScanIncludedPaths(includedPaths);
if (validatedIncludedPaths === null) {
throw new TypeError("includedPaths unexpectedly omitted");
}
for (const includedPath of validatedIncludedPaths) {
if (
!inventoryFiles.some(
(file) =>
file === includedPath || file.startsWith(`${includedPath}/`),
)
) {
throw new Error(
`secret scan included path matches no inventory file: ${includedPath}`,
);
}
}
return Object.freeze(
inventoryFiles.filter((file) =>
validatedIncludedPaths.some(
(includedPath) =>
file === includedPath || file.startsWith(`${includedPath}/`),
),
),
);
}