@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,371 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resource type catalog commands (Controller).
|
|
3
|
+
*
|
|
4
|
+
* Commands:
|
|
5
|
+
* - aifabrix resource-type create
|
|
6
|
+
* - aifabrix resource-type import
|
|
7
|
+
* - aifabrix resource-type get
|
|
8
|
+
* - aifabrix resource-type list
|
|
9
|
+
*
|
|
10
|
+
* @fileoverview Resource type CLI commands
|
|
11
|
+
* @author AI Fabrix Team
|
|
12
|
+
* @version 1.0.0
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
'use strict';
|
|
16
|
+
|
|
17
|
+
const chalk = require('chalk');
|
|
18
|
+
const logger = require('../utils/logger');
|
|
19
|
+
const { resolveControllerUrl } = require('../utils/controller-url');
|
|
20
|
+
const { normalizeControllerUrl, resolveEnvironment } = require('../core/config');
|
|
21
|
+
const { getOrRefreshDeviceToken } = require('../utils/token-manager');
|
|
22
|
+
const {
|
|
23
|
+
readResourceTypeCreateFile,
|
|
24
|
+
readResourceTypeCatalogFile
|
|
25
|
+
} = require('../resolvers/resource-type-file');
|
|
26
|
+
const {
|
|
27
|
+
formatBlockingError,
|
|
28
|
+
formatSuccessLine,
|
|
29
|
+
infoLine,
|
|
30
|
+
headerKeyValue
|
|
31
|
+
} = require('../utils/cli-layout-chalk');
|
|
32
|
+
const {
|
|
33
|
+
listResourceTypes,
|
|
34
|
+
getResourceType,
|
|
35
|
+
createResourceTypeIdempotent
|
|
36
|
+
} = require('../api/resource-types.api');
|
|
37
|
+
|
|
38
|
+
const RESOURCE_TYPE_KEY_PATTERN = /^[a-z][a-z0-9-]*$/;
|
|
39
|
+
|
|
40
|
+
/** Parent help for `aifabrix resource-type -h`. */
|
|
41
|
+
const RESOURCE_TYPE_HELP_AFTER = `
|
|
42
|
+
|
|
43
|
+
Examples:
|
|
44
|
+
$ aifabrix resource-type create --key customer --display-name "Customer"
|
|
45
|
+
$ aifabrix resource-type get customer
|
|
46
|
+
$ aifabrix resource-type list --search customer
|
|
47
|
+
|
|
48
|
+
Per-command help: aifabrix resource-type <command> --help
|
|
49
|
+
`;
|
|
50
|
+
|
|
51
|
+
const RESOURCE_TYPE_IMPORT_HELP_AFTER = `
|
|
52
|
+
|
|
53
|
+
Examples:
|
|
54
|
+
$ aifabrix resource-type import --file ./baseline-resourcetypes.json
|
|
55
|
+
$ aifabrix resource-type import --file /path/to/catalog.json
|
|
56
|
+
|
|
57
|
+
`;
|
|
58
|
+
|
|
59
|
+
const RESOURCE_TYPE_CREATE_HELP_AFTER = `
|
|
60
|
+
|
|
61
|
+
Examples:
|
|
62
|
+
$ aifabrix resource-type create --key customer --display-name "Customer"
|
|
63
|
+
$ aifabrix resource-type create --key deal --display-name "Deal" --category business --default-risk-level medium
|
|
64
|
+
$ aifabrix resource-type create --file ./customer.json
|
|
65
|
+
|
|
66
|
+
`;
|
|
67
|
+
|
|
68
|
+
const RESOURCE_TYPE_GET_HELP_AFTER = `
|
|
69
|
+
|
|
70
|
+
Examples:
|
|
71
|
+
$ aifabrix resource-type get customer
|
|
72
|
+
$ aifabrix resource-type get clx1234567890abcdef
|
|
73
|
+
|
|
74
|
+
`;
|
|
75
|
+
|
|
76
|
+
const RESOURCE_TYPE_LIST_HELP_AFTER = `
|
|
77
|
+
|
|
78
|
+
Examples:
|
|
79
|
+
$ aifabrix resource-type list
|
|
80
|
+
$ aifabrix resource-type list --page 1 --page-size 50
|
|
81
|
+
$ aifabrix resource-type list --search customer
|
|
82
|
+
|
|
83
|
+
`;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* @param {string} raw
|
|
87
|
+
* @returns {string}
|
|
88
|
+
*/
|
|
89
|
+
function requireResourceTypeKey(raw) {
|
|
90
|
+
const key = String(raw || '').trim();
|
|
91
|
+
if (!key) {
|
|
92
|
+
throw new Error('Resource type key is required (--key <key> or --file <path>).');
|
|
93
|
+
}
|
|
94
|
+
if (!RESOURCE_TYPE_KEY_PATTERN.test(key)) {
|
|
95
|
+
throw new Error(
|
|
96
|
+
'Resource type key must start with a lowercase letter and contain only lowercase letters, numbers, and hyphens.'
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
return key;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* @param {Object} options
|
|
104
|
+
* @returns {Promise<{ controllerUrl: string, authConfig: Object }>}
|
|
105
|
+
*/
|
|
106
|
+
async function resolveControllerAndAuth(_options) {
|
|
107
|
+
const controllerUrl = await resolveControllerUrl();
|
|
108
|
+
if (!controllerUrl) {
|
|
109
|
+
throw new Error('Controller URL is required. Run "aifabrix login" first.');
|
|
110
|
+
}
|
|
111
|
+
const normalized = normalizeControllerUrl(controllerUrl);
|
|
112
|
+
const deviceToken = await getOrRefreshDeviceToken(normalized);
|
|
113
|
+
if (!deviceToken || !deviceToken.token) {
|
|
114
|
+
throw new Error(
|
|
115
|
+
`Not authenticated for controller: ${controllerUrl}. ` +
|
|
116
|
+
'Run "aifabrix login" and try again.'
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
return {
|
|
120
|
+
controllerUrl: deviceToken.controller || normalized,
|
|
121
|
+
authConfig: { type: 'bearer', token: deviceToken.token }
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
async function resolveHeaderContext() {
|
|
126
|
+
const env = await resolveEnvironment();
|
|
127
|
+
const controllerUrl = await resolveControllerUrl();
|
|
128
|
+
const normalized = normalizeControllerUrl(controllerUrl);
|
|
129
|
+
return { environment: env || 'dev', controllerUrl: normalized };
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* @param {Object} options
|
|
134
|
+
* @returns {Object}
|
|
135
|
+
*/
|
|
136
|
+
function buildCreatePayload(options) {
|
|
137
|
+
let base = {};
|
|
138
|
+
if (options.file) {
|
|
139
|
+
base = readResourceTypeCreateFile(options.file);
|
|
140
|
+
}
|
|
141
|
+
const payload = { ...base };
|
|
142
|
+
if (options.key) payload.key = options.key;
|
|
143
|
+
if (options.displayName) payload.displayName = options.displayName;
|
|
144
|
+
if (options.description !== undefined) payload.description = options.description;
|
|
145
|
+
if (options.category) payload.category = options.category;
|
|
146
|
+
if (options.defaultRiskLevel) payload.defaultRiskLevel = options.defaultRiskLevel;
|
|
147
|
+
if (options.status) payload.status = options.status;
|
|
148
|
+
payload.key = requireResourceTypeKey(payload.key);
|
|
149
|
+
if (!payload.displayName) {
|
|
150
|
+
throw new Error('displayName is required (--display-name <name> or in --file).');
|
|
151
|
+
}
|
|
152
|
+
return payload;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* @param {Object} response
|
|
157
|
+
* @returns {any}
|
|
158
|
+
*/
|
|
159
|
+
function unwrapControllerData(response) {
|
|
160
|
+
return response?.data?.data ?? response?.data ?? response;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* @param {import('commander').Command} rt
|
|
165
|
+
*/
|
|
166
|
+
/**
|
|
167
|
+
* @param {Object[]} rows
|
|
168
|
+
* @param {string} controllerUrl
|
|
169
|
+
* @param {Object} authConfig
|
|
170
|
+
* @returns {Promise<{ created: number, existed: number, total: number }>}
|
|
171
|
+
*/
|
|
172
|
+
async function importResourceTypeRows(rows, controllerUrl, authConfig) {
|
|
173
|
+
let created = 0;
|
|
174
|
+
let existed = 0;
|
|
175
|
+
for (const row of rows) {
|
|
176
|
+
const payload = { ...row };
|
|
177
|
+
payload.key = requireResourceTypeKey(payload.key);
|
|
178
|
+
const out = await createResourceTypeIdempotent(controllerUrl, authConfig, payload);
|
|
179
|
+
if (out.created) {
|
|
180
|
+
created += 1;
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
existed += 1;
|
|
184
|
+
}
|
|
185
|
+
return { created, existed, total: rows.length };
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function setupResourceTypeImportCommand(rt) {
|
|
189
|
+
rt
|
|
190
|
+
.command('import')
|
|
191
|
+
.description('Import resource types from baseline catalog JSON (idempotent)')
|
|
192
|
+
.addHelpText('after', RESOURCE_TYPE_IMPORT_HELP_AFTER)
|
|
193
|
+
.requiredOption('--file <path>', 'Baseline catalog (resourceTypes[]) or JSON array')
|
|
194
|
+
.action(async(options) => {
|
|
195
|
+
try {
|
|
196
|
+
const { controllerUrl, authConfig } = await resolveControllerAndAuth(options);
|
|
197
|
+
const rows = readResourceTypeCatalogFile(options.file);
|
|
198
|
+
const summary = await importResourceTypeRows(rows, controllerUrl, authConfig);
|
|
199
|
+
logger.log(
|
|
200
|
+
formatSuccessLine(
|
|
201
|
+
`Resource types imported: ${summary.total} total ` +
|
|
202
|
+
`(${summary.created} created, ${summary.existed} already existed)`
|
|
203
|
+
)
|
|
204
|
+
);
|
|
205
|
+
} catch (e) {
|
|
206
|
+
logger.error(formatBlockingError(e.message));
|
|
207
|
+
process.exit(1);
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function setupResourceTypeCreateCommand(rt) {
|
|
213
|
+
rt
|
|
214
|
+
.command('create')
|
|
215
|
+
.description('Create resource type (idempotent; success if it already exists)')
|
|
216
|
+
.addHelpText('after', RESOURCE_TYPE_CREATE_HELP_AFTER)
|
|
217
|
+
.option('--file <path>', 'Read resource type create payload from JSON file')
|
|
218
|
+
.option('--key <key>', 'Catalog key (lowercase letters, digits, hyphens)')
|
|
219
|
+
.option('--display-name <name>', 'Display name')
|
|
220
|
+
.option('--description <text>', 'Description')
|
|
221
|
+
.option(
|
|
222
|
+
'--category <category>',
|
|
223
|
+
'business | collaboration | governance | content | communication | people'
|
|
224
|
+
)
|
|
225
|
+
.option('--default-risk-level <level>', 'low | medium | high | critical')
|
|
226
|
+
.option('--status <status>', 'draft | active | deprecated | retired')
|
|
227
|
+
.action(async(options) => {
|
|
228
|
+
try {
|
|
229
|
+
const { controllerUrl, authConfig } = await resolveControllerAndAuth(options);
|
|
230
|
+
const payload = buildCreatePayload(options);
|
|
231
|
+
const out = await createResourceTypeIdempotent(controllerUrl, authConfig, payload);
|
|
232
|
+
const row = unwrapControllerData(out.response);
|
|
233
|
+
const category = row.category || payload.category || 'business';
|
|
234
|
+
const risk = row.defaultRiskLevel || payload.defaultRiskLevel || 'medium';
|
|
235
|
+
if (out.created) {
|
|
236
|
+
logger.log(
|
|
237
|
+
formatSuccessLine(`Resource type created: ${row.key} (category: ${category}, risk: ${risk})`)
|
|
238
|
+
);
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
logger.log(formatSuccessLine(`Resource type exists: ${row.key} (category: ${category}, risk: ${risk})`));
|
|
242
|
+
logger.log(infoLine('No changes were needed.'));
|
|
243
|
+
} catch (e) {
|
|
244
|
+
logger.error(formatBlockingError(e.message));
|
|
245
|
+
process.exit(1);
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function setupResourceTypeGetCommand(rt) {
|
|
251
|
+
rt
|
|
252
|
+
.command('get <resourceTypeIdOrKey>')
|
|
253
|
+
.description('Get resource type by id or key')
|
|
254
|
+
.addHelpText('after', RESOURCE_TYPE_GET_HELP_AFTER)
|
|
255
|
+
.action(async(resourceTypeIdOrKey, options) => {
|
|
256
|
+
try {
|
|
257
|
+
const { environment, controllerUrl: headerControllerUrl } = await resolveHeaderContext();
|
|
258
|
+
const { controllerUrl, authConfig } = await resolveControllerAndAuth(options);
|
|
259
|
+
const res = await getResourceType(controllerUrl, authConfig, String(resourceTypeIdOrKey).trim());
|
|
260
|
+
const row = unwrapControllerData(res);
|
|
261
|
+
logger.log(
|
|
262
|
+
chalk.bold(`\n🏷️ Resource type in ${environment} environment (${headerControllerUrl}):\n`)
|
|
263
|
+
);
|
|
264
|
+
logger.log(headerKeyValue('Key:', row.key || '—'));
|
|
265
|
+
logger.log(headerKeyValue('Display:', row.displayName || '—'));
|
|
266
|
+
logger.log(headerKeyValue('Category:', row.category || '—'));
|
|
267
|
+
logger.log(headerKeyValue('Default risk:', row.defaultRiskLevel || '—'));
|
|
268
|
+
logger.log(headerKeyValue('Status:', row.status || '—'));
|
|
269
|
+
if (row.description) {
|
|
270
|
+
logger.log(headerKeyValue('Description:', row.description));
|
|
271
|
+
}
|
|
272
|
+
logger.log('');
|
|
273
|
+
} catch (e) {
|
|
274
|
+
logger.error(formatBlockingError(e.message));
|
|
275
|
+
process.exit(1);
|
|
276
|
+
}
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* @param {Array<Object>} items
|
|
282
|
+
* @param {string} environment
|
|
283
|
+
* @param {string} controllerUrl
|
|
284
|
+
*/
|
|
285
|
+
function displayResourceTypeList(items, environment, controllerUrl) {
|
|
286
|
+
logger.log(
|
|
287
|
+
chalk.bold(`\n🏷️ Resource types in ${environment} environment (${controllerUrl}):\n`)
|
|
288
|
+
);
|
|
289
|
+
if (!Array.isArray(items) || items.length === 0) {
|
|
290
|
+
logger.log(chalk.gray(' No resource types found.\n'));
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
const KEY_WIDTH = 22;
|
|
295
|
+
const DISPLAY_WIDTH = 30;
|
|
296
|
+
const CATEGORY_WIDTH = 16;
|
|
297
|
+
const RISK_WIDTH = 10;
|
|
298
|
+
const STATUS_WIDTH = 12;
|
|
299
|
+
const SEP_LEN = KEY_WIDTH + DISPLAY_WIDTH + CATEGORY_WIDTH + RISK_WIDTH + STATUS_WIDTH;
|
|
300
|
+
|
|
301
|
+
const keyCol = 'Key'.padEnd(KEY_WIDTH);
|
|
302
|
+
const displayCol = 'Display'.padEnd(DISPLAY_WIDTH);
|
|
303
|
+
const categoryCol = 'Category'.padEnd(CATEGORY_WIDTH);
|
|
304
|
+
const riskCol = 'Risk'.padEnd(RISK_WIDTH);
|
|
305
|
+
const statusCol = 'Status'.padEnd(STATUS_WIDTH);
|
|
306
|
+
logger.log(chalk.gray(`${keyCol}${displayCol}${categoryCol}${riskCol}${statusCol}`));
|
|
307
|
+
logger.log(chalk.gray('-'.repeat(SEP_LEN)));
|
|
308
|
+
|
|
309
|
+
items.forEach((d) => {
|
|
310
|
+
const key = (d?.key ?? '—').toString().padEnd(KEY_WIDTH);
|
|
311
|
+
const displayName = (d?.displayName ?? '—').toString().padEnd(DISPLAY_WIDTH);
|
|
312
|
+
const category = (d?.category ?? '—').toString().padEnd(CATEGORY_WIDTH);
|
|
313
|
+
const risk = (d?.defaultRiskLevel ?? '—').toString().padEnd(RISK_WIDTH);
|
|
314
|
+
const status = (d?.status ?? '—').toString().padEnd(STATUS_WIDTH);
|
|
315
|
+
logger.log(`${key}${displayName}${category}${risk}${status}`);
|
|
316
|
+
});
|
|
317
|
+
logger.log('');
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
function setupResourceTypeListCommand(rt) {
|
|
321
|
+
rt
|
|
322
|
+
.command('list')
|
|
323
|
+
.description('List resource types')
|
|
324
|
+
.addHelpText('after', RESOURCE_TYPE_LIST_HELP_AFTER)
|
|
325
|
+
.option('--page <n>', 'Page', (v) => parseInt(v, 10))
|
|
326
|
+
.option('--page-size <n>', 'Page size', (v) => parseInt(v, 10))
|
|
327
|
+
.option('--search <text>', 'Search by key/displayName/description')
|
|
328
|
+
.option('--category <category>', 'Filter by category')
|
|
329
|
+
.option('--status <status>', 'Filter by status')
|
|
330
|
+
.action(async(options) => {
|
|
331
|
+
try {
|
|
332
|
+
const { environment, controllerUrl: headerControllerUrl } = await resolveHeaderContext();
|
|
333
|
+
const { controllerUrl, authConfig } = await resolveControllerAndAuth(options);
|
|
334
|
+
const res = await listResourceTypes(controllerUrl, authConfig, {
|
|
335
|
+
page: options.page,
|
|
336
|
+
pageSize: options.pageSize,
|
|
337
|
+
search: options.search,
|
|
338
|
+
category: options.category,
|
|
339
|
+
status: options.status
|
|
340
|
+
});
|
|
341
|
+
const payload = unwrapControllerData(res);
|
|
342
|
+
const items = payload?.data ?? payload ?? [];
|
|
343
|
+
displayResourceTypeList(items, environment, headerControllerUrl);
|
|
344
|
+
} catch (e) {
|
|
345
|
+
logger.error(formatBlockingError(e.message));
|
|
346
|
+
process.exit(1);
|
|
347
|
+
}
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* @param {import('commander').Command} program
|
|
353
|
+
*/
|
|
354
|
+
function setupResourceTypeCommands(program) {
|
|
355
|
+
const rt = program
|
|
356
|
+
.command('resource-type')
|
|
357
|
+
.description('Manage the Controller Resource Type Catalog (COM)')
|
|
358
|
+
.addHelpText('after', RESOURCE_TYPE_HELP_AFTER);
|
|
359
|
+
setupResourceTypeCreateCommand(rt);
|
|
360
|
+
setupResourceTypeImportCommand(rt);
|
|
361
|
+
setupResourceTypeGetCommand(rt);
|
|
362
|
+
setupResourceTypeListCommand(rt);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
module.exports = {
|
|
366
|
+
setupResourceTypeCommands,
|
|
367
|
+
requireResourceTypeKey,
|
|
368
|
+
buildCreatePayload,
|
|
369
|
+
unwrapControllerData,
|
|
370
|
+
importResourceTypeRows
|
|
371
|
+
};
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview aifabrix secret get – read one secret (local user file or shared-only)
|
|
3
|
+
* @author AI Fabrix Team
|
|
4
|
+
* @version 2.0.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const { getAifabrixSecretsPath } = require('../core/config');
|
|
9
|
+
const { decryptSecretsObject } = require('../core/secrets-load');
|
|
10
|
+
const { loadPrimaryUserSecrets } = require('../utils/secrets-utils');
|
|
11
|
+
const { loadConfiguredSharedSecretsStore } = require('../utils/remote-secrets-loader');
|
|
12
|
+
const remoteDevAuth = require('../utils/remote-dev-auth');
|
|
13
|
+
const devApi = require('../api/dev.api');
|
|
14
|
+
const logger = require('../utils/logger');
|
|
15
|
+
|
|
16
|
+
const REMOTE_NOT_CONFIGURED_MSG =
|
|
17
|
+
'Remote server is not configured. Set remote-server and run "aifabrix dev init" first.';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Human-readable label for which store(s) were queried (paths included for file stores).
|
|
21
|
+
* @param {{ shared?: boolean }} options
|
|
22
|
+
* @returns {Promise<string>}
|
|
23
|
+
*/
|
|
24
|
+
async function resolveSecretsScopeLabel(options) {
|
|
25
|
+
const useSharedOnly = Boolean(options.shared || options['shared']);
|
|
26
|
+
const generalSecretsPath = await getAifabrixSecretsPath();
|
|
27
|
+
|
|
28
|
+
if (useSharedOnly) {
|
|
29
|
+
if (!generalSecretsPath) {
|
|
30
|
+
return 'shared secrets (aifabrix-secrets not configured; run aifabrix secret set-secrets-file <path>)';
|
|
31
|
+
}
|
|
32
|
+
const target = await remoteDevAuth.resolveSharedSecretsEndpoint(generalSecretsPath);
|
|
33
|
+
if (remoteDevAuth.isRemoteSecretsUrl(target)) {
|
|
34
|
+
const host = remoteDevAuth.getSharedSecretsRemoteHostname(target) || target;
|
|
35
|
+
return `shared secrets API (${host})`;
|
|
36
|
+
}
|
|
37
|
+
const resolved = path.isAbsolute(target) ? target : path.resolve(process.cwd(), target);
|
|
38
|
+
return `shared secrets file ${resolved}`;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const pathsUtil = require('../utils/paths');
|
|
42
|
+
const userPath = pathsUtil.getPrimaryUserSecretsLocalPath();
|
|
43
|
+
return `local secrets file ${userPath}`;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* @param {unknown} value
|
|
48
|
+
* @returns {boolean}
|
|
49
|
+
*/
|
|
50
|
+
function isSecretPresent(value) {
|
|
51
|
+
if (value === undefined || value === null) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
return String(value).trim() !== '';
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* @param {Array<{ name?: string, key?: string, value?: unknown }>} items
|
|
59
|
+
* @returns {Record<string, string>}
|
|
60
|
+
*/
|
|
61
|
+
function remoteSecretItemsToMap(items) {
|
|
62
|
+
const raw = {};
|
|
63
|
+
for (const item of items) {
|
|
64
|
+
const name = item?.name || item?.key;
|
|
65
|
+
if (typeof name === 'string' && item.value !== undefined) {
|
|
66
|
+
raw[name] = String(item.value);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return raw;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* @param {string} target
|
|
74
|
+
* @returns {Promise<Record<string, string>>}
|
|
75
|
+
*/
|
|
76
|
+
async function loadRemoteSharedSecretsDecrypted(target) {
|
|
77
|
+
const auth = await remoteDevAuth.getRemoteDevAuth();
|
|
78
|
+
if (!auth) {
|
|
79
|
+
throw new Error(REMOTE_NOT_CONFIGURED_MSG);
|
|
80
|
+
}
|
|
81
|
+
const items = await devApi.listSecrets(
|
|
82
|
+
auth.serverUrl,
|
|
83
|
+
auth.clientCertPem,
|
|
84
|
+
auth.serverCaPem || undefined,
|
|
85
|
+
target
|
|
86
|
+
);
|
|
87
|
+
const label = remoteDevAuth.getSharedSecretsRemoteHostname(target) || 'shared secrets API';
|
|
88
|
+
return decryptSecretsObject(remoteSecretItemsToMap(items), { defaultSourceLabel: label });
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Load shared secrets (file or remote), decrypted.
|
|
93
|
+
* @returns {Promise<Record<string, string>>}
|
|
94
|
+
*/
|
|
95
|
+
async function loadSharedSecretsDecrypted() {
|
|
96
|
+
const generalSecretsPath = await getAifabrixSecretsPath();
|
|
97
|
+
if (!generalSecretsPath) {
|
|
98
|
+
throw new Error('Shared secrets not configured. Set aifabrix-secrets in config.yaml.');
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const target = await remoteDevAuth.resolveSharedSecretsEndpoint(generalSecretsPath);
|
|
102
|
+
if (remoteDevAuth.isRemoteSecretsUrl(target)) {
|
|
103
|
+
return loadRemoteSharedSecretsDecrypted(target);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const raw = await loadConfiguredSharedSecretsStore();
|
|
107
|
+
if (!raw || typeof raw !== 'object') {
|
|
108
|
+
return {};
|
|
109
|
+
}
|
|
110
|
+
const resolvedPath = path.isAbsolute(target) ? target : path.resolve(process.cwd(), target);
|
|
111
|
+
return decryptSecretsObject(raw, { defaultSourceLabel: resolvedPath });
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Load and decrypt the primary user secrets file only (not aifabrix-secrets / shared).
|
|
116
|
+
* @returns {Promise<Record<string, string>>}
|
|
117
|
+
*/
|
|
118
|
+
async function loadLocalUserSecretsDecrypted() {
|
|
119
|
+
const pathsUtil = require('../utils/paths');
|
|
120
|
+
const userPath = pathsUtil.getPrimaryUserSecretsLocalPath();
|
|
121
|
+
const raw = loadPrimaryUserSecrets();
|
|
122
|
+
return decryptSecretsObject(raw || {}, { defaultSourceLabel: userPath });
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Load secrets for lookup: local user file (default) or shared store only (--shared).
|
|
127
|
+
* @param {{ shared?: boolean }} options
|
|
128
|
+
* @returns {Promise<Record<string, string>>}
|
|
129
|
+
*/
|
|
130
|
+
async function loadSecretsForGet(options) {
|
|
131
|
+
if (options.shared || options['shared']) {
|
|
132
|
+
return loadSharedSecretsDecrypted();
|
|
133
|
+
}
|
|
134
|
+
return loadLocalUserSecretsDecrypted();
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Handle secret get command.
|
|
139
|
+
* @param {string} key - Secret key (no kv:// prefix)
|
|
140
|
+
* @param {Object} options
|
|
141
|
+
* @param {boolean} [options.shared] - Shared store only (aifabrix-secrets); default is local user file only
|
|
142
|
+
* @param {boolean} [options.exists] - Exit 0 when present; no stdout (script-friendly)
|
|
143
|
+
* @param {boolean} [options.json] - JSON { key, exists, value }
|
|
144
|
+
* @returns {Promise<{ key: string, exists: boolean, value?: string }>}
|
|
145
|
+
*/
|
|
146
|
+
async function handleSecretsGet(key, options = {}) {
|
|
147
|
+
if (!key || typeof key !== 'string') {
|
|
148
|
+
throw new Error('Secret key is required and must be a string');
|
|
149
|
+
}
|
|
150
|
+
if (key.startsWith('kv://')) {
|
|
151
|
+
throw new Error(
|
|
152
|
+
'Secret key must not start with kv://. Use the key path without the prefix (e.g. hubspot-demo/token).'
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const secrets = await loadSecretsForGet(options);
|
|
157
|
+
const value = secrets[key];
|
|
158
|
+
const present = isSecretPresent(value);
|
|
159
|
+
|
|
160
|
+
if (!present) {
|
|
161
|
+
const scope = await resolveSecretsScopeLabel(options);
|
|
162
|
+
throw new Error(`Secret '${key}' is missing or empty in ${scope}.`);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (options.exists || options['exists']) {
|
|
166
|
+
return { key, exists: true };
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (options.json || options['json']) {
|
|
170
|
+
logger.log(JSON.stringify({ key, exists: true, value: String(value) }));
|
|
171
|
+
return { key, exists: true, value: String(value) };
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
logger.log(String(value));
|
|
175
|
+
return { key, exists: true, value: String(value) };
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
module.exports = {
|
|
179
|
+
handleSecretsGet,
|
|
180
|
+
isSecretPresent,
|
|
181
|
+
loadSecretsForGet,
|
|
182
|
+
loadLocalUserSecretsDecrypted,
|
|
183
|
+
resolveSecretsScopeLabel
|
|
184
|
+
};
|
|
@@ -56,6 +56,8 @@ function listKeysFromYamlFile(filePath) {
|
|
|
56
56
|
* @param {string} filePath - Absolute path
|
|
57
57
|
*/
|
|
58
58
|
function writeEmptySecretsFile(filePath) {
|
|
59
|
+
const { assertWritableSecretsPathForTests } = require('../utils/aifabrix-test-runtime-guard');
|
|
60
|
+
assertWritableSecretsPathForTests(filePath);
|
|
59
61
|
const yamlContent = yaml.dump({}, { indent: 2, lineWidth: -1, noRefs: true, sortKeys: false });
|
|
60
62
|
fs.writeFileSync(filePath, yamlContent, { mode: 0o600 });
|
|
61
63
|
}
|
|
@@ -217,4 +219,4 @@ async function handleSecretsRemoveAll(options) {
|
|
|
217
219
|
await removeAllSharedSecrets(generalSecretsPath, options);
|
|
218
220
|
}
|
|
219
221
|
|
|
220
|
-
module.exports = { handleSecretsRemoveAll };
|
|
222
|
+
module.exports = { handleSecretsRemoveAll, writeEmptySecretsFile };
|