@aifabrix/builder 2.43.0 → 2.44.1
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/.cursor/rules/cli-layout.mdc +75 -0
- package/.cursor/rules/project-rules.mdc +8 -0
- package/.npmrc.token +1 -0
- package/.nyc_output/55e9d034-ddab-4579-a706-e02a91d75c91.json +1 -0
- package/.nyc_output/processinfo/55e9d034-ddab-4579-a706-e02a91d75c91.json +1 -0
- package/.nyc_output/processinfo/index.json +1 -0
- package/README.md +1 -1
- 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 +31 -0
- package/integration/hubspot-test/create-hubspot.js +5 -5
- package/integration/hubspot-test/hubspot-test-datasource-company.json +58 -462
- package/integration/hubspot-test/hubspot-test-datasource-contact.json +61 -555
- package/integration/hubspot-test/hubspot-test-datasource-deal.json +63 -506
- package/integration/hubspot-test/hubspot-test-datasource-users.json +42 -83
- package/integration/hubspot-test/hubspot-test-deploy.json +3 -3
- package/integration/hubspot-test/test-dataplane-down-tests.js +1 -7
- package/integration/hubspot-test/test-dataplane-down.js +3 -3
- package/integration/hubspot-test/test.js +35 -43
- 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 +301 -0
- package/lib/api/certificates.api.js +62 -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 +11 -3
- package/lib/api/pipeline.api.js +67 -20
- package/lib/api/types/certificates.types.js +48 -0
- package/lib/api/types/dev.types.js +4 -3
- package/lib/api/types/pipeline.types.js +8 -5
- package/lib/api/types/validation-run.types.js +56 -0
- package/lib/api/validation-run.api.js +111 -0
- package/lib/api/validation-runner.js +109 -0
- package/lib/app/certification-show-enrich.js +129 -0
- package/lib/app/certification-verify-rows.js +60 -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 +16 -7
- package/lib/app/rotate-secret.js +14 -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 +44 -1
- package/lib/app/show.js +93 -9
- package/lib/build/index.js +13 -10
- package/lib/certification/cli-cert-sync-skip.js +21 -0
- package/lib/certification/merge-certification-from-artifact.js +185 -0
- package/lib/certification/post-unified-cert-sync.js +33 -0
- package/lib/certification/sync-after-external-command.js +52 -0
- package/lib/certification/sync-system-certification.js +197 -0
- package/lib/cli/index.js +2 -0
- package/lib/cli/setup-app.help.js +67 -0
- package/lib/cli/setup-app.js +61 -121
- package/lib/cli/setup-app.test-commands.js +195 -0
- package/lib/cli/setup-auth.js +19 -5
- 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 +170 -113
- package/lib/cli/setup-environment.js +7 -1
- package/lib/cli/setup-external-system.js +84 -23
- package/lib/cli/setup-infra.js +126 -47
- package/lib/cli/setup-parameters.js +32 -0
- package/lib/cli/setup-secrets.js +137 -18
- package/lib/cli/setup-service-user.js +1 -1
- package/lib/cli/setup-utility.js +54 -22
- 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 +32 -11
- package/lib/commands/auth-config.js +6 -6
- 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 +428 -0
- package/lib/commands/datasource-unified-test-cli.options.js +191 -0
- package/lib/commands/datasource-unified-test-e2e-cli-helpers.js +106 -0
- package/lib/commands/datasource-validation-cli.js +143 -0
- package/lib/commands/datasource.js +125 -95
- 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 +2 -2
- package/lib/commands/repair.js +21 -3
- package/lib/commands/secrets-list.js +23 -12
- package/lib/commands/secrets-remove-all.js +220 -0
- package/lib/commands/secrets-remove.js +21 -12
- package/lib/commands/secrets-set.js +21 -12
- package/lib/commands/secrets-validate.js +4 -4
- package/lib/commands/secure.js +10 -9
- package/lib/commands/service-user.js +26 -25
- package/lib/commands/test-e2e-external.js +27 -1
- package/lib/commands/up-common.js +3 -2
- package/lib/commands/up-dataplane.js +29 -16
- package/lib/commands/up-miso.js +19 -29
- package/lib/commands/upload.js +149 -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 +14 -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 +55 -56
- package/lib/core/diff.js +3 -2
- package/lib/core/ensure-encryption-key.js +1 -1
- 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 +200 -37
- package/lib/core/templates-env.js +4 -3
- package/lib/datasource/abac-validator.js +1 -10
- package/lib/datasource/deploy.js +75 -53
- package/lib/datasource/field-reference-validator.js +9 -6
- package/lib/datasource/integration-context.js +63 -0
- package/lib/datasource/list.js +8 -7
- package/lib/datasource/log-viewer.js +189 -67
- package/lib/datasource/resolve-app.js +4 -4
- package/lib/datasource/test-e2e.js +113 -146
- package/lib/datasource/test-integration.js +114 -122
- package/lib/datasource/unified-validation-run-body.js +68 -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 +93 -0
- package/lib/datasource/validate.js +157 -13
- 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 +166 -53
- package/lib/external-system/download-helpers.js +1 -1
- package/lib/external-system/download.js +7 -6
- package/lib/external-system/generator.js +92 -6
- 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.js +16 -4
- package/lib/generator/helpers.js +58 -3
- package/lib/generator/index.js +4 -0
- package/lib/generator/split-readme.js +12 -7
- package/lib/generator/split-variables.js +2 -1
- package/lib/generator/split.js +1 -1
- package/lib/generator/wizard-readme.js +3 -3
- package/lib/generator/wizard.js +8 -8
- package/lib/infrastructure/compose.js +70 -7
- package/lib/infrastructure/helpers-docker-check.js +67 -0
- package/lib/infrastructure/helpers.js +203 -42
- package/lib/infrastructure/index.js +31 -18
- package/lib/infrastructure/services.js +21 -67
- 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 +1200 -442
- package/lib/schema/external-system.schema.json +203 -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 +226 -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 +77 -17
- 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 +166 -7
- package/lib/utils/config-scoped-resources-preference.js +41 -0
- package/lib/utils/configuration-env-resolver.js +11 -8
- package/lib/utils/controller-deployment-outcome.js +68 -0
- package/lib/utils/credential-display.js +2 -2
- package/lib/utils/credential-secrets-env.js +5 -5
- 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-certificate-tty.js +82 -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 +459 -0
- package/lib/utils/datasource-test-run-exit.js +83 -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 +35 -8
- package/lib/utils/env-template.js +2 -2
- package/lib/utils/environment-scoped-resources.js +144 -0
- package/lib/utils/error-formatter.js +92 -13
- 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-readme.js +8 -1
- package/lib/utils/external-system-display.js +242 -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-system-test-tty-overview.js +120 -0
- package/lib/utils/external-system-system-test-tty.js +417 -0
- package/lib/utils/external-system-test-helpers.js +24 -6
- package/lib/utils/external-system-validators.js +30 -12
- package/lib/utils/health-check-url.js +119 -0
- package/lib/utils/health-check.js +59 -25
- package/lib/utils/help-builder.js +11 -8
- 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 +3 -4
- package/lib/utils/paths.js +148 -47
- 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 +169 -49
- package/lib/utils/secrets-helpers.js +70 -59
- package/lib/utils/secrets-kv-scope.js +60 -0
- package/lib/utils/secrets-utils.js +32 -38
- package/lib/utils/secrets-validation.js +3 -1
- package/lib/utils/secrets-yaml-preserve.js +109 -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 +1 -2
- 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 +112 -0
- package/lib/utils/validation-run-post-retry.js +85 -0
- package/lib/utils/validation-run-request.js +116 -0
- package/lib/utils/variable-transformer.js +21 -4
- package/lib/utils/yaml-preserve.js +33 -14
- package/lib/validation/datasource-warnings.js +56 -0
- package/lib/validation/env-template-auth.js +1 -1
- package/lib/validation/external-manifest-validator.js +27 -7
- package/lib/validation/validate-display.js +37 -31
- package/lib/validation/validate-external-cert-sync.js +23 -0
- package/lib/validation/validate.js +8 -14
- package/lib/validation/validator-unresolved-placeholders.js +98 -0
- package/lib/validation/validator.js +22 -65
- package/lib/validation/wizard-config-validator.js +2 -1
- package/package.json +9 -4
- package/scripts/check-datasource-test-run-schema-sync.js +34 -0
- package/scripts/diagnose-cli.js +150 -0
- package/scripts/install-local.js +307 -55
- package/scripts/pnpm-global-remove.js +48 -0
- package/templates/README.md +15 -2
- package/templates/applications/dataplane/application.yaml +52 -2
- package/templates/applications/dataplane/env.template +79 -17
- 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 +42 -12
- 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/external-datasource.yaml.hbs +197 -118
- package/templates/infra/compose.yaml.hbs +33 -16
- package/templates/infra/servers.json.hbs +3 -1
- package/templates/python/docker-compose.hbs +16 -0
- package/templates/typescript/docker-compose.hbs +16 -0
- package/lib/api/external-test.api.js +0 -111
- package/lib/schema/env-config.yaml +0 -60
|
@@ -11,14 +11,30 @@
|
|
|
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 secrets = require('../core/secrets');
|
|
17
18
|
const adminSecrets = require('../core/admin-secrets');
|
|
18
19
|
const logger = require('../utils/logger');
|
|
19
|
-
const dockerUtils = require('../utils/docker');
|
|
20
20
|
const paths = require('../utils/paths');
|
|
21
21
|
const secretsEnsure = require('../core/secrets-ensure');
|
|
22
|
+
const {
|
|
23
|
+
mergeInfraParameterDefaultsForCli,
|
|
24
|
+
getInfraParameterCatalog,
|
|
25
|
+
readRelaxedCatalogDefaults
|
|
26
|
+
} = require('../parameters/infra-parameter-catalog');
|
|
27
|
+
const { checkDockerAvailability } = require('./helpers-docker-check');
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Lazy-load core/secrets at call time. A top-level require creates a circular dependency:
|
|
31
|
+
* secrets → url-declarative-resolve → compose-generator → compose-generate-docker-compose → this module,
|
|
32
|
+
* which left `generateAdminSecretsEnv` / `formatAdminSecretsContent` undefined on the captured export.
|
|
33
|
+
* @returns {Object} core/secrets module exports (loadSecrets, generateAdminSecretsEnv, …)
|
|
34
|
+
*/
|
|
35
|
+
function getCoreSecrets() {
|
|
36
|
+
return require('../core/secrets');
|
|
37
|
+
}
|
|
22
38
|
|
|
23
39
|
/**
|
|
24
40
|
* Gets infrastructure directory name based on developer ID
|
|
@@ -43,22 +59,13 @@ function getInfraProjectName(devId) {
|
|
|
43
59
|
}
|
|
44
60
|
|
|
45
61
|
/**
|
|
46
|
-
*
|
|
47
|
-
* @
|
|
48
|
-
* @returns {Promise<void>}
|
|
49
|
-
* @throws {Error} If Docker is not available
|
|
62
|
+
* Fallback for admin password/email when validated catalog load failed but YAML is still readable.
|
|
63
|
+
* @returns {Record<string, string>}
|
|
50
64
|
*/
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
await dockerUtils.ensureDockerAndCompose();
|
|
54
|
-
} catch (error) {
|
|
55
|
-
throw new Error('Docker or Docker Compose is not available. Please install and start Docker.');
|
|
56
|
-
}
|
|
65
|
+
function readInfraDefaultScalars() {
|
|
66
|
+
return readRelaxedCatalogDefaults();
|
|
57
67
|
}
|
|
58
68
|
|
|
59
|
-
/** Default admin password for new local installations when admin-secrets.env is empty */
|
|
60
|
-
const DEFAULT_ADMIN_PASSWORD = 'admin123';
|
|
61
|
-
|
|
62
69
|
/**
|
|
63
70
|
* Log hint to reset Postgres volume when admin password was changed after first init.
|
|
64
71
|
* @param {string} infraDir - Path to infra directory
|
|
@@ -66,7 +73,7 @@ const DEFAULT_ADMIN_PASSWORD = 'admin123';
|
|
|
66
73
|
function logVolumeResetHint(infraDir) {
|
|
67
74
|
logger.log(chalk.yellow(
|
|
68
75
|
'If Postgres was already started with a different password, login will fail until you reset the volume. ' +
|
|
69
|
-
`Run: cd ${infraDir} && docker compose -f compose.yaml -p aifabrix down -v , then run 'aifabrix up-infra --
|
|
76
|
+
`Run: cd ${infraDir} && docker compose -f compose.yaml -p aifabrix down -v , then run 'aifabrix up-infra --adminPassword <password>' again.`
|
|
70
77
|
));
|
|
71
78
|
}
|
|
72
79
|
|
|
@@ -82,9 +89,8 @@ async function syncPostgresPasswordToStore(password) {
|
|
|
82
89
|
}
|
|
83
90
|
}
|
|
84
91
|
|
|
85
|
-
/**
|
|
92
|
+
/** Non-email defaults for admin-secrets.env merge (email default comes from infra.parameter.yaml `defaults`). */
|
|
86
93
|
const DEFAULT_ADMIN_OBJ = {
|
|
87
|
-
PGADMIN_DEFAULT_EMAIL: 'admin@aifabrix.dev',
|
|
88
94
|
REDIS_HOST: 'local:redis:6379:0:',
|
|
89
95
|
REDIS_COMMANDER_USER: 'admin'
|
|
90
96
|
};
|
|
@@ -96,23 +102,87 @@ const DEFAULT_ADMIN_OBJ = {
|
|
|
96
102
|
* @param {Object} adminObj - Decrypted admin secrets object
|
|
97
103
|
* @param {string} passwordToUse - Password to set for Postgres, pgAdmin, Redis Commander
|
|
98
104
|
* @param {boolean} shouldOverwriteWithAdminPwd - Whether this was an explicit admin password update
|
|
105
|
+
* @param {{ updateEmail?: boolean, emailToUse?: string }} [emailOpts]
|
|
99
106
|
*/
|
|
100
|
-
async function applyAdminSecretsUpdate(
|
|
107
|
+
async function applyAdminSecretsUpdate(
|
|
108
|
+
adminSecretsPath,
|
|
109
|
+
adminObj,
|
|
110
|
+
passwordToUse,
|
|
111
|
+
shouldOverwriteWithAdminPwd,
|
|
112
|
+
emailOpts
|
|
113
|
+
) {
|
|
101
114
|
const merged = { ...DEFAULT_ADMIN_OBJ, ...adminObj };
|
|
102
115
|
merged.POSTGRES_PASSWORD = passwordToUse;
|
|
103
116
|
merged.PGADMIN_DEFAULT_PASSWORD = passwordToUse;
|
|
104
117
|
merged.REDIS_COMMANDER_PASSWORD = passwordToUse;
|
|
105
|
-
|
|
106
|
-
|
|
118
|
+
if (emailOpts && emailOpts.updateEmail && emailOpts.emailToUse) {
|
|
119
|
+
merged.PGADMIN_DEFAULT_EMAIL = emailOpts.emailToUse;
|
|
120
|
+
}
|
|
121
|
+
const content = await getCoreSecrets().formatAdminSecretsContent(merged);
|
|
122
|
+
fsRealSync.writeFileSync(adminSecretsPath, content, { mode: 0o600 });
|
|
107
123
|
if (shouldOverwriteWithAdminPwd) {
|
|
108
124
|
logger.log('Updated admin password in admin-secrets.env.');
|
|
109
125
|
await syncPostgresPasswordToStore(passwordToUse);
|
|
110
|
-
logVolumeResetHint(path.join(paths.
|
|
126
|
+
logVolumeResetHint(path.join(paths.getAifabrixSystemDir(), getInfraDirName(0)));
|
|
127
|
+
} else if (emailOpts && emailOpts.updateEmail) {
|
|
128
|
+
logger.log('Updated admin email in admin-secrets.env.');
|
|
111
129
|
} else {
|
|
112
130
|
logger.log('Set default admin password in admin-secrets.env for local use.');
|
|
113
131
|
}
|
|
114
132
|
}
|
|
115
133
|
|
|
134
|
+
function loadAdminMergedDefaultsForInfra(options) {
|
|
135
|
+
try {
|
|
136
|
+
return mergeInfraParameterDefaultsForCli(getInfraParameterCatalog().data, options);
|
|
137
|
+
} catch {
|
|
138
|
+
return mergeInfraParameterDefaultsForCli({}, options);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function resolveAdminPasswordAndEmailCli(options, mergedDefaults) {
|
|
143
|
+
const infraDefaults = readInfraDefaultScalars();
|
|
144
|
+
const adminPwdCli = String(options.adminPassword || options.adminPwd || '').trim();
|
|
145
|
+
const adminPwdOverride = adminPwdCli !== '' ? adminPwdCli : null;
|
|
146
|
+
const passwordToUse =
|
|
147
|
+
adminPwdOverride !== null
|
|
148
|
+
? adminPwdOverride
|
|
149
|
+
: mergedDefaults.adminPassword || infraDefaults.adminPassword || '';
|
|
150
|
+
const emailCli = String(options.adminEmail || '').trim();
|
|
151
|
+
const emailOverride = emailCli !== '' ? emailCli : null;
|
|
152
|
+
const emailToUse =
|
|
153
|
+
emailOverride !== null
|
|
154
|
+
? emailOverride
|
|
155
|
+
: mergedDefaults.adminEmail || infraDefaults.adminEmail || '';
|
|
156
|
+
return { adminPwdOverride, passwordToUse, emailOverride, emailToUse };
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function computeAdminSecretsBackfillFlags(adminObj) {
|
|
160
|
+
const needsPasswordBackfill =
|
|
161
|
+
!(adminObj.POSTGRES_PASSWORD && adminObj.POSTGRES_PASSWORD.trim()) ||
|
|
162
|
+
!(adminObj.PGADMIN_DEFAULT_PASSWORD && adminObj.PGADMIN_DEFAULT_PASSWORD.trim()) ||
|
|
163
|
+
!(adminObj.REDIS_COMMANDER_PASSWORD && adminObj.REDIS_COMMANDER_PASSWORD.trim());
|
|
164
|
+
const needsEmailBackfill = !(adminObj.PGADMIN_DEFAULT_EMAIL && adminObj.PGADMIN_DEFAULT_EMAIL.trim());
|
|
165
|
+
return { needsPasswordBackfill, needsEmailBackfill };
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function resolvePasswordForAdminFile(
|
|
169
|
+
shouldOverwriteWithAdminPwd,
|
|
170
|
+
needsPasswordBackfill,
|
|
171
|
+
passwordToUse,
|
|
172
|
+
adminObj,
|
|
173
|
+
mergedDefaults
|
|
174
|
+
) {
|
|
175
|
+
if (shouldOverwriteWithAdminPwd || needsPasswordBackfill) {
|
|
176
|
+
return passwordToUse;
|
|
177
|
+
}
|
|
178
|
+
return (
|
|
179
|
+
String(adminObj.POSTGRES_PASSWORD || '').trim() ||
|
|
180
|
+
mergedDefaults.adminPassword ||
|
|
181
|
+
readInfraDefaultScalars().adminPassword ||
|
|
182
|
+
''
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
|
|
116
186
|
/**
|
|
117
187
|
* Ensure admin secrets file exists and set admin password.
|
|
118
188
|
* When adminPwd is provided, update POSTGRES_PASSWORD, PGADMIN_DEFAULT_PASSWORD, REDIS_COMMANDER_PASSWORD
|
|
@@ -121,42 +191,82 @@ async function applyAdminSecretsUpdate(adminSecretsPath, adminObj, passwordToUse
|
|
|
121
191
|
*
|
|
122
192
|
* @async
|
|
123
193
|
* @param {Object} [options] - Options
|
|
124
|
-
* @param {string} [options.
|
|
194
|
+
* @param {string} [options.adminPassword] - Override admin password (alias: adminPwd)
|
|
195
|
+
* @param {string} [options.adminPwd] - Override admin password for Postgres, pgAdmin, Redis Commander
|
|
196
|
+
* @param {string} [options.adminEmail] - Override pgAdmin default email (matches {{adminEmail}} defaults)
|
|
197
|
+
* @param {string} [options.userPassword] - Reserved for Keycloak user template (secrets use ensureInfraSecrets)
|
|
125
198
|
* @returns {Promise<string>} Path to admin secrets file
|
|
126
199
|
*/
|
|
127
200
|
async function ensureAdminSecrets(options = {}) {
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
201
|
+
const mergedDefaults = loadAdminMergedDefaultsForInfra(options);
|
|
202
|
+
const { adminPwdOverride, passwordToUse, emailOverride, emailToUse } = resolveAdminPasswordAndEmailCli(
|
|
203
|
+
options,
|
|
204
|
+
mergedDefaults
|
|
205
|
+
);
|
|
206
|
+
const adminSecretsPath = path.join(paths.getAifabrixSystemDir(), 'admin-secrets.env');
|
|
133
207
|
|
|
134
|
-
if (!
|
|
208
|
+
if (!fsRealSync.existsSync(adminSecretsPath)) {
|
|
135
209
|
logger.log('Generating admin-secrets.env...');
|
|
136
|
-
await
|
|
210
|
+
await getCoreSecrets().generateAdminSecretsEnv(undefined);
|
|
137
211
|
return adminSecretsPath;
|
|
138
212
|
}
|
|
139
213
|
|
|
140
214
|
const adminObj = await adminSecrets.readAndDecryptAdminSecrets(adminSecretsPath);
|
|
141
|
-
const
|
|
142
|
-
!(adminObj.PGADMIN_DEFAULT_PASSWORD && adminObj.PGADMIN_DEFAULT_PASSWORD.trim()) ||
|
|
143
|
-
!(adminObj.REDIS_COMMANDER_PASSWORD && adminObj.REDIS_COMMANDER_PASSWORD.trim());
|
|
215
|
+
const { needsPasswordBackfill, needsEmailBackfill } = computeAdminSecretsBackfillFlags(adminObj);
|
|
144
216
|
const shouldOverwriteWithAdminPwd = adminPwdOverride !== null;
|
|
217
|
+
const shouldOverwriteEmail = emailOverride !== null;
|
|
218
|
+
const updateEmail = shouldOverwriteEmail || needsEmailBackfill;
|
|
145
219
|
|
|
146
|
-
if (!shouldOverwriteWithAdminPwd && !
|
|
220
|
+
if (!shouldOverwriteWithAdminPwd && !needsPasswordBackfill && !updateEmail) {
|
|
147
221
|
return adminSecretsPath;
|
|
148
222
|
}
|
|
149
223
|
|
|
150
|
-
|
|
224
|
+
const passwordForFile = resolvePasswordForAdminFile(
|
|
225
|
+
shouldOverwriteWithAdminPwd,
|
|
226
|
+
needsPasswordBackfill,
|
|
227
|
+
passwordToUse,
|
|
228
|
+
adminObj,
|
|
229
|
+
mergedDefaults
|
|
230
|
+
);
|
|
231
|
+
|
|
232
|
+
await applyAdminSecretsUpdate(adminSecretsPath, adminObj, passwordForFile, shouldOverwriteWithAdminPwd, {
|
|
233
|
+
updateEmail,
|
|
234
|
+
emailToUse
|
|
235
|
+
});
|
|
151
236
|
return adminSecretsPath;
|
|
152
237
|
}
|
|
153
238
|
|
|
239
|
+
/** Host-side pgpass for pgAdmin bind mount (must exist before container starts so servers.json import succeeds). */
|
|
240
|
+
const PGPASS_BOOTSTRAP_BASENAME = '.pgpass.bootstrap';
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Writes pgpass next to servers.json for Docker bind mount into /pgadmin4 (not under /var/lib/pgadmin volume).
|
|
244
|
+
* Prefer chown to pgAdmin UID so mode 600 is readable in the container; fall back to 644 if not root.
|
|
245
|
+
*
|
|
246
|
+
* @param {string} infraDir - Infrastructure directory path
|
|
247
|
+
* @param {string} postgresPassword - PostgreSQL password for the pgpass line
|
|
248
|
+
*/
|
|
249
|
+
function writePgpassBootstrap(infraDir, postgresPassword) {
|
|
250
|
+
const line = `postgres:5432:postgres:pgadmin:${postgresPassword}\n`;
|
|
251
|
+
const dest = path.join(infraDir, PGPASS_BOOTSTRAP_BASENAME);
|
|
252
|
+
fs.writeFileSync(dest, line, { mode: 0o600 });
|
|
253
|
+
try {
|
|
254
|
+
fs.chownSync(dest, 5050, 5050);
|
|
255
|
+
} catch {
|
|
256
|
+
try {
|
|
257
|
+
fs.chmodSync(dest, 0o644);
|
|
258
|
+
} catch {
|
|
259
|
+
// Ignore — container may still read depending on daemon / user namespace
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
154
264
|
/**
|
|
155
|
-
* Generates pgAdmin4 servers.json only. pgpass
|
|
156
|
-
*
|
|
265
|
+
* Generates pgAdmin4 servers.json only. pgpass for the container is supplied via bind-mounted
|
|
266
|
+
* `.pgpass.bootstrap` (written by writePgpassBootstrap); not embedded in servers.json.
|
|
157
267
|
*
|
|
158
268
|
* @param {string} infraDir - Infrastructure directory path
|
|
159
|
-
* @param {string} postgresPassword -
|
|
269
|
+
* @param {string} postgresPassword - Used only for consistency / future template fields (password is not written into servers.json)
|
|
160
270
|
*/
|
|
161
271
|
function generatePgAdminConfig(infraDir, postgresPassword) {
|
|
162
272
|
const serversJsonTemplatePath = path.join(__dirname, '..', '..', 'templates', 'infra', 'servers.json.hbs');
|
|
@@ -215,7 +325,7 @@ async function ensureMisoInitScript(infraDir) {
|
|
|
215
325
|
const secretKey = 'databases-miso-controller-0-passwordKeyVault';
|
|
216
326
|
let password;
|
|
217
327
|
try {
|
|
218
|
-
const loaded = await
|
|
328
|
+
const loaded = await getCoreSecrets().loadSecrets(undefined);
|
|
219
329
|
const urlOrPassword = loaded[secretKey] || loaded['databases-miso-controller-0-urlKeyVault'];
|
|
220
330
|
const extracted = extractPasswordFromUrlOrValue(urlOrPassword);
|
|
221
331
|
if (extracted !== null && extracted.trim() !== '') {
|
|
@@ -263,10 +373,11 @@ psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "miso" -c "GRANT AL
|
|
|
263
373
|
* @async
|
|
264
374
|
* @param {string} devId - Developer ID
|
|
265
375
|
* @param {string} adminSecretsPath - Path to admin secrets file
|
|
376
|
+
* @param {{ pgpassBootstrap?: boolean }} [prepOptions] - When pgpassBootstrap is false, skip/remove host pgpass bootstrap file (pgAdmin disabled)
|
|
266
377
|
* @returns {Promise<Object>} Object with infraDir and postgresPassword
|
|
267
378
|
*/
|
|
268
|
-
async function prepareInfraDirectory(devId, adminSecretsPath) {
|
|
269
|
-
const aifabrixDir = paths.
|
|
379
|
+
async function prepareInfraDirectory(devId, adminSecretsPath, prepOptions = {}) {
|
|
380
|
+
const aifabrixDir = paths.getAifabrixSystemDir();
|
|
270
381
|
const infraDirName = getInfraDirName(devId);
|
|
271
382
|
const infraDir = path.join(aifabrixDir, infraDirName);
|
|
272
383
|
if (!fs.existsSync(infraDir)) {
|
|
@@ -283,12 +394,59 @@ async function prepareInfraDirectory(devId, adminSecretsPath) {
|
|
|
283
394
|
}
|
|
284
395
|
|
|
285
396
|
const adminObj = await adminSecrets.readAndDecryptAdminSecrets(adminSecretsPath);
|
|
286
|
-
const postgresPassword =
|
|
397
|
+
const postgresPassword =
|
|
398
|
+
(adminObj.POSTGRES_PASSWORD && adminObj.POSTGRES_PASSWORD.trim()) ||
|
|
399
|
+
readInfraDefaultScalars().adminPassword ||
|
|
400
|
+
'';
|
|
287
401
|
generatePgAdminConfig(infraDir, postgresPassword);
|
|
288
402
|
|
|
403
|
+
const pgpassBootstrap = prepOptions.pgpassBootstrap !== false;
|
|
404
|
+
const bootstrapPath = path.join(infraDir, PGPASS_BOOTSTRAP_BASENAME);
|
|
405
|
+
if (pgpassBootstrap) {
|
|
406
|
+
writePgpassBootstrap(infraDir, postgresPassword);
|
|
407
|
+
} else {
|
|
408
|
+
try {
|
|
409
|
+
if (fs.existsSync(bootstrapPath)) {
|
|
410
|
+
fs.unlinkSync(bootstrapPath);
|
|
411
|
+
}
|
|
412
|
+
} catch {
|
|
413
|
+
// Ignore
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
289
417
|
return { infraDir, postgresPassword };
|
|
290
418
|
}
|
|
291
419
|
|
|
420
|
+
/**
|
|
421
|
+
* Resolve infra working directory and admin-secrets path for stop/restart.
|
|
422
|
+
* Infra dir: prefer system dir compose; if missing, use legacy home when compose exists there.
|
|
423
|
+
* Admin secrets: prefer `admin-secrets.env` under system dir; if missing, use legacy home (covers mixed layouts).
|
|
424
|
+
*
|
|
425
|
+
* @param {string|number} devId - Developer ID
|
|
426
|
+
* @returns {{ infraDir: string, adminSecretsPath: string }}
|
|
427
|
+
*/
|
|
428
|
+
function resolveInfraStatePaths(devId) {
|
|
429
|
+
const syncFs = nodeFs();
|
|
430
|
+
const name = getInfraDirName(devId);
|
|
431
|
+
const systemBase = paths.getAifabrixSystemDir();
|
|
432
|
+
const legacyBase = paths.getAifabrixHome();
|
|
433
|
+
const sysInfra = path.join(systemBase, name);
|
|
434
|
+
const legInfra = path.join(legacyBase, name);
|
|
435
|
+
const sysCompose = path.join(sysInfra, 'compose.yaml');
|
|
436
|
+
const legCompose = path.join(legInfra, 'compose.yaml');
|
|
437
|
+
let infraDir = sysInfra;
|
|
438
|
+
if (!syncFs.existsSync(sysCompose) && syncFs.existsSync(legCompose) && legacyBase !== systemBase) {
|
|
439
|
+
infraDir = legInfra;
|
|
440
|
+
}
|
|
441
|
+
const sysAdmin = path.join(systemBase, 'admin-secrets.env');
|
|
442
|
+
const legAdmin = path.join(legacyBase, 'admin-secrets.env');
|
|
443
|
+
let adminSecretsPath = sysAdmin;
|
|
444
|
+
if (!syncFs.existsSync(sysAdmin) && syncFs.existsSync(legAdmin) && legacyBase !== systemBase) {
|
|
445
|
+
adminSecretsPath = legAdmin;
|
|
446
|
+
}
|
|
447
|
+
return { infraDir, adminSecretsPath };
|
|
448
|
+
}
|
|
449
|
+
|
|
292
450
|
/**
|
|
293
451
|
* Register Handlebars helper for equality comparison
|
|
294
452
|
*/
|
|
@@ -312,7 +470,10 @@ module.exports = {
|
|
|
312
470
|
checkDockerAvailability,
|
|
313
471
|
ensureAdminSecrets,
|
|
314
472
|
generatePgAdminConfig,
|
|
473
|
+
writePgpassBootstrap,
|
|
474
|
+
PGPASS_BOOTSTRAP_BASENAME,
|
|
315
475
|
prepareInfraDirectory,
|
|
476
|
+
resolveInfraStatePaths,
|
|
316
477
|
ensureMisoInitScript,
|
|
317
478
|
registerHandlebarsHelper
|
|
318
479
|
};
|
|
@@ -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');
|
|
@@ -72,18 +71,35 @@ async function withRunEnv(infraDir, adminSecretsPath, fn) {
|
|
|
72
71
|
* @async
|
|
73
72
|
* @function prepareInfrastructureEnvironment
|
|
74
73
|
* @param {string|number|null} developerId - Developer ID
|
|
75
|
-
* @param {Object} [options] - Options (traefik, adminPwd)
|
|
74
|
+
* @param {Object} [options] - Options (traefik, adminPwd, tlsEnabled)
|
|
76
75
|
* @returns {Promise<Object>} Prepared environment configuration
|
|
77
76
|
*/
|
|
78
77
|
async function prepareInfrastructureEnvironment(developerId, options = {}) {
|
|
79
78
|
await checkDockerAvailability();
|
|
80
|
-
|
|
81
|
-
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);
|
|
82
90
|
|
|
83
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
|
+
|
|
84
99
|
const devIdNum = typeof devId === 'string' ? parseInt(devId, 10) : devId;
|
|
85
100
|
const ports = devConfig.getDevPorts(devIdNum);
|
|
86
101
|
const idNum = devIdNum;
|
|
102
|
+
const trustForwardedHeaders = remoteServerHostIsNonLocalhost(remoteServer);
|
|
87
103
|
|
|
88
104
|
const templatePath = path.join(__dirname, '..', '..', 'templates', 'infra', 'compose.yaml.hbs');
|
|
89
105
|
if (!fs.existsSync(templatePath)) {
|
|
@@ -91,10 +107,12 @@ async function prepareInfrastructureEnvironment(developerId, options = {}) {
|
|
|
91
107
|
}
|
|
92
108
|
|
|
93
109
|
// Prepare infrastructure directory
|
|
94
|
-
const { infraDir } = await prepareInfraDirectory(devId, adminSecretsPath
|
|
110
|
+
const { infraDir } = await prepareInfraDirectory(devId, adminSecretsPath, {
|
|
111
|
+
pgpassBootstrap: options.pgadmin !== false
|
|
112
|
+
});
|
|
95
113
|
await ensureMisoInitScript(infraDir);
|
|
96
114
|
|
|
97
|
-
return { devId, idNum, ports, templatePath, infraDir, adminSecretsPath };
|
|
115
|
+
return { devId, idNum, ports, templatePath, infraDir, adminSecretsPath, trustForwardedHeaders };
|
|
98
116
|
}
|
|
99
117
|
|
|
100
118
|
/**
|
|
@@ -114,9 +132,10 @@ async function prepareInfrastructureEnvironment(developerId, options = {}) {
|
|
|
114
132
|
* // Infrastructure services are now running
|
|
115
133
|
*/
|
|
116
134
|
async function startInfra(developerId = null, options = {}) {
|
|
117
|
-
const { devId, idNum, ports, templatePath, infraDir } =
|
|
135
|
+
const { devId, idNum, ports, templatePath, infraDir, trustForwardedHeaders } =
|
|
136
|
+
await prepareInfrastructureEnvironment(developerId, options);
|
|
118
137
|
const { traefik = false, pgadmin = true, redisCommander = true } = options;
|
|
119
|
-
const traefikConfig = buildTraefikConfig(traefik);
|
|
138
|
+
const traefikConfig = { ...buildTraefikConfig(traefik), trustForwardedHeaders };
|
|
120
139
|
const validation = validateTraefikConfig(traefikConfig);
|
|
121
140
|
if (!validation.valid) {
|
|
122
141
|
throw new Error(validation.errors.join('\n'));
|
|
@@ -199,10 +218,8 @@ async function removeAppVolumes(appNames, devId) {
|
|
|
199
218
|
*/
|
|
200
219
|
async function stopInfra() {
|
|
201
220
|
const devId = await config.getDeveloperId();
|
|
202
|
-
const
|
|
203
|
-
const infraDir = path.join(aifabrixDir, getInfraDirName(devId));
|
|
221
|
+
const { infraDir, adminSecretsPath } = resolveInfraStatePaths(devId);
|
|
204
222
|
const composePath = path.join(infraDir, 'compose.yaml');
|
|
205
|
-
const adminSecretsPath = path.join(aifabrixDir, 'admin-secrets.env');
|
|
206
223
|
|
|
207
224
|
if (!fs.existsSync(composePath) || !fs.existsSync(adminSecretsPath)) {
|
|
208
225
|
logger.log('Infrastructure not running or not properly configured');
|
|
@@ -262,10 +279,8 @@ async function stopAllAppContainersAndVolumes(devId) {
|
|
|
262
279
|
*/
|
|
263
280
|
async function stopInfraWithVolumes() {
|
|
264
281
|
const devId = await config.getDeveloperId();
|
|
265
|
-
const
|
|
266
|
-
const infraDir = path.join(aifabrixDir, getInfraDirName(devId));
|
|
282
|
+
const { infraDir, adminSecretsPath } = resolveInfraStatePaths(devId);
|
|
267
283
|
const composePath = path.join(infraDir, 'compose.yaml');
|
|
268
|
-
const adminSecretsPath = path.join(aifabrixDir, 'admin-secrets.env');
|
|
269
284
|
|
|
270
285
|
if (!fs.existsSync(composePath) || !fs.existsSync(adminSecretsPath)) {
|
|
271
286
|
logger.log('Infrastructure not running or not properly configured');
|
|
@@ -307,10 +322,8 @@ async function restartService(serviceName) {
|
|
|
307
322
|
}
|
|
308
323
|
|
|
309
324
|
const devId = await config.getDeveloperId();
|
|
310
|
-
const
|
|
311
|
-
const infraDir = path.join(aifabrixDir, getInfraDirName(devId));
|
|
325
|
+
const { infraDir, adminSecretsPath } = resolveInfraStatePaths(devId);
|
|
312
326
|
const composePath = path.join(infraDir, 'compose.yaml');
|
|
313
|
-
const adminSecretsPath = path.join(aifabrixDir, 'admin-secrets.env');
|
|
314
327
|
|
|
315
328
|
if (!fs.existsSync(composePath) || !fs.existsSync(adminSecretsPath)) {
|
|
316
329
|
throw new Error('Infrastructure not properly configured');
|
|
@@ -9,7 +9,6 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
const { exec } = require('child_process');
|
|
12
|
-
const { promisify } = require('util');
|
|
13
12
|
const path = require('path');
|
|
14
13
|
const fs = require('fs');
|
|
15
14
|
const logger = require('../utils/logger');
|
|
@@ -19,13 +18,13 @@ const config = require('../core/config');
|
|
|
19
18
|
const { getInfraProjectName } = require('./helpers');
|
|
20
19
|
const adminSecrets = require('../core/admin-secrets');
|
|
21
20
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
// Wrapper to support cwd option and dev-config remote Docker (docker-endpoint + TLS)
|
|
22
|
+
async function execAsyncWithCwd(command, options = {}) {
|
|
23
|
+
const { getDockerExecEnv } = require('../utils/remote-docker-env');
|
|
24
|
+
const { cwd, env: extraEnv, ...execOptions } = options;
|
|
25
|
+
const env = { ...(await getDockerExecEnv()), ...(extraEnv || {}) };
|
|
26
26
|
return new Promise((resolve, reject) => {
|
|
27
|
-
|
|
28
|
-
exec(command, { ...execOptions, cwd }, (error, stdout, stderr) => {
|
|
27
|
+
exec(command, { ...execOptions, cwd, env }, (error, stdout, stderr) => {
|
|
29
28
|
if (error) {
|
|
30
29
|
reject(error);
|
|
31
30
|
} else {
|
|
@@ -51,29 +50,6 @@ async function startDockerServices(composePath, projectName, adminSecretsPath, i
|
|
|
51
50
|
logger.log('Infrastructure services started successfully');
|
|
52
51
|
}
|
|
53
52
|
|
|
54
|
-
/**
|
|
55
|
-
* Copy pgAdmin4 configuration files into container
|
|
56
|
-
* @async
|
|
57
|
-
* @param {string} pgadminContainerName - pgAdmin container name
|
|
58
|
-
* @param {string} serversJsonPath - Path to servers.json file
|
|
59
|
-
* @param {string} pgpassPath - Path to pgpass file
|
|
60
|
-
*/
|
|
61
|
-
async function copyPgAdminConfig(pgadminContainerName, serversJsonPath, pgpassPath) {
|
|
62
|
-
try {
|
|
63
|
-
await new Promise(resolve => setTimeout(resolve, 2000)); // Wait for container to be ready
|
|
64
|
-
if (fs.existsSync(serversJsonPath)) {
|
|
65
|
-
await execAsync(`docker cp "${serversJsonPath}" ${pgadminContainerName}:/pgadmin4/servers.json`);
|
|
66
|
-
}
|
|
67
|
-
if (fs.existsSync(pgpassPath)) {
|
|
68
|
-
await execAsync(`docker cp "${pgpassPath}" ${pgadminContainerName}:/pgpass`);
|
|
69
|
-
await execAsync(`docker exec ${pgadminContainerName} chmod 600 /pgpass`);
|
|
70
|
-
}
|
|
71
|
-
} catch (error) {
|
|
72
|
-
// Ignore copy errors - files might already be there or container not ready
|
|
73
|
-
logger.log('Note: Could not copy pgAdmin4 config files (this is OK if container was just restarted)');
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
53
|
/**
|
|
78
54
|
* Prepare run env file from decrypted admin secrets.
|
|
79
55
|
* @async
|
|
@@ -89,34 +65,12 @@ async function prepareRunEnv(infraDir) {
|
|
|
89
65
|
}
|
|
90
66
|
|
|
91
67
|
/**
|
|
92
|
-
*
|
|
93
|
-
* @async
|
|
94
|
-
* @param {string} infraDir - Infrastructure directory
|
|
95
|
-
* @param {Object} adminObj - Decrypted admin secrets object
|
|
96
|
-
* @param {string} devId - Developer ID
|
|
97
|
-
* @param {number} idNum - Developer ID number
|
|
98
|
-
* @returns {Promise<string>} Path to pgpass run file
|
|
99
|
-
*/
|
|
100
|
-
async function writePgpassAndCopyPgAdminConfig(infraDir, adminObj, devId, idNum) {
|
|
101
|
-
const pgpassRunPath = path.join(infraDir, '.pgpass.run');
|
|
102
|
-
const pgadminContainerName = idNum === 0 ? 'aifabrix-pgadmin' : `aifabrix-dev${devId}-pgadmin`;
|
|
103
|
-
const serversJsonPath = path.join(infraDir, 'servers.json');
|
|
104
|
-
const postgresPassword = adminObj.POSTGRES_PASSWORD || '';
|
|
105
|
-
const pgpassContent = `postgres:5432:postgres:pgadmin:${postgresPassword}\n`;
|
|
106
|
-
fs.writeFileSync(pgpassRunPath, pgpassContent, { mode: 0o600 });
|
|
107
|
-
await copyPgAdminConfig(pgadminContainerName, serversJsonPath, pgpassRunPath);
|
|
108
|
-
return pgpassRunPath;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Remove temporary run files (env and pgpass) if they exist.
|
|
68
|
+
* Remove temporary run files (env) if they exist.
|
|
113
69
|
* @param {string} runEnvPath - Path to .env.run
|
|
114
|
-
* @param {string} [pgpassRunPath] - Path to .pgpass.run
|
|
115
70
|
*/
|
|
116
|
-
function cleanupRunFiles(runEnvPath
|
|
71
|
+
function cleanupRunFiles(runEnvPath) {
|
|
117
72
|
try {
|
|
118
73
|
if (fs.existsSync(runEnvPath)) fs.unlinkSync(runEnvPath);
|
|
119
|
-
if (pgpassRunPath && fs.existsSync(pgpassRunPath)) fs.unlinkSync(pgpassRunPath);
|
|
120
74
|
} catch {
|
|
121
75
|
// Ignore unlink errors
|
|
122
76
|
}
|
|
@@ -136,11 +90,9 @@ function cleanupRunFiles(runEnvPath, pgpassRunPath) {
|
|
|
136
90
|
*/
|
|
137
91
|
async function startDockerServicesAndConfigure(composePath, devId, idNum, infraDir, opts = {}) {
|
|
138
92
|
let runEnvPath;
|
|
139
|
-
let pgpassRunPath;
|
|
140
|
-
let adminObj;
|
|
141
93
|
const { pgadmin = true, redisCommander = true, traefik = false } = opts;
|
|
142
94
|
try {
|
|
143
|
-
({
|
|
95
|
+
({ runEnvPath } = await prepareRunEnv(infraDir));
|
|
144
96
|
} catch (err) {
|
|
145
97
|
throw new Error(`Failed to prepare infra env: ${err.message}`);
|
|
146
98
|
}
|
|
@@ -148,13 +100,10 @@ async function startDockerServicesAndConfigure(composePath, devId, idNum, infraD
|
|
|
148
100
|
try {
|
|
149
101
|
const projectName = getInfraProjectName(devId);
|
|
150
102
|
await startDockerServices(composePath, projectName, runEnvPath, infraDir);
|
|
151
|
-
if (pgadmin) {
|
|
152
|
-
pgpassRunPath = await writePgpassAndCopyPgAdminConfig(infraDir, adminObj, devId, idNum);
|
|
153
|
-
}
|
|
154
103
|
await waitForServices(devId, { pgadmin, redisCommander, traefik });
|
|
155
104
|
logger.log('All services are healthy and ready');
|
|
156
105
|
} finally {
|
|
157
|
-
cleanupRunFiles(runEnvPath
|
|
106
|
+
cleanupRunFiles(runEnvPath);
|
|
158
107
|
}
|
|
159
108
|
}
|
|
160
109
|
|
|
@@ -195,8 +144,10 @@ async function waitForServices(devId = null, opts = {}) {
|
|
|
195
144
|
* @param {number|string|null} [devId] - Developer ID (null = use current)
|
|
196
145
|
* @param {Object} [options] - Options
|
|
197
146
|
* @param {boolean} [options.strict=false] - When true, only consider current dev's containers (no fallback to dev 0); use for up-miso and status consistency
|
|
198
|
-
* @param {boolean} [options.
|
|
199
|
-
* @param {boolean} [options.
|
|
147
|
+
* @param {boolean} [options.postgres=true] - When false, skip Postgres (and pgAdmin) checks — for apps with requires.database: false
|
|
148
|
+
* @param {boolean} [options.redis=true] - When false, skip Redis (and Redis Commander) checks — for apps with requires.redis: false
|
|
149
|
+
* @param {boolean} [options.pgadmin=true] - Include pgAdmin in health check (only when Postgres is checked)
|
|
150
|
+
* @param {boolean} [options.redisCommander=true] - Include Redis Commander in health check (only when Redis is checked)
|
|
200
151
|
* @param {boolean} [options.traefik=false] - Include Traefik in health check
|
|
201
152
|
* @returns {Promise<Object>} Health status of each service
|
|
202
153
|
*
|
|
@@ -206,10 +157,14 @@ async function waitForServices(devId = null, opts = {}) {
|
|
|
206
157
|
*/
|
|
207
158
|
async function checkInfraHealth(devId = null, options = {}) {
|
|
208
159
|
const developerId = devId || await config.getDeveloperId();
|
|
209
|
-
const
|
|
160
|
+
const includePostgres = options.postgres !== false;
|
|
161
|
+
const includeRedis = options.redis !== false;
|
|
162
|
+
const servicesWithHealthCheck = [];
|
|
163
|
+
if (includePostgres) servicesWithHealthCheck.push('postgres');
|
|
164
|
+
if (includeRedis) servicesWithHealthCheck.push('redis');
|
|
210
165
|
const servicesWithoutHealthCheck = [];
|
|
211
|
-
if (options.pgadmin !== false) servicesWithoutHealthCheck.push('pgadmin');
|
|
212
|
-
if (options.redisCommander !== false) servicesWithoutHealthCheck.push('redis-commander');
|
|
166
|
+
if (includePostgres && options.pgadmin !== false) servicesWithoutHealthCheck.push('pgadmin');
|
|
167
|
+
if (includeRedis && options.redisCommander !== false) servicesWithoutHealthCheck.push('redis-commander');
|
|
213
168
|
if (options.traefik === true) servicesWithoutHealthCheck.push('traefik');
|
|
214
169
|
const health = {};
|
|
215
170
|
const lookupOptions = options.strict ? { strict: true } : {};
|
|
@@ -230,7 +185,6 @@ async function checkInfraHealth(devId = null, options = {}) {
|
|
|
230
185
|
module.exports = {
|
|
231
186
|
execAsyncWithCwd,
|
|
232
187
|
startDockerServices,
|
|
233
|
-
copyPgAdminConfig,
|
|
234
188
|
startDockerServicesAndConfigure,
|
|
235
189
|
waitForServices,
|
|
236
190
|
checkInfraHealth
|