vskill 0.1.0 → 0.1.2
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/agents/agents-registry.d.ts +48 -37
- package/dist/agents/agents-registry.js +206 -261
- package/dist/agents/agents-registry.js.map +1 -1
- package/dist/agents/agents-registry.test.d.ts +1 -0
- package/dist/agents/agents-registry.test.js +203 -0
- package/dist/agents/agents-registry.test.js.map +1 -0
- package/dist/api/client.js +9 -1
- package/dist/api/client.js.map +1 -1
- package/dist/api/client.test.d.ts +1 -0
- package/dist/api/client.test.js +204 -0
- package/dist/api/client.test.js.map +1 -0
- package/dist/blocklist/blocklist.d.ts +23 -0
- package/dist/blocklist/blocklist.js +116 -0
- package/dist/blocklist/blocklist.js.map +1 -0
- package/dist/blocklist/blocklist.test.d.ts +1 -0
- package/dist/blocklist/blocklist.test.js +259 -0
- package/dist/blocklist/blocklist.test.js.map +1 -0
- package/dist/blocklist/types.d.ts +18 -0
- package/dist/blocklist/types.js +5 -0
- package/dist/blocklist/types.js.map +1 -0
- package/dist/commands/add.d.ts +2 -0
- package/dist/commands/add.js +221 -6
- package/dist/commands/add.js.map +1 -1
- package/dist/commands/add.test.d.ts +1 -0
- package/dist/commands/add.test.js +682 -0
- package/dist/commands/add.test.js.map +1 -0
- package/dist/commands/blocklist.d.ts +1 -0
- package/dist/commands/blocklist.js +87 -0
- package/dist/commands/blocklist.js.map +1 -0
- package/dist/commands/blocklist.test.d.ts +1 -0
- package/dist/commands/blocklist.test.js +158 -0
- package/dist/commands/blocklist.test.js.map +1 -0
- package/dist/commands/remove.d.ts +7 -0
- package/dist/commands/remove.js +91 -0
- package/dist/commands/remove.js.map +1 -0
- package/dist/commands/remove.test.d.ts +1 -0
- package/dist/commands/remove.test.js +164 -0
- package/dist/commands/remove.test.js.map +1 -0
- package/dist/commands/submit.d.ts +1 -1
- package/dist/commands/submit.js +26 -16
- package/dist/commands/submit.js.map +1 -1
- package/dist/commands/submit.test.d.ts +1 -0
- package/dist/commands/submit.test.js +74 -0
- package/dist/commands/submit.test.js.map +1 -0
- package/dist/index.js +21 -2
- package/dist/index.js.map +1 -1
- package/dist/lockfile/lockfile.test.d.ts +1 -0
- package/dist/lockfile/lockfile.test.js +196 -0
- package/dist/lockfile/lockfile.test.js.map +1 -0
- package/dist/lockfile/types.d.ts +8 -0
- package/dist/marketplace/index.d.ts +2 -0
- package/dist/marketplace/index.js +2 -0
- package/dist/marketplace/index.js.map +1 -0
- package/dist/marketplace/marketplace.d.ts +34 -0
- package/dist/marketplace/marketplace.js +51 -0
- package/dist/marketplace/marketplace.js.map +1 -0
- package/dist/marketplace/marketplace.test.d.ts +1 -0
- package/dist/marketplace/marketplace.test.js +103 -0
- package/dist/marketplace/marketplace.test.js.map +1 -0
- package/dist/scanner/index.d.ts +4 -0
- package/dist/scanner/index.js +4 -0
- package/dist/scanner/index.js.map +1 -1
- package/dist/scanner/patterns.test.d.ts +1 -0
- package/dist/scanner/patterns.test.js +353 -0
- package/dist/scanner/patterns.test.js.map +1 -0
- package/dist/scanner/repo-scanner.d.ts +30 -0
- package/dist/scanner/repo-scanner.js +190 -0
- package/dist/scanner/repo-scanner.js.map +1 -0
- package/dist/scanner/tier1.test.d.ts +1 -0
- package/dist/scanner/tier1.test.js +182 -0
- package/dist/scanner/tier1.test.js.map +1 -0
- package/dist/scanner/tier2-llm.d.ts +28 -0
- package/dist/scanner/tier2-llm.js +130 -0
- package/dist/scanner/tier2-llm.js.map +1 -0
- package/dist/scanner/types.d.ts +58 -0
- package/dist/scanner/types.js +5 -0
- package/dist/scanner/types.js.map +1 -0
- package/dist/security/index.d.ts +2 -0
- package/dist/security/index.js +2 -0
- package/dist/security/index.js.map +1 -0
- package/dist/security/platform-security.d.ts +17 -0
- package/dist/security/platform-security.js +34 -0
- package/dist/security/platform-security.js.map +1 -0
- package/dist/security/platform-security.test.d.ts +1 -0
- package/dist/security/platform-security.test.js +92 -0
- package/dist/security/platform-security.test.js.map +1 -0
- package/dist/settings/index.d.ts +2 -0
- package/dist/settings/index.js +2 -0
- package/dist/settings/index.js.map +1 -0
- package/dist/settings/settings.d.ts +16 -0
- package/dist/settings/settings.js +73 -0
- package/dist/settings/settings.js.map +1 -0
- package/dist/settings/settings.test.d.ts +1 -0
- package/dist/settings/settings.test.js +103 -0
- package/dist/settings/settings.test.js.map +1 -0
- package/dist/utils/__tests__/paths.test.d.ts +1 -0
- package/dist/utils/__tests__/paths.test.js +22 -0
- package/dist/utils/__tests__/paths.test.js.map +1 -0
- package/dist/utils/__tests__/validation.test.d.ts +1 -0
- package/dist/utils/__tests__/validation.test.js +49 -0
- package/dist/utils/__tests__/validation.test.js.map +1 -0
- package/dist/utils/browser.d.ts +6 -0
- package/dist/utils/browser.js +37 -0
- package/dist/utils/browser.js.map +1 -0
- package/dist/utils/paths.d.ts +5 -0
- package/dist/utils/paths.js +13 -0
- package/dist/utils/paths.js.map +1 -0
- package/dist/utils/validation.d.ts +14 -0
- package/dist/utils/validation.js +34 -0
- package/dist/utils/validation.js.map +1 -0
- package/package.json +5 -2
- package/scripts/preuninstall.cjs +58 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Blocklist module — malicious skills registry client with local cache
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "node:fs";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import { homedir } from "node:os";
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
// Constants
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
const CACHE_DIR = join(homedir(), ".vskill");
|
|
11
|
+
const CACHE_FILE = join(CACHE_DIR, "blocklist.json");
|
|
12
|
+
const STALE_THRESHOLD_MS = 60 * 60 * 1000; // 1 hour
|
|
13
|
+
const DEFAULT_API_URL = "https://verified-skill.com";
|
|
14
|
+
function getApiBaseUrl() {
|
|
15
|
+
return process.env.VSKILL_API_URL || DEFAULT_API_URL;
|
|
16
|
+
}
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
// Cache operations
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
/**
|
|
21
|
+
* Read the cached blocklist from disk.
|
|
22
|
+
* Returns null if the cache file does not exist or is corrupted.
|
|
23
|
+
*/
|
|
24
|
+
export function getCachedBlocklist() {
|
|
25
|
+
if (!existsSync(CACHE_FILE))
|
|
26
|
+
return null;
|
|
27
|
+
try {
|
|
28
|
+
const raw = readFileSync(CACHE_FILE, "utf-8");
|
|
29
|
+
return JSON.parse(raw);
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Check whether the cached blocklist is older than the stale threshold (1 hour).
|
|
37
|
+
*/
|
|
38
|
+
export function isBlocklistStale(cache) {
|
|
39
|
+
const fetchedAt = new Date(cache.fetchedAt).getTime();
|
|
40
|
+
if (isNaN(fetchedAt))
|
|
41
|
+
return true;
|
|
42
|
+
return Date.now() - fetchedAt > STALE_THRESHOLD_MS;
|
|
43
|
+
}
|
|
44
|
+
// ---------------------------------------------------------------------------
|
|
45
|
+
// API operations
|
|
46
|
+
// ---------------------------------------------------------------------------
|
|
47
|
+
/**
|
|
48
|
+
* Fetch the full blocklist from the API and write it to the local cache.
|
|
49
|
+
*/
|
|
50
|
+
export async function syncBlocklist() {
|
|
51
|
+
const url = `${getApiBaseUrl()}/api/v1/blocklist`;
|
|
52
|
+
const res = await fetch(url, {
|
|
53
|
+
headers: { Accept: "application/json" },
|
|
54
|
+
});
|
|
55
|
+
if (!res.ok) {
|
|
56
|
+
throw new Error(`Blocklist API error: ${res.status}`);
|
|
57
|
+
}
|
|
58
|
+
const data = await res.json();
|
|
59
|
+
const etag = res.headers.get("etag") || undefined;
|
|
60
|
+
const cache = {
|
|
61
|
+
entries: data.entries,
|
|
62
|
+
count: data.count,
|
|
63
|
+
lastUpdated: data.lastUpdated,
|
|
64
|
+
fetchedAt: new Date().toISOString(),
|
|
65
|
+
etag,
|
|
66
|
+
};
|
|
67
|
+
// Ensure cache directory exists
|
|
68
|
+
if (!existsSync(CACHE_DIR)) {
|
|
69
|
+
mkdirSync(CACHE_DIR, { recursive: true });
|
|
70
|
+
}
|
|
71
|
+
writeFileSync(CACHE_FILE, JSON.stringify(cache, null, 2), "utf-8");
|
|
72
|
+
return cache;
|
|
73
|
+
}
|
|
74
|
+
// ---------------------------------------------------------------------------
|
|
75
|
+
// Lookup
|
|
76
|
+
// ---------------------------------------------------------------------------
|
|
77
|
+
/**
|
|
78
|
+
* Find a matching entry in the blocklist by skill name or content hash.
|
|
79
|
+
*/
|
|
80
|
+
function findEntry(entries, skillName, contentHash) {
|
|
81
|
+
for (const entry of entries) {
|
|
82
|
+
if (entry.skillName === skillName)
|
|
83
|
+
return entry;
|
|
84
|
+
if (contentHash && entry.contentHash && entry.contentHash === contentHash) {
|
|
85
|
+
return entry;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Check whether a skill is on the blocklist.
|
|
92
|
+
*
|
|
93
|
+
* 1. Check local cache first.
|
|
94
|
+
* 2. If cache is stale, attempt to refresh from the API.
|
|
95
|
+
* 3. If the API is unreachable, fall back to the stale cache.
|
|
96
|
+
* 4. Returns the matching BlocklistEntry or null if not blocked.
|
|
97
|
+
*/
|
|
98
|
+
export async function checkBlocklist(skillName, contentHash) {
|
|
99
|
+
let cache = getCachedBlocklist();
|
|
100
|
+
if (cache && !isBlocklistStale(cache)) {
|
|
101
|
+
return findEntry(cache.entries, skillName, contentHash);
|
|
102
|
+
}
|
|
103
|
+
// Cache is stale or missing — try to refresh
|
|
104
|
+
try {
|
|
105
|
+
cache = await syncBlocklist();
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
// API unreachable — fall back to stale cache if available
|
|
109
|
+
if (cache) {
|
|
110
|
+
return findEntry(cache.entries, skillName, contentHash);
|
|
111
|
+
}
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
return findEntry(cache.entries, skillName, contentHash);
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=blocklist.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blocklist.js","sourceRoot":"","sources":["../../src/blocklist/blocklist.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
2
|
+
// ---------------------------------------------------------------------------
|
|
3
|
+
// Mocks — vi.hoisted for ESM compatibility
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
const mocks = vi.hoisted(() => ({
|
|
6
|
+
readFileSync: vi.fn(),
|
|
7
|
+
writeFileSync: vi.fn(),
|
|
8
|
+
mkdirSync: vi.fn(),
|
|
9
|
+
existsSync: vi.fn(),
|
|
10
|
+
fetch: vi.fn(),
|
|
11
|
+
}));
|
|
12
|
+
vi.mock("node:fs", () => ({
|
|
13
|
+
readFileSync: mocks.readFileSync,
|
|
14
|
+
writeFileSync: mocks.writeFileSync,
|
|
15
|
+
mkdirSync: mocks.mkdirSync,
|
|
16
|
+
existsSync: mocks.existsSync,
|
|
17
|
+
}));
|
|
18
|
+
// Mock global fetch
|
|
19
|
+
const originalFetch = globalThis.fetch;
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
// Import module under test AFTER mocks
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
const { checkBlocklist, syncBlocklist, getCachedBlocklist, isBlocklistStale, } = await import("./blocklist.js");
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
// Helpers
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
function makeEntry(overrides = {}) {
|
|
28
|
+
return {
|
|
29
|
+
skillName: "evil-skill",
|
|
30
|
+
threatType: "credential-theft",
|
|
31
|
+
severity: "critical",
|
|
32
|
+
reason: "Steals AWS credentials",
|
|
33
|
+
evidenceUrls: ["https://example.com/report"],
|
|
34
|
+
discoveredAt: "2026-02-01T00:00:00Z",
|
|
35
|
+
...overrides,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function makeCache(overrides = {}) {
|
|
39
|
+
return {
|
|
40
|
+
entries: [makeEntry()],
|
|
41
|
+
count: 1,
|
|
42
|
+
lastUpdated: "2026-02-01T00:00:00Z",
|
|
43
|
+
fetchedAt: new Date().toISOString(),
|
|
44
|
+
...overrides,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
// ---------------------------------------------------------------------------
|
|
48
|
+
// Tests
|
|
49
|
+
// ---------------------------------------------------------------------------
|
|
50
|
+
beforeEach(() => {
|
|
51
|
+
vi.clearAllMocks();
|
|
52
|
+
globalThis.fetch = mocks.fetch;
|
|
53
|
+
});
|
|
54
|
+
afterEach(() => {
|
|
55
|
+
globalThis.fetch = originalFetch;
|
|
56
|
+
delete process.env.VSKILL_API_URL;
|
|
57
|
+
});
|
|
58
|
+
describe("getCachedBlocklist", () => {
|
|
59
|
+
it("returns null when cache file does not exist", () => {
|
|
60
|
+
mocks.existsSync.mockReturnValue(false);
|
|
61
|
+
expect(getCachedBlocklist()).toBeNull();
|
|
62
|
+
});
|
|
63
|
+
it("returns parsed cache when file exists", () => {
|
|
64
|
+
const cache = makeCache();
|
|
65
|
+
mocks.existsSync.mockReturnValue(true);
|
|
66
|
+
mocks.readFileSync.mockReturnValue(JSON.stringify(cache));
|
|
67
|
+
const result = getCachedBlocklist();
|
|
68
|
+
expect(result).toEqual(cache);
|
|
69
|
+
});
|
|
70
|
+
it("returns null when cache file is corrupted", () => {
|
|
71
|
+
mocks.existsSync.mockReturnValue(true);
|
|
72
|
+
mocks.readFileSync.mockReturnValue("not json{{{");
|
|
73
|
+
expect(getCachedBlocklist()).toBeNull();
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
describe("isBlocklistStale", () => {
|
|
77
|
+
it("returns true when cache is older than 1 hour", () => {
|
|
78
|
+
const twoHoursAgo = new Date(Date.now() - 2 * 60 * 60 * 1000).toISOString();
|
|
79
|
+
const cache = makeCache({ fetchedAt: twoHoursAgo });
|
|
80
|
+
expect(isBlocklistStale(cache)).toBe(true);
|
|
81
|
+
});
|
|
82
|
+
it("returns false when cache is less than 1 hour old", () => {
|
|
83
|
+
const tenMinutesAgo = new Date(Date.now() - 10 * 60 * 1000).toISOString();
|
|
84
|
+
const cache = makeCache({ fetchedAt: tenMinutesAgo });
|
|
85
|
+
expect(isBlocklistStale(cache)).toBe(false);
|
|
86
|
+
});
|
|
87
|
+
it("returns true when fetchedAt is invalid", () => {
|
|
88
|
+
const cache = makeCache({ fetchedAt: "invalid-date" });
|
|
89
|
+
expect(isBlocklistStale(cache)).toBe(true);
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
describe("syncBlocklist", () => {
|
|
93
|
+
it("fetches from API and writes cache file", async () => {
|
|
94
|
+
const apiResponse = {
|
|
95
|
+
entries: [makeEntry()],
|
|
96
|
+
count: 1,
|
|
97
|
+
lastUpdated: "2026-02-01T00:00:00Z",
|
|
98
|
+
};
|
|
99
|
+
mocks.fetch.mockResolvedValue({
|
|
100
|
+
ok: true,
|
|
101
|
+
headers: { get: () => null },
|
|
102
|
+
json: async () => apiResponse,
|
|
103
|
+
});
|
|
104
|
+
mocks.existsSync.mockReturnValue(true);
|
|
105
|
+
const result = await syncBlocklist();
|
|
106
|
+
expect(mocks.fetch).toHaveBeenCalledWith("https://verified-skill.com/api/v1/blocklist", expect.any(Object));
|
|
107
|
+
expect(mocks.writeFileSync).toHaveBeenCalled();
|
|
108
|
+
expect(result.entries).toEqual(apiResponse.entries);
|
|
109
|
+
expect(result.count).toBe(1);
|
|
110
|
+
expect(result.fetchedAt).toBeDefined();
|
|
111
|
+
});
|
|
112
|
+
it("uses VSKILL_API_URL environment variable when set", async () => {
|
|
113
|
+
process.env.VSKILL_API_URL = "https://custom-api.example.com";
|
|
114
|
+
const apiResponse = {
|
|
115
|
+
entries: [],
|
|
116
|
+
count: 0,
|
|
117
|
+
lastUpdated: "2026-02-01T00:00:00Z",
|
|
118
|
+
};
|
|
119
|
+
mocks.fetch.mockResolvedValue({
|
|
120
|
+
ok: true,
|
|
121
|
+
headers: { get: () => null },
|
|
122
|
+
json: async () => apiResponse,
|
|
123
|
+
});
|
|
124
|
+
mocks.existsSync.mockReturnValue(true);
|
|
125
|
+
await syncBlocklist();
|
|
126
|
+
expect(mocks.fetch).toHaveBeenCalledWith("https://custom-api.example.com/api/v1/blocklist", expect.any(Object));
|
|
127
|
+
});
|
|
128
|
+
it("creates ~/.vskill directory if it doesn't exist", async () => {
|
|
129
|
+
const apiResponse = {
|
|
130
|
+
entries: [],
|
|
131
|
+
count: 0,
|
|
132
|
+
lastUpdated: "2026-02-01T00:00:00Z",
|
|
133
|
+
};
|
|
134
|
+
mocks.fetch.mockResolvedValue({
|
|
135
|
+
ok: true,
|
|
136
|
+
headers: { get: () => null },
|
|
137
|
+
json: async () => apiResponse,
|
|
138
|
+
});
|
|
139
|
+
mocks.existsSync.mockReturnValue(false);
|
|
140
|
+
await syncBlocklist();
|
|
141
|
+
expect(mocks.mkdirSync).toHaveBeenCalledWith(expect.stringContaining(".vskill"), { recursive: true });
|
|
142
|
+
});
|
|
143
|
+
it("stores etag from response headers", async () => {
|
|
144
|
+
const apiResponse = {
|
|
145
|
+
entries: [],
|
|
146
|
+
count: 0,
|
|
147
|
+
lastUpdated: "2026-02-01T00:00:00Z",
|
|
148
|
+
};
|
|
149
|
+
mocks.fetch.mockResolvedValue({
|
|
150
|
+
ok: true,
|
|
151
|
+
headers: { get: (h) => (h === "etag" ? '"abc123"' : null) },
|
|
152
|
+
json: async () => apiResponse,
|
|
153
|
+
});
|
|
154
|
+
mocks.existsSync.mockReturnValue(true);
|
|
155
|
+
const result = await syncBlocklist();
|
|
156
|
+
expect(result.etag).toBe('"abc123"');
|
|
157
|
+
});
|
|
158
|
+
it("throws when API returns non-ok response", async () => {
|
|
159
|
+
mocks.fetch.mockResolvedValue({
|
|
160
|
+
ok: false,
|
|
161
|
+
status: 500,
|
|
162
|
+
statusText: "Internal Server Error",
|
|
163
|
+
});
|
|
164
|
+
await expect(syncBlocklist()).rejects.toThrow("Blocklist API error: 500");
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
describe("checkBlocklist", () => {
|
|
168
|
+
it("returns matching entry from fresh cache", async () => {
|
|
169
|
+
const entry = makeEntry({ skillName: "evil-skill" });
|
|
170
|
+
const cache = makeCache({
|
|
171
|
+
entries: [entry],
|
|
172
|
+
fetchedAt: new Date().toISOString(),
|
|
173
|
+
});
|
|
174
|
+
mocks.existsSync.mockReturnValue(true);
|
|
175
|
+
mocks.readFileSync.mockReturnValue(JSON.stringify(cache));
|
|
176
|
+
const result = await checkBlocklist("evil-skill");
|
|
177
|
+
expect(result).toEqual(entry);
|
|
178
|
+
});
|
|
179
|
+
it("returns null when skill is not in blocklist", async () => {
|
|
180
|
+
const cache = makeCache({
|
|
181
|
+
entries: [makeEntry({ skillName: "evil-skill" })],
|
|
182
|
+
fetchedAt: new Date().toISOString(),
|
|
183
|
+
});
|
|
184
|
+
mocks.existsSync.mockReturnValue(true);
|
|
185
|
+
mocks.readFileSync.mockReturnValue(JSON.stringify(cache));
|
|
186
|
+
const result = await checkBlocklist("safe-skill");
|
|
187
|
+
expect(result).toBeNull();
|
|
188
|
+
});
|
|
189
|
+
it("refreshes cache when stale and API is available", async () => {
|
|
190
|
+
const twoHoursAgo = new Date(Date.now() - 2 * 60 * 60 * 1000).toISOString();
|
|
191
|
+
const staleCache = makeCache({
|
|
192
|
+
entries: [makeEntry({ skillName: "old-evil" })],
|
|
193
|
+
fetchedAt: twoHoursAgo,
|
|
194
|
+
});
|
|
195
|
+
const freshEntry = makeEntry({ skillName: "new-evil" });
|
|
196
|
+
mocks.existsSync.mockReturnValue(true);
|
|
197
|
+
mocks.readFileSync.mockReturnValue(JSON.stringify(staleCache));
|
|
198
|
+
mocks.fetch.mockResolvedValue({
|
|
199
|
+
ok: true,
|
|
200
|
+
headers: { get: () => null },
|
|
201
|
+
json: async () => ({
|
|
202
|
+
entries: [freshEntry],
|
|
203
|
+
count: 1,
|
|
204
|
+
lastUpdated: "2026-02-19T00:00:00Z",
|
|
205
|
+
}),
|
|
206
|
+
});
|
|
207
|
+
const result = await checkBlocklist("new-evil");
|
|
208
|
+
expect(result).toEqual(freshEntry);
|
|
209
|
+
expect(mocks.fetch).toHaveBeenCalled();
|
|
210
|
+
});
|
|
211
|
+
it("falls back to stale cache when API is unreachable", async () => {
|
|
212
|
+
const twoHoursAgo = new Date(Date.now() - 2 * 60 * 60 * 1000).toISOString();
|
|
213
|
+
const entry = makeEntry({ skillName: "evil-skill" });
|
|
214
|
+
const staleCache = makeCache({
|
|
215
|
+
entries: [entry],
|
|
216
|
+
fetchedAt: twoHoursAgo,
|
|
217
|
+
});
|
|
218
|
+
mocks.existsSync.mockReturnValue(true);
|
|
219
|
+
mocks.readFileSync.mockReturnValue(JSON.stringify(staleCache));
|
|
220
|
+
mocks.fetch.mockRejectedValue(new Error("Network error"));
|
|
221
|
+
const result = await checkBlocklist("evil-skill");
|
|
222
|
+
expect(result).toEqual(entry);
|
|
223
|
+
});
|
|
224
|
+
it("returns null when no cache exists and API is unreachable", async () => {
|
|
225
|
+
mocks.existsSync.mockReturnValue(false);
|
|
226
|
+
mocks.fetch.mockRejectedValue(new Error("Network error"));
|
|
227
|
+
const result = await checkBlocklist("evil-skill");
|
|
228
|
+
expect(result).toBeNull();
|
|
229
|
+
});
|
|
230
|
+
it("matches by contentHash when provided", async () => {
|
|
231
|
+
const entry = makeEntry({
|
|
232
|
+
skillName: "evil-skill",
|
|
233
|
+
contentHash: "sha256:abc123",
|
|
234
|
+
});
|
|
235
|
+
const cache = makeCache({
|
|
236
|
+
entries: [entry],
|
|
237
|
+
fetchedAt: new Date().toISOString(),
|
|
238
|
+
});
|
|
239
|
+
mocks.existsSync.mockReturnValue(true);
|
|
240
|
+
mocks.readFileSync.mockReturnValue(JSON.stringify(cache));
|
|
241
|
+
const result = await checkBlocklist("different-name", "sha256:abc123");
|
|
242
|
+
expect(result).toEqual(entry);
|
|
243
|
+
});
|
|
244
|
+
it("matches by name even when contentHash doesn't match", async () => {
|
|
245
|
+
const entry = makeEntry({
|
|
246
|
+
skillName: "evil-skill",
|
|
247
|
+
contentHash: "sha256:different",
|
|
248
|
+
});
|
|
249
|
+
const cache = makeCache({
|
|
250
|
+
entries: [entry],
|
|
251
|
+
fetchedAt: new Date().toISOString(),
|
|
252
|
+
});
|
|
253
|
+
mocks.existsSync.mockReturnValue(true);
|
|
254
|
+
mocks.readFileSync.mockReturnValue(JSON.stringify(cache));
|
|
255
|
+
const result = await checkBlocklist("evil-skill", "sha256:nomatch");
|
|
256
|
+
expect(result).toEqual(entry);
|
|
257
|
+
});
|
|
258
|
+
});
|
|
259
|
+
//# sourceMappingURL=blocklist.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blocklist.test.js","sourceRoot":"","sources":["../../src/blocklist/blocklist.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface BlocklistEntry {
|
|
2
|
+
skillName: string;
|
|
3
|
+
sourceUrl?: string;
|
|
4
|
+
sourceRegistry?: string;
|
|
5
|
+
contentHash?: string;
|
|
6
|
+
threatType: string;
|
|
7
|
+
severity: string;
|
|
8
|
+
reason: string;
|
|
9
|
+
evidenceUrls: string[];
|
|
10
|
+
discoveredAt: string;
|
|
11
|
+
}
|
|
12
|
+
export interface BlocklistCache {
|
|
13
|
+
entries: BlocklistEntry[];
|
|
14
|
+
count: number;
|
|
15
|
+
lastUpdated: string;
|
|
16
|
+
fetchedAt: string;
|
|
17
|
+
etag?: string;
|
|
18
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/blocklist/types.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,8CAA8C;AAC9C,8EAA8E"}
|