@aifabrix/builder 2.50.0 → 2.51.1
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/plans/Done/157.1-security-quality-violations-by-type.csv +374 -0
- package/.cursor/rules/assistant-driven-integration-build.mdc +40 -0
- package/integration/hubspot-test/create-hubspot.js +1 -16
- package/jest.isolated-projects.js +77 -1
- package/jest.projects.js +5 -426
- package/lib/api/assistants.api.js +67 -0
- package/lib/api/datasources-extended.api.js +6 -6
- package/lib/api/evidence-authoring-helpers.js +267 -0
- package/lib/api/evidence-authoring.api.js +337 -0
- package/lib/api/evidence-kinds.api.js +128 -0
- package/lib/api/evidence.api.js +57 -1
- package/lib/api/index.js +24 -7
- package/lib/api/pipeline.api.js +47 -3
- package/lib/api/records-bulk.api.js +28 -3
- package/lib/api/resource-types.api.js +4 -4
- package/lib/api/roles.api.js +121 -0
- package/lib/api/types/evidence-kinds.types.js +42 -0
- package/lib/api/types/evidence.types.js +156 -8
- package/lib/api/types/roles.types.js +36 -0
- package/lib/api/work.api.js +283 -0
- package/lib/app/certification-verify-rows.js +1 -1
- package/lib/app/run-deploy-job.js +108 -0
- package/lib/app/run-helpers.js +10 -3
- package/lib/app/run.js +8 -0
- package/lib/app/show.js +2 -2
- package/lib/certification/merge-certification-from-artifact.js +1 -1
- package/lib/channels/add-channel.js +54 -23
- package/lib/channels/approval-guides/chatgpt.js +8 -7
- package/lib/channels/approval-guides/microsoft-copilot.js +7 -8
- package/lib/channels/channel-artifact-generator.js +16 -3
- package/lib/channels/channel-credential.js +3 -1
- package/lib/channels/channel-probe-evidence.js +79 -0
- package/lib/channels/channel-probe.js +265 -13
- package/lib/channels/channel-runtime-resolver.js +120 -29
- package/lib/channels/channel-status-display.js +44 -0
- package/lib/channels/channel-targets.js +7 -0
- package/lib/channels/chatgpt-runtime-contract.js +29 -0
- package/lib/channels/microsoft-copilot-package.js +280 -0
- package/lib/channels/runtime-tool-catalog.js +165 -0
- package/lib/cli/index.js +6 -0
- package/lib/cli/setup-app.js +26 -5
- package/lib/cli/setup-dev.js +23 -7
- package/lib/cli/setup-external-system-help.js +8 -2
- package/lib/cli/setup-external-system.js +12 -0
- package/lib/cli/setup-utility-help-after.js +12 -0
- package/lib/cli/setup-utility-validate.js +41 -2
- package/lib/commands/app-test.js +2 -14
- package/lib/commands/datasource-load-export-cli.js +6 -1
- package/lib/commands/deploy-gate-failure-details.js +23 -0
- package/lib/commands/deploy-gate-orchestrator.js +64 -18
- package/lib/commands/dev-cli-handlers.js +6 -3
- package/lib/commands/dev-down.js +2 -6
- package/lib/commands/dev-init.js +7 -109
- package/lib/commands/dev-refresh.js +197 -0
- package/lib/commands/evidence-kind.js +478 -0
- package/lib/commands/governance-command-action.js +4 -2
- package/lib/commands/governance-generate-external.js +56 -21
- package/lib/commands/lifecycle-external.js +10 -4
- package/lib/commands/repair-datasource-apply.js +10 -1
- package/lib/commands/repair-datasource-run.js +4 -2
- package/lib/commands/repair-datasource-test-payload.js +80 -19
- package/lib/commands/repair-datasource-webhooks-sync-bridge.js +42 -3
- package/lib/commands/repair-internal.js +9 -1
- package/lib/commands/repair-openapi-export.js +1 -1
- package/lib/commands/repair-openapi-sync.js +43 -18
- package/lib/commands/resource-type.js +101 -18
- package/lib/commands/role-assistant.js +313 -0
- package/lib/commands/role.js +452 -0
- package/lib/commands/setup.js +1 -1
- package/lib/commands/upload-data-sync-finalize.js +5 -4
- package/lib/commands/upload-sidecar-followups.js +144 -47
- package/lib/commands/upload.js +43 -6
- package/lib/commands/validate-json.js +230 -0
- package/lib/commands/verify-governance-combined-external.js +73 -9
- package/lib/commands/verify-governance-db.js +80 -25
- package/lib/commands/verify-governance-external.js +29 -5
- package/lib/commands/verify-operations-step-plan.js +78 -40
- package/lib/commands/wizard-core-helpers.js +7 -3
- package/lib/commands/wizard-core.js +78 -9
- package/lib/core/audit-logger.js +1 -1
- package/lib/core/secrets-load.js +1 -3
- package/lib/datasource/bulk-loader-run-batches.js +4 -2
- package/lib/datasource/bulk-loader-service.js +5 -1
- package/lib/datasource/capability/relate-operations.js +1 -1
- package/lib/datasource/datasource-validate-summary.js +2 -2
- package/lib/datasource/validate.js +13 -6
- package/lib/external-system/deploy-helpers.js +35 -1
- package/lib/external-system/deploy.js +23 -10
- package/lib/external-system/download-helpers.js +111 -2
- package/lib/external-system/download-role-assistant.js +55 -0
- package/lib/external-system/download.js +45 -26
- package/lib/external-system/test-helpers.js +1 -1
- package/lib/external-system/test.js +39 -3
- package/lib/generator/builders.js +3 -0
- package/lib/generator/helpers.js +13 -5
- package/lib/generator/split-variables.js +9 -3
- package/lib/generator/wizard.js +51 -4
- package/lib/infrastructure/helpers-docker-check.js +6 -0
- package/lib/infrastructure/helpers.js +1 -1
- package/lib/lifecycle/access-control-abac.js +121 -0
- package/lib/lifecycle/lifecycle-governance-options.js +4 -1
- package/lib/lifecycle/product-model.js +3 -2
- package/lib/lifecycle/report-display.js +14 -2
- package/lib/programmatic/auth-config.js +3 -2
- package/lib/programmatic/bearer-auth.js +1 -1
- package/lib/programmatic/capability-registry.js +20 -1
- package/lib/programmatic/command-options.js +1 -0
- package/lib/programmatic/enterprise-mcp-client.js +18 -2
- package/lib/programmatic/index.js +4 -0
- package/lib/programmatic/manifest-patch-section.js +48 -9
- package/lib/programmatic/manifest-section-registry-data.js +3 -2
- package/lib/programmatic/manifest-section-registry.js +18 -1
- package/lib/programmatic/openapi-apply-result-schemas.js +44 -0
- package/lib/programmatic/openapi-component-schemas.js +16 -1
- package/lib/programmatic/openapi-description-enricher.js +3 -1
- package/lib/programmatic/openapi-descriptions.js +55 -5
- package/lib/programmatic/openapi-evidence-schemas.js +161 -0
- package/lib/programmatic/openapi-manifest-schemas.js +6 -2
- package/lib/programmatic/openapi-operation-bindings.js +99 -0
- package/lib/programmatic/openapi-request-schemas.js +36 -1
- package/lib/programmatic/openapi-result-schemas.js +29 -12
- package/lib/programmatic/openapi-schema-descriptions-certify.js +5 -1
- package/lib/programmatic/openapi-schema-descriptions-core.js +6 -3
- package/lib/programmatic/openapi-schema-descriptions-evidence.js +156 -0
- package/lib/programmatic/openapi-schema-descriptions-manifest.js +4 -3
- package/lib/programmatic/openapi-schema-descriptions-operations.js +70 -0
- package/lib/programmatic/openapi-schema-helpers.js +16 -1
- package/lib/programmatic/openapi-spec.js +48 -29
- package/lib/programmatic/orchestration-openapi-meta.js +5 -0
- package/lib/programmatic/request-timeout.js +3 -0
- package/lib/programmatic/route-handler-map.js +89 -2
- package/lib/programmatic/run-certify.js +15 -2
- package/lib/programmatic/run-deploy.js +74 -0
- package/lib/programmatic/run-evidence-authoring.js +80 -0
- package/lib/programmatic/run-protection.js +124 -0
- package/lib/programmatic/run-repository-emcp.js +11 -3
- package/lib/programmatic/run-template-workspace.js +42 -2
- package/lib/programmatic/workspace-context.js +6 -0
- package/lib/protection/auth-context.js +48 -6
- package/lib/protection/paths.js +22 -0
- package/lib/protection/run-protection-create-helpers.js +22 -1
- package/lib/protection/run-protection-create.js +1 -1
- package/lib/protection/sync-after-upload.js +1 -1
- package/lib/resolvers/evidence-kind-file.js +230 -0
- package/lib/resolvers/resource-type-file.js +36 -1
- package/lib/resolvers/role-file.js +227 -0
- package/lib/role-assistant/evidence-sync.js +450 -0
- package/lib/role-assistant/github-workflow.js +96 -0
- package/lib/role-assistant/knowledge-sync.js +465 -0
- package/lib/role-assistant/settings.js +126 -0
- package/lib/role-assistant/test-cases-evaluate.js +170 -0
- package/lib/role-assistant/test-cases-honesty.js +184 -0
- package/lib/role-assistant/test-cases.js +364 -0
- package/lib/role-assistant/test-runner-workhub-answers.js +203 -0
- package/lib/role-assistant/test-runner-workhub.js +385 -0
- package/lib/role-assistant/test-runner.js +500 -0
- package/lib/schema/application-schema.json +36 -2
- package/lib/schema/deployment-rules.yaml +1 -0
- package/lib/schema/external-datasource.schema.json +121 -4
- package/lib/schema/external-system.schema.json +20 -6
- package/lib/schema/infra.parameter.yaml +45 -1
- package/lib/schema/role-assistant-settings.schema.json +108 -0
- package/lib/schema/type/credential-field-registry.json +19 -3
- package/lib/utils/api.js +52 -21
- package/lib/utils/app-path-resolve.js +72 -24
- package/lib/utils/app-register-config.js +4 -3
- package/lib/utils/authentication-shape.js +3 -1
- package/lib/utils/cli-sync-options.js +59 -3
- package/lib/utils/cli-utils.js +11 -3
- package/lib/utils/deployment-validation.js +28 -3
- package/lib/utils/dev-ca-install.js +5 -6
- package/lib/utils/dev-config.js +2 -2
- package/lib/utils/dev-list-sort.js +145 -0
- package/lib/utils/dev-platform-tls.js +0 -63
- package/lib/utils/docker-build.js +46 -27
- package/lib/utils/docker-daemon-tls-ca.js +1 -1
- package/lib/utils/docker-exec.js +91 -6
- package/lib/utils/docker-run-ephemeral.js +55 -0
- package/lib/utils/enterprise-knowledge-paths.js +29 -12
- package/lib/utils/env-copy-keycloak.js +196 -0
- package/lib/utils/env-copy.js +35 -4
- package/lib/utils/error-formatters/error-parser.js +0 -3
- package/lib/utils/external-env-template.js +1 -1
- package/lib/utils/external-system-readiness-compact-blocks.js +28 -1
- package/lib/utils/external-system-readiness-compact-display.js +3 -0
- package/lib/utils/health-check-request.js +2 -3
- package/lib/utils/help-builder.js +4 -0
- package/lib/utils/image-name.js +22 -4
- package/lib/utils/logger.js +37 -4
- package/lib/utils/manifest-source-emit.js +1 -1
- package/lib/utils/paths.js +98 -26
- package/lib/utils/pipeline-upload-auth-retry.js +19 -3
- package/lib/utils/postgres-platform-bootstrap.js +24 -17
- package/lib/utils/postgres-wipe.js +5 -2
- package/lib/utils/remote-dev-auth.js +39 -4
- package/lib/utils/resolve-docker-image-ref.js +36 -6
- package/lib/utils/role-assistant-paths.js +98 -0
- package/lib/utils/schema-loader.js +41 -0
- package/lib/utils/schema-resolver.js +36 -4
- package/lib/utils/token-manager.js +47 -22
- package/lib/utils/upload-sync-options.js +17 -3
- package/lib/utils/url-declarative-resolve-load-doc.js +38 -1
- package/lib/validation/external-manifest-validator.js +31 -8
- package/lib/validation/openapi-contract-surface-validator.js +4 -0
- package/lib/validation/validate-external-file.js +8 -1
- package/lib/validation/validator.js +6 -5
- package/package.json +35 -12
- package/scripts/export-builder-api-evidence.js +3 -3
- package/scripts/lib/plan-actor.js +2 -2
- package/scripts/lib/plan-meta.js +1 -1
- package/scripts/lib/plan-parse.js +1 -1
- package/scripts/lib/plan-prevalidate-gates.js +12 -1
- package/scripts/lib/plan-run-report.js +13 -2
- package/scripts/pnpm/lib/resolve-aifabrix-bin.mjs +10 -10
- package/templates/applications/dataplane/application.yaml +47 -17
- package/templates/applications/dataplane/env.template +28 -9
- package/templates/applications/dataplane/rbac.yaml +78 -2
- package/templates/applications/miso-controller/application.yaml +10 -1
- package/templates/applications/miso-controller/env.template +13 -8
- package/templates/applications/miso-controller/rbac.yaml +72 -0
- package/templates/channels/chatgpt/install.template.md.hbs +42 -24
- package/templates/channels/chatgpt/integration/README.md +10 -7
- package/templates/channels/chatgpt/integration/application.json +2 -2
- package/templates/channels/chatgpt/integration/chatgpt-system.json +3 -3
- package/templates/channels/chatgpt/integration/env.template +1 -1
- package/templates/channels/chatgpt/manifest.template.json.hbs +36 -5
- package/templates/channels/microsoft-copilot/ai-plugin.template.json.hbs +28 -0
- package/templates/channels/microsoft-copilot/declarative-agent.template.json.hbs +22 -0
- package/templates/channels/microsoft-copilot/install.template.md.hbs +32 -22
- package/templates/channels/microsoft-copilot/integration/README.md +9 -7
- package/templates/channels/microsoft-copilot/integration/application.json +2 -2
- package/templates/channels/microsoft-copilot/integration/env.template +1 -1
- package/templates/channels/microsoft-copilot/integration/microsoft-copilot-system.json +7 -6
- package/templates/channels/microsoft-copilot/manifest.template.json.hbs +34 -6
- package/templates/channels/slack/integration/slack-system.json +60 -2
- package/templates/python/requirements.txt +1 -1
|
@@ -0,0 +1,478 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Evidence kind catalog commands (Controller).
|
|
3
|
+
*
|
|
4
|
+
* Commands:
|
|
5
|
+
* - aifabrix evidence-kind create|import|export|get|list
|
|
6
|
+
*
|
|
7
|
+
* Distinct from `aifabrix evidence` (Evidence Fabrix v2 rows).
|
|
8
|
+
*
|
|
9
|
+
* @fileoverview Evidence kind catalog CLI commands
|
|
10
|
+
* @author AI Fabrix Team
|
|
11
|
+
* @version 1.0.0
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
'use strict';
|
|
15
|
+
|
|
16
|
+
const chalk = require('chalk');
|
|
17
|
+
const logger = require('../utils/logger');
|
|
18
|
+
const { resolveControllerUrl } = require('../utils/controller-url');
|
|
19
|
+
const { normalizeControllerUrl, resolveEnvironment } = require('../core/config');
|
|
20
|
+
const { getOrRefreshDeviceToken } = require('../utils/token-manager');
|
|
21
|
+
const {
|
|
22
|
+
readEvidenceKindCreateFile,
|
|
23
|
+
readEvidenceKindCatalogFile,
|
|
24
|
+
writeEvidenceKindCatalogFile,
|
|
25
|
+
mapEvidenceKindFileToApiPayload,
|
|
26
|
+
mapEvidenceKindApiToFileRow
|
|
27
|
+
} = require('../resolvers/evidence-kind-file');
|
|
28
|
+
const {
|
|
29
|
+
formatBlockingError,
|
|
30
|
+
formatSuccessLine,
|
|
31
|
+
infoLine,
|
|
32
|
+
headerKeyValue
|
|
33
|
+
} = require('../utils/cli-layout-chalk');
|
|
34
|
+
const {
|
|
35
|
+
listEvidenceKinds,
|
|
36
|
+
getEvidenceKind,
|
|
37
|
+
createEvidenceKindIdempotent
|
|
38
|
+
} = require('../api/evidence-kinds.api');
|
|
39
|
+
|
|
40
|
+
const EVIDENCE_KIND_KEY_PATTERN = /^[a-z][a-z0-9_]*$/;
|
|
41
|
+
|
|
42
|
+
const EVIDENCE_KIND_HELP_AFTER = `
|
|
43
|
+
|
|
44
|
+
Examples:
|
|
45
|
+
$ aifabrix evidence-kind create --key obligation --display-name "Obligation" --domain governance --purpose "Track commitments"
|
|
46
|
+
$ aifabrix evidence-kind get obligation
|
|
47
|
+
$ aifabrix evidence-kind list --search risk
|
|
48
|
+
|
|
49
|
+
Per-command help: aifabrix evidence-kind <command> --help
|
|
50
|
+
`;
|
|
51
|
+
|
|
52
|
+
const EVIDENCE_KIND_IMPORT_HELP_AFTER = `
|
|
53
|
+
|
|
54
|
+
Examples:
|
|
55
|
+
$ aifabrix evidence-kind import --file ./baseline-evidence-kinds.json
|
|
56
|
+
`;
|
|
57
|
+
|
|
58
|
+
const EVIDENCE_KIND_EXPORT_HELP_AFTER = `
|
|
59
|
+
|
|
60
|
+
Examples:
|
|
61
|
+
$ aifabrix evidence-kind export --file ./evidence-kinds-export.json
|
|
62
|
+
`;
|
|
63
|
+
|
|
64
|
+
const EVIDENCE_KIND_CREATE_HELP_AFTER = `
|
|
65
|
+
|
|
66
|
+
Examples:
|
|
67
|
+
$ aifabrix evidence-kind create --key obligation --display-name "Obligation" --domain governance --purpose "Track commitments"
|
|
68
|
+
$ aifabrix evidence-kind create --key risk --display-name "Risk" --domain governance --purpose "..." --default-severity high
|
|
69
|
+
$ aifabrix evidence-kind create --file ./obligation.json
|
|
70
|
+
`;
|
|
71
|
+
|
|
72
|
+
const EVIDENCE_KIND_GET_HELP_AFTER = `
|
|
73
|
+
|
|
74
|
+
Examples:
|
|
75
|
+
$ aifabrix evidence-kind get obligation
|
|
76
|
+
$ aifabrix evidence-kind get clx1234567890abcdef
|
|
77
|
+
`;
|
|
78
|
+
|
|
79
|
+
const EVIDENCE_KIND_LIST_HELP_AFTER = `
|
|
80
|
+
|
|
81
|
+
Examples:
|
|
82
|
+
$ aifabrix evidence-kind list
|
|
83
|
+
$ aifabrix evidence-kind list --page 1 --page-size 50
|
|
84
|
+
$ aifabrix evidence-kind list --search risk
|
|
85
|
+
`;
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* @param {string} raw
|
|
89
|
+
* @returns {string}
|
|
90
|
+
*/
|
|
91
|
+
function requireEvidenceKindKey(raw) {
|
|
92
|
+
const key = String(raw || '').trim();
|
|
93
|
+
if (!key) {
|
|
94
|
+
throw new Error('Evidence kind key is required (--key <key> or --file <path>).');
|
|
95
|
+
}
|
|
96
|
+
if (!EVIDENCE_KIND_KEY_PATTERN.test(key)) {
|
|
97
|
+
throw new Error(
|
|
98
|
+
'Evidence kind key must start with a lowercase letter and contain only lowercase letters, numbers, and underscores.'
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
return key;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* @param {Object} _options
|
|
106
|
+
* @returns {Promise<{ controllerUrl: string, authConfig: Object }>}
|
|
107
|
+
*/
|
|
108
|
+
async function resolveControllerAndAuth(_options) {
|
|
109
|
+
const controllerUrl = await resolveControllerUrl();
|
|
110
|
+
if (!controllerUrl) {
|
|
111
|
+
throw new Error('Controller URL is required. Run "aifabrix login" first.');
|
|
112
|
+
}
|
|
113
|
+
const normalized = normalizeControllerUrl(controllerUrl);
|
|
114
|
+
const deviceToken = await getOrRefreshDeviceToken(normalized);
|
|
115
|
+
if (!deviceToken || !deviceToken.token) {
|
|
116
|
+
throw new Error(
|
|
117
|
+
`Not authenticated for controller: ${controllerUrl}. ` +
|
|
118
|
+
'Run "aifabrix login" and try again.'
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
return {
|
|
122
|
+
controllerUrl: deviceToken.controller || normalized,
|
|
123
|
+
authConfig: { type: 'bearer', token: deviceToken.token }
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
async function resolveHeaderContext() {
|
|
128
|
+
const env = await resolveEnvironment();
|
|
129
|
+
const controllerUrl = await resolveControllerUrl();
|
|
130
|
+
const normalized = normalizeControllerUrl(controllerUrl);
|
|
131
|
+
return { environment: env || 'dev', controllerUrl: normalized };
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* @param {Object} response
|
|
136
|
+
* @returns {any}
|
|
137
|
+
*/
|
|
138
|
+
function unwrapControllerData(response) {
|
|
139
|
+
return response?.data?.data ?? response?.data ?? response;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Build create payload from flags and optional --file (maps domain → domainKey).
|
|
144
|
+
* @param {Object} options
|
|
145
|
+
* @returns {Object}
|
|
146
|
+
*/
|
|
147
|
+
function buildCreatePayload(options) {
|
|
148
|
+
let base = {};
|
|
149
|
+
if (options.file) {
|
|
150
|
+
base = readEvidenceKindCreateFile(options.file);
|
|
151
|
+
}
|
|
152
|
+
const merged = { ...base };
|
|
153
|
+
if (options.key) merged.key = options.key;
|
|
154
|
+
if (options.displayName) merged.displayName = options.displayName;
|
|
155
|
+
if (options.description !== undefined) merged.description = options.description;
|
|
156
|
+
if (options.purpose !== undefined) merged.purpose = options.purpose;
|
|
157
|
+
if (options.expectedUse !== undefined) merged.expectedUse = options.expectedUse;
|
|
158
|
+
if (options.defaultSeverity) merged.defaultSeverity = options.defaultSeverity;
|
|
159
|
+
if (options.domain) {
|
|
160
|
+
merged.domain = options.domain;
|
|
161
|
+
delete merged.domainKey;
|
|
162
|
+
}
|
|
163
|
+
if (options.file && !options.domain && base.domainKey) {
|
|
164
|
+
return { ...base, key: requireEvidenceKindKey(merged.key || base.key) };
|
|
165
|
+
}
|
|
166
|
+
const payload = mapEvidenceKindFileToApiPayload(
|
|
167
|
+
{
|
|
168
|
+
...merged,
|
|
169
|
+
domain: merged.domain || merged.domainKey
|
|
170
|
+
},
|
|
171
|
+
0
|
|
172
|
+
);
|
|
173
|
+
payload.key = requireEvidenceKindKey(payload.key);
|
|
174
|
+
return payload;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* @param {Object[]} rows
|
|
179
|
+
* @param {string} controllerUrl
|
|
180
|
+
* @param {Object} authConfig
|
|
181
|
+
* @returns {Promise<{ created: number, existed: number, total: number }>}
|
|
182
|
+
*/
|
|
183
|
+
async function importEvidenceKindRows(rows, controllerUrl, authConfig) {
|
|
184
|
+
let created = 0;
|
|
185
|
+
let existed = 0;
|
|
186
|
+
for (const payload of rows) {
|
|
187
|
+
payload.key = requireEvidenceKindKey(payload.key);
|
|
188
|
+
const out = await createEvidenceKindIdempotent(controllerUrl, authConfig, payload);
|
|
189
|
+
if (out.created) {
|
|
190
|
+
created += 1;
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
existed += 1;
|
|
194
|
+
}
|
|
195
|
+
return { created, existed, total: rows.length };
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* @param {string} controllerUrl
|
|
200
|
+
* @param {Object} authConfig
|
|
201
|
+
* @returns {Promise<Object[]>}
|
|
202
|
+
*/
|
|
203
|
+
async function fetchAllEvidenceKinds(controllerUrl, authConfig) {
|
|
204
|
+
const all = [];
|
|
205
|
+
let page = 1;
|
|
206
|
+
const pageSize = 100;
|
|
207
|
+
for (;;) {
|
|
208
|
+
const res = await listEvidenceKinds(controllerUrl, authConfig, { page, pageSize });
|
|
209
|
+
const payload = unwrapControllerData(res);
|
|
210
|
+
const items = payload?.data ?? payload ?? [];
|
|
211
|
+
if (!Array.isArray(items) || items.length === 0) {
|
|
212
|
+
break;
|
|
213
|
+
}
|
|
214
|
+
all.push(...items);
|
|
215
|
+
if (items.length < pageSize) {
|
|
216
|
+
break;
|
|
217
|
+
}
|
|
218
|
+
page += 1;
|
|
219
|
+
}
|
|
220
|
+
return all;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function setupEvidenceKindImportCommand(cmd) {
|
|
224
|
+
cmd
|
|
225
|
+
.command('import')
|
|
226
|
+
.description('Import evidence kinds from baseline JSON (idempotent)')
|
|
227
|
+
.addHelpText('after', EVIDENCE_KIND_IMPORT_HELP_AFTER)
|
|
228
|
+
.requiredOption('--file <path>', 'Baseline catalog (evidenceKinds[]) or JSON array')
|
|
229
|
+
.action(async(options) => {
|
|
230
|
+
try {
|
|
231
|
+
const { controllerUrl, authConfig } = await resolveControllerAndAuth(options);
|
|
232
|
+
const rows = readEvidenceKindCatalogFile(options.file);
|
|
233
|
+
const summary = await importEvidenceKindRows(rows, controllerUrl, authConfig);
|
|
234
|
+
logger.log(
|
|
235
|
+
formatSuccessLine(
|
|
236
|
+
`Evidence kinds imported: ${summary.total} total ` +
|
|
237
|
+
`(${summary.created} created, ${summary.existed} already existed)`
|
|
238
|
+
)
|
|
239
|
+
);
|
|
240
|
+
} catch (e) {
|
|
241
|
+
logger.error(formatBlockingError(e.message));
|
|
242
|
+
process.exit(1);
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function setupEvidenceKindExportCommand(cmd) {
|
|
248
|
+
cmd
|
|
249
|
+
.command('export')
|
|
250
|
+
.description('Export evidence kinds to baseline-shaped JSON')
|
|
251
|
+
.addHelpText('after', EVIDENCE_KIND_EXPORT_HELP_AFTER)
|
|
252
|
+
.requiredOption('--file <path>', 'Output path for baseline catalog JSON')
|
|
253
|
+
.action(async(options) => {
|
|
254
|
+
try {
|
|
255
|
+
const { controllerUrl, authConfig } = await resolveControllerAndAuth(options);
|
|
256
|
+
const records = await fetchAllEvidenceKinds(controllerUrl, authConfig);
|
|
257
|
+
const rows = records.map(mapEvidenceKindApiToFileRow);
|
|
258
|
+
writeEvidenceKindCatalogFile(options.file, rows);
|
|
259
|
+
logger.log(
|
|
260
|
+
formatSuccessLine(`Evidence kinds exported: ${rows.length} written to ${options.file}`)
|
|
261
|
+
);
|
|
262
|
+
} catch (e) {
|
|
263
|
+
logger.error(formatBlockingError(e.message));
|
|
264
|
+
process.exit(1);
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function setupEvidenceKindCreateCommand(cmd) {
|
|
270
|
+
cmd
|
|
271
|
+
.command('create')
|
|
272
|
+
.description('Create evidence kind (idempotent; success if it already exists)')
|
|
273
|
+
.addHelpText('after', EVIDENCE_KIND_CREATE_HELP_AFTER)
|
|
274
|
+
.option('--file <path>', 'Read evidence kind create payload from JSON file')
|
|
275
|
+
.option('--key <key>', 'Catalog key (lowercase letters, digits, underscores)')
|
|
276
|
+
.option('--display-name <name>', 'Display name')
|
|
277
|
+
.option('--domain <domain>', 'Enterprise domain key (e.g. governance, sales)')
|
|
278
|
+
.option('--purpose <text>', 'Evidence kind purpose (required)')
|
|
279
|
+
.option('--expected-use <text>', 'Expected use guidance')
|
|
280
|
+
.option('--default-severity <level>', 'low | medium | high | critical')
|
|
281
|
+
.option('--description <text>', 'Description')
|
|
282
|
+
.action(async(options) => {
|
|
283
|
+
try {
|
|
284
|
+
const { controllerUrl, authConfig } = await resolveControllerAndAuth(options);
|
|
285
|
+
const payload = buildCreatePayload(options);
|
|
286
|
+
const out = await createEvidenceKindIdempotent(controllerUrl, authConfig, payload);
|
|
287
|
+
const row = unwrapControllerData(out.response);
|
|
288
|
+
const domain = row.domainKey || payload.domainKey || '—';
|
|
289
|
+
if (out.created) {
|
|
290
|
+
logger.log(formatSuccessLine(`Evidence kind created: ${row.key} (domain: ${domain})`));
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
logger.log(formatSuccessLine(`Evidence kind exists: ${row.key} (domain: ${domain})`));
|
|
294
|
+
logger.log(infoLine('No changes were needed.'));
|
|
295
|
+
} catch (e) {
|
|
296
|
+
logger.error(formatBlockingError(e.message));
|
|
297
|
+
process.exit(1);
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* @param {object} contribution
|
|
304
|
+
* @returns {string}
|
|
305
|
+
*/
|
|
306
|
+
function formatEvidenceKindContributionLine(contribution) {
|
|
307
|
+
const parts = [
|
|
308
|
+
contribution.key || '—',
|
|
309
|
+
contribution.typeRef || null,
|
|
310
|
+
contribution.referenceValue !== null
|
|
311
|
+
&& contribution.referenceValue !== undefined
|
|
312
|
+
&& contribution.unit
|
|
313
|
+
? `${contribution.referenceValue} ${contribution.unit}`
|
|
314
|
+
: contribution.unit || null,
|
|
315
|
+
contribution.primary ? 'primary' : null,
|
|
316
|
+
contribution.attributionKey || null,
|
|
317
|
+
contribution.attributionBoundary || null
|
|
318
|
+
].filter(Boolean);
|
|
319
|
+
return ` - ${parts.join(' · ')}`;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* @param {object} row
|
|
324
|
+
* @returns {void}
|
|
325
|
+
*/
|
|
326
|
+
function logEvidenceKindContributions(row) {
|
|
327
|
+
const contributions = row?.metadata?.contributions;
|
|
328
|
+
if (!Array.isArray(contributions) || contributions.length === 0) {
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
logger.log(headerKeyValue('Contributions:', `${contributions.length}`));
|
|
332
|
+
contributions.forEach((item) => {
|
|
333
|
+
logger.log(formatEvidenceKindContributionLine(item));
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* @param {object} row
|
|
339
|
+
* @param {string} environment
|
|
340
|
+
* @param {string} controllerUrl
|
|
341
|
+
* @returns {void}
|
|
342
|
+
*/
|
|
343
|
+
function displayEvidenceKindDetail(row, environment, controllerUrl) {
|
|
344
|
+
logger.log(
|
|
345
|
+
chalk.bold(`\n📎 Evidence kind in ${environment} environment (${controllerUrl}):\n`)
|
|
346
|
+
);
|
|
347
|
+
logger.log(headerKeyValue('Key:', row.key || '—'));
|
|
348
|
+
logger.log(headerKeyValue('Display:', row.displayName || '—'));
|
|
349
|
+
logger.log(headerKeyValue('Domain:', row.domainKey || '—'));
|
|
350
|
+
logger.log(headerKeyValue('Purpose:', row.purpose || '—'));
|
|
351
|
+
logger.log(headerKeyValue('Severity:', row.defaultSeverity || '—'));
|
|
352
|
+
logger.log(headerKeyValue('Active:', row.isActive === false ? 'false' : 'true'));
|
|
353
|
+
if (row.source) logger.log(headerKeyValue('Source:', row.source));
|
|
354
|
+
if (row.requiresApproval !== undefined) {
|
|
355
|
+
logger.log(headerKeyValue('Requires approval:', row.requiresApproval ? 'true' : 'false'));
|
|
356
|
+
}
|
|
357
|
+
if (row.expectedUse) logger.log(headerKeyValue('Expected use:', row.expectedUse));
|
|
358
|
+
if (row.description) logger.log(headerKeyValue('Description:', row.description));
|
|
359
|
+
logEvidenceKindContributions(row);
|
|
360
|
+
logger.log('');
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
function setupEvidenceKindGetCommand(cmd) {
|
|
364
|
+
cmd
|
|
365
|
+
.command('get <evidenceKindIdOrKey>')
|
|
366
|
+
.description('Get evidence kind by id or key')
|
|
367
|
+
.addHelpText('after', EVIDENCE_KIND_GET_HELP_AFTER)
|
|
368
|
+
.action(async(evidenceKindIdOrKey, options) => {
|
|
369
|
+
try {
|
|
370
|
+
const { environment, controllerUrl: headerControllerUrl } = await resolveHeaderContext();
|
|
371
|
+
const { controllerUrl, authConfig } = await resolveControllerAndAuth(options);
|
|
372
|
+
const res = await getEvidenceKind(controllerUrl, authConfig, String(evidenceKindIdOrKey).trim());
|
|
373
|
+
const row = unwrapControllerData(res);
|
|
374
|
+
displayEvidenceKindDetail(row, environment, headerControllerUrl);
|
|
375
|
+
} catch (e) {
|
|
376
|
+
logger.error(formatBlockingError(e.message));
|
|
377
|
+
process.exit(1);
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
const EVIDENCE_KIND_LIST_COLUMNS = { key: 24, display: 24, domain: 14, severity: 10, active: 8 };
|
|
383
|
+
|
|
384
|
+
function logEvidenceKindListHeader(columns) {
|
|
385
|
+
const keyCol = 'Key'.padEnd(columns.key);
|
|
386
|
+
const displayCol = 'Display'.padEnd(columns.display);
|
|
387
|
+
const domainCol = 'Domain'.padEnd(columns.domain);
|
|
388
|
+
const severityCol = 'Severity'.padEnd(columns.severity);
|
|
389
|
+
const activeCol = 'Active'.padEnd(columns.active);
|
|
390
|
+
logger.log(chalk.gray(`${keyCol}${displayCol}${domainCol}${severityCol}${activeCol}`));
|
|
391
|
+
logger.log(
|
|
392
|
+
chalk.gray(
|
|
393
|
+
'-'.repeat(
|
|
394
|
+
columns.key + columns.display + columns.domain + columns.severity + columns.active
|
|
395
|
+
)
|
|
396
|
+
)
|
|
397
|
+
);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
function logEvidenceKindListRows(items, columns) {
|
|
401
|
+
items.forEach((d) => {
|
|
402
|
+
const key = (d?.key ?? '—').toString().padEnd(columns.key);
|
|
403
|
+
const displayName = (d?.displayName ?? '—').toString().padEnd(columns.display);
|
|
404
|
+
const domain = (d?.domainKey ?? '—').toString().padEnd(columns.domain);
|
|
405
|
+
const severity = (d?.defaultSeverity ?? '—').toString().padEnd(columns.severity);
|
|
406
|
+
const active = (d?.isActive === false ? 'false' : 'true').padEnd(columns.active);
|
|
407
|
+
logger.log(`${key}${displayName}${domain}${severity}${active}`);
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
function displayEvidenceKindList(items, environment, controllerUrl) {
|
|
412
|
+
logger.log(
|
|
413
|
+
chalk.bold(`\n📎 Evidence kinds in ${environment} environment (${controllerUrl}):\n`)
|
|
414
|
+
);
|
|
415
|
+
if (!Array.isArray(items) || items.length === 0) {
|
|
416
|
+
logger.log(chalk.gray(' No evidence kinds found.\n'));
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
logEvidenceKindListHeader(EVIDENCE_KIND_LIST_COLUMNS);
|
|
420
|
+
logEvidenceKindListRows(items, EVIDENCE_KIND_LIST_COLUMNS);
|
|
421
|
+
logger.log('');
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
function setupEvidenceKindListCommand(cmd) {
|
|
425
|
+
cmd
|
|
426
|
+
.command('list')
|
|
427
|
+
.description('List evidence kinds')
|
|
428
|
+
.addHelpText('after', EVIDENCE_KIND_LIST_HELP_AFTER)
|
|
429
|
+
.option('--page <n>', 'Page', (v) => parseInt(v, 10))
|
|
430
|
+
.option('--page-size <n>', 'Page size', (v) => parseInt(v, 10))
|
|
431
|
+
.option('--search <text>', 'Search by key/displayName/description')
|
|
432
|
+
.option('--domain-key <domain>', 'Filter by domain key')
|
|
433
|
+
.action(async(options) => {
|
|
434
|
+
try {
|
|
435
|
+
const { environment, controllerUrl: headerControllerUrl } = await resolveHeaderContext();
|
|
436
|
+
const { controllerUrl, authConfig } = await resolveControllerAndAuth(options);
|
|
437
|
+
const res = await listEvidenceKinds(controllerUrl, authConfig, {
|
|
438
|
+
page: options.page,
|
|
439
|
+
pageSize: options.pageSize,
|
|
440
|
+
search: options.search,
|
|
441
|
+
domainKey: options.domainKey
|
|
442
|
+
});
|
|
443
|
+
const payload = unwrapControllerData(res);
|
|
444
|
+
const items = payload?.data ?? payload ?? [];
|
|
445
|
+
displayEvidenceKindList(items, environment, headerControllerUrl);
|
|
446
|
+
} catch (e) {
|
|
447
|
+
logger.error(formatBlockingError(e.message));
|
|
448
|
+
process.exit(1);
|
|
449
|
+
}
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* @param {import('commander').Command} program
|
|
455
|
+
*/
|
|
456
|
+
function setupEvidenceKindCommands(program) {
|
|
457
|
+
const cmd = program
|
|
458
|
+
.command('evidence-kind')
|
|
459
|
+
.description('Manage the Controller Evidence Kind Catalog')
|
|
460
|
+
.addHelpText('after', EVIDENCE_KIND_HELP_AFTER);
|
|
461
|
+
setupEvidenceKindCreateCommand(cmd);
|
|
462
|
+
setupEvidenceKindImportCommand(cmd);
|
|
463
|
+
setupEvidenceKindExportCommand(cmd);
|
|
464
|
+
setupEvidenceKindGetCommand(cmd);
|
|
465
|
+
setupEvidenceKindListCommand(cmd);
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
module.exports = {
|
|
469
|
+
setupEvidenceKindCommands,
|
|
470
|
+
requireEvidenceKindKey,
|
|
471
|
+
buildCreatePayload,
|
|
472
|
+
unwrapControllerData,
|
|
473
|
+
importEvidenceKindRows,
|
|
474
|
+
mapEvidenceKindFileToApiPayload,
|
|
475
|
+
mapEvidenceKindApiToFileRow,
|
|
476
|
+
displayEvidenceKindDetail,
|
|
477
|
+
formatEvidenceKindContributionLine
|
|
478
|
+
};
|
|
@@ -14,6 +14,7 @@ const { displayVerifyGovernanceTTY } = require('../lifecycle/report-display');
|
|
|
14
14
|
const { exitCodeFromVerdict } = require('../lifecycle/exit-codes');
|
|
15
15
|
const { buildJsonEnvelope } = require('../lifecycle/json-envelope');
|
|
16
16
|
const { formatSuccessLine } = require('../utils/cli-test-layout-chalk');
|
|
17
|
+
const { cliOptsSkipPublish } = require('../utils/cli-sync-options');
|
|
17
18
|
|
|
18
19
|
/**
|
|
19
20
|
* Commander repeatable-option collector. Splits comma-separated values so both
|
|
@@ -31,11 +32,12 @@ function collectString(value, previous) {
|
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
function normalizeGovernanceOptions(options, cmd) {
|
|
34
|
-
const
|
|
35
|
+
const parentCmd = cmd && cmd.parent ? cmd.parent : null;
|
|
36
|
+
const parent = parentCmd ? parentCmd.opts() : {};
|
|
35
37
|
return {
|
|
36
38
|
env: options.env || parent.env || 'dev',
|
|
37
39
|
verbose: options.verbose === true || parent.verbose === true,
|
|
38
|
-
noPublish: options
|
|
40
|
+
noPublish: cliOptsSkipPublish(options, cmd) || cliOptsSkipPublish(parent, parentCmd),
|
|
39
41
|
force: options.force === true || parent.force === true,
|
|
40
42
|
json: options.json === true || parent.json === true,
|
|
41
43
|
pack: options.pack,
|
|
@@ -12,33 +12,21 @@ const {
|
|
|
12
12
|
const { runWithVerifyStepProgress } = require('../lifecycle/verify-step-progress');
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
* @
|
|
16
|
-
* @param {
|
|
15
|
+
* @param {string[]} targetKeys
|
|
16
|
+
* @param {Object} ctx
|
|
17
17
|
* @param {Object} options
|
|
18
|
-
* @returns {Promise<
|
|
18
|
+
* @returns {Promise<Array>}
|
|
19
19
|
*/
|
|
20
|
-
async function
|
|
21
|
-
const subjects =
|
|
22
|
-
|
|
23
|
-
throw new Error(
|
|
24
|
-
'At least one --subject-user-id or --subject-email is required for governance generate'
|
|
25
|
-
);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const { resolvedKey, keys, authConfig, dataplaneUrl } =
|
|
29
|
-
await resolveGovernanceIntegrationContext(systemKey, options);
|
|
30
|
-
|
|
31
|
-
const profile = (options.certificationProfile || 'bronze').trim().toLowerCase();
|
|
32
|
-
const maxSamples = Number(options.maxSamplesPerPartition) || 25;
|
|
33
|
-
|
|
34
|
-
const results = await runWithVerifyStepProgress(
|
|
20
|
+
async function generatePacksForDatasourceKeys(targetKeys, ctx, options) {
|
|
21
|
+
const { dataplaneUrl, authConfig, resolvedKey, subjects, profile, maxSamples } = ctx;
|
|
22
|
+
return runWithVerifyStepProgress(
|
|
35
23
|
'Generating governance scenario packs',
|
|
36
24
|
async progress => {
|
|
37
25
|
const rows = [];
|
|
38
|
-
for (let index = 0; index <
|
|
39
|
-
const dsKey =
|
|
26
|
+
for (let index = 0; index < targetKeys.length; index += 1) {
|
|
27
|
+
const dsKey = targetKeys[index];
|
|
40
28
|
if (typeof progress.setLabel === 'function') {
|
|
41
|
-
progress.setLabel(`Generating pack: ${dsKey} (${index + 1}/${
|
|
29
|
+
progress.setLabel(`Generating pack: ${dsKey} (${index + 1}/${targetKeys.length})`);
|
|
42
30
|
}
|
|
43
31
|
const row = await generateDatasourceGovernancePack(
|
|
44
32
|
dataplaneUrl,
|
|
@@ -57,6 +45,53 @@ async function runGovernanceGenerateForExternalSystem(systemKey, options = {}) {
|
|
|
57
45
|
},
|
|
58
46
|
options
|
|
59
47
|
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* @async
|
|
52
|
+
* @param {string} systemKey
|
|
53
|
+
* @param {Object} options
|
|
54
|
+
* @returns {Promise<Object>}
|
|
55
|
+
*/
|
|
56
|
+
async function runGovernanceGenerateForExternalSystem(systemKey, options = {}) {
|
|
57
|
+
const subjects = buildSubjectsFromOptions(options);
|
|
58
|
+
if (subjects.length === 0) {
|
|
59
|
+
throw new Error(
|
|
60
|
+
'At least one --subject-user-id or --subject-email is required for governance generate'
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const { resolvedKey, keys, authConfig, dataplaneUrl } =
|
|
65
|
+
await resolveGovernanceIntegrationContext(systemKey, options);
|
|
66
|
+
|
|
67
|
+
const {
|
|
68
|
+
filterAbacRequiredDatasourceKeys
|
|
69
|
+
} = require('../lifecycle/access-control-abac');
|
|
70
|
+
const targetKeys = Array.isArray(options.datasourceKeys) && options.datasourceKeys.length
|
|
71
|
+
? options.datasourceKeys
|
|
72
|
+
: filterAbacRequiredDatasourceKeys(resolvedKey, keys);
|
|
73
|
+
|
|
74
|
+
if (targetKeys.length === 0) {
|
|
75
|
+
return {
|
|
76
|
+
systemKey: resolvedKey,
|
|
77
|
+
command: 'governance generate',
|
|
78
|
+
generated: 0,
|
|
79
|
+
results: []
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const results = await generatePacksForDatasourceKeys(
|
|
84
|
+
targetKeys,
|
|
85
|
+
{
|
|
86
|
+
dataplaneUrl,
|
|
87
|
+
authConfig,
|
|
88
|
+
resolvedKey,
|
|
89
|
+
subjects,
|
|
90
|
+
profile: (options.certificationProfile || 'bronze').trim().toLowerCase(),
|
|
91
|
+
maxSamples: Number(options.maxSamplesPerPartition) || 25
|
|
92
|
+
},
|
|
93
|
+
options
|
|
94
|
+
);
|
|
60
95
|
|
|
61
96
|
return {
|
|
62
97
|
systemKey: resolvedKey,
|
|
@@ -98,13 +98,18 @@ async function runLifecycleGovernanceCombinedIfNeeded(
|
|
|
98
98
|
*/
|
|
99
99
|
async function runMissingVerifyStepsLocally(systemKey, report, options) {
|
|
100
100
|
const runOpts = { ...options, noPublish: true };
|
|
101
|
-
|
|
101
|
+
const pathsUtil = require('../utils/paths');
|
|
102
|
+
const appType = await pathsUtil.detectAppType(systemKey).catch(() => null);
|
|
103
|
+
const isRoleAssistantPackage = appType?.baseDir === 'role-assistant';
|
|
104
|
+
// verify-operations is integration/-only; Role Assistant packages use dataplane lifecycle report.
|
|
105
|
+
if (report.operations?.verdict !== VERDICT.VERIFIED && !isRoleAssistantPackage) {
|
|
102
106
|
await runVerifyOperationsForExternalSystem(systemKey, runOpts);
|
|
103
107
|
}
|
|
104
108
|
if (report.trust?.verdict !== VERDICT.VERIFIED) {
|
|
105
109
|
await runVerifyTrustForExternalSystem(systemKey, runOpts);
|
|
106
110
|
}
|
|
107
|
-
if (report.governance?.verdict !== VERDICT.VERIFIED
|
|
111
|
+
if (report.governance?.verdict !== VERDICT.VERIFIED
|
|
112
|
+
&& report.governance?.verdict !== VERDICT.NOT_APPLICABLE) {
|
|
108
113
|
if (lifecycleHasGovernanceSubjects(options)) {
|
|
109
114
|
const { runVerifyGovernanceCombined } = require('./verify-governance-combined-external');
|
|
110
115
|
await runVerifyGovernanceCombined(
|
|
@@ -243,9 +248,10 @@ async function executeLifecycleWork(systemKey, options = {}) {
|
|
|
243
248
|
async function runLifecycleForExternalSystem(systemKey, options = {}) {
|
|
244
249
|
const pathsUtil = require('../utils/paths');
|
|
245
250
|
const appType = await pathsUtil.detectAppType(systemKey).catch(() => null);
|
|
246
|
-
|
|
251
|
+
const allowedRoots = new Set(['integration', 'role-assistant']);
|
|
252
|
+
if (!appType || !allowedRoots.has(appType.baseDir)) {
|
|
247
253
|
throw new Error(
|
|
248
|
-
'lifecycle applies to external
|
|
254
|
+
'lifecycle applies to external authoring folders only (integration/<systemKey>/ or role-assistant/<roleKey>/).'
|
|
249
255
|
);
|
|
250
256
|
}
|
|
251
257
|
|
|
@@ -84,7 +84,16 @@ function applyBaseDatasourceRepairs(parsed, none, changes, options, helpers) {
|
|
|
84
84
|
updated = helpers.repairMetadataSchemaFromAttributes(parsed, changes) || updated;
|
|
85
85
|
const warnings = Array.isArray(options.warnings) ? options.warnings : [];
|
|
86
86
|
updated = repairWebhookSection(parsed, changes, warnings) || updated;
|
|
87
|
-
updated = repairSyncBridgeSection(parsed, changes, warnings) || updated;
|
|
87
|
+
updated = repairSyncBridgeSection(parsed, changes, warnings, options) || updated;
|
|
88
|
+
if (
|
|
89
|
+
Number.isInteger(options.businessOrder) &&
|
|
90
|
+
options.businessOrder >= 1 &&
|
|
91
|
+
(parsed.businessOrder === undefined || parsed.businessOrder === null)
|
|
92
|
+
) {
|
|
93
|
+
parsed.businessOrder = options.businessOrder;
|
|
94
|
+
changes.push(`Set businessOrder ${options.businessOrder} (absent; datasource repair order)`);
|
|
95
|
+
updated = true;
|
|
96
|
+
}
|
|
88
97
|
collectWebhookSyncBridgeSystemWarnings(parsed, options.systemParsed, warnings);
|
|
89
98
|
return updated;
|
|
90
99
|
}
|
|
@@ -30,7 +30,8 @@ function runDatasourceRepairs(appPath, datasourceFiles, options, dryRun, changes
|
|
|
30
30
|
if (!datasourceFiles || datasourceFiles.length === 0) return false;
|
|
31
31
|
let updated = false;
|
|
32
32
|
const warnings = Array.isArray(context.warnings) ? context.warnings : [];
|
|
33
|
-
for (
|
|
33
|
+
for (let i = 0; i < datasourceFiles.length; i += 1) {
|
|
34
|
+
const fileName = datasourceFiles[i];
|
|
34
35
|
const filePath = path.join(appPath, fileName);
|
|
35
36
|
if (!fs.existsSync(filePath)) continue;
|
|
36
37
|
try {
|
|
@@ -41,7 +42,8 @@ function runDatasourceRepairs(appPath, datasourceFiles, options, dryRun, changes
|
|
|
41
42
|
test: options.test,
|
|
42
43
|
operations: options.operations,
|
|
43
44
|
systemParsed: context.systemParsed,
|
|
44
|
-
warnings
|
|
45
|
+
warnings,
|
|
46
|
+
businessOrder: i + 1
|
|
45
47
|
});
|
|
46
48
|
if (fileUpdated) {
|
|
47
49
|
updated = true;
|