@aifabrix/builder 2.45.5 → 2.47.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/project-rules.mdc +1 -0
- package/.npmrc.token +1 -0
- package/.temp/jest-protection-convert/run-IFN2nv/.protection/hubspot-companies.json +1 -0
- package/.temp/jest-protection-convert/run-IvmKLO/.protection/hubspot-companies.yaml +17 -0
- package/.temp/jest-protection-convert/run-SdvblF/.protection/hubspot-companies.json +1 -0
- package/.temp/jest-protection-convert/run-b51TsW/.protection/hubspot-companies.json +1 -0
- package/.temp/jest-protection-convert/run-fiLmb1/.protection/hubspot-companies.json +1 -0
- package/.temp/jest-protection-convert/run-qYGHMU/.protection/hubspot-companies.yaml +17 -0
- package/.temp/jest-protection-fixtures/hubspot-Mq5re8/hubspot-companies.yaml +17 -0
- package/.temp/jest-protection-fixtures/hubspot-f3u4YL/hubspot-companies.yaml +17 -0
- package/.temp/jest-protection-fixtures/hubspot-iQtd1O/hubspot-companies.yaml +17 -0
- package/.temp/jest-protection-fixtures/hubspot-mdmz5M/hubspot-companies.yaml +17 -0
- package/.temp/jest-protection-fixtures/hubspot-qbKYxQ/hubspot-companies.yaml +17 -0
- package/.temp/jest-protection-fixtures/hubspot-yzlJy6/hubspot-companies.yaml +17 -0
- package/.temp/validation/summary.txt +5 -0
- package/README.md +43 -17
- package/integration/hubspot-test/test-artifacts/wizard-hubspot-credential-real.yaml +1 -1
- package/integration/hubspot-test/test-artifacts/wizard-hubspot-env-vars.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 +146 -0
- package/jest.projects.js +65 -136
- package/lib/api/api-response-errors.js +124 -0
- package/lib/api/dataplane-health.api.js +19 -7
- package/lib/api/governance-scenario-pack.api.js +159 -0
- package/lib/api/index.js +43 -3
- package/lib/api/lifecycle.api.js +98 -0
- package/lib/api/pipeline.api.js +3 -1
- package/lib/api/records-bulk.api.js +14 -1
- package/lib/api/resource-types.api.js +107 -0
- package/lib/api/runtime-configuration.api.js +72 -0
- package/lib/api/types/resource-types.types.js +45 -0
- package/lib/api/user-groups.api.js +9 -9
- package/lib/api/users.api.js +8 -8
- package/lib/api/validation-runner.js +3 -1
- package/lib/api/wizard.api.js +10 -2
- package/lib/app/deploy-config.js +4 -1
- package/lib/app/down.js +78 -27
- package/lib/app/index.js +2 -2
- 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/app/run-resolve-image.js +2 -1
- package/lib/app/run-stop-containers.js +113 -0
- package/lib/app/run.js +1 -31
- package/lib/app/show-display.js +35 -0
- package/lib/app/show.js +32 -1
- package/lib/build/index.js +22 -5
- package/lib/build/miso-controller-npm-sdk-guard.js +25 -0
- package/lib/certification/sync-system-certification.js +13 -6
- package/lib/channels/add-channel.js +348 -0
- package/lib/channels/channel-artifact-generator.js +141 -0
- package/lib/channels/channel-audit.js +101 -0
- package/lib/channels/channel-auth-context.js +37 -0
- package/lib/channels/channel-credential.js +200 -0
- package/lib/channels/channel-display-name.js +64 -0
- package/lib/channels/channel-external-system.js +106 -0
- package/lib/channels/channel-integration-generator.js +274 -0
- package/lib/channels/channel-probe.js +89 -0
- package/lib/channels/channel-runtime-resolver.js +152 -0
- package/lib/channels/channel-status-display.js +141 -0
- package/lib/channels/channel-targets.js +115 -0
- package/lib/cli/index.js +20 -4
- package/lib/cli/infra-guided-auth.js +109 -0
- package/lib/cli/infra-guided.js +84 -81
- package/lib/cli/setup-app.help.js +0 -31
- package/lib/cli/setup-app.js +82 -5
- package/lib/cli/setup-app.test-commands.js +5 -57
- package/lib/cli/setup-auth.js +25 -0
- 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 +25 -3
- package/lib/cli/setup-infra-up-dataplane-action.js +2 -2
- package/lib/cli/setup-infra-up-platform-action.js +2 -1
- 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 +25 -2
- package/lib/cli/setup-utility-repair.js +198 -0
- package/lib/cli/setup-utility-resolve.js +44 -5
- package/lib/cli/setup-utility-validate.js +197 -0
- package/lib/cli/setup-utility.js +4 -239
- package/lib/commands/app-logs.js +54 -26
- package/lib/commands/app.js +41 -0
- package/lib/commands/auth-status-client-tokens.js +214 -0
- package/lib/commands/auth-status-dataplane-version.js +142 -68
- package/lib/commands/auth-status.js +43 -54
- package/lib/commands/channel.js +58 -0
- package/lib/commands/datasource-test-trust-cli.js +27 -23
- package/lib/commands/datasource-unified-test-cli.js +6 -3
- package/lib/commands/datasource-unified-test-cli.options.js +5 -1
- package/lib/commands/datasource.js +8 -8
- package/lib/commands/dev-show-display.js +8 -1
- 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 +49 -8
- package/lib/commands/identity-group-cli.js +66 -26
- package/lib/commands/identity-membership-role-cache.js +58 -37
- package/lib/commands/identity-shared.js +22 -1
- package/lib/commands/identity-user-cli.js +80 -34
- package/lib/commands/lifecycle-command-action.js +123 -0
- package/lib/commands/lifecycle-external.js +268 -0
- package/lib/commands/login.js +11 -2
- package/lib/commands/repair-auth-apply.js +153 -0
- package/lib/commands/repair-auth-config.js +8 -13
- package/lib/commands/repair-changed-files.js +41 -0
- package/lib/commands/repair-datasource-com-v2.js +15 -0
- package/lib/commands/repair-datasource-keys.js +4 -1
- package/lib/commands/repair-datasource-run.js +59 -0
- package/lib/commands/repair-datasource-service-contract.js +206 -0
- package/lib/commands/repair-datasource-test-payload.js +259 -0
- package/lib/commands/repair-datasource.js +49 -64
- package/lib/commands/repair-env-template.js +76 -25
- package/lib/commands/repair-external-run.js +216 -0
- package/lib/commands/repair-openapi-sync.js +49 -4
- package/lib/commands/repair-persist.js +4 -0
- package/lib/commands/repair-rbac.js +52 -1
- package/lib/commands/repair-steps.js +160 -0
- package/lib/commands/repair-system-alignment.js +7 -4
- package/lib/commands/repair.js +29 -296
- package/lib/commands/resource-type.js +371 -0
- 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 +70 -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 +24 -8
- package/lib/commands/test-governance-external.js +3 -24
- package/lib/commands/test-trust-external.js +48 -100
- package/lib/commands/up-common.js +57 -13
- package/lib/commands/up-dataplane.js +56 -15
- package/lib/commands/upload-publish-context.js +75 -0
- package/lib/commands/upload-sidecar-followups.js +89 -0
- package/lib/commands/upload.js +113 -110
- 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 +73 -0
- package/lib/commands/verify-trust-external.js +59 -0
- package/lib/commands/wizard-config-normalizer.js +43 -23
- package/lib/commands/wizard-core.js +2 -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-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 +90 -0
- package/lib/datasource/agent-trust-debug-log.js +1 -1
- package/lib/datasource/agent-trust-run.js +5 -3
- package/lib/datasource/audit-evidence-extract-debug.js +30 -18
- package/lib/datasource/audit-evidence-extract.js +7 -4
- package/lib/datasource/audit-evidence-verify-matrix.js +54 -26
- package/lib/datasource/bulk-loader-run-batches.js +15 -3
- package/lib/datasource/capability/capability-diff-slice.js +2 -2
- package/lib/datasource/capability/capability-manifest.js +254 -0
- package/lib/datasource/capability/capability-resolve.js +3 -4
- package/lib/datasource/capability/copy-operations.js +5 -3
- package/lib/datasource/capability/remove-operations.js +2 -1
- package/lib/datasource/capability/run-capability-copy.js +32 -4
- package/lib/datasource/capability/run-capability-diff.js +3 -3
- package/lib/datasource/capability/run-capability-dimension.js +2 -4
- package/lib/datasource/capability/run-capability-edit.js +4 -7
- package/lib/datasource/capability/run-capability-relate.js +2 -4
- package/lib/datasource/capability/run-capability-remove.js +2 -4
- package/lib/datasource/capability/validate-capability-slice.js +2 -1
- package/lib/datasource/datasource-identifier.js +2 -1
- package/lib/datasource/datasource-load-export-context.js +3 -0
- package/lib/datasource/datasource-validate-display.js +1 -1
- package/lib/datasource/field-reference-validator.js +24 -3
- package/lib/datasource/log-cleaner.js +2 -2
- package/lib/datasource/log-viewer.js +8 -8
- package/lib/datasource/orphan-profiles-validator.js +98 -0
- package/lib/datasource/test-e2e.js +4 -1
- package/lib/datasource/unified-validation-run-body.js +3 -1
- package/lib/datasource/unified-validation-run.js +5 -2
- package/lib/datasource/validate.js +41 -23
- package/lib/deployment/environment-poll-status.js +138 -0
- package/lib/deployment/environment.js +42 -34
- package/lib/external-system/download-helpers.js +87 -0
- package/lib/external-system/download.js +78 -138
- package/lib/external-system/generator.js +1 -55
- package/lib/external-system/integration-auth-context.js +45 -0
- package/lib/external-system/test-auth.js +12 -5
- package/lib/external-system/test.js +16 -21
- package/lib/generator/builders.js +11 -1
- package/lib/generator/external-controller-manifest.js +18 -0
- package/lib/generator/split.js +3 -1
- package/lib/generator/wizard.js +1 -28
- package/lib/governance/governance-cli-errors.js +96 -0
- package/lib/governance/governance-download-display.js +38 -0
- package/lib/governance/governance-run-display.js +215 -25
- package/lib/identity/fk-reference.js +65 -0
- package/lib/identity/identity-apply-core.js +13 -58
- package/lib/identity/identity-apply-phases.js +5 -1
- package/lib/identity/identity-display.js +243 -0
- package/lib/identity/identity-response-helpers.js +52 -0
- package/lib/identity/identity-sync-errors.js +62 -0
- package/lib/identity/resolve-user-id.js +129 -0
- package/lib/identity/username-default.js +31 -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/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-trust.js +70 -0
- package/lib/lifecycle/report-display.js +472 -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 +10 -4
- package/lib/resolvers/datasource-resolver.js +2 -3
- package/lib/resolvers/resource-type-file.js +159 -0
- package/lib/schema/application-schema.json +17 -1
- package/lib/schema/datasource-test-run.schema.json +89 -6
- package/lib/schema/deployment-rules.yaml +2 -1
- package/lib/schema/external-datasource.schema.json +2947 -2619
- package/lib/schema/external-system.schema.json +1418 -761
- package/lib/schema/infra.parameter.yaml +45 -0
- package/lib/schema/type/credential-field-registry.json +103 -97
- package/lib/schema/type/document-storage.json +9 -5
- 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/app-run-containers.js +25 -2
- package/lib/utils/authentication-shape.js +224 -0
- package/lib/utils/build-copy.js +36 -5
- package/lib/utils/build-resolve-image.js +66 -12
- package/lib/utils/celery-companion-apps.js +53 -0
- package/lib/utils/cli-secrets-error-format.js +83 -21
- package/lib/utils/cli-utils.js +20 -4
- package/lib/utils/compose-celery-worker.js +23 -0
- package/lib/utils/compose-generate-docker-compose.js +13 -1
- package/lib/utils/compose-traefik-ingress-base.js +16 -1
- package/lib/utils/config-secrets-path.js +46 -0
- package/lib/utils/configuration-env-resolver.js +36 -0
- package/lib/utils/controller-url.js +88 -1
- package/lib/utils/credential-secrets-env-kv.js +216 -0
- package/lib/utils/credential-secrets-env.js +175 -257
- package/lib/utils/dataplane-resolver.js +18 -2
- package/lib/utils/declarative-url-ports.js +27 -4
- package/lib/utils/deployment-auth-mode.js +41 -0
- package/lib/utils/developer-volume-id.js +33 -0
- package/lib/utils/docker-build.js +1 -4
- 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 +11 -3
- package/lib/utils/external-system-readiness-core.js +10 -0
- package/lib/utils/external-system-readiness-display.js +80 -23
- package/lib/utils/external-system-validators.js +8 -2
- package/lib/utils/health-check.js +4 -1
- package/lib/utils/help-builder.js +13 -8
- 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 +2 -0
- package/lib/utils/paths.js +25 -0
- package/lib/utils/pipeline-upload-auth-retry.js +82 -0
- package/lib/utils/platform-controller-url.js +157 -0
- package/lib/utils/platform-kv-ref.js +57 -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/runtime-configuration-download.js +189 -0
- package/lib/utils/runtime-configuration-values.js +119 -0
- package/lib/utils/schema-loader.js +19 -4
- package/lib/utils/secrets-generator.js +31 -25
- package/lib/utils/secrets-missing-error.js +164 -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 +12 -5
- 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 +8 -0
- package/lib/utils/validation-run-stage.js +45 -0
- package/lib/utils/worker-sidecars.js +142 -0
- package/lib/validation/external-manifest-validator.js +2 -0
- package/lib/validation/runtime-configuration-rules.js +98 -0
- package/lib/validation/validate-display-dimensions.js +154 -0
- package/lib/validation/validate-display-sections.js +276 -0
- package/lib/validation/validate-display-steps.js +67 -0
- package/lib/validation/validate-display.js +24 -402
- package/package.json +1 -1
- package/templates/applications/dataplane/application.yaml +7 -1
- package/templates/applications/dataplane/env.template +50 -14
- package/templates/applications/dataplane/rbac.yaml +108 -1
- package/templates/applications/miso-controller/application.yaml +2 -2
- package/templates/applications/miso-controller/env.template +53 -122
- package/templates/applications/miso-controller/rbac.yaml +28 -13
- package/templates/channels/chatgpt/install.template.md.hbs +49 -0
- package/templates/channels/chatgpt/manifest.template.json.hbs +9 -0
- package/templates/channels/microsoft-copilot/install.template.md.hbs +49 -0
- package/templates/channels/microsoft-copilot/manifest.template.json.hbs +8 -0
- package/templates/channels/slack/install.template.md.hbs +49 -0
- package/templates/channels/slack/manifest.template.json.hbs +66 -0
- package/templates/channels/teams-bot/install.template.md.hbs +49 -0
- package/templates/channels/teams-bot/manifest.template.json.hbs +13 -0
- package/templates/channels/web-embed/install.template.md.hbs +49 -0
- package/templates/channels/web-embed/manifest.template.json.hbs +8 -0
- package/templates/external-system/README.md.hbs +74 -17
- package/templates/python/docker-compose.hbs +75 -18
- package/templates/typescript/docker-compose.hbs +70 -17
- package/lib/commands/test-governance-command-action.js +0 -55
- package/lib/commands/test-trust-command-action.js +0 -118
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Developer ID suffix variants for Docker volume names (`dev6` vs `dev06`).
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Volume name suffix normalization for multi-dev Docker
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @param {string|number} developerId
|
|
13
|
+
* @returns {string[]}
|
|
14
|
+
*/
|
|
15
|
+
function collectDeveloperVolumeIdSuffixes(developerId) {
|
|
16
|
+
const raw = String(developerId).trim();
|
|
17
|
+
const idNum = parseInt(raw, 10);
|
|
18
|
+
if (Number.isNaN(idNum) || idNum === 0) {
|
|
19
|
+
return ['0'];
|
|
20
|
+
}
|
|
21
|
+
const suffixes = new Set([String(idNum), raw]);
|
|
22
|
+
if (raw.length === 1) {
|
|
23
|
+
suffixes.add(raw.padStart(2, '0'));
|
|
24
|
+
}
|
|
25
|
+
if (String(idNum).length === 1) {
|
|
26
|
+
suffixes.add(String(idNum).padStart(2, '0'));
|
|
27
|
+
}
|
|
28
|
+
return [...suffixes];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
module.exports = {
|
|
32
|
+
collectDeveloperVolumeIdSuffixes
|
|
33
|
+
};
|
|
@@ -264,10 +264,7 @@ async function executeDockerBuildWithTag(effectiveImageName, imageName, dockerfi
|
|
|
264
264
|
|
|
265
265
|
await executeBuild(effectiveImageName, dockerfilePath, contextPath, tag, options);
|
|
266
266
|
|
|
267
|
-
const wantCompatTag =
|
|
268
|
-
effectiveImageName !== imageName &&
|
|
269
|
-
options &&
|
|
270
|
-
options.base === true;
|
|
267
|
+
const wantCompatTag = effectiveImageName !== imageName && imageName;
|
|
271
268
|
if (!wantCompatTag) {
|
|
272
269
|
return;
|
|
273
270
|
}
|
package/lib/utils/env-copy.js
CHANGED
|
@@ -272,14 +272,16 @@ async function patchEnvContentForLocal(envContent, variables) {
|
|
|
272
272
|
* @param {string} outputPath - Resolved `build.envOutputPath`
|
|
273
273
|
* @param {string} envOutputPathLabel - Label for log (e.g. raw `build.envOutputPath` value)
|
|
274
274
|
*/
|
|
275
|
-
async function syncWrittenBuilderEnvToOutputPath(envPath, outputPath, envOutputPathLabel) {
|
|
275
|
+
async function syncWrittenBuilderEnvToOutputPath(envPath, outputPath, envOutputPathLabel, copyOptions = {}) {
|
|
276
276
|
const { parseEnvContentToMap, mergeEnvMapIntoContent } = require('../core/secrets');
|
|
277
277
|
const raw = fs.readFileSync(envPath, 'utf8');
|
|
278
278
|
const synced = substituteMntDataForLocal(raw, outputPath);
|
|
279
279
|
let toWrite = synced;
|
|
280
|
-
if (fs.existsSync(outputPath)) {
|
|
280
|
+
if (!copyOptions.freshEnv && fs.existsSync(outputPath)) {
|
|
281
281
|
const existingContent = fs.readFileSync(outputPath, 'utf8');
|
|
282
|
-
toWrite = mergeEnvMapIntoContent(existingContent, parseEnvContentToMap(synced)
|
|
282
|
+
toWrite = mergeEnvMapIntoContent(existingContent, parseEnvContentToMap(synced), {
|
|
283
|
+
appendMissingFromNewMap: true
|
|
284
|
+
});
|
|
283
285
|
}
|
|
284
286
|
fs.writeFileSync(outputPath, toWrite, { mode: 0o600 });
|
|
285
287
|
logger.log(formatSuccessLine(`Copied resolved .env to envOutputPath (${envOutputPathLabel})`));
|
|
@@ -300,10 +302,10 @@ async function writeLocalEnvToOutputPath(outputPath, appName, secretsPath, envOu
|
|
|
300
302
|
let localEnvContent = await generateEnvContent(appName, secretsPath, 'local', false, genOpts);
|
|
301
303
|
localEnvContent = substituteMntDataForLocal(localEnvContent, outputPath);
|
|
302
304
|
let toWrite = localEnvContent;
|
|
303
|
-
if (fs.existsSync(outputPath)) {
|
|
305
|
+
if (!extraOpts.freshEnv && fs.existsSync(outputPath)) {
|
|
304
306
|
const existingContent = fs.readFileSync(outputPath, 'utf8');
|
|
305
307
|
const localMap = parseEnvContentToMap(localEnvContent);
|
|
306
|
-
toWrite = mergeEnvMapIntoContent(existingContent, localMap);
|
|
308
|
+
toWrite = mergeEnvMapIntoContent(existingContent, localMap, { appendMissingFromNewMap: true });
|
|
307
309
|
}
|
|
308
310
|
fs.writeFileSync(outputPath, toWrite, { mode: 0o600 });
|
|
309
311
|
logger.log(formatSuccessLine(`Generated local .env at: ${envOutputPathLabel}`));
|
|
@@ -350,15 +352,16 @@ async function copyOrRegenerateEnvForNamedApp(opts) {
|
|
|
350
352
|
secretsPath,
|
|
351
353
|
label,
|
|
352
354
|
preferLocal,
|
|
353
|
-
appPathForLocal
|
|
355
|
+
appPathForLocal,
|
|
356
|
+
freshEnv
|
|
354
357
|
} = opts;
|
|
355
|
-
const localOpts = { appPath: appPathForLocal || undefined };
|
|
358
|
+
const localOpts = { appPath: appPathForLocal || undefined, freshEnv: freshEnv === true };
|
|
356
359
|
if (preferLocal) {
|
|
357
360
|
await writeLocalEnvToOutputPath(outputPath, appName, secretsPath, label, localOpts);
|
|
358
361
|
return;
|
|
359
362
|
}
|
|
360
363
|
if (fs.existsSync(envPath)) {
|
|
361
|
-
await syncWrittenBuilderEnvToOutputPath(envPath, outputPath, label);
|
|
364
|
+
await syncWrittenBuilderEnvToOutputPath(envPath, outputPath, label, { freshEnv: freshEnv === true });
|
|
362
365
|
return;
|
|
363
366
|
}
|
|
364
367
|
await writeLocalEnvToOutputPath(outputPath, appName, secretsPath, label, localOpts);
|
|
@@ -386,6 +389,7 @@ async function processEnvVariables(envPath, variablesPath, appName, secretsPath,
|
|
|
386
389
|
(variablesPath ? path.dirname(variablesPath) : null);
|
|
387
390
|
const preferLocal =
|
|
388
391
|
copyOptions && typeof copyOptions === 'object' && copyOptions.preferLocalEnvOutputPath === true;
|
|
392
|
+
const freshEnv = copyOptions && typeof copyOptions === 'object' && copyOptions.freshEnv === true;
|
|
389
393
|
if (appName) {
|
|
390
394
|
await copyOrRegenerateEnvForNamedApp({
|
|
391
395
|
envPath,
|
|
@@ -394,7 +398,8 @@ async function processEnvVariables(envPath, variablesPath, appName, secretsPath,
|
|
|
394
398
|
secretsPath,
|
|
395
399
|
label,
|
|
396
400
|
preferLocal,
|
|
397
|
-
appPathForLocal
|
|
401
|
+
appPathForLocal,
|
|
402
|
+
freshEnv
|
|
398
403
|
});
|
|
399
404
|
} else {
|
|
400
405
|
await writePatchedEnvToOutputPath(envPath, outputPath, variables, label);
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Comment active KV_* env lines that are not in the expected key set (stale auth vars).
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Shared orphan KV line handling for env.template repair and resolve merge
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Comments active KV_* lines whose env key is not in the expected set.
|
|
13
|
+
*
|
|
14
|
+
* @param {string} content - .env or env.template content
|
|
15
|
+
* @param {Set<string>|Map<string, unknown>} expectedKeys - Keys that should stay active
|
|
16
|
+
* @returns {{ content: string, changed: boolean }}
|
|
17
|
+
*/
|
|
18
|
+
function commentOrphanKvEnvLines(content, expectedKeys) {
|
|
19
|
+
const expected =
|
|
20
|
+
expectedKeys instanceof Set ? expectedKeys : new Set(expectedKeys.keys());
|
|
21
|
+
const changedRef = { value: false };
|
|
22
|
+
const out = (content || '').split(/\r?\n/).map((line) => {
|
|
23
|
+
const trimmed = line.trim();
|
|
24
|
+
if (!trimmed || trimmed.startsWith('#')) {
|
|
25
|
+
return line;
|
|
26
|
+
}
|
|
27
|
+
const eq = line.indexOf('=');
|
|
28
|
+
if (eq <= 0 || !/^KV_/i.test(trimmed)) {
|
|
29
|
+
return line;
|
|
30
|
+
}
|
|
31
|
+
const key = line.substring(0, eq).trim();
|
|
32
|
+
if (expected.has(key)) {
|
|
33
|
+
return line;
|
|
34
|
+
}
|
|
35
|
+
changedRef.value = true;
|
|
36
|
+
return `${line.match(/^\s*/)[0]}# ${trimmed}`;
|
|
37
|
+
});
|
|
38
|
+
const joined = out.join('\n');
|
|
39
|
+
const normalized = joined.length > 0 && !joined.endsWith('\n') ? `${joined}\n` : joined;
|
|
40
|
+
return { content: normalized, changed: changedRef.value };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
module.exports = { commentOrphanKvEnvLines };
|
|
@@ -10,6 +10,7 @@ const { formatBlockingError } = require('../cli-test-layout-chalk');
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
const chalk = require('chalk');
|
|
13
|
+
const { serviceLabelDisplayName } = require('../service-url-label');
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* Normalizes error message to string
|
|
@@ -56,9 +57,16 @@ function addControllerUrlToMessage(lines, errorData) {
|
|
|
56
57
|
* @param {Object} errorData - Error response data
|
|
57
58
|
*/
|
|
58
59
|
function formatConnectionRefusedError(lines, errorData) {
|
|
59
|
-
|
|
60
|
+
const label = serviceLabelDisplayName(errorData?.serviceLabel || 'service');
|
|
61
|
+
lines.push(chalk.yellow(`Cannot connect to ${label}.`));
|
|
60
62
|
addControllerUrlToMessage(lines, errorData);
|
|
61
|
-
|
|
63
|
+
if (label === 'dataplane') {
|
|
64
|
+
lines.push(chalk.gray('Check if the dataplane is running (e.g. aifabrix run dataplane --reload).'));
|
|
65
|
+
} else if (label === 'controller') {
|
|
66
|
+
lines.push(chalk.gray('Check if the controller is running.'));
|
|
67
|
+
} else {
|
|
68
|
+
lines.push(chalk.gray('Check the service URL and network.'));
|
|
69
|
+
}
|
|
62
70
|
}
|
|
63
71
|
|
|
64
72
|
/**
|
|
@@ -68,9 +76,10 @@ function formatConnectionRefusedError(lines, errorData) {
|
|
|
68
76
|
* @param {Object} errorData - Error response data
|
|
69
77
|
*/
|
|
70
78
|
function formatHostnameNotFoundError(lines, errorData) {
|
|
71
|
-
|
|
79
|
+
const label = serviceLabelDisplayName(errorData?.serviceLabel || 'service');
|
|
80
|
+
lines.push(chalk.yellow(`${label.charAt(0).toUpperCase()}${label.slice(1)} hostname not found.`));
|
|
72
81
|
addControllerUrlToMessage(lines, errorData);
|
|
73
|
-
lines.push(chalk.gray(
|
|
82
|
+
lines.push(chalk.gray(`Check your ${label} URL (see aifabrix auth status).`));
|
|
74
83
|
}
|
|
75
84
|
|
|
76
85
|
/**
|
|
@@ -13,6 +13,7 @@ const path = require('path');
|
|
|
13
13
|
const fs = require('fs');
|
|
14
14
|
const Handlebars = require('handlebars');
|
|
15
15
|
const { systemKeyToKvPrefix, kvEnvKeyToPath, securityKeyToVar } = require('./credential-secrets-env');
|
|
16
|
+
const { getAuthCredentialTemplate } = require('./authentication-shape');
|
|
16
17
|
|
|
17
18
|
/**
|
|
18
19
|
* Builds hint string from portalInput (options → enum, validation → min-max or pattern).
|
|
@@ -43,6 +44,7 @@ const FALLBACK_SECURITY_BY_AUTH = {
|
|
|
43
44
|
aad: ['clientId', 'clientSecret'],
|
|
44
45
|
apikey: ['apiKey'],
|
|
45
46
|
apiKey: ['apiKey'],
|
|
47
|
+
bearertoken: ['token'],
|
|
46
48
|
basic: ['username', 'password'],
|
|
47
49
|
queryParam: ['paramValue'],
|
|
48
50
|
oidc: [],
|
|
@@ -62,9 +64,15 @@ function buildAuthSecureVarsFromSystem(system) {
|
|
|
62
64
|
const systemKey = system?.key || 'external-system';
|
|
63
65
|
const prefix = systemKeyToKvPrefix(systemKey);
|
|
64
66
|
if (!prefix) return authSecureVars;
|
|
65
|
-
const
|
|
66
|
-
const
|
|
67
|
-
|
|
67
|
+
const authBlock = system?.authentication || system?.auth;
|
|
68
|
+
const credential = getAuthCredentialTemplate(authBlock);
|
|
69
|
+
const security = credential?.security || authBlock?.security;
|
|
70
|
+
const authMethod = (
|
|
71
|
+
credential?.method ||
|
|
72
|
+
authBlock?.method ||
|
|
73
|
+
authBlock?.type ||
|
|
74
|
+
'apikey'
|
|
75
|
+
).toLowerCase();
|
|
68
76
|
if (security && typeof security === 'object' && Object.keys(security).length > 0) {
|
|
69
77
|
for (const key of Object.keys(security)) {
|
|
70
78
|
const envName = `KV_${prefix}_${securityKeyToVar(key)}`;
|
|
@@ -28,6 +28,15 @@ function isPublicationResultShape(obj) {
|
|
|
28
28
|
return !!(obj && typeof obj === 'object' && (obj.uploadId || obj.system) && Array.isArray(obj.datasources));
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
/**
|
|
32
|
+
* True when dataplane skipped publish because manifest matches running config.
|
|
33
|
+
* @param {*} publication - Parsed PublicationResult
|
|
34
|
+
* @returns {boolean}
|
|
35
|
+
*/
|
|
36
|
+
function isPublicationUnchanged(publication) {
|
|
37
|
+
return !!(publication && publication.uploadStatus === 'unchanged');
|
|
38
|
+
}
|
|
39
|
+
|
|
31
40
|
/**
|
|
32
41
|
* Returns publication payload from upload API response.
|
|
33
42
|
* @param {*} res - Response from uploadApplicationViaPipeline
|
|
@@ -432,6 +441,7 @@ module.exports = {
|
|
|
432
441
|
unwrapApiData,
|
|
433
442
|
unwrapPublicationResult,
|
|
434
443
|
isPublicationResultShape,
|
|
444
|
+
isPublicationUnchanged,
|
|
435
445
|
classifyDatasourceTierADetail,
|
|
436
446
|
classifyDatasourceTierA,
|
|
437
447
|
formatTierAPartialHint,
|
|
@@ -128,25 +128,94 @@ function logServerValidationWarnings(validationBody) {
|
|
|
128
128
|
}
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
+
/**
|
|
132
|
+
* @param {Object[]} results - Probe result rows
|
|
133
|
+
* @returns {boolean}
|
|
134
|
+
*/
|
|
135
|
+
function connectivityCheckFailed(results) {
|
|
136
|
+
return results.some(
|
|
137
|
+
row =>
|
|
138
|
+
row?.endpointTestResults?.success === false
|
|
139
|
+
|| row?.endpointTestResults?.endpointReachable === false
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
131
143
|
/**
|
|
132
144
|
* @param {Object} results - Probe result rows
|
|
133
145
|
* @param {Object} summary - summarizeProbeResults output
|
|
134
146
|
*/
|
|
135
147
|
function logProbeCredentialLine(results, summary) {
|
|
136
148
|
logSeparator();
|
|
137
|
-
logSectionTitle('
|
|
138
|
-
|
|
139
|
-
if (anyEndpointFail) {
|
|
149
|
+
logSectionTitle('Connectivity check:');
|
|
150
|
+
if (connectivityCheckFailed(results)) {
|
|
140
151
|
logger.log(formatBlockingError('Failed (see Key Issues / endpoint test)'));
|
|
141
|
-
} else if (summary.failed > 0) {
|
|
142
|
-
logger.log(formatBlockingError('Some datasource checks failed'));
|
|
143
|
-
} else if (summary.partial > 0) {
|
|
144
|
-
logger.log(chalk.yellow('⚠ Completed with warnings'));
|
|
145
152
|
} else {
|
|
146
|
-
logger.log(formatSuccessLine('Passed'));
|
|
153
|
+
logger.log(formatSuccessLine('Passed (system credential / testEndpoint)'));
|
|
154
|
+
}
|
|
155
|
+
if (summary.partial > 0 || summary.failed > 0) {
|
|
156
|
+
logSeparator();
|
|
157
|
+
logSectionTitle('Datasource readiness:');
|
|
158
|
+
if (summary.failed > 0) {
|
|
159
|
+
logger.log(formatBlockingError('Some datasource checks failed'));
|
|
160
|
+
} else {
|
|
161
|
+
logger.log(
|
|
162
|
+
chalk.yellow(
|
|
163
|
+
'⚠ Partial — validation or certification warnings (not a failed credential test)'
|
|
164
|
+
)
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
logger.log(
|
|
168
|
+
chalk.gray(
|
|
169
|
+
' Upload --probe runs structural validation + certification tiers; live .env connectivity is separate.'
|
|
170
|
+
)
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* @param {Object[]} results
|
|
177
|
+
*/
|
|
178
|
+
function logProbeEmptyResultsWarningIfNeeded(results) {
|
|
179
|
+
if (results.length === 0) {
|
|
180
|
+
logger.log(chalk.yellow('⚠ No runtime datasource results were returned by the dataplane probe.'));
|
|
181
|
+
logger.log(chalk.gray(' Endpoint credential test may still pass even if datasource checks were not reported.'));
|
|
147
182
|
}
|
|
148
183
|
}
|
|
149
184
|
|
|
185
|
+
/**
|
|
186
|
+
* @param {Array<{ key: string, lines: string[] }>} issues
|
|
187
|
+
*/
|
|
188
|
+
function logProbeKeyIssues(issues) {
|
|
189
|
+
if (issues.length === 0) return;
|
|
190
|
+
logSeparator();
|
|
191
|
+
logSectionTitle('Key Issues:');
|
|
192
|
+
for (const { key, lines } of issues) {
|
|
193
|
+
logger.log(chalk.white(key));
|
|
194
|
+
for (const line of lines) {
|
|
195
|
+
logger.log(chalk.red(`- ${line}`));
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* @param {Object[]} results
|
|
202
|
+
* @param {Object} summary
|
|
203
|
+
* @returns {string[]}
|
|
204
|
+
*/
|
|
205
|
+
function buildProbeNextActionHints(results, summary) {
|
|
206
|
+
const hints = [];
|
|
207
|
+
if (connectivityCheckFailed(results)) {
|
|
208
|
+
hints.push('Fix API credentials or permissions (connectivity check failed)');
|
|
209
|
+
}
|
|
210
|
+
if (summary.failed > 0) {
|
|
211
|
+
hints.push('Fix datasource errors listed under Key Issues');
|
|
212
|
+
}
|
|
213
|
+
if (summary.partial > 0 && summary.failed === 0) {
|
|
214
|
+
hints.push('Review Key Issues for certification/validation warnings (ICC, MCP, dimensions)');
|
|
215
|
+
}
|
|
216
|
+
return hints;
|
|
217
|
+
}
|
|
218
|
+
|
|
150
219
|
/**
|
|
151
220
|
* @param {Object} probeRaw - Unwrapped POST /validation/run body
|
|
152
221
|
* @param {string} systemKey
|
|
@@ -156,25 +225,13 @@ function logProbeRuntimeBlock(probeRaw, systemKey) {
|
|
|
156
225
|
const summary = summarizeProbeResults(results);
|
|
157
226
|
logSeparator();
|
|
158
227
|
logger.log(chalk.bold('Runtime Readiness:'));
|
|
159
|
-
|
|
160
|
-
logger.log(chalk.yellow('⚠ No runtime datasource results were returned by the dataplane probe.'));
|
|
161
|
-
logger.log(chalk.gray(' Endpoint credential test may still pass even if datasource checks were not reported.'));
|
|
162
|
-
}
|
|
228
|
+
logProbeEmptyResultsWarningIfNeeded(results);
|
|
163
229
|
logDatasourceTable(summary.rows, summary);
|
|
164
|
-
|
|
165
|
-
logSeparator();
|
|
166
|
-
logSectionTitle('Key Issues:');
|
|
167
|
-
for (const { key, lines } of summary.issues) {
|
|
168
|
-
logger.log(chalk.white(key));
|
|
169
|
-
for (const line of lines) {
|
|
170
|
-
logger.log(chalk.red(`- ${line}`));
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
}
|
|
230
|
+
logProbeKeyIssues(summary.issues);
|
|
174
231
|
logProbeCredentialLine(results, summary);
|
|
175
232
|
logSeparator();
|
|
176
233
|
logNextActions(
|
|
177
|
-
|
|
234
|
+
buildProbeNextActionHints(results, summary),
|
|
178
235
|
`Run: aifabrix datasource test-e2e <datasourceKey> --app ${systemKey}`
|
|
179
236
|
);
|
|
180
237
|
}
|
|
@@ -392,8 +392,7 @@ function validateAgainstSchema(data, schema) {
|
|
|
392
392
|
validateSchema: false
|
|
393
393
|
});
|
|
394
394
|
addFormats(ajv);
|
|
395
|
-
//
|
|
396
|
-
// Adding them up-front keeps validation offline-safe and avoids unresolved $ref failures.
|
|
395
|
+
// Type schemas are referenced by $id from external-system and external-datasource manifests.
|
|
397
396
|
ajv.addSchema(require('../schema/type/document-storage.json'));
|
|
398
397
|
ajv.addSchema(require('../schema/type/message-service.json'));
|
|
399
398
|
ajv.addSchema(require('../schema/type/vector-store.json'));
|
|
@@ -404,6 +403,13 @@ function validateAgainstSchema(data, schema) {
|
|
|
404
403
|
}
|
|
405
404
|
// Normalize schema to handle nullable without type
|
|
406
405
|
const normalizedSchema = normalizeSchema(schemaCopy);
|
|
406
|
+
const schemaId = normalizedSchema.$id || '';
|
|
407
|
+
if (schemaId.includes('external-datasource')) {
|
|
408
|
+
const externalSystemSchema = require('../schema/external-system.schema.json');
|
|
409
|
+
if (!ajv.getSchema(externalSystemSchema.$id)) {
|
|
410
|
+
ajv.addSchema(externalSystemSchema, externalSystemSchema.$id);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
407
413
|
const validate = ajv.compile(normalizedSchema);
|
|
408
414
|
const valid = validate(data);
|
|
409
415
|
|
|
@@ -357,7 +357,10 @@ async function performHealthCheckAttempt(healthCheckUrl, attempt, maxAttempts, d
|
|
|
357
357
|
}
|
|
358
358
|
const healthCheckPassed = await checkHealthEndpoint(healthCheckUrl, debug);
|
|
359
359
|
if (healthCheckPassed) {
|
|
360
|
-
|
|
360
|
+
const { isSetupQuietOutput } = require('./setup-quiet-output');
|
|
361
|
+
if (!isSetupQuietOutput()) {
|
|
362
|
+
logger.log(formatSuccessLine('Application is healthy'));
|
|
363
|
+
}
|
|
361
364
|
if (debug) {
|
|
362
365
|
logger.log(chalk.gray(`[DEBUG] Health check passed after ${attempt + 1} attempt(s)`));
|
|
363
366
|
}
|
|
@@ -73,7 +73,12 @@ const CATEGORIES = [
|
|
|
73
73
|
{ name: 'app' },
|
|
74
74
|
{ name: 'credential' },
|
|
75
75
|
{ name: 'deployment' },
|
|
76
|
-
{ name: 'integration-client' }
|
|
76
|
+
{ name: 'integration-client' },
|
|
77
|
+
{ name: 'dimension' },
|
|
78
|
+
{ name: 'dimension value', term: 'dimension value <command>' },
|
|
79
|
+
{ name: 'resource-type' },
|
|
80
|
+
{ name: 'identity' },
|
|
81
|
+
{ name: 'protection' }
|
|
77
82
|
]
|
|
78
83
|
},
|
|
79
84
|
{
|
|
@@ -97,18 +102,18 @@ const CATEGORIES = [
|
|
|
97
102
|
{ name: 'upload', term: 'upload <systemKey>' },
|
|
98
103
|
{ name: 'delete', term: 'delete <systemKey>' },
|
|
99
104
|
{ name: 'repair', term: 'repair <systemKey>' },
|
|
105
|
+
{ name: 'channel', term: 'channel scaffold <channelTarget>' },
|
|
100
106
|
{ name: 'datasource' },
|
|
101
107
|
{ name: 'datasource load', term: 'datasource load <datasourceKey>' },
|
|
102
108
|
{ name: 'datasource export', term: 'datasource export <datasourceKey>' },
|
|
103
|
-
{ name: 'dimension' },
|
|
104
|
-
{ name: 'dimension value', term: 'dimension value <command>' },
|
|
105
|
-
{ name: 'identity' },
|
|
106
|
-
{ name: 'protection' },
|
|
107
109
|
{ name: 'test', term: 'test <appKey|systemKey>' },
|
|
110
|
+
{ name: 'test-integration', term: 'test-integration <appKey|systemKey>' },
|
|
108
111
|
{ name: 'test-e2e', term: 'test-e2e <appKey|systemKey>' },
|
|
109
|
-
{ name: '
|
|
110
|
-
{ name: '
|
|
111
|
-
{ name: '
|
|
112
|
+
{ name: 'verify-operations', term: 'verify-operations <systemKey>' },
|
|
113
|
+
{ name: 'verify-trust', term: 'verify-trust <systemKey>' },
|
|
114
|
+
{ name: 'verify-governance', term: 'verify-governance <systemKey>' },
|
|
115
|
+
{ name: 'governance', term: 'governance <generate|verify|download|upload> <systemKey>' },
|
|
116
|
+
{ name: 'lifecycle', term: 'lifecycle <systemKey>' }
|
|
112
117
|
]
|
|
113
118
|
},
|
|
114
119
|
{
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Poll Keycloak until the `aifabrix` realm is available (post-wipe / fresh install).
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Keycloak realm readiness for setup auth
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const { computeAppBaseUrl } = require('./platform-controller-url');
|
|
12
|
+
const config = require('../core/config');
|
|
13
|
+
const { readUrlsLocalRegistrySync } = require('./urls-local-registry');
|
|
14
|
+
const { normalizeFrontDoorPatternForHealth } = require('./health-check-url');
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @param {string} keycloakBase
|
|
18
|
+
* @returns {string}
|
|
19
|
+
*/
|
|
20
|
+
function buildRealmWellKnownUrl(keycloakBase) {
|
|
21
|
+
const base = String(keycloakBase || '').replace(/\/+$/, '');
|
|
22
|
+
return `${base}/realms/aifabrix/.well-known/openid-configuration`;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @async
|
|
27
|
+
* @param {string} url
|
|
28
|
+
* @returns {Promise<boolean>}
|
|
29
|
+
*/
|
|
30
|
+
async function probeRealmWellKnown(url) {
|
|
31
|
+
const controller = new AbortController();
|
|
32
|
+
const timer = setTimeout(() => controller.abort(), 8000);
|
|
33
|
+
try {
|
|
34
|
+
const res = await fetch(url, { method: 'GET', signal: controller.signal });
|
|
35
|
+
return res.ok;
|
|
36
|
+
} catch {
|
|
37
|
+
return false;
|
|
38
|
+
} finally {
|
|
39
|
+
clearTimeout(timer);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function computeKeycloakDirectBaseUrlFromRegistry(registry, developerIdNum) {
|
|
44
|
+
const portRaw = registry && registry['keycloak-port'];
|
|
45
|
+
const port =
|
|
46
|
+
typeof portRaw === 'number'
|
|
47
|
+
? portRaw
|
|
48
|
+
: typeof portRaw === 'string' && /^\d+$/.test(portRaw.trim())
|
|
49
|
+
? parseInt(portRaw.trim(), 10)
|
|
50
|
+
: null;
|
|
51
|
+
if (!port || port <= 0) {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
const patternRaw = registry && registry['keycloak-pattern'];
|
|
55
|
+
const pattern = typeof patternRaw === 'string' && patternRaw.trim() ? patternRaw.trim() : null;
|
|
56
|
+
const mount = pattern ? normalizeFrontDoorPatternForHealth(pattern) : null;
|
|
57
|
+
const adjusted = port + (Number.isFinite(developerIdNum) ? developerIdNum : 0) * 100;
|
|
58
|
+
return `http://localhost:${adjusted}${mount || ''}`;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Wait until Keycloak serves the aifabrix realm OIDC metadata.
|
|
63
|
+
*
|
|
64
|
+
* @async
|
|
65
|
+
* @param {{ timeoutSeconds?: number, intervalMs?: number }} [opts]
|
|
66
|
+
* @returns {Promise<void>}
|
|
67
|
+
* @throws {Error} On timeout
|
|
68
|
+
*/
|
|
69
|
+
async function waitForKeycloakRealmReady(opts = {}) {
|
|
70
|
+
const timeoutSeconds = Number.isFinite(opts.timeoutSeconds) ? opts.timeoutSeconds : 180;
|
|
71
|
+
const intervalMs = Number.isFinite(opts.intervalMs) ? opts.intervalMs : 3000;
|
|
72
|
+
const keycloakBase = await computeAppBaseUrl('keycloak');
|
|
73
|
+
const url = buildRealmWellKnownUrl(keycloakBase);
|
|
74
|
+
const registry = readUrlsLocalRegistrySync();
|
|
75
|
+
const developerIdRaw = await config.getDeveloperId();
|
|
76
|
+
const developerIdNum = typeof developerIdRaw === 'string' ? parseInt(developerIdRaw, 10) : developerIdRaw;
|
|
77
|
+
const directBase = computeKeycloakDirectBaseUrlFromRegistry(registry, developerIdNum);
|
|
78
|
+
const directUrl = directBase ? buildRealmWellKnownUrl(directBase) : null;
|
|
79
|
+
const deadline = Date.now() + timeoutSeconds * 1000;
|
|
80
|
+
|
|
81
|
+
while (Date.now() < deadline) {
|
|
82
|
+
if (await probeRealmWellKnown(url)) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
if (directUrl && (await probeRealmWellKnown(directUrl))) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
await new Promise((resolve) => setTimeout(resolve, intervalMs));
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
throw new Error(
|
|
92
|
+
`Keycloak realm "aifabrix" was not ready within ${timeoutSeconds}s (checked ${url}${directUrl ? ` and ${directUrl}` : ''}). ` +
|
|
93
|
+
'Ensure Miso Controller finished onboarding after the database wipe.'
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
module.exports = {
|
|
98
|
+
buildRealmWellKnownUrl,
|
|
99
|
+
waitForKeycloakRealmReady,
|
|
100
|
+
computeKeycloakDirectBaseUrlFromRegistry
|
|
101
|
+
};
|