@skillsmith/core 0.5.4 → 0.5.5
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/CHANGELOG.md +4 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/src/api/client.d.ts +4 -66
- package/dist/src/api/client.d.ts.map +1 -1
- package/dist/src/api/client.events.d.ts.map +1 -1
- package/dist/src/api/client.events.js +10 -1
- package/dist/src/api/client.events.js.map +1 -1
- package/dist/src/api/client.js +40 -66
- package/dist/src/api/client.js.map +1 -1
- package/dist/src/api/client.token-refresh.d.ts +3 -0
- package/dist/src/api/client.token-refresh.d.ts.map +1 -0
- package/dist/src/api/client.token-refresh.js +19 -0
- package/dist/src/api/client.token-refresh.js.map +1 -0
- package/dist/src/api/client.token-refresh.test.d.ts +2 -0
- package/dist/src/api/client.token-refresh.test.d.ts.map +1 -0
- package/dist/src/api/client.token-refresh.test.js +73 -0
- package/dist/src/api/client.token-refresh.test.js.map +1 -0
- package/dist/src/api/client.types.d.ts +2 -0
- package/dist/src/api/client.types.d.ts.map +1 -1
- package/dist/src/api/index.d.ts +1 -1
- package/dist/src/api/index.d.ts.map +1 -1
- package/dist/src/api/index.js +1 -1
- package/dist/src/api/index.js.map +1 -1
- package/dist/src/api/schemas.d.ts +319 -70
- package/dist/src/config/index.d.ts +4 -0
- package/dist/src/config/index.d.ts.map +1 -1
- package/dist/src/config/index.js +6 -0
- package/dist/src/config/index.js.map +1 -1
- package/dist/src/config/token-credentials.d.ts +13 -0
- package/dist/src/config/token-credentials.d.ts.map +1 -0
- package/dist/src/config/token-credentials.js +126 -0
- package/dist/src/config/token-credentials.js.map +1 -0
- package/dist/src/config/token-credentials.test.d.ts +10 -0
- package/dist/src/config/token-credentials.test.d.ts.map +1 -0
- package/dist/src/config/token-credentials.test.js +91 -0
- package/dist/src/config/token-credentials.test.js.map +1 -0
- package/dist/src/index.d.ts +4 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +5 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/scripts/__tests__/scan-imported-skills.test.js +34 -5
- package/dist/src/scripts/__tests__/scan-imported-skills.test.js.map +1 -1
- package/dist/src/scripts/github-import/blocklist.d.ts +65 -0
- package/dist/src/scripts/github-import/blocklist.d.ts.map +1 -0
- package/dist/src/scripts/github-import/blocklist.js +124 -0
- package/dist/src/scripts/github-import/blocklist.js.map +1 -0
- package/dist/src/scripts/github-import/index.d.ts +1 -0
- package/dist/src/scripts/github-import/index.d.ts.map +1 -1
- package/dist/src/scripts/github-import/index.js +3 -0
- package/dist/src/scripts/github-import/index.js.map +1 -1
- package/dist/src/scripts/github-import/signal-of-intent.d.ts +87 -0
- package/dist/src/scripts/github-import/signal-of-intent.d.ts.map +1 -0
- package/dist/src/scripts/github-import/signal-of-intent.js +213 -0
- package/dist/src/scripts/github-import/signal-of-intent.js.map +1 -0
- package/dist/src/scripts/github-import/types.d.ts +22 -0
- package/dist/src/scripts/github-import/types.d.ts.map +1 -1
- package/dist/src/scripts/github-import/types.js.map +1 -1
- package/dist/src/scripts/import-github-skills.js +73 -3
- package/dist/src/scripts/import-github-skills.js.map +1 -1
- package/dist/src/scripts/skill-scanner/allowlist.d.ts +38 -0
- package/dist/src/scripts/skill-scanner/allowlist.d.ts.map +1 -0
- package/dist/src/scripts/skill-scanner/allowlist.js +178 -0
- package/dist/src/scripts/skill-scanner/allowlist.js.map +1 -0
- package/dist/src/scripts/skill-scanner/scanner.d.ts +10 -2
- package/dist/src/scripts/skill-scanner/scanner.d.ts.map +1 -1
- package/dist/src/scripts/skill-scanner/scanner.js +15 -3
- package/dist/src/scripts/skill-scanner/scanner.js.map +1 -1
- package/dist/src/scripts/skill-scanner/trust-scorer.d.ts +20 -6
- package/dist/src/scripts/skill-scanner/trust-scorer.d.ts.map +1 -1
- package/dist/src/scripts/skill-scanner/trust-scorer.js +28 -9
- package/dist/src/scripts/skill-scanner/trust-scorer.js.map +1 -1
- package/dist/src/scripts/skill-scanner/types.d.ts +50 -0
- package/dist/src/scripts/skill-scanner/types.d.ts.map +1 -1
- package/dist/src/security/scanner/SecurityScanner.helpers.d.ts +18 -0
- package/dist/src/security/scanner/SecurityScanner.helpers.d.ts.map +1 -1
- package/dist/src/security/scanner/SecurityScanner.helpers.js +54 -6
- package/dist/src/security/scanner/SecurityScanner.helpers.js.map +1 -1
- package/dist/src/security/scanner/patterns.d.ts.map +1 -1
- package/dist/src/security/scanner/patterns.js +45 -5
- package/dist/src/security/scanner/patterns.js.map +1 -1
- package/dist/tests/api/client.events.test.d.ts +10 -0
- package/dist/tests/api/client.events.test.d.ts.map +1 -0
- package/dist/tests/api/client.events.test.js +85 -0
- package/dist/tests/api/client.events.test.js.map +1 -0
- package/dist/tests/github-import/blocklist.test.d.ts +15 -0
- package/dist/tests/github-import/blocklist.test.d.ts.map +1 -0
- package/dist/tests/github-import/blocklist.test.js +182 -0
- package/dist/tests/github-import/blocklist.test.js.map +1 -0
- package/dist/tests/github-import/signal-of-intent.test.d.ts +15 -0
- package/dist/tests/github-import/signal-of-intent.test.d.ts.map +1 -0
- package/dist/tests/github-import/signal-of-intent.test.js +171 -0
- package/dist/tests/github-import/signal-of-intent.test.js.map +1 -0
- package/dist/tests/security/scanner-regression-guard.test.d.ts +12 -0
- package/dist/tests/security/scanner-regression-guard.test.d.ts.map +1 -1
- package/dist/tests/security/scanner-regression-guard.test.js +15 -3
- package/dist/tests/security/scanner-regression-guard.test.js.map +1 -1
- package/dist/tests/security/scanner-wave2-fixtures.test.d.ts +12 -0
- package/dist/tests/security/scanner-wave2-fixtures.test.d.ts.map +1 -0
- package/dist/tests/security/scanner-wave2-fixtures.test.js +173 -0
- package/dist/tests/security/scanner-wave2-fixtures.test.js.map +1 -0
- package/dist/tests/security.test.js +1 -0
- package/dist/tests/security.test.js.map +1 -1
- package/dist/tests/skill-scanner/allowlist.test.d.ts +16 -0
- package/dist/tests/skill-scanner/allowlist.test.d.ts.map +1 -0
- package/dist/tests/skill-scanner/allowlist.test.js +332 -0
- package/dist/tests/skill-scanner/allowlist.test.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SMI-4408: Indexer blocklist tests.
|
|
3
|
+
*
|
|
4
|
+
* Covers:
|
|
5
|
+
* - Exact-match blocking (owner/name, case-sensitive)
|
|
6
|
+
* - Non-blocklisted repos pass through
|
|
7
|
+
* - Empty/missing blocklist file returns EMPTY_BLOCKLIST (no-op)
|
|
8
|
+
* - Schema validation: version=1, required fields, valid repo format, valid dates
|
|
9
|
+
* - Duplicate entries rejected at load
|
|
10
|
+
* - Malformed JSON rejected at load
|
|
11
|
+
* - Ship-it sanity check: data/indexer-blocklist.json parses and contains
|
|
12
|
+
* the 2 known-bad entries from SMI-4396 Wave 2 residuals.
|
|
13
|
+
*/
|
|
14
|
+
import { describe, it, expect } from 'vitest';
|
|
15
|
+
import * as fs from 'fs';
|
|
16
|
+
import * as os from 'os';
|
|
17
|
+
import * as path from 'path';
|
|
18
|
+
import { buildBlocklist, EMPTY_BLOCKLIST, loadBlocklist, parseBlocklistFile, } from '../../src/scripts/github-import/blocklist.js';
|
|
19
|
+
const VALID_ENTRY = {
|
|
20
|
+
repo: 'vinayaksavle/UploadDownloadPDF',
|
|
21
|
+
reason: 'ASP.NET MVC tutorial, not a Claude skill',
|
|
22
|
+
addedBy: 'ryansmith108',
|
|
23
|
+
addedAt: '2026-04-21',
|
|
24
|
+
};
|
|
25
|
+
// ------------------------ matcher behavior ------------------------
|
|
26
|
+
describe('BlocklistMatcher (SMI-4408)', () => {
|
|
27
|
+
it('blocks exact-match owner/name (case-sensitive)', () => {
|
|
28
|
+
const matcher = buildBlocklist([VALID_ENTRY]);
|
|
29
|
+
expect(matcher.isBlocked('vinayaksavle/UploadDownloadPDF')).toBe(true);
|
|
30
|
+
});
|
|
31
|
+
it('does not block case-mismatched repo (exact match)', () => {
|
|
32
|
+
const matcher = buildBlocklist([VALID_ENTRY]);
|
|
33
|
+
expect(matcher.isBlocked('vinayaksavle/uploaddownloadpdf')).toBe(false);
|
|
34
|
+
expect(matcher.isBlocked('Vinayaksavle/UploadDownloadPDF')).toBe(false);
|
|
35
|
+
});
|
|
36
|
+
it('does not block non-blocklisted repos', () => {
|
|
37
|
+
const matcher = buildBlocklist([VALID_ENTRY]);
|
|
38
|
+
expect(matcher.isBlocked('anthropics/skills')).toBe(false);
|
|
39
|
+
expect(matcher.isBlocked('smith-horn/skill-image-pipeline')).toBe(false);
|
|
40
|
+
});
|
|
41
|
+
it('does not match partial strings (substring not allowed)', () => {
|
|
42
|
+
const matcher = buildBlocklist([VALID_ENTRY]);
|
|
43
|
+
expect(matcher.isBlocked('vinayaksavle/UploadDownloadPDF-extra')).toBe(false);
|
|
44
|
+
expect(matcher.isBlocked('other/vinayaksavle/UploadDownloadPDF')).toBe(false);
|
|
45
|
+
});
|
|
46
|
+
it('exposes entries() for audit-log output', () => {
|
|
47
|
+
const matcher = buildBlocklist([VALID_ENTRY]);
|
|
48
|
+
const entries = matcher.entries();
|
|
49
|
+
expect(entries).toHaveLength(1);
|
|
50
|
+
expect(entries[0]).toEqual(VALID_ENTRY);
|
|
51
|
+
});
|
|
52
|
+
it('EMPTY_BLOCKLIST blocks nothing', () => {
|
|
53
|
+
expect(EMPTY_BLOCKLIST.isBlocked('anything/at-all')).toBe(false);
|
|
54
|
+
expect(EMPTY_BLOCKLIST.entries()).toEqual([]);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
// ------------------------ schema validation ------------------------
|
|
58
|
+
describe('parseBlocklistFile (SMI-4408)', () => {
|
|
59
|
+
const validFile = {
|
|
60
|
+
version: 1,
|
|
61
|
+
updatedAt: '2026-04-21',
|
|
62
|
+
blocked: [VALID_ENTRY],
|
|
63
|
+
};
|
|
64
|
+
it('parses a valid file', () => {
|
|
65
|
+
const result = parseBlocklistFile(validFile);
|
|
66
|
+
expect(result.version).toBe(1);
|
|
67
|
+
expect(result.updatedAt).toBe('2026-04-21');
|
|
68
|
+
expect(result.blocked).toHaveLength(1);
|
|
69
|
+
expect(result.blocked[0]).toEqual(VALID_ENTRY);
|
|
70
|
+
});
|
|
71
|
+
it('rejects non-object root', () => {
|
|
72
|
+
expect(() => parseBlocklistFile(null)).toThrow(/must be an object/i);
|
|
73
|
+
expect(() => parseBlocklistFile('string')).toThrow(/must be an object/i);
|
|
74
|
+
// Arrays pass typeof === 'object' but fail on missing `version` field.
|
|
75
|
+
expect(() => parseBlocklistFile([])).toThrow(/unsupported blocklist file version/i);
|
|
76
|
+
});
|
|
77
|
+
it('rejects unsupported version', () => {
|
|
78
|
+
expect(() => parseBlocklistFile({ ...validFile, version: 2 })).toThrow(/unsupported blocklist file version/i);
|
|
79
|
+
expect(() => parseBlocklistFile({ ...validFile, version: 0 })).toThrow(/unsupported blocklist file version/i);
|
|
80
|
+
});
|
|
81
|
+
it('rejects invalid updatedAt', () => {
|
|
82
|
+
expect(() => parseBlocklistFile({ ...validFile, updatedAt: '04/21/2026' })).toThrow(/updatedAt must be YYYY-MM-DD/i);
|
|
83
|
+
expect(() => parseBlocklistFile({ ...validFile, updatedAt: 42 })).toThrow(/updatedAt must be YYYY-MM-DD/i);
|
|
84
|
+
});
|
|
85
|
+
it('rejects blocked field when not an array', () => {
|
|
86
|
+
expect(() => parseBlocklistFile({ ...validFile, blocked: {} })).toThrow(/blocked must be an array/i);
|
|
87
|
+
});
|
|
88
|
+
it('rejects entry with missing required field', () => {
|
|
89
|
+
for (const field of ['repo', 'reason', 'addedBy', 'addedAt']) {
|
|
90
|
+
const badEntry = { ...VALID_ENTRY };
|
|
91
|
+
delete badEntry[field];
|
|
92
|
+
expect(() => parseBlocklistFile({ ...validFile, blocked: [badEntry] })).toThrow(new RegExp(`missing or empty required field: ${field}`, 'i'));
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
it('rejects entry with empty required field', () => {
|
|
96
|
+
expect(() => parseBlocklistFile({ ...validFile, blocked: [{ ...VALID_ENTRY, reason: '' }] })).toThrow(/missing or empty required field: reason/i);
|
|
97
|
+
});
|
|
98
|
+
it('rejects malformed repo string', () => {
|
|
99
|
+
const bad = ['no-slash', '/leading', 'trailing/', 'too/many/slashes', 'has spaces/ok'];
|
|
100
|
+
for (const repo of bad) {
|
|
101
|
+
expect(() => parseBlocklistFile({ ...validFile, blocked: [{ ...VALID_ENTRY, repo }] })).toThrow(/repo must be 'owner\/name'/i);
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
it('accepts GitHub-valid repo names with common punctuation', () => {
|
|
105
|
+
const good = ['foo/bar', 'foo-bar/baz.qux', 'Foo123/Bar_v2', 'org.name/repo-name'];
|
|
106
|
+
for (const repo of good) {
|
|
107
|
+
expect(() => parseBlocklistFile({ ...validFile, blocked: [{ ...VALID_ENTRY, repo }] })).not.toThrow();
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
it('rejects invalid addedAt format', () => {
|
|
111
|
+
expect(() => parseBlocklistFile({ ...validFile, blocked: [{ ...VALID_ENTRY, addedAt: 'yesterday' }] })).toThrow(/addedAt must be YYYY-MM-DD/i);
|
|
112
|
+
});
|
|
113
|
+
it('rejects duplicate repo entries', () => {
|
|
114
|
+
expect(() => parseBlocklistFile({
|
|
115
|
+
...validFile,
|
|
116
|
+
blocked: [VALID_ENTRY, { ...VALID_ENTRY, addedAt: '2026-04-22' }],
|
|
117
|
+
})).toThrow(/duplicate entry: vinayaksavle\/UploadDownloadPDF/i);
|
|
118
|
+
});
|
|
119
|
+
it('non-object entry rejected with index', () => {
|
|
120
|
+
expect(() => parseBlocklistFile({ ...validFile, blocked: [VALID_ENTRY, 'string-entry'] })).toThrow(/entry #1 is not an object/i);
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
// ------------------------ loadBlocklist ------------------------
|
|
124
|
+
describe('loadBlocklist (SMI-4408)', () => {
|
|
125
|
+
it('returns EMPTY_BLOCKLIST when file is absent', () => {
|
|
126
|
+
const tmp = path.join(os.tmpdir(), `blocklist-absent-${Date.now()}.json`);
|
|
127
|
+
const matcher = loadBlocklist(tmp);
|
|
128
|
+
expect(matcher).toBe(EMPTY_BLOCKLIST);
|
|
129
|
+
expect(matcher.isBlocked('anything/at-all')).toBe(false);
|
|
130
|
+
});
|
|
131
|
+
it('throws on malformed JSON', () => {
|
|
132
|
+
const tmp = path.join(os.tmpdir(), `blocklist-malformed-${Date.now()}.json`);
|
|
133
|
+
fs.writeFileSync(tmp, '{ not valid json');
|
|
134
|
+
try {
|
|
135
|
+
expect(() => loadBlocklist(tmp)).toThrow(/is not valid JSON/i);
|
|
136
|
+
}
|
|
137
|
+
finally {
|
|
138
|
+
fs.unlinkSync(tmp);
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
it('throws on invalid schema', () => {
|
|
142
|
+
const tmp = path.join(os.tmpdir(), `blocklist-invalid-${Date.now()}.json`);
|
|
143
|
+
fs.writeFileSync(tmp, JSON.stringify({ version: 2, updatedAt: '2026-04-21', blocked: [] }));
|
|
144
|
+
try {
|
|
145
|
+
expect(() => loadBlocklist(tmp)).toThrow(/unsupported blocklist file version/i);
|
|
146
|
+
}
|
|
147
|
+
finally {
|
|
148
|
+
fs.unlinkSync(tmp);
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
it('loads a valid file', () => {
|
|
152
|
+
const tmp = path.join(os.tmpdir(), `blocklist-valid-${Date.now()}.json`);
|
|
153
|
+
fs.writeFileSync(tmp, JSON.stringify({
|
|
154
|
+
version: 1,
|
|
155
|
+
updatedAt: '2026-04-21',
|
|
156
|
+
blocked: [VALID_ENTRY],
|
|
157
|
+
}));
|
|
158
|
+
try {
|
|
159
|
+
const matcher = loadBlocklist(tmp);
|
|
160
|
+
expect(matcher.isBlocked('vinayaksavle/UploadDownloadPDF')).toBe(true);
|
|
161
|
+
expect(matcher.isBlocked('anthropics/skills')).toBe(false);
|
|
162
|
+
}
|
|
163
|
+
finally {
|
|
164
|
+
fs.unlinkSync(tmp);
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
// ------------------------ ship-it sanity ------------------------
|
|
169
|
+
describe('data/indexer-blocklist.json (ship-it sanity)', () => {
|
|
170
|
+
it('is parseable and contains the 2 SMI-4396 Wave 2 residuals', () => {
|
|
171
|
+
const filePath = path.resolve(__dirname, '../../../../data/indexer-blocklist.json');
|
|
172
|
+
const raw = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
173
|
+
const parsed = parseBlocklistFile(raw);
|
|
174
|
+
expect(parsed.blocked.length).toBe(2);
|
|
175
|
+
const repos = parsed.blocked.map((e) => e.repo).sort();
|
|
176
|
+
expect(repos).toEqual(['Sfedfcv/redesigned-pancake', 'vinayaksavle/UploadDownloadPDF'].sort());
|
|
177
|
+
// Each entry must carry a reason for audit trail.
|
|
178
|
+
expect(parsed.blocked.every((e) => e.reason.length > 0)).toBe(true);
|
|
179
|
+
expect(parsed.blocked.every((e) => e.addedBy.length > 0)).toBe(true);
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
//# sourceMappingURL=blocklist.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blocklist.test.js","sourceRoot":"","sources":["../../../tests/github-import/blocklist.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SMI-4415: Unit tests for the signal-of-intent gate.
|
|
3
|
+
*
|
|
4
|
+
* Fixture-driven verification of the Wave 0 admit/reject gate criteria:
|
|
5
|
+
* - ≥ 98% known-good admission (known-good.json, 10 entries → 100% expected)
|
|
6
|
+
* - ≥ 95% non-skill rejection (non-skills.json, 20 entries → 100% expected)
|
|
7
|
+
*
|
|
8
|
+
* Plus explicit regression guards:
|
|
9
|
+
* - Plan-review H4 floor: metadata-only skills must reject even at high score
|
|
10
|
+
* - Score-boundary: score === SIGNAL_THRESHOLD with structural signal admits,
|
|
11
|
+
* score === SIGNAL_THRESHOLD - 1 rejects
|
|
12
|
+
* - mcp-server-only: structural but below threshold → reject
|
|
13
|
+
*/
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=signal-of-intent.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signal-of-intent.test.d.ts","sourceRoot":"","sources":["../../../tests/github-import/signal-of-intent.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG"}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SMI-4415: Unit tests for the signal-of-intent gate.
|
|
3
|
+
*
|
|
4
|
+
* Fixture-driven verification of the Wave 0 admit/reject gate criteria:
|
|
5
|
+
* - ≥ 98% known-good admission (known-good.json, 10 entries → 100% expected)
|
|
6
|
+
* - ≥ 95% non-skill rejection (non-skills.json, 20 entries → 100% expected)
|
|
7
|
+
*
|
|
8
|
+
* Plus explicit regression guards:
|
|
9
|
+
* - Plan-review H4 floor: metadata-only skills must reject even at high score
|
|
10
|
+
* - Score-boundary: score === SIGNAL_THRESHOLD with structural signal admits,
|
|
11
|
+
* score === SIGNAL_THRESHOLD - 1 rejects
|
|
12
|
+
* - mcp-server-only: structural but below threshold → reject
|
|
13
|
+
*/
|
|
14
|
+
import { describe, expect, it } from 'vitest';
|
|
15
|
+
import { readFileSync } from 'node:fs';
|
|
16
|
+
import { dirname, join } from 'node:path';
|
|
17
|
+
import { fileURLToPath } from 'node:url';
|
|
18
|
+
import { computeSignalScore, HIGH_TRUST_OWNERS, shouldIngest, SIGNAL_THRESHOLD, } from '../../src/scripts/github-import/signal-of-intent.js';
|
|
19
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
20
|
+
const FIXTURES_DIR = join(__dirname, 'fixtures');
|
|
21
|
+
function loadFixture(name) {
|
|
22
|
+
return JSON.parse(readFileSync(join(FIXTURES_DIR, name), 'utf-8'));
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Minimal ImportedSkill shape for synthetic regression tests. Fields not
|
|
26
|
+
* relevant to scoring get benign defaults.
|
|
27
|
+
*/
|
|
28
|
+
function makeSkill(partial) {
|
|
29
|
+
return {
|
|
30
|
+
id: partial.id ?? 'github/test/synthetic',
|
|
31
|
+
name: partial.name ?? 'synthetic',
|
|
32
|
+
description: partial.description ?? '',
|
|
33
|
+
author: partial.author ?? 'test',
|
|
34
|
+
repo_url: partial.repo_url ?? 'https://github.com/test/synthetic',
|
|
35
|
+
clone_url: partial.clone_url ?? 'https://github.com/test/synthetic.git',
|
|
36
|
+
stars: partial.stars ?? 0,
|
|
37
|
+
forks: partial.forks ?? 0,
|
|
38
|
+
topics: partial.topics ?? [],
|
|
39
|
+
language: partial.language ?? null,
|
|
40
|
+
license: partial.license ?? null,
|
|
41
|
+
created_at: partial.created_at ?? '2024-01-01T00:00:00Z',
|
|
42
|
+
updated_at: partial.updated_at ?? '2026-04-21T00:00:00Z',
|
|
43
|
+
source: partial.source ?? 'github',
|
|
44
|
+
query_type: partial.query_type ?? 'test',
|
|
45
|
+
imported_at: partial.imported_at ?? '2026-04-21T00:00:00Z',
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
describe('signal-of-intent gate', () => {
|
|
49
|
+
describe('known-good fixtures', () => {
|
|
50
|
+
const knownGood = loadFixture('known-good.json');
|
|
51
|
+
it('loads exactly 10 entries (Wave 0 sample size)', () => {
|
|
52
|
+
expect(knownGood).toHaveLength(10);
|
|
53
|
+
});
|
|
54
|
+
it.each(knownGood.map((s) => [s.id, s]))('admits %s', (_id, skill) => {
|
|
55
|
+
expect(shouldIngest(skill)).toBe(true);
|
|
56
|
+
});
|
|
57
|
+
it('hits 100% admit rate on Wave 0 fixture corpus', () => {
|
|
58
|
+
const admitted = knownGood.filter((s) => shouldIngest(s));
|
|
59
|
+
expect(admitted).toHaveLength(knownGood.length);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
describe('non-skill fixtures', () => {
|
|
63
|
+
const nonSkills = loadFixture('non-skills.json');
|
|
64
|
+
it('loads exactly 20 entries (Wave 0 sample size)', () => {
|
|
65
|
+
expect(nonSkills).toHaveLength(20);
|
|
66
|
+
});
|
|
67
|
+
it.each(nonSkills.map((s) => [s.id, s]))('rejects %s', (_id, skill) => {
|
|
68
|
+
expect(shouldIngest(skill)).toBe(false);
|
|
69
|
+
});
|
|
70
|
+
it('hits 100% reject rate on Wave 0 fixture corpus', () => {
|
|
71
|
+
const admitted = nonSkills.filter((s) => shouldIngest(s));
|
|
72
|
+
expect(admitted).toHaveLength(0);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
describe('structural-signal floor (plan-review H4)', () => {
|
|
76
|
+
it('rejects metadata-only skills even when total score exceeds threshold', () => {
|
|
77
|
+
// Every metadata signal fires: description(+2) + name(+2) + language(+1)
|
|
78
|
+
// + license(+1) + stars(+1) = 7, well above SIGNAL_THRESHOLD (4).
|
|
79
|
+
// But topics=[] and author not in HIGH_TRUST_OWNERS → no structural
|
|
80
|
+
// signal → shouldIngest MUST reject. This is the H4 regression guard.
|
|
81
|
+
const metadataOnly = makeSkill({
|
|
82
|
+
id: 'github/nobody/claude-skill',
|
|
83
|
+
name: 'claude-skill', // matches NAME_REGEX
|
|
84
|
+
description: 'A skill for anthropic claude-code users', // matches DESCRIPTION_REGEX
|
|
85
|
+
author: 'nobody', // NOT in HIGH_TRUST_OWNERS
|
|
86
|
+
topics: [], // no structural topic
|
|
87
|
+
language: 'TypeScript',
|
|
88
|
+
license: 'MIT',
|
|
89
|
+
stars: 500, // >= STARS_THRESHOLD
|
|
90
|
+
});
|
|
91
|
+
const { score, signals, hasStructuralSignal } = computeSignalScore(metadataOnly);
|
|
92
|
+
expect(score).toBeGreaterThan(SIGNAL_THRESHOLD);
|
|
93
|
+
expect(hasStructuralSignal).toBe(false);
|
|
94
|
+
expect(signals).toEqual(expect.arrayContaining([
|
|
95
|
+
'description-match',
|
|
96
|
+
'name-match',
|
|
97
|
+
'language-match',
|
|
98
|
+
'license-present',
|
|
99
|
+
'stars-threshold',
|
|
100
|
+
]));
|
|
101
|
+
expect(shouldIngest(metadataOnly)).toBe(false);
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
describe('boundary conditions', () => {
|
|
105
|
+
it('admits a structural skill whose score equals SIGNAL_THRESHOLD', () => {
|
|
106
|
+
// Structural topic alone = +4 (exactly SIGNAL_THRESHOLD).
|
|
107
|
+
const exactlyAtThreshold = makeSkill({
|
|
108
|
+
topics: ['claude-skill'], // +4, structural
|
|
109
|
+
// no other signals
|
|
110
|
+
});
|
|
111
|
+
const { score, hasStructuralSignal } = computeSignalScore(exactlyAtThreshold);
|
|
112
|
+
expect(score).toBe(SIGNAL_THRESHOLD);
|
|
113
|
+
expect(hasStructuralSignal).toBe(true);
|
|
114
|
+
expect(shouldIngest(exactlyAtThreshold)).toBe(true);
|
|
115
|
+
});
|
|
116
|
+
it('rejects a structural skill whose score is one below SIGNAL_THRESHOLD', () => {
|
|
117
|
+
// mcp-server (+1, structural) + license (+1) + stars (+1) = 3.
|
|
118
|
+
const justBelowThreshold = makeSkill({
|
|
119
|
+
topics: ['mcp-server'], // +1, structural
|
|
120
|
+
license: 'MIT', // +1
|
|
121
|
+
stars: 50, // +1
|
|
122
|
+
});
|
|
123
|
+
const { score, hasStructuralSignal } = computeSignalScore(justBelowThreshold);
|
|
124
|
+
expect(score).toBe(SIGNAL_THRESHOLD - 1);
|
|
125
|
+
expect(hasStructuralSignal).toBe(true);
|
|
126
|
+
expect(shouldIngest(justBelowThreshold)).toBe(false);
|
|
127
|
+
});
|
|
128
|
+
it('rejects mcp-server-only skills (structural but below threshold)', () => {
|
|
129
|
+
// Just the mcp-server topic, no other signals. score=1 < threshold.
|
|
130
|
+
const mcpOnly = makeSkill({ topics: ['mcp-server'] });
|
|
131
|
+
const { score, hasStructuralSignal } = computeSignalScore(mcpOnly);
|
|
132
|
+
expect(score).toBe(1);
|
|
133
|
+
expect(hasStructuralSignal).toBe(true);
|
|
134
|
+
expect(shouldIngest(mcpOnly)).toBe(false);
|
|
135
|
+
});
|
|
136
|
+
it('respects a caller-supplied threshold override', () => {
|
|
137
|
+
// Same mcp-server-only skill, but threshold lowered to 1 → admits.
|
|
138
|
+
const mcpOnly = makeSkill({ topics: ['mcp-server'] });
|
|
139
|
+
expect(shouldIngest(mcpOnly, 1)).toBe(true);
|
|
140
|
+
expect(shouldIngest(mcpOnly, 2)).toBe(false);
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
describe('HIGH_TRUST_OWNERS', () => {
|
|
144
|
+
it('admits trusted-owner skills with no topics (community marketplace case)', () => {
|
|
145
|
+
// `daymade/claude-code-skills` in Wave 0 R2: HIGH_TRUST_OWNERS entry,
|
|
146
|
+
// empty topics, would otherwise fail the structural floor. score = 5
|
|
147
|
+
// (owner alone) + metadata >= threshold.
|
|
148
|
+
const owner = Array.from(HIGH_TRUST_OWNERS)[0];
|
|
149
|
+
expect(owner).toBeDefined();
|
|
150
|
+
const trustedNoTopics = makeSkill({
|
|
151
|
+
author: owner,
|
|
152
|
+
topics: [],
|
|
153
|
+
description: 'claude skill',
|
|
154
|
+
name: 'claude-skill',
|
|
155
|
+
});
|
|
156
|
+
const { hasStructuralSignal, signals } = computeSignalScore(trustedNoTopics);
|
|
157
|
+
expect(hasStructuralSignal).toBe(true);
|
|
158
|
+
expect(signals).toContain('high-trust-owner');
|
|
159
|
+
expect(shouldIngest(trustedNoTopics)).toBe(true);
|
|
160
|
+
});
|
|
161
|
+
it('matches HIGH_TRUST_OWNERS case-insensitively', () => {
|
|
162
|
+
const skill = makeSkill({
|
|
163
|
+
author: 'ANTHROPICS', // uppercase
|
|
164
|
+
topics: [],
|
|
165
|
+
});
|
|
166
|
+
const { hasStructuralSignal } = computeSignalScore(skill);
|
|
167
|
+
expect(hasStructuralSignal).toBe(true);
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
//# sourceMappingURL=signal-of-intent.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signal-of-intent.test.js","sourceRoot":"","sources":["../../../tests/github-import/signal-of-intent.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAExC,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,YAAY,EACZ,gBAAgB,GACjB,MAAM,qDAAqD,CAAA;AAG5D,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;AACzD,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,CAAA;AAEhD,SAAS,WAAW,CAAC,IAAY;IAC/B,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,EAAE,OAAO,CAAC,CAAoB,CAAA;AACvF,CAAC;AAED;;;GAGG;AACH,SAAS,SAAS,CAAC,OAA+B;IAChD,OAAO;QACL,EAAE,EAAE,OAAO,CAAC,EAAE,IAAI,uBAAuB;QACzC,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,WAAW;QACjC,WAAW,EAAE,OAAO,CAAC,WAAW,IAAI,EAAE;QACtC,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,MAAM;QAChC,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,mCAAmC;QACjE,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,uCAAuC;QACvE,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;QACzB,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;QACzB,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,EAAE;QAC5B,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,IAAI;QAClC,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,IAAI;QAChC,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,sBAAsB;QACxD,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,sBAAsB;QACxD,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,QAAQ;QAClC,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,MAAM;QACxC,WAAW,EAAE,OAAO,CAAC,WAAW,IAAI,sBAAsB;KAC3D,CAAA;AACH,CAAC;AAED,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE;QACnC,MAAM,SAAS,GAAG,WAAW,CAAC,iBAAiB,CAAC,CAAA;QAEhD,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;YACvD,MAAM,CAAC,SAAS,CAAC,CAAC,YAAY,CAAC,EAAE,CAAC,CAAA;QACpC,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAU,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;YAC5E,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACxC,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;YACvD,MAAM,QAAQ,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAA;YACzD,MAAM,CAAC,QAAQ,CAAC,CAAC,YAAY,CAAC,SAAS,CAAC,MAAM,CAAC,CAAA;QACjD,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;QAClC,MAAM,SAAS,GAAG,WAAW,CAAC,iBAAiB,CAAC,CAAA;QAEhD,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;YACvD,MAAM,CAAC,SAAS,CAAC,CAAC,YAAY,CAAC,EAAE,CAAC,CAAA;QACpC,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAU,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;YAC7E,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACzC,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;YACxD,MAAM,QAAQ,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAA;YACzD,MAAM,CAAC,QAAQ,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;QAClC,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,QAAQ,CAAC,0CAA0C,EAAE,GAAG,EAAE;QACxD,EAAE,CAAC,sEAAsE,EAAE,GAAG,EAAE;YAC9E,yEAAyE;YACzE,kEAAkE;YAClE,oEAAoE;YACpE,sEAAsE;YACtE,MAAM,YAAY,GAAG,SAAS,CAAC;gBAC7B,EAAE,EAAE,4BAA4B;gBAChC,IAAI,EAAE,cAAc,EAAE,qBAAqB;gBAC3C,WAAW,EAAE,yCAAyC,EAAE,4BAA4B;gBACpF,MAAM,EAAE,QAAQ,EAAE,2BAA2B;gBAC7C,MAAM,EAAE,EAAE,EAAE,sBAAsB;gBAClC,QAAQ,EAAE,YAAY;gBACtB,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE,GAAG,EAAE,qBAAqB;aAClC,CAAC,CAAA;YAEF,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,mBAAmB,EAAE,GAAG,kBAAkB,CAAC,YAAY,CAAC,CAAA;YAChF,MAAM,CAAC,KAAK,CAAC,CAAC,eAAe,CAAC,gBAAgB,CAAC,CAAA;YAC/C,MAAM,CAAC,mBAAmB,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YACvC,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CACrB,MAAM,CAAC,eAAe,CAAC;gBACrB,mBAAmB;gBACnB,YAAY;gBACZ,gBAAgB;gBAChB,iBAAiB;gBACjB,iBAAiB;aAClB,CAAC,CACH,CAAA;YACD,MAAM,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QAChD,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE;QACnC,EAAE,CAAC,+DAA+D,EAAE,GAAG,EAAE;YACvE,0DAA0D;YAC1D,MAAM,kBAAkB,GAAG,SAAS,CAAC;gBACnC,MAAM,EAAE,CAAC,cAAc,CAAC,EAAE,iBAAiB;gBAC3C,mBAAmB;aACpB,CAAC,CAAA;YAEF,MAAM,EAAE,KAAK,EAAE,mBAAmB,EAAE,GAAG,kBAAkB,CAAC,kBAAkB,CAAC,CAAA;YAC7E,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAA;YACpC,MAAM,CAAC,mBAAmB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YACtC,MAAM,CAAC,YAAY,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACrD,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,sEAAsE,EAAE,GAAG,EAAE;YAC9E,+DAA+D;YAC/D,MAAM,kBAAkB,GAAG,SAAS,CAAC;gBACnC,MAAM,EAAE,CAAC,YAAY,CAAC,EAAE,iBAAiB;gBACzC,OAAO,EAAE,KAAK,EAAE,KAAK;gBACrB,KAAK,EAAE,EAAE,EAAE,KAAK;aACjB,CAAC,CAAA;YAEF,MAAM,EAAE,KAAK,EAAE,mBAAmB,EAAE,GAAG,kBAAkB,CAAC,kBAAkB,CAAC,CAAA;YAC7E,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,gBAAgB,GAAG,CAAC,CAAC,CAAA;YACxC,MAAM,CAAC,mBAAmB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YACtC,MAAM,CAAC,YAAY,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACtD,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,iEAAiE,EAAE,GAAG,EAAE;YACzE,oEAAoE;YACpE,MAAM,OAAO,GAAG,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,CAAA;YACrD,MAAM,EAAE,KAAK,EAAE,mBAAmB,EAAE,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAA;YAClE,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;YACrB,MAAM,CAAC,mBAAmB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YACtC,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QAC3C,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;YACvD,mEAAmE;YACnE,MAAM,OAAO,GAAG,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,CAAA;YACrD,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YAC3C,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QAC9C,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;QACjC,EAAE,CAAC,yEAAyE,EAAE,GAAG,EAAE;YACjF,sEAAsE;YACtE,qEAAqE;YACrE,yCAAyC;YACzC,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAA;YAC9C,MAAM,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE,CAAA;YAC3B,MAAM,eAAe,GAAG,SAAS,CAAC;gBAChC,MAAM,EAAE,KAAK;gBACb,MAAM,EAAE,EAAE;gBACV,WAAW,EAAE,cAAc;gBAC3B,IAAI,EAAE,cAAc;aACrB,CAAC,CAAA;YACF,MAAM,EAAE,mBAAmB,EAAE,OAAO,EAAE,GAAG,kBAAkB,CAAC,eAAe,CAAC,CAAA;YAC5E,MAAM,CAAC,mBAAmB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YACtC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,kBAAkB,CAAC,CAAA;YAC7C,MAAM,CAAC,YAAY,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAClD,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;YACtD,MAAM,KAAK,GAAG,SAAS,CAAC;gBACtB,MAAM,EAAE,YAAY,EAAE,YAAY;gBAClC,MAAM,EAAE,EAAE;aACX,CAAC,CAAA;YACF,MAAM,EAAE,mBAAmB,EAAE,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAA;YACzD,MAAM,CAAC,mBAAmB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACxC,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
|
@@ -6,7 +6,19 @@
|
|
|
6
6
|
* pattern removal during refactoring.
|
|
7
7
|
*
|
|
8
8
|
* Baseline validated: 2026-04-03
|
|
9
|
+
* SMI-4396 Wave 2 (2026-04-21): adjusted baselines for FP-rate tuning.
|
|
10
|
+
* - SENSITIVE_PATH_PATTERNS: 12 → 14 (tightened bare-keyword patterns
|
|
11
|
+
* to require assignment/path/file-ext context, expanding some into
|
|
12
|
+
* multiple variants).
|
|
13
|
+
* - DATA_EXFILTRATION_PATTERNS: 20 → 21 (word-boundary `\bcloud\b` fix
|
|
14
|
+
* plus new key/secret upload detector to preserve attack-shape coverage).
|
|
15
|
+
* - PRIVILEGE_ESCALATION_PATTERNS: 23 → 25 (removed bare `/escalat(e|ion)/i`
|
|
16
|
+
* documentation-keyword trigger; added 3 contextual variants).
|
|
17
|
+
* - Additionally: 12 → 15 ends up at 15 after adding explicit /etc/passwd
|
|
18
|
+
* system-file coverage (offsets the bare-keyword tightening).
|
|
19
|
+
*
|
|
9
20
|
* Reference: docs/internal/security/two-scanner-runbook.md
|
|
21
|
+
* docs/internal/implementation/smi-4396-imported-skills-security-triage.md
|
|
10
22
|
*/
|
|
11
23
|
export {};
|
|
12
24
|
//# sourceMappingURL=scanner-regression-guard.test.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scanner-regression-guard.test.d.ts","sourceRoot":"","sources":["../../../tests/security/scanner-regression-guard.test.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"scanner-regression-guard.test.d.ts","sourceRoot":"","sources":["../../../tests/security/scanner-regression-guard.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG"}
|
|
@@ -6,7 +6,19 @@
|
|
|
6
6
|
* pattern removal during refactoring.
|
|
7
7
|
*
|
|
8
8
|
* Baseline validated: 2026-04-03
|
|
9
|
+
* SMI-4396 Wave 2 (2026-04-21): adjusted baselines for FP-rate tuning.
|
|
10
|
+
* - SENSITIVE_PATH_PATTERNS: 12 → 14 (tightened bare-keyword patterns
|
|
11
|
+
* to require assignment/path/file-ext context, expanding some into
|
|
12
|
+
* multiple variants).
|
|
13
|
+
* - DATA_EXFILTRATION_PATTERNS: 20 → 21 (word-boundary `\bcloud\b` fix
|
|
14
|
+
* plus new key/secret upload detector to preserve attack-shape coverage).
|
|
15
|
+
* - PRIVILEGE_ESCALATION_PATTERNS: 23 → 25 (removed bare `/escalat(e|ion)/i`
|
|
16
|
+
* documentation-keyword trigger; added 3 contextual variants).
|
|
17
|
+
* - Additionally: 12 → 15 ends up at 15 after adding explicit /etc/passwd
|
|
18
|
+
* system-file coverage (offsets the bare-keyword tightening).
|
|
19
|
+
*
|
|
9
20
|
* Reference: docs/internal/security/two-scanner-runbook.md
|
|
21
|
+
* docs/internal/implementation/smi-4396-imported-skills-security-triage.md
|
|
10
22
|
*/
|
|
11
23
|
import { describe, it, expect } from 'vitest';
|
|
12
24
|
import { SecurityScanner, SENSITIVE_PATH_PATTERNS, JAILBREAK_PATTERNS, SUSPICIOUS_PATTERNS, SOCIAL_ENGINEERING_PATTERNS, PROMPT_LEAKING_PATTERNS, DATA_EXFILTRATION_PATTERNS, PRIVILEGE_ESCALATION_PATTERNS, SSRF_INSTRUCTION_PATTERNS, AI_DEFENCE_PATTERNS, PII_PATTERNS, } from '../../src/security/scanner/index.js';
|
|
@@ -16,13 +28,13 @@ import { SecurityScanner, SENSITIVE_PATH_PATTERNS, JAILBREAK_PATTERNS, SUSPICIOU
|
|
|
16
28
|
* removing patterns requires updating this file with justification.
|
|
17
29
|
*/
|
|
18
30
|
const BASELINE_PATTERN_COUNTS = {
|
|
19
|
-
SENSITIVE_PATH_PATTERNS: 12
|
|
31
|
+
SENSITIVE_PATH_PATTERNS: 15, // SMI-4396 Wave 2: 12 → 15 (bare-keyword tightened + /etc/passwd explicit)
|
|
20
32
|
JAILBREAK_PATTERNS: 15,
|
|
21
33
|
SUSPICIOUS_PATTERNS: 11,
|
|
22
34
|
SOCIAL_ENGINEERING_PATTERNS: 12,
|
|
23
35
|
PROMPT_LEAKING_PATTERNS: 14,
|
|
24
|
-
DATA_EXFILTRATION_PATTERNS: 20
|
|
25
|
-
PRIVILEGE_ESCALATION_PATTERNS: 23
|
|
36
|
+
DATA_EXFILTRATION_PATTERNS: 22, // SMI-4396 Wave 2: 20 → 22 (word-boundary + key-upload + verb-object prose)
|
|
37
|
+
PRIVILEGE_ESCALATION_PATTERNS: 25, // SMI-4396 Wave 2: 23 → 25 (-1 bare +3 contextual)
|
|
26
38
|
SSRF_INSTRUCTION_PATTERNS: 13,
|
|
27
39
|
AI_DEFENCE_PATTERNS: 16,
|
|
28
40
|
PII_PATTERNS: 11,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scanner-regression-guard.test.js","sourceRoot":"","sources":["../../../tests/security/scanner-regression-guard.test.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"scanner-regression-guard.test.js","sourceRoot":"","sources":["../../../tests/security/scanner-regression-guard.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SMI-4396 Wave 2 regression fixtures.
|
|
3
|
+
*
|
|
4
|
+
* Five FP-shape fixtures drawn from the 2026-04-21 baseline spot-check:
|
|
5
|
+
* each asserts the NEW scanner does NOT quarantine the skill on the shape
|
|
6
|
+
* that previously caused a CRITICAL/HIGH finding. One attack-shape
|
|
7
|
+
* fixture asserts the scanner DOES still trigger on the genuine
|
|
8
|
+
* "upload private keys to our cdn bucket" exfiltration pattern — keeps
|
|
9
|
+
* Wave 2's bcloud word-boundary from weakening real detection.
|
|
10
|
+
*/
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=scanner-wave2-fixtures.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scanner-wave2-fixtures.test.d.ts","sourceRoot":"","sources":["../../../tests/security/scanner-wave2-fixtures.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG"}
|