@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
package/lib/utils/docker.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Detects availability of Docker and determines the correct Docker Compose command
|
|
5
5
|
* across environments (Compose v2 plugin: "docker compose", Compose v1: "docker-compose").
|
|
6
|
+
* Uses docker-endpoint from dev config when set (see remote-docker-env / docker-exec).
|
|
6
7
|
*
|
|
7
8
|
* @fileoverview Docker/Compose detection helpers for AI Fabrix Builder
|
|
8
9
|
* @author AI Fabrix Team
|
|
@@ -11,10 +12,65 @@
|
|
|
11
12
|
|
|
12
13
|
'use strict';
|
|
13
14
|
|
|
14
|
-
const {
|
|
15
|
-
const { promisify } = require('util');
|
|
15
|
+
const { execWithDockerEnv } = require('./docker-exec');
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
/** Env override: full compose CLI prefix, e.g. `docker compose` or `docker-compose` (validated with version). */
|
|
18
|
+
const COMPOSE_CMD_ENV = 'AIFABRIX_COMPOSE_CMD';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Short string from exec failure (message + stderr) for user-visible errors.
|
|
22
|
+
* @param {unknown} err - Rejected error from exec
|
|
23
|
+
* @returns {string}
|
|
24
|
+
*/
|
|
25
|
+
function formatExecFailure(err) {
|
|
26
|
+
if (!err) return '';
|
|
27
|
+
const e = err;
|
|
28
|
+
const msg = typeof e.message === 'string' ? e.message.trim() : '';
|
|
29
|
+
const stderr = typeof e.stderr === 'string' ? e.stderr.trim() : '';
|
|
30
|
+
const combined = [msg, stderr].filter(Boolean).join(' ').trim();
|
|
31
|
+
if (!combined) return '';
|
|
32
|
+
return combined.length > 280 ? `${combined.slice(0, 277)}...` : combined;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Hint when docker compose likely failed talking to a remote TLS daemon, not missing plugin.
|
|
37
|
+
* @param {string} detail - formatExecFailure output
|
|
38
|
+
* @returns {string}
|
|
39
|
+
*/
|
|
40
|
+
function remoteTlsComposeHint(detail) {
|
|
41
|
+
const d = detail.toLowerCase();
|
|
42
|
+
if (!d) return '';
|
|
43
|
+
const tlsish =
|
|
44
|
+
d.includes('tls') ||
|
|
45
|
+
d.includes('certificate') ||
|
|
46
|
+
d.includes('x509') ||
|
|
47
|
+
d.includes('cert') ||
|
|
48
|
+
d.includes('connection refused') ||
|
|
49
|
+
d.includes('2376') ||
|
|
50
|
+
d.includes('eof') ||
|
|
51
|
+
d.includes('handshake');
|
|
52
|
+
if (!tlsish) return '';
|
|
53
|
+
return (
|
|
54
|
+
' This often means docker-endpoint TLS/client auth failed (place cert.pem, key.pem, ca.pem in ~/.aifabrix/certs/<developer-id>/, or set docker-tls-skip-verify only if appropriate), not a missing Compose plugin.'
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* @param {string} composeV2Failure - formatExecFailure from docker compose version
|
|
60
|
+
*/
|
|
61
|
+
function throwComposeCommandUnavailable(composeV2Failure) {
|
|
62
|
+
const v2bit = composeV2Failure
|
|
63
|
+
? ` "docker compose version" failed: ${composeV2Failure}.${remoteTlsComposeHint(composeV2Failure)} `
|
|
64
|
+
: ' ';
|
|
65
|
+
throw new Error(
|
|
66
|
+
'Docker Compose is not available. Tried: "docker compose", "docker-compose", "podman compose".' +
|
|
67
|
+
v2bit +
|
|
68
|
+
'Install the Compose v2 plugin (needs only the docker CLI + plugin; no unix socket required when docker-endpoint is set). ' +
|
|
69
|
+
'Example: sudo apt-get install -y docker-compose-plugin. ' +
|
|
70
|
+
`Or set ${COMPOSE_CMD_ENV} to a working compose prefix. ` +
|
|
71
|
+
'up-infra uses the Docker CLI as a client to the Engine API (remote tcp://…:2376 is OK); there is no separate Builder-only compose API.'
|
|
72
|
+
);
|
|
73
|
+
}
|
|
18
74
|
|
|
19
75
|
/**
|
|
20
76
|
* Checks that Docker CLI is available.
|
|
@@ -24,7 +80,29 @@ const execAsync = promisify(exec);
|
|
|
24
80
|
* @throws {Error} If docker is unavailable
|
|
25
81
|
*/
|
|
26
82
|
async function checkDockerCli() {
|
|
27
|
-
await
|
|
83
|
+
await execWithDockerEnv('docker --version');
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* @returns {Promise<string|null>} Resolved compose command prefix from env override, or null to auto-detect
|
|
88
|
+
*/
|
|
89
|
+
async function resolveComposeCmdOverride() {
|
|
90
|
+
const override =
|
|
91
|
+
typeof process.env[COMPOSE_CMD_ENV] === 'string' ? process.env[COMPOSE_CMD_ENV].trim() : '';
|
|
92
|
+
if (!override) return null;
|
|
93
|
+
try {
|
|
94
|
+
await execWithDockerEnv(`${override} version`);
|
|
95
|
+
return override;
|
|
96
|
+
} catch {
|
|
97
|
+
try {
|
|
98
|
+
await execWithDockerEnv(`${override} --version`);
|
|
99
|
+
return override;
|
|
100
|
+
} catch (err) {
|
|
101
|
+
throw new Error(
|
|
102
|
+
`${COMPOSE_CMD_ENV}="${override}" is set but failed (tried "version" and "--version"): ${err.message}`
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
28
106
|
}
|
|
29
107
|
|
|
30
108
|
/**
|
|
@@ -37,19 +115,29 @@ async function checkDockerCli() {
|
|
|
37
115
|
* @throws {Error} If neither v2 nor v1 is available
|
|
38
116
|
*/
|
|
39
117
|
async function getComposeCommand() {
|
|
40
|
-
|
|
118
|
+
const fromEnv = await resolveComposeCmdOverride();
|
|
119
|
+
if (fromEnv) return fromEnv;
|
|
120
|
+
|
|
121
|
+
let composeV2Failure = '';
|
|
41
122
|
try {
|
|
42
|
-
await
|
|
123
|
+
await execWithDockerEnv('docker compose version');
|
|
43
124
|
return 'docker compose';
|
|
44
|
-
} catch (
|
|
45
|
-
|
|
125
|
+
} catch (e) {
|
|
126
|
+
composeV2Failure = formatExecFailure(e);
|
|
46
127
|
}
|
|
47
128
|
|
|
48
129
|
try {
|
|
49
|
-
await
|
|
130
|
+
await execWithDockerEnv('docker-compose --version');
|
|
50
131
|
return 'docker-compose';
|
|
51
132
|
} catch (_) {
|
|
52
|
-
|
|
133
|
+
// Podman with compose (some hosts use podman-docker + podman compose)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
try {
|
|
137
|
+
await execWithDockerEnv('podman compose version');
|
|
138
|
+
return 'podman compose';
|
|
139
|
+
} catch (_) {
|
|
140
|
+
throwComposeCommandUnavailable(composeV2Failure);
|
|
53
141
|
}
|
|
54
142
|
}
|
|
55
143
|
|
|
@@ -70,4 +158,3 @@ module.exports = {
|
|
|
70
158
|
getComposeCommand,
|
|
71
159
|
ensureDockerAndCompose
|
|
72
160
|
};
|
|
73
|
-
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* When `docker-endpoint` is set but dev cert.pem/key.pem are missing, optionally call
|
|
3
|
+
* POST /api/dev/issue-cert using a one-time PIN from the environment (same flow as `aifabrix dev init`).
|
|
4
|
+
* There is no unauthenticated cert download; the PIN must be created from an enrolled machine.
|
|
5
|
+
*
|
|
6
|
+
* @fileoverview Auto issue-cert for remote Docker before infra / docker checks
|
|
7
|
+
* @author AI Fabrix Team
|
|
8
|
+
* @version 2.0.0
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
'use strict';
|
|
12
|
+
const { formatSuccessLine } = require('./cli-test-layout-chalk');
|
|
13
|
+
|
|
14
|
+
const path = require('path');
|
|
15
|
+
const fsSync = require('node:fs');
|
|
16
|
+
const fsRealSync = require('../internal/fs-real-sync');
|
|
17
|
+
const { nodeFs } = require('../internal/node-fs');
|
|
18
|
+
const chalk = require('chalk');
|
|
19
|
+
const config = require('../core/config');
|
|
20
|
+
const logger = require('./logger');
|
|
21
|
+
const devApi = require('../api/dev.api');
|
|
22
|
+
const { getConfigDirForPaths } = require('./paths');
|
|
23
|
+
const {
|
|
24
|
+
generateCSR,
|
|
25
|
+
getCertDir,
|
|
26
|
+
mergeCaPemBlocks,
|
|
27
|
+
normalizePemNewlines
|
|
28
|
+
} = require('./dev-cert-helper');
|
|
29
|
+
const { isSslUntrustedError, fetchInstallCa } = require('./dev-ca-install');
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Read one-time issue-cert PIN from env or first non-empty line of AIFABRIX_DEV_ISSUE_PIN_FILE.
|
|
33
|
+
* @returns {string|null}
|
|
34
|
+
*/
|
|
35
|
+
function readIssueCertPin() {
|
|
36
|
+
const a = process.env.AIFABRIX_DEV_ISSUE_PIN;
|
|
37
|
+
const b = process.env.AIFABRIX_ISSUE_CERT_PIN;
|
|
38
|
+
const fromEnv =
|
|
39
|
+
typeof a === 'string' && a.trim() ? a.trim() : typeof b === 'string' && b.trim() ? b.trim() : '';
|
|
40
|
+
if (fromEnv) return fromEnv;
|
|
41
|
+
const fp = process.env.AIFABRIX_DEV_ISSUE_PIN_FILE;
|
|
42
|
+
if (!fp || typeof fp !== 'string' || !fp.trim()) return null;
|
|
43
|
+
try {
|
|
44
|
+
const raw = fsRealSync.readFileSyncDirect(path.normalize(fp.trim()), { encoding: 'utf8' });
|
|
45
|
+
let content;
|
|
46
|
+
if (typeof raw === 'string') {
|
|
47
|
+
content = raw;
|
|
48
|
+
} else if (Buffer.isBuffer(raw)) {
|
|
49
|
+
content = raw.toString('utf8');
|
|
50
|
+
} else {
|
|
51
|
+
throw new Error('readFileSync did not return string content');
|
|
52
|
+
}
|
|
53
|
+
const line = content.split(/\r?\n/).find((l) => l.trim());
|
|
54
|
+
return line ? line.trim() : null;
|
|
55
|
+
} catch (e) {
|
|
56
|
+
throw new Error(`AIFABRIX_DEV_ISSUE_PIN_FILE (${fp}): ${e.message}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async function resolveServerCaForIssueCert(baseUrl) {
|
|
61
|
+
try {
|
|
62
|
+
await devApi.getHealth(baseUrl);
|
|
63
|
+
return null;
|
|
64
|
+
} catch (err) {
|
|
65
|
+
if (isSslUntrustedError(err)) {
|
|
66
|
+
const caBuf = await fetchInstallCa(baseUrl);
|
|
67
|
+
const caPemStr = caBuf.toString('utf8').trim();
|
|
68
|
+
await devApi.getHealth(baseUrl, caPemStr);
|
|
69
|
+
return caPemStr;
|
|
70
|
+
}
|
|
71
|
+
throw err;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async function requestIssueCert(baseUrl, devId, pin, csrPem, serverCaPem) {
|
|
76
|
+
try {
|
|
77
|
+
return await devApi.issueCert(
|
|
78
|
+
baseUrl,
|
|
79
|
+
{ developerId: devId, pin: pin.trim(), csr: csrPem },
|
|
80
|
+
serverCaPem || undefined
|
|
81
|
+
);
|
|
82
|
+
} catch (err) {
|
|
83
|
+
if (err.status === 401) {
|
|
84
|
+
throw new Error(
|
|
85
|
+
'Invalid or expired PIN (AIFABRIX_DEV_ISSUE_PIN / AIFABRIX_ISSUE_CERT_PIN). ' +
|
|
86
|
+
'Create a new PIN from an enrolled machine, e.g. `aifabrix dev pin <developerId>`.'
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
if (err.status === 404) {
|
|
90
|
+
throw new Error(`Developer ${devId} not found on Builder Server.`);
|
|
91
|
+
}
|
|
92
|
+
if (err.status === 503) {
|
|
93
|
+
throw new Error('Certificate signing is temporarily unavailable. Try again later.');
|
|
94
|
+
}
|
|
95
|
+
throw err;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async function saveDevCertMaterial(configDir, devId, certificatePem, keyPem, caPem) {
|
|
100
|
+
const fsp = nodeFs().promises;
|
|
101
|
+
const certDir = getCertDir(configDir, devId);
|
|
102
|
+
await fsp.mkdir(certDir, { recursive: true });
|
|
103
|
+
await fsp.writeFile(
|
|
104
|
+
path.join(certDir, 'cert.pem'),
|
|
105
|
+
normalizePemNewlines(certificatePem),
|
|
106
|
+
{ mode: 0o600 }
|
|
107
|
+
);
|
|
108
|
+
await fsp.writeFile(
|
|
109
|
+
path.join(certDir, 'key.pem'),
|
|
110
|
+
normalizePemNewlines(keyPem),
|
|
111
|
+
{ mode: 0o600 }
|
|
112
|
+
);
|
|
113
|
+
if (caPem && typeof caPem === 'string' && caPem.trim()) {
|
|
114
|
+
await fsp.writeFile(
|
|
115
|
+
path.join(certDir, 'ca.pem'),
|
|
116
|
+
normalizePemNewlines(caPem.trim()),
|
|
117
|
+
{ mode: 0o600 }
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
await config.setDeveloperId(devId);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* @returns {Promise<{ baseUrl: string, devId: string, certDir: string, configDir: string }|null>}
|
|
125
|
+
*/
|
|
126
|
+
async function readEnsureIssueCertContext() {
|
|
127
|
+
const endpoint = await config.getDockerEndpoint();
|
|
128
|
+
if (!endpoint || typeof endpoint !== 'string' || !endpoint.trim()) return null;
|
|
129
|
+
|
|
130
|
+
const remoteServer = await config.getRemoteServer();
|
|
131
|
+
if (!remoteServer || typeof remoteServer !== 'string' || !remoteServer.trim()) return null;
|
|
132
|
+
|
|
133
|
+
const devIdRaw = await config.getDeveloperId();
|
|
134
|
+
if (!devIdRaw || typeof devIdRaw !== 'string' || !String(devIdRaw).trim()) return null;
|
|
135
|
+
const devId = String(devIdRaw).trim();
|
|
136
|
+
|
|
137
|
+
const configDir = getConfigDirForPaths();
|
|
138
|
+
const certDir = getCertDir(configDir, devId);
|
|
139
|
+
if (
|
|
140
|
+
fsSync.existsSync(path.join(certDir, 'cert.pem')) &&
|
|
141
|
+
fsSync.existsSync(path.join(certDir, 'key.pem'))
|
|
142
|
+
) {
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return {
|
|
147
|
+
baseUrl: remoteServer.trim().replace(/\/+$/, ''),
|
|
148
|
+
devId,
|
|
149
|
+
certDir,
|
|
150
|
+
configDir
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function missingTlsFilesError(certDir, devId) {
|
|
155
|
+
return new Error(
|
|
156
|
+
`docker-endpoint is set but client TLS files are missing in ${certDir}. ` +
|
|
157
|
+
'On a PC that already has a client certificate to the Builder Server, run: aifabrix dev pin ' +
|
|
158
|
+
devId +
|
|
159
|
+
'. Then on this host: aifabrix dev init --pin <pin> if remote-server and developer-id are in config, ' +
|
|
160
|
+
'or export AIFABRIX_DEV_ISSUE_PIN=<pin> before retrying. ' +
|
|
161
|
+
'Alternatively, if the Docker engine does not require client certificates, set docker-tls-skip-verify or AIFABRIX_DOCKER_TLS_SKIP_VERIFY.'
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* If remote Docker is configured and TLS files are missing, run issue-cert when a PIN is supplied via env.
|
|
167
|
+
* If no PIN and TLS skip-verify is set in config or env, returns without error.
|
|
168
|
+
* If no PIN and verify is required, throws with instructions.
|
|
169
|
+
* @returns {Promise<void>}
|
|
170
|
+
*/
|
|
171
|
+
async function ensureDevCertsIfNeededForRemoteDocker() {
|
|
172
|
+
const ctx = await readEnsureIssueCertContext();
|
|
173
|
+
if (!ctx) return;
|
|
174
|
+
|
|
175
|
+
const pin = readIssueCertPin();
|
|
176
|
+
if (!pin) {
|
|
177
|
+
if (await config.getDockerTlsSkipVerify()) return;
|
|
178
|
+
throw missingTlsFilesError(ctx.certDir, ctx.devId);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
logger.log(chalk.blue('\n🔐 Fetching developer certificate from Builder Server (issue-cert)...\n'));
|
|
182
|
+
const serverCaPem = await resolveServerCaForIssueCert(ctx.baseUrl);
|
|
183
|
+
const { csrPem, keyPem } = generateCSR(ctx.devId);
|
|
184
|
+
const issueResponse = await requestIssueCert(ctx.baseUrl, ctx.devId, pin, csrPem, serverCaPem);
|
|
185
|
+
const caPem = mergeCaPemBlocks(serverCaPem, issueResponse.caCertificate, issueResponse.ca);
|
|
186
|
+
await saveDevCertMaterial(ctx.configDir, ctx.devId, issueResponse.certificate, keyPem, caPem);
|
|
187
|
+
logger.log(
|
|
188
|
+
formatSuccessLine('Saved TLS material to ') + chalk.cyan(ctx.certDir) + chalk.green(' for remote Docker.\n')
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
module.exports = { ensureDevCertsIfNeededForRemoteDocker, readIssueCertPin };
|
|
@@ -1,113 +1,32 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Environment config loader
|
|
2
|
+
* Environment config loader — infra defaults live in code ({@link module:lib/utils/infra-env-defaults}).
|
|
3
3
|
*
|
|
4
|
-
* @fileoverview
|
|
5
|
-
* Merges with user's env-config file if configured in ~/.aifabrix/config.yaml
|
|
4
|
+
* @fileoverview Replaces lib/schema/env-config.yaml + user merge
|
|
6
5
|
* @author AI Fabrix Team
|
|
7
|
-
* @version 2.
|
|
6
|
+
* @version 2.1.0
|
|
8
7
|
*/
|
|
9
8
|
|
|
10
9
|
'use strict';
|
|
11
10
|
|
|
12
|
-
const
|
|
13
|
-
const path = require('path');
|
|
14
|
-
const yaml = require('js-yaml');
|
|
15
|
-
const config = require('../core/config');
|
|
11
|
+
const { getDefaultEnvConfig } = require('./infra-env-defaults');
|
|
16
12
|
|
|
17
13
|
/**
|
|
18
|
-
*
|
|
19
|
-
* @
|
|
20
|
-
* @function loadUserEnvConfig
|
|
21
|
-
* @returns {Promise<Object|null>} Parsed user env-config or null if not configured
|
|
22
|
-
*/
|
|
23
|
-
async function loadUserEnvConfig() {
|
|
24
|
-
try {
|
|
25
|
-
const userEnvConfigPath = await config.getAifabrixEnvConfigPath();
|
|
26
|
-
if (!userEnvConfigPath) {
|
|
27
|
-
return null;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// Resolve path (support absolute and relative paths)
|
|
31
|
-
const resolvedPath = path.isAbsolute(userEnvConfigPath)
|
|
32
|
-
? userEnvConfigPath
|
|
33
|
-
: path.resolve(process.cwd(), userEnvConfigPath);
|
|
34
|
-
|
|
35
|
-
if (!fs.existsSync(resolvedPath)) {
|
|
36
|
-
return null;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const content = fs.readFileSync(resolvedPath, 'utf8');
|
|
40
|
-
const userConfig = yaml.load(content);
|
|
41
|
-
return userConfig && typeof userConfig === 'object' ? userConfig : null;
|
|
42
|
-
} catch (error) {
|
|
43
|
-
// Gracefully handle errors - fallback to base config only
|
|
44
|
-
return null;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Merges user env-config with base env-config
|
|
50
|
-
* User values override/extend base values
|
|
51
|
-
* @function mergeEnvConfigs
|
|
52
|
-
* @param {Object} baseConfig - Base env-config from lib/schema/env-config.yaml
|
|
53
|
-
* @param {Object|null} userConfig - User env-config or null
|
|
54
|
-
* @returns {Object} Merged env-config
|
|
55
|
-
*/
|
|
56
|
-
function mergeEnvConfigs(baseConfig, userConfig) {
|
|
57
|
-
if (!userConfig || typeof userConfig !== 'object') {
|
|
58
|
-
return baseConfig || {};
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// Deep merge environments
|
|
62
|
-
const merged = { ...baseConfig };
|
|
63
|
-
if (userConfig.environments && typeof userConfig.environments === 'object') {
|
|
64
|
-
merged.environments = { ...(baseConfig.environments || {}) };
|
|
65
|
-
for (const [env, envVars] of Object.entries(userConfig.environments)) {
|
|
66
|
-
if (envVars && typeof envVars === 'object') {
|
|
67
|
-
merged.environments[env] = {
|
|
68
|
-
...(merged.environments[env] || {}),
|
|
69
|
-
...envVars
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
return merged;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Load schema-only env-config (no user merge). Used for *_PUBLIC_PORT calculation
|
|
80
|
-
* so public ports always use canonical base (e.g. KEYCLOAK_PUBLIC_PORT = 8082 + devId*100).
|
|
81
|
-
*
|
|
82
|
-
* @function loadSchemaEnvConfig
|
|
83
|
-
* @returns {Object} Parsed schema env-config (environments.docker / .local only)
|
|
14
|
+
* Schema-only env-config (sync). Used for *_PUBLIC_PORT canonical bases.
|
|
15
|
+
* @returns {Object}
|
|
84
16
|
*/
|
|
85
17
|
function loadSchemaEnvConfig() {
|
|
86
|
-
|
|
87
|
-
const content = fs.readFileSync(envConfigPath, 'utf8');
|
|
88
|
-
return yaml.load(content) || {};
|
|
18
|
+
return getDefaultEnvConfig();
|
|
89
19
|
}
|
|
90
20
|
|
|
91
21
|
/**
|
|
92
|
-
* Load env config
|
|
93
|
-
*
|
|
94
|
-
* @async
|
|
95
|
-
* @function loadEnvConfig
|
|
96
|
-
* @returns {Promise<Object>} Parsed and merged env-config YAML
|
|
97
|
-
* @throws {Error} If base file cannot be read or parsed
|
|
22
|
+
* Load env config for interpolation (same as schema; no external YAML).
|
|
23
|
+
* @returns {Promise<Object>}
|
|
98
24
|
*/
|
|
99
25
|
async function loadEnvConfig() {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
// Load user env-config if configured
|
|
103
|
-
const userConfig = await loadUserEnvConfig();
|
|
104
|
-
|
|
105
|
-
// Merge user config with base (user overrides/extends base)
|
|
106
|
-
return mergeEnvConfigs(baseConfig, userConfig);
|
|
26
|
+
return getDefaultEnvConfig();
|
|
107
27
|
}
|
|
108
28
|
|
|
109
29
|
module.exports = {
|
|
110
30
|
loadEnvConfig,
|
|
111
31
|
loadSchemaEnvConfig
|
|
112
32
|
};
|
|
113
|
-
|
package/lib/utils/env-copy.js
CHANGED
|
@@ -7,12 +7,12 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
'use strict';
|
|
10
|
+
const { formatSuccessLine } = require('./cli-test-layout-chalk');
|
|
10
11
|
|
|
11
12
|
const fs = require('fs');
|
|
12
13
|
const fsp = require('fs').promises;
|
|
13
14
|
const path = require('path');
|
|
14
15
|
const yaml = require('js-yaml');
|
|
15
|
-
const chalk = require('chalk');
|
|
16
16
|
const logger = require('./logger');
|
|
17
17
|
const config = require('../core/config');
|
|
18
18
|
const devConfig = require('../utils/dev-config');
|
|
@@ -58,7 +58,12 @@ function readDeveloperIdFromConfig(config) {
|
|
|
58
58
|
*/
|
|
59
59
|
function substituteMntDataForLocal(content, outputPath) {
|
|
60
60
|
const outputDir = path.dirname(outputPath);
|
|
61
|
-
|
|
61
|
+
// Avoid introducing a drive letter for root-relative paths (e.g. "\tmp\out"),
|
|
62
|
+
// which are common in unit tests and some Windows path constructions.
|
|
63
|
+
const isWinRootRelative = process.platform === 'win32' && /^\\(?!\\)/.test(outputDir);
|
|
64
|
+
const localMountPath = isWinRootRelative
|
|
65
|
+
? path.win32.normalize(path.win32.join(outputDir, 'mount'))
|
|
66
|
+
: path.resolve(outputDir, 'mount');
|
|
62
67
|
if (!fs.existsSync(localMountPath)) {
|
|
63
68
|
fs.mkdirSync(localMountPath, { recursive: true });
|
|
64
69
|
}
|
|
@@ -77,7 +82,10 @@ function resolveEnvOutputPath(rawOutputPath, variablesPath) {
|
|
|
77
82
|
outputPath = rawOutputPath;
|
|
78
83
|
} else {
|
|
79
84
|
const variablesDir = path.dirname(variablesPath);
|
|
80
|
-
|
|
85
|
+
const isWinRootRelative = process.platform === 'win32' && /^\\(?!\\)/.test(variablesDir);
|
|
86
|
+
outputPath = isWinRootRelative
|
|
87
|
+
? path.win32.normalize(path.win32.join(variablesDir, rawOutputPath))
|
|
88
|
+
: path.resolve(variablesDir, rawOutputPath);
|
|
81
89
|
}
|
|
82
90
|
if (!outputPath.endsWith('.env')) {
|
|
83
91
|
if (fs.existsSync(outputPath) && fs.statSync(outputPath).isDirectory()) {
|
|
@@ -105,7 +113,7 @@ async function writeEnvOutputForReload(outputPath, runEnvPath) {
|
|
|
105
113
|
toWrite = mergeEnvMapIntoContent(existingContent, runMap);
|
|
106
114
|
}
|
|
107
115
|
await fsp.writeFile(outputPath, toWrite, { mode: 0o600 });
|
|
108
|
-
logger.log(
|
|
116
|
+
logger.log(formatSuccessLine(`Wrote .env to envOutputPath (same as container, for --reload): ${outputPath}`));
|
|
109
117
|
}
|
|
110
118
|
|
|
111
119
|
/**
|
|
@@ -125,7 +133,7 @@ async function writeEnvOutputForLocal(appName, outputPath) {
|
|
|
125
133
|
toWrite = mergeEnvMapIntoContent(existingContent, localMap);
|
|
126
134
|
}
|
|
127
135
|
await fsp.writeFile(outputPath, toWrite, { mode: 0o600 });
|
|
128
|
-
logger.log(
|
|
136
|
+
logger.log(formatSuccessLine(`Wrote .env to envOutputPath (localPort): ${outputPath}`));
|
|
129
137
|
}
|
|
130
138
|
|
|
131
139
|
/**
|
|
@@ -134,16 +142,17 @@ async function writeEnvOutputForLocal(appName, outputPath) {
|
|
|
134
142
|
* @returns {number} Developer-specific app port
|
|
135
143
|
*/
|
|
136
144
|
function calculateDevAppPort(baseAppPort) {
|
|
145
|
+
const { localHostPort, parseDeveloperIdNum } = require('./declarative-url-ports');
|
|
137
146
|
const devIdRaw = process.env.AIFABRIX_DEVELOPERID;
|
|
138
147
|
let devIdNum = Number.isFinite(parseInt(devIdRaw, 10)) ? parseInt(devIdRaw, 10) : null;
|
|
139
148
|
try {
|
|
140
149
|
if (devIdNum === null) {
|
|
141
|
-
devIdNum = readDeveloperIdFromConfig(config)
|
|
150
|
+
devIdNum = readDeveloperIdFromConfig(config);
|
|
142
151
|
}
|
|
143
152
|
} catch {
|
|
144
|
-
devIdNum =
|
|
153
|
+
devIdNum = null;
|
|
145
154
|
}
|
|
146
|
-
return
|
|
155
|
+
return localHostPort(baseAppPort, parseDeveloperIdNum(devIdNum));
|
|
147
156
|
}
|
|
148
157
|
|
|
149
158
|
/**
|
|
@@ -255,7 +264,7 @@ async function writeLocalEnvToOutputPath(outputPath, appName, secretsPath, envOu
|
|
|
255
264
|
toWrite = mergeEnvMapIntoContent(existingContent, localMap);
|
|
256
265
|
}
|
|
257
266
|
fs.writeFileSync(outputPath, toWrite, { mode: 0o600 });
|
|
258
|
-
logger.log(
|
|
267
|
+
logger.log(formatSuccessLine(`Generated local .env at: ${envOutputPathLabel}`));
|
|
259
268
|
}
|
|
260
269
|
|
|
261
270
|
/**
|
|
@@ -271,7 +280,7 @@ async function writePatchedEnvToOutputPath(envPath, outputPath, variables, envOu
|
|
|
271
280
|
let patchedContent = await patchEnvContentForLocal(envContent, variables);
|
|
272
281
|
patchedContent = substituteMntDataForLocal(patchedContent, outputPath);
|
|
273
282
|
fs.writeFileSync(outputPath, patchedContent, { mode: 0o600 });
|
|
274
|
-
logger.log(
|
|
283
|
+
logger.log(formatSuccessLine(`Copied .env to: ${envOutputPathLabel}`));
|
|
275
284
|
}
|
|
276
285
|
|
|
277
286
|
/**
|
package/lib/utils/env-map.js
CHANGED
|
@@ -292,6 +292,38 @@ function calculateDockerPublicPorts(result, devIdNum, schemaBaseVars = {}) {
|
|
|
292
292
|
}
|
|
293
293
|
}
|
|
294
294
|
|
|
295
|
+
/**
|
|
296
|
+
* Apply *_PUBLIC_PORT from schema env for local or docker context.
|
|
297
|
+
* @param {Object} result - Normalized env map (mutated)
|
|
298
|
+
* @param {'docker'|'local'} context
|
|
299
|
+
* @param {number} devIdNum
|
|
300
|
+
*/
|
|
301
|
+
function applyPublicPortAdjustmentsForContext(result, context, devIdNum) {
|
|
302
|
+
if (context !== 'local' && context !== 'docker') return;
|
|
303
|
+
const schemaCfg = loadSchemaEnvConfig();
|
|
304
|
+
const schemaBaseVars =
|
|
305
|
+
schemaCfg && schemaCfg.environments && schemaCfg.environments[context]
|
|
306
|
+
? schemaCfg.environments[context]
|
|
307
|
+
: {};
|
|
308
|
+
calculateDockerPublicPorts(result, devIdNum, schemaBaseVars);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Set TLS_ENABLED / HTTP_ENABLED from ~/.aifabrix/config.yaml (tlsEnabled).
|
|
313
|
+
* @param {Object} result - Env map (mutated)
|
|
314
|
+
*/
|
|
315
|
+
async function applyTlsHttpManifestFlags(result) {
|
|
316
|
+
let tlsOn = false;
|
|
317
|
+
try {
|
|
318
|
+
const userCfg = await config.getConfig();
|
|
319
|
+
tlsOn = Boolean(userCfg && userCfg.tlsEnabled === true);
|
|
320
|
+
} catch {
|
|
321
|
+
tlsOn = false;
|
|
322
|
+
}
|
|
323
|
+
result.TLS_ENABLED = tlsOn ? 'true' : 'false';
|
|
324
|
+
result.HTTP_ENABLED = tlsOn ? 'false' : 'true';
|
|
325
|
+
}
|
|
326
|
+
|
|
295
327
|
/**
|
|
296
328
|
* Build environment variable map for interpolation based on env-config.yaml
|
|
297
329
|
* - Supports values like "host:port" by splitting into *_HOST (host) and *_PORT (port)
|
|
@@ -300,6 +332,7 @@ function calculateDockerPublicPorts(result, devIdNum, schemaBaseVars = {}) {
|
|
|
300
332
|
* - Applies aifabrix-localhost override for local context if configured
|
|
301
333
|
* - Applies developer-id adjustment to port variables for local context
|
|
302
334
|
* - Calculates *_PUBLIC_PORT for both local and docker context (basePort + developer-id * 100)
|
|
335
|
+
* - Adds TLS_ENABLED and HTTP_ENABLED ("true" / "false"); HTTP_ENABLED = !TLS_ENABLED for manifest ${...} substitution
|
|
303
336
|
* @async
|
|
304
337
|
* @function buildEnvVarMap
|
|
305
338
|
* @param {'docker'|'local'} context - Environment context
|
|
@@ -323,15 +356,9 @@ async function buildEnvVarMap(context, osModule = null, developerId = null, opti
|
|
|
323
356
|
const devIdNum = await getDeveloperIdNumber(developerId);
|
|
324
357
|
if (context === 'local') {
|
|
325
358
|
applyLocalPortAdjustment(result, devIdNum);
|
|
326
|
-
const schemaCfg = loadSchemaEnvConfig();
|
|
327
|
-
const schemaBaseVars = (schemaCfg && schemaCfg.environments && schemaCfg.environments.local) ? schemaCfg.environments.local : {};
|
|
328
|
-
calculateDockerPublicPorts(result, devIdNum, schemaBaseVars);
|
|
329
|
-
} else if (context === 'docker') {
|
|
330
|
-
const schemaCfg = loadSchemaEnvConfig();
|
|
331
|
-
const schemaBaseVars = (schemaCfg && schemaCfg.environments && schemaCfg.environments[context]) ? schemaCfg.environments[context] : {};
|
|
332
|
-
calculateDockerPublicPorts(result, devIdNum, schemaBaseVars);
|
|
333
359
|
}
|
|
334
|
-
|
|
360
|
+
applyPublicPortAdjustmentsForContext(result, context, devIdNum);
|
|
361
|
+
await applyTlsHttpManifestFlags(result);
|
|
335
362
|
return result;
|
|
336
363
|
}
|
|
337
364
|
|
|
@@ -108,7 +108,7 @@ async function updateEnvTemplate(appKey, clientIdKey, clientSecretKey, _controll
|
|
|
108
108
|
const envTemplatePath = path.join(process.cwd(), 'builder', appKey, 'env.template');
|
|
109
109
|
|
|
110
110
|
if (!fsSync.existsSync(envTemplatePath)) {
|
|
111
|
-
logger.warn(chalk.yellow(
|
|
111
|
+
logger.warn(chalk.yellow(`⚠ env.template not found for ${appKey}, skipping update`));
|
|
112
112
|
return;
|
|
113
113
|
}
|
|
114
114
|
|
|
@@ -126,7 +126,7 @@ async function updateEnvTemplate(appKey, clientIdKey, clientSecretKey, _controll
|
|
|
126
126
|
|
|
127
127
|
await fs.writeFile(envTemplatePath, content, 'utf8');
|
|
128
128
|
} catch (error) {
|
|
129
|
-
logger.warn(chalk.yellow(
|
|
129
|
+
logger.warn(chalk.yellow(`⚠ Could not update env.template: ${error.message}`));
|
|
130
130
|
}
|
|
131
131
|
}
|
|
132
132
|
|