@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
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Single source of truth for resolving application port from application config.
|
|
5
5
|
* Use getContainerPort for container/Docker/deployment/registration; use getLocalPort
|
|
6
|
-
* for local
|
|
6
|
+
* for manifest listen port (same as port; local host uses port+10+dev*100 in secrets-helpers).
|
|
7
7
|
*
|
|
8
8
|
* @fileoverview Port resolution from variables (port, build.containerPort)
|
|
9
9
|
* @author AI Fabrix Team
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
const fs = require('fs');
|
|
16
16
|
const yaml = require('js-yaml');
|
|
17
|
+
const { DECLARATIVE_URL_INFRA_DEFAULTS } = require('./infra-env-defaults');
|
|
17
18
|
|
|
18
19
|
/**
|
|
19
20
|
* Resolve container port from variables object.
|
|
@@ -21,10 +22,10 @@ const yaml = require('js-yaml');
|
|
|
21
22
|
* When containerPort is empty or missing, main port is used (e.g. keycloak 8082:8080 vs miso 3000:3000).
|
|
22
23
|
*
|
|
23
24
|
* @param {Object} variables - Parsed application config (or subset with build, port)
|
|
24
|
-
* @param {number} [defaultPort
|
|
25
|
+
* @param {number} [defaultPort] - Default when neither build.containerPort nor port is set (infra fallback)
|
|
25
26
|
* @returns {number} Resolved container port
|
|
26
27
|
*/
|
|
27
|
-
function getContainerPort(variables, defaultPort =
|
|
28
|
+
function getContainerPort(variables, defaultPort = DECLARATIVE_URL_INFRA_DEFAULTS.manifestPortFallback) {
|
|
28
29
|
const v = variables || {};
|
|
29
30
|
const containerPort = v.build?.containerPort;
|
|
30
31
|
const useMain = containerPort === undefined || containerPort === null ||
|
|
@@ -36,20 +37,13 @@ function getContainerPort(variables, defaultPort = 3000) {
|
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
/**
|
|
39
|
-
* Resolve
|
|
40
|
-
* Precedence: build.localPort (when positive integer) → port → defaultPort.
|
|
41
|
-
* Used for env-copy, env-ports, getLocalPortFromPath, run compose host port.
|
|
42
|
-
*
|
|
40
|
+
* Resolve base application listen port (manifest `port` only; build.localPort removed).
|
|
43
41
|
* @param {Object} variables - Parsed application config
|
|
44
|
-
* @param {number} [defaultPort
|
|
45
|
-
* @returns {number}
|
|
42
|
+
* @param {number} [defaultPort] - Default when port is unset (infra fallback)
|
|
43
|
+
* @returns {number} Listen port
|
|
46
44
|
*/
|
|
47
|
-
function getLocalPort(variables, defaultPort =
|
|
45
|
+
function getLocalPort(variables, defaultPort = DECLARATIVE_URL_INFRA_DEFAULTS.manifestPortFallback) {
|
|
48
46
|
const v = variables || {};
|
|
49
|
-
const localPort = v.build?.localPort;
|
|
50
|
-
if (typeof localPort === 'number' && localPort > 0) {
|
|
51
|
-
return localPort;
|
|
52
|
-
}
|
|
53
47
|
return v.port ?? defaultPort;
|
|
54
48
|
}
|
|
55
49
|
|
|
@@ -94,22 +88,15 @@ function getContainerPortFromPath(variablesPath) {
|
|
|
94
88
|
}
|
|
95
89
|
|
|
96
90
|
/**
|
|
97
|
-
* Resolve
|
|
98
|
-
* Same rule as getLocalPort: build.localPort (when positive integer) → port.
|
|
99
|
-
* Returns null when file is missing or neither localPort nor port is set.
|
|
100
|
-
*
|
|
91
|
+
* Resolve manifest port from application config path.
|
|
101
92
|
* @param {string} variablesPath - Path to application config
|
|
102
|
-
* @returns {number|null}
|
|
93
|
+
* @returns {number|null} Port or null
|
|
103
94
|
*/
|
|
104
95
|
function getLocalPortFromPath(variablesPath) {
|
|
105
96
|
const v = loadVariablesFromPath(variablesPath);
|
|
106
97
|
if (!v) {
|
|
107
98
|
return null;
|
|
108
99
|
}
|
|
109
|
-
const localPort = v.build?.localPort;
|
|
110
|
-
if (typeof localPort === 'number' && localPort > 0) {
|
|
111
|
-
return localPort;
|
|
112
|
-
}
|
|
113
100
|
const p = v.port;
|
|
114
101
|
return (p !== undefined && p !== null) ? p : null;
|
|
115
102
|
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adjust Redis DB index in resolved .env content when environment-scoped resources are effective.
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview REDIS_DB and redis:// URL path segment (plan 117)
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Set pathname /dbIndex for redis(s) URLs.
|
|
13
|
+
*
|
|
14
|
+
* @param {string} urlStr - redis:// or rediss:// URL
|
|
15
|
+
* @param {number} dbIndex - logical DB (0–15 typical)
|
|
16
|
+
* @returns {string}
|
|
17
|
+
*/
|
|
18
|
+
function setRedisUrlDbIndex(urlStr, dbIndex) {
|
|
19
|
+
if (!urlStr || typeof urlStr !== 'string') return urlStr;
|
|
20
|
+
try {
|
|
21
|
+
const u = new URL(urlStr.trim());
|
|
22
|
+
if (u.protocol !== 'redis:' && u.protocol !== 'rediss:') {
|
|
23
|
+
return urlStr;
|
|
24
|
+
}
|
|
25
|
+
u.pathname = `/${dbIndex}`;
|
|
26
|
+
return u.toString();
|
|
27
|
+
} catch {
|
|
28
|
+
return urlStr;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Apply Redis DB index to REDIS_DB= and REDIS_URL= lines when effective.
|
|
34
|
+
*
|
|
35
|
+
* @param {string} content - .env text
|
|
36
|
+
* @param {number|null} dbIndex - from redisDbIndexForScopedRunEnv; skip if null
|
|
37
|
+
* @returns {string}
|
|
38
|
+
*/
|
|
39
|
+
function applyRedisDbIndexToEnvContent(content, dbIndex) {
|
|
40
|
+
if (dbIndex === null || dbIndex === undefined || typeof content !== 'string') {
|
|
41
|
+
return content;
|
|
42
|
+
}
|
|
43
|
+
const lines = content.split('\n');
|
|
44
|
+
const out = lines.map((line) => {
|
|
45
|
+
const trimmed = line.trim();
|
|
46
|
+
if (!trimmed || trimmed.startsWith('#')) return line;
|
|
47
|
+
const eq = trimmed.indexOf('=');
|
|
48
|
+
if (eq <= 0) return line;
|
|
49
|
+
const key = trimmed.slice(0, eq).trim();
|
|
50
|
+
const value = trimmed.slice(eq + 1);
|
|
51
|
+
if (key === 'REDIS_DB') {
|
|
52
|
+
return `${key}=${dbIndex}`;
|
|
53
|
+
}
|
|
54
|
+
if (key === 'REDIS_URL' && value && !value.startsWith('kv://')) {
|
|
55
|
+
return `${key}=${setRedisUrlDbIndex(value, dbIndex)}`;
|
|
56
|
+
}
|
|
57
|
+
return line;
|
|
58
|
+
});
|
|
59
|
+
return out.join('\n');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
module.exports = { applyRedisDbIndexToEnvContent, setRedisUrlDbIndex };
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Register AIFABRIX_HOME and AIFABRIX_WORK for new shells: Windows user env vars;
|
|
3
|
+
* POSIX writes a sourced script next to config.yaml and ensures a profile snippet.
|
|
4
|
+
*
|
|
5
|
+
* @fileoverview OS/shell registration after dev set-home / dev set-work
|
|
6
|
+
* @author AI Fabrix Team
|
|
7
|
+
* @version 2.0.0
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
'use strict';
|
|
11
|
+
|
|
12
|
+
const fsp = require('node:fs').promises;
|
|
13
|
+
const path = require('path');
|
|
14
|
+
const os = require('os');
|
|
15
|
+
const { promisify } = require('util');
|
|
16
|
+
const execFileCb = require('child_process').execFile;
|
|
17
|
+
const execFile = promisify(execFileCb);
|
|
18
|
+
|
|
19
|
+
const { getConfigDirForPaths } = require('./paths');
|
|
20
|
+
|
|
21
|
+
const SHELL_ENV_BASENAME = 'aifabrix-shell-env.sh';
|
|
22
|
+
const BLOCK_BEGIN = '# BEGIN aifabrix-builder shell env';
|
|
23
|
+
const BLOCK_END = '# END aifabrix-builder shell env';
|
|
24
|
+
|
|
25
|
+
const PROFILE_BLOCK_RE = /\n?# BEGIN aifabrix-builder shell env\n[\s\S]*?\n# END aifabrix-builder shell env\n?/;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Single-quote a path for POSIX export lines.
|
|
29
|
+
* @param {string} p - Path
|
|
30
|
+
* @returns {string} Quoted for sh
|
|
31
|
+
*/
|
|
32
|
+
function shSingleQuoted(p) {
|
|
33
|
+
const esc = String.fromCharCode(39, 92, 39, 39);
|
|
34
|
+
return `'${String(p).replace(/'/g, esc)}'`;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Build body for aifabrix-shell-env.sh (exports only; no secrets).
|
|
39
|
+
* @param {string|null} homeAbs - Resolved home or null
|
|
40
|
+
* @param {string|null} workAbs - Resolved work or null
|
|
41
|
+
* @returns {string} File content
|
|
42
|
+
*/
|
|
43
|
+
function buildPosixShellEnvBody(homeAbs, workAbs) {
|
|
44
|
+
const lines = ['# Managed by aifabrix dev set-home / set-work. Do not edit.'];
|
|
45
|
+
if (homeAbs) {
|
|
46
|
+
lines.push(`export AIFABRIX_HOME=${shSingleQuoted(homeAbs)}`);
|
|
47
|
+
}
|
|
48
|
+
if (workAbs) {
|
|
49
|
+
lines.push(`export AIFABRIX_WORK=${shSingleQuoted(workAbs)}`);
|
|
50
|
+
}
|
|
51
|
+
return `${lines.join('\n')}\n`;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Profile snippet that sources the shell env file.
|
|
56
|
+
* @param {string} envFileAbs - Absolute path to aifabrix-shell-env.sh
|
|
57
|
+
* @returns {string} Block including markers
|
|
58
|
+
*/
|
|
59
|
+
function buildProfileBlock(envFileAbs) {
|
|
60
|
+
const q = shSingleQuoted(envFileAbs);
|
|
61
|
+
return `${BLOCK_BEGIN}
|
|
62
|
+
[ -f ${q} ] && . ${q}
|
|
63
|
+
${BLOCK_END}
|
|
64
|
+
`;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Resolve YAML path string to absolute or null.
|
|
69
|
+
* @param {*} raw - Config value
|
|
70
|
+
* @returns {string|null}
|
|
71
|
+
*/
|
|
72
|
+
function absFromConfigRaw(raw) {
|
|
73
|
+
if (typeof raw !== 'string') return null;
|
|
74
|
+
const t = raw.trim();
|
|
75
|
+
if (!t) return null;
|
|
76
|
+
return path.resolve(t);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* PowerShell to set or remove a user-scoped environment variable.
|
|
81
|
+
* @param {string} name - Var name (caller must pass safe identifiers only)
|
|
82
|
+
* @param {string|null} value - Absolute path or null to remove
|
|
83
|
+
* @returns {string} PowerShell -Command argument body
|
|
84
|
+
*/
|
|
85
|
+
function psSetUserEnvStatement(name, value) {
|
|
86
|
+
if (value === null || value === undefined || value === '') {
|
|
87
|
+
return `[System.Environment]::SetEnvironmentVariable('${name}', $null, 'User')`;
|
|
88
|
+
}
|
|
89
|
+
const escaped = String(value).replace(/'/g, '\'\'');
|
|
90
|
+
return `[System.Environment]::SetEnvironmentVariable('${name}', '${escaped}', 'User')`;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Default rc file to patch (zsh vs bash).
|
|
95
|
+
* @param {string} homedir - User home
|
|
96
|
+
* @returns {string} Absolute profile path
|
|
97
|
+
*/
|
|
98
|
+
function defaultProfilePath(homedir) {
|
|
99
|
+
const shell = process.env.SHELL || '';
|
|
100
|
+
if (shell.includes('zsh')) {
|
|
101
|
+
return path.join(homedir, '.zshrc');
|
|
102
|
+
}
|
|
103
|
+
return path.join(homedir, '.bashrc');
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Ensure ~/.zshrc or ~/.bashrc contains a single marked block sourcing envFileAbs.
|
|
108
|
+
* @param {string} envFileAbs - Shell env file
|
|
109
|
+
* @param {object} [overrides] - Test hooks
|
|
110
|
+
* @param {string} [overrides.profilePath] - Profile file to edit
|
|
111
|
+
* @param {string} [overrides.homedir] - Home directory
|
|
112
|
+
* @returns {Promise<void>}
|
|
113
|
+
*/
|
|
114
|
+
async function ensureProfileShellBlock(envFileAbs, overrides = {}) {
|
|
115
|
+
const homedir = overrides.homedir ?? os.homedir();
|
|
116
|
+
const profilePath = overrides.profilePath ?? defaultProfilePath(homedir);
|
|
117
|
+
const snippet = buildProfileBlock(envFileAbs);
|
|
118
|
+
let existing = '';
|
|
119
|
+
try {
|
|
120
|
+
existing = await fsp.readFile(profilePath, 'utf8');
|
|
121
|
+
} catch (err) {
|
|
122
|
+
if (err.code !== 'ENOENT') {
|
|
123
|
+
throw err;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
if (PROFILE_BLOCK_RE.test(existing)) {
|
|
127
|
+
const next = existing.replace(PROFILE_BLOCK_RE, `\n${snippet.trimEnd()}\n`);
|
|
128
|
+
if (next !== existing) {
|
|
129
|
+
await fsp.writeFile(profilePath, next, 'utf8');
|
|
130
|
+
}
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
const sep = existing && !existing.endsWith('\n') ? '\n' : '';
|
|
134
|
+
await fsp.writeFile(profilePath, `${existing}${sep}${snippet}`, 'utf8');
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Apply Windows user env for both vars from current config (independent clear per key).
|
|
139
|
+
* @param {string|null} homeAbs
|
|
140
|
+
* @param {string|null} workAbs
|
|
141
|
+
* @param {Function} [execFileImpl] - execFile (for tests)
|
|
142
|
+
* @returns {Promise<void>}
|
|
143
|
+
*/
|
|
144
|
+
async function applyWindowsUserEnv(homeAbs, workAbs, execFileImpl = execFile) {
|
|
145
|
+
const script = `${psSetUserEnvStatement('AIFABRIX_HOME', homeAbs)}; ${psSetUserEnvStatement(
|
|
146
|
+
'AIFABRIX_WORK',
|
|
147
|
+
workAbs
|
|
148
|
+
)}`;
|
|
149
|
+
await execFileImpl(
|
|
150
|
+
'powershell.exe',
|
|
151
|
+
['-NoProfile', '-NonInteractive', '-Command', script],
|
|
152
|
+
{ windowsHide: true }
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Write POSIX shell env file and ensure profile sources it.
|
|
158
|
+
* @param {string|null} homeAbs
|
|
159
|
+
* @param {string|null} workAbs
|
|
160
|
+
* @param {object} overrides - Test hooks (same as ensureProfileShellBlock + getConfigDirForPaths)
|
|
161
|
+
* @returns {Promise<void>}
|
|
162
|
+
*/
|
|
163
|
+
async function applyPosixShellEnv(homeAbs, workAbs, overrides = {}) {
|
|
164
|
+
const configDir = overrides.getConfigDirForPaths ? overrides.getConfigDirForPaths() : getConfigDirForPaths();
|
|
165
|
+
const envFile = path.join(configDir, SHELL_ENV_BASENAME);
|
|
166
|
+
await fsp.mkdir(configDir, { recursive: true });
|
|
167
|
+
const body = buildPosixShellEnvBody(homeAbs, workAbs);
|
|
168
|
+
await fsp.writeFile(envFile, body, { mode: 0o600, flag: 'w' });
|
|
169
|
+
await ensureProfileShellBlock(path.resolve(envFile), overrides);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Sync user/shell environment from saved config.yaml (after set-home or set-work).
|
|
174
|
+
*
|
|
175
|
+
* @async
|
|
176
|
+
* @param {function(): Promise<object>} getConfigFn - Same as config.getConfig
|
|
177
|
+
* @param {object} [overrides] - Optional { platform, execFile, getConfigDirForPaths, profilePath, homedir }
|
|
178
|
+
* @returns {Promise<void>}
|
|
179
|
+
*/
|
|
180
|
+
async function registerAifabrixShellEnvFromConfig(getConfigFn, overrides = {}) {
|
|
181
|
+
const platform = overrides.platform ?? process.platform;
|
|
182
|
+
const config = await getConfigFn();
|
|
183
|
+
const homeAbs = absFromConfigRaw(config['aifabrix-home']);
|
|
184
|
+
const workAbs = absFromConfigRaw(config['aifabrix-work']);
|
|
185
|
+
|
|
186
|
+
if (platform === 'win32') {
|
|
187
|
+
await applyWindowsUserEnv(homeAbs, workAbs, overrides.execFile || execFile);
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
await applyPosixShellEnv(homeAbs, workAbs, overrides);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
module.exports = {
|
|
195
|
+
registerAifabrixShellEnvFromConfig,
|
|
196
|
+
buildPosixShellEnvBody,
|
|
197
|
+
buildProfileBlock,
|
|
198
|
+
shSingleQuoted,
|
|
199
|
+
psSetUserEnvStatement,
|
|
200
|
+
ensureProfileShellBlock,
|
|
201
|
+
SHELL_ENV_BASENAME,
|
|
202
|
+
BLOCK_BEGIN,
|
|
203
|
+
BLOCK_END
|
|
204
|
+
};
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Remote shared builder vs local Docker Desktop — developer-id rules (plan 018).
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Fail fast when remote-server is non-localhost but developer-id is not a positive integer
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @param {string|null|undefined} remoteServer - remote-server from config (URL or host)
|
|
13
|
+
* @returns {boolean} True when hostname is set and not localhost / loopback only
|
|
14
|
+
*/
|
|
15
|
+
function remoteServerHostIsNonLocalhost(remoteServer) {
|
|
16
|
+
const raw =
|
|
17
|
+
remoteServer === null || remoteServer === undefined ? '' : String(remoteServer).trim();
|
|
18
|
+
if (!raw) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
const withScheme = /^[a-z][a-z0-9+.-]*:\/\//i.test(raw) ? raw : `https://${raw}`;
|
|
23
|
+
const u = new URL(withScheme);
|
|
24
|
+
let h = (u.hostname || '').toLowerCase();
|
|
25
|
+
if (h.startsWith('[') && h.endsWith(']')) {
|
|
26
|
+
h = h.slice(1, -1);
|
|
27
|
+
}
|
|
28
|
+
if (!h) {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
if (h === 'localhost' || h === '127.0.0.1' || h === '::1') {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
return true;
|
|
35
|
+
} catch {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Host for user-facing messages (no path, no credentials).
|
|
42
|
+
* @param {string|null|undefined} remoteServer
|
|
43
|
+
* @returns {string}
|
|
44
|
+
*/
|
|
45
|
+
function remoteServerDisplayHost(remoteServer) {
|
|
46
|
+
const raw =
|
|
47
|
+
remoteServer === null || remoteServer === undefined ? '' : String(remoteServer).trim();
|
|
48
|
+
if (!raw) {
|
|
49
|
+
return '(remote-server)';
|
|
50
|
+
}
|
|
51
|
+
try {
|
|
52
|
+
const withScheme = /^[a-z][a-z0-9+.-]*:\/\//i.test(raw) ? raw : `https://${raw}`;
|
|
53
|
+
const u = new URL(withScheme);
|
|
54
|
+
return u.host || raw;
|
|
55
|
+
} catch {
|
|
56
|
+
return raw;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const REMOTE_DEV_ID_BODY =
|
|
61
|
+
'Remote builder at %s requires a positive developer-id (1, 2, 3, …).\n' +
|
|
62
|
+
'Developer-id 0 is only supported for local Docker Desktop (localhost).\n' +
|
|
63
|
+
'Set developer-id in ~/.aifabrix/config.yaml to match your dev account (e.g. 1 for dev01), ' +
|
|
64
|
+
'or run onboarding against the builder: aifabrix dev init …';
|
|
65
|
+
|
|
66
|
+
const REMOTE_DEV_ID_TAIL =
|
|
67
|
+
'\n\nIf you meant to work only on this machine, set remote-server to use localhost or remove the shared builder URL.';
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* When remote-server points at a shared (non-local) builder, require developer-id ≥ 1.
|
|
71
|
+
* @param {string|null|undefined} remoteServer
|
|
72
|
+
* @param {string|number|null|undefined} developerIdRaw
|
|
73
|
+
* @throws {Error} When remote builder and id missing, non-numeric, or < 1
|
|
74
|
+
*/
|
|
75
|
+
function assertRemoteBuilderDeveloperId(remoteServer, developerIdRaw) {
|
|
76
|
+
if (!remoteServerHostIsNonLocalhost(remoteServer)) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
const host = remoteServerDisplayHost(remoteServer);
|
|
80
|
+
const head = REMOTE_DEV_ID_BODY.replace('%s', host);
|
|
81
|
+
|
|
82
|
+
if (developerIdRaw === null || developerIdRaw === undefined || developerIdRaw === '') {
|
|
83
|
+
throw new Error(head + REMOTE_DEV_ID_TAIL);
|
|
84
|
+
}
|
|
85
|
+
const s = String(developerIdRaw).trim();
|
|
86
|
+
if (!/^\d+$/.test(s)) {
|
|
87
|
+
throw new Error(head + REMOTE_DEV_ID_TAIL);
|
|
88
|
+
}
|
|
89
|
+
const n = parseInt(s, 10);
|
|
90
|
+
if (n < 1) {
|
|
91
|
+
throw new Error(head + REMOTE_DEV_ID_TAIL);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
module.exports = {
|
|
96
|
+
remoteServerHostIsNonLocalhost,
|
|
97
|
+
remoteServerDisplayHost,
|
|
98
|
+
assertRemoteBuilderDeveloperId
|
|
99
|
+
};
|
|
@@ -4,35 +4,131 @@
|
|
|
4
4
|
* @version 2.0.0
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
const path = require('path');
|
|
7
8
|
const config = require('../core/config');
|
|
8
|
-
const { getCertDir, readClientCertPem } = require('./dev-cert-helper');
|
|
9
|
-
const { getConfigDirForPaths } = require('./paths');
|
|
9
|
+
const { getCertDir, readClientCertPem, readServerCaPem } = require('./dev-cert-helper');
|
|
10
|
+
const { getConfigDirForPaths, getAifabrixHome, getAifabrixWork } = require('./paths');
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
|
-
*
|
|
13
|
-
*
|
|
13
|
+
* Single API object so resolveSharedSecretsEndpoint and callers share one getRemoteDevAuth
|
|
14
|
+
* (Jest spies and partial mocks work reliably).
|
|
15
|
+
*/
|
|
16
|
+
const remoteDevAuth = {
|
|
17
|
+
/**
|
|
18
|
+
* Check if a string is an http(s) URL (for aifabrix-secrets remote mode).
|
|
19
|
+
* @param {string} value - Config value
|
|
20
|
+
* @returns {boolean}
|
|
21
|
+
*/
|
|
22
|
+
isRemoteSecretsUrl(value) {
|
|
23
|
+
return typeof value === 'string' && (value.startsWith('http://') || value.startsWith('https://'));
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Get Builder Server URL, client cert PEM, and optional dev root CA when remote is configured; otherwise null.
|
|
28
|
+
* serverCaPem comes from ca.pem (saved at dev init); required for Node TLS to private-CA servers.
|
|
29
|
+
* Use for cert-authenticated dev API calls (settings, users, ssh-keys, secrets).
|
|
30
|
+
* @returns {Promise<{ serverUrl: string, clientCertPem: string, serverCaPem: string|null }|null>}
|
|
31
|
+
*/
|
|
32
|
+
async getRemoteDevAuth() {
|
|
33
|
+
const serverUrl = await config.getRemoteServer();
|
|
34
|
+
if (!serverUrl) return null;
|
|
35
|
+
const devId = await config.getDeveloperId();
|
|
36
|
+
const certDir = getCertDir(getConfigDirForPaths(), devId);
|
|
37
|
+
const clientCertPem = readClientCertPem(certDir);
|
|
38
|
+
if (!clientCertPem) return null;
|
|
39
|
+
const serverCaPem = readServerCaPem(certDir);
|
|
40
|
+
return { serverUrl, clientCertPem, serverCaPem };
|
|
41
|
+
},
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Resolve where shared secrets read/write should go. After dev init, config may still hold a
|
|
45
|
+
* server-side filesystem path from GET /api/dev/settings (not an http URL) if merge did not rewrite it.
|
|
46
|
+
* Those paths are not writable on the developer machine; use the Builder secrets API instead when
|
|
47
|
+
* remote-server + client cert are configured and the path is not under aifabrix-home or aifabrix-work.
|
|
48
|
+
*
|
|
49
|
+
* @param {string} configuredPath - config.yaml aifabrix-secrets
|
|
50
|
+
* @returns {Promise<string>} Same string for local file targets, or https?://…/api/dev/secrets for remote API
|
|
51
|
+
*/
|
|
52
|
+
async resolveSharedSecretsEndpoint(configuredPath) {
|
|
53
|
+
if (!configuredPath || typeof configuredPath !== 'string') return configuredPath;
|
|
54
|
+
const trimmed = configuredPath.trim();
|
|
55
|
+
if (!trimmed) return configuredPath;
|
|
56
|
+
if (remoteDevAuth.isRemoteSecretsUrl(trimmed)) return trimmed.replace(/\/+$/, '');
|
|
57
|
+
const auth = await remoteDevAuth.getRemoteDevAuth();
|
|
58
|
+
if (!auth) return configuredPath;
|
|
59
|
+
const abs = normalizeSharedSecretsFilePath(trimmed);
|
|
60
|
+
if (!abs) return configuredPath;
|
|
61
|
+
const home = path.normalize(getAifabrixHome());
|
|
62
|
+
if (isPathUnderDir(abs, home)) return configuredPath;
|
|
63
|
+
const work = getAifabrixWork();
|
|
64
|
+
if (work) {
|
|
65
|
+
const w = path.normalize(work);
|
|
66
|
+
if (isPathUnderDir(abs, w)) return configuredPath;
|
|
67
|
+
}
|
|
68
|
+
const base = String(auth.serverUrl).replace(/\/+$/, '');
|
|
69
|
+
return `${base}/api/dev/secrets`;
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Hostname from a resolved shared-secrets API URL (for CLI labels).
|
|
74
|
+
* @param {string} secretsEndpointUrl - e.g. https://builder02.local/api/dev/secrets
|
|
75
|
+
* @returns {string|null} Hostname, or null if the URL cannot be parsed
|
|
76
|
+
*/
|
|
77
|
+
getSharedSecretsRemoteHostname(secretsEndpointUrl) {
|
|
78
|
+
try {
|
|
79
|
+
const u = new URL(String(secretsEndpointUrl));
|
|
80
|
+
return u.hostname || null;
|
|
81
|
+
} catch {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Titles/messages for `secret list --shared` when the store is remote.
|
|
88
|
+
* @param {string} secretsEndpointUrl - Resolved secrets API URL
|
|
89
|
+
* @returns {{ title: string, emptyMessage: string }}
|
|
90
|
+
*/
|
|
91
|
+
getSharedSecretsRemoteListLabels(secretsEndpointUrl) {
|
|
92
|
+
const host = remoteDevAuth.getSharedSecretsRemoteHostname(secretsEndpointUrl);
|
|
93
|
+
if (host) {
|
|
94
|
+
return {
|
|
95
|
+
title: `Shared secrets (remote - ${host})`,
|
|
96
|
+
emptyMessage: `No shared secrets (remote - ${host}).`
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
title: 'Shared secrets (remote)',
|
|
101
|
+
emptyMessage: 'No shared secrets (remote).'
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* True when normalized file path is dir or a descendant of base (same volume semantics as path relative checks).
|
|
108
|
+
* @param {string} filePath - Normalized absolute path
|
|
109
|
+
* @param {string} baseDir - Normalized absolute directory
|
|
14
110
|
* @returns {boolean}
|
|
15
111
|
*/
|
|
16
|
-
function
|
|
17
|
-
|
|
112
|
+
function isPathUnderDir(filePath, baseDir) {
|
|
113
|
+
if (!filePath || !baseDir) return false;
|
|
114
|
+
const f = filePath;
|
|
115
|
+
const d = baseDir;
|
|
116
|
+
if (f === d) return true;
|
|
117
|
+
const prefix = d.endsWith(path.sep) ? d : d + path.sep;
|
|
118
|
+
return f.startsWith(prefix);
|
|
18
119
|
}
|
|
19
120
|
|
|
20
121
|
/**
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* @returns {
|
|
122
|
+
* Normalize configured shared-secrets file path for "is this on the laptop?" checks.
|
|
123
|
+
* @param {string} configured - Raw config value
|
|
124
|
+
* @returns {string} Absolute normalized path
|
|
24
125
|
*/
|
|
25
|
-
|
|
26
|
-
const
|
|
27
|
-
if (!
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
if (!clientCertPem) return null;
|
|
32
|
-
return { serverUrl, clientCertPem };
|
|
126
|
+
function normalizeSharedSecretsFilePath(configured) {
|
|
127
|
+
const trimmed = String(configured || '').trim();
|
|
128
|
+
if (!trimmed) return '';
|
|
129
|
+
return path.isAbsolute(trimmed)
|
|
130
|
+
? path.normalize(trimmed)
|
|
131
|
+
: path.normalize(path.resolve(process.cwd(), trimmed));
|
|
33
132
|
}
|
|
34
133
|
|
|
35
|
-
module.exports =
|
|
36
|
-
isRemoteSecretsUrl,
|
|
37
|
-
getRemoteDevAuth
|
|
38
|
-
};
|
|
134
|
+
module.exports = remoteDevAuth;
|