@aifabrix/builder 2.42.1 → 2.44.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.cursor/rules/anchor-docs.mdc +15 -0
- package/README.md +2 -2
- package/anchor-docs/README.md +10 -0
- package/anchor-docs/_TEMPLATE +24 -0
- package/bin/aifabrix.js +13 -4
- package/integration/hubspot-test/README.md +157 -0
- package/integration/{hubspot → hubspot-test}/application.json +6 -6
- package/integration/{hubspot → hubspot-test}/create-hubspot.js +10 -10
- package/integration/hubspot-test/env.template +4 -0
- package/integration/hubspot-test/hubspot-test-datasource-company.json +138 -0
- package/integration/hubspot-test/hubspot-test-datasource-contact.json +146 -0
- package/integration/hubspot-test/hubspot-test-datasource-deal.json +146 -0
- package/integration/hubspot-test/hubspot-test-datasource-users.json +76 -0
- package/integration/{hubspot/hubspot-deploy.json → hubspot-test/hubspot-test-deploy.json} +201 -24
- package/integration/{hubspot/hubspot-system.json → hubspot-test/hubspot-test-system.json} +8 -7
- package/integration/hubspot-test/rbac.json +166 -0
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-hubspot-credential-real.yaml +3 -3
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-hubspot-env-vars.yaml +2 -2
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-add-datasource.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-credential-create.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-credential-select.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-known-platform.yaml +1 -1
- package/integration/hubspot-test/test-artifacts/wizard-invalid-missing-source.yaml +2 -0
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-mode.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-openapi-file.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-openapi-url.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-source.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-valid-for-dimension-array-test.yaml +1 -1
- package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-key-test.yaml +5 -0
- package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-path-test.yaml +5 -0
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-valid-for-dimension-test.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-valid-for-rbac-test.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-valid-for-rbac-yaml-test.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-dataplane-down-tests.js +1 -7
- package/integration/{hubspot → hubspot-test}/test-dataplane-down.js +3 -3
- package/integration/{hubspot → hubspot-test}/test.js +137 -102
- package/integration/{hubspot → hubspot-test}/wizard-hubspot-e2e.yaml +2 -2
- package/integration/{hubspot → hubspot-test}/wizard-hubspot-platform.yaml +1 -1
- package/integration/hubspot-test/wizard-hubspot-test-headless.yaml +23 -0
- package/integration/roundtrip-test-local/README.md +144 -0
- package/integration/roundtrip-test-local/application.yaml +13 -0
- package/integration/roundtrip-test-local/env.template +15 -0
- package/integration/roundtrip-test-local/roundtrip-test-local-datasource-roundtrip-test-company.yaml +14 -0
- package/integration/roundtrip-test-local/roundtrip-test-local-deploy.json +61 -0
- package/integration/roundtrip-test-local/roundtrip-test-local-system.yaml +25 -0
- package/integration/roundtrip-test-local2/README.md +144 -0
- package/integration/roundtrip-test-local2/application.yaml +13 -0
- package/integration/roundtrip-test-local2/env.template +15 -0
- package/integration/roundtrip-test-local2/roundtrip-test-local2-datasource-company.yaml +31 -0
- package/integration/roundtrip-test-local2/roundtrip-test-local2-deploy.json +86 -0
- package/integration/roundtrip-test-local2/roundtrip-test-local2-system.yaml +25 -0
- package/integration/test/wizard.yaml +8 -0
- package/jest.config.default.js +10 -0
- package/jest.config.integration.fixtures.js +22 -0
- package/jest.config.integration.js +21 -18
- package/jest.config.isolated.js +10 -0
- package/jest.projects.js +288 -0
- package/lib/api/datasources-core.api.js +3 -3
- package/lib/api/dev-mtls-request.js +110 -0
- package/lib/api/dev-server-https.js +145 -0
- package/lib/api/dev.api.js +133 -144
- package/lib/api/index.js +0 -1
- package/lib/api/pipeline.api.js +67 -20
- package/lib/api/service-users.api.js +111 -2
- package/lib/api/types/dev.types.js +4 -3
- package/lib/api/types/pipeline.types.js +8 -5
- package/lib/api/types/service-users.types.js +41 -0
- package/lib/api/types/validation-run.types.js +56 -0
- package/lib/api/validation-run.api.js +99 -0
- package/lib/api/validation-runner.js +99 -0
- package/lib/app/config.js +1 -1
- package/lib/app/deploy-status-display.js +2 -2
- package/lib/app/deploy.js +7 -6
- package/lib/app/display.js +2 -1
- package/lib/app/dockerfile.js +3 -2
- package/lib/app/down.js +2 -1
- package/lib/app/helpers.js +6 -5
- package/lib/app/index.js +27 -8
- package/lib/app/list.js +7 -6
- package/lib/app/push.js +4 -3
- package/lib/app/register.js +19 -8
- package/lib/app/rotate-secret.js +17 -13
- package/lib/app/run-container-start.js +184 -0
- package/lib/app/run-docker-fallback.js +108 -0
- package/lib/app/run-env-compose.js +30 -42
- package/lib/app/run-helpers.js +49 -126
- package/lib/app/run-infra-requirements.js +30 -0
- package/lib/app/run-resolve-image.js +21 -0
- package/lib/app/run.js +74 -21
- package/lib/app/show-display.js +1 -1
- package/lib/app/show.js +1 -1
- package/lib/build/index.js +13 -10
- package/lib/cli/index.js +2 -0
- package/lib/cli/setup-app.help.js +67 -0
- package/lib/cli/setup-app.js +59 -123
- package/lib/cli/setup-app.test-commands.js +179 -0
- package/lib/cli/setup-auth.js +36 -14
- package/lib/cli/setup-credential-deployment.js +22 -8
- package/lib/cli/setup-dev-path-commands.js +124 -0
- package/lib/cli/setup-dev.js +190 -103
- package/lib/cli/setup-environment.js +11 -20
- package/lib/cli/setup-external-system.js +62 -22
- package/lib/cli/setup-infra.js +139 -47
- package/lib/cli/setup-parameters.js +32 -0
- package/lib/cli/setup-secrets.js +147 -10
- package/lib/cli/setup-service-user.js +146 -20
- package/lib/cli/setup-utility.js +47 -19
- package/lib/commands/app-down.js +5 -7
- package/lib/commands/app-install.js +14 -7
- package/lib/commands/app-logs.js +13 -10
- package/lib/commands/app-shell.js +4 -1
- package/lib/commands/app-test.js +25 -19
- package/lib/commands/app.js +22 -10
- package/lib/commands/auth-config.js +10 -14
- package/lib/commands/auth-status.js +4 -3
- package/lib/commands/credential-env.js +4 -3
- package/lib/commands/credential-list.js +5 -4
- package/lib/commands/credential-push.js +4 -3
- package/lib/commands/datasource-unified-test-cli.js +495 -0
- package/lib/commands/datasource-unified-test-cli.options.js +149 -0
- package/lib/commands/datasource-validation-cli.js +129 -0
- package/lib/commands/datasource.js +123 -71
- package/lib/commands/deployment-list.js +6 -5
- package/lib/commands/dev-cli-handlers.js +122 -18
- package/lib/commands/dev-down.js +4 -3
- package/lib/commands/dev-init.js +231 -116
- package/lib/commands/dev-show-display.js +473 -0
- package/lib/commands/login-credentials.js +3 -2
- package/lib/commands/login-device.js +4 -3
- package/lib/commands/login.js +5 -4
- package/lib/commands/logout.js +8 -7
- package/lib/commands/parameters-validate.js +54 -0
- package/lib/commands/repair-datasource.js +314 -68
- package/lib/commands/repair-env-template.js +16 -10
- package/lib/commands/repair-rbac.js +25 -19
- package/lib/commands/repair.js +116 -32
- package/lib/commands/secrets-list.js +23 -12
- package/lib/commands/secrets-remove-all.js +220 -0
- package/lib/commands/secrets-remove.js +22 -13
- package/lib/commands/secrets-set.js +21 -12
- package/lib/commands/secrets-validate.js +20 -7
- package/lib/commands/secure.js +10 -9
- package/lib/commands/service-user.js +243 -13
- package/lib/commands/test-e2e-external.js +27 -1
- package/lib/commands/up-common.js +28 -2
- package/lib/commands/up-dataplane.js +31 -18
- package/lib/commands/up-miso.js +19 -29
- package/lib/commands/upload.js +138 -39
- package/lib/commands/wizard-core-helpers.js +1 -1
- package/lib/commands/wizard-dataplane.js +4 -3
- package/lib/commands/wizard-helpers.js +3 -3
- package/lib/commands/wizard.js +2 -2
- package/lib/core/admin-secrets.js +16 -5
- package/lib/core/audit-logger.js +12 -4
- package/lib/core/config-attach-extensions.js +46 -0
- package/lib/core/config-runtime-paths.js +29 -0
- package/lib/core/config.js +59 -58
- package/lib/core/diff.js +3 -2
- package/lib/core/ensure-encryption-key.js +2 -4
- package/lib/core/secrets-ensure-infra.js +77 -0
- package/lib/core/secrets-ensure.js +120 -64
- package/lib/core/secrets-env-write.js +35 -7
- package/lib/core/secrets-infra-placeholder-sync.js +61 -0
- package/lib/core/secrets.js +228 -42
- package/lib/core/templates-env.js +4 -3
- package/lib/core/templates.js +1 -1
- package/lib/datasource/abac-validator.js +148 -0
- package/lib/datasource/deploy.js +75 -53
- package/lib/datasource/field-reference-validator.js +77 -36
- package/lib/datasource/integration-context.js +63 -0
- package/lib/datasource/list.js +8 -7
- package/lib/datasource/log-viewer.js +252 -0
- package/lib/datasource/resolve-app.js +109 -0
- package/lib/datasource/test-e2e.js +95 -155
- package/lib/datasource/test-integration.js +121 -109
- package/lib/datasource/unified-validation-run-body.js +65 -0
- package/lib/datasource/unified-validation-run-post.js +23 -0
- package/lib/datasource/unified-validation-run-resolve.js +43 -0
- package/lib/datasource/unified-validation-run.js +92 -0
- package/lib/datasource/validate.js +162 -15
- package/lib/deployment/deployer.js +4 -3
- package/lib/deployment/environment.js +7 -6
- package/lib/deployment/push.js +17 -8
- package/lib/external-system/delete.js +4 -3
- package/lib/external-system/deploy.js +131 -53
- package/lib/external-system/download-helpers.js +1 -1
- package/lib/external-system/download.js +7 -6
- package/lib/external-system/generator.js +104 -14
- package/lib/external-system/integration-test-dispatch.js +26 -0
- package/lib/external-system/test-execution.js +5 -1
- package/lib/external-system/test-helpers.js +0 -4
- package/lib/external-system/test-system-level-helpers.js +110 -0
- package/lib/external-system/test-system-level.js +83 -44
- package/lib/external-system/test.js +59 -8
- package/lib/generator/builders.js +23 -11
- package/lib/generator/deploy-manifest-azure-kv.js +81 -0
- package/lib/generator/external-controller-manifest.js +3 -3
- package/lib/generator/external.js +23 -11
- package/lib/generator/helpers.js +71 -12
- package/lib/generator/index.js +8 -4
- package/lib/generator/split-readme.js +12 -7
- package/lib/generator/split-variables.js +2 -1
- package/lib/generator/split.js +46 -11
- package/lib/generator/wizard-readme.js +3 -3
- package/lib/generator/wizard.js +16 -13
- package/lib/infrastructure/compose.js +60 -6
- package/lib/infrastructure/helpers.js +238 -51
- package/lib/infrastructure/index.js +64 -37
- package/lib/infrastructure/services.js +21 -15
- package/lib/internal/fs-real-sync.js +104 -0
- package/lib/internal/node-fs.js +98 -0
- package/lib/parameters/database-secret-values.js +173 -0
- package/lib/parameters/infra-kv-discovery.js +121 -0
- package/lib/parameters/infra-parameter-catalog.js +458 -0
- package/lib/parameters/infra-parameter-validate.js +64 -0
- package/lib/schema/application-schema.json +37 -17
- package/lib/schema/datasource-test-run.schema.json +493 -0
- package/lib/schema/deployment-rules.yaml +102 -63
- package/lib/schema/external-datasource.schema.json +1201 -433
- package/lib/schema/external-system.schema.json +181 -5
- package/lib/schema/flag-map-validation-run.json +31 -0
- package/lib/schema/infra-parameter.schema.json +106 -0
- package/lib/schema/infra.parameter.yaml +421 -0
- package/lib/schema/type/credential-auth-templates.json +40 -0
- package/lib/schema/type/document-storage.json +213 -0
- package/lib/schema/type/message-service.json +123 -0
- package/lib/schema/type/vector-store.json +88 -0
- package/lib/utils/aifabrix-runtime-config-dir.js +132 -0
- package/lib/utils/api-error-handler.js +2 -2
- package/lib/utils/api.js +49 -14
- package/lib/utils/app-config-resolver.js +23 -1
- package/lib/utils/app-register-api.js +3 -2
- package/lib/utils/app-register-auth.js +1 -1
- package/lib/utils/app-register-config.js +4 -4
- package/lib/utils/app-register-display.js +3 -2
- package/lib/utils/app-register-validator.js +3 -2
- package/lib/utils/app-run-containers.js +26 -22
- package/lib/utils/app-scoped-config.js +31 -0
- package/lib/utils/app-service-env-from-builder.js +164 -0
- package/lib/utils/build-copy.js +1 -1
- package/lib/utils/build-helpers.js +20 -20
- package/lib/utils/build-resolve-image.js +165 -0
- package/lib/utils/cli-layout-chalk.js +8 -0
- package/lib/utils/cli-test-layout-chalk.js +267 -0
- package/lib/utils/cli-utils.js +88 -11
- package/lib/utils/compose-db-passwords.js +138 -0
- package/lib/utils/compose-generate-docker-compose.js +216 -0
- package/lib/utils/compose-generator.js +197 -291
- package/lib/utils/compose-miso-env.js +18 -0
- package/lib/utils/compose-traefik-ingress-base.js +158 -0
- package/lib/utils/config-paths.js +209 -6
- package/lib/utils/config-scoped-resources-preference.js +41 -0
- package/lib/utils/controller-deployment-outcome.js +68 -0
- package/lib/utils/credential-display.js +2 -2
- package/lib/utils/credential-secrets-env.js +16 -1
- package/lib/utils/dataplane-pipeline-warning.js +4 -3
- package/lib/utils/datasource-test-run-capability-scope.js +43 -0
- package/lib/utils/datasource-test-run-debug-display.js +137 -0
- package/lib/utils/datasource-test-run-debug-slice.js +93 -0
- package/lib/utils/datasource-test-run-display.js +442 -0
- package/lib/utils/datasource-test-run-exit.js +58 -0
- package/lib/utils/datasource-test-run-legacy-adapter.js +93 -0
- package/lib/utils/datasource-test-run-report-version.js +51 -0
- package/lib/utils/datasource-test-run-schema-sync.js +59 -0
- package/lib/utils/datasource-test-run-tty-log.js +81 -0
- package/lib/utils/datasource-validation-watch.js +266 -0
- package/lib/utils/declarative-url-ports.js +47 -0
- package/lib/utils/derive-env-key-from-client-id.js +41 -0
- package/lib/utils/dev-ca-install.js +185 -23
- package/lib/utils/dev-cert-helper.js +266 -17
- package/lib/utils/dev-hosts-helper.js +307 -0
- package/lib/utils/dev-init-cert-hints.js +37 -0
- package/lib/utils/dev-init-health-messages.js +52 -0
- package/lib/utils/dev-init-resolve.js +86 -0
- package/lib/utils/dev-init-ssh-merge.js +65 -0
- package/lib/utils/dev-ssh-config-helper.js +196 -0
- package/lib/utils/dev-user-groups.js +93 -0
- package/lib/utils/docker-build.js +42 -17
- package/lib/utils/docker-exec.js +28 -0
- package/lib/utils/docker-manifest-public-port.js +116 -0
- package/lib/utils/docker-not-running-hint.js +52 -0
- package/lib/utils/docker.js +98 -11
- package/lib/utils/ensure-dev-certs-for-remote-docker.js +192 -0
- package/lib/utils/env-config-loader.js +10 -91
- package/lib/utils/env-copy.js +19 -10
- package/lib/utils/env-map.js +42 -11
- package/lib/utils/env-template.js +2 -2
- package/lib/utils/environment-scoped-resources.js +144 -0
- package/lib/utils/error-formatter.js +125 -9
- package/lib/utils/error-formatters/http-status-errors.js +6 -5
- package/lib/utils/error-formatters/network-errors.js +2 -1
- package/lib/utils/error-formatters/permission-errors.js +2 -1
- package/lib/utils/error-formatters/validation-errors.js +2 -1
- package/lib/utils/external-env-template.js +180 -0
- package/lib/utils/external-readme.js +8 -1
- package/lib/utils/external-system-display.js +277 -136
- package/lib/utils/external-system-local-test-tty.js +389 -0
- package/lib/utils/external-system-readiness-core.js +377 -0
- package/lib/utils/external-system-readiness-deploy-display.js +270 -0
- package/lib/utils/external-system-readiness-display-internals.js +150 -0
- package/lib/utils/external-system-readiness-display.js +186 -0
- package/lib/utils/external-system-test-helpers.js +24 -6
- package/lib/utils/external-system-validators.js +32 -14
- package/lib/utils/health-check-url.js +119 -0
- package/lib/utils/health-check.js +59 -25
- package/lib/utils/help-builder.js +14 -13
- package/lib/utils/image-version.js +4 -8
- package/lib/utils/infra-containers.js +4 -7
- package/lib/utils/infra-env-defaults.js +162 -0
- package/lib/utils/infra-status-display.js +167 -0
- package/lib/utils/infra-status.js +16 -8
- package/lib/utils/local-secrets.js +29 -7
- package/lib/utils/paths.js +136 -48
- package/lib/utils/port-resolver.js +10 -23
- package/lib/utils/redis-env-scope.js +62 -0
- package/lib/utils/register-aifabrix-shell-env.js +204 -0
- package/lib/utils/remote-builder-validation.js +99 -0
- package/lib/utils/remote-dev-auth.js +117 -21
- package/lib/utils/remote-docker-env.js +67 -15
- package/lib/utils/remote-secrets-loader.js +13 -4
- package/lib/utils/resolve-docker-image-ref.js +124 -0
- package/lib/utils/schema-loader.js +22 -9
- package/lib/utils/secrets-bash-kv.js +25 -0
- package/lib/utils/secrets-generator.js +171 -51
- package/lib/utils/secrets-helpers.js +70 -59
- package/lib/utils/secrets-kv-scope.js +60 -0
- package/lib/utils/secrets-utils.js +35 -37
- package/lib/utils/secrets-validation.js +3 -1
- package/lib/utils/secrets-yaml-preserve.js +109 -0
- package/lib/utils/secure-file-permissions.js +91 -0
- package/lib/utils/ssh-key-helper.js +4 -2
- package/lib/utils/template-helpers.js +2 -2
- package/lib/utils/test-log-writer.js +3 -3
- package/lib/utils/token-manager.js +37 -5
- package/lib/utils/url-declarative-public-base.js +188 -0
- package/lib/utils/url-declarative-resolve-build.js +493 -0
- package/lib/utils/url-declarative-resolve-load-doc.js +51 -0
- package/lib/utils/url-declarative-resolve.js +220 -0
- package/lib/utils/url-declarative-token-parse.js +74 -0
- package/lib/utils/url-declarative-url-flags.js +50 -0
- package/lib/utils/url-declarative-vdir-inactive-env.js +99 -0
- package/lib/utils/url-public-path-prefix.js +34 -0
- package/lib/utils/urls-local-registry.js +220 -0
- package/lib/utils/validation-report-tty-kit.js +77 -0
- package/lib/utils/validation-run-poll.js +89 -0
- package/lib/utils/validation-run-post-retry.js +73 -0
- package/lib/utils/validation-run-request.js +98 -0
- package/lib/utils/variable-transformer.js +21 -4
- package/lib/utils/yaml-preserve.js +78 -1
- package/lib/validation/datasource-warnings.js +56 -0
- package/lib/validation/env-template-auth.js +50 -2
- package/lib/validation/external-manifest-validator.js +35 -7
- package/lib/validation/validate-display.js +37 -31
- package/lib/validation/validate.js +9 -10
- package/lib/validation/validator-unresolved-placeholders.js +98 -0
- package/lib/validation/validator.js +32 -78
- package/lib/validation/wizard-config-validator.js +2 -1
- package/package.json +11 -3
- package/scripts/check-datasource-test-run-schema-sync.js +34 -0
- package/scripts/diagnose-cli.js +150 -0
- package/scripts/install-local.js +304 -55
- package/templates/README.md +15 -2
- package/templates/applications/dataplane/application.yaml +52 -2
- package/templates/applications/dataplane/env.template +80 -18
- package/templates/applications/dataplane/rbac.yaml +8 -0
- package/templates/applications/keycloak/application.yaml +9 -1
- package/templates/applications/keycloak/env.template +15 -6
- package/templates/applications/miso-controller/application.yaml +10 -2
- package/templates/applications/miso-controller/env.template +55 -14
- package/templates/applications/miso-controller/rbac.yaml +5 -0
- package/templates/external-system/README.md.hbs +20 -7
- package/templates/external-system/deploy.js.hbs +5 -5
- package/templates/external-system/env.template.hbs +22 -0
- package/templates/external-system/external-datasource.yaml.hbs +197 -118
- package/templates/infra/compose.yaml.hbs +20 -4
- package/templates/python/docker-compose.hbs +16 -0
- package/templates/typescript/docker-compose.hbs +16 -0
- package/integration/hubspot/README.md +0 -102
- package/integration/hubspot/env.template +0 -4
- package/integration/hubspot/hubspot-datasource-company.json +0 -541
- package/integration/hubspot/hubspot-datasource-contact.json +0 -639
- package/integration/hubspot/hubspot-datasource-deal.json +0 -588
- package/integration/hubspot/hubspot-datasource-users.json +0 -116
- package/integration/hubspot/test-artifacts/wizard-invalid-missing-source.yaml +0 -2
- package/integration/hubspot/test-artifacts/wizard-valid-for-dimension-key-test.yaml +0 -5
- package/integration/hubspot/test-artifacts/wizard-valid-for-dimension-path-test.yaml +0 -5
- package/lib/api/external-test.api.js +0 -111
- package/lib/schema/env-config.yaml +0 -43
- /package/integration/{hubspot → hubspot-test}/companies.json +0 -0
- /package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-app-name.yaml +0 -0
- /package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-missing-app.yaml +0 -0
- /package/integration/{hubspot → hubspot-test}/test-dataplane-down-helpers.js +0 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Environment-scoped resource naming (shared infra: dev/tst on same Postgres/Redis/Docker).
|
|
3
|
+
* Effective only when user gate AND app flag AND run env is dev|tst.
|
|
4
|
+
*
|
|
5
|
+
* @fileoverview environmentScopedResources + useEnvironmentScopedResources helpers
|
|
6
|
+
* @author AI Fabrix Team
|
|
7
|
+
* @version 1.0.0
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
'use strict';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Run/env keys that participate in resource prefixing (not pro).
|
|
14
|
+
* @param {string} envKey - Normalized lowercase env key
|
|
15
|
+
* @returns {boolean}
|
|
16
|
+
*/
|
|
17
|
+
function isScopedRunEnvironmentKey(envKey) {
|
|
18
|
+
if (!envKey || typeof envKey !== 'string') return false;
|
|
19
|
+
const k = envKey.toLowerCase();
|
|
20
|
+
return k === 'dev' || k === 'tst';
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Effective local/deploy prefix behavior: user gate ∧ app flag ∧ dev|tst.
|
|
25
|
+
*
|
|
26
|
+
* @param {boolean} useEnvironmentScopedResources - ~/.aifabrix/config.yaml
|
|
27
|
+
* @param {boolean} appEnvironmentScopedResources - application.yaml
|
|
28
|
+
* @param {string} runEnvKey - dev | tst | pro | other (lowercase)
|
|
29
|
+
* @returns {boolean}
|
|
30
|
+
*/
|
|
31
|
+
function computeEffectiveEnvironmentScopedResources(
|
|
32
|
+
useEnvironmentScopedResources,
|
|
33
|
+
appEnvironmentScopedResources,
|
|
34
|
+
runEnvKey
|
|
35
|
+
) {
|
|
36
|
+
return (
|
|
37
|
+
Boolean(useEnvironmentScopedResources) &&
|
|
38
|
+
Boolean(appEnvironmentScopedResources) &&
|
|
39
|
+
isScopedRunEnvironmentKey(runEnvKey)
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Redis logical DB index when env-scoped resources are effective.
|
|
45
|
+
* dev → 0, tst → 1 (single shared Redis instance).
|
|
46
|
+
*
|
|
47
|
+
* @param {string} runEnvKey - dev | tst
|
|
48
|
+
* @returns {number|null} Index or null if not applicable
|
|
49
|
+
*/
|
|
50
|
+
function redisDbIndexForScopedRunEnv(runEnvKey) {
|
|
51
|
+
if (!runEnvKey || typeof runEnvKey !== 'string') return null;
|
|
52
|
+
const k = runEnvKey.toLowerCase();
|
|
53
|
+
if (k === 'dev') return 0;
|
|
54
|
+
if (k === 'tst') return 1;
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Docker container name for local `aifabrix run` when env-scoping applies.
|
|
60
|
+
*
|
|
61
|
+
* @param {string} appName - Application key
|
|
62
|
+
* @param {string|number} devId - Developer id
|
|
63
|
+
* @param {number} idNum - Parsed numeric developer id
|
|
64
|
+
* @param {string} envKey - dev | tst
|
|
65
|
+
* @returns {string}
|
|
66
|
+
*/
|
|
67
|
+
function buildScopedLocalContainerName(appName, devId, idNum, envKey) {
|
|
68
|
+
const e = String(envKey).toLowerCase();
|
|
69
|
+
if (idNum === 0) {
|
|
70
|
+
return `aifabrix-${e}-${appName}`;
|
|
71
|
+
}
|
|
72
|
+
return `aifabrix-dev${devId}-${e}-${appName}`;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Default local container name (no env scope).
|
|
77
|
+
*
|
|
78
|
+
* @param {string} appName - Application key
|
|
79
|
+
* @param {string|number} devId - Developer id
|
|
80
|
+
* @param {number} idNum - Parsed numeric developer id
|
|
81
|
+
* @returns {string}
|
|
82
|
+
*/
|
|
83
|
+
function buildDefaultLocalContainerName(appName, devId, idNum) {
|
|
84
|
+
if (idNum === 0) {
|
|
85
|
+
return `aifabrix-${appName}`;
|
|
86
|
+
}
|
|
87
|
+
return `aifabrix-dev${devId}-${appName}`;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Resolved container name for run/stop/status.
|
|
92
|
+
*
|
|
93
|
+
* @param {string} appName - Application key
|
|
94
|
+
* @param {string|number} developerId - Developer id
|
|
95
|
+
* @param {boolean} effectiveScoped - From {@link computeEffectiveEnvironmentScopedResources}
|
|
96
|
+
* @param {string} [runEnvKey] - dev | tst (required when effectiveScoped)
|
|
97
|
+
* @returns {string}
|
|
98
|
+
*/
|
|
99
|
+
function resolveRunContainerName(appName, developerId, effectiveScoped, runEnvKey) {
|
|
100
|
+
const idNum = typeof developerId === 'string' ? parseInt(developerId, 10) : developerId;
|
|
101
|
+
if (effectiveScoped && runEnvKey) {
|
|
102
|
+
return buildScopedLocalContainerName(appName, developerId, idNum, runEnvKey);
|
|
103
|
+
}
|
|
104
|
+
return buildDefaultLocalContainerName(appName, developerId, idNum);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Traefik PathPrefix: prefix /{envKey} before pattern base (e.g. /api → /dev/api).
|
|
109
|
+
*
|
|
110
|
+
* @param {string} basePath - From derivePathFromPattern
|
|
111
|
+
* @param {string} envKey - dev | tst
|
|
112
|
+
* @returns {string}
|
|
113
|
+
*/
|
|
114
|
+
function buildEnvScopedTraefikPath(basePath, envKey) {
|
|
115
|
+
const e = String(envKey).toLowerCase();
|
|
116
|
+
const trimmed = (basePath || '/').trim() || '/';
|
|
117
|
+
if (trimmed === '/') {
|
|
118
|
+
return `/${e}`;
|
|
119
|
+
}
|
|
120
|
+
const withSlash = trimmed.startsWith('/') ? trimmed : `/${trimmed}`;
|
|
121
|
+
return `/${e}${withSlash}`.replace(/\/{2,}/g, '/');
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Compose service + Traefik router key when env-scoped (unique per env on shared host).
|
|
126
|
+
*
|
|
127
|
+
* @param {string} appName - Application key
|
|
128
|
+
* @param {string} envKey - dev | tst
|
|
129
|
+
* @returns {string}
|
|
130
|
+
*/
|
|
131
|
+
function composeTraefikServiceKey(appName, envKey) {
|
|
132
|
+
return `${String(envKey).toLowerCase()}-${appName}`;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
module.exports = {
|
|
136
|
+
isScopedRunEnvironmentKey,
|
|
137
|
+
computeEffectiveEnvironmentScopedResources,
|
|
138
|
+
redisDbIndexForScopedRunEnv,
|
|
139
|
+
buildScopedLocalContainerName,
|
|
140
|
+
buildDefaultLocalContainerName,
|
|
141
|
+
resolveRunContainerName,
|
|
142
|
+
buildEnvScopedTraefikPath,
|
|
143
|
+
composeTraefikServiceKey
|
|
144
|
+
};
|
|
@@ -19,6 +19,8 @@ const PATTERN_DESCRIPTIONS = {
|
|
|
19
19
|
'^[a-z-]+$': 'lowercase letters and hyphens only',
|
|
20
20
|
'^[A-Z_][A-Z0-9_]*$': 'uppercase letters, numbers, and underscores (must start with letter or underscore)',
|
|
21
21
|
'^[a-zA-Z0-9_-]+$': 'letters, numbers, hyphens, and underscores only',
|
|
22
|
+
'^[a-zA-Z0-9_]+$': 'letters, numbers, and underscores only',
|
|
23
|
+
'^[a-zA-Z0-9_.]+$': 'letters, numbers, underscores, and dots only',
|
|
22
24
|
'^(http|https)://.*$': 'valid HTTP or HTTPS URL',
|
|
23
25
|
'^/[a-z0-9/-]*$': 'URL path starting with / (lowercase letters, numbers, hyphens, slashes)'
|
|
24
26
|
};
|
|
@@ -45,15 +47,52 @@ function getFieldName(error) {
|
|
|
45
47
|
return path ? `Field "${path}"` : 'Configuration';
|
|
46
48
|
}
|
|
47
49
|
|
|
50
|
+
/**
|
|
51
|
+
* Resolves a value from root using an AJV instancePath (JSON Pointer, e.g. /roles/0/value).
|
|
52
|
+
* @param {*} root - Object or array validated at root
|
|
53
|
+
* @param {string} instancePath - AJV instancePath (leading slash or empty)
|
|
54
|
+
* @returns {*|undefined}
|
|
55
|
+
*/
|
|
56
|
+
function getValueAtInstancePath(root, instancePath) {
|
|
57
|
+
if (root === undefined || root === null) return undefined;
|
|
58
|
+
if (!instancePath || instancePath === '' || instancePath === '/') return root;
|
|
59
|
+
const parts = instancePath.split('/').filter(Boolean);
|
|
60
|
+
let cur = root;
|
|
61
|
+
for (const p of parts) {
|
|
62
|
+
if (cur === undefined || cur === null) return undefined;
|
|
63
|
+
const key = /^\d+$/.test(p) ? parseInt(p, 10) : p;
|
|
64
|
+
cur = cur[key];
|
|
65
|
+
}
|
|
66
|
+
return cur;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Resolves the failing value for display (AJV may omit `data` depending on compile options).
|
|
71
|
+
* @param {Object} error - AJV error
|
|
72
|
+
* @param {Object} [options] - rootData or deploymentManifest (same shape as validated root)
|
|
73
|
+
* @returns {*|undefined}
|
|
74
|
+
*/
|
|
75
|
+
function resolveErrorDataValue(error, options = {}) {
|
|
76
|
+
if (error && error.data !== undefined) return error.data;
|
|
77
|
+
const root = options.rootData !== undefined ? options.rootData : options.deploymentManifest;
|
|
78
|
+
if (!root) return undefined;
|
|
79
|
+
return getValueAtInstancePath(root, error.instancePath || '');
|
|
80
|
+
}
|
|
81
|
+
|
|
48
82
|
/**
|
|
49
83
|
* Formats a pattern validation error with the actual invalid value
|
|
50
84
|
* @function formatPatternError
|
|
51
85
|
* @param {string} field - Field name
|
|
52
86
|
* @param {Object} error - Validation error object
|
|
87
|
+
* @param {Object} [options] - Pass rootData or deploymentManifest to show value when error.data is missing
|
|
53
88
|
* @returns {string} Formatted error message
|
|
54
89
|
*/
|
|
55
|
-
function formatPatternError(field, error) {
|
|
56
|
-
const
|
|
90
|
+
function formatPatternError(field, error, options = {}) {
|
|
91
|
+
const actual = resolveErrorDataValue(error, options);
|
|
92
|
+
const invalidValue =
|
|
93
|
+
actual === undefined
|
|
94
|
+
? '(unavailable — pass rootData/deploymentManifest to formatValidationErrors to show it)'
|
|
95
|
+
: JSON.stringify(actual);
|
|
57
96
|
const patternDesc = getPatternDescription(error.params?.pattern);
|
|
58
97
|
return `${field}: Invalid value ${invalidValue} - ${patternDesc}`;
|
|
59
98
|
}
|
|
@@ -119,6 +158,10 @@ function createKeywordFormatters(field, error) {
|
|
|
119
158
|
? `${field}: Must be at most ${params.limit} characters`
|
|
120
159
|
: `${field}: Too long`,
|
|
121
160
|
|
|
161
|
+
minItems: params.limit !== undefined
|
|
162
|
+
? `${field}: must have at least ${params.limit} item(s)`
|
|
163
|
+
: `${field}: too few items`,
|
|
164
|
+
|
|
122
165
|
enum: params.allowedValues && params.allowedValues.length > 0
|
|
123
166
|
? `${field}: Must be one of: ${params.allowedValues.join(', ')}`
|
|
124
167
|
: `${field}: Must be one of: unknown`
|
|
@@ -126,22 +169,93 @@ function createKeywordFormatters(field, error) {
|
|
|
126
169
|
}
|
|
127
170
|
|
|
128
171
|
/**
|
|
129
|
-
* Formats
|
|
130
|
-
*
|
|
131
|
-
* @
|
|
172
|
+
* Formats oneOf/anyOf validation errors with actionable message
|
|
173
|
+
* @param {string} field - Field name
|
|
174
|
+
* @param {Object} error - AJV error (keyword oneOf or anyOf)
|
|
175
|
+
* @returns {string} Formatted error message
|
|
176
|
+
*/
|
|
177
|
+
function formatOneOfAnyOfError(field, error) {
|
|
178
|
+
const instancePath = (error.instancePath || '').replace(/^\//, '');
|
|
179
|
+
if (instancePath === 'capabilities') {
|
|
180
|
+
return `${field}: must be either an array of operation names (e.g. ["list","get"]) or an object with boolean flags (e.g. { "list": true }).`;
|
|
181
|
+
}
|
|
182
|
+
return `${field}: value does not match any allowed shape. Check type and required fields.`;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Formats const validation errors
|
|
187
|
+
* @param {string} field - Field name
|
|
188
|
+
* @param {Object} error - AJV error (keyword const)
|
|
189
|
+
* @returns {string} Formatted error message
|
|
190
|
+
*/
|
|
191
|
+
function formatConstError(field, error) {
|
|
192
|
+
const allowed = error.params?.allowedValue;
|
|
193
|
+
if (allowed !== undefined) {
|
|
194
|
+
const display = typeof allowed === 'string' ? `"${allowed}"` : String(allowed);
|
|
195
|
+
return `${field}: must be exactly ${display}`;
|
|
196
|
+
}
|
|
197
|
+
return `${field}: invalid value (constraint violation)`;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/** JSON Pointer: /permissions/<index>/roles */
|
|
201
|
+
const PERMISSION_ROLES_INSTANCE_PATH = /^\/permissions\/(\d+)\/roles$/;
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Clear message when permissions[i].roles is [] (schema minItems: 1).
|
|
205
|
+
* @param {Object} error - AJV error
|
|
206
|
+
* @param {Object} [options] - Optional context
|
|
207
|
+
* @param {Object} [options.deploymentManifest] - Deploy JSON being validated (for permission name)
|
|
208
|
+
* @returns {string|null}
|
|
209
|
+
*/
|
|
210
|
+
function tryFormatPermissionRolesMinItemsError(error, options) {
|
|
211
|
+
if (error.keyword !== 'minItems') {
|
|
212
|
+
return null;
|
|
213
|
+
}
|
|
214
|
+
const m = (error.instancePath || '').match(PERMISSION_ROLES_INSTANCE_PATH);
|
|
215
|
+
if (!m) {
|
|
216
|
+
return null;
|
|
217
|
+
}
|
|
218
|
+
const idx = parseInt(m[1], 10);
|
|
219
|
+
const perms = options?.deploymentManifest?.permissions;
|
|
220
|
+
const perm = Array.isArray(perms) ? perms[idx] : null;
|
|
221
|
+
const named =
|
|
222
|
+
perm && typeof perm.name === 'string' && perm.name.trim()
|
|
223
|
+
? ` "${perm.name.trim()}"`
|
|
224
|
+
: ` at permissions[${idx}]`;
|
|
225
|
+
return (
|
|
226
|
+
`RBAC: permission${named} has an empty "roles" array. ` +
|
|
227
|
+
'Each permission must list at least one role, and each string must match a role "value" from your "roles" list ' +
|
|
228
|
+
'(in application.yaml or rbac.yaml under the app folder). ' +
|
|
229
|
+
'Add roles, e.g. roles: ["admin"], or remove the permission if it is unused.'
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
132
234
|
* @param {Object} error - Raw validation error from Ajv
|
|
235
|
+
* @param {Object} [options] - Optional; use deploymentManifest for richer RBAC messages
|
|
133
236
|
* @returns {string} Formatted error message
|
|
134
237
|
*/
|
|
135
|
-
function formatSingleError(error) {
|
|
238
|
+
function formatSingleError(error, options) {
|
|
136
239
|
const field = getFieldName(error);
|
|
137
240
|
|
|
241
|
+
const rbacRolesMsg = tryFormatPermissionRolesMinItemsError(error, options);
|
|
242
|
+
if (rbacRolesMsg) {
|
|
243
|
+
return rbacRolesMsg;
|
|
244
|
+
}
|
|
245
|
+
|
|
138
246
|
// Handle pattern errors with special formatting
|
|
139
247
|
if (error.keyword === 'pattern') {
|
|
140
|
-
return formatPatternError(field, error);
|
|
248
|
+
return formatPatternError(field, error, options);
|
|
141
249
|
}
|
|
142
250
|
if (error.keyword === 'additionalProperties') {
|
|
143
251
|
return formatAdditionalPropertiesError(field, error);
|
|
144
252
|
}
|
|
253
|
+
if (error.keyword === 'oneOf' || error.keyword === 'anyOf') {
|
|
254
|
+
return formatOneOfAnyOfError(field, error);
|
|
255
|
+
}
|
|
256
|
+
if (error.keyword === 'const') {
|
|
257
|
+
return formatConstError(field, error);
|
|
258
|
+
}
|
|
145
259
|
|
|
146
260
|
// Use object lookup for keyword-specific messages
|
|
147
261
|
const formatters = createKeywordFormatters(field, error);
|
|
@@ -157,18 +271,19 @@ function formatSingleError(error) {
|
|
|
157
271
|
*
|
|
158
272
|
* @function formatValidationErrors
|
|
159
273
|
* @param {Array} errors - Raw validation errors from Ajv
|
|
274
|
+
* @param {Object} [options] - Optional; pass `{ deploymentManifest }` or `{ rootData }` for RBAC/pattern detail
|
|
160
275
|
* @returns {Array} Formatted error messages
|
|
161
276
|
*
|
|
162
277
|
* @example
|
|
163
278
|
* const messages = formatValidationErrors(ajvErrors);
|
|
164
279
|
* // Returns: ['Port must be between 1 and 65535', 'Missing required field: displayName']
|
|
165
280
|
*/
|
|
166
|
-
function formatValidationErrors(errors) {
|
|
281
|
+
function formatValidationErrors(errors, options) {
|
|
167
282
|
if (!Array.isArray(errors)) {
|
|
168
283
|
return ['Unknown validation error'];
|
|
169
284
|
}
|
|
170
285
|
|
|
171
|
-
return errors.map(formatSingleError);
|
|
286
|
+
return errors.map((e) => formatSingleError(e, options));
|
|
172
287
|
}
|
|
173
288
|
|
|
174
289
|
/**
|
|
@@ -195,5 +310,6 @@ module.exports = {
|
|
|
195
310
|
formatValidationErrors,
|
|
196
311
|
formatMissingDbPasswordError,
|
|
197
312
|
getPatternDescription,
|
|
313
|
+
getValueAtInstancePath,
|
|
198
314
|
PATTERN_DESCRIPTIONS
|
|
199
315
|
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
const { formatBlockingError } = require('../cli-test-layout-chalk');
|
|
1
2
|
/**
|
|
2
3
|
* HTTP Status Error Formatters
|
|
3
4
|
*
|
|
@@ -123,7 +124,7 @@ function addAuthenticationGuidance(lines, errorData) {
|
|
|
123
124
|
|
|
124
125
|
function formatAuthenticationError(errorData) {
|
|
125
126
|
const lines = [];
|
|
126
|
-
lines.push(
|
|
127
|
+
lines.push(formatBlockingError('Authentication Failed\n'));
|
|
127
128
|
|
|
128
129
|
addControllerUrlInfo(lines, errorData);
|
|
129
130
|
addAttemptedUrlsInfo(lines, errorData);
|
|
@@ -148,7 +149,7 @@ function formatAuthenticationError(errorData) {
|
|
|
148
149
|
*/
|
|
149
150
|
function formatServerError(errorData) {
|
|
150
151
|
const lines = [];
|
|
151
|
-
lines.push(
|
|
152
|
+
lines.push(formatBlockingError('Server Error\n'));
|
|
152
153
|
|
|
153
154
|
// Show controller URL if available
|
|
154
155
|
if (errorData.controllerUrl) {
|
|
@@ -183,7 +184,7 @@ function formatServerError(errorData) {
|
|
|
183
184
|
*/
|
|
184
185
|
function formatConflictError(errorData) {
|
|
185
186
|
const lines = [];
|
|
186
|
-
lines.push(
|
|
187
|
+
lines.push(formatBlockingError('Conflict\n'));
|
|
187
188
|
|
|
188
189
|
// Show controller URL if available
|
|
189
190
|
if (errorData.controllerUrl) {
|
|
@@ -252,7 +253,7 @@ function getNotFoundGuidance(detail) {
|
|
|
252
253
|
*/
|
|
253
254
|
function formatNotFoundError(errorData) {
|
|
254
255
|
const lines = [];
|
|
255
|
-
lines.push(
|
|
256
|
+
lines.push(formatBlockingError('Not Found\n'));
|
|
256
257
|
|
|
257
258
|
// Show controller URL if available
|
|
258
259
|
if (errorData.controllerUrl) {
|
|
@@ -289,7 +290,7 @@ function formatNotFoundError(errorData) {
|
|
|
289
290
|
*/
|
|
290
291
|
function formatGenericError(errorData, statusCode) {
|
|
291
292
|
const lines = [];
|
|
292
|
-
lines.push(chalk.red(
|
|
293
|
+
lines.push(chalk.red(`✖ Error (HTTP ${statusCode})\n`));
|
|
293
294
|
|
|
294
295
|
// Show controller URL if available
|
|
295
296
|
if (errorData.controllerUrl) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
const { formatBlockingError } = require('../cli-test-layout-chalk');
|
|
1
2
|
/**
|
|
2
3
|
* Network Error Formatters
|
|
3
4
|
*
|
|
@@ -135,7 +136,7 @@ function addCorrelationId(lines, errorData) {
|
|
|
135
136
|
*/
|
|
136
137
|
function formatNetworkError(errorMessage, errorData) {
|
|
137
138
|
const lines = [];
|
|
138
|
-
lines.push(
|
|
139
|
+
lines.push(formatBlockingError('Network Error\n'));
|
|
139
140
|
|
|
140
141
|
addControllerUrlHeader(lines, errorData);
|
|
141
142
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
const { formatBlockingError } = require('../cli-test-layout-chalk');
|
|
1
2
|
/**
|
|
2
3
|
* Permission Error Formatters
|
|
3
4
|
*
|
|
@@ -103,7 +104,7 @@ function getPermissionDetailLines(errorData) {
|
|
|
103
104
|
*/
|
|
104
105
|
function formatPermissionError(errorData) {
|
|
105
106
|
const lines = [];
|
|
106
|
-
lines.push(
|
|
107
|
+
lines.push(formatBlockingError('Permission Denied\n'));
|
|
107
108
|
|
|
108
109
|
if (errorData.detail) {
|
|
109
110
|
lines.push(chalk.yellow(errorData.detail));
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
const { formatBlockingError } = require('../cli-test-layout-chalk');
|
|
1
2
|
/**
|
|
2
3
|
* Validation Error Formatters
|
|
3
4
|
*
|
|
@@ -111,7 +112,7 @@ function addValidationGuidance(lines, hasErrors) {
|
|
|
111
112
|
*/
|
|
112
113
|
function formatValidationError(errorData) {
|
|
113
114
|
const lines = [];
|
|
114
|
-
lines.push(
|
|
115
|
+
lines.push(formatBlockingError('Validation Error\n'));
|
|
115
116
|
|
|
116
117
|
addValidationErrorMessage(lines, errorData);
|
|
117
118
|
addValidationErrorsList(lines, errorData.errors);
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds Handlebars context and generates env.template content for external systems.
|
|
3
|
+
* Single source for create, download, split, and repair so env.template structure is consistent.
|
|
4
|
+
*
|
|
5
|
+
* @fileoverview External system env.template generation
|
|
6
|
+
* @author AI Fabrix Team
|
|
7
|
+
* @version 2.0.0
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
'use strict';
|
|
11
|
+
|
|
12
|
+
const path = require('path');
|
|
13
|
+
const fs = require('fs');
|
|
14
|
+
const Handlebars = require('handlebars');
|
|
15
|
+
const { systemKeyToKvPrefix, kvEnvKeyToPath, securityKeyToVar } = require('./credential-secrets-env');
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Builds hint string from portalInput (options → enum, validation → min-max or pattern).
|
|
19
|
+
* @param {Object} portalInput - Portal input config (label, options, validation)
|
|
20
|
+
* @returns {string} Hint suffix for comment
|
|
21
|
+
*/
|
|
22
|
+
function buildPortalInputHint(portalInput) {
|
|
23
|
+
if (!portalInput || typeof portalInput !== 'object') return '';
|
|
24
|
+
const parts = [];
|
|
25
|
+
if (Array.isArray(portalInput.options) && portalInput.options.length > 0) {
|
|
26
|
+
parts.push(`enum ${portalInput.options.join(',')}`);
|
|
27
|
+
}
|
|
28
|
+
const v = portalInput.validation;
|
|
29
|
+
if (v && typeof v === 'object') {
|
|
30
|
+
if (typeof v.minLength === 'number' || typeof v.maxLength === 'number') {
|
|
31
|
+
parts.push('min-max');
|
|
32
|
+
} else if (typeof v.pattern === 'string' && v.pattern) {
|
|
33
|
+
parts.push('pattern');
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return parts.length ? ` - ${parts.join(', ')}` : '';
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Fallback security keys by auth method when authentication.security is absent. */
|
|
40
|
+
const FALLBACK_SECURITY_BY_AUTH = {
|
|
41
|
+
oauth2: ['clientId', 'clientSecret'],
|
|
42
|
+
oauth: ['clientId', 'clientSecret'],
|
|
43
|
+
aad: ['clientId', 'clientSecret'],
|
|
44
|
+
apikey: ['apiKey'],
|
|
45
|
+
apiKey: ['apiKey'],
|
|
46
|
+
basic: ['username', 'password'],
|
|
47
|
+
queryParam: ['paramValue'],
|
|
48
|
+
oidc: [],
|
|
49
|
+
hmac: ['signingSecret'],
|
|
50
|
+
bearer: ['bearerToken'],
|
|
51
|
+
token: ['bearerToken'],
|
|
52
|
+
none: []
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Builds authSecureVars array from system authentication.security (or fallback by auth type).
|
|
57
|
+
* @param {Object} system - System object with key and authentication
|
|
58
|
+
* @returns {Array<{name: string, value: string}>}
|
|
59
|
+
*/
|
|
60
|
+
function buildAuthSecureVarsFromSystem(system) {
|
|
61
|
+
const authSecureVars = [];
|
|
62
|
+
const systemKey = system?.key || 'external-system';
|
|
63
|
+
const prefix = systemKeyToKvPrefix(systemKey);
|
|
64
|
+
if (!prefix) return authSecureVars;
|
|
65
|
+
const security = system?.authentication?.security || system?.auth?.security;
|
|
66
|
+
const authMethod = (system?.authentication?.method || system?.authentication?.type ||
|
|
67
|
+
system?.auth?.method || system?.auth?.type || 'apikey').toLowerCase();
|
|
68
|
+
if (security && typeof security === 'object' && Object.keys(security).length > 0) {
|
|
69
|
+
for (const key of Object.keys(security)) {
|
|
70
|
+
const envName = `KV_${prefix}_${securityKeyToVar(key)}`;
|
|
71
|
+
const pathVal = kvEnvKeyToPath(envName, systemKey);
|
|
72
|
+
authSecureVars.push({ name: envName, value: pathVal || `kv://${systemKey}/${key}` });
|
|
73
|
+
}
|
|
74
|
+
} else {
|
|
75
|
+
const keys = FALLBACK_SECURITY_BY_AUTH[authMethod] || FALLBACK_SECURITY_BY_AUTH.apikey;
|
|
76
|
+
for (const key of keys) {
|
|
77
|
+
authSecureVars.push({
|
|
78
|
+
name: `KV_${prefix}_${securityKeyToVar(key)}`,
|
|
79
|
+
value: `kv://${systemKey}/${key}`
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return authSecureVars;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Builds configuration array with name, value, comment from system.configuration.
|
|
88
|
+
* @param {Object} system - System object with configuration array
|
|
89
|
+
* @returns {Array<{name: string, value: string, comment: string}>}
|
|
90
|
+
*/
|
|
91
|
+
function buildConfigurationEntries(system) {
|
|
92
|
+
const configuration = [];
|
|
93
|
+
const configList = Array.isArray(system?.configuration) ? system.configuration : [];
|
|
94
|
+
for (const entry of configList) {
|
|
95
|
+
if (!entry || !entry.name) continue;
|
|
96
|
+
const label = entry.portalInput?.label || entry.name;
|
|
97
|
+
const hint = buildPortalInputHint(entry.portalInput || {});
|
|
98
|
+
let value = entry.value !== undefined && entry.value !== null ? String(entry.value) : '';
|
|
99
|
+
if (entry.location === 'keyvault' && value && !value.startsWith('kv://')) value = `kv://${value}`;
|
|
100
|
+
configuration.push({ name: entry.name, value, comment: `${label}${hint}` });
|
|
101
|
+
}
|
|
102
|
+
return configuration;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Builds template context from system object for env.template.hbs.
|
|
107
|
+
* @param {Object} system - Full system object (e.g. deployment.system or parsed system file)
|
|
108
|
+
* @returns {{ authMethod: string, authSecureVars: Array<{name: string, value: string}>, authNonSecureVarNames: string[], configuration: Array<{name: string, value: string, comment: string}> }}
|
|
109
|
+
*/
|
|
110
|
+
function buildExternalEnvTemplateContext(system) {
|
|
111
|
+
const authMethod = (system?.authentication?.method ||
|
|
112
|
+
system?.authentication?.type ||
|
|
113
|
+
system?.auth?.method ||
|
|
114
|
+
system?.auth?.type ||
|
|
115
|
+
'apikey').toLowerCase();
|
|
116
|
+
const authSecureVars = buildAuthSecureVarsFromSystem(system);
|
|
117
|
+
const authVars = system?.authentication?.variables || system?.auth?.variables || {};
|
|
118
|
+
const authNonSecureVarNames = Object.keys(authVars);
|
|
119
|
+
const configuration = buildConfigurationEntries(system);
|
|
120
|
+
return {
|
|
121
|
+
authMethod,
|
|
122
|
+
authSecureVars,
|
|
123
|
+
authNonSecureVarNames,
|
|
124
|
+
configuration
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** Inline fallback when env.template.hbs is missing or unreadable (e.g. CI path or bundled). */
|
|
129
|
+
const DEFAULT_ENV_TEMPLATE_HBS = `# Environment variables for external system integration
|
|
130
|
+
# Use kv:// (or aifabrix secret set) for sensitive values; plain values for non-sensitive configuration.
|
|
131
|
+
#
|
|
132
|
+
|
|
133
|
+
{{#if authMethod}}
|
|
134
|
+
# Authentication
|
|
135
|
+
# Type: {{authMethod}}
|
|
136
|
+
{{#each authSecureVars}}
|
|
137
|
+
{{name}}={{value}}
|
|
138
|
+
{{/each}}
|
|
139
|
+
{{#if authNonSecureVarNames}}
|
|
140
|
+
# Non-secure (e.g. URLs): {{#each authNonSecureVarNames}}{{this}}{{#unless @last}}, {{/unless}}{{/each}}
|
|
141
|
+
{{/if}}
|
|
142
|
+
|
|
143
|
+
{{/if}}
|
|
144
|
+
{{#if configuration.length}}
|
|
145
|
+
# Configuration
|
|
146
|
+
{{#each configuration}}
|
|
147
|
+
# {{comment}}
|
|
148
|
+
{{name}}={{value}}
|
|
149
|
+
{{/each}}
|
|
150
|
+
{{/if}}
|
|
151
|
+
`;
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Generates env.template content from system using the Handlebars template.
|
|
155
|
+
* @param {Object} system - Full system object (e.g. deployment.system or parsed system file)
|
|
156
|
+
* @returns {string} Rendered env.template content
|
|
157
|
+
*/
|
|
158
|
+
function generateExternalEnvTemplateContent(system) {
|
|
159
|
+
if (!system || typeof system !== 'object') {
|
|
160
|
+
return '# Environment variables for external system integration\n# Use kv:// (or aifabrix secret set) for sensitive values.\n\n';
|
|
161
|
+
}
|
|
162
|
+
let templateContent;
|
|
163
|
+
try {
|
|
164
|
+
const templatePath = path.join(__dirname, '..', '..', 'templates', 'external-system', 'env.template.hbs');
|
|
165
|
+
templateContent = fs.readFileSync(templatePath, 'utf8');
|
|
166
|
+
} catch (_) {
|
|
167
|
+
templateContent = undefined;
|
|
168
|
+
}
|
|
169
|
+
if (typeof templateContent !== 'string' || !templateContent.trim()) {
|
|
170
|
+
templateContent = DEFAULT_ENV_TEMPLATE_HBS;
|
|
171
|
+
}
|
|
172
|
+
const template = Handlebars.compile(templateContent);
|
|
173
|
+
const context = buildExternalEnvTemplateContext(system);
|
|
174
|
+
return template(context);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
module.exports = {
|
|
178
|
+
buildExternalEnvTemplateContext,
|
|
179
|
+
generateExternalEnvTemplateContent
|
|
180
|
+
};
|
|
@@ -133,6 +133,10 @@ function buildSecretPaths(systemKey, authType) {
|
|
|
133
133
|
* @param {Object} [params.authentication] - Full authentication object (authType used if authType not set)
|
|
134
134
|
* @returns {Object} Template context
|
|
135
135
|
*/
|
|
136
|
+
function rbacOptionalFilename(normalizedExt) {
|
|
137
|
+
return normalizedExt === '.yaml' || normalizedExt === '.yml' ? 'rbac.yaml' : 'rbac.json';
|
|
138
|
+
}
|
|
139
|
+
|
|
136
140
|
function buildExternalReadmeContext(params = {}) {
|
|
137
141
|
const appName = params.appName || params.systemKey || 'external-system';
|
|
138
142
|
const systemKey = params.systemKey || appName;
|
|
@@ -140,9 +144,11 @@ function buildExternalReadmeContext(params = {}) {
|
|
|
140
144
|
const description = params.description || `External system integration for ${systemKey}`;
|
|
141
145
|
const systemType = params.systemType || 'openapi';
|
|
142
146
|
const fileExt = params.fileExt !== undefined ? params.fileExt : '.json';
|
|
147
|
+
const normalizedExt = fileExt && fileExt.startsWith('.') ? fileExt : `.${fileExt || 'json'}`;
|
|
143
148
|
const datasources = normalizeDatasources(params.datasources, systemKey, fileExt);
|
|
144
149
|
const authType = params.authType || params.authentication?.type || params.authentication?.method || params.authentication?.authType;
|
|
145
150
|
const secretPaths = buildSecretPaths(systemKey, authType);
|
|
151
|
+
const rbacOptionalFile = rbacOptionalFilename(normalizedExt);
|
|
146
152
|
|
|
147
153
|
return {
|
|
148
154
|
appName,
|
|
@@ -150,7 +156,8 @@ function buildExternalReadmeContext(params = {}) {
|
|
|
150
156
|
displayName,
|
|
151
157
|
description,
|
|
152
158
|
systemType,
|
|
153
|
-
fileExt:
|
|
159
|
+
fileExt: normalizedExt,
|
|
160
|
+
rbacOptionalFile,
|
|
154
161
|
datasourceCount: datasources.length,
|
|
155
162
|
hasDatasources: datasources.length > 0,
|
|
156
163
|
datasources,
|