@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
|
@@ -9,99 +9,19 @@
|
|
|
9
9
|
* @version 2.0.0
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
const fs = require('fs');
|
|
13
|
-
const yaml = require('js-yaml');
|
|
14
12
|
const config = require('../core/config');
|
|
15
13
|
const logger = require('./logger');
|
|
16
|
-
const pathsUtil = require('./paths');
|
|
17
14
|
const {
|
|
18
15
|
refreshClientToken,
|
|
19
16
|
refreshDeviceToken
|
|
20
17
|
} = require('./token-manager-refresh');
|
|
21
18
|
const { warnRefreshFailureOnce, warnRefreshTokenExpiredOnce } = require('./token-manager-messages');
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Validate that secrets.local.yaml contains dataplane client credentials.
|
|
32
|
-
* If missing, the developer should run: aifabrix app rotate-secret dataplane
|
|
33
|
-
* @param {string} [secretsFilePath] - Path to secrets file; defaults to ~/.aifabrix/secrets.local.yaml
|
|
34
|
-
* @returns {{ valid: boolean, hint?: string }}
|
|
35
|
-
*/
|
|
36
|
-
function validateDataplaneSecrets(secretsFilePath) {
|
|
37
|
-
const filePath = secretsFilePath || getSecretsFilePath();
|
|
38
|
-
const hint = 'Dataplane credentials are missing. Run: aifabrix app rotate-secret dataplane';
|
|
39
|
-
try {
|
|
40
|
-
if (!fs.existsSync(filePath)) {
|
|
41
|
-
return { valid: false, hint };
|
|
42
|
-
}
|
|
43
|
-
const content = fs.readFileSync(filePath, 'utf8');
|
|
44
|
-
const secrets = yaml.load(content) || {};
|
|
45
|
-
const clientIdKey = `${DATAPLANE_APP_KEY}-client-idKeyVault`;
|
|
46
|
-
const clientSecretKey = `${DATAPLANE_APP_KEY}-client-secretKeyVault`;
|
|
47
|
-
const hasId = secrets[clientIdKey] !== null && secrets[clientIdKey] !== undefined && String(secrets[clientIdKey]).trim() !== '';
|
|
48
|
-
const hasSecret = secrets[clientSecretKey] !== null && secrets[clientSecretKey] !== undefined && String(secrets[clientSecretKey]).trim() !== '';
|
|
49
|
-
if (hasId && hasSecret) {
|
|
50
|
-
return { valid: true };
|
|
51
|
-
}
|
|
52
|
-
return { valid: false, hint };
|
|
53
|
-
} catch {
|
|
54
|
-
return { valid: false, hint };
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Load client credentials from secrets.local.yaml or process.env (e.g. integration/hubspot-test/.env).
|
|
60
|
-
* Reads secrets file using pattern: <app-name>-client-idKeyVault and <app-name>-client-secretKeyVault.
|
|
61
|
-
* If not found, checks process.env.CLIENTID and process.env.CLIENTSECRET (set when .env is loaded).
|
|
62
|
-
* @param {string} appName - Application name
|
|
63
|
-
* @returns {Promise<{clientId: string, clientSecret: string}|null>} Credentials or null if not found
|
|
64
|
-
*/
|
|
65
|
-
async function loadClientCredentials(appName) {
|
|
66
|
-
if (!appName || typeof appName !== 'string') {
|
|
67
|
-
throw new Error('App name is required and must be a string');
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
try {
|
|
71
|
-
const secretsFile = getSecretsFilePath();
|
|
72
|
-
if (fs.existsSync(secretsFile)) {
|
|
73
|
-
const content = fs.readFileSync(secretsFile, 'utf8');
|
|
74
|
-
const secrets = yaml.load(content) || {};
|
|
75
|
-
|
|
76
|
-
const clientIdKey = `${appName}-client-idKeyVault`;
|
|
77
|
-
const clientSecretKey = `${appName}-client-secretKeyVault`;
|
|
78
|
-
|
|
79
|
-
const clientId = secrets[clientIdKey];
|
|
80
|
-
const clientSecret = secrets[clientSecretKey];
|
|
81
|
-
|
|
82
|
-
if (clientId && clientSecret) {
|
|
83
|
-
return {
|
|
84
|
-
clientId: String(clientId),
|
|
85
|
-
clientSecret: String(clientSecret)
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
} catch (error) {
|
|
90
|
-
logger.warn(`Failed to load credentials from secrets.local.yaml: ${error.message}`);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// Fallback: use CLIENTID/CLIENTSECRET from process.env (e.g. from integration/hubspot-test/.env)
|
|
94
|
-
const envClientId = process.env.CLIENTID || process.env.CLIENT_ID;
|
|
95
|
-
const envClientSecret = process.env.CLIENTSECRET || process.env.CLIENT_SECRET;
|
|
96
|
-
if (envClientId && envClientSecret) {
|
|
97
|
-
return {
|
|
98
|
-
clientId: String(envClientId).trim(),
|
|
99
|
-
clientSecret: String(envClientSecret).trim()
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
return null;
|
|
104
|
-
}
|
|
19
|
+
const {
|
|
20
|
+
DATAPLANE_APP_KEY,
|
|
21
|
+
validateDataplaneSecrets,
|
|
22
|
+
loadClientCredentials,
|
|
23
|
+
resolveCredentialAppForDeployment
|
|
24
|
+
} = require('./token-manager-client-credentials');
|
|
105
25
|
|
|
106
26
|
/**
|
|
107
27
|
* Get device token for controller
|
|
@@ -201,8 +121,12 @@ async function getOrRefreshDeviceToken(controllerUrl) {
|
|
|
201
121
|
// Token needs refresh (expired or within 15 minutes of expiry)
|
|
202
122
|
// Try to refresh if refresh token exists
|
|
203
123
|
if (!tokenInfo.refreshToken) {
|
|
204
|
-
|
|
205
|
-
|
|
124
|
+
const { isSetupPlatformFlow } = require('../commands/setup-run-context');
|
|
125
|
+
if (!isSetupPlatformFlow()) {
|
|
126
|
+
logger.warn(
|
|
127
|
+
'Access token expired and no refresh token available. Please login again using: aifabrix login'
|
|
128
|
+
);
|
|
129
|
+
}
|
|
206
130
|
return null;
|
|
207
131
|
}
|
|
208
132
|
|
|
@@ -302,27 +226,34 @@ async function tryClientTokenAuth(environment, appName, controllerUrl) {
|
|
|
302
226
|
* @returns {Promise<{type: 'bearer'|'client-token', token: string, controller: string}>} Auth config: bearer = user token, client-token = app token (x-client-token header)
|
|
303
227
|
* @throws {Error} If no authentication method is available
|
|
304
228
|
*/
|
|
305
|
-
async function getDeploymentAuth(controllerUrl, environment, appName) {
|
|
229
|
+
async function getDeploymentAuth(controllerUrl, environment, appName, options = {}) {
|
|
230
|
+
const { getDeploymentAuthMode, shouldUseDeviceTokenForDeployment } = require('./deployment-auth-mode');
|
|
306
231
|
validateDeploymentAuthParams(controllerUrl, environment, appName);
|
|
232
|
+
const mode = getDeploymentAuthMode(options);
|
|
307
233
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
234
|
+
if (shouldUseDeviceTokenForDeployment(mode)) {
|
|
235
|
+
const deviceAuth = await tryDeviceTokenAuth(controllerUrl);
|
|
236
|
+
if (deviceAuth) {
|
|
237
|
+
return deviceAuth;
|
|
238
|
+
}
|
|
239
|
+
if (mode === 'device') {
|
|
240
|
+
throw new Error(
|
|
241
|
+
'Device token required (AIFABRIX_DEPLOYMENT_AUTH=device). Run: aifabrix login'
|
|
242
|
+
);
|
|
243
|
+
}
|
|
312
244
|
}
|
|
313
245
|
|
|
314
|
-
|
|
315
|
-
|
|
246
|
+
const { credentialApp, credentials } = await resolveCredentialAppForDeployment(appName);
|
|
247
|
+
|
|
248
|
+
const clientTokenAuth = await tryClientTokenAuth(environment, credentialApp, controllerUrl);
|
|
316
249
|
if (clientTokenAuth) {
|
|
317
250
|
return clientTokenAuth;
|
|
318
251
|
}
|
|
319
252
|
|
|
320
|
-
|
|
321
|
-
const credentials = await loadClientCredentials(appName);
|
|
322
|
-
if (credentials && credentials.clientId && credentials.clientSecret) {
|
|
253
|
+
if (credentials?.clientId && credentials?.clientSecret) {
|
|
323
254
|
try {
|
|
324
|
-
const refreshed = await refreshClientToken(environment,
|
|
325
|
-
if (refreshed
|
|
255
|
+
const refreshed = await refreshClientToken(environment, credentialApp, controllerUrl);
|
|
256
|
+
if (refreshed?.token) {
|
|
326
257
|
return {
|
|
327
258
|
type: 'client-token',
|
|
328
259
|
token: refreshed.token,
|
|
@@ -334,7 +265,11 @@ async function getDeploymentAuth(controllerUrl, environment, appName) {
|
|
|
334
265
|
}
|
|
335
266
|
}
|
|
336
267
|
|
|
337
|
-
throw new Error(
|
|
268
|
+
throw new Error(
|
|
269
|
+
'No authentication method available. For CI: set AIFABRIX_DEPLOYMENT_AUTH=client-credentials and ' +
|
|
270
|
+
`MISO_CLIENTID/MISO_CLIENTSECRET in .env or '${credentialApp}-client-idKeyVault' in secrets.local.yaml. ` +
|
|
271
|
+
'For interactive use: aifabrix login'
|
|
272
|
+
);
|
|
338
273
|
}
|
|
339
274
|
|
|
340
275
|
/**
|
|
@@ -451,19 +386,63 @@ async function getDeviceOnlyAuth(controllerUrl) {
|
|
|
451
386
|
}
|
|
452
387
|
|
|
453
388
|
/**
|
|
454
|
-
* Ensures auth config has a
|
|
455
|
-
* Dataplane pipeline
|
|
456
|
-
*
|
|
389
|
+
* Ensures auth config has a token Dataplane pipeline endpoints accept (Bearer or x-client-token).
|
|
390
|
+
* Dataplane pipeline rejects raw client id/secret; use POST /api/v1/auth/token first.
|
|
391
|
+
* When {@link process.env.AIFABRIX_DEPLOYMENT_AUTH} is `client-credentials`, keep application
|
|
392
|
+
* `x-client-token` auth (do not substitute API_KEY).
|
|
457
393
|
* @param {Object} authConfig - Authentication configuration (may have token, clientId, clientSecret)
|
|
458
394
|
* @throws {Error} If authConfig has only client id/secret (no token)
|
|
459
395
|
*/
|
|
396
|
+
/**
|
|
397
|
+
* Lab bypass: records/search accepts Bearer API_KEY but rejects x-client-token on some stacks.
|
|
398
|
+
* @param {Object} authConfig
|
|
399
|
+
* @returns {Object}
|
|
400
|
+
*/
|
|
401
|
+
function applyLabDataplaneApiKeyBearer(authConfig) {
|
|
402
|
+
const labKey = process.env.AIFABRIX_DATAPLANE_API_KEY || '';
|
|
403
|
+
if (!labKey) {
|
|
404
|
+
return authConfig;
|
|
405
|
+
}
|
|
406
|
+
authConfig.type = 'bearer';
|
|
407
|
+
authConfig.token = String(labKey);
|
|
408
|
+
return authConfig;
|
|
409
|
+
}
|
|
410
|
+
|
|
460
411
|
function requireBearerForDataplanePipeline(authConfig) {
|
|
412
|
+
if (authConfig.type === 'client-token' && authConfig.token) {
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
const preferAppClientToken =
|
|
417
|
+
String(process.env.AIFABRIX_DEPLOYMENT_AUTH || '').toLowerCase() === 'client-credentials';
|
|
418
|
+
|
|
419
|
+
if (!preferAppClientToken && process.env.API_KEY) {
|
|
420
|
+
const apiKey = String(process.env.API_KEY);
|
|
421
|
+
if (authConfig.type === 'bearer' && authConfig.token !== apiKey) {
|
|
422
|
+
authConfig.token = apiKey;
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
if (authConfig.type === 'client-token') {
|
|
426
|
+
authConfig.type = 'bearer';
|
|
427
|
+
authConfig.token = apiKey;
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
461
432
|
if (authConfig.token) {
|
|
462
433
|
return;
|
|
463
434
|
}
|
|
435
|
+
|
|
436
|
+
if (!preferAppClientToken && process.env.API_KEY) {
|
|
437
|
+
authConfig.type = 'bearer';
|
|
438
|
+
authConfig.token = String(process.env.API_KEY);
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
|
|
464
442
|
if (authConfig.clientId || authConfig.clientSecret) {
|
|
465
443
|
throw new Error(
|
|
466
|
-
'Dataplane pipeline endpoints require OAuth2 (Bearer token)
|
|
444
|
+
'Dataplane pipeline endpoints require OAuth2 (Bearer token) or x-client-token. ' +
|
|
445
|
+
'Client id/secret are not accepted. Run "aifabrix login" to authenticate, then retry.'
|
|
467
446
|
);
|
|
468
447
|
}
|
|
469
448
|
}
|
|
@@ -477,6 +456,7 @@ module.exports = {
|
|
|
477
456
|
refreshClientToken,
|
|
478
457
|
refreshDeviceToken,
|
|
479
458
|
loadClientCredentials,
|
|
459
|
+
resolveCredentialAppForDeployment,
|
|
480
460
|
getOrRefreshClientToken,
|
|
481
461
|
getOrRefreshDeviceToken,
|
|
482
462
|
forceRefreshDeviceToken,
|
|
@@ -484,5 +464,6 @@ module.exports = {
|
|
|
484
464
|
getDeviceOnlyAuth,
|
|
485
465
|
extractClientCredentials,
|
|
486
466
|
requireBearerForDataplanePipeline,
|
|
467
|
+
applyLabDataplaneApiKeyBearer,
|
|
487
468
|
validateDataplaneSecrets
|
|
488
469
|
};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Progress line + optional ora spinner for dataplane pipeline upload/publish.
|
|
3
|
+
* @author AI Fabrix Team
|
|
4
|
+
* @version 1.1.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
'use strict';
|
|
8
|
+
|
|
9
|
+
const chalk = require('chalk');
|
|
10
|
+
const logger = require('./logger');
|
|
11
|
+
const { formatProgress } = require('./cli-test-layout-chalk');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @param {Object} [options]
|
|
15
|
+
* @param {boolean} [options.json] - When true, skip progress line and spinner
|
|
16
|
+
* @returns {boolean}
|
|
17
|
+
*/
|
|
18
|
+
function shouldShowUploadPipelineProgress(options = {}) {
|
|
19
|
+
if (options.suppressPipelineSpinner === true) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
return options.json !== true;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @param {Object} [options]
|
|
27
|
+
* @returns {boolean}
|
|
28
|
+
*/
|
|
29
|
+
function shouldUseUploadPipelineSpinner(options = {}) {
|
|
30
|
+
if (!shouldShowUploadPipelineProgress(options)) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
return Boolean(process && process.stdout && process.stdout.isTTY);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Plain label for spinner / progress (no glyph).
|
|
38
|
+
* @param {string} systemKey
|
|
39
|
+
* @returns {string}
|
|
40
|
+
*/
|
|
41
|
+
function buildUploadPipelineSpinnerLabel(systemKey, opts = {}) {
|
|
42
|
+
if (opts.syncMode === true) {
|
|
43
|
+
return 'Checking config on dataplane…';
|
|
44
|
+
}
|
|
45
|
+
const key = systemKey && String(systemKey).trim() ? String(systemKey).trim() : 'integration';
|
|
46
|
+
return `Publishing ${key} to dataplane…`;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* @param {string} systemKey
|
|
51
|
+
* @param {Object} [opts]
|
|
52
|
+
* @returns {string}
|
|
53
|
+
*/
|
|
54
|
+
function buildUploadPipelineProgressText(systemKey, opts = {}) {
|
|
55
|
+
return formatProgress(buildUploadPipelineSpinnerLabel(systemKey, opts));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Run pipeline upload + OpenAPI sync with visible progress (⏳ line or ora with label on TTY).
|
|
60
|
+
*
|
|
61
|
+
* @async
|
|
62
|
+
* @param {Function} work - Zero-arg async function (publish + follow-up I/O)
|
|
63
|
+
* @param {Object} [opts]
|
|
64
|
+
* @param {string} [opts.systemKey]
|
|
65
|
+
* @param {boolean} [opts.json]
|
|
66
|
+
* @returns {Promise<*>}
|
|
67
|
+
*/
|
|
68
|
+
async function runWithUploadPipelineSpinner(work, opts = {}) {
|
|
69
|
+
if (!shouldShowUploadPipelineProgress(opts)) {
|
|
70
|
+
return work();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (!shouldUseUploadPipelineSpinner(opts)) {
|
|
74
|
+
logger.log(buildUploadPipelineProgressText(opts.systemKey, opts));
|
|
75
|
+
return work();
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const ora = require('ora');
|
|
79
|
+
const label = buildUploadPipelineSpinnerLabel(opts.systemKey, opts);
|
|
80
|
+
const spinner = ora({
|
|
81
|
+
text: chalk.white(label),
|
|
82
|
+
spinner: 'dots'
|
|
83
|
+
}).start();
|
|
84
|
+
|
|
85
|
+
try {
|
|
86
|
+
return await work();
|
|
87
|
+
} finally {
|
|
88
|
+
spinner.stop();
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
module.exports = {
|
|
93
|
+
shouldShowUploadPipelineProgress,
|
|
94
|
+
shouldUseUploadPipelineSpinner,
|
|
95
|
+
buildUploadPipelineSpinnerLabel,
|
|
96
|
+
buildUploadPipelineProgressText,
|
|
97
|
+
runWithUploadPipelineSpinner
|
|
98
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build options for `uploadExternalSystem` on test-command --sync paths.
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Minimal upload sync options (force, verbose)
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @param {Object} [options] - CLI options from test / sync callers
|
|
13
|
+
* @returns {{ minimal: true, verbose: boolean, silentResolve: true, syncMode: true, force?: true }}
|
|
14
|
+
*/
|
|
15
|
+
function buildMinimalUploadSyncOptions(options = {}) {
|
|
16
|
+
const out = {
|
|
17
|
+
minimal: true,
|
|
18
|
+
// CLI -v on verify-* / test-* is for run output, not preflight upload banners.
|
|
19
|
+
verbose: false,
|
|
20
|
+
silentResolve: true,
|
|
21
|
+
syncMode: true,
|
|
22
|
+
suppressPipelineSpinner: options.suppressPipelineSpinner === true
|
|
23
|
+
};
|
|
24
|
+
if (options.force === true) {
|
|
25
|
+
out.force = true;
|
|
26
|
+
}
|
|
27
|
+
return out;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Minimal sync paths (verify-*, test --sync) always suppress upload sidecar chatter.
|
|
32
|
+
* @param {Object} [options]
|
|
33
|
+
* @returns {boolean}
|
|
34
|
+
*/
|
|
35
|
+
function isQuietMinimalSync(options = {}) {
|
|
36
|
+
return options.minimal === true || options.syncMode === true;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
module.exports = {
|
|
40
|
+
buildMinimalUploadSyncOptions,
|
|
41
|
+
isQuietMinimalSync
|
|
42
|
+
};
|
|
@@ -51,6 +51,12 @@ function hostPortForProfile(profile, listenPort, developerIdNum) {
|
|
|
51
51
|
: localHostPort(listenPort, developerIdNum);
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
function localhostFrontDoorBaseForMissingRemote(opts) {
|
|
55
|
+
const { profile, developerIdNum } = opts || {};
|
|
56
|
+
const port = hostPortForProfile(profile, 3000, developerIdNum);
|
|
57
|
+
return `http://localhost:${port}`.replace(/\/+$/, '');
|
|
58
|
+
}
|
|
59
|
+
|
|
54
60
|
/**
|
|
55
61
|
* Scheme for `declarativePublicUrlsUseLocalhost` bases: always **http** for loopback reachability
|
|
56
62
|
* (ignore `tlsEnabled` / `remote-server` https — localhost URLs are not served with TLS in dev).
|
|
@@ -155,14 +161,26 @@ function templateUsesRemoteHostPlaceholder(hostTemplate) {
|
|
|
155
161
|
* @returns {string|null}
|
|
156
162
|
*/
|
|
157
163
|
function buildTraefikPublicBaseIfApplicable(opts) {
|
|
158
|
-
const {
|
|
159
|
-
|
|
164
|
+
const {
|
|
165
|
+
traefik,
|
|
166
|
+
pathActive,
|
|
167
|
+
hostTemplate,
|
|
168
|
+
developerIdRaw,
|
|
169
|
+
remoteServer,
|
|
170
|
+
infraTlsEnabled,
|
|
171
|
+
profile,
|
|
172
|
+
developerIdNum
|
|
173
|
+
} = opts;
|
|
160
174
|
// Plan 124: Traefik host authority only when pathActive (traefik ∧ frontDoorRouting.enabled)
|
|
161
175
|
if (!traefik || !pathActive || !hostTemplate || !String(hostTemplate).trim()) {
|
|
162
176
|
return null;
|
|
163
177
|
}
|
|
164
178
|
if (templateUsesRemoteHostPlaceholder(hostTemplate) && !String(remoteServer || '').trim()) {
|
|
165
|
-
|
|
179
|
+
// Local full-platform (no remote domain): use the single localhost front door port (3000 + devId×100).
|
|
180
|
+
return localhostFrontDoorBaseForMissingRemote({
|
|
181
|
+
profile,
|
|
182
|
+
developerIdNum
|
|
183
|
+
});
|
|
166
184
|
}
|
|
167
185
|
const expanded = expandFrontDoorHostTemplateForUrls(hostTemplate, {
|
|
168
186
|
developerIdRaw,
|
|
@@ -15,6 +15,7 @@ const yaml = require('js-yaml');
|
|
|
15
15
|
const { existsSync, readFileSync } = require('../internal/fs-real-sync');
|
|
16
16
|
const { DECLARATIVE_URL_INFRA_DEFAULTS } = require('./infra-env-defaults');
|
|
17
17
|
const { computePathActive } = require('./url-declarative-url-flags');
|
|
18
|
+
const { resolveInactiveVdirRewriteEnvKeys } = require('./app-relative-path-env');
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* Treat common YAML / string forms as enabled (strict `=== true` alone missed some parsers).
|
|
@@ -52,16 +53,22 @@ const INACTIVE_VDIR_PUBLIC_ENV_FALLBACK =
|
|
|
52
53
|
/**
|
|
53
54
|
* @param {string} content - .env template fragment
|
|
54
55
|
* @param {string} replacement
|
|
56
|
+
* @param {ReadonlySet<string>} rewriteKeys
|
|
55
57
|
* @returns {string}
|
|
56
58
|
*/
|
|
57
|
-
function applyInactiveVdirPublicTokenRewrite(content, replacement) {
|
|
59
|
+
function applyInactiveVdirPublicTokenRewrite(content, replacement, rewriteKeys) {
|
|
58
60
|
if (!content || !content.includes(URL_DECLARATIVE_VDIR_PUBLIC_TOKEN)) {
|
|
59
61
|
return content;
|
|
60
62
|
}
|
|
61
63
|
const escaped = URL_DECLARATIVE_VDIR_PUBLIC_TOKEN.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
62
64
|
// End line with [ \t]* only — \s would consume \n and strip line endings from the file.
|
|
63
|
-
const lineRe = new RegExp(`^(\\s*[A-Z][A-Z0-9_]*)\\s*=\\s*${escaped}[ \t]*$`, 'gm');
|
|
64
|
-
return content.replace(lineRe, (
|
|
65
|
+
const lineRe = new RegExp(`^(\\s*)([A-Z][A-Z0-9_]*)\\s*=\\s*${escaped}[ \t]*$`, 'gm');
|
|
66
|
+
return content.replace(lineRe, (match, indent, key) => {
|
|
67
|
+
if (!rewriteKeys.has(key)) {
|
|
68
|
+
return match;
|
|
69
|
+
}
|
|
70
|
+
return `${indent}${key}=${replacement}`;
|
|
71
|
+
});
|
|
65
72
|
}
|
|
66
73
|
|
|
67
74
|
/**
|
|
@@ -88,12 +95,15 @@ function rewriteInactiveDeclarativeVdirPublicContent(content, variablesPath, use
|
|
|
88
95
|
if (pathActive) {
|
|
89
96
|
return content;
|
|
90
97
|
}
|
|
91
|
-
|
|
98
|
+
const appKey = doc && doc.app && doc.app.key;
|
|
99
|
+
const rewriteKeys = resolveInactiveVdirRewriteEnvKeys(appKey);
|
|
100
|
+
return applyInactiveVdirPublicTokenRewrite(content, INACTIVE_VDIR_PUBLIC_ENV_FALLBACK, rewriteKeys);
|
|
92
101
|
}
|
|
93
102
|
|
|
94
103
|
module.exports = {
|
|
95
104
|
URL_DECLARATIVE_VDIR_PUBLIC_TOKEN,
|
|
96
105
|
INACTIVE_VDIR_PUBLIC_ENV_FALLBACK,
|
|
106
|
+
loadApplicationYamlDoc,
|
|
97
107
|
applyInactiveVdirPublicTokenRewrite,
|
|
98
108
|
rewriteInactiveDeclarativeVdirPublicContent,
|
|
99
109
|
isFrontDoorRoutingEnabledInDoc
|
|
@@ -23,10 +23,12 @@ function shouldUseValidationPollSpinner() {
|
|
|
23
23
|
* @param {number} deadlineMs - Wall-clock deadline (Date.now() + remaining budget)
|
|
24
24
|
* @returns {string}
|
|
25
25
|
*/
|
|
26
|
-
function buildValidationPollSpinnerText(envelope, attemptIndex, deadlineMs) {
|
|
26
|
+
function buildValidationPollSpinnerText(envelope, attemptIndex, deadlineMs, subject) {
|
|
27
27
|
const remainingSec = Math.max(0, Math.ceil((deadlineMs - Date.now()) / 1000));
|
|
28
|
+
const label =
|
|
29
|
+
subject && String(subject).trim() ? String(subject).trim() : 'validation run';
|
|
28
30
|
if (!envelope || typeof envelope !== 'object') {
|
|
29
|
-
return `Waiting for
|
|
31
|
+
return `Waiting for ${label}… starting (budget ~${remainingSec}s)`;
|
|
30
32
|
}
|
|
31
33
|
const c =
|
|
32
34
|
envelope.reportCompleteness !== undefined && envelope.reportCompleteness !== null
|
|
@@ -34,26 +36,37 @@ function buildValidationPollSpinnerText(envelope, attemptIndex, deadlineMs) {
|
|
|
34
36
|
: '?';
|
|
35
37
|
const st =
|
|
36
38
|
envelope.status !== undefined && envelope.status !== null ? String(envelope.status) : '?';
|
|
37
|
-
return `Waiting for
|
|
39
|
+
return `Waiting for ${label}… completeness=${c} status=${st} (poll ${attemptIndex + 1} · ~${remainingSec}s left)`;
|
|
38
40
|
}
|
|
39
41
|
|
|
40
42
|
const NON_TTY_THROTTLE_MS = 5000;
|
|
41
43
|
|
|
42
44
|
/**
|
|
43
45
|
* @param {number} deadlineMs - Absolute deadline for poll budget display
|
|
46
|
+
* @param {Object} [opts]
|
|
47
|
+
* @param {string} [opts.subject] - Datasource key or label shown in poll text
|
|
44
48
|
* @returns {{ usesSpinner: boolean, onPollProgress: Function, finish: () => void }}
|
|
45
49
|
*/
|
|
46
|
-
function createValidationPollHandlers(deadlineMs) {
|
|
50
|
+
function createValidationPollHandlers(deadlineMs, opts = {}) {
|
|
51
|
+
if (opts.quiet === true) {
|
|
52
|
+
return {
|
|
53
|
+
usesSpinner: false,
|
|
54
|
+
onPollProgress: () => {},
|
|
55
|
+
finish: () => {}
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const subject = opts.subject;
|
|
47
60
|
if (shouldUseValidationPollSpinner()) {
|
|
48
61
|
const ora = require('ora');
|
|
49
62
|
const spinner = ora({
|
|
50
|
-
text: buildValidationPollSpinnerText(null, 0, deadlineMs),
|
|
63
|
+
text: buildValidationPollSpinnerText(null, 0, deadlineMs, subject),
|
|
51
64
|
spinner: 'dots'
|
|
52
65
|
}).start();
|
|
53
66
|
return {
|
|
54
67
|
usesSpinner: true,
|
|
55
68
|
onPollProgress: (envelope, attemptIndex, _meta) => {
|
|
56
|
-
spinner.text = buildValidationPollSpinnerText(envelope, attemptIndex, deadlineMs);
|
|
69
|
+
spinner.text = buildValidationPollSpinnerText(envelope, attemptIndex, deadlineMs, subject);
|
|
57
70
|
},
|
|
58
71
|
finish: () => {
|
|
59
72
|
spinner.stop();
|
|
@@ -68,7 +81,9 @@ function createValidationPollHandlers(deadlineMs) {
|
|
|
68
81
|
const now = Date.now();
|
|
69
82
|
if (now - lastNonTtyLogAt < NON_TTY_THROTTLE_MS) return;
|
|
70
83
|
lastNonTtyLogAt = now;
|
|
71
|
-
logger.log(
|
|
84
|
+
logger.log(
|
|
85
|
+
chalk.gray(buildValidationPollSpinnerText(envelope, attemptIndex, deadlineMs, subject))
|
|
86
|
+
);
|
|
72
87
|
},
|
|
73
88
|
finish: () => {}
|
|
74
89
|
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Map legacy validation runType to contract stage (dataplane 370.07).
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
'use strict';
|
|
6
|
+
|
|
7
|
+
/** @typedef {'readiness'|'simulation'|'integration'|'e2e'} ValidationRunStage */
|
|
8
|
+
|
|
9
|
+
/** @type {Record<string, ValidationRunStage>} */
|
|
10
|
+
const RUN_TYPE_TO_STAGE = {
|
|
11
|
+
test: 'readiness',
|
|
12
|
+
integration: 'integration',
|
|
13
|
+
e2e: 'e2e'
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Contract stage for a CLI/API runType (default product mapping).
|
|
18
|
+
* @param {string} runType - test | integration | e2e
|
|
19
|
+
* @returns {ValidationRunStage}
|
|
20
|
+
*/
|
|
21
|
+
function stageForRunType(runType) {
|
|
22
|
+
const key = String(runType || 'test');
|
|
23
|
+
return RUN_TYPE_TO_STAGE[key] || 'readiness';
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Attach stage to a validation/run POST body when absent.
|
|
28
|
+
* @param {Object} body
|
|
29
|
+
* @param {string} [runType]
|
|
30
|
+
* @returns {Object}
|
|
31
|
+
*/
|
|
32
|
+
function withStageOnValidationRunBody(body, runType) {
|
|
33
|
+
const out = { ...body };
|
|
34
|
+
const rt = runType || out.runType || 'test';
|
|
35
|
+
if (!out.stage) {
|
|
36
|
+
out.stage = stageForRunType(rt);
|
|
37
|
+
}
|
|
38
|
+
return out;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
module.exports = {
|
|
42
|
+
RUN_TYPE_TO_STAGE,
|
|
43
|
+
stageForRunType,
|
|
44
|
+
withStageOnValidationRunBody
|
|
45
|
+
};
|