@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
package/README.md CHANGED
@@ -1,19 +1,66 @@
1
1
  # gspot
2
2
 
3
- gspot lints AI-generated code and writes rules for AI coding agents.
3
+ gspot sets up linters, formatters, and security scanners for your repository and runs them before every commit.
4
+
5
+ ## What it does
6
+
7
+ - **Picks the checks.** `gspot init` reads your files and turns on the checks for the languages and frameworks it
8
+ finds.
9
+ - **Pins the tools.** Each check runs a known tool, such as ESLint, Ruff, or ShellCheck, at one version everywhere.
10
+ - **Stops bad commits.** Git hooks check the staged files, and a CI job checks every push.
11
+ - **Writes rules for your agent.** `AGENTS.md` and one rule file for each language say how to write code that
12
+ passes.
13
+
14
+ ## What it flags
15
+
16
+ - Bugs and type errors
17
+ - Security problems and leaked secrets
18
+ - Vulnerable dependencies and licenses that you do not allow
19
+ - Formatting, broken links, and spelling
20
+ - Lint rules turned off without a reason
21
+ - With `gspot set level all`: naming, structure, doc comments, duplication, and complexity
22
+
23
+ A blocked commit lists each finding with its file, line, and rule:
24
+
25
+ ```text
26
+ javascript/eslint failed 2 findings
27
+ src/checkout.ts:4:8 @typescript-eslint/require-await Async function 'pay' has no 'await' expression.
28
+ src/checkout.ts:8:13 no-empty Empty block statement.
29
+ ```
4
30
 
5
31
  ## Install
6
32
 
7
- Commit your work, then run:
33
+ You need Git and Node.js 24.15 or newer. With mise, gspot also installs program tools such as Gitleaks and
34
+ ShellCheck.
8
35
 
