forgeos 0.1.0-alpha.4 → 0.1.0-alpha.40
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/.npmignore +10 -0
- package/AGENTS.md +142 -90
- package/CHANGELOG.md +418 -0
- package/LICENSE +21 -0
- package/README.md +67 -8
- package/adapters/go/README.md +23 -0
- package/adapters/go/go.mod +3 -0
- package/adapters/go/http.go +149 -0
- package/adapters/go/registry.go +234 -0
- package/adapters/go/types.go +136 -0
- package/adapters/java/README.md +68 -0
- package/adapters/java/pom.xml +34 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/Auth.java +20 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/Diagnostic.java +16 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/Entry.java +38 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/EntryKind.java +16 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/ErrorInfo.java +4 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/Forge.java +94 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeCall.java +12 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeContext.java +11 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeHandler.java +8 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeHttpHandler.java +179 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeRegistry.java +121 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/Json.java +14 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/Manifest.java +14 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/RequestEnvelope.java +6 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/ResponseEnvelope.java +25 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/Risk.java +18 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/Schemas.java +36 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/Service.java +65 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/TransactionMode.java +18 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/TypedForgeHandler.java +6 -0
- package/adapters/java-spring-boot-starter/README.md +32 -0
- package/adapters/java-spring-boot-starter/pom.xml +36 -0
- package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeCommand.java +22 -0
- package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeExternalService.java +15 -0
- package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeQuery.java +16 -0
- package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeServiceBeanCondition.java +18 -0
- package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeSpringAutoConfiguration.java +16 -0
- package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeSpringRuntime.java +104 -0
- package/adapters/java-spring-boot-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +1 -0
- package/bin/forge.mjs +18 -0
- package/docs/cair-protocol.md +103 -0
- package/docs/changelog.md +534 -0
- package/docs/forge-protocol.md +189 -0
- package/examples/go-billing/go.mod +7 -0
- package/examples/go-billing/main.go +120 -0
- package/examples/java-billing/pom.xml +52 -0
- package/examples/java-billing/src/main/java/dev/forgeos/examples/billing/CreateInvoiceInput.java +4 -0
- package/examples/java-billing/src/main/java/dev/forgeos/examples/billing/Invoice.java +11 -0
- package/examples/java-billing/src/main/java/dev/forgeos/examples/billing/Main.java +127 -0
- package/package.json +31 -3
- package/schemas/forge-manifest.schema.json +57 -0
- package/src/forge/_generated/releaseManifest.json +1 -2
- package/src/forge/_generated/releaseManifest.ts +3 -3
- package/src/forge/agent-adapters/index.ts +1584 -125
- package/src/forge/agent-adapters/types.ts +224 -1
- package/src/forge/agent-memory/bridge.ts +1333 -0
- package/src/forge/agent-memory/context-pack.ts +277 -0
- package/src/forge/agent-memory/hook-runner.ts +312 -0
- package/src/forge/agent-memory/mcp.ts +224 -0
- package/src/forge/agent-memory/normalize.ts +498 -0
- package/src/forge/agent-memory/redaction.ts +103 -0
- package/src/forge/agent-memory/sources/claude-code.ts +51 -0
- package/src/forge/agent-memory/sources/codex-hook-runner.mjs +273 -0
- package/src/forge/agent-memory/sources/codex.ts +119 -0
- package/src/forge/agent-memory/sources/cursor.ts +35 -0
- package/src/forge/agent-memory/types.ts +204 -0
- package/src/forge/bench.ts +248 -0
- package/src/forge/brownfield-import/index.ts +801 -0
- package/src/forge/brownfield-import/types.ts +127 -0
- package/src/forge/cair/action-journal.ts +61 -0
- package/src/forge/cair/action-parser.ts +314 -0
- package/src/forge/cair/action-validator.ts +40 -0
- package/src/forge/cair/actions.ts +1818 -0
- package/src/forge/cair/format.ts +77 -0
- package/src/forge/cair/index.ts +106 -0
- package/src/forge/cair/query.ts +478 -0
- package/src/forge/cair/snapshot.ts +315 -0
- package/src/forge/cair/types.ts +248 -0
- package/src/forge/cli/ai.ts +339 -21
- package/src/forge/cli/auth.ts +348 -10
- package/src/forge/cli/authmd.ts +441 -0
- package/src/forge/cli/baseline.ts +112 -0
- package/src/forge/cli/build.ts +20 -4
- package/src/forge/cli/changed.ts +437 -0
- package/src/forge/cli/codex-app-server.ts +877 -0
- package/src/forge/cli/commands.ts +1620 -20
- package/src/forge/cli/db.ts +209 -2
- package/src/forge/cli/deploy.ts +887 -0
- package/src/forge/cli/deps.ts +82 -13
- package/src/forge/cli/dev.ts +961 -46
- package/src/forge/cli/docs.ts +265 -0
- package/src/forge/cli/doctor.ts +297 -0
- package/src/forge/cli/field-test.ts +329 -0
- package/src/forge/cli/handoff.ts +336 -0
- package/src/forge/cli/index.ts +1 -0
- package/src/forge/cli/last-run.ts +84 -0
- package/src/forge/cli/main.ts +107 -3
- package/src/forge/cli/new.ts +152 -13
- package/src/forge/cli/next-actions.ts +23 -0
- package/src/forge/cli/output.ts +389 -6
- package/src/forge/cli/parse.ts +1050 -34
- package/src/forge/cli/progress.ts +51 -0
- package/src/forge/cli/query.ts +32 -0
- package/src/forge/cli/release.ts +35 -11
- package/src/forge/cli/rls.ts +43 -4
- package/src/forge/cli/run.ts +41 -0
- package/src/forge/cli/security.ts +112 -0
- package/src/forge/cli/self-host.ts +56 -14
- package/src/forge/cli/studio.ts +2218 -0
- package/src/forge/cli/verify.ts +1455 -32
- package/src/forge/cli/windows.ts +23 -0
- package/src/forge/cli/workos.ts +1020 -0
- package/src/forge/compiler/agent-contract/build.ts +670 -64
- package/src/forge/compiler/agent-contract/types.ts +45 -2
- package/src/forge/compiler/ai-registry/parse.ts +71 -2
- package/src/forge/compiler/api-surface/build.ts +47 -0
- package/src/forge/compiler/app-graph/build.ts +112 -9
- package/src/forge/compiler/app-graph/extract.ts +107 -0
- package/src/forge/compiler/app-graph/module-graph.ts +73 -78
- package/src/forge/compiler/app-graph/parser.ts +24 -24
- package/src/forge/compiler/app-graph/profile.ts +26 -0
- package/src/forge/compiler/app-graph/versions.ts +1 -1
- package/src/forge/compiler/classifier/capabilities.ts +3 -2
- package/src/forge/compiler/classifier/classify.ts +32 -8
- package/src/forge/compiler/classifier/secrets.ts +3 -2
- package/src/forge/compiler/classifier/signals.ts +91 -1
- package/src/forge/compiler/client-sdk/build-manifest.ts +59 -0
- package/src/forge/compiler/client-sdk/render-client.ts +295 -13
- package/src/forge/compiler/data-graph/parse.ts +20 -4
- package/src/forge/compiler/data-graph/sql/ddl.ts +144 -31
- package/src/forge/compiler/data-graph/sql/serialize.ts +4 -0
- package/src/forge/compiler/data-graph/sql/types.ts +1 -0
- package/src/forge/compiler/diagnostics/codes.ts +30 -0
- package/src/forge/compiler/diagnostics/create.ts +21 -2
- package/src/forge/compiler/diagnostics/index.ts +2 -0
- package/src/forge/compiler/emitter/barrel.ts +3 -0
- package/src/forge/compiler/emitter/render.ts +9 -0
- package/src/forge/compiler/external-manifest/registry.ts +205 -0
- package/src/forge/compiler/external-manifest/types.ts +91 -0
- package/src/forge/compiler/external-manifest/validate.ts +373 -0
- package/src/forge/compiler/frontend-graph/build.ts +142 -14
- package/src/forge/compiler/integration/add.ts +618 -24
- package/src/forge/compiler/integration/plan.ts +43 -12
- package/src/forge/compiler/integration/render.ts +29 -0
- package/src/forge/compiler/integration/snapshot.ts +2 -0
- package/src/forge/compiler/integration/templates/convex.ts +70 -0
- package/src/forge/compiler/integration/templates/index.ts +1 -0
- package/src/forge/compiler/integration/templates/render.ts +38 -0
- package/src/forge/compiler/integration/templates/types.ts +3 -0
- package/src/forge/compiler/integration/templates/workos.ts +1219 -0
- package/src/forge/compiler/make-registry/build.ts +8 -9
- package/src/forge/compiler/orchestrator/fast-check.ts +4 -0
- package/src/forge/compiler/orchestrator/generate-lock.ts +14 -3
- package/src/forge/compiler/orchestrator/manifest.ts +1 -1
- package/src/forge/compiler/orchestrator/plan-profile.ts +23 -0
- package/src/forge/compiler/orchestrator/plan.ts +247 -10
- package/src/forge/compiler/orchestrator/profile.ts +65 -0
- package/src/forge/compiler/orchestrator/run.ts +97 -31
- package/src/forge/compiler/orchestrator/serialize.ts +33 -8
- package/src/forge/compiler/orchestrator/types.ts +1 -1
- package/src/forge/compiler/package-graph/compiler.ts +3 -1
- package/src/forge/compiler/package-graph/constants.ts +1 -1
- package/src/forge/compiler/package-manager/adapter.ts +4 -1
- package/src/forge/compiler/package-manager/commands.ts +4 -0
- package/src/forge/compiler/package-manager/executor.ts +30 -1
- package/src/forge/compiler/package-upgrades/planner.ts +155 -18
- package/src/forge/compiler/package-upgrades/types.ts +2 -0
- package/src/forge/compiler/policy-registry/build.ts +47 -2
- package/src/forge/compiler/policy-registry/parse.ts +32 -2
- package/src/forge/compiler/recipes/definitions.ts +63 -0
- package/src/forge/compiler/recipes/index.ts +2 -0
- package/src/forge/compiler/recipes/registry.ts +6 -0
- package/src/forge/compiler/test-graph/build.ts +11 -3
- package/src/forge/compiler/types/app-graph.ts +8 -2
- package/src/forge/compiler/types/cli.ts +75 -1
- package/src/forge/compiler/types/dev-manifest.ts +4 -0
- package/src/forge/compiler/types/emit.ts +2 -0
- package/src/forge/compiler/types/frontend-graph.ts +2 -2
- package/src/forge/compiler/types/integration.ts +1 -0
- package/src/forge/compiler/types/package-graph.ts +6 -0
- package/src/forge/compiler/types/policy-registry.ts +3 -1
- package/src/forge/delta/classifier.ts +52 -0
- package/src/forge/delta/explain.ts +238 -0
- package/src/forge/delta/git-observer.ts +43 -0
- package/src/forge/delta/ids.ts +44 -0
- package/src/forge/delta/index.ts +25 -0
- package/src/forge/delta/recorder.ts +540 -0
- package/src/forge/delta/redaction.ts +50 -0
- package/src/forge/delta/schema.ts +240 -0
- package/src/forge/delta/session.ts +142 -0
- package/src/forge/delta/status.ts +1202 -0
- package/src/forge/delta/store.ts +3284 -0
- package/src/forge/delta/timeline.ts +178 -0
- package/src/forge/dev/server.ts +808 -17
- package/src/forge/dev/types.ts +15 -1
- package/src/forge/dev/watch.ts +17 -7
- package/src/forge/dev-console/cycle.ts +280 -33
- package/src/forge/dev-console/types.ts +47 -1
- package/src/forge/impact/index.ts +204 -9
- package/src/forge/impact/types.ts +33 -1
- package/src/forge/intent/index.ts +35 -16
- package/src/forge/make/fields.ts +26 -0
- package/src/forge/make/index.ts +40 -6
- package/src/forge/make/templates.ts +155 -2
- package/src/forge/make/types.ts +2 -1
- package/src/forge/policy.ts +1 -1
- package/src/forge/react/index.ts +160 -2
- package/src/forge/refactor/index.ts +1 -0
- package/src/forge/repair/rules/index.ts +2 -2
- package/src/forge/review/index.ts +158 -12
- package/src/forge/review/types.ts +15 -0
- package/src/forge/runtime/auth/config.ts +17 -0
- package/src/forge/runtime/auth/evaluate.ts +15 -2
- package/src/forge/runtime/auth/resolve.ts +61 -6
- package/src/forge/runtime/auth/types.ts +1 -0
- package/src/forge/runtime/db/factory.ts +1 -3
- package/src/forge/runtime/db/generated-client.ts +13 -2
- package/src/forge/runtime/db/memory-adapter.ts +139 -32
- package/src/forge/runtime/db/pglite-adapter.ts +263 -2
- package/src/forge/runtime/db/postgres-adapter.ts +6 -3
- package/src/forge/runtime/executor.ts +129 -16
- package/src/forge/runtime/external/bridge.ts +649 -0
- package/src/forge/runtime/runner/run-entry.ts +16 -7
- package/src/forge/runtime/telemetry/buffer.ts +4 -1
- package/src/forge/runtime/telemetry/scrubber.ts +35 -5
- package/src/forge/runtime/webhooks/security.ts +12 -7
- package/src/forge/server.ts +17 -3
- package/src/forge/ui/index.ts +209 -0
- package/src/forge/ui/types.ts +1 -0
- package/src/forge/version.ts +1 -1
- package/src/forge/vue/index.ts +422 -0
- package/src/forge/workspace/baseline.ts +112 -0
- package/src/forge/workspace/change-summary.ts +250 -0
- package/src/forge/workspace/forge-cli.ts +42 -0
- package/src/forge/workspace/git-summary.ts +391 -0
- package/templates/agent-workroom/AGENTS.md +29 -0
- package/templates/agent-workroom/README.md +34 -0
- package/templates/agent-workroom/forge.config.ts +3 -0
- package/templates/agent-workroom/package.json +33 -0
- package/templates/agent-workroom/src/actions/indexAgentSignal.ts +10 -0
- package/templates/agent-workroom/src/commands/openWorkroom.ts +61 -0
- package/templates/agent-workroom/src/commands/recordAgentSignal.ts +119 -0
- package/templates/agent-workroom/src/commands/recordCheckRun.ts +52 -0
- package/templates/agent-workroom/src/forge/schema.ts +54 -0
- package/templates/agent-workroom/src/policies.ts +6 -0
- package/templates/agent-workroom/src/queries/listWorkrooms.ts +11 -0
- package/templates/agent-workroom/src/queries/liveWorkroom.ts +63 -0
- package/templates/agent-workroom/tsconfig.json +16 -0
- package/templates/agent-workroom/web/index.html +12 -0
- package/templates/agent-workroom/web/package.json +21 -0
- package/templates/agent-workroom/web/src/App.tsx +345 -0
- package/templates/agent-workroom/web/src/lib/forge.ts +13 -0
- package/templates/agent-workroom/web/src/main.tsx +13 -0
- package/templates/agent-workroom/web/src/styles.css +545 -0
- package/templates/agent-workroom/web/tsconfig.json +27 -0
- package/templates/b2b-support-web/package.json +1 -0
- package/templates/b2b-support-web/web/package.json +1 -1
- package/templates/minimal-web/package.json +1 -1
- package/templates/minimal-web/web/package.json +2 -2
- package/templates/nuxt-web/.vscode/settings.json +14 -0
- package/templates/nuxt-web/README.md +30 -0
- package/templates/nuxt-web/forge.config.ts +3 -0
- package/templates/nuxt-web/package.json +33 -0
- package/templates/nuxt-web/src/actions/logNoteCreated.ts +11 -0
- package/templates/nuxt-web/src/commands/createNote.ts +26 -0
- package/templates/nuxt-web/src/forge/schema.ts +12 -0
- package/templates/nuxt-web/src/policies.ts +6 -0
- package/templates/nuxt-web/src/queries/listNotes.ts +8 -0
- package/templates/nuxt-web/src/queries/liveNotes.ts +8 -0
- package/templates/nuxt-web/tsconfig.json +17 -0
- package/templates/nuxt-web/web/app.vue +67 -0
- package/templates/nuxt-web/web/components/LiveNotes.vue +89 -0
- package/templates/nuxt-web/web/components/NoteComposer.vue +100 -0
- package/templates/nuxt-web/web/composables/forge.ts +13 -0
- package/templates/nuxt-web/web/composables/useNotes.ts +24 -0
- package/templates/nuxt-web/web/nuxt.config.ts +11 -0
- package/templates/nuxt-web/web/package.json +18 -0
- package/templates/nuxt-web/web/plugins/forge.client.ts +10 -0
- package/templates/nuxt-web/web/plugins/forge.server.ts +10 -0
- package/templates/nuxt-web/web/server/api/forge-health.get.ts +7 -0
- package/templates/nuxt-web/web/tsconfig.json +6 -0
- package/src/forge/_generated/actionSubscriptions.json +0 -2
- package/src/forge/_generated/actionSubscriptions.ts +0 -10
- package/src/forge/_generated/agentAdapterManifest.json +0 -2
- package/src/forge/_generated/agentAdapterManifest.ts +0 -73
- package/src/forge/_generated/agentContract.json +0 -2
- package/src/forge/_generated/agentContract.ts +0 -7829
- package/src/forge/_generated/agentQuickstart.md +0 -34
- package/src/forge/_generated/agentTools.json +0 -2
- package/src/forge/_generated/agentTools.md +0 -16
- package/src/forge/_generated/agentTools.ts +0 -12
- package/src/forge/_generated/aiContext.ts +0 -125
- package/src/forge/_generated/aiModels.json +0 -2
- package/src/forge/_generated/aiModels.ts +0 -51
- package/src/forge/_generated/aiProviders.json +0 -2
- package/src/forge/_generated/aiProviders.ts +0 -23
- package/src/forge/_generated/aiRegistry.json +0 -2
- package/src/forge/_generated/aiRegistry.ts +0 -31
- package/src/forge/_generated/api.json +0 -2
- package/src/forge/_generated/api.ts +0 -8
- package/src/forge/_generated/appGraph.json +0 -2
- package/src/forge/_generated/appGraph.ts +0 -14919
- package/src/forge/_generated/appMap.md +0 -55
- package/src/forge/_generated/artifactManifest.json +0 -2
- package/src/forge/_generated/artifactManifest.ts +0 -7
- package/src/forge/_generated/authClaims.json +0 -2
- package/src/forge/_generated/authClaims.ts +0 -13
- package/src/forge/_generated/authConfig.json +0 -2
- package/src/forge/_generated/authConfig.ts +0 -17
- package/src/forge/_generated/authContext.ts +0 -23
- package/src/forge/_generated/authRegistry.json +0 -2
- package/src/forge/_generated/authRegistry.ts +0 -25
- package/src/forge/_generated/buildInfo.json +0 -2
- package/src/forge/_generated/buildInfo.ts +0 -9
- package/src/forge/_generated/capabilityMap.json +0 -2
- package/src/forge/_generated/capabilityMap.md +0 -15
- package/src/forge/_generated/capabilityMap.ts +0 -17
- package/src/forge/_generated/client.ts +0 -282
- package/src/forge/_generated/clientApi.ts +0 -9
- package/src/forge/_generated/clientManifest.json +0 -2
- package/src/forge/_generated/clientManifest.ts +0 -39
- package/src/forge/_generated/clientTypes.ts +0 -78
- package/src/forge/_generated/configRegistry.json +0 -2
- package/src/forge/_generated/configRegistry.ts +0 -4
- package/src/forge/_generated/dataGraph.json +0 -2
- package/src/forge/_generated/dataGraph.ts +0 -8
- package/src/forge/_generated/db.json +0 -2
- package/src/forge/_generated/db.ts +0 -2
- package/src/forge/_generated/dbSecurityManifest.json +0 -2
- package/src/forge/_generated/dbSecurityManifest.ts +0 -15
- package/src/forge/_generated/dbSessionContext.json +0 -2
- package/src/forge/_generated/dbSessionContext.ts +0 -39
- package/src/forge/_generated/deployManifest.json +0 -2
- package/src/forge/_generated/deployManifest.ts +0 -14
- package/src/forge/_generated/devManifest.json +0 -2
- package/src/forge/_generated/devManifest.ts +0 -62
- package/src/forge/_generated/envSchema.json +0 -2
- package/src/forge/_generated/envSchema.ts +0 -59
- package/src/forge/_generated/frontendGraph.json +0 -2
- package/src/forge/_generated/frontendGraph.ts +0 -27
- package/src/forge/_generated/importGuards.json +0 -2
- package/src/forge/_generated/importGuards.ts +0 -686
- package/src/forge/_generated/index.ts +0 -68
- package/src/forge/_generated/liveProductionManifest.json +0 -2
- package/src/forge/_generated/liveProductionManifest.ts +0 -23
- package/src/forge/_generated/liveProtocol.json +0 -2
- package/src/forge/_generated/liveProtocol.ts +0 -21
- package/src/forge/_generated/liveQueryRegistry.json +0 -2
- package/src/forge/_generated/liveQueryRegistry.ts +0 -9
- package/src/forge/_generated/liveTransportConfig.json +0 -2
- package/src/forge/_generated/liveTransportConfig.ts +0 -19
- package/src/forge/_generated/makeRegistry.json +0 -2
- package/src/forge/_generated/makeRegistry.ts +0 -177
- package/src/forge/_generated/makeTemplates.json +0 -2
- package/src/forge/_generated/makeTemplates.ts +0 -66
- package/src/forge/_generated/mockMap.json +0 -2
- package/src/forge/_generated/mockMap.ts +0 -7
- package/src/forge/_generated/operationPlaybooks.md +0 -167
- package/src/forge/_generated/packageGraph.json +0 -2
- package/src/forge/_generated/packageGraph.ts +0 -249334
- package/src/forge/_generated/packageUpgradeRegistry.json +0 -2
- package/src/forge/_generated/packageUpgradeRegistry.ts +0 -15
- package/src/forge/_generated/permissionMatrix.json +0 -2
- package/src/forge/_generated/permissionMatrix.ts +0 -7
- package/src/forge/_generated/policyRegistry.json +0 -2
- package/src/forge/_generated/policyRegistry.ts +0 -11
- package/src/forge/_generated/queryRegistry.json +0 -2
- package/src/forge/_generated/queryRegistry.ts +0 -9
- package/src/forge/_generated/react.d.ts +0 -22
- package/src/forge/_generated/react.ts +0 -29
- package/src/forge/_generated/reactManifest.json +0 -2
- package/src/forge/_generated/reactManifest.ts +0 -19
- package/src/forge/_generated/rlsPolicies.json +0 -2
- package/src/forge/_generated/rlsPolicies.sql +0 -34
- package/src/forge/_generated/rlsPolicies.ts +0 -6
- package/src/forge/_generated/runtimeGraph.json +0 -2
- package/src/forge/_generated/runtimeGraph.ts +0 -8
- package/src/forge/_generated/runtimeMatrix.json +0 -2
- package/src/forge/_generated/runtimeMatrix.ts +0 -334130
- package/src/forge/_generated/runtimeRegistry.ts +0 -2
- package/src/forge/_generated/runtimeRules.md +0 -91
- package/src/forge/_generated/secretRegistry.json +0 -2
- package/src/forge/_generated/secretRegistry.ts +0 -50
- package/src/forge/_generated/secretsContext.ts +0 -11
- package/src/forge/_generated/serverApi.ts +0 -10
- package/src/forge/_generated/sourceMapManifest.json +0 -2
- package/src/forge/_generated/sourceMapManifest.ts +0 -7
- package/src/forge/_generated/sqlPlan.json +0 -2
- package/src/forge/_generated/sqlPlan.ts +0 -88
- package/src/forge/_generated/subscriptionManifest.json +0 -2
- package/src/forge/_generated/subscriptionManifest.ts +0 -7
- package/src/forge/_generated/symbolicationManifest.json +0 -2
- package/src/forge/_generated/symbolicationManifest.ts +0 -17
- package/src/forge/_generated/telemetryRegistry.json +0 -2
- package/src/forge/_generated/telemetryRegistry.ts +0 -9
- package/src/forge/_generated/telemetrySinks.json +0 -2
- package/src/forge/_generated/telemetrySinks.ts +0 -11
- package/src/forge/_generated/tenantScope.json +0 -2
- package/src/forge/_generated/tenantScope.ts +0 -8
- package/src/forge/_generated/testGraph.json +0 -2
- package/src/forge/_generated/testGraph.ts +0 -3430
- package/src/forge/_generated/testPlanRegistry.json +0 -2
- package/src/forge/_generated/testPlanRegistry.ts +0 -33
- package/src/forge/_generated/uiRoutes.json +0 -2
- package/src/forge/_generated/uiRoutes.ts +0 -16
- package/src/forge/_generated/uiScenarios.json +0 -2
- package/src/forge/_generated/uiScenarios.ts +0 -30
- package/src/forge/_generated/uiTestManifest.json +0 -2
- package/src/forge/_generated/uiTestManifest.ts +0 -27
- package/src/forge/_generated/workflowRegistry.json +0 -2
- package/src/forge/_generated/workflowRegistry.ts +0 -9
- package/src/forge/_generated/workflowSubscriptions.json +0 -2
- package/src/forge/_generated/workflowSubscriptions.ts +0 -10
package/src/forge/cli/auth.ts
CHANGED
|
@@ -4,18 +4,30 @@ import {
|
|
|
4
4
|
FORGE_AUTH_INVALID_AUDIENCE,
|
|
5
5
|
FORGE_AUTH_JWKS_FAILED,
|
|
6
6
|
} from "../compiler/diagnostics/codes.ts";
|
|
7
|
-
import { loadAuthConfigFromEnv } from "../runtime/auth/config.ts";
|
|
7
|
+
import { loadAuthConfigFromEnv, type AuthClaimsMapping } from "../runtime/auth/config.ts";
|
|
8
8
|
import { mapClaimsToAuthContext } from "../runtime/auth/claims.ts";
|
|
9
9
|
import { ForgeAuthError } from "../runtime/auth/errors.ts";
|
|
10
10
|
import { verifyJwtToken } from "../runtime/auth/verifier.ts";
|
|
11
|
+
import { loadSecretRegistry } from "../runtime/secrets/check.ts";
|
|
12
|
+
import { existsSync } from "node:fs";
|
|
13
|
+
import { join } from "node:path";
|
|
14
|
+
import { normalizeForgeCliCommandsInValue } from "../workspace/forge-cli.ts";
|
|
15
|
+
import {
|
|
16
|
+
collectExpectedResourceTypes,
|
|
17
|
+
collectPolicyPermissions,
|
|
18
|
+
missingValues,
|
|
19
|
+
parseSeedFile,
|
|
20
|
+
} from "./workos.ts";
|
|
11
21
|
|
|
12
|
-
export type AuthSubcommand = "check" | "config" | "decode" | "test-token" | "jwks" | "prove";
|
|
22
|
+
export type AuthSubcommand = "check" | "config" | "decode" | "test-token" | "jwks" | "prove" | "status";
|
|
13
23
|
|
|
14
24
|
export interface AuthCommandOptions {
|
|
15
25
|
subcommand: AuthSubcommand;
|
|
16
26
|
workspaceRoot: string;
|
|
17
27
|
json: boolean;
|
|
18
28
|
token?: string;
|
|
29
|
+
prod?: boolean;
|
|
30
|
+
scenario?: string;
|
|
19
31
|
}
|
|
20
32
|
|
|
21
33
|
export interface AuthCommandResult {
|
|
@@ -26,10 +38,40 @@ export interface AuthCommandResult {
|
|
|
26
38
|
exitCode: 0 | 1;
|
|
27
39
|
}
|
|
28
40
|
|
|
29
|
-
function
|
|
30
|
-
const
|
|
31
|
-
const
|
|
41
|
+
function detectWorkOS(workspaceRoot: string, claims: AuthClaimsMapping) {
|
|
42
|
+
const secretRegistry = loadSecretRegistry(workspaceRoot);
|
|
43
|
+
const secretNames = new Set((secretRegistry?.secrets ?? []).map((secret) => secret.name));
|
|
44
|
+
const detected =
|
|
45
|
+
secretNames.has("WORKOS_API_KEY") ||
|
|
46
|
+
secretNames.has("WORKOS_CLIENT_ID") ||
|
|
47
|
+
claims.tenantId === "organization_id";
|
|
48
|
+
const expectedClaims = {
|
|
49
|
+
userId: "sub",
|
|
50
|
+
email: "email",
|
|
51
|
+
tenantId: "organization_id",
|
|
52
|
+
role: "role",
|
|
53
|
+
roles: "roles",
|
|
54
|
+
permissions: "permissions",
|
|
55
|
+
};
|
|
56
|
+
const claimStatus = Object.entries(expectedClaims).map(([name, expected]) => ({
|
|
57
|
+
name,
|
|
58
|
+
expected,
|
|
59
|
+
actual: claims[name as keyof AuthClaimsMapping],
|
|
60
|
+
ok: claims[name as keyof AuthClaimsMapping] === expected,
|
|
61
|
+
}));
|
|
62
|
+
return {
|
|
63
|
+
detected,
|
|
64
|
+
requiredSecretsRegistered: ["WORKOS_API_KEY", "WORKOS_CLIENT_ID", "WORKOS_COOKIE_PASSWORD"].every((name) =>
|
|
65
|
+
secretNames.has(name)
|
|
66
|
+
),
|
|
67
|
+
webhookSecretRegistered: secretNames.has("WORKOS_WEBHOOK_SECRET"),
|
|
68
|
+
expectedClaims,
|
|
69
|
+
claimStatus,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
32
72
|
|
|
73
|
+
function configErrors(config: ReturnType<typeof loadAuthConfigFromEnv>): { code: string; message: string }[] {
|
|
74
|
+
const errors: { code: string; message: string }[] = [];
|
|
33
75
|
if ((config.mode === "jwt" || config.mode === "oidc") && !config.issuer) {
|
|
34
76
|
errors.push({
|
|
35
77
|
code: FORGE_AUTH_INVALID_ISSUER,
|
|
@@ -48,6 +90,183 @@ function validateConfig(workspaceRoot: string): AuthCommandResult {
|
|
|
48
90
|
message: "FORGE_AUTH_JWKS_URI is required for jwt auth",
|
|
49
91
|
});
|
|
50
92
|
}
|
|
93
|
+
return errors;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function buildAuthPosture(workspaceRoot: string) {
|
|
97
|
+
const config = loadAuthConfigFromEnv(workspaceRoot);
|
|
98
|
+
const productionMode = config.mode === "jwt" || config.mode === "oidc";
|
|
99
|
+
const errors = configErrors(config);
|
|
100
|
+
const configReady = errors.length === 0;
|
|
101
|
+
const classification = config.mode === "dev-headers"
|
|
102
|
+
? "local-dev"
|
|
103
|
+
: config.mode === "disabled"
|
|
104
|
+
? "unauthenticated"
|
|
105
|
+
: configReady
|
|
106
|
+
? "production-ready"
|
|
107
|
+
: "production-incomplete";
|
|
108
|
+
const reason = productionMode
|
|
109
|
+
? configReady
|
|
110
|
+
? "jwt/oidc production auth configuration is present"
|
|
111
|
+
: "jwt/oidc production auth is selected but required settings are missing"
|
|
112
|
+
: config.mode === "disabled"
|
|
113
|
+
? "auth is disabled; this is not suitable for public production traffic"
|
|
114
|
+
: "dev-headers auth is local-only and is not real production authentication";
|
|
115
|
+
return normalizeForgeCliCommandsInValue(workspaceRoot, {
|
|
116
|
+
schemaVersion: "0.1.0",
|
|
117
|
+
mode: config.mode,
|
|
118
|
+
classification,
|
|
119
|
+
localOnly: config.mode === "dev-headers",
|
|
120
|
+
productionReady: productionMode && configReady,
|
|
121
|
+
requiresTenant: config.requiresTenant,
|
|
122
|
+
bearerHeader: productionMode ? "Authorization: Bearer <token>" : null,
|
|
123
|
+
tenantClaim: config.claims.tenantId ?? "tenant_id",
|
|
124
|
+
environment: {
|
|
125
|
+
current: classification,
|
|
126
|
+
localDevelopment: config.mode === "dev-headers",
|
|
127
|
+
publicProduction: productionMode && configReady,
|
|
128
|
+
warning: reason,
|
|
129
|
+
},
|
|
130
|
+
localDevHeaders: config.mode === "dev-headers"
|
|
131
|
+
? {
|
|
132
|
+
acceptedHeaders: [
|
|
133
|
+
"x-forge-user-id",
|
|
134
|
+
"x-forge-tenant-id",
|
|
135
|
+
"x-forge-role",
|
|
136
|
+
"x-forge-roles",
|
|
137
|
+
"x-forge-permissions",
|
|
138
|
+
],
|
|
139
|
+
scope: "forge dev, tests, and local agent workflows only",
|
|
140
|
+
neverProduction: true,
|
|
141
|
+
}
|
|
142
|
+
: null,
|
|
143
|
+
productionRequirements: {
|
|
144
|
+
requiredMode: "jwt or oidc",
|
|
145
|
+
bearerHeader: "Authorization: Bearer <token>",
|
|
146
|
+
requiredEnv: [
|
|
147
|
+
"FORGE_AUTH_MODE",
|
|
148
|
+
"FORGE_AUTH_ISSUER",
|
|
149
|
+
"FORGE_AUTH_AUDIENCE",
|
|
150
|
+
config.mode === "oidc" ? "OIDC discovery at FORGE_AUTH_ISSUER" : "FORGE_AUTH_JWKS_URI",
|
|
151
|
+
],
|
|
152
|
+
proofCommand: "forge auth prove --prod --token <jwt> --json",
|
|
153
|
+
},
|
|
154
|
+
productionChecklist: [
|
|
155
|
+
{ item: "auth mode is jwt or oidc", ok: productionMode },
|
|
156
|
+
{ item: "FORGE_AUTH_ISSUER configured", ok: Boolean(config.issuer) },
|
|
157
|
+
{ item: "FORGE_AUTH_AUDIENCE configured", ok: Boolean(config.audience) },
|
|
158
|
+
{ item: "FORGE_AUTH_JWKS_URI or OIDC discovery configured", ok: config.mode === "oidc" || Boolean(config.jwksUri) },
|
|
159
|
+
{ item: "tenant claim mapped", ok: Boolean(config.claims.tenantId) },
|
|
160
|
+
{ item: "permission claim mapped", ok: Boolean(config.claims.permissions) },
|
|
161
|
+
{ item: "dev-headers disabled for public runtime", ok: config.mode !== "dev-headers" },
|
|
162
|
+
],
|
|
163
|
+
reason,
|
|
164
|
+
nextActions: productionMode
|
|
165
|
+
? configReady
|
|
166
|
+
? ["forge auth prove --prod --token <jwt> --json", "forge serve --json"]
|
|
167
|
+
: ["forge auth check --json", "configure FORGE_AUTH_ISSUER, FORGE_AUTH_AUDIENCE, and FORGE_AUTH_JWKS_URI or OIDC issuer"]
|
|
168
|
+
: ["set FORGE_AUTH_MODE=jwt or oidc for production", "forge auth prove --prod --token <jwt> --json"],
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function permissionSubsetForRestrictedTenant(permissions: string[]): string[] {
|
|
173
|
+
const readonly = permissions.filter((permission) =>
|
|
174
|
+
/(^|[:._-])(read|list|view|inspect|search)($|[:._-])/.test(permission)
|
|
175
|
+
);
|
|
176
|
+
if (readonly.length > 0) return readonly;
|
|
177
|
+
return permissions.slice(0, Math.max(1, Math.floor(permissions.length / 2)));
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function buildMultiTenantProof(workspaceRoot: string, workos: ReturnType<typeof detectWorkOS>, requiresTenant: boolean) {
|
|
181
|
+
const rootSeedPresent = existsSync(join(workspaceRoot, "workos-seed.yml"));
|
|
182
|
+
const generatedSeedPresent = existsSync(join(workspaceRoot, "src/forge/_generated/integrations/workos/workos-seed.yml"));
|
|
183
|
+
const authMdPresent = existsSync(join(workspaceRoot, "public/auth.md"));
|
|
184
|
+
const metadataPresent = existsSync(join(workspaceRoot, "public/.well-known/oauth-protected-resource"));
|
|
185
|
+
const activePermissions = collectPolicyPermissions(workspaceRoot);
|
|
186
|
+
const expectedResourceTypes = collectExpectedResourceTypes(workspaceRoot);
|
|
187
|
+
const seed = parseSeedFile(workspaceRoot);
|
|
188
|
+
const missingSeedPermissions = missingValues(activePermissions, seed.permissions);
|
|
189
|
+
const missingSeedResources = missingValues(expectedResourceTypes, seed.resourceTypes);
|
|
190
|
+
const acmePermissions = activePermissions;
|
|
191
|
+
const globexPermissions = permissionSubsetForRestrictedTenant(activePermissions);
|
|
192
|
+
const permissionVocabularyPresent = workos.detected && workos.claimStatus.some((claim) => claim.name === "permissions" && claim.ok);
|
|
193
|
+
const checks = [
|
|
194
|
+
{
|
|
195
|
+
id: "tenant-claim",
|
|
196
|
+
ok: requiresTenant && workos.claimStatus.some((claim) => claim.name === "tenantId" && claim.ok),
|
|
197
|
+
evidence: "Forge tenant claim maps to WorkOS organization_id and tenant auth is required.",
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
id: "permission-claim",
|
|
201
|
+
ok: activePermissions.length > 0 && permissionVocabularyPresent,
|
|
202
|
+
evidence: activePermissions.length > 0
|
|
203
|
+
? `Forge permissions claim maps to WorkOS permissions: ${activePermissions.join(", ")}.`
|
|
204
|
+
: "No active policy permissions were found in the generated policy registry.",
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
id: "seed-organizations",
|
|
208
|
+
ok: rootSeedPresent || generatedSeedPresent,
|
|
209
|
+
evidence: rootSeedPresent
|
|
210
|
+
? "workos-seed.yml exists at app root."
|
|
211
|
+
: generatedSeedPresent
|
|
212
|
+
? "generated WorkOS seed exists."
|
|
213
|
+
: "no WorkOS seed file found at app root or in generated integrations.",
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
id: "seed-permission-coverage",
|
|
217
|
+
ok: activePermissions.length > 0 && missingSeedPermissions.length === 0,
|
|
218
|
+
evidence: activePermissions.length === 0
|
|
219
|
+
? "No active policy permissions were found in the generated policy registry."
|
|
220
|
+
: missingSeedPermissions.length === 0
|
|
221
|
+
? `seed covers active app permission(s): ${activePermissions.join(", ")}`
|
|
222
|
+
: `seed missing active app permission(s): ${missingSeedPermissions.join(", ")}`,
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
id: "seed-resource-coverage",
|
|
226
|
+
ok: missingSeedResources.length === 0,
|
|
227
|
+
evidence: missingSeedResources.length === 0
|
|
228
|
+
? `seed covers expected app resource type(s): ${expectedResourceTypes.join(", ") || "none required"}`
|
|
229
|
+
: `seed missing expected app resource type(s): ${missingSeedResources.join(", ")}`,
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
id: "agent-auth-metadata",
|
|
233
|
+
ok: authMdPresent && metadataPresent,
|
|
234
|
+
evidence: "public/auth.md and protected resource metadata are present.",
|
|
235
|
+
},
|
|
236
|
+
];
|
|
237
|
+
return normalizeForgeCliCommandsInValue(workspaceRoot, {
|
|
238
|
+
scenario: "multi-tenant",
|
|
239
|
+
ok: checks.every((check) => check.ok),
|
|
240
|
+
claims: {
|
|
241
|
+
acme: { organization_id: "org_acme", role: "owner", permissions: acmePermissions },
|
|
242
|
+
globex: { organization_id: "org_globex", role: "member", permissions: globexPermissions },
|
|
243
|
+
},
|
|
244
|
+
appContract: {
|
|
245
|
+
activePermissions,
|
|
246
|
+
expectedResourceTypes,
|
|
247
|
+
seedPath: seed.path,
|
|
248
|
+
seedPermissions: seed.permissions,
|
|
249
|
+
seedResourceTypes: seed.resourceTypes,
|
|
250
|
+
},
|
|
251
|
+
invariants: [
|
|
252
|
+
"Acme and Globex must use different organization_id claim values.",
|
|
253
|
+
"Tenant-scoped reads must include the active organization_id.",
|
|
254
|
+
"Tenant-scoped writes must verify the resource tenant before mutation.",
|
|
255
|
+
"Role-only UI affordances are not sufficient; policies must use the app's generated permission vocabulary.",
|
|
256
|
+
],
|
|
257
|
+
checks,
|
|
258
|
+
nextActions: [
|
|
259
|
+
"forge workos doctor --json",
|
|
260
|
+
"forge workos seed --file workos-seed.yml --dry-run --json",
|
|
261
|
+
"run an HTTP E2E with Acme and Globex tokens before production",
|
|
262
|
+
],
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function validateConfig(workspaceRoot: string): AuthCommandResult {
|
|
267
|
+
const config = loadAuthConfigFromEnv(workspaceRoot);
|
|
268
|
+
const errors = configErrors(config);
|
|
269
|
+
const workos = detectWorkOS(workspaceRoot, config.claims);
|
|
51
270
|
|
|
52
271
|
return {
|
|
53
272
|
ok: errors.length === 0,
|
|
@@ -60,6 +279,8 @@ function validateConfig(workspaceRoot: string): AuthCommandResult {
|
|
|
60
279
|
algorithms: config.algorithms,
|
|
61
280
|
claims: config.claims,
|
|
62
281
|
requiresTenant: config.requiresTenant,
|
|
282
|
+
authPosture: buildAuthPosture(workspaceRoot),
|
|
283
|
+
workos,
|
|
63
284
|
errors,
|
|
64
285
|
},
|
|
65
286
|
error: errors[0],
|
|
@@ -69,6 +290,7 @@ function validateConfig(workspaceRoot: string): AuthCommandResult {
|
|
|
69
290
|
|
|
70
291
|
function publicConfig(workspaceRoot: string): AuthCommandResult {
|
|
71
292
|
const config = loadAuthConfigFromEnv(workspaceRoot);
|
|
293
|
+
const workos = detectWorkOS(workspaceRoot, config.claims);
|
|
72
294
|
return {
|
|
73
295
|
ok: true,
|
|
74
296
|
mode: config.mode,
|
|
@@ -80,6 +302,8 @@ function publicConfig(workspaceRoot: string): AuthCommandResult {
|
|
|
80
302
|
algorithms: config.algorithms,
|
|
81
303
|
claims: config.claims,
|
|
82
304
|
requiresTenant: config.requiresTenant,
|
|
305
|
+
authPosture: buildAuthPosture(workspaceRoot),
|
|
306
|
+
workos,
|
|
83
307
|
},
|
|
84
308
|
exitCode: 0,
|
|
85
309
|
};
|
|
@@ -160,22 +384,76 @@ async function testToken(
|
|
|
160
384
|
export async function runAuthCommand(
|
|
161
385
|
options: AuthCommandOptions,
|
|
162
386
|
): Promise<AuthCommandResult> {
|
|
387
|
+
if (options.subcommand === "status") {
|
|
388
|
+
const posture = buildAuthPosture(options.workspaceRoot);
|
|
389
|
+
return {
|
|
390
|
+
ok: true,
|
|
391
|
+
mode: posture.mode,
|
|
392
|
+
data: posture,
|
|
393
|
+
exitCode: 0,
|
|
394
|
+
};
|
|
395
|
+
}
|
|
163
396
|
if (options.subcommand === "check") {
|
|
164
|
-
|
|
397
|
+
const checked = validateConfig(options.workspaceRoot);
|
|
398
|
+
if (!options.prod) {
|
|
399
|
+
return checked;
|
|
400
|
+
}
|
|
401
|
+
const posture = buildAuthPosture(options.workspaceRoot);
|
|
402
|
+
const productionReady = posture.productionReady === true;
|
|
403
|
+
return {
|
|
404
|
+
ok: checked.ok && productionReady,
|
|
405
|
+
mode: checked.mode,
|
|
406
|
+
data: {
|
|
407
|
+
...(checked.data && typeof checked.data === "object" ? checked.data as Record<string, unknown> : {}),
|
|
408
|
+
production: true,
|
|
409
|
+
authPosture: posture,
|
|
410
|
+
productionCheck: {
|
|
411
|
+
ok: productionReady,
|
|
412
|
+
reason: posture.reason,
|
|
413
|
+
requiredMode: "jwt or oidc",
|
|
414
|
+
localOnlyModeRejected: posture.localOnly === true,
|
|
415
|
+
},
|
|
416
|
+
},
|
|
417
|
+
error: productionReady
|
|
418
|
+
? checked.error
|
|
419
|
+
: { code: "FORGE_AUTH_MODE_INVALID", message: "production auth requires FORGE_AUTH_MODE=jwt or oidc; dev-headers is local-only" },
|
|
420
|
+
exitCode: checked.ok && productionReady ? 0 : 1,
|
|
421
|
+
};
|
|
165
422
|
}
|
|
166
423
|
if (options.subcommand === "prove") {
|
|
167
424
|
const checked = validateConfig(options.workspaceRoot);
|
|
168
425
|
const config = loadAuthConfigFromEnv(options.workspaceRoot);
|
|
426
|
+
const workos = detectWorkOS(options.workspaceRoot, config.claims);
|
|
169
427
|
const productionMode = config.mode === "jwt" || config.mode === "oidc";
|
|
428
|
+
const workosClaimsOk = workos.claimStatus.every((claim) => claim.ok);
|
|
429
|
+
const posture = buildAuthPosture(options.workspaceRoot);
|
|
430
|
+
const tokenProof = options.token ? await testToken(options.workspaceRoot, options.token) : null;
|
|
431
|
+
const prodError = options.prod && !productionMode
|
|
432
|
+
? { code: "FORGE_AUTH_MODE_INVALID", message: "forge auth prove --prod requires FORGE_AUTH_MODE=jwt or oidc" }
|
|
433
|
+
: options.prod && !options.token
|
|
434
|
+
? { code: "FORGE_AUTH_MISSING_TOKEN", message: "forge auth prove --prod requires --token" }
|
|
435
|
+
: options.prod && tokenProof && !tokenProof.ok
|
|
436
|
+
? tokenProof.error
|
|
437
|
+
: undefined;
|
|
438
|
+
const proofOk = checked.ok && (!options.prod || (productionMode && tokenProof?.ok === true));
|
|
439
|
+
const multiTenantProof = options.scenario === "multi-tenant"
|
|
440
|
+
? buildMultiTenantProof(options.workspaceRoot, workos, config.requiresTenant)
|
|
441
|
+
: null;
|
|
442
|
+
const scenarioOk = !multiTenantProof || multiTenantProof.ok;
|
|
170
443
|
return {
|
|
171
|
-
ok:
|
|
444
|
+
ok: proofOk && scenarioOk,
|
|
172
445
|
mode: config.mode,
|
|
173
446
|
data: {
|
|
174
447
|
schemaVersion: "0.1.0",
|
|
175
448
|
kind: "auth-proof",
|
|
176
|
-
ok:
|
|
449
|
+
ok: proofOk,
|
|
177
450
|
mode: config.mode,
|
|
178
451
|
productionReady: productionMode && checked.ok,
|
|
452
|
+
prod: options.prod === true,
|
|
453
|
+
scenario: options.scenario ?? null,
|
|
454
|
+
authPosture: posture,
|
|
455
|
+
...(tokenProof ? { tokenProof: tokenProof.ok ? tokenProof.data : tokenProof.error } : {}),
|
|
456
|
+
...(multiTenantProof ? { multiTenantProof } : {}),
|
|
179
457
|
invariants: [
|
|
180
458
|
{
|
|
181
459
|
id: "INV-001",
|
|
@@ -191,11 +469,27 @@ export async function runAuthCommand(
|
|
|
191
469
|
status: checked.ok ? "passed" : "failed",
|
|
192
470
|
evidence: checked.data,
|
|
193
471
|
},
|
|
472
|
+
{
|
|
473
|
+
id: "INV-WORKOS-001",
|
|
474
|
+
name: "WorkOS adapter claim mapping is explicit when WorkOS is present",
|
|
475
|
+
status: !workos.detected ? "not-applicable" : workosClaimsOk ? "passed" : "failed",
|
|
476
|
+
evidence: workos.claimStatus,
|
|
477
|
+
},
|
|
478
|
+
{
|
|
479
|
+
id: "INV-WORKOS-002",
|
|
480
|
+
name: "WorkOS required secret names are registered without values",
|
|
481
|
+
status: !workos.detected ? "not-applicable" : workos.requiredSecretsRegistered ? "passed" : "failed",
|
|
482
|
+
evidence: {
|
|
483
|
+
required: ["WORKOS_API_KEY", "WORKOS_CLIENT_ID", "WORKOS_COOKIE_PASSWORD"],
|
|
484
|
+
webhookSecretRegistered: workos.webhookSecretRegistered,
|
|
485
|
+
},
|
|
486
|
+
},
|
|
194
487
|
],
|
|
488
|
+
workos,
|
|
195
489
|
checkedAt: "deterministic",
|
|
196
490
|
},
|
|
197
|
-
error: checked.error,
|
|
198
|
-
exitCode:
|
|
491
|
+
error: prodError ?? checked.error,
|
|
492
|
+
exitCode: proofOk && scenarioOk ? 0 : 1,
|
|
199
493
|
};
|
|
200
494
|
}
|
|
201
495
|
if (options.subcommand === "config") {
|
|
@@ -225,7 +519,51 @@ export function formatAuthJson(result: AuthCommandResult): string {
|
|
|
225
519
|
return `${JSON.stringify(result, null, 2)}\n`;
|
|
226
520
|
}
|
|
227
521
|
|
|
522
|
+
function authPostureFromResult(result: AuthCommandResult): Record<string, unknown> | null {
|
|
523
|
+
const data = result.data && typeof result.data === "object" ? result.data as Record<string, unknown> : {};
|
|
524
|
+
const direct = data.schemaVersion === "0.1.0" && "classification" in data ? data : null;
|
|
525
|
+
const nested = data.authPosture && typeof data.authPosture === "object"
|
|
526
|
+
? data.authPosture as Record<string, unknown>
|
|
527
|
+
: null;
|
|
528
|
+
return direct ?? nested;
|
|
529
|
+
}
|
|
530
|
+
|
|
228
531
|
export function formatAuthHuman(result: AuthCommandResult): string {
|
|
532
|
+
const posture = authPostureFromResult(result);
|
|
533
|
+
if (posture) {
|
|
534
|
+
const classification = typeof posture.classification === "string" ? posture.classification : result.mode;
|
|
535
|
+
const reason = typeof posture.reason === "string" ? posture.reason : result.error?.message;
|
|
536
|
+
const nextActions = Array.isArray(posture.nextActions) ? posture.nextActions.filter((item): item is string => typeof item === "string") : [];
|
|
537
|
+
const lines = [
|
|
538
|
+
`Auth ${result.mode}: ${result.ok ? "ok" : "failed"} (${classification})`,
|
|
539
|
+
`Production ready: ${posture.productionReady === true ? "yes" : "no"}`,
|
|
540
|
+
...(reason ? [`Reason: ${reason}`] : []),
|
|
541
|
+
];
|
|
542
|
+
const localDevHeaders = posture.localDevHeaders && typeof posture.localDevHeaders === "object"
|
|
543
|
+
? posture.localDevHeaders as Record<string, unknown>
|
|
544
|
+
: null;
|
|
545
|
+
const acceptedHeaders = Array.isArray(localDevHeaders?.acceptedHeaders)
|
|
546
|
+
? localDevHeaders.acceptedHeaders.filter((item): item is string => typeof item === "string")
|
|
547
|
+
: posture.localOnly === true || result.mode === "dev-headers"
|
|
548
|
+
? [
|
|
549
|
+
"x-forge-user-id",
|
|
550
|
+
"x-forge-tenant-id",
|
|
551
|
+
"x-forge-role",
|
|
552
|
+
"x-forge-roles",
|
|
553
|
+
"x-forge-permissions",
|
|
554
|
+
]
|
|
555
|
+
: [];
|
|
556
|
+
if (acceptedHeaders.length > 0) {
|
|
557
|
+
lines.push("Local dev headers:", ...acceptedHeaders.map((header) => ` ${header}`));
|
|
558
|
+
}
|
|
559
|
+
if (!result.ok && result.error) {
|
|
560
|
+
lines.push(`${result.error.code}: ${result.error.message}`);
|
|
561
|
+
}
|
|
562
|
+
if (nextActions.length > 0) {
|
|
563
|
+
lines.push("", "Next:", ...nextActions.map((action) => ` ${action}`));
|
|
564
|
+
}
|
|
565
|
+
return `${lines.join("\n")}\n`;
|
|
566
|
+
}
|
|
229
567
|
if (!result.ok) {
|
|
230
568
|
return `Auth ${result.mode}: failed\n${result.error?.code}: ${result.error?.message}\n`;
|
|
231
569
|
}
|