@gspothq/cli 0.1.1 → 0.2.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 (205) hide show
  1. package/README.md +58 -11
  2. package/configurations/database/postgres/manifest.toml +51 -57
  3. package/configurations/database/postgres/rules/POSTGRES.md +14 -13
  4. package/configurations/framework/astro/manifest.toml +33 -35
  5. package/configurations/framework/astro/rules/ASTRO.md +2 -2
  6. package/configurations/framework/expo/manifest.toml +19 -19
  7. package/configurations/framework/express/manifest.toml +10 -4
  8. package/configurations/framework/express/rules/EXPRESS.md +9 -7
  9. package/configurations/framework/fastapi/manifest.toml +9 -3
  10. package/configurations/framework/fastapi/rules/FASTAPI.md +19 -18
  11. package/configurations/framework/nestjs/manifest.toml +12 -12
  12. package/configurations/framework/nestjs/rules/NESTJS.md +9 -9
  13. package/configurations/framework/nextjs/manifest.toml +39 -79
  14. package/configurations/framework/nextjs/rules/NEXTJS.md +9 -7
  15. package/configurations/framework/nextjs/tool-files/semgrep/nextjs.yml +35 -0
  16. package/configurations/framework/react/manifest.toml +33 -43
  17. package/configurations/framework/react/rules/REACT.md +14 -20
  18. package/configurations/framework/react-dom/manifest.toml +6 -6
  19. package/configurations/framework/react-native/manifest.toml +11 -11
  20. package/configurations/framework/react-native/rules/REACT-NATIVE.md +3 -5
  21. package/configurations/framework/site/manifest.toml +57 -110
  22. package/configurations/framework/site/rules/SITE.md +1 -1
  23. package/configurations/framework/svelte/manifest.toml +29 -31
  24. package/configurations/framework/svelte/rules/SVELTE.md +6 -6
  25. package/configurations/framework/vue/manifest.toml +37 -37
  26. package/configurations/framework/vue/rules/VUE.md +6 -6
  27. package/configurations/general/commits/manifest.toml +20 -84
  28. package/configurations/general/commits/rules/GIT.md +24 -13
  29. package/configurations/general/coverage/manifest.toml +1 -1
  30. package/configurations/general/dependencies/manifest.toml +47 -107
  31. package/configurations/general/dependencies/rules/DEPENDENCIES.md +13 -7
  32. package/configurations/general/docs/manifest.toml +28 -43
  33. package/configurations/general/docs/rules/DOCS.md +16 -9
  34. package/configurations/general/duplication/manifest.toml +12 -14
  35. package/configurations/general/engineering/manifest.toml +6 -2
  36. package/configurations/general/engineering/rules/agent/PLANNING.md +9 -6
  37. package/configurations/general/engineering/rules/agent/SUPPRESSIONS.md +20 -11
  38. package/configurations/general/engineering/rules/agent/TASKS.md +6 -2
  39. package/configurations/general/engineering/rules/agent/WORKING.md +34 -29
  40. package/configurations/general/engineering/rules/code/ACCESSIBILITY.md +9 -7
  41. package/configurations/general/engineering/rules/code/CLI.md +12 -9
  42. package/configurations/general/engineering/rules/code/COMMENTS.md +11 -1
  43. package/configurations/general/engineering/rules/code/CONFIGURATION.md +2 -0
  44. package/configurations/general/engineering/rules/code/ERRORS.md +5 -3
  45. package/configurations/general/engineering/rules/code/HTTP.md +9 -10
  46. package/configurations/general/engineering/rules/code/LOGGING.md +10 -9
  47. package/configurations/general/engineering/rules/code/TESTING.md +18 -11
  48. package/configurations/general/files/manifest.toml +45 -73
  49. package/configurations/general/files/rules/YAML.md +20 -10
  50. package/configurations/general/format/manifest.toml +53 -106
  51. package/configurations/general/gspot/manifest.toml +19 -39
  52. package/configurations/general/gspot/rules/GENERATED.md +14 -4
  53. package/configurations/general/licenses/manifest.toml +12 -14
  54. package/configurations/general/naming/defaults.json +14 -13
  55. package/configurations/general/naming/manifest.toml +17 -17
  56. package/configurations/general/naming/rules/NAMING.md +87 -67
  57. package/configurations/general/prose/manifest.toml +166 -25
  58. package/configurations/general/prose/rules/WRITING.md +6 -2
  59. package/configurations/general/repository/manifest.toml +12 -12
  60. package/configurations/general/secrets/manifest.toml +52 -73
  61. package/configurations/general/secrets/rules/SECRETS.md +3 -1
  62. package/configurations/general/security/manifest.toml +29 -52
  63. package/configurations/general/security/rules/SECURITY.md +8 -6
  64. package/configurations/general/spelling/manifest.toml +15 -25
  65. package/configurations/general/structure/manifest.toml +31 -31
  66. package/configurations/infrastructure/ansible/manifest.toml +15 -15
  67. package/configurations/infrastructure/docker/manifest.toml +55 -67
  68. package/configurations/infrastructure/docker/rules/DOCKER.md +15 -13
  69. package/configurations/infrastructure/github-actions/manifest.toml +21 -41
  70. package/configurations/infrastructure/github-actions/rules/GITHUB-ACTIONS.md +16 -12
  71. package/configurations/infrastructure/github-actions/tool-files/zizmor.yml +5 -0
  72. package/configurations/infrastructure/nginx/manifest.toml +20 -20
  73. package/configurations/infrastructure/nginx/rules/NGINX.md +5 -4
  74. package/configurations/infrastructure/openapi/manifest.toml +20 -20
  75. package/configurations/infrastructure/openapi/rules/OPENAPI.md +3 -1
  76. package/configurations/infrastructure/xcode/manifest.toml +55 -75
  77. package/configurations/infrastructure/xcode/rules/XCODE.md +5 -3
  78. package/configurations/language/bash/manifest.toml +89 -170
  79. package/configurations/language/bash/rules/BASH.md +79 -17
  80. package/configurations/language/bash/rules/LANGUAGE.md +30 -26
  81. package/configurations/language/bash/rules/OPERATIONS.md +10 -8
  82. package/configurations/language/bash/rules/SAFETY.md +39 -35
  83. package/configurations/language/css/manifest.toml +22 -61
  84. package/configurations/language/css/rules/CSS.md +21 -2
  85. package/configurations/language/css/rules/TAILWIND.md +7 -5
  86. package/configurations/language/html/manifest.toml +16 -35
  87. package/configurations/language/html/rules/HTML.md +23 -5
  88. package/configurations/language/javascript/eslint-runtime-names.json +66 -61
  89. package/configurations/language/javascript/eslint-runtime.mjs +118 -0
  90. package/configurations/language/javascript/manifest.toml +135 -207
  91. package/configurations/language/javascript/rules/BUN.md +2 -2
  92. package/configurations/language/javascript/rules/COMPONENTS.md +4 -4
  93. package/configurations/language/javascript/rules/DENO.md +1 -1
  94. package/configurations/language/javascript/rules/JAVASCRIPT.md +30 -17
  95. package/configurations/language/javascript/rules/NODE.md +2 -2
  96. package/configurations/language/javascript/rules/PLAYWRIGHT.md +10 -9
  97. package/configurations/language/markdown/manifest.toml +20 -51
  98. package/configurations/language/python/manifest.toml +231 -342
  99. package/configurations/language/python/rules/DESIGN.md +40 -33
  100. package/configurations/language/python/rules/FLOW.md +8 -6
  101. package/configurations/language/python/rules/PACKAGING.md +14 -7
  102. package/configurations/language/python/rules/PYTHON.md +83 -33
  103. package/configurations/language/python/rules/TYPING.md +25 -23
  104. package/configurations/language/sql/manifest.toml +19 -37
  105. package/configurations/language/sql/rules/SQL.md +90 -2
  106. package/configurations/language/swift/manifest.toml +67 -78
  107. package/configurations/language/swift/rules/SWIFT.md +138 -40
  108. package/configurations/language/swift/rules/SWIFTUI.md +11 -9
  109. package/configurations/language/swift/rules/UIKIT.md +21 -19
  110. package/configurations/language/typescript/manifest.toml +34 -34
  111. package/configurations/language/typescript/rules/TYPESCRIPT.md +62 -10
  112. package/configurations/library/drizzle/manifest.toml +25 -38
  113. package/configurations/library/drizzle/rules/DRIZZLE.md +4 -2
  114. package/configurations/library/react-hook-form/manifest.toml +4 -4
  115. package/configurations/library/react-hook-form/rules/REACT-HOOK-FORM.md +15 -13
  116. package/configurations/library/tanstack-query/manifest.toml +6 -6
  117. package/configurations/library/tanstack-query/rules/TANSTACK-QUERY.md +5 -3
  118. package/configurations/library/testing-library/manifest.toml +6 -6
  119. package/configurations/library/translations/manifest.toml +22 -22
  120. package/configurations/library/translations/rules/NEXT-INTL.md +6 -8
  121. package/configurations/library/translations/rules/TRANSLATIONS.md +22 -23
  122. package/configurations/library/trpc/manifest.toml +3 -3
  123. package/configurations/library/trpc/rules/TRPC.md +8 -6
  124. package/configurations/library/zod/manifest.toml +6 -6
  125. package/configurations/library/zod/rules/ZOD.md +4 -2
  126. package/configurations/library/zustand/manifest.toml +4 -4
  127. package/configurations/library/zustand/rules/ZUSTAND.md +16 -14
  128. package/configurations/platform/cloudflare/manifest.toml +28 -47
  129. package/configurations/platform/cloudflare/rules/CLOUDFLARE.md +11 -6
  130. package/configurations/platform/supabase/manifest.toml +48 -61
  131. package/configurations/platform/supabase/rules/SUPABASE.md +27 -28
  132. package/configurations/testing/jest/manifest.toml +21 -22
  133. package/configurations/testing/pytest/manifest.toml +28 -28
  134. package/configurations/testing/swift-tests/manifest.toml +18 -29
  135. package/configurations/testing/swift-tests/rules/SWIFT-TESTS.md +7 -5
  136. package/configurations/testing/vitest/manifest.toml +32 -32
  137. package/configurations/testing/vitest/rules/VITEST.md +3 -1
  138. package/dist/gspot.js +22297 -24707
  139. package/dist/{linkinator-program.js → linkinator-process.js} +5 -7
  140. package/dist/{purgecss-program.js → purgecss-process.js} +12 -12
  141. package/package.json +7 -9
  142. package/configurations/infrastructure/github-actions/zizmor.yml +0 -3
  143. package/configurations/language/bash/rules/NAMING.md +0 -62
  144. package/configurations/language/css/rules/NAMING.md +0 -17
  145. package/configurations/language/html/rules/NAMING.md +0 -16
  146. package/configurations/language/javascript/rules/NAMING.md +0 -31
  147. package/configurations/language/markdown/markdownlint-cli2.mjs +0 -19
  148. package/configurations/language/python/rules/NAMING.md +0 -53
  149. package/configurations/language/sql/rules/NAMING.md +0 -90
  150. package/configurations/language/swift/rules/NAMING.md +0 -88
  151. package/configurations/language/typescript/rules/NAMING.md +0 -73
  152. package/configurations/library/swift-snapshot-testing/manifest.toml +0 -32
  153. package/dist/THIRD-PARTY-NOTICES.md +0 -25
  154. package/dist/eslint-rule-levels.json +0 -10
  155. package/dist/tool-versions.json +0 -3
  156. package/gspot.schema.json +0 -45991
  157. /package/{dist/LICENSE.md → LICENSE.md} +0 -0
  158. /package/configurations/framework/express/{semgrep → tool-files/semgrep}/express.yml +0 -0
  159. /package/configurations/framework/fastapi/{semgrep → tool-files/semgrep}/fastapi.yml +0 -0
  160. /package/configurations/general/dependencies/{syncpack.json → tool-files/syncpack.json} +0 -0
  161. /package/configurations/general/prose/{vale → tool-files/vale}/styles/LICENSES.md +0 -0
  162. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/ampm.yml +0 -0
  163. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/conscious-language.yml +0 -0
  164. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/contractions.yml +0 -0
  165. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/currency.yml +0 -0
  166. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/dashes.yml +0 -0
  167. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/date-ordinals.yml +0 -0
  168. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/dates.yml +0 -0
  169. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/file-paths.yml +0 -0
  170. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/future.yml +0 -0
  171. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/hedging.yml +0 -0
  172. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/history.yml +0 -0
  173. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/idioms.yml +0 -0
  174. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/interface-verbs.yml +0 -0
  175. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/jargon.yml +0 -0
  176. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/leading-conjunctions.yml +0 -0
  177. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/link-text.yml +0 -0
  178. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/locations.yml +0 -0
  179. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/marketing.yml +0 -0
  180. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/merge-conflict-markers.yml +0 -0
  181. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/militaristic-language.yml +0 -0
  182. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/modals.yml +0 -0
  183. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/numbered-units.yml +0 -0
  184. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/obvious-fields.yml +0 -0
  185. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/ordinal-adverbs.yml +0 -0
  186. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/percentage-numbers.yml +0 -0
  187. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/placeholders.yml +0 -0
  188. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/product-centric-writing.yml +0 -0
  189. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/punctuated-headings.yml +0 -0
  190. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/self-reference.yml +0 -0
  191. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/session-identifiers.yml +0 -0
  192. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/since.yml +0 -0
  193. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/straight-quotes.yml +0 -0
  194. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/suspended-hyphens.yml +0 -0
  195. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/symbols.yml +0 -0
  196. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/time-ranges.yml +0 -0
  197. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/url-prepositions.yml +0 -0
  198. /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/version-range.yml +0 -0
  199. /package/configurations/general/secrets/{gitleaks.toml → tool-files/gitleaks.toml} +0 -0
  200. /package/configurations/infrastructure/docker/{trivyignore → tool-files/trivyignore} +0 -0
  201. /package/configurations/language/bash/{semgrep → tool-files/semgrep}/bash.yml +0 -0
  202. /package/configurations/language/javascript/{semgrep → tool-files/semgrep}/javascript.yml +0 -0
  203. /package/configurations/language/swift/{semgrep → tool-files/semgrep}/swift.yml +0 -0
  204. /package/configurations/platform/cloudflare/{semgrep → tool-files/semgrep}/cloudflare.yml +0 -0
  205. /package/configurations/platform/supabase/{semgrep → tool-files/semgrep}/supabase.yml +0 -0
@@ -1,46 +1,36 @@
1
1
  [configuration]
2
- title = "Spelling"
3
2
  always_selected = true
4
- description = "typos over every text file, with the words this repository allows and the reason for each."
3
+ description = "Runs typos over every text file, with the allowed words and a reason for each."
4
+ title = "Spelling"
5
5
 
6
6
  [files]
7
7
  paths = ["**"]
8
8
 
9
9
  [[tool]]
10
- name = "typos"
11
- version = "1.43.5"
12
- mise = "typos"
13
10
  brew = "typos-cli"
14
11
  cargo = "typos-cli"
15
- winget = "crate-ci.typos"
16
- scoop = "typos"
17
12
  github = { name = "crate-ci/typos", version = "v1.43.5" }
18
- [[tool.replace]]
19
- file = "typos.toml"
20
- shared = false
21
-
22
- [[tool.replace]]
23
- file = ".typos.toml"
24
- shared = false
25
-
26
- [[tool.replace]]
27
- file = "_typos.toml"
28
- shared = false
13
+ mise = "typos"
14
+ name = "typos"
15
+ replace = ["typos.toml", ".typos.toml", "_typos.toml"]
16
+ scoop = "typos"
17
+ version = "1.43.5"
18
+ winget = "crate-ci.typos"
29
19
 
30
20
  [[tool_file]]
21
+ per_scope = true
31
22
  target = ".gspot/config/typos.toml"
32
23
  tool = "typos"
33
- per_scope = true
34
24
 
35
25
  [[check]]
36
- name = "typos"
37
- example = "A misspelled word in selected text reports a spelling finding. Correct it and rerun. Filename findings require a manual rename and reference updates."
38
- level = "recommended"
39
- stage = "commit"
40
26
  command = ["typos", "--isolated", "--config", "{tool_file:typos}", "--force-exclude", "--format", "json", "--color", "never", "{files}"]
41
- fix = ["typos", "--isolated", "--config", "{tool_file:typos}", "--force-exclude", "--no-check-filenames", "--write-changes", "--color", "never", "{files}"]
27
+ example = "A misspelled word reports a finding. Correct it, and for a file name, rename the file and update each reference to it."
42
28
  exit_codes = [2]
29
+ fix = ["typos", "--isolated", "--config", "{tool_file:typos}", "--force-exclude", "--no-check-filenames", "--write-changes", "--color", "never", "{files}"]
30
+ help = "Fix the spelling, or write the real name and its reason in the root allowed_words setting."
31
+ level = "recommended"
32
+ name = "typos"
43
33
  output = { format = "typos" }
34
+ stage = "commit"
44
35
  summary = "Finds misspelled words in code, comments, and documentation."
45
36
  why = "A typo in an identifier spreads to every caller; in prose it costs the reader a second look."
46
- help = "Fix the spelling, or write the real name and its reason in the root allowed_words setting."
@@ -1,70 +1,70 @@
1
1
  [configuration]
2
- title = "Structure"
3
2
  always_selected = true
4
- description = "The structural rules no standard linter ships, over every language: wrappers, barrels, lone files, and the size limits."
3
+ description = "Structural rules that no standard linter ships, for every language: wrappers, barrels, lone files, and size limits."
4
+ title = "Structure"
5
5
 
6
6
  [files]
7
7
  languages = true
8
8
 
9
9
  [[check]]
10
+ example = "With TypeScript at level `all`, a `feature/only.ts` alone in its folder reports `lone-file`. Move it up beside related code, and update its imports."
11
+ help = "Move the file up beside its neighbors, or use `gspot ignore structure/lone-files` with paths and a reason."
12
+ level = "all"
10
13
  name = "lone-files"
11
- example = "With the TypeScript configuration at level `all`, `feature/only.ts` reports `lone-file` when it is the folder's only code file. Move it beside related files and update references, or keep the folder when a second substantial file belongs to that feature. Adding `feature/second.ts` makes this folder contain two code files."
12
14
  runs = "scope"
13
- level = "all"
14
15
  stage = "commit"
15
16
  summary = "Finds a folder that holds one code file and nothing else."
16
- why = "A folder of one file adds a level to every path and promises siblings that never arrive."
17
- help = "Move the file up beside its neighbors, or use gspot ignore structure/lone-files with paths and a reason."
17
+ why = "A folder with one file adds a level to every import path and groups nothing."
18
18
 
19
19
  [[check]]
20
- name = "shared-prefixes"
21
20
  example = "Sibling files `asset-card.ts`, `asset-list.ts`, and `asset-row.ts` share a repeated prefix. Move them into `asset/` with names `card.ts`, `list.ts`, and `row.ts`, then update imports."
22
- runs = "scope"
21
+ help = "Move the files into a folder named after the shared prefix, or allow the set with a reason."
23
22
  level = "all"
23
+ name = "shared-prefixes"
24
+ runs = "scope"
24
25
  stage = "commit"
25
- summary = "Finds sibling files that share a name prefix, like asset-card, asset-list and asset-row in one folder."
26
- why = "Files that share a prefix are one concept split by suffix; they belong in a folder named after the prefix."
27
- help = "Move the files into a folder named after the shared prefix, or allow the set with a reason."
26
+ summary = "Finds sibling files that share a name prefix, such as `asset-card`, `asset-list`, and `asset-row`."
27
+ why = "Sibling files with one prefix split a single concept by suffix, and a folder of that name groups them."
28
28
 
29
29
  [[check]]
30
+ example = "A `report.ts` beside a `report/` folder reports a clash. Rename one after its job, and update each reference."
31
+ help = "Rename the file or the folder so their stems differ."
32
+ level = "all"
30
33
  name = "file-folder-clashes"
31
- example = "Sibling entries `report.ts` and `report/` have the same stem and report a collision. Rename the file or directory after its distinct responsibility and update every reference."
32
34
  runs = "scope"
33
- level = "all"
34
35
  stage = "commit"
35
- summary = "Finds a file and a folder in the same place with the same stem, like turn.ts beside turn/."
36
+ summary = "Finds a file and a folder with one stem in the same place, such as `turn.ts` beside `turn/`."
36
37
  why = "An import of ./turn names both, and a reader cannot tell which one loads."
37
- help = "Rename the file or the folder so their stems differ."
38
38
 
39
39
  [[check]]
40
- name = "file-lines"
41
- example = "A Python, Bash, or SQL source file above its language's code-line ceiling reports its count. Split independent responsibilities into their owners and rerun the check."
40
+ example = "A Python file over its line limit reports the count. Split it by responsibility."
41
+ files = { extensions = [".sh", ".bash", ".zsh", ".bats", ".py", ".pyi", ".sql", ".pgsql", ".psql"], tags = ["shebang:shell"], kinds = ["source"] }
42
+ help = "Split the file by responsibility, or raise limits.`<language>`.file_lines with a reason."
42
43
  level = "all"
43
- stage = "commit"
44
+ name = "long-files"
44
45
  runs = "scope"
45
- files = { extensions = [".sh", ".bash", ".zsh", ".bats", ".py", ".pyi", ".sql", ".pgsql", ".psql"], tags = ["shebang:shell"], kinds = ["source"] }
46
- summary = "Checks source code lines against each language's ceiling."
46
+ stage = "commit"
47
+ summary = "Checks the code line count of each file against the limit for its language."
47
48
  why = "A long file hides independent responsibilities from the reader."
48
- help = "Split the file by its responsibility, or raise its limits.`<language>`.file_lines with a reason."
49
49
 
50
50
  [[check]]
51
- name = "trivial-functions"
52
- example = "A Bash function that only calls another function reports its declaration. Inline that call into its callers and remove the forwarding function."
51
+ example = "A Bash function that only calls another reports a finding. Inline the call at each caller, and delete the wrapper."
52
+ files = { extensions = [".ts", ".tsx", ".js", ".mjs", ".cjs", ".py", ".swift", ".sh", ".bash", ".zsh", ".bats"], tags = ["shell"], kinds = ["source"] }
53
+ help = "Inline a forwarding function at its calls and delete it. Split independent statements into the files that use them."
53
54
  level = "all"
54
- stage = "commit"
55
+ name = "trivial-functions"
55
56
  runs = "scope"
56
- files = { extensions = [".py", ".swift", ".sh", ".bash", ".zsh", ".bats"], tags = ["shell"], kinds = ["source"] }
57
+ stage = "commit"
57
58
  summary = "Finds functions with too few statements and files that only forward to other code."
58
59
  why = "A function of one statement makes the reader jump for nothing."
59
- help = "Inline a forwarding function at its calls and delete it. Split independent statements into the files that use them."
60
60
 
61
61
  [[check]]
62
- name = "env-reads"
63
- example = "A Python file outside architecture.roles.environment_readers that reads os.environ reports that read. Move it into a declared environment reader and pass its value to callers."
62
+ example = "A Python file that uses `os.environ` outside `architecture.roles.environment_readers` reports a finding. Move that access into an environment reader, and pass the value to callers."
63
+ files = { extensions = [".py", ".swift", ".sh", ".bash", ".zsh", ".bats"], tags = ["shell"], kinds = ["source"] }
64
+ help = "Move the environment read into a file listed in architecture.roles.environment_readers, then pass the value to callers."
64
65
  level = "all"
65
- stage = "commit"
66
+ name = "environment-readers"
66
67
  runs = "scope"
67
- files = { extensions = [".py", ".swift", ".sh", ".bash", ".zsh", ".bats"], tags = ["shell"], kinds = ["source"] }
68
+ stage = "commit"
68
69
  summary = "Finds environment reads outside the files listed in architecture.roles.environment_readers."
69
70
  why = "Environment reads spread through the code hide which settings a program needs."
70
- help = "Move the environment read into a file listed in architecture.roles.environment_readers, then pass the value to callers."
@@ -1,33 +1,33 @@
1
1
  [configuration]
2
- title = "Ansible"
3
2
  description = "Ansible playbooks, roles, and collections checked by ansible-lint."
3
+ title = "Ansible"
4
4
 
5
5
  [files]
6
6
  paths = ["**/ansible.cfg", "**/galaxy.yml", "**/requirements.yml", "**/roles/*/tasks/main.yml"]
7
7
 
8
8
  [[tool]]
9
- name = "ansible-lint"
10
- version = "26.8.0"
11
- min_version = "24.0.0"
12
- pypi = "ansible-lint"
13
- mise = "pipx:ansible-lint"
14
9
  brew = "ansible-lint"
15
10
  builds = ["macos", "linux"]
11
+ min_version = "24.0.0"
12
+ mise = "pipx:ansible-lint"
13
+ name = "ansible-lint"
14
+ pypi = "ansible-lint"
15
+ version = "26.8.0"
16
16
 
17
17
  [[tool_file]]
18
+ per_scope = true
18
19
  target = ".gspot/config/ansible-lint.yml"
19
20
  tool = "ansible-lint"
20
- per_scope = true
21
21
 
22
22
  [[check]]
23
- name = "ansible-lint"
24
- example = "A task using `ansible.builtin.command: systemctl restart nginx` reports `command-instead-of-module`. Use `ansible.builtin.systemd` with `name: nginx` and `state: restarted` to express the intended service operation."
23
+ command = ["ansible-lint", "-c", "{tool_file:ansible-lint}", "--offline", "--nocolor", "-f", "pep8", "--profile", "{level:moderate:production}"]
24
+ example = "A task with `ansible.builtin.command: systemctl restart nginx` reports `command-instead-of-module`. Use `ansible.builtin.systemd` with `name: nginx` and `state: restarted` instead."
25
+ files = { extensions = [".yml", ".yaml", ".cfg", ".j2"] }
26
+ help = "Change the task the way the rule says. Turn one rule off with `gspot ignore ansible/ansible-lint --rule <id> --reason \"<why>\"`."
25
27
  level = "recommended"
26
- stage = "commit"
28
+ name = "ansible-lint"
27
29
  runs = "scope"
30
+ stage = "commit"
31
+ summary = "Runs the moderate ansible-lint profile at recommended and production at all, beside each ansible.cfg or at the scope root."
28
32
  tool = "ansible-lint"
29
- command = ["ansible-lint", "-c", "{tool_file:ansible-lint}", "--offline", "--nocolor", "-f", "pep8", "--profile", "{level:moderate:production}"]
30
- files = { extensions = [".yml", ".yaml", ".cfg", ".j2"] }
31
- summary = "Runs the moderate ansible-lint profile at recommended and production at all, beside each ansible.cfg or at the selected scope root."
32
- why = "A playbook runs as root on production hosts, and a task that is not idempotent changes them on every run."
33
- help = "Change the task the way the rule says. Turn one rule off with gspot ignore ansible/ansible-lint --rule `<id>` --reason \"`<why>`\"."
33
+ why = "Playbooks run as root on production hosts, and a non-idempotent task changes them each time."
@@ -1,9 +1,8 @@
1
- prefix_collisions = { prefixes = ["docker"] }
2
-
3
1
  allowed_words = ["Docker", "Trivy"]
2
+
4
3
  [configuration]
4
+ description = "Dockerfiles and Compose files: hadolint, Compose parsing, a `.dockerignore` beside each Dockerfile, and Trivy scans."
5
5
  title = "Docker"
6
- description = "Dockerfiles and Compose files: hadolint, a Compose file that parses, an ignore file beside every Dockerfile, and Trivy over the configuration."
7
6
 
8
7
  [detect]
9
8
  paths = ["**/Dockerfile", "**/Dockerfile.*", "**/*.dockerfile", "**/docker-compose*.yml", "**/docker-compose*.yaml", "**/compose*.yml", "**/compose*.yaml", "!**/*.dockerignore"]