9
- ```sh
10
- npm install --save-dev --save-exact @gspothq/cli
11
- git add package.json package-lock.json
12
- git commit -m "build: Add gspot"
13
- npx gspot init
14
- npx gspot install
15
- npx gspot check
36
+ | Package manager | Install | Run |
37
+ | ------------------------------ | -------------------------------------------------------------------------------- | -------------------- |
38
+ | npm | `npm install --save-dev --save-exact @gspothq/cli` | `npx gspot` |
39
+ | pnpm | `pnpm add --save-dev --save-exact @gspothq/cli` | `pnpm exec gspot` |
40
+ | Yarn | `yarn add --dev --exact @gspothq/cli` | `yarn exec gspot` |
41
+ | Bun | `bun add --dev --exact @gspothq/cli` | `bunx gspot` |
42
+ | mise, without a `package.json` | `mise use --pin node@24 --tool-option allow_low_downloads=true npm:@gspothq/cli` | `mise exec -- gspot` |
43
+
44
+ ## Set up
45
+
46
+ ```shell
47
+ npx gspot init # pick the checks, then write gspot.toml, the tool files, and the agent rules
48
+ npx gspot install # install the tools and turn on the Git hooks
49
+ npx gspot check # check every file now
16
50
  ```
17
51
 
18
- The [install guide](https://generativespotting.com/guides/install/) covers other package managers and mise. The
19
- [gspot guides and reference](https://generativespotting.com/) cover everything else.
52
+ Commit the files that `gspot init` writes. Git does not keep the installed tools or the hooks, so run
53
+ `npx gspot install` again in each new clone.
54
+
55
+ ## Documentation
56
+
57
+ - [Quickstart](https://generativespotting.com/start/quickstart/)
58
+ - [Read and fix findings](https://generativespotting.com/use/findings/)
59
+ - [Settings in gspot.toml](https://generativespotting.com/configure/gspot-toml/)
60
+ - [Every check](https://generativespotting.com/reference/checks/) and
61
+ [every command](https://generativespotting.com/reference/commands/)
62
+ - [Source code and issues](https://github.com/stefanionescu/gspot)
63
+
64
+ ## License
65
+
66
+ [Apache-2.0](https://github.com/stefanionescu/gspot/blob/main/LICENSE.md)
@@ -1,114 +1,108 @@
1
1
  allowed_words = ["PostgreSQL", "Postgres"]
2
+
2
3
  [configuration]
3
- title = "Postgres"
4
+ description = "Postgres migrations: squawk for changes that lock or break, ordered versions, and no edits after a run. Schema checks require row security, explicit grants, and an index under every foreign key."
4
5
  requires = ["sql"]
5
- description = "Postgres migrations: squawk for the changes that lock or break, ordered versions, and migrations that never change after they run. The schema checks ask for row security, explicit grants, and an index under every foreign key."
6
+ title = "Postgres"
6
7
 
7
8
  [detect]
8
- dependencies = ["pg", "postgres", "psycopg", "asyncpg", "@neondatabase/serverless"]
9
9
  content = { "prisma/schema.prisma" = '(?:^|\n)[\t ]*provider[\t ]*=[\t ]*"postgresql"' }
10
+ dependencies = ["pg", "postgres", "psycopg", "asyncpg", "@neondatabase/serverless"]
10
11
 
11
12
  [files]
12
13
  paths = ["db/migrations/*.sql", "migrations/*.sql", "**/supabase/migrations/*.sql"]
13
14
 
15
+ [defaults]
16
+ "tools.sqlfluff.dialect" = "postgres"
17
+
18
+ [[naming.override]]
19
+ allow_digits = true
20
+ categories = ["folders"]
21
+ paths = ["**/migrations/**"]
22
+ reason = "Migration directories use the migration tool timestamp names."
23
+
14
24
  [[tool]]
15
- name = "squawk"
16
- version = "2.64.0"
25
+ github = { name = "sbdchd/squawk", version = "v2.64.0" }
17
26
  min_version = "2.0.0"
18
27
  mise = "github:sbdchd/squawk"
28
+ name = "squawk"
19
29
  npm = "squawk-cli"
20
- github = { name = "sbdchd/squawk", version = "v2.64.0" }
21
- [[tool.replace]]
22
- file = ".squawk.toml"
23
- shared = false
24
-
25
- [[tool.replace]]
26
- file = "squawk.toml"
27
- shared = false
30
+ replace = [".squawk.toml", "squawk.toml"]
31
+ version = "2.64.0"
28
32
 
29
33
  [[tool_file]]
34
+ per_scope = true
30
35
  target = ".gspot/config/squawk.toml"
31
36
  tool = "squawk"
32
- per_scope = true
33
- rule_keys = ["excluded_rules"]
34
37
 
35
38
  [[check]]
36
- name = "squawk"
39
+ command = ["squawk", "--config", "{tool_file:squawk}", "--reporter", "json", "{files}"]
40
+ example = "A migration that adds a constraint with a full table scan reports a finding. Create the constraint first, and validate it in a separate migration."
37
41
  files = { paths = ["{setting:postgres.migrations_folder}/**/*.sql"] }
38
- example = "A migration adding a constraint that requires a disruptive table scan can report a migration-safety finding. Follow the reported rule to separate creation and validation or otherwise reduce the lock, then review the migration against the deployment database."
42
+ help = "Follow the advice squawk prints for the rule. Turn one rule off with `gspot ignore postgres/squawk --rule <name> --reason \"<why>\"`."
39
43
  level = "recommended"
40
- stage = "commit"
41
- command = ["squawk", "--config", "{tool_file:squawk}", "--reporter", "json", "{files}"]
44
+ name = "squawk"
42
45
  output = { format = "json", line_base = 0, fields = { file = "file", line = "line", column = "column", rule = "rule_name", message = "message" } }
43
- summary = "Reads every migration for the change that locks a table, rewrites it, or breaks the running application."
46
+ stage = "commit"
47
+ summary = "Checks every migration for changes that lock or rewrite a table, or break the running application."
44
48
  why = "A migration that takes an exclusive lock on a large table stops the application for as long as it runs."
