@codyswann/lisa 2.265.0 → 2.267.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.
Files changed (168) hide show
  1. package/dist/core/lisa-plugin-selection.d.ts +11 -0
  2. package/dist/core/lisa-plugin-selection.d.ts.map +1 -1
  3. package/dist/core/lisa-plugin-selection.js +11 -1
  4. package/dist/core/lisa-plugin-selection.js.map +1 -1
  5. package/dist/core/lisa.d.ts +0 -41
  6. package/dist/core/lisa.d.ts.map +1 -1
  7. package/dist/core/lisa.js +23 -104
  8. package/dist/core/lisa.js.map +1 -1
  9. package/dist/core/template-ownership.d.ts +46 -0
  10. package/dist/core/template-ownership.d.ts.map +1 -0
  11. package/dist/core/template-ownership.js +123 -0
  12. package/dist/core/template-ownership.js.map +1 -0
  13. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  14. package/dist/core/upstream-evidence-manifest.js +38 -7
  15. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  16. package/dist/health/deadline.d.ts +25 -0
  17. package/dist/health/deadline.d.ts.map +1 -0
  18. package/dist/health/deadline.js +50 -0
  19. package/dist/health/deadline.js.map +1 -0
  20. package/dist/health/deterministic.d.ts +34 -0
  21. package/dist/health/deterministic.d.ts.map +1 -0
  22. package/dist/health/deterministic.js +206 -0
  23. package/dist/health/deterministic.js.map +1 -0
  24. package/dist/health/finding-utils.d.ts +17 -0
  25. package/dist/health/finding-utils.d.ts.map +1 -0
  26. package/dist/health/finding-utils.js +25 -0
  27. package/dist/health/finding-utils.js.map +1 -0
  28. package/dist/health/governance-probes.d.ts +51 -0
  29. package/dist/health/governance-probes.d.ts.map +1 -0
  30. package/dist/health/governance-probes.js +94 -0
  31. package/dist/health/governance-probes.js.map +1 -0
  32. package/dist/health/hook-inspection.d.ts +35 -0
  33. package/dist/health/hook-inspection.d.ts.map +1 -0
  34. package/dist/health/hook-inspection.js +123 -0
  35. package/dist/health/hook-inspection.js.map +1 -0
  36. package/dist/health/index.d.ts +1 -0
  37. package/dist/health/index.d.ts.map +1 -1
  38. package/dist/health/index.js +1 -0
  39. package/dist/health/index.js.map +1 -1
  40. package/dist/health/plugin-inspection.d.ts +37 -0
  41. package/dist/health/plugin-inspection.d.ts.map +1 -0
  42. package/dist/health/plugin-inspection.js +128 -0
  43. package/dist/health/plugin-inspection.js.map +1 -0
  44. package/dist/health/project-probes.d.ts +34 -0
  45. package/dist/health/project-probes.d.ts.map +1 -0
  46. package/dist/health/project-probes.js +104 -0
  47. package/dist/health/project-probes.js.map +1 -0
  48. package/dist/health/read-only-fs.d.ts +54 -0
  49. package/dist/health/read-only-fs.d.ts.map +1 -0
  50. package/dist/health/read-only-fs.js +165 -0
  51. package/dist/health/read-only-fs.js.map +1 -0
  52. package/dist/health/ruleset-inspection.d.ts +57 -0
  53. package/dist/health/ruleset-inspection.d.ts.map +1 -0
  54. package/dist/health/ruleset-inspection.js +315 -0
  55. package/dist/health/ruleset-inspection.js.map +1 -0
  56. package/dist/health/template-inspection.d.ts +67 -0
  57. package/dist/health/template-inspection.d.ts.map +1 -0
  58. package/dist/health/template-inspection.js +469 -0
  59. package/dist/health/template-inspection.js.map +1 -0
  60. package/dist/strategies/copy-contents.d.ts +7 -25
  61. package/dist/strategies/copy-contents.d.ts.map +1 -1
  62. package/dist/strategies/copy-contents.js +32 -63
  63. package/dist/strategies/copy-contents.js.map +1 -1
  64. package/dist/strategies/merge.d.ts +7 -0
  65. package/dist/strategies/merge.d.ts.map +1 -1
  66. package/dist/strategies/merge.js +10 -1
  67. package/dist/strategies/merge.js.map +1 -1
  68. package/dist/strategies/package-lisa.d.ts +10 -1
  69. package/dist/strategies/package-lisa.d.ts.map +1 -1
  70. package/dist/strategies/package-lisa.js +18 -20
  71. package/dist/strategies/package-lisa.js.map +1 -1
  72. package/dist/strategies/tagged-merge.d.ts +7 -0
  73. package/dist/strategies/tagged-merge.d.ts.map +1 -1
  74. package/dist/strategies/tagged-merge.js +10 -1
  75. package/dist/strategies/tagged-merge.js.map +1 -1
  76. package/dist/sync/config-sync.d.ts +7 -0
  77. package/dist/sync/config-sync.d.ts.map +1 -1
  78. package/dist/sync/config-sync.js +23 -16
  79. package/dist/sync/config-sync.js.map +1 -1
  80. package/dist/utils/ignore-patterns.d.ts +18 -0
  81. package/dist/utils/ignore-patterns.d.ts.map +1 -1
  82. package/dist/utils/ignore-patterns.js +2 -2
  83. package/dist/utils/ignore-patterns.js.map +1 -1
  84. package/package.json +3 -2
  85. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  86. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  87. package/plugins/lisa/.codex-plugin/skills/lisa-implement/SKILL.md +22 -1
  88. package/plugins/lisa/.codex-plugin/skills/lisa-spec-conformance/SKILL.md +43 -11
  89. package/plugins/lisa/agents/spec-conformance-specialist.md +5 -2
  90. package/plugins/lisa/agents/verification-specialist.md +1 -1
  91. package/plugins/lisa/hooks/enforce-verification-gate.sh +83 -9
  92. package/plugins/lisa/rules/reference/verification.md +2 -0
  93. package/plugins/lisa/skills/lisa-implement/SKILL.md +22 -1
  94. package/plugins/lisa/skills/lisa-spec-conformance/SKILL.md +43 -11
  95. package/plugins/lisa-agy/agents/spec-conformance-specialist.md +5 -2
  96. package/plugins/lisa-agy/agents/verification-specialist.md +1 -1
  97. package/plugins/lisa-agy/plugin.json +1 -1
  98. package/plugins/lisa-agy/skills/lisa-implement/SKILL.md +22 -1
  99. package/plugins/lisa-agy/skills/lisa-spec-conformance/SKILL.md +43 -11
  100. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  101. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  102. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  103. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  104. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  105. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  106. package/plugins/lisa-copilot/agents/spec-conformance-specialist.agent.md +5 -2
  107. package/plugins/lisa-copilot/agents/verification-specialist.agent.md +1 -1
  108. package/plugins/lisa-copilot/hooks/enforce-verification-gate.sh +83 -9
  109. package/plugins/lisa-copilot/rules/reference/verification.md +2 -0
  110. package/plugins/lisa-copilot/skills/lisa-implement/SKILL.md +22 -1
  111. package/plugins/lisa-copilot/skills/lisa-spec-conformance/SKILL.md +43 -11
  112. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  113. package/plugins/lisa-cursor/agents/spec-conformance-specialist.md +5 -2
  114. package/plugins/lisa-cursor/agents/verification-specialist.md +1 -1
  115. package/plugins/lisa-cursor/hooks/enforce-verification-gate.sh +83 -9
  116. package/plugins/lisa-cursor/rules/verification-reference.mdc +2 -0
  117. package/plugins/lisa-cursor/skills/lisa-implement/SKILL.md +22 -1
  118. package/plugins/lisa-cursor/skills/lisa-spec-conformance/SKILL.md +43 -11
  119. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  120. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  121. package/plugins/lisa-expo-agy/plugin.json +1 -1
  122. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  123. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  124. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  125. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  126. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  127. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  128. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  129. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  130. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  131. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  132. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  133. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  134. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  135. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  136. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  137. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  138. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  139. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  140. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  141. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  142. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  143. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  144. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  145. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  146. package/plugins/lisa-rails-agy/plugin.json +1 -1
  147. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  148. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  149. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  150. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  151. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  152. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  153. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  154. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  155. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  156. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  157. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  158. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  159. package/plugins/src/base/agents/spec-conformance-specialist.md +5 -2
  160. package/plugins/src/base/agents/verification-specialist.md +1 -1
  161. package/plugins/src/base/hooks/enforce-verification-gate.sh +83 -9
  162. package/plugins/src/base/rules/reference/verification.md +2 -0
  163. package/plugins/src/base/skills/lisa-implement/SKILL.md +22 -1
  164. package/plugins/src/base/skills/lisa-spec-conformance/SKILL.md +43 -11
  165. package/scripts/detect-stale-workflow-inputs.mjs +21 -148
  166. package/scripts/lib/reusable-workflow-contract.d.mts +24 -0
  167. package/scripts/lib/reusable-workflow-contract.mjs +123 -0
  168. package/scripts/verify-health-deterministic-built.mjs +499 -0
