@aifabrix/builder 2.43.0 → 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 +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 +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/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 +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 +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 +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 +57 -121
- package/lib/cli/setup-app.test-commands.js +179 -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 +62 -22
- package/lib/cli/setup-infra.js +126 -47
- package/lib/cli/setup-parameters.js +32 -0
- package/lib/cli/setup-secrets.js +106 -8
- package/lib/cli/setup-service-user.js +1 -1
- package/lib/cli/setup-utility.js +36 -20
- 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 +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 +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 +105 -98
- 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 +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 +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 +84 -53
- package/lib/datasource/resolve-app.js +4 -4
- package/lib/datasource/test-e2e.js +95 -146
- package/lib/datasource/test-integration.js +114 -122
- 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 +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 +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 +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 +60 -6
- package/lib/infrastructure/helpers.js +201 -29
- package/lib/infrastructure/index.js +28 -17
- 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 +1200 -442
- 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-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/controller-deployment-outcome.js +68 -0
- package/lib/utils/credential-display.js +2 -2
- 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 +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 +234 -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 +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 +134 -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 +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 +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.js +4 -13
- 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 +7 -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 +75 -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 +20 -4
- 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
|
@@ -13,10 +13,15 @@ const { parseImageReference } = require('./parse-image');
|
|
|
13
13
|
* @param {Object} deployment - Deployment JSON object
|
|
14
14
|
* @returns {{ appName: string, config: Object }}
|
|
15
15
|
*/
|
|
16
|
-
function buildReadmeConfigForExternal(deployment) {
|
|
16
|
+
function buildReadmeConfigForExternal(deployment, options = {}) {
|
|
17
17
|
const system = deployment.system;
|
|
18
18
|
const appName = system.key || deployment.key || 'external-system';
|
|
19
19
|
const dataSources = deployment.dataSources || deployment.datasources || [];
|
|
20
|
+
const rawExt = options.fileExt;
|
|
21
|
+
const fileExt =
|
|
22
|
+
rawExt !== undefined && rawExt !== null && String(rawExt).trim() !== ''
|
|
23
|
+
? (String(rawExt).startsWith('.') ? String(rawExt) : `.${String(rawExt)}`)
|
|
24
|
+
: '.json';
|
|
20
25
|
return {
|
|
21
26
|
appName,
|
|
22
27
|
config: {
|
|
@@ -25,7 +30,7 @@ function buildReadmeConfigForExternal(deployment) {
|
|
|
25
30
|
systemType: system.type || 'openapi',
|
|
26
31
|
systemDisplayName: system.displayName || appName,
|
|
27
32
|
systemDescription: system.description || `External system integration for ${appName}`,
|
|
28
|
-
fileExt
|
|
33
|
+
fileExt,
|
|
29
34
|
datasourceCount: dataSources.length,
|
|
30
35
|
datasources: dataSources
|
|
31
36
|
}
|
|
@@ -49,7 +54,7 @@ function buildReadmeConfigForApp(deployment) {
|
|
|
49
54
|
displayName: deployment.displayName,
|
|
50
55
|
description: deployment.description,
|
|
51
56
|
port,
|
|
52
|
-
build: {
|
|
57
|
+
build: {},
|
|
53
58
|
image: { name: imageName, registry },
|
|
54
59
|
registry,
|
|
55
60
|
database: deployment.requiresDatabase,
|
|
@@ -80,9 +85,9 @@ function buildReadmeConfigForApp(deployment) {
|
|
|
80
85
|
* @param {Object} deployment - Deployment JSON object
|
|
81
86
|
* @returns {{ appName: string, config: Object }}
|
|
82
87
|
*/
|
|
83
|
-
function buildReadmeConfigFromDeployment(deployment) {
|
|
88
|
+
function buildReadmeConfigFromDeployment(deployment, options = {}) {
|
|
84
89
|
if (deployment.system && typeof deployment.system === 'object') {
|
|
85
|
-
return buildReadmeConfigForExternal(deployment);
|
|
90
|
+
return buildReadmeConfigForExternal(deployment, options);
|
|
86
91
|
}
|
|
87
92
|
return buildReadmeConfigForApp(deployment);
|
|
88
93
|
}
|
|
@@ -92,11 +97,11 @@ function buildReadmeConfigFromDeployment(deployment) {
|
|
|
92
97
|
* @param {Object} deployment - Deployment JSON object
|
|
93
98
|
* @returns {string} README.md content
|
|
94
99
|
*/
|
|
95
|
-
function generateReadmeFromDeployJson(deployment) {
|
|
100
|
+
function generateReadmeFromDeployJson(deployment, options = {}) {
|
|
96
101
|
if (!deployment || typeof deployment !== 'object') {
|
|
97
102
|
throw new Error('Deployment object is required');
|
|
98
103
|
}
|
|
99
|
-
const { appName, config } = buildReadmeConfigFromDeployment(deployment);
|
|
104
|
+
const { appName, config } = buildReadmeConfigFromDeployment(deployment, options);
|
|
100
105
|
return generateReadmeMd(appName, config);
|
|
101
106
|
}
|
|
102
107
|
|
|
@@ -56,7 +56,8 @@ function extractOptionalSections(deployment) {
|
|
|
56
56
|
const optional = {};
|
|
57
57
|
const names = [
|
|
58
58
|
'healthCheck', 'authentication', 'build', 'repository', 'deployment',
|
|
59
|
-
'startupCommand', 'runtimeVersion', 'scaling', 'frontDoorRouting'
|
|
59
|
+
'startupCommand', 'runtimeVersion', 'scaling', 'frontDoorRouting',
|
|
60
|
+
'environmentScopedResources'
|
|
60
61
|
];
|
|
61
62
|
for (const sectionName of names) {
|
|
62
63
|
extractOptionalSection(deployment, sectionName, optional);
|
package/lib/generator/split.js
CHANGED
|
@@ -440,7 +440,7 @@ async function splitDeployJson(deployJsonPath, outputDir = null, splitOptions =
|
|
|
440
440
|
|
|
441
441
|
const variables = extractVariablesYaml(deployment);
|
|
442
442
|
const rbac = extractRbacYaml(deployment);
|
|
443
|
-
const readme = generateReadmeFromDeployJson(deployment);
|
|
443
|
+
const readme = generateReadmeFromDeployJson(deployment, { fileExt: '.yaml' });
|
|
444
444
|
|
|
445
445
|
const result = await writeComponentFiles(finalOutputDir, envTemplate, variables, rbac, readme, writeOptions);
|
|
446
446
|
await applyExternalSystemFilesToResult(finalOutputDir, deployment, result);
|
|
@@ -6,10 +6,10 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
'use strict';
|
|
9
|
+
const { formatSuccessLine } = require('../utils/cli-test-layout-chalk');
|
|
9
10
|
|
|
10
11
|
const fs = require('fs').promises;
|
|
11
12
|
const path = require('path');
|
|
12
|
-
const chalk = require('chalk');
|
|
13
13
|
const logger = require('../utils/logger');
|
|
14
14
|
const { generateExternalReadmeContent } = require('../utils/external-readme');
|
|
15
15
|
|
|
@@ -48,7 +48,7 @@ async function generateReadme(options) {
|
|
|
48
48
|
|
|
49
49
|
if (aiGeneratedContent) {
|
|
50
50
|
await fs.writeFile(readmePath, aiGeneratedContent, 'utf8');
|
|
51
|
-
logger.log(
|
|
51
|
+
logger.log(formatSuccessLine('Generated README.md (AI-generated from dataplane)'));
|
|
52
52
|
return;
|
|
53
53
|
}
|
|
54
54
|
|
|
@@ -82,7 +82,7 @@ async function generateReadme(options) {
|
|
|
82
82
|
});
|
|
83
83
|
|
|
84
84
|
await fs.writeFile(readmePath, readmeContent, 'utf8');
|
|
85
|
-
logger.log(
|
|
85
|
+
logger.log(formatSuccessLine('Generated README.md (template)'));
|
|
86
86
|
} catch (error) {
|
|
87
87
|
throw new Error(`Failed to generate README.md: ${error.message}`);
|
|
88
88
|
}
|
package/lib/generator/wizard.js
CHANGED
|
@@ -8,10 +8,10 @@
|
|
|
8
8
|
* PASSWORD, BASEURL. See docs/external-systems.md and docs/wizard.md.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
+
const { formatSuccessLine } = require('../utils/cli-test-layout-chalk');
|
|
11
12
|
const fs = require('fs').promises;
|
|
12
13
|
const path = require('path');
|
|
13
14
|
const Handlebars = require('handlebars');
|
|
14
|
-
const chalk = require('chalk');
|
|
15
15
|
const logger = require('../utils/logger');
|
|
16
16
|
const { resolveApplicationConfigPath } = require('../utils/app-config-resolver');
|
|
17
17
|
const { loadConfigFile, writeConfigFile } = require('../utils/config-format');
|
|
@@ -61,7 +61,7 @@ async function writeSystemYamlFile(appPath, finalSystemKey, systemConfig, format
|
|
|
61
61
|
const systemFileName = `${finalSystemKey}-system${ext}`;
|
|
62
62
|
const systemFilePath = path.join(appPath, systemFileName);
|
|
63
63
|
writeConfigFile(systemFilePath, systemConfig, format === 'json' ? 'json' : 'yaml');
|
|
64
|
-
logger.log(
|
|
64
|
+
logger.log(formatSuccessLine(`Generated system file: ${systemFileName}`));
|
|
65
65
|
return systemFilePath;
|
|
66
66
|
}
|
|
67
67
|
|
|
@@ -97,7 +97,7 @@ async function writeDatasourceYamlFiles(appPath, finalSystemKey, datasourceConfi
|
|
|
97
97
|
const datasourceFilePath = path.join(appPath, datasourceFileName);
|
|
98
98
|
writeConfigFile(datasourceFilePath, datasourceConfig, fmt);
|
|
99
99
|
datasourceFileNames.push(datasourceFileName);
|
|
100
|
-
logger.log(
|
|
100
|
+
logger.log(formatSuccessLine(`Generated datasource file: ${datasourceFileName}`));
|
|
101
101
|
}
|
|
102
102
|
return datasourceFileNames;
|
|
103
103
|
}
|
|
@@ -135,7 +135,7 @@ async function generateConfigFilesForWizard(params) {
|
|
|
135
135
|
const envTemplatePath = path.join(appPath, 'env.template');
|
|
136
136
|
const envTemplateContent = generateExternalEnvTemplateContent(systemConfig);
|
|
137
137
|
await fs.writeFile(envTemplatePath, envTemplateContent, 'utf8');
|
|
138
|
-
logger.log(
|
|
138
|
+
logger.log(formatSuccessLine('Generated env.template'));
|
|
139
139
|
|
|
140
140
|
try {
|
|
141
141
|
const secretsEnsure = require('../core/secrets-ensure');
|
|
@@ -164,7 +164,7 @@ async function generateConfigFilesForWizard(params) {
|
|
|
164
164
|
const deployJson = toDeployJsonShape(manifest);
|
|
165
165
|
const deployManifestPath = path.join(appPath, `${finalSystemKey}-deploy.json`);
|
|
166
166
|
await fs.writeFile(deployManifestPath, JSON.stringify(deployJson, null, 2), 'utf8');
|
|
167
|
-
logger.log(
|
|
167
|
+
logger.log(formatSuccessLine(`Generated deployment manifest: ${finalSystemKey}-deploy.json`));
|
|
168
168
|
|
|
169
169
|
return {
|
|
170
170
|
variablesPath: configPath,
|
|
@@ -293,7 +293,7 @@ async function generateOrUpdateVariablesYaml(params) {
|
|
|
293
293
|
const fsSync = require('fs');
|
|
294
294
|
if (fsSync.existsSync(configPath)) fsSync.unlinkSync(configPath);
|
|
295
295
|
}
|
|
296
|
-
logger.log(
|
|
296
|
+
logger.log(formatSuccessLine(`Generated/updated application${ext}`));
|
|
297
297
|
return targetPath;
|
|
298
298
|
} catch (error) {
|
|
299
299
|
throw new Error(`Failed to generate application config: ${error.message}`);
|
|
@@ -417,7 +417,7 @@ async function _generateEnvTemplate(appPath, systemConfig, finalSystemKey) {
|
|
|
417
417
|
addBaseUrlLines(lines, systemConfig);
|
|
418
418
|
|
|
419
419
|
await fs.writeFile(envTemplatePath, lines.join('\n'), 'utf8');
|
|
420
|
-
logger.log(
|
|
420
|
+
logger.log(formatSuccessLine('Generated env.template'));
|
|
421
421
|
} catch (error) {
|
|
422
422
|
throw new Error(`Failed to generate env.template: ${error.message}`);
|
|
423
423
|
}
|
|
@@ -440,7 +440,7 @@ async function writeDeployScriptFromTemplate(templateName, outputPath, context)
|
|
|
440
440
|
const templatePath = path.join(templatesExternalDir, templateName);
|
|
441
441
|
const content = Handlebars.compile(await fs.readFile(templatePath, 'utf8'))(context);
|
|
442
442
|
await fs.writeFile(outputPath, content, 'utf8');
|
|
443
|
-
logger.log(
|
|
443
|
+
logger.log(formatSuccessLine(`Generated ${path.basename(outputPath)}`));
|
|
444
444
|
}
|
|
445
445
|
|
|
446
446
|
async function generateDeployScripts(appPath, systemKey, systemFileName, datasourceFileNames) {
|
|
@@ -12,6 +12,32 @@ const fs = require('fs');
|
|
|
12
12
|
const handlebars = require('handlebars');
|
|
13
13
|
const path = require('path');
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Normalize a host path for Docker Compose bind mounts. Docker Desktop sends
|
|
17
|
+
* mounts to a Linux VM; backslashes in Windows paths yield "invalid volume
|
|
18
|
+
* specification" from the daemon.
|
|
19
|
+
*
|
|
20
|
+
* On Windows, Compose often forwards binds as "SOURCE:TARGET:rw". A SOURCE
|
|
21
|
+
* like "C:/Users/..." is split at the first colon, so the engine must receive
|
|
22
|
+
* paths in Linux-VM form (e.g. "/c/Users/...") instead.
|
|
23
|
+
*
|
|
24
|
+
* @param {string} fsPath - Host path (absolute or relative)
|
|
25
|
+
* @returns {string} Path with forward slashes, resolved when relative
|
|
26
|
+
*/
|
|
27
|
+
function toDockerBindMountSource(fsPath) {
|
|
28
|
+
if (!fsPath || typeof fsPath !== 'string') {
|
|
29
|
+
return fsPath;
|
|
30
|
+
}
|
|
31
|
+
let resolved = path.resolve(fsPath).split(path.sep).join('/');
|
|
32
|
+
if (process.platform === 'win32') {
|
|
33
|
+
const drive = /^([a-zA-Z]):(\/.*)$/.exec(resolved);
|
|
34
|
+
if (drive) {
|
|
35
|
+
resolved = `/${drive[1].toLowerCase()}${drive[2]}`;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return resolved;
|
|
39
|
+
}
|
|
40
|
+
|
|
15
41
|
/**
|
|
16
42
|
* Builds Traefik configuration from environment variables
|
|
17
43
|
* @param {boolean} enabled - Whether Traefik should be included
|
|
@@ -22,7 +48,8 @@ function buildTraefikConfig(enabled) {
|
|
|
22
48
|
enabled: !!enabled,
|
|
23
49
|
certStore: process.env.TRAEFIK_CERT_STORE || null,
|
|
24
50
|
certFile: process.env.TRAEFIK_CERT_FILE || null,
|
|
25
|
-
keyFile: process.env.TRAEFIK_KEY_FILE || null
|
|
51
|
+
keyFile: process.env.TRAEFIK_KEY_FILE || null,
|
|
52
|
+
trustForwardedHeaders: false
|
|
26
53
|
};
|
|
27
54
|
}
|
|
28
55
|
|
|
@@ -40,13 +67,23 @@ function validateTraefikConfig(traefikConfig) {
|
|
|
40
67
|
|
|
41
68
|
if (traefikConfig.certStore) {
|
|
42
69
|
if (!traefikConfig.certFile || !traefikConfig.keyFile) {
|
|
43
|
-
errors.push(
|
|
70
|
+
errors.push(
|
|
71
|
+
'TLS is enabled for Traefik but certificate files are missing or invalid. ' +
|
|
72
|
+
'Set TRAEFIK_CERT_FILE and TRAEFIK_KEY_FILE (and TRAEFIK_CERT_STORE if used) to your local cert and key, ' +
|
|
73
|
+
'or disable TLS in application/frontDoorRouting for local development.'
|
|
74
|
+
);
|
|
44
75
|
} else {
|
|
45
76
|
if (!fs.existsSync(traefikConfig.certFile)) {
|
|
46
|
-
errors.push(
|
|
77
|
+
errors.push(
|
|
78
|
+
'TLS is enabled for Traefik but certificate files are missing or invalid. ' +
|
|
79
|
+
`Certificate file not found: ${traefikConfig.certFile}`
|
|
80
|
+
);
|
|
47
81
|
}
|
|
48
82
|
if (!fs.existsSync(traefikConfig.keyFile)) {
|
|
49
|
-
errors.push(
|
|
83
|
+
errors.push(
|
|
84
|
+
'TLS is enabled for Traefik but certificate files are missing or invalid. ' +
|
|
85
|
+
`Private key file not found: ${traefikConfig.keyFile}`
|
|
86
|
+
);
|
|
50
87
|
}
|
|
51
88
|
}
|
|
52
89
|
}
|
|
@@ -82,6 +119,20 @@ function generateComposeFile(templatePath, devId, idNum, ports, infraDir, option
|
|
|
82
119
|
const redisCommanderConfig = options.redisCommander && typeof options.redisCommander.enabled === 'boolean'
|
|
83
120
|
? options.redisCommander
|
|
84
121
|
: { enabled: true };
|
|
122
|
+
const traefikForCompose = traefikConfig && typeof traefikConfig === 'object'
|
|
123
|
+
? {
|
|
124
|
+
...traefikConfig,
|
|
125
|
+
trustForwardedHeaders: !!traefikConfig.trustForwardedHeaders,
|
|
126
|
+
...(traefikConfig.certFile
|
|
127
|
+
? { certFile: toDockerBindMountSource(traefikConfig.certFile) }
|
|
128
|
+
: {}),
|
|
129
|
+
...(traefikConfig.keyFile
|
|
130
|
+
? { keyFile: toDockerBindMountSource(traefikConfig.keyFile) }
|
|
131
|
+
: {})
|
|
132
|
+
}
|
|
133
|
+
: traefikConfig;
|
|
134
|
+
const initScriptsBind = toDockerBindMountSource(path.join(infraDir, 'init-scripts'));
|
|
135
|
+
const infraDirBind = toDockerBindMountSource(infraDir);
|
|
85
136
|
const composeContent = template({
|
|
86
137
|
devId: devId,
|
|
87
138
|
postgresPort: ports.postgres,
|
|
@@ -94,7 +145,9 @@ function generateComposeFile(templatePath, devId, idNum, ports, infraDir, option
|
|
|
94
145
|
serversJsonPath: serversJsonPath,
|
|
95
146
|
pgpassPath: pgpassPath,
|
|
96
147
|
infraDir: infraDir,
|
|
97
|
-
|
|
148
|
+
initScriptsBind: initScriptsBind,
|
|
149
|
+
infraDirBind: infraDirBind,
|
|
150
|
+
traefik: traefikForCompose,
|
|
98
151
|
pgadmin: pgadminConfig,
|
|
99
152
|
redisCommander: redisCommanderConfig
|
|
100
153
|
});
|
|
@@ -106,5 +159,6 @@ function generateComposeFile(templatePath, devId, idNum, ports, infraDir, option
|
|
|
106
159
|
module.exports = {
|
|
107
160
|
buildTraefikConfig,
|
|
108
161
|
validateTraefikConfig,
|
|
109
|
-
generateComposeFile
|
|
162
|
+
generateComposeFile,
|
|
163
|
+
toDockerBindMountSource
|
|
110
164
|
};
|
|
@@ -11,14 +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 secrets = require('../core/secrets');
|
|
17
18
|
const adminSecrets = require('../core/admin-secrets');
|
|
18
19
|
const logger = require('../utils/logger');
|
|
19
20
|
const dockerUtils = require('../utils/docker');
|
|
20
21
|
const paths = require('../utils/paths');
|
|
21
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
|
+
}
|
|
22
39
|
|
|
23
40
|
/**
|
|
24
41
|
* Gets infrastructure directory name based on developer ID
|
|
@@ -43,21 +60,64 @@ function getInfraProjectName(devId) {
|
|
|
43
60
|
}
|
|
44
61
|
|
|
45
62
|
/**
|
|
46
|
-
*
|
|
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).
|
|
47
100
|
* @async
|
|
48
101
|
* @returns {Promise<void>}
|
|
49
|
-
* @throws {Error} If Docker
|
|
102
|
+
* @throws {Error} If Docker/Compose cannot be used (includes underlying cause)
|
|
50
103
|
*/
|
|
51
104
|
async function checkDockerAvailability() {
|
|
105
|
+
await ensureDevCertsIfNeededForRemoteDocker();
|
|
52
106
|
try {
|
|
53
107
|
await dockerUtils.ensureDockerAndCompose();
|
|
54
108
|
} catch (error) {
|
|
55
|
-
|
|
109
|
+
const detail = (error && error.message) || String(error);
|
|
110
|
+
throw new Error(formatDockerInfrastructureFailure(detail));
|
|
56
111
|
}
|
|
57
112
|
}
|
|
58
113
|
|
|
59
|
-
/**
|
|
60
|
-
|
|
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
|
+
}
|
|
61
121
|
|
|
62
122
|
/**
|
|
63
123
|
* Log hint to reset Postgres volume when admin password was changed after first init.
|
|
@@ -66,7 +126,7 @@ const DEFAULT_ADMIN_PASSWORD = 'admin123';
|
|
|
66
126
|
function logVolumeResetHint(infraDir) {
|
|
67
127
|
logger.log(chalk.yellow(
|
|
68
128
|
'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 --
|
|
129
|
+
`Run: cd ${infraDir} && docker compose -f compose.yaml -p aifabrix down -v , then run 'aifabrix up-infra --adminPassword <password>' again.`
|
|
70
130
|
));
|
|
71
131
|
}
|
|
72
132
|
|
|
@@ -82,9 +142,8 @@ async function syncPostgresPasswordToStore(password) {
|
|
|
82
142
|
}
|
|
83
143
|
}
|
|
84
144
|
|
|
85
|
-
/**
|
|
145
|
+
/** Non-email defaults for admin-secrets.env merge (email default comes from infra.parameter.yaml `defaults`). */
|
|
86
146
|
const DEFAULT_ADMIN_OBJ = {
|
|
87
|
-
PGADMIN_DEFAULT_EMAIL: 'admin@aifabrix.dev',
|
|
88
147
|
REDIS_HOST: 'local:redis:6379:0:',
|
|
89
148
|
REDIS_COMMANDER_USER: 'admin'
|
|
90
149
|
};
|
|
@@ -96,23 +155,87 @@ const DEFAULT_ADMIN_OBJ = {
|
|
|
96
155
|
* @param {Object} adminObj - Decrypted admin secrets object
|
|
97
156
|
* @param {string} passwordToUse - Password to set for Postgres, pgAdmin, Redis Commander
|
|
98
157
|
* @param {boolean} shouldOverwriteWithAdminPwd - Whether this was an explicit admin password update
|
|
158
|
+
* @param {{ updateEmail?: boolean, emailToUse?: string }} [emailOpts]
|
|
99
159
|
*/
|
|
100
|
-
async function applyAdminSecretsUpdate(
|
|
160
|
+
async function applyAdminSecretsUpdate(
|
|
161
|
+
adminSecretsPath,
|
|
162
|
+
adminObj,
|
|
163
|
+
passwordToUse,
|
|
164
|
+
shouldOverwriteWithAdminPwd,
|
|
165
|
+
emailOpts
|
|
166
|
+
) {
|
|
101
167
|
const merged = { ...DEFAULT_ADMIN_OBJ, ...adminObj };
|
|
102
168
|
merged.POSTGRES_PASSWORD = passwordToUse;
|
|
103
169
|
merged.PGADMIN_DEFAULT_PASSWORD = passwordToUse;
|
|
104
170
|
merged.REDIS_COMMANDER_PASSWORD = passwordToUse;
|
|
105
|
-
|
|
106
|
-
|
|
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 });
|
|
107
176
|
if (shouldOverwriteWithAdminPwd) {
|
|
108
177
|
logger.log('Updated admin password in admin-secrets.env.');
|
|
109
178
|
await syncPostgresPasswordToStore(passwordToUse);
|
|
110
|
-
logVolumeResetHint(path.join(paths.
|
|
179
|
+
logVolumeResetHint(path.join(paths.getAifabrixSystemDir(), getInfraDirName(0)));
|
|
180
|
+
} else if (emailOpts && emailOpts.updateEmail) {
|
|
181
|
+
logger.log('Updated admin email in admin-secrets.env.');
|
|
111
182
|
} else {
|
|
112
183
|
logger.log('Set default admin password in admin-secrets.env for local use.');
|
|
113
184
|
}
|
|
114
185
|
}
|
|
115
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
|
+
|
|
116
239
|
/**
|
|
117
240
|
* Ensure admin secrets file exists and set admin password.
|
|
118
241
|
* When adminPwd is provided, update POSTGRES_PASSWORD, PGADMIN_DEFAULT_PASSWORD, REDIS_COMMANDER_PASSWORD
|
|
@@ -121,33 +244,48 @@ async function applyAdminSecretsUpdate(adminSecretsPath, adminObj, passwordToUse
|
|
|
121
244
|
*
|
|
122
245
|
* @async
|
|
123
246
|
* @param {Object} [options] - Options
|
|
124
|
-
* @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)
|
|
125
251
|
* @returns {Promise<string>} Path to admin secrets file
|
|
126
252
|
*/
|
|
127
253
|
async function ensureAdminSecrets(options = {}) {
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
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');
|
|
133
260
|
|
|
134
|
-
if (!
|
|
261
|
+
if (!fsRealSync.existsSync(adminSecretsPath)) {
|
|
135
262
|
logger.log('Generating admin-secrets.env...');
|
|
136
|
-
await
|
|
263
|
+
await getCoreSecrets().generateAdminSecretsEnv(undefined);
|
|
137
264
|
return adminSecretsPath;
|
|
138
265
|
}
|
|
139
266
|
|
|
140
267
|
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());
|
|
268
|
+
const { needsPasswordBackfill, needsEmailBackfill } = computeAdminSecretsBackfillFlags(adminObj);
|
|
144
269
|
const shouldOverwriteWithAdminPwd = adminPwdOverride !== null;
|
|
270
|
+
const shouldOverwriteEmail = emailOverride !== null;
|
|
271
|
+
const updateEmail = shouldOverwriteEmail || needsEmailBackfill;
|
|
145
272
|
|
|
146
|
-
if (!shouldOverwriteWithAdminPwd && !
|
|
273
|
+
if (!shouldOverwriteWithAdminPwd && !needsPasswordBackfill && !updateEmail) {
|
|
147
274
|
return adminSecretsPath;
|
|
148
275
|
}
|
|
149
276
|
|
|
150
|
-
|
|
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
|
+
});
|
|
151
289
|
return adminSecretsPath;
|
|
152
290
|
}
|
|
153
291
|
|
|
@@ -215,7 +353,7 @@ async function ensureMisoInitScript(infraDir) {
|
|
|
215
353
|
const secretKey = 'databases-miso-controller-0-passwordKeyVault';
|
|
216
354
|
let password;
|
|
217
355
|
try {
|
|
218
|
-
const loaded = await
|
|
356
|
+
const loaded = await getCoreSecrets().loadSecrets(undefined);
|
|
219
357
|
const urlOrPassword = loaded[secretKey] || loaded['databases-miso-controller-0-urlKeyVault'];
|
|
220
358
|
const extracted = extractPasswordFromUrlOrValue(urlOrPassword);
|
|
221
359
|
if (extracted !== null && extracted.trim() !== '') {
|
|
@@ -266,7 +404,7 @@ psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "miso" -c "GRANT AL
|
|
|
266
404
|
* @returns {Promise<Object>} Object with infraDir and postgresPassword
|
|
267
405
|
*/
|
|
268
406
|
async function prepareInfraDirectory(devId, adminSecretsPath) {
|
|
269
|
-
const aifabrixDir = paths.
|
|
407
|
+
const aifabrixDir = paths.getAifabrixSystemDir();
|
|
270
408
|
const infraDirName = getInfraDirName(devId);
|
|
271
409
|
const infraDir = path.join(aifabrixDir, infraDirName);
|
|
272
410
|
if (!fs.existsSync(infraDir)) {
|
|
@@ -283,12 +421,45 @@ async function prepareInfraDirectory(devId, adminSecretsPath) {
|
|
|
283
421
|
}
|
|
284
422
|
|
|
285
423
|
const adminObj = await adminSecrets.readAndDecryptAdminSecrets(adminSecretsPath);
|
|
286
|
-
const postgresPassword =
|
|
424
|
+
const postgresPassword =
|
|
425
|
+
(adminObj.POSTGRES_PASSWORD && adminObj.POSTGRES_PASSWORD.trim()) ||
|
|
426
|
+
readInfraDefaultScalars().adminPassword ||
|
|
427
|
+
'';
|
|
287
428
|
generatePgAdminConfig(infraDir, postgresPassword);
|
|
288
429
|
|
|
289
430
|
return { infraDir, postgresPassword };
|
|
290
431
|
}
|
|
291
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
|
+
|
|
292
463
|
/**
|
|
293
464
|
* Register Handlebars helper for equality comparison
|
|
294
465
|
*/
|
|
@@ -313,6 +484,7 @@ module.exports = {
|
|
|
313
484
|
ensureAdminSecrets,
|
|
314
485
|
generatePgAdminConfig,
|
|
315
486
|
prepareInfraDirectory,
|
|
487
|
+
resolveInfraStatePaths,
|
|
316
488
|
ensureMisoInitScript,
|
|
317
489
|
registerHandlebarsHelper
|
|
318
490
|
};
|