@ploaness/governance 1.1.0 → 1.3.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 (236) hide show
  1. package/dist/a11y-hit-target.d.ts.map +1 -1
  2. package/dist/a11y-hit-target.js +1 -21
  3. package/dist/a11y-hit-target.js.map +1 -1
  4. package/dist/a11y-incomplete.d.ts.map +1 -1
  5. package/dist/a11y-incomplete.js +1 -18
  6. package/dist/a11y-incomplete.js.map +1 -1
  7. package/dist/access-boundary.d.ts +43 -1
  8. package/dist/access-boundary.d.ts.map +1 -1
  9. package/dist/access-boundary.js +146 -5
  10. package/dist/access-boundary.js.map +1 -1
  11. package/dist/admin-view-coverage.d.ts.map +1 -1
  12. package/dist/admin-view-coverage.js +1 -17
  13. package/dist/admin-view-coverage.js.map +1 -1
  14. package/dist/asset-policy.d.ts.map +1 -1
  15. package/dist/asset-policy.js +1 -23
  16. package/dist/asset-policy.js.map +1 -1
  17. package/dist/axe-coverage.d.ts +3 -4
  18. package/dist/axe-coverage.d.ts.map +1 -1
  19. package/dist/axe-coverage.js +18 -51
  20. package/dist/axe-coverage.js.map +1 -1
  21. package/dist/blocklist-entries.d.ts +36 -0
  22. package/dist/blocklist-entries.d.ts.map +1 -0
  23. package/dist/blocklist-entries.js +338 -0
  24. package/dist/blocklist-entries.js.map +1 -0
  25. package/dist/blocklist.d.ts +91 -0
  26. package/dist/blocklist.d.ts.map +1 -0
  27. package/dist/blocklist.js +187 -0
  28. package/dist/blocklist.js.map +1 -0
  29. package/dist/checkov-check.d.ts +9 -0
  30. package/dist/checkov-check.d.ts.map +1 -0
  31. package/dist/checkov-check.js +4 -0
  32. package/dist/checkov-check.js.map +1 -0
  33. package/dist/checkov-checks-aws.d.ts +4 -0
  34. package/dist/checkov-checks-aws.d.ts.map +1 -0
  35. package/dist/checkov-checks-aws.js +93 -0
  36. package/dist/checkov-checks-aws.js.map +1 -0
  37. package/dist/checkov-checks-azure.d.ts +4 -0
  38. package/dist/checkov-checks-azure.d.ts.map +1 -0
  39. package/dist/checkov-checks-azure.js +32 -0
  40. package/dist/checkov-checks-azure.js.map +1 -0
  41. package/dist/checkov-checks-google.d.ts +6 -0
  42. package/dist/checkov-checks-google.d.ts.map +1 -0
  43. package/dist/checkov-checks-google.js +53 -0
  44. package/dist/checkov-checks-google.js.map +1 -0
  45. package/dist/checkov-policy.d.ts +63 -0
  46. package/dist/checkov-policy.d.ts.map +1 -0
  47. package/dist/checkov-policy.js +105 -0
  48. package/dist/checkov-policy.js.map +1 -0
  49. package/dist/container-failure.d.ts.map +1 -1
  50. package/dist/container-failure.js +1 -18
  51. package/dist/container-failure.js.map +1 -1
  52. package/dist/container-files.d.ts +16 -0
  53. package/dist/container-files.d.ts.map +1 -1
  54. package/dist/container-files.js +23 -8
  55. package/dist/container-files.js.map +1 -1
  56. package/dist/container-images.d.ts +43 -0
  57. package/dist/container-images.d.ts.map +1 -0
  58. package/dist/container-images.js +157 -0
  59. package/dist/container-images.js.map +1 -0
  60. package/dist/dependency-freshness.d.ts +8 -0
  61. package/dist/dependency-freshness.d.ts.map +1 -1
  62. package/dist/dependency-freshness.js +2 -18
  63. package/dist/dependency-freshness.js.map +1 -1
  64. package/dist/doc-blocks.d.ts.map +1 -1
  65. package/dist/doc-blocks.js +1 -13
  66. package/dist/doc-blocks.js.map +1 -1
  67. package/dist/editorconfig-policy.d.ts +7 -0
  68. package/dist/editorconfig-policy.d.ts.map +1 -1
  69. package/dist/editorconfig-policy.js +19 -12
  70. package/dist/editorconfig-policy.js.map +1 -1
  71. package/dist/environment-coherence.d.ts +59 -5
  72. package/dist/environment-coherence.d.ts.map +1 -1
  73. package/dist/environment-coherence.js +107 -27
  74. package/dist/environment-coherence.js.map +1 -1
  75. package/dist/environment-files.d.ts.map +1 -1
  76. package/dist/environment-files.js +1 -19
  77. package/dist/environment-files.js.map +1 -1
  78. package/dist/file-roles.d.ts +7 -2
  79. package/dist/file-roles.d.ts.map +1 -1
  80. package/dist/file-roles.js +10 -9
  81. package/dist/file-roles.js.map +1 -1
  82. package/dist/freshness-repair.d.ts +82 -0
  83. package/dist/freshness-repair.d.ts.map +1 -0
  84. package/dist/freshness-repair.js +91 -0
  85. package/dist/freshness-repair.js.map +1 -0
  86. package/dist/generated-denial.d.ts.map +1 -1
  87. package/dist/generated-denial.js +1 -9
  88. package/dist/generated-denial.js.map +1 -1
  89. package/dist/generated-drift.d.ts.map +1 -1
  90. package/dist/generated-drift.js +1 -12
  91. package/dist/generated-drift.js.map +1 -1
  92. package/dist/harness-package.d.ts +13 -0
  93. package/dist/harness-package.d.ts.map +1 -0
  94. package/dist/harness-package.js +20 -0
  95. package/dist/harness-package.js.map +1 -0
  96. package/dist/history-policy.d.ts.map +1 -1
  97. package/dist/history-policy.js +1 -7
  98. package/dist/history-policy.js.map +1 -1
  99. package/dist/image-assets.d.ts.map +1 -1
  100. package/dist/image-assets.js +1 -10
  101. package/dist/image-assets.js.map +1 -1
  102. package/dist/index.d.ts +20 -0
  103. package/dist/index.d.ts.map +1 -1
  104. package/dist/index.js +20 -0
  105. package/dist/index.js.map +1 -1
  106. package/dist/install-policy.d.ts +21 -0
  107. package/dist/install-policy.d.ts.map +1 -1
  108. package/dist/install-policy.js +53 -1
  109. package/dist/install-policy.js.map +1 -1
  110. package/dist/jsx-accessibility-scope.d.ts +17 -0
  111. package/dist/jsx-accessibility-scope.d.ts.map +1 -0
  112. package/dist/jsx-accessibility-scope.js +36 -0
  113. package/dist/jsx-accessibility-scope.js.map +1 -0
  114. package/dist/jsx-accessibility.d.ts +13 -0
  115. package/dist/jsx-accessibility.d.ts.map +1 -0
  116. package/dist/jsx-accessibility.js +188 -0
  117. package/dist/jsx-accessibility.js.map +1 -0
  118. package/dist/network-policy.d.ts.map +1 -1
  119. package/dist/network-policy.js +1 -12
  120. package/dist/network-policy.js.map +1 -1
  121. package/dist/oxlint-policy.d.ts +16 -0
  122. package/dist/oxlint-policy.d.ts.map +1 -0
  123. package/dist/oxlint-policy.js +28 -0
  124. package/dist/oxlint-policy.js.map +1 -0
  125. package/dist/oxlint-report.d.ts +29 -0
  126. package/dist/oxlint-report.d.ts.map +1 -0
  127. package/dist/oxlint-report.js +84 -0
  128. package/dist/oxlint-report.js.map +1 -0
  129. package/dist/oxlint-scope.d.ts +13 -0
  130. package/dist/oxlint-scope.d.ts.map +1 -0
  131. package/dist/oxlint-scope.js +46 -0
  132. package/dist/oxlint-scope.js.map +1 -0
  133. package/dist/oxlint-suppressions.d.ts +17 -0
  134. package/dist/oxlint-suppressions.d.ts.map +1 -0
  135. package/dist/oxlint-suppressions.js +72 -0
  136. package/dist/oxlint-suppressions.js.map +1 -0
  137. package/dist/paired-assets.d.ts.map +1 -1
  138. package/dist/paired-assets.js.map +1 -1
  139. package/dist/payload-access.d.ts +6 -0
  140. package/dist/payload-access.d.ts.map +1 -1
  141. package/dist/payload-access.js +166 -9
  142. package/dist/payload-access.js.map +1 -1
  143. package/dist/payload-bootstrap.d.ts +52 -0
  144. package/dist/payload-bootstrap.d.ts.map +1 -0
  145. package/dist/payload-bootstrap.js +195 -0
  146. package/dist/payload-bootstrap.js.map +1 -0
  147. package/dist/payload-configs.d.ts +0 -1
  148. package/dist/payload-configs.d.ts.map +1 -1
  149. package/dist/payload-configs.js +36 -17
  150. package/dist/payload-configs.js.map +1 -1
  151. package/dist/payload-database.d.ts +80 -0
  152. package/dist/payload-database.d.ts.map +1 -0
  153. package/dist/payload-database.js +164 -0
  154. package/dist/payload-database.js.map +1 -0
  155. package/dist/payload-defaults.d.ts +128 -0
  156. package/dist/payload-defaults.d.ts.map +1 -0
  157. package/dist/payload-defaults.js +295 -0
  158. package/dist/payload-defaults.js.map +1 -0
  159. package/dist/payload-policy.d.ts +21 -0
  160. package/dist/payload-policy.d.ts.map +1 -1
  161. package/dist/payload-policy.js +92 -43
  162. package/dist/payload-policy.js.map +1 -1
  163. package/dist/relationship-cleanup.d.ts.map +1 -1
  164. package/dist/relationship-cleanup.js +16 -16
  165. package/dist/relationship-cleanup.js.map +1 -1
  166. package/dist/release-age.d.ts.map +1 -1
  167. package/dist/release-age.js +1 -16
  168. package/dist/release-age.js.map +1 -1
  169. package/dist/request-limits.d.ts.map +1 -1
  170. package/dist/request-limits.js +1 -11
  171. package/dist/request-limits.js.map +1 -1
  172. package/dist/route-map.d.ts.map +1 -1
  173. package/dist/route-map.js +1 -16
  174. package/dist/route-map.js.map +1 -1
  175. package/dist/run-plan.d.ts.map +1 -1
  176. package/dist/run-plan.js +1 -19
  177. package/dist/run-plan.js.map +1 -1
  178. package/dist/secret-policy.d.ts.map +1 -1
  179. package/dist/secret-policy.js +1 -11
  180. package/dist/secret-policy.js.map +1 -1
  181. package/dist/settings-layering.d.ts +8 -30
  182. package/dist/settings-layering.d.ts.map +1 -1
  183. package/dist/settings-layering.js +19 -48
  184. package/dist/settings-layering.js.map +1 -1
  185. package/dist/settings.d.ts +9 -2
  186. package/dist/settings.d.ts.map +1 -1
  187. package/dist/settings.js.map +1 -1
  188. package/dist/shell-files.d.ts +45 -0
  189. package/dist/shell-files.d.ts.map +1 -0
  190. package/dist/shell-files.js +105 -0
  191. package/dist/shell-files.js.map +1 -0
  192. package/dist/source-security.d.ts +10 -0
  193. package/dist/source-security.d.ts.map +1 -1
  194. package/dist/source-security.js +88 -1
  195. package/dist/source-security.js.map +1 -1
  196. package/dist/source-text.d.ts +2 -0
  197. package/dist/source-text.d.ts.map +1 -1
  198. package/dist/source-text.js +7 -16
  199. package/dist/source-text.js.map +1 -1
  200. package/dist/terraform-files.d.ts +29 -0
  201. package/dist/terraform-files.d.ts.map +1 -0
  202. package/dist/terraform-files.js +50 -0
  203. package/dist/terraform-files.js.map +1 -0
  204. package/dist/terraform-policy.d.ts +13 -0
  205. package/dist/terraform-policy.d.ts.map +1 -0
  206. package/dist/terraform-policy.js +261 -0
  207. package/dist/terraform-policy.js.map +1 -0
  208. package/dist/terraform-providers.d.ts +28 -0
  209. package/dist/terraform-providers.d.ts.map +1 -0
  210. package/dist/terraform-providers.js +68 -0
  211. package/dist/terraform-providers.js.map +1 -0
  212. package/dist/toolchain-pins.d.ts +1 -1
  213. package/dist/toolchain-pins.d.ts.map +1 -1
  214. package/dist/toolchain-pins.js +11 -21
  215. package/dist/toolchain-pins.js.map +1 -1
  216. package/dist/version-policy.d.ts +7 -8
  217. package/dist/version-policy.d.ts.map +1 -1
  218. package/dist/version-policy.js +15 -26
  219. package/dist/version-policy.js.map +1 -1
  220. package/dist/vulnerability-policy.d.ts.map +1 -1
  221. package/dist/vulnerability-policy.js +1 -11
  222. package/dist/vulnerability-policy.js.map +1 -1
  223. package/dist/wiring-policy.d.ts.map +1 -1
  224. package/dist/wiring-policy.js +4 -1
  225. package/dist/wiring-policy.js.map +1 -1
  226. package/dist/wiring-violation.d.ts.map +1 -1
  227. package/dist/wiring-violation.js +1 -6
  228. package/dist/wiring-violation.js.map +1 -1
  229. package/dist/workspace-policy.d.ts.map +1 -1
  230. package/dist/workspace-policy.js +3 -9
  231. package/dist/workspace-policy.js.map +1 -1
  232. package/dist/yaml-blocks.d.ts +10 -0
  233. package/dist/yaml-blocks.d.ts.map +1 -1
  234. package/dist/yaml-blocks.js +20 -0
  235. package/dist/yaml-blocks.js.map +1 -1
  236. package/package.json +2 -2
