Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | 1796x 1794x 1794x 2x 1796x 5x 1247x 1247x 76x 1169x 1169x | /**
* File System Utilities for DSN Detection
*
* Shared utilities for handling file system errors during scanning.
*/
import { stat } from "node:fs/promises";
// biome-ignore lint/performance/noNamespaceImport: Sentry SDK recommends namespace import
import * as Sentry from "@sentry/node-core/light";
/**
* Check if an error is an expected file system error that should be silently ignored.
*
* Expected errors during file scanning:
* - ENOENT: File or directory does not exist
* - EACCES: Permission denied (e.g., no read access)
* - EPERM: Operation not permitted (e.g., file locked, or system-level restriction)
* - EISDIR: Path is a directory, not a file (e.g., `.env/` directory instead of `.env` file)
* - ENOTDIR: A path component is not a directory (e.g., `/file.txt/child`)
*
* All other errors are unexpected and should be reported to Sentry.
*
* @param error - The error to check
* @returns True if the error is expected and should be ignored
*/
function isIgnorableFileError(error: unknown): boolean {
if (error instanceof Error && "code" in error) {
const code = (error as NodeJS.ErrnoException).code;
return (
code === "ENOENT" ||
code === "EACCES" ||
code === "EPERM" ||
code === "EISDIR" ||
code === "ENOTDIR"
);
}
return false;
}
/**
* Handle a file system error by either ignoring it (for expected errors)
* or capturing it to Sentry (for unexpected errors).
*
* @param error - The error that occurred
* @param context - Additional context for Sentry (e.g., file path, operation)
*/
export function handleFileError(
error: unknown,
context: { operation: string; path?: string }
): void {
if (!isIgnorableFileError(error)) {
Sentry.captureException(error, {
tags: {
operation: context.operation,
},
extra: {
path: context.path,
},
});
}
}
/**
* Check if a path points to a regular file (not a FIFO, socket, device, etc.).
*
* Named pipes (FIFOs) — commonly used by 1Password to stream secrets via
* symlinked `.env` files — cause `readFile()` to block indefinitely
* waiting for a writer. This guard uses `stat()`, which follows symlinks
* and inspects file type without performing the blocking read, so a
* symlink → FIFO is correctly detected.
*
* @param filePath - Absolute path to check
* @param operation - Logical operation name for unexpected stat error reporting
* @returns True if the path is a regular file safe to read, false otherwise
*/
export async function isRegularFile(
filePath: string,
operation = "isRegularFile"
): Promise<boolean> {
try {
const stats = await stat(filePath);
return stats.isFile();
} catch (error) {
handleFileError(error, { operation, path: filePath });
return false;
}
}
|