@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,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview governance upload — push integration/<systemKey>/scenarios/*.yaml (424.0).
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
'use strict';
|
|
6
|
+
|
|
7
|
+
const { uploadGovernanceScenarioPacks } = require('../lifecycle/scenario-upload');
|
|
8
|
+
const { resolveGovernanceIntegrationContext } = require('./governance-cli-shared');
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @async
|
|
12
|
+
* @param {string} systemKey
|
|
13
|
+
* @param {Object} options
|
|
14
|
+
* @returns {Promise<Object>}
|
|
15
|
+
*/
|
|
16
|
+
async function runGovernanceUploadForExternalSystem(systemKey, options = {}) {
|
|
17
|
+
const { resolvedKey, authConfig, dataplaneUrl } = await resolveGovernanceIntegrationContext(
|
|
18
|
+
systemKey,
|
|
19
|
+
options
|
|
20
|
+
);
|
|
21
|
+
const uploaded = await uploadGovernanceScenarioPacks(
|
|
22
|
+
resolvedKey,
|
|
23
|
+
dataplaneUrl,
|
|
24
|
+
authConfig,
|
|
25
|
+
{ silent: options.json === true }
|
|
26
|
+
);
|
|
27
|
+
return {
|
|
28
|
+
systemKey: resolvedKey,
|
|
29
|
+
command: 'governance upload',
|
|
30
|
+
uploaded
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
module.exports = {
|
|
35
|
+
runGovernanceUploadForExternalSystem
|
|
36
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview governance verify — run persisted packs (424.0).
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
'use strict';
|
|
6
|
+
|
|
7
|
+
const { runVerifyGovernanceFromDbPacks } = require('./verify-governance-db');
|
|
8
|
+
const {
|
|
9
|
+
sumEnforcementScenarios,
|
|
10
|
+
aggregateCoverage,
|
|
11
|
+
buildPackOverrideResult
|
|
12
|
+
} = require('./verify-governance-result-builders');
|
|
13
|
+
const { VERDICT, verdictFromPassed } = require('../lifecycle/product-model');
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @async
|
|
17
|
+
* @param {string} systemKey
|
|
18
|
+
* @param {Object} options
|
|
19
|
+
* @returns {Promise<Object>}
|
|
20
|
+
*/
|
|
21
|
+
async function runGovernanceVerifyForExternalSystem(systemKey, options = {}) {
|
|
22
|
+
const pathsUtil = require('../utils/paths');
|
|
23
|
+
const appType = await pathsUtil.detectAppType(systemKey).catch(() => null);
|
|
24
|
+
if (!appType || appType.baseDir !== 'integration') {
|
|
25
|
+
throw new Error(
|
|
26
|
+
'governance verify applies to external integration folders only (integration/<systemKey>/).'
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (options.pack) {
|
|
31
|
+
const { runTestGovernanceForExternalSystem } = require('./test-governance-external');
|
|
32
|
+
const runPayload = await runTestGovernanceForExternalSystem(systemKey, options);
|
|
33
|
+
return buildPackOverrideResult(systemKey, runPayload, 'governance verify');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const { resolvedKey, datasourceRows } = await runVerifyGovernanceFromDbPacks(systemKey, options);
|
|
37
|
+
if (datasourceRows.length === 0) {
|
|
38
|
+
return {
|
|
39
|
+
systemKey: resolvedKey,
|
|
40
|
+
command: 'governance verify',
|
|
41
|
+
verdict: VERDICT.FAILED,
|
|
42
|
+
policyCoveragePercent: 0,
|
|
43
|
+
dimensionCoveragePercent: 0,
|
|
44
|
+
enforcementScenarios: { passed: 0, total: 0 },
|
|
45
|
+
datasourceRows: []
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const allVerified = datasourceRows.every(r => r.verdict === VERDICT.VERIFIED);
|
|
50
|
+
const coverage = aggregateCoverage(datasourceRows);
|
|
51
|
+
return {
|
|
52
|
+
systemKey: resolvedKey,
|
|
53
|
+
command: 'governance verify',
|
|
54
|
+
verdict: verdictFromPassed(allVerified),
|
|
55
|
+
policyCoveragePercent: coverage.policy ?? (allVerified ? 100 : 0),
|
|
56
|
+
dimensionCoveragePercent: coverage.dimension ?? (allVerified ? 100 : 0),
|
|
57
|
+
enforcementScenarios: sumEnforcementScenarios(datasourceRows),
|
|
58
|
+
datasourceRows
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
module.exports = {
|
|
63
|
+
runGovernanceVerifyForExternalSystem
|
|
64
|
+
};
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Integration validation scenario packs — governance command family (424.0).
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
'use strict';
|
|
6
|
+
|
|
7
|
+
const {
|
|
8
|
+
collectString,
|
|
9
|
+
governanceGenerateHandler,
|
|
10
|
+
governanceVerifyHandler,
|
|
11
|
+
governanceUploadHandler,
|
|
12
|
+
governanceDownloadHandler
|
|
13
|
+
} = require('./governance-command-action');
|
|
14
|
+
const {
|
|
15
|
+
GOVERNANCE_GENERATE_HELP_AFTER,
|
|
16
|
+
GOVERNANCE_VERIFY_HELP_AFTER,
|
|
17
|
+
GOVERNANCE_UPLOAD_HELP_AFTER,
|
|
18
|
+
GOVERNANCE_DOWNLOAD_HELP_AFTER,
|
|
19
|
+
GOVERNANCE_PARENT_HELP_AFTER
|
|
20
|
+
} = require('../cli/setup-certification.help');
|
|
21
|
+
|
|
22
|
+
const SHARED_OPTS = [
|
|
23
|
+
['-e, --env <env>', 'Environment: dev, tst, or pro', 'dev'],
|
|
24
|
+
['--no-sync', 'Skip publishing local integration files before dataplane calls'],
|
|
25
|
+
[
|
|
26
|
+
'--force',
|
|
27
|
+
'With default sync, pass force to upload (same as aifabrix upload --force)'
|
|
28
|
+
]
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @param {import('commander').Command} cmd
|
|
33
|
+
*/
|
|
34
|
+
function applySharedGovernanceOpts(cmd) {
|
|
35
|
+
for (const [flags, desc, defaultValue] of SHARED_OPTS) {
|
|
36
|
+
cmd.option(flags, desc, defaultValue);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* @param {import('commander').Command} governance
|
|
42
|
+
*/
|
|
43
|
+
function registerGovernanceGenerate(governance) {
|
|
44
|
+
const cmd = governance
|
|
45
|
+
.command('generate <systemKey>')
|
|
46
|
+
.description('Generate integration validation scenario packs on the dataplane')
|
|
47
|
+
.option(
|
|
48
|
+
'--certification-profile <profile>',
|
|
49
|
+
'Certification profile (bronze, silver, gold, …)',
|
|
50
|
+
'bronze'
|
|
51
|
+
)
|
|
52
|
+
.option(
|
|
53
|
+
'--subject-user-id <id>',
|
|
54
|
+
'Subject user id for generated scenarios (repeatable)',
|
|
55
|
+
collectString,
|
|
56
|
+
[]
|
|
57
|
+
)
|
|
58
|
+
.option(
|
|
59
|
+
'--subject-email <email>',
|
|
60
|
+
'Subject email for generated scenarios (repeatable)',
|
|
61
|
+
collectString,
|
|
62
|
+
[]
|
|
63
|
+
)
|
|
64
|
+
.option(
|
|
65
|
+
'--max-samples-per-partition <n>',
|
|
66
|
+
'Max keys per mustInclude/mustExclude partition',
|
|
67
|
+
'25'
|
|
68
|
+
)
|
|
69
|
+
.option('-v, --verbose', 'Verbose output')
|
|
70
|
+
.option('--json', 'Machine-readable envelope')
|
|
71
|
+
.addHelpText('after', GOVERNANCE_GENERATE_HELP_AFTER)
|
|
72
|
+
.action(governanceGenerateHandler);
|
|
73
|
+
applySharedGovernanceOpts(cmd);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* @param {import('commander').Command} governance
|
|
78
|
+
*/
|
|
79
|
+
function registerGovernanceVerify(governance) {
|
|
80
|
+
const cmd = governance
|
|
81
|
+
.command('verify <systemKey>')
|
|
82
|
+
.description('Run persisted scenario packs (governance:evaluate)')
|
|
83
|
+
.option(
|
|
84
|
+
'--pack <path>',
|
|
85
|
+
'Authoring override: local scenario pack YAML instead of dataplane active pack'
|
|
86
|
+
)
|
|
87
|
+
.option('-a, --app <path>', 'Integration folder override (with --pack)')
|
|
88
|
+
.option('--scenario <id>', 'Scenario subset when using --pack (repeatable)', collectString, [])
|
|
89
|
+
.option('-v, --verbose', 'Per-datasource breakdown')
|
|
90
|
+
.option('--json', 'Machine-readable envelope')
|
|
91
|
+
.addHelpText('after', GOVERNANCE_VERIFY_HELP_AFTER)
|
|
92
|
+
.action(governanceVerifyHandler);
|
|
93
|
+
applySharedGovernanceOpts(cmd);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* @param {import('commander').Command} governance
|
|
98
|
+
*/
|
|
99
|
+
function registerGovernanceUpload(governance) {
|
|
100
|
+
const cmd = governance
|
|
101
|
+
.command('upload <systemKey>')
|
|
102
|
+
.description('Upload integration/<systemKey>/scenarios/*.yaml to the dataplane')
|
|
103
|
+
.option('--json', 'Machine-readable envelope')
|
|
104
|
+
.addHelpText('after', GOVERNANCE_UPLOAD_HELP_AFTER)
|
|
105
|
+
.action(governanceUploadHandler);
|
|
106
|
+
applySharedGovernanceOpts(cmd);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* @param {import('commander').Command} governance
|
|
111
|
+
*/
|
|
112
|
+
function registerGovernanceDownload(governance) {
|
|
113
|
+
const cmd = governance
|
|
114
|
+
.command('download <systemKey>')
|
|
115
|
+
.description('Download active packs to integration/<systemKey>/scenarios/')
|
|
116
|
+
.option('--json', 'Machine-readable envelope')
|
|
117
|
+
.addHelpText('after', GOVERNANCE_DOWNLOAD_HELP_AFTER)
|
|
118
|
+
.action(governanceDownloadHandler);
|
|
119
|
+
applySharedGovernanceOpts(cmd);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* @param {import('commander').Command} program
|
|
124
|
+
*/
|
|
125
|
+
function setupGovernanceCommands(program) {
|
|
126
|
+
const governance = program
|
|
127
|
+
.command('governance')
|
|
128
|
+
.description(
|
|
129
|
+
'Integration validation scenario packs (generate, verify, download, upload)'
|
|
130
|
+
)
|
|
131
|
+
.addHelpText('after', GOVERNANCE_PARENT_HELP_AFTER);
|
|
132
|
+
|
|
133
|
+
applySharedGovernanceOpts(governance);
|
|
134
|
+
|
|
135
|
+
registerGovernanceGenerate(governance);
|
|
136
|
+
registerGovernanceVerify(governance);
|
|
137
|
+
registerGovernanceUpload(governance);
|
|
138
|
+
registerGovernanceDownload(governance);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
module.exports = {
|
|
142
|
+
setupGovernanceCommands,
|
|
143
|
+
collectString
|
|
144
|
+
};
|
|
@@ -7,14 +7,15 @@
|
|
|
7
7
|
'use strict';
|
|
8
8
|
|
|
9
9
|
const logger = require('../utils/logger');
|
|
10
|
-
const {
|
|
10
|
+
const { formatSuccessLine, headerKeyValue } = require('../utils/cli-layout-chalk');
|
|
11
11
|
const {
|
|
12
12
|
resolveControllerAndAuth,
|
|
13
13
|
resolveEnvKey,
|
|
14
14
|
requireNonEmpty,
|
|
15
15
|
unwrapControllerData,
|
|
16
16
|
throwIfApiFailed,
|
|
17
|
-
assertSyncStatsOk
|
|
17
|
+
assertSyncStatsOk,
|
|
18
|
+
logIdentityCliError
|
|
18
19
|
} = require('./identity-shared');
|
|
19
20
|
const { clearAuthCache } = require('../api/auth-cache.api');
|
|
20
21
|
const { fullSyncToDataplane } = require('../api/dataplane-sync.api');
|
|
@@ -70,7 +71,7 @@ function setupIdentityApplyCommand(identityCmd) {
|
|
|
70
71
|
);
|
|
71
72
|
}
|
|
72
73
|
} catch (e) {
|
|
73
|
-
|
|
74
|
+
logIdentityCliError(e.message);
|
|
74
75
|
process.exit(1);
|
|
75
76
|
}
|
|
76
77
|
});
|
|
@@ -103,6 +104,46 @@ async function maybePurgeCache(controllerUrl, authConfig, purgeCache) {
|
|
|
103
104
|
logger.log(formatSuccessLine('Controller cache cleared'));
|
|
104
105
|
}
|
|
105
106
|
|
|
107
|
+
/**
|
|
108
|
+
* @param {string} controllerUrl
|
|
109
|
+
* @param {string} envKey
|
|
110
|
+
* @param {Object} authConfig
|
|
111
|
+
* @returns {Promise<string>}
|
|
112
|
+
*/
|
|
113
|
+
async function resolveSyncDataplaneUrl(controllerUrl, envKey, authConfig) {
|
|
114
|
+
try {
|
|
115
|
+
const { resolveDataplaneUrl } = require('../utils/dataplane-resolver');
|
|
116
|
+
return await resolveDataplaneUrl(controllerUrl, envKey, authConfig, { silent: true });
|
|
117
|
+
} catch {
|
|
118
|
+
return '—';
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* @param {Object} params
|
|
124
|
+
* @param {string} params.controllerUrl
|
|
125
|
+
* @param {string} params.envKey
|
|
126
|
+
* @param {Object} params.authConfig
|
|
127
|
+
* @param {Object|null|undefined} params.stats
|
|
128
|
+
*/
|
|
129
|
+
async function printIdentitySyncSuccess({ controllerUrl, envKey, authConfig, stats }) {
|
|
130
|
+
const dataplaneUrl = await resolveSyncDataplaneUrl(controllerUrl, envKey, authConfig);
|
|
131
|
+
const usersProcessed = Number(stats?.usersProcessed ?? 0);
|
|
132
|
+
const groupsProcessed = Number(stats?.groupsProcessed ?? 0);
|
|
133
|
+
const syncErrors = Number(stats?.errors ?? 0);
|
|
134
|
+
|
|
135
|
+
logger.log('');
|
|
136
|
+
logger.log(formatSuccessLine(`Identity synced to dataplane (${envKey})`));
|
|
137
|
+
logger.log(headerKeyValue(' Controller:', controllerUrl));
|
|
138
|
+
logger.log(headerKeyValue(' Dataplane:', dataplaneUrl));
|
|
139
|
+
logger.log('');
|
|
140
|
+
logger.log(` Users: ${usersProcessed} processed`);
|
|
141
|
+
logger.log(` Groups: ${groupsProcessed} processed`);
|
|
142
|
+
if (syncErrors > 0) {
|
|
143
|
+
logger.log(` Errors: ${syncErrors}`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
106
147
|
async function runIdentitySyncAction(options) {
|
|
107
148
|
try {
|
|
108
149
|
const { controllerUrl, authConfig } = await resolveControllerAndAuth();
|
|
@@ -116,16 +157,16 @@ async function runIdentitySyncAction(options) {
|
|
|
116
157
|
printJson(stats);
|
|
117
158
|
return;
|
|
118
159
|
}
|
|
119
|
-
|
|
120
|
-
logger.log(` usersProcessed=${stats?.usersProcessed ?? 0}`);
|
|
121
|
-
logger.log(` groupsProcessed=${stats?.groupsProcessed ?? 0}`);
|
|
160
|
+
await printIdentitySyncSuccess({ controllerUrl, envKey, authConfig, stats });
|
|
122
161
|
} catch (e) {
|
|
123
|
-
|
|
162
|
+
logIdentityCliError(e.message);
|
|
124
163
|
process.exit(1);
|
|
125
164
|
}
|
|
126
165
|
}
|
|
127
166
|
|
|
128
167
|
module.exports = {
|
|
129
168
|
setupIdentityApplyCommand,
|
|
130
|
-
setupIdentitySyncCommand
|
|
169
|
+
setupIdentitySyncCommand,
|
|
170
|
+
printIdentitySyncSuccess,
|
|
171
|
+
resolveSyncDataplaneUrl
|
|
131
172
|
};
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
'use strict';
|
|
8
8
|
|
|
9
9
|
const logger = require('../utils/logger');
|
|
10
|
-
const { formatBlockingError, formatSuccessLine
|
|
10
|
+
const { formatBlockingError, formatSuccessLine } = require('../utils/cli-layout-chalk');
|
|
11
11
|
const {
|
|
12
12
|
resolveControllerAndAuth,
|
|
13
13
|
requireNonEmpty,
|
|
@@ -15,11 +15,26 @@ const {
|
|
|
15
15
|
throwIfApiFailed
|
|
16
16
|
} = require('./identity-shared');
|
|
17
17
|
const { listGroups, getGroup, createGroup, listGroupMembers } = require('../api/groups.api');
|
|
18
|
+
const {
|
|
19
|
+
extractPaginatedList,
|
|
20
|
+
printGroupMembersTable,
|
|
21
|
+
printGroupRecord,
|
|
22
|
+
printIdentityEmpty,
|
|
23
|
+
printIdentityListHeader,
|
|
24
|
+
printIdentityNotFound,
|
|
25
|
+
printIdentityTable,
|
|
26
|
+
printListPaginationFooter,
|
|
27
|
+
GROUP_LIST_COLUMNS
|
|
28
|
+
} = require('../identity/identity-display');
|
|
18
29
|
|
|
19
30
|
function printJson(data) {
|
|
20
31
|
logger.log(JSON.stringify(data, null, 2));
|
|
21
32
|
}
|
|
22
33
|
|
|
34
|
+
function groupNotFoundHints() {
|
|
35
|
+
return ['af identity group list --search <text>', 'Use group name or id from group list'];
|
|
36
|
+
}
|
|
37
|
+
|
|
23
38
|
function registerGroupCreate(groupCmd) {
|
|
24
39
|
groupCmd
|
|
25
40
|
.command('create')
|
|
@@ -51,7 +66,7 @@ function registerGroupList(groupCmd) {
|
|
|
51
66
|
.description('List groups')
|
|
52
67
|
.option('--page <n>', 'Page', (v) => parseInt(v, 10))
|
|
53
68
|
.option('--page-size <n>', 'Page size', (v) => parseInt(v, 10))
|
|
54
|
-
.option('--search <text>', 'Search groups')
|
|
69
|
+
.option('--search <text>', 'Search groups by name or display name')
|
|
55
70
|
.option('--json', 'JSON output')
|
|
56
71
|
.action(async(options) => {
|
|
57
72
|
try {
|
|
@@ -62,14 +77,24 @@ function registerGroupList(groupCmd) {
|
|
|
62
77
|
search: options.search
|
|
63
78
|
});
|
|
64
79
|
throwIfApiFailed(res);
|
|
65
|
-
const data = unwrapControllerData(res);
|
|
66
80
|
if (options.json) {
|
|
67
|
-
printJson(data);
|
|
81
|
+
printJson(res.data ?? res);
|
|
68
82
|
return;
|
|
69
83
|
}
|
|
70
|
-
const items =
|
|
71
|
-
|
|
72
|
-
|
|
84
|
+
const { items, meta } = extractPaginatedList(res);
|
|
85
|
+
printIdentityListHeader({
|
|
86
|
+
emoji: '👥',
|
|
87
|
+
title: 'Groups',
|
|
88
|
+
context: controllerUrl,
|
|
89
|
+
shown: items.length,
|
|
90
|
+
total: meta?.totalItems ?? items.length
|
|
91
|
+
});
|
|
92
|
+
if (items.length === 0) {
|
|
93
|
+
printIdentityEmpty('No groups found.', ['Try --search']);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
printIdentityTable(GROUP_LIST_COLUMNS, items);
|
|
97
|
+
printListPaginationFooter(meta);
|
|
73
98
|
} catch (e) {
|
|
74
99
|
logger.error(formatBlockingError(e.message));
|
|
75
100
|
process.exit(1);
|
|
@@ -79,22 +104,28 @@ function registerGroupList(groupCmd) {
|
|
|
79
104
|
|
|
80
105
|
function registerGroupGet(groupCmd) {
|
|
81
106
|
groupCmd
|
|
82
|
-
.command('get <
|
|
107
|
+
.command('get <groupIdOrName>')
|
|
83
108
|
.description('Get group by id or name')
|
|
84
109
|
.option('--json', 'JSON output')
|
|
85
|
-
.action(async(
|
|
110
|
+
.action(async(groupIdOrName, options) => {
|
|
86
111
|
try {
|
|
87
112
|
const { controllerUrl, authConfig } = await resolveControllerAndAuth();
|
|
88
|
-
const
|
|
89
|
-
|
|
113
|
+
const value = requireNonEmpty(groupIdOrName, 'groupIdOrName');
|
|
114
|
+
const res = await getGroup(controllerUrl, authConfig, value);
|
|
115
|
+
if (!res || res.success === false) {
|
|
116
|
+
printIdentityNotFound('Group', value, groupNotFoundHints());
|
|
117
|
+
process.exit(1);
|
|
118
|
+
}
|
|
90
119
|
const row = unwrapControllerData(res);
|
|
120
|
+
if (!row?.id) {
|
|
121
|
+
printIdentityNotFound('Group', value, groupNotFoundHints());
|
|
122
|
+
process.exit(1);
|
|
123
|
+
}
|
|
91
124
|
if (options.json) {
|
|
92
125
|
printJson(row);
|
|
93
126
|
return;
|
|
94
127
|
}
|
|
95
|
-
|
|
96
|
-
logger.log(headerKeyValue('Name:', row.name));
|
|
97
|
-
logger.log('');
|
|
128
|
+
printGroupRecord(row);
|
|
98
129
|
} catch (e) {
|
|
99
130
|
logger.error(formatBlockingError(e.message));
|
|
100
131
|
process.exit(1);
|
|
@@ -104,26 +135,35 @@ function registerGroupGet(groupCmd) {
|
|
|
104
135
|
|
|
105
136
|
function registerGroupMembers(groupCmd) {
|
|
106
137
|
groupCmd
|
|
107
|
-
.command('members <
|
|
138
|
+
.command('members <groupIdOrName>')
|
|
108
139
|
.description('List members of a group')
|
|
109
140
|
.option('--json', 'JSON output')
|
|
110
|
-
.action(async(
|
|
141
|
+
.action(async(groupIdOrName, options) => {
|
|
111
142
|
try {
|
|
112
143
|
const { controllerUrl, authConfig } = await resolveControllerAndAuth();
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
144
|
+
const value = requireNonEmpty(groupIdOrName, 'groupIdOrName');
|
|
145
|
+
const res = await listGroupMembers(controllerUrl, authConfig, value);
|
|
146
|
+
if (!res || res.success === false) {
|
|
147
|
+
printIdentityNotFound('Group', value, groupNotFoundHints());
|
|
148
|
+
process.exit(1);
|
|
149
|
+
}
|
|
119
150
|
const data = unwrapControllerData(res);
|
|
151
|
+
const items = Array.isArray(data) ? data : data?.data || [];
|
|
120
152
|
if (options.json) {
|
|
121
|
-
printJson(
|
|
153
|
+
printJson(items);
|
|
122
154
|
return;
|
|
123
155
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
156
|
+
printIdentityListHeader({
|
|
157
|
+
emoji: '👤',
|
|
158
|
+
title: `Members of ${value}`,
|
|
159
|
+
shown: items.length,
|
|
160
|
+
total: items.length
|
|
161
|
+
});
|
|
162
|
+
if (items.length === 0) {
|
|
163
|
+
printIdentityEmpty('No members in this group.');
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
printGroupMembersTable(items);
|
|
127
167
|
} catch (e) {
|
|
128
168
|
logger.error(formatBlockingError(e.message));
|
|
129
169
|
process.exit(1);
|
|
@@ -19,30 +19,43 @@ const {
|
|
|
19
19
|
const { addUserToGroup, removeUserFromGroup } = require('../api/user-groups.api');
|
|
20
20
|
const { listEnvironmentRoles, updateRoleGroups } = require('../api/environments.api');
|
|
21
21
|
const { clearAuthCache, invalidateAuthCache } = require('../api/auth-cache.api');
|
|
22
|
+
const {
|
|
23
|
+
printIdentityEmpty,
|
|
24
|
+
printIdentityListHeader,
|
|
25
|
+
printIdentityTable
|
|
26
|
+
} = require('../identity/identity-display');
|
|
22
27
|
|
|
23
28
|
function printJson(data) {
|
|
24
29
|
logger.log(JSON.stringify(data, null, 2));
|
|
25
30
|
}
|
|
26
31
|
|
|
32
|
+
const ROLE_LIST_COLUMNS = [
|
|
33
|
+
{ label: 'Role', width: 36, value: (r) => r.value || r.role || r.name || '—' },
|
|
34
|
+
{
|
|
35
|
+
label: 'Groups',
|
|
36
|
+
width: 44,
|
|
37
|
+
value: (r) => {
|
|
38
|
+
const groups = Array.isArray(r.groups) ? r.groups.filter(Boolean) : [];
|
|
39
|
+
return groups.length > 0 ? groups.join(', ') : '—';
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
];
|
|
43
|
+
|
|
27
44
|
/**
|
|
28
45
|
* @param {import('commander').Command} memCmd
|
|
29
46
|
*/
|
|
30
47
|
function setupIdentityMembershipCommands(memCmd) {
|
|
31
48
|
memCmd
|
|
32
|
-
.command('add <
|
|
33
|
-
.description('Add user to group (
|
|
34
|
-
.action(async(
|
|
49
|
+
.command('add <userIdOrEmail> <groupIdOrName>')
|
|
50
|
+
.description('Add user to group (id, email, username + group id or name)')
|
|
51
|
+
.action(async(userIdOrEmail, groupIdOrName) => {
|
|
35
52
|
try {
|
|
36
53
|
const { controllerUrl, authConfig } = await resolveControllerAndAuth();
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
requireNonEmpty(userId, 'userId'),
|
|
41
|
-
requireNonEmpty(groupId, 'groupId'),
|
|
42
|
-
{}
|
|
43
|
-
);
|
|
54
|
+
const userRef = requireNonEmpty(userIdOrEmail, 'userIdOrEmail');
|
|
55
|
+
const groupRef = requireNonEmpty(groupIdOrName, 'groupIdOrName');
|
|
56
|
+
const res = await addUserToGroup(controllerUrl, authConfig, userRef, groupRef, {});
|
|
44
57
|
throwIfApiFailed(res);
|
|
45
|
-
logger.log(formatSuccessLine(`Membership created: ${
|
|
58
|
+
logger.log(formatSuccessLine(`Membership created: ${userRef} → ${groupRef}`));
|
|
46
59
|
} catch (e) {
|
|
47
60
|
logger.error(formatBlockingError(e.message));
|
|
48
61
|
process.exit(1);
|
|
@@ -50,19 +63,16 @@ function setupIdentityMembershipCommands(memCmd) {
|
|
|
50
63
|
});
|
|
51
64
|
|
|
52
65
|
memCmd
|
|
53
|
-
.command('remove <
|
|
66
|
+
.command('remove <userIdOrEmail> <groupIdOrName>')
|
|
54
67
|
.description('Remove user from group')
|
|
55
|
-
.action(async(
|
|
68
|
+
.action(async(userIdOrEmail, groupIdOrName) => {
|
|
56
69
|
try {
|
|
57
70
|
const { controllerUrl, authConfig } = await resolveControllerAndAuth();
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
requireNonEmpty(userId, 'userId'),
|
|
62
|
-
requireNonEmpty(groupId, 'groupId')
|
|
63
|
-
);
|
|
71
|
+
const userRef = requireNonEmpty(userIdOrEmail, 'userIdOrEmail');
|
|
72
|
+
const groupRef = requireNonEmpty(groupIdOrName, 'groupIdOrName');
|
|
73
|
+
const res = await removeUserFromGroup(controllerUrl, authConfig, userRef, groupRef);
|
|
64
74
|
throwIfApiFailed(res);
|
|
65
|
-
logger.log(formatSuccessLine(`Membership removed: ${
|
|
75
|
+
logger.log(formatSuccessLine(`Membership removed: ${userRef} → ${groupRef}`));
|
|
66
76
|
} catch (e) {
|
|
67
77
|
logger.error(formatBlockingError(e.message));
|
|
68
78
|
process.exit(1);
|
|
@@ -73,29 +83,40 @@ function setupIdentityMembershipCommands(memCmd) {
|
|
|
73
83
|
/**
|
|
74
84
|
* @param {import('commander').Command} roleCmd
|
|
75
85
|
*/
|
|
86
|
+
async function handleRoleListAction(options) {
|
|
87
|
+
const { controllerUrl, authConfig } = await resolveControllerAndAuth();
|
|
88
|
+
const envKey = await resolveEnvKey(options);
|
|
89
|
+
const res = await listEnvironmentRoles(controllerUrl, envKey, authConfig);
|
|
90
|
+
throwIfApiFailed(res);
|
|
91
|
+
const data = unwrapControllerData(res);
|
|
92
|
+
if (options.json) {
|
|
93
|
+
printJson(data);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
const items = Array.isArray(data) ? data : data?.data || data?.roles || [];
|
|
97
|
+
printIdentityListHeader({
|
|
98
|
+
emoji: '🔐',
|
|
99
|
+
title: 'Role → group mappings',
|
|
100
|
+
context: `environment: ${envKey}`,
|
|
101
|
+
shown: (items || []).length,
|
|
102
|
+
total: (items || []).length
|
|
103
|
+
});
|
|
104
|
+
if (!items || items.length === 0) {
|
|
105
|
+
printIdentityEmpty('No roles found for this environment.');
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
printIdentityTable(ROLE_LIST_COLUMNS, items);
|
|
109
|
+
}
|
|
110
|
+
|
|
76
111
|
function setupIdentityRoleCommands(roleCmd) {
|
|
77
112
|
roleCmd
|
|
78
113
|
.command('list')
|
|
79
114
|
.description('List roles and group mappings for an environment')
|
|
80
|
-
.
|
|
115
|
+
.option('-e, --env <key>', 'Environment key (defaults from aifabrix config)')
|
|
81
116
|
.option('--json', 'JSON output')
|
|
82
117
|
.action(async(options) => {
|
|
83
118
|
try {
|
|
84
|
-
|
|
85
|
-
const envKey = await resolveEnvKey(options);
|
|
86
|
-
const res = await listEnvironmentRoles(controllerUrl, envKey, authConfig);
|
|
87
|
-
throwIfApiFailed(res);
|
|
88
|
-
const data = unwrapControllerData(res);
|
|
89
|
-
if (options.json) {
|
|
90
|
-
printJson(data);
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
const items = Array.isArray(data) ? data : data?.data || data?.roles || [];
|
|
94
|
-
(items || []).forEach((r) => {
|
|
95
|
-
const groups = Array.isArray(r.groups) ? r.groups.join(', ') : '';
|
|
96
|
-
logger.log(` ${r.value || r.role || r.name} → ${groups || '—'}`);
|
|
97
|
-
});
|
|
98
|
-
logger.log('');
|
|
119
|
+
await handleRoleListAction(options);
|
|
99
120
|
} catch (e) {
|
|
100
121
|
logger.error(formatBlockingError(e.message));
|
|
101
122
|
process.exit(1);
|
|
@@ -105,7 +126,7 @@ function setupIdentityRoleCommands(roleCmd) {
|
|
|
105
126
|
roleCmd
|
|
106
127
|
.command('set-groups <roleValue>')
|
|
107
128
|
.description('Map role to groups in an environment')
|
|
108
|
-
.
|
|
129
|
+
.option('-e, --env <key>', 'Environment key (defaults from aifabrix config)')
|
|
109
130
|
.requiredOption('--groups <names>', 'Comma-separated group names')
|
|
110
131
|
.action(async(roleValue, options) => {
|
|
111
132
|
try {
|
|
@@ -6,6 +6,9 @@
|
|
|
6
6
|
|
|
7
7
|
'use strict';
|
|
8
8
|
|
|
9
|
+
const chalk = require('chalk');
|
|
10
|
+
const logger = require('../utils/logger');
|
|
11
|
+
const { formatBlockingError } = require('../utils/cli-layout-chalk');
|
|
9
12
|
const { resolveControllerUrl } = require('../utils/controller-url');
|
|
10
13
|
const { normalizeControllerUrl, resolveEnvironment } = require('../core/config');
|
|
11
14
|
const { getOrRefreshDeviceToken } = require('../utils/token-manager');
|
|
@@ -82,6 +85,23 @@ function parseGroupsList(groupsArg) {
|
|
|
82
85
|
return parts;
|
|
83
86
|
}
|
|
84
87
|
|
|
88
|
+
/**
|
|
89
|
+
* Print a blocking CLI error with optional multi-line guidance in gray.
|
|
90
|
+
*
|
|
91
|
+
* @param {string} message
|
|
92
|
+
* @returns {void}
|
|
93
|
+
*/
|
|
94
|
+
function logIdentityCliError(message) {
|
|
95
|
+
const lines = String(message || '').split('\n');
|
|
96
|
+
const head = lines[0] || 'Request failed';
|
|
97
|
+
logger.error(formatBlockingError(head));
|
|
98
|
+
lines.slice(1).forEach((line) => {
|
|
99
|
+
if (line.trim()) {
|
|
100
|
+
logger.log(chalk.gray(line));
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
85
105
|
module.exports = {
|
|
86
106
|
resolveControllerAndAuth,
|
|
87
107
|
resolveEnvKey,
|
|
@@ -90,5 +110,6 @@ module.exports = {
|
|
|
90
110
|
unwrapControllerData,
|
|
91
111
|
throwIfApiFailed,
|
|
92
112
|
assertSyncStatsOk,
|
|
93
|
-
apiErrorMessage
|
|
113
|
+
apiErrorMessage,
|
|
114
|
+
logIdentityCliError
|
|
94
115
|
};
|