@skillsmith/core 0.12.3 → 0.12.4

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.
Files changed (188) hide show
  1. package/CHANGELOG.md +164 -0
  2. package/README.md +2 -2
  3. package/dist/.tsbuildinfo +1 -1
  4. package/dist/src/config/owned-lock.acquire.d.ts +8 -0
  5. package/dist/src/config/owned-lock.acquire.d.ts.map +1 -1
  6. package/dist/src/config/owned-lock.acquire.js +19 -4
  7. package/dist/src/config/owned-lock.acquire.js.map +1 -1
  8. package/dist/src/config/owned-lock.claim.d.ts +4 -2
  9. package/dist/src/config/owned-lock.claim.d.ts.map +1 -1
  10. package/dist/src/config/owned-lock.claim.js +42 -8
  11. package/dist/src/config/owned-lock.claim.js.map +1 -1
  12. package/dist/src/config/owned-lock.d.ts.map +1 -1
  13. package/dist/src/config/owned-lock.js +1 -0
  14. package/dist/src/config/owned-lock.js.map +1 -1
  15. package/dist/src/config/owned-lock.test.js +126 -2
  16. package/dist/src/config/owned-lock.test.js.map +1 -1
  17. package/dist/src/config/owned-lock.types.d.ts +9 -0
  18. package/dist/src/config/owned-lock.types.d.ts.map +1 -1
  19. package/dist/src/db/createDatabase.d.ts.map +1 -1
  20. package/dist/src/db/createDatabase.js +0 -2
  21. package/dist/src/db/createDatabase.js.map +1 -1
  22. package/dist/src/exports/services.install.d.ts +1 -0
  23. package/dist/src/exports/services.install.d.ts.map +1 -1
  24. package/dist/src/exports/services.install.js +5 -0
  25. package/dist/src/exports/services.install.js.map +1 -1
  26. package/dist/src/index.d.ts +1 -1
  27. package/dist/src/index.js +1 -1
  28. package/dist/src/install/fan-out.cleanup.d.ts +37 -0
  29. package/dist/src/install/fan-out.cleanup.d.ts.map +1 -0
  30. package/dist/src/install/fan-out.cleanup.js +75 -0
  31. package/dist/src/install/fan-out.cleanup.js.map +1 -0
  32. package/dist/src/install/fan-out.d.ts +41 -31
  33. package/dist/src/install/fan-out.d.ts.map +1 -1
  34. package/dist/src/install/fan-out.js +213 -112
  35. package/dist/src/install/fan-out.js.map +1 -1
  36. package/dist/src/install/fan-out.leftovers.d.ts +60 -0
  37. package/dist/src/install/fan-out.leftovers.d.ts.map +1 -0
  38. package/dist/src/install/fan-out.leftovers.js +251 -0
  39. package/dist/src/install/fan-out.leftovers.js.map +1 -0
  40. package/dist/src/install/fan-out.locks.d.ts +12 -0
  41. package/dist/src/install/fan-out.locks.d.ts.map +1 -0
  42. package/dist/src/install/fan-out.locks.js +114 -0
  43. package/dist/src/install/fan-out.locks.js.map +1 -0
  44. package/dist/src/install/fan-out.manifest.d.ts +64 -0
  45. package/dist/src/install/fan-out.manifest.d.ts.map +1 -0
  46. package/dist/src/install/fan-out.manifest.js +130 -0
  47. package/dist/src/install/fan-out.manifest.js.map +1 -0
  48. package/dist/src/install/fan-out.overwrite.d.ts +51 -0
  49. package/dist/src/install/fan-out.overwrite.d.ts.map +1 -0
  50. package/dist/src/install/fan-out.overwrite.js +343 -0
  51. package/dist/src/install/fan-out.overwrite.js.map +1 -0
  52. package/dist/src/install/remove-if-same.d.ts +58 -0
  53. package/dist/src/install/remove-if-same.d.ts.map +1 -0
  54. package/dist/src/install/remove-if-same.js +222 -0
  55. package/dist/src/install/remove-if-same.js.map +1 -0
  56. package/dist/src/provenance/backfill.d.ts.map +1 -1
  57. package/dist/src/provenance/backfill.js +15 -2
  58. package/dist/src/provenance/backfill.js.map +1 -1
  59. package/dist/src/security/scanner/SecurityScanner.scanners.d.ts.map +1 -1
  60. package/dist/src/security/scanner/SecurityScanner.scanners.js +8 -1
  61. package/dist/src/security/scanner/SecurityScanner.scanners.js.map +1 -1
  62. package/dist/src/security/scanner/SecurityScanner.value-gate.d.ts +22 -2
  63. package/dist/src/security/scanner/SecurityScanner.value-gate.d.ts.map +1 -1
  64. package/dist/src/security/scanner/SecurityScanner.value-gate.js +143 -6
  65. package/dist/src/security/scanner/SecurityScanner.value-gate.js.map +1 -1
  66. package/dist/src/security/scanner/SecurityScanner.weak-passwords.d.ts +2 -2
  67. package/dist/src/security/scanner/SecurityScanner.weak-passwords.d.ts.map +1 -1
  68. package/dist/src/security/scanner/SecurityScanner.weak-passwords.js +185 -190
  69. package/dist/src/security/scanner/SecurityScanner.weak-passwords.js.map +1 -1
  70. package/dist/src/security/scanner/patterns.d.ts +47 -2
  71. package/dist/src/security/scanner/patterns.d.ts.map +1 -1
  72. package/dist/src/security/scanner/patterns.js +48 -3
  73. package/dist/src/security/scanner/patterns.js.map +1 -1
  74. package/dist/src/security/scanner/patterns.sensitive-path.d.ts +31 -3
  75. package/dist/src/security/scanner/patterns.sensitive-path.d.ts.map +1 -1
  76. package/dist/src/security/scanner/patterns.sensitive-path.js +59 -4
  77. package/dist/src/security/scanner/patterns.sensitive-path.js.map +1 -1
  78. package/dist/src/services/agent-pack/prompt-source.d.ts.map +1 -1
  79. package/dist/src/services/agent-pack/prompt-source.js +3 -2
  80. package/dist/src/services/agent-pack/prompt-source.js.map +1 -1
  81. package/dist/src/services/skill-installation.content.d.ts +7 -2
  82. package/dist/src/services/skill-installation.content.d.ts.map +1 -1
  83. package/dist/src/services/skill-installation.content.js +75 -28
  84. package/dist/src/services/skill-installation.content.js.map +1 -1
  85. package/dist/src/services/skill-installation.helpers.d.ts.map +1 -1
  86. package/dist/src/services/skill-installation.helpers.js +8 -0
  87. package/dist/src/services/skill-installation.helpers.js.map +1 -1
  88. package/dist/src/services/skill-installation.io.d.ts +1 -29
  89. package/dist/src/services/skill-installation.io.d.ts.map +1 -1
  90. package/dist/src/services/skill-installation.io.dirs.d.ts +15 -0
  91. package/dist/src/services/skill-installation.io.dirs.d.ts.map +1 -0
  92. package/dist/src/services/skill-installation.io.dirs.js +84 -0
  93. package/dist/src/services/skill-installation.io.dirs.js.map +1 -0
  94. package/dist/src/services/skill-installation.io.js +6 -176
  95. package/dist/src/services/skill-installation.io.js.map +1 -1
  96. package/dist/src/services/skill-installation.io.rollback.d.ts +138 -0
  97. package/dist/src/services/skill-installation.io.rollback.d.ts.map +1 -0
  98. package/dist/src/services/skill-installation.io.rollback.js +218 -0
  99. package/dist/src/services/skill-installation.io.rollback.js.map +1 -0
  100. package/dist/src/services/skill-installation.io.write.d.ts +69 -0
  101. package/dist/src/services/skill-installation.io.write.d.ts.map +1 -0
  102. package/dist/src/services/skill-installation.io.write.js +417 -0
  103. package/dist/src/services/skill-installation.io.write.js.map +1 -0
  104. package/dist/src/services/skill-installation.service.d.ts.map +1 -1
  105. package/dist/src/services/skill-installation.service.finalize.d.ts +62 -0
  106. package/dist/src/services/skill-installation.service.finalize.d.ts.map +1 -0
  107. package/dist/src/services/skill-installation.service.finalize.js +136 -0
  108. package/dist/src/services/skill-installation.service.finalize.js.map +1 -0
  109. package/dist/src/services/skill-installation.service.js +66 -80
  110. package/dist/src/services/skill-installation.service.js.map +1 -1
  111. package/dist/src/services/skill-installation.target-guard.d.ts +82 -0
  112. package/dist/src/services/skill-installation.target-guard.d.ts.map +1 -0
  113. package/dist/src/services/skill-installation.target-guard.js +410 -0
  114. package/dist/src/services/skill-installation.target-guard.js.map +1 -0
  115. package/dist/src/services/skill-installation.types.d.ts +13 -1
  116. package/dist/src/services/skill-installation.types.d.ts.map +1 -1
  117. package/dist/src/services/skill-installation.types.js.map +1 -1
  118. package/dist/src/services/skill-installation.uninstall.d.ts +3 -1
  119. package/dist/src/services/skill-installation.uninstall.d.ts.map +1 -1
  120. package/dist/src/services/skill-installation.uninstall.helpers.d.ts +59 -0
  121. package/dist/src/services/skill-installation.uninstall.helpers.d.ts.map +1 -0
  122. package/dist/src/services/skill-installation.uninstall.helpers.js +124 -0
  123. package/dist/src/services/skill-installation.uninstall.helpers.js.map +1 -0
  124. package/dist/src/services/skill-installation.uninstall.js +148 -25
  125. package/dist/src/services/skill-installation.uninstall.js.map +1 -1
  126. package/dist/src/utils/safe-fs.d.ts +69 -0
  127. package/dist/src/utils/safe-fs.d.ts.map +1 -1
  128. package/dist/src/utils/safe-fs.js +113 -2
  129. package/dist/src/utils/safe-fs.js.map +1 -1
  130. package/dist/tests/install/fan-out.test.js +1951 -13
  131. package/dist/tests/install/fan-out.test.js.map +1 -1
  132. package/dist/tests/install/remove-if-same.test.d.ts +2 -0
  133. package/dist/tests/install/remove-if-same.test.d.ts.map +1 -0
  134. package/dist/tests/install/remove-if-same.test.js +298 -0
  135. package/dist/tests/install/remove-if-same.test.js.map +1 -0
  136. package/dist/tests/integration/fan-out-lock-contention.test.d.ts +11 -0
  137. package/dist/tests/integration/fan-out-lock-contention.test.d.ts.map +1 -0
  138. package/dist/tests/integration/fan-out-lock-contention.test.js +53 -0
  139. package/dist/tests/integration/fan-out-lock-contention.test.js.map +1 -0
  140. package/dist/tests/provenance/backfill.test.js +43 -0
  141. package/dist/tests/provenance/backfill.test.js.map +1 -1
  142. package/dist/tests/security/scanner-regression-guard.test.js +33 -5
  143. package/dist/tests/security/scanner-regression-guard.test.js.map +1 -1
  144. package/dist/tests/security/sensitive-path-adversarial-review.test.js +120 -0
  145. package/dist/tests/security/sensitive-path-adversarial-review.test.js.map +1 -1
  146. package/dist/tests/security/sensitive-path-boolean-flag.test.d.ts +2 -0
  147. package/dist/tests/security/sensitive-path-boolean-flag.test.d.ts.map +1 -0
  148. package/dist/tests/security/sensitive-path-boolean-flag.test.js +151 -0
  149. package/dist/tests/security/sensitive-path-boolean-flag.test.js.map +1 -0
  150. package/dist/tests/security/sensitive-path-fp.test.js +71 -5
  151. package/dist/tests/security/sensitive-path-fp.test.js.map +1 -1
  152. package/dist/tests/security/sensitive-path-prefixed-secrets.test.d.ts +2 -0
  153. package/dist/tests/security/sensitive-path-prefixed-secrets.test.d.ts.map +1 -0
  154. package/dist/tests/security/sensitive-path-prefixed-secrets.test.js +176 -0
  155. package/dist/tests/security/sensitive-path-prefixed-secrets.test.js.map +1 -0
  156. package/dist/tests/security/weak-password-lexicon.test.js +14 -4
  157. package/dist/tests/security/weak-password-lexicon.test.js.map +1 -1
  158. package/dist/tests/unit/services/skill-installation.content.test.js +23 -0
  159. package/dist/tests/unit/services/skill-installation.content.test.js.map +1 -1
  160. package/dist/tests/unit/services/skill-installation.io.client-agent-path.test.js +35 -14
  161. package/dist/tests/unit/services/skill-installation.io.client-agent-path.test.js.map +1 -1
  162. package/dist/tests/unit/services/skill-installation.io.rollback.test.d.ts +2 -0
  163. package/dist/tests/unit/services/skill-installation.io.rollback.test.d.ts.map +1 -0
  164. package/dist/tests/unit/services/skill-installation.io.rollback.test.js +984 -0
  165. package/dist/tests/unit/services/skill-installation.io.rollback.test.js.map +1 -0
  166. package/dist/tests/unit/services/skill-installation.io.rollback.unit.test.d.ts +2 -0
  167. package/dist/tests/unit/services/skill-installation.io.rollback.unit.test.d.ts.map +1 -0
  168. package/dist/tests/unit/services/skill-installation.io.rollback.unit.test.js +148 -0
  169. package/dist/tests/unit/services/skill-installation.io.rollback.unit.test.js.map +1 -0
  170. package/dist/tests/unit/services/skill-installation.service.error-codes.test.js +19 -0
  171. package/dist/tests/unit/services/skill-installation.service.error-codes.test.js.map +1 -1
  172. package/dist/tests/unit/services/skill-installation.service.finalize.test.d.ts +2 -0
  173. package/dist/tests/unit/services/skill-installation.service.finalize.test.d.ts.map +1 -0
  174. package/dist/tests/unit/services/skill-installation.service.finalize.test.js +147 -0
  175. package/dist/tests/unit/services/skill-installation.service.finalize.test.js.map +1 -0
  176. package/dist/tests/unit/services/skill-installation.service.test.js +43 -0
  177. package/dist/tests/unit/services/skill-installation.service.test.js.map +1 -1
  178. package/dist/tests/unit/services/skill-installation.target-guard.test.d.ts +2 -0
  179. package/dist/tests/unit/services/skill-installation.target-guard.test.d.ts.map +1 -0
  180. package/dist/tests/unit/services/skill-installation.target-guard.test.js +590 -0
  181. package/dist/tests/unit/services/skill-installation.target-guard.test.js.map +1 -0
  182. package/dist/tests/unit/services/skill-installation.uninstall.guard.test.d.ts +2 -0
  183. package/dist/tests/unit/services/skill-installation.uninstall.guard.test.d.ts.map +1 -0
  184. package/dist/tests/unit/services/skill-installation.uninstall.guard.test.js +473 -0
  185. package/dist/tests/unit/services/skill-installation.uninstall.guard.test.js.map +1 -0
  186. package/dist/tests/utils/safe-fs.test.js +129 -2
  187. package/dist/tests/utils/safe-fs.test.js.map +1 -1
  188. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -4,6 +4,170 @@ All notable changes to `@skillsmith/core` are documented here.
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## v0.12.4
8
+
9
+ - **Fix**: SMI-6507 + SMI-6496 -- remediation strings that actually work (#2803)
10
+ - **Fix**: SMI-6508 -- move MF-5 last; it was suppressing HIGH findings (#2808)
11
+ - **Fix**: SMI-6508 — detect prefixed secrets assignments at MEDIUM (MF-5) (#2806)
12
+ - **Fix**: SMI-6530 -- stop recommending bulk `skillsmith update` until the safety gate ships (#2801)
13
+ - **Fix**: SMI-6505 -- stop scoring an embedded key assigned a boolean as a credential (#2793)
14
+ - **Feature**: SMI-6441 -- MF-4b common-password veto (Wave 2) (#2786)
15
+ - **Fix (data loss)**: install and update no longer destroy a skill directory that already
16
+ existed. A failed write restores every overwritten file to its original bytes and removes only
17
+ files and directories the install created; a directory that existed is never deleted (it was
18
+ removed recursively, `.git` included). A new pre-write check, `checkInstallTarget`, refuses to
19
+ write into a git working tree (or a directory inside one, symlinks resolved), a directory
20
+ Skillsmith didn't install (no matching manifest entry, or a row marked local or adopted), and a
21
+ target that differs from the directory `update` compared (`expectedInstallPath`); `force` does
22
+ not override these. A restore that itself fails now raises `InstallRestoreError` naming the
23
+ unrestored files instead of a generic internal error. Private-registry content keys can no
24
+ longer create a `.git` path, and `--also-link --force` replaces a symlink or a fan-out copy
25
+ Skillsmith itself recorded (the new copy is written to a hidden staging folder and swapped into
26
+ place under a per-destination lock, so a failed or concurrent refresh never loses the existing
27
+ copy; the new copy is published by claiming its name with a primitive that refuses to replace —
28
+ `mkdir` for a directory, `symlink` for a link — and the copy it replaces is moved aside only
29
+ while it is still the one that was checked; a published link is recorded only while it is still
30
+ the link this call wrote; an empty destination is refused with an explanation of what it probably is, on the plain and the `--force` path alike, and a hidden folder an interrupted refresh left behind is described without claiming Skillsmith owns it) but still refuses a real directory Skillsmith never created, or a recorded copy that has
31
+ since grown a `.git` directory; uninstall's own cleanup applies the same `.git` refusal to a
32
+ recorded copy instead of deleting it. A copy an interrupted refresh left behind is reported as
33
+ a warning, and is never restored over a skill uninstalled since. The fan-out link manifest is
34
+ changed under its own lock (concurrent fan-outs of different skills lost records and could
35
+ corrupt it), and a corrupt one is moved aside with a warning rather than replaced by an empty
36
+ one that dropped every other skill's record; a manifest written by a newer version is left
37
+ untouched. An uninstall racing a re-link or a refresh leaves the records matching what is on
38
+ disk, and an uninstall that can't read the manifest says so. The per-target write queue now
39
+ classifies and snapshots every write independently (not just the first for a given path), so two
40
+ differently-cased files on a case-sensitive filesystem restore correctly, a short write is
41
+ retried until complete or reported as a restore failure, and a 0-byte file orphaned by a failed
42
+ create is still cleaned up. Rollback and fan-out cleanup never recursively delete a folder that
43
+ something else put at its path after Skillsmith created it, and a cleanup step that fails is
44
+ reported rather than silently ignored. A crashed refresh's staging folder is reported, never
45
+ deleted, and an uninstall re-checks a fan-out copy just before removing it. Each of these
46
+ deletes now checks the entry, moves it to a hidden name and checks it again there before
47
+ removing it, so a folder another program swaps in at that moment is never the one deleted.
48
+ Nothing is ever renamed back over whatever has taken a path — a rename replaces an empty
49
+ directory, a file or a symlink — so anything a call moved aside is reported with its exact path
50
+ instead. A regular file is the one exception: it goes back atomically, since `link`
51
+ fails rather than replacing. What a failed removal leaves behind is reported by the next
52
+ uninstall of that skill, as well as next to a fan-out destination, and a refresh now says why it
53
+ kept the copy it replaced, removes only the symlink it checked when replacing one, and puts a
54
+ copy back only while that path is still free. Uninstall refuses a skill folder that is a git working tree (`.git` at its root), even
55
+ with force and before adopting an untracked one; it removes only the folder it checked, and
56
+ keeps the manifest entry when it removes nothing. It also drops a skill's record only while every
57
+ field of that record still matches the one it removed, so an install claiming the same name
58
+ meanwhile keeps its own record — at the same path, or written in the same millisecond. A manifest
59
+ write that fails after the folder is gone now says so, and what to do about it, instead of
60
+ surfacing as a bare lock error, and a progress listener that throws can no longer stop an
61
+ uninstall from reporting what it removed and what it left behind. A warning about something left
62
+ behind no longer claims Skillsmith owns it: in a race it can be an entry another program put at
63
+ that path. Backfill never modifies a
64
+ `provenance: 'local'` row (SMI-6529, ADR-155).
65
+
66
+ - **Docs**: recorded the two missing `SCANNER_RULESET_VERSION` history entries for
67
+ `2026-09-11.1` and `2026-09-11.2`. Both bumps shipped correctly — the `comparable` gate does
68
+ re-scan — but the constant had moved twice past the end of its own documented history, so the
69
+ *direction* and the consequence-if-omitted were unrecorded for both. `.1` is
70
+ previously-clean-now-flagged (MF-5 delivers new detection). `.2` is the same direction for a
71
+ sharper reason: it invalidates verdicts `.1` computed wrongly under the array-position
72
+ suppression, so omitting it would have left the evasion alive in stored data even after the code
73
+ fix. Raised by another session (SMI-6554) after a downstream stale-dist failure. (SMI-6508)
74
+ - **Fix (security regression, same-day)**: the MF-5 prefixed-secrets entry added below was
75
+ positioned at index 4 of `SENSITIVE_PATH_PATTERNS`, and `scanSensitivePaths` `break`s on the
76
+ **first** entry that matches, in array order. An always-MEDIUM entry ahead of a HIGH-capable one
77
+ therefore **suppressed** it: 11 of the 16 patterns sat after MF-5, so any line where a
78
+ prefixed-`secrets` token co-occurred with one of them reported MEDIUM instead of that entry's
79
+ HIGH, and `passed` flipped from `false` to `true` — the install block disappeared. Appending the
80
+ 12-character comment `# a_secrets:` was sufficient to turn `cat ~/.ssh/id_rsa` and
81
+ `curl -F f=@/etc/passwd …` from blocking to passing, making this an attacker-controlled
82
+ suppression token rather than a theoretical ordering nit. **Fixed by moving the entry to LAST**,
83
+ after every HIGH-capable pattern. Realized blast radius was zero — of 636 skills carrying a
84
+ stored HIGH `sensitive_path` finding, none had a `location` matching the prefixed form — so no
85
+ stored verdict was wrongly cleared; the exposure was latent and adversarial. `SCANNER_RULESET_VERSION`
86
+ re-bumps to `2026-09-11.2` so verdicts stored under `.1` are not reused. A new
87
+ **ordering invariant** in `scanner-regression-guard.test.ts` now asserts that no always-MEDIUM
88
+ pattern precedes any HIGH-capable one, which generalises to the next such class; the eight
89
+ suppression cases are pinned in both the core and core↔edge suites. Caught by the post-merge
90
+ governance retro — a cross-family pre-merge gate, 3,175 passing tests and a 9-case manual
91
+ verification were all green over it, because every ordering test compared MF-5 only against the
92
+ one entry that precedes it. (SMI-6508)
93
+ - **Fix**: `sensitive_path` now detects a secret assigned to a **prefixed** key —
94
+ `API_SECRETS`, `app_secrets`, `mySecrets`, and the singular `API_SECRET`. `SECRETS_ASSIGN_PATTERN`
95
+ carries `\b`, and `_` is a word character, so that boundary could never match after an underscore
96
+ or a camelCase hump; SCREAMING_SNAKE and snake_case are the dominant conventions for
97
+ secret-bearing environment variables, so this missed the most likely real shape. The sibling
98
+ `credentials` and `password` patterns carry no boundary and were never affected. Fixed by a
99
+ **complementary** pattern matching exactly what the boundary excludes, rather than by removing it
100
+ — the two never match the same occurrence, and `MY-SECRETS=` / `my.secrets=` stay with the bare
101
+ pattern since `-` and `.` are non-word characters its `\b` already accepts.
102
+ - **Added**: a fifth `sensitive_path` severity class, **MF-5 (`OBSERVE_ONLY_MEDIUM_PATTERNS`)** —
103
+ always MEDIUM, never value-gated and never escalated. The prefixed form is classified here rather
104
+ than into MF-4 because MF-4 is HIGH by default, and a HIGH `sensitive_path` makes
105
+ `SecurityScanner` compute `passed = false`, which blocks installation with no allowlist in that
106
+ path. Measured against 66,495 real skill bodies in production: routing the prefixed form through
107
+ MF-4 would newly block 132 skills (0.20% of that corpus, ~975 extrapolated to the full registry),
108
+ and shape analysis put roughly 46% of those in false-positive-looking shapes. Shipping at MEDIUM
109
+ makes the detection visible at zero install cost and turns the open question into one the
110
+ accumulated findings can answer; promoting it later is a one-line move into the MF-4 set. The
111
+ severity-gate partition grows 4 classes → 5 and 15 patterns → 16, both guarded by the existing
112
+ regression test's totality check. **Deliberate asymmetry**: prefixed `password` / `credentials`
113
+ keys still reach HIGH, grandfathered rather than endorsed — their prefixed-form false-positive
114
+ rate has never been measured, and levelling in either direction without measuring would be the
115
+ wrong fix. `SCANNER_RULESET_VERSION` bumps to `2026-09-11.1` — *previously-clean-now-fires*, the
116
+ opposite direction from SMI-6505's bump and load-bearing for the same reason: without it the
117
+ `comparable` gate reuses the stored verdict and the new finding never reaches an already-scanned
118
+ skill. (SMI-6508)
119
+ - **Fix**: `createDatabaseSync`/`createDatabaseAsync`'s native-module error messages no longer
120
+ recommend `docker compose --profile dev up -d`. `@skillsmith/core` ships under Elastic License
121
+ 2.0 to external npm consumers (`@skillsmith/cli`, both MCP servers) who have no worktree tooling
122
+ and no `skillsmith-dev-1` container, so the Docker line was actively misleading for most of its
123
+ readers. The two remaining solutions (`npm rebuild better-sqlite3`, and `createDatabaseAsync()`'s
124
+ automatic WASM fallback) are correct in any environment. (SMI-6507)
125
+
126
+ - **Changed**: the agent pack's CLI fallback commands (`CLI_FALLBACK_COMMANDS` in
127
+ `services/agent-pack/prompt-source.ts`) now lead with `skillsmith update --all --dry-run` and
128
+ then per-skill updates, instead of recommending `skillsmith update --all` directly. Containment
129
+ for SMI-6528: `update --all` in CLI 0.8.8-0.8.10 can overwrite local edits in skill directories
130
+ that are git clones and can write into the wrong directory (SMI-6530).
131
+
132
+ - **Fix**: `sensitive_path` MF-4 no longer scores an **embedded** assignment key assigned a bare
133
+ boolean as a real credential. `allow_credentials=True` — the standard FastAPI/Starlette CORS
134
+ middleware flag — was scoring HIGH, which makes `SecurityScanner` compute `passed = false`, which
135
+ makes the install service reject the install. With no allowlist anywhere in the
136
+ `skill-installation.*` family, that made **any skill documenting FastAPI CORS setup uninstallable**
137
+ at a risk score of 1/100. The discriminator is the key, not the value: `credentials` matched inside
138
+ `allow_credentials` only because `CREDENTIALS_ASSIGN_PATTERN` carries no left boundary, so the fix
139
+ keys on the keyword being a *suffix of a longer identifier*. Bare `credentials:` / `secrets:` /
140
+ `password:` keys are untouched, and `AWS_CREDENTIALS=hunter2` still scores HIGH — deliberately
141
+ **not** fixed by adding `\b` to the pattern, which would have traded this false positive for that
142
+ false negative (tracked separately as SMI-6508, which documents the same missed-detection class
143
+ already live for `secrets`). `SCANNER_RULESET_VERSION` bumps to `2026-09-10.1` —
144
+ *previously-flagged-now-clean*, the same direction as SMI-5207's bump and the opposite of
145
+ SMI-6441's, and load-bearing for the same reason: without it the `comparable` gate keeps reusing
146
+ the stored pre-fix verdict and an already-scanned skill stays blocked. Two formatting variants are
147
+ accepted residuals and stay HIGH — a single-line multi-argument call, and a trailing inline comment
148
+ — because the relaxations that would fix them each leave part of the value span unexamined, which
149
+ measurably lets a real credential hide behind a boolean (both bypass shapes are pinned as
150
+ must-stay-HIGH tests). Adds a core↔edge behavioural parity test, which did not previously exist:
151
+ the existing twin guard only asserts the two `_shared` copies are byte-identical to each other, not
152
+ that they agree with `@skillsmith/core`.
153
+ - **Fix**: `sensitive_path` MF-4 no longer reads a two-word all-lowercase value as a harmless
154
+ documentation label when **every** one of its words is a known common password — `password: monkey
155
+ dragon` now scores HIGH, while `credentials: rotation policy` and ordinary documentation labels are
156
+ untouched. Closes SMI-5207's residual R-2 for the two-common-password case only; a value pairing
157
+ one common password with an ordinary word (`password: horse staple`) deliberately stays MEDIUM,
158
+ because it is not distinguishable from a documentation label at a false-positive rate this gate can
159
+ afford. This is the first `sensitive_path` change that can RAISE severity, so SMI-5207's
160
+ monotonic-non-increase safety argument no longer applies — see
161
+ [ADR-149](../../docs/internal/adr/149-generated-scanner-data-veto-severity-model.md) for the
162
+ severity-raising exception and its § *Revision, 2026-09-09* for why the predicate is `every` and
163
+ not `some` (55% of the emitted lexicon is ordinary English dictionary words, so a `some` predicate
164
+ reopens the documentation false-positive class unboundedly). `SCANNER_RULESET_VERSION` bumps to
165
+ `2026-09-09.1` — *previously-clean-now-flagged*, the opposite direction from SMI-5207's bump, so
166
+ without it an already-scanned skill keeps its stored clean verdict and never sees the tightened
167
+ rule. `assignmentHasRealValue()` gains an optional `{ weakPasswordVeto }` parameter (default on) —
168
+ a pure per-call parameter used only by the blast-radius verification harness, never module state
169
+ (SMI-6441 Wave 2)
170
+
7
171
  ## v0.12.3
8
172
 
9
173
  - **Add**: `SecurityScanner.weak-passwords.ts` — a generated, versioned list of common weak passwords (vendored from SecLists, hash-pinned, capped to the top 5,000 by frequency rank), built by the new `scripts/gen-weak-password-lexicon.mjs` generator and mirrored byte-identically into the Node and Deno/Supabase edge scanner twins. This wave ships the data pipeline only — no scanner behavior changes; the `sensitive_path` detection change that consumes this data is a separate, follow-on change (SMI-6441 Wave 1)
package/README.md CHANGED
@@ -6,13 +6,13 @@ Part of Skillsmith: a registry for sharing, scanning, and tracking agent skills
6
6
 
7
7
  ## Contents
8
8
 
9
- - [What's New](#whats-new-in-v0123)
9
+ - [What's New](#whats-new-in-v0124)
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.12.3
15
+ ## What's New in v0.12.4
16
16
 
17
17
  - **New `resolveSessionTier` client** (`sync/license-status-client.ts`): authenticates a stored `skillsmith login` session against `/license-status` so the MCP server can resolve a real subscription tier without a separately-configured `SKILLSMITH_API_KEY`, instead of silently falling back to `community`.
18
18
  - **Scanner: bundled-file scan expanded to operational code** (Gap 8 of the ClawHavoc remediation): the indexer now reads `scripts/`, `src/`, and `bin/` alongside `SKILL.md`, closing a blind spot where a backdoor buried mid-function in working operational code was structurally invisible.