dsh-vet 0.1.0 → 0.2.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/README.md CHANGED
@@ -4,9 +4,10 @@ Security vetting for DeepSeek Harness (DSH) plugins: permission & supply-chain
4
4
  audits before install, graded via the open [`dsh-vet/v1`](docs/dsh-vet-v1.md)
5
5
  report standard.
6
6
 
7
- > **Status: v0.1 complete.** Contract draft, reference scanner + CLI, rule
8
- > set with public rationales, and an 11-package calibration sweep are in;
9
- > the `0.1.0` npm release is the remaining step.
7
+ > **Status: v0.1 shipped.** [`dsh-vet@0.1.0` is live on npm](https://www.npmjs.com/package/dsh-vet)
8
+ > reference scanner, 15 calibrated rules, public rule rationales, and an
9
+ > 11-package ecosystem sweep record. v0.2 (author-side CI + badges) is next
10
+ > on the [roadmap](ROADMAP.md).
10
11
 
11
12
  ## Install
12
13
 
@@ -50,6 +51,25 @@ from the exact tarball that ships (`npm pack` → scan), seams declared in
50
51
  package.json. It is not an A-by-cheating report — every signal the scanner
51
52
  finds in itself is in there.
52
53
 
54
+ ## CI & badge for plugin authors
55
+
56
+ Audit your plugin on every push and PR, and publish your grade from the
57
+ report committed to your repository — shields.io reads the badge straight
58
+ from your repo, so its value is auditable through git history and no badge
59
+ service is involved:
60
+
61
+ ```yaml
62
+ - uses: rogerdigital/dsh-vet/action@v0.2.0
63
+ with:
64
+ specifier: '.'
65
+ commit-report: true
66
+ ```
67
+
68
+ Every run uploads the full report as an artifact; PRs get a single
69
+ edited-in-place findings comment. Badge snippet and all inputs:
70
+ [`action/README.md`](action/README.md). The `dsh-vet badge <report.json>`
71
+ command renders the shields endpoint JSON if you wire CI yourself.
72
+
53
73
  ## Why
54
74
 
55
75
  DSH's everything-is-a-plugin architecture is its greatest strength and its
package/lib/index.d.mts CHANGED
@@ -271,7 +271,7 @@ declare function runRules(analysis: Analysis, only?: string[]): VetFinding[];
271
271
  //#endregion
272
272
  //#region src/scanner.d.ts
273
273
  /** Kept in lockstep with package.json; a test asserts they match. */
274
- declare const SCANNER_VERSION = "0.1.0";
274
+ declare const SCANNER_VERSION = "0.2.0";
275
275
  interface ScanOptions extends ResolveOptions {
276
276
  /** Injectable clock for deterministic tests/reports. */
277
277
  now?: () => string;
@@ -281,6 +281,16 @@ interface ScanOptions extends ResolveOptions {
281
281
  declare function scanDirectory(dir: string, options?: ScanOptions): Promise<VetReport>;
282
282
  declare function scan(specifier: string, options?: ScanOptions): Promise<VetReport>;
283
283
  //#endregion
284
+ //#region src/badge.d.ts
285
+ interface ShieldsEndpointBadge {
286
+ schemaVersion: 1;
287
+ label: string;
288
+ message: string;
289
+ color: string;
290
+ isError?: boolean;
291
+ }
292
+ declare function renderBadge(report: VetReport): ShieldsEndpointBadge;
293
+ //#endregion
284
294
  //#region src/cli.d.ts
285
295
  /**
286
296
  * CLI (ROADMAP T4). Exit semantics per the dsh-vet/v1 spec: `0` for any
@@ -294,4 +304,4 @@ interface CliIo {
294
304
  /** Parse and run; returns the process exit code. */
295
305
  declare function runCli(argv: string[], io: CliIo): Promise<number>;
296
306
  //#endregion
297
- export { type Analysis, type Capability, type CapabilityUse, type CharcodeCall, type CliIo, type CreateReportInput, type DynamicImportUse, type EncodedLiteral, type EvalUse, type FindingInit, type ImportRef, type NetUse, type PkgJson, RULES, RULE_ID_PATTERN, type ResolveOptions, type ResolvedTarget, type Rule, type RuleContext, SCANNER_VERSION, SCHEMA_ID, type ScanOptions, type SourceFile, type SpecifierKind, type VetConfidence, VetError, type VetEvidence, type VetFinding, type VetGrade, type VetReport, type VetScanner, type VetSeverity, type VetSummary, type VetSummaryCounts, type VetTarget, type VetTargetKind, analyze, classifySpecifier, countFindings, createReport, gradeFor, isGraded, parseNpmSpecifier, reachableFrom, resolveTarget, ruleIds, runCli, runRules, scan, scanDirectory };
307
+ export { type Analysis, type Capability, type CapabilityUse, type CharcodeCall, type CliIo, type CreateReportInput, type DynamicImportUse, type EncodedLiteral, type EvalUse, type FindingInit, type ImportRef, type NetUse, type PkgJson, RULES, RULE_ID_PATTERN, type ResolveOptions, type ResolvedTarget, type Rule, type RuleContext, SCANNER_VERSION, SCHEMA_ID, type ScanOptions, type ShieldsEndpointBadge, type SourceFile, type SpecifierKind, type VetConfidence, VetError, type VetEvidence, type VetFinding, type VetGrade, type VetReport, type VetScanner, type VetSeverity, type VetSummary, type VetSummaryCounts, type VetTarget, type VetTargetKind, analyze, classifySpecifier, countFindings, createReport, gradeFor, isGraded, parseNpmSpecifier, reachableFrom, renderBadge, resolveTarget, ruleIds, runCli, runRules, scan, scanDirectory };
package/lib/index.mjs CHANGED
@@ -1601,7 +1601,7 @@ function runRules(analysis, only) {
1601
1601
  * over the same artifact with the same version are identical.
1602
1602
  */
1603
1603
  /** Kept in lockstep with package.json; a test asserts they match. */
1604
- const SCANNER_VERSION = "0.1.0";
1604
+ const SCANNER_VERSION = "0.2.0";
1605
1605
  async function scanDirectory(dir, options = {}) {
1606
1606
  const analysis = analyze(dir);
1607
1607
  return createReport({
@@ -1635,6 +1635,26 @@ async function scan(specifier, options = {}) {
1635
1635
  }
1636
1636
  }
1637
1637
  //#endregion
1638
+ //#region src/badge.ts
1639
+ const GRADE_COLOR = {
1640
+ A: "brightgreen",
1641
+ B: "green",
1642
+ C: "yellow",
1643
+ D: "orange",
1644
+ F: "red",
1645
+ X: "lightgrey"
1646
+ };
1647
+ function renderBadge(report) {
1648
+ const grade = report.summary.grade;
1649
+ return {
1650
+ schemaVersion: 1,
1651
+ label: "dsh-vet",
1652
+ message: grade === "X" ? "scan failed" : `grade ${grade}`,
1653
+ color: GRADE_COLOR[grade],
1654
+ ...grade === "X" ? { isError: true } : {}
1655
+ };
1656
+ }
1657
+ //#endregion
1638
1658
  //#region src/cli.ts
1639
1659
  /**
1640
1660
  * CLI (ROADMAP T4). Exit semantics per the dsh-vet/v1 spec: `0` for any
@@ -1642,6 +1662,7 @@ async function scan(specifier, options = {}) {
1642
1662
  * `--strict`/`--fail-on` turn threshold breaches into exit code 1.
1643
1663
  */
1644
1664
  const USAGE = `usage: dsh-vet <specifier> [options]
1665
+ dsh-vet badge <report.json>
1645
1666
 
1646
1667
  specifier npm package (name[@version]), git URL, or local path
1647
1668
 
@@ -1650,7 +1671,11 @@ const USAGE = `usage: dsh-vet <specifier> [options]
1650
1671
  --fail-on <sev> override the --strict threshold (critical|high|medium|low)
1651
1672
  --rules <ids> comma-separated rule ids to run
1652
1673
  --version print version
1653
- --help this text`;
1674
+ --help this text
1675
+
1676
+ badge render a shields.io endpoint badge (JSON) from a
1677
+ dsh-vet/v1 report file; used by CI to publish a grade
1678
+ badge whose value is the committed report`;
1654
1679
  const SEVERITY_ORDER = [
1655
1680
  "critical",
1656
1681
  "high",
@@ -1685,6 +1710,7 @@ function humanSummary(report) {
1685
1710
  }
1686
1711
  /** Parse and run; returns the process exit code. */
1687
1712
  async function runCli(argv, io) {
1713
+ if (argv[0] === "badge") return runBadge(argv.slice(1), io);
1688
1714
  let args;
1689
1715
  try {
1690
1716
  args = parseArgs({
@@ -1737,5 +1763,25 @@ async function runCli(argv, io) {
1737
1763
  return 2;
1738
1764
  }
1739
1765
  }
1766
+ function runBadge(argv, io) {
1767
+ const path = argv[0];
1768
+ if (!path || argv.length > 1 || path === "--help") {
1769
+ io.stderr(`usage: dsh-vet badge <report.json>\n\nRender a shields.io endpoint badge from a dsh-vet/v1 report.`);
1770
+ return 2;
1771
+ }
1772
+ let report;
1773
+ try {
1774
+ report = JSON.parse(readFileSync(path, "utf8"));
1775
+ } catch (err) {
1776
+ io.stderr(`dsh-vet badge: cannot read report: ${err.message}`);
1777
+ return 2;
1778
+ }
1779
+ if (report.schema !== "dsh-vet/v1") {
1780
+ io.stderr(`dsh-vet badge: not a ${SCHEMA_ID} report (schema: ${String(report.schema)})`);
1781
+ return 2;
1782
+ }
1783
+ io.stdout(JSON.stringify(renderBadge(report)));
1784
+ return 0;
1785
+ }
1740
1786
  //#endregion
1741
- export { RULES, RULE_ID_PATTERN, SCANNER_VERSION, SCHEMA_ID, VetError, analyze, classifySpecifier, countFindings, createReport, gradeFor, isGraded, parseNpmSpecifier, reachableFrom, resolveTarget, ruleIds, runCli, runRules, scan, scanDirectory };
1787
+ export { RULES, RULE_ID_PATTERN, SCANNER_VERSION, SCHEMA_ID, VetError, analyze, classifySpecifier, countFindings, createReport, gradeFor, isGraded, parseNpmSpecifier, reachableFrom, renderBadge, resolveTarget, ruleIds, runCli, runRules, scan, scanDirectory };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-vet",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Security vetting for DeepSeek Harness (DSH) plugins: permission & supply-chain audits before install, graded via the open dsh-vet/v1 report standard.",
5
5
  "dsh": {
6
6
  "seams": ["fs", "shell", "web"]