feat: initial open marketplace with llm-security, config-audit, ultraplan-local
This commit is contained in:
commit
f93d6abdae
380 changed files with 65935 additions and 0 deletions
137
plugins/llm-security/tests/scanners/network.test.mjs
Normal file
137
plugins/llm-security/tests/scanners/network.test.mjs
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
// network.test.mjs — Integration tests for the network-mapper
|
||||
// Tests against the evil-project-health fixture which contains URLs to:
|
||||
// - ngrok-free.app (SUSPICIOUS_DOMAINS — HIGH)
|
||||
// - webhook.site (SUSPICIOUS_DOMAINS — HIGH)
|
||||
// - requestbin.com (SUSPICIOUS_DOMAINS — HIGH)
|
||||
// - pipedream.net (SUSPICIOUS_DOMAINS — HIGH)
|
||||
// - pastebin.com (SUSPICIOUS_DOMAINS — HIGH)
|
||||
// - bit.ly (SUSPICIOUS_DOMAINS — HIGH, URL shortener)
|
||||
// - 192.168.x.x (private IP — MEDIUM)
|
||||
// - 45.33.32.156 (public IP — HIGH, bypasses DNS)
|
||||
//
|
||||
// We do NOT assert on DNS resolution — it is network-dependent.
|
||||
// Only URL pattern detection (Phase 1–2 of the scanner) is tested.
|
||||
|
||||
import { describe, it, beforeEach } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { resolve } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { resetCounter } from '../../scanners/lib/output.mjs';
|
||||
import { discoverFiles } from '../../scanners/lib/file-discovery.mjs';
|
||||
import { scan } from '../../scanners/network-mapper.mjs';
|
||||
|
||||
const __dirname = fileURLToPath(new URL('.', import.meta.url));
|
||||
const FIXTURE = resolve(__dirname, '../../examples/malicious-skill-demo/evil-project-health');
|
||||
|
||||
describe('network-mapper integration', () => {
|
||||
let discovery;
|
||||
|
||||
beforeEach(async () => {
|
||||
resetCounter();
|
||||
discovery = await discoverFiles(FIXTURE);
|
||||
});
|
||||
|
||||
it('returns status ok', async () => {
|
||||
const result = await scan(FIXTURE, discovery);
|
||||
assert.equal(result.status, 'ok', `Expected status 'ok', got '${result.status}'`);
|
||||
});
|
||||
|
||||
it('scans at least one file', async () => {
|
||||
const result = await scan(FIXTURE, discovery);
|
||||
assert.ok(result.files_scanned >= 1, `Expected files_scanned >= 1, got ${result.files_scanned}`);
|
||||
});
|
||||
|
||||
it('detects at least 2 suspicious domain findings', async () => {
|
||||
const result = await scan(FIXTURE, discovery);
|
||||
const suspiciousFindings = result.findings.filter(f => f.severity === 'high');
|
||||
assert.ok(
|
||||
suspiciousFindings.length >= 2,
|
||||
`Expected >= 2 HIGH severity network findings, got ${suspiciousFindings.length}. ` +
|
||||
`All findings: ${result.findings.map(f => `${f.severity}: ${f.title}`).join('; ')}`
|
||||
);
|
||||
});
|
||||
|
||||
it('reports total findings >= 2', async () => {
|
||||
const result = await scan(FIXTURE, discovery);
|
||||
assert.ok(
|
||||
result.findings.length >= 2,
|
||||
`Expected >= 2 network findings, got ${result.findings.length}`
|
||||
);
|
||||
});
|
||||
|
||||
it('detects ngrok-free.app as suspicious endpoint', async () => {
|
||||
const result = await scan(FIXTURE, discovery);
|
||||
const ngrokFinding = result.findings.find(
|
||||
f => f.title.toLowerCase().includes('ngrok') ||
|
||||
(f.evidence && f.evidence.toLowerCase().includes('ngrok'))
|
||||
);
|
||||
assert.ok(
|
||||
ngrokFinding,
|
||||
`Should detect ngrok-free.app. All titles: ${result.findings.map(f => f.title).join('; ')}`
|
||||
);
|
||||
});
|
||||
|
||||
it('detects webhook.site as suspicious endpoint', async () => {
|
||||
const result = await scan(FIXTURE, discovery);
|
||||
const webhookFinding = result.findings.find(
|
||||
f => f.title.toLowerCase().includes('webhook.site') ||
|
||||
(f.evidence && f.evidence.toLowerCase().includes('webhook.site'))
|
||||
);
|
||||
assert.ok(
|
||||
webhookFinding,
|
||||
`Should detect webhook.site. All titles: ${result.findings.map(f => f.title).join('; ')}`
|
||||
);
|
||||
});
|
||||
|
||||
it('suspicious domain findings reference owasp LLM02', async () => {
|
||||
const result = await scan(FIXTURE, discovery);
|
||||
const suspiciousFindings = result.findings.filter(
|
||||
f => f.severity === 'high' && f.title.toLowerCase().includes('suspicious')
|
||||
);
|
||||
for (const f of suspiciousFindings) {
|
||||
assert.equal(
|
||||
f.owasp, 'LLM02',
|
||||
`Suspicious domain finding ${f.id} should be LLM02, got ${f.owasp}`
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it('all findings have DS-NET- prefix', async () => {
|
||||
const result = await scan(FIXTURE, discovery);
|
||||
const wrongPrefix = result.findings.filter(f => !f.id.startsWith('DS-NET-'));
|
||||
assert.equal(
|
||||
wrongPrefix.length, 0,
|
||||
`All network findings should have DS-NET- prefix. Wrong: ${wrongPrefix.map(f => f.id).join(', ')}`
|
||||
);
|
||||
});
|
||||
|
||||
it('finding IDs start from DS-NET-001 after reset', async () => {
|
||||
const result = await scan(FIXTURE, discovery);
|
||||
if (result.findings.length === 0) return;
|
||||
assert.equal(result.findings[0].id, 'DS-NET-001');
|
||||
});
|
||||
|
||||
it('counts total matches findings array length', async () => {
|
||||
const result = await scan(FIXTURE, discovery);
|
||||
const countTotal = Object.values(result.counts).reduce((s, n) => s + n, 0);
|
||||
assert.equal(
|
||||
countTotal, result.findings.length,
|
||||
`counts total (${countTotal}) should match findings.length (${result.findings.length})`
|
||||
);
|
||||
});
|
||||
|
||||
it('does not emit findings for trusted domains (github.com, anthropic.com)', async () => {
|
||||
const result = await scan(FIXTURE, discovery);
|
||||
const trustedDomainFindings = result.findings.filter(
|
||||
f => (f.evidence && (
|
||||
f.evidence.includes('github.com') ||
|
||||
f.evidence.includes('anthropic.com') ||
|
||||
f.evidence.includes('npmjs.org')
|
||||
))
|
||||
);
|
||||
assert.equal(
|
||||
trustedDomainFindings.length, 0,
|
||||
`Should not flag trusted domains. Found: ${trustedDomainFindings.map(f => f.evidence).join(', ')}`
|
||||
);
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue