@aifabrix/builder 2.42.1 → 2.44.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.cursor/rules/anchor-docs.mdc +15 -0
- package/README.md +2 -2
- package/anchor-docs/README.md +10 -0
- package/anchor-docs/_TEMPLATE +24 -0
- package/bin/aifabrix.js +13 -4
- package/integration/hubspot-test/README.md +157 -0
- package/integration/{hubspot → hubspot-test}/application.json +6 -6
- package/integration/{hubspot → hubspot-test}/create-hubspot.js +10 -10
- package/integration/hubspot-test/env.template +4 -0
- package/integration/hubspot-test/hubspot-test-datasource-company.json +138 -0
- package/integration/hubspot-test/hubspot-test-datasource-contact.json +146 -0
- package/integration/hubspot-test/hubspot-test-datasource-deal.json +146 -0
- package/integration/hubspot-test/hubspot-test-datasource-users.json +76 -0
- package/integration/{hubspot/hubspot-deploy.json → hubspot-test/hubspot-test-deploy.json} +201 -24
- package/integration/{hubspot/hubspot-system.json → hubspot-test/hubspot-test-system.json} +8 -7
- package/integration/hubspot-test/rbac.json +166 -0
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-hubspot-credential-real.yaml +3 -3
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-hubspot-env-vars.yaml +2 -2
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-add-datasource.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-credential-create.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-credential-select.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-known-platform.yaml +1 -1
- package/integration/hubspot-test/test-artifacts/wizard-invalid-missing-source.yaml +2 -0
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-mode.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-openapi-file.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-openapi-url.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-source.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-valid-for-dimension-array-test.yaml +1 -1
- package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-key-test.yaml +5 -0
- package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-path-test.yaml +5 -0
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-valid-for-dimension-test.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-valid-for-rbac-test.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-valid-for-rbac-yaml-test.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-dataplane-down-tests.js +1 -7
- package/integration/{hubspot → hubspot-test}/test-dataplane-down.js +3 -3
- package/integration/{hubspot → hubspot-test}/test.js +137 -102
- package/integration/{hubspot → hubspot-test}/wizard-hubspot-e2e.yaml +2 -2
- package/integration/{hubspot → hubspot-test}/wizard-hubspot-platform.yaml +1 -1
- package/integration/hubspot-test/wizard-hubspot-test-headless.yaml +23 -0
- package/integration/roundtrip-test-local/README.md +144 -0
- package/integration/roundtrip-test-local/application.yaml +13 -0
- package/integration/roundtrip-test-local/env.template +15 -0
- package/integration/roundtrip-test-local/roundtrip-test-local-datasource-roundtrip-test-company.yaml +14 -0
- package/integration/roundtrip-test-local/roundtrip-test-local-deploy.json +61 -0
- package/integration/roundtrip-test-local/roundtrip-test-local-system.yaml +25 -0
- package/integration/roundtrip-test-local2/README.md +144 -0
- package/integration/roundtrip-test-local2/application.yaml +13 -0
- package/integration/roundtrip-test-local2/env.template +15 -0
- package/integration/roundtrip-test-local2/roundtrip-test-local2-datasource-company.yaml +31 -0
- package/integration/roundtrip-test-local2/roundtrip-test-local2-deploy.json +86 -0
- package/integration/roundtrip-test-local2/roundtrip-test-local2-system.yaml +25 -0
- package/integration/test/wizard.yaml +8 -0
- package/jest.config.default.js +10 -0
- package/jest.config.integration.fixtures.js +22 -0
- package/jest.config.integration.js +21 -18
- package/jest.config.isolated.js +10 -0
- package/jest.projects.js +288 -0
- package/lib/api/datasources-core.api.js +3 -3
- package/lib/api/dev-mtls-request.js +110 -0
- package/lib/api/dev-server-https.js +145 -0
- package/lib/api/dev.api.js +133 -144
- package/lib/api/index.js +0 -1
- package/lib/api/pipeline.api.js +67 -20
- package/lib/api/service-users.api.js +111 -2
- package/lib/api/types/dev.types.js +4 -3
- package/lib/api/types/pipeline.types.js +8 -5
- package/lib/api/types/service-users.types.js +41 -0
- package/lib/api/types/validation-run.types.js +56 -0
- package/lib/api/validation-run.api.js +99 -0
- package/lib/api/validation-runner.js +99 -0
- package/lib/app/config.js +1 -1
- package/lib/app/deploy-status-display.js +2 -2
- package/lib/app/deploy.js +7 -6
- package/lib/app/display.js +2 -1
- package/lib/app/dockerfile.js +3 -2
- package/lib/app/down.js +2 -1
- package/lib/app/helpers.js +6 -5
- package/lib/app/index.js +27 -8
- package/lib/app/list.js +7 -6
- package/lib/app/push.js +4 -3
- package/lib/app/register.js +19 -8
- package/lib/app/rotate-secret.js +17 -13
- package/lib/app/run-container-start.js +184 -0
- package/lib/app/run-docker-fallback.js +108 -0
- package/lib/app/run-env-compose.js +30 -42
- package/lib/app/run-helpers.js +49 -126
- package/lib/app/run-infra-requirements.js +30 -0
- package/lib/app/run-resolve-image.js +21 -0
- package/lib/app/run.js +74 -21
- package/lib/app/show-display.js +1 -1
- package/lib/app/show.js +1 -1
- package/lib/build/index.js +13 -10
- package/lib/cli/index.js +2 -0
- package/lib/cli/setup-app.help.js +67 -0
- package/lib/cli/setup-app.js +59 -123
- package/lib/cli/setup-app.test-commands.js +179 -0
- package/lib/cli/setup-auth.js +36 -14
- package/lib/cli/setup-credential-deployment.js +22 -8
- package/lib/cli/setup-dev-path-commands.js +124 -0
- package/lib/cli/setup-dev.js +190 -103
- package/lib/cli/setup-environment.js +11 -20
- package/lib/cli/setup-external-system.js +62 -22
- package/lib/cli/setup-infra.js +139 -47
- package/lib/cli/setup-parameters.js +32 -0
- package/lib/cli/setup-secrets.js +147 -10
- package/lib/cli/setup-service-user.js +146 -20
- package/lib/cli/setup-utility.js +47 -19
- package/lib/commands/app-down.js +5 -7
- package/lib/commands/app-install.js +14 -7
- package/lib/commands/app-logs.js +13 -10
- package/lib/commands/app-shell.js +4 -1
- package/lib/commands/app-test.js +25 -19
- package/lib/commands/app.js +22 -10
- package/lib/commands/auth-config.js +10 -14
- package/lib/commands/auth-status.js +4 -3
- package/lib/commands/credential-env.js +4 -3
- package/lib/commands/credential-list.js +5 -4
- package/lib/commands/credential-push.js +4 -3
- package/lib/commands/datasource-unified-test-cli.js +495 -0
- package/lib/commands/datasource-unified-test-cli.options.js +149 -0
- package/lib/commands/datasource-validation-cli.js +129 -0
- package/lib/commands/datasource.js +123 -71
- package/lib/commands/deployment-list.js +6 -5
- package/lib/commands/dev-cli-handlers.js +122 -18
- package/lib/commands/dev-down.js +4 -3
- package/lib/commands/dev-init.js +231 -116
- package/lib/commands/dev-show-display.js +473 -0
- package/lib/commands/login-credentials.js +3 -2
- package/lib/commands/login-device.js +4 -3
- package/lib/commands/login.js +5 -4
- package/lib/commands/logout.js +8 -7
- package/lib/commands/parameters-validate.js +54 -0
- package/lib/commands/repair-datasource.js +314 -68
- package/lib/commands/repair-env-template.js +16 -10
- package/lib/commands/repair-rbac.js +25 -19
- package/lib/commands/repair.js +116 -32
- package/lib/commands/secrets-list.js +23 -12
- package/lib/commands/secrets-remove-all.js +220 -0
- package/lib/commands/secrets-remove.js +22 -13
- package/lib/commands/secrets-set.js +21 -12
- package/lib/commands/secrets-validate.js +20 -7
- package/lib/commands/secure.js +10 -9
- package/lib/commands/service-user.js +243 -13
- package/lib/commands/test-e2e-external.js +27 -1
- package/lib/commands/up-common.js +28 -2
- package/lib/commands/up-dataplane.js +31 -18
- package/lib/commands/up-miso.js +19 -29
- package/lib/commands/upload.js +138 -39
- package/lib/commands/wizard-core-helpers.js +1 -1
- package/lib/commands/wizard-dataplane.js +4 -3
- package/lib/commands/wizard-helpers.js +3 -3
- package/lib/commands/wizard.js +2 -2
- package/lib/core/admin-secrets.js +16 -5
- package/lib/core/audit-logger.js +12 -4
- package/lib/core/config-attach-extensions.js +46 -0
- package/lib/core/config-runtime-paths.js +29 -0
- package/lib/core/config.js +59 -58
- package/lib/core/diff.js +3 -2
- package/lib/core/ensure-encryption-key.js +2 -4
- package/lib/core/secrets-ensure-infra.js +77 -0
- package/lib/core/secrets-ensure.js +120 -64
- package/lib/core/secrets-env-write.js +35 -7
- package/lib/core/secrets-infra-placeholder-sync.js +61 -0
- package/lib/core/secrets.js +228 -42
- package/lib/core/templates-env.js +4 -3
- package/lib/core/templates.js +1 -1
- package/lib/datasource/abac-validator.js +148 -0
- package/lib/datasource/deploy.js +75 -53
- package/lib/datasource/field-reference-validator.js +77 -36
- package/lib/datasource/integration-context.js +63 -0
- package/lib/datasource/list.js +8 -7
- package/lib/datasource/log-viewer.js +252 -0
- package/lib/datasource/resolve-app.js +109 -0
- package/lib/datasource/test-e2e.js +95 -155
- package/lib/datasource/test-integration.js +121 -109
- package/lib/datasource/unified-validation-run-body.js +65 -0
- package/lib/datasource/unified-validation-run-post.js +23 -0
- package/lib/datasource/unified-validation-run-resolve.js +43 -0
- package/lib/datasource/unified-validation-run.js +92 -0
- package/lib/datasource/validate.js +162 -15
- package/lib/deployment/deployer.js +4 -3
- package/lib/deployment/environment.js +7 -6
- package/lib/deployment/push.js +17 -8
- package/lib/external-system/delete.js +4 -3
- package/lib/external-system/deploy.js +131 -53
- package/lib/external-system/download-helpers.js +1 -1
- package/lib/external-system/download.js +7 -6
- package/lib/external-system/generator.js +104 -14
- package/lib/external-system/integration-test-dispatch.js +26 -0
- package/lib/external-system/test-execution.js +5 -1
- package/lib/external-system/test-helpers.js +0 -4
- package/lib/external-system/test-system-level-helpers.js +110 -0
- package/lib/external-system/test-system-level.js +83 -44
- package/lib/external-system/test.js +59 -8
- package/lib/generator/builders.js +23 -11
- package/lib/generator/deploy-manifest-azure-kv.js +81 -0
- package/lib/generator/external-controller-manifest.js +3 -3
- package/lib/generator/external.js +23 -11
- package/lib/generator/helpers.js +71 -12
- package/lib/generator/index.js +8 -4
- package/lib/generator/split-readme.js +12 -7
- package/lib/generator/split-variables.js +2 -1
- package/lib/generator/split.js +46 -11
- package/lib/generator/wizard-readme.js +3 -3
- package/lib/generator/wizard.js +16 -13
- package/lib/infrastructure/compose.js +60 -6
- package/lib/infrastructure/helpers.js +238 -51
- package/lib/infrastructure/index.js +64 -37
- package/lib/infrastructure/services.js +21 -15
- package/lib/internal/fs-real-sync.js +104 -0
- package/lib/internal/node-fs.js +98 -0
- package/lib/parameters/database-secret-values.js +173 -0
- package/lib/parameters/infra-kv-discovery.js +121 -0
- package/lib/parameters/infra-parameter-catalog.js +458 -0
- package/lib/parameters/infra-parameter-validate.js +64 -0
- package/lib/schema/application-schema.json +37 -17
- package/lib/schema/datasource-test-run.schema.json +493 -0
- package/lib/schema/deployment-rules.yaml +102 -63
- package/lib/schema/external-datasource.schema.json +1201 -433
- package/lib/schema/external-system.schema.json +181 -5
- package/lib/schema/flag-map-validation-run.json +31 -0
- package/lib/schema/infra-parameter.schema.json +106 -0
- package/lib/schema/infra.parameter.yaml +421 -0
- package/lib/schema/type/credential-auth-templates.json +40 -0
- package/lib/schema/type/document-storage.json +213 -0
- package/lib/schema/type/message-service.json +123 -0
- package/lib/schema/type/vector-store.json +88 -0
- package/lib/utils/aifabrix-runtime-config-dir.js +132 -0
- package/lib/utils/api-error-handler.js +2 -2
- package/lib/utils/api.js +49 -14
- package/lib/utils/app-config-resolver.js +23 -1
- package/lib/utils/app-register-api.js +3 -2
- package/lib/utils/app-register-auth.js +1 -1
- package/lib/utils/app-register-config.js +4 -4
- package/lib/utils/app-register-display.js +3 -2
- package/lib/utils/app-register-validator.js +3 -2
- package/lib/utils/app-run-containers.js +26 -22
- package/lib/utils/app-scoped-config.js +31 -0
- package/lib/utils/app-service-env-from-builder.js +164 -0
- package/lib/utils/build-copy.js +1 -1
- package/lib/utils/build-helpers.js +20 -20
- package/lib/utils/build-resolve-image.js +165 -0
- package/lib/utils/cli-layout-chalk.js +8 -0
- package/lib/utils/cli-test-layout-chalk.js +267 -0
- package/lib/utils/cli-utils.js +88 -11
- package/lib/utils/compose-db-passwords.js +138 -0
- package/lib/utils/compose-generate-docker-compose.js +216 -0
- package/lib/utils/compose-generator.js +197 -291
- package/lib/utils/compose-miso-env.js +18 -0
- package/lib/utils/compose-traefik-ingress-base.js +158 -0
- package/lib/utils/config-paths.js +209 -6
- package/lib/utils/config-scoped-resources-preference.js +41 -0
- package/lib/utils/controller-deployment-outcome.js +68 -0
- package/lib/utils/credential-display.js +2 -2
- package/lib/utils/credential-secrets-env.js +16 -1
- package/lib/utils/dataplane-pipeline-warning.js +4 -3
- package/lib/utils/datasource-test-run-capability-scope.js +43 -0
- package/lib/utils/datasource-test-run-debug-display.js +137 -0
- package/lib/utils/datasource-test-run-debug-slice.js +93 -0
- package/lib/utils/datasource-test-run-display.js +442 -0
- package/lib/utils/datasource-test-run-exit.js +58 -0
- package/lib/utils/datasource-test-run-legacy-adapter.js +93 -0
- package/lib/utils/datasource-test-run-report-version.js +51 -0
- package/lib/utils/datasource-test-run-schema-sync.js +59 -0
- package/lib/utils/datasource-test-run-tty-log.js +81 -0
- package/lib/utils/datasource-validation-watch.js +266 -0
- package/lib/utils/declarative-url-ports.js +47 -0
- package/lib/utils/derive-env-key-from-client-id.js +41 -0
- package/lib/utils/dev-ca-install.js +185 -23
- package/lib/utils/dev-cert-helper.js +266 -17
- package/lib/utils/dev-hosts-helper.js +307 -0
- package/lib/utils/dev-init-cert-hints.js +37 -0
- package/lib/utils/dev-init-health-messages.js +52 -0
- package/lib/utils/dev-init-resolve.js +86 -0
- package/lib/utils/dev-init-ssh-merge.js +65 -0
- package/lib/utils/dev-ssh-config-helper.js +196 -0
- package/lib/utils/dev-user-groups.js +93 -0
- package/lib/utils/docker-build.js +42 -17
- package/lib/utils/docker-exec.js +28 -0
- package/lib/utils/docker-manifest-public-port.js +116 -0
- package/lib/utils/docker-not-running-hint.js +52 -0
- package/lib/utils/docker.js +98 -11
- package/lib/utils/ensure-dev-certs-for-remote-docker.js +192 -0
- package/lib/utils/env-config-loader.js +10 -91
- package/lib/utils/env-copy.js +19 -10
- package/lib/utils/env-map.js +42 -11
- package/lib/utils/env-template.js +2 -2
- package/lib/utils/environment-scoped-resources.js +144 -0
- package/lib/utils/error-formatter.js +125 -9
- package/lib/utils/error-formatters/http-status-errors.js +6 -5
- package/lib/utils/error-formatters/network-errors.js +2 -1
- package/lib/utils/error-formatters/permission-errors.js +2 -1
- package/lib/utils/error-formatters/validation-errors.js +2 -1
- package/lib/utils/external-env-template.js +180 -0
- package/lib/utils/external-readme.js +8 -1
- package/lib/utils/external-system-display.js +277 -136
- package/lib/utils/external-system-local-test-tty.js +389 -0
- package/lib/utils/external-system-readiness-core.js +377 -0
- package/lib/utils/external-system-readiness-deploy-display.js +270 -0
- package/lib/utils/external-system-readiness-display-internals.js +150 -0
- package/lib/utils/external-system-readiness-display.js +186 -0
- package/lib/utils/external-system-test-helpers.js +24 -6
- package/lib/utils/external-system-validators.js +32 -14
- package/lib/utils/health-check-url.js +119 -0
- package/lib/utils/health-check.js +59 -25
- package/lib/utils/help-builder.js +14 -13
- package/lib/utils/image-version.js +4 -8
- package/lib/utils/infra-containers.js +4 -7
- package/lib/utils/infra-env-defaults.js +162 -0
- package/lib/utils/infra-status-display.js +167 -0
- package/lib/utils/infra-status.js +16 -8
- package/lib/utils/local-secrets.js +29 -7
- package/lib/utils/paths.js +136 -48
- package/lib/utils/port-resolver.js +10 -23
- package/lib/utils/redis-env-scope.js +62 -0
- package/lib/utils/register-aifabrix-shell-env.js +204 -0
- package/lib/utils/remote-builder-validation.js +99 -0
- package/lib/utils/remote-dev-auth.js +117 -21
- package/lib/utils/remote-docker-env.js +67 -15
- package/lib/utils/remote-secrets-loader.js +13 -4
- package/lib/utils/resolve-docker-image-ref.js +124 -0
- package/lib/utils/schema-loader.js +22 -9
- package/lib/utils/secrets-bash-kv.js +25 -0
- package/lib/utils/secrets-generator.js +171 -51
- package/lib/utils/secrets-helpers.js +70 -59
- package/lib/utils/secrets-kv-scope.js +60 -0
- package/lib/utils/secrets-utils.js +35 -37
- package/lib/utils/secrets-validation.js +3 -1
- package/lib/utils/secrets-yaml-preserve.js +109 -0
- package/lib/utils/secure-file-permissions.js +91 -0
- package/lib/utils/ssh-key-helper.js +4 -2
- package/lib/utils/template-helpers.js +2 -2
- package/lib/utils/test-log-writer.js +3 -3
- package/lib/utils/token-manager.js +37 -5
- package/lib/utils/url-declarative-public-base.js +188 -0
- package/lib/utils/url-declarative-resolve-build.js +493 -0
- package/lib/utils/url-declarative-resolve-load-doc.js +51 -0
- package/lib/utils/url-declarative-resolve.js +220 -0
- package/lib/utils/url-declarative-token-parse.js +74 -0
- package/lib/utils/url-declarative-url-flags.js +50 -0
- package/lib/utils/url-declarative-vdir-inactive-env.js +99 -0
- package/lib/utils/url-public-path-prefix.js +34 -0
- package/lib/utils/urls-local-registry.js +220 -0
- package/lib/utils/validation-report-tty-kit.js +77 -0
- package/lib/utils/validation-run-poll.js +89 -0
- package/lib/utils/validation-run-post-retry.js +73 -0
- package/lib/utils/validation-run-request.js +98 -0
- package/lib/utils/variable-transformer.js +21 -4
- package/lib/utils/yaml-preserve.js +78 -1
- package/lib/validation/datasource-warnings.js +56 -0
- package/lib/validation/env-template-auth.js +50 -2
- package/lib/validation/external-manifest-validator.js +35 -7
- package/lib/validation/validate-display.js +37 -31
- package/lib/validation/validate.js +9 -10
- package/lib/validation/validator-unresolved-placeholders.js +98 -0
- package/lib/validation/validator.js +32 -78
- package/lib/validation/wizard-config-validator.js +2 -1
- package/package.json +11 -3
- package/scripts/check-datasource-test-run-schema-sync.js +34 -0
- package/scripts/diagnose-cli.js +150 -0
- package/scripts/install-local.js +304 -55
- package/templates/README.md +15 -2
- package/templates/applications/dataplane/application.yaml +52 -2
- package/templates/applications/dataplane/env.template +80 -18
- package/templates/applications/dataplane/rbac.yaml +8 -0
- package/templates/applications/keycloak/application.yaml +9 -1
- package/templates/applications/keycloak/env.template +15 -6
- package/templates/applications/miso-controller/application.yaml +10 -2
- package/templates/applications/miso-controller/env.template +55 -14
- package/templates/applications/miso-controller/rbac.yaml +5 -0
- package/templates/external-system/README.md.hbs +20 -7
- package/templates/external-system/deploy.js.hbs +5 -5
- package/templates/external-system/env.template.hbs +22 -0
- package/templates/external-system/external-datasource.yaml.hbs +197 -118
- package/templates/infra/compose.yaml.hbs +20 -4
- package/templates/python/docker-compose.hbs +16 -0
- package/templates/typescript/docker-compose.hbs +16 -0
- package/integration/hubspot/README.md +0 -102
- package/integration/hubspot/env.template +0 -4
- package/integration/hubspot/hubspot-datasource-company.json +0 -541
- package/integration/hubspot/hubspot-datasource-contact.json +0 -639
- package/integration/hubspot/hubspot-datasource-deal.json +0 -588
- package/integration/hubspot/hubspot-datasource-users.json +0 -116
- package/integration/hubspot/test-artifacts/wizard-invalid-missing-source.yaml +0 -2
- package/integration/hubspot/test-artifacts/wizard-valid-for-dimension-key-test.yaml +0 -5
- package/integration/hubspot/test-artifacts/wizard-valid-for-dimension-path-test.yaml +0 -5
- package/lib/api/external-test.api.js +0 -111
- package/lib/schema/env-config.yaml +0 -43
- /package/integration/{hubspot → hubspot-test}/companies.json +0 -0
- /package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-app-name.yaml +0 -0
- /package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-missing-app.yaml +0 -0
- /package/integration/{hubspot → hubspot-test}/test-dataplane-down-helpers.js +0 -0
|
@@ -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
|
];
|
|
@@ -56,38 +58,199 @@ async function setPathConfig(getConfigFn, saveConfigFn, key, value, errorMsg) {
|
|
|
56
58
|
await saveConfigFn(config);
|
|
57
59
|
}
|
|
58
60
|
|
|
61
|
+
/**
|
|
62
|
+
* Clear a path config key (set to undefined so getPathConfig returns null).
|
|
63
|
+
* @param {Function} getConfigFn - Function to get config
|
|
64
|
+
* @param {Function} saveConfigFn - Function to save config
|
|
65
|
+
* @param {string} key - Configuration key
|
|
66
|
+
* @returns {Promise<void>}
|
|
67
|
+
*/
|
|
68
|
+
async function clearPathConfig(getConfigFn, saveConfigFn, key) {
|
|
69
|
+
const config = await getConfigFn();
|
|
70
|
+
config[key] = undefined;
|
|
71
|
+
await saveConfigFn(config);
|
|
72
|
+
}
|
|
73
|
+
|
|
59
74
|
function createHomeAndSecretsPathFunctions(getConfigFn, saveConfigFn) {
|
|
60
75
|
return {
|
|
61
76
|
async getAifabrixHomeOverride() {
|
|
62
77
|
return getPathConfig(getConfigFn, 'aifabrix-home');
|
|
63
78
|
},
|
|
64
79
|
async setAifabrixHomeOverride(homePath) {
|
|
65
|
-
|
|
80
|
+
if (typeof homePath !== 'string') {
|
|
81
|
+
throw new Error('Home path is required and must be a string');
|
|
82
|
+
}
|
|
83
|
+
const trimmed = homePath.trim();
|
|
84
|
+
if (trimmed === '') {
|
|
85
|
+
await clearPathConfig(getConfigFn, saveConfigFn, 'aifabrix-home');
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
await setPathConfig(getConfigFn, saveConfigFn, 'aifabrix-home', trimmed, 'Home path must be a non-empty string');
|
|
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
|
+
);
|
|
66
110
|
},
|
|
67
111
|
async getAifabrixSecretsPath() {
|
|
68
112
|
return getPathConfig(getConfigFn, 'aifabrix-secrets');
|
|
69
113
|
},
|
|
70
114
|
async setAifabrixSecretsPath(secretsPath) {
|
|
71
|
-
|
|
115
|
+
if (typeof secretsPath !== 'string') {
|
|
116
|
+
throw new Error('Secrets path is required and must be a string');
|
|
117
|
+
}
|
|
118
|
+
const trimmed = secretsPath.trim();
|
|
119
|
+
if (trimmed === '') {
|
|
120
|
+
await clearPathConfig(getConfigFn, saveConfigFn, 'aifabrix-secrets');
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
await setPathConfig(getConfigFn, saveConfigFn, 'aifabrix-secrets', trimmed, 'Secrets path must be a non-empty string');
|
|
72
124
|
}
|
|
73
125
|
};
|
|
74
126
|
}
|
|
75
127
|
|
|
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));
|
|
168
|
+
}
|
|
169
|
+
|
|
76
170
|
function createEnvConfigPathFunctions(getConfigFn, saveConfigFn) {
|
|
77
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
|
+
*/
|
|
78
176
|
async getAifabrixEnvConfigPath() {
|
|
79
|
-
|
|
177
|
+
const value = await getPathConfig(getConfigFn, 'aifabrix-env-config');
|
|
178
|
+
if (!value || typeof value !== 'string') {
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
return resolveEnvConfigPathToAbsolute(value, getConfigFn);
|
|
80
182
|
},
|
|
81
183
|
async setAifabrixEnvConfigPath(envConfigPath) {
|
|
82
|
-
|
|
184
|
+
if (typeof envConfigPath !== 'string') {
|
|
185
|
+
throw new Error('Env config path is required and must be a string');
|
|
186
|
+
}
|
|
187
|
+
const trimmed = envConfigPath.trim();
|
|
188
|
+
if (trimmed === '') {
|
|
189
|
+
await clearPathConfig(getConfigFn, saveConfigFn, 'aifabrix-env-config');
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
await setPathConfig(getConfigFn, saveConfigFn, 'aifabrix-env-config', trimmed, 'Env config path must be a non-empty string');
|
|
83
193
|
},
|
|
84
194
|
async getAifabrixBuilderDir() {
|
|
85
195
|
const envConfigPath = await getPathConfig(getConfigFn, 'aifabrix-env-config');
|
|
86
|
-
|
|
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);
|
|
87
221
|
}
|
|
88
222
|
};
|
|
89
223
|
}
|
|
90
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
|
+
|
|
91
254
|
function createRemoteConfigGetters(getConfigFn) {
|
|
92
255
|
return {
|
|
93
256
|
async getRemoteServer() {
|
|
@@ -96,6 +259,25 @@ function createRemoteConfigGetters(getConfigFn) {
|
|
|
96
259
|
async getDockerEndpoint() {
|
|
97
260
|
return getPathConfig(getConfigFn, 'docker-endpoint');
|
|
98
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
|
+
},
|
|
99
281
|
async getUserMutagenFolder() {
|
|
100
282
|
return getPathConfig(getConfigFn, 'user-mutagen-folder');
|
|
101
283
|
},
|
|
@@ -125,6 +307,24 @@ function createRemoteConfigSetters(getConfigFn, saveConfigFn) {
|
|
|
125
307
|
const config = await getConfigFn();
|
|
126
308
|
config['docker-endpoint'] = value || undefined;
|
|
127
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);
|
|
128
328
|
}
|
|
129
329
|
};
|
|
130
330
|
}
|
|
@@ -155,7 +355,8 @@ function applySecretsUrlFromRemote(config) {
|
|
|
155
355
|
const secretsPath = config['aifabrix-secrets'];
|
|
156
356
|
if (!remoteServer || !secretsPath || isHttpUrl(secretsPath)) return;
|
|
157
357
|
const base = typeof remoteServer === 'string' ? remoteServer.trim().replace(/\/+$/, '') : '';
|
|
158
|
-
if (base)
|
|
358
|
+
if (!base) return;
|
|
359
|
+
config['aifabrix-secrets'] = `${base}/api/dev/secrets`;
|
|
159
360
|
}
|
|
160
361
|
|
|
161
362
|
function applySyncAndDockerFromHost(config) {
|
|
@@ -168,6 +369,7 @@ function applySyncAndDockerFromHost(config) {
|
|
|
168
369
|
async function mergeRemoteSettingsImpl(getConfigFn, saveConfigFn, settings) {
|
|
169
370
|
if (!settings || typeof settings !== 'object') return;
|
|
170
371
|
const config = await getConfigFn();
|
|
372
|
+
delete config['aifabrix-secrets-path'];
|
|
171
373
|
for (const key of SETTINGS_RESPONSE_KEYS) {
|
|
172
374
|
const raw = settings[key];
|
|
173
375
|
if (raw === undefined || raw === null) continue;
|
|
@@ -214,6 +416,7 @@ module.exports = {
|
|
|
214
416
|
getPathConfig,
|
|
215
417
|
setPathConfig,
|
|
216
418
|
createPathConfigFunctions,
|
|
419
|
+
resolveEnvConfigPathToAbsolute,
|
|
217
420
|
SETTINGS_RESPONSE_KEYS
|
|
218
421
|
};
|
|
219
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
|
|
|
@@ -92,6 +92,17 @@ function kvPathInferred(segments) {
|
|
|
92
92
|
return (namespace && pathVar) ? `kv://${namespace}/${pathVar}` : null;
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
+
/**
|
|
96
|
+
* Returns the path segment used in kv://<systemKey>/<segment> for a given security key.
|
|
97
|
+
* Uses the same derivation as env key → path (securityKeyToVar + varSegmentsToCamelCase).
|
|
98
|
+
* @param {string} securityKey - Security key (e.g. 'apiKey', 'clientId', 'clientSecret')
|
|
99
|
+
* @returns {string} Canonical path segment (e.g. 'apiKey', 'clientId')
|
|
100
|
+
*/
|
|
101
|
+
function getKvPathSegmentForSecurityKey(securityKey) {
|
|
102
|
+
if (!securityKey || typeof securityKey !== 'string') return '';
|
|
103
|
+
return varSegmentsToCamelCase([securityKeyToVar(securityKey)]);
|
|
104
|
+
}
|
|
105
|
+
|
|
95
106
|
/**
|
|
96
107
|
* Converts KV_* env key to kv:// path in format kv://<system-key>/<variable>.
|
|
97
108
|
* System-key uses hyphens (e.g. microsoft-teams); variable is camelCase (e.g. clientId).
|
|
@@ -220,7 +231,10 @@ function buildItemsFromEnv(envFilePath, secrets, itemsByKey) {
|
|
|
220
231
|
const fromEnv = collectKvEnvVarsAsSecretItems(envMap);
|
|
221
232
|
for (const { key, value } of fromEnv) {
|
|
222
233
|
const resolved = resolveKvValue(secrets, value);
|
|
223
|
-
|
|
234
|
+
// Skip placeholder: value that equals the kv path (e.g. from env.template) must not be pushed as the secret
|
|
235
|
+
if (resolved !== null && resolved !== undefined && isValidKvPath(key) && resolved.trim() !== key.trim()) {
|
|
236
|
+
itemsByKey.set(key, resolved);
|
|
237
|
+
}
|
|
224
238
|
}
|
|
225
239
|
} catch {
|
|
226
240
|
// Best-effort: continue without .env items
|
|
@@ -349,6 +363,7 @@ module.exports = {
|
|
|
349
363
|
collectKvRefsFromPayload,
|
|
350
364
|
pushCredentialSecrets,
|
|
351
365
|
kvEnvKeyToPath,
|
|
366
|
+
getKvPathSegmentForSecurityKey,
|
|
352
367
|
systemKeyToKvPrefix,
|
|
353
368
|
securityKeyToVar,
|
|
354
369
|
isValidKvPath,
|
|
@@ -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
|
+
};
|