skill-preflight 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 +132 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +109 -0
- package/dist/cli.js.map +1 -0
- package/dist/core/categories.d.ts +3 -0
- package/dist/core/categories.js +11 -0
- package/dist/core/categories.js.map +1 -0
- package/dist/core/filesystem.d.ts +9 -0
- package/dist/core/filesystem.js +115 -0
- package/dist/core/filesystem.js.map +1 -0
- package/dist/core/rules.d.ts +2 -0
- package/dist/core/rules.js +713 -0
- package/dist/core/rules.js.map +1 -0
- package/dist/core/scan.d.ts +3 -0
- package/dist/core/scan.js +119 -0
- package/dist/core/scan.js.map +1 -0
- package/dist/core/scoring.d.ts +8 -0
- package/dist/core/scoring.js +36 -0
- package/dist/core/scoring.js.map +1 -0
- package/dist/core/types.d.ts +98 -0
- package/dist/core/types.js +2 -0
- package/dist/core/types.js.map +1 -0
- package/dist/core/utils.d.ts +10 -0
- package/dist/core/utils.js +82 -0
- package/dist/core/utils.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/report/render.d.ts +4 -0
- package/dist/report/render.js +303 -0
- package/dist/report/render.js.map +1 -0
- package/docs/github-action.md +74 -0
- package/docs/release.md +57 -0
- package/docs/rules.md +53 -0
- package/package.json +57 -0
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
export function renderReport(report, format) {
|
|
2
|
+
switch (format) {
|
|
3
|
+
case "json":
|
|
4
|
+
return `${JSON.stringify(report, null, 2)}\n`;
|
|
5
|
+
case "markdown":
|
|
6
|
+
return renderMarkdown(report);
|
|
7
|
+
case "html":
|
|
8
|
+
return renderHtml(report);
|
|
9
|
+
case "sarif":
|
|
10
|
+
return renderSarif(report);
|
|
11
|
+
case "text":
|
|
12
|
+
return renderText(report);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export function parseFormat(value) {
|
|
16
|
+
if (value === "text" || value === "json" || value === "markdown" || value === "html" || value === "sarif") {
|
|
17
|
+
return value;
|
|
18
|
+
}
|
|
19
|
+
throw new Error(`Unsupported format: ${value}. Use text, json, markdown, html, or sarif.`);
|
|
20
|
+
}
|
|
21
|
+
function renderText(report) {
|
|
22
|
+
const lines = [];
|
|
23
|
+
lines.push("SkillPreflight Report");
|
|
24
|
+
lines.push(`Target: ${report.target}`);
|
|
25
|
+
lines.push(`Generated: ${report.generatedAt}`);
|
|
26
|
+
lines.push(`Skills scanned: ${report.summary.count}`);
|
|
27
|
+
lines.push(`Average score: ${report.summary.averageScore}/100`);
|
|
28
|
+
lines.push("");
|
|
29
|
+
for (const skill of report.reports) {
|
|
30
|
+
lines.push(`${skill.skillName}: ${skill.score}/100 (${skill.grade}) - ${skill.recommendation}`);
|
|
31
|
+
lines.push(`Path: ${skill.rootPath}`);
|
|
32
|
+
lines.push("Category scores:");
|
|
33
|
+
for (const category of skill.categories) {
|
|
34
|
+
lines.push(` - ${category.label}: ${category.score}/${category.maxScore}`);
|
|
35
|
+
}
|
|
36
|
+
lines.push("Metrics:");
|
|
37
|
+
lines.push(` - Files: ${skill.metrics.totalFiles}`);
|
|
38
|
+
lines.push(` - Size: ${formatBytes(skill.metrics.totalBytes)}`);
|
|
39
|
+
lines.push(` - Estimated activation tokens: ${skill.metrics.estimatedActivationTokens}`);
|
|
40
|
+
if (skill.findings.length === 0) {
|
|
41
|
+
lines.push("Findings: none");
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
lines.push("Top findings:");
|
|
45
|
+
for (const finding of skill.findings.slice(0, 8)) {
|
|
46
|
+
lines.push(` - [${finding.severity.toUpperCase()}] ${finding.title}${formatLocation(finding)}`);
|
|
47
|
+
lines.push(` ${finding.description}`);
|
|
48
|
+
lines.push(` Fix: ${finding.recommendation}`);
|
|
49
|
+
}
|
|
50
|
+
if (skill.findings.length > 8) {
|
|
51
|
+
lines.push(` - ... ${skill.findings.length - 8} more findings`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
lines.push("");
|
|
55
|
+
}
|
|
56
|
+
return `${lines.join("\n")}\n`;
|
|
57
|
+
}
|
|
58
|
+
function renderMarkdown(report) {
|
|
59
|
+
const lines = [];
|
|
60
|
+
lines.push("# SkillPreflight Report");
|
|
61
|
+
lines.push("");
|
|
62
|
+
lines.push(`- Target: \`${report.target}\``);
|
|
63
|
+
lines.push(`- Generated: \`${report.generatedAt}\``);
|
|
64
|
+
lines.push(`- Skills scanned: ${report.summary.count}`);
|
|
65
|
+
lines.push(`- Average score: ${report.summary.averageScore}/100`);
|
|
66
|
+
lines.push(`- High risk skills: ${report.summary.highRiskCount}`);
|
|
67
|
+
lines.push("");
|
|
68
|
+
for (const skill of report.reports) {
|
|
69
|
+
lines.push(`## ${skill.skillName}: ${skill.score}/100 (${skill.grade})`);
|
|
70
|
+
lines.push("");
|
|
71
|
+
lines.push(`**Recommendation:** ${skill.recommendation}`);
|
|
72
|
+
lines.push("");
|
|
73
|
+
lines.push(`**Path:** \`${skill.rootPath}\``);
|
|
74
|
+
lines.push("");
|
|
75
|
+
lines.push("| Category | Score |");
|
|
76
|
+
lines.push("| --- | ---: |");
|
|
77
|
+
for (const category of skill.categories) {
|
|
78
|
+
lines.push(`| ${category.label} | ${category.score}/${category.maxScore} |`);
|
|
79
|
+
}
|
|
80
|
+
lines.push("");
|
|
81
|
+
lines.push("| Metric | Value |");
|
|
82
|
+
lines.push("| --- | ---: |");
|
|
83
|
+
lines.push(`| Files | ${skill.metrics.totalFiles} |`);
|
|
84
|
+
lines.push(`| Size | ${formatBytes(skill.metrics.totalBytes)} |`);
|
|
85
|
+
lines.push(`| Estimated activation tokens | ${skill.metrics.estimatedActivationTokens} |`);
|
|
86
|
+
lines.push("");
|
|
87
|
+
lines.push("### Findings");
|
|
88
|
+
lines.push("");
|
|
89
|
+
if (skill.findings.length === 0) {
|
|
90
|
+
lines.push("No findings.");
|
|
91
|
+
lines.push("");
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
for (const finding of skill.findings) {
|
|
95
|
+
lines.push(`- **[${finding.severity.toUpperCase()}] ${finding.title}**${formatLocation(finding)}`);
|
|
96
|
+
lines.push(` ${finding.description}`);
|
|
97
|
+
lines.push(` Recommendation: ${finding.recommendation}`);
|
|
98
|
+
}
|
|
99
|
+
lines.push("");
|
|
100
|
+
}
|
|
101
|
+
return `${lines.join("\n")}\n`;
|
|
102
|
+
}
|
|
103
|
+
function renderHtml(report) {
|
|
104
|
+
const skillSections = report.reports.map(renderSkillHtml).join("\n");
|
|
105
|
+
return `<!doctype html>
|
|
106
|
+
<html lang="en">
|
|
107
|
+
<head>
|
|
108
|
+
<meta charset="utf-8">
|
|
109
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
110
|
+
<title>SkillPreflight Report</title>
|
|
111
|
+
<style>
|
|
112
|
+
:root { color-scheme: light dark; font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; }
|
|
113
|
+
body { margin: 0; background: #f6f7f9; color: #17202a; }
|
|
114
|
+
main { max-width: 1040px; margin: 0 auto; padding: 32px 20px 56px; }
|
|
115
|
+
header { margin-bottom: 24px; }
|
|
116
|
+
h1 { font-size: 28px; margin: 0 0 8px; }
|
|
117
|
+
h2 { font-size: 22px; margin: 0 0 12px; }
|
|
118
|
+
.summary, .skill { background: #fff; border: 1px solid #d9dee7; border-radius: 8px; padding: 18px; margin: 16px 0; }
|
|
119
|
+
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: 12px; }
|
|
120
|
+
.metric { background: #f0f3f7; border-radius: 6px; padding: 12px; }
|
|
121
|
+
.metric span { display: block; color: #5f6b7a; font-size: 12px; }
|
|
122
|
+
.metric strong { display: block; font-size: 20px; margin-top: 4px; }
|
|
123
|
+
table { width: 100%; border-collapse: collapse; margin: 12px 0; }
|
|
124
|
+
th, td { border-bottom: 1px solid #e5e8ef; padding: 9px; text-align: left; }
|
|
125
|
+
th:last-child, td:last-child { text-align: right; }
|
|
126
|
+
.finding { border-left: 4px solid #8a97a8; padding: 10px 12px; background: #f8fafc; margin: 10px 0; border-radius: 4px; }
|
|
127
|
+
.critical, .high { border-left-color: #c0392b; }
|
|
128
|
+
.medium { border-left-color: #d9822b; }
|
|
129
|
+
.low { border-left-color: #3978c3; }
|
|
130
|
+
code { background: #eef1f5; padding: 2px 5px; border-radius: 4px; }
|
|
131
|
+
@media (prefers-color-scheme: dark) {
|
|
132
|
+
body { background: #11161d; color: #e8edf4; }
|
|
133
|
+
.summary, .skill { background: #18212b; border-color: #2b3847; }
|
|
134
|
+
.metric, .finding { background: #202b36; }
|
|
135
|
+
th, td { border-bottom-color: #2b3847; }
|
|
136
|
+
code { background: #263240; }
|
|
137
|
+
}
|
|
138
|
+
</style>
|
|
139
|
+
</head>
|
|
140
|
+
<body>
|
|
141
|
+
<main>
|
|
142
|
+
<header>
|
|
143
|
+
<h1>SkillPreflight Report</h1>
|
|
144
|
+
<div>Target: <code>${escapeHtml(report.target)}</code></div>
|
|
145
|
+
<div>Generated: <code>${escapeHtml(report.generatedAt)}</code></div>
|
|
146
|
+
</header>
|
|
147
|
+
<section class="summary">
|
|
148
|
+
<div class="grid">
|
|
149
|
+
<div class="metric"><span>Skills scanned</span><strong>${report.summary.count}</strong></div>
|
|
150
|
+
<div class="metric"><span>Average score</span><strong>${report.summary.averageScore}/100</strong></div>
|
|
151
|
+
<div class="metric"><span>Minimum score</span><strong>${report.summary.minScore}/100</strong></div>
|
|
152
|
+
<div class="metric"><span>High risk</span><strong>${report.summary.highRiskCount}</strong></div>
|
|
153
|
+
</div>
|
|
154
|
+
</section>
|
|
155
|
+
${skillSections}
|
|
156
|
+
</main>
|
|
157
|
+
</body>
|
|
158
|
+
</html>
|
|
159
|
+
`;
|
|
160
|
+
}
|
|
161
|
+
function renderSarif(report) {
|
|
162
|
+
const ruleMap = new Map();
|
|
163
|
+
const results = [];
|
|
164
|
+
for (const skill of report.reports) {
|
|
165
|
+
for (const finding of skill.findings) {
|
|
166
|
+
ruleMap.set(finding.id, finding);
|
|
167
|
+
results.push({
|
|
168
|
+
ruleId: finding.id,
|
|
169
|
+
level: sarifLevel(finding),
|
|
170
|
+
message: {
|
|
171
|
+
text: `${finding.title}: ${finding.description} Recommendation: ${finding.recommendation}`
|
|
172
|
+
},
|
|
173
|
+
locations: [
|
|
174
|
+
{
|
|
175
|
+
physicalLocation: {
|
|
176
|
+
artifactLocation: {
|
|
177
|
+
uri: finding.file ? normalizeSarifUri(finding.file) : normalizeSarifUri(skill.rootPath)
|
|
178
|
+
},
|
|
179
|
+
region: finding.line ? { startLine: finding.line } : undefined
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
],
|
|
183
|
+
properties: {
|
|
184
|
+
category: finding.category,
|
|
185
|
+
severity: finding.severity,
|
|
186
|
+
scoreImpact: finding.scoreImpact,
|
|
187
|
+
skillName: skill.skillName,
|
|
188
|
+
skillScore: skill.score
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
const rules = [...ruleMap.values()].map((finding) => ({
|
|
194
|
+
id: finding.id,
|
|
195
|
+
name: finding.title,
|
|
196
|
+
shortDescription: {
|
|
197
|
+
text: finding.title
|
|
198
|
+
},
|
|
199
|
+
fullDescription: {
|
|
200
|
+
text: finding.description
|
|
201
|
+
},
|
|
202
|
+
help: {
|
|
203
|
+
text: finding.recommendation
|
|
204
|
+
},
|
|
205
|
+
properties: {
|
|
206
|
+
category: finding.category,
|
|
207
|
+
severity: finding.severity
|
|
208
|
+
}
|
|
209
|
+
}));
|
|
210
|
+
return `${JSON.stringify({
|
|
211
|
+
version: "2.1.0",
|
|
212
|
+
$schema: "https://json.schemastore.org/sarif-2.1.0.json",
|
|
213
|
+
runs: [
|
|
214
|
+
{
|
|
215
|
+
tool: {
|
|
216
|
+
driver: {
|
|
217
|
+
name: "SkillPreflight",
|
|
218
|
+
informationUri: "https://github.com/agent-contracts/skill-preflight",
|
|
219
|
+
rules
|
|
220
|
+
}
|
|
221
|
+
},
|
|
222
|
+
automationDetails: {
|
|
223
|
+
id: "skill-preflight"
|
|
224
|
+
},
|
|
225
|
+
properties: {
|
|
226
|
+
target: report.target,
|
|
227
|
+
generatedAt: report.generatedAt,
|
|
228
|
+
averageScore: report.summary.averageScore,
|
|
229
|
+
highRiskCount: report.summary.highRiskCount
|
|
230
|
+
},
|
|
231
|
+
results
|
|
232
|
+
}
|
|
233
|
+
]
|
|
234
|
+
}, null, 2)}\n`;
|
|
235
|
+
}
|
|
236
|
+
function renderSkillHtml(skill) {
|
|
237
|
+
const categories = skill.categories
|
|
238
|
+
.map((category) => `<tr><td>${escapeHtml(category.label)}</td><td>${category.score}/${category.maxScore}</td></tr>`)
|
|
239
|
+
.join("");
|
|
240
|
+
const findings = skill.findings.length === 0
|
|
241
|
+
? "<p>No findings.</p>"
|
|
242
|
+
: skill.findings
|
|
243
|
+
.map((finding) => `<div class="finding ${finding.severity}">
|
|
244
|
+
<strong>[${finding.severity.toUpperCase()}] ${escapeHtml(finding.title)}</strong>
|
|
245
|
+
<div>${escapeHtml(formatLocation(finding))}</div>
|
|
246
|
+
<p>${escapeHtml(finding.description)}</p>
|
|
247
|
+
<p><strong>Recommendation:</strong> ${escapeHtml(finding.recommendation)}</p>
|
|
248
|
+
</div>`)
|
|
249
|
+
.join("\n");
|
|
250
|
+
return `<section class="skill">
|
|
251
|
+
<h2>${escapeHtml(skill.skillName)}: ${skill.score}/100 (${skill.grade})</h2>
|
|
252
|
+
<p><strong>Recommendation:</strong> ${escapeHtml(skill.recommendation)}</p>
|
|
253
|
+
<p><strong>Path:</strong> <code>${escapeHtml(skill.rootPath)}</code></p>
|
|
254
|
+
<div class="grid">
|
|
255
|
+
<div class="metric"><span>Files</span><strong>${skill.metrics.totalFiles}</strong></div>
|
|
256
|
+
<div class="metric"><span>Size</span><strong>${formatBytes(skill.metrics.totalBytes)}</strong></div>
|
|
257
|
+
<div class="metric"><span>Activation tokens</span><strong>${skill.metrics.estimatedActivationTokens}</strong></div>
|
|
258
|
+
</div>
|
|
259
|
+
<table>
|
|
260
|
+
<thead><tr><th>Category</th><th>Score</th></tr></thead>
|
|
261
|
+
<tbody>${categories}</tbody>
|
|
262
|
+
</table>
|
|
263
|
+
<h3>Findings</h3>
|
|
264
|
+
${findings}
|
|
265
|
+
</section>`;
|
|
266
|
+
}
|
|
267
|
+
function formatLocation(finding) {
|
|
268
|
+
if (!finding.file) {
|
|
269
|
+
return "";
|
|
270
|
+
}
|
|
271
|
+
return finding.line ? ` (${finding.file}:${finding.line})` : ` (${finding.file})`;
|
|
272
|
+
}
|
|
273
|
+
function formatBytes(bytes) {
|
|
274
|
+
if (bytes < 1024) {
|
|
275
|
+
return `${bytes} B`;
|
|
276
|
+
}
|
|
277
|
+
const kb = bytes / 1024;
|
|
278
|
+
if (kb < 1024) {
|
|
279
|
+
return `${kb.toFixed(1)} KB`;
|
|
280
|
+
}
|
|
281
|
+
return `${(kb / 1024).toFixed(1)} MB`;
|
|
282
|
+
}
|
|
283
|
+
function escapeHtml(value) {
|
|
284
|
+
return value
|
|
285
|
+
.replaceAll("&", "&")
|
|
286
|
+
.replaceAll("<", "<")
|
|
287
|
+
.replaceAll(">", ">")
|
|
288
|
+
.replaceAll('"', """)
|
|
289
|
+
.replaceAll("'", "'");
|
|
290
|
+
}
|
|
291
|
+
function sarifLevel(finding) {
|
|
292
|
+
if (finding.severity === "critical" || finding.severity === "high") {
|
|
293
|
+
return "error";
|
|
294
|
+
}
|
|
295
|
+
if (finding.severity === "medium") {
|
|
296
|
+
return "warning";
|
|
297
|
+
}
|
|
298
|
+
return "note";
|
|
299
|
+
}
|
|
300
|
+
function normalizeSarifUri(value) {
|
|
301
|
+
return value.replaceAll("\\", "/");
|
|
302
|
+
}
|
|
303
|
+
//# sourceMappingURL=render.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.js","sourceRoot":"","sources":["../../src/report/render.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# GitHub Action
|
|
2
|
+
|
|
3
|
+
SkillPreflight can run in a skill repository before users install the skill.
|
|
4
|
+
|
|
5
|
+
## Basic Workflow
|
|
6
|
+
|
|
7
|
+
```yaml
|
|
8
|
+
name: SkillPreflight
|
|
9
|
+
|
|
10
|
+
on:
|
|
11
|
+
pull_request:
|
|
12
|
+
push:
|
|
13
|
+
branches:
|
|
14
|
+
- main
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
scan:
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v4
|
|
22
|
+
|
|
23
|
+
- uses: agent-contracts/skill-preflight@v1
|
|
24
|
+
with:
|
|
25
|
+
target: "."
|
|
26
|
+
fail-below: "70"
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## SARIF Upload
|
|
30
|
+
|
|
31
|
+
Use SARIF when you want findings to appear in GitHub code scanning.
|
|
32
|
+
|
|
33
|
+
```yaml
|
|
34
|
+
name: SkillPreflight
|
|
35
|
+
|
|
36
|
+
on:
|
|
37
|
+
pull_request:
|
|
38
|
+
push:
|
|
39
|
+
branches:
|
|
40
|
+
- main
|
|
41
|
+
|
|
42
|
+
permissions:
|
|
43
|
+
security-events: write
|
|
44
|
+
contents: read
|
|
45
|
+
|
|
46
|
+
jobs:
|
|
47
|
+
scan:
|
|
48
|
+
runs-on: ubuntu-latest
|
|
49
|
+
|
|
50
|
+
steps:
|
|
51
|
+
- uses: actions/checkout@v4
|
|
52
|
+
|
|
53
|
+
- uses: agent-contracts/skill-preflight@v1
|
|
54
|
+
with:
|
|
55
|
+
target: "."
|
|
56
|
+
format: sarif
|
|
57
|
+
out: skill-preflight.sarif
|
|
58
|
+
fail-below: "70"
|
|
59
|
+
|
|
60
|
+
- uses: github/codeql-action/upload-sarif@v3
|
|
61
|
+
if: always()
|
|
62
|
+
with:
|
|
63
|
+
sarif_file: skill-preflight.sarif
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Notes
|
|
67
|
+
|
|
68
|
+
The composite action runs the published npm package with `npx`.
|
|
69
|
+
|
|
70
|
+
Before the first public release, replace the action usage with a direct command:
|
|
71
|
+
|
|
72
|
+
```yaml
|
|
73
|
+
- run: npx -y skill-preflight@latest scan . --fail-below 70
|
|
74
|
+
```
|
package/docs/release.md
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Release Checklist
|
|
2
|
+
|
|
3
|
+
Use this checklist before publishing SkillPreflight.
|
|
4
|
+
|
|
5
|
+
## Local Verification
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install
|
|
9
|
+
npm test
|
|
10
|
+
npm pack --dry-run
|
|
11
|
+
node dist/index.js scan examples/risky-skill
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## npm Publish
|
|
15
|
+
|
|
16
|
+
1. Confirm `package.json` name, version, license, and repository fields.
|
|
17
|
+
2. Log in:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm login
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
3. Publish:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm publish --access public
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
After publishing, users can run:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npx skill-preflight scan ./my-skill
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## GitHub Repository
|
|
36
|
+
|
|
37
|
+
1. Create a public GitHub repository.
|
|
38
|
+
2. Add the remote:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
git remote add origin https://github.com/agent-contracts/skill-preflight.git
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
3. Commit and push:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
git add .
|
|
48
|
+
git commit -m "Initial SkillPreflight MVP"
|
|
49
|
+
git branch -M main
|
|
50
|
+
git push -u origin main
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## First Milestones
|
|
54
|
+
|
|
55
|
+
- Add a public score badge for README files.
|
|
56
|
+
- Add a website or hosted report viewer.
|
|
57
|
+
- Add npm provenance and signed release workflow.
|
package/docs/rules.md
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Rule Catalog
|
|
2
|
+
|
|
3
|
+
SkillPreflight uses static analysis only. It reads files but does not execute skill scripts.
|
|
4
|
+
|
|
5
|
+
## Security
|
|
6
|
+
|
|
7
|
+
- Remote script execution, such as `curl ... | sh`.
|
|
8
|
+
- Dynamic shell, Node.js, or PowerShell execution.
|
|
9
|
+
- PowerShell encoded commands and execution policy bypasses.
|
|
10
|
+
- Broad destructive delete commands.
|
|
11
|
+
- Secret-like local data access, including `.env`, SSH keys, API keys, browser cookies, and login data.
|
|
12
|
+
- Suspicious webhook, paste, and ad-hoc upload endpoints.
|
|
13
|
+
- Prompt injection phrases that attempt to override system or developer instructions.
|
|
14
|
+
|
|
15
|
+
## Dependency and Install Risk
|
|
16
|
+
|
|
17
|
+
- npm lifecycle scripts: `preinstall`, `install`, `postinstall`, and `prepare`.
|
|
18
|
+
- Dangerous npm lifecycle scripts that download or dynamically execute code.
|
|
19
|
+
- Node dependencies using `*`, `latest`, `^`, `~`, Git URLs, HTTP URLs, or local file specs.
|
|
20
|
+
- Python `requirements.txt` dependencies that are unpinned.
|
|
21
|
+
- Python dependencies that install from remote URLs or Git repositories.
|
|
22
|
+
- Dependency manifests without lockfiles.
|
|
23
|
+
|
|
24
|
+
## MCP Config Risk
|
|
25
|
+
|
|
26
|
+
SkillPreflight detects common MCP JSON files, including `.mcp.json`, `mcp*.json`, and `claude_desktop_config.json`.
|
|
27
|
+
|
|
28
|
+
It flags:
|
|
29
|
+
|
|
30
|
+
- MCP servers launched through a shell, such as `bash`, `sh`, `cmd`, or `powershell`.
|
|
31
|
+
- `npx`, `uvx`, and `pipx` MCP servers without pinned package versions.
|
|
32
|
+
- Broad local paths such as user home directories.
|
|
33
|
+
- Hardcoded secret-like values in MCP `env`.
|
|
34
|
+
|
|
35
|
+
## Token Efficiency
|
|
36
|
+
|
|
37
|
+
- Large `SKILL.md` files.
|
|
38
|
+
- Large main skill files without a progressive disclosure structure.
|
|
39
|
+
- Repeated long instruction lines.
|
|
40
|
+
|
|
41
|
+
## Reliability and Maintainability
|
|
42
|
+
|
|
43
|
+
- Missing README.
|
|
44
|
+
- Missing license.
|
|
45
|
+
- Missing skill metadata frontmatter.
|
|
46
|
+
- Missing examples.
|
|
47
|
+
- Missing tests, fixtures, or evals.
|
|
48
|
+
- Vague operational language.
|
|
49
|
+
|
|
50
|
+
## Compatibility
|
|
51
|
+
|
|
52
|
+
- Hardcoded user paths.
|
|
53
|
+
- OS-specific commands without fallback guidance.
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "skill-preflight",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Pre-install safety, token, and maintainability scorecard for AI agent skills.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"skill-preflight": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"docs",
|
|
12
|
+
"README.md",
|
|
13
|
+
"LICENSE"
|
|
14
|
+
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsc -p tsconfig.json",
|
|
17
|
+
"dev": "tsx src/index.ts",
|
|
18
|
+
"test": "npm run build && node --test test/scan.test.mjs",
|
|
19
|
+
"scan:good": "tsx src/index.ts scan examples/good-skill",
|
|
20
|
+
"scan:risky": "tsx src/index.ts scan examples/risky-skill",
|
|
21
|
+
"prepack": "npm run build"
|
|
22
|
+
},
|
|
23
|
+
"keywords": [
|
|
24
|
+
"agent",
|
|
25
|
+
"skills",
|
|
26
|
+
"security",
|
|
27
|
+
"scanner",
|
|
28
|
+
"codex",
|
|
29
|
+
"claude",
|
|
30
|
+
"mcp",
|
|
31
|
+
"llm"
|
|
32
|
+
],
|
|
33
|
+
"author": "",
|
|
34
|
+
"license": "MIT",
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": "git+https://github.com/agent-contracts/skill-preflight.git"
|
|
38
|
+
},
|
|
39
|
+
"bugs": {
|
|
40
|
+
"url": "https://github.com/agent-contracts/skill-preflight/issues"
|
|
41
|
+
},
|
|
42
|
+
"homepage": "https://github.com/agent-contracts/skill-preflight#readme",
|
|
43
|
+
"publishConfig": {
|
|
44
|
+
"registry": "https://registry.npmjs.org/"
|
|
45
|
+
},
|
|
46
|
+
"engines": {
|
|
47
|
+
"node": ">=20"
|
|
48
|
+
},
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"commander": "^12.1.0"
|
|
51
|
+
},
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"@types/node": "^20.19.0",
|
|
54
|
+
"tsx": "^4.20.3",
|
|
55
|
+
"typescript": "^5.8.3"
|
|
56
|
+
}
|
|
57
|
+
}
|