@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.
- package/DISCLOSURE +1 -0
- package/README.md +118 -2
- package/bundles/expo-mobile/.agents/skills/lattice-feature-handoff/SKILL.md +31 -0
- package/bundles/expo-mobile/.agents/skills/lattice-release-manager/SKILL.md +29 -0
- package/bundles/expo-mobile/.agents/skills/lattice-verify/SKILL.md +27 -0
- package/bundles/expo-mobile/.claude/agents/lattice-feature-agent.md +10 -0
- package/bundles/expo-mobile/.claude/agents/lattice-release-manager.md +9 -0
- package/bundles/expo-mobile/.claude/hooks/README.md +9 -0
- package/bundles/expo-mobile/.claude/hooks/pre-commit-verify.mjs +10 -0
- package/bundles/expo-mobile/.claude/hooks/pre-tool-use.mjs +51 -0
- package/bundles/expo-mobile/.claude/rules/lattice-core.md +20 -0
- package/bundles/expo-mobile/.claude/settings.json +38 -0
- package/bundles/expo-mobile/.claude/skills/lattice-verify/SKILL.md +27 -0
- package/bundles/expo-mobile/.codex/agents/lattice-feature-agent.toml +9 -0
- package/bundles/expo-mobile/.codex/agents/lattice-release-manager.toml +9 -0
- package/bundles/expo-mobile/.cursor/mcp.json +34 -0
- package/bundles/expo-mobile/.cursor/rules/lattice-core.mdc +35 -0
- package/bundles/expo-mobile/.cursor/rules.md +94 -0
- package/bundles/expo-mobile/.env.example +19 -0
- package/bundles/expo-mobile/.github/PULL_REQUEST_TEMPLATE.md +42 -0
- package/bundles/expo-mobile/.github/agents/lattice-feature-agent.agent.md +7 -0
- package/bundles/expo-mobile/.github/agents/lattice-release-manager.agent.md +7 -0
- package/bundles/expo-mobile/.github/copilot-instructions.md +37 -0
- package/bundles/expo-mobile/.github/instructions/lattice-core.instructions.md +11 -0
- package/bundles/expo-mobile/.github/workflows/ci.yml +26 -0
- package/bundles/expo-mobile/.gitmessage +24 -0
- package/bundles/expo-mobile/.lattice/config.json +9 -0
- package/bundles/expo-mobile/.lattice/dependency-security.json +91 -0
- package/bundles/expo-mobile/.lattice/prompts/01-feature.md +36 -0
- package/bundles/expo-mobile/.lattice/prompts/02-bugfix.md +32 -0
- package/bundles/expo-mobile/.lattice/prompts/03-refactor.md +30 -0
- package/bundles/expo-mobile/.lattice/prompts/04-test.md +31 -0
- package/bundles/expo-mobile/.lattice/prompts/05-polish.md +38 -0
- package/bundles/expo-mobile/.lattice/prompts/06-security.md +32 -0
- package/bundles/expo-mobile/.lattice/release-workflow.json +55 -0
- package/bundles/expo-mobile/.lattice/schemas/feature-handoff.schema.json +264 -0
- package/bundles/expo-mobile/.lattice/templates/feature-handoff.json +52 -0
- package/bundles/expo-mobile/.mcp.json +35 -0
- package/bundles/expo-mobile/AGENTS.md +58 -0
- package/bundles/expo-mobile/CLAUDE.md +75 -0
- package/bundles/expo-mobile/PROJECT_GUIDE.md +299 -0
- package/bundles/expo-mobile/README.md +39 -0
- package/bundles/expo-mobile/__tests__/home.test.tsx +22 -0
- package/bundles/expo-mobile/app/_layout.tsx +20 -0
- package/bundles/expo-mobile/app/index.tsx +72 -0
- package/bundles/expo-mobile/app.json +33 -0
- package/bundles/expo-mobile/components/ui/Button.tsx +75 -0
- package/bundles/expo-mobile/components/ui/Input.tsx +50 -0
- package/bundles/expo-mobile/components/ui/index.ts +2 -0
- package/bundles/expo-mobile/docs/LATTICE_RELEASE_WORKFLOW.md +53 -0
- package/bundles/expo-mobile/docs/rules/codex.md +62 -0
- package/bundles/expo-mobile/eslint.config.js +7 -0
- package/bundles/expo-mobile/lib/supabase/client.ts +22 -0
- package/bundles/expo-mobile/lib/supabase/realtime.ts +10 -0
- package/bundles/expo-mobile/lib/supabase/storage.ts +6 -0
- package/bundles/expo-mobile/package.json +65 -0
- package/bundles/expo-mobile/plugins/with-lattice-commons-io.cjs +42 -0
- package/bundles/expo-mobile/prompts/01-feature-implementation.md +48 -0
- package/bundles/expo-mobile/prompts/02-bug-fix.md +43 -0
- package/bundles/expo-mobile/prompts/03-safe-refactor.md +38 -0
- package/bundles/expo-mobile/prompts/04-test-first.md +41 -0
- package/bundles/expo-mobile/prompts/05-ui-polish.md +44 -0
- package/bundles/expo-mobile/prompts/06-security-review.md +39 -0
- package/bundles/expo-mobile/prompts/quality.md +143 -0
- package/bundles/expo-mobile/supabase/migrations/001_initial_schema.sql +66 -0
- package/bundles/expo-mobile/tsconfig.json +21 -0
- package/bundles/expo-mobile/types/database.types.ts +76 -0
- package/bundles/expo-mobile/vendor/m2ai-braces-3.0.3-m2ai.1.tar +0 -0
- package/bundles/expo-supabase/.agents/skills/lattice-feature-handoff/SKILL.md +31 -0
- package/bundles/expo-supabase/.agents/skills/lattice-release-manager/SKILL.md +29 -0
- package/bundles/expo-supabase/.agents/skills/lattice-verify/SKILL.md +27 -0
- package/bundles/expo-supabase/.claude/agents/lattice-feature-agent.md +10 -0
- package/bundles/expo-supabase/.claude/agents/lattice-release-manager.md +9 -0
- package/bundles/expo-supabase/.claude/hooks/README.md +9 -0
- package/bundles/expo-supabase/.claude/hooks/pre-commit-verify.mjs +10 -0
- package/bundles/expo-supabase/.claude/hooks/pre-tool-use.mjs +51 -0
- package/bundles/expo-supabase/.claude/rules/lattice-core.md +20 -0
- package/bundles/expo-supabase/.claude/settings.json +38 -0
- package/bundles/expo-supabase/.claude/skills/lattice-verify/SKILL.md +27 -0
- package/bundles/expo-supabase/.codex/agents/lattice-feature-agent.toml +9 -0
- package/bundles/expo-supabase/.codex/agents/lattice-release-manager.toml +9 -0
- package/bundles/expo-supabase/.cursor/mcp.json +34 -0
- package/bundles/expo-supabase/.cursor/rules/lattice-core.mdc +35 -0
- package/bundles/expo-supabase/.cursor/rules.md +94 -0
- package/bundles/expo-supabase/.env.example +12 -0
- package/bundles/expo-supabase/.github/PULL_REQUEST_TEMPLATE.md +42 -0
- package/bundles/expo-supabase/.github/agents/lattice-feature-agent.agent.md +7 -0
- package/bundles/expo-supabase/.github/agents/lattice-release-manager.agent.md +7 -0
- package/bundles/expo-supabase/.github/copilot-instructions.md +37 -0
- package/bundles/expo-supabase/.github/instructions/lattice-core.instructions.md +11 -0
- package/bundles/expo-supabase/.github/workflows/ci.yml +26 -0
- package/bundles/expo-supabase/.gitmessage +24 -0
- package/bundles/expo-supabase/.lattice/config.json +9 -0
- package/bundles/expo-supabase/.lattice/dependency-security.json +91 -0
- package/bundles/expo-supabase/.lattice/prompts/01-feature.md +36 -0
- package/bundles/expo-supabase/.lattice/prompts/02-bugfix.md +32 -0
- package/bundles/expo-supabase/.lattice/prompts/03-refactor.md +30 -0
- package/bundles/expo-supabase/.lattice/prompts/04-test.md +31 -0
- package/bundles/expo-supabase/.lattice/prompts/05-polish.md +38 -0
- package/bundles/expo-supabase/.lattice/prompts/06-security.md +32 -0
- package/bundles/expo-supabase/.lattice/release-workflow.json +55 -0
- package/bundles/expo-supabase/.lattice/schemas/feature-handoff.schema.json +264 -0
- package/bundles/expo-supabase/.lattice/templates/feature-handoff.json +52 -0
- package/bundles/expo-supabase/.mcp.json +35 -0
- package/bundles/expo-supabase/AGENTS.md +58 -0
- package/bundles/expo-supabase/CLAUDE.md +75 -0
- package/bundles/expo-supabase/PROJECT_GUIDE.md +201 -0
- package/bundles/expo-supabase/README.md +38 -0
- package/bundles/expo-supabase/__tests__/home.test.tsx +22 -0
- package/bundles/expo-supabase/app/_layout.tsx +14 -0
- package/bundles/expo-supabase/app/index.tsx +72 -0
- package/bundles/expo-supabase/app.json +33 -0
- package/bundles/expo-supabase/components/ui/Button.tsx +75 -0
- package/bundles/expo-supabase/components/ui/Input.tsx +50 -0
- package/bundles/expo-supabase/components/ui/index.ts +2 -0
- package/bundles/expo-supabase/docs/LATTICE_RELEASE_WORKFLOW.md +53 -0
- package/bundles/expo-supabase/docs/rules/codex.md +62 -0
- package/bundles/expo-supabase/eslint.config.js +7 -0
- package/bundles/expo-supabase/lib/supabase/client.ts +22 -0
- package/bundles/expo-supabase/lib/supabase/realtime.ts +10 -0
- package/bundles/expo-supabase/lib/supabase/storage.ts +6 -0
- package/bundles/expo-supabase/package.json +60 -0
- package/bundles/expo-supabase/plugins/with-lattice-commons-io.cjs +42 -0
- package/bundles/expo-supabase/prompts/01-feature-implementation.md +8 -0
- package/bundles/expo-supabase/prompts/02-bug-fix.md +9 -0
- package/bundles/expo-supabase/prompts/03-safe-refactor.md +8 -0
- package/bundles/expo-supabase/prompts/04-test-first.md +7 -0
- package/bundles/expo-supabase/prompts/05-ui-polish.md +7 -0
- package/bundles/expo-supabase/prompts/06-security-review.md +7 -0
- package/bundles/expo-supabase/prompts/quality.md +143 -0
- package/bundles/expo-supabase/supabase/migrations/001_initial_schema.sql +66 -0
- package/bundles/expo-supabase/tsconfig.json +21 -0
- package/bundles/expo-supabase/types/database.types.ts +76 -0
- package/bundles/expo-supabase/vendor/m2ai-braces-3.0.3-m2ai.1.tar +0 -0
- package/bundles/nextjs-landing/.agents/skills/lattice-feature-handoff/SKILL.md +31 -0
- package/bundles/nextjs-landing/.agents/skills/lattice-release-manager/SKILL.md +29 -0
- package/bundles/nextjs-landing/.agents/skills/lattice-verify/SKILL.md +27 -0
- package/bundles/nextjs-landing/.claude/agents/lattice-feature-agent.md +10 -0
- package/bundles/nextjs-landing/.claude/agents/lattice-release-manager.md +9 -0
- package/bundles/nextjs-landing/.claude/hooks/README.md +9 -0
- package/bundles/nextjs-landing/.claude/hooks/pre-commit-verify.mjs +10 -0
- package/bundles/nextjs-landing/.claude/hooks/pre-tool-use.mjs +51 -0
- package/bundles/nextjs-landing/.claude/rules/lattice-core.md +20 -0
- package/bundles/nextjs-landing/.claude/settings.json +38 -0
- package/bundles/nextjs-landing/.claude/skills/lattice-verify/SKILL.md +27 -0
- package/bundles/nextjs-landing/.codex/agents/lattice-feature-agent.toml +9 -0
- package/bundles/nextjs-landing/.codex/agents/lattice-release-manager.toml +9 -0
- package/bundles/nextjs-landing/.cursor/mcp.json +34 -0
- package/bundles/nextjs-landing/.cursor/rules/lattice-core.mdc +35 -0
- package/bundles/nextjs-landing/.cursor/rules.md +95 -0
- package/bundles/nextjs-landing/.env.example +24 -0
- package/bundles/nextjs-landing/.github/PULL_REQUEST_TEMPLATE.md +42 -0
- package/bundles/nextjs-landing/.github/agents/lattice-feature-agent.agent.md +7 -0
- package/bundles/nextjs-landing/.github/agents/lattice-release-manager.agent.md +7 -0
- package/bundles/nextjs-landing/.github/copilot-instructions.md +37 -0
- package/bundles/nextjs-landing/.github/instructions/lattice-core.instructions.md +11 -0
- package/bundles/nextjs-landing/.github/workflows/ci.yml +26 -0
- package/bundles/nextjs-landing/.gitmessage +24 -0
- package/bundles/nextjs-landing/.lattice/config.json +9 -0
- package/bundles/nextjs-landing/.lattice/dependency-security.json +46 -0
- package/bundles/nextjs-landing/.lattice/prompts/01-feature.md +36 -0
- package/bundles/nextjs-landing/.lattice/prompts/02-bugfix.md +32 -0
- package/bundles/nextjs-landing/.lattice/prompts/03-refactor.md +30 -0
- package/bundles/nextjs-landing/.lattice/prompts/04-test.md +31 -0
- package/bundles/nextjs-landing/.lattice/prompts/05-polish.md +38 -0
- package/bundles/nextjs-landing/.lattice/prompts/06-security.md +32 -0
- package/bundles/nextjs-landing/.lattice/release-workflow.json +55 -0
- package/bundles/nextjs-landing/.lattice/schemas/feature-handoff.schema.json +264 -0
- package/bundles/nextjs-landing/.lattice/templates/feature-handoff.json +52 -0
- package/bundles/nextjs-landing/.mcp.json +35 -0
- package/bundles/nextjs-landing/AGENTS.md +58 -0
- package/bundles/nextjs-landing/CLAUDE.md +76 -0
- package/bundles/nextjs-landing/PROJECT_GUIDE.md +216 -0
- package/bundles/nextjs-landing/README.md +39 -0
- package/bundles/nextjs-landing/app/api/example/[id]/route.ts +34 -0
- package/bundles/nextjs-landing/app/api/example/route.ts +24 -0
- package/bundles/nextjs-landing/app/api/health/route.ts +8 -0
- package/bundles/nextjs-landing/app/global-error.tsx +17 -0
- package/bundles/nextjs-landing/app/globals.css +55 -0
- package/bundles/nextjs-landing/app/layout.tsx +22 -0
- package/bundles/nextjs-landing/app/page.tsx +42 -0
- package/bundles/nextjs-landing/components/ui/button.tsx +39 -0
- package/bundles/nextjs-landing/components/ui/card.tsx +53 -0
- package/bundles/nextjs-landing/components/ui/index.ts +4 -0
- package/bundles/nextjs-landing/components/ui/input.tsx +23 -0
- package/bundles/nextjs-landing/components/ui/spinner.tsx +22 -0
- package/bundles/nextjs-landing/docs/LATTICE_RELEASE_WORKFLOW.md +53 -0
- package/bundles/nextjs-landing/docs/rules/codex.md +62 -0
- package/bundles/nextjs-landing/eslint.config.mjs +16 -0
- package/bundles/nextjs-landing/instrumentation-client.ts +30 -0
- package/bundles/nextjs-landing/instrumentation.ts +12 -0
- package/bundles/nextjs-landing/jest.config.mjs +16 -0
- package/bundles/nextjs-landing/jest.setup.js +1 -0
- package/bundles/nextjs-landing/lib/utils.ts +6 -0
- package/bundles/nextjs-landing/next-env.d.ts +5 -0
- package/bundles/nextjs-landing/next.config.ts +15 -0
- package/bundles/nextjs-landing/package.json +48 -0
- package/bundles/nextjs-landing/postcss.config.mjs +7 -0
- package/bundles/nextjs-landing/prompts/01-feature-implementation.md +9 -0
- package/bundles/nextjs-landing/prompts/02-bug-fix.md +10 -0
- package/bundles/nextjs-landing/prompts/03-safe-refactor.md +8 -0
- package/bundles/nextjs-landing/prompts/04-test-first.md +8 -0
- package/bundles/nextjs-landing/prompts/05-ui-polish.md +8 -0
- package/bundles/nextjs-landing/prompts/06-security-review.md +7 -0
- package/bundles/nextjs-landing/prompts/quality.md +269 -0
- package/bundles/nextjs-landing/sentry.edge.config.ts +15 -0
- package/bundles/nextjs-landing/sentry.server.config.ts +15 -0
- package/bundles/nextjs-landing/tsconfig.json +42 -0
- package/bundles/nextjs-landing/vendor/m2ai-braces-3.0.3-m2ai.1.tar +0 -0
- package/bundles/nextjs-saas/.agents/skills/lattice-feature-handoff/SKILL.md +31 -0
- package/bundles/nextjs-saas/.agents/skills/lattice-release-manager/SKILL.md +29 -0
- package/bundles/nextjs-saas/.agents/skills/lattice-verify/SKILL.md +27 -0
- package/bundles/nextjs-saas/.claude/agents/lattice-feature-agent.md +10 -0
- package/bundles/nextjs-saas/.claude/agents/lattice-release-manager.md +9 -0
- package/bundles/nextjs-saas/.claude/hooks/README.md +9 -0
- package/bundles/nextjs-saas/.claude/hooks/pre-commit-verify.mjs +10 -0
- package/bundles/nextjs-saas/.claude/hooks/pre-tool-use.mjs +51 -0
- package/bundles/nextjs-saas/.claude/rules/lattice-core.md +20 -0
- package/bundles/nextjs-saas/.claude/settings.json +38 -0
- package/bundles/nextjs-saas/.claude/skills/lattice-verify/SKILL.md +27 -0
- package/bundles/nextjs-saas/.codex/agents/lattice-feature-agent.toml +9 -0
- package/bundles/nextjs-saas/.codex/agents/lattice-release-manager.toml +9 -0
- package/bundles/nextjs-saas/.cursor/mcp.json +34 -0
- package/bundles/nextjs-saas/.cursor/rules/lattice-core.mdc +35 -0
- package/bundles/nextjs-saas/.cursor/rules.md +95 -0
- package/bundles/nextjs-saas/.env.example +48 -0
- package/bundles/nextjs-saas/.github/PULL_REQUEST_TEMPLATE.md +42 -0
- package/bundles/nextjs-saas/.github/agents/lattice-feature-agent.agent.md +7 -0
- package/bundles/nextjs-saas/.github/agents/lattice-release-manager.agent.md +7 -0
- package/bundles/nextjs-saas/.github/copilot-instructions.md +37 -0
- package/bundles/nextjs-saas/.github/instructions/lattice-core.instructions.md +11 -0
- package/bundles/nextjs-saas/.github/workflows/ci.yml +26 -0
- package/bundles/nextjs-saas/.gitmessage +24 -0
- package/bundles/nextjs-saas/.lattice/config.json +9 -0
- package/bundles/nextjs-saas/.lattice/dependency-security.json +46 -0
- package/bundles/nextjs-saas/.lattice/prompts/01-feature.md +36 -0
- package/bundles/nextjs-saas/.lattice/prompts/02-bugfix.md +32 -0
- package/bundles/nextjs-saas/.lattice/prompts/03-refactor.md +30 -0
- package/bundles/nextjs-saas/.lattice/prompts/04-test.md +31 -0
- package/bundles/nextjs-saas/.lattice/prompts/05-polish.md +38 -0
- package/bundles/nextjs-saas/.lattice/prompts/06-security.md +32 -0
- package/bundles/nextjs-saas/.lattice/prompts/quality.md +269 -0
- package/bundles/nextjs-saas/.lattice/release-workflow.json +55 -0
- package/bundles/nextjs-saas/.lattice/schemas/feature-handoff.schema.json +264 -0
- package/bundles/nextjs-saas/.lattice/templates/feature-handoff.json +52 -0
- package/bundles/nextjs-saas/.mcp.json +35 -0
- package/bundles/nextjs-saas/AGENTS.md +58 -0
- package/bundles/nextjs-saas/CLAUDE.md +76 -0
- package/bundles/nextjs-saas/PROJECT_GUIDE.md +279 -0
- package/bundles/nextjs-saas/README.md +42 -0
- package/bundles/nextjs-saas/app/(auth)/forgot-password/page.tsx +101 -0
- package/bundles/nextjs-saas/app/(auth)/layout.tsx +7 -0
- package/bundles/nextjs-saas/app/(auth)/login/page.tsx +108 -0
- package/bundles/nextjs-saas/app/(auth)/reset-password/page.tsx +135 -0
- package/bundles/nextjs-saas/app/(auth)/signup/page.tsx +144 -0
- package/bundles/nextjs-saas/app/(dashboard)/dashboard/page.tsx +80 -0
- package/bundles/nextjs-saas/app/(dashboard)/layout.tsx +49 -0
- package/bundles/nextjs-saas/app/api/billing/checkout/route.ts +47 -0
- package/bundles/nextjs-saas/app/api/billing/portal/route.ts +29 -0
- package/bundles/nextjs-saas/app/api/example/[id]/route.ts +93 -0
- package/bundles/nextjs-saas/app/api/example/route.ts +61 -0
- package/bundles/nextjs-saas/app/api/health/route.ts +8 -0
- package/bundles/nextjs-saas/app/api/stripe/webhook/route.ts +57 -0
- package/bundles/nextjs-saas/app/api/user/route.ts +49 -0
- package/bundles/nextjs-saas/app/auth/callback/route.ts +16 -0
- package/bundles/nextjs-saas/app/auth/signout/route.ts +10 -0
- package/bundles/nextjs-saas/app/global-error.tsx +17 -0
- package/bundles/nextjs-saas/app/globals.css +55 -0
- package/bundles/nextjs-saas/app/layout.tsx +22 -0
- package/bundles/nextjs-saas/app/page.tsx +84 -0
- package/bundles/nextjs-saas/components/ui/button.tsx +39 -0
- package/bundles/nextjs-saas/components/ui/card.tsx +53 -0
- package/bundles/nextjs-saas/components/ui/index.ts +4 -0
- package/bundles/nextjs-saas/components/ui/input.tsx +23 -0
- package/bundles/nextjs-saas/components/ui/spinner.tsx +22 -0
- package/bundles/nextjs-saas/docs/LATTICE_RELEASE_WORKFLOW.md +53 -0
- package/bundles/nextjs-saas/docs/rules/codex.md +62 -0
- package/bundles/nextjs-saas/eslint.config.mjs +16 -0
- package/bundles/nextjs-saas/instrumentation-client.ts +30 -0
- package/bundles/nextjs-saas/instrumentation.ts +12 -0
- package/bundles/nextjs-saas/jest.config.mjs +16 -0
- package/bundles/nextjs-saas/jest.setup.js +1 -0
- package/bundles/nextjs-saas/lib/auth/password-recovery.ts +94 -0
- package/bundles/nextjs-saas/lib/stripe.ts +10 -0
- package/bundles/nextjs-saas/lib/supabase/admin.ts +14 -0
- package/bundles/nextjs-saas/lib/supabase/client.ts +8 -0
- package/bundles/nextjs-saas/lib/supabase/server.ts +27 -0
- package/bundles/nextjs-saas/lib/utils.ts +6 -0
- package/bundles/nextjs-saas/next-env.d.ts +5 -0
- package/bundles/nextjs-saas/next.config.ts +15 -0
- package/bundles/nextjs-saas/package.json +50 -0
- package/bundles/nextjs-saas/postcss.config.mjs +7 -0
- package/bundles/nextjs-saas/prompts/01-feature-implementation.md +92 -0
- package/bundles/nextjs-saas/prompts/02-bug-fix.md +78 -0
- package/bundles/nextjs-saas/prompts/03-safe-refactor.md +82 -0
- package/bundles/nextjs-saas/prompts/04-test-first.md +80 -0
- package/bundles/nextjs-saas/prompts/05-ui-polish.md +82 -0
- package/bundles/nextjs-saas/prompts/06-security-review.md +74 -0
- package/bundles/nextjs-saas/proxy.ts +61 -0
- package/bundles/nextjs-saas/sentry.edge.config.ts +15 -0
- package/bundles/nextjs-saas/sentry.server.config.ts +15 -0
- package/bundles/nextjs-saas/supabase/migrations/001_initial_schema.sql +66 -0
- package/bundles/nextjs-saas/supabase/migrations/002_billing.sql +17 -0
- package/bundles/nextjs-saas/tsconfig.json +42 -0
- package/bundles/nextjs-saas/types/database.types.ts +76 -0
- package/bundles/nextjs-saas/vendor/m2ai-braces-3.0.3-m2ai.1.tar +0 -0
- package/bundles/nextjs-trpc/.agents/skills/lattice-feature-handoff/SKILL.md +31 -0
- package/bundles/nextjs-trpc/.agents/skills/lattice-release-manager/SKILL.md +29 -0
- package/bundles/nextjs-trpc/.agents/skills/lattice-verify/SKILL.md +27 -0
- package/bundles/nextjs-trpc/.claude/agents/lattice-feature-agent.md +10 -0
- package/bundles/nextjs-trpc/.claude/agents/lattice-release-manager.md +9 -0
- package/bundles/nextjs-trpc/.claude/hooks/README.md +9 -0
- package/bundles/nextjs-trpc/.claude/hooks/pre-commit-verify.mjs +10 -0
- package/bundles/nextjs-trpc/.claude/hooks/pre-tool-use.mjs +51 -0
- package/bundles/nextjs-trpc/.claude/rules/lattice-core.md +20 -0
- package/bundles/nextjs-trpc/.claude/settings.json +38 -0
- package/bundles/nextjs-trpc/.claude/skills/lattice-verify/SKILL.md +27 -0
- package/bundles/nextjs-trpc/.codex/agents/lattice-feature-agent.toml +9 -0
- package/bundles/nextjs-trpc/.codex/agents/lattice-release-manager.toml +9 -0
- package/bundles/nextjs-trpc/.cursor/mcp.json +34 -0
- package/bundles/nextjs-trpc/.cursor/rules/lattice-core.mdc +35 -0
- package/bundles/nextjs-trpc/.cursor/rules.md +95 -0
- package/bundles/nextjs-trpc/.env.example +21 -0
- package/bundles/nextjs-trpc/.github/PULL_REQUEST_TEMPLATE.md +42 -0
- package/bundles/nextjs-trpc/.github/agents/lattice-feature-agent.agent.md +7 -0
- package/bundles/nextjs-trpc/.github/agents/lattice-release-manager.agent.md +7 -0
- package/bundles/nextjs-trpc/.github/copilot-instructions.md +37 -0
- package/bundles/nextjs-trpc/.github/instructions/lattice-core.instructions.md +11 -0
- package/bundles/nextjs-trpc/.github/workflows/ci.yml +26 -0
- package/bundles/nextjs-trpc/.gitmessage +24 -0
- package/bundles/nextjs-trpc/.lattice/config.json +9 -0
- package/bundles/nextjs-trpc/.lattice/dependency-security.json +46 -0
- package/bundles/nextjs-trpc/.lattice/prompts/01-feature.md +36 -0
- package/bundles/nextjs-trpc/.lattice/prompts/02-bugfix.md +32 -0
- package/bundles/nextjs-trpc/.lattice/prompts/03-refactor.md +30 -0
- package/bundles/nextjs-trpc/.lattice/prompts/04-test.md +31 -0
- package/bundles/nextjs-trpc/.lattice/prompts/05-polish.md +38 -0
- package/bundles/nextjs-trpc/.lattice/prompts/06-security.md +32 -0
- package/bundles/nextjs-trpc/.lattice/release-workflow.json +55 -0
- package/bundles/nextjs-trpc/.lattice/schemas/feature-handoff.schema.json +264 -0
- package/bundles/nextjs-trpc/.lattice/templates/feature-handoff.json +52 -0
- package/bundles/nextjs-trpc/.mcp.json +35 -0
- package/bundles/nextjs-trpc/AGENTS.md +58 -0
- package/bundles/nextjs-trpc/CLAUDE.md +76 -0
- package/bundles/nextjs-trpc/PROJECT_GUIDE.md +187 -0
- package/bundles/nextjs-trpc/README.md +49 -0
- package/bundles/nextjs-trpc/app/api/trpc/[trpc]/route.ts +12 -0
- package/bundles/nextjs-trpc/app/global-error.tsx +17 -0
- package/bundles/nextjs-trpc/app/globals.css +55 -0
- package/bundles/nextjs-trpc/app/layout.tsx +19 -0
- package/bundles/nextjs-trpc/app/page.tsx +16 -0
- package/bundles/nextjs-trpc/app/providers.tsx +24 -0
- package/bundles/nextjs-trpc/components/ui/button.tsx +39 -0
- package/bundles/nextjs-trpc/components/ui/card.tsx +53 -0
- package/bundles/nextjs-trpc/components/ui/index.ts +4 -0
- package/bundles/nextjs-trpc/components/ui/input.tsx +23 -0
- package/bundles/nextjs-trpc/components/ui/spinner.tsx +22 -0
- package/bundles/nextjs-trpc/components/user-list.tsx +17 -0
- package/bundles/nextjs-trpc/docs/LATTICE_RELEASE_WORKFLOW.md +53 -0
- package/bundles/nextjs-trpc/docs/rules/codex.md +62 -0
- package/bundles/nextjs-trpc/eslint.config.mjs +16 -0
- package/bundles/nextjs-trpc/instrumentation-client.ts +20 -0
- package/bundles/nextjs-trpc/instrumentation.ts +12 -0
- package/bundles/nextjs-trpc/jest.config.mjs +16 -0
- package/bundles/nextjs-trpc/jest.setup.js +1 -0
- package/bundles/nextjs-trpc/lib/db.ts +17 -0
- package/bundles/nextjs-trpc/lib/trpc/react.tsx +7 -0
- package/bundles/nextjs-trpc/lib/utils.ts +6 -0
- package/bundles/nextjs-trpc/next-env.d.ts +5 -0
- package/bundles/nextjs-trpc/next.config.ts +15 -0
- package/bundles/nextjs-trpc/package.json +62 -0
- package/bundles/nextjs-trpc/postcss.config.mjs +7 -0
- package/bundles/nextjs-trpc/prisma/schema.prisma +41 -0
- package/bundles/nextjs-trpc/prisma.config.ts +10 -0
- package/bundles/nextjs-trpc/prompts/01-feature-implementation.md +9 -0
- package/bundles/nextjs-trpc/prompts/02-bug-fix.md +9 -0
- package/bundles/nextjs-trpc/prompts/03-safe-refactor.md +8 -0
- package/bundles/nextjs-trpc/prompts/04-test-first.md +8 -0
- package/bundles/nextjs-trpc/prompts/05-ui-polish.md +7 -0
- package/bundles/nextjs-trpc/prompts/06-security-review.md +7 -0
- package/bundles/nextjs-trpc/prompts/quality.md +269 -0
- package/bundles/nextjs-trpc/sentry.edge.config.ts +15 -0
- package/bundles/nextjs-trpc/sentry.server.config.ts +15 -0
- package/bundles/nextjs-trpc/server/routers/_app.test.ts +60 -0
- package/bundles/nextjs-trpc/server/routers/_app.ts +25 -0
- package/bundles/nextjs-trpc/server/trpc.ts +12 -0
- package/bundles/nextjs-trpc/tsconfig.json +42 -0
- package/bundles/nextjs-trpc/vendor/m2ai-braces-3.0.3-m2ai.1.tar +0 -0
- package/dist/agent-install-session.d.ts +17 -0
- package/dist/agent-install-session.d.ts.map +1 -0
- package/dist/agent-install-session.js +106 -0
- package/dist/agent-install-session.js.map +1 -0
- package/dist/agent-install-session.test.d.ts +2 -0
- package/dist/agent-install-session.test.d.ts.map +1 -0
- package/dist/agent-install-session.test.js +62 -0
- package/dist/agent-install-session.test.js.map +1 -0
- package/dist/agent-install.d.ts +41 -0
- package/dist/agent-install.d.ts.map +1 -0
- package/dist/agent-install.js +42 -0
- package/dist/agent-install.js.map +1 -0
- package/dist/agent-install.test.d.ts +2 -0
- package/dist/agent-install.test.d.ts.map +1 -0
- package/dist/agent-install.test.js +58 -0
- package/dist/agent-install.test.js.map +1 -0
- package/dist/apply-merge.test.d.ts +2 -0
- package/dist/apply-merge.test.d.ts.map +1 -0
- package/dist/apply-merge.test.js +123 -0
- package/dist/apply-merge.test.js.map +1 -0
- package/dist/bundle-download.d.ts +23 -0
- package/dist/bundle-download.d.ts.map +1 -0
- package/dist/bundle-download.js +180 -0
- package/dist/bundle-download.js.map +1 -0
- package/dist/bundle-download.test.d.ts +2 -0
- package/dist/bundle-download.test.d.ts.map +1 -0
- package/dist/bundle-download.test.js +200 -0
- package/dist/bundle-download.test.js.map +1 -0
- package/dist/bundle-rollback.test.d.ts +2 -0
- package/dist/bundle-rollback.test.d.ts.map +1 -0
- package/dist/bundle-rollback.test.js +127 -0
- package/dist/bundle-rollback.test.js.map +1 -0
- package/dist/bundle-scaffold.test.d.ts +2 -0
- package/dist/bundle-scaffold.test.d.ts.map +1 -0
- package/dist/bundle-scaffold.test.js +105 -0
- package/dist/bundle-scaffold.test.js.map +1 -0
- package/dist/commands.d.ts +132 -0
- package/dist/commands.d.ts.map +1 -0
- package/dist/commands.js +2012 -0
- package/dist/commands.js.map +1 -0
- package/dist/credential-store.d.ts +27 -0
- package/dist/credential-store.d.ts.map +1 -0
- package/dist/credential-store.js +48 -0
- package/dist/credential-store.js.map +1 -0
- package/dist/credential-store.test.d.ts +2 -0
- package/dist/credential-store.test.d.ts.map +1 -0
- package/dist/credential-store.test.js +80 -0
- package/dist/credential-store.test.js.map +1 -0
- package/dist/delivered-project-files.d.ts +31 -0
- package/dist/delivered-project-files.d.ts.map +1 -0
- package/dist/delivered-project-files.js +158 -0
- package/dist/delivered-project-files.js.map +1 -0
- package/dist/delivered-project-files.test.d.ts +2 -0
- package/dist/delivered-project-files.test.d.ts.map +1 -0
- package/dist/delivered-project-files.test.js +107 -0
- package/dist/delivered-project-files.test.js.map +1 -0
- package/dist/doctor-agents.test.d.ts +2 -0
- package/dist/doctor-agents.test.d.ts.map +1 -0
- package/dist/doctor-agents.test.js +65 -0
- package/dist/doctor-agents.test.js.map +1 -0
- package/dist/hermes-install.d.ts +102 -0
- package/dist/hermes-install.d.ts.map +1 -0
- package/dist/hermes-install.js +641 -0
- package/dist/hermes-install.js.map +1 -0
- package/dist/hermes-install.test.d.ts +2 -0
- package/dist/hermes-install.test.d.ts.map +1 -0
- package/dist/hermes-install.test.js +866 -0
- package/dist/hermes-install.test.js.map +1 -0
- package/dist/index.d.ts +115 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5311 -0
- package/dist/index.js.map +1 -0
- package/dist/openclaw-install.d.ts +67 -0
- package/dist/openclaw-install.d.ts.map +1 -0
- package/dist/openclaw-install.js +358 -0
- package/dist/openclaw-install.js.map +1 -0
- package/dist/openclaw-install.test.d.ts +2 -0
- package/dist/openclaw-install.test.d.ts.map +1 -0
- package/dist/openclaw-install.test.js +296 -0
- package/dist/openclaw-install.test.js.map +1 -0
- package/dist/password-recovery-bundle.test.d.ts +2 -0
- package/dist/password-recovery-bundle.test.d.ts.map +1 -0
- package/dist/password-recovery-bundle.test.js +132 -0
- package/dist/password-recovery-bundle.test.js.map +1 -0
- package/dist/project-bundle-env.d.ts +19 -0
- package/dist/project-bundle-env.d.ts.map +1 -0
- package/dist/project-bundle-env.js +111 -0
- package/dist/project-bundle-env.js.map +1 -0
- package/dist/project-bundle-env.test.d.ts +2 -0
- package/dist/project-bundle-env.test.d.ts.map +1 -0
- package/dist/project-bundle-env.test.js +93 -0
- package/dist/project-bundle-env.test.js.map +1 -0
- package/dist/project-path-confinement.test.d.ts +2 -0
- package/dist/project-path-confinement.test.d.ts.map +1 -0
- package/dist/project-path-confinement.test.js +222 -0
- package/dist/project-path-confinement.test.js.map +1 -0
- package/dist/security/api.d.ts +18 -0
- package/dist/security/api.d.ts.map +1 -0
- package/dist/security/api.js +238 -0
- package/dist/security/api.js.map +1 -0
- package/dist/security/api.test.d.ts +2 -0
- package/dist/security/api.test.d.ts.map +1 -0
- package/dist/security/api.test.js +220 -0
- package/dist/security/api.test.js.map +1 -0
- package/dist/security/artifact.d.ts +10 -0
- package/dist/security/artifact.d.ts.map +1 -0
- package/dist/security/artifact.js +283 -0
- package/dist/security/artifact.js.map +1 -0
- package/dist/security/artifact.test.d.ts +2 -0
- package/dist/security/artifact.test.d.ts.map +1 -0
- package/dist/security/artifact.test.js +229 -0
- package/dist/security/artifact.test.js.map +1 -0
- package/dist/security/commands.d.ts +42 -0
- package/dist/security/commands.d.ts.map +1 -0
- package/dist/security/commands.js +825 -0
- package/dist/security/commands.js.map +1 -0
- package/dist/security/commands.test.d.ts +2 -0
- package/dist/security/commands.test.d.ts.map +1 -0
- package/dist/security/commands.test.js +1051 -0
- package/dist/security/commands.test.js.map +1 -0
- package/dist/security/connection.d.ts +19 -0
- package/dist/security/connection.d.ts.map +1 -0
- package/dist/security/connection.js +145 -0
- package/dist/security/connection.js.map +1 -0
- package/dist/security/connection.test.d.ts +2 -0
- package/dist/security/connection.test.d.ts.map +1 -0
- package/dist/security/connection.test.js +62 -0
- package/dist/security/connection.test.js.map +1 -0
- package/dist/security/index-routing.test.d.ts +2 -0
- package/dist/security/index-routing.test.d.ts.map +1 -0
- package/dist/security/index-routing.test.js +169 -0
- package/dist/security/index-routing.test.js.map +1 -0
- package/dist/security/journal.d.ts +26 -0
- package/dist/security/journal.d.ts.map +1 -0
- package/dist/security/journal.js +441 -0
- package/dist/security/journal.js.map +1 -0
- package/dist/security/journal.test.d.ts +2 -0
- package/dist/security/journal.test.d.ts.map +1 -0
- package/dist/security/journal.test.js +226 -0
- package/dist/security/journal.test.js.map +1 -0
- package/dist/security/package-verifier.d.ts +15 -0
- package/dist/security/package-verifier.d.ts.map +1 -0
- package/dist/security/package-verifier.js +65 -0
- package/dist/security/package-verifier.js.map +1 -0
- package/dist/security/package-verifier.test.d.ts +2 -0
- package/dist/security/package-verifier.test.d.ts.map +1 -0
- package/dist/security/package-verifier.test.js +57 -0
- package/dist/security/package-verifier.test.js.map +1 -0
- package/dist/security/runtime.d.ts +43 -0
- package/dist/security/runtime.d.ts.map +1 -0
- package/dist/security/runtime.js +81 -0
- package/dist/security/runtime.js.map +1 -0
- package/dist/security/runtime.test.d.ts +2 -0
- package/dist/security/runtime.test.d.ts.map +1 -0
- package/dist/security/runtime.test.js +88 -0
- package/dist/security/runtime.test.js.map +1 -0
- package/dist/security/types.d.ts +169 -0
- package/dist/security/types.d.ts.map +1 -0
- package/dist/security/types.js +3 -0
- package/dist/security/types.js.map +1 -0
- package/dist/security-runtime/LICENSE +202 -0
- package/dist/security-runtime/NOTICE +16 -0
- package/dist/security-runtime/artifact-manifest.json +960 -0
- package/dist/security-runtime/bin/vsg.mjs +5 -0
- package/dist/security-runtime/lattice-catalog.json +176585 -0
- package/dist/security-runtime/lattice-runtime.mjs +90 -0
- package/dist/security-runtime/licensing/candidates/apache-source-license-evidence.json +478 -0
- package/dist/security-runtime/licensing/candidates/betterleaks-generic-api-key.json +76 -0
- package/dist/security-runtime/licensing/candidates/betterleaks-jwt.json +74 -0
- package/dist/security-runtime/licensing/candidates/blackberry-additional-source-declaration-evidence.json +276 -0
- package/dist/security-runtime/licensing/candidates/blackberry-source-declaration-evidence.json +369 -0
- package/dist/security-runtime/licensing/candidates/cado-source-declaration-evidence.json +283 -0
- package/dist/security-runtime/licensing/candidates/commercial-rule-candidate.json +280 -0
- package/dist/security-runtime/licensing/candidates/commercial-runtime-release.json +389 -0
- package/dist/security-runtime/licensing/candidates/data-feed-evidence.json +259 -0
- package/dist/security-runtime/licensing/candidates/gitlab-sast-rule-identities.json +178 -0
- package/dist/security-runtime/licensing/candidates/gitlab-sast-source-evidence.json +1824 -0
- package/dist/security-runtime/licensing/candidates/gitlab-sast-source-notice-bundle.json +45 -0
- package/dist/security-runtime/licensing/candidates/malpedia-source-license-evidence.json +41 -0
- package/dist/security-runtime/licensing/candidates/rule-license-evidence.json +376 -0
- package/dist/security-runtime/licensing/candidates/runner-image-composition.json +1500 -0
- package/dist/security-runtime/licensing/candidates/selected-runtime-coverage.json +91 -0
- package/dist/security-runtime/licensing/candidates/yara-forge-20260927.json +58502 -0
- package/dist/security-runtime/licensing/commercial-components.json +379 -0
- package/dist/security-runtime/licensing/notices/betterleaks-1.9.0-MIT.txt +21 -0
- package/dist/security-runtime/licensing/notices/candidate-sources/sha256/28a9529c7d0bb4dc51f4bf5c116a3d16ef247a052f7591466768ddf563fd1cf5.txt +428 -0
- package/dist/security-runtime/licensing/notices/candidate-sources/sha256/33acf42afdd03163d75fe856cb431e70710e0b5deede3362e6d1c4697cfe1c6a.txt +28 -0
- package/dist/security-runtime/licensing/notices/candidate-sources/sha256/3972dc9744f6499f0f9b2dbf76696f2ae7ad8af9b23dde66d6af86c9dfb36986.txt +674 -0
- package/dist/security-runtime/licensing/notices/candidate-sources/sha256/4fecb8fcaf80fd9a6315bca5225ee43377015b46a0459c2925495be885cab19a.txt +21 -0
- package/dist/security-runtime/licensing/notices/candidate-sources/sha256/811515f8723aa4007de2fbb75a364127fdec51cda534b87a7ea8f2fef2f96dd7.txt +24 -0
- package/dist/security-runtime/licensing/notices/candidate-sources/sha256/814442c3987a2c0411171ad8ad43118e8c08f85c9c5d1dcdecc9787c7ca8689b.txt +664 -0
- package/dist/security-runtime/licensing/notices/candidate-sources/sha256/8a959b2413d0c83ca1b3ce9153076c649abf2e4bbfebbb493fb24c2074a1eb8a.txt +38 -0
- package/dist/security-runtime/licensing/notices/candidate-sources/sha256/995182e185856186fbbe49f150409ae026aa4cda7e94f83c6ed737cbb77fa9c7.txt +23 -0
- package/dist/security-runtime/licensing/notices/candidate-sources/sha256/9b8e1305e46d1dd4011b6ed933c9f6223e08c9c4625001c5fd75a34fa930f616.txt +202 -0
- package/dist/security-runtime/licensing/notices/candidate-sources/sha256/a01f1a28424bfe7f49a23d339a01847cfa9ace3864d5e7295051772a4bae2271.txt +38 -0
- package/dist/security-runtime/licensing/notices/candidate-sources/sha256/a5681bf9b05db14d86776930017c647ad9e6e56ff6bbcfdf21e5848288dfaf1b.txt +165 -0
- package/dist/security-runtime/licensing/notices/candidate-sources/sha256/a5b8bd9ae96c630bbf229d61c5c5def20274e00be39abfd2fab4d7879ceab462.txt +24 -0
- package/dist/security-runtime/licensing/notices/candidate-sources/sha256/ada32b3747ce108d5e8bab7918af94abbd03f2fe2a46304f74c6333bbfd914ed.txt +8 -0
- package/dist/security-runtime/licensing/notices/candidate-sources/sha256/c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4.txt +201 -0
- package/dist/security-runtime/licensing/notices/candidate-sources/sha256/c738ae413cf561f174e34f6961f8ca458aae2369a73640dda6234c629b98bcc4.txt +2732 -0
- package/dist/security-runtime/licensing/notices/candidate-sources/sha256/ce41c9a2c986277f7f9ab146a2195c1888a5d8da062e22d7c9c88666bb7c38cd.txt +17 -0
- package/dist/security-runtime/licensing/notices/candidate-sources/sha256/d5f4c36a0528e01cfdd9e4fc60879201d3af49b41c520200643d321fe53da5f9.txt +17 -0
- package/dist/security-runtime/licensing/notices/candidate-sources/sha256/e08c368ccd455f85c7fb9e04830e730f26e9dbb5c0f77bc88e09a5b0cb37df5b.txt +38 -0
- package/dist/security-runtime/licensing/notices/candidate-sources/sha256/e9efb2f7daf11bb6379c06c16b870dddcecc4a10f8704bb8aad807529c8b3c97.txt +8 -0
- package/dist/security-runtime/licensing/notices/gitleaks-generic-origin-782f3104-MIT.txt +21 -0
- package/dist/security-runtime/package.json +17 -0
- package/dist/security-runtime/playbook/README.md +76 -0
- package/dist/security-runtime/playbook/access-control.md +56 -0
- package/dist/security-runtime/playbook/ai-features.md +53 -0
- package/dist/security-runtime/playbook/desktop-python.md +59 -0
- package/dist/security-runtime/playbook/input-handling.md +59 -0
- package/dist/security-runtime/playbook/mobile-expo.md +59 -0
- package/dist/security-runtime/playbook/payments.md +53 -0
- package/dist/security-runtime/playbook/privacy-account-recovery.md +59 -0
- package/dist/security-runtime/playbook/secrets-config.md +47 -0
- package/dist/security-runtime/playbook/supabase.md +48 -0
- package/dist/security-runtime/playbook/supply-chain.md +62 -0
- package/dist/security-runtime/playbook/webhooks-integrations.md +52 -0
- package/dist/security-runtime/rules/vsg-ai-key-in-client.yaml +41 -0
- package/dist/security-runtime/rules/vsg-ai-output-raw-html.yaml +35 -0
- package/dist/security-runtime/rules/vsg-angular-sanitizer-bypass.yaml +23 -0
- package/dist/security-runtime/rules/vsg-expo-token-in-asyncstorage.yaml +22 -0
- package/dist/security-runtime/rules/vsg-flask-public-bind.yaml +32 -0
- package/dist/security-runtime/rules/vsg-nextjs-action-write-no-auth.yaml +144 -0
- package/dist/security-runtime/rules/vsg-nextjs-inline-action-write-no-auth.yaml +161 -0
- package/dist/security-runtime/rules/vsg-nextjs-route-write-no-auth.yaml +193 -0
- package/dist/security-runtime/rules/vsg-nosql-where-injection.yaml +36 -0
- package/dist/security-runtime/rules/vsg-python-pickle-load.yaml +26 -0
- package/dist/security-runtime/rules/vsg-python-requests-verify-false.yaml +34 -0
- package/dist/security-runtime/rules/vsg-python-subprocess-shell.yaml +23 -0
- package/dist/security-runtime/rules/vsg-stripe-client-price.yaml +51 -0
- package/dist/security-runtime/rules/vsg-stripe-webhook-no-signature.yaml +31 -0
- package/dist/security-runtime/rules/vsg-stripe-webhook-pages-no-signature.yaml +51 -0
- package/dist/security-runtime/rules/vsg-supabase-service-role-in-client.yaml +27 -0
- package/dist/security-runtime/rules/vsg-supabase-service-role-public-env.yaml +24 -0
- package/dist/security-runtime/rules/vsg-xml-external-entities.yaml +19 -0
- package/dist/security-runtime/src/agent/brief.mjs +95 -0
- package/dist/security-runtime/src/agent/discover.mjs +108 -0
- package/dist/security-runtime/src/agent/exec.mjs +64 -0
- package/dist/security-runtime/src/agent/ingest.mjs +213 -0
- package/dist/security-runtime/src/agent/report.mjs +94 -0
- package/dist/security-runtime/src/agent/schema.mjs +62 -0
- package/dist/security-runtime/src/agent/tokenize.mjs +38 -0
- package/dist/security-runtime/src/checks/README.md +8 -0
- package/dist/security-runtime/src/checks/_lib/gitfiles.mjs +35 -0
- package/dist/security-runtime/src/checks/_lib/lockfiles.mjs +135 -0
- package/dist/security-runtime/src/checks/_lib/osv.mjs +6 -0
- package/dist/security-runtime/src/checks/_lib/secrets.mjs +381 -0
- package/dist/security-runtime/src/checks/_lib/targets.mjs +79 -0
- package/dist/security-runtime/src/checks/agent-review/index.mjs +52 -0
- package/dist/security-runtime/src/checks/agent-surface/config.mjs +223 -0
- package/dist/security-runtime/src/checks/agent-surface/index.mjs +113 -0
- package/dist/security-runtime/src/checks/agent-surface/instructions.mjs +87 -0
- package/dist/security-runtime/src/checks/agent-surface/patterns.mjs +68 -0
- package/dist/security-runtime/src/checks/agent-surface/unicode.mjs +88 -0
- package/dist/security-runtime/src/checks/code/auth-helpers.mjs +659 -0
- package/dist/security-runtime/src/checks/code/index.mjs +617 -0
- package/dist/security-runtime/src/checks/code/opengrep-container.mjs +85 -0
- package/dist/security-runtime/src/checks/code/opengrep-runner.mjs +86 -0
- package/dist/security-runtime/src/checks/code/selected-opengrep-runner.mjs +112 -0
- package/dist/security-runtime/src/checks/dep-change/guarddog.mjs +142 -0
- package/dist/security-runtime/src/checks/dep-change/index.mjs +316 -0
- package/dist/security-runtime/src/checks/dep-change/registries.mjs +199 -0
- package/dist/security-runtime/src/checks/deps-vuln/index.mjs +305 -0
- package/dist/security-runtime/src/checks/desktop-config/index.mjs +112 -0
- package/dist/security-runtime/src/checks/dns-mail/index.mjs +71 -0
- package/dist/security-runtime/src/checks/iac/index.mjs +83 -0
- package/dist/security-runtime/src/checks/install-posture/index.mjs +123 -0
- package/dist/security-runtime/src/checks/licenses/index.mjs +143 -0
- package/dist/security-runtime/src/checks/live-basic/index.mjs +77 -0
- package/dist/security-runtime/src/checks/live-js-secrets/index.mjs +100 -0
- package/dist/security-runtime/src/checks/malware/clamav.mjs +17 -0
- package/dist/security-runtime/src/checks/malware/defender.mjs +43 -0
- package/dist/security-runtime/src/checks/malware/index.mjs +186 -0
- package/dist/security-runtime/src/checks/malware/targets.mjs +147 -0
- package/dist/security-runtime/src/checks/malware/yara-runner.mjs +201 -0
- package/dist/security-runtime/src/checks/malware/yara.mjs +124 -0
- package/dist/security-runtime/src/checks/mobile-config/index.mjs +173 -0
- package/dist/security-runtime/src/checks/mobile-config/mobsf.mjs +105 -0
- package/dist/security-runtime/src/checks/posture/index.mjs +133 -0
- package/dist/security-runtime/src/checks/project-scripts/index.mjs +187 -0
- package/dist/security-runtime/src/checks/sbom/index.mjs +98 -0
- package/dist/security-runtime/src/checks/secrets-build/index.mjs +63 -0
- package/dist/security-runtime/src/checks/secrets-history/index.mjs +112 -0
- package/dist/security-runtime/src/checks/secrets-tree/env.mjs +120 -0
- package/dist/security-runtime/src/checks/secrets-tree/index.mjs +73 -0
- package/dist/security-runtime/src/checks/supabase-static/index.mjs +240 -0
- package/dist/security-runtime/src/checks/supabase-static/sql.mjs +557 -0
- package/dist/security-runtime/src/checks/workflows/index.mjs +93 -0
- package/dist/security-runtime/src/cli/deep.mjs +13 -0
- package/dist/security-runtime/src/cli/doctor.mjs +82 -0
- package/dist/security-runtime/src/cli/index.mjs +60 -0
- package/dist/security-runtime/src/cli/live-common.mjs +27 -0
- package/dist/security-runtime/src/cli/parse.mjs +56 -0
- package/dist/security-runtime/src/cli/portfolio.mjs +34 -0
- package/dist/security-runtime/src/cli/release.mjs +28 -0
- package/dist/security-runtime/src/cli/report.mjs +18 -0
- package/dist/security-runtime/src/cli/run-common.mjs +54 -0
- package/dist/security-runtime/src/cli/scan.mjs +12 -0
- package/dist/security-runtime/src/cli/setup.mjs +59 -0
- package/dist/security-runtime/src/cli/url.mjs +38 -0
- package/dist/security-runtime/src/core/accept.mjs +141 -0
- package/dist/security-runtime/src/core/archive.mjs +114 -0
- package/dist/security-runtime/src/core/base-ref.mjs +43 -0
- package/dist/security-runtime/src/core/checks.mjs +39 -0
- package/dist/security-runtime/src/core/detect.mjs +90 -0
- package/dist/security-runtime/src/core/errors.mjs +5 -0
- package/dist/security-runtime/src/core/fetch.mjs +139 -0
- package/dist/security-runtime/src/core/findings.mjs +177 -0
- package/dist/security-runtime/src/core/gate.mjs +131 -0
- package/dist/security-runtime/src/core/installer.mjs +255 -0
- package/dist/security-runtime/src/core/lock.mjs +38 -0
- package/dist/security-runtime/src/core/nested.mjs +107 -0
- package/dist/security-runtime/src/core/paths.mjs +20 -0
- package/dist/security-runtime/src/core/pipeline.mjs +196 -0
- package/dist/security-runtime/src/core/registry.mjs +81 -0
- package/dist/security-runtime/src/core/report.mjs +128 -0
- package/dist/security-runtime/src/core/runner.mjs +86 -0
- package/dist/security-runtime/src/core/sarif.mjs +141 -0
- package/dist/security-runtime/src/lattice/artifact.mjs +1201 -0
- package/dist/security-runtime/src/lattice/execution.mjs +45 -0
- package/dist/security-runtime/src/lattice/export.mjs +215 -0
- package/dist/security-runtime/src/lattice/provenance.mjs +70 -0
- package/dist/security-runtime/src/lattice/runtime.mjs +158 -0
- package/dist/security-runtime/src/lattice/selected-runtime.mjs +189 -0
- package/dist/security-runtime/src/lattice/source-acquirer.mjs +51 -0
- package/dist/security-runtime/src/lattice/source-fetcher.mjs +88 -0
- package/dist/security-runtime/src/lattice/transport.mjs +232 -0
- package/dist/security-runtime/src/live/analyze.mjs +101 -0
- package/dist/security-runtime/src/live/exposure.mjs +79 -0
- package/dist/security-runtime/src/live/secrets.mjs +31 -0
- package/dist/security-runtime/src/live/session.mjs +98 -0
- package/dist/security-runtime/src/live/targets.mjs +81 -0
- package/dist/security-runtime/src/portfolio/index.mjs +116 -0
- package/dist/security-runtime/tools/registry/betterleaks.json +29 -0
- package/dist/security-runtime/tools/registry/guarddog.json +9 -0
- package/dist/security-runtime/tools/registry/mobsf.json +10 -0
- package/dist/security-runtime/tools/registry/opengrep.json +28 -0
- package/dist/security-runtime/tools/registry/osv-scanner.json +14 -0
- package/dist/security-runtime/tools/registry/semgrep-rules.json +21 -0
- package/dist/security-runtime/tools/registry/trivy.json +30 -0
- package/dist/security-runtime/tools/registry/yara-forge-exclusions.json +14 -0
- package/dist/security-runtime/tools/registry/yara-forge.json +22 -0
- package/dist/security-runtime/tools/registry/yara-runner.json +10 -0
- package/dist/security-runtime/tools/registry/yara-x.json +24 -0
- package/dist/security-runtime/tools/registry/zizmor.json +30 -0
- package/dist/spinner.d.ts +16 -0
- package/dist/spinner.d.ts.map +1 -0
- package/dist/spinner.js +72 -0
- package/dist/spinner.js.map +1 -0
- package/dist/verify.test.d.ts +2 -0
- package/dist/verify.test.d.ts.map +1 -0
- package/dist/verify.test.js +98 -0
- package/dist/verify.test.js.map +1 -0
- package/package.json +73 -4
|
@@ -0,0 +1,825 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.runSecurityCommand = runSecurityCommand;
|
|
7
|
+
exports.isSecurityRunMode = isSecurityRunMode;
|
|
8
|
+
const node_crypto_1 = require("node:crypto");
|
|
9
|
+
const node_path_1 = require("node:path");
|
|
10
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
11
|
+
const api_js_1 = require("./api.js");
|
|
12
|
+
const artifact_js_1 = require("./artifact.js");
|
|
13
|
+
const connection_js_1 = require("./connection.js");
|
|
14
|
+
const journal_js_1 = require("./journal.js");
|
|
15
|
+
const runtime_js_1 = require("./runtime.js");
|
|
16
|
+
const RUN_COMMANDS = new Set(['scan', 'deep', 'release', 'report', 'publish']);
|
|
17
|
+
const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
18
|
+
const MAX_FINISH_BYTES = 1_048_576;
|
|
19
|
+
function valueFor(args, flag) {
|
|
20
|
+
const indexes = args.map((value, index) => value === flag ? index : -1).filter((index) => index >= 0);
|
|
21
|
+
if (indexes.length > 1)
|
|
22
|
+
throw new Error(`${flag} may be supplied only once.`);
|
|
23
|
+
if (indexes.length === 0)
|
|
24
|
+
return undefined;
|
|
25
|
+
const value = args[indexes[0] + 1];
|
|
26
|
+
if (!value || value.startsWith('--'))
|
|
27
|
+
throw new Error(`${flag} requires a value.`);
|
|
28
|
+
return value;
|
|
29
|
+
}
|
|
30
|
+
function option(args, ...flags) {
|
|
31
|
+
const values = flags.map((flag) => valueFor(args, flag)).filter((value) => !!value);
|
|
32
|
+
if (values.length > 1 && new Set(values).size > 1)
|
|
33
|
+
throw new Error(`${flags.join('/')} values conflict.`);
|
|
34
|
+
return values[0];
|
|
35
|
+
}
|
|
36
|
+
function uuidOption(args, flag) {
|
|
37
|
+
const value = valueFor(args, flag);
|
|
38
|
+
if (value && !UUID.test(value))
|
|
39
|
+
throw new Error(`${flag} must be a UUID.`);
|
|
40
|
+
return value?.toLowerCase();
|
|
41
|
+
}
|
|
42
|
+
function printSecurityHelp(write) {
|
|
43
|
+
write('Lattice Security (customer-run VSG adapter)');
|
|
44
|
+
write('');
|
|
45
|
+
write(' lattice security connect --app <uuid> [--api-url <origin>]');
|
|
46
|
+
write(' lattice security status [--app <uuid>] [--json]');
|
|
47
|
+
write(' lattice security scan|deep|release|report [--publish] [--entitlement <uuid>]');
|
|
48
|
+
write(' lattice security publish --report <retained-vsg-output-directory> --parent-run <uuid>');
|
|
49
|
+
write(' lattice security publish --journal <uuid>');
|
|
50
|
+
write(' lattice security logout [--app <uuid>]');
|
|
51
|
+
write('');
|
|
52
|
+
write('deep/release project scripts require interactive consent or --allow-project-scripts.');
|
|
53
|
+
write('publish --report re-exports a retained VSG output directory through the artifact exporter, which verifies current source and runtime provenance; it does not upload arbitrary JSON.');
|
|
54
|
+
write('Tokens are entered through a masked prompt or LATTICE_SECURITY_TOKEN and are never accepted as command arguments.');
|
|
55
|
+
}
|
|
56
|
+
function statusLines(status) {
|
|
57
|
+
const lines = [
|
|
58
|
+
`Security app: ${status.app.name} (${status.app.id})`,
|
|
59
|
+
`Repository: ${status.app.repositoryIdentity}`,
|
|
60
|
+
`Publication: ${status.publicationEnabled ? 'enabled' : 'disabled'}`,
|
|
61
|
+
];
|
|
62
|
+
if (status.releaseBlockers.length > 0)
|
|
63
|
+
lines.push(`Release blockers: ${status.releaseBlockers.join(', ')}`);
|
|
64
|
+
if (status.entitlements.length === 0)
|
|
65
|
+
lines.push('Entitlements: none');
|
|
66
|
+
for (const entitlement of status.entitlements) {
|
|
67
|
+
lines.push(`${entitlement.kind} ${entitlement.id}: ${entitlement.remainingUnits} remaining, ${entitlement.reservedUnits} reserved, artifact ${entitlement.artifactStatus}`);
|
|
68
|
+
}
|
|
69
|
+
return lines;
|
|
70
|
+
}
|
|
71
|
+
async function defaultPromptToken() {
|
|
72
|
+
const response = await inquirer_1.default.prompt([
|
|
73
|
+
{ type: 'password', name: 'token', message: 'Paste the app-scoped Security token:', mask: '*' },
|
|
74
|
+
]);
|
|
75
|
+
return response.token;
|
|
76
|
+
}
|
|
77
|
+
async function defaultConfirmProjectScripts() {
|
|
78
|
+
if (!process.stdin.isTTY)
|
|
79
|
+
return false;
|
|
80
|
+
const response = await inquirer_1.default.prompt([{
|
|
81
|
+
type: 'confirm', name: 'approved', default: false,
|
|
82
|
+
message: 'Allow VSG to run this project\'s own scripts with your local user permissions?',
|
|
83
|
+
}]);
|
|
84
|
+
return response.approved;
|
|
85
|
+
}
|
|
86
|
+
function connectionOptions(args, deps) {
|
|
87
|
+
return {
|
|
88
|
+
appId: option(args, '--app', '--app-id'),
|
|
89
|
+
apiUrl: valueFor(args, '--api-url'),
|
|
90
|
+
filePath: deps.connectionPath ?? (0, connection_js_1.defaultSecurityConnectionPath)(),
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
async function connect(args, deps) {
|
|
94
|
+
const env = deps.env ?? process.env;
|
|
95
|
+
const appId = (0, connection_js_1.validateSecurityAppId)(option(args, '--app', '--app-id') ?? env.LATTICE_SECURITY_APP_ID ?? '');
|
|
96
|
+
const apiUrl = (0, connection_js_1.normalizeSecurityApiUrl)(valueFor(args, '--api-url') ?? env.LATTICE_SECURITY_API_URL ?? env.LATTICE_API_URL ?? 'https://latticeai.app');
|
|
97
|
+
const token = (0, connection_js_1.validateSecurityToken)(env.LATTICE_SECURITY_TOKEN ?? await (deps.promptToken ?? defaultPromptToken)());
|
|
98
|
+
const connection = { apiUrl, appId, token, connectedAt: new Date().toISOString() };
|
|
99
|
+
const response = await (deps.getStatus ?? api_js_1.getSecurityStatus)(connection);
|
|
100
|
+
await (deps.saveConnection ?? connection_js_1.saveSecurityConnection)(connection, deps.connectionPath ?? (0, connection_js_1.defaultSecurityConnectionPath)());
|
|
101
|
+
(deps.stdout ?? console.log)(`Connected Security app ${response.app.name} (${response.app.id}).`);
|
|
102
|
+
return 0;
|
|
103
|
+
}
|
|
104
|
+
async function status(args, deps) {
|
|
105
|
+
const connection = await (deps.resolveConnection ?? connection_js_1.resolveSecurityConnection)(connectionOptions(args, deps));
|
|
106
|
+
const response = await (deps.getStatus ?? api_js_1.getSecurityStatus)(connection);
|
|
107
|
+
const write = deps.stdout ?? console.log;
|
|
108
|
+
if (args.includes('--json'))
|
|
109
|
+
write(JSON.stringify(response, null, 2));
|
|
110
|
+
else
|
|
111
|
+
statusLines(response).forEach((line) => write(line));
|
|
112
|
+
return 0;
|
|
113
|
+
}
|
|
114
|
+
async function logout(args, deps) {
|
|
115
|
+
const removed = await (deps.removeConnection ?? connection_js_1.removeSecurityConnection)(connectionOptions(args, deps));
|
|
116
|
+
(deps.stdout ?? console.log)(`Removed the local Security connection for app ${removed.appId}.`);
|
|
117
|
+
return 0;
|
|
118
|
+
}
|
|
119
|
+
function runtimeMatches(required, actual) {
|
|
120
|
+
return required !== null && Object.keys(actual).every((key) => (required[key] === actual[key]));
|
|
121
|
+
}
|
|
122
|
+
function matchingEntitlements(statusResponse, inspection) {
|
|
123
|
+
return statusResponse.entitlements.filter((item) => (item.providerStatus === 'active'
|
|
124
|
+
&& item.artifactStatus === 'rights_cleared'
|
|
125
|
+
&& runtimeMatches(item.requiredRuntime, inspection.manifest.identity)));
|
|
126
|
+
}
|
|
127
|
+
function assertLocalEntitlement(statusResponse, inspection, mode) {
|
|
128
|
+
if (!statusResponse.entitledModes.includes(mode))
|
|
129
|
+
throw new Error(`Security mode ${mode} is not entitled for this app.`);
|
|
130
|
+
if (matchingEntitlements(statusResponse, inspection).filter((item) => !(mode === 'scan' && item.kind === 'security_launch')).length === 0) {
|
|
131
|
+
throw new Error('No Security entitlement matches this exact commercial runtime.');
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
function selectEntitlement(statusResponse, inspection, args, mode) {
|
|
135
|
+
if (!statusResponse.publicationEnabled)
|
|
136
|
+
throw new Error('Security publication is disabled for this app.');
|
|
137
|
+
if (!statusResponse.entitledModes.includes(mode))
|
|
138
|
+
throw new Error(`Security mode ${mode} is not entitled for this app.`);
|
|
139
|
+
const requested = uuidOption(args, '--entitlement');
|
|
140
|
+
const candidates = matchingEntitlements(statusResponse, inspection).filter((item) => (item.remainingUnits > 0 && !(mode === 'scan' && item.kind === 'security_launch')));
|
|
141
|
+
if (requested) {
|
|
142
|
+
const selected = candidates.find((item) => item.id === requested);
|
|
143
|
+
if (!selected)
|
|
144
|
+
throw new Error('The selected Security entitlement is unavailable, exhausted, or not bound to a rights-cleared runtime.');
|
|
145
|
+
return selected.id;
|
|
146
|
+
}
|
|
147
|
+
if (candidates.length !== 1) {
|
|
148
|
+
throw new Error(candidates.length === 0
|
|
149
|
+
? 'No publishable Security entitlement is available.'
|
|
150
|
+
: 'Multiple Security entitlements are available; select one with --entitlement.');
|
|
151
|
+
}
|
|
152
|
+
return candidates[0].id;
|
|
153
|
+
}
|
|
154
|
+
function exactFinishBody(report) {
|
|
155
|
+
const body = JSON.stringify({ outcome: 'completed', report });
|
|
156
|
+
if (Buffer.byteLength(body, 'utf8') > MAX_FINISH_BYTES)
|
|
157
|
+
throw new Error('Security publish request exceeds the 1 MiB wire limit.');
|
|
158
|
+
return body;
|
|
159
|
+
}
|
|
160
|
+
function syncFailureExit(localExit, error) {
|
|
161
|
+
if (localExit === 1 || localExit === 3)
|
|
162
|
+
return localExit;
|
|
163
|
+
if (error instanceof api_js_1.SecurityApiRequestError && error.status !== null && [401, 402, 403, 404, 429].includes(error.status))
|
|
164
|
+
return 3;
|
|
165
|
+
return 2;
|
|
166
|
+
}
|
|
167
|
+
function finishFailureMessage(journalId, error, pendingMessage, deps) {
|
|
168
|
+
if (!(error instanceof api_js_1.SecurityApiRequestError) || error.retryable)
|
|
169
|
+
return pendingMessage;
|
|
170
|
+
const code = boundedSecurityError(error.code, [], deps).replace(/[^a-zA-Z0-9_.-]/g, '_').slice(0, 80);
|
|
171
|
+
const status = error.status === null ? '' : ` HTTP ${error.status}`;
|
|
172
|
+
return `Security publication was refused by the service${status} (${code}): ${boundedSecurityError(error, [], deps)}. The local result and journal ${journalId} are retained.`;
|
|
173
|
+
}
|
|
174
|
+
function requiresLocalAgentReview(report) {
|
|
175
|
+
if (!report || typeof report !== 'object' || !Array.isArray(report.checks))
|
|
176
|
+
return false;
|
|
177
|
+
return report.checks.some((check) => (!!check && typeof check === 'object'
|
|
178
|
+
&& 'id' in check && check.id === 'agent-review'
|
|
179
|
+
&& 'status' in check && check.status === 'missing'
|
|
180
|
+
&& 'required' in check && check.required === true));
|
|
181
|
+
}
|
|
182
|
+
function completedReportFromSavedRequest(body) {
|
|
183
|
+
try {
|
|
184
|
+
const request = JSON.parse(body);
|
|
185
|
+
if (!request || typeof request !== 'object'
|
|
186
|
+
|| !('outcome' in request) || request.outcome !== 'completed'
|
|
187
|
+
|| !('report' in request))
|
|
188
|
+
return null;
|
|
189
|
+
return request.report;
|
|
190
|
+
}
|
|
191
|
+
catch {
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
function quoteCommandPath(path) {
|
|
196
|
+
return process.platform === 'win32'
|
|
197
|
+
? `'${path.replaceAll("'", "''")}'`
|
|
198
|
+
: `'${path.replaceAll("'", "'\\''")}'`;
|
|
199
|
+
}
|
|
200
|
+
function printLocalReviewContinuation(report, appId, repo, outDir, initialRunId, write) {
|
|
201
|
+
if (!requiresLocalAgentReview(report))
|
|
202
|
+
return;
|
|
203
|
+
const briefPath = (0, node_path_1.join)(outDir, 'agent', 'brief.md');
|
|
204
|
+
write(`VSG requires local agent review. Open ${quoteCommandPath(briefPath)} and complete the review with your chosen reviewer.`);
|
|
205
|
+
write('After review, generate a fresh report from the retained output:');
|
|
206
|
+
write(` lattice security report --app ${appId} --repo ${quoteCommandPath(repo)} --out ${quoteCommandPath(outDir)}`);
|
|
207
|
+
if (initialRunId) {
|
|
208
|
+
write(`Publish that fresh report as a retest of initial cloud run ${initialRunId}:`);
|
|
209
|
+
write(` lattice security publish --app ${appId} --repo ${quoteCommandPath(repo)} --report ${quoteCommandPath(outDir)} --parent-run ${initialRunId}`);
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
write('No initial cloud run ID is available for this local run; a parent-bound publication needs the actual initial run ID.');
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
function isSourceChangedError(error) {
|
|
216
|
+
return !!error && typeof error === 'object' && 'code' in error && error.code === 'source_changed';
|
|
217
|
+
}
|
|
218
|
+
function isJournalContentionError(error) {
|
|
219
|
+
if (!error || typeof error !== 'object')
|
|
220
|
+
return false;
|
|
221
|
+
if ('code' in error && ['ENOENT', 'EPERM', 'EACCES', 'EBUSY'].includes(String(error.code)))
|
|
222
|
+
return true;
|
|
223
|
+
if (!(error instanceof Error))
|
|
224
|
+
return false;
|
|
225
|
+
return [
|
|
226
|
+
'Security publish journal is not resumable.',
|
|
227
|
+
'Security publish journal is not awaiting begin.',
|
|
228
|
+
'Security publish journal is not awaiting acknowledgment.',
|
|
229
|
+
'Security publish journal cannot record this local result.',
|
|
230
|
+
'Security publish journal is not awaiting a finish request.',
|
|
231
|
+
].includes(error.message);
|
|
232
|
+
}
|
|
233
|
+
async function verifyCommercialRuntime(args, statusResponse, deps) {
|
|
234
|
+
const root = valueFor(args, '--artifact') ?? deps.artifactRoot ?? (0, node_path_1.join)(__dirname, '..', 'security-runtime');
|
|
235
|
+
const inspection = await (deps.inspectArtifact ?? artifact_js_1.inspectSecurityArtifact)(root);
|
|
236
|
+
try {
|
|
237
|
+
(deps.assertArtifactEligible ?? artifact_js_1.assertCommercialArtifactEligible)(inspection);
|
|
238
|
+
}
|
|
239
|
+
catch (error) {
|
|
240
|
+
const server = statusResponse.releaseBlockers.length > 0 ? ` Server blockers: ${statusResponse.releaseBlockers.join(', ')}.` : '';
|
|
241
|
+
throw new Error(`${error instanceof Error ? error.message : String(error)}${server}`);
|
|
242
|
+
}
|
|
243
|
+
return inspection;
|
|
244
|
+
}
|
|
245
|
+
async function confirmScripts(mode, args, deps) {
|
|
246
|
+
if (mode !== 'deep' && mode !== 'release')
|
|
247
|
+
return;
|
|
248
|
+
if (args.includes('--allow-project-scripts'))
|
|
249
|
+
return;
|
|
250
|
+
if (!await (deps.confirmProjectScripts ?? defaultConfirmProjectScripts)()) {
|
|
251
|
+
throw new Error(`Security ${mode} requires consent to run project scripts. Re-run interactively or pass --allow-project-scripts.`);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
function beginJournalInput(clientRequestId, connection, entitlementId, mode, parentRunId, context) {
|
|
255
|
+
return {
|
|
256
|
+
id: clientRequestId, apiUrl: connection.apiUrl, appId: connection.appId, clientRequestId,
|
|
257
|
+
entitlementId, mode, parentRunId, ...context,
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
async function cleanupAcknowledgedJournal(journal, deps) {
|
|
261
|
+
const root = deps.journalRoot ?? (0, journal_js_1.defaultSecurityJournalRoot)();
|
|
262
|
+
try {
|
|
263
|
+
await (deps.removeJournal ?? journal_js_1.removeSecurityPublishJournal)(journal.id, root);
|
|
264
|
+
}
|
|
265
|
+
catch {
|
|
266
|
+
(deps.stderr ?? console.error)(`Security cloud result was accepted; local journal cleanup remains for ${journal.id}.`);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
function sameRecoveryOwner(parent, child) {
|
|
270
|
+
return child.recoveryParentId === parent.id && child.apiUrl === parent.apiUrl && child.appId === parent.appId
|
|
271
|
+
&& child.recoveryRootId === (parent.recoveryRootId ?? parent.id)
|
|
272
|
+
&& child.artifactRoot === parent.artifactRoot && child.artifactManifestSha256 === parent.artifactManifestSha256
|
|
273
|
+
&& child.repositoryIdentity === parent.repositoryIdentity && child.repo === parent.repo && child.outDir === parent.outDir
|
|
274
|
+
&& child.entitlementId === parent.entitlementId && child.mode === parent.mode
|
|
275
|
+
&& child.parentRunId === parent.parentRunId && child.retainedCompleted && parent.retainedCompleted
|
|
276
|
+
&& child.localExit === parent.localExit && child.reportPath === parent.reportPath;
|
|
277
|
+
}
|
|
278
|
+
async function cleanupReceiptPayloads(receipt, deps) {
|
|
279
|
+
const root = deps.journalRoot ?? (0, journal_js_1.defaultSecurityJournalRoot)();
|
|
280
|
+
try {
|
|
281
|
+
for (const journalId of receipt.journalIds) {
|
|
282
|
+
await (deps.removeJournal ?? journal_js_1.removeSecurityPublishJournal)(journalId, root, true);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
catch {
|
|
286
|
+
(deps.stderr ?? console.error)(`Security cloud result was accepted; recovery journal cleanup remains for ${receipt.rootJournalId}.`);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
async function cleanupAcknowledgedRecoveryGraph(final, deps) {
|
|
290
|
+
if (final.state !== 'acknowledged' || final.recoveryParentId === null || final.recoveryRootId === null
|
|
291
|
+
|| !final.runId || final.localExit === null || final.acknowledgedExit === null) {
|
|
292
|
+
throw new Error('Security recovery acknowledgment is invalid.');
|
|
293
|
+
}
|
|
294
|
+
const root = deps.journalRoot ?? (0, journal_js_1.defaultSecurityJournalRoot)();
|
|
295
|
+
const existingReceipt = await (deps.readAcknowledgment ?? journal_js_1.readSecurityAcknowledgment)(final.recoveryRootId, root);
|
|
296
|
+
if (existingReceipt) {
|
|
297
|
+
await cleanupReceiptPayloads(existingReceipt, deps);
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
const chain = [final];
|
|
301
|
+
let child = final;
|
|
302
|
+
try {
|
|
303
|
+
while (child.recoveryParentId !== null) {
|
|
304
|
+
const parent = await (deps.readAnyJournal ?? journal_js_1.readSecurityJournal)(child.recoveryParentId, root);
|
|
305
|
+
const link = await (deps.readRecovery ?? journal_js_1.readSecurityRecovery)(parent.id, root);
|
|
306
|
+
if (!link || link.childJournalId !== child.id || !sameRecoveryOwner(parent, child)) {
|
|
307
|
+
throw new Error('Security recovery graph ownership or lineage is invalid.');
|
|
308
|
+
}
|
|
309
|
+
chain.push(parent);
|
|
310
|
+
child = parent;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
catch (error) {
|
|
314
|
+
const concurrentReceipt = await (deps.readAcknowledgment ?? journal_js_1.readSecurityAcknowledgment)(final.recoveryRootId, root);
|
|
315
|
+
if (!concurrentReceipt)
|
|
316
|
+
throw error;
|
|
317
|
+
await cleanupReceiptPayloads(concurrentReceipt, deps);
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
const rootJournal = chain.at(-1);
|
|
321
|
+
const receipt = {
|
|
322
|
+
version: 1,
|
|
323
|
+
rootJournalId: rootJournal.id,
|
|
324
|
+
finalJournalId: final.id,
|
|
325
|
+
finalRunId: final.runId,
|
|
326
|
+
journalIds: chain.map((journal) => journal.id),
|
|
327
|
+
apiUrl: final.apiUrl,
|
|
328
|
+
appId: final.appId,
|
|
329
|
+
localExit: final.acknowledgedExit,
|
|
330
|
+
acknowledgedAt: new Date().toISOString(),
|
|
331
|
+
};
|
|
332
|
+
await (deps.saveAcknowledgment ?? journal_js_1.saveSecurityAcknowledgment)(receipt, root);
|
|
333
|
+
await cleanupReceiptPayloads(receipt, deps);
|
|
334
|
+
}
|
|
335
|
+
async function finishJournal(journal, body, connection, localExit, deps) {
|
|
336
|
+
const root = deps.journalRoot ?? (0, journal_js_1.defaultSecurityJournalRoot)();
|
|
337
|
+
const pending = await (deps.setJournalRequest ?? journal_js_1.setSecurityPublishJournalRequest)({
|
|
338
|
+
...journal,
|
|
339
|
+
acknowledgedExit: localExit,
|
|
340
|
+
}, body, root);
|
|
341
|
+
if (!pending.runId)
|
|
342
|
+
throw new Error('Security publish journal has no reserved run.');
|
|
343
|
+
if (pending.state === 'acknowledged') {
|
|
344
|
+
if (pending.recoveryParentId === null)
|
|
345
|
+
await cleanupAcknowledgedJournal(pending, deps);
|
|
346
|
+
else
|
|
347
|
+
await cleanupAcknowledgedRecoveryGraph(pending, deps);
|
|
348
|
+
return { exitCode: pending.acknowledgedExit ?? localExit, synchronized: true };
|
|
349
|
+
}
|
|
350
|
+
try {
|
|
351
|
+
await (deps.finishRun ?? api_js_1.finishSecurityRun)(connection, pending.runId, body);
|
|
352
|
+
}
|
|
353
|
+
catch (error) {
|
|
354
|
+
(deps.stderr ?? console.error)(finishFailureMessage(pending.id, error, `Security result is local; cloud sync is pending for app ${pending.appId} in journal ${pending.id}. Retry the exact saved request with lattice security publish --app ${pending.appId} --journal ${pending.id}. This replays the immutable request and does not include agent-review findings added afterward.`, deps));
|
|
355
|
+
return { exitCode: syncFailureExit(localExit, error), synchronized: false };
|
|
356
|
+
}
|
|
357
|
+
let acknowledged;
|
|
358
|
+
try {
|
|
359
|
+
acknowledged = await (deps.markJournalAcknowledged ?? journal_js_1.markSecurityJournalAcknowledged)(pending, root);
|
|
360
|
+
}
|
|
361
|
+
catch {
|
|
362
|
+
(deps.stderr ?? console.error)(`Security cloud result was accepted; local acknowledgment could not be recorded for journal ${pending.id}.`);
|
|
363
|
+
return { exitCode: localExit, synchronized: true };
|
|
364
|
+
}
|
|
365
|
+
if (acknowledged.recoveryParentId === null)
|
|
366
|
+
await cleanupAcknowledgedJournal(acknowledged, deps);
|
|
367
|
+
else
|
|
368
|
+
await cleanupAcknowledgedRecoveryGraph(acknowledged, deps);
|
|
369
|
+
return { exitCode: localExit, synchronized: true };
|
|
370
|
+
}
|
|
371
|
+
async function abortReservedRunResult(journal, connection, reason, deps, localExit = 2) {
|
|
372
|
+
return finishJournal(journal, JSON.stringify({ outcome: 'aborted', reason }), connection, localExit, deps);
|
|
373
|
+
}
|
|
374
|
+
async function abortReservedRun(journal, connection, reason, deps, localExit = 2) {
|
|
375
|
+
return (await abortReservedRunResult(journal, connection, reason, deps, localExit)).exitCode;
|
|
376
|
+
}
|
|
377
|
+
function reservationExpired(journal) {
|
|
378
|
+
return journal.reservationExpiresAt !== null && Date.parse(journal.reservationExpiresAt) <= Date.now();
|
|
379
|
+
}
|
|
380
|
+
function expiredLeaseError(error) {
|
|
381
|
+
return error instanceof api_js_1.SecurityApiRequestError
|
|
382
|
+
&& (error.status === 409 || error.status === 410)
|
|
383
|
+
&& /expired|lease|reservation/i.test(error.code);
|
|
384
|
+
}
|
|
385
|
+
async function exportRetainedJournal(journal, inspection, runId, writeLocalReport, deps) {
|
|
386
|
+
return (deps.exportReport ?? runtime_js_1.exportSecurityReport)({
|
|
387
|
+
inspection,
|
|
388
|
+
repo: journal.repo,
|
|
389
|
+
outDir: journal.outDir,
|
|
390
|
+
runId,
|
|
391
|
+
mode: journal.mode,
|
|
392
|
+
repositoryIdentity: journal.repositoryIdentity,
|
|
393
|
+
writeLocalReport,
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
async function completedRecoveryExit(journal, connection, deps) {
|
|
397
|
+
const root = deps.journalRoot ?? (0, journal_js_1.defaultSecurityJournalRoot)();
|
|
398
|
+
const recoveryRootId = journal.recoveryRootId ?? journal.id;
|
|
399
|
+
const receipt = await (deps.readAcknowledgment ?? journal_js_1.readSecurityAcknowledgment)(recoveryRootId, root);
|
|
400
|
+
if (!receipt)
|
|
401
|
+
return null;
|
|
402
|
+
if (receipt.apiUrl !== connection.apiUrl || receipt.appId !== connection.appId
|
|
403
|
+
|| !receipt.journalIds.some((journalId) => journalId.toLowerCase() === journal.id.toLowerCase())) {
|
|
404
|
+
throw new Error('Security acknowledgment receipt belongs to a different app connection or recovery lineage.');
|
|
405
|
+
}
|
|
406
|
+
await cleanupReceiptPayloads(receipt, deps);
|
|
407
|
+
return receipt.localExit;
|
|
408
|
+
}
|
|
409
|
+
async function recoverExpiredJournal(parent, connection, deps) {
|
|
410
|
+
if (!parent.retainedCompleted || parent.localExit === null || !parent.reportPath) {
|
|
411
|
+
throw new Error(`Security journal ${parent.id} has no completed retained result to recover; run the scan again.`);
|
|
412
|
+
}
|
|
413
|
+
const completedExit = await completedRecoveryExit(parent, connection, deps);
|
|
414
|
+
if (completedExit !== null)
|
|
415
|
+
return { exitCode: completedExit, synchronized: true };
|
|
416
|
+
const root = deps.journalRoot ?? (0, journal_js_1.defaultSecurityJournalRoot)();
|
|
417
|
+
const existingRecovery = await (deps.readRecovery ?? journal_js_1.readSecurityRecovery)(parent.id, root);
|
|
418
|
+
let child = null;
|
|
419
|
+
if (existingRecovery) {
|
|
420
|
+
child = await (deps.readAnyJournal ?? journal_js_1.readSecurityJournal)(existingRecovery.childJournalId, root);
|
|
421
|
+
if (!sameRecoveryOwner(parent, child))
|
|
422
|
+
throw new Error('Security recovery journal does not match its parent.');
|
|
423
|
+
if (child.state !== 'begin_pending')
|
|
424
|
+
return resumeJournal(child, connection, deps);
|
|
425
|
+
}
|
|
426
|
+
const statusResponse = await (deps.getStatus ?? api_js_1.getSecurityStatus)(connection);
|
|
427
|
+
if (statusResponse.app.repositoryIdentity !== parent.repositoryIdentity) {
|
|
428
|
+
throw new Error('Security journal repository identity no longer matches this app.');
|
|
429
|
+
}
|
|
430
|
+
const inspection = await (deps.inspectArtifact ?? artifact_js_1.inspectSecurityArtifact)(parent.artifactRoot);
|
|
431
|
+
(deps.assertArtifactEligible ?? artifact_js_1.assertCommercialArtifactEligible)(inspection);
|
|
432
|
+
if (inspection.manifestSha256 !== parent.artifactManifestSha256) {
|
|
433
|
+
throw new Error('Security journal requires a different commercial artifact.');
|
|
434
|
+
}
|
|
435
|
+
selectEntitlement(statusResponse, inspection, ['--entitlement', parent.entitlementId], parent.mode);
|
|
436
|
+
await exportRetainedJournal(parent, inspection, (0, node_crypto_1.randomUUID)(), false, deps);
|
|
437
|
+
const preCreateExit = await completedRecoveryExit(parent, connection, deps);
|
|
438
|
+
if (preCreateExit !== null)
|
|
439
|
+
return { exitCode: preCreateExit, synchronized: true };
|
|
440
|
+
if (!child) {
|
|
441
|
+
const recovery = await (deps.createOrReadRecovery ?? journal_js_1.createOrReadSecurityRecovery)(parent.id, root);
|
|
442
|
+
try {
|
|
443
|
+
child = await (deps.readAnyJournal ?? journal_js_1.readSecurityJournal)(recovery.childJournalId, root);
|
|
444
|
+
}
|
|
445
|
+
catch (error) {
|
|
446
|
+
if (!(error && typeof error === 'object' && 'code' in error && error.code === 'ENOENT'))
|
|
447
|
+
throw error;
|
|
448
|
+
try {
|
|
449
|
+
child = await (deps.createBeginJournal ?? journal_js_1.createSecurityBeginJournal)(beginJournalInput(recovery.childJournalId, connection, parent.entitlementId, parent.mode, parent.parentRunId, {
|
|
450
|
+
recoveryParentId: parent.id,
|
|
451
|
+
recoveryRootId: parent.recoveryRootId ?? parent.id,
|
|
452
|
+
repo: parent.repo,
|
|
453
|
+
outDir: parent.outDir,
|
|
454
|
+
artifactRoot: parent.artifactRoot,
|
|
455
|
+
artifactManifestSha256: parent.artifactManifestSha256,
|
|
456
|
+
repositoryIdentity: parent.repositoryIdentity,
|
|
457
|
+
retainedCompleted: true,
|
|
458
|
+
localExit: parent.localExit,
|
|
459
|
+
acknowledgedExit: null,
|
|
460
|
+
reportPath: parent.reportPath,
|
|
461
|
+
}), root);
|
|
462
|
+
}
|
|
463
|
+
catch (createError) {
|
|
464
|
+
if (!(createError instanceof Error && /already exists/.test(createError.message)))
|
|
465
|
+
throw createError;
|
|
466
|
+
child = await (deps.readAnyJournal ?? journal_js_1.readSecurityJournal)(recovery.childJournalId, root);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
if (!sameRecoveryOwner(parent, child)) {
|
|
471
|
+
throw new Error('Security recovery journal does not match its parent.');
|
|
472
|
+
}
|
|
473
|
+
const preResumeExit = await completedRecoveryExit(child, connection, deps);
|
|
474
|
+
if (preResumeExit !== null)
|
|
475
|
+
return { exitCode: preResumeExit, synchronized: true };
|
|
476
|
+
return resumeJournal(child, connection, deps, inspection);
|
|
477
|
+
}
|
|
478
|
+
async function resumeJournal(initial, connection, deps, knownInspection) {
|
|
479
|
+
const root = deps.journalRoot ?? (0, journal_js_1.defaultSecurityJournalRoot)();
|
|
480
|
+
let journal = initial;
|
|
481
|
+
if (journal.state === 'acknowledged') {
|
|
482
|
+
if (journal.recoveryParentId === null)
|
|
483
|
+
await cleanupAcknowledgedJournal(journal, deps);
|
|
484
|
+
else
|
|
485
|
+
await cleanupAcknowledgedRecoveryGraph(journal, deps);
|
|
486
|
+
(deps.stdout ?? console.log)(`Security publish journal ${journal.id} is already synchronized.`);
|
|
487
|
+
return { exitCode: journal.acknowledgedExit ?? journal.localExit ?? 0, synchronized: true };
|
|
488
|
+
}
|
|
489
|
+
if (journal.state === 'pending_finish') {
|
|
490
|
+
if (reservationExpired(journal))
|
|
491
|
+
return recoverExpiredJournal(journal, connection, deps);
|
|
492
|
+
const retained = await (deps.readJournal ?? journal_js_1.readSecurityPublishJournal)(journal.id, root);
|
|
493
|
+
if (!retained.journal.runId)
|
|
494
|
+
throw new Error('Security publish journal has no reserved run.');
|
|
495
|
+
try {
|
|
496
|
+
await (deps.finishRun ?? api_js_1.finishSecurityRun)(connection, retained.journal.runId, retained.exactRequestBody);
|
|
497
|
+
}
|
|
498
|
+
catch (error) {
|
|
499
|
+
if (expiredLeaseError(error))
|
|
500
|
+
return recoverExpiredJournal(retained.journal, connection, deps);
|
|
501
|
+
(deps.stderr ?? console.error)(finishFailureMessage(journal.id, error, `Security cloud sync remains pending for app ${retained.journal.appId} in journal ${journal.id}. Retry the exact saved request with lattice security publish --app ${retained.journal.appId} --journal ${journal.id}. This replays the immutable request and does not include agent-review findings added afterward.`, deps));
|
|
502
|
+
return {
|
|
503
|
+
exitCode: syncFailureExit(retained.journal.acknowledgedExit ?? retained.journal.localExit ?? 0, error),
|
|
504
|
+
synchronized: false,
|
|
505
|
+
};
|
|
506
|
+
}
|
|
507
|
+
const acknowledged = await (deps.markJournalAcknowledged ?? journal_js_1.markSecurityJournalAcknowledged)(retained.journal, root);
|
|
508
|
+
if (acknowledged.recoveryParentId === null)
|
|
509
|
+
await cleanupAcknowledgedJournal(acknowledged, deps);
|
|
510
|
+
else
|
|
511
|
+
await cleanupAcknowledgedRecoveryGraph(acknowledged, deps);
|
|
512
|
+
(deps.stdout ?? console.log)(`Security publish journal ${journal.id} synchronized.`);
|
|
513
|
+
if (retained.journal.mode === 'deep' || retained.journal.mode === 'release') {
|
|
514
|
+
printLocalReviewContinuation(completedReportFromSavedRequest(retained.exactRequestBody), retained.journal.appId, retained.journal.repo, retained.journal.outDir, retained.journal.runId, deps.stdout ?? console.log);
|
|
515
|
+
}
|
|
516
|
+
return { exitCode: journal.acknowledgedExit ?? journal.localExit ?? 0, synchronized: true };
|
|
517
|
+
}
|
|
518
|
+
if (journal.state === 'begin_pending') {
|
|
519
|
+
const begin = await (deps.beginRun ?? api_js_1.beginSecurityRun)(connection, {
|
|
520
|
+
clientRequestId: journal.clientRequestId,
|
|
521
|
+
entitlementId: journal.entitlementId,
|
|
522
|
+
mode: journal.mode,
|
|
523
|
+
parentRunId: journal.parentRunId,
|
|
524
|
+
});
|
|
525
|
+
if (begin.state === 'expired') {
|
|
526
|
+
if (journal.retainedCompleted)
|
|
527
|
+
return recoverExpiredJournal(journal, connection, deps);
|
|
528
|
+
throw new Error(`Security journal ${journal.id} expired before a completed result was retained; run the scan again.`);
|
|
529
|
+
}
|
|
530
|
+
if (begin.state !== 'reserved')
|
|
531
|
+
throw new Error(`Security journal ${journal.id} cannot resume from server state ${begin.state}.`);
|
|
532
|
+
journal = await (deps.setJournalReservation ?? journal_js_1.setSecurityJournalReservation)(journal, begin, root);
|
|
533
|
+
}
|
|
534
|
+
if (!['reserved', 'result_ready'].includes(journal.state))
|
|
535
|
+
throw new Error('Security publish journal is not resumable.');
|
|
536
|
+
if (reservationExpired(journal)) {
|
|
537
|
+
if (journal.retainedCompleted)
|
|
538
|
+
return recoverExpiredJournal(journal, connection, deps);
|
|
539
|
+
throw new Error(`Security journal ${journal.id} expired before a completed result was retained; run the scan again.`);
|
|
540
|
+
}
|
|
541
|
+
if (!journal.retainedCompleted || journal.localExit === null || !journal.reportPath) {
|
|
542
|
+
throw new Error(`Security journal ${journal.id} has no completed retained result to resume; run the scan again.`);
|
|
543
|
+
}
|
|
544
|
+
const localExit = journal.localExit;
|
|
545
|
+
const inspection = knownInspection ?? await (deps.inspectArtifact ?? artifact_js_1.inspectSecurityArtifact)(journal.artifactRoot);
|
|
546
|
+
(deps.assertArtifactEligible ?? artifact_js_1.assertCommercialArtifactEligible)(inspection);
|
|
547
|
+
if (inspection.manifestSha256 !== journal.artifactManifestSha256 || !journal.runId) {
|
|
548
|
+
throw new Error('Security recovery journal requires a different commercial artifact.');
|
|
549
|
+
}
|
|
550
|
+
let exported;
|
|
551
|
+
try {
|
|
552
|
+
exported = await exportRetainedJournal(journal, inspection, journal.runId, true, deps);
|
|
553
|
+
}
|
|
554
|
+
catch (error) {
|
|
555
|
+
const reason = isSourceChangedError(error) ? 'source_changed' : 'publisher_failed';
|
|
556
|
+
const abortResult = await abortReservedRunResult(journal, connection, reason, deps, localExit === 1 ? 1 : 2);
|
|
557
|
+
(deps.stderr ?? console.error)(`Security retained report export failed: ${boundedSecurityError(error, [], deps)}`);
|
|
558
|
+
return abortResult;
|
|
559
|
+
}
|
|
560
|
+
if (journal.state === 'reserved') {
|
|
561
|
+
journal = await (deps.setJournalResult ?? journal_js_1.setSecurityJournalResult)(journal, {
|
|
562
|
+
reportPath: exported.reportPath,
|
|
563
|
+
localExit,
|
|
564
|
+
}, root);
|
|
565
|
+
}
|
|
566
|
+
else {
|
|
567
|
+
journal = { ...journal, reportPath: exported.reportPath };
|
|
568
|
+
}
|
|
569
|
+
if (journal.state === 'pending_finish' || journal.state === 'acknowledged') {
|
|
570
|
+
return resumeJournal(journal, connection, deps, inspection);
|
|
571
|
+
}
|
|
572
|
+
const result = await finishJournal(journal, exactFinishBody(exported.compactReport), connection, localExit, deps);
|
|
573
|
+
if (result.synchronized)
|
|
574
|
+
(deps.stdout ?? console.log)(`Security publish journal ${journal.id} synchronized.`);
|
|
575
|
+
return result;
|
|
576
|
+
}
|
|
577
|
+
async function retryJournal(args, connection, deps) {
|
|
578
|
+
const id = uuidOption(args, '--journal');
|
|
579
|
+
if (!id)
|
|
580
|
+
throw new Error('security publish --journal requires a journal UUID.');
|
|
581
|
+
const root = deps.journalRoot ?? (0, journal_js_1.defaultSecurityJournalRoot)();
|
|
582
|
+
const readReceipt = deps.readAcknowledgment ?? journal_js_1.readSecurityAcknowledgment;
|
|
583
|
+
const finishFromReceipt = async (receipt, requestedId) => {
|
|
584
|
+
if (receipt.apiUrl !== connection.apiUrl || receipt.appId !== connection.appId
|
|
585
|
+
|| !receipt.journalIds.some((journalId) => journalId.toLowerCase() === requestedId.toLowerCase())) {
|
|
586
|
+
throw new Error('Security acknowledgment receipt belongs to a different app connection or recovery lineage.');
|
|
587
|
+
}
|
|
588
|
+
await cleanupReceiptPayloads(receipt, deps);
|
|
589
|
+
(deps.stdout ?? console.log)(`Security publish journal ${requestedId} is already synchronized.`);
|
|
590
|
+
return receipt.localExit;
|
|
591
|
+
};
|
|
592
|
+
const existingReceipt = await readReceipt(id, root);
|
|
593
|
+
if (existingReceipt)
|
|
594
|
+
return finishFromReceipt(existingReceipt, id);
|
|
595
|
+
let initial;
|
|
596
|
+
try {
|
|
597
|
+
initial = await (deps.readAnyJournal ?? journal_js_1.readSecurityJournal)(id, root);
|
|
598
|
+
}
|
|
599
|
+
catch (error) {
|
|
600
|
+
const concurrentReceipt = await readReceipt(id, root);
|
|
601
|
+
if (!concurrentReceipt)
|
|
602
|
+
throw error;
|
|
603
|
+
return finishFromReceipt(concurrentReceipt, id);
|
|
604
|
+
}
|
|
605
|
+
const recoveryRootId = initial.recoveryRootId ?? initial.id;
|
|
606
|
+
const concurrentReceipt = await readReceipt(recoveryRootId, root);
|
|
607
|
+
if (concurrentReceipt)
|
|
608
|
+
return finishFromReceipt(concurrentReceipt, id);
|
|
609
|
+
if (initial.apiUrl !== connection.apiUrl || initial.appId !== connection.appId) {
|
|
610
|
+
throw new Error('Security publish journal belongs to a different app connection.');
|
|
611
|
+
}
|
|
612
|
+
const requiresRecoveryReceipt = initial.recoveryRootId !== null
|
|
613
|
+
|| (initial.retainedCompleted && reservationExpired(initial));
|
|
614
|
+
for (let attempt = 0;; attempt += 1) {
|
|
615
|
+
const terminalReceipt = await readReceipt(recoveryRootId, root);
|
|
616
|
+
if (terminalReceipt)
|
|
617
|
+
return finishFromReceipt(terminalReceipt, id);
|
|
618
|
+
try {
|
|
619
|
+
const result = await resumeJournal(initial, connection, deps);
|
|
620
|
+
if (!requiresRecoveryReceipt || !result.synchronized)
|
|
621
|
+
return result.exitCode;
|
|
622
|
+
const receiptAfterResume = await readReceipt(recoveryRootId, root);
|
|
623
|
+
if (receiptAfterResume)
|
|
624
|
+
return finishFromReceipt(receiptAfterResume, id);
|
|
625
|
+
if (attempt >= 49)
|
|
626
|
+
throw new Error('Security recovery acknowledgment was not recorded; retry this journal.');
|
|
627
|
+
}
|
|
628
|
+
catch (error) {
|
|
629
|
+
if (!isJournalContentionError(error))
|
|
630
|
+
throw error;
|
|
631
|
+
const receiptAfterFailure = await readReceipt(recoveryRootId, root);
|
|
632
|
+
if (receiptAfterFailure)
|
|
633
|
+
return finishFromReceipt(receiptAfterFailure, id);
|
|
634
|
+
if (attempt >= 49)
|
|
635
|
+
throw error;
|
|
636
|
+
}
|
|
637
|
+
await new Promise((resolveDelay) => setTimeout(resolveDelay, 10));
|
|
638
|
+
initial = await (deps.readAnyJournal ?? journal_js_1.readSecurityJournal)(id, root).catch(() => initial);
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
async function executeCommercialCommand(command, args, deps) {
|
|
642
|
+
for (const flag of ['--fix', '--install-hook', '--allowlist'])
|
|
643
|
+
if (args.includes(flag))
|
|
644
|
+
throw new Error(`${flag} cannot be combined with the paid VSG adapter.`);
|
|
645
|
+
const connection = await (deps.resolveConnection ?? connection_js_1.resolveSecurityConnection)(connectionOptions(args, deps));
|
|
646
|
+
if (command === 'publish' && args.includes('--journal'))
|
|
647
|
+
return retryJournal(args, connection, deps);
|
|
648
|
+
const statusResponse = await (deps.getStatus ?? api_js_1.getSecurityStatus)(connection);
|
|
649
|
+
const inspection = await verifyCommercialRuntime(args, statusResponse, deps);
|
|
650
|
+
const retainedReport = command === 'publish' ? valueFor(args, '--report') : undefined;
|
|
651
|
+
const mode = retainedReport ? 'report' : command;
|
|
652
|
+
if (!['scan', 'deep', 'release', 'report'].includes(mode))
|
|
653
|
+
throw new Error('security publish requires --report or --journal.');
|
|
654
|
+
await confirmScripts(mode, args, deps);
|
|
655
|
+
const publish = command === 'publish' || args.includes('--publish');
|
|
656
|
+
const parentRunId = uuidOption(args, '--parent-run') ?? null;
|
|
657
|
+
if (mode === 'report' && publish && !parentRunId)
|
|
658
|
+
throw new Error('Published report retests require --parent-run <uuid>.');
|
|
659
|
+
const repo = (0, node_path_1.resolve)(deps.cwd ?? process.cwd(), valueFor(args, '--repo') ?? '.');
|
|
660
|
+
const runtimeOptions = {
|
|
661
|
+
inspection, repo, mode,
|
|
662
|
+
repositoryIdentity: statusResponse.app.repositoryIdentity,
|
|
663
|
+
validateCredentials: args.includes('--validate-credentials'),
|
|
664
|
+
releaseUrl: valueFor(args, '--url'), base: valueFor(args, '--base'), compare: valueFor(args, '--compare'),
|
|
665
|
+
};
|
|
666
|
+
const retainedOutDir = retainedReport ? (0, node_path_1.resolve)(repo, retainedReport) : null;
|
|
667
|
+
if (!publish) {
|
|
668
|
+
assertLocalEntitlement(statusResponse, inspection, mode);
|
|
669
|
+
const runId = (0, node_crypto_1.randomUUID)();
|
|
670
|
+
const outDir = (0, node_path_1.resolve)(repo, valueFor(args, '--out') ?? (0, node_path_1.join)('.vsg', 'security', runId));
|
|
671
|
+
let result;
|
|
672
|
+
try {
|
|
673
|
+
result = await (deps.runRuntime ?? runtime_js_1.runSecurityRuntime)({ ...runtimeOptions, outDir, runId });
|
|
674
|
+
}
|
|
675
|
+
catch (error) {
|
|
676
|
+
(deps.stderr ?? console.error)(`Security scanner failed: ${boundedSecurityError(error, args, deps)}`);
|
|
677
|
+
return 2;
|
|
678
|
+
}
|
|
679
|
+
const write = deps.stdout ?? console.log;
|
|
680
|
+
if (result.reportPath)
|
|
681
|
+
write(`Security result retained locally at ${result.reportPath}.`);
|
|
682
|
+
if (mode === 'deep' || mode === 'release') {
|
|
683
|
+
printLocalReviewContinuation(result.report, connection.appId, repo, outDir, null, write);
|
|
684
|
+
}
|
|
685
|
+
return result.exitCode;
|
|
686
|
+
}
|
|
687
|
+
let retainedReportPath = null;
|
|
688
|
+
if (retainedOutDir) {
|
|
689
|
+
const preflight = await (deps.exportReport ?? runtime_js_1.exportSecurityReport)({
|
|
690
|
+
...runtimeOptions,
|
|
691
|
+
outDir: retainedOutDir,
|
|
692
|
+
runId: (0, node_crypto_1.randomUUID)(),
|
|
693
|
+
writeLocalReport: false,
|
|
694
|
+
});
|
|
695
|
+
retainedReportPath = preflight.reportPath;
|
|
696
|
+
}
|
|
697
|
+
const entitlementId = selectEntitlement(statusResponse, inspection, args, mode);
|
|
698
|
+
const clientRequestId = (0, node_crypto_1.randomUUID)();
|
|
699
|
+
const outDir = retainedOutDir ?? (0, node_path_1.resolve)(repo, valueFor(args, '--out') ?? (0, node_path_1.join)('.vsg', 'security', clientRequestId));
|
|
700
|
+
const journalRoot = deps.journalRoot ?? (0, journal_js_1.defaultSecurityJournalRoot)();
|
|
701
|
+
let journal = await (deps.createBeginJournal ?? journal_js_1.createSecurityBeginJournal)(beginJournalInput(clientRequestId, connection, entitlementId, mode, parentRunId, {
|
|
702
|
+
recoveryParentId: null,
|
|
703
|
+
recoveryRootId: null,
|
|
704
|
+
repo,
|
|
705
|
+
outDir,
|
|
706
|
+
artifactRoot: inspection.artifactRoot,
|
|
707
|
+
artifactManifestSha256: inspection.manifestSha256,
|
|
708
|
+
repositoryIdentity: statusResponse.app.repositoryIdentity,
|
|
709
|
+
retainedCompleted: retainedOutDir !== null,
|
|
710
|
+
localExit: retainedOutDir ? 0 : null,
|
|
711
|
+
acknowledgedExit: null,
|
|
712
|
+
reportPath: retainedReportPath,
|
|
713
|
+
}), journalRoot);
|
|
714
|
+
let begin;
|
|
715
|
+
try {
|
|
716
|
+
begin = await (deps.beginRun ?? api_js_1.beginSecurityRun)(connection, { clientRequestId, entitlementId, mode, parentRunId });
|
|
717
|
+
}
|
|
718
|
+
catch (error) {
|
|
719
|
+
if (error instanceof api_js_1.SecurityApiRequestError && error.status !== null && error.status !== 409 && error.status < 500) {
|
|
720
|
+
await (deps.removeJournal ?? journal_js_1.removeSecurityPublishJournal)(journal.id, journalRoot);
|
|
721
|
+
}
|
|
722
|
+
else {
|
|
723
|
+
(deps.stderr ?? console.error)(`Security begin is pending in journal ${journal.id}; retry with security publish --journal ${journal.id}.`);
|
|
724
|
+
}
|
|
725
|
+
return syncFailureExit(0, error);
|
|
726
|
+
}
|
|
727
|
+
if (begin.state !== 'reserved') {
|
|
728
|
+
(deps.stderr ?? console.error)(`Security begin returned ${begin.state}; journal ${journal.id} cannot continue without a new completed local result.`);
|
|
729
|
+
return 3;
|
|
730
|
+
}
|
|
731
|
+
journal = await (deps.setJournalReservation ?? journal_js_1.setSecurityJournalReservation)(journal, begin, journalRoot);
|
|
732
|
+
let report = null;
|
|
733
|
+
try {
|
|
734
|
+
let compactReport;
|
|
735
|
+
let reportPath;
|
|
736
|
+
let localExit = 0;
|
|
737
|
+
if (retainedOutDir) {
|
|
738
|
+
const exported = await (deps.exportReport ?? runtime_js_1.exportSecurityReport)({
|
|
739
|
+
...runtimeOptions,
|
|
740
|
+
outDir: retainedOutDir,
|
|
741
|
+
runId: begin.runId,
|
|
742
|
+
writeLocalReport: true,
|
|
743
|
+
});
|
|
744
|
+
compactReport = exported.compactReport;
|
|
745
|
+
reportPath = exported.reportPath;
|
|
746
|
+
}
|
|
747
|
+
else {
|
|
748
|
+
const result = await (deps.runRuntime ?? runtime_js_1.runSecurityRuntime)({ ...runtimeOptions, outDir, runId: begin.runId });
|
|
749
|
+
localExit = result.exitCode;
|
|
750
|
+
if (!result.compactReport || !result.reportPath)
|
|
751
|
+
return abortReservedRun(journal, connection, 'scanner_failed', deps, result.exitCode);
|
|
752
|
+
compactReport = result.compactReport;
|
|
753
|
+
reportPath = result.reportPath;
|
|
754
|
+
report = result.report;
|
|
755
|
+
}
|
|
756
|
+
journal = await (deps.setJournalResult ?? journal_js_1.setSecurityJournalResult)(journal, { reportPath, localExit }, journalRoot);
|
|
757
|
+
const finish = await finishJournal(journal, exactFinishBody(compactReport), connection, localExit, deps);
|
|
758
|
+
if (finish.synchronized)
|
|
759
|
+
(deps.stdout ?? console.log)(`Security result published from ${reportPath}.`);
|
|
760
|
+
if (finish.synchronized && (mode === 'deep' || mode === 'release')) {
|
|
761
|
+
printLocalReviewContinuation(report, connection.appId, repo, outDir, begin.runId, deps.stdout ?? console.log);
|
|
762
|
+
}
|
|
763
|
+
return finish.exitCode;
|
|
764
|
+
}
|
|
765
|
+
catch (error) {
|
|
766
|
+
const reason = isSourceChangedError(error) ? 'source_changed' : retainedOutDir ? 'publisher_failed' : 'scanner_failed';
|
|
767
|
+
const abortExit = await abortReservedRun(journal, connection, reason, deps);
|
|
768
|
+
(deps.stderr ?? console.error)(`Security scanner/export failed: ${boundedSecurityError(error, args, deps)}`);
|
|
769
|
+
return abortExit;
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
async function runSecurityCommandImpl(args, deps) {
|
|
773
|
+
const command = args[0];
|
|
774
|
+
const rest = args.slice(1);
|
|
775
|
+
if (!command || command === 'help' || command === '--help' || command === '-h') {
|
|
776
|
+
printSecurityHelp(deps.stdout ?? console.log);
|
|
777
|
+
return 0;
|
|
778
|
+
}
|
|
779
|
+
if (command === 'connect')
|
|
780
|
+
return connect(rest, deps);
|
|
781
|
+
if (command === 'status')
|
|
782
|
+
return status(rest, deps);
|
|
783
|
+
if (command === 'logout')
|
|
784
|
+
return logout(rest, deps);
|
|
785
|
+
if (RUN_COMMANDS.has(command))
|
|
786
|
+
return executeCommercialCommand(command, rest, deps);
|
|
787
|
+
throw new Error(`Unknown Security command: ${command}. Run "lattice security help" for usage.`);
|
|
788
|
+
}
|
|
789
|
+
function forbiddenTokenArgument(args) {
|
|
790
|
+
return args.some((value) => value === '--token' || value.startsWith('--token='));
|
|
791
|
+
}
|
|
792
|
+
function boundedSecurityError(error, args, deps) {
|
|
793
|
+
let message = error instanceof Error ? error.message : String(error);
|
|
794
|
+
const secrets = [
|
|
795
|
+
deps.env?.LATTICE_SECURITY_TOKEN,
|
|
796
|
+
...args.flatMap((value, index) => {
|
|
797
|
+
if (value === '--token')
|
|
798
|
+
return args[index + 1] ? [args[index + 1]] : [];
|
|
799
|
+
if (value.startsWith('--token='))
|
|
800
|
+
return [value.slice('--token='.length)];
|
|
801
|
+
return [];
|
|
802
|
+
}),
|
|
803
|
+
].filter((value) => !!value);
|
|
804
|
+
for (const secret of secrets)
|
|
805
|
+
message = message.split(secret).join('[REDACTED]');
|
|
806
|
+
return message.slice(0, 2_000);
|
|
807
|
+
}
|
|
808
|
+
async function runSecurityCommand(args, deps = {}) {
|
|
809
|
+
const writeError = deps.stderr ?? console.error;
|
|
810
|
+
if (forbiddenTokenArgument(args)) {
|
|
811
|
+
writeError('Security error: --token is forbidden because command arguments can be logged. Use the masked prompt or LATTICE_SECURITY_TOKEN.');
|
|
812
|
+
return 3;
|
|
813
|
+
}
|
|
814
|
+
try {
|
|
815
|
+
return await runSecurityCommandImpl(args, deps);
|
|
816
|
+
}
|
|
817
|
+
catch (error) {
|
|
818
|
+
writeError(`Security error: ${boundedSecurityError(error, args, deps)}`);
|
|
819
|
+
return 3;
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
function isSecurityRunMode(value) {
|
|
823
|
+
return value === 'scan' || value === 'deep' || value === 'release' || value === 'report';
|
|
824
|
+
}
|
|
825
|
+
//# sourceMappingURL=commands.js.map
|