45
- help = "Follow the help squawk prints for the rule. Turn one rule off with gspot ignore postgres/squawk --rule `<name>` --reason \"`<why>`\"."
46
49
 
47
50
  [[check]]
48
- name = "migration-order"
49
- example = "A new migration numbered before the latest committed migration reports an ordering finding. Give the new migration a version later than the committed maximum without renaming already applied migrations."
51
+ example = "A new migration numbered below the latest committed one reports a finding. Give it a later version, and leave applied migrations unchanged."
52
+ help = "Rename the new migration with a version later than the newest committed one."
50
53
  level = "recommended"
51
- stage = "commit"
54
+ name = "migration-order"
52
55
  runs = "scope"
56
+ stage = "commit"
53
57
  summary = "Checks that every migration has a version, that no two share one, and that a new migration sorts after the committed ones."
54
- why = "A migration that sorts before one already applied never runs on the databases that are ahead of it."
55
- help = "Rename the new migration with a version later than the newest committed one."
58
+ why = "A migration that sorts before an applied one never runs on databases already past it."
56
59
 
57
60
  [[check]]
58
- name = "edited-migrations"
59
- example = "Editing an already committed migration reports a frozen-history finding. Preserve the intended change as a new migration, restore the original migration bytes, and rerun. Do not rewrite a migration already applied to shared databases."
61
+ example = "An edit to a committed migration reports a finding. Restore the original file, and write the change as a new migration."
62
+ help = "Restore the file with `git checkout`, and write the change as a new migration."
60
63
  level = "recommended"
61
- stage = "commit"
64
+ name = "edited-migrations"
62
65
  runs = "scope"
66
+ stage = "commit"
63
67
  summary = "Checks that no migration at or before postgres.frozen_through differs from its committed text."
64
- why = "A migration that ran never runs again, so an edit to it changes new databases only and the environments drift apart."
65
- help = "Restore the file with git checkout, and write the change as a new migration."
68
+ why = "An applied migration never runs again, so an edit reaches only new databases, and environments drift apart."
66
69
 
67
70
  [[check]]
68
- name = "row-level-security"
69
- example = "A newly created table without row-level security reports a missing-RLS finding. Add `ALTER TABLE ... ENABLE ROW LEVEL SECURITY` for the table."
71
+ example = "A new table without row-level security reports a finding. Add `ALTER TABLE ... ENABLE ROW LEVEL SECURITY` for it."
72
+ help = "Enable row level security on the table."
70
73
  level = "recommended"
71
- stage = "commit"
74
+ name = "row-level-security"
72
75
  runs = "scope"
76
+ stage = "commit"
73
77
  summary = "Checks that every table in a client schema turns on row level security."
74
- why = "A table in an exposed schema with no row security is readable and writable by every client that holds the public key."
75
- help = "Enable row level security on the table."
78
+ why = "In an exposed schema, every client with the public key can read and write a table that has no row security."
76
79
 
77
80
  [[check]]
78
- name = "grants"
79
81
  example = "The statement `GRANT ALL ON TABLE public.items TO app_reader;` reports a broad grant. If the role only reads rows, use `GRANT SELECT ON TABLE public.items TO app_reader;`."
82
+ help = "Name the privileges the role needs, such as `SELECT` alone."
80
83
  level = "recommended"
81
- stage = "commit"
84
+ name = "grants"
82
85
  runs = "scope"
83
- summary = "Refuses a grant of every privilege in a migration."
84
- why = "Granting everything includes truncating the table, adding triggers, and every privilege a later Postgres adds, which nobody meant to give."
85
- help = "Name the privileges the role needs, such as `SELECT` alone."
86
+ stage = "commit"
87
+ summary = "Reports a migration that grants all privileges."
88
+ why = "A full grant includes truncating the table, adding triggers, and each privilege a later Postgres adds, which nobody meant to give."
86
89
 
87
90
  [[check]]
