UNPKG

@dreamhorizonorg/sentinel

Version:

Open-source, zero-dependency tool that blocks compromised packages BEFORE download. Built to counter supply chain and credential theft attacks like Shai-Hulud.

104 lines (86 loc) 2.96 kB
/** * Data source path resolution utilities * Pure functions for resolving compromised packages data source paths */ import fs from 'fs'; import path from 'path'; import { COMPROMISED_PACKAGES_FILENAME, USER_INSTALL_DIR } from '../constants/app.constants.mjs'; import { isDirectory, pathExists } from './file.utils.mjs'; import { getProjectRoot, resolveUserPath } from './path.utils.mjs'; /** * Get data source path from config * Smart handling: if path is a folder, looks for compromised-packages.json inside */ export const getDataSourcePath = (config = {}) => { // Priority 1: Explicit local data source (file or folder) if (config.dataSourcePath) { const resolvedPath = path.resolve(config.dataSourcePath); // If it's a directory, look for standard filename if (isDirectory(resolvedPath)) { const jsonPath = path.join(resolvedPath, COMPROMISED_PACKAGES_FILENAME); if (pathExists(jsonPath)) { return jsonPath; } // If folder exists but JSON not found, return folder (will show error later) return resolvedPath; } // If it's a file or doesn't exist yet, return as-is return resolvedPath; } // Priority 2: HTTP endpoint if (config.endpoint) { return config.endpoint; } // Priority 3: Local folder (legacy support, but treat same as dataSourcePath) if (config.localFolder) { const resolvedPath = path.resolve(config.localFolder); const jsonPath = path.join(resolvedPath, COMPROMISED_PACKAGES_FILENAME); if (pathExists(jsonPath)) { return jsonPath; } return resolvedPath; } // Priority 4: Default locations (root file pattern) const JSON_REPO_CONFIG = path.join(getProjectRoot(), 'config', COMPROMISED_PACKAGES_FILENAME); const JSON_USER_CONFIG = resolveUserPath(USER_INSTALL_DIR, 'config', COMPROMISED_PACKAGES_FILENAME); if (pathExists(JSON_REPO_CONFIG)) { return JSON_REPO_CONFIG; } if (pathExists(JSON_USER_CONFIG)) { return JSON_USER_CONFIG; } return JSON_REPO_CONFIG; // Will show error if not found }; /** * Load JSON from file */ export const loadJsonFromFile = (filePath) => { const content = fs.readFileSync(filePath, 'utf-8'); return JSON.parse(content); }; /** * Convert JSON records to compromised map */ export const jsonToMap = (packages) => { const compromisedMap = new Map(); if (!Array.isArray(packages)) { packages = [packages]; } for (const pkg of packages) { const packageName = pkg.name?.trim(); if (!packageName) continue; if (!compromisedMap.has(packageName)) { compromisedMap.set(packageName, new Set()); } const versions = pkg.compromisedVersions ?? []; if (Array.isArray(versions)) { versions.forEach(v => { const version = String(v).trim(); if (version) { compromisedMap.get(packageName).add(version); } }); } } return compromisedMap; };