@skillsmith/core 0.11.6 → 0.12.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/CHANGELOG.md +208 -0
- package/README.md +2 -2
- package/dist/.tsbuildinfo +1 -1
- package/dist/src/api/client.types.d.ts +9 -0
- package/dist/src/api/client.types.d.ts.map +1 -1
- package/dist/src/api/schemas.d.ts +6 -0
- package/dist/src/api/schemas.d.ts.map +1 -1
- package/dist/src/api/schemas.js +5 -0
- package/dist/src/api/schemas.js.map +1 -1
- package/dist/src/api/security-summary.d.ts +10 -1
- package/dist/src/api/security-summary.d.ts.map +1 -1
- package/dist/src/api/security-summary.js +9 -0
- package/dist/src/api/security-summary.js.map +1 -1
- package/dist/src/api/security-summary.test.js +79 -1
- package/dist/src/api/security-summary.test.js.map +1 -1
- package/dist/src/api/types.d.ts +9 -0
- package/dist/src/api/types.d.ts.map +1 -1
- package/dist/src/exports/services.d.ts +2 -2
- package/dist/src/exports/services.d.ts.map +1 -1
- package/dist/src/exports/services.js +4 -2
- package/dist/src/exports/services.js.map +1 -1
- package/dist/src/index.d.ts +3 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +8 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/install/agent-config-merge.json-array.d.ts +16 -0
- package/dist/src/install/agent-config-merge.json-array.d.ts.map +1 -1
- package/dist/src/install/agent-config-merge.json-array.js +32 -3
- package/dist/src/install/agent-config-merge.json-array.js.map +1 -1
- package/dist/src/install/agent-harness-targets.d.ts +5 -0
- package/dist/src/install/agent-harness-targets.d.ts.map +1 -1
- package/dist/src/install/agent-harness-targets.js +19 -4
- package/dist/src/install/agent-harness-targets.js.map +1 -1
- package/dist/src/install/agent-pack-installer.cursor-hooks.d.ts +29 -0
- package/dist/src/install/agent-pack-installer.cursor-hooks.d.ts.map +1 -0
- package/dist/src/install/agent-pack-installer.cursor-hooks.js +233 -0
- package/dist/src/install/agent-pack-installer.cursor-hooks.js.map +1 -0
- package/dist/src/install/agent-pack-installer.cursor-hooks.test.d.ts +2 -0
- package/dist/src/install/agent-pack-installer.cursor-hooks.test.d.ts.map +1 -0
- package/dist/src/install/agent-pack-installer.cursor-hooks.test.js +225 -0
- package/dist/src/install/agent-pack-installer.cursor-hooks.test.js.map +1 -0
- package/dist/src/install/agent-pack-installer.d.ts +10 -5
- package/dist/src/install/agent-pack-installer.d.ts.map +1 -1
- package/dist/src/install/agent-pack-installer.harness.d.ts +10 -2
- package/dist/src/install/agent-pack-installer.harness.d.ts.map +1 -1
- package/dist/src/install/agent-pack-installer.harness.js +9 -2
- package/dist/src/install/agent-pack-installer.harness.js.map +1 -1
- package/dist/src/install/agent-pack-installer.js +15 -6
- package/dist/src/install/agent-pack-installer.js.map +1 -1
- package/dist/src/install/agent-pack-installer.test.js +3 -0
- package/dist/src/install/agent-pack-installer.test.js.map +1 -1
- package/dist/src/scripts/__tests__/scan-imported-skills.test.js +25 -0
- package/dist/src/scripts/__tests__/scan-imported-skills.test.js.map +1 -1
- package/dist/src/scripts/skill-scanner/trust-scorer.js +1 -1
- package/dist/src/scripts/skill-scanner/trust-scorer.js.map +1 -1
- package/dist/src/security/scanner/SecurityScanner.archive.d.ts +34 -0
- package/dist/src/security/scanner/SecurityScanner.archive.d.ts.map +1 -0
- package/dist/src/security/scanner/SecurityScanner.archive.js +218 -0
- package/dist/src/security/scanner/SecurityScanner.archive.js.map +1 -0
- package/dist/src/security/scanner/SecurityScanner.compound.d.ts +1 -0
- package/dist/src/security/scanner/SecurityScanner.compound.d.ts.map +1 -1
- package/dist/src/security/scanner/SecurityScanner.compound.js +117 -38
- package/dist/src/security/scanner/SecurityScanner.compound.js.map +1 -1
- package/dist/src/security/scanner/SecurityScanner.d.ts +41 -4
- package/dist/src/security/scanner/SecurityScanner.d.ts.map +1 -1
- package/dist/src/security/scanner/SecurityScanner.decoy.d.ts +72 -0
- package/dist/src/security/scanner/SecurityScanner.decoy.d.ts.map +1 -0
- package/dist/src/security/scanner/SecurityScanner.decoy.js +265 -0
- package/dist/src/security/scanner/SecurityScanner.decoy.js.map +1 -0
- package/dist/src/security/scanner/SecurityScanner.encoding.d.ts +56 -0
- package/dist/src/security/scanner/SecurityScanner.encoding.d.ts.map +1 -0
- package/dist/src/security/scanner/SecurityScanner.encoding.js +270 -0
- package/dist/src/security/scanner/SecurityScanner.encoding.js.map +1 -0
- package/dist/src/security/scanner/SecurityScanner.exec.d.ts +23 -20
- package/dist/src/security/scanner/SecurityScanner.exec.d.ts.map +1 -1
- package/dist/src/security/scanner/SecurityScanner.exec.js +207 -52
- package/dist/src/security/scanner/SecurityScanner.exec.js.map +1 -1
- package/dist/src/security/scanner/SecurityScanner.fetch-correlation.d.ts +115 -0
- package/dist/src/security/scanner/SecurityScanner.fetch-correlation.d.ts.map +1 -0
- package/dist/src/security/scanner/SecurityScanner.fetch-correlation.js +181 -0
- package/dist/src/security/scanner/SecurityScanner.fetch-correlation.js.map +1 -0
- package/dist/src/security/scanner/SecurityScanner.helpers.d.ts +14 -11
- package/dist/src/security/scanner/SecurityScanner.helpers.d.ts.map +1 -1
- package/dist/src/security/scanner/SecurityScanner.helpers.js +26 -124
- package/dist/src/security/scanner/SecurityScanner.helpers.js.map +1 -1
- package/dist/src/security/scanner/SecurityScanner.js +114 -36
- package/dist/src/security/scanner/SecurityScanner.js.map +1 -1
- package/dist/src/security/scanner/SecurityScanner.paste-host.d.ts +69 -0
- package/dist/src/security/scanner/SecurityScanner.paste-host.d.ts.map +1 -0
- package/dist/src/security/scanner/SecurityScanner.paste-host.js +342 -0
- package/dist/src/security/scanner/SecurityScanner.paste-host.js.map +1 -0
- package/dist/src/security/scanner/SecurityScanner.risk-score.d.ts +27 -0
- package/dist/src/security/scanner/SecurityScanner.risk-score.d.ts.map +1 -0
- package/dist/src/security/scanner/SecurityScanner.risk-score.js +178 -0
- package/dist/src/security/scanner/SecurityScanner.risk-score.js.map +1 -0
- package/dist/src/security/scanner/SecurityScanner.urls.d.ts +20 -0
- package/dist/src/security/scanner/SecurityScanner.urls.d.ts.map +1 -0
- package/dist/src/security/scanner/SecurityScanner.urls.js +26 -0
- package/dist/src/security/scanner/SecurityScanner.urls.js.map +1 -0
- package/dist/src/security/scanner/index.d.ts +2 -2
- package/dist/src/security/scanner/index.d.ts.map +1 -1
- package/dist/src/security/scanner/index.js +5 -1
- package/dist/src/security/scanner/index.js.map +1 -1
- package/dist/src/security/scanner/multiline-category-closure.test.js +6 -0
- package/dist/src/security/scanner/multiline-category-closure.test.js.map +1 -1
- package/dist/src/security/scanner/patterns.d.ts +41 -21
- package/dist/src/security/scanner/patterns.d.ts.map +1 -1
- package/dist/src/security/scanner/patterns.exec.d.ts +89 -0
- package/dist/src/security/scanner/patterns.exec.d.ts.map +1 -0
- package/dist/src/security/scanner/patterns.exec.js +115 -0
- package/dist/src/security/scanner/patterns.exec.js.map +1 -0
- package/dist/src/security/scanner/patterns.js +78 -41
- package/dist/src/security/scanner/patterns.js.map +1 -1
- package/dist/src/security/scanner/types.d.ts +15 -1
- package/dist/src/security/scanner/types.d.ts.map +1 -1
- package/dist/src/security/scanner/typosquat.d.ts +10 -0
- package/dist/src/security/scanner/typosquat.d.ts.map +1 -1
- package/dist/src/security/scanner/typosquat.js +5 -1
- package/dist/src/security/scanner/typosquat.js.map +1 -1
- package/dist/src/security/scanner/weights.d.ts +12 -3
- package/dist/src/security/scanner/weights.d.ts.map +1 -1
- package/dist/src/security/scanner/weights.js +50 -1
- package/dist/src/security/scanner/weights.js.map +1 -1
- package/dist/src/services/agent-pack/prompt-source.d.ts +15 -0
- package/dist/src/services/agent-pack/prompt-source.d.ts.map +1 -1
- package/dist/src/services/agent-pack/prompt-source.js +32 -1
- package/dist/src/services/agent-pack/prompt-source.js.map +1 -1
- package/dist/src/services/agent-pack/skill-md.d.ts.map +1 -1
- package/dist/src/services/agent-pack/skill-md.js +9 -1
- package/dist/src/services/agent-pack/skill-md.js.map +1 -1
- package/dist/src/services/bundled-sibling-scan.d.ts +87 -13
- package/dist/src/services/bundled-sibling-scan.d.ts.map +1 -1
- package/dist/src/services/bundled-sibling-scan.js +177 -33
- package/dist/src/services/bundled-sibling-scan.js.map +1 -1
- package/dist/src/services/recommend-guard.d.ts +19 -0
- package/dist/src/services/recommend-guard.d.ts.map +1 -1
- package/dist/src/services/recommend-guard.js +28 -0
- package/dist/src/services/recommend-guard.js.map +1 -1
- package/dist/src/services/recommend-guard.test.js +23 -3
- package/dist/src/services/recommend-guard.test.js.map +1 -1
- package/dist/src/sync/index.d.ts +1 -0
- package/dist/src/sync/index.d.ts.map +1 -1
- package/dist/src/sync/index.js +2 -0
- package/dist/src/sync/index.js.map +1 -1
- package/dist/src/sync/license-status-client.d.ts +56 -0
- package/dist/src/sync/license-status-client.d.ts.map +1 -0
- package/dist/src/sync/license-status-client.js +118 -0
- package/dist/src/sync/license-status-client.js.map +1 -0
- package/dist/src/sync/license-status-client.test.d.ts +14 -0
- package/dist/src/sync/license-status-client.test.d.ts.map +1 -0
- package/dist/src/sync/license-status-client.test.js +136 -0
- package/dist/src/sync/license-status-client.test.js.map +1 -0
- package/dist/src/types.d.ts +13 -0
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/utils/version-check.d.ts +58 -5
- package/dist/src/utils/version-check.d.ts.map +1 -1
- package/dist/src/utils/version-check.js +73 -2
- package/dist/src/utils/version-check.js.map +1 -1
- package/dist/src/utils/version-check.test.js +49 -10
- package/dist/src/utils/version-check.test.js.map +1 -1
- package/dist/tests/SecurityScanner.scoring.test.js +123 -0
- package/dist/tests/SecurityScanner.scoring.test.js.map +1 -1
- package/dist/tests/security/advisory-severity-guard.test.d.ts +20 -0
- package/dist/tests/security/advisory-severity-guard.test.d.ts.map +1 -0
- package/dist/tests/security/advisory-severity-guard.test.js +70 -0
- package/dist/tests/security/advisory-severity-guard.test.js.map +1 -0
- package/dist/tests/security/archive-evasion.test.d.ts +2 -0
- package/dist/tests/security/archive-evasion.test.d.ts.map +1 -0
- package/dist/tests/security/archive-evasion.test.js +126 -0
- package/dist/tests/security/archive-evasion.test.js.map +1 -0
- package/dist/tests/security/clawhavoc-e2e.fixtures.d.ts +71 -0
- package/dist/tests/security/clawhavoc-e2e.fixtures.d.ts.map +1 -0
- package/dist/tests/security/clawhavoc-e2e.fixtures.js +135 -0
- package/dist/tests/security/clawhavoc-e2e.fixtures.js.map +1 -0
- package/dist/tests/security/co-signal-escalation.test.d.ts +30 -0
- package/dist/tests/security/co-signal-escalation.test.d.ts.map +1 -0
- package/dist/tests/security/co-signal-escalation.test.js +494 -0
- package/dist/tests/security/co-signal-escalation.test.js.map +1 -0
- package/dist/tests/security/decoy-misdirection.test.d.ts +2 -0
- package/dist/tests/security/decoy-misdirection.test.d.ts.map +1 -0
- package/dist/tests/security/decoy-misdirection.test.js +130 -0
- package/dist/tests/security/decoy-misdirection.test.js.map +1 -0
- package/dist/tests/security/encoded-payload.test.d.ts +2 -0
- package/dist/tests/security/encoded-payload.test.d.ts.map +1 -0
- package/dist/tests/security/encoded-payload.test.js +199 -0
- package/dist/tests/security/encoded-payload.test.js.map +1 -0
- package/dist/tests/security/gatekeeper-bypass.test.d.ts +2 -0
- package/dist/tests/security/gatekeeper-bypass.test.d.ts.map +1 -0
- package/dist/tests/security/gatekeeper-bypass.test.js +167 -0
- package/dist/tests/security/gatekeeper-bypass.test.js.map +1 -0
- package/dist/tests/security/paste-host-fetch.test.d.ts +2 -0
- package/dist/tests/security/paste-host-fetch.test.d.ts.map +1 -0
- package/dist/tests/security/paste-host-fetch.test.js +199 -0
- package/dist/tests/security/paste-host-fetch.test.js.map +1 -0
- package/dist/tests/security/scanner-regression-guard.test.js +5 -0
- package/dist/tests/security/scanner-regression-guard.test.js.map +1 -1
- package/dist/tests/security/smi5879-corroboration.core.test.d.ts +31 -0
- package/dist/tests/security/smi5879-corroboration.core.test.d.ts.map +1 -0
- package/dist/tests/security/smi5879-corroboration.core.test.js +157 -0
- package/dist/tests/security/smi5879-corroboration.core.test.js.map +1 -0
- package/dist/tests/services/aidefence-feedback.test.js +5 -0
- package/dist/tests/services/aidefence-feedback.test.js.map +1 -1
- package/dist/tests/services/bundled-sibling-scan.test.js +171 -10
- package/dist/tests/services/bundled-sibling-scan.test.js.map +1 -1
- package/dist/tests/skill-md-cli-fallback-parity.test.d.ts +22 -0
- package/dist/tests/skill-md-cli-fallback-parity.test.d.ts.map +1 -0
- package/dist/tests/skill-md-cli-fallback-parity.test.js +92 -0
- package/dist/tests/skill-md-cli-fallback-parity.test.js.map +1 -0
- package/dist/tests/skill-scanner/allowlist.test.js +14 -1
- package/dist/tests/skill-scanner/allowlist.test.js.map +1 -1
- package/package.json +7 -7
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,214 @@ All notable changes to `@skillsmith/core` are documented here.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## v0.12.0
|
|
8
|
+
|
|
9
|
+
- **Cadence**: Mechanical cadence alignment (no changes since v0.11.7).
|
|
10
|
+
- **Feature**: new `resolveSessionTier` client (`sync/license-status-client.ts`, SMI-6098) —
|
|
11
|
+
authenticates the stored device-login session against `/license-status` (proactively refreshing
|
|
12
|
+
via the existing `resolveAccessToken` helper) so the MCP server can resolve a real subscription
|
|
13
|
+
tier for a `skillsmith login` session with no separately-configured `SKILLSMITH_API_KEY`.
|
|
14
|
+
Throws `SessionTierAuthError` (no session / refresh failed) or `SessionTierTransientError`
|
|
15
|
+
(network error, HTTP 429/5xx, unexpected response) so callers never conflate "couldn't check"
|
|
16
|
+
with a definitive `community` result.
|
|
17
|
+
- **Fix**: `analyzeMarkdownContext`'s indented-code-block heuristic (4+ spaces or a tab = a
|
|
18
|
+
markdown documentation example) was being applied unconditionally to every scanned file,
|
|
19
|
+
including the new Gap 8 extended siblings — real, non-markdown source files. Since virtually all
|
|
20
|
+
indented Python/Ruby/Perl/etc. control-flow bodies match this pattern, it silently downgraded
|
|
21
|
+
`sensitive_path` findings from `high` to `medium` and blocked `escalateCodeExecution`'s
|
|
22
|
+
co-signal escalation path in those files, discovered via a genuine multi-signal backdoor fixture
|
|
23
|
+
(a `~/.ssh` read next to a `curl|bash`) that failed to escalate to `critical` purely because its
|
|
24
|
+
containing function body was indented. `analyzeMarkdownContext`/`scanSkillContent` (both edge
|
|
25
|
+
twins) and core's `SecurityScanner.scan()` now take an `isMarkdown` parameter (default `true`,
|
|
26
|
+
byte-identical behavior for every existing caller) that the indexer's extended-sibling scan path
|
|
27
|
+
and `bundled-sibling-scan.ts`'s executable-code candidates now pass `false` for.
|
|
28
|
+
- **Feature**: scoped bundled-file scan expansion to operational code (SMI-6033 Wave 2, Gap 8) —
|
|
29
|
+
the final wave of the ClawHavoc scanner-gap remediation initiative. The indexer previously only
|
|
30
|
+
ever read `SKILL.md` plus 7 fixed sibling filenames, never `scripts/`, `src/`, or `bin/`, so a
|
|
31
|
+
backdoor buried mid-function in otherwise-working operational code was structurally invisible to
|
|
32
|
+
the scanner. New `fetchRepoTreeEntries` (run-scoped memoized, budgeted via
|
|
33
|
+
`MAX_TREE_FETCHES_PER_RUN`/`SKILLSMITH_MAX_TREE_FETCHES_PER_RUN`, default 300) fetches the
|
|
34
|
+
repo's git tree once per repo per run; `enumerateExtendedSiblingTargets` deterministically ranks
|
|
35
|
+
and caps (`MAX_EXTENDED_SIBLING_FILES = 20`) executable-code candidates (`.sh .py .js .mjs .cjs
|
|
36
|
+
.ts .rb .php .ps1 .pl`) by SKILL.md-reference, entry-point naming, path depth, then lexicographic
|
|
37
|
+
order. Two new `skills` columns (`scan_coverage_incomplete`/`scan_coverage_note`) record — never
|
|
38
|
+
silently — when the extended selection couldn't cover everything (count cap, size cap, a
|
|
39
|
+
transient sibling-fetch failure, a Trees API fetch failure, a truncated tree response, or a
|
|
40
|
+
spent per-run fetch budget); a clean 404 does not count. Surfaced in `get_skill`, `search`, and
|
|
41
|
+
`skill_recommend` output as a plain informational caveat (never a rejection signal). Local
|
|
42
|
+
`skill_rescan`/`skill_validate` gets the same ranked, capped selection via
|
|
43
|
+
`bundled-sibling-scan.ts`'s `collectExecutableCodeFiles` (replacing the narrower `.sh`-only
|
|
44
|
+
`collectShFiles`), closing that module's own documented Phase-3 follow-up — this narrows its
|
|
45
|
+
existing local scan-file cap from 50 to 20 to match the registry-side cap, an intentional
|
|
46
|
+
behavior change, not a pure addition.
|
|
47
|
+
- **Fix**: adversarial review of the above (2026-08-16) found that applying the existing
|
|
48
|
+
sibling-rejection rule (any `code_execution`/`obfuscated_directive` finding on a non-doc sibling
|
|
49
|
+
standalone-quarantines) unchanged to the new extended surface would have quarantined ordinary
|
|
50
|
+
installer scripts — a `scripts/install.sh` using the industry-standard `curl | bash` idiom
|
|
51
|
+
(rustup, Homebrew, nvm, bun) scores the SAME `code_execution:medium` finding as an actual
|
|
52
|
+
backdoor, and the plan's own policy is explicit that a bare `curl | bash` must never
|
|
53
|
+
standalone-quarantine. `mergeSiblingScans`/`isExecutionThreat` now require `critical` severity
|
|
54
|
+
for a `code_execution` finding to drive rejection specifically on an extended-surface sibling
|
|
55
|
+
(reached only via the existing co-signal escalation model, i.e. a real secondary signal like a
|
|
56
|
+
`~/.ssh` read nearby) — the original 7 fixed siblings' rejection rule is completely unchanged.
|
|
57
|
+
`obfuscated_directive` remains rejectable at any severity on both surfaces (delta-gated against a
|
|
58
|
+
real decode step, no legitimate-installer shape). The Deno edge indexer's Trees-API memoization
|
|
59
|
+
and per-run fetch budget, previously documented as "run-scoped" on the (incorrect) assumption
|
|
60
|
+
that each invocation is a fresh process, are now actually reset at the top of every
|
|
61
|
+
`Deno.serve` invocation (`index.ts`) — left unreset, a warm isolate could silently report a stale
|
|
62
|
+
scan as fully covered.
|
|
63
|
+
- **Fix**: `prompt-source.ts`'s `agent-pack` T2 quota-forecast job body still had the stale
|
|
64
|
+
`1,000-call`/`10,000 calls` quota numbers, while the committed `packages/mcp-server` bundled
|
|
65
|
+
SKILL.md output was hand-corrected to `100-call`/`1,000 calls` — generator and committed
|
|
66
|
+
artifact had drifted, which `agent-pack.assets.test.ts`'s byte-identical drift-gate test would
|
|
67
|
+
have failed on merge. Fixed at the actual generator source so the two stay in sync
|
|
68
|
+
(SMI-5893 Wave 11, GH#2368 C-19)
|
|
69
|
+
- **Fix**: `formatUpdateNotification` (`utils/version-check.ts`) now includes `result.updateCommand`
|
|
70
|
+
again — an earlier draft dropped the "how do I get the new npm version" instruction entirely
|
|
71
|
+
in favor of on-disk-artifact-refresh commands, which run against the still-old installed
|
|
72
|
+
binary and never upgrade anything; both instructions are necessary and neither substitutes the
|
|
73
|
+
other. The message also now names the artifact-refresh commands (`setup --force[--client]`,
|
|
74
|
+
`agent install`) needed to pick up hooks/SKILL.md/agent-pack changes, since upgrading the npm
|
|
75
|
+
package alone never rewrites those. New `resolveUpdateNotificationClient()` resolves
|
|
76
|
+
`SKILLSMITH_CLIENT` for this message without ever throwing (the only call site awaits it inside
|
|
77
|
+
a `.then()` with an empty `.catch()`, so an uncaught throw on an invalid env value silently
|
|
78
|
+
dropped the entire notification) and without guessing `'claude-code'` when unset (only Cursor's
|
|
79
|
+
generated config sets this env var; defaulting would point every other client at the wrong
|
|
80
|
+
install path) (SMI-5893 Wave 10, GH#2368 C-06/C-07/C-22)
|
|
81
|
+
- **Fix**: Cursor `hooks.json` installation (`agent-pack-installer.cursor-hooks.ts`) now cleans up
|
|
82
|
+
dead legacy `hooks.SessionStart`/`hooks.SessionEnd` keys a pre-Wave-8a install wrote before this
|
|
83
|
+
file's key-casing was corrected — those never got removed once the correct keys started being
|
|
84
|
+
written, so a re-merge left both the correct entries and the orphaned legacy ones in the same
|
|
85
|
+
file. Skips the cleanup entirely when either wire call reports a top-level-default conflict
|
|
86
|
+
(`ensureTopLevelDefaults`), since the real installer deliberately wrote nothing in that case and
|
|
87
|
+
running cleanup regardless would still silently delete the user's legacy hooks with nothing
|
|
88
|
+
installed to replace them. `hookEntryCommand` (`agent-pack-installer.harness.ts`) and
|
|
89
|
+
`writeBackup` (`agent-config-merge.json-array.ts`) are now exported for reuse by this cleanup
|
|
90
|
+
instead of being duplicated (SMI-5893 Wave 10, GH#2368 C-07)
|
|
91
|
+
- **Fix**: PR #2375 post-merge review follow-up (three findings). `recommend`'s shared footer text no longer claims detection "across all clients" — each surface (CLI, MCP) scans exactly one client per call, never a union. Cursor `hooks.json` installation's `ensureTopLevelDefaults` now fails closed (`status: 'conflict'`, no write) instead of silently preserving an existing incompatible top-level value (e.g. a wrong `version`) while still merging hook entries in (SMI-5893)
|
|
92
|
+
- **Fix**: Restored two verified drift points between the core and edge (production) security
|
|
93
|
+
scanners — the edge co-signal escalation set now includes `sensitive_path` (matching core), and
|
|
94
|
+
the edge `escalateCodeExecution` gained the SMI-5880 locality gate so a co-signal elsewhere in a
|
|
95
|
+
long document can no longer escalate a distant, unrelated `code_execution` finding. Exported
|
|
96
|
+
`AUTHORITY_CLAIMING_AFFIXES` from `typosquat.ts` (previously module-private) for reuse by a
|
|
97
|
+
planned decoy-URL detector (SMI-6033 Wave 1)
|
|
98
|
+
- **Feature**: two new security scanner detectors (SMI-6033 Wave 3). `gatekeeper_bypass`
|
|
99
|
+
(`SecurityScanner.compound.ts`) fires standalone-critical on an `xattr -c` (clear all extended
|
|
100
|
+
attributes) or `xattr -d com.apple.quarantine` command when the target basename correlates with
|
|
101
|
+
a fetch destination elsewhere in the content — uncorrelated usage stays medium; a later fix in
|
|
102
|
+
this wave also adds a trust-tier carve-out (see below). `archive_evasion` (new
|
|
103
|
+
`SecurityScanner.archive.ts`) detects password-protected archive usage via two sub-signals — CLI
|
|
104
|
+
invocation syntax (`unzip -P`, `unrar x -p<pw>`, `7z x -p<pw>`, `zip -P <pw> ... -e`) and prose
|
|
105
|
+
co-occurrence (an archive noun + a password noun within a bounded ±2-line window) — and reaches
|
|
106
|
+
standalone-critical only when the CLI form carries an inline literal (not `$VAR`, not a
|
|
107
|
+
placeholder) password AND the archive's target basename correlates with a fetch destination
|
|
108
|
+
elsewhere in the content; every other shape (out-of-band password, uncorrelated CLI usage, or
|
|
109
|
+
prose-only mention) stays medium/advisory. Both new finding types share the top-tier
|
|
110
|
+
weight/coefficient (2.0/0.40) already used by `code_execution`/`obfuscated_directive` — severity
|
|
111
|
+
alone (not a second weight tier) produces the two-outcome split. Both are wired into
|
|
112
|
+
`SecurityScanner.scan()` and mirrored byte-for-byte into the edge twins
|
|
113
|
+
(`supabase/functions/_shared/` and `scripts/indexer/_shared/`).
|
|
114
|
+
- **Feature**: paste/snippet-host reputation detector (SMI-6033 Wave 3, Gap 4). Two reputation
|
|
115
|
+
tiers (`patterns.ts`): `ANON_PASTE_HOSTS` + `URL_SHORTENER_DOMAINS` require real execution
|
|
116
|
+
evidence (direct pipe to an interpreter, npx direct-exec, or a later chmod/exec/source
|
|
117
|
+
correlation) to reach standalone-critical; `TRANSIENT_TRANSFER_HOSTS` (transfer.sh, file.io,
|
|
118
|
+
tmpfiles.org, temp.sh) is always medium, never critical — a deliberate exception for legitimate
|
|
119
|
+
debugging/incident-response fetches of ephemeral reproducers. `extractUrls` is promoted from a
|
|
120
|
+
private `SecurityScanner.ts` method to a shared `SecurityScanner.urls.ts` export so the existing
|
|
121
|
+
`scanUrls` detector and the new one (`SecurityScanner.paste-host.ts`, finding type
|
|
122
|
+
`paste_host_fetch`) share a single URL-extraction implementation. A paste-host URL that is merely
|
|
123
|
+
linked/mentioned, or fetched-but-not-executed, gets no new finding — it stays covered by the
|
|
124
|
+
existing `scanUrls` `url`:medium finding, unchanged. Shares the same top-tier weight/coefficient
|
|
125
|
+
(2.0/0.40) as `gatekeeper_bypass`/`archive_evasion`. Wired into `SecurityScanner.scan()` and
|
|
126
|
+
mirrored byte-for-byte into the edge twins (`supabase/functions/_shared/` and
|
|
127
|
+
`scripts/indexer/_shared/`).
|
|
128
|
+
- **Feature**: encoded-payload decode-and-recursively-rescan detector (SMI-6033 Wave 3, Gap 2).
|
|
129
|
+
Rather than a heuristic "this looks suspicious" flag, the new detector (`SecurityScanner.encoding.ts`,
|
|
130
|
+
finding type `encoded_payload`) finds a contiguous base64-alphabet run (`[A-Za-z0-9+/]{120,}={0,2}`
|
|
131
|
+
— the character class's deliberate exclusion of `-`/`_` is what keeps base64url-encoded JWTs out,
|
|
132
|
+
not a separate check), skips a candidate immediately preceded by a `data:image/`, `data:font/`, or
|
|
133
|
+
`data:audio/` prefix (benign data-URI blobs) or larger than ~200KB, attempts exactly one base64
|
|
134
|
+
decode, and — only when the result is valid UTF-8 with a plausible-text printable-character ratio —
|
|
135
|
+
recursively invokes the SAME scanner's full detector suite against the decoded text, folding its
|
|
136
|
+
findings into the outer `findings` array. This reuses the entire pattern arsenal instead of
|
|
137
|
+
duplicating it: a decoded `curl|bash` natively trips `code_execution` at its own top-tier severity,
|
|
138
|
+
exactly as if the attacker had shipped it undecoded. Recursion is bounded to depth 1 STRUCTURALLY,
|
|
139
|
+
not by convention — `SecurityScanner.ts`'s new private `runDetectors(content, lineContexts,
|
|
140
|
+
skipEncodedPayload)` method is what both the outer scan and the encoded-payload detector's own
|
|
141
|
+
recursive rescan call, and the rescan callback always passes `skipEncodedPayload: true`, so a base64
|
|
142
|
+
blob discovered inside already-decoded content can never itself be decoded. Two resource bounds cap
|
|
143
|
+
the cost of a single document scan: `MAX_BASE64_CANDIDATES = 8` per document and an aggregate
|
|
144
|
+
`MAX_DECODED_TOTAL_BYTES = 256_000` across all candidates. Each finding folded in from decoded
|
|
145
|
+
content carries a new `decodedFrom` field (`types.ts`) set to the OUTER document line the blob was
|
|
146
|
+
found on — the same provenance-marker role `filePath` already plays for a sibling-file finding. The
|
|
147
|
+
wrapper `encoded_payload` finding itself is deliberately advisory-tier only (weight 1.2 / coefficient
|
|
148
|
+
0.04 — the `sensitive_path`/`typosquat` tier, NOT the 2.0/0.40 tier the other three Wave 3 detectors
|
|
149
|
+
use), since the escalation this gap achieves comes for free from whatever the decoded content's own
|
|
150
|
+
findings already are. Wired into `SecurityScanner.scan()` and mirrored byte-for-byte into the edge
|
|
151
|
+
twins (`supabase/functions/_shared/` and `scripts/indexer/_shared/`).
|
|
152
|
+
- **Fix**: `SecurityScanner.archive.ts` and `SecurityScanner.paste-host.ts` (SMI-6033 Wave 3) each
|
|
153
|
+
had a direct `.match(...)`/`.test(...)` call that bypassed this scanner's established
|
|
154
|
+
`safeRegexTest`/`safeRegexCheck` ReDoS-safe wrappers, flagged by CodeQL as a polynomial regular
|
|
155
|
+
expression on uncontrolled data. Routed all 8 call sites through the wrappers, matching the
|
|
156
|
+
convention already used everywhere else in the scanner, and mirrored the same fix into both edge
|
|
157
|
+
twins (`supabase/functions/_shared/` and `scripts/indexer/_shared/`), adding a local
|
|
158
|
+
`safeRegexCheck` helper alongside the existing local `safeRegexTest` in each Node-port file
|
|
159
|
+
(the edge twins can't share an import across the git-crypt boundary)
|
|
160
|
+
- **Feature**: `decoy_misdirection` URL-misdirection detector (SMI-6033 Wave 4, Gap 6). Catches a
|
|
161
|
+
skill fetching from a domain that doesn't match a vendor brand/authority claim made nearby in
|
|
162
|
+
the skill's own prose (e.g. "the official Anthropic toolkit" fetched from an unrelated domain).
|
|
163
|
+
Reuses `BRAND_ALIASES`/`AUTHORITY_CLAIMING_AFFIXES` from the existing typosquat detector, plus a
|
|
164
|
+
new `BRAND_CANONICAL_DOMAINS` map (`BRAND_ALIASES`' values are GitHub owner slugs, not DNS
|
|
165
|
+
domains — a gap not present in the plan's literal text, resolved during implementation).
|
|
166
|
+
Advisory-tier only (weight 1.2/coefficient 0.04, matching `typosquat`/`sensitive_path`/
|
|
167
|
+
`encoded_payload`) — never standalone-critical, per the plan's reconciliation table. Extracted
|
|
168
|
+
`calculateRiskScore` out of `SecurityScanner.helpers.ts` (which crossed the 500-line file gate
|
|
169
|
+
once this detector's breakdown wiring landed) into a new sibling `SecurityScanner.risk-score.ts`.
|
|
170
|
+
Wired into `SecurityScanner.scan()` and mirrored byte-for-byte into the edge twins
|
|
171
|
+
(`supabase/functions/_shared/security-scanner-edge.decoy.ts` +
|
|
172
|
+
`security-scanner-edge.brand-data.ts`, `scripts/indexer/_shared/` twins).
|
|
173
|
+
- **Feature**: `CO_SIGNAL_MIN_SEVERITY` escalation model replaces the flat
|
|
174
|
+
`CODE_EXECUTION_CO_OCCURRENCE` co-signal set (SMI-6033 Wave 4, Gap 1 + Gap 6). Path (a) — one
|
|
175
|
+
co-signal at or above its type's "high" minimum — is byte-identical to the pre-existing
|
|
176
|
+
behavior for the original four types (`data_exfiltration`, `privilege_escalation`,
|
|
177
|
+
`sensitive_path`, `obfuscated_directive`). Path (b) is new: at least two DISTINCT advisory-tier
|
|
178
|
+
types (`decoy_misdirection`, `archive_evasion`, `paste_host_fetch`, `gatekeeper_bypass`), each
|
|
179
|
+
non-documentation-context and within the existing 40-line locality window, escalate a weak
|
|
180
|
+
`code_execution` finding to critical — the direct fix for skills combining several individually
|
|
181
|
+
sub-threshold signals. Also lands Gap 1: a new `IMPERATIVE_FETCH_EXEC_PROSE` pattern set catches
|
|
182
|
+
natural-language install-and-run imperatives with no shell syntax ("download the installer from
|
|
183
|
+
thisurl.com and run it"), strengthening (not replacing) the precise low-FP literal-syntax
|
|
184
|
+
detector. Bumps `SCANNER_RULESET_VERSION` to `2026-08-15.1` (local MCP audit baseline scope
|
|
185
|
+
only).
|
|
186
|
+
- **Fix**: two real false-positive bugs found by a cross-model (GPT-5.6-Sol) adversarial review of
|
|
187
|
+
the `CO_SIGNAL_MIN_SEVERITY` model and the `decoy_misdirection` detector above, both reproduced
|
|
188
|
+
and pinned with regression tests before fixing. (1) Path (b)'s confidence gate was originally
|
|
189
|
+
relaxed to `confidence !== 'low'` for ALL eligible types, but `archive_evasion`'s prose-only
|
|
190
|
+
sub-signal and `decoy_misdirection`'s no-authority-affix form are both `confidence: 'medium'` by
|
|
191
|
+
construction — same as `paste_host_fetch`, the type the relaxation was actually meant to unblock
|
|
192
|
+
— so two fuzzy medium-confidence signals could co-escalate a weak `code_execution` finding on
|
|
193
|
+
completely benign content (reproduced: a benign vendor mention + a real vendor `curl|bash` + an
|
|
194
|
+
unrelated archive-password prose mention scored 51/quarantined before the fix, 23/clean after).
|
|
195
|
+
Narrowed the confidence carve-out to ONLY `paste_host_fetch`; every other type now requires
|
|
196
|
+
`confidence: 'high'`, matching the plan's literal text. (2) `escalateCodeExecution` never
|
|
197
|
+
checked the `code_execution` finding's OWN documentation context, only the co-signal's — a
|
|
198
|
+
finding inside a fenced security-research example could still be escalated by genuine non-doc
|
|
199
|
+
co-signals elsewhere in the document. (3) Two detector-precision fixes in `decoy_misdirection`
|
|
200
|
+
itself: a URL merely mentioned in prose on the same line as an unrelated fetch-verb usage (e.g.
|
|
201
|
+
`curl --version; see mirror docs at <url>`) was wrongly treated as the fetch target — fixed with
|
|
202
|
+
a strict `isActualFetchTarget` tokenization check; and the authority-affix search scanned the
|
|
203
|
+
entire ±5-line correlation window instead of the brand token's own line, letting an unrelated
|
|
204
|
+
nearby "official"/"authorized" phrase wrongly inflate confidence to `high` — scoped to the brand
|
|
205
|
+
token's own line. All four fixes applied identically to both edge twins.
|
|
206
|
+
|
|
207
|
+
## v0.11.7
|
|
208
|
+
|
|
209
|
+
- **Fix**: Cursor UAT follow-up — website onboarding, CLI/MCP parity, hooks schema (#2375)
|
|
210
|
+
- **Feature**: SMI-5879 Wave 1 -- implement G-5 fixture-corpus corroboration (#2354)
|
|
211
|
+
- **Fix**: Cursor's `hooks.json` is now written in Cursor's actual native schema (`{ version: 1, hooks: { sessionStart: [{ command }] } }`) instead of Claude Code's entry shape (`{ matcher, hooks: [{ type, command }] }`) — the prior shape was silently invalid, and Cursor drops all hooks when the required top-level `version` key is missing. New `install/agent-pack-installer.cursor-hooks.ts` builder, split out from the shared Claude/generic JSON-hooks installer since the two schemas are structurally different, not just differently-keyed (SMI-5893 Wave 8, GH#2368)
|
|
212
|
+
- **Feature**: bundled agent-pack SKILL.md generation (`services/agent-pack/skill-md.ts`) now includes a "CLI Fallback" section, matching the pattern already shipped in `@skillsmith/cli`'s bundled skill, so an agent with a disconnected MCP server has a documented fallback instead of instructing dead tool calls (SMI-5893 Wave 6, GH#2368)
|
|
213
|
+
- **Feature**: new `services/recommend-guard.ts` shared helper (footer-text + dedup-by-`skill.id`) used by both `@skillsmith/cli` and `@skillsmith/mcp-server`'s `recommend` implementations, replacing two independent hardcoded-footer implementations (SMI-5893 Wave 7, GH#2368)
|
|
214
|
+
|
|
7
215
|
## v0.11.6
|
|
8
216
|
|
|
9
217
|
- **Fix**: Harden manifest concurrency (uninstall lock, temp-file races) (#2331)
|
package/README.md
CHANGED
|
@@ -6,13 +6,13 @@ Part of Skillsmith: a lifecycle layer for agent skills across teams.
|
|
|
6
6
|
|
|
7
7
|
## Contents
|
|
8
8
|
|
|
9
|
-
- [What's New](#whats-new-in-
|
|
9
|
+
- [What's New](#whats-new-in-v0120)
|
|
10
10
|
- [Installation](#installation)
|
|
11
11
|
- [Quick Start](#quick-start)
|
|
12
12
|
- [Features](#features)
|
|
13
13
|
- [Exports](#exports)
|
|
14
14
|
|
|
15
|
-
## What's New in v0.
|
|
15
|
+
## What's New in v0.12.0
|
|
16
16
|
|
|
17
17
|
- **Security-status reporting unified**: CLI and MCP now derive security-scan status (pass/fail, risk score, findings count) from one shared `deriveSecuritySummaryFromApiSkill`/`deriveSecuritySummaryFromSkillRow`, instead of two independently-maintained copies that could disagree on the same skill.
|
|
18
18
|
- **`skill_compare` reuses `get_skill`'s resolution**: new shared `resolveSkillApiFirst()` fixes compare only ever hitting the local SQLite cache (no longer kept in sync with the remote-first registry), which made real, searchable skills report "not found."
|