vskill 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/audit/__fixtures__/clean-project/app.d.ts +1 -0
- package/dist/audit/__fixtures__/clean-project/app.js +8 -0
- package/dist/audit/__fixtures__/clean-project/app.js.map +1 -0
- package/dist/audit/__fixtures__/clean-project/utils.d.ts +2 -0
- package/dist/audit/__fixtures__/clean-project/utils.js +8 -0
- package/dist/audit/__fixtures__/clean-project/utils.js.map +1 -0
- package/dist/audit/__fixtures__/mixed-project/risky.d.ts +1 -0
- package/dist/audit/__fixtures__/mixed-project/risky.js +6 -0
- package/dist/audit/__fixtures__/mixed-project/risky.js.map +1 -0
- package/dist/audit/__fixtures__/mixed-project/safe.d.ts +1 -0
- package/dist/audit/__fixtures__/mixed-project/safe.js +5 -0
- package/dist/audit/__fixtures__/mixed-project/safe.js.map +1 -0
- package/dist/audit/__fixtures__/vulnerable-project/handler.d.ts +4 -0
- package/dist/audit/__fixtures__/vulnerable-project/handler.js +21 -0
- package/dist/audit/__fixtures__/vulnerable-project/handler.js.map +1 -0
- package/dist/audit/audit-integration.test.d.ts +1 -0
- package/dist/audit/audit-integration.test.js +92 -0
- package/dist/audit/audit-integration.test.js.map +1 -0
- package/dist/audit/audit-llm.d.ts +25 -0
- package/dist/audit/audit-llm.js +139 -0
- package/dist/audit/audit-llm.js.map +1 -0
- package/dist/audit/audit-llm.test.d.ts +1 -0
- package/dist/audit/audit-llm.test.js +110 -0
- package/dist/audit/audit-llm.test.js.map +1 -0
- package/dist/audit/audit-patterns.d.ts +31 -0
- package/dist/audit/audit-patterns.js +239 -0
- package/dist/audit/audit-patterns.js.map +1 -0
- package/dist/audit/audit-patterns.test.d.ts +1 -0
- package/dist/audit/audit-patterns.test.js +91 -0
- package/dist/audit/audit-patterns.test.js.map +1 -0
- package/dist/audit/audit-scanner.d.ts +16 -0
- package/dist/audit/audit-scanner.js +151 -0
- package/dist/audit/audit-scanner.js.map +1 -0
- package/dist/audit/audit-scanner.test.d.ts +1 -0
- package/dist/audit/audit-scanner.test.js +112 -0
- package/dist/audit/audit-scanner.test.js.map +1 -0
- package/dist/audit/audit-types.d.ts +98 -0
- package/dist/audit/audit-types.js +19 -0
- package/dist/audit/audit-types.js.map +1 -0
- package/dist/audit/audit-types.test.d.ts +1 -0
- package/dist/audit/audit-types.test.js +140 -0
- package/dist/audit/audit-types.test.js.map +1 -0
- package/dist/audit/config.d.ts +13 -0
- package/dist/audit/config.js +90 -0
- package/dist/audit/config.js.map +1 -0
- package/dist/audit/config.test.d.ts +1 -0
- package/dist/audit/config.test.js +44 -0
- package/dist/audit/config.test.js.map +1 -0
- package/dist/audit/file-discovery.d.ts +15 -0
- package/dist/audit/file-discovery.js +153 -0
- package/dist/audit/file-discovery.js.map +1 -0
- package/dist/audit/file-discovery.test.d.ts +1 -0
- package/dist/audit/file-discovery.test.js +120 -0
- package/dist/audit/file-discovery.test.js.map +1 -0
- package/dist/audit/fix-suggestions.d.ts +13 -0
- package/dist/audit/fix-suggestions.js +84 -0
- package/dist/audit/fix-suggestions.js.map +1 -0
- package/dist/audit/fix-suggestions.test.d.ts +1 -0
- package/dist/audit/fix-suggestions.test.js +35 -0
- package/dist/audit/fix-suggestions.test.js.map +1 -0
- package/dist/audit/formatters/json-formatter.d.ts +8 -0
- package/dist/audit/formatters/json-formatter.js +10 -0
- package/dist/audit/formatters/json-formatter.js.map +1 -0
- package/dist/audit/formatters/json-formatter.test.d.ts +1 -0
- package/dist/audit/formatters/json-formatter.test.js +49 -0
- package/dist/audit/formatters/json-formatter.test.js.map +1 -0
- package/dist/audit/formatters/report-formatter.d.ts +8 -0
- package/dist/audit/formatters/report-formatter.js +97 -0
- package/dist/audit/formatters/report-formatter.js.map +1 -0
- package/dist/audit/formatters/report-formatter.test.d.ts +1 -0
- package/dist/audit/formatters/report-formatter.test.js +51 -0
- package/dist/audit/formatters/report-formatter.test.js.map +1 -0
- package/dist/audit/formatters/sarif-formatter.d.ts +11 -0
- package/dist/audit/formatters/sarif-formatter.js +87 -0
- package/dist/audit/formatters/sarif-formatter.js.map +1 -0
- package/dist/audit/formatters/sarif-formatter.test.d.ts +1 -0
- package/dist/audit/formatters/sarif-formatter.test.js +71 -0
- package/dist/audit/formatters/sarif-formatter.test.js.map +1 -0
- package/dist/audit/formatters/terminal-formatter.d.ts +9 -0
- package/dist/audit/formatters/terminal-formatter.js +61 -0
- package/dist/audit/formatters/terminal-formatter.js.map +1 -0
- package/dist/audit/formatters/terminal-formatter.test.d.ts +1 -0
- package/dist/audit/formatters/terminal-formatter.test.js +51 -0
- package/dist/audit/formatters/terminal-formatter.test.js.map +1 -0
- package/dist/audit/index.d.ts +2 -0
- package/dist/audit/index.js +2 -0
- package/dist/audit/index.js.map +1 -0
- package/dist/blocklist/blocklist-e2e.test.d.ts +1 -0
- package/dist/blocklist/blocklist-e2e.test.js +346 -0
- package/dist/blocklist/blocklist-e2e.test.js.map +1 -0
- package/dist/commands/add-blocklist-e2e.test.d.ts +1 -0
- package/dist/commands/add-blocklist-e2e.test.js +390 -0
- package/dist/commands/add-blocklist-e2e.test.js.map +1 -0
- package/dist/commands/add.js +184 -7
- package/dist/commands/add.js.map +1 -1
- package/dist/commands/add.test.js +159 -19
- package/dist/commands/add.test.js.map +1 -1
- package/dist/commands/audit.d.ts +23 -0
- package/dist/commands/audit.js +100 -0
- package/dist/commands/audit.js.map +1 -0
- package/dist/commands/audit.test.d.ts +1 -0
- package/dist/commands/audit.test.js +79 -0
- package/dist/commands/audit.test.js.map +1 -0
- package/dist/discovery/github-tree.d.ts +15 -0
- package/dist/discovery/github-tree.js +54 -0
- package/dist/discovery/github-tree.js.map +1 -0
- package/dist/discovery/github-tree.test.d.ts +1 -0
- package/dist/discovery/github-tree.test.js +143 -0
- package/dist/discovery/github-tree.test.js.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -1
- package/dist/lockfile/index.d.ts +1 -0
- package/dist/lockfile/index.js +1 -0
- package/dist/lockfile/index.js.map +1 -1
- package/dist/lockfile/lockfile.js +2 -1
- package/dist/lockfile/lockfile.js.map +1 -1
- package/dist/lockfile/project-root.d.ts +11 -0
- package/dist/lockfile/project-root.js +29 -0
- package/dist/lockfile/project-root.js.map +1 -0
- package/dist/lockfile/project-root.test.d.ts +1 -0
- package/dist/lockfile/project-root.test.js +49 -0
- package/dist/lockfile/project-root.test.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// E2E integration tests: blocklist blocking with REAL malicious skill data
|
|
3
|
+
//
|
|
4
|
+
// These tests simulate the full chain:
|
|
5
|
+
// API response (real seed data) -> local cache -> checkBlocklist -> block
|
|
6
|
+
//
|
|
7
|
+
// They use the actual ClawHub malicious skill names, threat types, severities,
|
|
8
|
+
// and reasons from the verified-skill.com seed data to prove that a developer
|
|
9
|
+
// attempting to install a known-malicious skill is:
|
|
10
|
+
// 1. Blocked with the correct threat details
|
|
11
|
+
// 2. Shown the exact reason WHY it's blocked
|
|
12
|
+
// 3. Allowed through with --force but with a prominent warning
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
// Mocks
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
const mocks = vi.hoisted(() => ({
|
|
19
|
+
readFileSync: vi.fn(),
|
|
20
|
+
writeFileSync: vi.fn(),
|
|
21
|
+
mkdirSync: vi.fn(),
|
|
22
|
+
existsSync: vi.fn(),
|
|
23
|
+
}));
|
|
24
|
+
vi.mock("node:fs", () => ({
|
|
25
|
+
readFileSync: mocks.readFileSync,
|
|
26
|
+
writeFileSync: mocks.writeFileSync,
|
|
27
|
+
mkdirSync: mocks.mkdirSync,
|
|
28
|
+
existsSync: mocks.existsSync,
|
|
29
|
+
}));
|
|
30
|
+
const { checkBlocklist, getCachedBlocklist, syncBlocklist } = await import("./blocklist.js");
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
// Real seed data — mirrors the actual seed from vskill-platform
|
|
33
|
+
// These are the EXACT entries from blocklist-seed-data.ts
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
const REAL_SEED_ENTRIES = [
|
|
36
|
+
// hightower6eu — platform impersonation
|
|
37
|
+
{
|
|
38
|
+
skillName: "Clawhub",
|
|
39
|
+
sourceUrl: "https://github.com/hightower6eu/Clawhub",
|
|
40
|
+
sourceRegistry: "clawhub",
|
|
41
|
+
threatType: "platform-impersonation",
|
|
42
|
+
severity: "critical",
|
|
43
|
+
reason: "Impersonates the ClawHub/GitHub platform to trick users into running malicious code",
|
|
44
|
+
evidenceUrls: [
|
|
45
|
+
"https://snyk.io/blog/toxicskills-mcp-exploit",
|
|
46
|
+
"https://www.aikido.dev/blog/malicious-mcp-servers",
|
|
47
|
+
],
|
|
48
|
+
discoveredAt: "2025-12-01T00:00:00.000Z",
|
|
49
|
+
},
|
|
50
|
+
// hightower6eu — credential theft
|
|
51
|
+
{
|
|
52
|
+
skillName: "Polymarket Trading Bot",
|
|
53
|
+
sourceUrl: "https://github.com/hightower6eu/polymarket-trading-bot",
|
|
54
|
+
sourceRegistry: "clawhub",
|
|
55
|
+
threatType: "credential-theft",
|
|
56
|
+
severity: "critical",
|
|
57
|
+
reason: "Trading bot facade stealing wallet credentials and API keys",
|
|
58
|
+
evidenceUrls: ["https://snyk.io/blog/toxicskills-mcp-exploit"],
|
|
59
|
+
discoveredAt: "2025-12-01T00:00:00.000Z",
|
|
60
|
+
},
|
|
61
|
+
// hightower6eu — auto-updater trojan
|
|
62
|
+
{
|
|
63
|
+
skillName: "Skills Auto-Updater",
|
|
64
|
+
sourceUrl: "https://github.com/hightower6eu/skills-auto-updater",
|
|
65
|
+
sourceRegistry: "clawhub",
|
|
66
|
+
threatType: "auto-updater-trojan",
|
|
67
|
+
severity: "high",
|
|
68
|
+
reason: "Auto-updater trojan that downloads and executes malicious payloads",
|
|
69
|
+
evidenceUrls: ["https://snyk.io/blog/toxicskills-mcp-exploit"],
|
|
70
|
+
discoveredAt: "2025-12-01T00:00:00.000Z",
|
|
71
|
+
},
|
|
72
|
+
// Aslaep123 — base64 credential exfil
|
|
73
|
+
{
|
|
74
|
+
skillName: "polymarket-traiding-bot",
|
|
75
|
+
sourceUrl: "https://github.com/Aslaep123/polymarket-traiding-bot",
|
|
76
|
+
sourceRegistry: "clawhub",
|
|
77
|
+
threatType: "credential-theft",
|
|
78
|
+
severity: "critical",
|
|
79
|
+
reason: "Base64-encoded credential exfiltration via hidden HTTP requests",
|
|
80
|
+
evidenceUrls: [
|
|
81
|
+
"https://snyk.io/blog/toxicskills-mcp-exploit",
|
|
82
|
+
"https://www.aikido.dev/blog/malicious-mcp-servers",
|
|
83
|
+
],
|
|
84
|
+
discoveredAt: "2025-12-01T00:00:00.000Z",
|
|
85
|
+
},
|
|
86
|
+
// aztr0nutzs — prompt injection
|
|
87
|
+
{
|
|
88
|
+
skillName: "google-qx4",
|
|
89
|
+
sourceUrl: "https://github.com/aztr0nutzs/google-qx4",
|
|
90
|
+
sourceRegistry: "clawhub",
|
|
91
|
+
threatType: "prompt-injection",
|
|
92
|
+
severity: "critical",
|
|
93
|
+
reason: "Prompt injection via fake Google integration skill",
|
|
94
|
+
evidenceUrls: ["https://www.aikido.dev/blog/malicious-mcp-servers"],
|
|
95
|
+
discoveredAt: "2025-12-01T00:00:00.000Z",
|
|
96
|
+
},
|
|
97
|
+
// zaycv — typosquatting
|
|
98
|
+
{
|
|
99
|
+
skillName: "clawhud",
|
|
100
|
+
sourceUrl: "https://github.com/zaycv/clawhud",
|
|
101
|
+
sourceRegistry: "clawhub",
|
|
102
|
+
threatType: "typosquatting",
|
|
103
|
+
severity: "high",
|
|
104
|
+
reason: "Typosquatting ClawHub (clawhud vs clawhub) to mislead users",
|
|
105
|
+
evidenceUrls: ["https://www.aikido.dev/blog/malicious-mcp-servers"],
|
|
106
|
+
discoveredAt: "2025-12-01T00:00:00.000Z",
|
|
107
|
+
},
|
|
108
|
+
// zaycv — typosquatting (homoglyph)
|
|
109
|
+
{
|
|
110
|
+
skillName: "cIawhub",
|
|
111
|
+
sourceUrl: "https://github.com/zaycv/cIawhub",
|
|
112
|
+
sourceRegistry: "clawhub",
|
|
113
|
+
threatType: "typosquatting",
|
|
114
|
+
severity: "high",
|
|
115
|
+
reason: "Typosquatting ClawHub using uppercase I for lowercase l (cIawhub)",
|
|
116
|
+
evidenceUrls: ["https://www.aikido.dev/blog/malicious-mcp-servers"],
|
|
117
|
+
discoveredAt: "2025-12-01T00:00:00.000Z",
|
|
118
|
+
},
|
|
119
|
+
];
|
|
120
|
+
function makeFreshCache(entries = REAL_SEED_ENTRIES) {
|
|
121
|
+
return {
|
|
122
|
+
entries,
|
|
123
|
+
count: entries.length,
|
|
124
|
+
lastUpdated: "2026-02-19T00:00:00Z",
|
|
125
|
+
fetchedAt: new Date().toISOString(), // fresh (within 1 hour)
|
|
126
|
+
etag: '"seed-data"',
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
// ---------------------------------------------------------------------------
|
|
130
|
+
// Tests
|
|
131
|
+
// ---------------------------------------------------------------------------
|
|
132
|
+
const originalFetch = globalThis.fetch;
|
|
133
|
+
beforeEach(() => {
|
|
134
|
+
vi.clearAllMocks();
|
|
135
|
+
});
|
|
136
|
+
afterEach(() => {
|
|
137
|
+
globalThis.fetch = originalFetch;
|
|
138
|
+
delete process.env.VSKILL_API_URL;
|
|
139
|
+
});
|
|
140
|
+
// ============================================================================
|
|
141
|
+
// 1. Blocking known malicious skills by exact name
|
|
142
|
+
// ============================================================================
|
|
143
|
+
describe("E2E: blocking known malicious skills from ClawHub seed data", () => {
|
|
144
|
+
beforeEach(() => {
|
|
145
|
+
// Simulate fresh local cache with real seed data
|
|
146
|
+
mocks.existsSync.mockReturnValue(true);
|
|
147
|
+
mocks.readFileSync.mockReturnValue(JSON.stringify(makeFreshCache()));
|
|
148
|
+
});
|
|
149
|
+
it("blocks hightower6eu's Clawhub (platform-impersonation, critical)", async () => {
|
|
150
|
+
const result = await checkBlocklist("Clawhub");
|
|
151
|
+
expect(result).not.toBeNull();
|
|
152
|
+
expect(result.skillName).toBe("Clawhub");
|
|
153
|
+
expect(result.threatType).toBe("platform-impersonation");
|
|
154
|
+
expect(result.severity).toBe("critical");
|
|
155
|
+
expect(result.reason).toContain("Impersonates the ClawHub");
|
|
156
|
+
expect(result.sourceRegistry).toBe("clawhub");
|
|
157
|
+
});
|
|
158
|
+
it("blocks hightower6eu's Polymarket Trading Bot (credential-theft, critical)", async () => {
|
|
159
|
+
const result = await checkBlocklist("Polymarket Trading Bot");
|
|
160
|
+
expect(result).not.toBeNull();
|
|
161
|
+
expect(result.skillName).toBe("Polymarket Trading Bot");
|
|
162
|
+
expect(result.threatType).toBe("credential-theft");
|
|
163
|
+
expect(result.severity).toBe("critical");
|
|
164
|
+
expect(result.reason).toContain("wallet credentials");
|
|
165
|
+
});
|
|
166
|
+
it("blocks hightower6eu's Skills Auto-Updater (auto-updater-trojan, high)", async () => {
|
|
167
|
+
const result = await checkBlocklist("Skills Auto-Updater");
|
|
168
|
+
expect(result).not.toBeNull();
|
|
169
|
+
expect(result.threatType).toBe("auto-updater-trojan");
|
|
170
|
+
expect(result.severity).toBe("high");
|
|
171
|
+
expect(result.reason).toContain("malicious payloads");
|
|
172
|
+
});
|
|
173
|
+
it("blocks Aslaep123's polymarket-traiding-bot (credential-theft, critical)", async () => {
|
|
174
|
+
const result = await checkBlocklist("polymarket-traiding-bot");
|
|
175
|
+
expect(result).not.toBeNull();
|
|
176
|
+
expect(result.threatType).toBe("credential-theft");
|
|
177
|
+
expect(result.severity).toBe("critical");
|
|
178
|
+
expect(result.reason).toContain("Base64-encoded credential exfiltration");
|
|
179
|
+
expect(result.evidenceUrls).toContain("https://snyk.io/blog/toxicskills-mcp-exploit");
|
|
180
|
+
});
|
|
181
|
+
it("blocks aztr0nutzs's google-qx4 (prompt-injection, critical)", async () => {
|
|
182
|
+
const result = await checkBlocklist("google-qx4");
|
|
183
|
+
expect(result).not.toBeNull();
|
|
184
|
+
expect(result.threatType).toBe("prompt-injection");
|
|
185
|
+
expect(result.severity).toBe("critical");
|
|
186
|
+
expect(result.reason).toContain("Prompt injection");
|
|
187
|
+
});
|
|
188
|
+
it("blocks zaycv's clawhud typosquatting (typosquatting, high)", async () => {
|
|
189
|
+
const result = await checkBlocklist("clawhud");
|
|
190
|
+
expect(result).not.toBeNull();
|
|
191
|
+
expect(result.threatType).toBe("typosquatting");
|
|
192
|
+
expect(result.severity).toBe("high");
|
|
193
|
+
expect(result.reason).toContain("clawhud vs clawhub");
|
|
194
|
+
});
|
|
195
|
+
it("blocks zaycv's cIawhub homoglyph attack (typosquatting, high)", async () => {
|
|
196
|
+
const result = await checkBlocklist("cIawhub");
|
|
197
|
+
expect(result).not.toBeNull();
|
|
198
|
+
expect(result.threatType).toBe("typosquatting");
|
|
199
|
+
expect(result.reason).toContain("uppercase I for lowercase l");
|
|
200
|
+
});
|
|
201
|
+
it("allows legitimate skill that is NOT on the blocklist", async () => {
|
|
202
|
+
const result = await checkBlocklist("my-safe-coding-assistant");
|
|
203
|
+
expect(result).toBeNull();
|
|
204
|
+
});
|
|
205
|
+
});
|
|
206
|
+
// ============================================================================
|
|
207
|
+
// 2. API sync produces correct cache from real data
|
|
208
|
+
// ============================================================================
|
|
209
|
+
describe("E2E: API sync with real seed data", () => {
|
|
210
|
+
it("syncs 22 entries from API and all are searchable", async () => {
|
|
211
|
+
// Simulate the API returning the full seed data
|
|
212
|
+
globalThis.fetch = vi.fn().mockResolvedValue({
|
|
213
|
+
ok: true,
|
|
214
|
+
headers: { get: (h) => (h === "etag" ? '"v1"' : null) },
|
|
215
|
+
json: async () => ({
|
|
216
|
+
entries: REAL_SEED_ENTRIES,
|
|
217
|
+
count: REAL_SEED_ENTRIES.length,
|
|
218
|
+
lastUpdated: "2026-02-19T00:00:00Z",
|
|
219
|
+
}),
|
|
220
|
+
});
|
|
221
|
+
mocks.existsSync.mockReturnValue(true);
|
|
222
|
+
const cache = await syncBlocklist();
|
|
223
|
+
expect(cache.entries).toHaveLength(REAL_SEED_ENTRIES.length);
|
|
224
|
+
expect(cache.count).toBe(REAL_SEED_ENTRIES.length);
|
|
225
|
+
expect(cache.etag).toBe('"v1"');
|
|
226
|
+
// Verify writeFileSync was called with the cache
|
|
227
|
+
expect(mocks.writeFileSync).toHaveBeenCalledTimes(1);
|
|
228
|
+
const writtenData = JSON.parse(mocks.writeFileSync.mock.calls[0][1]);
|
|
229
|
+
expect(writtenData.entries).toHaveLength(REAL_SEED_ENTRIES.length);
|
|
230
|
+
// Every entry should have required fields
|
|
231
|
+
for (const entry of writtenData.entries) {
|
|
232
|
+
expect(entry.skillName).toBeTruthy();
|
|
233
|
+
expect(entry.threatType).toBeTruthy();
|
|
234
|
+
expect(entry.severity).toBeTruthy();
|
|
235
|
+
expect(entry.reason).toBeTruthy();
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
it("cached data allows blocking every seed entry by name", async () => {
|
|
239
|
+
// Set up fresh cache with all seed data
|
|
240
|
+
mocks.existsSync.mockReturnValue(true);
|
|
241
|
+
mocks.readFileSync.mockReturnValue(JSON.stringify(makeFreshCache()));
|
|
242
|
+
// Check every single seed entry is findable
|
|
243
|
+
for (const entry of REAL_SEED_ENTRIES) {
|
|
244
|
+
const result = await checkBlocklist(entry.skillName);
|
|
245
|
+
expect(result).not.toBeNull();
|
|
246
|
+
expect(result.skillName).toBe(entry.skillName);
|
|
247
|
+
expect(result.threatType).toBe(entry.threatType);
|
|
248
|
+
expect(result.severity).toBe(entry.severity);
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
});
|
|
252
|
+
// ============================================================================
|
|
253
|
+
// 3. Stale cache refresh with real data
|
|
254
|
+
// ============================================================================
|
|
255
|
+
describe("E2E: stale cache refresh with real seed data", () => {
|
|
256
|
+
it("refreshes stale cache from API and blocks newly added skills", async () => {
|
|
257
|
+
// Start with stale cache that has only 2 entries
|
|
258
|
+
const twoHoursAgo = new Date(Date.now() - 2 * 60 * 60 * 1000).toISOString();
|
|
259
|
+
const staleCache = makeFreshCache(REAL_SEED_ENTRIES.slice(0, 2));
|
|
260
|
+
staleCache.fetchedAt = twoHoursAgo;
|
|
261
|
+
mocks.existsSync.mockReturnValue(true);
|
|
262
|
+
mocks.readFileSync.mockReturnValue(JSON.stringify(staleCache));
|
|
263
|
+
// API returns full data
|
|
264
|
+
globalThis.fetch = vi.fn().mockResolvedValue({
|
|
265
|
+
ok: true,
|
|
266
|
+
headers: { get: () => null },
|
|
267
|
+
json: async () => ({
|
|
268
|
+
entries: REAL_SEED_ENTRIES,
|
|
269
|
+
count: REAL_SEED_ENTRIES.length,
|
|
270
|
+
lastUpdated: "2026-02-19T00:00:00Z",
|
|
271
|
+
}),
|
|
272
|
+
});
|
|
273
|
+
// google-qx4 was not in stale cache (only first 2 entries)
|
|
274
|
+
// but after refresh it should be findable
|
|
275
|
+
const result = await checkBlocklist("google-qx4");
|
|
276
|
+
expect(result).not.toBeNull();
|
|
277
|
+
expect(result.threatType).toBe("prompt-injection");
|
|
278
|
+
expect(result.severity).toBe("critical");
|
|
279
|
+
});
|
|
280
|
+
it("falls back to stale cache when API is down, still blocks known skills", async () => {
|
|
281
|
+
const twoHoursAgo = new Date(Date.now() - 2 * 60 * 60 * 1000).toISOString();
|
|
282
|
+
const staleCache = makeFreshCache();
|
|
283
|
+
staleCache.fetchedAt = twoHoursAgo;
|
|
284
|
+
mocks.existsSync.mockReturnValue(true);
|
|
285
|
+
mocks.readFileSync.mockReturnValue(JSON.stringify(staleCache));
|
|
286
|
+
// API is down
|
|
287
|
+
globalThis.fetch = vi
|
|
288
|
+
.fn()
|
|
289
|
+
.mockRejectedValue(new Error("ECONNREFUSED"));
|
|
290
|
+
// Should still block from stale cache
|
|
291
|
+
const result = await checkBlocklist("polymarket-traiding-bot");
|
|
292
|
+
expect(result).not.toBeNull();
|
|
293
|
+
expect(result.threatType).toBe("credential-theft");
|
|
294
|
+
expect(result.reason).toContain("Base64-encoded");
|
|
295
|
+
});
|
|
296
|
+
});
|
|
297
|
+
// ============================================================================
|
|
298
|
+
// 4. All 5 threat types are represented and catchable
|
|
299
|
+
// ============================================================================
|
|
300
|
+
describe("E2E: all threat types from ClawHub research are catchable", () => {
|
|
301
|
+
beforeEach(() => {
|
|
302
|
+
mocks.existsSync.mockReturnValue(true);
|
|
303
|
+
mocks.readFileSync.mockReturnValue(JSON.stringify(makeFreshCache()));
|
|
304
|
+
});
|
|
305
|
+
const threatTypeCases = [
|
|
306
|
+
{
|
|
307
|
+
name: "platform-impersonation (hightower6eu)",
|
|
308
|
+
skillName: "Clawhub",
|
|
309
|
+
expectedType: "platform-impersonation",
|
|
310
|
+
expectedSeverity: "critical",
|
|
311
|
+
},
|
|
312
|
+
{
|
|
313
|
+
name: "credential-theft (Aslaep123)",
|
|
314
|
+
skillName: "polymarket-traiding-bot",
|
|
315
|
+
expectedType: "credential-theft",
|
|
316
|
+
expectedSeverity: "critical",
|
|
317
|
+
},
|
|
318
|
+
{
|
|
319
|
+
name: "auto-updater-trojan (hightower6eu)",
|
|
320
|
+
skillName: "Skills Auto-Updater",
|
|
321
|
+
expectedType: "auto-updater-trojan",
|
|
322
|
+
expectedSeverity: "high",
|
|
323
|
+
},
|
|
324
|
+
{
|
|
325
|
+
name: "prompt-injection (aztr0nutzs)",
|
|
326
|
+
skillName: "google-qx4",
|
|
327
|
+
expectedType: "prompt-injection",
|
|
328
|
+
expectedSeverity: "critical",
|
|
329
|
+
},
|
|
330
|
+
{
|
|
331
|
+
name: "typosquatting (zaycv)",
|
|
332
|
+
skillName: "clawhud",
|
|
333
|
+
expectedType: "typosquatting",
|
|
334
|
+
expectedSeverity: "high",
|
|
335
|
+
},
|
|
336
|
+
];
|
|
337
|
+
it.each(threatTypeCases)("catches $name: $skillName", async ({ skillName, expectedType, expectedSeverity }) => {
|
|
338
|
+
const result = await checkBlocklist(skillName);
|
|
339
|
+
expect(result).not.toBeNull();
|
|
340
|
+
expect(result.threatType).toBe(expectedType);
|
|
341
|
+
expect(result.severity).toBe(expectedSeverity);
|
|
342
|
+
expect(result.reason.length).toBeGreaterThan(10); // has meaningful reason
|
|
343
|
+
expect(result.evidenceUrls.length).toBeGreaterThan(0); // has evidence
|
|
344
|
+
});
|
|
345
|
+
});
|
|
346
|
+
//# sourceMappingURL=blocklist-e2e.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blocklist-e2e.test.js","sourceRoot":"","sources":["../../src/blocklist/blocklist-e2e.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|