88
- name = "definer-search-path"
89
- example = "A `SECURITY DEFINER` function without an explicit safe search path reports a finding. Add `SET search_path = ''` to the definition and schema-qualify the objects used in its body."
91
+ example = "A `SECURITY DEFINER` function without a safe search path reports a finding. Add `SET search_path = ''` to the definition, and schema-qualify the objects in its body."
92
+ help = "Give the function an empty `search_path` in its definition, and qualify every name inside it."
90
93
  level = "recommended"
91
- stage = "commit"
94
+ name = "definer-search-path"
92
95
  runs = "scope"
96
+ stage = "commit"
93
97
  summary = "Checks that every SECURITY DEFINER function sets its search_path."
94
98
  why = "A definer function runs with its owner's rights, and a caller who controls the search path chooses the objects it touches."
95
- help = "Give the function an empty `search_path` in its definition, and qualify every name inside it."
96
99
 
97
100
  [[check]]
98
- name = "foreign-key-indexes"
99
101
  example = "A foreign key on `orders.customer_id` without an index starting with that column reports a missing index. Add `CREATE INDEX orders_customer_id_idx ON orders (customer_id);` in the migration set."
102
+ help = "Create an index that starts with the foreign key column."
100
103
  level = "recommended"
101
- stage = "commit"
104
+ name = "foreign-key-indexes"
102
105
  runs = "scope"
106
+ stage = "commit"
103
107
  summary = "Checks that an index, a primary key, or a unique key leads with every foreign key column."
104
108
  why = "Deleting a parent row scans the whole child table when the foreign key has no index."
105
- help = "Create an index that starts with the foreign key column."
106
-
107
- [[naming.override]]
108
- paths = ["**/migrations/**"]
109
- categories = ["directories"]
110
- allow_digits = true
111
- reason = "Migration directories use the migration tool timestamp names."
112
-
113
- [defaults]
114
- "tools.sqlfluff.dialect" = "postgres"
@@ -1,12 +1,13 @@
1
1
  # Postgres
2
2
 
3
- Migrations, tables, row security, functions, grants, data migrations, and tests of a Postgres
4
- database. Use the roles and schemas the application declares.
3
+ Read this rule when you change Postgres migrations, policies, functions, grants, or database tests.
4
+
5
+ Use the roles and schemas the application declares.
5
6
 
6
7
  ## Migrations
7
8
 
8
- - Create a blank migration with the project's migration command, then edit the generated file.
9
- - Repair migration history only when the user asks for that task.
9
+ - Create a blank migration with the command the project uses, then edit the generated file.
10
+ - Repair migration history only when the user asks.
10
11
  - Make every durable change through a migration. Never use a web console or SQL editor on a remote database.
11
12
  - Use idempotent data definition language (DDL) only when the public interface promises repeated execution and you verify existing definitions. Do not hide schema drift with `IF NOT EXISTS`.
12
13
 
@@ -14,39 +15,39 @@ database. Use the roles and schemas the application declares.
14
15
 
15
16
  - Use UUIDv7 keys when rows need time order.
16
17
  - Use `TIMESTAMPTZ` for timestamps. Mutable rows that need audit columns get `created_at` and
17
- `updated_at`, which the declared timestamp trigger or write owner updates.
18
+ `updated_at`, which the declared timestamp trigger or the writing code updates.
18
19
  - Index common filters, ordering columns, and frequent row security predicates.
19
20
  - Durable invariants live in the database as generated columns, uniqueness, and check
20
21
  constraints, not only in client validation.
21
22
 
22
23
  ## Row-level security
23
24
 
24
- - Every policy names its roles with `TO`, unless every role belongs in it.
25
+ - Each policy names its roles with `TO`, unless all roles belong in it.
25
26
  - Wrap the identity function of an ownership check in a scalar subquery, so the planner evaluates
26
27
  it once per statement instead of once per row.
27
- - `UPDATE` needs both a `SELECT` policy and an `UPDATE` policy.
28
+ - `UPDATE` needs both a `SELECT` and an `UPDATE` policy.
28
29
 
