@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.
86 lines (71 loc) • 2.94 kB
JavaScript
/**
* Snyk Vulnerability Provider
* Snyk's comprehensive vulnerability database
* API: https://snyk.io/api
*
* Note: Snyk API requires authentication (API token)
*/
import { VulnerabilityProvider } from './provider.interface.mjs';
import { fetchJsonFromUrl } from '../utils/http.utils.mjs';
import { logVerbose, logWarning } from '../utils/log.utils.mjs';
import { colors } from '../utils/color.utils.mjs';
import { DEFAULT_TIMEOUT_MS, DEFAULT_SEVERITY } from '../constants/app.constants.mjs';
import { INFO_MESSAGES } from '../constants/validation.constants.mjs';
export class SnykProvider extends VulnerabilityProvider {
name = 'Snyk';
getDefaultConfig() {
return {
...super.getDefaultConfig(),
enabled: false, // Disabled by default (REQUIRES API token)
apiUrl: 'https://api.snyk.io/v1/test/npm',
timeout: DEFAULT_TIMEOUT_MS,
token: null // REQUIRED: Snyk API token (get one at https://snyk.io)
};
}
isEnabled(config = {}) {
const providerConfig = { ...this.getDefaultConfig(), ...config };
// Snyk REQUIRES API token - cannot work without it
return providerConfig.enabled && !!providerConfig.token;
}
async check(packageName, version = null, config = {}) {
if (!this.isEnabled(config)) {
return { found: false };
}
const providerConfig = { ...this.getDefaultConfig(), ...config };
if (!providerConfig.token) {
logWarning(colors.yellow('[Snyk] API token not configured. Skipping.'), config.logMode);
return { found: false };
}
try {
// Snyk API: POST /v1/test/npm/{packageName}
const packageSpec = version ? `${packageName}@${version}` : packageName;
const apiUrl = `${providerConfig.apiUrl}/${packageSpec}`;
logVerbose(colors.dim(INFO_MESSAGES.PROVIDER_CHECKING('Snyk', packageName, version)), config.logMode);
const response = await fetchJsonFromUrl(apiUrl, {
method: 'POST',
headers: {
'Authorization': `token ${providerConfig.token}`,
'Content-Type': 'application/json'
},
timeout: providerConfig.timeout
});
if (response && response.issues && response.issues.vulnerabilities && response.issues.vulnerabilities.length > 0) {
// Get the most severe vulnerability
const vuln = response.issues.vulnerabilities[0];
return {
found: true,
severity: vuln.severity?.toLowerCase() ?? DEFAULT_SEVERITY,
title: vuln.title ?? vuln.id,
source: 'Snyk',
cve: vuln.identifiers?.CVE?.[0],
url: vuln.url ?? `https://security.snyk.io/vuln/${vuln.id}`
};
}
return { found: false };
} catch (error) {
// Fail silently - don't block installation if provider is down
logVerbose(colors.dim(INFO_MESSAGES.PROVIDER_ERROR('Snyk', error.message)), config.logMode);
return { found: false };
}
}
}