@skillsmith/core 0.12.3 → 0.12.5

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