29
30
  | Operation | Policy expression |
30
31
  | ----------- | ------------------------------------------------------------------------------- |
31
32
  | Read rows | `USING` selects visible existing rows |
32
33
  | Insert rows | `WITH CHECK` validates the proposed row; an insert policy has no `USING` clause |
33
34
  | Update rows | `USING` selects existing rows and `WITH CHECK` validates their new values |
34
- | Delete rows | `USING` selects rows that may be deleted |
35
+ | Delete rows | `USING` selects rows the role may delete |
35
36
 
36
- - Permissive policies broaden access and restrictive policies add conditions; review how every
37
- policy for the role combines.
37
+ - Permissive policies broaden access and restrictive ones add conditions; review how all
38
+ policies for the role combine.
38
39
  - Check resource ownership and tenant membership. Check proposed values too, so an update cannot
39
40
  move a row into another user's or tenant's scope.
40
41
  - Handle an unauthenticated identity explicitly, and limit anonymous access to the rows and
41
42
  operations the public API exposes.
42
43
  - Authorize from trusted claims and current membership data, never from user-editable template
43
- metadata, and account for stale claims after a membership change.
44
- - Grants and row level security (RLS) provide separate controls: restrict table and schema privileges, then limit rows with
44
+ metadata. Account for stale claims after a membership change.
45
+ - Grants and row level security (RLS) control access separately: restrict table and schema privileges, then limit rows with
45
46
  policies. RLS does not cover `TRUNCATE`.
46
47
  - A `USING (true)` policy fits only a public or service-only table, and the
47
48
  migration says why.
48
49
  - A privileged service role still needs explicit table grants, never a bypass for precise ones.
49
- - A view that clients can read sets `security_invoker = true` on Postgres 15 and later to respect
50
+ - A view that clients can read sets `security_invoker = true` on Postgres 15 and later to apply
50
51
  the RLS of its tables. Otherwise, revoke access to it or keep it in a private schema.
51
52
 
52
53
  ## Functions and grants
@@ -1,10 +1,8 @@
1
-
2
-
3
1
  [configuration]
4
- title = "Astro"
2
+ description = "Astro components: ESLint applies the recommended and accessibility rules of eslint-plugin-astro as errors to frontmatter, markup, and scripts. `astro check` reports type errors in each component."
5
3
  requires = ["javascript"]
6
4
  suggests = ["typescript", "css"]
7
- description = "Astro components: ESLint reads the frontmatter, the markup, and the scripts together with the recommended and accessibility rules of the Astro plugin as errors, and astro check reports type errors in every component."
5
+ title = "Astro"
8
6
 
9
7
  [detect]
10
8
  dependencies = ["astro"]
@@ -14,12 +12,15 @@ extensions = [".astro"]
14
12
  extensions = [".astro"]
15
13
  filenames = ["astro.config.mjs", "astro.config.ts"]
16
14
 
15
+ [defaults]
16
+ "tools.eslint.import_extension" = "extensionless"
17
+
17
18
  [[tool]]
19
+ kind = "library"
18
20
  name = "eslint-plugin-astro"
21
+ npm = "eslint-plugin-astro"
19
22
  rule_prefix = "astro"
20
- kind = "library"
21
23
  version = "1.7.0"
22
- npm = "eslint-plugin-astro"
23
24
 
24
25
  [tool.eslint]
25
26
  extensions = [".astro"]
@@ -29,15 +30,15 @@ name = "eslint-plugin-jsx-a11y"
29
30
 
30
31
  [[tool]]
31
32
  name = "astro-check"
32
- version = "0.9.10"
33
33
  npm = "@astrojs/check"
34
+ version = "0.9.10"
34
35
  version_command = ["astro", "check", "--version"]
35
36
 
36
37
  [[tool]]
37
- name = "prettier-plugin-astro"
38
38
  kind = "library"
39
- version = "1.0.1"
39
+ name = "prettier-plugin-astro"
40
40
  npm = "prettier-plugin-astro"
