@m2-ai/lattice-cli 0.0.0-stage → 0.8.7

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 (743) hide show
  1. package/DISCLOSURE +1 -0
  2. package/README.md +118 -2
  3. package/bundles/expo-mobile/.agents/skills/lattice-feature-handoff/SKILL.md +31 -0
  4. package/bundles/expo-mobile/.agents/skills/lattice-release-manager/SKILL.md +29 -0
  5. package/bundles/expo-mobile/.agents/skills/lattice-verify/SKILL.md +27 -0
  6. package/bundles/expo-mobile/.claude/agents/lattice-feature-agent.md +10 -0
  7. package/bundles/expo-mobile/.claude/agents/lattice-release-manager.md +9 -0
  8. package/bundles/expo-mobile/.claude/hooks/README.md +9 -0
  9. package/bundles/expo-mobile/.claude/hooks/pre-commit-verify.mjs +10 -0
  10. package/bundles/expo-mobile/.claude/hooks/pre-tool-use.mjs +51 -0
  11. package/bundles/expo-mobile/.claude/rules/lattice-core.md +20 -0
  12. package/bundles/expo-mobile/.claude/settings.json +38 -0
  13. package/bundles/expo-mobile/.claude/skills/lattice-verify/SKILL.md +27 -0
  14. package/bundles/expo-mobile/.codex/agents/lattice-feature-agent.toml +9 -0
  15. package/bundles/expo-mobile/.codex/agents/lattice-release-manager.toml +9 -0
  16. package/bundles/expo-mobile/.cursor/mcp.json +34 -0
  17. package/bundles/expo-mobile/.cursor/rules/lattice-core.mdc +35 -0
  18. package/bundles/expo-mobile/.cursor/rules.md +94 -0
  19. package/bundles/expo-mobile/.env.example +19 -0
  20. package/bundles/expo-mobile/.github/PULL_REQUEST_TEMPLATE.md +42 -0
  21. package/bundles/expo-mobile/.github/agents/lattice-feature-agent.agent.md +7 -0
  22. package/bundles/expo-mobile/.github/agents/lattice-release-manager.agent.md +7 -0
  23. package/bundles/expo-mobile/.github/copilot-instructions.md +37 -0
  24. package/bundles/expo-mobile/.github/instructions/lattice-core.instructions.md +11 -0
  25. package/bundles/expo-mobile/.github/workflows/ci.yml +26 -0
  26. package/bundles/expo-mobile/.gitmessage +24 -0
  27. package/bundles/expo-mobile/.lattice/config.json +9 -0
  28. package/bundles/expo-mobile/.lattice/dependency-security.json +91 -0
  29. package/bundles/expo-mobile/.lattice/prompts/01-feature.md +36 -0
  30. package/bundles/expo-mobile/.lattice/prompts/02-bugfix.md +32 -0
  31. package/bundles/expo-mobile/.lattice/prompts/03-refactor.md +30 -0
  32. package/bundles/expo-mobile/.lattice/prompts/04-test.md +31 -0
  33. package/bundles/expo-mobile/.lattice/prompts/05-polish.md +38 -0
  34. package/bundles/expo-mobile/.lattice/prompts/06-security.md +32 -0
  35. package/bundles/expo-mobile/.lattice/release-workflow.json +55 -0
  36. package/bundles/expo-mobile/.lattice/schemas/feature-handoff.schema.json +264 -0
  37. package/bundles/expo-mobile/.lattice/templates/feature-handoff.json +52 -0
  38. package/bundles/expo-mobile/.mcp.json +35 -0
  39. package/bundles/expo-mobile/AGENTS.md +58 -0
  40. package/bundles/expo-mobile/CLAUDE.md +75 -0
  41. package/bundles/expo-mobile/PROJECT_GUIDE.md +299 -0
  42. package/bundles/expo-mobile/README.md +39 -0
  43. package/bundles/expo-mobile/__tests__/home.test.tsx +22 -0
  44. package/bundles/expo-mobile/app/_layout.tsx +20 -0
  45. package/bundles/expo-mobile/app/index.tsx +72 -0
  46. package/bundles/expo-mobile/app.json +33 -0
  47. package/bundles/expo-mobile/components/ui/Button.tsx +75 -0
  48. package/bundles/expo-mobile/components/ui/Input.tsx +50 -0
  49. package/bundles/expo-mobile/components/ui/index.ts +2 -0
  50. package/bundles/expo-mobile/docs/LATTICE_RELEASE_WORKFLOW.md +53 -0
  51. package/bundles/expo-mobile/docs/rules/codex.md +62 -0
  52. package/bundles/expo-mobile/eslint.config.js +7 -0
  53. package/bundles/expo-mobile/lib/supabase/client.ts +22 -0
  54. package/bundles/expo-mobile/lib/supabase/realtime.ts +10 -0
  55. package/bundles/expo-mobile/lib/supabase/storage.ts +6 -0
  56. package/bundles/expo-mobile/package.json +65 -0
  57. package/bundles/expo-mobile/plugins/with-lattice-commons-io.cjs +42 -0
  58. package/bundles/expo-mobile/prompts/01-feature-implementation.md +48 -0
  59. package/bundles/expo-mobile/prompts/02-bug-fix.md +43 -0
  60. package/bundles/expo-mobile/prompts/03-safe-refactor.md +38 -0
  61. package/bundles/expo-mobile/prompts/04-test-first.md +41 -0
  62. package/bundles/expo-mobile/prompts/05-ui-polish.md +44 -0
  63. package/bundles/expo-mobile/prompts/06-security-review.md +39 -0
  64. package/bundles/expo-mobile/prompts/quality.md +143 -0
  65. package/bundles/expo-mobile/supabase/migrations/001_initial_schema.sql +66 -0
  66. package/bundles/expo-mobile/tsconfig.json +21 -0
  67. package/bundles/expo-mobile/types/database.types.ts +76 -0
  68. package/bundles/expo-mobile/vendor/m2ai-braces-3.0.3-m2ai.1.tar +0 -0
  69. package/bundles/expo-supabase/.agents/skills/lattice-feature-handoff/SKILL.md +31 -0
  70. package/bundles/expo-supabase/.agents/skills/lattice-release-manager/SKILL.md +29 -0
  71. package/bundles/expo-supabase/.agents/skills/lattice-verify/SKILL.md +27 -0
  72. package/bundles/expo-supabase/.claude/agents/lattice-feature-agent.md +10 -0
  73. package/bundles/expo-supabase/.claude/agents/lattice-release-manager.md +9 -0
  74. package/bundles/expo-supabase/.claude/hooks/README.md +9 -0
  75. package/bundles/expo-supabase/.claude/hooks/pre-commit-verify.mjs +10 -0
  76. package/bundles/expo-supabase/.claude/hooks/pre-tool-use.mjs +51 -0
  77. package/bundles/expo-supabase/.claude/rules/lattice-core.md +20 -0
  78. package/bundles/expo-supabase/.claude/settings.json +38 -0
  79. package/bundles/expo-supabase/.claude/skills/lattice-verify/SKILL.md +27 -0
  80. package/bundles/expo-supabase/.codex/agents/lattice-feature-agent.toml +9 -0
  81. package/bundles/expo-supabase/.codex/agents/lattice-release-manager.toml +9 -0
  82. package/bundles/expo-supabase/.cursor/mcp.json +34 -0
  83. package/bundles/expo-supabase/.cursor/rules/lattice-core.mdc +35 -0
  84. package/bundles/expo-supabase/.cursor/rules.md +94 -0
  85. package/bundles/expo-supabase/.env.example +12 -0
  86. package/bundles/expo-supabase/.github/PULL_REQUEST_TEMPLATE.md +42 -0
  87. package/bundles/expo-supabase/.github/agents/lattice-feature-agent.agent.md +7 -0
  88. package/bundles/expo-supabase/.github/agents/lattice-release-manager.agent.md +7 -0
  89. package/bundles/expo-supabase/.github/copilot-instructions.md +37 -0
  90. package/bundles/expo-supabase/.github/instructions/lattice-core.instructions.md +11 -0
  91. package/bundles/expo-supabase/.github/workflows/ci.yml +26 -0
  92. package/bundles/expo-supabase/.gitmessage +24 -0
  93. package/bundles/expo-supabase/.lattice/config.json +9 -0
  94. package/bundles/expo-supabase/.lattice/dependency-security.json +91 -0
  95. package/bundles/expo-supabase/.lattice/prompts/01-feature.md +36 -0
  96. package/bundles/expo-supabase/.lattice/prompts/02-bugfix.md +32 -0
  97. package/bundles/expo-supabase/.lattice/prompts/03-refactor.md +30 -0
  98. package/bundles/expo-supabase/.lattice/prompts/04-test.md +31 -0
  99. package/bundles/expo-supabase/.lattice/prompts/05-polish.md +38 -0
  100. package/bundles/expo-supabase/.lattice/prompts/06-security.md +32 -0
  101. package/bundles/expo-supabase/.lattice/release-workflow.json +55 -0
  102. package/bundles/expo-supabase/.lattice/schemas/feature-handoff.schema.json +264 -0
  103. package/bundles/expo-supabase/.lattice/templates/feature-handoff.json +52 -0
  104. package/bundles/expo-supabase/.mcp.json +35 -0
  105. package/bundles/expo-supabase/AGENTS.md +58 -0
  106. package/bundles/expo-supabase/CLAUDE.md +75 -0
  107. package/bundles/expo-supabase/PROJECT_GUIDE.md +201 -0
  108. package/bundles/expo-supabase/README.md +38 -0
  109. package/bundles/expo-supabase/__tests__/home.test.tsx +22 -0
  110. package/bundles/expo-supabase/app/_layout.tsx +14 -0
  111. package/bundles/expo-supabase/app/index.tsx +72 -0
  112. package/bundles/expo-supabase/app.json +33 -0
  113. package/bundles/expo-supabase/components/ui/Button.tsx +75 -0
  114. package/bundles/expo-supabase/components/ui/Input.tsx +50 -0
  115. package/bundles/expo-supabase/components/ui/index.ts +2 -0
  116. package/bundles/expo-supabase/docs/LATTICE_RELEASE_WORKFLOW.md +53 -0
  117. package/bundles/expo-supabase/docs/rules/codex.md +62 -0
  118. package/bundles/expo-supabase/eslint.config.js +7 -0
  119. package/bundles/expo-supabase/lib/supabase/client.ts +22 -0
  120. package/bundles/expo-supabase/lib/supabase/realtime.ts +10 -0
  121. package/bundles/expo-supabase/lib/supabase/storage.ts +6 -0
  122. package/bundles/expo-supabase/package.json +60 -0
  123. package/bundles/expo-supabase/plugins/with-lattice-commons-io.cjs +42 -0
  124. package/bundles/expo-supabase/prompts/01-feature-implementation.md +8 -0
  125. package/bundles/expo-supabase/prompts/02-bug-fix.md +9 -0
  126. package/bundles/expo-supabase/prompts/03-safe-refactor.md +8 -0
  127. package/bundles/expo-supabase/prompts/04-test-first.md +7 -0
  128. package/bundles/expo-supabase/prompts/05-ui-polish.md +7 -0
  129. package/bundles/expo-supabase/prompts/06-security-review.md +7 -0
  130. package/bundles/expo-supabase/prompts/quality.md +143 -0
  131. package/bundles/expo-supabase/supabase/migrations/001_initial_schema.sql +66 -0
  132. package/bundles/expo-supabase/tsconfig.json +21 -0
  133. package/bundles/expo-supabase/types/database.types.ts +76 -0
  134. package/bundles/expo-supabase/vendor/m2ai-braces-3.0.3-m2ai.1.tar +0 -0
  135. package/bundles/nextjs-landing/.agents/skills/lattice-feature-handoff/SKILL.md +31 -0
  136. package/bundles/nextjs-landing/.agents/skills/lattice-release-manager/SKILL.md +29 -0
  137. package/bundles/nextjs-landing/.agents/skills/lattice-verify/SKILL.md +27 -0
  138. package/bundles/nextjs-landing/.claude/agents/lattice-feature-agent.md +10 -0
  139. package/bundles/nextjs-landing/.claude/agents/lattice-release-manager.md +9 -0
  140. package/bundles/nextjs-landing/.claude/hooks/README.md +9 -0
  141. package/bundles/nextjs-landing/.claude/hooks/pre-commit-verify.mjs +10 -0
  142. package/bundles/nextjs-landing/.claude/hooks/pre-tool-use.mjs +51 -0
  143. package/bundles/nextjs-landing/.claude/rules/lattice-core.md +20 -0
  144. package/bundles/nextjs-landing/.claude/settings.json +38 -0
  145. package/bundles/nextjs-landing/.claude/skills/lattice-verify/SKILL.md +27 -0
  146. package/bundles/nextjs-landing/.codex/agents/lattice-feature-agent.toml +9 -0
  147. package/bundles/nextjs-landing/.codex/agents/lattice-release-manager.toml +9 -0
  148. package/bundles/nextjs-landing/.cursor/mcp.json +34 -0
  149. package/bundles/nextjs-landing/.cursor/rules/lattice-core.mdc +35 -0
  150. package/bundles/nextjs-landing/.cursor/rules.md +95 -0
  151. package/bundles/nextjs-landing/.env.example +24 -0
  152. package/bundles/nextjs-landing/.github/PULL_REQUEST_TEMPLATE.md +42 -0
  153. package/bundles/nextjs-landing/.github/agents/lattice-feature-agent.agent.md +7 -0
  154. package/bundles/nextjs-landing/.github/agents/lattice-release-manager.agent.md +7 -0
  155. package/bundles/nextjs-landing/.github/copilot-instructions.md +37 -0
  156. package/bundles/nextjs-landing/.github/instructions/lattice-core.instructions.md +11 -0
  157. package/bundles/nextjs-landing/.github/workflows/ci.yml +26 -0
  158. package/bundles/nextjs-landing/.gitmessage +24 -0
  159. package/bundles/nextjs-landing/.lattice/config.json +9 -0
  160. package/bundles/nextjs-landing/.lattice/dependency-security.json +46 -0
  161. package/bundles/nextjs-landing/.lattice/prompts/01-feature.md +36 -0
  162. package/bundles/nextjs-landing/.lattice/prompts/02-bugfix.md +32 -0
  163. package/bundles/nextjs-landing/.lattice/prompts/03-refactor.md +30 -0
  164. package/bundles/nextjs-landing/.lattice/prompts/04-test.md +31 -0
  165. package/bundles/nextjs-landing/.lattice/prompts/05-polish.md +38 -0
  166. package/bundles/nextjs-landing/.lattice/prompts/06-security.md +32 -0
  167. package/bundles/nextjs-landing/.lattice/release-workflow.json +55 -0
  168. package/bundles/nextjs-landing/.lattice/schemas/feature-handoff.schema.json +264 -0
  169. package/bundles/nextjs-landing/.lattice/templates/feature-handoff.json +52 -0
  170. package/bundles/nextjs-landing/.mcp.json +35 -0
  171. package/bundles/nextjs-landing/AGENTS.md +58 -0
  172. package/bundles/nextjs-landing/CLAUDE.md +76 -0
  173. package/bundles/nextjs-landing/PROJECT_GUIDE.md +216 -0
  174. package/bundles/nextjs-landing/README.md +39 -0
  175. package/bundles/nextjs-landing/app/api/example/[id]/route.ts +34 -0
  176. package/bundles/nextjs-landing/app/api/example/route.ts +24 -0
  177. package/bundles/nextjs-landing/app/api/health/route.ts +8 -0
  178. package/bundles/nextjs-landing/app/global-error.tsx +17 -0
  179. package/bundles/nextjs-landing/app/globals.css +55 -0
  180. package/bundles/nextjs-landing/app/layout.tsx +22 -0
  181. package/bundles/nextjs-landing/app/page.tsx +42 -0
  182. package/bundles/nextjs-landing/components/ui/button.tsx +39 -0
  183. package/bundles/nextjs-landing/components/ui/card.tsx +53 -0
  184. package/bundles/nextjs-landing/components/ui/index.ts +4 -0
  185. package/bundles/nextjs-landing/components/ui/input.tsx +23 -0
  186. package/bundles/nextjs-landing/components/ui/spinner.tsx +22 -0
  187. package/bundles/nextjs-landing/docs/LATTICE_RELEASE_WORKFLOW.md +53 -0
  188. package/bundles/nextjs-landing/docs/rules/codex.md +62 -0
  189. package/bundles/nextjs-landing/eslint.config.mjs +16 -0
  190. package/bundles/nextjs-landing/instrumentation-client.ts +30 -0
  191. package/bundles/nextjs-landing/instrumentation.ts +12 -0
  192. package/bundles/nextjs-landing/jest.config.mjs +16 -0
  193. package/bundles/nextjs-landing/jest.setup.js +1 -0
  194. package/bundles/nextjs-landing/lib/utils.ts +6 -0
  195. package/bundles/nextjs-landing/next-env.d.ts +5 -0
  196. package/bundles/nextjs-landing/next.config.ts +15 -0
  197. package/bundles/nextjs-landing/package.json +48 -0
  198. package/bundles/nextjs-landing/postcss.config.mjs +7 -0
  199. package/bundles/nextjs-landing/prompts/01-feature-implementation.md +9 -0
  200. package/bundles/nextjs-landing/prompts/02-bug-fix.md +10 -0
  201. package/bundles/nextjs-landing/prompts/03-safe-refactor.md +8 -0
  202. package/bundles/nextjs-landing/prompts/04-test-first.md +8 -0
  203. package/bundles/nextjs-landing/prompts/05-ui-polish.md +8 -0
  204. package/bundles/nextjs-landing/prompts/06-security-review.md +7 -0
  205. package/bundles/nextjs-landing/prompts/quality.md +269 -0
  206. package/bundles/nextjs-landing/sentry.edge.config.ts +15 -0
  207. package/bundles/nextjs-landing/sentry.server.config.ts +15 -0
  208. package/bundles/nextjs-landing/tsconfig.json +42 -0
  209. package/bundles/nextjs-landing/vendor/m2ai-braces-3.0.3-m2ai.1.tar +0 -0
  210. package/bundles/nextjs-saas/.agents/skills/lattice-feature-handoff/SKILL.md +31 -0
  211. package/bundles/nextjs-saas/.agents/skills/lattice-release-manager/SKILL.md +29 -0
  212. package/bundles/nextjs-saas/.agents/skills/lattice-verify/SKILL.md +27 -0
  213. package/bundles/nextjs-saas/.claude/agents/lattice-feature-agent.md +10 -0
  214. package/bundles/nextjs-saas/.claude/agents/lattice-release-manager.md +9 -0
  215. package/bundles/nextjs-saas/.claude/hooks/README.md +9 -0
  216. package/bundles/nextjs-saas/.claude/hooks/pre-commit-verify.mjs +10 -0
  217. package/bundles/nextjs-saas/.claude/hooks/pre-tool-use.mjs +51 -0
  218. package/bundles/nextjs-saas/.claude/rules/lattice-core.md +20 -0
  219. package/bundles/nextjs-saas/.claude/settings.json +38 -0
  220. package/bundles/nextjs-saas/.claude/skills/lattice-verify/SKILL.md +27 -0
  221. package/bundles/nextjs-saas/.codex/agents/lattice-feature-agent.toml +9 -0
  222. package/bundles/nextjs-saas/.codex/agents/lattice-release-manager.toml +9 -0
  223. package/bundles/nextjs-saas/.cursor/mcp.json +34 -0
  224. package/bundles/nextjs-saas/.cursor/rules/lattice-core.mdc +35 -0
  225. package/bundles/nextjs-saas/.cursor/rules.md +95 -0
  226. package/bundles/nextjs-saas/.env.example +48 -0
  227. package/bundles/nextjs-saas/.github/PULL_REQUEST_TEMPLATE.md +42 -0
  228. package/bundles/nextjs-saas/.github/agents/lattice-feature-agent.agent.md +7 -0
  229. package/bundles/nextjs-saas/.github/agents/lattice-release-manager.agent.md +7 -0
  230. package/bundles/nextjs-saas/.github/copilot-instructions.md +37 -0
  231. package/bundles/nextjs-saas/.github/instructions/lattice-core.instructions.md +11 -0
  232. package/bundles/nextjs-saas/.github/workflows/ci.yml +26 -0
  233. package/bundles/nextjs-saas/.gitmessage +24 -0
  234. package/bundles/nextjs-saas/.lattice/config.json +9 -0
  235. package/bundles/nextjs-saas/.lattice/dependency-security.json +46 -0
  236. package/bundles/nextjs-saas/.lattice/prompts/01-feature.md +36 -0
  237. package/bundles/nextjs-saas/.lattice/prompts/02-bugfix.md +32 -0
  238. package/bundles/nextjs-saas/.lattice/prompts/03-refactor.md +30 -0
  239. package/bundles/nextjs-saas/.lattice/prompts/04-test.md +31 -0
  240. package/bundles/nextjs-saas/.lattice/prompts/05-polish.md +38 -0
  241. package/bundles/nextjs-saas/.lattice/prompts/06-security.md +32 -0
  242. package/bundles/nextjs-saas/.lattice/prompts/quality.md +269 -0
  243. package/bundles/nextjs-saas/.lattice/release-workflow.json +55 -0
  244. package/bundles/nextjs-saas/.lattice/schemas/feature-handoff.schema.json +264 -0
  245. package/bundles/nextjs-saas/.lattice/templates/feature-handoff.json +52 -0
  246. package/bundles/nextjs-saas/.mcp.json +35 -0
  247. package/bundles/nextjs-saas/AGENTS.md +58 -0
  248. package/bundles/nextjs-saas/CLAUDE.md +76 -0
  249. package/bundles/nextjs-saas/PROJECT_GUIDE.md +279 -0
  250. package/bundles/nextjs-saas/README.md +42 -0
  251. package/bundles/nextjs-saas/app/(auth)/forgot-password/page.tsx +101 -0
  252. package/bundles/nextjs-saas/app/(auth)/layout.tsx +7 -0
  253. package/bundles/nextjs-saas/app/(auth)/login/page.tsx +108 -0
  254. package/bundles/nextjs-saas/app/(auth)/reset-password/page.tsx +135 -0
  255. package/bundles/nextjs-saas/app/(auth)/signup/page.tsx +144 -0
  256. package/bundles/nextjs-saas/app/(dashboard)/dashboard/page.tsx +80 -0
  257. package/bundles/nextjs-saas/app/(dashboard)/layout.tsx +49 -0
  258. package/bundles/nextjs-saas/app/api/billing/checkout/route.ts +47 -0
  259. package/bundles/nextjs-saas/app/api/billing/portal/route.ts +29 -0
  260. package/bundles/nextjs-saas/app/api/example/[id]/route.ts +93 -0
  261. package/bundles/nextjs-saas/app/api/example/route.ts +61 -0
  262. package/bundles/nextjs-saas/app/api/health/route.ts +8 -0
  263. package/bundles/nextjs-saas/app/api/stripe/webhook/route.ts +57 -0
  264. package/bundles/nextjs-saas/app/api/user/route.ts +49 -0
  265. package/bundles/nextjs-saas/app/auth/callback/route.ts +16 -0
  266. package/bundles/nextjs-saas/app/auth/signout/route.ts +10 -0
  267. package/bundles/nextjs-saas/app/global-error.tsx +17 -0
  268. package/bundles/nextjs-saas/app/globals.css +55 -0
  269. package/bundles/nextjs-saas/app/layout.tsx +22 -0
  270. package/bundles/nextjs-saas/app/page.tsx +84 -0
  271. package/bundles/nextjs-saas/components/ui/button.tsx +39 -0
  272. package/bundles/nextjs-saas/components/ui/card.tsx +53 -0
  273. package/bundles/nextjs-saas/components/ui/index.ts +4 -0
  274. package/bundles/nextjs-saas/components/ui/input.tsx +23 -0
  275. package/bundles/nextjs-saas/components/ui/spinner.tsx +22 -0
  276. package/bundles/nextjs-saas/docs/LATTICE_RELEASE_WORKFLOW.md +53 -0
  277. package/bundles/nextjs-saas/docs/rules/codex.md +62 -0
  278. package/bundles/nextjs-saas/eslint.config.mjs +16 -0
  279. package/bundles/nextjs-saas/instrumentation-client.ts +30 -0
  280. package/bundles/nextjs-saas/instrumentation.ts +12 -0
  281. package/bundles/nextjs-saas/jest.config.mjs +16 -0
  282. package/bundles/nextjs-saas/jest.setup.js +1 -0
  283. package/bundles/nextjs-saas/lib/auth/password-recovery.ts +94 -0
  284. package/bundles/nextjs-saas/lib/stripe.ts +10 -0
  285. package/bundles/nextjs-saas/lib/supabase/admin.ts +14 -0
  286. package/bundles/nextjs-saas/lib/supabase/client.ts +8 -0
  287. package/bundles/nextjs-saas/lib/supabase/server.ts +27 -0
  288. package/bundles/nextjs-saas/lib/utils.ts +6 -0
  289. package/bundles/nextjs-saas/next-env.d.ts +5 -0
  290. package/bundles/nextjs-saas/next.config.ts +15 -0
  291. package/bundles/nextjs-saas/package.json +50 -0
  292. package/bundles/nextjs-saas/postcss.config.mjs +7 -0
  293. package/bundles/nextjs-saas/prompts/01-feature-implementation.md +92 -0
  294. package/bundles/nextjs-saas/prompts/02-bug-fix.md +78 -0
  295. package/bundles/nextjs-saas/prompts/03-safe-refactor.md +82 -0
  296. package/bundles/nextjs-saas/prompts/04-test-first.md +80 -0
  297. package/bundles/nextjs-saas/prompts/05-ui-polish.md +82 -0
  298. package/bundles/nextjs-saas/prompts/06-security-review.md +74 -0
  299. package/bundles/nextjs-saas/proxy.ts +61 -0
  300. package/bundles/nextjs-saas/sentry.edge.config.ts +15 -0
  301. package/bundles/nextjs-saas/sentry.server.config.ts +15 -0
  302. package/bundles/nextjs-saas/supabase/migrations/001_initial_schema.sql +66 -0
  303. package/bundles/nextjs-saas/supabase/migrations/002_billing.sql +17 -0
  304. package/bundles/nextjs-saas/tsconfig.json +42 -0
  305. package/bundles/nextjs-saas/types/database.types.ts +76 -0
  306. package/bundles/nextjs-saas/vendor/m2ai-braces-3.0.3-m2ai.1.tar +0 -0
  307. package/bundles/nextjs-trpc/.agents/skills/lattice-feature-handoff/SKILL.md +31 -0
  308. package/bundles/nextjs-trpc/.agents/skills/lattice-release-manager/SKILL.md +29 -0
  309. package/bundles/nextjs-trpc/.agents/skills/lattice-verify/SKILL.md +27 -0
  310. package/bundles/nextjs-trpc/.claude/agents/lattice-feature-agent.md +10 -0
  311. package/bundles/nextjs-trpc/.claude/agents/lattice-release-manager.md +9 -0
  312. package/bundles/nextjs-trpc/.claude/hooks/README.md +9 -0
  313. package/bundles/nextjs-trpc/.claude/hooks/pre-commit-verify.mjs +10 -0
  314. package/bundles/nextjs-trpc/.claude/hooks/pre-tool-use.mjs +51 -0
  315. package/bundles/nextjs-trpc/.claude/rules/lattice-core.md +20 -0
  316. package/bundles/nextjs-trpc/.claude/settings.json +38 -0
  317. package/bundles/nextjs-trpc/.claude/skills/lattice-verify/SKILL.md +27 -0
  318. package/bundles/nextjs-trpc/.codex/agents/lattice-feature-agent.toml +9 -0
  319. package/bundles/nextjs-trpc/.codex/agents/lattice-release-manager.toml +9 -0
  320. package/bundles/nextjs-trpc/.cursor/mcp.json +34 -0
  321. package/bundles/nextjs-trpc/.cursor/rules/lattice-core.mdc +35 -0
  322. package/bundles/nextjs-trpc/.cursor/rules.md +95 -0
  323. package/bundles/nextjs-trpc/.env.example +21 -0
  324. package/bundles/nextjs-trpc/.github/PULL_REQUEST_TEMPLATE.md +42 -0
  325. package/bundles/nextjs-trpc/.github/agents/lattice-feature-agent.agent.md +7 -0
  326. package/bundles/nextjs-trpc/.github/agents/lattice-release-manager.agent.md +7 -0
  327. package/bundles/nextjs-trpc/.github/copilot-instructions.md +37 -0
  328. package/bundles/nextjs-trpc/.github/instructions/lattice-core.instructions.md +11 -0
  329. package/bundles/nextjs-trpc/.github/workflows/ci.yml +26 -0
  330. package/bundles/nextjs-trpc/.gitmessage +24 -0
  331. package/bundles/nextjs-trpc/.lattice/config.json +9 -0
  332. package/bundles/nextjs-trpc/.lattice/dependency-security.json +46 -0
  333. package/bundles/nextjs-trpc/.lattice/prompts/01-feature.md +36 -0
  334. package/bundles/nextjs-trpc/.lattice/prompts/02-bugfix.md +32 -0
  335. package/bundles/nextjs-trpc/.lattice/prompts/03-refactor.md +30 -0
  336. package/bundles/nextjs-trpc/.lattice/prompts/04-test.md +31 -0
  337. package/bundles/nextjs-trpc/.lattice/prompts/05-polish.md +38 -0
  338. package/bundles/nextjs-trpc/.lattice/prompts/06-security.md +32 -0
  339. package/bundles/nextjs-trpc/.lattice/release-workflow.json +55 -0
  340. package/bundles/nextjs-trpc/.lattice/schemas/feature-handoff.schema.json +264 -0
  341. package/bundles/nextjs-trpc/.lattice/templates/feature-handoff.json +52 -0
  342. package/bundles/nextjs-trpc/.mcp.json +35 -0
  343. package/bundles/nextjs-trpc/AGENTS.md +58 -0
  344. package/bundles/nextjs-trpc/CLAUDE.md +76 -0
  345. package/bundles/nextjs-trpc/PROJECT_GUIDE.md +187 -0
  346. package/bundles/nextjs-trpc/README.md +49 -0
  347. package/bundles/nextjs-trpc/app/api/trpc/[trpc]/route.ts +12 -0
  348. package/bundles/nextjs-trpc/app/global-error.tsx +17 -0
  349. package/bundles/nextjs-trpc/app/globals.css +55 -0
  350. package/bundles/nextjs-trpc/app/layout.tsx +19 -0
  351. package/bundles/nextjs-trpc/app/page.tsx +16 -0
  352. package/bundles/nextjs-trpc/app/providers.tsx +24 -0
  353. package/bundles/nextjs-trpc/components/ui/button.tsx +39 -0
  354. package/bundles/nextjs-trpc/components/ui/card.tsx +53 -0
  355. package/bundles/nextjs-trpc/components/ui/index.ts +4 -0
  356. package/bundles/nextjs-trpc/components/ui/input.tsx +23 -0
  357. package/bundles/nextjs-trpc/components/ui/spinner.tsx +22 -0
  358. package/bundles/nextjs-trpc/components/user-list.tsx +17 -0
  359. package/bundles/nextjs-trpc/docs/LATTICE_RELEASE_WORKFLOW.md +53 -0
  360. package/bundles/nextjs-trpc/docs/rules/codex.md +62 -0
  361. package/bundles/nextjs-trpc/eslint.config.mjs +16 -0
  362. package/bundles/nextjs-trpc/instrumentation-client.ts +20 -0
  363. package/bundles/nextjs-trpc/instrumentation.ts +12 -0
  364. package/bundles/nextjs-trpc/jest.config.mjs +16 -0
  365. package/bundles/nextjs-trpc/jest.setup.js +1 -0
  366. package/bundles/nextjs-trpc/lib/db.ts +17 -0
  367. package/bundles/nextjs-trpc/lib/trpc/react.tsx +7 -0
  368. package/bundles/nextjs-trpc/lib/utils.ts +6 -0
  369. package/bundles/nextjs-trpc/next-env.d.ts +5 -0
  370. package/bundles/nextjs-trpc/next.config.ts +15 -0
  371. package/bundles/nextjs-trpc/package.json +62 -0
  372. package/bundles/nextjs-trpc/postcss.config.mjs +7 -0
  373. package/bundles/nextjs-trpc/prisma/schema.prisma +41 -0
  374. package/bundles/nextjs-trpc/prisma.config.ts +10 -0
  375. package/bundles/nextjs-trpc/prompts/01-feature-implementation.md +9 -0
  376. package/bundles/nextjs-trpc/prompts/02-bug-fix.md +9 -0
  377. package/bundles/nextjs-trpc/prompts/03-safe-refactor.md +8 -0
  378. package/bundles/nextjs-trpc/prompts/04-test-first.md +8 -0
  379. package/bundles/nextjs-trpc/prompts/05-ui-polish.md +7 -0
  380. package/bundles/nextjs-trpc/prompts/06-security-review.md +7 -0
  381. package/bundles/nextjs-trpc/prompts/quality.md +269 -0
  382. package/bundles/nextjs-trpc/sentry.edge.config.ts +15 -0
  383. package/bundles/nextjs-trpc/sentry.server.config.ts +15 -0
  384. package/bundles/nextjs-trpc/server/routers/_app.test.ts +60 -0
  385. package/bundles/nextjs-trpc/server/routers/_app.ts +25 -0
  386. package/bundles/nextjs-trpc/server/trpc.ts +12 -0
  387. package/bundles/nextjs-trpc/tsconfig.json +42 -0
  388. package/bundles/nextjs-trpc/vendor/m2ai-braces-3.0.3-m2ai.1.tar +0 -0
  389. package/dist/agent-install-session.d.ts +17 -0
  390. package/dist/agent-install-session.d.ts.map +1 -0
  391. package/dist/agent-install-session.js +106 -0
  392. package/dist/agent-install-session.js.map +1 -0
  393. package/dist/agent-install-session.test.d.ts +2 -0
  394. package/dist/agent-install-session.test.d.ts.map +1 -0
  395. package/dist/agent-install-session.test.js +62 -0
  396. package/dist/agent-install-session.test.js.map +1 -0
  397. package/dist/agent-install.d.ts +41 -0
  398. package/dist/agent-install.d.ts.map +1 -0
  399. package/dist/agent-install.js +42 -0
  400. package/dist/agent-install.js.map +1 -0
  401. package/dist/agent-install.test.d.ts +2 -0
  402. package/dist/agent-install.test.d.ts.map +1 -0
  403. package/dist/agent-install.test.js +58 -0
  404. package/dist/agent-install.test.js.map +1 -0
  405. package/dist/apply-merge.test.d.ts +2 -0
  406. package/dist/apply-merge.test.d.ts.map +1 -0
  407. package/dist/apply-merge.test.js +123 -0
  408. package/dist/apply-merge.test.js.map +1 -0
  409. package/dist/bundle-download.d.ts +23 -0
  410. package/dist/bundle-download.d.ts.map +1 -0
  411. package/dist/bundle-download.js +180 -0
  412. package/dist/bundle-download.js.map +1 -0
  413. package/dist/bundle-download.test.d.ts +2 -0
  414. package/dist/bundle-download.test.d.ts.map +1 -0
  415. package/dist/bundle-download.test.js +200 -0
  416. package/dist/bundle-download.test.js.map +1 -0
  417. package/dist/bundle-rollback.test.d.ts +2 -0
  418. package/dist/bundle-rollback.test.d.ts.map +1 -0
  419. package/dist/bundle-rollback.test.js +127 -0
  420. package/dist/bundle-rollback.test.js.map +1 -0
  421. package/dist/bundle-scaffold.test.d.ts +2 -0
  422. package/dist/bundle-scaffold.test.d.ts.map +1 -0
  423. package/dist/bundle-scaffold.test.js +105 -0
  424. package/dist/bundle-scaffold.test.js.map +1 -0
  425. package/dist/commands.d.ts +132 -0
  426. package/dist/commands.d.ts.map +1 -0
  427. package/dist/commands.js +2012 -0
  428. package/dist/commands.js.map +1 -0
  429. package/dist/credential-store.d.ts +27 -0
  430. package/dist/credential-store.d.ts.map +1 -0
  431. package/dist/credential-store.js +48 -0
  432. package/dist/credential-store.js.map +1 -0
  433. package/dist/credential-store.test.d.ts +2 -0
  434. package/dist/credential-store.test.d.ts.map +1 -0
  435. package/dist/credential-store.test.js +80 -0
  436. package/dist/credential-store.test.js.map +1 -0
  437. package/dist/delivered-project-files.d.ts +31 -0
  438. package/dist/delivered-project-files.d.ts.map +1 -0
  439. package/dist/delivered-project-files.js +158 -0
  440. package/dist/delivered-project-files.js.map +1 -0
  441. package/dist/delivered-project-files.test.d.ts +2 -0
  442. package/dist/delivered-project-files.test.d.ts.map +1 -0
  443. package/dist/delivered-project-files.test.js +107 -0
  444. package/dist/delivered-project-files.test.js.map +1 -0
  445. package/dist/doctor-agents.test.d.ts +2 -0
  446. package/dist/doctor-agents.test.d.ts.map +1 -0
  447. package/dist/doctor-agents.test.js +65 -0
  448. package/dist/doctor-agents.test.js.map +1 -0
  449. package/dist/hermes-install.d.ts +102 -0
  450. package/dist/hermes-install.d.ts.map +1 -0
  451. package/dist/hermes-install.js +641 -0
  452. package/dist/hermes-install.js.map +1 -0
  453. package/dist/hermes-install.test.d.ts +2 -0
  454. package/dist/hermes-install.test.d.ts.map +1 -0
  455. package/dist/hermes-install.test.js +866 -0
  456. package/dist/hermes-install.test.js.map +1 -0
  457. package/dist/index.d.ts +115 -0
  458. package/dist/index.d.ts.map +1 -0
  459. package/dist/index.js +5311 -0
  460. package/dist/index.js.map +1 -0
  461. package/dist/openclaw-install.d.ts +67 -0
  462. package/dist/openclaw-install.d.ts.map +1 -0
  463. package/dist/openclaw-install.js +358 -0
  464. package/dist/openclaw-install.js.map +1 -0
  465. package/dist/openclaw-install.test.d.ts +2 -0
  466. package/dist/openclaw-install.test.d.ts.map +1 -0
  467. package/dist/openclaw-install.test.js +296 -0
  468. package/dist/openclaw-install.test.js.map +1 -0
  469. package/dist/password-recovery-bundle.test.d.ts +2 -0
  470. package/dist/password-recovery-bundle.test.d.ts.map +1 -0
  471. package/dist/password-recovery-bundle.test.js +132 -0
  472. package/dist/password-recovery-bundle.test.js.map +1 -0
  473. package/dist/project-bundle-env.d.ts +19 -0
  474. package/dist/project-bundle-env.d.ts.map +1 -0
  475. package/dist/project-bundle-env.js +111 -0
  476. package/dist/project-bundle-env.js.map +1 -0
  477. package/dist/project-bundle-env.test.d.ts +2 -0
  478. package/dist/project-bundle-env.test.d.ts.map +1 -0
  479. package/dist/project-bundle-env.test.js +93 -0
  480. package/dist/project-bundle-env.test.js.map +1 -0
  481. package/dist/project-path-confinement.test.d.ts +2 -0
  482. package/dist/project-path-confinement.test.d.ts.map +1 -0
  483. package/dist/project-path-confinement.test.js +222 -0
  484. package/dist/project-path-confinement.test.js.map +1 -0
  485. package/dist/security/api.d.ts +18 -0
  486. package/dist/security/api.d.ts.map +1 -0
  487. package/dist/security/api.js +238 -0
  488. package/dist/security/api.js.map +1 -0
  489. package/dist/security/api.test.d.ts +2 -0
  490. package/dist/security/api.test.d.ts.map +1 -0
  491. package/dist/security/api.test.js +220 -0
  492. package/dist/security/api.test.js.map +1 -0
  493. package/dist/security/artifact.d.ts +10 -0
  494. package/dist/security/artifact.d.ts.map +1 -0
  495. package/dist/security/artifact.js +283 -0
  496. package/dist/security/artifact.js.map +1 -0
  497. package/dist/security/artifact.test.d.ts +2 -0
  498. package/dist/security/artifact.test.d.ts.map +1 -0
  499. package/dist/security/artifact.test.js +229 -0
  500. package/dist/security/artifact.test.js.map +1 -0
  501. package/dist/security/commands.d.ts +42 -0
  502. package/dist/security/commands.d.ts.map +1 -0
  503. package/dist/security/commands.js +825 -0
  504. package/dist/security/commands.js.map +1 -0
  505. package/dist/security/commands.test.d.ts +2 -0
  506. package/dist/security/commands.test.d.ts.map +1 -0
  507. package/dist/security/commands.test.js +1051 -0
  508. package/dist/security/commands.test.js.map +1 -0
  509. package/dist/security/connection.d.ts +19 -0
  510. package/dist/security/connection.d.ts.map +1 -0
  511. package/dist/security/connection.js +145 -0
  512. package/dist/security/connection.js.map +1 -0
  513. package/dist/security/connection.test.d.ts +2 -0
  514. package/dist/security/connection.test.d.ts.map +1 -0
  515. package/dist/security/connection.test.js +62 -0
  516. package/dist/security/connection.test.js.map +1 -0
  517. package/dist/security/index-routing.test.d.ts +2 -0
  518. package/dist/security/index-routing.test.d.ts.map +1 -0
  519. package/dist/security/index-routing.test.js +169 -0
  520. package/dist/security/index-routing.test.js.map +1 -0
  521. package/dist/security/journal.d.ts +26 -0
  522. package/dist/security/journal.d.ts.map +1 -0
  523. package/dist/security/journal.js +441 -0
  524. package/dist/security/journal.js.map +1 -0
  525. package/dist/security/journal.test.d.ts +2 -0
  526. package/dist/security/journal.test.d.ts.map +1 -0
  527. package/dist/security/journal.test.js +226 -0
  528. package/dist/security/journal.test.js.map +1 -0
  529. package/dist/security/package-verifier.d.ts +15 -0
  530. package/dist/security/package-verifier.d.ts.map +1 -0
  531. package/dist/security/package-verifier.js +65 -0
  532. package/dist/security/package-verifier.js.map +1 -0
  533. package/dist/security/package-verifier.test.d.ts +2 -0
  534. package/dist/security/package-verifier.test.d.ts.map +1 -0
  535. package/dist/security/package-verifier.test.js +57 -0
  536. package/dist/security/package-verifier.test.js.map +1 -0
  537. package/dist/security/runtime.d.ts +43 -0
  538. package/dist/security/runtime.d.ts.map +1 -0
  539. package/dist/security/runtime.js +81 -0
  540. package/dist/security/runtime.js.map +1 -0
  541. package/dist/security/runtime.test.d.ts +2 -0
  542. package/dist/security/runtime.test.d.ts.map +1 -0
  543. package/dist/security/runtime.test.js +88 -0
  544. package/dist/security/runtime.test.js.map +1 -0
  545. package/dist/security/types.d.ts +169 -0
  546. package/dist/security/types.d.ts.map +1 -0
  547. package/dist/security/types.js +3 -0
  548. package/dist/security/types.js.map +1 -0
  549. package/dist/security-runtime/LICENSE +202 -0
  550. package/dist/security-runtime/NOTICE +16 -0
  551. package/dist/security-runtime/artifact-manifest.json +960 -0
  552. package/dist/security-runtime/bin/vsg.mjs +5 -0
  553. package/dist/security-runtime/lattice-catalog.json +176585 -0
  554. package/dist/security-runtime/lattice-runtime.mjs +90 -0
  555. package/dist/security-runtime/licensing/candidates/apache-source-license-evidence.json +478 -0
  556. package/dist/security-runtime/licensing/candidates/betterleaks-generic-api-key.json +76 -0
  557. package/dist/security-runtime/licensing/candidates/betterleaks-jwt.json +74 -0
  558. package/dist/security-runtime/licensing/candidates/blackberry-additional-source-declaration-evidence.json +276 -0
  559. package/dist/security-runtime/licensing/candidates/blackberry-source-declaration-evidence.json +369 -0
  560. package/dist/security-runtime/licensing/candidates/cado-source-declaration-evidence.json +283 -0
  561. package/dist/security-runtime/licensing/candidates/commercial-rule-candidate.json +280 -0
  562. package/dist/security-runtime/licensing/candidates/commercial-runtime-release.json +389 -0
  563. package/dist/security-runtime/licensing/candidates/data-feed-evidence.json +259 -0
  564. package/dist/security-runtime/licensing/candidates/gitlab-sast-rule-identities.json +178 -0
  565. package/dist/security-runtime/licensing/candidates/gitlab-sast-source-evidence.json +1824 -0
  566. package/dist/security-runtime/licensing/candidates/gitlab-sast-source-notice-bundle.json +45 -0
  567. package/dist/security-runtime/licensing/candidates/malpedia-source-license-evidence.json +41 -0
  568. package/dist/security-runtime/licensing/candidates/rule-license-evidence.json +376 -0
  569. package/dist/security-runtime/licensing/candidates/runner-image-composition.json +1500 -0
  570. package/dist/security-runtime/licensing/candidates/selected-runtime-coverage.json +91 -0
  571. package/dist/security-runtime/licensing/candidates/yara-forge-20260927.json +58502 -0
  572. package/dist/security-runtime/licensing/commercial-components.json +379 -0
  573. package/dist/security-runtime/licensing/notices/betterleaks-1.9.0-MIT.txt +21 -0
  574. package/dist/security-runtime/licensing/notices/candidate-sources/sha256/28a9529c7d0bb4dc51f4bf5c116a3d16ef247a052f7591466768ddf563fd1cf5.txt +428 -0
  575. package/dist/security-runtime/licensing/notices/candidate-sources/sha256/33acf42afdd03163d75fe856cb431e70710e0b5deede3362e6d1c4697cfe1c6a.txt +28 -0
  576. package/dist/security-runtime/licensing/notices/candidate-sources/sha256/3972dc9744f6499f0f9b2dbf76696f2ae7ad8af9b23dde66d6af86c9dfb36986.txt +674 -0
  577. package/dist/security-runtime/licensing/notices/candidate-sources/sha256/4fecb8fcaf80fd9a6315bca5225ee43377015b46a0459c2925495be885cab19a.txt +21 -0
  578. package/dist/security-runtime/licensing/notices/candidate-sources/sha256/811515f8723aa4007de2fbb75a364127fdec51cda534b87a7ea8f2fef2f96dd7.txt +24 -0
  579. package/dist/security-runtime/licensing/notices/candidate-sources/sha256/814442c3987a2c0411171ad8ad43118e8c08f85c9c5d1dcdecc9787c7ca8689b.txt +664 -0
  580. package/dist/security-runtime/licensing/notices/candidate-sources/sha256/8a959b2413d0c83ca1b3ce9153076c649abf2e4bbfebbb493fb24c2074a1eb8a.txt +38 -0
  581. package/dist/security-runtime/licensing/notices/candidate-sources/sha256/995182e185856186fbbe49f150409ae026aa4cda7e94f83c6ed737cbb77fa9c7.txt +23 -0
  582. package/dist/security-runtime/licensing/notices/candidate-sources/sha256/9b8e1305e46d1dd4011b6ed933c9f6223e08c9c4625001c5fd75a34fa930f616.txt +202 -0
  583. package/dist/security-runtime/licensing/notices/candidate-sources/sha256/a01f1a28424bfe7f49a23d339a01847cfa9ace3864d5e7295051772a4bae2271.txt +38 -0
  584. package/dist/security-runtime/licensing/notices/candidate-sources/sha256/a5681bf9b05db14d86776930017c647ad9e6e56ff6bbcfdf21e5848288dfaf1b.txt +165 -0
  585. package/dist/security-runtime/licensing/notices/candidate-sources/sha256/a5b8bd9ae96c630bbf229d61c5c5def20274e00be39abfd2fab4d7879ceab462.txt +24 -0
  586. package/dist/security-runtime/licensing/notices/candidate-sources/sha256/ada32b3747ce108d5e8bab7918af94abbd03f2fe2a46304f74c6333bbfd914ed.txt +8 -0
  587. package/dist/security-runtime/licensing/notices/candidate-sources/sha256/c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4.txt +201 -0
  588. package/dist/security-runtime/licensing/notices/candidate-sources/sha256/c738ae413cf561f174e34f6961f8ca458aae2369a73640dda6234c629b98bcc4.txt +2732 -0
  589. package/dist/security-runtime/licensing/notices/candidate-sources/sha256/ce41c9a2c986277f7f9ab146a2195c1888a5d8da062e22d7c9c88666bb7c38cd.txt +17 -0
  590. package/dist/security-runtime/licensing/notices/candidate-sources/sha256/d5f4c36a0528e01cfdd9e4fc60879201d3af49b41c520200643d321fe53da5f9.txt +17 -0
  591. package/dist/security-runtime/licensing/notices/candidate-sources/sha256/e08c368ccd455f85c7fb9e04830e730f26e9dbb5c0f77bc88e09a5b0cb37df5b.txt +38 -0
  592. package/dist/security-runtime/licensing/notices/candidate-sources/sha256/e9efb2f7daf11bb6379c06c16b870dddcecc4a10f8704bb8aad807529c8b3c97.txt +8 -0
  593. package/dist/security-runtime/licensing/notices/gitleaks-generic-origin-782f3104-MIT.txt +21 -0
  594. package/dist/security-runtime/package.json +17 -0
  595. package/dist/security-runtime/playbook/README.md +76 -0
  596. package/dist/security-runtime/playbook/access-control.md +56 -0
  597. package/dist/security-runtime/playbook/ai-features.md +53 -0
  598. package/dist/security-runtime/playbook/desktop-python.md +59 -0
  599. package/dist/security-runtime/playbook/input-handling.md +59 -0
  600. package/dist/security-runtime/playbook/mobile-expo.md +59 -0
  601. package/dist/security-runtime/playbook/payments.md +53 -0
  602. package/dist/security-runtime/playbook/privacy-account-recovery.md +59 -0
  603. package/dist/security-runtime/playbook/secrets-config.md +47 -0
  604. package/dist/security-runtime/playbook/supabase.md +48 -0
  605. package/dist/security-runtime/playbook/supply-chain.md +62 -0
  606. package/dist/security-runtime/playbook/webhooks-integrations.md +52 -0
  607. package/dist/security-runtime/rules/vsg-ai-key-in-client.yaml +41 -0
  608. package/dist/security-runtime/rules/vsg-ai-output-raw-html.yaml +35 -0
  609. package/dist/security-runtime/rules/vsg-angular-sanitizer-bypass.yaml +23 -0
  610. package/dist/security-runtime/rules/vsg-expo-token-in-asyncstorage.yaml +22 -0
  611. package/dist/security-runtime/rules/vsg-flask-public-bind.yaml +32 -0
  612. package/dist/security-runtime/rules/vsg-nextjs-action-write-no-auth.yaml +144 -0
  613. package/dist/security-runtime/rules/vsg-nextjs-inline-action-write-no-auth.yaml +161 -0
  614. package/dist/security-runtime/rules/vsg-nextjs-route-write-no-auth.yaml +193 -0
  615. package/dist/security-runtime/rules/vsg-nosql-where-injection.yaml +36 -0
  616. package/dist/security-runtime/rules/vsg-python-pickle-load.yaml +26 -0
  617. package/dist/security-runtime/rules/vsg-python-requests-verify-false.yaml +34 -0
  618. package/dist/security-runtime/rules/vsg-python-subprocess-shell.yaml +23 -0
  619. package/dist/security-runtime/rules/vsg-stripe-client-price.yaml +51 -0
  620. package/dist/security-runtime/rules/vsg-stripe-webhook-no-signature.yaml +31 -0
  621. package/dist/security-runtime/rules/vsg-stripe-webhook-pages-no-signature.yaml +51 -0
  622. package/dist/security-runtime/rules/vsg-supabase-service-role-in-client.yaml +27 -0
  623. package/dist/security-runtime/rules/vsg-supabase-service-role-public-env.yaml +24 -0
  624. package/dist/security-runtime/rules/vsg-xml-external-entities.yaml +19 -0
  625. package/dist/security-runtime/src/agent/brief.mjs +95 -0
  626. package/dist/security-runtime/src/agent/discover.mjs +108 -0
  627. package/dist/security-runtime/src/agent/exec.mjs +64 -0
  628. package/dist/security-runtime/src/agent/ingest.mjs +213 -0
  629. package/dist/security-runtime/src/agent/report.mjs +94 -0
  630. package/dist/security-runtime/src/agent/schema.mjs +62 -0
  631. package/dist/security-runtime/src/agent/tokenize.mjs +38 -0
  632. package/dist/security-runtime/src/checks/README.md +8 -0
  633. package/dist/security-runtime/src/checks/_lib/gitfiles.mjs +35 -0
  634. package/dist/security-runtime/src/checks/_lib/lockfiles.mjs +135 -0
  635. package/dist/security-runtime/src/checks/_lib/osv.mjs +6 -0
  636. package/dist/security-runtime/src/checks/_lib/secrets.mjs +381 -0
  637. package/dist/security-runtime/src/checks/_lib/targets.mjs +79 -0
  638. package/dist/security-runtime/src/checks/agent-review/index.mjs +52 -0
  639. package/dist/security-runtime/src/checks/agent-surface/config.mjs +223 -0
  640. package/dist/security-runtime/src/checks/agent-surface/index.mjs +113 -0
  641. package/dist/security-runtime/src/checks/agent-surface/instructions.mjs +87 -0
  642. package/dist/security-runtime/src/checks/agent-surface/patterns.mjs +68 -0
  643. package/dist/security-runtime/src/checks/agent-surface/unicode.mjs +88 -0
  644. package/dist/security-runtime/src/checks/code/auth-helpers.mjs +659 -0
  645. package/dist/security-runtime/src/checks/code/index.mjs +617 -0
  646. package/dist/security-runtime/src/checks/code/opengrep-container.mjs +85 -0
  647. package/dist/security-runtime/src/checks/code/opengrep-runner.mjs +86 -0
  648. package/dist/security-runtime/src/checks/code/selected-opengrep-runner.mjs +112 -0
  649. package/dist/security-runtime/src/checks/dep-change/guarddog.mjs +142 -0
  650. package/dist/security-runtime/src/checks/dep-change/index.mjs +316 -0
  651. package/dist/security-runtime/src/checks/dep-change/registries.mjs +199 -0
  652. package/dist/security-runtime/src/checks/deps-vuln/index.mjs +305 -0
  653. package/dist/security-runtime/src/checks/desktop-config/index.mjs +112 -0
  654. package/dist/security-runtime/src/checks/dns-mail/index.mjs +71 -0
  655. package/dist/security-runtime/src/checks/iac/index.mjs +83 -0
  656. package/dist/security-runtime/src/checks/install-posture/index.mjs +123 -0
  657. package/dist/security-runtime/src/checks/licenses/index.mjs +143 -0
  658. package/dist/security-runtime/src/checks/live-basic/index.mjs +77 -0
  659. package/dist/security-runtime/src/checks/live-js-secrets/index.mjs +100 -0
  660. package/dist/security-runtime/src/checks/malware/clamav.mjs +17 -0
  661. package/dist/security-runtime/src/checks/malware/defender.mjs +43 -0
  662. package/dist/security-runtime/src/checks/malware/index.mjs +186 -0
  663. package/dist/security-runtime/src/checks/malware/targets.mjs +147 -0
  664. package/dist/security-runtime/src/checks/malware/yara-runner.mjs +201 -0
  665. package/dist/security-runtime/src/checks/malware/yara.mjs +124 -0
  666. package/dist/security-runtime/src/checks/mobile-config/index.mjs +173 -0
  667. package/dist/security-runtime/src/checks/mobile-config/mobsf.mjs +105 -0
  668. package/dist/security-runtime/src/checks/posture/index.mjs +133 -0
  669. package/dist/security-runtime/src/checks/project-scripts/index.mjs +187 -0
  670. package/dist/security-runtime/src/checks/sbom/index.mjs +98 -0
  671. package/dist/security-runtime/src/checks/secrets-build/index.mjs +63 -0
  672. package/dist/security-runtime/src/checks/secrets-history/index.mjs +112 -0
  673. package/dist/security-runtime/src/checks/secrets-tree/env.mjs +120 -0
  674. package/dist/security-runtime/src/checks/secrets-tree/index.mjs +73 -0
  675. package/dist/security-runtime/src/checks/supabase-static/index.mjs +240 -0
  676. package/dist/security-runtime/src/checks/supabase-static/sql.mjs +557 -0
  677. package/dist/security-runtime/src/checks/workflows/index.mjs +93 -0
  678. package/dist/security-runtime/src/cli/deep.mjs +13 -0
  679. package/dist/security-runtime/src/cli/doctor.mjs +82 -0
  680. package/dist/security-runtime/src/cli/index.mjs +60 -0
  681. package/dist/security-runtime/src/cli/live-common.mjs +27 -0
  682. package/dist/security-runtime/src/cli/parse.mjs +56 -0
  683. package/dist/security-runtime/src/cli/portfolio.mjs +34 -0
  684. package/dist/security-runtime/src/cli/release.mjs +28 -0
  685. package/dist/security-runtime/src/cli/report.mjs +18 -0
  686. package/dist/security-runtime/src/cli/run-common.mjs +54 -0
  687. package/dist/security-runtime/src/cli/scan.mjs +12 -0
  688. package/dist/security-runtime/src/cli/setup.mjs +59 -0
  689. package/dist/security-runtime/src/cli/url.mjs +38 -0
  690. package/dist/security-runtime/src/core/accept.mjs +141 -0
  691. package/dist/security-runtime/src/core/archive.mjs +114 -0
  692. package/dist/security-runtime/src/core/base-ref.mjs +43 -0
  693. package/dist/security-runtime/src/core/checks.mjs +39 -0
  694. package/dist/security-runtime/src/core/detect.mjs +90 -0
  695. package/dist/security-runtime/src/core/errors.mjs +5 -0
  696. package/dist/security-runtime/src/core/fetch.mjs +139 -0
  697. package/dist/security-runtime/src/core/findings.mjs +177 -0
  698. package/dist/security-runtime/src/core/gate.mjs +131 -0
  699. package/dist/security-runtime/src/core/installer.mjs +255 -0
  700. package/dist/security-runtime/src/core/lock.mjs +38 -0
  701. package/dist/security-runtime/src/core/nested.mjs +107 -0
  702. package/dist/security-runtime/src/core/paths.mjs +20 -0
  703. package/dist/security-runtime/src/core/pipeline.mjs +196 -0
  704. package/dist/security-runtime/src/core/registry.mjs +81 -0
  705. package/dist/security-runtime/src/core/report.mjs +128 -0
  706. package/dist/security-runtime/src/core/runner.mjs +86 -0
  707. package/dist/security-runtime/src/core/sarif.mjs +141 -0
  708. package/dist/security-runtime/src/lattice/artifact.mjs +1201 -0
  709. package/dist/security-runtime/src/lattice/execution.mjs +45 -0
  710. package/dist/security-runtime/src/lattice/export.mjs +215 -0
  711. package/dist/security-runtime/src/lattice/provenance.mjs +70 -0
  712. package/dist/security-runtime/src/lattice/runtime.mjs +158 -0
  713. package/dist/security-runtime/src/lattice/selected-runtime.mjs +189 -0
  714. package/dist/security-runtime/src/lattice/source-acquirer.mjs +51 -0
  715. package/dist/security-runtime/src/lattice/source-fetcher.mjs +88 -0
  716. package/dist/security-runtime/src/lattice/transport.mjs +232 -0
  717. package/dist/security-runtime/src/live/analyze.mjs +101 -0
  718. package/dist/security-runtime/src/live/exposure.mjs +79 -0
  719. package/dist/security-runtime/src/live/secrets.mjs +31 -0
  720. package/dist/security-runtime/src/live/session.mjs +98 -0
  721. package/dist/security-runtime/src/live/targets.mjs +81 -0
  722. package/dist/security-runtime/src/portfolio/index.mjs +116 -0
  723. package/dist/security-runtime/tools/registry/betterleaks.json +29 -0
  724. package/dist/security-runtime/tools/registry/guarddog.json +9 -0
  725. package/dist/security-runtime/tools/registry/mobsf.json +10 -0
  726. package/dist/security-runtime/tools/registry/opengrep.json +28 -0
  727. package/dist/security-runtime/tools/registry/osv-scanner.json +14 -0
  728. package/dist/security-runtime/tools/registry/semgrep-rules.json +21 -0
  729. package/dist/security-runtime/tools/registry/trivy.json +30 -0
  730. package/dist/security-runtime/tools/registry/yara-forge-exclusions.json +14 -0
  731. package/dist/security-runtime/tools/registry/yara-forge.json +22 -0
  732. package/dist/security-runtime/tools/registry/yara-runner.json +10 -0
  733. package/dist/security-runtime/tools/registry/yara-x.json +24 -0
  734. package/dist/security-runtime/tools/registry/zizmor.json +30 -0
  735. package/dist/spinner.d.ts +16 -0
  736. package/dist/spinner.d.ts.map +1 -0
  737. package/dist/spinner.js +72 -0
  738. package/dist/spinner.js.map +1 -0
  739. package/dist/verify.test.d.ts +2 -0
  740. package/dist/verify.test.d.ts.map +1 -0
  741. package/dist/verify.test.js +98 -0
  742. package/dist/verify.test.js.map +1 -0
  743. package/package.json +73 -4
