@codyswann/lisa 3.46.0 → 3.46.2

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 (66) hide show
  1. package/all/copy-overwrite/scripts/lisa-gates.mjs +74 -3
  2. package/cdk/copy-overwrite/knip.json +1 -0
  3. package/dist/core/lisa-owned-hash-ledger.d.ts.map +1 -1
  4. package/dist/core/lisa-owned-hash-ledger.js +2 -0
  5. package/dist/core/lisa-owned-hash-ledger.js.map +1 -1
  6. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  7. package/dist/core/upstream-evidence-manifest.js +13 -9
  8. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  9. package/expo/copy-overwrite/eslint.config.ts +18 -13
  10. package/expo/copy-overwrite/knip.json +9 -1
  11. package/harper-fabric/copy-overwrite/knip.json +1 -1
  12. package/nestjs/copy-overwrite/knip.json +1 -0
  13. package/package.json +7 -3
  14. package/phaser/copy-overwrite/knip.json +1 -1
  15. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  16. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  17. package/plugins/lisa-agy/plugin.json +1 -1
  18. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  19. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  20. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  21. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  22. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  23. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  24. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  25. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  26. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  27. package/plugins/lisa-expo-agy/plugin.json +1 -1
  28. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  29. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  30. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  31. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  32. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  33. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  34. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  35. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  36. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  37. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  38. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  39. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  40. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  41. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  42. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  43. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  44. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  45. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  46. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  47. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  48. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  49. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  50. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  51. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  52. package/plugins/lisa-rails-agy/plugin.json +1 -1
  53. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  54. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  55. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  56. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  57. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  58. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  59. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  60. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  61. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  62. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  63. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  64. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  65. package/scripts/check-security-floors.mjs +110 -13
  66. package/typescript/copy-overwrite/knip.json +1 -0
@@ -23,6 +23,7 @@
23
23
  * @module scripts/check-security-floors
24
24
  */
25
25
 
26
+ import { execFileSync } from "node:child_process";
26
27
  import { readFileSync } from "node:fs";
27
28
  import { globSync } from "node:fs";
28
29
 
@@ -72,19 +73,80 @@ export function resolveSelfReference(manifest, name) {
72
73
  return null;
73
74
  }
74
75
 
76
+ /**
77
+ * Where the governance manifests live.
78
+ *
79
+ * The root entry is listed separately because the per-stack pattern is one
80
+ * level deep and never matched it. That miss cost nine floors — the root
81
+ * manifest is the one whose force/defaults/merge sections decide what every
82
+ * project's package.json becomes — and the audit reported clean for all of
83
+ * them, because a floor nobody looked at is indistinguishable in the output
84
+ * from a floor that passed.
85
+ */
86
+ const MANIFEST_PATTERNS = Object.freeze([
87
+ "package.lisa.json",
88
+ "*/package-lisa/package.lisa.json",
89
+ ]);
90
+
91
+ /** Paths that are copies of a manifest rather than a manifest. */
92
+ const NOT_A_MANIFEST = [
93
+ "node_modules",
94
+ ".worktrees",
95
+ "dist/",
96
+ "tests/fixtures",
97
+ ];
98
+
99
+ /**
100
+ * Every manifest git tracks, so the glob can be checked against reality.
101
+ *
102
+ * Returns null when the question cannot be asked — outside a checkout, or with
103
+ * no git. A null is reported as "not reconciled", never folded into "nothing
104
+ * missing": the whole defect being fixed here is a scan that narrowed silently.
105
+ * @returns {string[]|null} Tracked manifest paths, or null when unknowable.
106
+ */
107
+ function trackedManifests() {
108
+ try {
109
+ return execFileSync(
110
+ "/usr/bin/git",
111
+ ["ls-files", "-z", "*package.lisa.json"],
112
+ {
113
+ encoding: "utf8",
114
+ maxBuffer: 8 * 1024 * 1024,
115
+ stdio: ["ignore", "pipe", "ignore"],
116
+ }
117
+ )
118
+ .split("\0")
119
+ .filter(Boolean)
120
+ .filter(
121
+ file => !NOT_A_MANIFEST.some(fragment => file.includes(fragment))
122
+ );
123
+ } catch {
124
+ return null;
125
+ }
126
+ }
127
+
75
128
  /**
76
129
  * Every version constraint declared across the template manifests.
77
130
  * @returns {{found: Map<string, Array<{file: string, path: string, spec: string}>>,
78
- * unresolved: Array<{file: string, path: string, name: string, spec: string}>}}
79
- * Constraints by package name, plus self-references pointing at nothing.
131
+ * unresolved: Array<{file: string, path: string, name: string, spec: string}>,
132
+ * scanned: string[], unscanned: string[]|null}}
133
+ * Constraints by package name, self-references pointing at nothing, the
134
+ * manifests read, and any tracked manifest the patterns did not reach.
80
135
  */
