@aifabrix/builder 2.42.1 → 2.44.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/.cursor/rules/anchor-docs.mdc +15 -0
- package/README.md +2 -2
- package/anchor-docs/README.md +10 -0
- package/anchor-docs/_TEMPLATE +24 -0
- package/bin/aifabrix.js +13 -4
- package/integration/hubspot-test/README.md +157 -0
- package/integration/{hubspot → hubspot-test}/application.json +6 -6
- package/integration/{hubspot → hubspot-test}/create-hubspot.js +10 -10
- package/integration/hubspot-test/env.template +4 -0
- package/integration/hubspot-test/hubspot-test-datasource-company.json +138 -0
- package/integration/hubspot-test/hubspot-test-datasource-contact.json +146 -0
- package/integration/hubspot-test/hubspot-test-datasource-deal.json +146 -0
- package/integration/hubspot-test/hubspot-test-datasource-users.json +76 -0
- package/integration/{hubspot/hubspot-deploy.json → hubspot-test/hubspot-test-deploy.json} +201 -24
- package/integration/{hubspot/hubspot-system.json → hubspot-test/hubspot-test-system.json} +8 -7
- package/integration/hubspot-test/rbac.json +166 -0
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-hubspot-credential-real.yaml +3 -3
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-hubspot-env-vars.yaml +2 -2
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-add-datasource.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-credential-create.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-credential-select.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-known-platform.yaml +1 -1
- package/integration/hubspot-test/test-artifacts/wizard-invalid-missing-source.yaml +2 -0
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-mode.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-openapi-file.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-openapi-url.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-source.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-valid-for-dimension-array-test.yaml +1 -1
- package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-key-test.yaml +5 -0
- package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-path-test.yaml +5 -0
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-valid-for-dimension-test.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-valid-for-rbac-test.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-valid-for-rbac-yaml-test.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-dataplane-down-tests.js +1 -7
- package/integration/{hubspot → hubspot-test}/test-dataplane-down.js +3 -3
- package/integration/{hubspot → hubspot-test}/test.js +137 -102
- package/integration/{hubspot → hubspot-test}/wizard-hubspot-e2e.yaml +2 -2
- package/integration/{hubspot → hubspot-test}/wizard-hubspot-platform.yaml +1 -1
- package/integration/hubspot-test/wizard-hubspot-test-headless.yaml +23 -0
- package/integration/roundtrip-test-local/README.md +144 -0
- package/integration/roundtrip-test-local/application.yaml +13 -0
- package/integration/roundtrip-test-local/env.template +15 -0
- package/integration/roundtrip-test-local/roundtrip-test-local-datasource-roundtrip-test-company.yaml +14 -0
- package/integration/roundtrip-test-local/roundtrip-test-local-deploy.json +61 -0
- package/integration/roundtrip-test-local/roundtrip-test-local-system.yaml +25 -0
- package/integration/roundtrip-test-local2/README.md +144 -0
- package/integration/roundtrip-test-local2/application.yaml +13 -0
- package/integration/roundtrip-test-local2/env.template +15 -0
- package/integration/roundtrip-test-local2/roundtrip-test-local2-datasource-company.yaml +31 -0
- package/integration/roundtrip-test-local2/roundtrip-test-local2-deploy.json +86 -0
- package/integration/roundtrip-test-local2/roundtrip-test-local2-system.yaml +25 -0
- package/integration/test/wizard.yaml +8 -0
- package/jest.config.default.js +10 -0
- package/jest.config.integration.fixtures.js +22 -0
- package/jest.config.integration.js +21 -18
- package/jest.config.isolated.js +10 -0
- package/jest.projects.js +288 -0
- package/lib/api/datasources-core.api.js +3 -3
- package/lib/api/dev-mtls-request.js +110 -0
- package/lib/api/dev-server-https.js +145 -0
- package/lib/api/dev.api.js +133 -144
- package/lib/api/index.js +0 -1
- package/lib/api/pipeline.api.js +67 -20
- package/lib/api/service-users.api.js +111 -2
- package/lib/api/types/dev.types.js +4 -3
- package/lib/api/types/pipeline.types.js +8 -5
- package/lib/api/types/service-users.types.js +41 -0
- package/lib/api/types/validation-run.types.js +56 -0
- package/lib/api/validation-run.api.js +99 -0
- package/lib/api/validation-runner.js +99 -0
- package/lib/app/config.js +1 -1
- package/lib/app/deploy-status-display.js +2 -2
- package/lib/app/deploy.js +7 -6
- package/lib/app/display.js +2 -1
- package/lib/app/dockerfile.js +3 -2
- package/lib/app/down.js +2 -1
- package/lib/app/helpers.js +6 -5
- package/lib/app/index.js +27 -8
- package/lib/app/list.js +7 -6
- package/lib/app/push.js +4 -3
- package/lib/app/register.js +19 -8
- package/lib/app/rotate-secret.js +17 -13
- package/lib/app/run-container-start.js +184 -0
- package/lib/app/run-docker-fallback.js +108 -0
- package/lib/app/run-env-compose.js +30 -42
- package/lib/app/run-helpers.js +49 -126
- package/lib/app/run-infra-requirements.js +30 -0
- package/lib/app/run-resolve-image.js +21 -0
- package/lib/app/run.js +74 -21
- package/lib/app/show-display.js +1 -1
- package/lib/app/show.js +1 -1
- package/lib/build/index.js +13 -10
- package/lib/cli/index.js +2 -0
- package/lib/cli/setup-app.help.js +67 -0
- package/lib/cli/setup-app.js +59 -123
- package/lib/cli/setup-app.test-commands.js +179 -0
- package/lib/cli/setup-auth.js +36 -14
- package/lib/cli/setup-credential-deployment.js +22 -8
- package/lib/cli/setup-dev-path-commands.js +124 -0
- package/lib/cli/setup-dev.js +190 -103
- package/lib/cli/setup-environment.js +11 -20
- package/lib/cli/setup-external-system.js +62 -22
- package/lib/cli/setup-infra.js +139 -47
- package/lib/cli/setup-parameters.js +32 -0
- package/lib/cli/setup-secrets.js +147 -10
- package/lib/cli/setup-service-user.js +146 -20
- package/lib/cli/setup-utility.js +47 -19
- package/lib/commands/app-down.js +5 -7
- package/lib/commands/app-install.js +14 -7
- package/lib/commands/app-logs.js +13 -10
- package/lib/commands/app-shell.js +4 -1
- package/lib/commands/app-test.js +25 -19
- package/lib/commands/app.js +22 -10
- package/lib/commands/auth-config.js +10 -14
- package/lib/commands/auth-status.js +4 -3
- package/lib/commands/credential-env.js +4 -3
- package/lib/commands/credential-list.js +5 -4
- package/lib/commands/credential-push.js +4 -3
- package/lib/commands/datasource-unified-test-cli.js +495 -0
- package/lib/commands/datasource-unified-test-cli.options.js +149 -0
- package/lib/commands/datasource-validation-cli.js +129 -0
- package/lib/commands/datasource.js +123 -71
- package/lib/commands/deployment-list.js +6 -5
- package/lib/commands/dev-cli-handlers.js +122 -18
- package/lib/commands/dev-down.js +4 -3
- package/lib/commands/dev-init.js +231 -116
- package/lib/commands/dev-show-display.js +473 -0
- package/lib/commands/login-credentials.js +3 -2
- package/lib/commands/login-device.js +4 -3
- package/lib/commands/login.js +5 -4
- package/lib/commands/logout.js +8 -7
- package/lib/commands/parameters-validate.js +54 -0
- package/lib/commands/repair-datasource.js +314 -68
- package/lib/commands/repair-env-template.js +16 -10
- package/lib/commands/repair-rbac.js +25 -19
- package/lib/commands/repair.js +116 -32
- package/lib/commands/secrets-list.js +23 -12
- package/lib/commands/secrets-remove-all.js +220 -0
- package/lib/commands/secrets-remove.js +22 -13
- package/lib/commands/secrets-set.js +21 -12
- package/lib/commands/secrets-validate.js +20 -7
- package/lib/commands/secure.js +10 -9
- package/lib/commands/service-user.js +243 -13
- package/lib/commands/test-e2e-external.js +27 -1
- package/lib/commands/up-common.js +28 -2
- package/lib/commands/up-dataplane.js +31 -18
- package/lib/commands/up-miso.js +19 -29
- package/lib/commands/upload.js +138 -39
- package/lib/commands/wizard-core-helpers.js +1 -1
- package/lib/commands/wizard-dataplane.js +4 -3
- package/lib/commands/wizard-helpers.js +3 -3
- package/lib/commands/wizard.js +2 -2
- package/lib/core/admin-secrets.js +16 -5
- package/lib/core/audit-logger.js +12 -4
- package/lib/core/config-attach-extensions.js +46 -0
- package/lib/core/config-runtime-paths.js +29 -0
- package/lib/core/config.js +59 -58
- package/lib/core/diff.js +3 -2
- package/lib/core/ensure-encryption-key.js +2 -4
- package/lib/core/secrets-ensure-infra.js +77 -0
- package/lib/core/secrets-ensure.js +120 -64
- package/lib/core/secrets-env-write.js +35 -7
- package/lib/core/secrets-infra-placeholder-sync.js +61 -0
- package/lib/core/secrets.js +228 -42
- package/lib/core/templates-env.js +4 -3
- package/lib/core/templates.js +1 -1
- package/lib/datasource/abac-validator.js +148 -0
- package/lib/datasource/deploy.js +75 -53
- package/lib/datasource/field-reference-validator.js +77 -36
- package/lib/datasource/integration-context.js +63 -0
- package/lib/datasource/list.js +8 -7
- package/lib/datasource/log-viewer.js +252 -0
- package/lib/datasource/resolve-app.js +109 -0
- package/lib/datasource/test-e2e.js +95 -155
- package/lib/datasource/test-integration.js +121 -109
- package/lib/datasource/unified-validation-run-body.js +65 -0
- package/lib/datasource/unified-validation-run-post.js +23 -0
- package/lib/datasource/unified-validation-run-resolve.js +43 -0
- package/lib/datasource/unified-validation-run.js +92 -0
- package/lib/datasource/validate.js +162 -15
- package/lib/deployment/deployer.js +4 -3
- package/lib/deployment/environment.js +7 -6
- package/lib/deployment/push.js +17 -8
- package/lib/external-system/delete.js +4 -3
- package/lib/external-system/deploy.js +131 -53
- package/lib/external-system/download-helpers.js +1 -1
- package/lib/external-system/download.js +7 -6
- package/lib/external-system/generator.js +104 -14
- package/lib/external-system/integration-test-dispatch.js +26 -0
- package/lib/external-system/test-execution.js +5 -1
- package/lib/external-system/test-helpers.js +0 -4
- package/lib/external-system/test-system-level-helpers.js +110 -0
- package/lib/external-system/test-system-level.js +83 -44
- package/lib/external-system/test.js +59 -8
- package/lib/generator/builders.js +23 -11
- package/lib/generator/deploy-manifest-azure-kv.js +81 -0
- package/lib/generator/external-controller-manifest.js +3 -3
- package/lib/generator/external.js +23 -11
- package/lib/generator/helpers.js +71 -12
- package/lib/generator/index.js +8 -4
- package/lib/generator/split-readme.js +12 -7
- package/lib/generator/split-variables.js +2 -1
- package/lib/generator/split.js +46 -11
- package/lib/generator/wizard-readme.js +3 -3
- package/lib/generator/wizard.js +16 -13
- package/lib/infrastructure/compose.js +60 -6
- package/lib/infrastructure/helpers.js +238 -51
- package/lib/infrastructure/index.js +64 -37
- package/lib/infrastructure/services.js +21 -15
- package/lib/internal/fs-real-sync.js +104 -0
- package/lib/internal/node-fs.js +98 -0
- package/lib/parameters/database-secret-values.js +173 -0
- package/lib/parameters/infra-kv-discovery.js +121 -0
- package/lib/parameters/infra-parameter-catalog.js +458 -0
- package/lib/parameters/infra-parameter-validate.js +64 -0
- package/lib/schema/application-schema.json +37 -17
- package/lib/schema/datasource-test-run.schema.json +493 -0
- package/lib/schema/deployment-rules.yaml +102 -63
- package/lib/schema/external-datasource.schema.json +1201 -433
- package/lib/schema/external-system.schema.json +181 -5
- package/lib/schema/flag-map-validation-run.json +31 -0
- package/lib/schema/infra-parameter.schema.json +106 -0
- package/lib/schema/infra.parameter.yaml +421 -0
- package/lib/schema/type/credential-auth-templates.json +40 -0
- package/lib/schema/type/document-storage.json +213 -0
- package/lib/schema/type/message-service.json +123 -0
- package/lib/schema/type/vector-store.json +88 -0
- package/lib/utils/aifabrix-runtime-config-dir.js +132 -0
- package/lib/utils/api-error-handler.js +2 -2
- package/lib/utils/api.js +49 -14
- package/lib/utils/app-config-resolver.js +23 -1
- package/lib/utils/app-register-api.js +3 -2
- package/lib/utils/app-register-auth.js +1 -1
- package/lib/utils/app-register-config.js +4 -4
- package/lib/utils/app-register-display.js +3 -2
- package/lib/utils/app-register-validator.js +3 -2
- package/lib/utils/app-run-containers.js +26 -22
- package/lib/utils/app-scoped-config.js +31 -0
- package/lib/utils/app-service-env-from-builder.js +164 -0
- package/lib/utils/build-copy.js +1 -1
- package/lib/utils/build-helpers.js +20 -20
- package/lib/utils/build-resolve-image.js +165 -0
- package/lib/utils/cli-layout-chalk.js +8 -0
- package/lib/utils/cli-test-layout-chalk.js +267 -0
- package/lib/utils/cli-utils.js +88 -11
- package/lib/utils/compose-db-passwords.js +138 -0
- package/lib/utils/compose-generate-docker-compose.js +216 -0
- package/lib/utils/compose-generator.js +197 -291
- package/lib/utils/compose-miso-env.js +18 -0
- package/lib/utils/compose-traefik-ingress-base.js +158 -0
- package/lib/utils/config-paths.js +209 -6
- package/lib/utils/config-scoped-resources-preference.js +41 -0
- package/lib/utils/controller-deployment-outcome.js +68 -0
- package/lib/utils/credential-display.js +2 -2
- package/lib/utils/credential-secrets-env.js +16 -1
- package/lib/utils/dataplane-pipeline-warning.js +4 -3
- package/lib/utils/datasource-test-run-capability-scope.js +43 -0
- package/lib/utils/datasource-test-run-debug-display.js +137 -0
- package/lib/utils/datasource-test-run-debug-slice.js +93 -0
- package/lib/utils/datasource-test-run-display.js +442 -0
- package/lib/utils/datasource-test-run-exit.js +58 -0
- package/lib/utils/datasource-test-run-legacy-adapter.js +93 -0
- package/lib/utils/datasource-test-run-report-version.js +51 -0
- package/lib/utils/datasource-test-run-schema-sync.js +59 -0
- package/lib/utils/datasource-test-run-tty-log.js +81 -0
- package/lib/utils/datasource-validation-watch.js +266 -0
- package/lib/utils/declarative-url-ports.js +47 -0
- package/lib/utils/derive-env-key-from-client-id.js +41 -0
- package/lib/utils/dev-ca-install.js +185 -23
- package/lib/utils/dev-cert-helper.js +266 -17
- package/lib/utils/dev-hosts-helper.js +307 -0
- package/lib/utils/dev-init-cert-hints.js +37 -0
- package/lib/utils/dev-init-health-messages.js +52 -0
- package/lib/utils/dev-init-resolve.js +86 -0
- package/lib/utils/dev-init-ssh-merge.js +65 -0
- package/lib/utils/dev-ssh-config-helper.js +196 -0
- package/lib/utils/dev-user-groups.js +93 -0
- package/lib/utils/docker-build.js +42 -17
- package/lib/utils/docker-exec.js +28 -0
- package/lib/utils/docker-manifest-public-port.js +116 -0
- package/lib/utils/docker-not-running-hint.js +52 -0
- package/lib/utils/docker.js +98 -11
- package/lib/utils/ensure-dev-certs-for-remote-docker.js +192 -0
- package/lib/utils/env-config-loader.js +10 -91
- package/lib/utils/env-copy.js +19 -10
- package/lib/utils/env-map.js +42 -11
- package/lib/utils/env-template.js +2 -2
- package/lib/utils/environment-scoped-resources.js +144 -0
- package/lib/utils/error-formatter.js +125 -9
- package/lib/utils/error-formatters/http-status-errors.js +6 -5
- package/lib/utils/error-formatters/network-errors.js +2 -1
- package/lib/utils/error-formatters/permission-errors.js +2 -1
- package/lib/utils/error-formatters/validation-errors.js +2 -1
- package/lib/utils/external-env-template.js +180 -0
- package/lib/utils/external-readme.js +8 -1
- package/lib/utils/external-system-display.js +277 -136
- package/lib/utils/external-system-local-test-tty.js +389 -0
- package/lib/utils/external-system-readiness-core.js +377 -0
- package/lib/utils/external-system-readiness-deploy-display.js +270 -0
- package/lib/utils/external-system-readiness-display-internals.js +150 -0
- package/lib/utils/external-system-readiness-display.js +186 -0
- package/lib/utils/external-system-test-helpers.js +24 -6
- package/lib/utils/external-system-validators.js +32 -14
- package/lib/utils/health-check-url.js +119 -0
- package/lib/utils/health-check.js +59 -25
- package/lib/utils/help-builder.js +14 -13
- package/lib/utils/image-version.js +4 -8
- package/lib/utils/infra-containers.js +4 -7
- package/lib/utils/infra-env-defaults.js +162 -0
- package/lib/utils/infra-status-display.js +167 -0
- package/lib/utils/infra-status.js +16 -8
- package/lib/utils/local-secrets.js +29 -7
- package/lib/utils/paths.js +136 -48
- package/lib/utils/port-resolver.js +10 -23
- package/lib/utils/redis-env-scope.js +62 -0
- package/lib/utils/register-aifabrix-shell-env.js +204 -0
- package/lib/utils/remote-builder-validation.js +99 -0
- package/lib/utils/remote-dev-auth.js +117 -21
- package/lib/utils/remote-docker-env.js +67 -15
- package/lib/utils/remote-secrets-loader.js +13 -4
- package/lib/utils/resolve-docker-image-ref.js +124 -0
- package/lib/utils/schema-loader.js +22 -9
- package/lib/utils/secrets-bash-kv.js +25 -0
- package/lib/utils/secrets-generator.js +171 -51
- package/lib/utils/secrets-helpers.js +70 -59
- package/lib/utils/secrets-kv-scope.js +60 -0
- package/lib/utils/secrets-utils.js +35 -37
- package/lib/utils/secrets-validation.js +3 -1
- package/lib/utils/secrets-yaml-preserve.js +109 -0
- package/lib/utils/secure-file-permissions.js +91 -0
- package/lib/utils/ssh-key-helper.js +4 -2
- package/lib/utils/template-helpers.js +2 -2
- package/lib/utils/test-log-writer.js +3 -3
- package/lib/utils/token-manager.js +37 -5
- package/lib/utils/url-declarative-public-base.js +188 -0
- package/lib/utils/url-declarative-resolve-build.js +493 -0
- package/lib/utils/url-declarative-resolve-load-doc.js +51 -0
- package/lib/utils/url-declarative-resolve.js +220 -0
- package/lib/utils/url-declarative-token-parse.js +74 -0
- package/lib/utils/url-declarative-url-flags.js +50 -0
- package/lib/utils/url-declarative-vdir-inactive-env.js +99 -0
- package/lib/utils/url-public-path-prefix.js +34 -0
- package/lib/utils/urls-local-registry.js +220 -0
- package/lib/utils/validation-report-tty-kit.js +77 -0
- package/lib/utils/validation-run-poll.js +89 -0
- package/lib/utils/validation-run-post-retry.js +73 -0
- package/lib/utils/validation-run-request.js +98 -0
- package/lib/utils/variable-transformer.js +21 -4
- package/lib/utils/yaml-preserve.js +78 -1
- package/lib/validation/datasource-warnings.js +56 -0
- package/lib/validation/env-template-auth.js +50 -2
- package/lib/validation/external-manifest-validator.js +35 -7
- package/lib/validation/validate-display.js +37 -31
- package/lib/validation/validate.js +9 -10
- package/lib/validation/validator-unresolved-placeholders.js +98 -0
- package/lib/validation/validator.js +32 -78
- package/lib/validation/wizard-config-validator.js +2 -1
- package/package.json +11 -3
- package/scripts/check-datasource-test-run-schema-sync.js +34 -0
- package/scripts/diagnose-cli.js +150 -0
- package/scripts/install-local.js +304 -55
- package/templates/README.md +15 -2
- package/templates/applications/dataplane/application.yaml +52 -2
- package/templates/applications/dataplane/env.template +80 -18
- package/templates/applications/dataplane/rbac.yaml +8 -0
- package/templates/applications/keycloak/application.yaml +9 -1
- package/templates/applications/keycloak/env.template +15 -6
- package/templates/applications/miso-controller/application.yaml +10 -2
- package/templates/applications/miso-controller/env.template +55 -14
- package/templates/applications/miso-controller/rbac.yaml +5 -0
- package/templates/external-system/README.md.hbs +20 -7
- package/templates/external-system/deploy.js.hbs +5 -5
- package/templates/external-system/env.template.hbs +22 -0
- package/templates/external-system/external-datasource.yaml.hbs +197 -118
- package/templates/infra/compose.yaml.hbs +20 -4
- package/templates/python/docker-compose.hbs +16 -0
- package/templates/typescript/docker-compose.hbs +16 -0
- package/integration/hubspot/README.md +0 -102
- package/integration/hubspot/env.template +0 -4
- package/integration/hubspot/hubspot-datasource-company.json +0 -541
- package/integration/hubspot/hubspot-datasource-contact.json +0 -639
- package/integration/hubspot/hubspot-datasource-deal.json +0 -588
- package/integration/hubspot/hubspot-datasource-users.json +0 -116
- package/integration/hubspot/test-artifacts/wizard-invalid-missing-source.yaml +0 -2
- package/integration/hubspot/test-artifacts/wizard-valid-for-dimension-key-test.yaml +0 -5
- package/integration/hubspot/test-artifacts/wizard-valid-for-dimension-path-test.yaml +0 -5
- package/lib/api/external-test.api.js +0 -111
- package/lib/schema/env-config.yaml +0 -43
- /package/integration/{hubspot → hubspot-test}/companies.json +0 -0
- /package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-app-name.yaml +0 -0
- /package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-missing-app.yaml +0 -0
- /package/integration/{hubspot → hubspot-test}/test-dataplane-down-helpers.js +0 -0
|
@@ -11,13 +11,31 @@
|
|
|
11
11
|
|
|
12
12
|
const path = require('path');
|
|
13
13
|
const fs = require('fs');
|
|
14
|
+
const fsRealSync = require('../internal/fs-real-sync');
|
|
15
|
+
const { nodeFs } = require('../internal/node-fs');
|
|
14
16
|
const chalk = require('chalk');
|
|
15
17
|
const handlebars = require('handlebars');
|
|
16
|
-
const
|
|
18
|
+
const adminSecrets = require('../core/admin-secrets');
|
|
17
19
|
const logger = require('../utils/logger');
|
|
18
20
|
const dockerUtils = require('../utils/docker');
|
|
19
21
|
const paths = require('../utils/paths');
|
|
20
22
|
const secretsEnsure = require('../core/secrets-ensure');
|
|
23
|
+
const {
|
|
24
|
+
mergeInfraParameterDefaultsForCli,
|
|
25
|
+
getInfraParameterCatalog,
|
|
26
|
+
readRelaxedCatalogDefaults
|
|
27
|
+
} = require('../parameters/infra-parameter-catalog');
|
|
28
|
+
const { ensureDevCertsIfNeededForRemoteDocker } = require('../utils/ensure-dev-certs-for-remote-docker');
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Lazy-load core/secrets at call time. A top-level require creates a circular dependency:
|
|
32
|
+
* secrets → url-declarative-resolve → compose-generator → compose-generate-docker-compose → this module,
|
|
33
|
+
* which left `generateAdminSecretsEnv` / `formatAdminSecretsContent` undefined on the captured export.
|
|
34
|
+
* @returns {Object} core/secrets module exports (loadSecrets, generateAdminSecretsEnv, …)
|
|
35
|
+
*/
|
|
36
|
+
function getCoreSecrets() {
|
|
37
|
+
return require('../core/secrets');
|
|
38
|
+
}
|
|
21
39
|
|
|
22
40
|
/**
|
|
23
41
|
* Gets infrastructure directory name based on developer ID
|
|
@@ -42,21 +60,64 @@ function getInfraProjectName(devId) {
|
|
|
42
60
|
}
|
|
43
61
|
|
|
44
62
|
/**
|
|
45
|
-
*
|
|
63
|
+
* User-facing error when Docker/Compose checks fail (tailored by underlying message).
|
|
64
|
+
* @param {string} detail - Error message from ensureDockerAndCompose / Docker CLI
|
|
65
|
+
* @returns {string}
|
|
66
|
+
*/
|
|
67
|
+
function formatDockerInfrastructureFailure(detail) {
|
|
68
|
+
const cause = (detail || '').trim() || 'unknown error';
|
|
69
|
+
|
|
70
|
+
if (/Docker Compose is not available/i.test(cause)) {
|
|
71
|
+
return (
|
|
72
|
+
'Cannot use Docker for infrastructure: Docker Compose check failed (see Cause below).\n\n' +
|
|
73
|
+
`Cause: ${cause}\n\n` +
|
|
74
|
+
'If Cause mentions TLS, certificate, or handshake, fix client TLS for docker-endpoint (cert.pem, key.pem, ca.pem under ~/.aifabrix/certs/<developer-id>/) or docker-tls-skip-verify when appropriate. ' +
|
|
75
|
+
'If Cause suggests a missing plugin, install Docker Compose v2 for your user (docker CLI + plugin; no unix socket needed when using tcp:// docker-endpoint). ' +
|
|
76
|
+
'Or set AIFABRIX_COMPOSE_CMD. Run `aifabrix doctor` for diagnostics.'
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (/AIFABRIX_COMPOSE_CMD/i.test(cause) && /is set but failed/i.test(cause)) {
|
|
81
|
+
return (
|
|
82
|
+
'Cannot use Docker for infrastructure: AIFABRIX_COMPOSE_CMD failed.\n\n' +
|
|
83
|
+
`Cause: ${cause}\n\n` +
|
|
84
|
+
'Unset or fix AIFABRIX_COMPOSE_CMD, or install a working Compose. Run `aifabrix doctor` for diagnostics.'
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return (
|
|
89
|
+
'Cannot use Docker for infrastructure (Docker CLI missing, Compose missing, or remote Docker misconfigured).\n\n' +
|
|
90
|
+
`Cause: ${cause}\n\n` +
|
|
91
|
+
'Install Docker Engine and Compose on this machine (or set AIFABRIX_COMPOSE_CMD). ' +
|
|
92
|
+
'If you use docker-endpoint in dev config: install cert.pem, key.pem, and ca.pem for full TLS verify; use `aifabrix dev pin` / ' +
|
|
93
|
+
'`dev init --pin` as needed; or enable TLS skip-verify (config or AIFABRIX_DOCKER_TLS_SKIP_VERIFY) when appropriate. ' +
|
|
94
|
+
'Run `aifabrix doctor` for diagnostics.'
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Check Docker availability (local daemon or remote via docker-endpoint + TLS).
|
|
46
100
|
* @async
|
|
47
101
|
* @returns {Promise<void>}
|
|
48
|
-
* @throws {Error} If Docker
|
|
102
|
+
* @throws {Error} If Docker/Compose cannot be used (includes underlying cause)
|
|
49
103
|
*/
|
|
50
104
|
async function checkDockerAvailability() {
|
|
105
|
+
await ensureDevCertsIfNeededForRemoteDocker();
|
|
51
106
|
try {
|
|
52
107
|
await dockerUtils.ensureDockerAndCompose();
|
|
53
108
|
} catch (error) {
|
|
54
|
-
|
|
109
|
+
const detail = (error && error.message) || String(error);
|
|
110
|
+
throw new Error(formatDockerInfrastructureFailure(detail));
|
|
55
111
|
}
|
|
56
112
|
}
|
|
57
113
|
|
|
58
|
-
/**
|
|
59
|
-
|
|
114
|
+
/**
|
|
115
|
+
* Fallback for admin password/email when validated catalog load failed but YAML is still readable.
|
|
116
|
+
* @returns {Record<string, string>}
|
|
117
|
+
*/
|
|
118
|
+
function readInfraDefaultScalars() {
|
|
119
|
+
return readRelaxedCatalogDefaults();
|
|
120
|
+
}
|
|
60
121
|
|
|
61
122
|
/**
|
|
62
123
|
* Log hint to reset Postgres volume when admin password was changed after first init.
|
|
@@ -65,23 +126,10 @@ const DEFAULT_ADMIN_PASSWORD = 'admin123';
|
|
|
65
126
|
function logVolumeResetHint(infraDir) {
|
|
66
127
|
logger.log(chalk.yellow(
|
|
67
128
|
'If Postgres was already started with a different password, login will fail until you reset the volume. ' +
|
|
68
|
-
`Run: cd ${infraDir} && docker compose -f compose.yaml -p aifabrix down -v , then run 'aifabrix up-infra --
|
|
129
|
+
`Run: cd ${infraDir} && docker compose -f compose.yaml -p aifabrix down -v , then run 'aifabrix up-infra --adminPassword <password>' again.`
|
|
69
130
|
));
|
|
70
131
|
}
|
|
71
132
|
|
|
72
|
-
/**
|
|
73
|
-
* Apply password to admin-secrets file content (all three password keys).
|
|
74
|
-
* @param {string} content - Current file content
|
|
75
|
-
* @param {string} password - Password to set
|
|
76
|
-
* @returns {string} Updated content
|
|
77
|
-
*/
|
|
78
|
-
function applyPasswordToAdminSecretsContent(content, password) {
|
|
79
|
-
return content
|
|
80
|
-
.replace(/^POSTGRES_PASSWORD=.*$/m, `POSTGRES_PASSWORD=${password}`)
|
|
81
|
-
.replace(/^PGADMIN_DEFAULT_PASSWORD=.*$/m, `PGADMIN_DEFAULT_PASSWORD=${password}`)
|
|
82
|
-
.replace(/^REDIS_COMMANDER_PASSWORD=.*$/m, `REDIS_COMMANDER_PASSWORD=${password}`);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
133
|
/**
|
|
86
134
|
* Sync postgres-passwordKeyVault to the main secrets store (file or remote).
|
|
87
135
|
* @param {string} password - Password to store
|
|
@@ -94,44 +142,150 @@ async function syncPostgresPasswordToStore(password) {
|
|
|
94
142
|
}
|
|
95
143
|
}
|
|
96
144
|
|
|
145
|
+
/** Non-email defaults for admin-secrets.env merge (email default comes from infra.parameter.yaml `defaults`). */
|
|
146
|
+
const DEFAULT_ADMIN_OBJ = {
|
|
147
|
+
REDIS_HOST: 'local:redis:6379:0:',
|
|
148
|
+
REDIS_COMMANDER_USER: 'admin'
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Writes merged admin secrets to disk and logs/syncs as needed.
|
|
153
|
+
* @async
|
|
154
|
+
* @param {string} adminSecretsPath - Path to admin-secrets.env
|
|
155
|
+
* @param {Object} adminObj - Decrypted admin secrets object
|
|
156
|
+
* @param {string} passwordToUse - Password to set for Postgres, pgAdmin, Redis Commander
|
|
157
|
+
* @param {boolean} shouldOverwriteWithAdminPwd - Whether this was an explicit admin password update
|
|
158
|
+
* @param {{ updateEmail?: boolean, emailToUse?: string }} [emailOpts]
|
|
159
|
+
*/
|
|
160
|
+
async function applyAdminSecretsUpdate(
|
|
161
|
+
adminSecretsPath,
|
|
162
|
+
adminObj,
|
|
163
|
+
passwordToUse,
|
|
164
|
+
shouldOverwriteWithAdminPwd,
|
|
165
|
+
emailOpts
|
|
166
|
+
) {
|
|
167
|
+
const merged = { ...DEFAULT_ADMIN_OBJ, ...adminObj };
|
|
168
|
+
merged.POSTGRES_PASSWORD = passwordToUse;
|
|
169
|
+
merged.PGADMIN_DEFAULT_PASSWORD = passwordToUse;
|
|
170
|
+
merged.REDIS_COMMANDER_PASSWORD = passwordToUse;
|
|
171
|
+
if (emailOpts && emailOpts.updateEmail && emailOpts.emailToUse) {
|
|
172
|
+
merged.PGADMIN_DEFAULT_EMAIL = emailOpts.emailToUse;
|
|
173
|
+
}
|
|
174
|
+
const content = await getCoreSecrets().formatAdminSecretsContent(merged);
|
|
175
|
+
fsRealSync.writeFileSync(adminSecretsPath, content, { mode: 0o600 });
|
|
176
|
+
if (shouldOverwriteWithAdminPwd) {
|
|
177
|
+
logger.log('Updated admin password in admin-secrets.env.');
|
|
178
|
+
await syncPostgresPasswordToStore(passwordToUse);
|
|
179
|
+
logVolumeResetHint(path.join(paths.getAifabrixSystemDir(), getInfraDirName(0)));
|
|
180
|
+
} else if (emailOpts && emailOpts.updateEmail) {
|
|
181
|
+
logger.log('Updated admin email in admin-secrets.env.');
|
|
182
|
+
} else {
|
|
183
|
+
logger.log('Set default admin password in admin-secrets.env for local use.');
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function loadAdminMergedDefaultsForInfra(options) {
|
|
188
|
+
try {
|
|
189
|
+
return mergeInfraParameterDefaultsForCli(getInfraParameterCatalog().data, options);
|
|
190
|
+
} catch {
|
|
191
|
+
return mergeInfraParameterDefaultsForCli({}, options);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function resolveAdminPasswordAndEmailCli(options, mergedDefaults) {
|
|
196
|
+
const infraDefaults = readInfraDefaultScalars();
|
|
197
|
+
const adminPwdCli = String(options.adminPassword || options.adminPwd || '').trim();
|
|
198
|
+
const adminPwdOverride = adminPwdCli !== '' ? adminPwdCli : null;
|
|
199
|
+
const passwordToUse =
|
|
200
|
+
adminPwdOverride !== null
|
|
201
|
+
? adminPwdOverride
|
|
202
|
+
: mergedDefaults.adminPassword || infraDefaults.adminPassword || '';
|
|
203
|
+
const emailCli = String(options.adminEmail || '').trim();
|
|
204
|
+
const emailOverride = emailCli !== '' ? emailCli : null;
|
|
205
|
+
const emailToUse =
|
|
206
|
+
emailOverride !== null
|
|
207
|
+
? emailOverride
|
|
208
|
+
: mergedDefaults.adminEmail || infraDefaults.adminEmail || '';
|
|
209
|
+
return { adminPwdOverride, passwordToUse, emailOverride, emailToUse };
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function computeAdminSecretsBackfillFlags(adminObj) {
|
|
213
|
+
const needsPasswordBackfill =
|
|
214
|
+
!(adminObj.POSTGRES_PASSWORD && adminObj.POSTGRES_PASSWORD.trim()) ||
|
|
215
|
+
!(adminObj.PGADMIN_DEFAULT_PASSWORD && adminObj.PGADMIN_DEFAULT_PASSWORD.trim()) ||
|
|
216
|
+
!(adminObj.REDIS_COMMANDER_PASSWORD && adminObj.REDIS_COMMANDER_PASSWORD.trim());
|
|
217
|
+
const needsEmailBackfill = !(adminObj.PGADMIN_DEFAULT_EMAIL && adminObj.PGADMIN_DEFAULT_EMAIL.trim());
|
|
218
|
+
return { needsPasswordBackfill, needsEmailBackfill };
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function resolvePasswordForAdminFile(
|
|
222
|
+
shouldOverwriteWithAdminPwd,
|
|
223
|
+
needsPasswordBackfill,
|
|
224
|
+
passwordToUse,
|
|
225
|
+
adminObj,
|
|
226
|
+
mergedDefaults
|
|
227
|
+
) {
|
|
228
|
+
if (shouldOverwriteWithAdminPwd || needsPasswordBackfill) {
|
|
229
|
+
return passwordToUse;
|
|
230
|
+
}
|
|
231
|
+
return (
|
|
232
|
+
String(adminObj.POSTGRES_PASSWORD || '').trim() ||
|
|
233
|
+
mergedDefaults.adminPassword ||
|
|
234
|
+
readInfraDefaultScalars().adminPassword ||
|
|
235
|
+
''
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
|
|
97
239
|
/**
|
|
98
240
|
* Ensure admin secrets file exists and set admin password.
|
|
99
241
|
* When adminPwd is provided, update POSTGRES_PASSWORD, PGADMIN_DEFAULT_PASSWORD, REDIS_COMMANDER_PASSWORD
|
|
100
242
|
* in admin-secrets.env (overwrites existing values). Otherwise only backfill empty fields.
|
|
243
|
+
* Reads and writes using decrypted values; writes encrypted when secrets-encryption key is set.
|
|
101
244
|
*
|
|
102
245
|
* @async
|
|
103
246
|
* @param {Object} [options] - Options
|
|
104
|
-
* @param {string} [options.
|
|
247
|
+
* @param {string} [options.adminPassword] - Override admin password (alias: adminPwd)
|
|
248
|
+
* @param {string} [options.adminPwd] - Override admin password for Postgres, pgAdmin, Redis Commander
|
|
249
|
+
* @param {string} [options.adminEmail] - Override pgAdmin default email (matches {{adminEmail}} defaults)
|
|
250
|
+
* @param {string} [options.userPassword] - Reserved for Keycloak user template (secrets use ensureInfraSecrets)
|
|
105
251
|
* @returns {Promise<string>} Path to admin secrets file
|
|
106
252
|
*/
|
|
107
253
|
async function ensureAdminSecrets(options = {}) {
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
254
|
+
const mergedDefaults = loadAdminMergedDefaultsForInfra(options);
|
|
255
|
+
const { adminPwdOverride, passwordToUse, emailOverride, emailToUse } = resolveAdminPasswordAndEmailCli(
|
|
256
|
+
options,
|
|
257
|
+
mergedDefaults
|
|
258
|
+
);
|
|
259
|
+
const adminSecretsPath = path.join(paths.getAifabrixSystemDir(), 'admin-secrets.env');
|
|
112
260
|
|
|
113
|
-
|
|
114
|
-
if (!fs.existsSync(adminSecretsPath)) {
|
|
261
|
+
if (!fsRealSync.existsSync(adminSecretsPath)) {
|
|
115
262
|
logger.log('Generating admin-secrets.env...');
|
|
116
|
-
await
|
|
263
|
+
await getCoreSecrets().generateAdminSecretsEnv(undefined);
|
|
264
|
+
return adminSecretsPath;
|
|
117
265
|
}
|
|
118
|
-
|
|
119
|
-
const
|
|
120
|
-
|
|
121
|
-
/^REDIS_COMMANDER_PASSWORD=\s*$/m.test(content);
|
|
266
|
+
|
|
267
|
+
const adminObj = await adminSecrets.readAndDecryptAdminSecrets(adminSecretsPath);
|
|
268
|
+
const { needsPasswordBackfill, needsEmailBackfill } = computeAdminSecretsBackfillFlags(adminObj);
|
|
122
269
|
const shouldOverwriteWithAdminPwd = adminPwdOverride !== null;
|
|
270
|
+
const shouldOverwriteEmail = emailOverride !== null;
|
|
271
|
+
const updateEmail = shouldOverwriteEmail || needsEmailBackfill;
|
|
123
272
|
|
|
124
|
-
if (shouldOverwriteWithAdminPwd) {
|
|
125
|
-
|
|
126
|
-
fs.writeFileSync(adminSecretsPath, content, { mode: 0o600 });
|
|
127
|
-
logger.log('Updated admin password in admin-secrets.env.');
|
|
128
|
-
await syncPostgresPasswordToStore(passwordToUse);
|
|
129
|
-
logVolumeResetHint(path.join(paths.getAifabrixHome(), getInfraDirName(0)));
|
|
130
|
-
} else if (needsBackfill) {
|
|
131
|
-
content = applyPasswordToAdminSecretsContent(content, passwordToUse);
|
|
132
|
-
fs.writeFileSync(adminSecretsPath, content, { mode: 0o600 });
|
|
133
|
-
logger.log('Set default admin password in admin-secrets.env for local use.');
|
|
273
|
+
if (!shouldOverwriteWithAdminPwd && !needsPasswordBackfill && !updateEmail) {
|
|
274
|
+
return adminSecretsPath;
|
|
134
275
|
}
|
|
276
|
+
|
|
277
|
+
const passwordForFile = resolvePasswordForAdminFile(
|
|
278
|
+
shouldOverwriteWithAdminPwd,
|
|
279
|
+
needsPasswordBackfill,
|
|
280
|
+
passwordToUse,
|
|
281
|
+
adminObj,
|
|
282
|
+
mergedDefaults
|
|
283
|
+
);
|
|
284
|
+
|
|
285
|
+
await applyAdminSecretsUpdate(adminSecretsPath, adminObj, passwordForFile, shouldOverwriteWithAdminPwd, {
|
|
286
|
+
updateEmail,
|
|
287
|
+
emailToUse
|
|
288
|
+
});
|
|
135
289
|
return adminSecretsPath;
|
|
136
290
|
}
|
|
137
291
|
|
|
@@ -199,7 +353,7 @@ async function ensureMisoInitScript(infraDir) {
|
|
|
199
353
|
const secretKey = 'databases-miso-controller-0-passwordKeyVault';
|
|
200
354
|
let password;
|
|
201
355
|
try {
|
|
202
|
-
const loaded = await
|
|
356
|
+
const loaded = await getCoreSecrets().loadSecrets(undefined);
|
|
203
357
|
const urlOrPassword = loaded[secretKey] || loaded['databases-miso-controller-0-urlKeyVault'];
|
|
204
358
|
const extracted = extractPasswordFromUrlOrValue(urlOrPassword);
|
|
205
359
|
if (extracted !== null && extracted.trim() !== '') {
|
|
@@ -243,13 +397,14 @@ psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "miso" -c "GRANT AL
|
|
|
243
397
|
}
|
|
244
398
|
|
|
245
399
|
/**
|
|
246
|
-
* Prepare infrastructure directory and extract postgres password
|
|
400
|
+
* Prepare infrastructure directory and extract postgres password from decrypted admin secrets.
|
|
401
|
+
* @async
|
|
247
402
|
* @param {string} devId - Developer ID
|
|
248
403
|
* @param {string} adminSecretsPath - Path to admin secrets file
|
|
249
|
-
* @returns {Object} Object with infraDir and postgresPassword
|
|
404
|
+
* @returns {Promise<Object>} Object with infraDir and postgresPassword
|
|
250
405
|
*/
|
|
251
|
-
function prepareInfraDirectory(devId, adminSecretsPath) {
|
|
252
|
-
const aifabrixDir = paths.
|
|
406
|
+
async function prepareInfraDirectory(devId, adminSecretsPath) {
|
|
407
|
+
const aifabrixDir = paths.getAifabrixSystemDir();
|
|
253
408
|
const infraDirName = getInfraDirName(devId);
|
|
254
409
|
const infraDir = path.join(aifabrixDir, infraDirName);
|
|
255
410
|
if (!fs.existsSync(infraDir)) {
|
|
@@ -265,15 +420,46 @@ function prepareInfraDirectory(devId, adminSecretsPath) {
|
|
|
265
420
|
}
|
|
266
421
|
}
|
|
267
422
|
|
|
268
|
-
const
|
|
269
|
-
const
|
|
270
|
-
|
|
271
|
-
|
|
423
|
+
const adminObj = await adminSecrets.readAndDecryptAdminSecrets(adminSecretsPath);
|
|
424
|
+
const postgresPassword =
|
|
425
|
+
(adminObj.POSTGRES_PASSWORD && adminObj.POSTGRES_PASSWORD.trim()) ||
|
|
426
|
+
readInfraDefaultScalars().adminPassword ||
|
|
427
|
+
'';
|
|
272
428
|
generatePgAdminConfig(infraDir, postgresPassword);
|
|
273
429
|
|
|
274
430
|
return { infraDir, postgresPassword };
|
|
275
431
|
}
|
|
276
432
|
|
|
433
|
+
/**
|
|
434
|
+
* Resolve infra working directory and admin-secrets path for stop/restart.
|
|
435
|
+
* Infra dir: prefer system dir compose; if missing, use legacy home when compose exists there.
|
|
436
|
+
* Admin secrets: prefer `admin-secrets.env` under system dir; if missing, use legacy home (covers mixed layouts).
|
|
437
|
+
*
|
|
438
|
+
* @param {string|number} devId - Developer ID
|
|
439
|
+
* @returns {{ infraDir: string, adminSecretsPath: string }}
|
|
440
|
+
*/
|
|
441
|
+
function resolveInfraStatePaths(devId) {
|
|
442
|
+
const syncFs = nodeFs();
|
|
443
|
+
const name = getInfraDirName(devId);
|
|
444
|
+
const systemBase = paths.getAifabrixSystemDir();
|
|
445
|
+
const legacyBase = paths.getAifabrixHome();
|
|
446
|
+
const sysInfra = path.join(systemBase, name);
|
|
447
|
+
const legInfra = path.join(legacyBase, name);
|
|
448
|
+
const sysCompose = path.join(sysInfra, 'compose.yaml');
|
|
449
|
+
const legCompose = path.join(legInfra, 'compose.yaml');
|
|
450
|
+
let infraDir = sysInfra;
|
|
451
|
+
if (!syncFs.existsSync(sysCompose) && syncFs.existsSync(legCompose) && legacyBase !== systemBase) {
|
|
452
|
+
infraDir = legInfra;
|
|
453
|
+
}
|
|
454
|
+
const sysAdmin = path.join(systemBase, 'admin-secrets.env');
|
|
455
|
+
const legAdmin = path.join(legacyBase, 'admin-secrets.env');
|
|
456
|
+
let adminSecretsPath = sysAdmin;
|
|
457
|
+
if (!syncFs.existsSync(sysAdmin) && syncFs.existsSync(legAdmin) && legacyBase !== systemBase) {
|
|
458
|
+
adminSecretsPath = legAdmin;
|
|
459
|
+
}
|
|
460
|
+
return { infraDir, adminSecretsPath };
|
|
461
|
+
}
|
|
462
|
+
|
|
277
463
|
/**
|
|
278
464
|
* Register Handlebars helper for equality comparison
|
|
279
465
|
*/
|
|
@@ -298,6 +484,7 @@ module.exports = {
|
|
|
298
484
|
ensureAdminSecrets,
|
|
299
485
|
generatePgAdminConfig,
|
|
300
486
|
prepareInfraDirectory,
|
|
487
|
+
resolveInfraStatePaths,
|
|
301
488
|
ensureMisoInitScript,
|
|
302
489
|
registerHandlebarsHelper
|
|
303
490
|
};
|
|
@@ -15,14 +15,13 @@ const config = require('../core/config');
|
|
|
15
15
|
const devConfig = require('../utils/dev-config');
|
|
16
16
|
const logger = require('../utils/logger');
|
|
17
17
|
const dockerUtils = require('../utils/docker');
|
|
18
|
-
const paths = require('../utils/paths');
|
|
19
18
|
const statusHelpers = require('../utils/infra-status');
|
|
20
19
|
const {
|
|
21
|
-
getInfraDirName,
|
|
22
20
|
getInfraProjectName,
|
|
23
21
|
checkDockerAvailability,
|
|
24
22
|
ensureAdminSecrets,
|
|
25
23
|
prepareInfraDirectory,
|
|
24
|
+
resolveInfraStatePaths,
|
|
26
25
|
ensureMisoInitScript,
|
|
27
26
|
registerHandlebarsHelper
|
|
28
27
|
} = require('./helpers');
|
|
@@ -37,8 +36,34 @@ const {
|
|
|
37
36
|
startDockerServicesAndConfigure,
|
|
38
37
|
checkInfraHealth
|
|
39
38
|
} = require('./services');
|
|
39
|
+
const adminSecrets = require('../core/admin-secrets');
|
|
40
40
|
// Lazy require to avoid circular dependency: infra -> app/down -> run-helpers -> infra
|
|
41
41
|
|
|
42
|
+
/**
|
|
43
|
+
* Runs a callback with a temporary .env.run file in infraDir (created from admin-secrets).
|
|
44
|
+
* Removes the file in a finally block.
|
|
45
|
+
* @async
|
|
46
|
+
* @param {string} infraDir - Infrastructure directory path
|
|
47
|
+
* @param {string} adminSecretsPath - Path to admin-secrets.env
|
|
48
|
+
* @param {function(string): Promise<void>} fn - Callback receiving runEnvPath
|
|
49
|
+
* @returns {Promise<void>}
|
|
50
|
+
*/
|
|
51
|
+
async function withRunEnv(infraDir, adminSecretsPath, fn) {
|
|
52
|
+
const runEnvPath = path.join(infraDir, '.env.run');
|
|
53
|
+
try {
|
|
54
|
+
const adminObj = await adminSecrets.readAndDecryptAdminSecrets(adminSecretsPath);
|
|
55
|
+
const content = adminSecrets.envObjectToContent(adminObj);
|
|
56
|
+
fs.writeFileSync(runEnvPath, content, { mode: 0o600 });
|
|
57
|
+
await fn(runEnvPath);
|
|
58
|
+
} finally {
|
|
59
|
+
try {
|
|
60
|
+
if (fs.existsSync(runEnvPath)) fs.unlinkSync(runEnvPath);
|
|
61
|
+
} catch {
|
|
62
|
+
// Ignore unlink errors
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
42
67
|
/**
|
|
43
68
|
* Prepares infrastructure environment
|
|
44
69
|
* Ensures infra secrets exist, then admin-secrets.env, then miso init script.
|
|
@@ -46,18 +71,35 @@ const {
|
|
|
46
71
|
* @async
|
|
47
72
|
* @function prepareInfrastructureEnvironment
|
|
48
73
|
* @param {string|number|null} developerId - Developer ID
|
|
49
|
-
* @param {Object} [options] - Options (traefik, adminPwd)
|
|
74
|
+
* @param {Object} [options] - Options (traefik, adminPwd, tlsEnabled)
|
|
50
75
|
* @returns {Promise<Object>} Prepared environment configuration
|
|
51
76
|
*/
|
|
52
77
|
async function prepareInfrastructureEnvironment(developerId, options = {}) {
|
|
53
78
|
await checkDockerAvailability();
|
|
54
|
-
|
|
55
|
-
const
|
|
79
|
+
const adminPass = options.adminPassword || options.adminPwd;
|
|
80
|
+
const tlsEnabled = options.tlsEnabled === true;
|
|
81
|
+
const infraOpts = {
|
|
82
|
+
adminPassword: adminPass,
|
|
83
|
+
adminPwd: adminPass,
|
|
84
|
+
adminEmail: options.adminEmail,
|
|
85
|
+
userPassword: options.userPassword,
|
|
86
|
+
tlsEnabled
|
|
87
|
+
};
|
|
88
|
+
await secretsEnsure.ensureInfraSecrets(infraOpts);
|
|
89
|
+
const adminSecretsPath = await ensureAdminSecrets(infraOpts);
|
|
56
90
|
|
|
57
91
|
const devId = developerId || await config.getDeveloperId();
|
|
92
|
+
const remoteServer = await config.getRemoteServer();
|
|
93
|
+
const {
|
|
94
|
+
assertRemoteBuilderDeveloperId,
|
|
95
|
+
remoteServerHostIsNonLocalhost
|
|
96
|
+
} = require('../utils/remote-builder-validation');
|
|
97
|
+
assertRemoteBuilderDeveloperId(remoteServer, devId);
|
|
98
|
+
|
|
58
99
|
const devIdNum = typeof devId === 'string' ? parseInt(devId, 10) : devId;
|
|
59
100
|
const ports = devConfig.getDevPorts(devIdNum);
|
|
60
101
|
const idNum = devIdNum;
|
|
102
|
+
const trustForwardedHeaders = remoteServerHostIsNonLocalhost(remoteServer);
|
|
61
103
|
|
|
62
104
|
const templatePath = path.join(__dirname, '..', '..', 'templates', 'infra', 'compose.yaml.hbs');
|
|
63
105
|
if (!fs.existsSync(templatePath)) {
|
|
@@ -65,10 +107,10 @@ async function prepareInfrastructureEnvironment(developerId, options = {}) {
|
|
|
65
107
|
}
|
|
66
108
|
|
|
67
109
|
// Prepare infrastructure directory
|
|
68
|
-
const { infraDir } = prepareInfraDirectory(devId, adminSecretsPath);
|
|
110
|
+
const { infraDir } = await prepareInfraDirectory(devId, adminSecretsPath);
|
|
69
111
|
await ensureMisoInitScript(infraDir);
|
|
70
112
|
|
|
71
|
-
return { devId, idNum, ports, templatePath, infraDir, adminSecretsPath };
|
|
113
|
+
return { devId, idNum, ports, templatePath, infraDir, adminSecretsPath, trustForwardedHeaders };
|
|
72
114
|
}
|
|
73
115
|
|
|
74
116
|
/**
|
|
@@ -88,9 +130,10 @@ async function prepareInfrastructureEnvironment(developerId, options = {}) {
|
|
|
88
130
|
* // Infrastructure services are now running
|
|
89
131
|
*/
|
|
90
132
|
async function startInfra(developerId = null, options = {}) {
|
|
91
|
-
const { devId, idNum, ports, templatePath, infraDir } =
|
|
133
|
+
const { devId, idNum, ports, templatePath, infraDir, trustForwardedHeaders } =
|
|
134
|
+
await prepareInfrastructureEnvironment(developerId, options);
|
|
92
135
|
const { traefik = false, pgadmin = true, redisCommander = true } = options;
|
|
93
|
-
const traefikConfig = buildTraefikConfig(traefik);
|
|
136
|
+
const traefikConfig = { ...buildTraefikConfig(traefik), trustForwardedHeaders };
|
|
94
137
|
const validation = validateTraefikConfig(traefikConfig);
|
|
95
138
|
if (!validation.valid) {
|
|
96
139
|
throw new Error(validation.errors.join('\n'));
|
|
@@ -173,28 +216,23 @@ async function removeAppVolumes(appNames, devId) {
|
|
|
173
216
|
*/
|
|
174
217
|
async function stopInfra() {
|
|
175
218
|
const devId = await config.getDeveloperId();
|
|
176
|
-
const
|
|
177
|
-
const infraDirName = getInfraDirName(devId);
|
|
178
|
-
const infraDir = path.join(aifabrixDir, infraDirName);
|
|
219
|
+
const { infraDir, adminSecretsPath } = resolveInfraStatePaths(devId);
|
|
179
220
|
const composePath = path.join(infraDir, 'compose.yaml');
|
|
180
|
-
const adminSecretsPath = path.join(aifabrixDir, 'admin-secrets.env');
|
|
181
221
|
|
|
182
222
|
if (!fs.existsSync(composePath) || !fs.existsSync(adminSecretsPath)) {
|
|
183
223
|
logger.log('Infrastructure not running or not properly configured');
|
|
184
224
|
return;
|
|
185
225
|
}
|
|
186
226
|
|
|
187
|
-
|
|
227
|
+
await withRunEnv(infraDir, adminSecretsPath, async(runEnvPath) => {
|
|
188
228
|
logger.log('Stopping application containers on the same network...');
|
|
189
229
|
await stopAllAppContainers(devId);
|
|
190
230
|
logger.log('Stopping infrastructure services...');
|
|
191
231
|
const projectName = getInfraProjectName(devId);
|
|
192
232
|
const composeCmd = await dockerUtils.getComposeCommand();
|
|
193
|
-
await execAsyncWithCwd(`${composeCmd} -f "${composePath}" -p ${projectName} --env-file "${
|
|
233
|
+
await execAsyncWithCwd(`${composeCmd} -f "${composePath}" -p ${projectName} --env-file "${runEnvPath}" down`, { cwd: infraDir });
|
|
194
234
|
logger.log('Infrastructure services stopped');
|
|
195
|
-
}
|
|
196
|
-
// Keep the compose file for future use
|
|
197
|
-
}
|
|
235
|
+
});
|
|
198
236
|
}
|
|
199
237
|
|
|
200
238
|
/**
|
|
@@ -239,28 +277,23 @@ async function stopAllAppContainersAndVolumes(devId) {
|
|
|
239
277
|
*/
|
|
240
278
|
async function stopInfraWithVolumes() {
|
|
241
279
|
const devId = await config.getDeveloperId();
|
|
242
|
-
const
|
|
243
|
-
const infraDirName = getInfraDirName(devId);
|
|
244
|
-
const infraDir = path.join(aifabrixDir, infraDirName);
|
|
280
|
+
const { infraDir, adminSecretsPath } = resolveInfraStatePaths(devId);
|
|
245
281
|
const composePath = path.join(infraDir, 'compose.yaml');
|
|
246
|
-
const adminSecretsPath = path.join(aifabrixDir, 'admin-secrets.env');
|
|
247
282
|
|
|
248
283
|
if (!fs.existsSync(composePath) || !fs.existsSync(adminSecretsPath)) {
|
|
249
284
|
logger.log('Infrastructure not running or not properly configured');
|
|
250
285
|
return;
|
|
251
286
|
}
|
|
252
287
|
|
|
253
|
-
|
|
288
|
+
await withRunEnv(infraDir, adminSecretsPath, async(runEnvPath) => {
|
|
254
289
|
logger.log('Stopping application containers on the same network...');
|
|
255
290
|
await stopAllAppContainersAndVolumes(devId);
|
|
256
291
|
logger.log('Stopping infrastructure services and removing all data...');
|
|
257
292
|
const projectName = getInfraProjectName(devId);
|
|
258
293
|
const composeCmd = await dockerUtils.getComposeCommand();
|
|
259
|
-
await execAsyncWithCwd(`${composeCmd} -f "${composePath}" -p ${projectName} --env-file "${
|
|
294
|
+
await execAsyncWithCwd(`${composeCmd} -f "${composePath}" -p ${projectName} --env-file "${runEnvPath}" down -v`, { cwd: infraDir });
|
|
260
295
|
logger.log('Infrastructure services stopped and all data removed');
|
|
261
|
-
}
|
|
262
|
-
// Keep the compose file for future use
|
|
263
|
-
}
|
|
296
|
+
});
|
|
264
297
|
}
|
|
265
298
|
|
|
266
299
|
/**
|
|
@@ -281,32 +314,26 @@ async function restartService(serviceName) {
|
|
|
281
314
|
if (!serviceName || typeof serviceName !== 'string') {
|
|
282
315
|
throw new Error('Service name is required and must be a string');
|
|
283
316
|
}
|
|
284
|
-
|
|
285
317
|
const validServices = ['postgres', 'redis', 'pgadmin', 'redis-commander', 'traefik'];
|
|
286
318
|
if (!validServices.includes(serviceName)) {
|
|
287
319
|
throw new Error(`Invalid service name. Must be one of: ${validServices.join(', ')}`);
|
|
288
320
|
}
|
|
289
321
|
|
|
290
322
|
const devId = await config.getDeveloperId();
|
|
291
|
-
const
|
|
292
|
-
const infraDirName = getInfraDirName(devId);
|
|
293
|
-
const infraDir = path.join(aifabrixDir, infraDirName);
|
|
323
|
+
const { infraDir, adminSecretsPath } = resolveInfraStatePaths(devId);
|
|
294
324
|
const composePath = path.join(infraDir, 'compose.yaml');
|
|
295
|
-
const adminSecretsPath = path.join(aifabrixDir, 'admin-secrets.env');
|
|
296
325
|
|
|
297
326
|
if (!fs.existsSync(composePath) || !fs.existsSync(adminSecretsPath)) {
|
|
298
327
|
throw new Error('Infrastructure not properly configured');
|
|
299
328
|
}
|
|
300
329
|
|
|
301
|
-
|
|
330
|
+
await withRunEnv(infraDir, adminSecretsPath, async(runEnvPath) => {
|
|
302
331
|
logger.log(`Restarting ${serviceName} service...`);
|
|
303
332
|
const projectName = getInfraProjectName(devId);
|
|
304
333
|
const composeCmd = await dockerUtils.getComposeCommand();
|
|
305
|
-
await execAsyncWithCwd(`${composeCmd} -f "${composePath}" -p ${projectName} --env-file "${
|
|
334
|
+
await execAsyncWithCwd(`${composeCmd} -f "${composePath}" -p ${projectName} --env-file "${runEnvPath}" restart ${serviceName}`, { cwd: infraDir });
|
|
306
335
|
logger.log(`${serviceName} service restarted successfully`);
|
|
307
|
-
}
|
|
308
|
-
// Keep the compose file for future use
|
|
309
|
-
}
|
|
336
|
+
});
|
|
310
337
|
}
|
|
311
338
|
|
|
312
339
|
// Re-export status helper functions
|