@@ -0,0 +1,557 @@
1
+ // Minimal PostgreSQL migration reader for supabase-static (REQ-014). It tokenizes SQL (comments, quoted identifiers,
2
+ // strings, dollar-quoted bodies), splits statements, and replays the security-relevant ones in filename order to build the
3
+ // final schema state. It never executes SQL and never looks inside dollar-quoted bodies except to flag DO blocks and
4
+ // functions that enable RLS.
5
+
6
+ // ---- tokenizer ----
7
+ // Token kinds: w = unquoted word (lowercased), q = "quoted identifier", s = 'string', d = $tag$ body $tag$, n = number, p = punctuation.
8
+ const WORD = /[A-Za-z_\u0080-￿][\w$\u0080-￿]*/y;
9
+ const DOLLAR = /\$([A-Za-z_\u0080-￿][\w\u0080-￿]*)?\$/y;
10
+ const NUMBER = /\d[\d.]*(?:[eE][+-]?\d+)?/y;
11
+ const PARAM = /\$\d+/y;
12
+
13
+ export function tokenize(sql) {
14
+ const toks = [];
15
+ const n = sql.length;
16
+ let i = 0;
17
+ let line = 1;
18
+ const quoted = (q, escapes) => {
19
+ let out = '';
20
+ i++; // opening quote
21
+ while (i < n) {
22
+ const c = sql[i];
23
+ if (c === '\n') line++;
24
+ if (escapes && c === '\\' && i + 1 < n) { out += sql[i + 1]; if (sql[i + 1] === '\n') line++; i += 2; continue; }
25
+ if (c === q) { if (sql[i + 1] === q) { out += q; i += 2; continue; } i++; return out; }
26
+ out += c; i++;
27
+ }
28
+ return out; // unterminated: take the rest of the file
29
+ };
30
+ while (i < n) {
31
+ const c = sql[i];
32
+ if (c === '\n') { line++; i++; continue; }
33
+ if (c === ' ' || c === '\t' || c === '\r' || c === '\f' || c === '\v') { i++; continue; }
34
+ if (c === '-' && sql[i + 1] === '-') { while (i < n && sql[i] !== '\n') i++; continue; }
35
+ if (c === '/' && sql[i + 1] === '*') {
36
+ let depth = 1;
37
+ i += 2;
38
+ while (i < n && depth > 0) {
39
+ if (sql[i] === '/' && sql[i + 1] === '*') { depth++; i += 2; } else if (sql[i] === '*' && sql[i + 1] === '/') { depth--; i += 2; } else { if (sql[i] === '\n') line++; i++; }
40
+ }
41
+ continue;
42
+ }
43
+ const start = i;
44
+ const l = line;
45
+ const push = (k, v) => toks.push({ k, v, line: l, pos: start, end: i });
46
+ if (c === "'") { push('s', quoted("'", false)); continue; }
47
+ if ((c === 'e' || c === 'E') && sql[i + 1] === "'") { i++; push('s', quoted("'", true)); continue; }
48
+ if (c === '"') { push('q', quoted('"', false)); continue; }
49
+ if (c === '$') {
50
+ DOLLAR.lastIndex = i;
51
+ const m = DOLLAR.exec(sql);
52
+ if (m) {
53
+ const tag = m[0];
54
+ const bodyStart = i + tag.length;
55
+ const close = sql.indexOf(tag, bodyStart);
56
+ const body = close === -1 ? sql.slice(bodyStart) : sql.slice(bodyStart, close);
57
+ for (const ch of body) if (ch === '\n') line++;
58
+ i = close === -1 ? n : close + tag.length;
59
+ push('d', body);
60
+ continue;
61
+ }
62
+ PARAM.lastIndex = i;
63
+ const pm = PARAM.exec(sql);
64
+ i += pm ? pm[0].length : 1;
65
+ push('n', sql.slice(start, i));
66
+ continue;
67
+ }
68
+ WORD.lastIndex = i;
69
+ const w = WORD.exec(sql);
70
+ if (w) { i += w[0].length; push('w', w[0].toLowerCase()); continue; }
71
+ NUMBER.lastIndex = i;
72
+ const num = NUMBER.exec(sql);
73
+ if (num) { i += num[0].length; push('n', num[0]); continue; }
74
+ i++;
75
+ push('p', c);
76
+ }
77
+ return toks;
78
+ }
79
+
80
+ /** Splits tokens at top-level semicolons. Each statement: { toks, line, start, end }. */
81
+ export function splitStatements(toks) {
82
+ const out = [];
83
+ let cur = [];
84
+ const flush = () => { if (cur.length) out.push({ toks: cur, line: cur[0].line, start: cur[0].pos, end: cur.at(-1).end }); cur = []; };
85
+ for (const t of toks) { if (t.k === 'p' && t.v === ';') flush(); else cur.push(t); }
86
+ flush();
87
+ return out;
88
+ }
89
+
90
+ // ---- token helpers ----
91
+ const W = (t, v) => t?.k === 'w' && t.v === v;
92
+ const P = (t, v) => t?.k === 'p' && t.v === v;
93
+ const isName = (t) => t?.k === 'w' || t?.k === 'q';
94
+ const seq = (toks, i, ...ws) => ws.every((w, j) => W(toks[i + j], w));
95
+ const keyOf = (schema, name) => `${schema}.${name}`;
96
+
97
+ /** Qualified name at i: { schema, name, next }. Unqualified names are in schema public. Normalized: unquoted lowercased, quoted verbatim. */
98
+ function qname(toks, i) {
99
+ const parts = [];
100
+ let j = i;
101
+ while (isName(toks[j])) {
102
+ parts.push(toks[j].v);
103
+ j++;
104
+ if (P(toks[j], '.') && isName(toks[j + 1])) { j++; continue; }
105
+ break;
106
+ }
107
+ if (!parts.length) return null;
108
+ return { schema: parts.length > 1 ? parts.at(-2) : 'public', name: parts.at(-1), next: j };
109
+ }
110
+
111
+ /** toks[i] must be "(": returns { inner, next } where next is the index after the matching ")". */
112
+ function group(toks, i) {
113
+ if (!P(toks[i], '(')) throw new Error('expected "("');
114
+ let depth = 0;
115
+ for (let j = i; j < toks.length; j++) {
116
+ if (P(toks[j], '(')) depth++;
117
+ else if (P(toks[j], ')') && --depth === 0) return { inner: toks.slice(i + 1, j), next: j + 1 };
118
+ }
119
+ throw new Error('unbalanced parentheses');
120
+ }
121
+
122
+ /** Splits tokens at depth-0 commas. */
123
+ function splitCommas(toks) {
124
+ const parts = [[]];
125
+ let depth = 0;
126
+ for (const t of toks) {
127
+ if (P(t, '(')) depth++;
128
+ else if (P(t, ')')) depth--;
129
+ if (depth === 0 && P(t, ',')) parts.push([]); else parts.at(-1).push(t);
130
+ }
131
+ return parts.filter((p) => p.length);
132
+ }
133
+
134
+ /** An expression that is literally true: true, (true), ((true)). */
135
+ export function isTrueExpr(toks) {
136
+ let t = toks;
137
+ while (t && t.length >= 3 && P(t[0], '(') && P(t.at(-1), ')') && group(t, 0).next === t.length) t = t.slice(1, -1);
138
+ return !!t && t.length === 1 && W(t[0], 'true');
139
+ }
140
+
141
+ const truthy = (t) => !!t && ((t.k === 'w' && ['true', 'on', 'yes', 't'].includes(t.v)) || (t.k === 'n' && t.v === '1') || (t.k === 's' && ['true', 'on', 'yes', 't', '1'].includes(t.v.toLowerCase())));
142
+ const falsy = (t) => !!t && ((t.k === 'w' && ['false', 'off', 'no', 'f'].includes(t.v)) || (t.k === 'n' && t.v === '0') || (t.k === 's' && ['false', 'off', 'no', 'f', '0'].includes(t.v.toLowerCase())));
143
+
144
+ /** Value of a reloption such as security_invoker inside a parenthesized option list; null when the option is absent. */
145
+ function optionValue(inner, name) {
146
+ const i = inner.findIndex((t) => isName(t) && t.v === name);
147
+ if (i === -1) return null;
148
+ if (!P(inner[i + 1], '=')) return true; // an option without a value means true
149
+ return truthy(inner[i + 2]);
150
+ }
151
+
152
+ /** Parses policy clauses starting at i: AS, FOR, TO, USING (...), WITH CHECK (...). Missing clauses are undefined. */
153
+ function policyClauses(toks, i) {
154
+ const out = {};
155
+ while (i < toks.length) {
156
+ if (W(toks[i], 'as') && (W(toks[i + 1], 'permissive') || W(toks[i + 1], 'restrictive'))) { out.restrictive = toks[i + 1].v === 'restrictive'; i += 2; }
157
+ else if (W(toks[i], 'for') && isName(toks[i + 1])) { out.cmd = toks[i + 1].v; i += 2; }
158
+ else if (W(toks[i], 'to')) {
159
+ i++;
160
+ out.roles = [];
161
+ while (isName(toks[i])) {
162
+ out.roles.push(toks[i].v);
163
+ i++;
164
+ if (P(toks[i], ',')) i++; else break;
165
+ }
166
+ } else if (W(toks[i], 'using')) { const g = group(toks, i + 1); out.using = g.inner; i = g.next; }
167
+ else if (seq(toks, i, 'with', 'check')) { const g = group(toks, i + 2); out.check = g.inner; i = g.next; }
168
+ else i++;
169
+ }
170
+ return out;
171
+ }
172
+
173
+ /** Argument list of a function reduced to what ALTER FUNCTION accepts: defaults removed. */
174
+ function signature(inner, src) {
175
+ return splitCommas(inner).map((arg) => {
176
+ let depth = 0;
177
+ let cut = arg.length;
178
+ for (let j = 0; j < arg.length; j++) {
179
+ if (P(arg[j], '(')) depth++;
180
+ else if (P(arg[j], ')')) depth--;
181
+ else if (depth === 0 && (W(arg[j], 'default') || P(arg[j], '='))) { cut = j; break; }
182
+ }
183
+ const a = arg.slice(0, cut);
184
+ return a.length ? src.slice(a[0].pos, a.at(-1).end).replace(/\s+/g, ' ') : '';
185
+ }).filter(Boolean).join(', ');
186
+ }
187
+
188
+ const snippet = (src, st) => src.slice(st.start, st.end).replace(/\s+/g, ' ').slice(0, 240);
189
+
190
+ /** Fresh schema state for one migrations directory. */
191
+ export function newState() {
192
+ return { tables: new Map(), policies: [], functions: new Map(), views: new Map(), buckets: new Map(), autoRls: false, dynamicRls: [], dynamicRlsApplied: [], statements: 0, skipped: [] };
193
+ }
194
+
195
+ function dropMany(toks, i, fn) {
196
+ if (seq(toks, i, 'if', 'exists')) i += 2;
197
+ for (;;) {
198
+ const q = qname(toks, i);
199
+ if (!q) throw new Error('expected a name');
200
+ i = q.next;
201
+ if (P(toks[i], '(')) i = group(toks, i).next; // function argument list
202
+ fn(q);
203
+ if (P(toks[i], ',')) i++; else break;
204
+ }
205
+ }
206
+
207
+ function renameTable(state, from, to) {
208
+ const t = state.tables.get(from);
209
+ if (!t) return;
210
+ state.tables.delete(from);
211
+ state.tables.set(to, t);
212
+ for (const p of state.policies) if (p.table === from) p.table = to;
213
+ }
214
+
215
+ function createStatement(state, st, ctx) {
216
+ const t = st.toks;
217
+ let i = 1;
218
+ if (seq(t, i, 'or', 'replace')) i += 2;
219
+ while (t[i]?.k === 'w' && ['global', 'local', 'temp', 'temporary', 'unlogged', 'recursive', 'trusted'].includes(t[i].v)) {
220
+ if (t[i].v === 'temp' || t[i].v === 'temporary') return; // temporary objects are not exposed
221
+ i++;
222
+ }
223
+ const kind = t[i]?.k === 'w' ? t[i].v : '';
224
+ i++;
225
+ if (kind === 'table') {
226
+ let ifNot = false;
227
+ if (seq(t, i, 'if', 'not', 'exists')) { i += 3; ifNot = true; }
228
+ const q = qname(t, i);
229
+ if (!q) throw new Error('expected a table name');
230
+ const key = keyOf(q.schema, q.name);
231
+ if (ifNot && state.tables.has(key)) return;
232
+ state.tables.set(key, { schema: q.schema, name: q.name, rls: state.autoRls, anonOpen: true, authOpen: true, file: ctx.file, line: st.line, text: snippet(ctx.src, st) });
233
+ } else if (kind === 'policy') {
234
+ if (!isName(t[i]) || !W(t[i + 1], 'on')) throw new Error('expected a policy name and ON');
235
+ const name = t[i].v;
236
+ const q = qname(t, i + 2);
237
+ if (!q) throw new Error('expected a table name');
238
+ const c = policyClauses(t, q.next);
239
+ const table = keyOf(q.schema, q.name);
240
+ state.policies = state.policies.filter((p) => !(p.table === table && p.name === name));
241
+ state.policies.push({
242
+ name, table, schema: q.schema, tableName: q.name, cmd: c.cmd ?? 'all', roles: c.roles ?? [], restrictive: !!c.restrictive,
243
+ using: c.using ?? null, check: c.check ?? null, file: ctx.file, line: st.line, text: snippet(ctx.src, st),
244
+ });
245
+ } else if (kind === 'function' || kind === 'procedure') {
246
+ const q = qname(t, i);
247
+ if (!q || !P(t[q.next], '(')) throw new Error('expected a function name and argument list');
248
+ const args = group(t, q.next);
249
+ const rest = t.slice(args.next);
250
+ let definer = false;
251
+ let searchPath = false;
252
+ let bodyHasRls = false;
253
+ for (let j = 0; j < rest.length; j++) {
254
+ if (seq(rest, j, 'security', 'definer')) definer = true;
255
+ else if (seq(rest, j, 'security', 'invoker')) definer = false;
256
+ else if (W(rest[j], 'set') && isName(rest[j + 1]) && rest[j + 1].v === 'search_path') searchPath = true;
257
+ else if (rest[j].k === 'd' && /row\s+level\s+security/i.test(rest[j].v)) bodyHasRls = true;
258
+ }
259
+ state.functions.set(keyOf(q.schema, q.name), { schema: q.schema, name: q.name, definer, searchPath, bodyHasRls, args: signature(args.inner, ctx.src), file: ctx.file, line: st.line, text: snippet(ctx.src, st) });
260
+ } else if (kind === 'view') {
261
+ const q = qname(t, i);
262
+ if (!q) throw new Error('expected a view name');
263
+ let depth = 0;
264
+ let invoker = false;
265
+ for (let j = q.next; j < t.length; j++) {
266
+ if (P(t[j], '(')) depth++;
267
+ else if (P(t[j], ')')) depth--;
268
+ else if (depth === 0 && W(t[j], 'as')) break;
269
+ else if (depth === 0 && W(t[j], 'with') && P(t[j + 1], '(')) invoker = optionValue(group(t, j + 1).inner, 'security_invoker') === true;
270
+ }
271
+ state.views.set(keyOf(q.schema, q.name), { schema: q.schema, name: q.name, invoker, file: ctx.file, line: st.line, text: snippet(ctx.src, st) });
272
+ } else if (kind === 'event' && W(t[i], 'trigger')) {
273
+ // an event trigger that runs a function which enables RLS makes tables created afterwards RLS-enabled
274
+ const j = t.findIndex((x, k) => k > i && W(x, 'execute') && (W(t[k + 1], 'function') || W(t[k + 1], 'procedure')));
275
+ const q = j === -1 ? null : qname(t, j + 2);
276
+ if (q && state.functions.get(keyOf(q.schema, q.name))?.bodyHasRls) state.autoRls = true;
277
+ }
278
+ }
279
+
280
+ function alterStatement(state, st, ctx) {
281
+ const t = st.toks;
282
+ let i = 1;
283
+ const kind = t[i]?.k === 'w' ? t[i].v : '';
284
+ i++;
285
+ if (kind === 'table') {
286
+ if (seq(t, i, 'if', 'exists')) i += 2;
287
+ if (W(t[i], 'only')) i++;
288
+ const q = qname(t, i);
289
+ if (!q) throw new Error('expected a table name');
290
+ let key = keyOf(q.schema, q.name);
291
+ const tbl = state.tables.get(key);
292
+ if (!tbl) return; // created outside these migrations
293
+ for (let j = q.next; j < t.length; j++) {
294
+ if (seq(t, j, 'enable', 'row', 'level', 'security')) tbl.rls = true;
295
+ else if (seq(t, j, 'disable', 'row', 'level', 'security')) tbl.rls = false;
296
+ else if (W(t[j], 'rename') && W(t[j + 1], 'to') && isName(t[j + 2])) {
297
+ const to = keyOf(tbl.schema, t[j + 2].v);
298
+ renameTable(state, key, to);
299
+ tbl.name = t[j + 2].v;
300
+ key = to;
301
+ } else if (seq(t, j, 'set', 'schema') && isName(t[j + 2])) {
302
+ const to = keyOf(t[j + 2].v, tbl.name);
303
+ renameTable(state, key, to);
304
+ tbl.schema = t[j + 2].v;
305
+ key = to;
306
+ }
307
+ }
308
+ } else if (kind === 'policy') {
309
+ if (!isName(t[i]) || !W(t[i + 1], 'on')) throw new Error('expected a policy name and ON');
310
+ const name = t[i].v;
311
+ const q = qname(t, i + 2);
312
+ if (!q) throw new Error('expected a table name');
313
+ const table = keyOf(q.schema, q.name);
314
+ const p = state.policies.find((x) => x.table === table && x.name === name);
315
+ if (!p) return;
316
+ if (W(t[q.next], 'rename') && W(t[q.next + 1], 'to') && isName(t[q.next + 2])) { p.name = t[q.next + 2].v; return; }
317
+ const c = policyClauses(t, q.next);
318
+ if (c.roles) p.roles = c.roles;
319
+ if (c.using) p.using = c.using;
320
+ if (c.check) p.check = c.check;
321
+ p.file = ctx.file;
322
+ p.line = st.line;
323
+ p.text = snippet(ctx.src, st);
324
+ } else if (kind === 'function' || kind === 'procedure' || kind === 'routine') {
325
+ const q = qname(t, i);
326
+ if (!q) throw new Error('expected a function name');
327
+ const key = keyOf(q.schema, q.name);
328
+ const f = state.functions.get(key);
329
+ if (!f) return;
330
+ for (let j = q.next; j < t.length; j++) {
331
+ if (seq(t, j, 'security', 'definer')) f.definer = true;
332
+ else if (seq(t, j, 'security', 'invoker')) f.definer = false;
333
+ else if (W(t[j], 'set') && isName(t[j + 1]) && t[j + 1].v === 'search_path') f.searchPath = true;
334
+ else if (W(t[j], 'reset') && isName(t[j + 1]) && t[j + 1].v === 'search_path') f.searchPath = false;
335
+ else if (W(t[j], 'rename') && W(t[j + 1], 'to') && isName(t[j + 2])) {
336
+ state.functions.delete(key);
337
+ f.name = t[j + 2].v;
338
+ state.functions.set(keyOf(f.schema, f.name), f);
339
+ }
340
+ }
341
+ } else if (kind === 'view') {
342
+ if (seq(t, i, 'if', 'exists')) i += 2;
343
+ const q = qname(t, i);
344
+ if (!q) throw new Error('expected a view name');
345
+ const key = keyOf(q.schema, q.name);
346
+ const v = state.views.get(key);
347
+ if (!v) return;
348
+ const k = q.next;
349
+ if (W(t[k], 'rename') && W(t[k + 1], 'to') && isName(t[k + 2])) {
350
+ state.views.delete(key);
351
+ v.name = t[k + 2].v;
352
+ state.views.set(keyOf(v.schema, v.name), v);
353
+ } else if (seq(t, k, 'set', 'schema') && isName(t[k + 2])) {
354
+ state.views.delete(key);
355
+ v.schema = t[k + 2].v;
356
+ state.views.set(keyOf(v.schema, v.name), v);
357
+ } else if (W(t[k], 'set') && P(t[k + 1], '(')) {
358
+ const val = optionValue(group(t, k + 1).inner, 'security_invoker');
359
+ if (val !== null) v.invoker = val;
360
+ } else if (W(t[k], 'reset') && P(t[k + 1], '(')) {
361
+ if (group(t, k + 1).inner.some((x) => isName(x) && x.v === 'security_invoker')) v.invoker = false;
362
+ }
363
+ }
364
+ }
365
+
366
+ function dropStatement(state, st) {
367
+ const t = st.toks;
368
+ let i = 1;
369
+ const kind = t[i]?.k === 'w' ? t[i].v : '';
370
+ i++;
371
+ if (kind === 'table') {
372
+ dropMany(t, i, (q) => {
373
+ const key = keyOf(q.schema, q.name);
374
+ state.tables.delete(key);
375
+ state.policies = state.policies.filter((p) => p.table !== key);
376
+ });
377
+ } else if (kind === 'view') dropMany(t, i, (q) => state.views.delete(keyOf(q.schema, q.name)));
378
+ else if (kind === 'function' || kind === 'procedure' || kind === 'routine') dropMany(t, i, (q) => state.functions.delete(keyOf(q.schema, q.name)));
379
+ else if (kind === 'policy') {
380
+ if (seq(t, i, 'if', 'exists')) i += 2;
381
+ if (!isName(t[i]) || !W(t[i + 1], 'on')) throw new Error('expected a policy name and ON');
382
+ const name = t[i].v;
383
+ const q = qname(t, i + 2);
384
+ if (!q) throw new Error('expected a table name');
385
+ const table = keyOf(q.schema, q.name);
386
+ state.policies = state.policies.filter((p) => !(p.table === table && p.name === name));
387
+ }
388
+ }
389
+
390
+ const NOT_TABLE_TARGETS = ['schema', 'function', 'sequence', 'database', 'domain', 'type', 'language', 'procedure', 'routine', 'all', 'foreign', 'large', 'tablespace', 'parameter'];
391
+
392
+ /** GRANT and REVOKE on tables for anon/authenticated: a table revoked from both is not reachable through the API even without RLS. */
393
+ function privilegeStatement(state, st) {
394
+ const t = st.toks;
395
+ const grant = W(t[0], 'grant');
396
+ const on = t.findIndex((x) => W(x, 'on'));
397
+ const to = t.findIndex((x, k) => k > on && W(x, grant ? 'to' : 'from'));
398
+ if (on === -1 || to === -1) return;
399
+ const privs = t.slice(1, on).filter((x) => x.k === 'w').map((x) => x.v);
400
+ let i = on + 1;
401
+ let targets;
402
+ if (seq(t, i, 'all', 'tables', 'in', 'schema')) {
403
+ const schemas = new Set(t.slice(i + 4, to).filter(isName).map((x) => x.v));
404
+ targets = [...state.tables.values()].filter((x) => schemas.has(x.schema));
405
+ } else {
406
+ if (W(t[i], 'table')) i++;
407
+ else if (t[i]?.k === 'w' && NOT_TABLE_TARGETS.includes(t[i].v)) return;
408
+ targets = [];
409
+ for (const part of splitCommas(t.slice(i, to))) {
410
+ const q = qname(part, 0);
411
+ const tbl = q && state.tables.get(keyOf(q.schema, q.name));
412
+ if (tbl) targets.push(tbl);
413
+ }
414
+ }
415
+ const roles = new Set(t.slice(to + 1).filter(isName).map((x) => x.v));
416
+ const anon = roles.has('anon') || roles.has('public');
417
+ const auth = roles.has('authenticated') || roles.has('public');
418
+ for (const tbl of targets) {
419
+ if (grant) { if (anon) tbl.anonOpen = true; if (auth) tbl.authOpen = true; }
420
+ else if (privs.includes('all')) { if (anon) tbl.anonOpen = false; if (auth) tbl.authOpen = false; }
421
+ }
422
+ }
423
+
424
+ const isBuckets = (q) => q && q.schema === 'storage' && q.name === 'buckets';
425
+ const stringsOf = (toks) => toks.filter((x) => x.k === 's').map((x) => x.v);
426
+ const bucket = (id, isPublic, ctx, st) => ({ id, public: isPublic, file: ctx.file, line: st.line, text: snippet(ctx.src, st) });
427
+
428
+ function insertStatement(state, st, ctx) {
429
+ const t = st.toks;
430
+ if (!W(t[1], 'into')) return;
431
+ const q = qname(t, 2);
432
+ if (!isBuckets(q)) return;
433
+ if (!P(t[q.next], '(')) throw new Error('expected a column list');
434
+ const cols = group(t, q.next);
435
+ if (!W(t[cols.next], 'values')) throw new Error('only INSERT ... VALUES into storage.buckets is analyzed');
436
+ const names = splitCommas(cols.inner).map((c) => c[0]?.v ?? '');
437
+ const pub = names.indexOf('public');
438
+ const idCol = names.includes('id') ? names.indexOf('id') : names.indexOf('name');
439
+ let i = cols.next + 1;
440
+ while (P(t[i], '(')) {
441
+ const g = group(t, i);
442
+ const vals = splitCommas(g.inner);
443
+ const id = idCol >= 0 && vals[idCol]?.length === 1 && vals[idCol][0].k === 's' ? vals[idCol][0].v : `(row at line ${st.line})`;
444
+ const isPublic = pub >= 0 && vals[pub]?.length === 1 && truthy(vals[pub][0]);
445
+ state.buckets.set(id, bucket(id, isPublic, ctx, st));
446
+ i = g.next;
447
+ if (P(t[i], ',')) i++; else break;
448
+ }
449
+ }
450
+
451
+ function updateStatement(state, st, ctx) {
452
+ const t = st.toks;
453
+ const q = qname(t, 1);
454
+ if (!isBuckets(q) || !W(t[q.next], 'set')) return;
455
+ const whereAt = t.findIndex((x) => W(x, 'where'));
456
+ const setPart = t.slice(q.next + 1, whereAt === -1 ? t.length : whereAt);
457
+ const i = setPart.findIndex((x, k) => W(x, 'public') && P(setPart[k + 1], '=') && setPart[k + 2]);
458
+ if (i === -1) return;
459
+ const value = setPart[i + 2];
460
+ if (!truthy(value) && !falsy(value)) return; // not a literal
461
+ const makePublic = truthy(value);
462
+ let ids = null; // null: every bucket; []: a condition we cannot read
463
+ if (whereAt !== -1) {
464
+ const w = t.slice(whereAt + 1);
465
+ const byId = isName(w[0]) && ['id', 'name'].includes(w[0].v);
466
+ const simple = byId && ((P(w[1], '=') && w[2]?.k === 's' && w.length === 3) || (W(w[1], 'in') && P(w[2], '(') && group(w, 2).next === w.length));
467
+ ids = simple ? stringsOf(w) : [];
468
+ }
469
+ if (ids === null) { for (const [id] of state.buckets) state.buckets.set(id, bucket(id, makePublic, ctx, st)); return; }
470
+ if (!ids.length) {
471
+ if (makePublic) { const id = `(rows matched by the condition at line ${st.line})`; state.buckets.set(id, bucket(id, true, ctx, st)); }
472
+ return;
473
+ }
474
+ for (const id of ids) state.buckets.set(id, bucket(id, makePublic, ctx, st));
475
+ }
476
+
477
+ function deleteStatement(state, st) {
478
+ const t = st.toks;
479
+ if (!W(t[1], 'from')) return;
480
+ const q = qname(t, 2);
481
+ if (!isBuckets(q)) return;
482
+ const w = t.findIndex((x) => W(x, 'where'));
483
+ if (w === -1) { state.buckets.clear(); return; }
484
+ if (isName(t[w + 1]) && ['id', 'name'].includes(t[w + 1].v)) for (const id of stringsOf(t.slice(w + 2))) state.buckets.delete(id);
485
+ }
486
+
487
+ /**
488
+ * What a DO block puts under row level security, or null when the block is not one of two plain loops. Returns { schemas } (every table that
489
+ * exists at that point in these schemas) or { tables: ['schema.name', ...] } (exactly those tables):
490
+ * for t in select tablename from pg_tables where schemaname = 'public' loop execute format('alter table public.%I enable row level security', t.tablename); end loop;
491
+ * foreach t in array array['a', 'b'] loop execute format('alter table public.%I enable row level security', t); ... end loop;
492
+ * Only unconditional loops count. The first needs a catalog query with nothing but a schema filter (pg_tables, or information_schema.tables with
493
+ * an optional table_type = 'BASE TABLE'); the second needs a literal list. The body must be EXECUTE statements only, one of which is an
494
+ * ALTER TABLE ... ENABLE ROW LEVEL SECURITY on the loop's table, and none may disable RLS. Anything else (extra conditions, IF or CONTINUE inside
495
+ * the loop, other statements) is not understood and the table stays reported.
496
+ */
497
+ export function doBlockRlsCover(body) {
498
+ const text = String(body).replace(/--[^\n]*/g, ' ').replace(/\/\*[\s\S]*?\*\//g, ' ').replace(/\s+/g, ' ').trim().toLowerCase();
499
+ const enablesRls = (loopBody) => {
500
+ const strings = loopBody.match(/'[^']*'/g) ?? [];
501
+ const statements = loopBody.replace(/'[^']*'/g, "''").split(';').map((x) => x.trim()).filter(Boolean);
502
+ if (!statements.length || !statements.every((x) => /^execute\s/.test(x))) return null; // anything but EXECUTE statements is not understood
503
+ if (strings.some((s) => /\bdisable\b/.test(s))) return null;
504
+ return strings.map((s) => /\balter table\s+(?:only\s+)?([a-z_][\w$]*)\.%i\s+enable row level security\b/.exec(s)?.[1]).find(Boolean) ?? null;
505
+ };
506
+ const each = /\bforeach\s+\w+\s+in\s+array\s+array\s*\[\s*((?:'[a-z_][\w$]*'\s*,?\s*)+)\]\s*loop\s+(.*?)\s*end\s+loop\b/.exec(text);
507
+ if (each) {
508
+ const schema = enablesRls(each[2]);
509
+ return schema ? { tables: [...each[1].matchAll(/'([^']+)'/g)].map((x) => `${schema}.${x[1]}`) } : null;
510
+ }
511
+ const m = /\bfor\s+\w+\s+in\s+select\s+(.+?)\s+from\s+(pg_catalog\.pg_tables|pg_tables|information_schema\.tables)\s+where\s+(.+?)\s+loop\s+(.*?)\s*end\s+loop\b/.exec(text);
512
+ if (!m) return null;
513
+ const [, columns, source, cond, loopBody] = m;
514
+ if (!/^(?:\w+\.)?(?:tablename|table_name)$/.test(columns.trim())) return null;
515
+ if (!enablesRls(loopBody)) return null;
516
+ const schemaCol = source.endsWith('pg_tables') ? 'schemaname' : 'table_schema';
517
+ let schemas = null;
518
+ for (const part of cond.split(/\s+and\s+/)) {
519
+ const eq = new RegExp(`^(?:\\w+\\.)?${schemaCol}\\s*=\\s*'([a-z_][\\w$]*)'$`).exec(part.trim());
520
+ const list = new RegExp(`^(?:\\w+\\.)?${schemaCol}\\s+in\\s*\\(\\s*('[a-z_][\\w$]*'(?:\\s*,\\s*'[a-z_][\\w$]*')*)\\s*\\)$`).exec(part.trim());
521
+ if (eq && !schemas) schemas = [eq[1]];
522
+ else if (list && !schemas) schemas = [...list[1].matchAll(/'([^']+)'/g)].map((x) => x[1]);
523
+ else if (!(source === 'information_schema.tables' && /^(?:\w+\.)?table_type\s*=\s*'base table'$/.test(part.trim()))) return null;
524
+ }
525
+ return schemas ? { schemas } : null;
526
+ }
527
+
528
+ /** Replays one migration file into the state. Never throws: statements that fail to parse are counted in state.skipped. */
529
+ export function applyMigration(state, file, src) {
530
+ const ctx = { file, src };
531
+ for (const st of splitStatements(tokenize(src))) {
532
+ state.statements++;
533
+ const verb = st.toks[0]?.k === 'w' ? st.toks[0].v : '';
534
+ try {
535
+ if (verb === 'create') createStatement(state, st, ctx);
536
+ else if (verb === 'alter') alterStatement(state, st, ctx);
537
+ else if (verb === 'drop') dropStatement(state, st);
538
+ else if (verb === 'grant' || verb === 'revoke') privilegeStatement(state, st);
539
+ else if (verb === 'insert') insertStatement(state, st, ctx);
540
+ else if (verb === 'update') updateStatement(state, st, ctx);
541
+ else if (verb === 'delete') deleteStatement(state, st);
542
+ else if (verb === 'do') {
543
+ const body = st.toks.find((x) => x.k === 'd' || x.k === 's');
544
+ if (body && /row\s+level\s+security/i.test(body.v)) {
545
+ const cover = doBlockRlsCover(body.v);
546
+ if (cover) {
547
+ // the block enables RLS on the listed tables, or on every table that exists right now in the listed schemas; tables created later are not covered
548
+ for (const [key, tbl] of state.tables) if (cover.tables ? cover.tables.includes(key) : cover.schemas.includes(tbl.schema)) tbl.rls = true;
549
+ state.dynamicRlsApplied.push({ file, line: st.line, ...(cover.schemas ? { schemas: cover.schemas } : { tables: cover.tables.length }) });
550
+ } else state.dynamicRls.push({ file, line: st.line });
551
+ }
552
+ }
553
+ } catch (e) {
554
+ state.skipped.push({ file, line: st.line, reason: e.message, text: snippet(src, st).slice(0, 120) });
555
+ }
556
+ }
557
+ }
@@ -0,0 +1,93 @@
1
+ // workflows (REQ-016): zizmor over GitHub Actions workflows and composite action files.
2
+ // Offline unless a GitHub token is present (then zizmor also runs its online audits). The token reaches only zizmor.
3
+ import fs from 'node:fs';
4
+ import path from 'node:path';
5
+ import { normalizeSarif } from '../../core/sarif.mjs';
6
+
7
+ export const id = 'workflows';
8
+ export const title = 'GitHub Actions workflow security';
9
+ export const modes = ['scan', 'deep', 'release'];
10
+ export const requiredIn = [];
11
+ export const timeoutSec = 300;
12
+
13
+ export const applies = (ctx) => (ctx.detection.workflows.length > 0
14
+ ? true
15
+ : { applies: false, reason: 'no GitHub Actions workflow or composite action file was found' });
16
+
17
+ const SEVERITY = { informational: 'info', low: 'low', medium: 'medium', high: 'high' };
18
+ const CONFIDENCE = { low: 'low', medium: 'medium', high: 'high' };
19
+ const FIX = {
20
+ 'zizmor/unpinned-uses': 'Pin the action to a full commit SHA (with the version in a comment), not a tag or branch.',
21
+ 'zizmor/template-injection': 'Pass the value through an environment variable (env: NAME: ${{ ... }}) and use "$NAME" in the script instead of expanding it inline.',
22
+ 'zizmor/excessive-permissions': 'Set the narrowest permissions the job needs (for example permissions: contents: read) instead of write-all or broad write scopes.',
23
+ 'zizmor/dangerous-triggers': 'Use pull_request instead of pull_request_target or workflow_run, or never check out or run code from the pull request in that workflow.',
24
+ 'zizmor/artipacked': 'Set persist-credentials: false on actions/checkout so the token is not left in .git/config.',
25
+ };
26
+
27
+ const hasToken = () => !!(process.env.GH_TOKEN || process.env.GITHUB_TOKEN);
28
+
29
+ /** zizmor reports paths relative to the git root, which can sit above the scanned directory: find the real file under repo. */
30
+ function repoRelative(repo, file) {
31
+ const parts = String(file ?? '').split('/').filter(Boolean);
32
+ for (let i = 0; i < parts.length; i++) {
33
+ const rest = parts.slice(i).join('/');
34
+ if (fs.existsSync(path.join(repo, rest))) return rest;
35
+ }
36
+ return parts.join('/');
37
+ }
38
+
39
+ /** Maps zizmor SARIF to raw findings: zizmor's own severity and confidence decide, so High with High confidence blocks. */
40
+ export function mapZizmor(sarif, repo) {
41
+ const results = (sarif?.runs ?? []).flatMap((r) => r.results ?? []);
42
+ const rules = new Map((sarif?.runs ?? []).flatMap((r) => r.tool?.driver?.rules ?? []).map((r) => [r.id, r]));
43
+ const raw = normalizeSarif(sarif, { tool: 'zizmor', category: 'workflow', repo });
44
+ return raw.map((f, i) => {
45
+ const p = results[i]?.properties ?? {};
46
+ const rule = rules.get(f.ruleId);
47
+ const fix = FIX[f.ruleId] ?? (rule?.helpUri ? `Follow the guidance at ${rule.helpUri}.` : 'See the zizmor audit documentation for this rule.');
48
+ return {
49
+ ...f,
50
+ title: rule?.help?.text ? `${rule.help.text} (${rule.name ?? f.ruleId})` : f.title,
51
+ severity: SEVERITY[String(p['zizmor/severity'] ?? '').toLowerCase()] ?? f.severity,
52
+ confidence: CONFIDENCE[String(p['zizmor/confidence'] ?? '').toLowerCase()] ?? 'medium',
53
+ location: { file: repoRelative(repo, f.location.file), line: f.location.line },
54
+ fix,
55
+ };
56
+ });
57
+ }
58
+
59
+ export async function run(ctx) {
60
+ // auditor persona: write-all permissions are only reported there. Below Medium is style noise (unnamed jobs, missing concurrency).
61
+ // --no-config and --no-ignores: the scanned repository cannot switch rules off; acceptances live in vsg.accept.json.
62
+ const base = ['--format', 'sarif', '--persona', 'auditor', '--min-severity', 'medium', '--no-config', '--no-ignores', '--no-progress', '--strict-collection', '--collect=workflows', '--collect=actions'];
63
+ const online = hasToken();
64
+ // Inputs are the .github folders that detection found (it already leaves out nested repositories and worktrees), not "." which would walk them.
65
+ const inputs = [...new Set(ctx.detection.workflows.map((w) => w.slice(0, w.indexOf('.github/') + '.github'.length)))].sort().map((d) => `./${d}`);
66
+ let res = await ctx.runTool('zizmor', [...base, ...(online ? [] : ['--offline']), ...inputs]);
67
+ let degraded = '';
68
+ if (online && res.status === 'ran' && res.exitCode !== 0 && !(res.exitCode >= 10 && res.exitCode <= 14)) {
69
+ // the online audits need the GitHub API; fall back to the offline audits rather than reporting nothing
70
+ degraded = `online audits failed (exit ${res.exitCode}); ran offline instead`;
71
+ res = await ctx.runTool('zizmor', [...base, '--offline', ...inputs]);
72
+ }
73
+ if (res.status !== 'ran') return { status: 'not_run', reason: res.reason };
74
+ if (res.truncated) return { status: 'not_run', reason: 'zizmor output was too large to read completely.' };
75
+ // zizmor signals findings through exit codes 10 to 14 (and 0 with SARIF): those are results, not failures.
76
+ if (res.exitCode !== 0 && !(res.exitCode >= 10 && res.exitCode <= 14)) {
77
+ const tail = res.stderr.trim().split(/\r?\n/).slice(-3).join(' | ');
78
+ return { status: 'not_run', reason: `zizmor failed with exit code ${res.exitCode}${tail ? `: ${tail}` : ''}.` };
79
+ }
80
+ let sarif;
81
+ try { sarif = JSON.parse(res.stdout); } catch { return { status: 'not_run', reason: 'zizmor did not return valid SARIF.' }; }
82
+ const findings = mapZizmor(sarif, ctx.repo);
83
+ return {
84
+ status: 'ran',
85
+ reason: degraded ? `degraded: ${degraded}` : '',
86
+ findings,
87
+ toolVersion: ctx.registry?.get('zizmor')?.version ?? null,
88
+ dataVersions: { mode: online && !degraded ? 'online' : 'offline' },
89
+ evidence: { zizmorExitCode: res.exitCode, mode: online && !degraded ? 'online' : 'offline', results: findings.length },
90
+ };
91
+ }
92
+
93
+ export default { id, title, modes, requiredIn, timeoutSec, applies, run };
@@ -0,0 +1,13 @@
1
+ import { RUN_OPTIONS, runMode } from './run-common.mjs';
2
+
3
+ // Stage 1a: the shared run path only. The deep-only checks arrive with their own packets.
4
+ export default {
5
+ name: 'deep',
6
+ summary: 'Full repository audit, including history, malware and the agent-review brief',
7
+ usage: '[path]',
8
+ maxPositionals: 1,
9
+ purpose: 'Runs the scan checks plus history secrets, malware, licenses, Supabase static analysis and agent review. Checks that are not built yet are reported as did-not-run, so the verdict is INCOMPLETE rather than PASS.',
10
+ options: [...RUN_OPTIONS, { flag: '--no-validate', type: 'bool', help: 'Do not validate found credentials against their issuers' }],
11
+ examples: ['vsg deep', 'vsg deep ../my-app --json'],
12
+ run: (args, io) => runMode('deep', args, io),
13
+ };