@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
package/lib/core/secrets.js
CHANGED
|
@@ -24,10 +24,14 @@ const {
|
|
|
24
24
|
rewriteInfraEndpoints,
|
|
25
25
|
readYamlAtPath,
|
|
26
26
|
applyCanonicalSecretsOverride,
|
|
27
|
-
ensureNonEmptySecrets,
|
|
28
27
|
validateSecrets
|
|
29
28
|
} = require('../utils/secrets-helpers');
|
|
30
29
|
const { buildEnvVarMap } = require('../utils/env-map');
|
|
30
|
+
const {
|
|
31
|
+
mergeInfraParameterDefaultsForCli,
|
|
32
|
+
getInfraParameterCatalog,
|
|
33
|
+
readRelaxedCatalogDefaults
|
|
34
|
+
} = require('../parameters/infra-parameter-catalog');
|
|
31
35
|
const { resolveServicePortsInEnvContent } = require('../utils/secrets-url');
|
|
32
36
|
const {
|
|
33
37
|
updatePortForDocker,
|
|
@@ -35,7 +39,7 @@ const {
|
|
|
35
39
|
applyDockerEnvOverride,
|
|
36
40
|
getContainerPortFromDockerEnv
|
|
37
41
|
} = require('./secrets-docker-env');
|
|
38
|
-
const { getContainerPortFromPath } = require('../utils/port-resolver');
|
|
42
|
+
const { getContainerPortFromPath, loadVariablesFromPath } = require('../utils/port-resolver');
|
|
39
43
|
const {
|
|
40
44
|
generateMissingSecrets,
|
|
41
45
|
createDefaultSecrets
|
|
@@ -48,10 +52,21 @@ const {
|
|
|
48
52
|
const {
|
|
49
53
|
loadUserSecrets,
|
|
50
54
|
loadPrimaryUserSecrets,
|
|
51
|
-
loadDefaultSecrets
|
|
55
|
+
loadDefaultSecrets,
|
|
56
|
+
ensurePrimaryUserSecretsFileExists
|
|
52
57
|
} = require('../utils/secrets-utils');
|
|
53
58
|
const { decryptSecret, isEncrypted } = require('../utils/secrets-encryption');
|
|
54
59
|
const pathsUtil = require('../utils/paths');
|
|
60
|
+
const { ensureSecureFilePermissions } = require('../utils/secure-file-permissions');
|
|
61
|
+
const { readAppEnvironmentScopedFlagForAppPath } = require('../utils/app-scoped-config');
|
|
62
|
+
const { computeEffectiveEnvironmentScopedResources, redisDbIndexForScopedRunEnv } = require('../utils/environment-scoped-resources');
|
|
63
|
+
const { applyRedisDbIndexToEnvContent } = require('../utils/redis-env-scope');
|
|
64
|
+
const { expandDeclarativeUrlsInEnvContent } = require('../utils/url-declarative-resolve');
|
|
65
|
+
const { rewriteInactiveDeclarativeVdirPublicContent } = require('../utils/url-declarative-vdir-inactive-env');
|
|
66
|
+
const {
|
|
67
|
+
mergeDockerManifestPublishedPort,
|
|
68
|
+
rewriteDockerManifestPublicPortEnvLine
|
|
69
|
+
} = require('../utils/docker-manifest-public-port');
|
|
55
70
|
|
|
56
71
|
/**
|
|
57
72
|
* Generates a canonical secret name from an environment variable key.
|
|
@@ -127,8 +142,8 @@ async function decryptSecretsObject(secrets) {
|
|
|
127
142
|
* @function loadSecrets
|
|
128
143
|
* @param {string} [secretsPath] - Path to secrets file (optional, for explicit override)
|
|
129
144
|
* @param {string} [appName] - Application name (optional, for backward compatibility)
|
|
130
|
-
* @returns {Promise<Object>} Loaded secrets object with decrypted values
|
|
131
|
-
* @throws {Error} If
|
|
145
|
+
* @returns {Promise<Object>} Loaded secrets object with decrypted values (may be empty after bootstrap file create)
|
|
146
|
+
* @throws {Error} If explicit secretsPath is set but file is missing or invalid
|
|
132
147
|
*
|
|
133
148
|
* @example
|
|
134
149
|
* const secrets = await loadSecrets('../../secrets.local.yaml');
|
|
@@ -150,6 +165,7 @@ function mergeUserWithConfigFile(userSecrets, resolvedConfigPath) {
|
|
|
150
165
|
if (!fs.existsSync(resolvedConfigPath)) {
|
|
151
166
|
return null;
|
|
152
167
|
}
|
|
168
|
+
ensureSecureFilePermissions(resolvedConfigPath);
|
|
153
169
|
let configSecrets;
|
|
154
170
|
try {
|
|
155
171
|
configSecrets = readYamlAtPath(resolvedConfigPath);
|
|
@@ -170,16 +186,17 @@ function mergeUserWithConfigFile(userSecrets, resolvedConfigPath) {
|
|
|
170
186
|
|
|
171
187
|
/**
|
|
172
188
|
* Loads config secrets path, merges with user secrets (user/master wins, public fills missing).
|
|
173
|
-
* User/master =
|
|
189
|
+
* User/master = getPrimaryUserSecretsLocalPath() (config dir; same file as loadPrimaryUserSecrets).
|
|
174
190
|
* Public = aifabrix-secrets path from config. Used by loadSecrets cascade.
|
|
175
|
-
* When
|
|
191
|
+
* When the effective shared-secrets target (after remote-dev resolution) is an http(s) URL,
|
|
192
|
+
* fetches shared secrets from API (never persisted to disk).
|
|
176
193
|
*
|
|
177
194
|
* @async
|
|
178
195
|
* @returns {Promise<Object|null>} Merged secrets object or null
|
|
179
196
|
*/
|
|
180
197
|
async function loadMergedConfigAndUserSecrets() {
|
|
181
198
|
const { loadRemoteSharedSecrets, mergeUserWithRemoteSecrets } = require('../utils/remote-secrets-loader');
|
|
182
|
-
const
|
|
199
|
+
const remoteDevAuth = require('../utils/remote-dev-auth');
|
|
183
200
|
const userSecrets = loadPrimaryUserSecrets();
|
|
184
201
|
const hasKeys = (obj) => obj && Object.keys(obj).length > 0;
|
|
185
202
|
const userOrNull = () => (hasKeys(userSecrets) ? userSecrets : null);
|
|
@@ -188,7 +205,8 @@ async function loadMergedConfigAndUserSecrets() {
|
|
|
188
205
|
if (!configSecretsPath) {
|
|
189
206
|
return userOrNull();
|
|
190
207
|
}
|
|
191
|
-
|
|
208
|
+
const effectiveShared = await remoteDevAuth.resolveSharedSecretsEndpoint(configSecretsPath);
|
|
209
|
+
if (remoteDevAuth.isRemoteSecretsUrl(effectiveShared)) {
|
|
192
210
|
const remoteSecrets = await loadRemoteSharedSecrets();
|
|
193
211
|
const merged = mergeUserWithRemoteSecrets(userSecrets, remoteSecrets);
|
|
194
212
|
return hasKeys(merged) ? merged : userOrNull();
|
|
@@ -225,6 +243,7 @@ async function loadSecretsWithFallbacks() {
|
|
|
225
243
|
if (projectRoot) {
|
|
226
244
|
const builderPath = path.join(projectRoot, 'builder', 'secrets.local.yaml');
|
|
227
245
|
if (fs.existsSync(builderPath)) {
|
|
246
|
+
ensureSecureFilePermissions(builderPath);
|
|
228
247
|
const builderSecrets = mergeUserWithConfigFile(merged || {}, builderPath);
|
|
229
248
|
if (builderSecrets) merged = builderSecrets;
|
|
230
249
|
}
|
|
@@ -244,15 +263,19 @@ async function loadSecrets(secretsPath, _appName) {
|
|
|
244
263
|
if (!fs.existsSync(resolvedPath)) {
|
|
245
264
|
throw new Error(`Secrets file not found: ${resolvedPath}`);
|
|
246
265
|
}
|
|
266
|
+
ensureSecureFilePermissions(resolvedPath);
|
|
247
267
|
const explicitSecrets = readYamlAtPath(resolvedPath);
|
|
248
268
|
if (!explicitSecrets || typeof explicitSecrets !== 'object') {
|
|
249
269
|
throw new Error(`Invalid secrets file format: ${resolvedPath}`);
|
|
250
270
|
}
|
|
251
271
|
return await decryptSecretsObject(explicitSecrets);
|
|
252
272
|
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
273
|
+
let mergedSecrets = await loadSecretsWithFallbacks();
|
|
274
|
+
if (!mergedSecrets || Object.keys(mergedSecrets).length === 0) {
|
|
275
|
+
ensurePrimaryUserSecretsFileExists();
|
|
276
|
+
mergedSecrets = await loadSecretsWithFallbacks();
|
|
277
|
+
}
|
|
278
|
+
return await decryptSecretsObject(mergedSecrets || {});
|
|
256
279
|
}
|
|
257
280
|
|
|
258
281
|
/**
|
|
@@ -275,7 +298,7 @@ async function loadSecrets(secretsPath, _appName) {
|
|
|
275
298
|
* const resolved = await resolveKvReferences(template, secrets, 'local');
|
|
276
299
|
* // Returns: 'DATABASE_URL=postgresql://user:pass@localhost:5432/db'
|
|
277
300
|
*/
|
|
278
|
-
async function resolveKvReferences(envTemplate, secrets, environment = 'local', secretsFilePaths = null, appName = null) {
|
|
301
|
+
async function resolveKvReferences(envTemplate, secrets, environment = 'local', secretsFilePaths = null, appName = null, scopedKv = null) {
|
|
279
302
|
const os = require('os');
|
|
280
303
|
|
|
281
304
|
// Get developer-id for port variables (local and docker: *_PUBLIC_PORT = base + devId*100)
|
|
@@ -286,25 +309,56 @@ async function resolveKvReferences(envTemplate, secrets, environment = 'local',
|
|
|
286
309
|
// ignore, buildEnvVarMap will use default
|
|
287
310
|
}
|
|
288
311
|
|
|
289
|
-
|
|
312
|
+
const envKey = String(environment || 'local').toLowerCase();
|
|
313
|
+
const mapContext = envKey === 'docker' || envKey === 'local' ? envKey : 'local';
|
|
314
|
+
|
|
315
|
+
let envVars = await buildEnvVarMap(mapContext, os, developerId);
|
|
290
316
|
if (!envVars || Object.keys(envVars).length === 0) {
|
|
291
317
|
// Fallback to local environment variables if requested environment does not exist
|
|
292
318
|
envVars = await buildEnvVarMap('local', os, developerId);
|
|
293
319
|
}
|
|
294
320
|
const resolved = interpolateEnvVars(envTemplate, envVars);
|
|
295
|
-
const missing = collectMissingSecrets(resolved, secrets);
|
|
321
|
+
const missing = collectMissingSecrets(resolved, secrets, scopedKv);
|
|
296
322
|
if (missing.length > 0) {
|
|
297
323
|
const fileInfo = formatMissingSecretsFileInfo(secretsFilePaths);
|
|
298
324
|
const resolveCommand = appName ? `aifabrix resolve ${appName}` : 'aifabrix resolve <app-name>';
|
|
299
325
|
throw new Error(`Missing secrets: ${missing.join(', ')}${fileInfo}\n\nRun "${resolveCommand}" to generate missing secrets.`);
|
|
300
326
|
}
|
|
301
|
-
return replaceKvInContent(resolved, secrets, envVars);
|
|
327
|
+
return replaceKvInContent(resolved, secrets, envVars, scopedKv);
|
|
302
328
|
}
|
|
303
329
|
|
|
304
|
-
/**
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
330
|
+
/**
|
|
331
|
+
* Resolve run env key and effective env-scoped kv/redis behavior for generateEnvContent.
|
|
332
|
+
*
|
|
333
|
+
* @async
|
|
334
|
+
* @param {string} appPath - Builder application directory
|
|
335
|
+
* @param {Object} [options] - generateEnvContent options; may set runEnvKey
|
|
336
|
+
* @returns {Promise<{ runEnvKey: string, effective: boolean }>}
|
|
337
|
+
*/
|
|
338
|
+
async function buildScopedKvContext(appPath, options = {}) {
|
|
339
|
+
let runEnvKey;
|
|
340
|
+
if (options.runEnvKey !== undefined && options.runEnvKey !== null) {
|
|
341
|
+
runEnvKey = String(options.runEnvKey).toLowerCase();
|
|
342
|
+
} else if (typeof config.getCurrentEnvironment === 'function') {
|
|
343
|
+
runEnvKey = String((await config.getCurrentEnvironment()) || 'dev').toLowerCase();
|
|
344
|
+
} else {
|
|
345
|
+
runEnvKey = 'dev';
|
|
346
|
+
}
|
|
347
|
+
const userCfg =
|
|
348
|
+
typeof config.getConfig === 'function'
|
|
349
|
+
? await config.getConfig()
|
|
350
|
+
: { useEnvironmentScopedResources: false };
|
|
351
|
+
const useGate = Boolean(userCfg.useEnvironmentScopedResources);
|
|
352
|
+
const appFlag = readAppEnvironmentScopedFlagForAppPath(appPath);
|
|
353
|
+
const effective = computeEffectiveEnvironmentScopedResources(useGate, appFlag, runEnvKey);
|
|
354
|
+
return { runEnvKey, effective };
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Redis/DB service endpoints for docker env interpolation.
|
|
359
|
+
* @returns {Promise<{ redisHost: string, redisPort: number, dbHost: string, dbPort: number }>}
|
|
360
|
+
*/
|
|
361
|
+
async function getDockerRedisDbEndpoints() {
|
|
308
362
|
const { getEnvHosts, getServiceHost, getServicePort, getLocalhostOverride } = require('../utils/env-endpoints');
|
|
309
363
|
const hosts = await getEnvHosts('docker');
|
|
310
364
|
const localhostOverride = getLocalhostOverride('docker');
|
|
@@ -312,16 +366,97 @@ async function applyDockerTransformations(resolved, variablesPath) {
|
|
|
312
366
|
const redisPort = await getServicePort('REDIS_PORT', 'redis', hosts, 'docker', null);
|
|
313
367
|
const dbHost = getServiceHost(hosts.DB_HOST, 'docker', 'postgres', localhostOverride);
|
|
314
368
|
const dbPort = await getServicePort('DB_PORT', 'postgres', hosts, 'docker', null);
|
|
369
|
+
return { redisHost, redisPort, dbHost, dbPort };
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Config inputs for declarative url:// expansion (keeps expandDeclarativeUrlsIfPresent small).
|
|
374
|
+
* @param {string} appPath
|
|
375
|
+
* @returns {Promise<Object>}
|
|
376
|
+
*/
|
|
377
|
+
async function loadDeclarativeUrlExpandInputs(appPath) {
|
|
378
|
+
const userCfg = await config.getConfig();
|
|
379
|
+
let remoteServer = null;
|
|
380
|
+
try {
|
|
381
|
+
const rs = await config.getRemoteServer();
|
|
382
|
+
if (rs && String(rs).trim()) {
|
|
383
|
+
remoteServer = String(rs).trim();
|
|
384
|
+
}
|
|
385
|
+
} catch {
|
|
386
|
+
remoteServer = null;
|
|
387
|
+
}
|
|
388
|
+
let developerIdRaw = null;
|
|
389
|
+
try {
|
|
390
|
+
developerIdRaw = await config.getDeveloperId();
|
|
391
|
+
} catch {
|
|
392
|
+
developerIdRaw = null;
|
|
393
|
+
}
|
|
394
|
+
let infraTlsEnabled = false;
|
|
395
|
+
try {
|
|
396
|
+
infraTlsEnabled = await config.getTlsEnabled();
|
|
397
|
+
} catch {
|
|
398
|
+
infraTlsEnabled = false;
|
|
399
|
+
}
|
|
400
|
+
return {
|
|
401
|
+
userCfg,
|
|
402
|
+
remoteServer,
|
|
403
|
+
developerIdRaw,
|
|
404
|
+
infraTlsEnabled,
|
|
405
|
+
appScopedFlag: readAppEnvironmentScopedFlagForAppPath(appPath)
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* After kv:// resolution, expand url:// references when application config exists.
|
|
411
|
+
* @param {string} resolved
|
|
412
|
+
* @param {string} appName
|
|
413
|
+
* @param {string} appPath
|
|
414
|
+
* @param {string|null} variablesPath
|
|
415
|
+
* @param {string} environment
|
|
416
|
+
* @param {boolean} envOnly
|
|
417
|
+
* @returns {Promise<string>}
|
|
418
|
+
*/
|
|
419
|
+
async function expandDeclarativeUrlsIfPresent(resolved, appName, appPath, variablesPath, environment, envOnly) {
|
|
420
|
+
if (envOnly || !variablesPath) {
|
|
421
|
+
return resolved;
|
|
422
|
+
}
|
|
423
|
+
const { userCfg, remoteServer, developerIdRaw, infraTlsEnabled, appScopedFlag } =
|
|
424
|
+
await loadDeclarativeUrlExpandInputs(appPath);
|
|
425
|
+
resolved = rewriteInactiveDeclarativeVdirPublicContent(resolved, variablesPath, userCfg);
|
|
426
|
+
if (!resolved.includes('url://')) {
|
|
427
|
+
return resolved;
|
|
428
|
+
}
|
|
429
|
+
return expandDeclarativeUrlsInEnvContent(resolved, {
|
|
430
|
+
profile: environment === 'docker' ? 'docker' : 'local',
|
|
431
|
+
currentAppKey: appName,
|
|
432
|
+
variablesPath,
|
|
433
|
+
useEnvironmentScopedResources: Boolean(userCfg.useEnvironmentScopedResources),
|
|
434
|
+
appEnvironmentScopedResources: appScopedFlag,
|
|
435
|
+
remoteServer,
|
|
436
|
+
developerIdRaw,
|
|
437
|
+
traefik: Boolean(userCfg.traefik),
|
|
438
|
+
infraTlsEnabled
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/** Docker env transformations: ports, infra endpoints, PORT. */
|
|
443
|
+
async function applyDockerTransformations(resolved, variablesPath) {
|
|
444
|
+
resolved = await resolveServicePortsInEnvContent(resolved, 'docker');
|
|
445
|
+
resolved = await rewriteInfraEndpoints(resolved, 'docker');
|
|
446
|
+
const { redisHost, redisPort, dbHost, dbPort } = await getDockerRedisDbEndpoints();
|
|
315
447
|
let dockerEnv = await getBaseDockerEnv();
|
|
316
448
|
dockerEnv = applyDockerEnvOverride(dockerEnv);
|
|
317
449
|
const containerPort = getContainerPortFromPath(variablesPath) ?? getContainerPortFromDockerEnv(dockerEnv) ?? 3000;
|
|
318
450
|
const envVars = await buildEnvVarMap('docker', null, null, { appPort: containerPort });
|
|
451
|
+
const appDoc = loadVariablesFromPath(variablesPath);
|
|
452
|
+
await mergeDockerManifestPublishedPort(envVars, appDoc);
|
|
319
453
|
envVars.REDIS_HOST = redisHost;
|
|
320
454
|
envVars.REDIS_PORT = String(redisPort);
|
|
321
455
|
envVars.DB_HOST = dbHost;
|
|
322
456
|
envVars.DB_PORT = String(dbPort);
|
|
323
457
|
envVars.PORT = String(containerPort);
|
|
324
458
|
resolved = interpolateEnvVars(resolved, envVars);
|
|
459
|
+
resolved = rewriteDockerManifestPublicPortEnvLine(resolved, envVars, appDoc);
|
|
325
460
|
return updatePortForDocker(resolved, variablesPath);
|
|
326
461
|
}
|
|
327
462
|
/** Environment-specific transformations to resolved content. */
|
|
@@ -353,8 +488,22 @@ async function generateEnvContent(appName, secretsPath, environment = 'local', f
|
|
|
353
488
|
await secretsEnsure.ensureSecretsFromEnvTemplate(templatePath, { preferredFilePath: preferredPath });
|
|
354
489
|
}
|
|
355
490
|
const secrets = await loadSecrets(secretsPath, appName);
|
|
356
|
-
|
|
491
|
+
const { runEnvKey, effective } = await buildScopedKvContext(appPath, options);
|
|
492
|
+
const scopedKv = { envKey: runEnvKey, effective };
|
|
493
|
+
let resolved = await resolveKvReferences(template, secrets, environment, secretsPaths, appName, scopedKv);
|
|
494
|
+
resolved = await expandDeclarativeUrlsIfPresent(
|
|
495
|
+
resolved,
|
|
496
|
+
appName,
|
|
497
|
+
appPath,
|
|
498
|
+
variablesPath,
|
|
499
|
+
environment,
|
|
500
|
+
Boolean(options.envOnly)
|
|
501
|
+
);
|
|
357
502
|
resolved = await applyEnvironmentTransformations(resolved, environment, variablesPath);
|
|
503
|
+
if (effective) {
|
|
504
|
+
const idx = redisDbIndexForScopedRunEnv(runEnvKey);
|
|
505
|
+
resolved = applyRedisDbIndexToEnvContent(resolved, idx);
|
|
506
|
+
}
|
|
358
507
|
|
|
359
508
|
return resolved;
|
|
360
509
|
}
|
|
@@ -516,40 +665,76 @@ async function generateEnvFile(appName, secretsPath, environment = 'local', forc
|
|
|
516
665
|
return envPath;
|
|
517
666
|
}
|
|
518
667
|
|
|
519
|
-
/**
|
|
520
|
-
|
|
521
|
-
|
|
668
|
+
/**
|
|
669
|
+
* Writes admin env key-value pairs to content; encrypts values when encryption key is set.
|
|
670
|
+
* @async
|
|
671
|
+
* @param {Object.<string, string>} adminObj - Key-value object (e.g. POSTGRES_PASSWORD, ...)
|
|
672
|
+
* @returns {Promise<string>} .env-style content (plaintext or secure:// for secrets)
|
|
673
|
+
*/
|
|
674
|
+
async function formatAdminSecretsContent(adminObj) {
|
|
675
|
+
const encryptionKey = await config.getSecretsEncryptionKey();
|
|
676
|
+
const { encryptSecret } = require('../utils/secrets-encryption');
|
|
677
|
+
const lines = ['# Infrastructure Admin Credentials'];
|
|
678
|
+
for (const [k, v] of Object.entries(adminObj)) {
|
|
679
|
+
const value = (v === null || v === undefined) ? '' : String(v).replace(/\n/g, ' ').trim();
|
|
680
|
+
const valueToWrite = encryptionKey ? encryptSecret(value, encryptionKey) : value;
|
|
681
|
+
lines.push(`${k}=${valueToWrite}`);
|
|
682
|
+
}
|
|
683
|
+
return lines.join('\n');
|
|
684
|
+
}
|
|
522
685
|
|
|
686
|
+
async function loadSecretsOrBootstrapForAdmin(secretsPath) {
|
|
523
687
|
try {
|
|
524
|
-
|
|
688
|
+
return await loadSecrets(secretsPath);
|
|
525
689
|
} catch (error) {
|
|
526
690
|
const defaultSecretsPath = secretsPath || path.join(pathsUtil.getAifabrixHome(), 'secrets.yaml');
|
|
527
691
|
if (!fs.existsSync(defaultSecretsPath)) {
|
|
528
692
|
logger.log('Creating default secrets file...');
|
|
529
693
|
await createDefaultSecrets(defaultSecretsPath);
|
|
530
|
-
|
|
531
|
-
} else {
|
|
532
|
-
throw error;
|
|
694
|
+
return await loadSecrets(secretsPath);
|
|
533
695
|
}
|
|
696
|
+
throw error;
|
|
534
697
|
}
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
function getInfraDefaultsMergedForAdmin() {
|
|
701
|
+
try {
|
|
702
|
+
return mergeInfraParameterDefaultsForCli(getInfraParameterCatalog().data, {});
|
|
703
|
+
} catch {
|
|
704
|
+
return {};
|
|
539
705
|
}
|
|
706
|
+
}
|
|
540
707
|
|
|
708
|
+
function buildLocalAdminSecretsObject(secrets, infraDefaults) {
|
|
541
709
|
const raw = secrets['postgres-passwordKeyVault'];
|
|
542
|
-
const
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
710
|
+
const relaxed = readRelaxedCatalogDefaults();
|
|
711
|
+
const postgresPassword =
|
|
712
|
+
(raw && String(raw).trim()) ||
|
|
713
|
+
infraDefaults.adminPassword ||
|
|
714
|
+
relaxed.adminPassword ||
|
|
715
|
+
'';
|
|
716
|
+
const pgAdminEmail = infraDefaults.adminEmail || relaxed.adminEmail || '';
|
|
717
|
+
return {
|
|
718
|
+
POSTGRES_PASSWORD: postgresPassword,
|
|
719
|
+
PGADMIN_DEFAULT_EMAIL: pgAdminEmail,
|
|
720
|
+
PGADMIN_DEFAULT_PASSWORD: postgresPassword,
|
|
721
|
+
REDIS_HOST: 'local:redis:6379:0:',
|
|
722
|
+
REDIS_COMMANDER_USER: 'admin',
|
|
723
|
+
REDIS_COMMANDER_PASSWORD: postgresPassword
|
|
724
|
+
};
|
|
725
|
+
}
|
|
552
726
|
|
|
727
|
+
/** Generates admin secrets for infrastructure (beside config.yaml, typically ~/.aifabrix/admin-secrets.env). Defaults from infra.parameter.yaml `defaults`. */
|
|
728
|
+
async function generateAdminSecretsEnv(secretsPath) {
|
|
729
|
+
const secrets = await loadSecretsOrBootstrapForAdmin(secretsPath);
|
|
730
|
+
const infraDefaults = getInfraDefaultsMergedForAdmin();
|
|
731
|
+
const adminObj = buildLocalAdminSecretsObject(secrets, infraDefaults);
|
|
732
|
+
const aifabrixDir = pathsUtil.getAifabrixSystemDir();
|
|
733
|
+
const adminEnvPath = path.join(aifabrixDir, 'admin-secrets.env');
|
|
734
|
+
if (!fs.existsSync(aifabrixDir)) {
|
|
735
|
+
fs.mkdirSync(aifabrixDir, { recursive: true, mode: 0o700 });
|
|
736
|
+
}
|
|
737
|
+
const adminSecrets = await formatAdminSecretsContent(adminObj);
|
|
553
738
|
fs.writeFileSync(adminEnvPath, adminSecrets, { mode: 0o600 });
|
|
554
739
|
return adminEnvPath;
|
|
555
740
|
}
|
|
@@ -560,6 +745,7 @@ module.exports = {
|
|
|
560
745
|
generateEnvContent,
|
|
561
746
|
generateMissingSecrets,
|
|
562
747
|
generateAdminSecretsEnv,
|
|
748
|
+
formatAdminSecretsContent,
|
|
563
749
|
validateSecrets,
|
|
564
750
|
createDefaultSecrets,
|
|
565
751
|
getCanonicalSecretName,
|
|
@@ -106,9 +106,10 @@ function buildMonitoringEnv(config) {
|
|
|
106
106
|
return {
|
|
107
107
|
'MISO_CONTROLLER_URL': config.controllerUrl || 'https://controller.aifabrix.dev',
|
|
108
108
|
'MISO_ENVIRONMENT': 'dev',
|
|
109
|
-
|
|
110
|
-
'
|
|
111
|
-
'
|
|
109
|
+
// Filled after `aifabrix register <app>`; empty avoids bogus kv placeholders in new apps
|
|
110
|
+
'MISO_CLIENTID': '',
|
|
111
|
+
'MISO_CLIENTSECRET': '',
|
|
112
|
+
'MISO_WEB_SERVER_URL': 'url://miso-controller-public'
|
|
112
113
|
};
|
|
113
114
|
}
|
|
114
115
|
|
package/lib/core/templates.js
CHANGED
|
@@ -268,7 +268,7 @@ function generateSecretsYaml(config, existingSecrets = {}) {
|
|
|
268
268
|
Object.entries(existingSecrets).forEach(([key, value]) => {
|
|
269
269
|
secrets.data[key] = Buffer.from(value).toString('base64');
|
|
270
270
|
});
|
|
271
|
-
return yaml.dump(secrets, { indent: 2, lineWidth:
|
|
271
|
+
return yaml.dump(secrets, { indent: 2, lineWidth: -1, noRefs: true, sortKeys: false });
|
|
272
272
|
}
|
|
273
273
|
|
|
274
274
|
module.exports = {
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ABAC (Attribute-Based Access Control) validator for external datasources.
|
|
3
|
+
*
|
|
4
|
+
* Validates config.abac.dimensions (dimension-to-attribute references),
|
|
5
|
+
* config.abac.crossSystemJson (allowed operators, one per path, value types),
|
|
6
|
+
* and errors on legacy config.abac.crossSystem.
|
|
7
|
+
*
|
|
8
|
+
* @fileoverview ABAC validation for AI Fabrix Builder
|
|
9
|
+
* @author AI Fabrix Team
|
|
10
|
+
* @version 2.0.0
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const DIMENSION_KEY_PATTERN = /^[a-zA-Z0-9_]+$/;
|
|
14
|
+
const ATTRIBUTE_PATH_PATTERN = /^[a-zA-Z0-9_.]+$/;
|
|
15
|
+
const CROSS_SYSTEM_JSON_PATH_PATTERN = /^[a-zA-Z0-9_.]+$/;
|
|
16
|
+
const ALLOWED_CROSS_SYSTEM_OPERATORS = new Set([
|
|
17
|
+
'eq', 'ne', 'gt', 'lt', 'gte', 'lte', 'in', 'nin', 'contains', 'like', 'isNull', 'isNotNull'
|
|
18
|
+
]);
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Validates dimension keys and attribute path values for a dimensions object.
|
|
22
|
+
*
|
|
23
|
+
* @param {Object} dimensions - Object mapping dimension keys to attribute paths
|
|
24
|
+
* @param {string} source - Label for error messages (e.g. "config.abac.dimensions")
|
|
25
|
+
* @param {Set<string>} validAttributeNames - Set of valid attribute names (from fieldMappings.attributes)
|
|
26
|
+
* @returns {string[]} Error messages
|
|
27
|
+
*/
|
|
28
|
+
function validateDimensionsObject(dimensions, source, validAttributeNames) {
|
|
29
|
+
const errors = [];
|
|
30
|
+
if (!dimensions || typeof dimensions !== 'object' || Array.isArray(dimensions)) {
|
|
31
|
+
return errors;
|
|
32
|
+
}
|
|
33
|
+
for (const [dimKey, attrPath] of Object.entries(dimensions)) {
|
|
34
|
+
if (!DIMENSION_KEY_PATTERN.test(dimKey)) {
|
|
35
|
+
errors.push(
|
|
36
|
+
`${source}: dimension key '${dimKey}' must contain only letters, numbers, and underscores. Add '${dimKey}' to fieldMappings.attributes or fix the key.`
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
if (typeof attrPath !== 'string' || !ATTRIBUTE_PATH_PATTERN.test(attrPath)) {
|
|
40
|
+
errors.push(
|
|
41
|
+
`${source}: attribute path for dimension '${dimKey}' must be a string with letters, numbers, underscores, and dots only.`
|
|
42
|
+
);
|
|
43
|
+
} else if (validAttributeNames && validAttributeNames.size > 0) {
|
|
44
|
+
const normalizedName = attrPath.includes('.') ? attrPath.split('.').pop() : attrPath;
|
|
45
|
+
if (!validAttributeNames.has(attrPath) && !validAttributeNames.has(normalizedName)) {
|
|
46
|
+
errors.push(
|
|
47
|
+
`${source}: dimension '${dimKey}' maps to '${attrPath}' which is not in fieldMappings.attributes. Add the attribute or remove from dimensions.`
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return errors;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Validates crossSystemJson: path format, exactly one operator per path, allowed operators and value types.
|
|
57
|
+
*
|
|
58
|
+
* @param {Object} crossSystemJson - Object mapping field paths to operator objects
|
|
59
|
+
* @returns {string[]} Error messages
|
|
60
|
+
*/
|
|
61
|
+
function validateCrossSystemJson(crossSystemJson) {
|
|
62
|
+
const errors = [];
|
|
63
|
+
if (!crossSystemJson || typeof crossSystemJson !== 'object' || Array.isArray(crossSystemJson)) {
|
|
64
|
+
return errors;
|
|
65
|
+
}
|
|
66
|
+
for (const [path, opObj] of Object.entries(crossSystemJson)) {
|
|
67
|
+
if (!CROSS_SYSTEM_JSON_PATH_PATTERN.test(path)) {
|
|
68
|
+
errors.push(
|
|
69
|
+
`config.abac.crossSystemJson: path '${path}' must contain only letters, numbers, underscores, and dots.`
|
|
70
|
+
);
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
if (typeof opObj !== 'object' || opObj === null || Array.isArray(opObj)) {
|
|
74
|
+
errors.push(
|
|
75
|
+
`config.abac.crossSystemJson.${path}: value must be an object with exactly one operator (e.g. { "eq": "user.country" }).`
|
|
76
|
+
);
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
const keys = Object.keys(opObj);
|
|
80
|
+
if (keys.length === 0) {
|
|
81
|
+
errors.push(
|
|
82
|
+
`config.abac.crossSystemJson.${path}: object must have exactly one operator. Allowed: ${[...ALLOWED_CROSS_SYSTEM_OPERATORS].join(', ')}.`
|
|
83
|
+
);
|
|
84
|
+
} else if (keys.length > 1) {
|
|
85
|
+
errors.push(
|
|
86
|
+
`config.abac.crossSystemJson.${path}: must have exactly one operator per path, got ${keys.join(', ')}. Use one of: ${[...ALLOWED_CROSS_SYSTEM_OPERATORS].join(', ')}.`
|
|
87
|
+
);
|
|
88
|
+
} else {
|
|
89
|
+
const op = keys[0];
|
|
90
|
+
if (!ALLOWED_CROSS_SYSTEM_OPERATORS.has(op)) {
|
|
91
|
+
errors.push(
|
|
92
|
+
`config.abac.crossSystemJson.${path}: unknown operator '${op}'. Allowed: ${[...ALLOWED_CROSS_SYSTEM_OPERATORS].join(', ')}.`
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return errors;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Validates ABAC configuration for a parsed datasource.
|
|
102
|
+
* Checks dimensions from config.abac, crossSystemJson, and rejects legacy crossSystem.
|
|
103
|
+
*
|
|
104
|
+
* @function validateAbac
|
|
105
|
+
* @param {Object} parsed - Parsed datasource object (after JSON parse)
|
|
106
|
+
* @returns {string[]} Array of error messages; empty if valid
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* const errors = validateAbac(parsed);
|
|
110
|
+
* if (errors.length > 0) errors.forEach(e => console.error(e));
|
|
111
|
+
*/
|
|
112
|
+
function validateAbac(parsed) {
|
|
113
|
+
const errors = [];
|
|
114
|
+
const abac = parsed?.config?.abac;
|
|
115
|
+
if (!abac || typeof abac !== 'object') {
|
|
116
|
+
return errors;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if ('crossSystem' in abac) {
|
|
120
|
+
errors.push(
|
|
121
|
+
'config.abac.crossSystem is deprecated. Use config.abac.crossSystemJson or config.abac.crossSystemSql instead.'
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const attributeNames = new Set(
|
|
126
|
+
Object.keys(parsed?.fieldMappings?.attributes ?? {})
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
if (abac.dimensions) {
|
|
130
|
+
errors.push(...validateDimensionsObject(
|
|
131
|
+
abac.dimensions,
|
|
132
|
+
'config.abac.dimensions',
|
|
133
|
+
attributeNames
|
|
134
|
+
));
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (abac.crossSystemJson) {
|
|
138
|
+
errors.push(...validateCrossSystemJson(abac.crossSystemJson));
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return errors;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
module.exports = {
|
|
145
|
+
validateAbac,
|
|
146
|
+
validateDimensionsObject,
|
|
147
|
+
validateCrossSystemJson
|
|
148
|
+
};
|