@@ -0,0 +1,72 @@
1
+ import { OXLINT_ACCESSIBILITY_NAMES, oxlintRuleNames, oxlintRules } from './oxlint-policy.js';
2
+ const NATIVE = 'oxlint';
3
+ const LEGACY = 'eslint';
4
+ const DISABLE = 'disable';
5
+ const CLAUSE_COUNT = 2;
6
+ const RULES = oxlintRuleNames(oxlintRules(true));
7
+ const LEGACY_RULES = new Set([...RULES].flatMap((rule) => [
8
+ rule,
9
+ rule.slice(rule.indexOf('/') + 1),
10
+ ]));
11
+ const commentBody = (text) => text
12
+ .replace(/^\/\/?\*?/u, '')
13
+ .replace(/\*\/$/u, '')
14
+ .trim();
15
+ /** Whether a native directive opens a suppression and therefore spends the existing budget. */
16
+ export const isOxlintSuppression = (comment) => commentBody(comment.text).startsWith(`${NATIVE}-${DISABLE}`);
17
+ const directiveProblems = (body, applicable) => {
18
+ const [declaration = '', explanation = ''] = body.split(' -- ', CLAUSE_COUNT);
19
+ const [form = '', ...names] = declaration.split(/\s+/u);
20
+ const rules = names
21
+ .join(' ')
22
+ .split(/[\s,]+/u)
23
+ .filter(Boolean);
24
+ return [
25
+ ...([`${NATIVE}-${DISABLE}-next-line`, `${NATIVE}-${DISABLE}-line`].includes(form)
26
+ ? []
27
+ : ['use a line or next-line Oxlint suppression, never a file-wide directive']),
28
+ ...(rules.length > 0 && rules.every((rule) => applicable.includes(rule))
29
+ ? []
30
+ : ['name the exact governed rule(s) active for this file']),
31
+ ...(explanation.trim().length > 0 ? [] : ['provide a suppression reason after --']),
32
+ ];
33
+ };
34
+ const isLegacySuppression = (body) => {
35
+ const isLegacy = body.startsWith(`${LEGACY}-${DISABLE}`) || body.startsWith(`${LEGACY}-enable`);
36
+ const declaration = (body.split('--', CLAUSE_COUNT)[0] ?? '').trim();
37
+ const isBlanket = [
38
+ `${LEGACY}-enable`,
39
+ `${LEGACY}-${DISABLE}`,
40
+ `${LEGACY}-${DISABLE}-next-line`,
41
+ `${LEGACY}-${DISABLE}-line`,
42
+ ].includes(declaration);
43
+ const hasNativeRule = declaration
44
+ .split(/[\s,:]+/u)
45
+ .some((name) => LEGACY_RULES.has(name) || name.startsWith('jsx-a11y/'));
46
+ const isInline = body.startsWith(`${LEGACY} `) && hasNativeRule;
47
+ return isInline || (isLegacy && (isBlanket || hasNativeRule));
48
+ };
49
+ /** A narrow directive for another ESLint rule remains that analyzer's responsibility. */
50
+ export const isEslintOwnedSuppression = (comment) => {
51
+ const body = commentBody(comment.text);
52
+ return ((body.startsWith(`${LEGACY}-${DISABLE}`) || body.startsWith(`${LEGACY}-enable`)) &&
53
+ !isLegacySuppression(body));
54
+ };
55
+ /**
56
+ * Validate suppressions before the tool can obey them.
57
+ * @param comments parser-recognized source comments.
58
+ * @param applicable the canonical rules actually enabled for this file.
59
+ * @returns line-numbered findings for broad, stale-namespace, or unexplained directives.
60
+ */
61
+ export const oxlintSuppressionProblems = (comments, applicable = OXLINT_ACCESSIBILITY_NAMES) => comments.flatMap((comment) => {
62
+ const body = commentBody(comment.text);
63
+ if (body.startsWith(`${NATIVE}-`)) {
64
+ return directiveProblems(body, applicable).map((problem) => `line ${String(comment.line)}: ${problem}`);
65
+ }
66
+ return isLegacySuppression(body)
67
+ ? [
68
+ `line ${String(comment.line)}: use a named, explained Oxlint line suppression for native-owned rules`,
69
+ ]
70
+ : [];
71
+ });
72
+ //# sourceMappingURL=oxlint-suppressions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oxlint-suppressions.js","sourceRoot":"","sources":["../src/oxlint-suppressions.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"paired-assets.d.ts","sourceRoot":"","sources":["../src/paired-assets.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAiCrD,0DAA0D;AAC1D,MAAM,WAAW,WAAW;IAC1B,yEAAyE;IACzE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,+DAA+D;IAC/D,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAC3B;AAED,4FAA4F;AAC5F,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAA;IAC1B,2EAA2E;IAC3E,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,CAAA;IACxC,2EAA2E;IAC3E,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,CAAA;CAC1C;AAED,8CAA8C;AAC9C,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CACxB;AAED;;;;GAIG;AACH,eAAO,MAAM,YAAY,GAAI,QAAQ,SAAS,YAAY,EAAE,KAAG,SAAS,WAAW,EAY9E,CAAA;AAkBL;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,GAC/B,QAAQ,SAAS,gBAAgB,EAAE,KAClC,SAAS,gBAAgB,EAIxB,CAAA"}
1
+ {"version":3,"file":"paired-assets.d.ts","sourceRoot":"","sources":["../src/paired-assets.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAiCrD,0DAA0D;AAC1D,MAAM,WAAW,WAAW;IAC1B,yEAAyE;IACzE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,+DAA+D;IAC/D,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAC3B;AAED,4FAA4F;AAC5F,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAA;IAC1B,2EAA2E;IAC3E,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,CAAA;IACxC,2EAA2E;IAC3E,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,CAAA;CAC1C;AAED,8CAA8C;AAC9C,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CACxB;AAED;;;;GAIG;AACH,eAAO,MAAM,YAAY,GAAI,QAAQ,SAAS,YAAY,EAAE,KAAG,SAAS,WAAW,EAY9E,CAAA;AAkBL;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,GAC/B,QAAQ,SAAS,gBAAgB,EAAE,KAClC,SAAS,gBAAgB,EAIxB,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"paired-assets.js","sourceRoot":"","sources":["../src/paired-assets.ts"],"names":[],"mappings":"AAaA,+FAA+F;AAC/F,MAAM,eAAe,GAAW,OAAO,CAAA;AAEvC,wGAAwG;AACxG,MAAM,YAAY,GAAW,QAAQ,CAAA;AAErC,kGAAkG;AAClG,wCAAwC;AACxC,EAAE;AACF,qGAAqG;AACrG,uGAAuG;AACvG,uGAAuG;AACvG,mGAAmG;AACnG,qGAAqG;AACrG,oGAAoG;AACpG,uCAAuC;AACvC,EAAE;AACF,qGAAqG;AACrG,wGAAwG;AACxG,yBAAyB;AACzB,EAAE;AACF,qGAAqG;AACrG,MAAM,oBAAoB,GAAwB,IAAI,GAAG,CAAS;IAChE,0BAA0B;IAC1B,eAAe;IACf,4BAA4B;IAC5B,wCAAwC;IACxC,uCAAuC;IACvC,cAAc;CACf,CAAC,CAAA;AAyBF;;;;GAIG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,MAA+B,EAA0B,EAAE,CACtF,MAAM;KACH,MAAM,CACL,CAAC,KAAmB,EAAW,EAAE,CAC/B,CAAC,KAAK,CAAC,WAAW,KAAK,QAAQ,IAAI,KAAK,CAAC,WAAW,KAAK,MAAM,CAAC;IAChE,CAAC,oBAAoB,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CACxC;KACA,GAAG,CACF,CAAC,KAAmB,EAAe,EAAE,CAAC,CAAC;IACrC,QAAQ,EAAE,KAAK,CAAC,IAAI;IACpB,SAAS,EAAE,GAAG,eAAe,IAAI,KAAK,CAAC,IAAI,GAAG,YAAY,EAAE;CAC7D,CAAC,CACH,CAAA;AAEL,MAAM,WAAW,GAAG,CAAC,KAAuB,EAAsB,EAAE;IAClE,IAAI,KAAK,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;QACpC,OAAO,CACL,4BAA4B,KAAK,CAAC,IAAI,CAAC,SAAS,4BAA4B;YAC5E,2CAA2C,CAC5C,CAAA;IACH,CAAC;IACD,IAAI,KAAK,CAAC,YAAY,KAAK,SAAS,EAAE,CAAC;QACrC,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,oDAAoD,CAAA;IACpF,CAAC;IACD,OAAO,KAAK,CAAC,WAAW,KAAK,KAAK,CAAC,YAAY;QAC7C,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,sBAAsB,KAAK,CAAC,IAAI,CAAC,QAAQ,oBAAoB;YAClF,4DAA4D,CAAA;AACpE,CAAC,CAAA;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAClC,MAAmC,EACN,EAAE,CAC/B,MAAM,CAAC,OAAO,CAAC,CAAC,KAAuB,EAA+B,EAAE;IACtE,MAAM,MAAM,GAAuB,WAAW,CAAC,KAAK,CAAC,CAAA;IACrD,OAAO,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAA;AAChF,CAAC,CAAC,CAAA"}
1
+ {"version":3,"file":"paired-assets.js","sourceRoot":"","sources":["../src/paired-assets.ts"],"names":[],"mappings":"AAGA,+FAA+F;AAC/F,MAAM,eAAe,GAAW,OAAO,CAAA;AAEvC,wGAAwG;AACxG,MAAM,YAAY,GAAW,QAAQ,CAAA;AAErC,kGAAkG;AAClG,wCAAwC;AACxC,EAAE;AACF,qGAAqG;AACrG,uGAAuG;AACvG,uGAAuG;AACvG,mGAAmG;AACnG,qGAAqG;AACrG,oGAAoG;AACpG,uCAAuC;AACvC,EAAE;AACF,qGAAqG;AACrG,wGAAwG;AACxG,yBAAyB;AACzB,EAAE;AACF,qGAAqG;AACrG,MAAM,oBAAoB,GAAwB,IAAI,GAAG,CAAS;IAChE,0BAA0B;IAC1B,eAAe;IACf,4BAA4B;IAC5B,wCAAwC;IACxC,uCAAuC;IACvC,cAAc;CACf,CAAC,CAAA;AAyBF;;;;GAIG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,MAA+B,EAA0B,EAAE,CACtF,MAAM;KACH,MAAM,CACL,CAAC,KAAmB,EAAW,EAAE,CAC/B,CAAC,KAAK,CAAC,WAAW,KAAK,QAAQ,IAAI,KAAK,CAAC,WAAW,KAAK,MAAM,CAAC;IAChE,CAAC,oBAAoB,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CACxC;KACA,GAAG,CACF,CAAC,KAAmB,EAAe,EAAE,CAAC,CAAC;IACrC,QAAQ,EAAE,KAAK,CAAC,IAAI;IACpB,SAAS,EAAE,GAAG,eAAe,IAAI,KAAK,CAAC,IAAI,GAAG,YAAY,EAAE;CAC7D,CAAC,CACH,CAAA;AAEL,MAAM,WAAW,GAAG,CAAC,KAAuB,EAAsB,EAAE;IAClE,IAAI,KAAK,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;QACpC,OAAO,CACL,4BAA4B,KAAK,CAAC,IAAI,CAAC,SAAS,4BAA4B;YAC5E,2CAA2C,CAC5C,CAAA;IACH,CAAC;IACD,IAAI,KAAK,CAAC,YAAY,KAAK,SAAS,EAAE,CAAC;QACrC,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,oDAAoD,CAAA;IACpF,CAAC;IACD,OAAO,KAAK,CAAC,WAAW,KAAK,KAAK,CAAC,YAAY;QAC7C,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,sBAAsB,KAAK,CAAC,IAAI,CAAC,QAAQ,oBAAoB;YAClF,4DAA4D,CAAA;AACpE,CAAC,CAAA;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAClC,MAAmC,EACN,EAAE,CAC/B,MAAM,CAAC,OAAO,CAAC,CAAC,KAAuB,EAA+B,EAAE;IACtE,MAAM,MAAM,GAAuB,WAAW,CAAC,KAAK,CAAC,CAAA;IACrD,OAAO,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAA;AAChF,CAAC,CAAC,CAAA"}
@@ -2,8 +2,14 @@ import { type PayloadViolation } from './payload-source.js';
2
2
  export declare const findUndeclaredAccess: (source: string) => readonly PayloadViolation[];
3
3
  /** Report an auth collection that leaves the login-attempt cap and lock time to Payload's defaults. */
4
4
  export declare const findUnhardenedAuth: (source: string) => readonly PayloadViolation[];
5
+ /** Report an auth collection that leaves who may clear a lockout to Payload's default. */
6
+ export declare const findUnlockableAuth: (source: string) => readonly PayloadViolation[];
5
7
  /** Report a config whose drafts are readable by an unauthenticated client. */
6
8
  export declare const findAnonymousDraftReads: (source: string) => readonly PayloadViolation[];
9
+ /** Report a config that keeps versions and leaves who may read them to Payload's fall-through. */
10
+ export declare const findUndeclaredVersionReads: (source: string) => readonly PayloadViolation[];
7
11
  /** Report an upload collection that accepts whatever file type Payload's defaults allow. */
8
12
  export declare const findUnrestrictedUploads: (source: string) => readonly PayloadViolation[];
13
+ /** Report an upload collection that admits SVG, or may, without deciding the headers it is served with. */
14
+ export declare const findUndecidedSvgHeaders: (source: string) => readonly PayloadViolation[];
9
15
  //# sourceMappingURL=payload-access.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"payload-access.d.ts","sourceRoot":"","sources":["../src/payload-access.ts"],"names":[],"mappings":"AAaA,OAAO,EAIL,KAAK,gBAAgB,EACtB,MAAM,qBAAqB,CAAA;AAe5B,eAAO,MAAM,oBAAoB,GAAI,QAAQ,MAAM,KAAG,SAAS,gBAAgB,EAqB5E,CAAA;AA8CH,uGAAuG;AACvG,eAAO,MAAM,kBAAkB,GAAI,QAAQ,MAAM,KAAG,SAAS,gBAAgB,EAK1E,CAAA;AA2CH,8EAA8E;AAC9E,eAAO,MAAM,uBAAuB,GAAI,QAAQ,MAAM,KAAG,SAAS,gBAAgB,EAe/E,CAAA;AA6BH,4FAA4F;AAC5F,eAAO,MAAM,uBAAuB,GAAI,QAAQ,MAAM,KAAG,SAAS,gBAAgB,EAK/E,CAAA"}
1
+ {"version":3,"file":"payload-access.d.ts","sourceRoot":"","sources":["../src/payload-access.ts"],"names":[],"mappings":"AAaA,OAAO,EAIL,KAAK,gBAAgB,EACtB,MAAM,qBAAqB,CAAA;AAsB5B,eAAO,MAAM,oBAAoB,GAAI,QAAQ,MAAM,KAAG,SAAS,gBAAgB,EAqB5E,CAAA;AA8CH,uGAAuG;AACvG,eAAO,MAAM,kBAAkB,GAAI,QAAQ,MAAM,KAAG,SAAS,gBAAgB,EAK1E,CAAA;AA6BH,0FAA0F;AAC1F,eAAO,MAAM,kBAAkB,GAAI,QAAQ,MAAM,KAAG,SAAS,gBAAgB,EAK1E,CAAA;AAgDH,8EAA8E;AAC9E,eAAO,MAAM,uBAAuB,GAAI,QAAQ,MAAM,KAAG,SAAS,gBAAgB,EAe/E,CAAA;AAiBH,kGAAkG;AAClG,eAAO,MAAM,0BAA0B,GAAI,QAAQ,MAAM,KAAG,SAAS,gBAAgB,EAkBlF,CAAA;AA6BH,4FAA4F;AAC5F,eAAO,MAAM,uBAAuB,GAAI,QAAQ,MAAM,KAAG,SAAS,gBAAgB,EAK/E,CAAA;AAsIH,2GAA2G;AAC3G,eAAO,MAAM,uBAAuB,GAAI,QAAQ,MAAM,KAAG,SAAS,gBAAgB,EAK/E,CAAA"}
@@ -7,12 +7,12 @@
7
7
  // make on the project's behalf if the project does not make it first.
8
8
  import { payloadConfigsIn, } from './payload-configs.js';
9
9
  import { configBody, depthOneBlockKeys, depthOneValue, } from './payload-source.js';
10
- import { NOT_FOUND, topLevelKeys } from './source-text.js';
10
+ import { balancedArguments, NOT_FOUND, scanDelimited, topLevelKeys, } from './source-text.js';
11
11
  const eachConfig = (source, judge) => payloadConfigsIn(source).flatMap((found) => judge(found.kind, found));
12
12
  // Payload fills the missing operations in during sanitisation, so a partial access block is invisible
13
- // the moment the app boots - and its default for a non-auth collection is public read. Checking that
14
- // the word `access` appears somewhere in the file, which is what this rule used to do, accepted a block
15
- // that declared one operation out of four.
13
+ // the moment the app boots - and its default admits every signed-in user to every operation. Checking
14
+ // that the word `access` appears somewhere in the file, which is what this rule used to do, accepted a
15
+ // block that declared one operation out of four.
16
16
  export const findUndeclaredAccess = (source) => eachConfig(source, (kind, found) => {
17
17
  const declared = depthOneBlockKeys(found.body, 'access');
18
18
  const missing = kind.operations.filter((operation) => !declared.includes(operation));
@@ -23,8 +23,8 @@ export const findUndeclaredAccess = (source) => eachConfig(source, (kind, found)
23
23
  line: found.line,
24
24
  rule: 'require-complete-access',
25
25
  reason: `a ${kind.label} must declare access for ${kind.operations.join(', ')}; ` +
26
- `${missing.join(', ')} ${missing.length === 1 ? 'is' : 'are'} left to the Payload ` +
27
- 'defaults, which allow public read',
26
+ `${missing.join(', ')} ${missing.length === 1 ? 'is' : 'are'} left to Payload's ` +
27
+ 'default, which admits every signed-in user',
28
28
  },
29
29
  ];
30
30
  });
@@ -65,6 +65,32 @@ const unhardenedAuthIn = (found) => {
65
65
  };
66
66
  /** Report an auth collection that leaves the login-attempt cap and lock time to Payload's defaults. */
67
67
  export const findUnhardenedAuth = (source) => eachConfig(source, (kind, found) => kind.label === COLLECTION ? unhardenedAuthIn(found) : []);
68
+ // The cap above, undone from inside. `unlock` is one of the operations Payload fills the access block
69
+ // with during sanitisation, so a collection that decides create, read, update and delete has still said
70
+ // nothing about who may clear a locked account - and the default admits every signed-in user. One
71
+ // ordinary account can therefore lift the lockout on another as fast as the attempts accrue, which
72
+ // leaves the attempt cap and lock time enforced by the rule above protecting nothing. Advisory
73
+ // GHSA-jg8r-5jh2-v2xj is this default, reported against Payload itself.
74
+ const UNLOCK_OPERATION = 'unlock';
75
+ const unlockableAuthIn = (found) => {
76
+ if (depthOneValue(found.body, 'auth') === undefined) {
77
+ return [];
78
+ }
79
+ const declared = depthOneBlockKeys(found.body, 'access');
80
+ return declared.includes(UNLOCK_OPERATION)
81
+ ? []
82
+ : [
83
+ {
84
+ line: found.line,
85
+ rule: 'require-unlock-access',
86
+ reason: `an auth collection must declare access for ${UNLOCK_OPERATION}; Payload fills it with ` +
87
+ 'a default that admits every signed-in user, so one account can clear the lockout on ' +
88
+ 'another and undo the attempt cap',
89
+ },
90
+ ];
91
+ };
92
+ /** Report an auth collection that leaves who may clear a lockout to Payload's default. */
93
+ export const findUnlockableAuth = (source) => eachConfig(source, (kind, found) => kind.label === COLLECTION ? unlockableAuthIn(found) : []);
68
94
  // A draft is unpublished content. With versions.drafts enabled, `?draft=true` serves it to whoever the
69
95
  // read rule admits - so a read that is unconditionally true publishes every draft to anyone.
70
96
  const DRAFTS_ENABLED = /drafts\s*:\s*(?:true|\{)/;
@@ -87,9 +113,14 @@ const blockEnd = (access, open) => {
87
113
  // collection itself were open to anyone.
88
114
  //
89
115
  // Only the inline form is decidable here, and the lint pass forbids that form in a config file, so a
90
- // conforming project writes `read: anyone` and this rule stays silent on it. What covers the conforming
91
- // case is the managed access-boundary sweep, which asks the running application what it grants rather
92
- // than reading the source. This rule reaches a config declared outside the linted directories.
116
+ // conforming project writes `read: anyone` and this rule stays silent on it. This rule therefore
117
+ // reaches only a config declared outside the linted directories.
118
+ //
119
+ // What covers the conforming case is `findUnconstrainedDraftReads` in payload-defaults.ts, which asks
120
+ // the built configuration's own read rule what it answers a stranger and reads the constraint it hands
121
+ // back. The anonymous sweep does NOT cover it: the sweep separates a grant carrying a query constraint
122
+ // from one that does not, and never opens the constraint, so a read filtered by audience and not by
123
+ // status passed it. That gap was open for as long as this comment claimed the sweep closed it.
93
124
  const isDraftExposed = (body) => {
94
125
  const versions = depthOneValue(body, 'versions');
95
126
  if (versions === undefined || !DRAFTS_ENABLED.test(versions)) {
@@ -113,6 +144,32 @@ export const findAnonymousDraftReads = (source) => eachConfig(source, (kind, fou
113
144
  },
114
145
  ]
115
146
  : []);
147
+ // The read rule, bypassed by asking a different question. A version carries the whole document, and
148
+ // `readVersions` is the one access operation Payload never fills in - for a collection or a global - so
149
+ // an undeclared rule is not absent but open: `executeAccess` falls through to "any signed-in user" when
150
+ // it is handed nothing. A read narrowed to an audience by a `Where` filter therefore still hands every
151
+ // stored version of every document to anyone signed in. This is asked wherever versions are kept rather
152
+ // than only where drafts are, because the versions route exists either way.
153
+ const VERSIONS_DISABLED = /^\s*false\s*(?=[,}])/;
154
+ const READ_VERSIONS_OPERATION = 'readVersions';
155
+ const carriesVersions = (body) => {
156
+ const versions = depthOneValue(body, 'versions');
157
+ return versions !== undefined && !VERSIONS_DISABLED.test(versions);
158
+ };
159
+ /** Report a config that keeps versions and leaves who may read them to Payload's fall-through. */
160
+ export const findUndeclaredVersionReads = (source) => eachConfig(source, (kind, found) => carriesVersions(found.body) &&
161
+ !depthOneBlockKeys(found.body, 'access').includes(READ_VERSIONS_OPERATION)
162
+ ? [
163
+ {
164
+ line: found.line,
165
+ rule: 'require-version-read-access',
166
+ reason: `a ${kind.label} that keeps versions must declare access for ` +
167
+ `${READ_VERSIONS_OPERATION}; Payload leaves it undeclared and then admits every ` +
168
+ 'signed-in user, so a scoped read is bypassed by asking for a version of a document ' +
169
+ 'instead of the document',
170
+ },
171
+ ]
172
+ : []);
116
173
  // `mimeTypes` defaults to undefined, so an upload collection takes whatever a client sends until the
117
174
  // project says otherwise. Served from the application's own origin, an uploaded SVG is script that runs
118
175
  // as the site, which is why the restriction is required rather than advised. No size cap is asked for
@@ -139,4 +196,104 @@ const unrestrictedUploadIn = (found) => {
139
196
  };
140
197
  /** Report an upload collection that accepts whatever file type Payload's defaults allow. */
141
198
  export const findUnrestrictedUploads = (source) => eachConfig(source, (kind, found) => kind.label === COLLECTION ? unrestrictedUploadIn(found) : []);
199
+ // An upload collection that admits SVG and has not decided how the file is served.
200
+ //
201
+ // Payload adds `Content-Security-Policy: script-src 'none'` to an SVG file response, and refuses an SVG
202
+ // whose text carries a script - but only on the branch where content detection found nothing and fell
203
+ // back to the extension. An SVG that opens with an XML declaration is detected as XML, retyped as SVG,
204
+ // and skips that check entirely. So a collection that admits SVG must decide the headers itself, through
205
+ // `modifyResponseHeaders`, or through a `handlers` entry, which answers before the headers hook runs and
206
+ // is therefore the same decision. Admission is read the way Payload reads it in `validateMimeType`: an
207
+ // entry loses its first `*` and must be a prefix of the file's type, and an empty list admits everything.
208
+ //
209
+ // A list this reader cannot see - an imported constant, a spread, a call, a template with a
210
+ // substitution - is treated as admitting SVG, because a rule whose silence means "safe" cannot be silent
211
+ // where it cannot read. The repair is cheap either way: write the list inline, or declare the headers,
212
+ // which cost an image nothing.
213
+ const SVG_MIME_TYPE = 'image/svg+xml';
214
+ const RESPONSE_HEADER_KEYS = ['modifyResponseHeaders', 'handlers'];
215
+ const ARRAY_OPEN = '[';
216
+ const EMPTY_LIST = '[]';
217
+ // A quoted string with nothing that could be a substitution inside it; a MIME type carries no quote.
218
+ const STRING_LITERAL = /^(['"`])([^'"`$]*)\1$/;
219
+ // The upload block alone, cut where its own braces close. `depthOneValue` runs to the end of the
220
+ // collection literal, so a depth-one key looked for in that slice would also be found in the NEXT
221
+ // block: `admin: { mimeTypes: ... }` would answer for `upload`.
222
+ const uploadBlockOf = (found) => {
223
+ const value = depthOneValue(found.body, 'upload');
224
+ if (value === undefined) {
225
+ return undefined;
226
+ }
227
+ const open = value.indexOf('{');
228
+ return value.trimStart().startsWith('{') ? value.slice(open, blockEnd(value, open)) : undefined;
229
+ };
230
+ const coversSvg = (entry) => SVG_MIME_TYPE.startsWith(entry.replace('*', ''));
231
+ // The depth-zero elements of an array's inner text. `topLevelSlice` cannot serve here: the scanner
232
+ // jumps a string literal whole, so that slice drops exactly the characters this rule reads.
233
+ const arrayElements = (inner) => {
234
+ const commas = scanDelimited(inner, 0, (found, step) => step.character === ',' && step.depth === 0
235
+ ? { state: [...found, step.index], stop: false }
236
+ : { state: found, stop: false }, []);
237
+ const bounds = [-1, ...commas, inner.length];
238
+ return bounds
239
+ .slice(0, -1)
240
+ .map((start, position) => inner.slice(start + 1, bounds[position + 1] ?? inner.length).trim())
241
+ .filter((element) => element.length > 0);
242
+ };
243
+ const literalOf = (element) => STRING_LITERAL.exec(element)?.[2];
244
+ // A provable admission outranks an unreadable neighbour, so `[...IMAGE_TYPES, 'image/svg+xml']` is
245
+ // reported for the entry that can be named rather than for the spread that cannot.
246
+ const svgAdmissionOf = (raw) => {
247
+ if (!raw.trimStart().startsWith(ARRAY_OPEN)) {
248
+ return { verdict: 'unreadable' };
249
+ }
250
+ const inner = balancedArguments(raw, raw.indexOf(ARRAY_OPEN));
251
+ if (inner === undefined) {
252
+ return { verdict: 'unreadable' };
253
+ }
254
+ const elements = arrayElements(inner);
255
+ if (elements.length === 0) {
256
+ return { verdict: 'admitted', entry: EMPTY_LIST };
257
+ }
258
+ const literals = elements.map((element) => literalOf(element));
259
+ const admitting = literals.find((literal) => literal !== undefined && coversSvg(literal));
260
+ if (admitting !== undefined) {
261
+ return { verdict: 'admitted', entry: admitting };
262
+ }
263
+ return literals.every((literal) => literal !== undefined)
264
+ ? { verdict: 'excluded' }
265
+ : { verdict: 'unreadable' };
266
+ };
267
+ const SVG_REPAIR = 'set Content-Disposition: attachment and Content-Security-Policy: sandbox in modifyResponseHeaders';
268
+ const SVG_HAZARD = 'an SVG served from this origin is script that runs as the site';
269
+ const svgReason = (admission) => {
270
+ const preamble = `an upload collection admitting SVG must declare ${RESPONSE_HEADER_KEYS.join(' or ')}; `;
271
+ if (admission.verdict === 'unreadable') {
272
+ return (`${preamble}mimeTypes here is not an inline list of string literals, so whether it admits ` +
273
+ `${SVG_MIME_TYPE} cannot be read from this file, and ${SVG_HAZARD}; write the list inline, or ${SVG_REPAIR}`);
274
+ }
275
+ const admits = admission.entry === EMPTY_LIST
276
+ ? `the empty mimeTypes list admits every type, ${SVG_MIME_TYPE} included`
277
+ : `the mimeTypes entry '${admission.entry}' admits ${SVG_MIME_TYPE}`;
278
+ return (`${preamble}${admits}, ${SVG_HAZARD}, and Payload's own scripted-SVG check skips a file that ` +
279
+ `opens with an XML declaration; ${SVG_REPAIR}, or drop the entry`);
280
+ };
281
+ const undecidedSvgHeadersIn = (found) => {
282
+ const block = uploadBlockOf(found);
283
+ if (block === undefined) {
284
+ return [];
285
+ }
286
+ const keys = topLevelKeys(block, 0);
287
+ // An absent list is the restriction rule's finding, so one collection never carries both.
288
+ if (!keys.includes(UPLOAD_RESTRICTION) ||
289
+ RESPONSE_HEADER_KEYS.some((key) => keys.includes(key))) {
290
+ return [];
291
+ }
292
+ const admission = svgAdmissionOf(depthOneValue(block, UPLOAD_RESTRICTION) ?? '');
293
+ return admission.verdict === 'excluded'
294
+ ? []
295
+ : [{ line: found.line, rule: 'require-svg-response-headers', reason: svgReason(admission) }];
296
+ };
297
+ /** Report an upload collection that admits SVG, or may, without deciding the headers it is served with. */
298
+ export const findUndecidedSvgHeaders = (source) => eachConfig(source, (kind, found) => kind.label === COLLECTION ? undecidedSvgHeadersIn(found) : []);
142
299
  //# sourceMappingURL=payload-access.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"payload-access.js","sourceRoot":"","sources":["../src/payload-access.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"payload-access.js","sourceRoot":"","sources":["../src/payload-access.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ import type { SpecSource } from './axe-coverage.js';
2
+ import type { LocatedViolation } from './relationship-cleanup.js';
3
+ /**
4
+ * The Local API operations that change stored state.
5
+ *
6
+ * Derived from the one catalogue rather than written out again: a second list is a second thing to keep
7
+ * in step, and the two would disagree the first time Payload gained an operation. A read at boot is
8
+ * legitimate and deliberately absent from this set.
9
+ */
10
+ export declare const LOCAL_API_MUTATIONS: readonly string[];
11
+ /** The body of a configuration's boot hook, and the line its configuration begins on. */
12
+ export interface BootstrapHook {
13
+ readonly body: string;
14
+ readonly line: number;
15
+ }
16
+ /**
17
+ * The boot hook every root configuration in a source declares.
18
+ * @param code the file's text, with comments already stripped.
19
+ * @returns one entry per configuration that declares `onInit` with a body.
20
+ */
21
+ export declare const bootstrapHooksIn: (code: string) => readonly BootstrapHook[];
22
+ /**
23
+ * The module specifier a name is imported from.
24
+ * @param code the importing file's text.
25
+ * @param name the imported binding to find.
26
+ * @returns the specifier, or undefined when the file imports no such name.
27
+ */
28
+ export declare const moduleOfImport: (code: string, name: string) => string | undefined;
29
+ /**
30
+ * The repository-relative paths a specifier could name, in the order a resolver would try them.
31
+ * @param specifier the module specifier as written.
32
+ * @param fromPath the member-relative path of the importing file.
33
+ * @returns the candidate paths, empty when the specifier names a package rather than project source.
34
+ */
35
+ export declare const candidatePathsFor: (specifier: string, fromPath: string) => readonly string[];
36
+ /**
37
+ * The body of a named export.
38
+ * @param source the module's text, with comments already stripped.
39
+ * @param name the exported binding to read.
40
+ * @returns the body, or undefined when the module exports no such binding with one.
41
+ */
42
+ export declare const exportedBodyIn: (source: string, name: string) => string | undefined;
43
+ /**
44
+ * Report every Local API write a boot hook performs, or reaches in one call.
45
+ *
46
+ * Reported against the configuration that schedules the write rather than the module that performs it:
47
+ * the module may be a legitimate seed, and what makes it a defect is being wired into `onInit`.
48
+ * @param files every source file of the member, as read.
49
+ * @returns one violation per write, located on the configuration that declares the hook.
50
+ */
51
+ export declare const findBootstrapWrites: (files: readonly SpecSource[]) => readonly LocatedViolation[];
52
+ //# sourceMappingURL=payload-bootstrap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"payload-bootstrap.d.ts","sourceRoot":"","sources":["../src/payload-bootstrap.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAInD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAA;AAajE;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,EAAE,SAAS,MAAM,EAEhD,CAAA;AAED,yFAAyF;AACzF,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CACtB;AAaD;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,GAAI,MAAM,MAAM,KAAG,SAAS,aAAa,EAKlE,CAAA;AAkDJ;;;;;GAKG;AACH,eAAO,MAAM,cAAc,GAAI,MAAM,MAAM,EAAE,MAAM,MAAM,KAAG,MAAM,GAAG,SAI3D,CAAA;AAkCV;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,GAAI,WAAW,MAAM,EAAE,UAAU,MAAM,KAAG,SAAS,MAAM,EAQtF,CAAA;AAgBD;;;;;GAKG;AACH,eAAO,MAAM,cAAc,GAAI,QAAQ,MAAM,EAAE,MAAM,MAAM,KAAG,MAAM,GAAG,SAGtE,CAAA;AAiDD;;;;;;;GAOG;AACH,eAAO,MAAM,mBAAmB,GAAI,OAAO,SAAS,UAAU,EAAE,KAAG,SAAS,gBAAgB,EAexF,CAAA"}
@@ -0,0 +1,195 @@
1
+ import { rootConfigsIn } from './payload-database.js';
2
+ import { LOCAL_API_CALLS, PAYLOAD_RECEIVER } from './payload-policy.js';
3
+ import { depthOneValue } from './payload-source.js';
4
+ import { balancedArguments, NOT_FOUND, occurrences, stripComments } from './source-text.js';
5
+ /** The operations that change stored state, named as the catalogue spells them. */
6
+ const MUTATION_NAMES = new Set([
7
+ 'create',
8
+ 'delete',
9
+ 'restoreGlobalVersion',
10
+ 'restoreVersion',
11
+ 'update',
12
+ 'updateGlobal',
13
+ ]);
14
+ /**
15
+ * The Local API operations that change stored state.
16
+ *
17
+ * Derived from the one catalogue rather than written out again: a second list is a second thing to keep
18
+ * in step, and the two would disagree the first time Payload gained an operation. A read at boot is
19
+ * legitimate and deliberately absent from this set.
20
+ */
21
+ export const LOCAL_API_MUTATIONS = LOCAL_API_CALLS.filter((call) => MUTATION_NAMES.has(call.slice(1, -1)));
22
+ const ARROW = '=>';
23
+ // The body a hook value opens, found after the arrow rather than at the first brace: a hook written
24
+ // `async ({ payload }) => { ... }` destructures before it opens, and the first brace is that pattern.
25
+ const hookBodyIn = (value) => {
26
+ const arrow = value.indexOf(ARROW);
27
+ const from = arrow === NOT_FOUND ? 0 : arrow + ARROW.length;
28
+ const open = value.indexOf('{', from);
29
+ return open === NOT_FOUND ? undefined : balancedArguments(value, open);
30
+ };
31
+ /**
32
+ * The boot hook every root configuration in a source declares.
33
+ * @param code the file's text, with comments already stripped.
34
+ * @returns one entry per configuration that declares `onInit` with a body.
35
+ */
36
+ export const bootstrapHooksIn = (code) => rootConfigsIn(code).flatMap((config) => {
37
+ const value = depthOneValue(config.body, 'onInit');
38
+ const body = value === undefined ? undefined : hookBodyIn(value);
39
+ return body === undefined ? [] : [{ body, line: config.line }];
40
+ });
41
+ // A Local API mutation performed on a Payload receiver, anywhere in a body.
42
+ //
43
+ // Distinct operations, not occurrences: a seed that writes two globals performs `updateGlobal` twice,
44
+ // and reporting it twice would print the same sentence twice for one repair. What the reader has to act
45
+ // on is that the body writes at all.
46
+ const mutationsIn = (body) => [
47
+ ...new Set(LOCAL_API_MUTATIONS.flatMap((call) => occurrences(body, call)
48
+ .filter((found) => PAYLOAD_RECEIVER.test(body.slice(0, found)))
49
+ .map(() => call.slice(1, -1)))),
50
+ ];
51
+ // The names a body calls. The keywords are removed because `if (` and `while (` are indistinguishable
52
+ // from a call by this pattern, and a keyword can never name an import.
53
+ const CALLED_IDENTIFIER = /\b([a-z_$][\w$]*)\s*\(/gi;
54
+ const STATEMENT_KEYWORDS = new Set([
55
+ 'await',
56
+ 'catch',
57
+ 'for',
58
+ 'function',
59
+ 'if',
60
+ 'return',
61
+ 'switch',
62
+ 'typeof',
63
+ 'while',
64
+ ]);
65
+ const calledNamesIn = (body) => [
66
+ ...new Set([...body.matchAll(CALLED_IDENTIFIER)]
67
+ .map((match) => match[1] ?? '')
68
+ .filter((name) => !STATEMENT_KEYWORDS.has(name))),
69
+ ];
70
+ // Every quantifier here is bounded by a literal that cannot itself match, so the scan is linear: a
71
+ // binding clause runs to the one brace that closes it, and a specifier to the one quote that ends it.
72
+ const IMPORT_BINDING = /\bimport\s+\{([^}]+)\}\s+from\s*['"]([^'"]+)['"]/g;
73
+ const boundNames = (clause) => clause
74
+ .split(',')
75
+ .map((binding) => binding.trim().split(/\s+/).at(-1) ?? '')
76
+ .filter((name) => name.length > 0);
77
+ /**
78
+ * The module specifier a name is imported from.
79
+ * @param code the importing file's text.
80
+ * @param name the imported binding to find.
81
+ * @returns the specifier, or undefined when the file imports no such name.
82
+ */
83
+ export const moduleOfImport = (code, name) => [...code.matchAll(IMPORT_BINDING)]
84
+ .filter((match) => boundNames(match[1] ?? '').includes(name))
85
+ .map((match) => match[2])
86
+ .at(0);
87
+ const SOURCE_EXTENSIONS = ['.ts', '.tsx'];
88
+ const ALIAS = '@/';
89
+ const ALIAS_ROOT = 'src/';
90
+ const directoryOf = (filePath) => {
91
+ const slash = filePath.lastIndexOf('/');
92
+ return slash === NOT_FOUND ? '' : filePath.slice(0, slash);
93
+ };
94
+ // `.` and `..` resolved without node:path, which keeps this layer free of every runtime module.
95
+ const flattened = (segments) => segments.reduce((kept, segment) => {
96
+ if (segment === '' || segment === '.') {
97
+ return kept;
98
+ }
99
+ return segment === '..' ? kept.slice(0, -1) : [...kept, segment];
100
+ }, []);
101
+ // The path a specifier names before an extension is tried. A package specifier resolves to nothing,
102
+ // which is what keeps the rule inside the member's own source.
103
+ const resolvedBase = (specifier, fromPath) => {
104
+ if (specifier.startsWith(ALIAS)) {
105
+ return `${ALIAS_ROOT}${specifier.slice(ALIAS.length)}`;
106
+ }
107
+ return specifier.startsWith('.')
108
+ ? flattened([...directoryOf(fromPath).split('/'), ...specifier.split('/')]).join('/')
109
+ : undefined;
110
+ };
111
+ /**
112
+ * The repository-relative paths a specifier could name, in the order a resolver would try them.
113
+ * @param specifier the module specifier as written.
114
+ * @param fromPath the member-relative path of the importing file.
115
+ * @returns the candidate paths, empty when the specifier names a package rather than project source.
116
+ */
117
+ export const candidatePathsFor = (specifier, fromPath) => {
118
+ const base = resolvedBase(specifier, fromPath);
119
+ return base === undefined
120
+ ? []
121
+ : [
122
+ ...SOURCE_EXTENSIONS.map((extension) => `${base}${extension}`),
123
+ `${base}/index.ts`,
124
+ ];
125
+ };
126
+ // The body of one named export, so a module holding an unrelated writer beside the function the hook
127
+ // actually calls is not reported for the writer it never reached.
128
+ const declarationOf = (name) => new RegExp(String.raw `export\s+(?:async\s+)?(?:function\s+|const\s+)${name}\b`);
129
+ const bodyAfter = (source, at) => {
130
+ const open = source.indexOf('(', at);
131
+ const parameters = open === NOT_FOUND ? undefined : balancedArguments(source, open);
132
+ const from = parameters === undefined ? at : open + parameters.length + 1;
133
+ const brace = source.indexOf('{', from);
134
+ return brace === NOT_FOUND ? undefined : balancedArguments(source, brace);
135
+ };
136
+ /**
137
+ * The body of a named export.
138
+ * @param source the module's text, with comments already stripped.
139
+ * @param name the exported binding to read.
140
+ * @returns the body, or undefined when the module exports no such binding with one.
141
+ */
142
+ export const exportedBodyIn = (source, name) => {
143
+ const found = declarationOf(name).exec(source);
144
+ return found === null ? undefined : bodyAfter(source, found.index);
145
+ };
146
+ const RULE = 'no-boot-time-writes';
147
+ const REPAIR = 'move the write behind a command the project runs deliberately, such as a seed script invoked by ' +
148
+ 'its own package script';
149
+ const directReason = (call) => `onInit: must not write through the Local API; ${call}() here runs on every boot of every ` +
150
+ 'container, so a restart, a new replica and a redeploy each overwrite whatever an editor last ' +
151
+ `saved - ${REPAIR}`;
152
+ const reachedReason = (name, specifier, call) => `onInit: must not reach a Local API write; it calls ${name}() from "${specifier}", which runs ` +
153
+ `${call}() in its own body, so every boot of every container overwrites whatever an editor last ` +
154
+ `saved - ${REPAIR}`;
155
+ const sourceAt = (files, paths) => files
156
+ .filter((file) => paths.includes(file.path))
157
+ .map((file) => stripComments(file.source))
158
+ .at(0);
159
+ // One call out of the hook: the name has to be imported, the module has to be one of this member's own
160
+ // files, and the export it names has to perform the write itself.
161
+ const reachedWrites = (code, hook, file, files) => calledNamesIn(hook.body).flatMap((name) => {
162
+ const specifier = moduleOfImport(code, name);
163
+ if (specifier === undefined) {
164
+ return [];
165
+ }
166
+ const target = sourceAt(files, candidatePathsFor(specifier, file.path));
167
+ const body = target === undefined ? undefined : exportedBodyIn(target, name);
168
+ return body === undefined
169
+ ? []
170
+ : mutationsIn(body).map((call) => ({
171
+ line: hook.line,
172
+ rule: RULE,
173
+ reason: reachedReason(name, specifier, call),
174
+ }));
175
+ });
176
+ /**
177
+ * Report every Local API write a boot hook performs, or reaches in one call.
178
+ *
179
+ * Reported against the configuration that schedules the write rather than the module that performs it:
180
+ * the module may be a legitimate seed, and what makes it a defect is being wired into `onInit`.
181
+ * @param files every source file of the member, as read.
182
+ * @returns one violation per write, located on the configuration that declares the hook.
183
+ */
184
+ export const findBootstrapWrites = (files) => files.flatMap((file) => {
185
+ const code = stripComments(file.source);
186
+ return bootstrapHooksIn(code).flatMap((hook) => [
187
+ ...mutationsIn(hook.body).map((call) => ({
188
+ line: hook.line,
189
+ rule: RULE,
190
+ reason: directReason(call),
191
+ })),
192
+ ...reachedWrites(code, hook, file, files),
193
+ ].map((violation) => ({ path: file.path, violation })));
194
+ });
195
+ //# sourceMappingURL=payload-bootstrap.js.map