41
+ version = "1.0.1"
41
42
 
42
43
  [tool.prettier]
43
44
  entry = "dist/index.js"
@@ -49,26 +50,6 @@ files = "*.astro"
49
50
  [tool.prettier.overrides.options]
50
51
  parser = "astro"
51
52
 
52
- [[check]]
53
- name = "astro-check"
54
- example = "A component whose frontmatter holds `const count: number = 'three';` reports `ts(2322)`. Give the value the declared type, such as `const count: number = 3;`."
55
- level = "recommended"
56
- stage = "push"
57
- runs = "scope"
58
- cwd = "scope"
59
- command = ["astro-check", "astro", "check", "--minimumSeverity", "warning", "--minimumFailingSeverity", "warning"]
60
- exit_codes = [1]
61
- summary = "Runs astro check over the scope: the type errors and warnings of every Astro component."
62
- why = "The TypeScript compiler cannot read a component file, so a type error inside one ships unless the Astro checker reads it."
63
- help = "Read the first error astro check prints and fix that component; later errors are often the same mistake."
64
-
65
- [check.files]
66
- extensions = [".astro"]
67
-
68
- [check.output]
69
- format = "regex"
70
- pattern = "^(?<file>[^:\\s][^:]*\\.astro):(?<line>\\d+):(?<column>\\d+) - (?:error|warning) (?<rule>[a-z-]+\\(\\d+\\)): (?<message>.*)$"
71
-
72
53
  [eslint]
73
54
  all_level_rules = ["astro/no-unused-css-selector", "astro/prefer-class-list-directive", "astro/prefer-object-class-list", "astro/prefer-split-class-list"]
74
55
 
@@ -81,15 +62,32 @@ package = "eslint-plugin-astro"
81
62
  source = "configs.flat/jsx-a11y-recommended"
82
63
 
83
64
  [[eslint.rules_off]]
84
- rules = ["gspot/no-trivial-files"]
85
65
  files = ["**/*.astro", "**/*.astro/*.ts", "**/*.astro/*.js"]
86
66
  reason = "A component is markup, never a file that only forwards: a script that only imports a module is how Astro bundles client code, and Astro reads the props of a component from the Props type in its own frontmatter."
87
-
88
- [defaults]
89
- "tools.eslint.import_extension" = "extensionless"
67
+ rules = ["gspot/no-trivial-files"]
90
68
 
91
69
  [[tool_file]]
92
- target = ".gspot/config/eslint.config.mjs"
93
- tool = "eslint"
94
70
  fragment = true
95
71
  required_tools = ["eslint-plugin-astro", "eslint-plugin-jsx-a11y"]
72
+ target = ".gspot/config/eslint.config.mjs"
73
+ tool = "eslint"
74
+
75
+ [[check]]
76
+ command = ["astro-check", "astro", "check", "--minimumSeverity", "warning", "--minimumFailingSeverity", "warning"]
77
+ cwd = "scope"
78
+ example = "A component whose frontmatter holds `const count: number = 'three';` reports `ts(2322)`. Give the value the declared type, such as `const count: number = 3;`."
79
+ exit_codes = [1]
80
+ help = "Fix the first error `astro check` prints; later errors often come from the same mistake."
81
+ level = "recommended"
82
+ name = "astro-check"
83
+ runs = "scope"
84
+ stage = "push"
85
+ summary = "Runs astro check over the scope: the type errors and warnings of every Astro component."
86
+ why = "tsc cannot parse a component file, so a type error inside one ships unless `astro check` catches it."
87
+
88
+ [check.files]
89
+ extensions = [".astro"]
90
+
91
+ [check.output]
92
+ format = "regex"
93
+ pattern = "^(?<file>[^:\\s][^:]*\\.astro):(?<line>\\d+):(?<column>\\d+) - (?:error|warning) (?<rule>[a-z-]+\\(\\d+\\)): (?<message>.*)$"
@@ -1,6 +1,6 @@
1
1
  # Astro
2
2
 
