acidtest 0.1.0
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/LICENSE +21 -0
- package/README.md +104 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +170 -0
- package/dist/index.js.map +1 -0
- package/dist/layers/code.d.ts +10 -0
- package/dist/layers/code.d.ts.map +1 -0
- package/dist/layers/code.js +196 -0
- package/dist/layers/code.js.map +1 -0
- package/dist/layers/crossref.d.ts +10 -0
- package/dist/layers/crossref.d.ts.map +1 -0
- package/dist/layers/crossref.js +143 -0
- package/dist/layers/crossref.js.map +1 -0
- package/dist/layers/injection.d.ts +10 -0
- package/dist/layers/injection.d.ts.map +1 -0
- package/dist/layers/injection.js +88 -0
- package/dist/layers/injection.js.map +1 -0
- package/dist/layers/permissions.d.ts +10 -0
- package/dist/layers/permissions.d.ts.map +1 -0
- package/dist/layers/permissions.js +120 -0
- package/dist/layers/permissions.js.map +1 -0
- package/dist/pattern-loader.d.ts +14 -0
- package/dist/pattern-loader.d.ts.map +1 -0
- package/dist/pattern-loader.js +50 -0
- package/dist/pattern-loader.js.map +1 -0
- package/dist/patterns/credential-patterns.json +77 -0
- package/dist/patterns/dangerous-imports.json +113 -0
- package/dist/patterns/exfiltration-sinks.json +77 -0
- package/dist/patterns/obfuscation.json +65 -0
- package/dist/patterns/prompt-injection.json +125 -0
- package/dist/patterns/sensitive-paths.json +89 -0
- package/dist/reporter.d.ts +14 -0
- package/dist/reporter.d.ts.map +1 -0
- package/dist/reporter.js +175 -0
- package/dist/reporter.js.map +1 -0
- package/dist/scanner.d.ts +15 -0
- package/dist/scanner.d.ts.map +1 -0
- package/dist/scanner.js +176 -0
- package/dist/scanner.js.map +1 -0
- package/dist/scoring.d.ts +23 -0
- package/dist/scoring.d.ts.map +1 -0
- package/dist/scoring.js +85 -0
- package/dist/scoring.js.map +1 -0
- package/dist/types.d.ts +112 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/package.json +46 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main scanner orchestrator
|
|
3
|
+
* Coordinates all four scanning layers
|
|
4
|
+
*/
|
|
5
|
+
import type { ScanResult } from './types.js';
|
|
6
|
+
/**
|
|
7
|
+
* Main scan function
|
|
8
|
+
* Scans a skill directory or SKILL.md file
|
|
9
|
+
*/
|
|
10
|
+
export declare function scanSkill(skillPath: string): Promise<ScanResult>;
|
|
11
|
+
/**
|
|
12
|
+
* Scan multiple skills in a directory
|
|
13
|
+
*/
|
|
14
|
+
export declare function scanAllSkills(directory: string): Promise<ScanResult[]>;
|
|
15
|
+
//# sourceMappingURL=scanner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,KAAK,EAAmB,UAAU,EAAW,MAAM,YAAY,CAAC;AASvE;;;GAGG;AACH,wBAAsB,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAmDtE;AAqGD;;GAEG;AACH,wBAAsB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAmB5E"}
|
package/dist/scanner.js
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main scanner orchestrator
|
|
3
|
+
* Coordinates all four scanning layers
|
|
4
|
+
*/
|
|
5
|
+
import { readFileSync, existsSync, statSync } from 'fs';
|
|
6
|
+
import { join, basename, extname } from 'path';
|
|
7
|
+
import { glob } from 'glob';
|
|
8
|
+
import matter from 'gray-matter';
|
|
9
|
+
import { scanPermissions } from './layers/permissions.js';
|
|
10
|
+
import { scanInjection } from './layers/injection.js';
|
|
11
|
+
import { scanCode } from './layers/code.js';
|
|
12
|
+
import { scanCrossReference } from './layers/crossref.js';
|
|
13
|
+
import { calculateScore, determineStatus, generateRecommendation } from './scoring.js';
|
|
14
|
+
const VERSION = '0.1.0';
|
|
15
|
+
/**
|
|
16
|
+
* Main scan function
|
|
17
|
+
* Scans a skill directory or SKILL.md file
|
|
18
|
+
*/
|
|
19
|
+
export async function scanSkill(skillPath) {
|
|
20
|
+
// Load the skill
|
|
21
|
+
const skill = await loadSkill(skillPath);
|
|
22
|
+
// Run all four scanning layers
|
|
23
|
+
const layer1 = await scanPermissions(skill);
|
|
24
|
+
const layer2 = await scanInjection(skill);
|
|
25
|
+
const layer3 = await scanCode(skill);
|
|
26
|
+
// Combine findings from layers 1-3 for cross-reference
|
|
27
|
+
const previousFindings = [
|
|
28
|
+
...layer1.findings,
|
|
29
|
+
...layer2.findings,
|
|
30
|
+
...layer3.findings
|
|
31
|
+
];
|
|
32
|
+
const layer4 = await scanCrossReference(skill, previousFindings);
|
|
33
|
+
// Combine all findings
|
|
34
|
+
const allFindings = [
|
|
35
|
+
...layer1.findings,
|
|
36
|
+
...layer2.findings,
|
|
37
|
+
...layer3.findings,
|
|
38
|
+
...layer4.findings
|
|
39
|
+
];
|
|
40
|
+
// Calculate score and status
|
|
41
|
+
const score = calculateScore(allFindings);
|
|
42
|
+
const status = determineStatus(score);
|
|
43
|
+
const recommendation = generateRecommendation(status, allFindings);
|
|
44
|
+
// Build result
|
|
45
|
+
const result = {
|
|
46
|
+
tool: 'acidtest',
|
|
47
|
+
version: VERSION,
|
|
48
|
+
skill: {
|
|
49
|
+
name: skill.name,
|
|
50
|
+
path: skill.path
|
|
51
|
+
},
|
|
52
|
+
score,
|
|
53
|
+
status,
|
|
54
|
+
permissions: {
|
|
55
|
+
bins: skill.metadata.bins,
|
|
56
|
+
env: skill.metadata.env,
|
|
57
|
+
tools: skill.metadata['allowed-tools']
|
|
58
|
+
},
|
|
59
|
+
findings: allFindings,
|
|
60
|
+
recommendation
|
|
61
|
+
};
|
|
62
|
+
return result;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Load a skill from a directory or SKILL.md file
|
|
66
|
+
*/
|
|
67
|
+
async function loadSkill(skillPath) {
|
|
68
|
+
let skillMdPath;
|
|
69
|
+
let skillDir;
|
|
70
|
+
// Determine if path is a directory or file
|
|
71
|
+
if (existsSync(skillPath) && statSync(skillPath).isDirectory()) {
|
|
72
|
+
skillDir = skillPath;
|
|
73
|
+
skillMdPath = join(skillPath, 'SKILL.md');
|
|
74
|
+
}
|
|
75
|
+
else if (basename(skillPath) === 'SKILL.md') {
|
|
76
|
+
skillMdPath = skillPath;
|
|
77
|
+
skillDir = join(skillPath, '..');
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
throw new Error('Path must be a skill directory or SKILL.md file');
|
|
81
|
+
}
|
|
82
|
+
// Check if SKILL.md exists
|
|
83
|
+
if (!existsSync(skillMdPath)) {
|
|
84
|
+
throw new Error(`SKILL.md not found at: ${skillMdPath}`);
|
|
85
|
+
}
|
|
86
|
+
// Read and parse SKILL.md
|
|
87
|
+
const skillContent = readFileSync(skillMdPath, 'utf-8');
|
|
88
|
+
const parsed = matter(skillContent);
|
|
89
|
+
// Extract metadata and markdown
|
|
90
|
+
const metadata = parsed.data;
|
|
91
|
+
const markdownContent = parsed.content;
|
|
92
|
+
// Determine skill name
|
|
93
|
+
const skillName = metadata.name ||
|
|
94
|
+
basename(skillDir) ||
|
|
95
|
+
'unknown-skill';
|
|
96
|
+
// Find all code files (.ts, .js, .mjs, .cjs)
|
|
97
|
+
const codeFiles = await findCodeFiles(skillDir);
|
|
98
|
+
return {
|
|
99
|
+
name: skillName,
|
|
100
|
+
path: skillPath,
|
|
101
|
+
metadata,
|
|
102
|
+
markdownContent,
|
|
103
|
+
codeFiles
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Find all code files in skill directory
|
|
108
|
+
*/
|
|
109
|
+
async function findCodeFiles(skillDir) {
|
|
110
|
+
const codeFiles = [];
|
|
111
|
+
// Search for .ts, .js, .mjs, .cjs files
|
|
112
|
+
const patterns = [
|
|
113
|
+
join(skillDir, '**/*.ts'),
|
|
114
|
+
join(skillDir, '**/*.js'),
|
|
115
|
+
join(skillDir, '**/*.mjs'),
|
|
116
|
+
join(skillDir, '**/*.cjs')
|
|
117
|
+
];
|
|
118
|
+
for (const pattern of patterns) {
|
|
119
|
+
try {
|
|
120
|
+
const files = await glob(pattern, {
|
|
121
|
+
ignore: ['**/node_modules/**', '**/dist/**', '**/build/**']
|
|
122
|
+
});
|
|
123
|
+
for (const filePath of files) {
|
|
124
|
+
try {
|
|
125
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
126
|
+
const ext = extname(filePath).slice(1); // Remove leading dot
|
|
127
|
+
// Determine extension type
|
|
128
|
+
let extension;
|
|
129
|
+
if (ext === 'ts')
|
|
130
|
+
extension = 'ts';
|
|
131
|
+
else if (ext === 'mjs')
|
|
132
|
+
extension = 'mjs';
|
|
133
|
+
else if (ext === 'cjs')
|
|
134
|
+
extension = 'cjs';
|
|
135
|
+
else
|
|
136
|
+
extension = 'js';
|
|
137
|
+
codeFiles.push({
|
|
138
|
+
path: filePath,
|
|
139
|
+
content,
|
|
140
|
+
extension
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
catch (error) {
|
|
144
|
+
// Skip files that can't be read
|
|
145
|
+
console.warn(`Warning: Could not read file: ${filePath}`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
// Skip pattern if glob fails
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return codeFiles;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Scan multiple skills in a directory
|
|
157
|
+
*/
|
|
158
|
+
export async function scanAllSkills(directory) {
|
|
159
|
+
const results = [];
|
|
160
|
+
// Find all SKILL.md files
|
|
161
|
+
const pattern = join(directory, '**/SKILL.md');
|
|
162
|
+
const skillFiles = await glob(pattern, {
|
|
163
|
+
ignore: ['**/node_modules/**']
|
|
164
|
+
});
|
|
165
|
+
for (const skillFile of skillFiles) {
|
|
166
|
+
try {
|
|
167
|
+
const result = await scanSkill(skillFile);
|
|
168
|
+
results.push(result);
|
|
169
|
+
}
|
|
170
|
+
catch (error) {
|
|
171
|
+
console.warn(`Warning: Could not scan skill at ${skillFile}:`, error.message);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return results;
|
|
175
|
+
}
|
|
176
|
+
//# sourceMappingURL=scanner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scanner.js","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scoring engine
|
|
3
|
+
* Calculates trust score from security findings
|
|
4
|
+
*/
|
|
5
|
+
import type { Finding, Status, Severity } from './types.js';
|
|
6
|
+
/**
|
|
7
|
+
* Calculate trust score from findings
|
|
8
|
+
* Score starts at 100 and deductions are made for each finding
|
|
9
|
+
*/
|
|
10
|
+
export declare function calculateScore(findings: Finding[]): number;
|
|
11
|
+
/**
|
|
12
|
+
* Determine overall status from score
|
|
13
|
+
*/
|
|
14
|
+
export declare function determineStatus(score: number): Status;
|
|
15
|
+
/**
|
|
16
|
+
* Generate recommendation based on status and findings
|
|
17
|
+
*/
|
|
18
|
+
export declare function generateRecommendation(status: Status, findings: Finding[]): string;
|
|
19
|
+
/**
|
|
20
|
+
* Get severity counts from findings
|
|
21
|
+
*/
|
|
22
|
+
export declare function getSeverityCounts(findings: Finding[]): Record<Severity, number>;
|
|
23
|
+
//# sourceMappingURL=scoring.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scoring.d.ts","sourceRoot":"","sources":["../src/scoring.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAa5D;;;GAGG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,MAAM,CAU1D;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKrD;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,OAAO,EAAE,GAClB,MAAM,CAwCR;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,CAc/E"}
|
package/dist/scoring.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scoring engine
|
|
3
|
+
* Calculates trust score from security findings
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Severity point deductions
|
|
7
|
+
*/
|
|
8
|
+
const SEVERITY_POINTS = {
|
|
9
|
+
CRITICAL: 25,
|
|
10
|
+
HIGH: 15,
|
|
11
|
+
MEDIUM: 8,
|
|
12
|
+
LOW: 3,
|
|
13
|
+
INFO: 0
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Calculate trust score from findings
|
|
17
|
+
* Score starts at 100 and deductions are made for each finding
|
|
18
|
+
*/
|
|
19
|
+
export function calculateScore(findings) {
|
|
20
|
+
let score = 100;
|
|
21
|
+
for (const finding of findings) {
|
|
22
|
+
const deduction = SEVERITY_POINTS[finding.severity];
|
|
23
|
+
score -= deduction;
|
|
24
|
+
}
|
|
25
|
+
// Floor at 0
|
|
26
|
+
return Math.max(0, score);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Determine overall status from score
|
|
30
|
+
*/
|
|
31
|
+
export function determineStatus(score) {
|
|
32
|
+
if (score >= 80)
|
|
33
|
+
return 'PASS';
|
|
34
|
+
if (score >= 50)
|
|
35
|
+
return 'WARN';
|
|
36
|
+
if (score >= 20)
|
|
37
|
+
return 'FAIL';
|
|
38
|
+
return 'DANGER';
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Generate recommendation based on status and findings
|
|
42
|
+
*/
|
|
43
|
+
export function generateRecommendation(status, findings) {
|
|
44
|
+
// Check for critical permission mismatches or exfiltration
|
|
45
|
+
const hasCriticalMismatch = findings.some(f => f.severity === 'CRITICAL' && f.category === 'permission-mismatch');
|
|
46
|
+
const hasExfiltration = findings.some(f => f.category.includes('exfiltration') || f.title.toLowerCase().includes('exfiltrate'));
|
|
47
|
+
const hasPromptInjection = findings.some(f => f.category === 'prompt-injection' && f.severity === 'CRITICAL');
|
|
48
|
+
if (hasCriticalMismatch || hasExfiltration) {
|
|
49
|
+
return 'Do not install. Undeclared data exfiltration detected.';
|
|
50
|
+
}
|
|
51
|
+
if (hasPromptInjection) {
|
|
52
|
+
return 'Do not install. Prompt injection attempt detected.';
|
|
53
|
+
}
|
|
54
|
+
switch (status) {
|
|
55
|
+
case 'DANGER':
|
|
56
|
+
return 'Do not install. Skill presents severe security risks.';
|
|
57
|
+
case 'FAIL':
|
|
58
|
+
return 'Do not install without thorough review. Multiple security issues detected.';
|
|
59
|
+
case 'WARN':
|
|
60
|
+
return 'Review recommended. Some security concerns detected.';
|
|
61
|
+
case 'PASS':
|
|
62
|
+
return findings.length === 0
|
|
63
|
+
? 'Skill appears safe to install.'
|
|
64
|
+
: 'Skill appears relatively safe, but review findings.';
|
|
65
|
+
default:
|
|
66
|
+
return 'Unable to determine safety.';
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Get severity counts from findings
|
|
71
|
+
*/
|
|
72
|
+
export function getSeverityCounts(findings) {
|
|
73
|
+
const counts = {
|
|
74
|
+
CRITICAL: 0,
|
|
75
|
+
HIGH: 0,
|
|
76
|
+
MEDIUM: 0,
|
|
77
|
+
LOW: 0,
|
|
78
|
+
INFO: 0
|
|
79
|
+
};
|
|
80
|
+
for (const finding of findings) {
|
|
81
|
+
counts[finding.severity]++;
|
|
82
|
+
}
|
|
83
|
+
return counts;
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=scoring.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scoring.js","sourceRoot":"","sources":["../src/scoring.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH;;GAEG;AACH,MAAM,eAAe,GAA6B;IAChD,QAAQ,EAAE,EAAE;IACZ,IAAI,EAAE,EAAE;IACR,MAAM,EAAE,CAAC;IACT,GAAG,EAAE,CAAC;IACN,IAAI,EAAE,CAAC;CACR,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,QAAmB;IAChD,IAAI,KAAK,GAAG,GAAG,CAAC;IAEhB,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,SAAS,GAAG,eAAe,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACpD,KAAK,IAAI,SAAS,CAAC;IACrB,CAAC;IAED,aAAa;IACb,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;AAC5B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,KAAa;IAC3C,IAAI,KAAK,IAAI,EAAE;QAAE,OAAO,MAAM,CAAC;IAC/B,IAAI,KAAK,IAAI,EAAE;QAAE,OAAO,MAAM,CAAC;IAC/B,IAAI,KAAK,IAAI,EAAE;QAAE,OAAO,MAAM,CAAC;IAC/B,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,sBAAsB,CACpC,MAAc,EACd,QAAmB;IAEnB,2DAA2D;IAC3D,MAAM,mBAAmB,GAAG,QAAQ,CAAC,IAAI,CACvC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,UAAU,IAAI,CAAC,CAAC,QAAQ,KAAK,qBAAqB,CACvE,CAAC;IAEF,MAAM,eAAe,GAAG,QAAQ,CAAC,IAAI,CACnC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CACzF,CAAC;IAEF,MAAM,kBAAkB,GAAG,QAAQ,CAAC,IAAI,CACtC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,kBAAkB,IAAI,CAAC,CAAC,QAAQ,KAAK,UAAU,CACpE,CAAC;IAEF,IAAI,mBAAmB,IAAI,eAAe,EAAE,CAAC;QAC3C,OAAO,wDAAwD,CAAC;IAClE,CAAC;IAED,IAAI,kBAAkB,EAAE,CAAC;QACvB,OAAO,oDAAoD,CAAC;IAC9D,CAAC;IAED,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,QAAQ;YACX,OAAO,uDAAuD,CAAC;QAEjE,KAAK,MAAM;YACT,OAAO,4EAA4E,CAAC;QAEtF,KAAK,MAAM;YACT,OAAO,sDAAsD,CAAC;QAEhE,KAAK,MAAM;YACT,OAAO,QAAQ,CAAC,MAAM,KAAK,CAAC;gBAC1B,CAAC,CAAC,gCAAgC;gBAClC,CAAC,CAAC,qDAAqD,CAAC;QAE5D;YACE,OAAO,6BAA6B,CAAC;IACzC,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,QAAmB;IACnD,MAAM,MAAM,GAA6B;QACvC,QAAQ,EAAE,CAAC;QACX,IAAI,EAAE,CAAC;QACP,MAAM,EAAE,CAAC;QACT,GAAG,EAAE,CAAC;QACN,IAAI,EAAE,CAAC;KACR,CAAC;IAEF,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;IAC7B,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core TypeScript interfaces for AcidTest security scanner
|
|
3
|
+
*/
|
|
4
|
+
export type Severity = 'CRITICAL' | 'HIGH' | 'MEDIUM' | 'LOW' | 'INFO';
|
|
5
|
+
export type Status = 'PASS' | 'WARN' | 'FAIL' | 'DANGER';
|
|
6
|
+
export type Layer = 'permissions' | 'markdown' | 'code' | 'crossref';
|
|
7
|
+
export type PatternMatchType = 'regex' | 'ast' | 'exact';
|
|
8
|
+
/**
|
|
9
|
+
* Pattern match configuration
|
|
10
|
+
*/
|
|
11
|
+
export interface PatternMatch {
|
|
12
|
+
type: PatternMatchType;
|
|
13
|
+
value: string;
|
|
14
|
+
flags?: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Detection pattern definition
|
|
18
|
+
*/
|
|
19
|
+
export interface Pattern {
|
|
20
|
+
id: string;
|
|
21
|
+
name: string;
|
|
22
|
+
description?: string;
|
|
23
|
+
severity: Severity;
|
|
24
|
+
match: PatternMatch;
|
|
25
|
+
layer: Layer;
|
|
26
|
+
category?: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Pattern category file structure
|
|
30
|
+
*/
|
|
31
|
+
export interface PatternCategory {
|
|
32
|
+
category: string;
|
|
33
|
+
patterns: Pattern[];
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Skill metadata from YAML frontmatter
|
|
37
|
+
*/
|
|
38
|
+
export interface SkillMetadata {
|
|
39
|
+
name?: string;
|
|
40
|
+
description?: string;
|
|
41
|
+
version?: string;
|
|
42
|
+
env?: string[];
|
|
43
|
+
bins?: string[];
|
|
44
|
+
'allowed-tools'?: string[];
|
|
45
|
+
[key: string]: unknown;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Parsed skill structure
|
|
49
|
+
*/
|
|
50
|
+
export interface Skill {
|
|
51
|
+
name: string;
|
|
52
|
+
path: string;
|
|
53
|
+
metadata: SkillMetadata;
|
|
54
|
+
markdownContent: string;
|
|
55
|
+
codeFiles: CodeFile[];
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Code file structure
|
|
59
|
+
*/
|
|
60
|
+
export interface CodeFile {
|
|
61
|
+
path: string;
|
|
62
|
+
content: string;
|
|
63
|
+
extension: 'ts' | 'js' | 'mjs' | 'cjs';
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Individual security finding
|
|
67
|
+
*/
|
|
68
|
+
export interface Finding {
|
|
69
|
+
severity: Severity;
|
|
70
|
+
category: string;
|
|
71
|
+
title: string;
|
|
72
|
+
file?: string;
|
|
73
|
+
line?: number;
|
|
74
|
+
detail: string;
|
|
75
|
+
evidence?: string;
|
|
76
|
+
patternId?: string;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Layer scan result
|
|
80
|
+
*/
|
|
81
|
+
export interface LayerResult {
|
|
82
|
+
layer: Layer;
|
|
83
|
+
findings: Finding[];
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Complete scan result
|
|
87
|
+
*/
|
|
88
|
+
export interface ScanResult {
|
|
89
|
+
tool: string;
|
|
90
|
+
version: string;
|
|
91
|
+
skill: {
|
|
92
|
+
name: string;
|
|
93
|
+
path: string;
|
|
94
|
+
};
|
|
95
|
+
score: number;
|
|
96
|
+
status: Status;
|
|
97
|
+
permissions: {
|
|
98
|
+
bins?: string[];
|
|
99
|
+
env?: string[];
|
|
100
|
+
tools?: string[];
|
|
101
|
+
};
|
|
102
|
+
findings: Finding[];
|
|
103
|
+
recommendation: string;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* CLI options
|
|
107
|
+
*/
|
|
108
|
+
export interface CliOptions {
|
|
109
|
+
json?: boolean;
|
|
110
|
+
verbose?: boolean;
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "acidtest",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Security scanner for AI agent skills. Scan before you install.",
|
|
6
|
+
"bin": {
|
|
7
|
+
"acidtest": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsc && mkdir -p dist/patterns && cp src/patterns/*.json dist/patterns/",
|
|
11
|
+
"dev": "npm run build && node dist/index.js",
|
|
12
|
+
"watch": "tsc --watch"
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"keywords": [
|
|
18
|
+
"security",
|
|
19
|
+
"agent",
|
|
20
|
+
"agentskills",
|
|
21
|
+
"openclaw",
|
|
22
|
+
"moltbot",
|
|
23
|
+
"skill-scanner",
|
|
24
|
+
"prompt-injection",
|
|
25
|
+
"ai-security"
|
|
26
|
+
],
|
|
27
|
+
"author": "Currently",
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"repository": {
|
|
30
|
+
"type": "git",
|
|
31
|
+
"url": "https://github.com/currentlycurrently/acidtest"
|
|
32
|
+
},
|
|
33
|
+
"homepage": "https://acidtest.dev",
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"chalk": "^5.3.0",
|
|
36
|
+
"glob": "^10.3.10",
|
|
37
|
+
"gray-matter": "^4.0.3",
|
|
38
|
+
"typescript": "^5.3.3"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@types/node": "^20.11.0"
|
|
42
|
+
},
|
|
43
|
+
"engines": {
|
|
44
|
+
"node": ">=18.0.0"
|
|
45
|
+
}
|
|
46
|
+
}
|