@aifabrix/builder 2.43.0 → 2.44.1
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/.cursor/rules/cli-layout.mdc +75 -0
- package/.cursor/rules/project-rules.mdc +8 -0
- package/.npmrc.token +1 -0
- package/.nyc_output/55e9d034-ddab-4579-a706-e02a91d75c91.json +1 -0
- package/.nyc_output/processinfo/55e9d034-ddab-4579-a706-e02a91d75c91.json +1 -0
- package/.nyc_output/processinfo/index.json +1 -0
- package/README.md +1 -1
- package/anchor-docs/README.md +10 -0
- package/anchor-docs/_TEMPLATE +24 -0
- package/bin/aifabrix.js +13 -4
- package/integration/hubspot-test/README.md +31 -0
- package/integration/hubspot-test/create-hubspot.js +5 -5
- package/integration/hubspot-test/hubspot-test-datasource-company.json +58 -462
- package/integration/hubspot-test/hubspot-test-datasource-contact.json +61 -555
- package/integration/hubspot-test/hubspot-test-datasource-deal.json +63 -506
- package/integration/hubspot-test/hubspot-test-datasource-users.json +42 -83
- package/integration/hubspot-test/hubspot-test-deploy.json +3 -3
- package/integration/hubspot-test/test-dataplane-down-tests.js +1 -7
- package/integration/hubspot-test/test-dataplane-down.js +3 -3
- package/integration/hubspot-test/test.js +35 -43
- package/integration/hubspot-test/wizard-hubspot-test-headless.yaml +23 -0
- package/integration/roundtrip-test-local/README.md +144 -0
- package/integration/roundtrip-test-local/application.yaml +13 -0
- package/integration/roundtrip-test-local/env.template +15 -0
- package/integration/roundtrip-test-local/roundtrip-test-local-datasource-roundtrip-test-company.yaml +14 -0
- package/integration/roundtrip-test-local/roundtrip-test-local-deploy.json +61 -0
- package/integration/roundtrip-test-local/roundtrip-test-local-system.yaml +25 -0
- package/integration/roundtrip-test-local2/README.md +144 -0
- package/integration/roundtrip-test-local2/application.yaml +13 -0
- package/integration/roundtrip-test-local2/env.template +15 -0
- package/integration/roundtrip-test-local2/roundtrip-test-local2-datasource-company.yaml +31 -0
- package/integration/roundtrip-test-local2/roundtrip-test-local2-deploy.json +86 -0
- package/integration/roundtrip-test-local2/roundtrip-test-local2-system.yaml +25 -0
- package/integration/test/wizard.yaml +8 -0
- package/jest.config.default.js +10 -0
- package/jest.config.integration.fixtures.js +22 -0
- package/jest.config.integration.js +21 -18
- package/jest.config.isolated.js +10 -0
- package/jest.projects.js +301 -0
- package/lib/api/certificates.api.js +62 -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 +11 -3
- package/lib/api/pipeline.api.js +67 -20
- package/lib/api/types/certificates.types.js +48 -0
- package/lib/api/types/dev.types.js +4 -3
- package/lib/api/types/pipeline.types.js +8 -5
- package/lib/api/types/validation-run.types.js +56 -0
- package/lib/api/validation-run.api.js +111 -0
- package/lib/api/validation-runner.js +109 -0
- package/lib/app/certification-show-enrich.js +129 -0
- package/lib/app/certification-verify-rows.js +60 -0
- package/lib/app/config.js +1 -1
- package/lib/app/deploy-status-display.js +2 -2
- package/lib/app/deploy.js +7 -6
- package/lib/app/display.js +2 -1
- package/lib/app/dockerfile.js +3 -2
- package/lib/app/down.js +2 -1
- package/lib/app/helpers.js +6 -5
- package/lib/app/index.js +27 -8
- package/lib/app/list.js +7 -6
- package/lib/app/push.js +4 -3
- package/lib/app/register.js +16 -7
- package/lib/app/rotate-secret.js +14 -13
- package/lib/app/run-container-start.js +184 -0
- package/lib/app/run-docker-fallback.js +108 -0
- package/lib/app/run-env-compose.js +30 -42
- package/lib/app/run-helpers.js +49 -126
- package/lib/app/run-infra-requirements.js +30 -0
- package/lib/app/run-resolve-image.js +21 -0
- package/lib/app/run.js +74 -21
- package/lib/app/show-display.js +44 -1
- package/lib/app/show.js +93 -9
- package/lib/build/index.js +13 -10
- package/lib/certification/cli-cert-sync-skip.js +21 -0
- package/lib/certification/merge-certification-from-artifact.js +185 -0
- package/lib/certification/post-unified-cert-sync.js +33 -0
- package/lib/certification/sync-after-external-command.js +52 -0
- package/lib/certification/sync-system-certification.js +197 -0
- package/lib/cli/index.js +2 -0
- package/lib/cli/setup-app.help.js +67 -0
- package/lib/cli/setup-app.js +61 -121
- package/lib/cli/setup-app.test-commands.js +195 -0
- package/lib/cli/setup-auth.js +19 -5
- package/lib/cli/setup-credential-deployment.js +22 -8
- package/lib/cli/setup-dev-path-commands.js +124 -0
- package/lib/cli/setup-dev.js +170 -113
- package/lib/cli/setup-environment.js +7 -1
- package/lib/cli/setup-external-system.js +84 -23
- package/lib/cli/setup-infra.js +126 -47
- package/lib/cli/setup-parameters.js +32 -0
- package/lib/cli/setup-secrets.js +137 -18
- package/lib/cli/setup-service-user.js +1 -1
- package/lib/cli/setup-utility.js +54 -22
- 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 +32 -11
- package/lib/commands/auth-config.js +6 -6
- package/lib/commands/auth-status.js +4 -3
- package/lib/commands/credential-env.js +4 -3
- package/lib/commands/credential-list.js +5 -4
- package/lib/commands/credential-push.js +4 -3
- package/lib/commands/datasource-unified-test-cli.js +428 -0
- package/lib/commands/datasource-unified-test-cli.options.js +191 -0
- package/lib/commands/datasource-unified-test-e2e-cli-helpers.js +106 -0
- package/lib/commands/datasource-validation-cli.js +143 -0
- package/lib/commands/datasource.js +125 -95
- package/lib/commands/deployment-list.js +6 -5
- package/lib/commands/dev-cli-handlers.js +122 -18
- package/lib/commands/dev-down.js +4 -3
- package/lib/commands/dev-init.js +231 -116
- package/lib/commands/dev-show-display.js +473 -0
- package/lib/commands/login-credentials.js +3 -2
- package/lib/commands/login-device.js +4 -3
- package/lib/commands/login.js +5 -4
- package/lib/commands/logout.js +8 -7
- package/lib/commands/parameters-validate.js +54 -0
- package/lib/commands/repair-datasource.js +314 -68
- package/lib/commands/repair-env-template.js +2 -2
- package/lib/commands/repair.js +21 -3
- package/lib/commands/secrets-list.js +23 -12
- package/lib/commands/secrets-remove-all.js +220 -0
- package/lib/commands/secrets-remove.js +21 -12
- package/lib/commands/secrets-set.js +21 -12
- package/lib/commands/secrets-validate.js +4 -4
- package/lib/commands/secure.js +10 -9
- package/lib/commands/service-user.js +26 -25
- package/lib/commands/test-e2e-external.js +27 -1
- package/lib/commands/up-common.js +3 -2
- package/lib/commands/up-dataplane.js +29 -16
- package/lib/commands/up-miso.js +19 -29
- package/lib/commands/upload.js +149 -39
- package/lib/commands/wizard-core-helpers.js +1 -1
- package/lib/commands/wizard-dataplane.js +4 -3
- package/lib/commands/wizard-helpers.js +3 -3
- package/lib/commands/wizard.js +2 -2
- package/lib/core/admin-secrets.js +14 -5
- package/lib/core/audit-logger.js +12 -4
- package/lib/core/config-attach-extensions.js +46 -0
- package/lib/core/config-runtime-paths.js +29 -0
- package/lib/core/config.js +55 -56
- package/lib/core/diff.js +3 -2
- package/lib/core/ensure-encryption-key.js +1 -1
- package/lib/core/secrets-ensure-infra.js +77 -0
- package/lib/core/secrets-ensure.js +120 -64
- package/lib/core/secrets-env-write.js +35 -7
- package/lib/core/secrets-infra-placeholder-sync.js +61 -0
- package/lib/core/secrets.js +200 -37
- package/lib/core/templates-env.js +4 -3
- package/lib/datasource/abac-validator.js +1 -10
- package/lib/datasource/deploy.js +75 -53
- package/lib/datasource/field-reference-validator.js +9 -6
- package/lib/datasource/integration-context.js +63 -0
- package/lib/datasource/list.js +8 -7
- package/lib/datasource/log-viewer.js +189 -67
- package/lib/datasource/resolve-app.js +4 -4
- package/lib/datasource/test-e2e.js +113 -146
- package/lib/datasource/test-integration.js +114 -122
- package/lib/datasource/unified-validation-run-body.js +68 -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 +93 -0
- package/lib/datasource/validate.js +157 -13
- package/lib/deployment/deployer.js +4 -3
- package/lib/deployment/environment.js +7 -6
- package/lib/deployment/push.js +17 -8
- package/lib/external-system/delete.js +4 -3
- package/lib/external-system/deploy.js +166 -53
- package/lib/external-system/download-helpers.js +1 -1
- package/lib/external-system/download.js +7 -6
- package/lib/external-system/generator.js +92 -6
- package/lib/external-system/integration-test-dispatch.js +26 -0
- package/lib/external-system/test-execution.js +5 -1
- package/lib/external-system/test-helpers.js +0 -4
- package/lib/external-system/test-system-level-helpers.js +110 -0
- package/lib/external-system/test-system-level.js +83 -44
- package/lib/external-system/test.js +59 -8
- package/lib/generator/builders.js +23 -11
- package/lib/generator/deploy-manifest-azure-kv.js +81 -0
- package/lib/generator/external.js +16 -4
- package/lib/generator/helpers.js +58 -3
- package/lib/generator/index.js +4 -0
- package/lib/generator/split-readme.js +12 -7
- package/lib/generator/split-variables.js +2 -1
- package/lib/generator/split.js +1 -1
- package/lib/generator/wizard-readme.js +3 -3
- package/lib/generator/wizard.js +8 -8
- package/lib/infrastructure/compose.js +70 -7
- package/lib/infrastructure/helpers-docker-check.js +67 -0
- package/lib/infrastructure/helpers.js +203 -42
- package/lib/infrastructure/index.js +31 -18
- package/lib/infrastructure/services.js +21 -67
- package/lib/internal/fs-real-sync.js +104 -0
- package/lib/internal/node-fs.js +98 -0
- package/lib/parameters/database-secret-values.js +173 -0
- package/lib/parameters/infra-kv-discovery.js +121 -0
- package/lib/parameters/infra-parameter-catalog.js +458 -0
- package/lib/parameters/infra-parameter-validate.js +64 -0
- package/lib/schema/application-schema.json +37 -17
- package/lib/schema/datasource-test-run.schema.json +493 -0
- package/lib/schema/deployment-rules.yaml +102 -63
- package/lib/schema/external-datasource.schema.json +1200 -442
- package/lib/schema/external-system.schema.json +203 -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 +226 -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 +77 -17
- package/lib/utils/app-register-api.js +3 -2
- package/lib/utils/app-register-auth.js +1 -1
- package/lib/utils/app-register-config.js +4 -4
- package/lib/utils/app-register-display.js +3 -2
- package/lib/utils/app-register-validator.js +3 -2
- package/lib/utils/app-run-containers.js +26 -22
- package/lib/utils/app-scoped-config.js +31 -0
- package/lib/utils/app-service-env-from-builder.js +164 -0
- package/lib/utils/build-copy.js +1 -1
- package/lib/utils/build-helpers.js +20 -20
- package/lib/utils/build-resolve-image.js +165 -0
- package/lib/utils/cli-layout-chalk.js +8 -0
- package/lib/utils/cli-test-layout-chalk.js +267 -0
- package/lib/utils/cli-utils.js +88 -11
- package/lib/utils/compose-db-passwords.js +138 -0
- package/lib/utils/compose-generate-docker-compose.js +216 -0
- package/lib/utils/compose-generator.js +197 -291
- package/lib/utils/compose-miso-env.js +18 -0
- package/lib/utils/compose-traefik-ingress-base.js +158 -0
- package/lib/utils/config-paths.js +166 -7
- package/lib/utils/config-scoped-resources-preference.js +41 -0
- package/lib/utils/configuration-env-resolver.js +11 -8
- package/lib/utils/controller-deployment-outcome.js +68 -0
- package/lib/utils/credential-display.js +2 -2
- package/lib/utils/credential-secrets-env.js +5 -5
- 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-certificate-tty.js +82 -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 +459 -0
- package/lib/utils/datasource-test-run-exit.js +83 -0
- package/lib/utils/datasource-test-run-legacy-adapter.js +93 -0
- package/lib/utils/datasource-test-run-report-version.js +51 -0
- package/lib/utils/datasource-test-run-schema-sync.js +59 -0
- package/lib/utils/datasource-test-run-tty-log.js +81 -0
- package/lib/utils/datasource-validation-watch.js +266 -0
- package/lib/utils/declarative-url-ports.js +47 -0
- package/lib/utils/derive-env-key-from-client-id.js +41 -0
- package/lib/utils/dev-ca-install.js +185 -23
- package/lib/utils/dev-cert-helper.js +266 -17
- package/lib/utils/dev-hosts-helper.js +307 -0
- package/lib/utils/dev-init-cert-hints.js +37 -0
- package/lib/utils/dev-init-health-messages.js +52 -0
- package/lib/utils/dev-init-resolve.js +86 -0
- package/lib/utils/dev-init-ssh-merge.js +65 -0
- package/lib/utils/dev-ssh-config-helper.js +196 -0
- package/lib/utils/dev-user-groups.js +93 -0
- package/lib/utils/docker-build.js +42 -17
- package/lib/utils/docker-exec.js +28 -0
- package/lib/utils/docker-manifest-public-port.js +116 -0
- package/lib/utils/docker-not-running-hint.js +52 -0
- package/lib/utils/docker.js +98 -11
- package/lib/utils/ensure-dev-certs-for-remote-docker.js +192 -0
- package/lib/utils/env-config-loader.js +10 -91
- package/lib/utils/env-copy.js +19 -10
- package/lib/utils/env-map.js +35 -8
- package/lib/utils/env-template.js +2 -2
- package/lib/utils/environment-scoped-resources.js +144 -0
- package/lib/utils/error-formatter.js +92 -13
- package/lib/utils/error-formatters/http-status-errors.js +6 -5
- package/lib/utils/error-formatters/network-errors.js +2 -1
- package/lib/utils/error-formatters/permission-errors.js +2 -1
- package/lib/utils/error-formatters/validation-errors.js +2 -1
- package/lib/utils/external-readme.js +8 -1
- package/lib/utils/external-system-display.js +242 -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-system-test-tty-overview.js +120 -0
- package/lib/utils/external-system-system-test-tty.js +417 -0
- package/lib/utils/external-system-test-helpers.js +24 -6
- package/lib/utils/external-system-validators.js +30 -12
- package/lib/utils/health-check-url.js +119 -0
- package/lib/utils/health-check.js +59 -25
- package/lib/utils/help-builder.js +11 -8
- package/lib/utils/image-version.js +4 -8
- package/lib/utils/infra-containers.js +4 -7
- package/lib/utils/infra-env-defaults.js +162 -0
- package/lib/utils/infra-status-display.js +167 -0
- package/lib/utils/infra-status.js +16 -8
- package/lib/utils/local-secrets.js +3 -4
- package/lib/utils/paths.js +148 -47
- package/lib/utils/port-resolver.js +10 -23
- package/lib/utils/redis-env-scope.js +62 -0
- package/lib/utils/register-aifabrix-shell-env.js +204 -0
- package/lib/utils/remote-builder-validation.js +99 -0
- package/lib/utils/remote-dev-auth.js +117 -21
- package/lib/utils/remote-docker-env.js +67 -15
- package/lib/utils/remote-secrets-loader.js +13 -4
- package/lib/utils/resolve-docker-image-ref.js +124 -0
- package/lib/utils/schema-loader.js +22 -9
- package/lib/utils/secrets-bash-kv.js +25 -0
- package/lib/utils/secrets-generator.js +169 -49
- package/lib/utils/secrets-helpers.js +70 -59
- package/lib/utils/secrets-kv-scope.js +60 -0
- package/lib/utils/secrets-utils.js +32 -38
- package/lib/utils/secrets-validation.js +3 -1
- package/lib/utils/secrets-yaml-preserve.js +109 -0
- package/lib/utils/ssh-key-helper.js +4 -2
- package/lib/utils/template-helpers.js +2 -2
- package/lib/utils/test-log-writer.js +3 -3
- package/lib/utils/token-manager.js +1 -2
- package/lib/utils/url-declarative-public-base.js +188 -0
- package/lib/utils/url-declarative-resolve-build.js +493 -0
- package/lib/utils/url-declarative-resolve-load-doc.js +51 -0
- package/lib/utils/url-declarative-resolve.js +220 -0
- package/lib/utils/url-declarative-token-parse.js +74 -0
- package/lib/utils/url-declarative-url-flags.js +50 -0
- package/lib/utils/url-declarative-vdir-inactive-env.js +99 -0
- package/lib/utils/url-public-path-prefix.js +34 -0
- package/lib/utils/urls-local-registry.js +220 -0
- package/lib/utils/validation-report-tty-kit.js +77 -0
- package/lib/utils/validation-run-poll.js +112 -0
- package/lib/utils/validation-run-post-retry.js +85 -0
- package/lib/utils/validation-run-request.js +116 -0
- package/lib/utils/variable-transformer.js +21 -4
- package/lib/utils/yaml-preserve.js +33 -14
- package/lib/validation/datasource-warnings.js +56 -0
- package/lib/validation/env-template-auth.js +1 -1
- package/lib/validation/external-manifest-validator.js +27 -7
- package/lib/validation/validate-display.js +37 -31
- package/lib/validation/validate-external-cert-sync.js +23 -0
- package/lib/validation/validate.js +8 -14
- package/lib/validation/validator-unresolved-placeholders.js +98 -0
- package/lib/validation/validator.js +22 -65
- package/lib/validation/wizard-config-validator.js +2 -1
- package/package.json +9 -4
- package/scripts/check-datasource-test-run-schema-sync.js +34 -0
- package/scripts/diagnose-cli.js +150 -0
- package/scripts/install-local.js +307 -55
- package/scripts/pnpm-global-remove.js +48 -0
- package/templates/README.md +15 -2
- package/templates/applications/dataplane/application.yaml +52 -2
- package/templates/applications/dataplane/env.template +79 -17
- package/templates/applications/dataplane/rbac.yaml +8 -0
- package/templates/applications/keycloak/application.yaml +9 -1
- package/templates/applications/keycloak/env.template +15 -6
- package/templates/applications/miso-controller/application.yaml +10 -2
- package/templates/applications/miso-controller/env.template +42 -12
- package/templates/applications/miso-controller/rbac.yaml +5 -0
- package/templates/external-system/README.md.hbs +20 -7
- package/templates/external-system/deploy.js.hbs +5 -5
- package/templates/external-system/external-datasource.yaml.hbs +197 -118
- package/templates/infra/compose.yaml.hbs +33 -16
- package/templates/infra/servers.json.hbs +3 -1
- package/templates/python/docker-compose.hbs +16 -0
- package/templates/typescript/docker-compose.hbs +16 -0
- package/lib/api/external-test.api.js +0 -111
- package/lib/schema/env-config.yaml +0 -60
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview System-level TTY renderer for DatasourceTestRun fan-out results (plan §17).
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
'use strict';
|
|
6
|
+
|
|
7
|
+
const chalk = require('chalk');
|
|
8
|
+
const logger = require('./logger');
|
|
9
|
+
const {
|
|
10
|
+
SEP,
|
|
11
|
+
statusGlyph
|
|
12
|
+
} = require('./datasource-test-run-display');
|
|
13
|
+
const {
|
|
14
|
+
sectionTitle,
|
|
15
|
+
headerKeyValue,
|
|
16
|
+
formatStatusKeyValue,
|
|
17
|
+
integrationFooterLine,
|
|
18
|
+
colorRollupPrefixedLine,
|
|
19
|
+
metadata: metaGray
|
|
20
|
+
} = require('./cli-test-layout-chalk');
|
|
21
|
+
const {
|
|
22
|
+
formatDataQualityLines,
|
|
23
|
+
readinessLineFromDataReadiness,
|
|
24
|
+
verdictLineFromEnvelope
|
|
25
|
+
} = require('./validation-report-tty-kit');
|
|
26
|
+
const {
|
|
27
|
+
logCapabilitiesOverview: logCapabilitiesOverviewSection,
|
|
28
|
+
logIntegrationHealthSection: logIntegrationHealthSectionBlock
|
|
29
|
+
} = require('./external-system-system-test-tty-overview');
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @param {'ok'|'warn'|'fail'|'skipped'|null} st
|
|
33
|
+
* @returns {number}
|
|
34
|
+
*/
|
|
35
|
+
function statusRank(st) {
|
|
36
|
+
if (st === 'fail') return 0;
|
|
37
|
+
if (st === 'warn') return 1;
|
|
38
|
+
if (st === 'ok') return 2;
|
|
39
|
+
if (st === 'skipped') return 3;
|
|
40
|
+
return 4;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Per-row status for system rollup and tables: CLI/transport failure overrides envelope-only OK.
|
|
45
|
+
* @param {{ skipped?: boolean, success?: boolean, datasourceTestRun?: { status?: string }|null }} r
|
|
46
|
+
* @returns {'ok'|'warn'|'fail'|'skipped'}
|
|
47
|
+
*/
|
|
48
|
+
function rollupRowStatus(r) {
|
|
49
|
+
if (r && r.skipped) return 'skipped';
|
|
50
|
+
if (r && r.success === false) return 'fail';
|
|
51
|
+
const env = r && r.datasourceTestRun;
|
|
52
|
+
return env && typeof env.status === 'string' ? env.status : 'ok';
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* @param {Array<{ key: string, skipped?: boolean, datasourceTestRun?: Object|null, success?: boolean }>} rows
|
|
57
|
+
* @returns {'ok'|'warn'|'fail'|'skipped'}
|
|
58
|
+
*/
|
|
59
|
+
function deriveSystemStatus(rows) {
|
|
60
|
+
if (!Array.isArray(rows) || rows.length === 0) return 'ok';
|
|
61
|
+
const statuses = rows.map(rollupRowStatus);
|
|
62
|
+
if (statuses.some(s => s === 'fail')) return 'fail';
|
|
63
|
+
if (statuses.some(s => s === 'warn')) return 'warn';
|
|
64
|
+
if (statuses.every(s => s === 'skipped')) return 'skipped';
|
|
65
|
+
// Mixed ok/skipped => warn per plan.
|
|
66
|
+
return statuses.every(s => s === 'ok') ? 'ok' : 'warn';
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function bucketIssueSeverity(issue) {
|
|
70
|
+
const sev = issue && issue.severity ? String(issue.severity).toLowerCase() : '';
|
|
71
|
+
if (sev === 'error' || sev === 'critical' || sev === 'high' || sev === 'fatal') return 'fail';
|
|
72
|
+
if (sev === 'warn' || sev === 'warning' || sev === 'medium') return 'warn';
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Minimal heuristic rollups backed by envelope fields (no engine codenames).
|
|
78
|
+
* @param {Object|null|undefined} env
|
|
79
|
+
* @returns {'ok'|'warn'|'fail'}
|
|
80
|
+
*/
|
|
81
|
+
function dqFromEnvelope(env) {
|
|
82
|
+
const v = env && env.validation;
|
|
83
|
+
const st = v && typeof v.status === 'string' ? String(v.status) : null;
|
|
84
|
+
if (st === 'fail') return 'fail';
|
|
85
|
+
if (st === 'warn') return 'warn';
|
|
86
|
+
|
|
87
|
+
const issues = v && Array.isArray(v.issues) ? v.issues : [];
|
|
88
|
+
if (issues.some(i => bucketIssueSeverity(i) === 'fail')) return 'fail';
|
|
89
|
+
if (issues.some(i => bucketIssueSeverity(i) === 'warn')) return 'warn';
|
|
90
|
+
return 'ok';
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* @param {Array} rows
|
|
95
|
+
* @returns {{ schema: 'ok'|'warn'|'fail', consistency: 'ok'|'warn'|'fail', reliability: 'ok'|'warn'|'fail' }}
|
|
96
|
+
*/
|
|
97
|
+
function deriveSystemDataQuality(rows) {
|
|
98
|
+
const envs = rows
|
|
99
|
+
.map(r => (r && r.datasourceTestRun && typeof r.datasourceTestRun === 'object' ? r.datasourceTestRun : null))
|
|
100
|
+
.filter(Boolean);
|
|
101
|
+
if (envs.length === 0) {
|
|
102
|
+
return { schema: 'warn', consistency: 'warn', reliability: 'warn' };
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const picks = envs.map(dqFromEnvelope);
|
|
106
|
+
const agg = picks.some(x => x === 'fail') ? 'fail' : picks.some(x => x === 'warn') ? 'warn' : 'ok';
|
|
107
|
+
return { schema: agg, consistency: agg, reliability: agg };
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* @param {Array} rows
|
|
112
|
+
* @returns {'ready'|'partial'|'not_ready'|null}
|
|
113
|
+
*/
|
|
114
|
+
function deriveSystemReadiness(rows) {
|
|
115
|
+
const envs = rows
|
|
116
|
+
.map(r => (r && r.datasourceTestRun && typeof r.datasourceTestRun === 'object' ? r.datasourceTestRun : null))
|
|
117
|
+
.filter(Boolean);
|
|
118
|
+
const drs = envs
|
|
119
|
+
.map(e => e.validation && e.validation.dataReadiness)
|
|
120
|
+
.filter(Boolean);
|
|
121
|
+
if (drs.length === 0) return null;
|
|
122
|
+
if (drs.some(x => x === 'not_ready')) return 'not_ready';
|
|
123
|
+
if (drs.some(x => x === 'partial')) return 'partial';
|
|
124
|
+
return 'ready';
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function countByStatus(rows) {
|
|
128
|
+
const counts = { ok: 0, warn: 0, fail: 0, skipped: 0 };
|
|
129
|
+
for (const r of rows) {
|
|
130
|
+
const s = rollupRowStatus(r);
|
|
131
|
+
if (counts[s] !== undefined) counts[s] += 1;
|
|
132
|
+
}
|
|
133
|
+
return counts;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function pickBlockingDatasourceKey(rows) {
|
|
137
|
+
const keys = rows
|
|
138
|
+
.map(r => {
|
|
139
|
+
const env = r && r.datasourceTestRun;
|
|
140
|
+
const st = rollupRowStatus(r);
|
|
141
|
+
const key =
|
|
142
|
+
env && env.datasourceKey
|
|
143
|
+
? String(env.datasourceKey)
|
|
144
|
+
: r && r.key
|
|
145
|
+
? String(r.key)
|
|
146
|
+
: '';
|
|
147
|
+
return { key, st };
|
|
148
|
+
})
|
|
149
|
+
.filter(x => x.key);
|
|
150
|
+
keys.sort((a, b) => {
|
|
151
|
+
const d = statusRank(a.st) - statusRank(b.st);
|
|
152
|
+
if (d !== 0) return d;
|
|
153
|
+
return a.key.localeCompare(b.key);
|
|
154
|
+
});
|
|
155
|
+
return keys.length ? keys[0].key : null;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function issueKey(issue) {
|
|
159
|
+
const code = issue && issue.code ? String(issue.code) : '';
|
|
160
|
+
const msg = issue && issue.message ? String(issue.message) : '';
|
|
161
|
+
return `${code}::${msg}`.toLowerCase();
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function issueSortKey(it) {
|
|
165
|
+
return `${statusRank(it.severity)}::${it.datasourceKey}::${it.message}`.toLowerCase();
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function extractRowIssues(row) {
|
|
169
|
+
const env = row && row.datasourceTestRun;
|
|
170
|
+
const datasourceKey = (env && env.datasourceKey) || (row && row.key) || 'datasource';
|
|
171
|
+
const issues = env && env.validation && Array.isArray(env.validation.issues) ? env.validation.issues : [];
|
|
172
|
+
const envStatus = env && typeof env.status === 'string' ? env.status : null;
|
|
173
|
+
return { datasourceKey: String(datasourceKey), issues, envStatus };
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function toIssueItem(datasourceKey, envStatus, iss) {
|
|
177
|
+
const sev =
|
|
178
|
+
bucketIssueSeverity(iss) ||
|
|
179
|
+
(envStatus === 'fail' ? 'fail' : envStatus === 'warn' ? 'warn' : 'ok');
|
|
180
|
+
const msg = iss && iss.message ? String(iss.message) : iss && iss.code ? String(iss.code) : 'Issue';
|
|
181
|
+
return { datasourceKey, message: msg, severity: sev };
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function collectKeyIssues(rows, cap) {
|
|
185
|
+
/** @type {{ datasourceKey: string, message: string, severity: 'fail'|'warn'|'ok' }[]} */
|
|
186
|
+
const out = [];
|
|
187
|
+
const seen = new Set();
|
|
188
|
+
for (const row of rows) {
|
|
189
|
+
const { datasourceKey, issues, envStatus } = extractRowIssues(row);
|
|
190
|
+
for (const iss of issues) {
|
|
191
|
+
const k = `${datasourceKey}::${issueKey(iss)}`;
|
|
192
|
+
if (seen.has(k)) continue;
|
|
193
|
+
seen.add(k);
|
|
194
|
+
out.push(toIssueItem(datasourceKey, envStatus, iss));
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
out.sort((a, b) => issueSortKey(a).localeCompare(issueSortKey(b)));
|
|
198
|
+
return out.slice(0, Math.max(0, cap));
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function certificateBucket(env) {
|
|
202
|
+
const cert = env && env.certificate;
|
|
203
|
+
if (!cert || typeof cert !== 'object') return { status: null, level: null };
|
|
204
|
+
return {
|
|
205
|
+
status: cert.status ? String(cert.status) : null,
|
|
206
|
+
level: cert.level ? String(cert.level) : null
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function systemCertStatus(rows) {
|
|
211
|
+
const certs = rows
|
|
212
|
+
.map(r => (r && r.datasourceTestRun ? certificateBucket(r.datasourceTestRun) : { status: null, level: null }))
|
|
213
|
+
.filter(c => c.status !== null);
|
|
214
|
+
if (certs.length === 0) return null;
|
|
215
|
+
if (certs.some(c => c.status === 'not_passed')) return 'not_passed';
|
|
216
|
+
return 'passed';
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function drillDownCommand(runType, datasourceKey) {
|
|
220
|
+
if (!datasourceKey) return null;
|
|
221
|
+
if (runType === 'e2e') return `aifabrix datasource test-e2e ${datasourceKey}`;
|
|
222
|
+
if (runType === 'integration') return `aifabrix datasource test-integration ${datasourceKey}`;
|
|
223
|
+
return `aifabrix datasource test ${datasourceKey}`;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function logSystemHeader(results, runType, systemStatus) {
|
|
227
|
+
logger.log('');
|
|
228
|
+
logger.log(sectionTitle('Server test results'));
|
|
229
|
+
logger.log('');
|
|
230
|
+
logger.log(headerKeyValue('System:', results.systemKey));
|
|
231
|
+
logger.log(
|
|
232
|
+
headerKeyValue(
|
|
233
|
+
'Run:',
|
|
234
|
+
runType === 'e2e' ? 'test-e2e (dataplane)' : 'test-integration (dataplane)'
|
|
235
|
+
)
|
|
236
|
+
);
|
|
237
|
+
logger.log(formatStatusKeyValue(systemStatus, statusGlyph(systemStatus)));
|
|
238
|
+
logger.log('');
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
function logVerdictAndSummary(runType, systemStatus, certStatus, counts) {
|
|
242
|
+
logger.log(sectionTitle('Verdict:'));
|
|
243
|
+
logger.log(chalk.white(verdictLineFromEnvelope(systemStatus, certStatus, runType)));
|
|
244
|
+
logger.log('');
|
|
245
|
+
logger.log(sectionTitle('Summary:'));
|
|
246
|
+
logger.log(
|
|
247
|
+
chalk.white(
|
|
248
|
+
`${counts.ok + counts.warn + counts.fail} datasource(s): ${counts.ok} ok, ${counts.warn} warn, ${counts.fail} fail${counts.skipped ? `, ${counts.skipped} skipped` : ''}`
|
|
249
|
+
)
|
|
250
|
+
);
|
|
251
|
+
logger.log('');
|
|
252
|
+
logger.log(metaGray(SEP));
|
|
253
|
+
logger.log('');
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function logDataQualityAndReadiness(rows) {
|
|
257
|
+
logger.log(sectionTitle('Data Quality:'));
|
|
258
|
+
const dq = deriveSystemDataQuality(rows);
|
|
259
|
+
const dqLines = formatDataQualityLines(dq, {
|
|
260
|
+
schema: 'structural coverage aggregated across datasources.',
|
|
261
|
+
consistency: 'issues aggregated across datasources.',
|
|
262
|
+
reliability: 'issues aggregated across datasources.'
|
|
263
|
+
});
|
|
264
|
+
dqLines.map(colorRollupPrefixedLine).forEach(l => logger.log(l));
|
|
265
|
+
|
|
266
|
+
const readiness = deriveSystemReadiness(rows);
|
|
267
|
+
const readinessLine = readinessLineFromDataReadiness(readiness);
|
|
268
|
+
if (readinessLine) {
|
|
269
|
+
logger.log('');
|
|
270
|
+
logger.log(colorRollupPrefixedLine(readinessLine));
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
logger.log('');
|
|
274
|
+
logger.log(metaGray(SEP));
|
|
275
|
+
logger.log('');
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
function logDatasourceTable(rows, counts, verbose) {
|
|
279
|
+
logger.log(sectionTitle('Datasources:'));
|
|
280
|
+
logger.log('');
|
|
281
|
+
if (!verbose && counts.ok > 0) {
|
|
282
|
+
logger.log(chalk.gray(`✔ ${counts.ok} datasource(s) fully ready`));
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
function rowStatus(r) {
|
|
286
|
+
return rollupRowStatus(r);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
function readinessLabel(env, st) {
|
|
290
|
+
const ready = env && env.validation ? env.validation.dataReadiness : null;
|
|
291
|
+
if (ready === 'not_ready') return 'Not ready';
|
|
292
|
+
if (ready === 'partial') return 'Partial';
|
|
293
|
+
if (ready === 'ready') return 'Ready';
|
|
294
|
+
if (st === 'fail') return 'Not ready';
|
|
295
|
+
if (st === 'warn') return 'Partial';
|
|
296
|
+
return 'Ready';
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
function shouldListRow(r) {
|
|
300
|
+
if (verbose) return true;
|
|
301
|
+
const st = rowStatus(r);
|
|
302
|
+
return st === 'warn' || st === 'fail';
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
const listRows = rows.filter(shouldListRow);
|
|
306
|
+
for (const r of listRows) {
|
|
307
|
+
const env = r && r.datasourceTestRun;
|
|
308
|
+
const key = (env && env.datasourceKey) || (r && r.key) || 'datasource';
|
|
309
|
+
const st = rowStatus(r);
|
|
310
|
+
const readyLabel = readinessLabel(env, st);
|
|
311
|
+
logger.log(`${statusGlyph(st)} ${chalk.white(String(key).padEnd(22))} (${readyLabel})`);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
function logBlockingDatasource(blocking) {
|
|
316
|
+
if (!blocking) return;
|
|
317
|
+
logger.log('');
|
|
318
|
+
logger.log(chalk.white(`Blocking datasource: ${blocking}`));
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function logKeyIssuesSection(rows) {
|
|
322
|
+
const issues = collectKeyIssues(rows, 5);
|
|
323
|
+
if (issues.length === 0) return false;
|
|
324
|
+
logger.log('');
|
|
325
|
+
logger.log(metaGray(SEP));
|
|
326
|
+
logger.log('');
|
|
327
|
+
logger.log(sectionTitle('Key issues:'));
|
|
328
|
+
logger.log('');
|
|
329
|
+
let cur = null;
|
|
330
|
+
for (const it of issues) {
|
|
331
|
+
if (cur !== it.datasourceKey) {
|
|
332
|
+
cur = it.datasourceKey;
|
|
333
|
+
logger.log(chalk.white(cur));
|
|
334
|
+
}
|
|
335
|
+
logger.log(chalk.white(`- ${it.message}`));
|
|
336
|
+
}
|
|
337
|
+
return true;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
function logCertificationSection(rows) {
|
|
341
|
+
const certSt = systemCertStatus(rows);
|
|
342
|
+
if (!certSt) return;
|
|
343
|
+
logger.log('');
|
|
344
|
+
logger.log(metaGray(SEP));
|
|
345
|
+
logger.log('');
|
|
346
|
+
logger.log(sectionTitle('Certification:'));
|
|
347
|
+
logger.log('');
|
|
348
|
+
logger.log(chalk.white(`System level: ${certSt === 'passed' ? '✔ Achieved' : '✖ Not achieved'}`));
|
|
349
|
+
logger.log('');
|
|
350
|
+
logger.log(chalk.white('Breakdown:'));
|
|
351
|
+
for (const r of rows) {
|
|
352
|
+
const env = r && r.datasourceTestRun;
|
|
353
|
+
if (!env) continue;
|
|
354
|
+
const cert = certificateBucket(env);
|
|
355
|
+
if (!cert.status) continue;
|
|
356
|
+
const g = cert.status === 'passed' ? '✔' : '✖';
|
|
357
|
+
const tier = cert.level ? cert.level : '(no level)';
|
|
358
|
+
logger.log(chalk.white(`- ${env.datasourceKey}: ${g} ${tier}`));
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
function logUseAndFooter(results, runType, systemStatus, blocking) {
|
|
363
|
+
logger.log('');
|
|
364
|
+
logger.log(metaGray(SEP));
|
|
365
|
+
logger.log('');
|
|
366
|
+
logger.log(sectionTitle('Use:'));
|
|
367
|
+
const cmd = drillDownCommand(runType, blocking);
|
|
368
|
+
logger.log(chalk.white(cmd || 'aifabrix datasource test <datasourceKey>'));
|
|
369
|
+
logger.log(
|
|
370
|
+
integrationFooterLine(
|
|
371
|
+
results.success,
|
|
372
|
+
systemStatus,
|
|
373
|
+
'All server tests passed.',
|
|
374
|
+
'Server tests completed with warnings.',
|
|
375
|
+
'Some server tests failed.'
|
|
376
|
+
)
|
|
377
|
+
);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* Render system-level aggregate (plan §17) for DatasourceTestRun wrapper results.
|
|
382
|
+
* @param {Object} results
|
|
383
|
+
* @param {Object} opts
|
|
384
|
+
* @param {'integration'|'e2e'} opts.runType
|
|
385
|
+
* @param {boolean} opts.verbose
|
|
386
|
+
*/
|
|
387
|
+
function displaySystemAggregateDatasourceTestRuns(results, opts) {
|
|
388
|
+
const rows = Array.isArray(results.datasourceResults) ? results.datasourceResults : [];
|
|
389
|
+
const runType = opts.runType === 'e2e' ? 'e2e' : 'integration';
|
|
390
|
+
const systemStatus = deriveSystemStatus(rows);
|
|
391
|
+
const counts = countByStatus(rows);
|
|
392
|
+
const blocking = pickBlockingDatasourceKey(rows);
|
|
393
|
+
logSystemHeader(results, runType, systemStatus);
|
|
394
|
+
logVerdictAndSummary(runType, systemStatus, systemCertStatus(rows), counts);
|
|
395
|
+
logDataQualityAndReadiness(rows);
|
|
396
|
+
logDatasourceTable(rows, counts, Boolean(opts.verbose));
|
|
397
|
+
logBlockingDatasource(blocking);
|
|
398
|
+
logKeyIssuesSection(rows);
|
|
399
|
+
const ttyIo = { log: logger.log.bind(logger), chalk, metaGray, sectionTitle, statusGlyph, SEP };
|
|
400
|
+
logCapabilitiesOverviewSection(rows, ttyIo);
|
|
401
|
+
logIntegrationHealthSectionBlock(rows, runType, ttyIo);
|
|
402
|
+
logCertificationSection(rows);
|
|
403
|
+
logUseAndFooter(results, runType, systemStatus, blocking);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
module.exports = {
|
|
407
|
+
displaySystemAggregateDatasourceTestRuns,
|
|
408
|
+
deriveSystemStatus,
|
|
409
|
+
deriveSystemDataQuality,
|
|
410
|
+
deriveSystemReadiness,
|
|
411
|
+
rollupRowStatus,
|
|
412
|
+
pickBlockingDatasourceKey,
|
|
413
|
+
collectKeyIssues,
|
|
414
|
+
systemCertStatus,
|
|
415
|
+
drillDownCommand
|
|
416
|
+
};
|
|
417
|
+
|
|
@@ -12,9 +12,32 @@
|
|
|
12
12
|
const fs = require('fs').promises;
|
|
13
13
|
const path = require('path');
|
|
14
14
|
const { testDatasourceViaPipeline } = require('../api/pipeline.api');
|
|
15
|
+
const { integrationResultFromEnvelope, firstIssueMessage } = require('./datasource-test-run-legacy-adapter');
|
|
15
16
|
|
|
16
17
|
/** Pipeline test endpoints accept client credentials; do not enforce Bearer-only */
|
|
17
18
|
|
|
19
|
+
/**
|
|
20
|
+
* Parse successful pipeline test body (envelope or legacy).
|
|
21
|
+
* @param {Object} body
|
|
22
|
+
* @param {string} datasourceKey
|
|
23
|
+
* @returns {Object}
|
|
24
|
+
* @throws {Error} When body indicates failure
|
|
25
|
+
*/
|
|
26
|
+
function parsePipelineTestResponseBody(body, datasourceKey) {
|
|
27
|
+
if (body && typeof body === 'object' && typeof body.status === 'string' && body.datasourceKey) {
|
|
28
|
+
if (body.status === 'fail') {
|
|
29
|
+
const errMsg = firstIssueMessage(body) || 'Test failed';
|
|
30
|
+
throw new Error(`Test endpoint failed: ${errMsg}`);
|
|
31
|
+
}
|
|
32
|
+
return integrationResultFromEnvelope(body, datasourceKey);
|
|
33
|
+
}
|
|
34
|
+
if (body.success === false) {
|
|
35
|
+
const errMsg = body.error || body.formattedError || 'Test failed';
|
|
36
|
+
throw new Error(`Test endpoint failed: ${errMsg}`);
|
|
37
|
+
}
|
|
38
|
+
return body.data || body;
|
|
39
|
+
}
|
|
40
|
+
|
|
18
41
|
/**
|
|
19
42
|
* Retry API call with exponential backoff
|
|
20
43
|
* @async
|
|
@@ -73,13 +96,8 @@ async function callPipelineTestEndpoint({ systemKey, datasourceKey, payloadTempl
|
|
|
73
96
|
if (!response.success || !response.data) {
|
|
74
97
|
throw new Error(`Test endpoint failed: ${response.error || response.formattedError || 'Unknown error'}`);
|
|
75
98
|
}
|
|
76
|
-
// When 200 with success: false in body, pass through; caller interprets via data.success
|
|
77
|
-
if (response.data?.success === false) {
|
|
78
|
-
const errMsg = response.data?.error || response.data?.formattedError || 'Test failed';
|
|
79
|
-
throw new Error(`Test endpoint failed: ${errMsg}`);
|
|
80
|
-
}
|
|
81
99
|
|
|
82
|
-
return response.data
|
|
100
|
+
return parsePipelineTestResponseBody(response.data, datasourceKey);
|
|
83
101
|
}
|
|
84
102
|
|
|
85
103
|
/**
|
|
@@ -119,24 +119,38 @@ function checkPathExistsInPayload(fieldPath, payloadTemplate) {
|
|
|
119
119
|
}
|
|
120
120
|
|
|
121
121
|
/**
|
|
122
|
-
*
|
|
123
|
-
* @param {Object}
|
|
122
|
+
* Root dimensions (dimensionBinding): local bindings as dimKey → metadata path string for validateDimensions.
|
|
123
|
+
* @param {Object} datasource - Datasource config
|
|
124
|
+
* @returns {Object} Map suitable for validateDimensions
|
|
125
|
+
*/
|
|
126
|
+
function getDimensionsMapForValidation(datasource) {
|
|
127
|
+
const root = datasource?.dimensions;
|
|
128
|
+
if (!root || typeof root !== 'object' || Array.isArray(root)) return {};
|
|
129
|
+
const out = {};
|
|
130
|
+
for (const [dimKey, binding] of Object.entries(root)) {
|
|
131
|
+
if (binding && typeof binding === 'object' && typeof binding.field === 'string') {
|
|
132
|
+
out[dimKey] = `metadata.${binding.field}`;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return out;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Validates dimensions object structure and content (path strings).
|
|
140
|
+
* @param {Object} dimensions - dimKey → path (e.g. metadata.country)
|
|
124
141
|
* @param {Object} results - Results object to update
|
|
125
142
|
*/
|
|
126
143
|
function validateDimensions(dimensions, results) {
|
|
127
|
-
if (!dimensions) {
|
|
128
|
-
results.
|
|
129
|
-
results.valid = false;
|
|
144
|
+
if (!dimensions || typeof dimensions !== 'object' || Array.isArray(dimensions)) {
|
|
145
|
+
results.warnings.push('No dimensions configured (schema v2.4: use root dimensions; optional but recommended for ABAC)');
|
|
130
146
|
return;
|
|
131
147
|
}
|
|
132
148
|
|
|
133
|
-
if (
|
|
134
|
-
results.
|
|
135
|
-
results.valid = false;
|
|
149
|
+
if (Object.keys(dimensions).length === 0) {
|
|
150
|
+
results.warnings.push('Dimensions object is empty');
|
|
136
151
|
return;
|
|
137
152
|
}
|
|
138
153
|
|
|
139
|
-
// Validate dimension keys and values
|
|
140
154
|
for (const [dimensionKey, attributePath] of Object.entries(dimensions)) {
|
|
141
155
|
if (!/^[a-zA-Z0-9_]+$/.test(dimensionKey)) {
|
|
142
156
|
results.errors.push(`Invalid dimension key '${dimensionKey}': dimension key must contain only letters, numbers, and underscores`);
|
|
@@ -180,7 +194,7 @@ function validateAttributesStructure(attributes, results) {
|
|
|
180
194
|
*/
|
|
181
195
|
function validateSingleAttribute(attributeName, attributeConfig, payloadTemplate, results) {
|
|
182
196
|
if (!attributeConfig || typeof attributeConfig !== 'object') {
|
|
183
|
-
results.errors.push(`Attribute '${attributeName}' must be an object with expression
|
|
197
|
+
results.errors.push(`Attribute '${attributeName}' must be an object with expression`);
|
|
184
198
|
results.valid = false;
|
|
185
199
|
return;
|
|
186
200
|
}
|
|
@@ -224,8 +238,7 @@ function validateFieldMappings(datasource, testPayload) {
|
|
|
224
238
|
return results;
|
|
225
239
|
}
|
|
226
240
|
|
|
227
|
-
|
|
228
|
-
validateDimensions(datasource.fieldMappings.dimensions, results);
|
|
241
|
+
validateDimensions(getDimensionsMapForValidation(datasource), results);
|
|
229
242
|
|
|
230
243
|
// Validate attributes structure (required in new schema)
|
|
231
244
|
const attributes = validateAttributesStructure(datasource.fieldMappings.attributes, results);
|
|
@@ -322,6 +335,11 @@ function validateAgainstSchema(data, schema) {
|
|
|
322
335
|
validateSchema: false
|
|
323
336
|
});
|
|
324
337
|
addFormats(ajv);
|
|
338
|
+
// Some schemas (e.g. external-datasource.schema.json) reference these by $id (aifabrix://schema/type/*).
|
|
339
|
+
// Adding them up-front keeps validation offline-safe and avoids unresolved $ref failures.
|
|
340
|
+
ajv.addSchema(require('../schema/type/document-storage.json'));
|
|
341
|
+
ajv.addSchema(require('../schema/type/message-service.json'));
|
|
342
|
+
ajv.addSchema(require('../schema/type/vector-store.json'));
|
|
325
343
|
// Remove $schema for draft-2020-12 to avoid AJV issues
|
|
326
344
|
const schemaCopy = { ...schema };
|
|
327
345
|
if (schemaCopy.$schema && schemaCopy.$schema.includes('2020-12')) {
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Health check URL resolution helpers.
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Compute health check URL using declarative public URL logic (Traefik/frontDoorRouting)
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
'use strict';
|
|
8
|
+
|
|
9
|
+
const { computePublicUrlBaseString } = require('./url-declarative-public-base');
|
|
10
|
+
const { parseDeveloperIdNum } = require('./declarative-url-ports');
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Join URL path segments with exactly one slash between them.
|
|
14
|
+
* @param {string} a
|
|
15
|
+
* @param {string} b
|
|
16
|
+
* @returns {string}
|
|
17
|
+
*/
|
|
18
|
+
function joinUrlPath(a, b) {
|
|
19
|
+
const left = String(a || '').replace(/\/+$/, '');
|
|
20
|
+
const right = String(b || '').replace(/^\/+/, '');
|
|
21
|
+
if (!left) return `/${right}`;
|
|
22
|
+
if (!right) return left || '/';
|
|
23
|
+
return `${left}/${right}`;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Convert a frontDoorRouting.pattern (Traefik/Front Door wildcard route) into a concrete mount path.
|
|
28
|
+
* Example: "/auth/*" -> "/auth"
|
|
29
|
+
*
|
|
30
|
+
* @param {string} pattern
|
|
31
|
+
* @returns {string}
|
|
32
|
+
*/
|
|
33
|
+
function normalizeFrontDoorPatternForHealth(pattern) {
|
|
34
|
+
let p = String(pattern || '').trim();
|
|
35
|
+
if (!p) return '/';
|
|
36
|
+
if (!p.startsWith('/')) p = `/${p}`;
|
|
37
|
+
// Drop wildcard suffixes used for routing.
|
|
38
|
+
p = p.replace(/\/\*+$/, '');
|
|
39
|
+
p = p.replace(/\*+$/, '');
|
|
40
|
+
// Drop trailing path params like "/foo/{bar}" if present (health is mounted at the base).
|
|
41
|
+
p = p.replace(/\/\{[^}]+\}$/, '');
|
|
42
|
+
// Normalize slashes and trailing slash.
|
|
43
|
+
p = p.replace(/\/{2,}/g, '/');
|
|
44
|
+
p = p.replace(/\/+$/, '');
|
|
45
|
+
return p || '/';
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* @param {Object|null} appConfig
|
|
50
|
+
* @returns {boolean}
|
|
51
|
+
*/
|
|
52
|
+
function frontDoorEnabled(appConfig) {
|
|
53
|
+
return Boolean(appConfig && appConfig.frontDoorRouting && appConfig.frontDoorRouting.enabled === true);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* @param {Object|null} appConfig
|
|
58
|
+
* @returns {string|null}
|
|
59
|
+
*/
|
|
60
|
+
function frontDoorPattern(appConfig) {
|
|
61
|
+
const p = appConfig && appConfig.frontDoorRouting ? appConfig.frontDoorRouting.pattern : null;
|
|
62
|
+
return (typeof p === 'string' && p.trim()) ? p.trim() : null;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Compute the Traefik front-door health check URL when applicable.
|
|
67
|
+
*
|
|
68
|
+
* Returns null when Traefik/frontDoorRouting isn't active or cannot be resolved.
|
|
69
|
+
*
|
|
70
|
+
* @async
|
|
71
|
+
* @param {string} appName
|
|
72
|
+
* @param {number} healthCheckPort
|
|
73
|
+
* @param {Object|null} appConfig
|
|
74
|
+
* @returns {Promise<string|null>}
|
|
75
|
+
*/
|
|
76
|
+
async function computeTraefikHealthCheckUrl(appName, healthCheckPort, appConfig) {
|
|
77
|
+
if (!frontDoorEnabled(appConfig)) return null;
|
|
78
|
+
const pattern = frontDoorPattern(appConfig);
|
|
79
|
+
if (!pattern) return null;
|
|
80
|
+
|
|
81
|
+
const coreConfig = require('../core/config');
|
|
82
|
+
const userCfg = await coreConfig.getConfig();
|
|
83
|
+
if (!(userCfg && userCfg.traefik)) return null;
|
|
84
|
+
|
|
85
|
+
const infraTlsEnabled = Boolean(userCfg && userCfg.tlsEnabled);
|
|
86
|
+
const remoteServer = await coreConfig.getRemoteServer();
|
|
87
|
+
const developerIdRaw = await coreConfig.getDeveloperId();
|
|
88
|
+
const developerIdNum = parseDeveloperIdNum(developerIdRaw);
|
|
89
|
+
|
|
90
|
+
// Health checks originate from the CLI on the host, not from inside a container.
|
|
91
|
+
const profile = 'local';
|
|
92
|
+
const fd = appConfig.frontDoorRouting;
|
|
93
|
+
const listenPort = Number(appConfig?.port || 3000);
|
|
94
|
+
|
|
95
|
+
const publicBase = computePublicUrlBaseString({
|
|
96
|
+
traefik: true,
|
|
97
|
+
pathActive: true,
|
|
98
|
+
hostTemplate: fd.host,
|
|
99
|
+
tls: fd.tls,
|
|
100
|
+
developerIdRaw,
|
|
101
|
+
remoteServer,
|
|
102
|
+
profile,
|
|
103
|
+
listenPort,
|
|
104
|
+
developerIdNum,
|
|
105
|
+
infraTlsEnabled
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
const healthCheckPath = appConfig?.healthCheck?.path || '/health';
|
|
109
|
+
const mountPath = normalizeFrontDoorPatternForHealth(pattern);
|
|
110
|
+
const baseWithFrontDoor = joinUrlPath(publicBase, mountPath);
|
|
111
|
+
return joinUrlPath(baseWithFrontDoor, healthCheckPath);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
module.exports = {
|
|
115
|
+
joinUrlPath,
|
|
116
|
+
normalizeFrontDoorPatternForHealth,
|
|
117
|
+
computeTraefikHealthCheckUrl
|
|
118
|
+
};
|
|
119
|
+
|