81
- function collectFloors() {
136
+ export function collectFloors() {
82
137
  const found = new Map();
83
138
  /** `$name` references pointing at nothing this manifest declares. */
84
139
  const unresolved = [];
85
- const files = globSync("*/package-lisa/package.lisa.json").filter(
86
- file => !file.includes("node_modules") && !file.includes(".worktrees")
140
+ const files = globSync(MANIFEST_PATTERNS).filter(
141
+ file => !NOT_A_MANIFEST.some(fragment => file.includes(fragment))
87
142
  );
143
+ // What the patterns reach, against what the repository actually carries. A
144
+ // glob is exactly the kind of thing that narrows by one level and keeps
145
+ // reporting a clean sheet for the files it stopped opening.
146
+ const tracked = trackedManifests();
147
+ const scanned = new Set(files);
148
+ const unscanned =
149
+ tracked === null ? null : tracked.filter(file => !scanned.has(file));
88
150
  for (const file of files) {
89
151
  let manifest;
90
152
  try {
@@ -137,7 +199,7 @@ function collectFloors() {
137
199
  }
138
200
  }
139
201
  }
140
- return { found, unresolved };
202
+ return { found, unresolved, scanned: files, unscanned };
141
203
  }
142
204
 
143
205
  /**
@@ -246,10 +308,11 @@ async function advisoriesFor(name) {
246
308
 
247
309
  /**
248
310
  * Audit every collected floor.
249
- * @returns {Promise<{problems: Array, unreachable: Array, unresolved: Array, checked: number}>} Findings.
311
+ * @returns {Promise<{problems: Array, unreachable: Array, unresolved: Array,
312
+ * unscanned: string[]|null, manifests: number, checked: number}>} Findings.
250
313
  */
251
314
  async function audit() {
252
- const { found: floors, unresolved } = collectFloors();
315
+ const { found: floors, unresolved, scanned, unscanned } = collectFloors();
253
316
  const problems = [];
254
317
  const unreachable = [];
255
318
  for (const [name, sites] of floors) {
@@ -281,21 +344,33 @@ async function audit() {
281
344
  }
282
345
  }
283
346
  }
284
- return { problems, unreachable, unresolved, checked: floors.size };
347
+ return {
348
+ problems,
349
+ unreachable,
350
+ unresolved,
351
+ unscanned,
352
+ manifests: scanned.length,
353
+ checked: floors.size,
354
+ };
285
355
  }
286
356
 
287
357
  async function main() {
288
358
  const strict = process.argv.includes("--strict");
289
359
  const asJson = process.argv.includes("--json");
290
- const { problems, unreachable, unresolved, checked } = await audit();
360
+ const { problems, unreachable, unresolved, unscanned, manifests, checked } =
361
+ await audit();
291
362
 
292
363
  if (asJson) {
293
364
  console.log(
294
- JSON.stringify({ problems, unreachable, unresolved, checked }, null, 2)
365
+ JSON.stringify(
366
+ { problems, unreachable, unresolved, unscanned, manifests, checked },
367
+ null,
368
+ 2
369
+ )
295
370
  );
296
371
  } else if (problems.length === 0) {
297
372
  console.log(
298
- `## Security floors\n\nNo force-pinned floor permits a high or critical vulnerable release. ${checked} package(s) checked.`
373
+ `## Security floors\n\nNo force-pinned floor permits a high or critical vulnerable release. ${checked} package(s) across ${manifests} manifest(s) checked.`
299
374
  );
300
375
  } else {
301
376
  console.log("## Security floors\n");
@@ -331,6 +406,23 @@ async function main() {
331
406
  );
332
407
  }
333
408
 
409
+ // A manifest the patterns never opened is the same failure as a package the
410
+ // advisory API never answered for: unexamined, and reported clean unless the
411
+ // difference is stated. Printed whether or not anything else went wrong.
412
+ if (!asJson && unscanned === null) {
413
+ console.log(
414
+ "\n> **Manifest coverage was not reconciled.** `git ls-files` could not be consulted, so nothing confirms the patterns reached every tracked manifest."
415
+ );
416
+ }
417
+ if (!asJson && unscanned !== null && unscanned.length > 0) {
418
+ console.log(
419
+ `\n> **${unscanned.length} tracked manifest(s) were NOT scanned.** Their floors are audited by nothing, which reads as clean: ${unscanned.join(", ")}.`
420
+ );
421
+ console.log(
422
+ "> Fix by widening `MANIFEST_PATTERNS` in this script and the `paths:` trigger in `.github/workflows/security-floors.yml` to match."
423
+ );
424
+ }
425
+
334
426
  if (!asJson && unreachable.length > 0) {
335
427
  const limited = unreachable.filter(entry =>
336
428
  entry.reason.includes("rate limited")
@@ -357,9 +449,14 @@ async function main() {
357
449
  // degradation this script exists to prevent.
358
450
  // An unresolved self-reference gates for the same reason an inconclusive one
359
451
  // does: it is a floor nobody checked, and letting it pass reports it clean.
452
+ // An unscanned tracked manifest gates for the same reason an inconclusive
453
+ // lookup does: it is a floor nobody checked, and passing reports it clean.
360
454
  if (
361
455
  strict &&
362
- (problems.length > 0 || unreachable.length > 0 || unresolved.length > 0)
456
+ (problems.length > 0 ||
457
+ unreachable.length > 0 ||
458
+ unresolved.length > 0 ||
459
+ (unscanned !== null && unscanned.length > 0))
363
460
  ) {
364
461
  process.exitCode = 1;
365
462
  }
@@ -48,6 +48,7 @@
48
48
  "husky",
49
49
  "knip",
50
50
  "prettier",
51
+ "printf",
51
52
  "tsc",
52
53
  "vitest"
53
54
  ],