@aifabrix/builder 2.45.0 → 2.46.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/cli-layout.mdc +2 -0
- package/.cursor/rules/cli-product-neutral.mdc +43 -0
- package/.cursor/rules/docs-rules.mdc +3 -1
- package/.cursor/rules/project-rules.mdc +1 -0
- package/README.md +43 -17
- package/integration/hubspot-test/wizard-hubspot-e2e.yaml +1 -1
- package/jest.config.default.js +2 -1
- package/jest.config.isolated.js +2 -1
- package/jest.global-live-fabrix-hooks.js +36 -0
- package/jest.isolated-projects.js +130 -0
- package/jest.projects.js +69 -121
- package/lib/api/agent-metadata-validation.api.js +93 -0
- package/lib/api/api-response-errors.js +124 -0
- package/lib/api/audit-api-helpers.js +68 -0
- package/lib/api/audit.api.js +119 -0
- package/lib/api/auth-cache.api.js +44 -0
- package/lib/api/certificates.api.js +4 -4
- package/lib/api/credential.api.js +2 -2
- package/lib/api/dataplane-health.api.js +137 -0
- package/lib/api/dataplane-sync.api.js +27 -0
- package/lib/api/datasources-core.api.js +21 -18
- package/lib/api/datasources-extended.api.js +22 -22
- package/lib/api/dimensions.api.js +3 -0
- package/lib/api/external-systems.api.js +13 -13
- package/lib/api/governance-scenario-pack.api.js +159 -0
- package/lib/api/governance-scenarios.api.js +39 -0
- package/lib/api/groups.api.js +79 -0
- package/lib/api/index.js +88 -5
- package/lib/api/lifecycle.api.js +77 -0
- package/lib/api/pipeline.api.js +7 -5
- package/lib/api/protection.api.js +157 -0
- package/lib/api/records-bulk.api.js +43 -0
- package/lib/api/records-search-parse.js +49 -0
- package/lib/api/records-search.api.js +29 -0
- package/lib/api/types/agent-metadata-validation.types.js +67 -0
- package/lib/api/types/audit.types.js +72 -0
- package/lib/api/types/dataplane-health.types.js +27 -0
- package/lib/api/types/dimensions.types.js +2 -0
- package/lib/api/types/governance-scenarios.types.js +39 -0
- package/lib/api/types/protection.types.js +69 -0
- package/lib/api/types/records-bulk.types.js +35 -0
- package/lib/api/types/records-search.types.js +28 -0
- package/lib/api/user-groups.api.js +50 -0
- package/lib/api/users.api.js +95 -0
- package/lib/api/validation-run.api.js +3 -3
- package/lib/api/validation-runner.js +5 -3
- package/lib/api/wizard-platform.api.js +3 -3
- package/lib/api/wizard.api.js +21 -21
- package/lib/app/deploy-config.js +4 -1
- package/lib/app/deploy.js +34 -19
- package/lib/app/down.js +20 -1
- package/lib/app/push.js +4 -5
- package/lib/app/register.js +7 -4
- package/lib/app/run-env-compose.js +84 -30
- package/lib/build/index.js +5 -0
- package/lib/certification/sync-system-certification.js +13 -6
- package/lib/cli/index.js +8 -2
- package/lib/cli/infra-guided-auth.js +109 -0
- package/lib/cli/infra-guided.js +91 -69
- package/lib/cli/setup-app.help.js +19 -2
- package/lib/cli/setup-app.js +58 -23
- package/lib/cli/setup-app.test-commands.js +28 -21
- package/lib/cli/setup-auth.js +55 -3
- package/lib/cli/setup-certification-commands.js +147 -0
- package/lib/cli/setup-certification.help.js +141 -0
- package/lib/cli/setup-environment.js +19 -2
- package/lib/cli/setup-external-system-help.js +62 -0
- package/lib/cli/setup-external-system.js +62 -6
- package/lib/cli/setup-infra.js +9 -1
- package/lib/cli/setup-platform.js +6 -1
- package/lib/cli/setup-secrets.js +33 -1
- package/lib/cli/setup-utility-help-after.js +65 -0
- package/lib/cli/setup-utility-repair.js +198 -0
- package/lib/cli/setup-utility-resolve.js +42 -6
- package/lib/cli/setup-utility-validate.js +197 -0
- package/lib/cli/setup-utility.js +41 -258
- package/lib/commands/auth-status-client-tokens.js +214 -0
- package/lib/commands/auth-status-dataplane-version.js +269 -0
- package/lib/commands/auth-status-display.js +94 -0
- package/lib/commands/auth-status.js +111 -53
- package/lib/commands/credential-push.js +10 -5
- package/lib/commands/datasource-load-export-cli.js +178 -0
- package/lib/commands/datasource-test-trust-cli.js +118 -0
- package/lib/commands/datasource-unified-test-cli.js +31 -20
- package/lib/commands/datasource-unified-test-cli.options.js +22 -3
- package/lib/commands/datasource-unified-test-e2e-cli-helpers.js +5 -5
- package/lib/commands/datasource-verify-audit-cli.js +96 -0
- package/lib/commands/datasource.js +68 -1
- package/lib/commands/dev-show-display.js +8 -1
- package/lib/commands/dimension-value.js +43 -13
- package/lib/commands/dimension.js +38 -7
- package/lib/commands/governance-cli-shared.js +94 -0
- package/lib/commands/governance-command-action.js +132 -0
- package/lib/commands/governance-download-external.js +34 -0
- package/lib/commands/governance-generate-external.js +71 -0
- package/lib/commands/governance-upload-external.js +36 -0
- package/lib/commands/governance-verify-external.js +64 -0
- package/lib/commands/governance.js +144 -0
- package/lib/commands/identity-apply-sync.js +131 -0
- package/lib/commands/identity-group-cli.js +146 -0
- package/lib/commands/identity-membership-role-cache.js +175 -0
- package/lib/commands/identity-shared.js +94 -0
- package/lib/commands/identity-user-cli.js +158 -0
- package/lib/commands/identity.js +43 -0
- package/lib/commands/lifecycle-command-action.js +123 -0
- package/lib/commands/lifecycle-external.js +268 -0
- package/lib/commands/login.js +56 -17
- package/lib/commands/protection-cli-leaves.js +286 -0
- package/lib/commands/protection.js +50 -0
- package/lib/commands/repair-auth-apply.js +127 -0
- package/lib/commands/repair-changed-files.js +41 -0
- package/lib/commands/repair-datasource-keys.js +4 -1
- package/lib/commands/repair-datasource-run.js +59 -0
- package/lib/commands/repair-datasource-test-payload.js +259 -0
- package/lib/commands/repair-datasource.js +1 -51
- package/lib/commands/repair-env-template.js +64 -13
- package/lib/commands/repair-external-run.js +216 -0
- package/lib/commands/repair-openapi-sync.js +23 -0
- package/lib/commands/repair-persist.js +4 -0
- package/lib/commands/repair-rbac.js +52 -1
- package/lib/commands/repair-steps.js +145 -0
- package/lib/commands/repair.js +29 -286
- package/lib/commands/secrets-get.js +184 -0
- package/lib/commands/secrets-remove-all.js +3 -1
- package/lib/commands/setup-image-refresh.js +146 -0
- package/lib/commands/setup-modes.js +158 -162
- package/lib/commands/setup-platform-auth.js +76 -0
- package/lib/commands/setup-prompts-admin.js +244 -0
- package/lib/commands/setup-prompts-platform-mode.js +67 -0
- package/lib/commands/setup-prompts-validators.js +36 -0
- package/lib/commands/setup-prompts.js +24 -76
- package/lib/commands/setup-run-context.js +45 -0
- package/lib/commands/setup-spinners.js +39 -0
- package/lib/commands/setup.js +27 -5
- package/lib/commands/teardown.js +39 -0
- package/lib/commands/test-e2e-external.js +61 -14
- package/lib/commands/test-governance-cli-options.js +47 -0
- package/lib/commands/test-governance-external.js +67 -0
- package/lib/commands/test-trust-cli-options.js +32 -0
- package/lib/commands/test-trust-external.js +126 -0
- package/lib/commands/up-common.js +25 -13
- package/lib/commands/up-dataplane.js +50 -13
- package/lib/commands/upload-publish-context.js +75 -0
- package/lib/commands/upload-sidecar-followups.js +89 -0
- package/lib/commands/upload.js +108 -105
- package/lib/commands/verify-governance-combined-external.js +61 -0
- package/lib/commands/verify-governance-command-action.js +64 -0
- package/lib/commands/verify-governance-db.js +102 -0
- package/lib/commands/verify-governance-external.js +77 -0
- package/lib/commands/verify-governance-result-builders.js +71 -0
- package/lib/commands/verify-operations-command-action.js +68 -0
- package/lib/commands/verify-operations-external.js +268 -0
- package/lib/commands/verify-operations-persist.js +75 -0
- package/lib/commands/verify-operations-step-plan.js +68 -0
- package/lib/commands/verify-operations-steps.js +111 -0
- package/lib/commands/verify-trust-command-action.js +70 -0
- package/lib/commands/verify-trust-external.js +67 -0
- package/lib/commands/wizard-config-normalizer.js +43 -23
- package/lib/commands/wizard-core.js +5 -0
- package/lib/core/admin-password-generator.js +38 -0
- package/lib/core/admin-secrets-bundle.js +111 -0
- package/lib/core/admin-secrets-env-overlay.js +62 -0
- package/lib/core/admin-secrets.js +32 -4
- package/lib/core/config-attach-extensions.js +3 -0
- package/lib/core/config-device-dataplane.js +185 -0
- package/lib/core/config-platform-controller.js +44 -0
- package/lib/core/config-setup-installation-profile.js +42 -0
- package/lib/core/config-setup-platform-mode.js +46 -0
- package/lib/core/config.js +46 -36
- package/lib/core/secrets-admin-env.js +6 -2
- package/lib/core/secrets-ensure.js +4 -0
- package/lib/core/secrets-env-content.js +54 -48
- package/lib/core/secrets-env-write.js +10 -1
- package/lib/core/secrets-infra-placeholder-sync.js +2 -0
- package/lib/core/setup-installation-profile.js +43 -0
- package/lib/core/setup-platform-mode.js +55 -0
- package/lib/datasource/agent-trust-debug-log.js +45 -0
- package/lib/datasource/agent-trust-fetch.js +115 -0
- package/lib/datasource/agent-trust-map.js +101 -0
- package/lib/datasource/agent-trust-mock.js +44 -0
- package/lib/datasource/agent-trust-run.js +95 -0
- package/lib/datasource/agent-trust-timeout.js +25 -0
- package/lib/datasource/audit-evidence-display.js +80 -0
- package/lib/datasource/audit-evidence-extract-debug.js +115 -0
- package/lib/datasource/audit-evidence-extract.js +180 -0
- package/lib/datasource/audit-evidence-matrix-rows.js +158 -0
- package/lib/datasource/audit-evidence-operation-aliases.js +63 -0
- package/lib/datasource/audit-evidence-poll.js +109 -0
- package/lib/datasource/audit-evidence-run.js +177 -0
- package/lib/datasource/audit-evidence-verify-helpers.js +167 -0
- package/lib/datasource/audit-evidence-verify-matrix.js +205 -0
- package/lib/datasource/audit-evidence-verify.js +108 -0
- package/lib/datasource/bulk-loader-run-batches.js +100 -0
- package/lib/datasource/bulk-loader-service-retry.js +52 -0
- package/lib/datasource/bulk-loader-service.js +127 -0
- package/lib/datasource/capability/run-capability-dimension.js +2 -1
- package/lib/datasource/datasource-exporter-resolve.js +82 -0
- package/lib/datasource/datasource-exporter-service.js +144 -0
- package/lib/datasource/datasource-identifier.js +148 -0
- package/lib/datasource/datasource-load-export-context.js +95 -0
- package/lib/datasource/integration-context.js +6 -4
- package/lib/datasource/local-data-paths.js +145 -0
- package/lib/datasource/log-cleaner.js +241 -0
- package/lib/datasource/log-viewer.js +111 -6
- package/lib/datasource/record-file-parser.js +85 -0
- package/lib/datasource/record-mapper.js +129 -0
- package/lib/datasource/resolve-app.js +74 -55
- package/lib/datasource/test-e2e.js +29 -2
- package/lib/datasource/unified-validation-run-body.js +3 -1
- package/lib/datasource/unified-validation-run-resolve.js +45 -12
- package/lib/datasource/unified-validation-run.js +47 -18
- package/lib/datasource/validate.js +37 -20
- package/lib/deployment/environment-poll-status.js +138 -0
- package/lib/deployment/environment.js +42 -34
- package/lib/external-system/download.js +21 -20
- package/lib/external-system/generator.js +5 -1
- package/lib/external-system/integration-auth-context.js +45 -0
- package/lib/external-system/test-auth.js +12 -5
- package/lib/external-system/test-system-level.js +25 -4
- package/lib/external-system/test.js +9 -7
- package/lib/generator/external-controller-manifest.js +15 -0
- package/lib/governance/governance-cli-errors.js +96 -0
- package/lib/governance/governance-download-display.js +38 -0
- package/lib/governance/governance-pack-loader.js +70 -0
- package/lib/governance/governance-run-display.js +309 -0
- package/lib/identity/identity-apply-core.js +108 -0
- package/lib/identity/identity-apply-phases.js +244 -0
- package/lib/identity/identity-apply-service.js +77 -0
- package/lib/identity/identity-csv-parser.js +114 -0
- package/lib/infrastructure/admin-secrets-apply.js +84 -0
- package/lib/infrastructure/admin-secrets-ensure.js +130 -0
- package/lib/infrastructure/admin-secrets-resolve.js +95 -0
- package/lib/infrastructure/admin-secrets-sync.js +91 -0
- package/lib/infrastructure/helpers.js +23 -129
- package/lib/infrastructure/index.js +5 -6
- package/lib/infrastructure/orphan-infra-docker-teardown.js +11 -5
- package/lib/internal/fs-real-sync.js +29 -1
- package/lib/lifecycle/certification-progress.js +231 -0
- package/lib/lifecycle/dataplane-ui-url.js +145 -0
- package/lib/lifecycle/exit-codes.js +24 -0
- package/lib/lifecycle/json-envelope.js +25 -0
- package/lib/lifecycle/lifecycle-governance-options.js +51 -0
- package/lib/lifecycle/logger-quiet.js +29 -0
- package/lib/lifecycle/open-api-published.js +59 -0
- package/lib/lifecycle/operations-readiness-metrics.js +101 -0
- package/lib/lifecycle/product-model.js +196 -0
- package/lib/lifecycle/report-display.js +471 -0
- package/lib/lifecycle/scenario-upload.js +191 -0
- package/lib/lifecycle/verify-step-progress.js +87 -0
- package/lib/parameters/infra-kv-discovery.js +27 -2
- package/lib/protection/auth-context.js +51 -0
- package/lib/protection/convert-batch.js +90 -0
- package/lib/protection/load.js +41 -0
- package/lib/protection/paths.js +158 -0
- package/lib/protection/preflight-datasource-ready.js +46 -0
- package/lib/protection/protection-create-probe-lines.js +142 -0
- package/lib/protection/protection-create-probes.js +95 -0
- package/lib/protection/protection-create-scaffold.js +281 -0
- package/lib/protection/protection-display-helpers.js +445 -0
- package/lib/protection/protection-display.js +215 -0
- package/lib/protection/protection-preset-registry.js +97 -0
- package/lib/protection/report-exit.js +62 -0
- package/lib/protection/resolve.js +202 -0
- package/lib/protection/run-commands-validate.js +130 -0
- package/lib/protection/run-commands.js +216 -0
- package/lib/protection/run-protection-create-helpers.js +134 -0
- package/lib/protection/run-protection-create-probes-flow.js +43 -0
- package/lib/protection/run-protection-create.js +191 -0
- package/lib/protection/scope.js +22 -0
- package/lib/protection/sync-after-upload.js +64 -0
- package/lib/protection/upload-batch.js +127 -0
- package/lib/protection/validate-batch.js +113 -0
- package/lib/protection/validate-local.js +65 -0
- package/lib/resolvers/dimension-file.js +29 -4
- package/lib/schema/application-schema.json +1 -1
- package/lib/schema/datasource-test-run.schema.json +89 -6
- package/lib/schema/external-datasource.schema.json +2636 -2588
- package/lib/schema/external-system.schema.json +1089 -761
- package/lib/schema/flag-map-validation-run.json +2 -2
- package/lib/schema/infra.parameter.yaml +45 -0
- package/lib/schema/protection.schema.json +374 -0
- package/lib/schema/type/credential-field-registry.json +642 -0
- package/lib/schema/wizard-config.schema.json +1 -1
- package/lib/utils/agent-trust-run-display.js +231 -0
- package/lib/utils/agent-trust-run-exit.js +59 -0
- package/lib/utils/agent-trust-wait-ui.js +94 -0
- package/lib/utils/aifabrix-test-runtime-guard.js +125 -0
- package/lib/utils/api.js +55 -31
- package/lib/utils/app-relative-path-env.js +112 -0
- package/lib/utils/cli-exit-codes.js +30 -0
- package/lib/utils/cli-secrets-error-format.js +83 -21
- package/lib/utils/cli-sync-options.js +33 -0
- package/lib/utils/cli-utils.js +16 -4
- package/lib/utils/compose-generate-docker-compose.js +4 -0
- package/lib/utils/compose-traefik-ingress-base.js +16 -1
- package/lib/utils/config-secrets-path.js +46 -0
- package/lib/utils/controller-url.js +88 -1
- package/lib/utils/credential-push-ui.js +90 -0
- package/lib/utils/credential-secrets-env.js +137 -9
- package/lib/utils/dataplane-cli-version-gate.js +202 -0
- package/lib/utils/dataplane-cli-version-help.js +74 -0
- package/lib/utils/dataplane-resolver.js +129 -2
- package/lib/utils/datasource-export-display.js +137 -0
- package/lib/utils/datasource-load-display.js +174 -0
- package/lib/utils/datasource-load-export-ui.js +120 -0
- package/lib/utils/datasource-test-run-capability-scope.js +3 -3
- package/lib/utils/datasource-test-run-display.js +3 -3
- package/lib/utils/datasource-test-run-tty-log.js +5 -1
- package/lib/utils/declarative-url-ports.js +3 -3
- package/lib/utils/deployment-auth-mode.js +41 -0
- package/lib/utils/developer-volume-id.js +33 -0
- package/lib/utils/env-copy.js +14 -9
- package/lib/utils/env-kv-orphan-lines.js +43 -0
- package/lib/utils/error-formatters/network-errors.js +13 -4
- package/lib/utils/external-env-template.js +1 -0
- package/lib/utils/external-system-readiness-core.js +10 -0
- package/lib/utils/external-system-readiness-display.js +80 -23
- package/lib/utils/health-check.js +4 -1
- package/lib/utils/help-builder.js +35 -26
- package/lib/utils/keycloak-realm-ready.js +101 -0
- package/lib/utils/load-cip-capacity-display-config.js +61 -15
- package/lib/utils/manifest-source-emit.js +24 -0
- package/lib/utils/pipeline-upload-auth-retry.js +82 -0
- package/lib/utils/platform-controller-url.js +156 -0
- package/lib/utils/postgres-platform-bootstrap.js +199 -0
- package/lib/utils/postgres-wipe.js +9 -2
- package/lib/utils/resolve-env-mode.js +47 -0
- package/lib/utils/secrets-generator.js +31 -25
- package/lib/utils/secrets-missing-error.js +164 -0
- package/lib/utils/semver-compare.js +127 -0
- package/lib/utils/service-url-label.js +81 -0
- package/lib/utils/setup-quiet-output.js +25 -0
- package/lib/utils/template-helpers.js +15 -0
- package/lib/utils/token-manager-client-credentials.js +201 -0
- package/lib/utils/token-manager-messages.js +8 -0
- package/lib/utils/token-manager-refresh.js +12 -2
- package/lib/utils/token-manager.js +86 -105
- package/lib/utils/upload-pipeline-ui.js +98 -0
- package/lib/utils/upload-sync-options.js +42 -0
- package/lib/utils/url-declarative-public-base.js +21 -3
- package/lib/utils/url-declarative-vdir-inactive-env.js +14 -4
- package/lib/utils/validation-poll-ui.js +22 -7
- package/lib/utils/validation-run-stage.js +45 -0
- package/lib/validation/wizard-config-validator.js +58 -19
- package/package.json +1 -1
- package/templates/applications/dataplane/application.yaml +2 -1
- package/templates/applications/dataplane/env.template +36 -1
- package/templates/applications/dataplane/rbac.yaml +4 -0
- package/templates/applications/miso-controller/env.template +16 -0
- package/templates/external-system/README.md.hbs +116 -11
- package/templates/python/docker-compose.hbs +19 -18
- package/templates/typescript/docker-compose.hbs +18 -17
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Poll helpers for environment deploy status (deployment-by-ID).
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Parse pipeline/environments deployment poll responses and fail fast on terminal HTTP errors
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const TERMINAL_POLL_HTTP_STATUSES = new Set([400, 401, 403, 404, 410, 422]);
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @param {Object|null|undefined} response - API client response
|
|
13
|
+
* @returns {boolean}
|
|
14
|
+
*/
|
|
15
|
+
function isTerminalPollApiResponse(response) {
|
|
16
|
+
return Boolean(
|
|
17
|
+
response &&
|
|
18
|
+
response.success === false &&
|
|
19
|
+
typeof response.status === 'number' &&
|
|
20
|
+
TERMINAL_POLL_HTTP_STATUSES.has(response.status)
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @param {Object|null|undefined} response - Successful API client response
|
|
26
|
+
* @returns {Object|null} Deployment record or null
|
|
27
|
+
*/
|
|
28
|
+
function extractDeploymentRecord(response) {
|
|
29
|
+
if (!response || response.success === false) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
if (response?.data?.data) {
|
|
33
|
+
return response.data.data;
|
|
34
|
+
}
|
|
35
|
+
if (response?.data && typeof response.data === 'object' && response.data.status) {
|
|
36
|
+
return response.data;
|
|
37
|
+
}
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* @param {Object|null|undefined} pipelineRes
|
|
43
|
+
* @param {Object|null|undefined} envRes
|
|
44
|
+
* @returns {Error}
|
|
45
|
+
*/
|
|
46
|
+
/**
|
|
47
|
+
* @param {string} requestedEnvKey
|
|
48
|
+
* @param {Error} error
|
|
49
|
+
* @returns {Error}
|
|
50
|
+
*/
|
|
51
|
+
function enrichPollTerminalError(requestedEnvKey, error) {
|
|
52
|
+
if (!error?.pollTerminal || error.status !== 404) {
|
|
53
|
+
return error;
|
|
54
|
+
}
|
|
55
|
+
const base = error.message || '';
|
|
56
|
+
if (!base.includes('Environment with key')) {
|
|
57
|
+
return error;
|
|
58
|
+
}
|
|
59
|
+
error.message =
|
|
60
|
+
`${base}\n\n` +
|
|
61
|
+
'The deployment may have been created under a different environment key ' +
|
|
62
|
+
'(for example evaluation-mode fallback to miso). Check controller logs for ' +
|
|
63
|
+
`effectiveEnvironmentKey, register '${requestedEnvKey}' in the controller, or run ` +
|
|
64
|
+
'aifabrix env deploy miso.';
|
|
65
|
+
return error;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function buildPollStatusError(pipelineRes, envRes) {
|
|
69
|
+
const terminal = [pipelineRes, envRes].filter(isTerminalPollApiResponse);
|
|
70
|
+
const source = terminal[0] || pipelineRes || envRes;
|
|
71
|
+
const message = source?.formattedError || source?.error || 'Unable to retrieve deployment status';
|
|
72
|
+
const err = new Error(message);
|
|
73
|
+
err.pollTerminal = true;
|
|
74
|
+
if (typeof source?.status === 'number') {
|
|
75
|
+
err.status = source.status;
|
|
76
|
+
}
|
|
77
|
+
return err;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Fetches deployment status by ID (pipeline endpoint first, then environments).
|
|
82
|
+
*
|
|
83
|
+
* @async
|
|
84
|
+
* @param {Function} getPipelineDeployment - pipeline.api getPipelineDeployment
|
|
85
|
+
* @param {Function} getDeployment - deployments.api getDeployment
|
|
86
|
+
* @param {string} controllerUrl
|
|
87
|
+
* @param {string} envKey
|
|
88
|
+
* @param {string} deploymentId
|
|
89
|
+
* @param {Object} apiAuthConfig
|
|
90
|
+
* @returns {Promise<Object|null>} Deployment record or null when status is not yet available (retry)
|
|
91
|
+
* @throws {Error} When both endpoints return a terminal HTTP error (e.g. environment not found)
|
|
92
|
+
*/
|
|
93
|
+
async function fetchDeploymentStatusById(
|
|
94
|
+
getPipelineDeployment,
|
|
95
|
+
getDeployment,
|
|
96
|
+
controllerUrl,
|
|
97
|
+
envKey,
|
|
98
|
+
deploymentId,
|
|
99
|
+
apiAuthConfig
|
|
100
|
+
) {
|
|
101
|
+
let pipelineRes;
|
|
102
|
+
let envRes;
|
|
103
|
+
|
|
104
|
+
try {
|
|
105
|
+
pipelineRes = await getPipelineDeployment(controllerUrl, envKey, deploymentId, apiAuthConfig);
|
|
106
|
+
const fromPipeline = extractDeploymentRecord(pipelineRes);
|
|
107
|
+
if (fromPipeline) {
|
|
108
|
+
return fromPipeline;
|
|
109
|
+
}
|
|
110
|
+
} catch (err) {
|
|
111
|
+
pipelineRes = { success: false, error: err?.message || String(err) };
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
try {
|
|
115
|
+
envRes = await getDeployment(controllerUrl, envKey, deploymentId, apiAuthConfig);
|
|
116
|
+
const fromEnv = extractDeploymentRecord(envRes);
|
|
117
|
+
if (fromEnv) {
|
|
118
|
+
return fromEnv;
|
|
119
|
+
}
|
|
120
|
+
} catch (err) {
|
|
121
|
+
envRes = { success: false, error: err?.message || String(err) };
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (isTerminalPollApiResponse(pipelineRes) || isTerminalPollApiResponse(envRes)) {
|
|
125
|
+
throw buildPollStatusError(pipelineRes, envRes);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
module.exports = {
|
|
132
|
+
TERMINAL_POLL_HTTP_STATUSES,
|
|
133
|
+
isTerminalPollApiResponse,
|
|
134
|
+
extractDeploymentRecord,
|
|
135
|
+
enrichPollTerminalError,
|
|
136
|
+
buildPollStatusError,
|
|
137
|
+
fetchDeploymentStatusById
|
|
138
|
+
};
|
|
@@ -25,6 +25,7 @@ const {
|
|
|
25
25
|
buildEnvironmentConfigFromPreset,
|
|
26
26
|
loadAndValidateEnvironmentDeployConfig
|
|
27
27
|
} = require('./environment-config');
|
|
28
|
+
const { fetchDeploymentStatusById, enrichPollTerminalError } = require('./environment-poll-status');
|
|
28
29
|
|
|
29
30
|
/**
|
|
30
31
|
* Validates environment deployment prerequisites
|
|
@@ -161,31 +162,24 @@ async function sendEnvironmentDeployment(controllerUrl, envKey, authConfig, opti
|
|
|
161
162
|
}
|
|
162
163
|
|
|
163
164
|
/**
|
|
164
|
-
* Fetches deployment status by ID (pipeline endpoint first, then environments)
|
|
165
|
-
* Mirrors miso-controller manual test: GET pipeline/deployments/:id then GET environments/deployments/:id
|
|
165
|
+
* Fetches deployment status by ID (pipeline endpoint first, then environments).
|
|
166
166
|
* @async
|
|
167
167
|
* @param {string} controllerUrl - Controller URL
|
|
168
168
|
* @param {string} envKey - Environment key
|
|
169
169
|
* @param {string} deploymentId - Deployment ID
|
|
170
170
|
* @param {Object} apiAuthConfig - Auth config { type: 'bearer', token }
|
|
171
|
-
* @returns {Promise<Object|null>} Deployment record
|
|
171
|
+
* @returns {Promise<Object|null>} Deployment record or null when still in progress
|
|
172
|
+
* @throws {Error} On terminal poll errors (e.g. environment or deployment not found)
|
|
172
173
|
*/
|
|
173
174
|
async function getDeploymentStatusById(controllerUrl, envKey, deploymentId, apiAuthConfig) {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
const envRes = await getDeployment(controllerUrl, envKey, deploymentId, apiAuthConfig);
|
|
183
|
-
if (envRes?.data?.data) return envRes.data.data;
|
|
184
|
-
if (envRes?.data && typeof envRes.data === 'object' && envRes.data.status) return envRes.data;
|
|
185
|
-
} catch {
|
|
186
|
-
// Ignore
|
|
187
|
-
}
|
|
188
|
-
return null;
|
|
175
|
+
return fetchDeploymentStatusById(
|
|
176
|
+
getPipelineDeployment,
|
|
177
|
+
getDeployment,
|
|
178
|
+
controllerUrl,
|
|
179
|
+
envKey,
|
|
180
|
+
deploymentId,
|
|
181
|
+
apiAuthConfig
|
|
182
|
+
);
|
|
189
183
|
}
|
|
190
184
|
|
|
191
185
|
/**
|
|
@@ -218,6 +212,33 @@ function processDeploymentStatusResponse(deployment, validatedEnvKey) {
|
|
|
218
212
|
return null;
|
|
219
213
|
}
|
|
220
214
|
|
|
215
|
+
/**
|
|
216
|
+
* @param {number} attempt
|
|
217
|
+
* @param {number} maxAttempts
|
|
218
|
+
* @param {Object|null} deployment
|
|
219
|
+
*/
|
|
220
|
+
function logPollAttemptProgress(attempt, maxAttempts, deployment) {
|
|
221
|
+
const progress = deployment?.progress ?? 0;
|
|
222
|
+
const statusLabel = deployment?.status ?? 'pending';
|
|
223
|
+
logger.log(chalk.gray(` Attempt ${attempt}/${maxAttempts}... Status: ${statusLabel} (${progress}%)`));
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* @param {Error} error
|
|
228
|
+
* @param {string} validatedEnvKey
|
|
229
|
+
* @throws {Error}
|
|
230
|
+
*/
|
|
231
|
+
function handlePollIterationError(error, validatedEnvKey) {
|
|
232
|
+
const msg = error?.message || '';
|
|
233
|
+
const isDeploymentFailed =
|
|
234
|
+
msg.includes('Environment deployment failed') ||
|
|
235
|
+
(msg.includes('failed') && !error.pollTerminal);
|
|
236
|
+
if (error.pollTerminal || isDeploymentFailed) {
|
|
237
|
+
throw enrichPollTerminalError(validatedEnvKey, error);
|
|
238
|
+
}
|
|
239
|
+
logger.log(chalk.yellow(` ⚠ Status check failed (will retry): ${msg}`));
|
|
240
|
+
}
|
|
241
|
+
|
|
221
242
|
/**
|
|
222
243
|
* Polls environment deployment status
|
|
223
244
|
* @async
|
|
@@ -231,44 +252,31 @@ function processDeploymentStatusResponse(deployment, validatedEnvKey) {
|
|
|
231
252
|
async function pollEnvironmentStatus(deploymentId, controllerUrl, envKey, authConfig, options = {}) {
|
|
232
253
|
const validatedUrl = validateControllerUrl(controllerUrl);
|
|
233
254
|
const validatedEnvKey = validateEnvironmentKey(envKey);
|
|
234
|
-
|
|
235
255
|
const pollInterval = options.pollInterval || 5000;
|
|
236
256
|
const maxAttempts = options.maxAttempts || 60;
|
|
257
|
+
const apiAuthConfig = { type: 'bearer', token: authConfig.token };
|
|
237
258
|
|
|
238
259
|
logger.log(chalk.blue(`⏳ Polling environment status (${pollInterval}ms intervals)...`));
|
|
239
260
|
|
|
240
|
-
// Use centralized API client
|
|
241
|
-
const apiAuthConfig = { type: 'bearer', token: authConfig.token };
|
|
242
|
-
|
|
243
261
|
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
244
262
|
try {
|
|
245
263
|
await new Promise(resolve => setTimeout(resolve, pollInterval));
|
|
246
|
-
|
|
247
264
|
const deployment = await getDeploymentStatusById(
|
|
248
265
|
validatedUrl,
|
|
249
266
|
validatedEnvKey,
|
|
250
267
|
deploymentId,
|
|
251
268
|
apiAuthConfig
|
|
252
269
|
);
|
|
253
|
-
|
|
254
|
-
const statusLabel = deployment?.status ?? 'pending';
|
|
255
|
-
if (attempt <= maxAttempts) {
|
|
256
|
-
logger.log(chalk.gray(` Attempt ${attempt}/${maxAttempts}... Status: ${statusLabel} (${progress}%)`));
|
|
257
|
-
}
|
|
270
|
+
logPollAttemptProgress(attempt, maxAttempts, deployment);
|
|
258
271
|
const statusResult = processDeploymentStatusResponse(deployment, validatedEnvKey);
|
|
259
272
|
if (statusResult) {
|
|
260
273
|
return statusResult;
|
|
261
274
|
}
|
|
262
275
|
} catch (error) {
|
|
263
|
-
|
|
264
|
-
if (error.message && error.message.includes('failed')) {
|
|
265
|
-
throw error;
|
|
266
|
-
}
|
|
267
|
-
// Otherwise, continue polling
|
|
276
|
+
handlePollIterationError(error, validatedEnvKey);
|
|
268
277
|
}
|
|
269
278
|
}
|
|
270
279
|
|
|
271
|
-
// Timeout
|
|
272
280
|
throw new Error(`Environment deployment timeout after ${maxAttempts} attempts. Check controller logs for status.`);
|
|
273
281
|
}
|
|
274
282
|
|
|
@@ -437,30 +437,24 @@ function logDownloadCommandHeader(systemKey) {
|
|
|
437
437
|
}
|
|
438
438
|
|
|
439
439
|
/**
|
|
440
|
-
* Downloads external system from dataplane to local development structure
|
|
440
|
+
* Downloads external system from dataplane to local development structure.
|
|
441
441
|
* @async
|
|
442
|
-
* @
|
|
443
|
-
* @param {
|
|
444
|
-
* @
|
|
445
|
-
* @param {string} [options.format] - Output format: 'yaml' (default) or 'json' (runs convert after split)
|
|
446
|
-
* @param {string} [options.environment] - Environment (dev, tst, pro)
|
|
447
|
-
* @param {string} [options.controller] - Controller URL
|
|
448
|
-
* @param {boolean} [options.dryRun] - Show what would be downloaded without actually downloading
|
|
449
|
-
* @param {boolean} [options.force] - Overwrite existing README.md without prompting
|
|
450
|
-
* @returns {Promise<void>} Resolves when download completes
|
|
451
|
-
* @throws {Error} If download fails
|
|
442
|
+
* @param {string} systemKey
|
|
443
|
+
* @param {Object} [options]
|
|
444
|
+
* @returns {Promise<void>}
|
|
452
445
|
*/
|
|
453
446
|
async function downloadExternalSystem(systemKey, options = {}) {
|
|
454
447
|
validateSystemKeyFormat(systemKey);
|
|
455
|
-
|
|
456
448
|
const format = (options.format || 'yaml').toLowerCase();
|
|
457
449
|
|
|
458
450
|
try {
|
|
459
451
|
logDownloadCommandHeader(systemKey);
|
|
460
|
-
|
|
461
452
|
const config = await getConfig();
|
|
462
|
-
const { authConfig, dataplaneUrl } = await setupAuthenticationAndDataplane(
|
|
463
|
-
|
|
453
|
+
const { authConfig, dataplaneUrl } = await setupAuthenticationAndDataplane(
|
|
454
|
+
systemKey,
|
|
455
|
+
options,
|
|
456
|
+
config
|
|
457
|
+
);
|
|
464
458
|
if (options.dryRun) {
|
|
465
459
|
handleDryRun(systemKey, dataplaneUrl);
|
|
466
460
|
return;
|
|
@@ -468,15 +462,22 @@ async function downloadExternalSystem(systemKey, options = {}) {
|
|
|
468
462
|
|
|
469
463
|
const manifest = await downloadFullManifest(dataplaneUrl, systemKey, authConfig);
|
|
470
464
|
validateAndLogDownloadedData(manifest.application, manifest.dataSources);
|
|
471
|
-
|
|
472
465
|
const finalPath = getIntegrationPath(systemKey);
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
466
|
+
await processDownloadedSystem(
|
|
467
|
+
systemKey,
|
|
468
|
+
manifest,
|
|
469
|
+
await resolveDownloadSplitOptions(finalPath, options)
|
|
470
|
+
);
|
|
471
|
+
const { downloadGovernanceScenarioPacksFromManifest } = require('../lifecycle/scenario-upload');
|
|
472
|
+
await downloadGovernanceScenarioPacksFromManifest(
|
|
473
|
+
systemKey,
|
|
474
|
+
manifest,
|
|
475
|
+
dataplaneUrl,
|
|
476
|
+
authConfig
|
|
477
|
+
);
|
|
476
478
|
if (format === 'json') {
|
|
477
479
|
await runConvertToJsonIfRequested(systemKey);
|
|
478
480
|
}
|
|
479
|
-
|
|
480
481
|
displayDownloadSuccess(systemKey, finalPath, manifest.dataSources.length);
|
|
481
482
|
} catch (error) {
|
|
482
483
|
throw new Error(`Failed to download external system: ${error.message}`);
|
|
@@ -26,7 +26,7 @@ handlebars.registerHelper('json', (obj) => JSON.stringify(obj));
|
|
|
26
26
|
* Build authentication object per schema authenticationVariablesByMethod.
|
|
27
27
|
* Security values use canonical kv://<systemKey>/<segment> paths (segment from getKvPathSegmentForSecurityKey).
|
|
28
28
|
* @param {string} systemKey - External system key
|
|
29
|
-
* @param {string} authType - Auth method (oauth2, aad, apikey, basic, queryParam, oidc, hmac, none)
|
|
29
|
+
* @param {string} authType - Auth method (oauth2, aad, apikey, bearerToken, basic, queryParam, oidc, hmac, none)
|
|
30
30
|
* @returns {{ method: string, variables: Object, security: Object }} Authentication object
|
|
31
31
|
*/
|
|
32
32
|
function buildAuthenticationFromMethod(systemKey, authType) {
|
|
@@ -50,6 +50,10 @@ function buildAuthenticationFromMethod(systemKey, authType) {
|
|
|
50
50
|
variables: { baseUrl: base, headerName: 'X-API-Key' },
|
|
51
51
|
security: { apiKey: kvPath('apiKey') }
|
|
52
52
|
},
|
|
53
|
+
bearerToken: {
|
|
54
|
+
variables: { baseUrl: base, headerName: 'Authorization', prefix: 'Bearer' },
|
|
55
|
+
security: { token: kvPath('token') }
|
|
56
|
+
},
|
|
53
57
|
basic: {
|
|
54
58
|
variables: { baseUrl: base },
|
|
55
59
|
security: { username: kvPath('username'), password: kvPath('password') }
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reuse dataplane auth resolved during sync/upload across verify and test commands.
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Integration auth context helpers
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const { setupIntegrationTestAuth } = require('./test-auth');
|
|
12
|
+
const { getConfig } = require('../core/config');
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @param {Object} options
|
|
16
|
+
* @returns {Object}
|
|
17
|
+
*/
|
|
18
|
+
function integrationAuthOptions(options) {
|
|
19
|
+
const base = {
|
|
20
|
+
environment: options.env,
|
|
21
|
+
silentResolve: options.silentResolve === true
|
|
22
|
+
};
|
|
23
|
+
if (options.authConfig && options.dataplaneUrl) {
|
|
24
|
+
return { ...base, authConfig: options.authConfig, dataplaneUrl: options.dataplaneUrl };
|
|
25
|
+
}
|
|
26
|
+
return base;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @param {string} systemKey
|
|
31
|
+
* @param {Object} options
|
|
32
|
+
* @returns {Promise<{ authConfig: Object, dataplaneUrl: string }>}
|
|
33
|
+
*/
|
|
34
|
+
async function resolveIntegrationAuth(systemKey, options) {
|
|
35
|
+
if (options.authConfig && options.dataplaneUrl) {
|
|
36
|
+
return { authConfig: options.authConfig, dataplaneUrl: options.dataplaneUrl };
|
|
37
|
+
}
|
|
38
|
+
const configObj = await getConfig();
|
|
39
|
+
return setupIntegrationTestAuth(systemKey, integrationAuthOptions(options), configObj);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
module.exports = {
|
|
43
|
+
integrationAuthOptions,
|
|
44
|
+
resolveIntegrationAuth
|
|
45
|
+
};
|
|
@@ -26,9 +26,14 @@ const { resolveControllerUrl } = require('../utils/controller-url');
|
|
|
26
26
|
* @throws {Error} If authentication fails
|
|
27
27
|
*/
|
|
28
28
|
async function setupIntegrationTestAuth(appName, options, _config) {
|
|
29
|
+
const opts = options && typeof options === 'object' ? options : {};
|
|
30
|
+
if (opts.authConfig && opts.dataplaneUrl) {
|
|
31
|
+
return { authConfig: opts.authConfig, dataplaneUrl: opts.dataplaneUrl };
|
|
32
|
+
}
|
|
33
|
+
|
|
29
34
|
const { resolveEnvironment } = require('../core/config');
|
|
30
|
-
const environment = (
|
|
31
|
-
?
|
|
35
|
+
const environment = (opts.environment && typeof opts.environment === 'string' && opts.environment.trim())
|
|
36
|
+
? opts.environment.trim()
|
|
32
37
|
: await resolveEnvironment();
|
|
33
38
|
const controllerUrl = await resolveControllerUrl();
|
|
34
39
|
const authConfig = await getDeploymentAuth(controllerUrl, environment, appName);
|
|
@@ -38,10 +43,12 @@ async function setupIntegrationTestAuth(appName, options, _config) {
|
|
|
38
43
|
}
|
|
39
44
|
|
|
40
45
|
let dataplaneUrl;
|
|
41
|
-
if (
|
|
42
|
-
dataplaneUrl =
|
|
46
|
+
if (opts.dataplane && typeof opts.dataplane === 'string' && opts.dataplane.trim()) {
|
|
47
|
+
dataplaneUrl = opts.dataplane.trim();
|
|
43
48
|
} else {
|
|
44
|
-
dataplaneUrl = await resolveDataplaneUrl(controllerUrl, environment, authConfig
|
|
49
|
+
dataplaneUrl = await resolveDataplaneUrl(controllerUrl, environment, authConfig, {
|
|
50
|
+
silent: opts.silentResolve === true
|
|
51
|
+
});
|
|
45
52
|
}
|
|
46
53
|
|
|
47
54
|
return { authConfig, dataplaneUrl };
|
|
@@ -16,7 +16,7 @@ const { getIntegrationPath } = require('../utils/paths');
|
|
|
16
16
|
const { runUnifiedDatasourceValidation } = require('../datasource/unified-validation-run');
|
|
17
17
|
|
|
18
18
|
async function runOneDatasourceKey(appName, datasourceKey, opts) {
|
|
19
|
-
const { environment, runType, debug, timeoutMs } = opts;
|
|
19
|
+
const { environment, runType, debug, timeoutMs, authConfig, dataplaneUrl } = opts;
|
|
20
20
|
try {
|
|
21
21
|
const uni = await runUnifiedDatasourceValidation(datasourceKey, {
|
|
22
22
|
app: appName,
|
|
@@ -26,7 +26,9 @@ async function runOneDatasourceKey(appName, datasourceKey, opts) {
|
|
|
26
26
|
verbose: false,
|
|
27
27
|
timeout: timeoutMs,
|
|
28
28
|
async: true,
|
|
29
|
-
noAsync: false
|
|
29
|
+
noAsync: false,
|
|
30
|
+
authConfig,
|
|
31
|
+
dataplaneUrl
|
|
30
32
|
});
|
|
31
33
|
|
|
32
34
|
if (uni.apiError) {
|
|
@@ -89,7 +91,17 @@ async function maybeWriteSystemRunLog(appName, systemKey, datasourceKeys, runTyp
|
|
|
89
91
|
* @param {number} [params.timeout] - Request timeout
|
|
90
92
|
* @returns {Promise<{success: boolean, datasourceResults: Object[]}>}
|
|
91
93
|
*/
|
|
92
|
-
async function runSystemLevelTest({
|
|
94
|
+
async function runSystemLevelTest({
|
|
95
|
+
appName,
|
|
96
|
+
systemKey,
|
|
97
|
+
datasourceKeys,
|
|
98
|
+
environment,
|
|
99
|
+
runType,
|
|
100
|
+
debug,
|
|
101
|
+
timeout,
|
|
102
|
+
authConfig,
|
|
103
|
+
dataplaneUrl
|
|
104
|
+
}) {
|
|
93
105
|
if (!Array.isArray(datasourceKeys) || datasourceKeys.length === 0) {
|
|
94
106
|
return { success: true, datasourceResults: [] };
|
|
95
107
|
}
|
|
@@ -100,7 +112,16 @@ async function runSystemLevelTest({ appName, systemKey, datasourceKeys, environm
|
|
|
100
112
|
// Keep sequential to avoid spiking external APIs / dataplane concurrency in CLI runs.
|
|
101
113
|
// (Plan allows parallel later, but UX needs stable logs first.)
|
|
102
114
|
// eslint-disable-next-line no-await-in-loop -- intentional sequential execution
|
|
103
|
-
results.push(
|
|
115
|
+
results.push(
|
|
116
|
+
await runOneDatasourceKey(appName, key, {
|
|
117
|
+
environment,
|
|
118
|
+
runType,
|
|
119
|
+
debug,
|
|
120
|
+
timeoutMs,
|
|
121
|
+
authConfig,
|
|
122
|
+
dataplaneUrl
|
|
123
|
+
})
|
|
124
|
+
);
|
|
104
125
|
}
|
|
105
126
|
|
|
106
127
|
const success = results.every(r => r.success);
|
|
@@ -38,6 +38,7 @@ const {
|
|
|
38
38
|
} = require('./test-execution');
|
|
39
39
|
const { runSystemLevelTest } = require('./test-system-level');
|
|
40
40
|
const { shouldUseSystemLevelIntegrationCall } = require('./integration-test-dispatch');
|
|
41
|
+
const { cliOptsSkipSync } = require('../utils/cli-sync-options');
|
|
41
42
|
|
|
42
43
|
/**
|
|
43
44
|
* Loads and parses application config file
|
|
@@ -412,7 +413,8 @@ function determineDatasourcesToTest(datasourceFiles, datasourceFilter) {
|
|
|
412
413
|
* @param {string} [options.controller] - Controller URL
|
|
413
414
|
* @param {boolean} [options.verbose] - Show detailed test output
|
|
414
415
|
* @param {number} [options.timeout] - Request timeout in milliseconds
|
|
415
|
-
* @param {boolean} [options.
|
|
416
|
+
* @param {boolean} [options.noSync] - When true, skip publish (exercise dataplane config already deployed)
|
|
417
|
+
* @param {boolean} [options.sync] - Legacy explicit sync; ignored when `noSync` / `--no-sync` is set
|
|
416
418
|
* @returns {Promise<Object>} Integration test results
|
|
417
419
|
* @throws {Error} If testing fails
|
|
418
420
|
*/
|
|
@@ -457,13 +459,11 @@ async function testExternalSystemIntegration(appName, options = {}) {
|
|
|
457
459
|
|
|
458
460
|
const { systemKey, authConfig, dataplaneUrl, datasourcesToTest, customPayload } = await prepareIntegrationTestEnvironment(appName, options);
|
|
459
461
|
|
|
460
|
-
if (options
|
|
462
|
+
if (!cliOptsSkipSync(options)) {
|
|
461
463
|
logger.log(chalk.cyan('Syncing local config to dataplane…'));
|
|
462
464
|
const { uploadExternalSystem } = require('../commands/upload');
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
minimal: true
|
|
466
|
-
});
|
|
465
|
+
const { buildMinimalUploadSyncOptions } = require('../utils/upload-sync-options');
|
|
466
|
+
await uploadExternalSystem(systemKey, buildMinimalUploadSyncOptions(options));
|
|
467
467
|
logger.log(formatSuccessLine('Sync complete'));
|
|
468
468
|
}
|
|
469
469
|
|
|
@@ -486,7 +486,9 @@ async function testExternalSystemIntegration(appName, options = {}) {
|
|
|
486
486
|
environment: options.environment,
|
|
487
487
|
runType: 'integration',
|
|
488
488
|
debug: options.debug,
|
|
489
|
-
timeout
|
|
489
|
+
timeout,
|
|
490
|
+
authConfig,
|
|
491
|
+
dataplaneUrl
|
|
490
492
|
});
|
|
491
493
|
results.success = systemResult.success;
|
|
492
494
|
results.datasourceResults = systemResult.datasourceResults;
|
|
@@ -22,6 +22,19 @@ const { loadVariables, loadRbac } = require('./helpers');
|
|
|
22
22
|
* @param {Object} systemJson - System JSON object
|
|
23
23
|
* @param {Object|null} rbac - RBAC configuration
|
|
24
24
|
*/
|
|
25
|
+
/**
|
|
26
|
+
* Maps legacy integration auth method names to schema 1.3.0 values before upload/deploy.
|
|
27
|
+
* @param {Object} systemJson - System JSON object (mutated in place)
|
|
28
|
+
*/
|
|
29
|
+
function normalizeLegacyAuthMethod(systemJson) {
|
|
30
|
+
const auth = systemJson && systemJson.authentication;
|
|
31
|
+
if (!auth || typeof auth !== 'object') return;
|
|
32
|
+
const method = String(auth.method || '').trim().toLowerCase();
|
|
33
|
+
if (method === 'bearerkey') {
|
|
34
|
+
auth.method = 'bearerToken';
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
25
38
|
function mergeRbacIntoSystemJson(systemJson, rbac) {
|
|
26
39
|
if (!rbac) {
|
|
27
40
|
return;
|
|
@@ -78,6 +91,7 @@ function extractAppMetadata(variables, appName) {
|
|
|
78
91
|
*/
|
|
79
92
|
async function loadSystemWithRbac(appPath, schemaBasePath, systemFile) {
|
|
80
93
|
const systemJson = await loadSystemFile(appPath, schemaBasePath, systemFile);
|
|
94
|
+
normalizeLegacyAuthMethod(systemJson);
|
|
81
95
|
const rbacPath = resolveRbacPath(appPath);
|
|
82
96
|
const rbac = rbacPath ? loadRbac(rbacPath) : null;
|
|
83
97
|
mergeRbacIntoSystemJson(systemJson, rbac);
|
|
@@ -187,6 +201,7 @@ function toDeployJsonShape(manifest) {
|
|
|
187
201
|
}
|
|
188
202
|
|
|
189
203
|
module.exports = {
|
|
204
|
+
normalizeLegacyAuthMethod,
|
|
190
205
|
generateControllerManifest,
|
|
191
206
|
toDeployJsonShape
|
|
192
207
|
};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Governance CLI error messages (424.0).
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
'use strict';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @param {Error|string} err
|
|
9
|
+
* @returns {boolean}
|
|
10
|
+
*/
|
|
11
|
+
function isGovernancePackNotFoundError(err) {
|
|
12
|
+
const raw = (err && err.message) || String(err);
|
|
13
|
+
return /not found/i.test(raw) || /\b404\b/.test(raw);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @param {Error|string} err
|
|
18
|
+
* @returns {boolean}
|
|
19
|
+
*/
|
|
20
|
+
function isGovernanceCoverageSchemaError(err) {
|
|
21
|
+
const raw = (err && err.message) || String(err);
|
|
22
|
+
return (
|
|
23
|
+
raw.includes('\'coverage\' is a required property') || /spec\.coverage/i.test(raw)
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Short, non-duplicative CLI message from a dataplane governance API error.
|
|
29
|
+
* @param {Error|string} err
|
|
30
|
+
* @returns {string}
|
|
31
|
+
*/
|
|
32
|
+
function shortGovernanceApiError(err) {
|
|
33
|
+
const raw = ((err && err.message) || String(err)).trim();
|
|
34
|
+
if (isGovernancePackNotFoundError(err)) {
|
|
35
|
+
return 'No active pack on dataplane';
|
|
36
|
+
}
|
|
37
|
+
if (isGovernanceCoverageSchemaError(err)) {
|
|
38
|
+
return 'Pack missing spec.coverage (424.0 schema)';
|
|
39
|
+
}
|
|
40
|
+
const firstLine = raw.split('\n').find(line => line.trim()) || raw;
|
|
41
|
+
if (/^Governance scenario pack not found/i.test(firstLine)) {
|
|
42
|
+
return 'No active pack on dataplane';
|
|
43
|
+
}
|
|
44
|
+
return firstLine.length > 100 ? `${firstLine.slice(0, 97)}...` : firstLine;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* User-facing hint after a failed governance pack upload (validation).
|
|
49
|
+
* @param {string} systemKey
|
|
50
|
+
* @returns {string}
|
|
51
|
+
*/
|
|
52
|
+
function governanceUploadSchemaHint(systemKey) {
|
|
53
|
+
return (
|
|
54
|
+
'Scenario pack does not meet the 424.0 schema. Use dataplane-first generation:\n' +
|
|
55
|
+
` aifabrix governance generate ${systemKey} --subject-email <email>\n` +
|
|
56
|
+
'Or: aifabrix verify-governance ' +
|
|
57
|
+
`${systemKey} --subject-email <email>`
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Clarify subject-resolution 400s (dataplane reachable; User row missing).
|
|
63
|
+
* @param {Error} err
|
|
64
|
+
* @param {{ subjectEmails?: string[] }} [context]
|
|
65
|
+
* @returns {Error}
|
|
66
|
+
*/
|
|
67
|
+
function enrichUnresolvableGovernanceSubjectsError(err, context = {}) {
|
|
68
|
+
const hay = `${err.message || ''} ${err.formatted || ''}`;
|
|
69
|
+
if (!hay.includes('No resolvable subjects')) {
|
|
70
|
+
return err;
|
|
71
|
+
}
|
|
72
|
+
const emails = Array.isArray(context.subjectEmails)
|
|
73
|
+
? context.subjectEmails.filter(Boolean)
|
|
74
|
+
: [];
|
|
75
|
+
const lines = [
|
|
76
|
+
'',
|
|
77
|
+
'The dataplane is reachable. This is not a network or controller error.',
|
|
78
|
+
'Pack generation needs --subject-email values that match existing dataplane User rows.',
|
|
79
|
+
emails.length > 0 ? `Subject email(s) you passed: ${emails.join(', ')}` : null,
|
|
80
|
+
'Check:',
|
|
81
|
+
' aifabrix identity user list --search <email>',
|
|
82
|
+
'If the user is missing, apply your identity CSV first:',
|
|
83
|
+
' aifabrix identity apply --file integration/<systemKey>/fixtures/<users>.csv --filter-prefix <systemKey>',
|
|
84
|
+
' aifabrix identity sync -e dev --purge-cache'
|
|
85
|
+
].filter(line => line !== null);
|
|
86
|
+
err.formatted = `${err.formatted || err.message}${lines.join('\n')}`;
|
|
87
|
+
return err;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
module.exports = {
|
|
91
|
+
isGovernancePackNotFoundError,
|
|
92
|
+
isGovernanceCoverageSchemaError,
|
|
93
|
+
shortGovernanceApiError,
|
|
94
|
+
governanceUploadSchemaHint,
|
|
95
|
+
enrichUnresolvableGovernanceSubjectsError
|
|
96
|
+
};
|