mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2026-09-09 18:03:21 +00:00
[AAE-46514] - Fixing other improvements and comments
This commit is contained in:
@@ -154,7 +154,8 @@ async function fetchFromOSV(projectDependencies) {
|
|||||||
package: { name: dep.name, ecosystem: 'npm' },
|
package: { name: dep.name, ecosystem: 'npm' },
|
||||||
version: dep.version
|
version: dep.version
|
||||||
}))
|
}))
|
||||||
})
|
}),
|
||||||
|
signal: AbortSignal.timeout(30000)
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
@@ -300,7 +301,8 @@ async function fetchFromGitHubAdvisory() {
|
|||||||
headers: {
|
headers: {
|
||||||
'Accept': 'application/vnd.github+json',
|
'Accept': 'application/vnd.github+json',
|
||||||
'X-GitHub-Api-Version': '2022-11-28'
|
'X-GitHub-Api-Version': '2022-11-28'
|
||||||
}
|
},
|
||||||
|
signal: AbortSignal.timeout(15000)
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -601,7 +603,9 @@ async function main() {
|
|||||||
violations.push(...checkLockfileDependencies(lockfile.packages, blockedPackages));
|
violations.push(...checkLockfileDependencies(lockfile.packages, blockedPackages));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check with Meterian CLI for additional vulnerability coverage
|
// Check with Meterian CLI for additional vulnerability coverage (informational by default)
|
||||||
|
// Set ADF_METERIAN_BLOCK=1 to make Meterian findings block installation
|
||||||
|
const meterianFindings = [];
|
||||||
if (lockfile?.packages) {
|
if (lockfile?.packages) {
|
||||||
console.log('');
|
console.log('');
|
||||||
const deps = Object.entries(lockfile.packages)
|
const deps = Object.entries(lockfile.packages)
|
||||||
@@ -614,7 +618,7 @@ async function main() {
|
|||||||
|
|
||||||
const meterianResult = await checkWithMeterian(deps);
|
const meterianResult = await checkWithMeterian(deps);
|
||||||
for (const vuln of meterianResult.vulnerable || []) {
|
for (const vuln of meterianResult.vulnerable || []) {
|
||||||
violations.push({
|
meterianFindings.push({
|
||||||
package: vuln.name,
|
package: vuln.name,
|
||||||
version: vuln.version,
|
version: vuln.version,
|
||||||
reason: `${vuln.severity}: ${vuln.id}${vuln.safeVersions?.length ? ` (safe: ${vuln.safeVersions[0]})` : ''}`,
|
reason: `${vuln.severity}: ${vuln.id}${vuln.safeVersions?.length ? ` (safe: ${vuln.safeVersions[0]})` : ''}`,
|
||||||
@@ -623,6 +627,18 @@ async function main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Meterian findings are informational unless ADF_METERIAN_BLOCK is set
|
||||||
|
const blockOnMeterian = process.env.ADF_METERIAN_BLOCK === '1' || process.env.ADF_METERIAN_BLOCK === 'true';
|
||||||
|
if (blockOnMeterian) {
|
||||||
|
violations.push(...meterianFindings);
|
||||||
|
} else if (meterianFindings.length > 0) {
|
||||||
|
console.log('\n⚠️ Meterian found vulnerabilities (informational, not blocking):');
|
||||||
|
for (const v of meterianFindings) {
|
||||||
|
console.log(` ${v.package}@${v.version} - ${v.reason}`);
|
||||||
|
}
|
||||||
|
console.log(' Set ADF_METERIAN_BLOCK=1 to block on these findings.\n');
|
||||||
|
}
|
||||||
|
|
||||||
// Deduplicate
|
// Deduplicate
|
||||||
const uniqueViolations = violations.filter((v, i, arr) =>
|
const uniqueViolations = violations.filter((v, i, arr) =>
|
||||||
arr.findIndex(x => x.package === v.package && x.version === v.version) === i
|
arr.findIndex(x => x.package === v.package && x.version === v.version) === i
|
||||||
@@ -651,9 +667,12 @@ async function main() {
|
|||||||
console.error(' • Exfiltrate sensitive data\n');
|
console.error(' • Exfiltrate sensitive data\n');
|
||||||
|
|
||||||
// Delete node_modules to prevent using compromised packages
|
// Delete node_modules to prevent using compromised packages
|
||||||
|
// Set ADF_SECURITY_KEEP_NODE_MODULES=1 to skip deletion (e.g., in CI for caching)
|
||||||
|
const skipDeletion = process.env.ADF_SECURITY_KEEP_NODE_MODULES === '1' || process.env.ADF_SECURITY_KEEP_NODE_MODULES === 'true';
|
||||||
const nodeModulesPath = join(ROOT_DIR, 'node_modules');
|
const nodeModulesPath = join(ROOT_DIR, 'node_modules');
|
||||||
if (existsSync(nodeModulesPath)) {
|
if (existsSync(nodeModulesPath) && !skipDeletion) {
|
||||||
console.error('🗑️ Removing node_modules to prevent use of compromised packages...\n');
|
console.error('🗑️ Removing node_modules to prevent use of compromised packages...');
|
||||||
|
console.error(' (Set ADF_SECURITY_KEEP_NODE_MODULES=1 to skip deletion)\n');
|
||||||
try {
|
try {
|
||||||
rmSync(nodeModulesPath, { recursive: true, force: true });
|
rmSync(nodeModulesPath, { recursive: true, force: true });
|
||||||
console.error('✅ node_modules deleted successfully.\n');
|
console.error('✅ node_modules deleted successfully.\n');
|
||||||
@@ -661,6 +680,8 @@ async function main() {
|
|||||||
console.error(`⚠️ Could not delete node_modules: ${e.message}`);
|
console.error(`⚠️ Could not delete node_modules: ${e.message}`);
|
||||||
console.error(' Please delete it manually before proceeding.\n');
|
console.error(' Please delete it manually before proceeding.\n');
|
||||||
}
|
}
|
||||||
|
} else if (skipDeletion) {
|
||||||
|
console.error('⚠️ Skipping node_modules deletion (ADF_SECURITY_KEEP_NODE_MODULES=1)\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
console.error('📋 REQUIRED ACTIONS:');
|
console.error('📋 REQUIRED ACTIONS:');
|
||||||
|
|||||||
@@ -58,41 +58,66 @@ function readCache() {
|
|||||||
try {
|
try {
|
||||||
const data = JSON.parse(readFileSync(cachePath, 'utf8'));
|
const data = JSON.parse(readFileSync(cachePath, 'utf8'));
|
||||||
if (Date.now() - data.timestamp < CACHE_TTL) {
|
if (Date.now() - data.timestamp < CACHE_TTL) {
|
||||||
return new Set(data.threats);
|
return {
|
||||||
|
threats: new Set(data.threats),
|
||||||
|
ranges: data.ranges || []
|
||||||
|
};
|
||||||
}
|
}
|
||||||
} catch { /* ignore */ }
|
} catch { /* ignore */ }
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function writeCache(threats) {
|
function writeCache(threats, ranges) {
|
||||||
try {
|
try {
|
||||||
if (!existsSync(CACHE_DIR)) {
|
if (!existsSync(CACHE_DIR)) {
|
||||||
mkdirSync(CACHE_DIR, { recursive: true });
|
mkdirSync(CACHE_DIR, { recursive: true });
|
||||||
}
|
}
|
||||||
writeFileSync(join(CACHE_DIR, 'threats.json'), JSON.stringify({
|
writeFileSync(join(CACHE_DIR, 'threats.json'), JSON.stringify({
|
||||||
timestamp: Date.now(),
|
timestamp: Date.now(),
|
||||||
threats: [...threats]
|
threats: [...threats],
|
||||||
|
ranges: ranges
|
||||||
}));
|
}));
|
||||||
} catch { /* ignore */ }
|
} catch { /* ignore */ }
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchOSV() {
|
async function fetchOSV(projectDependencies) {
|
||||||
try {
|
// Query OSV batch API for the project's actual dependencies
|
||||||
const response = await fetch('https://osv-vulnerabilities.storage.googleapis.com/npm/all.zip', {
|
if (!projectDependencies || projectDependencies.length === 0) {
|
||||||
signal: AbortSignal.timeout(10000)
|
return new Set();
|
||||||
});
|
}
|
||||||
if (!response.ok) return new Set();
|
|
||||||
|
|
||||||
const buffer = await response.arrayBuffer();
|
|
||||||
const text = new TextDecoder().decode(buffer);
|
|
||||||
const malicious = new Set();
|
const malicious = new Set();
|
||||||
|
|
||||||
// Parse JSONL format looking for MALWARE type
|
|
||||||
for (const line of text.split('\n')) {
|
|
||||||
if (!line.trim()) continue;
|
|
||||||
try {
|
try {
|
||||||
const vuln = JSON.parse(line);
|
// Process in batches of 1000
|
||||||
if (vuln.database_specific?.type === 'MALWARE' && vuln.affected) {
|
const batchSize = 1000;
|
||||||
|
for (let i = 0; i < projectDependencies.length; i += batchSize) {
|
||||||
|
const batch = projectDependencies.slice(i, i + batchSize);
|
||||||
|
const response = await fetch('https://api.osv.dev/v1/querybatch', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({
|
||||||
|
queries: batch.map(dep => ({
|
||||||
|
package: { name: dep.name, ecosystem: 'npm' },
|
||||||
|
version: dep.version
|
||||||
|
}))
|
||||||
|
}),
|
||||||
|
signal: AbortSignal.timeout(30000)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) continue;
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
for (const result of data.results || []) {
|
||||||
|
for (const vuln of result.vulns || []) {
|
||||||
|
const summary = [vuln.summary || '', vuln.details || ''].join(' ').toLowerCase();
|
||||||
|
const isMalware = summary.includes('malware') ||
|
||||||
|
summary.includes('malicious') ||
|
||||||
|
summary.includes('compromised') ||
|
||||||
|
summary.includes('supply chain') ||
|
||||||
|
summary.includes('backdoor');
|
||||||
|
|
||||||
|
if (isMalware && vuln.affected) {
|
||||||
for (const affected of vuln.affected) {
|
for (const affected of vuln.affected) {
|
||||||
if (affected.package?.ecosystem === 'npm' && affected.package?.name) {
|
if (affected.package?.ecosystem === 'npm' && affected.package?.name) {
|
||||||
const versions = affected.versions || [];
|
const versions = affected.versions || [];
|
||||||
@@ -102,12 +127,14 @@ async function fetchOSV() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch { /* skip invalid lines */ }
|
|
||||||
}
|
}
|
||||||
return malicious;
|
}
|
||||||
|
}
|
||||||
} catch {
|
} catch {
|
||||||
return new Set();
|
// Ignore errors, return what we have
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return malicious;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchGitHubAdvisory() {
|
async function fetchGitHubAdvisory() {
|
||||||
@@ -284,22 +311,28 @@ async function main() {
|
|||||||
console.log(` Checking ${packages.length} packages (${fromPackageJson} from package.json, ${fromLockfile} from lockfile)\n`);
|
console.log(` Checking ${packages.length} packages (${fromPackageJson} from package.json, ${fromLockfile} from lockfile)\n`);
|
||||||
|
|
||||||
// Try to use cache first
|
// Try to use cache first
|
||||||
let threats = readCache();
|
const cache = readCache();
|
||||||
let fromCache = true;
|
let threats;
|
||||||
|
let ghRanges;
|
||||||
|
|
||||||
if (!threats) {
|
if (!cache) {
|
||||||
fromCache = false;
|
|
||||||
console.log(' Fetching latest security databases...\n');
|
console.log(' Fetching latest security databases...\n');
|
||||||
|
|
||||||
const [osvThreats, ghThreats] = await Promise.all([
|
const [osvThreats, ghThreats] = await Promise.all([
|
||||||
fetchOSV().then(r => { console.log(` 📡 OSV: ${r.size} malware entries`); return r; }),
|
fetchOSV(packages).then(r => { console.log(` 📡 OSV: ${r.size} malware entries`); return r; }),
|
||||||
fetchGitHubAdvisory().then(r => { console.log(` 📡 GitHub Advisory: ${r.size} malware entries`); return r; })
|
fetchGitHubAdvisory().then(r => { console.log(` 📡 GitHub Advisory: ${r.size} malware entries`); return r; })
|
||||||
]);
|
]);
|
||||||
|
|
||||||
threats = new Set([...KNOWN_MALICIOUS, ...osvThreats]);
|
threats = new Set([...KNOWN_MALICIOUS, ...osvThreats]);
|
||||||
|
ghRanges = [...ghThreats];
|
||||||
|
|
||||||
// Store GitHub advisories separately (they have version ranges)
|
// Cache the results including ranges
|
||||||
const ghRanges = [...ghThreats];
|
writeCache(threats, ghRanges);
|
||||||
|
} else {
|
||||||
|
threats = cache.threats;
|
||||||
|
ghRanges = cache.ranges;
|
||||||
|
console.log(` Using cached security database (${threats.size} exact + ${ghRanges.length} ranges)\n`);
|
||||||
|
}
|
||||||
|
|
||||||
// Check packages against exact matches and ranges
|
// Check packages against exact matches and ranges
|
||||||
const found = [];
|
const found = [];
|
||||||
@@ -343,34 +376,7 @@ async function main() {
|
|||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cache the results
|
console.log(`\n✅ Security check passed (${threats.size} exact + ${ghRanges.length} ranges checked)`)
|
||||||
writeCache(threats);
|
|
||||||
console.log(`\n✅ Security check passed (${threats.size + ghRanges.length} known threats checked)`);
|
|
||||||
} else {
|
|
||||||
// Quick check against cached threats
|
|
||||||
const found = [];
|
|
||||||
for (const pkg of packages) {
|
|
||||||
const exact = `${pkg.name}@${pkg.version}`;
|
|
||||||
if (threats.has(exact)) {
|
|
||||||
found.push(pkg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (found.length > 0) {
|
|
||||||
console.log('\n' + '!'.repeat(70));
|
|
||||||
console.log('🚨 MALICIOUS PACKAGES DETECTED - BLOCKING INSTALLATION');
|
|
||||||
console.log('!'.repeat(70) + '\n');
|
|
||||||
|
|
||||||
for (const pkg of found) {
|
|
||||||
console.log(` ❌ ${pkg.name}@${pkg.version}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('\n='.repeat(70) + '\n');
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(`✅ Security check passed (cached, ${threats.size} known threats)`);
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('='.repeat(70) + '\n');
|
console.log('='.repeat(70) + '\n');
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user