@skillctl/security 0.3.0 → 0.4.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2026 skillctl contributors
3
+ Copyright (c) 2026 xFurti, Gabry848
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export { runAudit, auditExitCode } from './runner.js';
2
+ export { validateSkillDir } from './validate-skill.js';
2
3
  export type { AuditReport, AuditFinding, AuditSeverity } from './types.js';
3
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACtD,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC"}
package/dist/index.js CHANGED
@@ -1,2 +1,3 @@
1
1
  export { runAudit, auditExitCode } from './runner.js';
2
+ export { validateSkillDir } from './validate-skill.js';
2
3
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"integrity-drift.d.ts","sourceRoot":"","sources":["../../src/rules/integrity-drift.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEpD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CA0BtF"}
1
+ {"version":3,"file":"integrity-drift.d.ts","sourceRoot":"","sources":["../../src/rules/integrity-drift.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEpD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CA2BtF"}
@@ -1,18 +1,19 @@
1
1
  import { stat } from 'node:fs/promises';
2
- import { computeDirIntegrity } from '@skillctl/core';
2
+ import { computeDirIntegrity, resolveEntryCanonicalPath } from '@skillctl/core';
3
3
  export async function checkIntegrityDrift(lock) {
4
4
  const findings = [];
5
5
  for (const [name, entry] of Object.entries(lock.skills)) {
6
+ const path = await resolveEntryCanonicalPath(entry);
6
7
  try {
7
- await stat(entry.canonicalPath);
8
- const integrity = await computeDirIntegrity(entry.canonicalPath);
8
+ await stat(path);
9
+ const integrity = await computeDirIntegrity(path);
9
10
  if (integrity !== entry.integrity) {
10
11
  findings.push({
11
12
  rule: 'integrity-drift',
12
13
  severity: 'error',
13
14
  skill: name,
14
15
  message: `Canonical integrity mismatch (lock: ${entry.integrity.slice(0, 24)}...)`,
15
- path: entry.canonicalPath,
16
+ path,
16
17
  });
17
18
  }
18
19
  }
@@ -22,7 +23,7 @@ export async function checkIntegrityDrift(lock) {
22
23
  severity: 'error',
23
24
  skill: name,
24
25
  message: 'Canonical path missing',
25
- path: entry.canonicalPath,
26
+ path,
26
27
  });
27
28
  }
28
29
  }
