@skillsmith/core 0.4.9 → 0.4.10
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/README.md +1 -1
- package/dist/.tsbuildinfo +1 -1
- package/dist/src/analysis/adapters/java-parsers.d.ts.map +1 -1
- package/dist/src/analysis/adapters/java-parsers.js +9 -2
- package/dist/src/analysis/adapters/java-parsers.js.map +1 -1
- package/dist/src/api/client.d.ts +1 -0
- package/dist/src/api/client.d.ts.map +1 -1
- package/dist/src/api/client.js.map +1 -1
- package/dist/src/api/schemas.d.ts +11 -4
- package/dist/src/api/schemas.d.ts.map +1 -1
- package/dist/src/api/schemas.js +8 -1
- package/dist/src/api/schemas.js.map +1 -1
- package/dist/src/db/drivers/betterSqlite3Driver.d.ts.map +1 -1
- package/dist/src/db/drivers/betterSqlite3Driver.js +5 -3
- package/dist/src/db/drivers/betterSqlite3Driver.js.map +1 -1
- package/dist/src/exports/services.d.ts +1 -0
- package/dist/src/exports/services.d.ts.map +1 -1
- package/dist/src/exports/services.js +4 -0
- package/dist/src/exports/services.js.map +1 -1
- package/dist/src/index.d.ts +3 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +6 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/indexer/SkillParser.d.ts +20 -0
- package/dist/src/indexer/SkillParser.d.ts.map +1 -1
- package/dist/src/indexer/SkillParser.js +58 -0
- package/dist/src/indexer/SkillParser.js.map +1 -1
- package/dist/src/repositories/quarantine/QuarantineRepository.d.ts.map +1 -1
- package/dist/src/repositories/quarantine/QuarantineRepository.js +4 -1
- package/dist/src/repositories/quarantine/QuarantineRepository.js.map +1 -1
- package/dist/src/scripts/validation/types.d.ts +2 -2
- package/dist/src/security/audit-types.d.ts +2 -2
- package/dist/src/security/audit-types.d.ts.map +1 -1
- package/dist/src/security/audit-types.js.map +1 -1
- package/dist/src/security/sanitization.d.ts.map +1 -1
- package/dist/src/security/sanitization.js +25 -17
- package/dist/src/security/sanitization.js.map +1 -1
- package/dist/src/services/index.d.ts +9 -0
- package/dist/src/services/index.d.ts.map +1 -0
- package/dist/src/services/index.js +10 -0
- package/dist/src/services/index.js.map +1 -0
- package/dist/src/services/quarantine/QuarantineService.d.ts +149 -0
- package/dist/src/services/quarantine/QuarantineService.d.ts.map +1 -0
- package/dist/src/services/quarantine/QuarantineService.js +406 -0
- package/dist/src/services/quarantine/QuarantineService.js.map +1 -0
- package/dist/src/services/quarantine/index.d.ts +10 -0
- package/dist/src/services/quarantine/index.d.ts.map +1 -0
- package/dist/src/services/quarantine/index.js +14 -0
- package/dist/src/services/quarantine/index.js.map +1 -0
- package/dist/src/services/quarantine/types.d.ts +127 -0
- package/dist/src/services/quarantine/types.d.ts.map +1 -0
- package/dist/src/services/quarantine/types.js +59 -0
- package/dist/src/services/quarantine/types.js.map +1 -0
- package/dist/src/types/skill.d.ts +6 -1
- package/dist/src/types/skill.d.ts.map +1 -1
- package/dist/src/types/skill.js.map +1 -1
- package/dist/src/types.d.ts +1 -1
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/utils/index.d.ts +1 -0
- package/dist/src/utils/index.d.ts.map +1 -1
- package/dist/src/utils/index.js +2 -0
- package/dist/src/utils/index.js.map +1 -1
- package/dist/src/utils/safe-fs.d.ts +63 -0
- package/dist/src/utils/safe-fs.d.ts.map +1 -0
- package/dist/src/utils/safe-fs.js +119 -0
- package/dist/src/utils/safe-fs.js.map +1 -0
- package/dist/src/validation/input-validators.d.ts.map +1 -1
- package/dist/src/validation/input-validators.js +11 -4
- package/dist/src/validation/input-validators.js.map +1 -1
- package/dist/tests/QuarantineRepository.test.js +39 -2
- package/dist/tests/QuarantineRepository.test.js.map +1 -1
- package/dist/tests/edge-cases/EdgeCases.test.js +5 -2
- package/dist/tests/edge-cases/EdgeCases.test.js.map +1 -1
- package/dist/tests/integration/QuarantineService.test.d.ts +11 -0
- package/dist/tests/integration/QuarantineService.test.d.ts.map +1 -0
- package/dist/tests/integration/QuarantineService.test.js +378 -0
- package/dist/tests/integration/QuarantineService.test.js.map +1 -0
- package/dist/tests/unit/check-references.test.d.ts +2 -0
- package/dist/tests/unit/check-references.test.d.ts.map +1 -0
- package/dist/tests/unit/check-references.test.js +118 -0
- package/dist/tests/unit/check-references.test.js.map +1 -0
- package/dist/tests/utils/safe-fs.test.d.ts +12 -0
- package/dist/tests/utils/safe-fs.test.d.ts.map +1 -0
- package/dist/tests/utils/safe-fs.test.js +116 -0
- package/dist/tests/utils/safe-fs.test.js.map +1 -0
- package/package.json +14 -10
- package/dist/tests/db/driver-parity.integration.test.d.ts +0 -16
- package/dist/tests/db/driver-parity.integration.test.d.ts.map +0 -1
- package/dist/tests/db/driver-parity.integration.test.js +0 -555
- package/dist/tests/db/driver-parity.integration.test.js.map +0 -1
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SMI-2269: QuarantineService Integration Tests
|
|
3
|
+
*
|
|
4
|
+
* Tests for authenticated quarantine review operations including:
|
|
5
|
+
* - Session validation
|
|
6
|
+
* - Permission checks (security_reviewer role)
|
|
7
|
+
* - Multi-approval workflow for MALICIOUS severity
|
|
8
|
+
* - Audit logging with verified identities
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=QuarantineService.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"QuarantineService.test.d.ts","sourceRoot":"","sources":["../../../tests/integration/QuarantineService.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SMI-2269: QuarantineService Integration Tests
|
|
3
|
+
*
|
|
4
|
+
* Tests for authenticated quarantine review operations including:
|
|
5
|
+
* - Session validation
|
|
6
|
+
* - Permission checks (security_reviewer role)
|
|
7
|
+
* - Multi-approval workflow for MALICIOUS severity
|
|
8
|
+
* - Audit logging with verified identities
|
|
9
|
+
*/
|
|
10
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
11
|
+
import { QuarantineService } from '../../src/services/quarantine/QuarantineService.js';
|
|
12
|
+
import { QuarantineServiceError } from '../../src/services/quarantine/types.js';
|
|
13
|
+
import { QuarantineRepository } from '../../src/repositories/quarantine/index.js';
|
|
14
|
+
import { AuditLogger } from '../../src/security/AuditLogger.js';
|
|
15
|
+
import { createDatabaseSync } from '../../src/db/createDatabase.js';
|
|
16
|
+
// ============================================================================
|
|
17
|
+
// Test Helpers
|
|
18
|
+
// ============================================================================
|
|
19
|
+
/**
|
|
20
|
+
* Create a mock authenticated session for testing
|
|
21
|
+
*/
|
|
22
|
+
function createMockSession(overrides = {}) {
|
|
23
|
+
return {
|
|
24
|
+
userId: 'user-123',
|
|
25
|
+
email: 'reviewer@example.com',
|
|
26
|
+
displayName: 'Test Reviewer',
|
|
27
|
+
permissions: ['quarantine:read', 'quarantine:review'],
|
|
28
|
+
sessionId: 'session-456',
|
|
29
|
+
expiresAt: new Date(Date.now() + 3600000), // 1 hour from now
|
|
30
|
+
...overrides,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Create a session with specific permissions
|
|
35
|
+
*/
|
|
36
|
+
function createSessionWithPermissions(permissions) {
|
|
37
|
+
return createMockSession({ permissions });
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Create an expired session
|
|
41
|
+
*/
|
|
42
|
+
function createExpiredSession() {
|
|
43
|
+
return createMockSession({
|
|
44
|
+
expiresAt: new Date(Date.now() - 1000), // Expired 1 second ago
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
// ============================================================================
|
|
48
|
+
// Test Suite
|
|
49
|
+
// ============================================================================
|
|
50
|
+
describe('SMI-2269: QuarantineService Authentication', () => {
|
|
51
|
+
let db;
|
|
52
|
+
let repository;
|
|
53
|
+
let auditLogger;
|
|
54
|
+
let service;
|
|
55
|
+
beforeEach(() => {
|
|
56
|
+
// Create in-memory database for testing
|
|
57
|
+
db = createDatabaseSync(':memory:');
|
|
58
|
+
auditLogger = new AuditLogger(db);
|
|
59
|
+
repository = new QuarantineRepository(db, auditLogger);
|
|
60
|
+
service = new QuarantineService(repository, auditLogger);
|
|
61
|
+
});
|
|
62
|
+
afterEach(() => {
|
|
63
|
+
db.close();
|
|
64
|
+
});
|
|
65
|
+
// ==========================================================================
|
|
66
|
+
// Session Validation Tests
|
|
67
|
+
// ==========================================================================
|
|
68
|
+
describe('Session Validation', () => {
|
|
69
|
+
it('should reject expired sessions', () => {
|
|
70
|
+
const session = createExpiredSession();
|
|
71
|
+
expect(() => service.findById(session, 'some-id')).toThrow(QuarantineServiceError);
|
|
72
|
+
expect(() => service.findById(session, 'some-id')).toThrow('Session has expired');
|
|
73
|
+
});
|
|
74
|
+
it('should accept valid sessions', () => {
|
|
75
|
+
const session = createMockSession();
|
|
76
|
+
// Should not throw
|
|
77
|
+
expect(() => service.findById(session, 'nonexistent-id')).not.toThrow();
|
|
78
|
+
});
|
|
79
|
+
it('should include session expiry in error details', () => {
|
|
80
|
+
const session = createExpiredSession();
|
|
81
|
+
try {
|
|
82
|
+
service.findById(session, 'some-id');
|
|
83
|
+
expect.fail('Should have thrown');
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
expect(error).toBeInstanceOf(QuarantineServiceError);
|
|
87
|
+
expect(error.code).toBe('SESSION_EXPIRED');
|
|
88
|
+
expect(error.details?.expiresAt).toBeDefined();
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
// ==========================================================================
|
|
93
|
+
// Permission Tests
|
|
94
|
+
// ==========================================================================
|
|
95
|
+
describe('Permission Enforcement', () => {
|
|
96
|
+
it('should reject users without quarantine:read permission', () => {
|
|
97
|
+
const session = createSessionWithPermissions([]);
|
|
98
|
+
expect(() => service.findById(session, 'some-id')).toThrow(QuarantineServiceError);
|
|
99
|
+
expect(() => service.findById(session, 'some-id')).toThrow('Permission denied');
|
|
100
|
+
});
|
|
101
|
+
it('should allow read with quarantine:read permission', () => {
|
|
102
|
+
const session = createSessionWithPermissions(['quarantine:read']);
|
|
103
|
+
// Should not throw
|
|
104
|
+
expect(() => service.findById(session, 'nonexistent-id')).not.toThrow();
|
|
105
|
+
});
|
|
106
|
+
it('should reject review without quarantine:review permission', () => {
|
|
107
|
+
const session = createSessionWithPermissions(['quarantine:read']);
|
|
108
|
+
// Create a quarantine entry first
|
|
109
|
+
const entry = repository.create({
|
|
110
|
+
skillId: 'test/skill',
|
|
111
|
+
source: 'test',
|
|
112
|
+
quarantineReason: 'Test reason',
|
|
113
|
+
severity: 'SUSPICIOUS',
|
|
114
|
+
});
|
|
115
|
+
expect(() => service.review(session, entry.id, {
|
|
116
|
+
reviewStatus: 'approved',
|
|
117
|
+
})).toThrow('Permission denied');
|
|
118
|
+
});
|
|
119
|
+
it('should allow admin users to bypass permission checks', () => {
|
|
120
|
+
const session = createSessionWithPermissions(['quarantine:admin']);
|
|
121
|
+
// Admin should be able to read without explicit read permission
|
|
122
|
+
expect(() => service.findById(session, 'nonexistent-id')).not.toThrow();
|
|
123
|
+
});
|
|
124
|
+
it('should include required permission in error details', () => {
|
|
125
|
+
const session = createSessionWithPermissions([]);
|
|
126
|
+
try {
|
|
127
|
+
service.findById(session, 'some-id');
|
|
128
|
+
expect.fail('Should have thrown');
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
expect(error).toBeInstanceOf(QuarantineServiceError);
|
|
132
|
+
expect(error.code).toBe('INSUFFICIENT_PERMISSIONS');
|
|
133
|
+
expect(error.details?.required).toBe('quarantine:read');
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
// ==========================================================================
|
|
138
|
+
// Review Tests
|
|
139
|
+
// ==========================================================================
|
|
140
|
+
describe('Authenticated Review', () => {
|
|
141
|
+
it('should include verified reviewer identity in result', () => {
|
|
142
|
+
const session = createMockSession({
|
|
143
|
+
userId: 'verified-user-123',
|
|
144
|
+
email: 'verified@example.com',
|
|
145
|
+
displayName: 'Verified Reviewer',
|
|
146
|
+
});
|
|
147
|
+
const entry = repository.create({
|
|
148
|
+
skillId: 'test/skill',
|
|
149
|
+
source: 'test',
|
|
150
|
+
quarantineReason: 'Test reason',
|
|
151
|
+
severity: 'SUSPICIOUS',
|
|
152
|
+
});
|
|
153
|
+
const result = service.review(session, entry.id, {
|
|
154
|
+
reviewStatus: 'approved',
|
|
155
|
+
reviewNotes: 'Verified safe',
|
|
156
|
+
});
|
|
157
|
+
expect(result.reviewedBy.userId).toBe('verified-user-123');
|
|
158
|
+
expect(result.reviewedBy.email).toBe('verified@example.com');
|
|
159
|
+
expect(result.reviewedBy.displayName).toBe('Verified Reviewer');
|
|
160
|
+
});
|
|
161
|
+
it('should reject review of non-existent entry', () => {
|
|
162
|
+
const session = createMockSession();
|
|
163
|
+
expect(() => service.review(session, 'nonexistent-id', {
|
|
164
|
+
reviewStatus: 'approved',
|
|
165
|
+
})).toThrow('Quarantine entry not found');
|
|
166
|
+
});
|
|
167
|
+
it('should reject review of already-reviewed entry', () => {
|
|
168
|
+
const session = createMockSession();
|
|
169
|
+
const entry = repository.create({
|
|
170
|
+
skillId: 'test/skill',
|
|
171
|
+
source: 'test',
|
|
172
|
+
quarantineReason: 'Test reason',
|
|
173
|
+
severity: 'SUSPICIOUS',
|
|
174
|
+
});
|
|
175
|
+
// First review should succeed
|
|
176
|
+
service.review(session, entry.id, {
|
|
177
|
+
reviewStatus: 'approved',
|
|
178
|
+
});
|
|
179
|
+
// Second review should fail
|
|
180
|
+
expect(() => service.review(session, entry.id, {
|
|
181
|
+
reviewStatus: 'rejected',
|
|
182
|
+
})).toThrow('already reviewed');
|
|
183
|
+
});
|
|
184
|
+
it('should log audit event with session details', () => {
|
|
185
|
+
const session = createMockSession({
|
|
186
|
+
sessionId: 'audit-test-session',
|
|
187
|
+
});
|
|
188
|
+
const entry = repository.create({
|
|
189
|
+
skillId: 'test/audit-skill',
|
|
190
|
+
source: 'test',
|
|
191
|
+
quarantineReason: 'Test reason',
|
|
192
|
+
severity: 'SUSPICIOUS',
|
|
193
|
+
});
|
|
194
|
+
// Spy on audit logger
|
|
195
|
+
const logSpy = vi.spyOn(auditLogger, 'log');
|
|
196
|
+
service.review(session, entry.id, {
|
|
197
|
+
reviewStatus: 'approved',
|
|
198
|
+
});
|
|
199
|
+
// Check audit was logged
|
|
200
|
+
expect(logSpy).toHaveBeenCalledWith(expect.objectContaining({
|
|
201
|
+
event_type: 'quarantine_authenticated_review',
|
|
202
|
+
actor: 'reviewer',
|
|
203
|
+
resource: 'test/audit-skill',
|
|
204
|
+
action: 'review',
|
|
205
|
+
result: 'success',
|
|
206
|
+
metadata: expect.objectContaining({
|
|
207
|
+
sessionId: 'audit-test-session',
|
|
208
|
+
reviewer: expect.objectContaining({
|
|
209
|
+
userId: session.userId,
|
|
210
|
+
email: session.email,
|
|
211
|
+
}),
|
|
212
|
+
}),
|
|
213
|
+
}));
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
// ==========================================================================
|
|
217
|
+
// MALICIOUS Severity Multi-Approval Tests
|
|
218
|
+
// ==========================================================================
|
|
219
|
+
describe('Multi-Approval Workflow (MALICIOUS Severity)', () => {
|
|
220
|
+
it('should require quarantine:review_malicious permission for MALICIOUS reviews', () => {
|
|
221
|
+
const session = createSessionWithPermissions(['quarantine:read', 'quarantine:review']);
|
|
222
|
+
const entry = repository.create({
|
|
223
|
+
skillId: 'test/malicious-skill',
|
|
224
|
+
source: 'test',
|
|
225
|
+
quarantineReason: 'Malicious code detected',
|
|
226
|
+
severity: 'MALICIOUS',
|
|
227
|
+
});
|
|
228
|
+
expect(() => service.review(session, entry.id, {
|
|
229
|
+
reviewStatus: 'approved',
|
|
230
|
+
})).toThrow('quarantine:review_malicious required');
|
|
231
|
+
});
|
|
232
|
+
it('should start multi-approval workflow for MALICIOUS approval', () => {
|
|
233
|
+
const session = createSessionWithPermissions([
|
|
234
|
+
'quarantine:read',
|
|
235
|
+
'quarantine:review',
|
|
236
|
+
'quarantine:review_malicious',
|
|
237
|
+
]);
|
|
238
|
+
const entry = repository.create({
|
|
239
|
+
skillId: 'test/malicious-skill',
|
|
240
|
+
source: 'test',
|
|
241
|
+
quarantineReason: 'Malicious code detected',
|
|
242
|
+
severity: 'MALICIOUS',
|
|
243
|
+
});
|
|
244
|
+
const result = service.review(session, entry.id, {
|
|
245
|
+
reviewStatus: 'approved',
|
|
246
|
+
reviewNotes: 'First approval',
|
|
247
|
+
});
|
|
248
|
+
expect(result.approved).toBe(false); // Not yet approved (needs 2 approvals)
|
|
249
|
+
expect(result.multiApprovalStatus).toBeDefined();
|
|
250
|
+
expect(result.multiApprovalStatus?.currentApprovals.length).toBe(1);
|
|
251
|
+
expect(result.multiApprovalStatus?.requiredApprovals).toBe(2);
|
|
252
|
+
});
|
|
253
|
+
it('should complete approval when enough reviewers approve', () => {
|
|
254
|
+
const session1 = createSessionWithPermissions([
|
|
255
|
+
'quarantine:read',
|
|
256
|
+
'quarantine:review',
|
|
257
|
+
'quarantine:review_malicious',
|
|
258
|
+
]);
|
|
259
|
+
const session2 = createMockSession({
|
|
260
|
+
userId: 'user-456',
|
|
261
|
+
email: 'reviewer2@example.com',
|
|
262
|
+
permissions: ['quarantine:read', 'quarantine:review', 'quarantine:review_malicious'],
|
|
263
|
+
});
|
|
264
|
+
const entry = repository.create({
|
|
265
|
+
skillId: 'test/malicious-skill',
|
|
266
|
+
source: 'test',
|
|
267
|
+
quarantineReason: 'Malicious code detected',
|
|
268
|
+
severity: 'MALICIOUS',
|
|
269
|
+
});
|
|
270
|
+
// First approval
|
|
271
|
+
const result1 = service.review(session1, entry.id, {
|
|
272
|
+
reviewStatus: 'approved',
|
|
273
|
+
reviewNotes: 'First approval',
|
|
274
|
+
});
|
|
275
|
+
expect(result1.approved).toBe(false);
|
|
276
|
+
// Second approval
|
|
277
|
+
const result2 = service.review(session2, entry.id, {
|
|
278
|
+
reviewStatus: 'approved',
|
|
279
|
+
reviewNotes: 'Second approval',
|
|
280
|
+
});
|
|
281
|
+
expect(result2.approved).toBe(true);
|
|
282
|
+
expect(result2.multiApprovalStatus?.isComplete).toBe(true);
|
|
283
|
+
});
|
|
284
|
+
it('should prevent same user from approving twice', () => {
|
|
285
|
+
const session = createSessionWithPermissions([
|
|
286
|
+
'quarantine:read',
|
|
287
|
+
'quarantine:review',
|
|
288
|
+
'quarantine:review_malicious',
|
|
289
|
+
]);
|
|
290
|
+
const entry = repository.create({
|
|
291
|
+
skillId: 'test/malicious-skill',
|
|
292
|
+
source: 'test',
|
|
293
|
+
quarantineReason: 'Malicious code detected',
|
|
294
|
+
severity: 'MALICIOUS',
|
|
295
|
+
});
|
|
296
|
+
// First approval should work
|
|
297
|
+
service.review(session, entry.id, {
|
|
298
|
+
reviewStatus: 'approved',
|
|
299
|
+
});
|
|
300
|
+
// Same user trying to approve again should fail
|
|
301
|
+
expect(() => service.review(session, entry.id, {
|
|
302
|
+
reviewStatus: 'approved',
|
|
303
|
+
})).toThrow('already approved');
|
|
304
|
+
});
|
|
305
|
+
it('should allow MALICIOUS rejection without multi-approval', () => {
|
|
306
|
+
const session = createSessionWithPermissions([
|
|
307
|
+
'quarantine:read',
|
|
308
|
+
'quarantine:review',
|
|
309
|
+
'quarantine:review_malicious',
|
|
310
|
+
]);
|
|
311
|
+
const entry = repository.create({
|
|
312
|
+
skillId: 'test/malicious-skill',
|
|
313
|
+
source: 'test',
|
|
314
|
+
quarantineReason: 'Malicious code detected',
|
|
315
|
+
severity: 'MALICIOUS',
|
|
316
|
+
});
|
|
317
|
+
// Rejection should work immediately (no multi-approval needed)
|
|
318
|
+
const result = service.review(session, entry.id, {
|
|
319
|
+
reviewStatus: 'rejected',
|
|
320
|
+
reviewNotes: 'Confirmed malicious',
|
|
321
|
+
});
|
|
322
|
+
expect(result.approved).toBe(false);
|
|
323
|
+
expect(result.multiApprovalStatus).toBeUndefined();
|
|
324
|
+
});
|
|
325
|
+
it('should track multi-approval status', () => {
|
|
326
|
+
const session = createSessionWithPermissions([
|
|
327
|
+
'quarantine:read',
|
|
328
|
+
'quarantine:review',
|
|
329
|
+
'quarantine:review_malicious',
|
|
330
|
+
]);
|
|
331
|
+
const entry = repository.create({
|
|
332
|
+
skillId: 'test/malicious-skill',
|
|
333
|
+
source: 'test',
|
|
334
|
+
quarantineReason: 'Malicious code detected',
|
|
335
|
+
severity: 'MALICIOUS',
|
|
336
|
+
});
|
|
337
|
+
// First approval
|
|
338
|
+
service.review(session, entry.id, {
|
|
339
|
+
reviewStatus: 'approved',
|
|
340
|
+
});
|
|
341
|
+
// Check status
|
|
342
|
+
const status = service.getMultiApprovalStatus(session, entry.id);
|
|
343
|
+
expect(status).not.toBeNull();
|
|
344
|
+
expect(status?.currentApprovals.length).toBe(1);
|
|
345
|
+
expect(status?.isComplete).toBe(false);
|
|
346
|
+
});
|
|
347
|
+
});
|
|
348
|
+
// ==========================================================================
|
|
349
|
+
// Error Handling Tests
|
|
350
|
+
// ==========================================================================
|
|
351
|
+
describe('Error Handling', () => {
|
|
352
|
+
it('should return typed error codes', () => {
|
|
353
|
+
const session = createExpiredSession();
|
|
354
|
+
try {
|
|
355
|
+
service.findById(session, 'some-id');
|
|
356
|
+
expect.fail('Should have thrown');
|
|
357
|
+
}
|
|
358
|
+
catch (error) {
|
|
359
|
+
expect(error).toBeInstanceOf(QuarantineServiceError);
|
|
360
|
+
expect(error.code).toBe('SESSION_EXPIRED');
|
|
361
|
+
expect(error.name).toBe('QuarantineServiceError');
|
|
362
|
+
}
|
|
363
|
+
});
|
|
364
|
+
it('should include error details for debugging', () => {
|
|
365
|
+
const session = createSessionWithPermissions([]);
|
|
366
|
+
try {
|
|
367
|
+
service.findById(session, 'some-id');
|
|
368
|
+
expect.fail('Should have thrown');
|
|
369
|
+
}
|
|
370
|
+
catch (error) {
|
|
371
|
+
expect(error).toBeInstanceOf(QuarantineServiceError);
|
|
372
|
+
expect(error.details).toBeDefined();
|
|
373
|
+
expect(error.details?.available).toEqual([]);
|
|
374
|
+
}
|
|
375
|
+
});
|
|
376
|
+
});
|
|
377
|
+
});
|
|
378
|
+
//# sourceMappingURL=QuarantineService.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"QuarantineService.test.js","sourceRoot":"","sources":["../../../tests/integration/QuarantineService.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-references.test.d.ts","sourceRoot":"","sources":["../../../tests/unit/check-references.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { SkillParser } from '../../src/indexer/SkillParser.js';
|
|
3
|
+
describe('SkillParser.checkReferences', () => {
|
|
4
|
+
describe('default patterns', () => {
|
|
5
|
+
it('detects Docker container names (e.g., myproject-dev-1)', () => {
|
|
6
|
+
const content = 'Run: docker exec myproject-dev-1 npm test';
|
|
7
|
+
const result = SkillParser.checkReferences(content);
|
|
8
|
+
expect(result.matches).toHaveLength(1);
|
|
9
|
+
expect(result.matches[0]).toMatchObject({
|
|
10
|
+
line: 1,
|
|
11
|
+
text: 'myproject-dev-1',
|
|
12
|
+
pattern: 'Docker container name',
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
it('detects npm package scopes (e.g., @my-org/)', () => {
|
|
16
|
+
const content = 'import { foo } from "@my-org/utils"';
|
|
17
|
+
const result = SkillParser.checkReferences(content);
|
|
18
|
+
expect(result.matches).toHaveLength(1);
|
|
19
|
+
expect(result.matches[0]).toMatchObject({
|
|
20
|
+
text: '@my-org/',
|
|
21
|
+
pattern: 'npm package scope',
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
it('detects project URLs (e.g., https://myapp.app/)', () => {
|
|
25
|
+
const content = 'Visit https://myapp.app/ for more info';
|
|
26
|
+
const result = SkillParser.checkReferences(content);
|
|
27
|
+
expect(result.matches).toHaveLength(1);
|
|
28
|
+
expect(result.matches[0]).toMatchObject({
|
|
29
|
+
text: 'https://myapp.app/',
|
|
30
|
+
pattern: 'Project URL',
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
it('detects GitHub repo references (e.g., github.com/org/repo)', () => {
|
|
34
|
+
const content = 'Source: github.com/smith-horn/skillsmith';
|
|
35
|
+
const result = SkillParser.checkReferences(content);
|
|
36
|
+
expect(result.matches).toHaveLength(1);
|
|
37
|
+
expect(result.matches[0]).toMatchObject({
|
|
38
|
+
text: 'github.com/smith-horn/skillsmith',
|
|
39
|
+
pattern: 'GitHub repo reference',
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
it('detects specific line counts (e.g., 1212 lines)', () => {
|
|
43
|
+
const content = 'This file has 1212 lines of code';
|
|
44
|
+
const result = SkillParser.checkReferences(content);
|
|
45
|
+
expect(result.matches).toHaveLength(1);
|
|
46
|
+
expect(result.matches[0]).toMatchObject({
|
|
47
|
+
text: '1212 lines',
|
|
48
|
+
pattern: 'Specific line count',
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
describe('custom patterns', () => {
|
|
53
|
+
it('merges custom patterns with defaults', () => {
|
|
54
|
+
const content = 'Use ACME_SECRET_KEY for auth\ndocker exec acme-dev-1 test';
|
|
55
|
+
const custom = [/ACME_[A-Z_]+/g];
|
|
56
|
+
const result = SkillParser.checkReferences(content, custom);
|
|
57
|
+
const patterns = result.matches.map((m) => m.pattern);
|
|
58
|
+
expect(patterns).toContain('Custom pattern');
|
|
59
|
+
expect(patterns).toContain('Docker container name');
|
|
60
|
+
});
|
|
61
|
+
it('labels custom pattern matches as "Custom pattern"', () => {
|
|
62
|
+
const content = 'token: xoxb-abc-123';
|
|
63
|
+
const custom = [/xoxb-[a-z]+-\d+/g];
|
|
64
|
+
const result = SkillParser.checkReferences(content, custom);
|
|
65
|
+
expect(result.matches).toHaveLength(1);
|
|
66
|
+
expect(result.matches[0].pattern).toBe('Custom pattern');
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
describe('edge cases', () => {
|
|
70
|
+
it('returns empty results for content with no matches', () => {
|
|
71
|
+
const content = 'A simple skill that formats code.';
|
|
72
|
+
const result = SkillParser.checkReferences(content);
|
|
73
|
+
expect(result.warnings).toHaveLength(0);
|
|
74
|
+
expect(result.matches).toHaveLength(0);
|
|
75
|
+
});
|
|
76
|
+
it('handles empty string content', () => {
|
|
77
|
+
const result = SkillParser.checkReferences('');
|
|
78
|
+
expect(result.warnings).toHaveLength(0);
|
|
79
|
+
expect(result.matches).toHaveLength(0);
|
|
80
|
+
});
|
|
81
|
+
it('truncates matched text to 80 characters', () => {
|
|
82
|
+
// GitHub repo pattern matches [a-zA-Z-]+ for org and repo segments
|
|
83
|
+
const longRepo = 'github.com/' + 'a-'.repeat(50) + 'a/' + 'b-'.repeat(50) + 'b';
|
|
84
|
+
const result = SkillParser.checkReferences(longRepo);
|
|
85
|
+
const ghMatch = result.matches.find((m) => m.pattern === 'GitHub repo reference');
|
|
86
|
+
expect(ghMatch).toBeDefined();
|
|
87
|
+
expect(ghMatch.text).toHaveLength(83); // 80 + '...'
|
|
88
|
+
expect(ghMatch.text).toMatch(/\.\.\.$/u);
|
|
89
|
+
});
|
|
90
|
+
it('reports correct line numbers (1-based)', () => {
|
|
91
|
+
const content = 'line one\nline two\ngithub.com/org/repo on line three';
|
|
92
|
+
const result = SkillParser.checkReferences(content);
|
|
93
|
+
expect(result.matches).toHaveLength(1);
|
|
94
|
+
expect(result.matches[0].line).toBe(3);
|
|
95
|
+
});
|
|
96
|
+
it('handles multiple matches on the same line', () => {
|
|
97
|
+
const content = 'See github.com/org/repo and github.com/other/lib';
|
|
98
|
+
const result = SkillParser.checkReferences(content);
|
|
99
|
+
const ghMatches = result.matches.filter((m) => m.pattern === 'GitHub repo reference');
|
|
100
|
+
expect(ghMatches).toHaveLength(2);
|
|
101
|
+
expect(ghMatches[0].line).toBe(1);
|
|
102
|
+
expect(ghMatches[1].line).toBe(1);
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
describe('false positive awareness', () => {
|
|
106
|
+
it('matches legitimate npm scopes (documents false positive risk)', () => {
|
|
107
|
+
// The pattern /@[a-z]+-[a-z]+\// matches any hyphenated scope,
|
|
108
|
+
// including legitimate ones like @babel-core/ or @my-lib/.
|
|
109
|
+
// This is by design: the method flags for review, not rejection.
|
|
110
|
+
const content = 'import { x } from "@some-lib/core"';
|
|
111
|
+
const result = SkillParser.checkReferences(content);
|
|
112
|
+
expect(result.matches).toHaveLength(1);
|
|
113
|
+
expect(result.matches[0].pattern).toBe('npm package scope');
|
|
114
|
+
expect(result.warnings[0]).toContain('project-specific reference');
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
//# sourceMappingURL=check-references.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-references.test.js","sourceRoot":"","sources":["../../../tests/unit/check-references.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SMI-2274: Safe filesystem operations tests
|
|
3
|
+
*
|
|
4
|
+
* Tests for symlink-safe file write operations.
|
|
5
|
+
* Covers:
|
|
6
|
+
* - Normal file writes
|
|
7
|
+
* - Symlink detection and rejection
|
|
8
|
+
* - Non-existent file creation
|
|
9
|
+
* - Explicit file permissions
|
|
10
|
+
*/
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=safe-fs.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"safe-fs.test.d.ts","sourceRoot":"","sources":["../../../tests/utils/safe-fs.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG"}
|