forgeos 0.1.0-alpha.4 → 0.1.0-alpha.41
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 +433 -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 +548 -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-manager/version.ts +36 -12
- 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
|
@@ -6,6 +6,8 @@ import { serializeCanonical } from "../compiler/primitives/serialize.ts";
|
|
|
6
6
|
import { stripDeterministicHeader } from "../compiler/primitives/header.ts";
|
|
7
7
|
import { analyzeImpact, buildImpactTestPlan, detectChangedFiles } from "../impact/index.ts";
|
|
8
8
|
import type { ImpactCommandOptions, ImpactSource } from "../impact/types.ts";
|
|
9
|
+
import { buildDiffPlanFromChangeSummary, categorizeFiles } from "../workspace/change-summary.ts";
|
|
10
|
+
import type { CategorizedFileSummary, ChangeType } from "../workspace/change-summary.ts";
|
|
9
11
|
import type {
|
|
10
12
|
ReviewChanged,
|
|
11
13
|
ReviewCommandOptions,
|
|
@@ -14,6 +16,8 @@ import type {
|
|
|
14
16
|
ReviewFinding,
|
|
15
17
|
ReviewFindingCategory,
|
|
16
18
|
ReviewFindingSeverity,
|
|
19
|
+
ReviewFocus,
|
|
20
|
+
ReviewDiffPlan,
|
|
17
21
|
ReviewReport,
|
|
18
22
|
ReviewResult,
|
|
19
23
|
ReviewRisk,
|
|
@@ -41,6 +45,21 @@ const ALL_CATEGORIES: ReviewFindingCategory[] = [
|
|
|
41
45
|
"agent",
|
|
42
46
|
];
|
|
43
47
|
|
|
48
|
+
const SYSTEM_ENV_NAMES = new Set([
|
|
49
|
+
"CI",
|
|
50
|
+
"HOME",
|
|
51
|
+
"PATH",
|
|
52
|
+
"PWD",
|
|
53
|
+
"SHELL",
|
|
54
|
+
"TEMP",
|
|
55
|
+
"TMP",
|
|
56
|
+
"USER",
|
|
57
|
+
"USERNAME",
|
|
58
|
+
"USERPROFILE",
|
|
59
|
+
]);
|
|
60
|
+
|
|
61
|
+
const SECRET_ENV_PATTERN = /(^|_)(API_KEY|AUTH_TOKEN|CLIENT_SECRET|CREDENTIALS|JWT_SECRET|PASSWORD|PRIVATE_KEY|SECRET|SECRET_KEY|TOKEN|WEBHOOK_SECRET)$/;
|
|
62
|
+
|
|
44
63
|
const RULE_DOCS: ReviewRuleDoc[] = [
|
|
45
64
|
{
|
|
46
65
|
id: "runtime-command-forbidden-import",
|
|
@@ -124,6 +143,32 @@ function changedFromFiles(files: string[]): ReviewChanged {
|
|
|
124
143
|
};
|
|
125
144
|
}
|
|
126
145
|
|
|
146
|
+
function buildReviewFocus(changeSummary: CategorizedFileSummary): ReviewFocus {
|
|
147
|
+
const authoredOrder = ([
|
|
148
|
+
"source",
|
|
149
|
+
"tests",
|
|
150
|
+
"docs",
|
|
151
|
+
"config",
|
|
152
|
+
"operational",
|
|
153
|
+
"assets",
|
|
154
|
+
"other",
|
|
155
|
+
] satisfies ChangeType[])
|
|
156
|
+
.filter((type) => changeSummary.byType[type].count > 0);
|
|
157
|
+
const suggestedOrder: ChangeType[] = [...authoredOrder];
|
|
158
|
+
if (changeSummary.byType.generated.count > 0) {
|
|
159
|
+
suggestedOrder.push("generated");
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
first: "authoredChanges",
|
|
163
|
+
then: "derivedArtifacts",
|
|
164
|
+
generatedIsDerived: true,
|
|
165
|
+
suggestedOrder,
|
|
166
|
+
summary: changeSummary.byType.generated.count > 0
|
|
167
|
+
? "Review authored changes first; inspect generated artifacts after the source cause is understood."
|
|
168
|
+
: "Review authored changes directly; no generated artifacts changed.",
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
|
|
127
172
|
function loadContext(options: ReviewCommandOptions): ReviewContext {
|
|
128
173
|
const source = sourceFromOptions(options);
|
|
129
174
|
const impactSource = impactSourceFromReview(source);
|
|
@@ -190,9 +235,22 @@ function isTestFile(file: string): boolean {
|
|
|
190
235
|
return /\.(test|spec)\.(ts|tsx|js|jsx)$/.test(file) || normalize(file).startsWith("tests/");
|
|
191
236
|
}
|
|
192
237
|
|
|
238
|
+
function isDocumentationFile(file: string): boolean {
|
|
239
|
+
const normalized = normalize(file);
|
|
240
|
+
return normalized.startsWith("docs/") ||
|
|
241
|
+
normalized.startsWith("marketing/") ||
|
|
242
|
+
normalized.endsWith(".md") ||
|
|
243
|
+
normalized.endsWith(".mdx");
|
|
244
|
+
}
|
|
245
|
+
|
|
193
246
|
function isForgeToolingFile(file: string): boolean {
|
|
194
247
|
const normalized = normalize(file);
|
|
195
|
-
return normalized.startsWith("src/forge/cli/") ||
|
|
248
|
+
return normalized.startsWith("src/forge/cli/") ||
|
|
249
|
+
normalized.startsWith("src/forge/review/") ||
|
|
250
|
+
normalized.startsWith("src/forge/dev/") ||
|
|
251
|
+
normalized.startsWith("src/forge/dev-console/") ||
|
|
252
|
+
normalized.startsWith("src/forge/compiler/package-manager/") ||
|
|
253
|
+
normalized.startsWith("src/forge/compiler/integration/");
|
|
196
254
|
}
|
|
197
255
|
|
|
198
256
|
function includesCategory(options: ReviewCommandOptions, category: ReviewFindingCategory): boolean {
|
|
@@ -200,20 +258,47 @@ function includesCategory(options: ReviewCommandOptions, category: ReviewFinding
|
|
|
200
258
|
return options.include.length === 0 || options.include.includes(category);
|
|
201
259
|
}
|
|
202
260
|
|
|
203
|
-
function
|
|
261
|
+
function processEnvNamesFromText(text: string): string[] {
|
|
204
262
|
const names = new Set<string>();
|
|
205
|
-
for (const regex of [/process\.env\.([A-Z0-9_]+)/g, /process\.env\[['"]([A-Z0-9_]+)['"]\]/g
|
|
263
|
+
for (const regex of [/process\.env\.([A-Z0-9_]+)/g, /process\.env\[['"]([A-Z0-9_]+)['"]\]/g]) {
|
|
206
264
|
let match: RegExpExecArray | null;
|
|
207
265
|
while ((match = regex.exec(text))) names.add(match[1]);
|
|
208
266
|
}
|
|
209
267
|
return [...names].sort();
|
|
210
268
|
}
|
|
211
269
|
|
|
212
|
-
function
|
|
270
|
+
function ctxSecretNamesFromText(text: string): string[] {
|
|
271
|
+
const names = new Set<string>();
|
|
272
|
+
const regex = /ctx\.secrets\.get\(['"]([A-Z0-9_]+)['"]\)/g;
|
|
273
|
+
let match: RegExpExecArray | null;
|
|
274
|
+
while ((match = regex.exec(text))) names.add(match[1]);
|
|
275
|
+
return [...names].sort();
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
function isSecretEnvName(name: string): boolean {
|
|
279
|
+
if (SYSTEM_ENV_NAMES.has(name)) return false;
|
|
280
|
+
return SECRET_ENV_PATTERN.test(name);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function secretNamesFromText(text: string): string[] {
|
|
284
|
+
const names = new Set<string>();
|
|
285
|
+
for (const name of processEnvNamesFromText(text)) {
|
|
286
|
+
if (isSecretEnvName(name)) names.add(name);
|
|
287
|
+
}
|
|
288
|
+
for (const name of ctxSecretNamesFromText(text)) names.add(name);
|
|
289
|
+
return [...names].sort();
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function publicSecretNamesFromText(text: string): string[] {
|
|
213
293
|
const names = new Set<string>();
|
|
214
294
|
for (const regex of [/process\.env\.([A-Z0-9_]+)/g, /process\.env\[['"]([A-Z0-9_]+)['"]\]/g]) {
|
|
215
295
|
let match: RegExpExecArray | null;
|
|
216
|
-
while ((match = regex.exec(text)))
|
|
296
|
+
while ((match = regex.exec(text))) {
|
|
297
|
+
const name = match[1];
|
|
298
|
+
if ((name.startsWith("PUBLIC_") || name.startsWith("NEXT_PUBLIC_")) && isSecretEnvName(name)) {
|
|
299
|
+
names.add(name);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
217
302
|
}
|
|
218
303
|
return [...names].sort();
|
|
219
304
|
}
|
|
@@ -352,15 +437,16 @@ function secretRules(ctx: ReviewContext): ReviewFinding[] {
|
|
|
352
437
|
const findings: ReviewFinding[] = [];
|
|
353
438
|
const documented = ctx.envExample;
|
|
354
439
|
for (const [file, text] of ctx.fileTexts) {
|
|
355
|
-
if (isTestFile(file) ||
|
|
440
|
+
if (isTestFile(file) || isDocumentationFile(file)) continue;
|
|
356
441
|
const names = secretNamesFromText(text);
|
|
357
|
-
|
|
442
|
+
const directSecretEnvNames = processEnvNamesFromText(text).filter(isSecretEnvName);
|
|
443
|
+
if (directSecretEnvNames.length > 0 && !isForgeToolingFile(file)) {
|
|
358
444
|
findings.push(finding({
|
|
359
445
|
severity: "error",
|
|
360
446
|
category: "secrets",
|
|
361
447
|
code: "secret-direct-process-env",
|
|
362
448
|
title: "Direct process.env usage introduced",
|
|
363
|
-
message: "
|
|
449
|
+
message: `${directSecretEnvNames.join(", ")} should be accessed through ctx.secrets or generated config context.`,
|
|
364
450
|
file,
|
|
365
451
|
suggestedCommands: ["forge secrets check", "forge refactor replace-process-env <ENV_VAR>"],
|
|
366
452
|
autoRepair: { available: true, command: "forge refactor replace-process-env <ENV_VAR>", confidence: "medium" },
|
|
@@ -378,7 +464,7 @@ function secretRules(ctx: ReviewContext): ReviewFinding[] {
|
|
|
378
464
|
suggestedCommands: ["forge secrets check"],
|
|
379
465
|
}));
|
|
380
466
|
}
|
|
381
|
-
if (
|
|
467
|
+
if (publicSecretNamesFromText(text).includes(name)) {
|
|
382
468
|
findings.push(finding({
|
|
383
469
|
severity: "blocking",
|
|
384
470
|
category: "secrets",
|
|
@@ -693,6 +779,9 @@ function buildReport(options: ReviewCommandOptions): ReviewReport {
|
|
|
693
779
|
findings: findings.map((item) => [item.code, item.file, item.severity]),
|
|
694
780
|
})).slice(0, 12)}`;
|
|
695
781
|
const generatedPaths = ctx.changed.generated;
|
|
782
|
+
const changeSummary = categorizeFiles(ctx.changed.files);
|
|
783
|
+
const reviewFocus = buildReviewFocus(changeSummary);
|
|
784
|
+
const diffPlan: ReviewDiffPlan = buildDiffPlanFromChangeSummary(changeSummary);
|
|
696
785
|
return {
|
|
697
786
|
schemaVersion: "0.1.0",
|
|
698
787
|
reviewVersion: REVIEW_VERSION,
|
|
@@ -709,6 +798,9 @@ function buildReport(options: ReviewCommandOptions): ReviewReport {
|
|
|
709
798
|
risk,
|
|
710
799
|
findings,
|
|
711
800
|
changed: ctx.changed,
|
|
801
|
+
changeSummary,
|
|
802
|
+
reviewFocus,
|
|
803
|
+
diffPlan,
|
|
712
804
|
impacted: ctx.impacted,
|
|
713
805
|
checks: [
|
|
714
806
|
{ name: "impact-analysis", ok: true, message: `risk ${risk.level}` },
|
|
@@ -755,7 +847,13 @@ ${report.summary.bullets.map((bullet) => `- ${bullet}`).join("\n")}
|
|
|
755
847
|
|
|
756
848
|
## Changed Files
|
|
757
849
|
|
|
758
|
-
${report.changed.files.map((file) => `- ${file}`).join("\n") || "- none"}
|
|
850
|
+
${report.changed.files.filter((file) => !file.startsWith(`${GENERATED}/`) && file !== "forge.lock").map((file) => `- ${file}`).join("\n") || "- none"}
|
|
851
|
+
|
|
852
|
+
Generated artifacts are derived and collapsed by default.
|
|
853
|
+
|
|
854
|
+
- Generated files: ${report.diffPlan.generatedFiles}
|
|
855
|
+
- Authored diff: \`${report.diffPlan.authoredDiffCommand}\`
|
|
856
|
+
- Generated diff: \`${report.diffPlan.generatedDiffCommand}\`
|
|
759
857
|
|
|
760
858
|
## Findings
|
|
761
859
|
|
|
@@ -958,8 +1056,54 @@ export function runReviewCommand(options: ReviewCommandOptions): ReviewResult {
|
|
|
958
1056
|
}
|
|
959
1057
|
}
|
|
960
1058
|
|
|
961
|
-
|
|
962
|
-
|
|
1059
|
+
function compactReviewReport(result: ReviewResult): unknown {
|
|
1060
|
+
const report = result.report;
|
|
1061
|
+
if (!report) return result.reports ?? result.explanation ?? result;
|
|
1062
|
+
const impacted = {
|
|
1063
|
+
...report.impacted,
|
|
1064
|
+
generatedArtifacts: report.impacted.generatedArtifacts.length,
|
|
1065
|
+
};
|
|
1066
|
+
return {
|
|
1067
|
+
schemaVersion: report.schemaVersion,
|
|
1068
|
+
reviewVersion: report.reviewVersion,
|
|
1069
|
+
ok: result.ok,
|
|
1070
|
+
id: report.id,
|
|
1071
|
+
source: report.source,
|
|
1072
|
+
summary: report.summary,
|
|
1073
|
+
risk: report.risk,
|
|
1074
|
+
findings: report.findings,
|
|
1075
|
+
changed: {
|
|
1076
|
+
files: report.changed.files.length,
|
|
1077
|
+
tests: report.changed.tests.length,
|
|
1078
|
+
sourceFiles: report.changed.sourceFiles.length,
|
|
1079
|
+
generated: report.changed.generated.length,
|
|
1080
|
+
packageFiles: report.changed.packageFiles.length,
|
|
1081
|
+
deployFiles: report.changed.deployFiles.length,
|
|
1082
|
+
},
|
|
1083
|
+
changeSummary: report.changeSummary,
|
|
1084
|
+
reviewFocus: report.reviewFocus,
|
|
1085
|
+
diffPlan: report.diffPlan,
|
|
1086
|
+
impacted,
|
|
1087
|
+
checks: report.checks,
|
|
1088
|
+
recommendedCommands: report.recommendedCommands,
|
|
1089
|
+
humanChecklist: report.humanChecklist,
|
|
1090
|
+
agentInstructions: report.agentInstructions,
|
|
1091
|
+
generatedArtifacts: {
|
|
1092
|
+
paths: report.generatedArtifacts.paths.length,
|
|
1093
|
+
stale: report.generatedArtifacts.stale,
|
|
1094
|
+
},
|
|
1095
|
+
writeResult: result.writeResult,
|
|
1096
|
+
diagnostics: result.diagnostics,
|
|
1097
|
+
exitCode: result.exitCode,
|
|
1098
|
+
fullCommand: "forge review run --changed --full --json",
|
|
1099
|
+
};
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
export function formatReviewJson(result: ReviewResult, options: { full?: boolean } = {}): string {
|
|
1103
|
+
const payload = options.full
|
|
1104
|
+
? result.report ?? result.reports ?? result.explanation ?? result
|
|
1105
|
+
: compactReviewReport(result);
|
|
1106
|
+
return `${JSON.stringify(payload, null, 2)}\n`;
|
|
963
1107
|
}
|
|
964
1108
|
|
|
965
1109
|
export function formatReviewHuman(result: ReviewResult): string {
|
|
@@ -978,6 +1122,8 @@ ${result.reports.map((report) => `- ${report.id}: ${report.dir}`).join("\n") ||
|
|
|
978
1122
|
|
|
979
1123
|
Risk: ${report.risk.level} (${report.risk.score})
|
|
980
1124
|
Findings: ${report.findings.length}
|
|
1125
|
+
Review focus: ${report.reviewFocus.summary}
|
|
1126
|
+
Review order: ${report.reviewFocus.suggestedOrder.join(" -> ") || "none"}
|
|
981
1127
|
|
|
982
1128
|
Blocking issues:
|
|
983
1129
|
${report.findings.filter((finding) => finding.severity === "blocking").map((finding) => ` - ${finding.code}: ${finding.message}`).join("\n") || " - none"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Diagnostic } from "../compiler/types/diagnostic.ts";
|
|
2
2
|
import type { ImpactedSystems, ImpactSource } from "../impact/types.ts";
|
|
3
|
+
import type { CategorizedFileSummary, ChangeType, DiffPlan } from "../workspace/change-summary.ts";
|
|
3
4
|
|
|
4
5
|
export type ReviewSubcommand = "run" | "inspect" | "list" | "explain";
|
|
5
6
|
export type ReviewMode = "quick" | "standard" | "strict";
|
|
@@ -26,6 +27,7 @@ export interface ReviewCommandOptions {
|
|
|
26
27
|
json: boolean;
|
|
27
28
|
md: boolean;
|
|
28
29
|
sarif: boolean;
|
|
30
|
+
full?: boolean;
|
|
29
31
|
write: boolean;
|
|
30
32
|
changed: boolean;
|
|
31
33
|
staged: boolean;
|
|
@@ -60,6 +62,16 @@ export interface ReviewChanged {
|
|
|
60
62
|
deployFiles: string[];
|
|
61
63
|
}
|
|
62
64
|
|
|
65
|
+
export interface ReviewFocus {
|
|
66
|
+
first: "authoredChanges";
|
|
67
|
+
then: "derivedArtifacts";
|
|
68
|
+
generatedIsDerived: boolean;
|
|
69
|
+
suggestedOrder: ChangeType[];
|
|
70
|
+
summary: string;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export type ReviewDiffPlan = DiffPlan;
|
|
74
|
+
|
|
63
75
|
export interface ReviewSummary {
|
|
64
76
|
title: string;
|
|
65
77
|
bullets: string[];
|
|
@@ -130,6 +142,9 @@ export interface ReviewReport {
|
|
|
130
142
|
risk: ReviewRisk;
|
|
131
143
|
findings: ReviewFinding[];
|
|
132
144
|
changed: ReviewChanged;
|
|
145
|
+
changeSummary: CategorizedFileSummary;
|
|
146
|
+
reviewFocus: ReviewFocus;
|
|
147
|
+
diffPlan: ReviewDiffPlan;
|
|
133
148
|
impacted: ImpactedSystems;
|
|
134
149
|
checks: ReviewCheckResult[];
|
|
135
150
|
recommendedCommands: string[];
|
|
@@ -146,3 +146,20 @@ export function buildDefaultAuthRegistry(
|
|
|
146
146
|
requiresTenant,
|
|
147
147
|
};
|
|
148
148
|
}
|
|
149
|
+
|
|
150
|
+
export function buildWorkOSAuthRegistry(
|
|
151
|
+
requiresTenant: boolean,
|
|
152
|
+
): AuthRegistryArtifact {
|
|
153
|
+
return {
|
|
154
|
+
...buildDefaultAuthRegistry(requiresTenant),
|
|
155
|
+
claims: {
|
|
156
|
+
userId: "sub",
|
|
157
|
+
tenantId: "organization_id",
|
|
158
|
+
role: "role",
|
|
159
|
+
roles: "roles",
|
|
160
|
+
permissions: "permissions",
|
|
161
|
+
email: "email",
|
|
162
|
+
name: "name",
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
}
|
|
@@ -22,6 +22,18 @@ function roleAllowed(
|
|
|
22
22
|
return roles.some((role) => entry.roles.includes(role));
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
function permissionAllowed(
|
|
26
|
+
matrix: PermissionMatrix,
|
|
27
|
+
policy: string,
|
|
28
|
+
permissions: string[],
|
|
29
|
+
): boolean {
|
|
30
|
+
const entry = matrix.entries.find((candidate) => candidate.policy === policy);
|
|
31
|
+
if (!entry) {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
return permissions.some((permission) => (entry.permissions ?? []).includes(permission));
|
|
35
|
+
}
|
|
36
|
+
|
|
25
37
|
function authRoles(auth: Extract<AuthContext, { kind: "user" }>): string[] {
|
|
26
38
|
return [...new Set([...(auth.role ? [auth.role] : []), ...(auth.roles ?? [])])];
|
|
27
39
|
}
|
|
@@ -93,7 +105,8 @@ function evaluateAuthRequirement(
|
|
|
93
105
|
}
|
|
94
106
|
|
|
95
107
|
const roles = authRoles(auth);
|
|
96
|
-
const allowed = roleAllowed(matrix, resolved.policy, roles)
|
|
108
|
+
const allowed = roleAllowed(matrix, resolved.policy, roles) ||
|
|
109
|
+
permissionAllowed(matrix, resolved.policy, auth.permissions ?? []);
|
|
97
110
|
const role = primaryRole(roles);
|
|
98
111
|
if (allowed) {
|
|
99
112
|
return { allowed: true, policy: resolved.policy, role };
|
|
@@ -102,7 +115,7 @@ function evaluateAuthRequirement(
|
|
|
102
115
|
return {
|
|
103
116
|
allowed: false,
|
|
104
117
|
code: FORGE_POLICY_DENIED,
|
|
105
|
-
message: `role '${role}' denied for policy '${resolved.policy}'`,
|
|
118
|
+
message: `role '${role}' and permissions denied for policy '${resolved.policy}'`,
|
|
106
119
|
policy: resolved.policy,
|
|
107
120
|
role,
|
|
108
121
|
};
|
|
@@ -3,37 +3,87 @@ import type { AuthContext } from "./types.ts";
|
|
|
3
3
|
export interface AuthHeaderInput {
|
|
4
4
|
userId?: string;
|
|
5
5
|
tenantId?: string;
|
|
6
|
+
organizationId?: string;
|
|
7
|
+
organizationMembershipId?: string;
|
|
6
8
|
role?: string;
|
|
9
|
+
roles?: string[];
|
|
10
|
+
permissions?: string[];
|
|
11
|
+
claims?: Record<string, unknown>;
|
|
7
12
|
}
|
|
8
13
|
|
|
9
14
|
export interface CliAuthInput {
|
|
10
15
|
userId?: string;
|
|
11
16
|
tenantId?: string;
|
|
12
17
|
role?: string;
|
|
18
|
+
roles?: string[];
|
|
19
|
+
permissions?: string[];
|
|
13
20
|
}
|
|
14
21
|
|
|
15
22
|
export function resolveAuthFromHeaders(input: AuthHeaderInput): AuthContext {
|
|
16
|
-
const { userId,
|
|
17
|
-
|
|
23
|
+
const { userId, role } = input;
|
|
24
|
+
const tenantId = input.tenantId ?? input.organizationId;
|
|
25
|
+
const roles = [...new Set([...(role ? [role] : []), ...(input.roles ?? [])])];
|
|
26
|
+
const claims = {
|
|
27
|
+
...(input.claims ?? {}),
|
|
28
|
+
...(input.organizationId ? { organization_id: input.organizationId } : {}),
|
|
29
|
+
...(input.organizationMembershipId
|
|
30
|
+
? { organization_membership_id: input.organizationMembershipId }
|
|
31
|
+
: {}),
|
|
32
|
+
};
|
|
33
|
+
const hasClaims = Object.keys(claims).length > 0;
|
|
34
|
+
if (userId && (role || roles.length > 0 || (input.permissions ?? []).length > 0 || hasClaims)) {
|
|
18
35
|
return {
|
|
19
36
|
kind: "user",
|
|
20
37
|
userId,
|
|
21
38
|
...(tenantId ? { tenantId } : {}),
|
|
22
|
-
role,
|
|
23
|
-
roles
|
|
24
|
-
permissions: [],
|
|
39
|
+
...(role ? { role } : roles[0] ? { role: roles[0] } : {}),
|
|
40
|
+
roles,
|
|
41
|
+
permissions: [...new Set(input.permissions ?? [])].sort(),
|
|
25
42
|
token: {
|
|
26
43
|
issuer: "dev-headers",
|
|
27
44
|
audience: "dev",
|
|
28
45
|
subject: userId,
|
|
29
46
|
authProvider: "dev-headers",
|
|
30
47
|
},
|
|
31
|
-
claims: {},
|
|
48
|
+
...(hasClaims ? { claims } : {}),
|
|
32
49
|
};
|
|
33
50
|
}
|
|
34
51
|
return { kind: "anonymous" };
|
|
35
52
|
}
|
|
36
53
|
|
|
54
|
+
function parseHeaderList(value: string | null): string[] {
|
|
55
|
+
if (!value) {
|
|
56
|
+
return [];
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
const parsed = JSON.parse(value) as unknown;
|
|
60
|
+
if (Array.isArray(parsed)) {
|
|
61
|
+
return parsed.filter((entry): entry is string => typeof entry === "string" && entry.length > 0);
|
|
62
|
+
}
|
|
63
|
+
} catch {
|
|
64
|
+
// Fall through to comma-separated dev header parsing.
|
|
65
|
+
}
|
|
66
|
+
return value
|
|
67
|
+
.split(",")
|
|
68
|
+
.map((entry) => entry.trim())
|
|
69
|
+
.filter(Boolean);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function parseClaims(value: string | null): Record<string, unknown> | undefined {
|
|
73
|
+
if (!value) {
|
|
74
|
+
return undefined;
|
|
75
|
+
}
|
|
76
|
+
try {
|
|
77
|
+
const parsed = JSON.parse(value) as unknown;
|
|
78
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
79
|
+
return parsed as Record<string, unknown>;
|
|
80
|
+
}
|
|
81
|
+
} catch {
|
|
82
|
+
// Invalid dev claims should not break the whole request; policies can still use explicit headers.
|
|
83
|
+
}
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
|
|
37
87
|
export function resolveAuthFromCli(input: CliAuthInput): AuthContext {
|
|
38
88
|
return resolveAuthFromHeaders(input);
|
|
39
89
|
}
|
|
@@ -42,7 +92,12 @@ export function parseAuthHeaders(headers: Headers): AuthContext {
|
|
|
42
92
|
return resolveAuthFromHeaders({
|
|
43
93
|
userId: headers.get("x-forge-user-id") ?? undefined,
|
|
44
94
|
tenantId: headers.get("x-forge-tenant-id") ?? undefined,
|
|
95
|
+
organizationId: headers.get("x-forge-organization-id") ?? undefined,
|
|
96
|
+
organizationMembershipId: headers.get("x-forge-organization-membership-id") ?? undefined,
|
|
45
97
|
role: headers.get("x-forge-role") ?? undefined,
|
|
98
|
+
roles: parseHeaderList(headers.get("x-forge-roles")),
|
|
99
|
+
permissions: parseHeaderList(headers.get("x-forge-permissions")),
|
|
100
|
+
claims: parseClaims(headers.get("x-forge-claims")),
|
|
46
101
|
});
|
|
47
102
|
}
|
|
48
103
|
|
|
@@ -72,6 +72,7 @@ export function snapshotAuth(auth: AuthContext): AuthSnapshot {
|
|
|
72
72
|
...(auth.email ? { email: auth.email } : {}),
|
|
73
73
|
...(auth.name ? { name: auth.name } : {}),
|
|
74
74
|
...(auth.token ? { token: auth.token } : {}),
|
|
75
|
+
...(auth.claims ? { claims: auth.claims } : {}),
|
|
75
76
|
};
|
|
76
77
|
}
|
|
77
78
|
|
|
@@ -4,7 +4,7 @@ import { FORGE_DB_CONNECT_FAILED } from "../../compiler/diagnostics/codes.ts";
|
|
|
4
4
|
import type { Diagnostic } from "../../compiler/types/diagnostic.ts";
|
|
5
5
|
import type { DbAdapter, DbAdapterKind } from "./adapter.ts";
|
|
6
6
|
import { createMemoryAdapter } from "./memory-adapter.ts";
|
|
7
|
-
import { createPgliteAdapter } from "./pglite-adapter.ts";
|
|
7
|
+
import { createPgliteAdapter, DEFAULT_PGLITE_DIR } from "./pglite-adapter.ts";
|
|
8
8
|
import { createPostgresAdapter } from "./postgres-adapter.ts";
|
|
9
9
|
|
|
10
10
|
export interface CreateDbAdapterOptions {
|
|
@@ -19,8 +19,6 @@ export interface CreateDbAdapterResult {
|
|
|
19
19
|
diagnostics: Diagnostic[];
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
const DEFAULT_PGLITE_DIR = ".forge/pglite";
|
|
23
|
-
|
|
24
22
|
export async function createDbAdapter(
|
|
25
23
|
options: CreateDbAdapterOptions,
|
|
26
24
|
): Promise<CreateDbAdapterResult> {
|
|
@@ -37,6 +37,10 @@ export interface GeneratedDbClientOptions {
|
|
|
37
37
|
writeTracker?: WriteTracker;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
function camelCase(value: string): string {
|
|
41
|
+
return value.replace(/[_-]([a-zA-Z0-9])/g, (_match, char: string) => char.toUpperCase());
|
|
42
|
+
}
|
|
43
|
+
|
|
40
44
|
function quoteIdent(ident: string): string {
|
|
41
45
|
return `"${ident.replace(/"/g, '""')}"`;
|
|
42
46
|
}
|
|
@@ -286,8 +290,15 @@ export function createGeneratedDbClient(
|
|
|
286
290
|
): DbClient {
|
|
287
291
|
const client: DbClient = {};
|
|
288
292
|
|
|
289
|
-
for (const [
|
|
290
|
-
|
|
293
|
+
for (const [accessName, entry] of Object.entries(tableMap).sort()) {
|
|
294
|
+
const tableClient = createTableClient(tx, entry.tableName, entry, options);
|
|
295
|
+
client[accessName] = tableClient;
|
|
296
|
+
|
|
297
|
+
for (const alias of new Set([camelCase(accessName), camelCase(entry.tableName)])) {
|
|
298
|
+
if (alias && client[alias] === undefined) {
|
|
299
|
+
client[alias] = tableClient;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
291
302
|
}
|
|
292
303
|
|
|
293
304
|
return client;
|