@@ -1 +1 @@
1
- {"version":3,"file":"integrity-drift.js","sourceRoot":"","sources":["../../src/rules/integrity-drift.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAExC,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAGrD,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,IAAmB;IAC3D,MAAM,QAAQ,GAAmB,EAAE,CAAC;IACpC,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QACxD,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;YAChC,MAAM,SAAS,GAAG,MAAM,mBAAmB,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;YACjE,IAAI,SAAS,KAAK,KAAK,CAAC,SAAS,EAAE,CAAC;gBAClC,QAAQ,CAAC,IAAI,CAAC;oBACZ,IAAI,EAAE,iBAAiB;oBACvB,QAAQ,EAAE,OAAO;oBACjB,KAAK,EAAE,IAAI;oBACX,OAAO,EAAE,uCAAuC,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM;oBAClF,IAAI,EAAE,KAAK,CAAC,aAAa;iBAC1B,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,QAAQ,CAAC,IAAI,CAAC;gBACZ,IAAI,EAAE,iBAAiB;gBACvB,QAAQ,EAAE,OAAO;gBACjB,KAAK,EAAE,IAAI;gBACX,OAAO,EAAE,wBAAwB;gBACjC,IAAI,EAAE,KAAK,CAAC,aAAa;aAC1B,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC"}
1
+ {"version":3,"file":"integrity-drift.js","sourceRoot":"","sources":["../../src/rules/integrity-drift.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAExC,OAAO,EAAE,mBAAmB,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC;AAGhF,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,IAAmB;IAC3D,MAAM,QAAQ,GAAmB,EAAE,CAAC;IACpC,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QACxD,MAAM,IAAI,GAAG,MAAM,yBAAyB,CAAC,KAAK,CAAC,CAAC;QACpD,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC;YACjB,MAAM,SAAS,GAAG,MAAM,mBAAmB,CAAC,IAAI,CAAC,CAAC;YAClD,IAAI,SAAS,KAAK,KAAK,CAAC,SAAS,EAAE,CAAC;gBAClC,QAAQ,CAAC,IAAI,CAAC;oBACZ,IAAI,EAAE,iBAAiB;oBACvB,QAAQ,EAAE,OAAO;oBACjB,KAAK,EAAE,IAAI;oBACX,OAAO,EAAE,uCAAuC,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM;oBAClF,IAAI;iBACL,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,QAAQ,CAAC,IAAI,CAAC;gBACZ,IAAI,EAAE,iBAAiB;gBACvB,QAAQ,EAAE,OAAO;gBACjB,KAAK,EAAE,IAAI;gBACX,OAAO,EAAE,wBAAwB;gBACjC,IAAI;aACL,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAgB,MAAM,YAAY,CAAC;AAO5D,wBAAsB,QAAQ,CAAC,GAAG,SAAgB,GAAG,OAAO,CAAC,WAAW,CAAC,CAwBxE;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,UAAQ,GAAG,MAAM,CAKzE"}
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAgB,MAAM,YAAY,CAAC;AAO5D,wBAAsB,QAAQ,CAAC,GAAG,SAAgB,GAAG,OAAO,CAAC,WAAW,CAAC,CAyBxE;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,UAAQ,GAAG,MAAM,CAKzE"}
package/dist/runner.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { resolveEntryCanonicalPath } from '@skillctl/core';
1
2
  import { loadLockfile } from '@skillctl/lockfile';
2
3
  import { checkIntegrityDrift } from './rules/integrity-drift.js';
3
4
  import { checkScriptHeuristics } from './rules/script-heuristics.js';
@@ -12,10 +13,11 @@ export async function runAudit(cwd = process.cwd()) {
12
13
  const findings = [];
13
14
  findings.push(...(await checkIntegrityDrift(lock)));
14
15
  for (const [name, entry] of Object.entries(lock.skills)) {
15
- findings.push(...(await checkNameDirMatch(name, entry.canonicalPath)));
16
- findings.push(...(await checkScriptHeuristics(name, entry.canonicalPath)));
17
- findings.push(...(await checkPathTraversal(name, entry.canonicalPath)));
18
- findings.push(...(await checkSizeLimits(name, entry.canonicalPath)));
16
+ const canonicalPath = await resolveEntryCanonicalPath(entry);
17
+ findings.push(...(await checkNameDirMatch(name, canonicalPath)));
18
+ findings.push(...(await checkScriptHeuristics(name, canonicalPath)));
19
+ findings.push(...(await checkPathTraversal(name, canonicalPath)));
20
+ findings.push(...(await checkSizeLimits(name, canonicalPath)));
19
21
  }
20
22
  const hasError = findings.some((f) => f.severity === 'error');
21
23
  const hasWarning = findings.some((f) => f.severity === 'warning');
@@ -1 +1 @@
1
- {"version":3,"file":"runner.js","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEzD,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE;IAChD,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,GAAG,CAAC,CAAC;IACrC,IAAI,CAAC,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACnD,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;IACpD,CAAC;IAED,MAAM,QAAQ,GAAmB,EAAE,CAAC;IACpC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAEpD,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QACxD,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,iBAAiB,CAAC,IAAI,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;QACvE,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,qBAAqB,CAAC,IAAI,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;QAC3E,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,kBAAkB,CAAC,IAAI,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;QACxE,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,eAAe,CAAC,IAAI,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;IACvE,CAAC;IAED,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC;IAC9D,MAAM,UAAU,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC;IAElE,OAAO;QACL,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI;QAC5D,QAAQ;QACR,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM;KACzC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,MAAmB,EAAE,MAAM,GAAG,KAAK;IAC/D,IAAI,MAAM,CAAC,MAAM,KAAK,QAAQ;QAAE,OAAO,CAAC,CAAC;IACzC,IAAI,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,UAAU;QAAE,OAAO,CAAC,CAAC;IACrD,IAAI,MAAM,CAAC,MAAM,KAAK,UAAU;QAAE,OAAO,CAAC,CAAC;IAC3C,OAAO,CAAC,CAAC;AACX,CAAC"}
1
+ {"version":3,"file":"runner.js","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEzD,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE;IAChD,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,GAAG,CAAC,CAAC;IACrC,IAAI,CAAC,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACnD,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;IACpD,CAAC;IAED,MAAM,QAAQ,GAAmB,EAAE,CAAC;IACpC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAEpD,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QACxD,MAAM,aAAa,GAAG,MAAM,yBAAyB,CAAC,KAAK,CAAC,CAAC;QAC7D,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,iBAAiB,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC;QACjE,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,qBAAqB,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC;QACrE,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,kBAAkB,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC;QAClE,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,eAAe,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC;IACjE,CAAC;IAED,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC;IAC9D,MAAM,UAAU,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC;IAElE,OAAO;QACL,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI;QAC5D,QAAQ;QACR,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM;KACzC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,MAAmB,EAAE,MAAM,GAAG,KAAK;IAC/D,IAAI,MAAM,CAAC,MAAM,KAAK,QAAQ;QAAE,OAAO,CAAC,CAAC;IACzC,IAAI,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,UAAU;QAAE,OAAO,CAAC,CAAC;IACrD,IAAI,MAAM,CAAC,MAAM,KAAK,UAAU;QAAE,OAAO,CAAC,CAAC;IAC3C,OAAO,CAAC,CAAC;AACX,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=validate-skill.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate-skill.test.d.ts","sourceRoot":"","sources":["../../src/test/validate-skill.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,35 @@
1
+ import { test } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises';
4
+ import { join } from 'node:path';
5
+ import { tmpdir } from 'node:os';
6
+ import { validateSkillDir } from '../validate-skill.js';
7
+ test('validateSkillDir passes for valid skill directory', async () => {
8
+ const root = await mkdtemp(join(tmpdir(), 'validate-skill-'));
9
+ const skillDir = join(root, 'demo-skill');
10
+ try {
11
+ await mkdir(skillDir, { recursive: true });
12
+ await writeFile(join(skillDir, 'SKILL.md'), '---\nname: demo-skill\n---\n# Demo\n');
13
+ const report = await validateSkillDir(skillDir);
14
+ assert.equal(report.status, 'ok');
15
+ assert.equal(report.scanned, 1);
16
+ assert.equal(report.findings.length, 0);
17
+ }
18
+ finally {
19
+ await rm(root, { recursive: true, force: true });
20
+ }
21
+ });
22
+ test('validateSkillDir errors when SKILL.md is missing', async () => {
23
+ const root = await mkdtemp(join(tmpdir(), 'validate-skill-'));
24
+ const skillDir = join(root, 'empty-skill');
25
+ try {
26
+ await mkdir(skillDir, { recursive: true });
27
+ const report = await validateSkillDir(skillDir);
28
+ assert.equal(report.status, 'errors');
29
+ assert.ok(report.findings.some((f) => f.rule === 'skill-md-missing'));
30
+ }
31
+ finally {
32
+ await rm(root, { recursive: true, force: true });
33
+ }
34
+ });
35
+ //# sourceMappingURL=validate-skill.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate-skill.test.js","sourceRoot":"","sources":["../../src/test/validate-skill.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAExD,IAAI,CAAC,mDAAmD,EAAE,KAAK,IAAI,EAAE;IACnE,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,iBAAiB,CAAC,CAAC,CAAC;IAC9D,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IAC1C,IAAI,CAAC;QACH,MAAM,KAAK,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3C,MAAM,SAAS,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,EAAE,sCAAsC,CAAC,CAAC;QACpF,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,QAAQ,CAAC,CAAC;QAChD,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAClC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAChC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAC1C,CAAC;YAAS,CAAC;QACT,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACnD,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;IAClE,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,iBAAiB,CAAC,CAAC,CAAC;IAC9D,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;IAC3C,IAAI,CAAC;QACH,MAAM,KAAK,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3C,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,QAAQ,CAAC,CAAC;QAChD,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QACtC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,kBAAkB,CAAC,CAAC,CAAC;IACxE,CAAC;YAAS,CAAC;QACT,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACnD,CAAC;AACH,CAAC,CAAC,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { AuditReport } from './types.js';
2
+ /** Validate a single skill directory (SKILL.md layout) without a project lockfile. */
3
+ export declare function validateSkillDir(skillPath: string): Promise<AuditReport>;
4
+ //# sourceMappingURL=validate-skill.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate-skill.d.ts","sourceRoot":"","sources":["../src/validate-skill.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAgB,WAAW,EAAE,MAAM,YAAY,CAAC;AAkB5D,sFAAsF;AACtF,wBAAsB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAkE9E"}
@@ -0,0 +1,83 @@
1
+ import { stat } from 'node:fs/promises';
2
+ import { basename, join, resolve } from 'node:path';
3
+ import { canonicalizeName } from '@skillctl/core';
4
+ import { checkNameDirMatch } from './rules/name-dir-match.js';
5
+ import { checkScriptHeuristics } from './rules/script-heuristics.js';
6
+ import { checkPathTraversal } from './rules/path-traversal.js';
7
+ import { checkSizeLimits } from './rules/size-limits.js';
8
+ async function findSkillMarkdown(skillPath) {
9
+ for (const f of ['SKILL.md', 'skill.md']) {
10
+ try {
11
+ await stat(join(skillPath, f));
12
+ return true;
13
+ }
14
+ catch {
15
+ // continue
16
+ }
17
+ }
18
+ return false;
19
+ }
20
+ /** Validate a single skill directory (SKILL.md layout) without a project lockfile. */
21
+ export async function validateSkillDir(skillPath) {
22
+ const abs = resolve(skillPath);
23
+ let dirStat;
24
+ try {
25
+ dirStat = await stat(abs);
26
+ }
27
+ catch {
28
+ const name = canonicalizeName(basename(abs));
29
+ return {
30
+ status: 'errors',
31
+ scanned: 0,
32
+ findings: [
33
+ {
34
+ rule: 'skill-dir-missing',
35
+ severity: 'error',
36
+ skill: name,
37
+ message: `Skill directory not found: ${abs}`,
38
+ path: abs,
39
+ },
40
+ ],
41
+ };
42
+ }
43
+ if (!dirStat.isDirectory()) {
44
+ const name = canonicalizeName(basename(abs));
45
+ return {
46
+ status: 'errors',
47
+ scanned: 0,
48
+ findings: [
49
+ {
50
+ rule: 'skill-dir-missing',
51
+ severity: 'error',
52
+ skill: name,
53
+ message: 'Path is not a directory',
54
+ path: abs,
55
+ },
56
+ ],
57
+ };
58
+ }
59
+ const name = canonicalizeName(basename(abs));
60
+ const findings = [];
61
+ if (!(await findSkillMarkdown(abs))) {
62
+ findings.push({
63
+ rule: 'skill-md-missing',
64
+ severity: 'error',
65
+ skill: name,
66
+ message: 'SKILL.md (or skill.md) not found',
67
+ path: abs,
68
+ });
69
+ return { status: 'errors', findings, scanned: 0 };
70
+ }
71
+ findings.push(...(await checkNameDirMatch(name, abs)));
72
+ findings.push(...(await checkScriptHeuristics(name, abs)));
73
+ findings.push(...(await checkPathTraversal(name, abs)));
74
+ findings.push(...(await checkSizeLimits(name, abs)));
75
+ const hasError = findings.some((f) => f.severity === 'error');
76
+ const hasWarning = findings.some((f) => f.severity === 'warning');
77
+ return {
78
+ status: hasError ? 'errors' : hasWarning ? 'warnings' : 'ok',
79
+ findings,
80
+ scanned: 1,
81
+ };
82
+ }
83
+ //# sourceMappingURL=validate-skill.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate-skill.js","sourceRoot":"","sources":["../src/validate-skill.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@skillctl/security",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Security scanner and audit for skillctl skills",
5
5
  "license": "MIT",
6
- "author": "skillctl contributors",
6
+ "author": "xFurti & Gabry848",
7
7
  "type": "module",
8
8
  "main": "./dist/index.js",
9
9
  "types": "./dist/index.d.ts",
@@ -11,8 +11,8 @@
11
11
  "dist"
12
12
  ],
13
13
  "dependencies": {
14
- "@skillctl/core": "0.3.0",
15
- "@skillctl/lockfile": "0.3.0"
14
+ "@skillctl/core": "0.4.0",
15
+ "@skillctl/lockfile": "0.4.0"
16
16
  },
17
17
  "devDependencies": {
18
18
  "@types/node": "^20.14.0",