3
- These rules cover Astro components, islands, markup, routing, and the data a page loads.
3
+ Read this rule when you change Astro components, pages, or content collections.
4
4
 
5
5
  ## Components
6
6
 
@@ -19,7 +19,7 @@ These rules cover Astro components, islands, markup, routing, and the data a pag
19
19
  - Ship HTML by default. Add a `client:` directive only to a component that needs the browser.
20
20
  - Pick the most deferred directive that works: `client:visible` or `client:idle` before `client:load`.
21
21
  - `client:only` names the framework of the component, such as `client:only="react"`.
22
- - Astro serializes island props, so pass plain data. A function or a class instance does not survive the trip.
22
+ - Astro serializes island props, so pass plain data. A function or a class instance does not survive serialization.
23
23
 
24
24
  ## Markup
25
25
 
@@ -1,7 +1,7 @@
1
1
  [configuration]
2
- title = "Expo"
2
+ description = "Expo applications: rules for public environment variables and DOM exports, and the project and SDK checks of Expo Doctor. The React Native configuration adds the component and style rules."
3
3
  requires = ["react-native"]
4
- description = "Expo applications: rules for public environment variables and DOM exports, plus Expo Doctor's project and SDK compatibility checks. React Native supplies the native component and style rules."
4
+ title = "Expo"
5
5
 
6
6
  [detect]
7
7
  dependencies = ["expo"]
@@ -10,34 +10,34 @@ dependencies = ["expo"]
10
10
  filenames = ["app.json", "app.config.js", "app.config.ts", "eas.json"]
11
11
 
12
12
  [[tool]]
13
+ kind = "library"
13
14
  name = "eslint-plugin-expo"
15
+ npm = "eslint-plugin-expo"
14
16
  rule_prefix = "expo"
15
- kind = "library"
16
17
  version = "1.1.0"
17
- npm = "eslint-plugin-expo"
18
18
 
19
19
  [[tool]]
20
20
  name = "expo-doctor"
21
- version = "1.20.4"
22
21
  npm = "expo-doctor"
23
-
24
- [[check]]
25
- name = "doctor"
26
- tool = "expo-doctor"
27
- example = "An Expo project whose installed `react-native` differs from the version its Expo SDK expects reports a failed Doctor check. Install the expected version with `npx expo install --check` and rerun."
28
- level = "recommended"
29
- stage = "push"
30
- runs = "scope"
31
- needs = ["network"]
32
- summary = "Runs Expo Doctor in the selected Expo scope and reports each failed check with its issues."
33
- why = "A native package on the wrong version for the Expo SDK builds and then crashes on the device."
34
- help = "Read the issues and advice Expo Doctor prints for the failed check, then run npx expo install --check."
22
+ version = "1.20.4"
35
23
 
36
24
  [eslint]
37
25
  all_level_rules = ["expo/prefer-box-shadow"]
38
26
 
39
27
  [[tool_file]]
40
- target = ".gspot/config/eslint.config.mjs"
41
- tool = "eslint"
42
28
  fragment = true
43
29
  required_tools = ["eslint-plugin-expo"]
30
+ target = ".gspot/config/eslint.config.mjs"
31
+ tool = "eslint"
32
+
33
+ [[check]]
34
+ example = "A `react-native` version that differs from the one the Expo SDK requires fails a Doctor check. Run `npx expo install --check` to install the matching version."
35
+ help = "Follow the advice Expo Doctor prints, then run `npx expo install --check`."
36
+ level = "recommended"
37
+ name = "expo-doctor"
38
+ needs = ["network"]
39
+ runs = "scope"
40
+ stage = "push"
41
+ summary = "Runs Expo Doctor and reports each failed check with its details."
42
+ tool = "expo-doctor"
43
+ why = "A native package on the wrong version for the Expo SDK builds and then crashes on the device."
@@ -1,17 +1,23 @@
1
1
  [configuration]
2
- title = "Express"
2
+ description = "An Express service: Semgrep rules for request handling, and an OpenAPI document that lints and matches its source."
3
3
  requires = ["javascript"]
