@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
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Traefik ingress path/host/TLS and StripPrefix derivation helpers for compose generation.
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Traefik PathPrefix + host expansion (shared with health path resolution)
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 2.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const {
|
|
10
|
+
buildEnvScopedTraefikPath
|
|
11
|
+
} = require('./environment-scoped-resources');
|
|
12
|
+
const { parseDeveloperIdNum } = require('./declarative-url-ports');
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Derives base path from routing pattern by removing trailing wildcards
|
|
16
|
+
* @param {string} pattern - URL pattern (e.g., '/app/*', '/api/v1/*')
|
|
17
|
+
* @returns {string} Base path for routing
|
|
18
|
+
*/
|
|
19
|
+
function derivePathFromPattern(pattern) {
|
|
20
|
+
if (!pattern || typeof pattern !== 'string') {
|
|
21
|
+
return '/';
|
|
22
|
+
}
|
|
23
|
+
const trimmed = pattern.trim();
|
|
24
|
+
if (trimmed === '/' || trimmed === '') {
|
|
25
|
+
return '/';
|
|
26
|
+
}
|
|
27
|
+
const withoutWildcards = trimmed.replace(/\*+$/g, '');
|
|
28
|
+
const withoutTrailingSlashes = withoutWildcards.replace(/\/+$/g, '');
|
|
29
|
+
return withoutTrailingSlashes || '/';
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Resolve Traefik TLS from application.yaml `frontDoorRouting.tls` (boolean or string).
|
|
34
|
+
* String "false" disables TLS; placeholders (e.g. ${TLS_ENABLED}) are treated as enabled.
|
|
35
|
+
* @param {unknown} tls - Raw tls value
|
|
36
|
+
* @returns {boolean}
|
|
37
|
+
*/
|
|
38
|
+
function resolveTraefikTlsEnabled(tls) {
|
|
39
|
+
if (tls === false || tls === 'false') {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Developer label for frontDoorRouting.host only. Id 0 / missing / empty → no subdomain (empty string).
|
|
47
|
+
* Non-zero → dev01, dev02, … (same padding as buildDevUsername).
|
|
48
|
+
*
|
|
49
|
+
* @param {string|number|null|undefined} devId
|
|
50
|
+
* @returns {string}
|
|
51
|
+
*/
|
|
52
|
+
function buildDevUsernameForFrontDoorHost(devId) {
|
|
53
|
+
const n = parseDeveloperIdNum(devId);
|
|
54
|
+
if (n === 0) {
|
|
55
|
+
return '';
|
|
56
|
+
}
|
|
57
|
+
const s = String(n);
|
|
58
|
+
const padded = s.length === 1 ? s.padStart(2, '0') : s;
|
|
59
|
+
return `dev${padded}`;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Expand frontDoorRouting.host placeholders (Traefik labels + url:// base). Same rules as declarative URL resolver.
|
|
64
|
+
* Normalizes ${DEV_USERNAME}${REMOTE_HOST} to insert a dot. Trims stray leading/trailing dots (e.g. id 0 + `.${REMOTE_HOST}` → bare remote hostname).
|
|
65
|
+
*
|
|
66
|
+
* @param {string} template
|
|
67
|
+
* @param {string|number|null|undefined} developerIdRaw
|
|
68
|
+
* @param {string|null|undefined} remoteServer
|
|
69
|
+
* @returns {string}
|
|
70
|
+
*/
|
|
71
|
+
function expandFrontDoorHostPlaceholders(template, developerIdRaw, remoteServer) {
|
|
72
|
+
let t = String(template || '');
|
|
73
|
+
t = t.replace(/\$\{DEV_USERNAME\}\$\{REMOTE_HOST\}/g, '${DEV_USERNAME}.${REMOTE_HOST}');
|
|
74
|
+
const devU = buildDevUsernameForFrontDoorHost(developerIdRaw);
|
|
75
|
+
t = t.replace(/\$\{DEV_USERNAME\}/g, devU);
|
|
76
|
+
let remoteHost = '';
|
|
77
|
+
try {
|
|
78
|
+
if (remoteServer && String(remoteServer).trim()) {
|
|
79
|
+
remoteHost = new URL(String(remoteServer).trim()).hostname;
|
|
80
|
+
}
|
|
81
|
+
} catch {
|
|
82
|
+
remoteHost = '';
|
|
83
|
+
}
|
|
84
|
+
t = t.replace(/\$\{REMOTE_HOST\}/g, remoteHost);
|
|
85
|
+
t = t.replace(/^\.+/g, '').replace(/\.{2,}/g, '.').replace(/\.+$/g, '').trim();
|
|
86
|
+
return t;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Traefik PathPrefix / host / TLS from frontDoorRouting (public ingress). Does not include StripPrefix — that follows
|
|
91
|
+
* the in-container health path: private URL is `http://<service>:<port>` plus the probe path; `/dev`, `/tst`, `/auth`,
|
|
92
|
+
* etc. are public path segments only.
|
|
93
|
+
*
|
|
94
|
+
* @param {Object} config - Application configuration (application.yaml shape)
|
|
95
|
+
* @param {string|number} devId - Developer id for host expansion
|
|
96
|
+
* @param {Object|null} scopeOpts - Env-scoped Traefik path (effectiveEnvironmentScopedResources, runEnvKey)
|
|
97
|
+
* @param {string|null|undefined} remoteServer - For ${REMOTE_HOST}
|
|
98
|
+
* @returns {{ enabled: false } | { enabled: true, host: string, path: string, tls: boolean, certStore: string|null }}
|
|
99
|
+
*/
|
|
100
|
+
function buildTraefikIngressBase(config, devId, scopeOpts, remoteServer) {
|
|
101
|
+
const frontDoor = config.frontDoorRouting;
|
|
102
|
+
if (!frontDoor || frontDoor.enabled !== true) {
|
|
103
|
+
return { enabled: false };
|
|
104
|
+
}
|
|
105
|
+
if (!frontDoor.host || typeof frontDoor.host !== 'string') {
|
|
106
|
+
throw new Error('frontDoorRouting.host is required when frontDoorRouting.enabled is true');
|
|
107
|
+
}
|
|
108
|
+
const host = expandFrontDoorHostPlaceholders(frontDoor.host, devId, remoteServer);
|
|
109
|
+
const basePath = derivePathFromPattern(frontDoor.pattern);
|
|
110
|
+
let pathOut = basePath;
|
|
111
|
+
if (
|
|
112
|
+
scopeOpts &&
|
|
113
|
+
scopeOpts.effectiveEnvironmentScopedResources &&
|
|
114
|
+
scopeOpts.runEnvKey &&
|
|
115
|
+
(scopeOpts.runEnvKey === 'dev' || scopeOpts.runEnvKey === 'tst')
|
|
116
|
+
) {
|
|
117
|
+
pathOut = buildEnvScopedTraefikPath(basePath, scopeOpts.runEnvKey);
|
|
118
|
+
}
|
|
119
|
+
return {
|
|
120
|
+
enabled: true,
|
|
121
|
+
host,
|
|
122
|
+
path: pathOut,
|
|
123
|
+
tls: resolveTraefikTlsEnabled(frontDoor.tls),
|
|
124
|
+
certStore: frontDoor.certStore || null
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Whether Traefik should apply StripPrefix so the backend sees the same path as the Docker health probe.
|
|
130
|
+
* When the resolved compose health path already lies under the public PathPrefix (e.g. /auth/health/ready), forward
|
|
131
|
+
* the full path. When the probe is root-only (e.g. /health) but PathPrefix is /miso, strip the prefix.
|
|
132
|
+
*
|
|
133
|
+
* @param {string} traefikPath - PathPrefix value (slashes normalized, no trailing slash except '/')
|
|
134
|
+
* @param {string} resolvedHealthPath - Output of resolveHealthCheckPathWithFrontDoorVdir with compose opts
|
|
135
|
+
* @returns {boolean} true when StripPrefix middleware labels should be emitted
|
|
136
|
+
*/
|
|
137
|
+
function computeTraefikStripPathPrefix(traefikPath, resolvedHealthPath) {
|
|
138
|
+
const healthRaw = String(resolvedHealthPath || '/').trim();
|
|
139
|
+
const health = healthRaw.replace(/\/+$/, '') || '/';
|
|
140
|
+
const prefixRaw = String(traefikPath || '/').trim();
|
|
141
|
+
const prefix = prefixRaw.replace(/\/+$/, '') || '/';
|
|
142
|
+
if (prefix === '/' || prefix === '') {
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
if (health === prefix || health.startsWith(`${prefix}/`)) {
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
module.exports = {
|
|
152
|
+
derivePathFromPattern,
|
|
153
|
+
resolveTraefikTlsEnabled,
|
|
154
|
+
buildDevUsernameForFrontDoorHost,
|
|
155
|
+
expandFrontDoorHostPlaceholders,
|
|
156
|
+
buildTraefikIngressBase,
|
|
157
|
+
computeTraefikStripPathPrefix
|
|
158
|
+
};
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* @version 2.0.0
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
+
const fs = require('fs');
|
|
11
12
|
const path = require('path');
|
|
12
13
|
|
|
13
14
|
/**
|
|
@@ -21,6 +22,7 @@ const SETTINGS_RESPONSE_KEYS = [
|
|
|
21
22
|
'aifabrix-env-config',
|
|
22
23
|
'remote-server',
|
|
23
24
|
'docker-endpoint',
|
|
25
|
+
'docker-tls-skip-verify',
|
|
24
26
|
'sync-ssh-user',
|
|
25
27
|
'sync-ssh-host'
|
|
26
28
|
];
|
|
@@ -85,6 +87,27 @@ function createHomeAndSecretsPathFunctions(getConfigFn, saveConfigFn) {
|
|
|
85
87
|
}
|
|
86
88
|
await setPathConfig(getConfigFn, saveConfigFn, 'aifabrix-home', trimmed, 'Home path must be a non-empty string');
|
|
87
89
|
},
|
|
90
|
+
async getAifabrixWorkOverride() {
|
|
91
|
+
return getPathConfig(getConfigFn, 'aifabrix-work');
|
|
92
|
+
},
|
|
93
|
+
async setAifabrixWorkOverride(workPath) {
|
|
94
|
+
if (typeof workPath !== 'string') {
|
|
95
|
+
throw new Error('Work path is required and must be a string');
|
|
96
|
+
}
|
|
97
|
+
const trimmed = workPath.trim();
|
|
98
|
+
if (trimmed === '') {
|
|
99
|
+
await clearPathConfig(getConfigFn, saveConfigFn, 'aifabrix-work');
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
const resolved = path.resolve(trimmed);
|
|
103
|
+
await setPathConfig(
|
|
104
|
+
getConfigFn,
|
|
105
|
+
saveConfigFn,
|
|
106
|
+
'aifabrix-work',
|
|
107
|
+
resolved,
|
|
108
|
+
'Work path must be a non-empty string'
|
|
109
|
+
);
|
|
110
|
+
},
|
|
88
111
|
async getAifabrixSecretsPath() {
|
|
89
112
|
return getPathConfig(getConfigFn, 'aifabrix-secrets');
|
|
90
113
|
},
|
|
@@ -102,16 +125,60 @@ function createHomeAndSecretsPathFunctions(getConfigFn, saveConfigFn) {
|
|
|
102
125
|
};
|
|
103
126
|
}
|
|
104
127
|
|
|
105
|
-
/**
|
|
106
|
-
|
|
107
|
-
|
|
128
|
+
/**
|
|
129
|
+
* Resolve configured `aifabrix-env-config` to an absolute path.
|
|
130
|
+
* Relative paths are resolved against the workspace root first: `aifabrix-work` from the same config,
|
|
131
|
+
* then {@link module:lib/utils/paths.getAifabrixWork} (env `AIFABRIX_WORK` + on-disk yaml). If neither
|
|
132
|
+
* is set, falls back to `aifabrix-home` from config, then {@link module:lib/utils/paths.getAifabrixHome}.
|
|
133
|
+
* Never uses the process current working directory alone as the anchor.
|
|
134
|
+
*
|
|
135
|
+
* @async
|
|
136
|
+
* @param {string} raw - Non-empty path string from config (may be relative)
|
|
137
|
+
* @param {Function} getConfigFn - Async config loader
|
|
138
|
+
* @returns {Promise<string>} Normalized absolute path
|
|
139
|
+
*/
|
|
140
|
+
async function resolveEnvConfigPathToAbsolute(raw, getConfigFn) {
|
|
141
|
+
const trimmed = String(raw || '').trim();
|
|
142
|
+
if (!trimmed) {
|
|
143
|
+
throw new Error('Env config path must be a non-empty string');
|
|
144
|
+
}
|
|
145
|
+
if (path.isAbsolute(trimmed)) {
|
|
146
|
+
return path.normalize(path.resolve(trimmed));
|
|
147
|
+
}
|
|
148
|
+
const pathsMod = require('./paths');
|
|
149
|
+
|
|
150
|
+
const workFromConfig = await getPathConfig(getConfigFn, 'aifabrix-work');
|
|
151
|
+
let workBase =
|
|
152
|
+
workFromConfig && String(workFromConfig).trim() !== ''
|
|
153
|
+
? path.resolve(String(workFromConfig).trim())
|
|
154
|
+
: null;
|
|
155
|
+
if (!workBase) {
|
|
156
|
+
workBase = pathsMod.getAifabrixWork();
|
|
157
|
+
}
|
|
158
|
+
if (workBase && String(workBase).trim() !== '') {
|
|
159
|
+
return path.normalize(path.resolve(String(workBase).trim(), trimmed));
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const homeFromConfig = await getPathConfig(getConfigFn, 'aifabrix-home');
|
|
163
|
+
const base =
|
|
164
|
+
homeFromConfig && String(homeFromConfig).trim() !== ''
|
|
165
|
+
? path.resolve(String(homeFromConfig).trim())
|
|
166
|
+
: pathsMod.getAifabrixHome();
|
|
167
|
+
return path.normalize(path.resolve(base, trimmed));
|
|
108
168
|
}
|
|
109
169
|
|
|
110
170
|
function createEnvConfigPathFunctions(getConfigFn, saveConfigFn) {
|
|
111
171
|
return {
|
|
172
|
+
/**
|
|
173
|
+
* Legacy `aifabrix-env-config` path when still set in config (infra defaults are in code).
|
|
174
|
+
* @returns {Promise<string|null>}
|
|
175
|
+
*/
|
|
112
176
|
async getAifabrixEnvConfigPath() {
|
|
113
177
|
const value = await getPathConfig(getConfigFn, 'aifabrix-env-config');
|
|
114
|
-
|
|
178
|
+
if (!value || typeof value !== 'string') {
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
return resolveEnvConfigPathToAbsolute(value, getConfigFn);
|
|
115
182
|
},
|
|
116
183
|
async setAifabrixEnvConfigPath(envConfigPath) {
|
|
117
184
|
if (typeof envConfigPath !== 'string') {
|
|
@@ -126,11 +193,64 @@ function createEnvConfigPathFunctions(getConfigFn, saveConfigFn) {
|
|
|
126
193
|
},
|
|
127
194
|
async getAifabrixBuilderDir() {
|
|
128
195
|
const envConfigPath = await getPathConfig(getConfigFn, 'aifabrix-env-config');
|
|
129
|
-
|
|
196
|
+
if (envConfigPath && typeof envConfigPath === 'string') {
|
|
197
|
+
const absolute = await resolveEnvConfigPathToAbsolute(envConfigPath.trim(), getConfigFn);
|
|
198
|
+
return path.dirname(absolute);
|
|
199
|
+
}
|
|
200
|
+
const pathsMod = require('./paths');
|
|
201
|
+
const tryDir = (base) => {
|
|
202
|
+
if (!base) {
|
|
203
|
+
return null;
|
|
204
|
+
}
|
|
205
|
+
const b = path.join(base, 'builder');
|
|
206
|
+
try {
|
|
207
|
+
if (fs.existsSync(b) && fs.statSync(b).isDirectory()) {
|
|
208
|
+
return b;
|
|
209
|
+
}
|
|
210
|
+
} catch {
|
|
211
|
+
/* ignore */
|
|
212
|
+
}
|
|
213
|
+
return null;
|
|
214
|
+
};
|
|
215
|
+
const fromProject = tryDir(pathsMod.getProjectRoot());
|
|
216
|
+
if (fromProject) {
|
|
217
|
+
return fromProject;
|
|
218
|
+
}
|
|
219
|
+
const work = pathsMod.getAifabrixWork();
|
|
220
|
+
return tryDir(work);
|
|
130
221
|
}
|
|
131
222
|
};
|
|
132
223
|
}
|
|
133
224
|
|
|
225
|
+
/**
|
|
226
|
+
* Whether remote Docker TLS should skip server certificate verification (dev / self-signed daemon).
|
|
227
|
+
* Env AIFABRIX_DOCKER_TLS_SKIP_VERIFY=1|true forces skip when set.
|
|
228
|
+
* @param {*} raw - Config or settings value
|
|
229
|
+
* @returns {boolean}
|
|
230
|
+
*/
|
|
231
|
+
function isDockerTlsSkipVerifyTruthy(raw) {
|
|
232
|
+
if (raw === true || raw === 1) return true;
|
|
233
|
+
if (typeof raw === 'string') {
|
|
234
|
+
const s = raw.trim().toLowerCase();
|
|
235
|
+
return s === 'true' || s === '1' || s === 'yes';
|
|
236
|
+
}
|
|
237
|
+
return false;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Explicit opt-out of TLS verify skip in config (docker-tls-skip-verify: false).
|
|
242
|
+
* @param {*} raw - Config value
|
|
243
|
+
* @returns {boolean}
|
|
244
|
+
*/
|
|
245
|
+
function isDockerTlsSkipVerifyExplicitlyFalse(raw) {
|
|
246
|
+
if (raw === false) return true;
|
|
247
|
+
if (typeof raw === 'string') {
|
|
248
|
+
const s = raw.trim().toLowerCase();
|
|
249
|
+
return s === 'false' || s === '0' || s === 'no';
|
|
250
|
+
}
|
|
251
|
+
return false;
|
|
252
|
+
}
|
|
253
|
+
|
|
134
254
|
function createRemoteConfigGetters(getConfigFn) {
|
|
135
255
|
return {
|
|
136
256
|
async getRemoteServer() {
|
|
@@ -139,6 +259,25 @@ function createRemoteConfigGetters(getConfigFn) {
|
|
|
139
259
|
async getDockerEndpoint() {
|
|
140
260
|
return getPathConfig(getConfigFn, 'docker-endpoint');
|
|
141
261
|
},
|
|
262
|
+
/**
|
|
263
|
+
* When true, Docker CLI may use DOCKER_TLS_VERIFY=0 only when ca.pem is absent (no trust anchor).
|
|
264
|
+
* If ca.pem exists (e.g. after issue-cert), the daemon is always verified regardless of this flag.
|
|
265
|
+
*/
|
|
266
|
+
async getDockerTlsSkipVerify() {
|
|
267
|
+
const envRaw = process.env.AIFABRIX_DOCKER_TLS_SKIP_VERIFY;
|
|
268
|
+
if (envRaw !== undefined && String(envRaw).trim() !== '') {
|
|
269
|
+
return isDockerTlsSkipVerifyTruthy(String(envRaw).trim());
|
|
270
|
+
}
|
|
271
|
+
const config = await getConfigFn();
|
|
272
|
+
const flag = config['docker-tls-skip-verify'];
|
|
273
|
+
if (isDockerTlsSkipVerifyExplicitlyFalse(flag)) {
|
|
274
|
+
return false;
|
|
275
|
+
}
|
|
276
|
+
if (isDockerTlsSkipVerifyTruthy(flag)) {
|
|
277
|
+
return true;
|
|
278
|
+
}
|
|
279
|
+
return false;
|
|
280
|
+
},
|
|
142
281
|
async getUserMutagenFolder() {
|
|
143
282
|
return getPathConfig(getConfigFn, 'user-mutagen-folder');
|
|
144
283
|
},
|
|
@@ -168,6 +307,24 @@ function createRemoteConfigSetters(getConfigFn, saveConfigFn) {
|
|
|
168
307
|
const config = await getConfigFn();
|
|
169
308
|
config['docker-endpoint'] = value || undefined;
|
|
170
309
|
await saveConfigFn(config);
|
|
310
|
+
},
|
|
311
|
+
async setDockerTlsSkipVerify(value) {
|
|
312
|
+
const config = await getConfigFn();
|
|
313
|
+
if (value === null || value === undefined) {
|
|
314
|
+
config['docker-tls-skip-verify'] = undefined;
|
|
315
|
+
} else if (typeof value === 'boolean') {
|
|
316
|
+
config['docker-tls-skip-verify'] = value;
|
|
317
|
+
} else if (typeof value === 'string') {
|
|
318
|
+
const s = value.trim().toLowerCase();
|
|
319
|
+
if (s === '' || s === 'false' || s === '0' || s === 'no') {
|
|
320
|
+
config['docker-tls-skip-verify'] = false;
|
|
321
|
+
} else {
|
|
322
|
+
config['docker-tls-skip-verify'] = isDockerTlsSkipVerifyTruthy(value);
|
|
323
|
+
}
|
|
324
|
+
} else {
|
|
325
|
+
throw new Error('docker-tls-skip-verify must be a boolean or string');
|
|
326
|
+
}
|
|
327
|
+
await saveConfigFn(config);
|
|
171
328
|
}
|
|
172
329
|
};
|
|
173
330
|
}
|
|
@@ -198,7 +355,8 @@ function applySecretsUrlFromRemote(config) {
|
|
|
198
355
|
const secretsPath = config['aifabrix-secrets'];
|
|
199
356
|
if (!remoteServer || !secretsPath || isHttpUrl(secretsPath)) return;
|
|
200
357
|
const base = typeof remoteServer === 'string' ? remoteServer.trim().replace(/\/+$/, '') : '';
|
|
201
|
-
if (base)
|
|
358
|
+
if (!base) return;
|
|
359
|
+
config['aifabrix-secrets'] = `${base}/api/dev/secrets`;
|
|
202
360
|
}
|
|
203
361
|
|
|
204
362
|
function applySyncAndDockerFromHost(config) {
|
|
@@ -211,6 +369,7 @@ function applySyncAndDockerFromHost(config) {
|
|
|
211
369
|
async function mergeRemoteSettingsImpl(getConfigFn, saveConfigFn, settings) {
|
|
212
370
|
if (!settings || typeof settings !== 'object') return;
|
|
213
371
|
const config = await getConfigFn();
|
|
372
|
+
delete config['aifabrix-secrets-path'];
|
|
214
373
|
for (const key of SETTINGS_RESPONSE_KEYS) {
|
|
215
374
|
const raw = settings[key];
|
|
216
375
|
if (raw === undefined || raw === null) continue;
|
|
@@ -257,7 +416,7 @@ module.exports = {
|
|
|
257
416
|
getPathConfig,
|
|
258
417
|
setPathConfig,
|
|
259
418
|
createPathConfigFunctions,
|
|
260
|
-
|
|
419
|
+
resolveEnvConfigPathToAbsolute,
|
|
261
420
|
SETTINGS_RESPONSE_KEYS
|
|
262
421
|
};
|
|
263
422
|
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* User preference: useEnvironmentScopedResources in ~/.aifabrix/config.yaml
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Gate for environment-scoped resource resolution (plan 117)
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @param {Function} getConfigFn - async () => config object
|
|
13
|
+
* @param {Function} saveConfigFn - async (config) => void
|
|
14
|
+
* @returns {{ getUseEnvironmentScopedResources: Function, setUseEnvironmentScopedResources: Function }}
|
|
15
|
+
*/
|
|
16
|
+
function createScopedResourcesPreferenceFunctions(getConfigFn, saveConfigFn) {
|
|
17
|
+
return {
|
|
18
|
+
/**
|
|
19
|
+
* @returns {Promise<boolean>}
|
|
20
|
+
*/
|
|
21
|
+
async getUseEnvironmentScopedResources() {
|
|
22
|
+
const cfg = await getConfigFn();
|
|
23
|
+
return Boolean(cfg.useEnvironmentScopedResources);
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @param {boolean} value - Activate (true) or passivate (false) user gate
|
|
28
|
+
* @returns {Promise<void>}
|
|
29
|
+
*/
|
|
30
|
+
async setUseEnvironmentScopedResources(value) {
|
|
31
|
+
if (typeof value !== 'boolean') {
|
|
32
|
+
throw new Error('useEnvironmentScopedResources must be a boolean');
|
|
33
|
+
}
|
|
34
|
+
const cfg = await getConfigFn();
|
|
35
|
+
cfg.useEnvironmentScopedResources = value;
|
|
36
|
+
await saveConfigFn(cfg);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
module.exports = { createScopedResourcesPreferenceFunctions };
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interprets deployToController / poll result for CLI messaging (status, errors).
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Controller pipeline deployment outcome parsing
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 2.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @typedef {Object} ControllerDeploymentOutcome
|
|
11
|
+
* @property {boolean} ok - False only for terminal failure-like statuses from controller
|
|
12
|
+
* @property {string|null} statusLabel - Raw status string when present
|
|
13
|
+
* @property {string|null} message - Optional deployment message from API
|
|
14
|
+
* @property {string|null} error - Optional error string from API
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @param {unknown} value - Candidate string field
|
|
19
|
+
* @returns {string|null} Trimmed non-empty string or null
|
|
20
|
+
*/
|
|
21
|
+
function nonEmptyTrimmed(value) {
|
|
22
|
+
if (value === undefined || value === null) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
const t = String(value).trim();
|
|
26
|
+
return t ? t : null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @param {Object} block - status object from API
|
|
31
|
+
* @returns {string|null}
|
|
32
|
+
*/
|
|
33
|
+
function resolveRawStatusLabel(block) {
|
|
34
|
+
if (typeof block.status === 'string') {
|
|
35
|
+
return block.status;
|
|
36
|
+
}
|
|
37
|
+
if (typeof block.deploymentStatus === 'string') {
|
|
38
|
+
return block.deploymentStatus;
|
|
39
|
+
}
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @param {Object|null|undefined} result - deployToController return value
|
|
45
|
+
* @returns {ControllerDeploymentOutcome}
|
|
46
|
+
*/
|
|
47
|
+
function parseControllerDeploymentOutcome(result) {
|
|
48
|
+
const block = result && result.status && typeof result.status === 'object' ? result.status : null;
|
|
49
|
+
if (!block) {
|
|
50
|
+
return { ok: true, statusLabel: null, message: null, error: null };
|
|
51
|
+
}
|
|
52
|
+
const raw = resolveRawStatusLabel(block);
|
|
53
|
+
const message = nonEmptyTrimmed(block.message);
|
|
54
|
+
const error = nonEmptyTrimmed(block.error);
|
|
55
|
+
if (!raw) {
|
|
56
|
+
return { ok: true, statusLabel: null, message, error };
|
|
57
|
+
}
|
|
58
|
+
const s = raw.toLowerCase();
|
|
59
|
+
const failed = s === 'failed' || s === 'cancelled' || s === 'error';
|
|
60
|
+
return {
|
|
61
|
+
ok: !failed,
|
|
62
|
+
statusLabel: raw,
|
|
63
|
+
message,
|
|
64
|
+
error
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
module.exports = { parseControllerDeploymentOutcome };
|
|
@@ -11,9 +11,9 @@ const chalk = require('chalk');
|
|
|
11
11
|
|
|
12
12
|
/** @type {{ verified: string, pending: string, failed: string, expired: string }} */
|
|
13
13
|
const STATUS_ICONS = {
|
|
14
|
-
verified: '
|
|
14
|
+
verified: ' ✔',
|
|
15
15
|
pending: ' ○',
|
|
16
|
-
failed: '
|
|
16
|
+
failed: ' ✖',
|
|
17
17
|
expired: ' ⊘'
|
|
18
18
|
};
|
|
19
19
|
|
|
@@ -7,19 +7,20 @@
|
|
|
7
7
|
* @version 2.0.0
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
const chalk = require('chalk');
|
|
11
10
|
const logger = require('./logger');
|
|
11
|
+
const { metadata } = require('./cli-test-layout-chalk');
|
|
12
12
|
|
|
13
13
|
/** Message shown when CLI is about to call Dataplane pipeline upload or publish APIs. */
|
|
14
14
|
const DATAPLANE_PIPELINE_WARNING =
|
|
15
15
|
'Configuration will be sent to the Dataplane pipeline API. Ensure you are targeting the correct environment and have the required permissions.';
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
|
-
* Log the Dataplane pipeline
|
|
18
|
+
* Log the Dataplane pipeline notice (non-warning) to the console.
|
|
19
19
|
* Call before uploadApplicationViaPipeline or publishDatasourceViaPipeline.
|
|
20
20
|
*/
|
|
21
21
|
function logDataplanePipelineWarning() {
|
|
22
|
-
|
|
22
|
+
// Informational: this is expected behavior for upload/publish flows.
|
|
23
|
+
logger.log(metadata(`Dataplane pipeline: ${DATAPLANE_PIPELINE_WARNING}`));
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
module.exports = {
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Single-capability CLI contract when --capability is set.
|
|
3
|
+
* @author AI Fabrix Team
|
|
4
|
+
* @version 2.0.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @param {Object|null|undefined} envelope - DatasourceTestRun-like
|
|
9
|
+
* @param {string|undefined|null} requestedCapabilityKey - From CLI --capability
|
|
10
|
+
* @returns {{ violated: boolean, message?: string, count?: number }}
|
|
11
|
+
*/
|
|
12
|
+
function analyzeCapabilityScope(envelope, requestedCapabilityKey) {
|
|
13
|
+
const key =
|
|
14
|
+
requestedCapabilityKey !== undefined &&
|
|
15
|
+
requestedCapabilityKey !== null &&
|
|
16
|
+
String(requestedCapabilityKey).trim() !== ''
|
|
17
|
+
? String(requestedCapabilityKey).trim()
|
|
18
|
+
: '';
|
|
19
|
+
if (!key) {
|
|
20
|
+
return { violated: false };
|
|
21
|
+
}
|
|
22
|
+
const caps =
|
|
23
|
+
envelope && typeof envelope === 'object' && Array.isArray(envelope.capabilities)
|
|
24
|
+
? envelope.capabilities
|
|
25
|
+
: [];
|
|
26
|
+
if (caps.length <= 1) {
|
|
27
|
+
return { violated: false };
|
|
28
|
+
}
|
|
29
|
+
const keys = caps.map(c =>
|
|
30
|
+
c && c.key !== undefined && c.key !== null ? String(c.key) : '?'
|
|
31
|
+
);
|
|
32
|
+
const preview = keys.slice(0, 8).join(', ');
|
|
33
|
+
const suffix = keys.length > 8 ? ', …' : '';
|
|
34
|
+
return {
|
|
35
|
+
violated: true,
|
|
36
|
+
count: caps.length,
|
|
37
|
+
message: `Capabilities scope: with --capability "${key}", expected a single row in capabilities[]; server returned ${caps.length} (${preview}${suffix}).`
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
module.exports = {
|
|
42
|
+
analyzeCapabilityScope
|
|
43
|
+
};
|