@ankhorage/infra 4.1.12 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/README.md +21 -32
- package/dist/cli/bin.d.ts +1 -8
- package/dist/cli/bin.d.ts.map +1 -1
- package/dist/cli/bin.js +2 -34
- package/dist/cli/bin.js.map +1 -1
- package/dist/cli/commands/destroy.d.ts +11 -0
- package/dist/cli/commands/destroy.d.ts.map +1 -0
- package/dist/cli/commands/destroy.js +51 -0
- package/dist/cli/commands/destroy.js.map +1 -0
- package/dist/cli/commands/down.d.ts +11 -0
- package/dist/cli/commands/down.d.ts.map +1 -0
- package/dist/cli/commands/down.js +27 -0
- package/dist/cli/commands/down.js.map +1 -0
- package/dist/cli/commands/generate.d.ts +11 -0
- package/dist/cli/commands/generate.d.ts.map +1 -0
- package/dist/cli/commands/generate.js +29 -0
- package/dist/cli/commands/generate.js.map +1 -0
- package/dist/cli/commands/outputs.d.ts +11 -0
- package/dist/cli/commands/outputs.d.ts.map +1 -0
- package/dist/cli/commands/outputs.js +25 -0
- package/dist/cli/commands/outputs.js.map +1 -0
- package/dist/cli/commands/plan.d.ts +11 -0
- package/dist/cli/commands/plan.d.ts.map +1 -0
- package/dist/cli/commands/plan.js +19 -0
- package/dist/cli/commands/plan.js.map +1 -0
- package/dist/cli/commands/status.d.ts +11 -0
- package/dist/cli/commands/status.d.ts.map +1 -0
- package/dist/cli/commands/status.js +19 -0
- package/dist/cli/commands/status.js.map +1 -0
- package/dist/cli/commands/up.d.ts +11 -0
- package/dist/cli/commands/up.d.ts.map +1 -0
- package/dist/cli/commands/up.js +28 -0
- package/dist/cli/commands/up.js.map +1 -0
- package/dist/cli/commands/validate.d.ts +11 -0
- package/dist/cli/commands/validate.d.ts.map +1 -0
- package/dist/cli/commands/validate.js +19 -0
- package/dist/cli/commands/validate.js.map +1 -0
- package/dist/cli/constants.d.ts +66 -0
- package/dist/cli/constants.d.ts.map +1 -0
- package/dist/cli/constants.js +19 -0
- package/dist/cli/constants.js.map +1 -0
- package/dist/cli/createDefaultInfraCommandContext.d.ts +4 -0
- package/dist/cli/createDefaultInfraCommandContext.d.ts.map +1 -0
- package/dist/{commandContext.js → cli/createDefaultInfraCommandContext.js} +4 -3
- package/dist/cli/createDefaultInfraCommandContext.js.map +1 -0
- package/dist/cli/createInfraRuntimeProvider.d.ts +5 -0
- package/dist/cli/createInfraRuntimeProvider.d.ts.map +1 -0
- package/dist/cli/createInfraRuntimeProvider.js +22 -0
- package/dist/cli/createInfraRuntimeProvider.js.map +1 -0
- package/dist/cli/createProviderCommandDescriptors.d.ts +4 -0
- package/dist/cli/createProviderCommandDescriptors.d.ts.map +1 -0
- package/dist/cli/createProviderCommandDescriptors.js +6 -0
- package/dist/cli/createProviderCommandDescriptors.js.map +1 -0
- package/dist/cli/findInfraCommand.d.ts +4 -0
- package/dist/cli/findInfraCommand.d.ts.map +1 -0
- package/dist/cli/findInfraCommand.js +6 -0
- package/dist/cli/findInfraCommand.js.map +1 -0
- package/dist/cli/index.d.ts +3 -8
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +2 -24
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/renderInfraRootHelp.d.ts +3 -0
- package/dist/cli/renderInfraRootHelp.d.ts.map +1 -0
- package/dist/cli/renderInfraRootHelp.js +21 -0
- package/dist/cli/renderInfraRootHelp.js.map +1 -0
- package/dist/cli/renderUnknownInfraCommand.d.ts +3 -0
- package/dist/cli/renderUnknownInfraCommand.d.ts.map +1 -0
- package/dist/cli/renderUnknownInfraCommand.js +5 -0
- package/dist/cli/renderUnknownInfraCommand.js.map +1 -0
- package/dist/cli/runInfraCliAsync.d.ts +10 -0
- package/dist/cli/runInfraCliAsync.d.ts.map +1 -0
- package/dist/cli/runInfraCliAsync.js +34 -0
- package/dist/cli/runInfraCliAsync.js.map +1 -0
- package/dist/cli/runInfraCommandAsync.d.ts +4 -0
- package/dist/cli/runInfraCommandAsync.d.ts.map +1 -0
- package/dist/cli/runInfraCommandAsync.js +100 -0
- package/dist/cli/runInfraCommandAsync.js.map +1 -0
- package/dist/cli/utils/prepareInfraCommandOperationAsync.d.ts +4 -0
- package/dist/cli/utils/prepareInfraCommandOperationAsync.d.ts.map +1 -0
- package/dist/cli/utils/prepareInfraCommandOperationAsync.js +45 -0
- package/dist/cli/utils/prepareInfraCommandOperationAsync.js.map +1 -0
- package/dist/cli/utils/requireInfraSuccess.d.ts +7 -0
- package/dist/cli/utils/requireInfraSuccess.d.ts.map +1 -0
- package/dist/cli/utils/requireInfraSuccess.js +17 -0
- package/dist/cli/utils/requireInfraSuccess.js.map +1 -0
- package/dist/cli/utils/resolveInfraPersistence.d.ts +4 -0
- package/dist/cli/utils/resolveInfraPersistence.d.ts.map +1 -0
- package/dist/cli/utils/resolveInfraPersistence.js +17 -0
- package/dist/cli/utils/resolveInfraPersistence.js.map +1 -0
- package/dist/cli/utils/writeInfraEnvironmentOutputs.d.ts +5 -0
- package/dist/cli/utils/writeInfraEnvironmentOutputs.d.ts.map +1 -0
- package/dist/cli/utils/writeInfraEnvironmentOutputs.js +16 -0
- package/dist/cli/utils/writeInfraEnvironmentOutputs.js.map +1 -0
- package/dist/cli/utils/writeInfraStructured.d.ts +4 -0
- package/dist/cli/utils/writeInfraStructured.d.ts.map +1 -0
- package/dist/cli/utils/writeInfraStructured.js +8 -0
- package/dist/cli/utils/writeInfraStructured.js.map +1 -0
- package/dist/constants.d.ts +10 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/{packageMetadata.js → constants.js} +6 -3
- package/dist/constants.js.map +1 -0
- package/dist/features/environment-lifecycle/adapters/outbound/createEnvironmentInfraCredentialPort.d.ts +4 -0
- package/dist/features/environment-lifecycle/adapters/outbound/createEnvironmentInfraCredentialPort.d.ts.map +1 -0
- package/dist/features/environment-lifecycle/adapters/outbound/createEnvironmentInfraCredentialPort.js +35 -0
- package/dist/features/environment-lifecycle/adapters/outbound/createEnvironmentInfraCredentialPort.js.map +1 -0
- package/dist/features/environment-lifecycle/adapters/outbound/createEnvironmentInfraSecretPort.d.ts +4 -0
- package/dist/features/environment-lifecycle/adapters/outbound/createEnvironmentInfraSecretPort.d.ts.map +1 -0
- package/dist/features/environment-lifecycle/adapters/outbound/createEnvironmentInfraSecretPort.js +23 -0
- package/dist/features/environment-lifecycle/adapters/outbound/createEnvironmentInfraSecretPort.js.map +1 -0
- package/dist/features/environment-lifecycle/adapters/outbound/createNodeInfraAdapterPackageResolver.d.ts +4 -0
- package/dist/features/environment-lifecycle/adapters/outbound/createNodeInfraAdapterPackageResolver.d.ts.map +1 -0
- package/dist/features/environment-lifecycle/adapters/outbound/createNodeInfraAdapterPackageResolver.js +9 -0
- package/dist/features/environment-lifecycle/adapters/outbound/createNodeInfraAdapterPackageResolver.js.map +1 -0
- package/dist/features/environment-lifecycle/adapters/outbound/readStoredInfraStateAsync.d.ts +5 -0
- package/dist/features/environment-lifecycle/adapters/outbound/readStoredInfraStateAsync.d.ts.map +1 -0
- package/dist/features/environment-lifecycle/adapters/outbound/readStoredInfraStateAsync.js +28 -0
- package/dist/features/environment-lifecycle/adapters/outbound/readStoredInfraStateAsync.js.map +1 -0
- package/dist/features/environment-lifecycle/adapters/outbound/removeStoredInfraStateAsync.d.ts +4 -0
- package/dist/features/environment-lifecycle/adapters/outbound/removeStoredInfraStateAsync.d.ts.map +1 -0
- package/dist/features/environment-lifecycle/adapters/outbound/removeStoredInfraStateAsync.js +7 -0
- package/dist/features/environment-lifecycle/adapters/outbound/removeStoredInfraStateAsync.js.map +1 -0
- package/dist/features/environment-lifecycle/adapters/outbound/resolveInfraProjectAsync.d.ts +7 -0
- package/dist/features/environment-lifecycle/adapters/outbound/resolveInfraProjectAsync.d.ts.map +1 -0
- package/dist/{project.js → features/environment-lifecycle/adapters/outbound/resolveInfraProjectAsync.js} +10 -34
- package/dist/features/environment-lifecycle/adapters/outbound/resolveInfraProjectAsync.js.map +1 -0
- package/dist/features/environment-lifecycle/adapters/outbound/writeInfraGeneratedArtifactsAsync.d.ts +5 -0
- package/dist/features/environment-lifecycle/adapters/outbound/writeInfraGeneratedArtifactsAsync.d.ts.map +1 -0
- package/dist/features/environment-lifecycle/adapters/outbound/writeInfraGeneratedArtifactsAsync.js +28 -0
- package/dist/features/environment-lifecycle/adapters/outbound/writeInfraGeneratedArtifactsAsync.js.map +1 -0
- package/dist/features/environment-lifecycle/adapters/outbound/writeStoredInfraStateAsync.d.ts +4 -0
- package/dist/features/environment-lifecycle/adapters/outbound/writeStoredInfraStateAsync.d.ts.map +1 -0
- package/dist/features/environment-lifecycle/adapters/outbound/writeStoredInfraStateAsync.js +16 -0
- package/dist/features/environment-lifecycle/adapters/outbound/writeStoredInfraStateAsync.js.map +1 -0
- package/dist/features/environment-lifecycle/application/ports/outbound/infraAdapterPackage.d.ts +9 -0
- package/dist/features/environment-lifecycle/application/ports/outbound/infraAdapterPackage.d.ts.map +1 -0
- package/dist/features/environment-lifecycle/application/ports/outbound/infraAdapterPackage.js +2 -0
- package/dist/features/environment-lifecycle/application/ports/outbound/infraAdapterPackage.js.map +1 -0
- package/dist/features/environment-lifecycle/application/use-cases/collectInfraWorkloadsAsync.d.ts +4 -0
- package/dist/features/environment-lifecycle/application/use-cases/collectInfraWorkloadsAsync.d.ts.map +1 -0
- package/dist/features/environment-lifecycle/application/use-cases/collectInfraWorkloadsAsync.js +15 -0
- package/dist/features/environment-lifecycle/application/use-cases/collectInfraWorkloadsAsync.js.map +1 -0
- package/dist/features/environment-lifecycle/application/use-cases/destroyInfraEnvironmentAsync.d.ts +4 -0
- package/dist/features/environment-lifecycle/application/use-cases/destroyInfraEnvironmentAsync.d.ts.map +1 -0
- package/dist/features/environment-lifecycle/application/use-cases/destroyInfraEnvironmentAsync.js +84 -0
- package/dist/features/environment-lifecycle/application/use-cases/destroyInfraEnvironmentAsync.js.map +1 -0
- package/dist/features/environment-lifecycle/application/use-cases/downInfraEnvironmentAsync.d.ts +4 -0
- package/dist/features/environment-lifecycle/application/use-cases/downInfraEnvironmentAsync.d.ts.map +1 -0
- package/dist/features/environment-lifecycle/application/use-cases/downInfraEnvironmentAsync.js +55 -0
- package/dist/features/environment-lifecycle/application/use-cases/downInfraEnvironmentAsync.js.map +1 -0
- package/dist/features/environment-lifecycle/application/use-cases/generateInfraEnvironmentAsync.d.ts +4 -0
- package/dist/features/environment-lifecycle/application/use-cases/generateInfraEnvironmentAsync.d.ts.map +1 -0
- package/dist/features/environment-lifecycle/application/use-cases/generateInfraEnvironmentAsync.js +38 -0
- package/dist/features/environment-lifecycle/application/use-cases/generateInfraEnvironmentAsync.js.map +1 -0
- package/dist/features/environment-lifecycle/application/use-cases/getInfraEnvironmentOutputs.d.ts +4 -0
- package/dist/features/environment-lifecycle/application/use-cases/getInfraEnvironmentOutputs.d.ts.map +1 -0
- package/dist/features/environment-lifecycle/application/use-cases/getInfraEnvironmentOutputs.js +34 -0
- package/dist/features/environment-lifecycle/application/use-cases/getInfraEnvironmentOutputs.js.map +1 -0
- package/dist/features/environment-lifecycle/application/use-cases/planInfraEnvironmentAsync.d.ts +4 -0
- package/dist/features/environment-lifecycle/application/use-cases/planInfraEnvironmentAsync.d.ts.map +1 -0
- package/dist/features/environment-lifecycle/application/use-cases/planInfraEnvironmentAsync.js +57 -0
- package/dist/features/environment-lifecycle/application/use-cases/planInfraEnvironmentAsync.js.map +1 -0
- package/dist/features/environment-lifecycle/application/use-cases/prepareInfraOperationAsync.d.ts +5 -0
- package/dist/features/environment-lifecycle/application/use-cases/prepareInfraOperationAsync.d.ts.map +1 -0
- package/dist/features/environment-lifecycle/application/use-cases/prepareInfraOperationAsync.js +109 -0
- package/dist/features/environment-lifecycle/application/use-cases/prepareInfraOperationAsync.js.map +1 -0
- package/dist/features/environment-lifecycle/application/use-cases/resolveInfraAdaptersAsync.d.ts +6 -0
- package/dist/features/environment-lifecycle/application/use-cases/resolveInfraAdaptersAsync.d.ts.map +1 -0
- package/dist/features/environment-lifecycle/application/use-cases/resolveInfraAdaptersAsync.js +181 -0
- package/dist/features/environment-lifecycle/application/use-cases/resolveInfraAdaptersAsync.js.map +1 -0
- package/dist/features/environment-lifecycle/application/use-cases/statusInfraEnvironmentAsync.d.ts +4 -0
- package/dist/features/environment-lifecycle/application/use-cases/statusInfraEnvironmentAsync.d.ts.map +1 -0
- package/dist/features/environment-lifecycle/application/use-cases/statusInfraEnvironmentAsync.js +68 -0
- package/dist/features/environment-lifecycle/application/use-cases/statusInfraEnvironmentAsync.js.map +1 -0
- package/dist/features/environment-lifecycle/application/use-cases/upInfraEnvironmentAsync.d.ts +4 -0
- package/dist/features/environment-lifecycle/application/use-cases/upInfraEnvironmentAsync.d.ts.map +1 -0
- package/dist/features/environment-lifecycle/application/use-cases/upInfraEnvironmentAsync.js +98 -0
- package/dist/features/environment-lifecycle/application/use-cases/upInfraEnvironmentAsync.js.map +1 -0
- package/dist/features/environment-lifecycle/application/use-cases/validateInfraAdaptersAsync.d.ts +5 -0
- package/dist/features/environment-lifecycle/application/use-cases/validateInfraAdaptersAsync.d.ts.map +1 -0
- package/dist/features/environment-lifecycle/application/use-cases/validateInfraAdaptersAsync.js +17 -0
- package/dist/features/environment-lifecycle/application/use-cases/validateInfraAdaptersAsync.js.map +1 -0
- package/dist/features/environment-lifecycle/application/use-cases/validateInfraEnvironmentAsync.d.ts +4 -0
- package/dist/features/environment-lifecycle/application/use-cases/validateInfraEnvironmentAsync.d.ts.map +1 -0
- package/dist/features/environment-lifecycle/application/use-cases/validateInfraEnvironmentAsync.js +13 -0
- package/dist/features/environment-lifecycle/application/use-cases/validateInfraEnvironmentAsync.js.map +1 -0
- package/dist/features/environment-lifecycle/composition/createInfraCommandServices.d.ts +4 -0
- package/dist/features/environment-lifecycle/composition/createInfraCommandServices.d.ts.map +1 -0
- package/dist/features/environment-lifecycle/composition/createInfraCommandServices.js +43 -0
- package/dist/features/environment-lifecycle/composition/createInfraCommandServices.js.map +1 -0
- package/dist/features/environment-lifecycle/domain/orderInfraPlanActions.d.ts +4 -0
- package/dist/features/environment-lifecycle/domain/orderInfraPlanActions.d.ts.map +1 -0
- package/dist/features/environment-lifecycle/domain/orderInfraPlanActions.js +54 -0
- package/dist/features/environment-lifecycle/domain/orderInfraPlanActions.js.map +1 -0
- package/dist/features/environment-lifecycle/domain/resolveInfraEnvironment.d.ts +5 -0
- package/dist/features/environment-lifecycle/domain/resolveInfraEnvironment.d.ts.map +1 -0
- package/dist/features/environment-lifecycle/domain/resolveInfraEnvironment.js +39 -0
- package/dist/features/environment-lifecycle/domain/resolveInfraEnvironment.js.map +1 -0
- package/dist/features/environment-lifecycle/utils/appendInfraFailure.d.ts +7 -0
- package/dist/features/environment-lifecycle/utils/appendInfraFailure.d.ts.map +1 -0
- package/dist/features/environment-lifecycle/utils/appendInfraFailure.js +5 -0
- package/dist/features/environment-lifecycle/utils/appendInfraFailure.js.map +1 -0
- package/dist/features/environment-lifecycle/utils/createInfraExecutionContext.d.ts +5 -0
- package/dist/features/environment-lifecycle/utils/createInfraExecutionContext.d.ts.map +1 -0
- package/dist/features/environment-lifecycle/utils/createInfraExecutionContext.js +13 -0
- package/dist/features/environment-lifecycle/utils/createInfraExecutionContext.js.map +1 -0
- package/dist/features/environment-lifecycle/utils/createInfraFailure.d.ts +4 -0
- package/dist/features/environment-lifecycle/utils/createInfraFailure.d.ts.map +1 -0
- package/dist/features/environment-lifecycle/utils/createInfraFailure.js +5 -0
- package/dist/features/environment-lifecycle/utils/createInfraFailure.js.map +1 -0
- package/dist/features/environment-lifecycle/utils/createInfraLedger.d.ts +12 -0
- package/dist/features/environment-lifecycle/utils/createInfraLedger.d.ts.map +1 -0
- package/dist/features/environment-lifecycle/utils/createInfraLedger.js +14 -0
- package/dist/features/environment-lifecycle/utils/createInfraLedger.js.map +1 -0
- package/dist/features/environment-lifecycle/utils/infraIdentityKey.d.ts +4 -0
- package/dist/features/environment-lifecycle/utils/infraIdentityKey.d.ts.map +1 -0
- package/dist/features/environment-lifecycle/utils/infraIdentityKey.js +5 -0
- package/dist/features/environment-lifecycle/utils/infraIdentityKey.js.map +1 -0
- package/dist/features/environment-lifecycle/utils/isInfraStoredState.d.ts +4 -0
- package/dist/features/environment-lifecycle/utils/isInfraStoredState.d.ts.map +1 -0
- package/dist/features/environment-lifecycle/utils/isInfraStoredState.js +103 -0
- package/dist/features/environment-lifecycle/utils/isInfraStoredState.js.map +1 -0
- package/dist/features/environment-lifecycle/utils/mergeInfraOutputs.d.ts +4 -0
- package/dist/features/environment-lifecycle/utils/mergeInfraOutputs.d.ts.map +1 -0
- package/dist/features/environment-lifecycle/utils/mergeInfraOutputs.js +10 -0
- package/dist/features/environment-lifecycle/utils/mergeInfraOutputs.js.map +1 -0
- package/dist/features/environment-lifecycle/utils/mergeInfraResources.d.ts +4 -0
- package/dist/features/environment-lifecycle/utils/mergeInfraResources.d.ts.map +1 -0
- package/dist/features/environment-lifecycle/utils/mergeInfraResources.js +10 -0
- package/dist/features/environment-lifecycle/utils/mergeInfraResources.js.map +1 -0
- package/dist/features/environment-lifecycle/utils/normalizeInfraEnvironmentKey.d.ts +3 -0
- package/dist/features/environment-lifecycle/utils/normalizeInfraEnvironmentKey.d.ts.map +1 -0
- package/dist/features/environment-lifecycle/utils/normalizeInfraEnvironmentKey.js +8 -0
- package/dist/features/environment-lifecycle/utils/normalizeInfraEnvironmentKey.js.map +1 -0
- package/dist/features/environment-lifecycle/utils/resolveInfraStatePath.d.ts +4 -0
- package/dist/features/environment-lifecycle/utils/resolveInfraStatePath.d.ts.map +1 -0
- package/dist/features/environment-lifecycle/utils/resolveInfraStatePath.js +11 -0
- package/dist/features/environment-lifecycle/utils/resolveInfraStatePath.js.map +1 -0
- package/dist/features/environment-lifecycle/utils/resolveProjectFile.d.ts +3 -0
- package/dist/features/environment-lifecycle/utils/resolveProjectFile.d.ts.map +1 -0
- package/dist/features/environment-lifecycle/utils/resolveProjectFile.js +19 -0
- package/dist/features/environment-lifecycle/utils/resolveProjectFile.js.map +1 -0
- package/dist/features/environment-lifecycle/utils/retainUnchangedAdapterOutputs.d.ts +4 -0
- package/dist/features/environment-lifecycle/utils/retainUnchangedAdapterOutputs.d.ts.map +1 -0
- package/dist/features/environment-lifecycle/utils/retainUnchangedAdapterOutputs.js +6 -0
- package/dist/features/environment-lifecycle/utils/retainUnchangedAdapterOutputs.js.map +1 -0
- package/dist/features/environment-lifecycle/utils/retainUnchangedAdapterResources.d.ts +4 -0
- package/dist/features/environment-lifecycle/utils/retainUnchangedAdapterResources.d.ts.map +1 -0
- package/dist/features/environment-lifecycle/utils/retainUnchangedAdapterResources.js +6 -0
- package/dist/features/environment-lifecycle/utils/retainUnchangedAdapterResources.js.map +1 -0
- package/dist/index.d.ts +16 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -15
- package/dist/index.js.map +1 -1
- package/dist/metadata/index.d.ts +1 -1
- package/dist/metadata/index.d.ts.map +1 -1
- package/dist/metadata/index.js +1 -1
- package/dist/metadata/index.js.map +1 -1
- package/dist/project/index.d.ts +7 -5
- package/dist/project/index.d.ts.map +1 -1
- package/dist/project/index.js +6 -5
- package/dist/project/index.js.map +1 -1
- package/dist/readme-usage.js +17 -26
- package/dist/readme-usage.js.map +1 -1
- package/dist/testSupport.d.ts +1 -1
- package/dist/testSupport.d.ts.map +1 -1
- package/dist/testSupport.js +11 -1
- package/dist/testSupport.js.map +1 -1
- package/dist/types/infraCli.d.ts +91 -0
- package/dist/types/infraCli.d.ts.map +1 -0
- package/dist/types/infraCli.js +2 -0
- package/dist/types/infraCli.js.map +1 -0
- package/dist/types/infraOrchestration.d.ts +84 -0
- package/dist/types/infraOrchestration.d.ts.map +1 -0
- package/dist/types/infraOrchestration.js +2 -0
- package/dist/types/infraOrchestration.js.map +1 -0
- package/dist/{project.d.ts → types/infraProject.d.ts} +6 -6
- package/dist/types/infraProject.d.ts.map +1 -0
- package/dist/types/infraProject.js +2 -0
- package/dist/types/infraProject.js.map +1 -0
- package/package.json +20 -10
- package/src/adapterPackages.integration.test.ts +79 -0
- package/src/cli/bin.ts +2 -61
- package/src/cli/cli.test.ts +35 -126
- package/src/cli/commands/destroy.ts +57 -0
- package/src/cli/commands/down.ts +28 -0
- package/src/cli/commands/generate.ts +34 -0
- package/src/cli/commands/outputs.ts +25 -0
- package/src/cli/commands/plan.ts +20 -0
- package/src/cli/commands/status.ts +20 -0
- package/src/cli/commands/up.ts +29 -0
- package/src/cli/commands/validate.ts +20 -0
- package/src/cli/constants.ts +19 -0
- package/src/cli/createDefaultInfraCommandContext.ts +17 -0
- package/src/cli/createInfraRuntimeProvider.ts +35 -0
- package/src/cli/createProviderCommandDescriptors.ts +8 -0
- package/src/cli/findInfraCommand.ts +7 -0
- package/src/cli/index.test.ts +12 -20
- package/src/cli/index.ts +7 -49
- package/src/cli/renderInfraRootHelp.ts +23 -0
- package/src/cli/renderUnknownInfraCommand.ts +4 -0
- package/src/cli/runInfraCliAsync.ts +51 -0
- package/src/cli/runInfraCommandAsync.ts +114 -0
- package/src/cli/utils/prepareInfraCommandOperationAsync.ts +64 -0
- package/src/cli/utils/requireInfraSuccess.ts +24 -0
- package/src/cli/utils/resolveInfraPersistence.ts +22 -0
- package/src/cli/utils/writeInfraEnvironmentOutputs.ts +24 -0
- package/src/cli/utils/writeInfraStructured.ts +11 -0
- package/src/commands.test.ts +198 -196
- package/src/{packageMetadata.ts → constants.ts} +5 -2
- package/src/environmentLifecycle.test.ts +193 -0
- package/src/features/environment-lifecycle/adapters/outbound/createEnvironmentInfraCredentialPort.ts +52 -0
- package/src/features/environment-lifecycle/adapters/outbound/createEnvironmentInfraSecretPort.ts +32 -0
- package/src/features/environment-lifecycle/adapters/outbound/createNodeInfraAdapterPackageResolver.ts +10 -0
- package/src/features/environment-lifecycle/adapters/outbound/readStoredInfraStateAsync.ts +34 -0
- package/src/features/environment-lifecycle/adapters/outbound/removeStoredInfraStateAsync.ts +12 -0
- package/src/{project.ts → features/environment-lifecycle/adapters/outbound/resolveInfraProjectAsync.ts} +10 -45
- package/src/features/environment-lifecycle/adapters/outbound/writeInfraGeneratedArtifactsAsync.ts +34 -0
- package/src/features/environment-lifecycle/adapters/outbound/writeStoredInfraStateAsync.ts +21 -0
- package/src/features/environment-lifecycle/application/ports/outbound/infraAdapterPackage.ts +10 -0
- package/src/features/environment-lifecycle/application/use-cases/collectInfraWorkloadsAsync.ts +25 -0
- package/src/features/environment-lifecycle/application/use-cases/destroyInfraEnvironmentAsync.ts +119 -0
- package/src/features/environment-lifecycle/application/use-cases/downInfraEnvironmentAsync.ts +65 -0
- package/src/features/environment-lifecycle/application/use-cases/generateInfraEnvironmentAsync.ts +51 -0
- package/src/features/environment-lifecycle/application/use-cases/getInfraEnvironmentOutputs.ts +41 -0
- package/src/features/environment-lifecycle/application/use-cases/planInfraEnvironmentAsync.ts +67 -0
- package/src/features/environment-lifecycle/application/use-cases/prepareInfraOperationAsync.ts +137 -0
- package/src/features/environment-lifecycle/application/use-cases/resolveInfraAdaptersAsync.ts +257 -0
- package/src/features/environment-lifecycle/application/use-cases/statusInfraEnvironmentAsync.ts +80 -0
- package/src/features/environment-lifecycle/application/use-cases/upInfraEnvironmentAsync.ts +126 -0
- package/src/features/environment-lifecycle/application/use-cases/validateInfraAdaptersAsync.ts +25 -0
- package/src/features/environment-lifecycle/application/use-cases/validateInfraEnvironmentAsync.ts +21 -0
- package/src/features/environment-lifecycle/composition/createInfraCommandServices.ts +47 -0
- package/src/features/environment-lifecycle/domain/orderInfraPlanActions.ts +64 -0
- package/src/features/environment-lifecycle/domain/resolveInfraEnvironment.ts +62 -0
- package/src/features/environment-lifecycle/utils/appendInfraFailure.ts +9 -0
- package/src/features/environment-lifecycle/utils/createInfraExecutionContext.ts +24 -0
- package/src/features/environment-lifecycle/utils/createInfraFailure.ts +6 -0
- package/src/features/environment-lifecycle/utils/createInfraLedger.ts +30 -0
- package/src/features/environment-lifecycle/utils/infraIdentityKey.ts +6 -0
- package/src/features/environment-lifecycle/utils/isInfraStoredState.ts +141 -0
- package/src/features/environment-lifecycle/utils/mergeInfraOutputs.ts +14 -0
- package/src/features/environment-lifecycle/utils/mergeInfraResources.ts +14 -0
- package/src/features/environment-lifecycle/utils/normalizeInfraEnvironmentKey.ts +7 -0
- package/src/features/environment-lifecycle/utils/resolveInfraStatePath.ts +12 -0
- package/src/features/environment-lifecycle/utils/resolveProjectFile.ts +22 -0
- package/src/features/environment-lifecycle/utils/retainUnchangedAdapterOutputs.ts +15 -0
- package/src/features/environment-lifecycle/utils/retainUnchangedAdapterResources.ts +15 -0
- package/src/index.test.ts +22 -315
- package/src/index.ts +41 -53
- package/src/infraComposition.integration.test.ts +128 -0
- package/src/infraOperations.test.ts +386 -0
- package/src/infraUp.test.ts +260 -0
- package/src/metadata/index.ts +1 -1
- package/src/package.test.ts +4 -2
- package/src/project/index.test.ts +8 -188
- package/src/project/index.ts +7 -22
- package/src/project.test.ts +39 -189
- package/src/projectContractsParser.test.ts +2 -2
- package/src/projectInfrastructure.test.ts +121 -167
- package/src/readme-usage.ts +17 -26
- package/src/testSupport.ts +12 -2
- package/src/types/infraCli.ts +115 -0
- package/src/types/infraOrchestration.ts +126 -0
- package/src/types/infraProject.ts +15 -0
- package/dist/adapters/minikube/auth/index.d.ts +0 -8
- package/dist/adapters/minikube/auth/index.d.ts.map +0 -1
- package/dist/adapters/minikube/auth/index.js +0 -29
- package/dist/adapters/minikube/auth/index.js.map +0 -1
- package/dist/adapters/minikube/auth/oauthRuntime.d.ts +0 -4
- package/dist/adapters/minikube/auth/oauthRuntime.d.ts.map +0 -1
- package/dist/adapters/minikube/auth/oauthRuntime.js +0 -138
- package/dist/adapters/minikube/auth/oauthRuntime.js.map +0 -1
- package/dist/adapters/minikube/auth/supabase/index.d.ts +0 -7
- package/dist/adapters/minikube/auth/supabase/index.d.ts.map +0 -1
- package/dist/adapters/minikube/auth/supabase/index.js +0 -232
- package/dist/adapters/minikube/auth/supabase/index.js.map +0 -1
- package/dist/adapters/minikube/auth/supabase/profile.d.ts +0 -20
- package/dist/adapters/minikube/auth/supabase/profile.d.ts.map +0 -1
- package/dist/adapters/minikube/auth/supabase/profile.js +0 -452
- package/dist/adapters/minikube/auth/supabase/profile.js.map +0 -1
- package/dist/adapters/minikube/auth/targetAwareOAuthRuntime.d.ts +0 -7
- package/dist/adapters/minikube/auth/targetAwareOAuthRuntime.d.ts.map +0 -1
- package/dist/adapters/minikube/auth/targetAwareOAuthRuntime.js +0 -104
- package/dist/adapters/minikube/auth/targetAwareOAuthRuntime.js.map +0 -1
- package/dist/adapters/minikube/authz/cerbos/index.d.ts +0 -13
- package/dist/adapters/minikube/authz/cerbos/index.d.ts.map +0 -1
- package/dist/adapters/minikube/authz/cerbos/index.js +0 -382
- package/dist/adapters/minikube/authz/cerbos/index.js.map +0 -1
- package/dist/adapters/minikube/authz/index.d.ts +0 -9
- package/dist/adapters/minikube/authz/index.d.ts.map +0 -1
- package/dist/adapters/minikube/authz/index.js +0 -23
- package/dist/adapters/minikube/authz/index.js.map +0 -1
- package/dist/adapters/minikube/base/index.d.ts +0 -14
- package/dist/adapters/minikube/base/index.d.ts.map +0 -1
- package/dist/adapters/minikube/base/index.js +0 -3433
- package/dist/adapters/minikube/base/index.js.map +0 -1
- package/dist/adapters/minikube/base/supabaseMigrations.d.ts +0 -2
- package/dist/adapters/minikube/base/supabaseMigrations.d.ts.map +0 -1
- package/dist/adapters/minikube/base/supabaseMigrations.js +0 -6
- package/dist/adapters/minikube/base/supabaseMigrations.js.map +0 -1
- package/dist/adapters/minikube/contracts.d.ts +0 -34
- package/dist/adapters/minikube/contracts.d.ts.map +0 -1
- package/dist/adapters/minikube/contracts.js +0 -10
- package/dist/adapters/minikube/contracts.js.map +0 -1
- package/dist/adapters/minikube/index.d.ts +0 -3
- package/dist/adapters/minikube/index.d.ts.map +0 -1
- package/dist/adapters/minikube/index.js +0 -136
- package/dist/adapters/minikube/index.js.map +0 -1
- package/dist/adapters/minikube/secrets/index.d.ts +0 -7
- package/dist/adapters/minikube/secrets/index.d.ts.map +0 -1
- package/dist/adapters/minikube/secrets/index.js +0 -13
- package/dist/adapters/minikube/secrets/index.js.map +0 -1
- package/dist/adapters/minikube/secrets/supabase-vault/index.d.ts +0 -8
- package/dist/adapters/minikube/secrets/supabase-vault/index.d.ts.map +0 -1
- package/dist/adapters/minikube/secrets/supabase-vault/index.js +0 -118
- package/dist/adapters/minikube/secrets/supabase-vault/index.js.map +0 -1
- package/dist/adapters/minikube/storage/index.d.ts +0 -7
- package/dist/adapters/minikube/storage/index.d.ts.map +0 -1
- package/dist/adapters/minikube/storage/index.js +0 -77
- package/dist/adapters/minikube/storage/index.js.map +0 -1
- package/dist/adapters/minikube/storage/supabase/index.d.ts +0 -7
- package/dist/adapters/minikube/storage/supabase/index.d.ts.map +0 -1
- package/dist/adapters/minikube/storage/supabase/index.js +0 -82
- package/dist/adapters/minikube/storage/supabase/index.js.map +0 -1
- package/dist/authRedirects.d.ts +0 -19
- package/dist/authRedirects.d.ts.map +0 -1
- package/dist/authRedirects.js +0 -80
- package/dist/authRedirects.js.map +0 -1
- package/dist/authTargetRedirects.d.ts +0 -12
- package/dist/authTargetRedirects.d.ts.map +0 -1
- package/dist/authTargetRedirects.js +0 -32
- package/dist/authTargetRedirects.js.map +0 -1
- package/dist/commandContext.d.ts +0 -12
- package/dist/commandContext.d.ts.map +0 -1
- package/dist/commandContext.js.map +0 -1
- package/dist/commands.d.ts +0 -95
- package/dist/commands.d.ts.map +0 -1
- package/dist/commands.js +0 -256
- package/dist/commands.js.map +0 -1
- package/dist/infraValidation.d.ts +0 -4
- package/dist/infraValidation.d.ts.map +0 -1
- package/dist/infraValidation.js +0 -63
- package/dist/infraValidation.js.map +0 -1
- package/dist/packageMetadata.d.ts +0 -10
- package/dist/packageMetadata.d.ts.map +0 -1
- package/dist/packageMetadata.js.map +0 -1
- package/dist/project.d.ts.map +0 -1
- package/dist/project.js.map +0 -1
- package/dist/projectDatabase.d.ts +0 -5
- package/dist/projectDatabase.d.ts.map +0 -1
- package/dist/projectDatabase.js +0 -22
- package/dist/projectDatabase.js.map +0 -1
- package/dist/projectEnvironment.d.ts +0 -6
- package/dist/projectEnvironment.d.ts.map +0 -1
- package/dist/projectEnvironment.js +0 -45
- package/dist/projectEnvironment.js.map +0 -1
- package/dist/projectInfrastructure.d.ts +0 -38
- package/dist/projectInfrastructure.d.ts.map +0 -1
- package/dist/projectInfrastructure.js +0 -145
- package/dist/projectInfrastructure.js.map +0 -1
- package/dist/runtime.d.ts +0 -54
- package/dist/runtime.d.ts.map +0 -1
- package/dist/runtime.js +0 -151
- package/dist/runtime.js.map +0 -1
- package/dist/secretStore.d.ts +0 -19
- package/dist/secretStore.d.ts.map +0 -1
- package/dist/secretStore.js +0 -22
- package/dist/secretStore.js.map +0 -1
- package/dist/types.d.ts +0 -70
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -2
- package/dist/types.js.map +0 -1
- package/src/adapters/minikube/README.md +0 -115
- package/src/adapters/minikube/appRuntimeServing.test.ts +0 -28
- package/src/adapters/minikube/auth/index.ts +0 -40
- package/src/adapters/minikube/auth/oauthRuntime.ts +0 -163
- package/src/adapters/minikube/auth/supabase/index.test.ts +0 -227
- package/src/adapters/minikube/auth/supabase/index.ts +0 -293
- package/src/adapters/minikube/auth/supabase/oauthRuntime.test.ts +0 -154
- package/src/adapters/minikube/auth/supabase/profile.integration.test.ts +0 -1028
- package/src/adapters/minikube/auth/supabase/profile.ts +0 -526
- package/src/adapters/minikube/auth/supabase/providerAssignments.test.ts +0 -36
- package/src/adapters/minikube/auth/targetAwareOAuthRuntime.test.ts +0 -83
- package/src/adapters/minikube/auth/targetAwareOAuthRuntime.ts +0 -136
- package/src/adapters/minikube/authz/cerbos/index.ts +0 -486
- package/src/adapters/minikube/authz/index.ts +0 -32
- package/src/adapters/minikube/base/appImageBuild.test.ts +0 -352
- package/src/adapters/minikube/base/index.test.ts +0 -693
- package/src/adapters/minikube/base/index.ts +0 -3763
- package/src/adapters/minikube/base/portForwardRuntime.test.ts +0 -624
- package/src/adapters/minikube/base/supabaseMigrations.test.ts +0 -168
- package/src/adapters/minikube/base/supabaseMigrations.ts +0 -5
- package/src/adapters/minikube/base/twoAppIsolation.integration.test.ts +0 -898
- package/src/adapters/minikube/base/upgradeReconciliation.test.ts +0 -135
- package/src/adapters/minikube/contracts.ts +0 -46
- package/src/adapters/minikube/index.ts +0 -172
- package/src/adapters/minikube/secrets/index.test.ts +0 -147
- package/src/adapters/minikube/secrets/index.ts +0 -19
- package/src/adapters/minikube/secrets/supabase-vault/index.ts +0 -139
- package/src/adapters/minikube/storage/index.ts +0 -91
- package/src/adapters/minikube/storage/supabase/index.ts +0 -108
- package/src/apiInfrastructure.test.ts +0 -69
- package/src/authRedirects.test.ts +0 -63
- package/src/authRedirects.ts +0 -113
- package/src/authTargetRedirects.test.ts +0 -62
- package/src/authTargetRedirects.ts +0 -46
- package/src/commandContext.ts +0 -27
- package/src/commands.ts +0 -404
- package/src/generatedApiLedgerCleanup.test.ts +0 -72
- package/src/infraApiValidation.test.ts +0 -42
- package/src/infraValidation.ts +0 -99
- package/src/minikubeImageLifecycle.test.ts +0 -35
- package/src/projectDatabase.ts +0 -27
- package/src/projectEnvironment.ts +0 -51
- package/src/projectInfrastructure.ts +0 -221
- package/src/runtime.test.ts +0 -124
- package/src/runtime.ts +0 -234
- package/src/secretStore.test.ts +0 -76
- package/src/secretStore.ts +0 -44
- package/src/types.ts +0 -82
|
@@ -1,1028 +0,0 @@
|
|
|
1
|
-
import { execFile as execFileCallback } from 'node:child_process';
|
|
2
|
-
import { chmod, mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
|
|
3
|
-
import { tmpdir } from 'node:os';
|
|
4
|
-
import path from 'node:path';
|
|
5
|
-
import { promisify } from 'node:util';
|
|
6
|
-
|
|
7
|
-
import { describe, expect, test } from 'bun:test';
|
|
8
|
-
|
|
9
|
-
import { generateInfrastructure as generateRawInfrastructure } from '../../../../index';
|
|
10
|
-
import { createAppManifest } from '../../../../testSupport';
|
|
11
|
-
import type { GeneratedInfrastructureFile, InfraManifestInput } from '../../../../types';
|
|
12
|
-
|
|
13
|
-
const execFile = promisify(execFileCallback);
|
|
14
|
-
const INTEGRATION_TIMEOUT_MS = 300_000;
|
|
15
|
-
const integrationTest = process.env.ANKH_SUPABASE_INTEGRATION === '1' ? test : test.skip;
|
|
16
|
-
|
|
17
|
-
function generateInfrastructure(
|
|
18
|
-
manifest: InfraManifestInput,
|
|
19
|
-
options: { namespaceHint?: string } = {},
|
|
20
|
-
): ReturnType<typeof generateRawInfrastructure> {
|
|
21
|
-
const slug = options.namespaceHint ?? 'profile-integration';
|
|
22
|
-
return generateRawInfrastructure(manifest, {
|
|
23
|
-
...options,
|
|
24
|
-
appManifest: createAppManifest(slug),
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
describe('generated Supabase profile reconciliation integration', () => {
|
|
29
|
-
integrationTest(
|
|
30
|
-
'drops stale managed columns while preserving custom columns',
|
|
31
|
-
async () => {
|
|
32
|
-
const { appRoot, minikubeRoot, namespaceHint } = await createIntegrationProject();
|
|
33
|
-
|
|
34
|
-
try {
|
|
35
|
-
await writeGeneratedFiles(
|
|
36
|
-
appRoot,
|
|
37
|
-
generateInfrastructure(createManifest({ fields: ['email', 'displayName'] }), {
|
|
38
|
-
namespaceHint,
|
|
39
|
-
}).files,
|
|
40
|
-
);
|
|
41
|
-
|
|
42
|
-
await runLocalSupabaseEnv(minikubeRoot);
|
|
43
|
-
await runSupabaseSql(
|
|
44
|
-
minikubeRoot,
|
|
45
|
-
'alter table public.profiles add column if not exists custom_note text;',
|
|
46
|
-
);
|
|
47
|
-
|
|
48
|
-
await writeGeneratedFiles(
|
|
49
|
-
appRoot,
|
|
50
|
-
generateInfrastructure(createManifest({ fields: ['email', 'avatarUrl'] }), {
|
|
51
|
-
namespaceHint,
|
|
52
|
-
}).files,
|
|
53
|
-
);
|
|
54
|
-
await runLocalSupabaseEnv(minikubeRoot);
|
|
55
|
-
|
|
56
|
-
await runSupabaseSql(
|
|
57
|
-
minikubeRoot,
|
|
58
|
-
`do $$
|
|
59
|
-
begin
|
|
60
|
-
if not exists (
|
|
61
|
-
select 1 from information_schema.columns
|
|
62
|
-
where table_schema = 'public' and table_name = 'profiles' and column_name = 'custom_note'
|
|
63
|
-
) then
|
|
64
|
-
raise exception 'custom column was not preserved';
|
|
65
|
-
end if;
|
|
66
|
-
|
|
67
|
-
if exists (
|
|
68
|
-
select 1 from information_schema.columns
|
|
69
|
-
where table_schema = 'public' and table_name = 'profiles' and column_name = 'display_name'
|
|
70
|
-
) then
|
|
71
|
-
raise exception 'stale managed column display_name was not removed';
|
|
72
|
-
end if;
|
|
73
|
-
|
|
74
|
-
if not exists (
|
|
75
|
-
select 1 from information_schema.columns
|
|
76
|
-
where table_schema = 'public' and table_name = 'profiles' and column_name = 'avatar_url'
|
|
77
|
-
) then
|
|
78
|
-
raise exception 'new managed column avatar_url was not added';
|
|
79
|
-
end if;
|
|
80
|
-
end;
|
|
81
|
-
$$;`,
|
|
82
|
-
);
|
|
83
|
-
|
|
84
|
-
await runSupabaseSql(
|
|
85
|
-
minikubeRoot,
|
|
86
|
-
`do $$
|
|
87
|
-
begin
|
|
88
|
-
if not exists (
|
|
89
|
-
select 1
|
|
90
|
-
from ankhorage_internal.generated_schema_state
|
|
91
|
-
where artifact_key = 'auth.profile'
|
|
92
|
-
and table_name = 'profiles'
|
|
93
|
-
) then
|
|
94
|
-
raise exception 'missing applied profile state';
|
|
95
|
-
end if;
|
|
96
|
-
end;
|
|
97
|
-
$$;`,
|
|
98
|
-
);
|
|
99
|
-
} finally {
|
|
100
|
-
await execFile('supabase', ['--workdir', minikubeRoot, 'stop', '--no-backup']).catch(() => {
|
|
101
|
-
// Best-effort cleanup for gated local integration runs.
|
|
102
|
-
});
|
|
103
|
-
await rm(appRoot, { recursive: true, force: true });
|
|
104
|
-
}
|
|
105
|
-
},
|
|
106
|
-
INTEGRATION_TIMEOUT_MS,
|
|
107
|
-
);
|
|
108
|
-
|
|
109
|
-
integrationTest(
|
|
110
|
-
'is idempotent for unchanged generated reconciliation',
|
|
111
|
-
async () => {
|
|
112
|
-
const { appRoot, minikubeRoot, namespaceHint } = await createIntegrationProject();
|
|
113
|
-
|
|
114
|
-
try {
|
|
115
|
-
await writeGeneratedFiles(
|
|
116
|
-
appRoot,
|
|
117
|
-
generateInfrastructure(createManifest({ fields: ['email', 'displayName'] }), {
|
|
118
|
-
namespaceHint,
|
|
119
|
-
}).files,
|
|
120
|
-
);
|
|
121
|
-
|
|
122
|
-
await runLocalSupabaseEnv(minikubeRoot);
|
|
123
|
-
await runLocalSupabaseEnv(minikubeRoot);
|
|
124
|
-
|
|
125
|
-
await runSupabaseSql(
|
|
126
|
-
minikubeRoot,
|
|
127
|
-
`do $$
|
|
128
|
-
begin
|
|
129
|
-
if not exists (
|
|
130
|
-
select 1
|
|
131
|
-
from ankhorage_internal.generated_schema_state
|
|
132
|
-
where artifact_key = 'auth.profile'
|
|
133
|
-
and table_name = 'profiles'
|
|
134
|
-
) then
|
|
135
|
-
raise exception 'missing applied profile state';
|
|
136
|
-
end if;
|
|
137
|
-
end;
|
|
138
|
-
$$;`,
|
|
139
|
-
);
|
|
140
|
-
} finally {
|
|
141
|
-
await cleanupIntegrationProject(appRoot, minikubeRoot);
|
|
142
|
-
}
|
|
143
|
-
},
|
|
144
|
-
INTEGRATION_TIMEOUT_MS,
|
|
145
|
-
);
|
|
146
|
-
|
|
147
|
-
integrationTest(
|
|
148
|
-
'boots clean disabled profile and writes client env idempotently',
|
|
149
|
-
async () => {
|
|
150
|
-
const { appRoot, minikubeRoot, namespaceHint } = await createIntegrationProject();
|
|
151
|
-
|
|
152
|
-
try {
|
|
153
|
-
await writeGeneratedFiles(
|
|
154
|
-
appRoot,
|
|
155
|
-
generateInfrastructure(createManifest({ table: undefined, fields: ['email'] }), {
|
|
156
|
-
namespaceHint,
|
|
157
|
-
}).files,
|
|
158
|
-
);
|
|
159
|
-
|
|
160
|
-
await runLocalSupabaseEnv(minikubeRoot);
|
|
161
|
-
await runLocalSupabaseEnv(minikubeRoot);
|
|
162
|
-
|
|
163
|
-
const { stdout: statusEnv } = await execFile('supabase', [
|
|
164
|
-
'--workdir',
|
|
165
|
-
minikubeRoot,
|
|
166
|
-
'status',
|
|
167
|
-
'-o',
|
|
168
|
-
'env',
|
|
169
|
-
]);
|
|
170
|
-
const expectedUrl = readStatusEnv(statusEnv, 'API_URL');
|
|
171
|
-
const expectedAnonKey = readStatusEnv(statusEnv, 'ANON_KEY');
|
|
172
|
-
const appEnv = await readFile(path.join(appRoot, '.env.local'), 'utf8');
|
|
173
|
-
|
|
174
|
-
expect(readStatusEnv(appEnv, 'EXPO_PUBLIC_SUPABASE_URL')).toBe(expectedUrl);
|
|
175
|
-
expect(readStatusEnv(appEnv, 'EXPO_PUBLIC_SUPABASE_ANON_KEY')).toBe(expectedAnonKey);
|
|
176
|
-
} finally {
|
|
177
|
-
await cleanupIntegrationProject(appRoot, minikubeRoot);
|
|
178
|
-
}
|
|
179
|
-
},
|
|
180
|
-
INTEGRATION_TIMEOUT_MS,
|
|
181
|
-
);
|
|
182
|
-
|
|
183
|
-
integrationTest(
|
|
184
|
-
'accepts disabled profile when state table exists without auth profile state',
|
|
185
|
-
async () => {
|
|
186
|
-
const { appRoot, minikubeRoot, namespaceHint } = await createIntegrationProject();
|
|
187
|
-
|
|
188
|
-
try {
|
|
189
|
-
await writeGeneratedFiles(
|
|
190
|
-
appRoot,
|
|
191
|
-
generateInfrastructure(createManifest({ table: undefined, fields: ['email'] }), {
|
|
192
|
-
namespaceHint,
|
|
193
|
-
}).files,
|
|
194
|
-
);
|
|
195
|
-
|
|
196
|
-
await runLocalSupabaseEnv(minikubeRoot);
|
|
197
|
-
await runSupabaseSql(
|
|
198
|
-
minikubeRoot,
|
|
199
|
-
`create schema if not exists ankhorage_internal;
|
|
200
|
-
create table if not exists ankhorage_internal.generated_schema_state (
|
|
201
|
-
artifact_key text primary key,
|
|
202
|
-
table_name text,
|
|
203
|
-
content_hash text,
|
|
204
|
-
updated_at timestamptz not null default now()
|
|
205
|
-
);
|
|
206
|
-
insert into ankhorage_internal.generated_schema_state (
|
|
207
|
-
artifact_key,
|
|
208
|
-
table_name,
|
|
209
|
-
content_hash
|
|
210
|
-
)
|
|
211
|
-
values ('storage.bucket', 'objects', repeat('1', 64))
|
|
212
|
-
on conflict (artifact_key) do update
|
|
213
|
-
set table_name = excluded.table_name,
|
|
214
|
-
content_hash = excluded.content_hash,
|
|
215
|
-
updated_at = now();`,
|
|
216
|
-
);
|
|
217
|
-
|
|
218
|
-
await runLocalSupabaseEnv(minikubeRoot);
|
|
219
|
-
} finally {
|
|
220
|
-
await cleanupIntegrationProject(appRoot, minikubeRoot);
|
|
221
|
-
}
|
|
222
|
-
},
|
|
223
|
-
INTEGRATION_TIMEOUT_MS,
|
|
224
|
-
);
|
|
225
|
-
|
|
226
|
-
integrationTest(
|
|
227
|
-
'status reports clean disabled profile as skipped',
|
|
228
|
-
async () => {
|
|
229
|
-
const { appRoot, minikubeRoot, namespaceHint } = await createIntegrationProject();
|
|
230
|
-
|
|
231
|
-
try {
|
|
232
|
-
await writeGeneratedFiles(
|
|
233
|
-
appRoot,
|
|
234
|
-
generateInfrastructure(createManifest({ table: undefined, fields: ['email'] }), {
|
|
235
|
-
namespaceHint,
|
|
236
|
-
}).files,
|
|
237
|
-
);
|
|
238
|
-
await runLocalSupabaseEnv(minikubeRoot);
|
|
239
|
-
|
|
240
|
-
const output = await runGeneratedStatus(minikubeRoot);
|
|
241
|
-
expect(output).toContain('- profile reconciliation: skipped (no profile table configured)');
|
|
242
|
-
expect(output).toContain('- profile schema: skipped (no profile table configured)');
|
|
243
|
-
} finally {
|
|
244
|
-
await cleanupIntegrationProject(appRoot, minikubeRoot);
|
|
245
|
-
}
|
|
246
|
-
},
|
|
247
|
-
INTEGRATION_TIMEOUT_MS,
|
|
248
|
-
);
|
|
249
|
-
|
|
250
|
-
integrationTest(
|
|
251
|
-
'rejects profile table rename once generated state exists',
|
|
252
|
-
async () => {
|
|
253
|
-
const { appRoot, minikubeRoot, namespaceHint } = await createIntegrationProject();
|
|
254
|
-
|
|
255
|
-
try {
|
|
256
|
-
await writeGeneratedFiles(
|
|
257
|
-
appRoot,
|
|
258
|
-
generateInfrastructure(createManifest({ table: 'profiles', fields: ['email'] }), {
|
|
259
|
-
namespaceHint,
|
|
260
|
-
}).files,
|
|
261
|
-
);
|
|
262
|
-
await runLocalSupabaseEnv(minikubeRoot);
|
|
263
|
-
|
|
264
|
-
await writeGeneratedFiles(
|
|
265
|
-
appRoot,
|
|
266
|
-
generateInfrastructure(createManifest({ table: 'members', fields: ['email'] }), {
|
|
267
|
-
namespaceHint,
|
|
268
|
-
}).files,
|
|
269
|
-
);
|
|
270
|
-
|
|
271
|
-
const failure = await expectLocalSupabaseEnvFailure(minikubeRoot);
|
|
272
|
-
expect(failure).toContain('profile.table changed from');
|
|
273
|
-
} finally {
|
|
274
|
-
await cleanupIntegrationProject(appRoot, minikubeRoot);
|
|
275
|
-
}
|
|
276
|
-
},
|
|
277
|
-
INTEGRATION_TIMEOUT_MS,
|
|
278
|
-
);
|
|
279
|
-
|
|
280
|
-
integrationTest(
|
|
281
|
-
'rejects profile table removal once generated state exists',
|
|
282
|
-
async () => {
|
|
283
|
-
const { appRoot, minikubeRoot, namespaceHint } = await createIntegrationProject();
|
|
284
|
-
|
|
285
|
-
try {
|
|
286
|
-
await writeGeneratedFiles(
|
|
287
|
-
appRoot,
|
|
288
|
-
generateInfrastructure(createManifest({ table: 'profiles', fields: ['email'] }), {
|
|
289
|
-
namespaceHint,
|
|
290
|
-
}).files,
|
|
291
|
-
);
|
|
292
|
-
await runLocalSupabaseEnv(minikubeRoot);
|
|
293
|
-
|
|
294
|
-
await writeGeneratedFiles(
|
|
295
|
-
appRoot,
|
|
296
|
-
generateInfrastructure(createManifest({ table: undefined, fields: ['email'] }), {
|
|
297
|
-
namespaceHint,
|
|
298
|
-
}).files,
|
|
299
|
-
);
|
|
300
|
-
|
|
301
|
-
const failure = await expectLocalSupabaseEnvFailure(minikubeRoot);
|
|
302
|
-
expect(failure).toContain('auth.profile.table was removed');
|
|
303
|
-
} finally {
|
|
304
|
-
await cleanupIntegrationProject(appRoot, minikubeRoot);
|
|
305
|
-
}
|
|
306
|
-
},
|
|
307
|
-
INTEGRATION_TIMEOUT_MS,
|
|
308
|
-
);
|
|
309
|
-
|
|
310
|
-
integrationTest(
|
|
311
|
-
'stops startup on generated SQL failure',
|
|
312
|
-
async () => {
|
|
313
|
-
const { appRoot, minikubeRoot, namespaceHint } = await createIntegrationProject();
|
|
314
|
-
|
|
315
|
-
try {
|
|
316
|
-
await writeGeneratedFiles(
|
|
317
|
-
appRoot,
|
|
318
|
-
generateInfrastructure(createManifest({ fields: ['email'] }), { namespaceHint }).files,
|
|
319
|
-
);
|
|
320
|
-
await writeFile(
|
|
321
|
-
path.join(minikubeRoot, 'supabase/generated/auth_profiles.sql'),
|
|
322
|
-
'begin;\nselect definitely_missing_function();\ncommit;\n',
|
|
323
|
-
'utf8',
|
|
324
|
-
);
|
|
325
|
-
|
|
326
|
-
const failure = await expectLocalSupabaseEnvFailure(minikubeRoot);
|
|
327
|
-
expect(failure).toContain('Generated profile reconciliation failed.');
|
|
328
|
-
expect(failure).toContain('auth_profiles.sql');
|
|
329
|
-
expect(failure).toContain('Exit status:');
|
|
330
|
-
} finally {
|
|
331
|
-
await cleanupIntegrationProject(appRoot, minikubeRoot);
|
|
332
|
-
}
|
|
333
|
-
},
|
|
334
|
-
INTEGRATION_TIMEOUT_MS,
|
|
335
|
-
);
|
|
336
|
-
|
|
337
|
-
integrationTest(
|
|
338
|
-
'preserves unrelated custom foreign keys to auth.users',
|
|
339
|
-
async () => {
|
|
340
|
-
const { appRoot, minikubeRoot, namespaceHint } = await createIntegrationProject();
|
|
341
|
-
|
|
342
|
-
try {
|
|
343
|
-
await writeGeneratedFiles(
|
|
344
|
-
appRoot,
|
|
345
|
-
generateInfrastructure(createManifest({ fields: ['email'] }), { namespaceHint }).files,
|
|
346
|
-
);
|
|
347
|
-
await runLocalSupabaseEnv(minikubeRoot);
|
|
348
|
-
await runSupabaseSql(
|
|
349
|
-
minikubeRoot,
|
|
350
|
-
`alter table public.profiles add column if not exists manager_id uuid;
|
|
351
|
-
alter table public.profiles
|
|
352
|
-
add constraint profiles_manager_id_auth_users_fkey
|
|
353
|
-
foreign key (manager_id) references auth.users(id) on delete set null;`,
|
|
354
|
-
);
|
|
355
|
-
|
|
356
|
-
await runLocalSupabaseEnv(minikubeRoot);
|
|
357
|
-
await runSupabaseSql(
|
|
358
|
-
minikubeRoot,
|
|
359
|
-
`do $$
|
|
360
|
-
begin
|
|
361
|
-
if not exists (
|
|
362
|
-
select 1
|
|
363
|
-
from pg_constraint
|
|
364
|
-
where conrelid = 'public.profiles'::regclass
|
|
365
|
-
and conname = 'profiles_manager_id_auth_users_fkey'
|
|
366
|
-
) then
|
|
367
|
-
raise exception 'custom auth.users foreign key was not preserved';
|
|
368
|
-
end if;
|
|
369
|
-
end;
|
|
370
|
-
$$;`,
|
|
371
|
-
);
|
|
372
|
-
} finally {
|
|
373
|
-
await cleanupIntegrationProject(appRoot, minikubeRoot);
|
|
374
|
-
}
|
|
375
|
-
},
|
|
376
|
-
INTEGRATION_TIMEOUT_MS,
|
|
377
|
-
);
|
|
378
|
-
|
|
379
|
-
integrationTest(
|
|
380
|
-
'status reports stale checksum drift',
|
|
381
|
-
async () => {
|
|
382
|
-
const { appRoot, minikubeRoot, namespaceHint } = await createIntegrationProject();
|
|
383
|
-
|
|
384
|
-
try {
|
|
385
|
-
await writeGeneratedFiles(
|
|
386
|
-
appRoot,
|
|
387
|
-
generateInfrastructure(createManifest({ fields: ['email'] }), { namespaceHint }).files,
|
|
388
|
-
);
|
|
389
|
-
await runLocalSupabaseEnv(minikubeRoot);
|
|
390
|
-
await runSupabaseSql(
|
|
391
|
-
minikubeRoot,
|
|
392
|
-
`update ankhorage_internal.generated_schema_state
|
|
393
|
-
set content_hash = repeat('0', 64)
|
|
394
|
-
where artifact_key = 'auth.profile';`,
|
|
395
|
-
);
|
|
396
|
-
|
|
397
|
-
const failure = await expectGeneratedStatusFailure(minikubeRoot);
|
|
398
|
-
expect(failure).toContain('profile reconciliation: pending or stale');
|
|
399
|
-
} finally {
|
|
400
|
-
await cleanupIntegrationProject(appRoot, minikubeRoot);
|
|
401
|
-
}
|
|
402
|
-
},
|
|
403
|
-
INTEGRATION_TIMEOUT_MS,
|
|
404
|
-
);
|
|
405
|
-
|
|
406
|
-
integrationTest(
|
|
407
|
-
'status reports extra permissive profile policy drift',
|
|
408
|
-
async () => {
|
|
409
|
-
const { appRoot, minikubeRoot, namespaceHint } = await createIntegrationProject();
|
|
410
|
-
|
|
411
|
-
try {
|
|
412
|
-
await writeGeneratedFiles(
|
|
413
|
-
appRoot,
|
|
414
|
-
generateInfrastructure(createManifest({ fields: ['email'] }), { namespaceHint }).files,
|
|
415
|
-
);
|
|
416
|
-
await runLocalSupabaseEnv(minikubeRoot);
|
|
417
|
-
await runSupabaseSql(
|
|
418
|
-
minikubeRoot,
|
|
419
|
-
`create policy profiles_select_everything
|
|
420
|
-
on public.profiles
|
|
421
|
-
for select
|
|
422
|
-
to authenticated
|
|
423
|
-
using (true);`,
|
|
424
|
-
);
|
|
425
|
-
|
|
426
|
-
const failure = await expectGeneratedStatusFailure(minikubeRoot);
|
|
427
|
-
expect(failure).toContain('profile schema: drift detected');
|
|
428
|
-
} finally {
|
|
429
|
-
await cleanupIntegrationProject(appRoot, minikubeRoot);
|
|
430
|
-
}
|
|
431
|
-
},
|
|
432
|
-
INTEGRATION_TIMEOUT_MS,
|
|
433
|
-
);
|
|
434
|
-
|
|
435
|
-
integrationTest(
|
|
436
|
-
'status reports authenticated insert and delete privilege drift',
|
|
437
|
-
async () => {
|
|
438
|
-
const { appRoot, minikubeRoot, namespaceHint } = await createIntegrationProject();
|
|
439
|
-
|
|
440
|
-
try {
|
|
441
|
-
await writeGeneratedFiles(
|
|
442
|
-
appRoot,
|
|
443
|
-
generateInfrastructure(createManifest({ fields: ['email'] }), { namespaceHint }).files,
|
|
444
|
-
);
|
|
445
|
-
await runLocalSupabaseEnv(minikubeRoot);
|
|
446
|
-
await runSupabaseSql(
|
|
447
|
-
minikubeRoot,
|
|
448
|
-
'grant insert, delete on table public.profiles to authenticated;',
|
|
449
|
-
);
|
|
450
|
-
|
|
451
|
-
const failure = await expectGeneratedStatusFailure(minikubeRoot);
|
|
452
|
-
expect(failure).toContain('profile schema: drift detected');
|
|
453
|
-
} finally {
|
|
454
|
-
await cleanupIntegrationProject(appRoot, minikubeRoot);
|
|
455
|
-
}
|
|
456
|
-
},
|
|
457
|
-
INTEGRATION_TIMEOUT_MS,
|
|
458
|
-
);
|
|
459
|
-
|
|
460
|
-
integrationTest(
|
|
461
|
-
'status reports column-scoped privilege drift',
|
|
462
|
-
async () => {
|
|
463
|
-
const { appRoot, minikubeRoot, namespaceHint } = await createIntegrationProject();
|
|
464
|
-
|
|
465
|
-
try {
|
|
466
|
-
await writeGeneratedFiles(
|
|
467
|
-
appRoot,
|
|
468
|
-
generateInfrastructure(createManifest({ fields: ['email'] }), { namespaceHint }).files,
|
|
469
|
-
);
|
|
470
|
-
await runLocalSupabaseEnv(minikubeRoot);
|
|
471
|
-
await runSupabaseSql(
|
|
472
|
-
minikubeRoot,
|
|
473
|
-
`grant select (email), insert (email), update (email)
|
|
474
|
-
on table public.profiles to anon;
|
|
475
|
-
grant insert (email)
|
|
476
|
-
on table public.profiles to authenticated;`,
|
|
477
|
-
);
|
|
478
|
-
|
|
479
|
-
const failure = await expectGeneratedStatusFailure(minikubeRoot);
|
|
480
|
-
expect(failure).toContain('profile schema: drift detected');
|
|
481
|
-
} finally {
|
|
482
|
-
await cleanupIntegrationProject(appRoot, minikubeRoot);
|
|
483
|
-
}
|
|
484
|
-
},
|
|
485
|
-
INTEGRATION_TIMEOUT_MS,
|
|
486
|
-
);
|
|
487
|
-
|
|
488
|
-
integrationTest(
|
|
489
|
-
'status reports column-scoped references privilege drift',
|
|
490
|
-
async () => {
|
|
491
|
-
const { appRoot, minikubeRoot, namespaceHint } = await createIntegrationProject();
|
|
492
|
-
|
|
493
|
-
try {
|
|
494
|
-
await writeGeneratedFiles(
|
|
495
|
-
appRoot,
|
|
496
|
-
generateInfrastructure(createManifest({ fields: ['email'] }), { namespaceHint }).files,
|
|
497
|
-
);
|
|
498
|
-
await runLocalSupabaseEnv(minikubeRoot);
|
|
499
|
-
await runSupabaseSql(
|
|
500
|
-
minikubeRoot,
|
|
501
|
-
'grant references (email) on table public.profiles to anon;',
|
|
502
|
-
);
|
|
503
|
-
|
|
504
|
-
const anonFailure = await expectGeneratedStatusFailure(minikubeRoot);
|
|
505
|
-
expect(anonFailure).toContain('profile schema: drift detected');
|
|
506
|
-
|
|
507
|
-
await runSupabaseSql(
|
|
508
|
-
minikubeRoot,
|
|
509
|
-
`revoke references (email) on table public.profiles from anon;
|
|
510
|
-
grant references (email) on table public.profiles to authenticated;`,
|
|
511
|
-
);
|
|
512
|
-
|
|
513
|
-
const authenticatedFailure = await expectGeneratedStatusFailure(minikubeRoot);
|
|
514
|
-
expect(authenticatedFailure).toContain('profile schema: drift detected');
|
|
515
|
-
} finally {
|
|
516
|
-
await cleanupIntegrationProject(appRoot, minikubeRoot);
|
|
517
|
-
}
|
|
518
|
-
},
|
|
519
|
-
INTEGRATION_TIMEOUT_MS,
|
|
520
|
-
);
|
|
521
|
-
|
|
522
|
-
integrationTest(
|
|
523
|
-
'status reports custom-column update privilege drift',
|
|
524
|
-
async () => {
|
|
525
|
-
const { appRoot, minikubeRoot, namespaceHint } = await createIntegrationProject();
|
|
526
|
-
|
|
527
|
-
try {
|
|
528
|
-
await writeGeneratedFiles(
|
|
529
|
-
appRoot,
|
|
530
|
-
generateInfrastructure(createManifest({ fields: ['email'] }), { namespaceHint }).files,
|
|
531
|
-
);
|
|
532
|
-
await runLocalSupabaseEnv(minikubeRoot);
|
|
533
|
-
await runSupabaseSql(
|
|
534
|
-
minikubeRoot,
|
|
535
|
-
`alter table public.profiles add column if not exists custom_note text;
|
|
536
|
-
grant update (custom_note) on table public.profiles to authenticated;`,
|
|
537
|
-
);
|
|
538
|
-
|
|
539
|
-
const failure = await expectGeneratedStatusFailure(minikubeRoot);
|
|
540
|
-
expect(failure).toContain('profile schema: drift detected');
|
|
541
|
-
} finally {
|
|
542
|
-
await cleanupIntegrationProject(appRoot, minikubeRoot);
|
|
543
|
-
}
|
|
544
|
-
},
|
|
545
|
-
INTEGRATION_TIMEOUT_MS,
|
|
546
|
-
);
|
|
547
|
-
|
|
548
|
-
integrationTest(
|
|
549
|
-
'enforces trigger-created profiles, own-profile RLS, and cascade delete',
|
|
550
|
-
async () => {
|
|
551
|
-
const { appRoot, minikubeRoot, namespaceHint } = await createIntegrationProject();
|
|
552
|
-
const firstUserId = '11111111-1111-4111-8111-111111111111';
|
|
553
|
-
const secondUserId = '22222222-2222-4222-8222-222222222222';
|
|
554
|
-
|
|
555
|
-
try {
|
|
556
|
-
await writeGeneratedFiles(
|
|
557
|
-
appRoot,
|
|
558
|
-
generateInfrastructure(createManifest({ fields: ['email'] }), { namespaceHint }).files,
|
|
559
|
-
);
|
|
560
|
-
await runLocalSupabaseEnv(minikubeRoot);
|
|
561
|
-
await runSupabaseSql(
|
|
562
|
-
minikubeRoot,
|
|
563
|
-
`insert into auth.users (
|
|
564
|
-
instance_id,
|
|
565
|
-
id,
|
|
566
|
-
aud,
|
|
567
|
-
role,
|
|
568
|
-
email,
|
|
569
|
-
encrypted_password,
|
|
570
|
-
email_confirmed_at,
|
|
571
|
-
raw_app_meta_data,
|
|
572
|
-
raw_user_meta_data,
|
|
573
|
-
created_at,
|
|
574
|
-
updated_at
|
|
575
|
-
)
|
|
576
|
-
values
|
|
577
|
-
(
|
|
578
|
-
'00000000-0000-0000-0000-000000000000',
|
|
579
|
-
'${firstUserId}',
|
|
580
|
-
'authenticated',
|
|
581
|
-
'authenticated',
|
|
582
|
-
'first@example.test',
|
|
583
|
-
'not-a-real-password-hash',
|
|
584
|
-
now(),
|
|
585
|
-
'{"provider":"email","providers":["email"]}'::jsonb,
|
|
586
|
-
'{}'::jsonb,
|
|
587
|
-
now(),
|
|
588
|
-
now()
|
|
589
|
-
),
|
|
590
|
-
(
|
|
591
|
-
'00000000-0000-0000-0000-000000000000',
|
|
592
|
-
'${secondUserId}',
|
|
593
|
-
'authenticated',
|
|
594
|
-
'authenticated',
|
|
595
|
-
'second@example.test',
|
|
596
|
-
'not-a-real-password-hash',
|
|
597
|
-
now(),
|
|
598
|
-
'{"provider":"email","providers":["email"]}'::jsonb,
|
|
599
|
-
'{}'::jsonb,
|
|
600
|
-
now(),
|
|
601
|
-
now()
|
|
602
|
-
);
|
|
603
|
-
|
|
604
|
-
do $$
|
|
605
|
-
begin
|
|
606
|
-
if not exists (
|
|
607
|
-
select 1 from public.profiles
|
|
608
|
-
where id = '${firstUserId}'::uuid and email = 'first@example.test'
|
|
609
|
-
) then
|
|
610
|
-
raise exception 'trigger did not create first profile row';
|
|
611
|
-
end if;
|
|
612
|
-
|
|
613
|
-
if not exists (
|
|
614
|
-
select 1 from public.profiles
|
|
615
|
-
where id = '${secondUserId}'::uuid and email = 'second@example.test'
|
|
616
|
-
) then
|
|
617
|
-
raise exception 'trigger did not create second profile row';
|
|
618
|
-
end if;
|
|
619
|
-
end;
|
|
620
|
-
$$;
|
|
621
|
-
|
|
622
|
-
begin;
|
|
623
|
-
set local role authenticated;
|
|
624
|
-
set local request.jwt.claim.sub = '${firstUserId}';
|
|
625
|
-
do $$
|
|
626
|
-
declare
|
|
627
|
-
visible_profiles integer;
|
|
628
|
-
begin
|
|
629
|
-
select count(*) into visible_profiles from public.profiles;
|
|
630
|
-
if visible_profiles <> 1 then
|
|
631
|
-
raise exception 'RLS exposed % profile rows to first user', visible_profiles;
|
|
632
|
-
end if;
|
|
633
|
-
|
|
634
|
-
if not exists (select 1 from public.profiles where id = '${firstUserId}'::uuid) then
|
|
635
|
-
raise exception 'RLS hid first user own profile';
|
|
636
|
-
end if;
|
|
637
|
-
|
|
638
|
-
if exists (select 1 from public.profiles where id = '${secondUserId}'::uuid) then
|
|
639
|
-
raise exception 'RLS exposed second user profile to first user';
|
|
640
|
-
end if;
|
|
641
|
-
|
|
642
|
-
update public.profiles
|
|
643
|
-
set email = 'first-updated@example.test'
|
|
644
|
-
where id = '${firstUserId}'::uuid;
|
|
645
|
-
|
|
646
|
-
if not exists (
|
|
647
|
-
select 1 from public.profiles
|
|
648
|
-
where id = '${firstUserId}'::uuid and email = 'first-updated@example.test'
|
|
649
|
-
) then
|
|
650
|
-
raise exception 'RLS did not allow own profile update';
|
|
651
|
-
end if;
|
|
652
|
-
end;
|
|
653
|
-
$$;
|
|
654
|
-
commit;
|
|
655
|
-
|
|
656
|
-
delete from auth.users where id = '${firstUserId}'::uuid;
|
|
657
|
-
|
|
658
|
-
do $$
|
|
659
|
-
begin
|
|
660
|
-
if exists (select 1 from public.profiles where id = '${firstUserId}'::uuid) then
|
|
661
|
-
raise exception 'profile row survived auth.users cascade delete';
|
|
662
|
-
end if;
|
|
663
|
-
|
|
664
|
-
if not exists (select 1 from public.profiles where id = '${secondUserId}'::uuid) then
|
|
665
|
-
raise exception 'cascade delete removed unrelated profile row';
|
|
666
|
-
end if;
|
|
667
|
-
end;
|
|
668
|
-
$$;`,
|
|
669
|
-
);
|
|
670
|
-
} finally {
|
|
671
|
-
await cleanupIntegrationProject(appRoot, minikubeRoot);
|
|
672
|
-
}
|
|
673
|
-
},
|
|
674
|
-
INTEGRATION_TIMEOUT_MS,
|
|
675
|
-
);
|
|
676
|
-
|
|
677
|
-
integrationTest(
|
|
678
|
-
'reports and applies pending immutable migrations',
|
|
679
|
-
async () => {
|
|
680
|
-
const { appRoot, minikubeRoot, namespaceHint } = await createIntegrationProject();
|
|
681
|
-
|
|
682
|
-
try {
|
|
683
|
-
await writeGeneratedFiles(
|
|
684
|
-
appRoot,
|
|
685
|
-
generateInfrastructure(createManifest({ fields: ['email'] }), { namespaceHint }).files,
|
|
686
|
-
);
|
|
687
|
-
await runLocalSupabaseEnv(minikubeRoot);
|
|
688
|
-
await mkdir(path.join(minikubeRoot, 'supabase/migrations'), { recursive: true });
|
|
689
|
-
await writeFile(
|
|
690
|
-
path.join(minikubeRoot, 'supabase/migrations/20260711000000_create_pending_marker.sql'),
|
|
691
|
-
'create table public.pending_migration_marker (id uuid primary key default gen_random_uuid());\n',
|
|
692
|
-
'utf8',
|
|
693
|
-
);
|
|
694
|
-
|
|
695
|
-
const pendingStatus = await expectGeneratedStatusFailure(minikubeRoot);
|
|
696
|
-
expect(pendingStatus).toContain('immutable migrations: pending');
|
|
697
|
-
|
|
698
|
-
await runLocalSupabaseEnv(minikubeRoot);
|
|
699
|
-
await runSupabaseSql(
|
|
700
|
-
minikubeRoot,
|
|
701
|
-
`do $$
|
|
702
|
-
begin
|
|
703
|
-
if to_regclass('public.pending_migration_marker') is null then
|
|
704
|
-
raise exception 'pending immutable migration was not applied';
|
|
705
|
-
end if;
|
|
706
|
-
end;
|
|
707
|
-
$$;`,
|
|
708
|
-
);
|
|
709
|
-
} finally {
|
|
710
|
-
await cleanupIntegrationProject(appRoot, minikubeRoot);
|
|
711
|
-
}
|
|
712
|
-
},
|
|
713
|
-
INTEGRATION_TIMEOUT_MS,
|
|
714
|
-
);
|
|
715
|
-
|
|
716
|
-
integrationTest(
|
|
717
|
-
'status reports malformed primary key and foreign key drift',
|
|
718
|
-
async () => {
|
|
719
|
-
const { appRoot, minikubeRoot, namespaceHint } = await createIntegrationProject();
|
|
720
|
-
|
|
721
|
-
try {
|
|
722
|
-
await writeGeneratedFiles(
|
|
723
|
-
appRoot,
|
|
724
|
-
generateInfrastructure(createManifest({ fields: ['email'] }), { namespaceHint }).files,
|
|
725
|
-
);
|
|
726
|
-
await runLocalSupabaseEnv(minikubeRoot);
|
|
727
|
-
await runSupabaseSql(
|
|
728
|
-
minikubeRoot,
|
|
729
|
-
`alter table public.profiles drop constraint profiles_pkey;
|
|
730
|
-
alter table public.profiles add column if not exists pk_extra uuid not null default gen_random_uuid();
|
|
731
|
-
alter table public.profiles add constraint profiles_pkey primary key (id, pk_extra);`,
|
|
732
|
-
);
|
|
733
|
-
|
|
734
|
-
const malformedPkStatus = await expectGeneratedStatusFailure(minikubeRoot);
|
|
735
|
-
expect(malformedPkStatus).toContain('profile schema: drift detected');
|
|
736
|
-
|
|
737
|
-
await runSupabaseSql(
|
|
738
|
-
minikubeRoot,
|
|
739
|
-
`alter table public.profiles drop constraint profiles_pkey;
|
|
740
|
-
alter table public.profiles drop column pk_extra;
|
|
741
|
-
alter table public.profiles add constraint profiles_pkey primary key (id);`,
|
|
742
|
-
);
|
|
743
|
-
await runLocalSupabaseEnv(minikubeRoot);
|
|
744
|
-
await runSupabaseSql(
|
|
745
|
-
minikubeRoot,
|
|
746
|
-
`do $$
|
|
747
|
-
declare
|
|
748
|
-
fk_name text;
|
|
749
|
-
begin
|
|
750
|
-
select c.conname
|
|
751
|
-
into fk_name
|
|
752
|
-
from pg_constraint c
|
|
753
|
-
where c.conrelid = 'public.profiles'::regclass
|
|
754
|
-
and c.contype = 'f'
|
|
755
|
-
and c.confrelid = 'auth.users'::regclass
|
|
756
|
-
and c.conkey = array[
|
|
757
|
-
(
|
|
758
|
-
select a.attnum
|
|
759
|
-
from pg_attribute a
|
|
760
|
-
where a.attrelid = 'public.profiles'::regclass
|
|
761
|
-
and a.attname = 'id'
|
|
762
|
-
and not a.attisdropped
|
|
763
|
-
)
|
|
764
|
-
]::smallint[]
|
|
765
|
-
limit 1;
|
|
766
|
-
|
|
767
|
-
if fk_name is null then
|
|
768
|
-
raise exception 'managed id foreign key was not found before drift injection';
|
|
769
|
-
end if;
|
|
770
|
-
|
|
771
|
-
execute format('alter table public.profiles drop constraint %I', fk_name);
|
|
772
|
-
end;
|
|
773
|
-
$$;
|
|
774
|
-
|
|
775
|
-
alter table public.profiles
|
|
776
|
-
add constraint profiles_id_auth_users_restrict_fkey
|
|
777
|
-
foreign key (id) references auth.users(id) on delete restrict;`,
|
|
778
|
-
);
|
|
779
|
-
|
|
780
|
-
const malformedFkStatus = await expectGeneratedStatusFailure(minikubeRoot);
|
|
781
|
-
expect(malformedFkStatus).toContain('profile schema: drift detected');
|
|
782
|
-
} finally {
|
|
783
|
-
await cleanupIntegrationProject(appRoot, minikubeRoot);
|
|
784
|
-
}
|
|
785
|
-
},
|
|
786
|
-
INTEGRATION_TIMEOUT_MS,
|
|
787
|
-
);
|
|
788
|
-
|
|
789
|
-
integrationTest('rejects public.users at generation time', () => {
|
|
790
|
-
expect(() =>
|
|
791
|
-
generateInfrastructure(createManifest({ table: 'users', fields: ['email'] })),
|
|
792
|
-
).toThrow('Invalid Supabase profile table identifier "users"');
|
|
793
|
-
});
|
|
794
|
-
});
|
|
795
|
-
|
|
796
|
-
async function createIntegrationProject(): Promise<{
|
|
797
|
-
appRoot: string;
|
|
798
|
-
minikubeRoot: string;
|
|
799
|
-
namespaceHint: string;
|
|
800
|
-
}> {
|
|
801
|
-
const appRoot = await mkdtemp(path.join(tmpdir(), 'ankh-infra-supabase-'));
|
|
802
|
-
const namespaceHint = `profile-${Date.now().toString(36)}`;
|
|
803
|
-
return {
|
|
804
|
-
appRoot,
|
|
805
|
-
minikubeRoot: path.join(appRoot, 'infra/minikube'),
|
|
806
|
-
namespaceHint,
|
|
807
|
-
};
|
|
808
|
-
}
|
|
809
|
-
|
|
810
|
-
async function cleanupIntegrationProject(appRoot: string, minikubeRoot: string): Promise<void> {
|
|
811
|
-
await execFile('supabase', ['--workdir', minikubeRoot, 'stop', '--no-backup']).catch(() => {
|
|
812
|
-
// Best-effort cleanup for gated local integration runs.
|
|
813
|
-
});
|
|
814
|
-
await rm(appRoot, { recursive: true, force: true });
|
|
815
|
-
}
|
|
816
|
-
|
|
817
|
-
async function writeGeneratedFiles(
|
|
818
|
-
appRoot: string,
|
|
819
|
-
files: readonly GeneratedInfrastructureFile[],
|
|
820
|
-
): Promise<void> {
|
|
821
|
-
for (const file of files) {
|
|
822
|
-
const target = path.join(appRoot, file.path);
|
|
823
|
-
await mkdir(path.dirname(target), { recursive: true });
|
|
824
|
-
await writeFile(target, file.content, 'utf8');
|
|
825
|
-
if (file.executable) {
|
|
826
|
-
await chmod(target, 0o755);
|
|
827
|
-
}
|
|
828
|
-
}
|
|
829
|
-
}
|
|
830
|
-
|
|
831
|
-
async function runLocalSupabaseEnv(minikubeRoot: string): Promise<void> {
|
|
832
|
-
await execFile(path.join(minikubeRoot, 'scripts/supabase-local-env.sh'), {
|
|
833
|
-
cwd: minikubeRoot,
|
|
834
|
-
env: { ...process.env, SUPABASE_PROJECT_DIR: minikubeRoot },
|
|
835
|
-
});
|
|
836
|
-
}
|
|
837
|
-
|
|
838
|
-
async function expectLocalSupabaseEnvFailure(minikubeRoot: string): Promise<string> {
|
|
839
|
-
try {
|
|
840
|
-
await runLocalSupabaseEnv(minikubeRoot);
|
|
841
|
-
} catch (error) {
|
|
842
|
-
const failure = error as { stdout?: string; stderr?: string };
|
|
843
|
-
return `${failure.stdout ?? ''}\n${failure.stderr ?? ''}`;
|
|
844
|
-
}
|
|
845
|
-
|
|
846
|
-
throw new Error('Expected local Supabase bootstrap to fail');
|
|
847
|
-
}
|
|
848
|
-
|
|
849
|
-
async function expectGeneratedStatusFailure(minikubeRoot: string): Promise<string> {
|
|
850
|
-
const fakeBin = path.join(minikubeRoot, 'fake-bin');
|
|
851
|
-
const fakeKubectl = path.join(fakeBin, 'kubectl');
|
|
852
|
-
await mkdir(fakeBin, { recursive: true });
|
|
853
|
-
await writeFile(
|
|
854
|
-
fakeKubectl,
|
|
855
|
-
`#!/usr/bin/env bash
|
|
856
|
-
set -euo pipefail
|
|
857
|
-
|
|
858
|
-
if [[ "\${1:-}" == "config" && "\${2:-}" == "current-context" ]]; then
|
|
859
|
-
echo fake-context
|
|
860
|
-
exit 0
|
|
861
|
-
fi
|
|
862
|
-
|
|
863
|
-
if [[ "\${1:-}" == "cluster-info" ]]; then
|
|
864
|
-
echo "Kubernetes control plane is running"
|
|
865
|
-
exit 0
|
|
866
|
-
fi
|
|
867
|
-
|
|
868
|
-
if [[ "\${1:-}" == "get" && "\${2:-}" == "namespace" ]]; then
|
|
869
|
-
exit 0
|
|
870
|
-
fi
|
|
871
|
-
|
|
872
|
-
if [[ "\${1:-}" == "get" && "\${2:-}" == "all" ]]; then
|
|
873
|
-
exit 0
|
|
874
|
-
fi
|
|
875
|
-
|
|
876
|
-
if [[ "\${1:-}" == "-n" && "\${3:-}" == "get" && "\${4:-}" == "configmap" ]]; then
|
|
877
|
-
exit 0
|
|
878
|
-
fi
|
|
879
|
-
|
|
880
|
-
if [[ "\${1:-}" == "-n" && "\${3:-}" == "get" && "\${4:-}" == "secret" ]]; then
|
|
881
|
-
exit 1
|
|
882
|
-
fi
|
|
883
|
-
|
|
884
|
-
exit 0
|
|
885
|
-
`,
|
|
886
|
-
'utf8',
|
|
887
|
-
);
|
|
888
|
-
await chmod(fakeKubectl, 0o755);
|
|
889
|
-
|
|
890
|
-
try {
|
|
891
|
-
await execFile(path.join(minikubeRoot, 'scripts/status.sh'), {
|
|
892
|
-
cwd: minikubeRoot,
|
|
893
|
-
env: {
|
|
894
|
-
...process.env,
|
|
895
|
-
PATH: `${fakeBin}:${process.env.PATH ?? ''}`,
|
|
896
|
-
SUPABASE_PROJECT_DIR: minikubeRoot,
|
|
897
|
-
},
|
|
898
|
-
});
|
|
899
|
-
} catch (error) {
|
|
900
|
-
const failure = error as { stdout?: string; stderr?: string };
|
|
901
|
-
return `${failure.stdout ?? ''}\n${failure.stderr ?? ''}`;
|
|
902
|
-
}
|
|
903
|
-
|
|
904
|
-
throw new Error('Expected generated status script to fail');
|
|
905
|
-
}
|
|
906
|
-
|
|
907
|
-
async function runGeneratedStatus(minikubeRoot: string): Promise<string> {
|
|
908
|
-
const fakeBin = path.join(minikubeRoot, 'fake-status-bin');
|
|
909
|
-
const fakeKubectl = path.join(fakeBin, 'kubectl');
|
|
910
|
-
await mkdir(fakeBin, { recursive: true });
|
|
911
|
-
await writeFile(
|
|
912
|
-
fakeKubectl,
|
|
913
|
-
`#!/usr/bin/env bash
|
|
914
|
-
set -euo pipefail
|
|
915
|
-
|
|
916
|
-
if [[ "\${1:-}" == "config" && "\${2:-}" == "current-context" ]]; then
|
|
917
|
-
echo fake-context
|
|
918
|
-
exit 0
|
|
919
|
-
fi
|
|
920
|
-
|
|
921
|
-
if [[ "\${1:-}" == "cluster-info" ]]; then
|
|
922
|
-
echo "Kubernetes control plane is running"
|
|
923
|
-
exit 0
|
|
924
|
-
fi
|
|
925
|
-
|
|
926
|
-
if [[ "\${1:-}" == "get" && "\${2:-}" == "namespace" ]]; then
|
|
927
|
-
exit 0
|
|
928
|
-
fi
|
|
929
|
-
|
|
930
|
-
if [[ "\${1:-}" == "get" && "\${2:-}" == "all" ]]; then
|
|
931
|
-
exit 0
|
|
932
|
-
fi
|
|
933
|
-
|
|
934
|
-
if [[ "\${1:-}" == "-n" && "\${3:-}" == "get" && "\${4:-}" == "configmap" ]]; then
|
|
935
|
-
exit 0
|
|
936
|
-
fi
|
|
937
|
-
|
|
938
|
-
if [[ "\${1:-}" == "-n" && "\${3:-}" == "get" && "\${4:-}" == "secret" ]]; then
|
|
939
|
-
exit 1
|
|
940
|
-
fi
|
|
941
|
-
|
|
942
|
-
exit 0
|
|
943
|
-
`,
|
|
944
|
-
'utf8',
|
|
945
|
-
);
|
|
946
|
-
await chmod(fakeKubectl, 0o755);
|
|
947
|
-
|
|
948
|
-
const result = await execFile(path.join(minikubeRoot, 'scripts/status.sh'), {
|
|
949
|
-
cwd: minikubeRoot,
|
|
950
|
-
env: {
|
|
951
|
-
...process.env,
|
|
952
|
-
PATH: `${fakeBin}:${process.env.PATH ?? ''}`,
|
|
953
|
-
SUPABASE_PROJECT_DIR: minikubeRoot,
|
|
954
|
-
},
|
|
955
|
-
});
|
|
956
|
-
|
|
957
|
-
return `${result.stdout}\n${result.stderr}`;
|
|
958
|
-
}
|
|
959
|
-
|
|
960
|
-
async function runSupabaseSql(minikubeRoot: string, sql: string): Promise<void> {
|
|
961
|
-
const { stdout } = await execFile('supabase', ['--workdir', minikubeRoot, 'status', '-o', 'env']);
|
|
962
|
-
const dbUrl = readStatusEnv(stdout, 'DB_URL');
|
|
963
|
-
const sqlFile = path.join(minikubeRoot, `integration-${Date.now().toString(36)}.sql`);
|
|
964
|
-
await writeFile(sqlFile, sql, 'utf8');
|
|
965
|
-
await execFile('psql', [dbUrl, '-v', 'ON_ERROR_STOP=1', '-q', '-f', sqlFile]);
|
|
966
|
-
await rm(sqlFile, { force: true });
|
|
967
|
-
}
|
|
968
|
-
|
|
969
|
-
function readStatusEnv(source: string, key: string): string {
|
|
970
|
-
const line = source
|
|
971
|
-
.split('\n')
|
|
972
|
-
.find(
|
|
973
|
-
(entry) =>
|
|
974
|
-
entry === `${key}=` || entry.startsWith(`${key}=`) || entry.startsWith(`export ${key}=`),
|
|
975
|
-
);
|
|
976
|
-
if (!line) {
|
|
977
|
-
throw new Error(`Missing ${key} from supabase status output`);
|
|
978
|
-
}
|
|
979
|
-
return line
|
|
980
|
-
.replace(/^export /, '')
|
|
981
|
-
.slice(`${key}=`.length)
|
|
982
|
-
.replace(/^"|"$/g, '');
|
|
983
|
-
}
|
|
984
|
-
|
|
985
|
-
function createManifest(args: {
|
|
986
|
-
fields: readonly string[];
|
|
987
|
-
table?: string;
|
|
988
|
-
createStrategy?: 'trigger' | 'api';
|
|
989
|
-
}): InfraManifestInput {
|
|
990
|
-
const table = Object.hasOwn(args, 'table') ? args.table : 'profiles';
|
|
991
|
-
return {
|
|
992
|
-
deployment: {
|
|
993
|
-
target: 'minikube',
|
|
994
|
-
monitoring: false,
|
|
995
|
-
},
|
|
996
|
-
auth: {
|
|
997
|
-
scope: 'global',
|
|
998
|
-
provider: 'supabase',
|
|
999
|
-
authorization: {
|
|
1000
|
-
kind: 'RBAC',
|
|
1001
|
-
engine: 'native',
|
|
1002
|
-
},
|
|
1003
|
-
...(table
|
|
1004
|
-
? {
|
|
1005
|
-
profile: {
|
|
1006
|
-
table,
|
|
1007
|
-
fields: args.fields,
|
|
1008
|
-
primaryKey: 'authUserId',
|
|
1009
|
-
createStrategy: args.createStrategy ?? 'trigger',
|
|
1010
|
-
updateStrategy: 'api',
|
|
1011
|
-
},
|
|
1012
|
-
}
|
|
1013
|
-
: {
|
|
1014
|
-
profile: {
|
|
1015
|
-
fields: args.fields,
|
|
1016
|
-
},
|
|
1017
|
-
}),
|
|
1018
|
-
},
|
|
1019
|
-
database: {
|
|
1020
|
-
provider: 'supabase',
|
|
1021
|
-
tier: 'dev',
|
|
1022
|
-
},
|
|
1023
|
-
networking: {
|
|
1024
|
-
cdn: false,
|
|
1025
|
-
},
|
|
1026
|
-
modules: [],
|
|
1027
|
-
};
|
|
1028
|
-
}
|