@@ -0,0 +1,165 @@
1
+ /** Confined, bounded filesystem reads for deterministic health probes. */
2
+ import { constants } from "node:fs";
3
+ import { lstat, open, realpath } from "node:fs/promises";
4
+ import path from "node:path";
5
+ const DEFAULT_MAX_BYTES = 512 * 1024;
6
+ const READ_CHUNK_BYTES = 64 * 1024;
7
+ /**
8
+ * Resolve a project-relative path without permitting traversal.
9
+ * @param root - Canonical project root
10
+ * @param relativePath - Project-relative path
11
+ * @returns Confined absolute path
12
+ */
13
+ export function resolveProjectPath(root, relativePath) {
14
+ if (path.isAbsolute(relativePath)) {
15
+ throw new Error("Health path must be project-relative");
16
+ }
17
+ const target = path.resolve(root, relativePath);
18
+ if (target !== root && !target.startsWith(`${root}${path.sep}`)) {
19
+ throw new Error("Health path escapes project root");
20
+ }
21
+ return target;
22
+ }
23
+ /**
24
+ * Assert that one lstat result is a bounded regular file.
25
+ * @param stat - File metadata
26
+ * @param maximumBytes - Maximum allowed size
27
+ */
28
+ function assertBoundedFile(stat, maximumBytes) {
29
+ if (!stat.isFile() || stat.isSymbolicLink()) {
30
+ throw new Error("Unsafe health project file");
31
+ }
32
+ if (stat.size > maximumBytes) {
33
+ throw new Error("Health project file exceeds size limit");
34
+ }
35
+ }
36
+ /**
37
+ * Read at most maximum plus one bytes without unbounded stream behavior.
38
+ * @param handle - Open nonblocking regular-file handle
39
+ * @param maximumBytes - Maximum allowed payload size
40
+ * @param offset - Current read offset
41
+ * @returns Bounded bytes
42
+ */
43
+ async function readBounded(handle, maximumBytes, offset = 0) {
44
+ const remaining = maximumBytes + 1 - offset;
45
+ if (remaining <= 0)
46
+ return Buffer.alloc(0);
47
+ const chunk = Buffer.allocUnsafe(Math.min(READ_CHUNK_BYTES, remaining));
48
+ const { bytesRead } = await handle.read(chunk, 0, chunk.length, offset);
49
+ if (bytesRead === 0)
50
+ return Buffer.alloc(0);
51
+ const current = chunk.subarray(0, bytesRead);
52
+ const tail = await readBounded(handle, maximumBytes, offset + bytesRead);
53
+ return Buffer.concat([current, tail], bytesRead + tail.length);
54
+ }
55
+ /**
56
+ * Read one stable regular file without following a target outside the project.
57
+ * @param root - Canonical project root
58
+ * @param relativePath - Project-relative path
59
+ * @param maximumBytes - Maximum permitted file size
60
+ * @returns File bytes, or undefined when absent
61
+ */
62
+ export async function readProjectFile(root, relativePath, maximumBytes = DEFAULT_MAX_BYTES) {
63
+ const target = resolveProjectPath(root, relativePath);
64
+ try {
65
+ const before = await lstat(target);
66
+ assertBoundedFile(before, maximumBytes);
67
+ const actual = await realpath(target);
68
+ if (!actual.startsWith(`${root}${path.sep}`)) {
69
+ throw new Error("Unsafe health project file escapes project root");
70
+ }
71
+ const handle = await open(target, constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK);
72
+ try {
73
+ const opened = await handle.stat();
74
+ assertBoundedFile(opened, maximumBytes);
75
+ if (opened.dev !== before.dev || opened.ino !== before.ino) {
76
+ throw new Error("Health project file changed during read");
77
+ }
78
+ const bytes = await readBounded(handle, maximumBytes);
79
+ if (bytes.length > maximumBytes) {
80
+ throw new Error("Health project file exceeds size limit");
81
+ }
82
+ const after = await handle.stat();
83
+ if (after.size !== opened.size || bytes.length !== after.size) {
84
+ throw new Error("Health project file changed during read");
85
+ }
86
+ return { bytes, mode: opened.mode };
87
+ }
88
+ finally {
89
+ await handle.close();
90
+ }
91
+ }
92
+ catch (error) {
93
+ if (error.code === "ENOENT")
94
+ return undefined;
95
+ throw error;
96
+ }
97
+ }
98
+ /**
99
+ * Read just the bytes from one confined stable regular file.
100
+ * @param root - Canonical project root
101
+ * @param relativePath - Project-relative path
102
+ * @param maximumBytes - Maximum permitted file size
103
+ * @returns File bytes, or undefined when absent
104
+ */
105
+ export async function readProjectBytes(root, relativePath, maximumBytes = DEFAULT_MAX_BYTES) {
106
+ return (await readProjectFile(root, relativePath, maximumBytes))?.bytes;
107
+ }
108
+ /**
109
+ * Classify a confined path without following symbolic links or accepting
110
+ * special files such as FIFOs and devices.
111
+ * @param root - Canonical project root
112
+ * @param relativePath - Project-relative path
113
+ * @returns Safe path kind
114
+ */
115
+ export async function projectPathKind(root, relativePath) {
116
+ const target = resolveProjectPath(root, relativePath);
117
+ try {
118
+ const stat = await lstat(target);
119
+ if (stat.isSymbolicLink())
120
+ throw new Error("Unsafe health project path");
121
+ if (!stat.isFile() && !stat.isDirectory()) {
122
+ throw new Error("Unsafe health project path");
123
+ }
124
+ const actual = await realpath(target);
125
+ if (actual !== root && !actual.startsWith(`${root}${path.sep}`)) {
126
+ throw new Error("Unsafe health project path escapes project root");
127
+ }
128
+ return stat.isDirectory() ? "directory" : "file";
129
+ }
130
+ catch (error) {
131
+ if (error.code === "ENOENT")
132
+ return "missing";
133
+ throw error;
134
+ }
135
+ }
136
+ /**
137
+ * Read strict UTF-8 text from a confined project file.
138
+ * @param root - Canonical project root
139
+ * @param relativePath - Project-relative path
140
+ * @param maximumBytes - Maximum permitted file size
141
+ * @returns Text, or undefined when absent
142
+ */
143
+ export async function readProjectText(root, relativePath, maximumBytes = DEFAULT_MAX_BYTES) {
144
+ const bytes = await readProjectBytes(root, relativePath, maximumBytes);
145
+ return bytes === undefined
146
+ ? undefined
147
+ : new TextDecoder("utf-8", { fatal: true }).decode(bytes);
148
+ }
149
+ /**
150
+ * Read a JSON object without exposing its values in failures.
151
+ * @param root - Canonical project root
152
+ * @param relativePath - Project-relative JSON path
153
+ * @returns Parsed object, or undefined when absent
154
+ */
155
+ export async function readProjectJsonObject(root, relativePath) {
156
+ const text = await readProjectText(root, relativePath);
157
+ if (text === undefined)
158
+ return undefined;
159
+ const parsed = JSON.parse(text);
160
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
161
+ throw new Error("Health project JSON must be an object");
162
+ }
163
+ return parsed;
164
+ }
165
+ //# sourceMappingURL=read-only-fs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read-only-fs.js","sourceRoot":"","sources":["../../src/health/read-only-fs.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,OAAO,EAAE,SAAS,EAAc,MAAM,SAAS,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAmB,MAAM,kBAAkB,CAAC;AAC1E,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,MAAM,iBAAiB,GAAG,GAAG,GAAG,IAAI,CAAC;AACrC,MAAM,gBAAgB,GAAG,EAAE,GAAG,IAAI,CAAC;AAWnC;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAY,EAAE,YAAoB;IACnE,IAAI,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QAClC,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAC1D,CAAC;IACD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IAChD,IAAI,MAAM,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC;QAChE,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IACtD,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;GAIG;AACH,SAAS,iBAAiB,CAAC,IAAW,EAAE,YAAoB;IAC1D,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,IAAI,CAAC,cAAc,EAAE,EAAE,CAAC;QAC5C,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;IAChD,CAAC;IACD,IAAI,IAAI,CAAC,IAAI,GAAG,YAAY,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;IAC5D,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,KAAK,UAAU,WAAW,CACxB,MAAkB,EAClB,YAAoB,EACpB,MAAM,GAAG,CAAC;IAEV,MAAM,SAAS,GAAG,YAAY,GAAG,CAAC,GAAG,MAAM,CAAC;IAC5C,IAAI,SAAS,IAAI,CAAC;QAAE,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC3C,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,gBAAgB,EAAE,SAAS,CAAC,CAAC,CAAC;IACxE,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxE,IAAI,SAAS,KAAK,CAAC;QAAE,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC5C,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;IAC7C,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACzE,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;AACjE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,IAAY,EACZ,YAAoB,EACpB,YAAY,GAAG,iBAAiB;IAEhC,MAAM,MAAM,GAAG,kBAAkB,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IACtD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,CAAC;QACnC,iBAAiB,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;QACxC,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC;QACtC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC;YAC7C,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;QACrE,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,IAAI,CACvB,MAAM,EACN,SAAS,CAAC,QAAQ,GAAG,SAAS,CAAC,UAAU,GAAG,SAAS,CAAC,UAAU,CACjE,CAAC;QACF,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;YACnC,iBAAiB,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;YACxC,IAAI,MAAM,CAAC,GAAG,KAAK,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,GAAG,KAAK,MAAM,CAAC,GAAG,EAAE,CAAC;gBAC3D,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;YAC7D,CAAC;YACD,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;YACtD,IAAI,KAAK,CAAC,MAAM,GAAG,YAAY,EAAE,CAAC;gBAChC,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;YAC5D,CAAC;YACD,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;YAClC,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,CAAC,IAAI,IAAI,KAAK,CAAC,MAAM,KAAK,KAAK,CAAC,IAAI,EAAE,CAAC;gBAC9D,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;YAC7D,CAAC;YACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC;QACtC,CAAC;gBAAS,CAAC;YACT,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QACvB,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,SAAS,CAAC;QACzE,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,IAAY,EACZ,YAAoB,EACpB,YAAY,GAAG,iBAAiB;IAEhC,OAAO,CAAC,MAAM,eAAe,CAAC,IAAI,EAAE,YAAY,EAAE,YAAY,CAAC,CAAC,EAAE,KAAK,CAAC;AAC1E,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,IAAY,EACZ,YAAoB;IAEpB,MAAM,MAAM,GAAG,kBAAkB,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IACtD,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,CAAC;QACjC,IAAI,IAAI,CAAC,cAAc,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;QACzE,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;YAC1C,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;QAChD,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC;QACtC,IAAI,MAAM,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC;YAChE,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;QACrE,CAAC;QACD,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC;IACnD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,SAAS,CAAC;QACzE,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,IAAY,EACZ,YAAoB,EACpB,YAAY,GAAG,iBAAiB;IAEhC,MAAM,KAAK,GAAG,MAAM,gBAAgB,CAAC,IAAI,EAAE,YAAY,EAAE,YAAY,CAAC,CAAC;IACvE,OAAO,KAAK,KAAK,SAAS;QACxB,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,IAAI,WAAW,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC9D,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,IAAY,EACZ,YAAoB;IAEpB,MAAM,IAAI,GAAG,MAAM,eAAe,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IACvD,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IACzC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAY,CAAC;IAC3C,IAAI,MAAM,KAAK,IAAI,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3E,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;IAC3D,CAAC;IACD,OAAO,MAA2C,CAAC;AACrD,CAAC"}
@@ -0,0 +1,57 @@
1
+ import type { ProjectType } from "../core/config.js";
2
+ import type { HealthFinding } from "./contract.js";
3
+ /** Material ruleset fields health compares. */
4
+ export interface HealthRuleset {
5
+ readonly name: string;
6
+ readonly target: unknown;
7
+ readonly enforcement: unknown;
8
+ readonly conditions: unknown;
9
+ readonly rules: unknown;
10
+ }
11
+ /**
12
+ * Injectable structured ruleset reader. Implementations must honor `signal`
13
+ * and release any owned handles before settling.
14
+ */
15
+ export type RulesetReader = (owner: string, repo: string, projectRoot: string, timeoutMs: number, signal: AbortSignal) => Promise<readonly HealthRuleset[]>;
16
+ /** Ruleset comparison result containing names only. */
17
+ export interface RulesetDrift {
18
+ readonly missing: readonly string[];
19
+ readonly drifted: readonly string[];
20
+ }
21
+ /**
22
+ * Default fixed-argv detailed GitHub ruleset reader.
23
+ * @param owner
24
+ * @param repo
25
+ * @param projectRoot
26
+ * @param timeoutMs
27
+ * @param signal
28
+ */
29
+ export declare const readGithubRulesets: RulesetReader;
30
+ /**
31
+ * Read expected material rulesets after the same per-project normalization as apply.
32
+ * @param lisaRoot - Lisa package root
33
+ * @param projectRoot - Canonical host root
34
+ * @param types - Canonically ordered project types
35
+ * @param config - Safe project config
36
+ * @returns Expected rulesets sorted by name
37
+ */
38
+ export declare function expectedRulesets(lisaRoot: string, projectRoot: string, types: readonly ProjectType[], config: Readonly<Record<string, unknown>>): Promise<readonly HealthRuleset[]>;
39
+ /**
40
+ * Compare expected and observed material ruleset documents.
41
+ * @param expected
42
+ * @param actual
43
+ */
44
+ export declare function compareRulesets(expected: readonly HealthRuleset[], actual: readonly HealthRuleset[]): RulesetDrift;
45
+ /**
46
+ * Collect and compare detailed material GitHub ruleset state.
47
+ * @param lisaRoot - Lisa package root
48
+ * @param projectRoot - Canonical host root
49
+ * @param types - Safely detected project types
50
+ * @param config - Safe project config
51
+ * @param reader - Structured remote ruleset reader
52
+ * @param timeoutMs - Remaining shared deadline
53
+ * @param signal - Shared cancellation signal
54
+ * @returns GitHub ruleset finding
55
+ */
56
+ export declare function rulesetFinding(lisaRoot: string, projectRoot: string, types: readonly ProjectType[], config: Readonly<Record<string, unknown>>, reader: RulesetReader, timeoutMs: number, signal: AbortSignal): Promise<HealthFinding>;
57
+ //# sourceMappingURL=ruleset-inspection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ruleset-inspection.d.ts","sourceRoot":"","sources":["../../src/health/ruleset-inspection.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AA0BnD,+CAA+C;AAC/C,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;IAC9B,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB;AAED;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG,CAC1B,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,WAAW,KAChB,OAAO,CAAC,SAAS,aAAa,EAAE,CAAC,CAAC;AAEvC,uDAAuD;AACvD,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC;AAgED;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB,EAAE,aAsChC,CAAC;AAsEF;;;;;;;GAOG;AAEH,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,SAAS,WAAW,EAAE,EAC7B,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACxC,OAAO,CAAC,SAAS,aAAa,EAAE,CAAC,CA4BnC;AA4CD;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,SAAS,aAAa,EAAE,EAClC,MAAM,EAAE,SAAS,aAAa,EAAE,GAC/B,YAAY,CAiCd;AAuBD;;;;;;;;;;GAUG;AACH,wBAAsB,cAAc,CAClC,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,SAAS,WAAW,EAAE,EAC7B,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACzC,MAAM,EAAE,aAAa,EACrB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,aAAa,CAAC,CAwCxB"}
@@ -0,0 +1,315 @@
1
+ /** Structured, bounded GitHub ruleset collection and canonical comparison. */
2
+ /* eslint-disable jsdoc/require-param-description, jsdoc/require-returns, max-lines -- structured collection and normalization stay colocated */
3
+ import { execFile } from "node:child_process";
4
+ import { readFile } from "node:fs/promises";
5
+ import path from "node:path";
6
+ import { listFilesRecursive } from "../utils/file-operations.js";
7
+ import { deterministicFinding, namedReason } from "./finding-utils.js";
8
+ import { projectPathKind } from "./read-only-fs.js";
9
+ const GH_TIMEOUT_MS = 15_000;
10
+ const MAX_GH_OUTPUT_BYTES = 256 * 1024;
11
+ const MAX_RULESETS = 32;
12
+ const ACTIONS_INTEGRATION_ID = 15_368;
13
+ const REPOSITORY_PART = /^[A-Za-z0-9_.-]{1,100}$/u;
14
+ const RULESET_CHECK = "github.rulesets";
15
+ const WARN = "warn";
16
+ /**
17
+ * Return a sorted copy without mutating caller-owned input.
18
+ * @param items - Caller-owned items
19
+ * @param compare - Stable comparator
20
+ */
21
+ function sortedCopy(items, compare) {
22
+ const copy = [...items];
23
+ // eslint-disable-next-line functional/immutable-data -- only the detached copy is sorted
24
+ return copy.sort(compare);
25
+ }
26
+ /**
27
+ * Run one fixed-argv bounded gh JSON read.
28
+ * @param argv
29
+ * @param cwd
30
+ * @param timeoutMs
31
+ * @param signal
32
+ */
33
+ function readGhJson(argv, cwd, timeoutMs, signal) {
34
+ return new Promise((resolve, reject) => {
35
+ execFile(
36
+ // eslint-disable-next-line sonarjs/no-os-command-from-path -- fixed user-installed gh executable
37
+ "gh", [...argv], {
38
+ cwd,
39
+ encoding: "utf8",
40
+ maxBuffer: MAX_GH_OUTPUT_BYTES,
41
+ signal,
42
+ killSignal: "SIGKILL",
43
+ timeout: Math.max(1, Math.min(timeoutMs, GH_TIMEOUT_MS)),
44
+ }, (error, stdout) => {
45
+ if (error !== null) {
46
+ reject(error);
47
+ return;
48
+ }
49
+ try {
50
+ resolve(JSON.parse(stdout));
51
+ }
52
+ catch (parseError) {
53
+ reject(parseError);
54
+ }
55
+ });
56
+ });
57
+ }
58
+ /**
59
+ * Validate and project one detailed GitHub ruleset response.
60
+ * @param candidate
61
+ */
62
+ function projectRuleset(candidate) {
63
+ if (candidate === null || typeof candidate !== "object") {
64
+ throw new Error("Ruleset detail was not an object");
65
+ }
66
+ const name = Reflect.get(candidate, "name");
67
+ if (typeof name !== "string" || name.trim().length === 0) {
68
+ throw new Error("Ruleset detail omitted its name");
69
+ }
70
+ return {
71
+ name,
72
+ target: Reflect.get(candidate, "target"),
73
+ enforcement: Reflect.get(candidate, "enforcement"),
74
+ conditions: Reflect.get(candidate, "conditions"),
75
+ rules: Reflect.get(candidate, "rules"),
76
+ };
77
+ }
78
+ /**
79
+ * Default fixed-argv detailed GitHub ruleset reader.
80
+ * @param owner
81
+ * @param repo
82
+ * @param projectRoot
83
+ * @param timeoutMs
84
+ * @param signal
85
+ */
86
+ export const readGithubRulesets = async (owner, repo, projectRoot, timeoutMs, signal) => {
87
+ const listed = await readGhJson(["api", "-X", "GET", `repos/${owner}/${repo}/rulesets`], projectRoot, timeoutMs, signal);
88
+ if (!Array.isArray(listed) || listed.length > MAX_RULESETS) {
89
+ throw new Error("Ruleset list exceeded its bounded contract");
90
+ }
91
+ const details = await Promise.all(listed.map(async (entry) => {
92
+ if (entry === null || typeof entry !== "object") {
93
+ throw new Error("Ruleset list entry was not an object");
94
+ }
95
+ const id = Reflect.get(entry, "id");
96
+ if (!Number.isSafeInteger(id)) {
97
+ throw new Error("Ruleset list entry omitted its id");
98
+ }
99
+ return projectRuleset(await readGhJson(["api", "-X", "GET", `repos/${owner}/${repo}/rulesets/${String(id)}`], projectRoot, timeoutMs, signal));
100
+ }));
101
+ return sortedCopy(details, (left, right) => left.name.localeCompare(right.name));
102
+ };
103
+ /**
104
+ * Read configured required-check opt-outs without exposing their values.
105
+ * @param config
106
+ */
107
+ function droppedChecks(config) {
108
+ const github = config.github;
109
+ const rulesets = github !== null && typeof github === "object" && !Array.isArray(github)
110
+ ? Reflect.get(github, "rulesets")
111
+ : undefined;
112
+ const dropped = rulesets !== null &&
113
+ typeof rulesets === "object" &&
114
+ !Array.isArray(rulesets)
115
+ ? Reflect.get(rulesets, "dropRequiredChecks")
116
+ : undefined;
117
+ return new Set(Array.isArray(dropped)
118
+ ? dropped.filter(item => typeof item === "string")
119
+ : []);
120
+ }
121
+ /**
122
+ * Apply workflow and configured required-check normalization used by apply.
123
+ * @param rules
124
+ * @param hasWorkflows
125
+ * @param dropped
126
+ */
127
+ function normalizeExpectedRules(rules, hasWorkflows, dropped) {
128
+ if (!Array.isArray(rules))
129
+ return rules;
130
+ return rules.flatMap(rule => {
131
+ if (rule === null ||
132
+ typeof rule !== "object" ||
133
+ Reflect.get(rule, "type") !== "required_status_checks") {
134
+ return [rule];
135
+ }
136
+ const parameters = Reflect.get(rule, "parameters");
137
+ if (parameters === null || typeof parameters !== "object")
138
+ return [rule];
139
+ const checks = Reflect.get(parameters, "required_status_checks");
140
+ if (!Array.isArray(checks))
141
+ return [rule];
142
+ const retained = checks.filter(check => {
143
+ if (check === null || typeof check !== "object")
144
+ return true;
145
+ const integration = Reflect.get(check, "integration_id");
146
+ const context = Reflect.get(check, "context");
147
+ return ((hasWorkflows || integration !== ACTIONS_INTEGRATION_ID) &&
148
+ (typeof context !== "string" || !dropped.has(context)));
149
+ });
150
+ if (retained.length === 0)
151
+ return [];
152
+ return [
153
+ {
154
+ ...rule,
155
+ parameters: { ...parameters, required_status_checks: retained },
156
+ },
157
+ ];
158
+ });
159
+ }
160
+ /**
161
+ * Read expected material rulesets after the same per-project normalization as apply.
162
+ * @param lisaRoot - Lisa package root
163
+ * @param projectRoot - Canonical host root
164
+ * @param types - Canonically ordered project types
165
+ * @param config - Safe project config
166
+ * @returns Expected rulesets sorted by name
167
+ */
168
+ // eslint-disable-next-line sonarjs/cognitive-complexity -- normalization mirrors the apply contract explicitly
169
+ export async function expectedRulesets(lisaRoot, projectRoot, types, config) {
170
+ const hasWorkflows = (await projectPathKind(projectRoot, path.join(".github", "workflows"))) ===
171
+ "directory";
172
+ const dropped = droppedChecks(config);
173
+ const byName = new Map();
174
+ for (const type of ["all", ...types]) {
175
+ const directory = path.join(lisaRoot, type, "github-rulesets");
176
+ try {
177
+ for (const file of await listFilesRecursive(directory)) {
178
+ const parsed = JSON.parse(await readFile(file, "utf8"));
179
+ const projected = projectRuleset(parsed);
180
+ const normalized = {
181
+ ...projected,
182
+ rules: normalizeExpectedRules(projected.rules, hasWorkflows, dropped),
183
+ };
184
+ if (!Array.isArray(normalized.rules) || normalized.rules.length > 0) {
185
+ // eslint-disable-next-line functional/immutable-data -- most-specific stack wins in the bounded plan
186
+ byName.set(normalized.name, normalized);
187
+ }
188
+ }
189
+ }
190
+ catch (error) {
191
+ if (error.code !== "ENOENT")
192
+ throw error;
193
+ }
194
+ }
195
+ return [...byName.values()].sort((left, right) => left.name.localeCompare(right.name));
196
+ }
197
+ /**
198
+ * Canonicalize semantically unordered JSON objects and arrays.
199
+ * @param value
200
+ */
201
+ function canonical(value) {
202
+ if (Array.isArray(value)) {
203
+ return value
204
+ .map(canonical)
205
+ .sort((left, right) => JSON.stringify(left).localeCompare(JSON.stringify(right)));
206
+ }
207
+ if (value !== null && typeof value === "object") {
208
+ return Object.fromEntries(Object.entries(value)
209
+ .sort(([left], [right]) => left.localeCompare(right))
210
+ .map(([key, item]) => [key, canonical(item)]));
211
+ }
212
+ return value;
213
+ }
214
+ /**
215
+ * Remove read-only defaults GitHub may add to otherwise equivalent rules.
216
+ * This projection is applied symmetrically so authored non-default values
217
+ * remain material.
218
+ * @param value
219
+ */
220
+ function withoutGithubDefaults(value) {
221
+ if (Array.isArray(value))
222
+ return value.map(withoutGithubDefaults);
223
+ if (value !== null && typeof value === "object") {
224
+ return Object.fromEntries(Object.entries(value).flatMap(([key, item]) => key === "required_reviewers" && Array.isArray(item) && item.length === 0
225
+ ? []
226
+ : [[key, withoutGithubDefaults(item)]]));
227
+ }
228
+ return value;
229
+ }
230
+ /**
231
+ * Compare expected and observed material ruleset documents.
232
+ * @param expected
233
+ * @param actual
234
+ */
235
+ export function compareRulesets(expected, actual) {
236
+ const observed = new Map(actual.map(item => [item.name, item]));
237
+ const missing = expected
238
+ .filter(item => !observed.has(item.name))
239
+ .map(item => item.name);
240
+ const drifted = expected.flatMap(item => {
241
+ const present = observed.get(item.name);
242
+ if (present === undefined)
243
+ return [];
244
+ const expectedMaterial = canonical(withoutGithubDefaults({
245
+ target: item.target,
246
+ enforcement: item.enforcement,
247
+ conditions: item.conditions,
248
+ rules: item.rules,
249
+ }));
250
+ const actualMaterial = canonical(withoutGithubDefaults({
251
+ target: present.target,
252
+ enforcement: present.enforcement,
253
+ conditions: present.conditions,
254
+ rules: present.rules,
255
+ }));
256
+ if (JSON.stringify(expectedMaterial) !== JSON.stringify(actualMaterial)) {
257
+ return [item.name];
258
+ }
259
+ return [];
260
+ });
261
+ return {
262
+ missing: sortedCopy(missing, (left, right) => left.localeCompare(right)),
263
+ drifted: sortedCopy(drifted, (left, right) => left.localeCompare(right)),
264
+ };
265
+ }
266
+ /**
267
+ * Extract a safe GitHub target without reporting configured values.
268
+ * @param config
269
+ */
270
+ function githubTarget(config) {
271
+ const github = config.github;
272
+ if (github === null || typeof github !== "object" || Array.isArray(github)) {
273
+ return undefined;
274
+ }
275
+ const owner = Reflect.get(github, "org");
276
+ const repo = Reflect.get(github, "repo");
277
+ return typeof owner === "string" &&
278
+ typeof repo === "string" &&
279
+ REPOSITORY_PART.test(owner) &&
280
+ REPOSITORY_PART.test(repo)
281
+ ? { owner, repo }
282
+ : undefined;
283
+ }
284
+ /**
285
+ * Collect and compare detailed material GitHub ruleset state.
286
+ * @param lisaRoot - Lisa package root
287
+ * @param projectRoot - Canonical host root
288
+ * @param types - Safely detected project types
289
+ * @param config - Safe project config
290
+ * @param reader - Structured remote ruleset reader
291
+ * @param timeoutMs - Remaining shared deadline
292
+ * @param signal - Shared cancellation signal
293
+ * @returns GitHub ruleset finding
294
+ */
295
+ export async function rulesetFinding(lisaRoot, projectRoot, types, config, reader, timeoutMs, signal) {
296
+ const target = githubTarget(config);
297
+ if (target === undefined) {
298
+ return deterministicFinding("github.rulesets", "warn", "GitHub rulesets are unavailable without a configured repository.");
299
+ }
300
+ const actual = await reader(target.owner, target.repo, projectRoot, timeoutMs, signal).catch(() => undefined);
301
+ if (actual === undefined) {
302
+ return deterministicFinding(RULESET_CHECK, WARN, "GitHub rulesets could not be observed within the deterministic deadline.");
303
+ }
304
+ const expected = await expectedRulesets(lisaRoot, projectRoot, types, config);
305
+ const drift = compareRulesets(expected, actual);
306
+ const names = [
307
+ ...drift.missing.map(name => `${name} missing`),
308
+ ...drift.drifted.map(name => `${name} drifted`),
309
+ ];
310
+ return names.length === 0
311
+ ? deterministicFinding(RULESET_CHECK, "pass", "Required GitHub rulesets are active and materially current.")
312
+ : deterministicFinding(RULESET_CHECK, "fail", namedReason("GitHub ruleset drift", names));
313
+ }
314
+ /* eslint-enable jsdoc/require-param-description, jsdoc/require-returns, max-lines -- restore repository defaults */
315
+ //# sourceMappingURL=ruleset-inspection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ruleset-inspection.js","sourceRoot":"","sources":["../../src/health/ruleset-inspection.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,67 @@
1
+ import { type ProjectType } from "../core/config.js";
2
+ import { DEFAULT_PROJECT_LEARNINGS_FILE } from "../core/project-config.js";
3
+ declare const MANAGED = "managed";
4
+ declare const HOOKS = "hooks";
5
+ declare const WORKFLOWS = "workflows";
6
+ /** Template categories reported by separate deterministic findings. */
7
+ export type ManagedTemplateCategory = typeof MANAGED | typeof HOOKS | typeof WORKFLOWS;
8
+ /** Stale or unresolvable reusable-workflow inputs. */
9
+ export interface WorkflowInputInspection {
10
+ readonly stale: readonly string[];
11
+ readonly unknown: readonly string[];
12
+ }
13
+ /** Safely-detected project shape reused by health probes. */
14
+ export interface HealthProjectShape {
15
+ readonly types: readonly ProjectType[];
16
+ readonly packageJson: Readonly<Record<string, unknown>> | undefined;
17
+ }
18
+ /**
19
+ * Detect project types using only confined, bounded project reads.
20
+ * @param projectRoot - Canonical host project root
21
+ * @returns Safe project shape
22
+ */
23
+ export declare function detectHealthProjectShape(projectRoot: string): Promise<HealthProjectShape>;
24
+ /**
25
+ * Backward-compatible type-only detector surface.
26
+ * @param projectRoot
27
+ */
28
+ export declare function detectHealthProjectTypes(projectRoot: string): Promise<readonly ProjectType[]>;
29
+ /**
30
+ * Inspect one category using Lisa's shared ownership and pure comparators.
31
+ * @param lisaRoot - Lisa package root
32
+ * @param projectRoot - Canonical host root
33
+ * @param types - Canonically ordered types
34
+ * @param category - Health category
35
+ * @param config - Safe project config
36
+ * @returns Sorted project-relative drift paths
37
+ */
38
+ export declare function inspectManagedTemplates(lisaRoot: string, projectRoot: string, types: readonly ProjectType[], category: ManagedTemplateCategory, config?: Readonly<Record<string, unknown>>): Promise<readonly string[]>;
39
+ /**
40
+ * Require applicable create-only workflow presence while preserving bytes.
41
+ * @param lisaRoot - Lisa package root
42
+ * @param projectRoot - Canonical host root
43
+ * @param types - Canonically ordered types
44
+ * @param config - Safe project config
45
+ * @returns Missing workflow paths
46
+ */
47
+ export declare function inspectCreateOnlyWorkflows(lisaRoot: string, projectRoot: string, types: readonly ProjectType[], config?: Readonly<Record<string, unknown>>): Promise<readonly string[]>;
48
+ /**
49
+ * Inspect applicable create-only workflow caller inputs against shipped contracts.
50
+ * @param lisaRoot - Lisa package root
51
+ * @param projectRoot - Canonical host root
52
+ * @param types - Canonically ordered types
53
+ * @param config - Safe project config
54
+ * @returns Stale and unknown caller descriptions
55
+ */
56
+ export declare function inspectWorkflowInputs(lisaRoot: string, projectRoot: string, types: readonly ProjectType[], config?: Readonly<Record<string, unknown>>): Promise<WorkflowInputInspection>;
57
+ /**
58
+ * Inspect package.json through the exact pure package-lisa planner.
59
+ * @param lisaRoot - Lisa package root
60
+ * @param projectRoot - Canonical host root
61
+ * @param types - Safely detected project types
62
+ * @param packageJson - Safely captured package document
63
+ * @returns Whether package.json conforms
64
+ */
65
+ export declare function packageJsonConforms(lisaRoot: string, projectRoot: string, types?: readonly ProjectType[], packageJson?: Readonly<Record<string, unknown>>): Promise<boolean>;
66
+ export { DEFAULT_PROJECT_LEARNINGS_FILE };
67
+ //# sourceMappingURL=template-inspection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-inspection.d.ts","sourceRoot":"","sources":["../../src/health/template-inspection.ts"],"names":[],"mappings":"AAMA,OAAO,EAIL,KAAK,WAAW,EACjB,MAAM,mBAAmB,CAAC;AAK3B,OAAO,EACL,8BAA8B,EAI/B,MAAM,2BAA2B,CAAC;AAyBnC,QAAA,MAAM,OAAO,YAAY,CAAC;AAC1B,QAAA,MAAM,KAAK,UAAU,CAAC;AACtB,QAAA,MAAM,SAAS,cAAc,CAAC;AAc9B,uEAAuE;AACvE,MAAM,MAAM,uBAAuB,GAC/B,OAAO,OAAO,GACd,OAAO,KAAK,GACZ,OAAO,SAAS,CAAC;AAiBrB,sDAAsD;AACtD,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC;AAED,6DAA6D;AAC7D,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,KAAK,EAAE,SAAS,WAAW,EAAE,CAAC;IACvC,QAAQ,CAAC,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC;CACrE;AAiFD;;;;GAIG;AAEH,wBAAsB,wBAAwB,CAC5C,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,kBAAkB,CAAC,CAuD7B;AAED;;;GAGG;AACH,wBAAsB,wBAAwB,CAC5C,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,SAAS,WAAW,EAAE,CAAC,CAEjC;AA4RD;;;;;;;;GAQG;AACH,wBAAsB,uBAAuB,CAC3C,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,SAAS,WAAW,EAAE,EAC7B,QAAQ,EAAE,uBAAuB,EACjC,MAAM,GAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAM,GAC7C,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC,CAyB5B;AAED;;;;;;;GAOG;AACH,wBAAsB,0BAA0B,CAC9C,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,SAAS,WAAW,EAAE,EAC7B,MAAM,GAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAM,GAC7C,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC,CAkB5B;AAED;;;;;;;GAOG;AAEH,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,SAAS,WAAW,EAAE,EAC7B,MAAM,GAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAM,GAC7C,OAAO,CAAC,uBAAuB,CAAC,CAuDlC;AAED;;;;;;;GAOG;AACH,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,KAAK,CAAC,EAAE,SAAS,WAAW,EAAE,EAC9B,WAAW,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAC9C,OAAO,CAAC,OAAO,CAAC,CAalB;AAED,OAAO,EAAE,8BAA8B,EAAE,CAAC"}