@@ -11,117 +10,106 @@ paths = ["**/Dockerfile", "**/Dockerfile.*", "**/*.dockerfile", "**/docker-compo
11
10
  [files]
12
11
  paths = ["**/Dockerfile", "**/Dockerfile.*", "**/*.dockerfile", "**/docker-compose*.yml", "**/docker-compose*.yaml", "**/compose*.yml", "**/compose*.yaml", "**/.dockerignore", "**/*.dockerignore"]
13
12
 
13
+ [shared_prefixes]
14
+ prefixes = ["docker"]
15
+
14
16
  [[tool]]
15
- name = "hadolint"
16
- version = "2.14.0"
17
- mise = "hadolint"
18
17
  brew = "hadolint"
19
18
  github = { name = "hadolint/hadolint", version = "v2.14.0" }
19
+ mise = "hadolint"
20
+ name = "hadolint"
21
+ replace = [".hadolint.yaml", ".hadolint.yml"]
20
22
  scoop = "hadolint"
21
- [[tool.replace]]
22
- file = ".hadolint.yaml"
23
- shared = false
24
-
25
- [[tool.replace]]
26
- file = ".hadolint.yml"
27
- shared = false
23
+ version = "2.14.0"
28
24
 
29
25
  [[tool]]
30
- name = "trivy"
31
- version = "0.69.3"
32
- mise = "trivy"
33
26
  brew = "trivy"
34
27
  github = { name = "aquasecurity/trivy", version = "v0.69.3" }
35
- [[tool.replace]]
36
- file = "trivy.yaml"
37
- shared = false
38
-
39
- [[tool.replace]]
40
- file = ".trivyignore"
41
- shared = false
28
+ mise = "trivy"
29
+ name = "trivy"
30
+ replace = ["trivy.yaml", ".trivyignore"]
31
+ version = "0.69.3"
42
32
 
43
33
  [[tool]]
44
- name = "docker"
45
34
  install_hint = "install Docker Desktop or the docker engine"
35
+ name = "docker"
46
36
  system = true
47
37
 
48
38
  [[tool_file]]
39
+ per_scope = true
49
40
  target = ".gspot/config/hadolint.yml"
50
41
  tool = "hadolint"
51
- per_scope = true
52
- rule_keys = ["ignored"]
53
42
 
54
43
  [[tool_file]]
44
+ per_scope = true
55
45
  target = ".gspot/config/trivy.yml"
56
46
  tool = "trivy"
57
- per_scope = true
58
47
 
59
48
  [[tool_file]]
60
- source = "trivyignore"
49
+ per_scope = true
61
50
  target = ".gspot/config/trivyignore"
62
51
  tool = "trivy"
63
- per_scope = true
64
52
 
65
53
  [[check]]
66
- name = "hadolint"
67
- example = "The instruction `FROM node:latest` reports DL3007 because the tag changes over time. Select a reviewed, explicit version tag or digest and rerun."
68
- level = "recommended"
69
- stage = "commit"
70
54
  command = ["hadolint", "--no-color", "--config", "{tool_file:hadolint}", "{files}"]
55
+ example = "`FROM node:latest` reports DL3007, because that tag moves. Pin an explicit version tag or a digest."
71
56
  files = { paths = ["**/Dockerfile", "**/Dockerfile.*", "**/*.dockerfile", "!**/*.dockerignore"] }
57
+ help = "Change the instruction the way the rule says. Turn one rule off with `gspot ignore docker/hadolint --rule <id> --reason \"<why>\"`."
58
+ level = "recommended"
59
+ name = "hadolint"
72
60
  output = { format = "regex", pattern = "^(?<file>.+?):(?<line>\\d+) (?<rule>[A-Z]+\\d+) [a-z]+: (?<message>.*)$" }
61
+ stage = "commit"
73
62
  summary = "Lints every Dockerfile, and runs ShellCheck over its RUN lines."
74
- why = "An unpinned base image or a cache left in a layer makes a build nobody can repeat and an image larger than it needs to be."
75
- help = "Change the instruction the way the rule says. Turn one rule off with gspot ignore docker/hadolint --rule `<id>` --reason \"`<why>`\"."
63
+ why = "An unpinned base image makes a build nobody can repeat, and a cache left in a layer bloats the result."
76
64
 
77
65
  [[check]]
78
- name = "compose"
79
- example = "A Compose service with an unknown key such as `bogus` fails configuration validation. Remove the key or replace it with the supported setting for the intended behavior."
80
- level = "recommended"
81
- stage = "push"
82
- needs = ["docker"]
83
- tool = "docker"
84
- runs = "scope"
85
66
  command = ["docker", "compose", "-f", "{file}", "config", "--quiet", "--no-env-resolution"]
67
+ example = "A Compose service with the unknown key `bogus` fails to parse. Remove the key, or use a supported one."
86
68
  files = { paths = ["**/docker-compose*.yml", "**/docker-compose*.yaml", "**/compose*.yml", "**/compose*.yaml"] }
87
- output = { format = "lines" }
88
- summary = "Asks Docker Compose to parse every Compose file, which needs no running daemon."
89
- why = "A Compose file that is valid YAML can still name a key Compose refuses, and the first person to learn that is deploying."
90
69
  help = "Read the message Compose prints; it names the key and the service."
70
+ level = "recommended"
71
+ name = "compose"
72
+ needs = ["docker"]
73
+ output = { format = "lines" }
74
+ runs = "scope"
75
+ stage = "push"
76
+ summary = "Parses every Compose file with `docker compose config`, which needs no running daemon."
77
+ tool = "docker"
78
+ why = "Valid YAML can still hold a key that Compose rejects, and otherwise the first sign comes during a deploy."
91
79
 
92
80
  [[check]]
93
- name = "dockerignore"
94
- example = "A Dockerfile without a neighboring `.dockerignore` reports the missing context exclusions. Add `.dockerignore` with the required entries named in the finding, such as `.git` and dependency directories."
81
+ example = "A Dockerfile with no `.dockerignore` beside it reports a finding. Add one that excludes the paths the finding names, such as `.git` and installed dependencies."
82
+ help = "Add a .dockerignore beside the Dockerfile with the paths the message names."
95
83
  level = "recommended"
96
- stage = "commit"
84
+ name = "dockerignore"
97
85
  runs = "once"
98
- summary = "Checks that an ignore file sits beside every Dockerfile and keeps the git folder, installed dependencies, and environment files out of the build."
99
- why = "Without it the whole folder goes to the daemon, and copying the folder puts the history and the secrets into the image."
100
- help = "Add a .dockerignore beside the Dockerfile with the entries the message names."
86
+ stage = "commit"
87
+ summary = "Checks that an ignore file sits beside every Dockerfile and keeps the `.git` folder, installed dependencies, and environment files out of the build."
88
+ why = "Without it, the daemon receives the whole folder, and a `COPY` of it puts the history and secrets into the image."
101
89
 
102
90
  [[check]]
103
- name = "trivy-config"
104
- example = "A Dockerfile whose final application stage runs as root can report a container-security finding. Create an unprivileged user, grant it only required file access, and select it with `USER` before running the application."
105
- level = "recommended"
106
- stage = "push"
107
- runs = "scope"
108
- run_in_copy = true
109
91
  command = ["trivy", "config", "--misconfig-scanners", "dockerfile", "--quiet", "--skip-check-update", "--config", "{tool_file:trivy}", "--ignorefile", "{tool_file:trivyignore}", "--exit-code", "10", "--format", "sarif", "{root}"]
110
- tool = "trivy"
92
+ example = "A Dockerfile whose final stage runs as root reports a finding. Create an unprivileged user, and switch to it with `USER` before the application starts."
111
93
  exit_codes = [10]
94
+ help = "Change the file the way the message says. Accept one advisory with `gspot ignore docker/trivy-config --rule <id> --reason \"...\"`."
95
+ level = "recommended"
96
+ name = "trivy-config"
112
97
  output = { format = "sarif" }
98
+ run_in_copy = true
99
+ runs = "scope"
100
+ stage = "push"
113
101
  summary = "Scans Dockerfiles for HIGH and CRITICAL misconfigurations, including a root user and exposed secrets."
114
- why = "A container that runs as root turns any bug in the service into control of the container."
115
- help = "Change the file the way the message says. Accept one advisory with gspot ignore docker/trivy-config --rule `<id>` --reason \"...\"."
102
+ tool = "trivy"
103
+ why = "A root user turns any bug in the service into full control of the container."
116
104
 
117
105
  [[check]]
118
- name = "trivy-image"
119
- example = "A configured image containing a package with a known advisory reports that advisory. Move to a reviewed image version containing the package fix, then rerun the image scan. Results depend on the advisory database and available image."
106
+ example = "An image with a vulnerable package reports the advisory. Move to an image version with the fixed package."
107
+ help = "Move to a newer tag of the image. Accept one advisory with `gspot ignore docker/trivy-image --rule <id> --reason \"...\"`."
120
108
  level = "recommended"
121
- stage = "manual"
122
- runs = "scope"
109
+ name = "trivy-image"
123
110
  needs = ["docker"]
124
- tool = "trivy"
111
+ runs = "scope"
112
+ stage = "manual"
125
113
  summary = "Scans every image a Compose file names for known vulnerabilities in its packages."
126
- why = "A base image carries hundreds of packages, and their advisories arrive after the image was chosen."
127
- help = "Move to a newer tag of the image. Accept one advisory with gspot ignore docker/trivy-image --rule `<id>` --reason \"...\"."
114
+ tool = "trivy"
115
+ why = "A base image carries hundreds of packages, and new advisories keep arriving after you pick it."
@@ -1,12 +1,14 @@
1
1
  # Docker
2
2
 
3
+ Read this rule when you change a Dockerfile, a Compose file, or `.dockerignore`.
4
+
3
5
  ## Image inputs
4
6
 
5
- Select a base image that supports the application's runtime, target architecture, native libraries,
7
+ Select a base image that supports the application's runtime, target architecture, system libraries,
6
8
  and certificate requirements. Tags can change, so pin a reviewed digest when the build requires
7
9
  immutable input, and keep an update process for security fixes: a digest never patches itself.
8
10
 
9
- Use a supported runtime release. For native modules, keep the build and runtime operating system,
11
+ Use a supported runtime release. For compiled modules, keep the build and runtime operating system,
10
12
  libc, and architecture compatible. Alpine, Debian, and distroless images have different runtime
11
13
  and operational requirements; no single variant fits every application.
12
14
 
@@ -48,7 +50,7 @@ CMD ["node", "dist/main.js"]
48
50
  Use the package manager the project declares; for Bun, its pinned version with
49
51
  `bun install --frozen-lockfile`, adding `--production` for runtime dependencies. The final image
50
52
  holds a package-manager binary only when the runtime uses it. A statically linked `server` built
51
- for the target platform needs no package manager or shell, only the certificates, time-zone data,
53
+ for the target system needs no package manager or shell, only the certificates, time-zone data,
52
54
  or other runtime files it reads.
53
55
 
54
56
  ```dockerfile
@@ -61,11 +63,11 @@ ENTRYPOINT ["/server"]
61
63
  ## Package installation and downloads
62
64
 
63
65
  hadolint reports unpinned images and packages, apt cleanup, `ADD` for local files, and shell-form
64
- commands. Review these additional requirements:
66
+ commands. Also apply these requirements:
65
67
 
66
68
  - Install application dependencies from the declared lockfile without updating it during the build.
67
- - Refresh repository metadata and install packages in the same `RUN`, so cached metadata cannot
68
- select an unintended version.
69
+ - Refresh repository metadata and install packages in the same `RUN`, so a stale cache cannot
70
+ pick an unintended version.
69
71
  - Refresh base images for operating-system fixes. A targeted package upgrade needs an explicit
70
72
  dependency change, never an unbounded distribution upgrade in every build.
71
73
  - Verify a downloaded executable's digest or signature before installing it.
@@ -77,7 +79,7 @@ commands. Review these additional requirements:
77
79
 
78
80
  Put stable build inputs before frequently changing application source when that improves cache
79
81
  reuse. Put substantial shell behavior in an existing script. Keep the final image's user,
80
- working directory, environment, and startup command in documented locations. Do not add a wrapper script
82
+ working folder, environment, and startup command in documented locations. Do not add a wrapper script
81
83
  for a command the container can run directly.
82
84
 
83
85
  ## Build context and ignore files
@@ -92,11 +94,11 @@ Dockerfile that uses it. A deny-by-default context suits a small, stable input s
92
94
 
93
95
  Use BuildKit secret mounts for private registry authentication and other build credentials.
94
96
  Read the secret only inside the `RUN` instruction that requires it. Copying it into a layer keeps
95
- it in image history even if a later layer removes it.
97
+ it in image history even after a later step removes it.
96
98
 
97
99
  ## Shell and process behavior
98
100
 
99
- Use the shell syntax actually selected for `RUN`; the default shell does not run Bash. A required
101
+ Match `RUN` syntax to the configured shell; the default one does not run Bash. A required
100
102
  entrypoint script validates configuration and uses `exec` for its final handoff. A documented
101
103
  process supervisor forwards signals and reaps its children, and no init wrapper hides missing
102
104
  shutdown behavior in the application.
@@ -110,9 +112,9 @@ The application's shutdown limit fits the orchestrator's grace period.
110
112
  service sets `NODE_ENV=production` where the runtime expects it.
111
113
  - Expose only the required ports, and bind private local services to localhost. Never add Linux
112
114
  capabilities, public debug ports, or disabled TLS verification to make a build or service work.
113
- - Resource limits fit the deployment and leave room for native memory, buffers, and runtime
114
- overhead beyond a language heap limit. Ask the user for memory measurements before changing a limit
115
- when the task provides none.
115
+ - Resource limits fit the deployment and leave room for off-heap memory, buffers, and runtime
116
+ overhead beyond the language heap. Ask the user for memory measurements before changing a limit
117
+ when the task has none.
116
118
 
117
119
  ## Compose
118
120
 
@@ -123,7 +125,7 @@ development source or host dependencies.
123
125
 
124
126
  ## Verification
125
127
 
126
- Do not build or run images unless the user asks or the repository's checks require it. Give the user a list of items to check: the image's user, command, runtime files, permissions, exposed ports, startup,
128
+ Do not build or run images unless the user asks or the repository's checks require it. Give the user a checklist: image user, command, runtime files, permissions, exposed ports, startup,
127
129
  readiness, shutdown, and resource limits. Image documentation names the current build arguments,
128
130
  supported platforms, runtime environment, and artifact paths.
129
131
 
@@ -1,76 +1,56 @@
1
1
  allowed_words = ["GitHub"]
2
+
2
3
  [configuration]
4
+ description = "GitHub Actions workflows: actionlint for syntax and expressions, and zizmor for security audits and action pins."
3
5
  title = "GitHub Actions"
4
- description = "GitHub Actions workflows: actionlint for syntax and expressions, pinact for the commits actions are pinned to, and zizmor for security audits."
5
6
 
6
7
  [files]
7
8
  paths = ["**/.github/workflows/*.{yml,yaml}", "**/action.{yml,yaml}"]
8
9
 
9
10
  [[tool]]
10
- name = "actionlint"
11
- version = "1.7.12"
12
- mise = "actionlint"
13
11
  brew = "actionlint"
14
12
  github = { name = "rhysd/actionlint", version = "v1.7.12" }
13
+ mise = "actionlint"
14
+ name = "actionlint"
15
+ version = "1.7.12"
15
16
 
16
17
  [[tool]]
17
18
  name = "shellcheck"
18
19
 
19
20
  [[tool]]
20
- name = "pinact"
21
- crash_pattern = '(?:ERROR|FATAL).*?(?:\b(?:401|403|408|429|5[0-9]{2})\b|dial tcp|TLS handshake|x509:|context deadline exceeded|connection reset|no such host)'
22
- version = "5.0.0"
23
- mise = "pinact"
24
- brew = "pinact"
25
- github = { name = "suzuki-shunsuke/pinact", version = "v5.0.0" }
26
-
27
- [[tool]]
28
- name = "zizmor"
29
- version = "1.30.1"
30
- mise = "zizmor"
31
- pypi = "zizmor"
32
21
  brew = "zizmor"
33
22
  cargo = "zizmor"
23
+ mise = "zizmor"
24
+ name = "zizmor"
25
+ pypi = "zizmor"
26
+ version = "1.30.1"
34
27
 
35
28
  [[tool_file]]
36
- source = "zizmor.yml"
37
29
  target = ".gspot/config/zizmor.yml"
38
30
  tool = "zizmor"
39
31
 
40
32
  [[check]]
41
- name = "actionlint"
42
- example = "A workflow using an unknown expression context such as `${{ unknown.value }}` reports an actionlint error. Replace it with a supported context and property for that workflow location."
43
- level = "recommended"
44
- stage = "commit"
45
- tool = ["actionlint", "shellcheck"]
46
33
  command = ["actionlint", "-no-color", "{files}"]
47
- files = { paths = ["**/.github/workflows/*.{yml,yaml}"] }
34
+ example = "A workflow expression with the unknown context `${{ unknown.value }}` reports an error. Use a supported context and property there instead."
48
35
  exit_codes = [1]
36
+ files = { paths = ["**/.github/workflows/*.{yml,yaml}"] }
37
+ help = "Fix the line actionlint names."
38
+ level = "recommended"
39
+ name = "actionlint"
49
40
  output = { format = "regex", pattern = "^(?<file>[^:]+):(?<line>\\d+):(?<column>\\d+): (?<message>.*?) \\[(?<rule>[a-z-]+)\\]$" }
41
+ stage = "commit"
50
42
  summary = "Checks every GitHub Actions workflow with actionlint: syntax, expressions, action inputs, and shell steps."
43
+ tool = ["actionlint", "shellcheck"]
51
44
  why = "A workflow error surfaces on the first push after the change, in CI, where it costs a round trip."
52
- help = "Fix the line actionlint names."
53
45
 
54
46
  [[check]]
55
- name = "pinact"
56
- example = "An action reference such as `actions/checkout@v4` without a full commit pin reports an unpinned action. Resolve a reviewed release to its full commit SHA and record the matching version comment beside the pin."
57
- level = "recommended"
58
- stage = "push"
59
- needs = ["network"]
60
- command = ["pinact", "run", "--verify-comment", "--check", "{files}"]
61
- output = { format = "lines" }
62
- summary = "Checks that each GitHub action has a full commit pin that exists and a matching version comment."
63
- why = "A tag can move between runs, a nonexistent commit prevents the workflow from starting, and a wrong version comment hides the intended release."
64
- help = "Replace the invalid action pin with a verified commit and its matching version comment."
65
-
66
- [[check]]
67
- name = "zizmor"
68
- example = "A workflow interpolating pull-request text directly into a shell command can report a template-injection audit. Pass the text through a step environment variable and quote its expansion instead of interpolating it into shell code."
69
- level = "recommended"
70
- stage = "commit"
71
47
  command = ["zizmor", "--offline", "--no-progress", "--format", "github", "--config", "{tool_file:zizmor}", "{files}"]
48
+ example = "A workflow that puts pull request text straight into a shell command reports `template-injection`. Pass the text through a step environment variable, and quote its expansion."
72
49
  exit_codes = [11, 12, 13, 14]
50
+ help = "Apply the fix zizmor names, or turn one audit off with `gspot ignore github-actions/zizmor --rule <audit> --reason \"<why>\"`."
51
+ level = "recommended"
52
+ name = "zizmor"
73
53
  output = { format = "regex", pattern = "^::(?:warning|error|notice) file=(?<file>[^,]+),line=(?<line>\\d+),title=(?<rule>[^:]+)::(?<message>.*)$" }
54
+ stage = "commit"
74
55
  summary = "Audits GitHub Actions workflows and composite actions with zizmor for template injection, excessive permissions, and dangerous triggers."
75
56
  why = "A workflow runs with the repository's credentials; an injectable expression can hand them to a stranger."
76
- help = "Apply the fix zizmor names, or turn one audit off with gspot ignore github-actions/zizmor --rule `<audit>` --reason \"`<why>`\"."
@@ -1,13 +1,17 @@
1
1
  # GitHub Actions
2
2
 
3
+ Read this rule when you change a GitHub Actions workflow or action.
4
+
3
5
  ## Workflow shape
4
6
 
5
- - Every job has `timeout-minutes`. Every workflow that can run twice for one ref has a
6
- `concurrency` group with `cancel-in-progress` for pull requests.
7
+ - Every job has `timeout-minutes`.
8
+ - Every workflow that can run twice for one ref has a `concurrency` group. Cancel a run in progress only for a pull
9
+ request. Never cancel a run on the default branch or a tag; its result records that commit.
7
10
  - Pin a runner image such as `ubuntu-24.04` for each job. Do not use `ubuntu-latest`.
8
- - No `continue-on-error` without a reason comment. Required failures must fail the job.
9
- - Upload diagnostics after failed checks with an explicit status condition. Deployments and
10
- release publication require successful prerequisites.
11
+ - No `continue-on-error` without a reason comment. Required steps that break must fail the job.
12
+ - Upload diagnostics after failed checks with an explicit status condition. Deployments and release publication
13
+ require successful prerequisites.
14
+ - Before a release job publishes a package or creates a release, it runs the tests or needs the job that does.
11
15
 
12
16
  ## Repository actions and secrets
13
17
 
@@ -17,19 +21,19 @@
17
21
 
18
22
  ## Scripts
19
23
 
20
- - Declare the shell required by the script. The explicit Bash shell in GitHub Actions enables `-e` and
21
- `pipefail`, but does not enable `-u`. Enable required options and validate inputs explicitly.
24
+ - Declare the shell required by the script. The explicit Bash shell in GitHub Actions turns on `-e` and
25
+ `pipefail`, but not `-u`. Enable required options and validate inputs explicitly.
22
26
  - Key caches on the lockfile hash and the runtime version. Restore keys never match a
23
27
  different lockfile.
24
28
 
25
29
  ## Outputs
26
30
 
27
31
  - Artifacts and summaries name the job and the ref. Set retention explicitly.
28
- - Give deploy credentials only to the workflow that deploys. Run it on a protected
29
- environment with a reviewer.
30
-
31
- See [the GitHub shell configuration](https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax#jobsjob_idstepsshell)
32
- for the command each runner uses.
32
+ - Each job leaves a result that a later one, a deployment, or a person uses. Do not upload an artifact that no job
33
+ downloads. Do not build the same output in two workflows.
34
+ - Give deploy credentials only to the job that deploys, as `env` on the step that needs them. Deploy only from the
35
+ default branch or a release tag. When the repository uses GitHub environments, run the job in a protected
36
+ one with a reviewer.
33
37
 
34
38
  ## Workflow organization
35
39