4
4
  suggests = ["openapi"]
5
- description = "An Express service: the Semgrep rules for request handling, an OpenAPI document that lints and matches its source."
5
+ title = "Express"
6
6
 
7
7
  [detect]
8
8
  dependencies = ["express"]
9
9
 
10
10
  [[eslint.selectors]]
11
- selector = "CallExpression[callee.property.name=/^(json|send)$/] ObjectExpression > Property[key.name=/^(message|error)$/] > TemplateLiteral.value[expressions.length>0]"
12
11
  message = "A message a client reads names no identifier; put the value in its own field."
12
+ selector = "CallExpression[callee.property.name=/^(json|send)$/] ObjectExpression > Property[key.name=/^(message|error)$/] > TemplateLiteral.value[expressions.length>0]"
13
13
 
14
14
  [[tool_file]]
15
+ fragment = true
15
16
  target = ".gspot/config/eslint.config.mjs"
16
17
  tool = "eslint"
17
- fragment = true
18
+
19
+ [[tool_file]]
20
+ per_scope = true
21
+ target = ".gspot/config/semgrep/express.yml"
22
+ tool = "semgrep"
23
+ when = { configuration = "security" }
@@ -1,6 +1,8 @@
1
1
  # Express
2
2
 
3
- Routes, middleware, errors, and body parsing in an Express service, on top of the HTTP rules.
3
+ Read this rule when you change routes, middleware, or error handling in an Express service.
4
+
5
+ Follow the HTTP rules too.
4
6
 
5
7
  ## Routes and middleware
6
8
 
@@ -33,18 +35,18 @@ router.post('/orders', authenticate, validateBody(submitOrderSchema), async (req
33
35
 
34
36
  - Middleware can enforce ownership. It reaches the database for product behavior only through auth
35
37
  or ownership helpers built for that boundary.
36
- - A permission check that depends on domain state belongs in a module; a transport-level one
37
- belongs in ownership middleware.
38
+ - A permission check that depends on domain state belongs in a module, and a transport-level one
39
+ in ownership middleware.
38
40
 
39
41
  ## Errors
40
42
 
41
- - Express 5 forwards the rejection of a promise that a route or middleware returns, so return the
42
- promise and add no wrapper that repeats this. Express 4 needs the project's async handler or an
43
+ - Express 5 forwards a rejected promise that a route or middleware returns, so return it and add
44
+ no wrapper that repeats this. Express 4 needs the project's async handler or an
43
45
  explicit `next(error)`.
44
46
  - Callback-based asynchronous work passes its errors to `next(error)` in both versions.
45
47
  - Error middleware keeps its four-argument signature, even when the function does not use an argument.
46
- - After the response sends its headers, error middleware calls `next(error)` instead of writing a
47
- second response.
48
+ - After the headers go out, error middleware calls `next(error)` instead of writing a second
49
+ response.
48
50
  - The not-found handler comes after every route.
49
51
 
50
52
  ## Body parsing and proxies
@@ -1,11 +1,17 @@
1
1
  [configuration]
2
- title = "FastAPI"
2
+ description = "Checks FastAPI routes with Ruff. With security, adds Semgrep rules for request handling, and suggests the OpenAPI configuration."
3
3
  requires = ["python"]
4
4
  suggests = ["openapi"]
5
- description = "Checks FastAPI route declarations with Ruff. Adds Semgrep request-handling rules when security is selected and suggests the OpenAPI configuration."
5
+ title = "FastAPI"
6
6
 
7
7
  [detect]
8
8
  dependencies = ["fastapi"]
9
9
 
10
- [ruff_rules]
10
+ [ruff]
11
11
  recommended = ["FAST001", "FAST002", "FAST003"]
12
+
13
+ [[tool_file]]
14
+ per_scope = true
15
+ target = ".gspot/config/semgrep/fastapi.yml"
16
+ tool = "semgrep"
17
+ when = { configuration = "security" }