@rhize/skill-forge 0.20.0 → 0.20.1
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 +7 -4
- package/dist/cli.js +71 -14
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
**The supply-chain gate for agent skills.**
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
Published version: `@rhize/skill-forge@0.20.0` (2026-09-14), 0.x beta (Pro features free until 1.0).
|
|
6
|
+
Released through the tag/OIDC workflow; `npm view @rhize/skill-forge version` reports the
|
|
7
|
+
current published version.
|
|
8
8
|
|
|
9
9
|
> This project is unrelated to the [`skillforge`](https://www.npmjs.com/package/skillforge)
|
|
10
10
|
> package on npm, which is a Claude Skills *evaluation* framework. `skill-forge` (this package,
|
|
@@ -128,7 +128,10 @@ per-feature implementation status.
|
|
|
128
128
|
outright; a lower-severity finding produces `warn`; a clean scan is `pass`.
|
|
129
129
|
- **npm-sourced MCP candidates:** fetched with `--ignore-scripts`, and every tarball member path is
|
|
130
130
|
validated before extraction (a path-traversal guard).
|
|
131
|
-
- **SkillSpector, when installed,**
|
|
131
|
+
- **SkillSpector, when installed,** adds its individual findings, including modern `issues`
|
|
132
|
+
reports. Its absence preserves the built-in-only gate. A failed, malformed or incomplete
|
|
133
|
+
installed scan is an explicit HIGH `skillspector-unavailable` finding, which blocks under
|
|
134
|
+
default strictness. A LOW aggregate score cannot hide a HIGH individual issue.
|
|
132
135
|
|
|
133
136
|
See [docs/security-model.md](docs/security-model.md) for the full rule table and current status of
|
|
134
137
|
each check.
|
package/dist/cli.js
CHANGED
|
@@ -1515,10 +1515,68 @@ function which(cmd) {
|
|
|
1515
1515
|
}
|
|
1516
1516
|
return void 0;
|
|
1517
1517
|
}
|
|
1518
|
-
function
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1518
|
+
function scannerUnavailable(targetPath) {
|
|
1519
|
+
return {
|
|
1520
|
+
severity: "HIGH",
|
|
1521
|
+
rule: "skillspector-unavailable",
|
|
1522
|
+
file: targetPath,
|
|
1523
|
+
detail: "Installed SkillSpector failed or returned an unsupported/incomplete report; external safety evidence is unavailable."
|
|
1524
|
+
};
|
|
1525
|
+
}
|
|
1526
|
+
function reportRecord(value) {
|
|
1527
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("Invalid report record");
|
|
1528
|
+
return value;
|
|
1529
|
+
}
|
|
1530
|
+
function reportSeverity(value) {
|
|
1531
|
+
if (typeof value !== "string") throw new Error("Missing severity");
|
|
1532
|
+
const severity = value.toUpperCase();
|
|
1533
|
+
if (severity === "LOW" || severity === "MEDIUM" || severity === "HIGH" || severity === "CRITICAL") return severity;
|
|
1534
|
+
throw new Error("Unknown severity");
|
|
1535
|
+
}
|
|
1536
|
+
function parseSkillSpectorReport(value, targetPath) {
|
|
1537
|
+
try {
|
|
1538
|
+
const report = reportRecord(value);
|
|
1539
|
+
const modern = "issues" in report;
|
|
1540
|
+
const raw = modern ? report.issues : report.filtered_findings ?? report.findings;
|
|
1541
|
+
if (!Array.isArray(raw)) throw new Error("Missing findings");
|
|
1542
|
+
const findings = raw.map((entry) => {
|
|
1543
|
+
const issue = reportRecord(entry);
|
|
1544
|
+
const rule = modern ? issue.id : issue.rule_id;
|
|
1545
|
+
const detail = modern ? issue.finding ?? issue.explanation : issue.message;
|
|
1546
|
+
if (typeof rule !== "string" || !rule || typeof detail !== "string") throw new Error("Invalid finding");
|
|
1547
|
+
const location = modern ? reportRecord(issue.location) : void 0;
|
|
1548
|
+
if (location && typeof location.file !== "string") throw new Error("Invalid location");
|
|
1549
|
+
const line = location?.start_line;
|
|
1550
|
+
return {
|
|
1551
|
+
severity: reportSeverity(issue.severity),
|
|
1552
|
+
rule,
|
|
1553
|
+
file: location?.file ?? targetPath,
|
|
1554
|
+
detail: typeof line === "number" && Number.isInteger(line) && line > 0 ? `${line}: ${detail}` : detail
|
|
1555
|
+
};
|
|
1556
|
+
});
|
|
1557
|
+
const assessment = modern ? reportRecord(report.risk_assessment) : void 0;
|
|
1558
|
+
const summary = assessment?.severity ?? report.risk_severity;
|
|
1559
|
+
if (modern || summary !== void 0) {
|
|
1560
|
+
const severity = reportSeverity(summary);
|
|
1561
|
+
if (severity !== "LOW") findings.push({
|
|
1562
|
+
severity,
|
|
1563
|
+
rule: "skillspector-summary",
|
|
1564
|
+
file: targetPath,
|
|
1565
|
+
detail: `SkillSpector aggregate risk: ${severity}.`
|
|
1566
|
+
});
|
|
1567
|
+
}
|
|
1568
|
+
if (modern) {
|
|
1569
|
+
const completeness = reportRecord(report.analysis_completeness);
|
|
1570
|
+
if (report.execution_successful !== true || completeness.is_complete !== true || completeness.execution_successful === false) {
|
|
1571
|
+
findings.push(scannerUnavailable(targetPath));
|
|
1572
|
+
}
|
|
1573
|
+
} else if (report.execution_successful === false) {
|
|
1574
|
+
findings.push(scannerUnavailable(targetPath));
|
|
1575
|
+
}
|
|
1576
|
+
return findings;
|
|
1577
|
+
} catch {
|
|
1578
|
+
return [scannerUnavailable(targetPath)];
|
|
1579
|
+
}
|
|
1522
1580
|
}
|
|
1523
1581
|
async function scanWithSkillSpector(targetPath) {
|
|
1524
1582
|
const bin = which("skillspector");
|
|
@@ -1528,16 +1586,15 @@ async function scanWithSkillSpector(targetPath) {
|
|
|
1528
1586
|
timeout: 6e4,
|
|
1529
1587
|
maxBuffer: 10 * 1024 * 1024
|
|
1530
1588
|
});
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
return [];
|
|
1589
|
+
return parseSkillSpectorReport(JSON.parse(stdout), targetPath);
|
|
1590
|
+
} catch (error) {
|
|
1591
|
+
const failed = scannerUnavailable(targetPath);
|
|
1592
|
+
try {
|
|
1593
|
+
const stdout = error.stdout;
|
|
1594
|
+
return stdout ? [...parseSkillSpectorReport(JSON.parse(stdout), targetPath), failed] : [failed];
|
|
1595
|
+
} catch {
|
|
1596
|
+
return [failed];
|
|
1597
|
+
}
|
|
1541
1598
|
}
|
|
1542
1599
|
}
|
|
1543
1600
|
async function scanSafety(targetPath, strictness = DEFAULT_STRICTNESS, capturedFiles) {
|