@aifabrix/builder 2.51.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/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.api.js +57 -1
- package/lib/api/index.js +24 -7
- package/lib/api/pipeline.api.js +43 -3
- package/lib/api/records-bulk.api.js +28 -3
- package/lib/api/types/evidence.types.js +156 -8
- package/lib/api/work.api.js +283 -0
- 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/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 +14 -2
- 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 +2 -0
- package/lib/cli/setup-app.js +4 -0
- package/lib/cli/setup-external-system-help.js +8 -2
- package/lib/cli/setup-external-system.js +12 -0
- 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 +19 -17
- package/lib/commands/dev-down.js +2 -6
- package/lib/commands/evidence-kind.js +65 -15
- 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-sync.js +34 -17
- package/lib/commands/role-assistant.js +313 -0
- 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/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/wizard-core-helpers.js +7 -3
- package/lib/commands/wizard-core.js +78 -9
- package/lib/datasource/bulk-loader-run-batches.js +4 -2
- package/lib/datasource/bulk-loader-service.js +5 -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/wizard.js +51 -4
- 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/capability-registry.js +20 -1
- package/lib/programmatic/command-options.js +1 -0
- 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/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 +1 -1
- package/lib/programmatic/openapi-schema-descriptions-certify.js +5 -1
- package/lib/programmatic/openapi-schema-descriptions-core.js +1 -1
- 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-spec.js +47 -28
- 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-template-workspace.js +28 -1
- 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/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 +16 -2
- package/lib/schema/deployment-rules.yaml +1 -0
- package/lib/schema/external-datasource.schema.json +38 -4
- package/lib/schema/external-system.schema.json +4 -4
- package/lib/schema/infra.parameter.yaml +20 -0
- package/lib/schema/role-assistant-settings.schema.json +108 -0
- package/lib/utils/api.js +52 -27
- package/lib/utils/app-path-resolve.js +72 -24
- package/lib/utils/authentication-shape.js +3 -1
- package/lib/utils/deployment-validation.js +28 -3
- 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 +34 -1
- package/lib/utils/external-system-readiness-compact-display.js +3 -0
- package/lib/utils/help-builder.js +1 -0
- package/lib/utils/paths.js +67 -23
- package/lib/utils/pipeline-upload-auth-retry.js +15 -3
- 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 +38 -29
- package/lib/utils/url-declarative-resolve-load-doc.js +38 -1
- package/lib/validation/external-manifest-validator.js +31 -8
- package/lib/validation/validate-external-file.js +8 -1
- package/package.json +2 -1
- package/scripts/export-builder-api-evidence.js +1 -1
- package/templates/applications/dataplane/application.yaml +23 -15
- package/templates/applications/dataplane/env.template +1 -1
- package/templates/applications/dataplane/rbac.yaml +14 -0
- package/templates/applications/miso-controller/application.yaml +1 -1
- package/templates/applications/miso-controller/env.template +3 -1
- 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/.cursor/plans/{157.1-security-quality-violations-by-type.csv → Done/157.1-security-quality-violations-by-type.csv} +0 -0
|
@@ -11,12 +11,45 @@
|
|
|
11
11
|
const {
|
|
12
12
|
formatSuccessLine,
|
|
13
13
|
formatSuccessParagraph,
|
|
14
|
+
formatWarningLine,
|
|
14
15
|
sectionTitle,
|
|
15
16
|
headerKeyValue
|
|
16
17
|
} = require('../utils/cli-test-layout-chalk');
|
|
17
18
|
const logger = require('../utils/logger');
|
|
18
19
|
const { generateExternalReadmeContent } = require('../utils/external-readme');
|
|
19
20
|
const { getAuthCredentialTemplate } = require('../utils/authentication-shape');
|
|
21
|
+
const {
|
|
22
|
+
getCwdIntegrationRoot,
|
|
23
|
+
getCwdBuilderRoot,
|
|
24
|
+
getAppsMaterializationParent
|
|
25
|
+
} = require('../utils/paths');
|
|
26
|
+
const {
|
|
27
|
+
SYSTEM_KIND_ENTERPRISE_KNOWLEDGE,
|
|
28
|
+
getCwdEnterpriseKnowledgeRoot,
|
|
29
|
+
getEnterpriseKnowledgeRoot
|
|
30
|
+
} = require('../utils/enterprise-knowledge-paths');
|
|
31
|
+
const {
|
|
32
|
+
SYSTEM_KIND_DIGITAL_WORKER,
|
|
33
|
+
getCwdRoleAssistantRoot,
|
|
34
|
+
getRoleAssistantRoot
|
|
35
|
+
} = require('../utils/role-assistant-paths');
|
|
36
|
+
const path = require('path');
|
|
37
|
+
|
|
38
|
+
/** Runtime/API fields that must not appear on external-system manifests. */
|
|
39
|
+
const NON_MANIFEST_SYSTEM_KEYS = ['showOpenApiDocs'];
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* True when cwd looks like a product/workspace repo (integration, builder, or EK tree).
|
|
43
|
+
* @returns {boolean}
|
|
44
|
+
*/
|
|
45
|
+
function cwdHasWorkspaceTree() {
|
|
46
|
+
return Boolean(
|
|
47
|
+
getCwdIntegrationRoot() ||
|
|
48
|
+
getCwdBuilderRoot() ||
|
|
49
|
+
getCwdEnterpriseKnowledgeRoot() ||
|
|
50
|
+
getCwdRoleAssistantRoot()
|
|
51
|
+
);
|
|
52
|
+
}
|
|
20
53
|
|
|
21
54
|
/**
|
|
22
55
|
* Validates system type from downloaded application
|
|
@@ -68,6 +101,61 @@ function validateDownloadedData(application, dataSources) {
|
|
|
68
101
|
}
|
|
69
102
|
}
|
|
70
103
|
|
|
104
|
+
/**
|
|
105
|
+
* Strip dataplane runtime fields that are not part of external-system.schema.json.
|
|
106
|
+
* @param {Object} application
|
|
107
|
+
* @returns {Object}
|
|
108
|
+
*/
|
|
109
|
+
function sanitizeDownloadedApplication(application) {
|
|
110
|
+
if (!application || typeof application !== 'object') {
|
|
111
|
+
return application;
|
|
112
|
+
}
|
|
113
|
+
const cleaned = { ...application };
|
|
114
|
+
for (const key of NON_MANIFEST_SYSTEM_KEYS) {
|
|
115
|
+
delete cleaned[key];
|
|
116
|
+
}
|
|
117
|
+
return cleaned;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Download destination:
|
|
122
|
+
* - If cwd has `integration/`, `builder/`, or `enterprise-knowledge/` → write under cwd
|
|
123
|
+
* - Else → `aifabrix-work` / materialization parent
|
|
124
|
+
* Ignores materialization orphans when cwd has a workspace tree so re-download lands in-repo.
|
|
125
|
+
* @param {string} systemKey
|
|
126
|
+
* @param {Object} application
|
|
127
|
+
* @returns {string}
|
|
128
|
+
*/
|
|
129
|
+
function resolveDownloadDestinationPath(systemKey, application) {
|
|
130
|
+
const kind =
|
|
131
|
+
application && typeof application.systemKind === 'string'
|
|
132
|
+
? application.systemKind.trim()
|
|
133
|
+
: '';
|
|
134
|
+
const useCwd = cwdHasWorkspaceTree();
|
|
135
|
+
if (kind === SYSTEM_KIND_DIGITAL_WORKER) {
|
|
136
|
+
if (useCwd) {
|
|
137
|
+
const cwdRoleAssistant = getCwdRoleAssistantRoot();
|
|
138
|
+
const roleAssistantRoot = cwdRoleAssistant || path.join(path.resolve(process.cwd()), 'role-assistant');
|
|
139
|
+
return path.join(roleAssistantRoot, systemKey);
|
|
140
|
+
}
|
|
141
|
+
return path.join(getRoleAssistantRoot(), systemKey);
|
|
142
|
+
}
|
|
143
|
+
if (kind === SYSTEM_KIND_ENTERPRISE_KNOWLEDGE) {
|
|
144
|
+
if (useCwd) {
|
|
145
|
+
const cwdEk = getCwdEnterpriseKnowledgeRoot();
|
|
146
|
+
const ekRoot = cwdEk || path.join(path.resolve(process.cwd()), 'enterprise-knowledge');
|
|
147
|
+
return path.join(ekRoot, systemKey);
|
|
148
|
+
}
|
|
149
|
+
return path.join(getEnterpriseKnowledgeRoot(), systemKey);
|
|
150
|
+
}
|
|
151
|
+
if (useCwd) {
|
|
152
|
+
const cwdInt = getCwdIntegrationRoot();
|
|
153
|
+
const intRoot = cwdInt || path.join(path.resolve(process.cwd()), 'integration');
|
|
154
|
+
return path.join(intRoot, systemKey);
|
|
155
|
+
}
|
|
156
|
+
return path.join(getAppsMaterializationParent(), 'integration', systemKey);
|
|
157
|
+
}
|
|
158
|
+
|
|
71
159
|
function logDownloadCommandHeader(systemKey) {
|
|
72
160
|
logger.log('');
|
|
73
161
|
logger.log(sectionTitle('Download'));
|
|
@@ -83,13 +171,31 @@ function displayDownloadSuccess(systemKey, finalPath, datasourceCount) {
|
|
|
83
171
|
logger.log(headerKeyValue('Location:', finalPath));
|
|
84
172
|
}
|
|
85
173
|
|
|
174
|
+
/**
|
|
175
|
+
* Convert YAML components to JSON after download. On validation failure, keep takeout
|
|
176
|
+
* and warn — do not discard downloaded files.
|
|
177
|
+
* @param {string} systemKey
|
|
178
|
+
* @returns {Promise<{converted: boolean, error?: string}>}
|
|
179
|
+
*/
|
|
86
180
|
async function runConvertToJsonIfRequested(systemKey) {
|
|
87
181
|
const { runConvert } = require('../commands/convert');
|
|
88
182
|
try {
|
|
89
183
|
await runConvert(systemKey, { format: 'json', force: true });
|
|
90
184
|
logger.log(formatSuccessLine('Converted component files to JSON'));
|
|
185
|
+
return { converted: true };
|
|
91
186
|
} catch (convertErr) {
|
|
92
|
-
|
|
187
|
+
const message = convertErr && convertErr.message ? convertErr.message : String(convertErr);
|
|
188
|
+
logger.log(
|
|
189
|
+
formatWarningLine(
|
|
190
|
+
`Download saved files, but convert to JSON failed: ${message}`
|
|
191
|
+
)
|
|
192
|
+
);
|
|
193
|
+
logger.log(
|
|
194
|
+
formatWarningLine(
|
|
195
|
+
'Fix schema errors in the downloaded files, then run: aifabrix convert <systemKey> --format json'
|
|
196
|
+
)
|
|
197
|
+
);
|
|
198
|
+
return { converted: false, error: message };
|
|
93
199
|
}
|
|
94
200
|
}
|
|
95
201
|
|
|
@@ -183,10 +289,13 @@ function generateReadme(systemKey, application, dataSources) {
|
|
|
183
289
|
module.exports = {
|
|
184
290
|
validateSystemType,
|
|
185
291
|
validateDownloadedData,
|
|
292
|
+
sanitizeDownloadedApplication,
|
|
293
|
+
resolveDownloadDestinationPath,
|
|
186
294
|
logDownloadCommandHeader,
|
|
187
295
|
displayDownloadSuccess,
|
|
188
296
|
runConvertToJsonIfRequested,
|
|
189
297
|
generateVariablesYaml,
|
|
190
|
-
generateReadme
|
|
298
|
+
generateReadme,
|
|
299
|
+
NON_MANIFEST_SYSTEM_KEYS
|
|
191
300
|
};
|
|
192
301
|
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Role Assistant sidecar handling during external-system download.
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Post-download evidence/knowledge/workflow actions for digitalWorker systems
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const logger = require('../utils/logger');
|
|
12
|
+
const { formatWarningLine } = require('../utils/cli-test-layout-chalk');
|
|
13
|
+
const { exportRoleAssistantKnowledge, logKnowledgeExportSummary } = require('../role-assistant/knowledge-sync');
|
|
14
|
+
const { exportRoleAssistantEvidence, logRoleAssistantEvidenceExportSummary } = require('../role-assistant/evidence-sync');
|
|
15
|
+
|
|
16
|
+
async function maybeExportRoleAssistantEvidenceArtifacts(systemKey, manifest, dataplaneUrl, authConfig, options) {
|
|
17
|
+
try {
|
|
18
|
+
const evidenceResult = await exportRoleAssistantEvidence({
|
|
19
|
+
systemKey,
|
|
20
|
+
dataplaneUrl,
|
|
21
|
+
authConfig,
|
|
22
|
+
manifest,
|
|
23
|
+
pathOptions: options.pathOptions || {}
|
|
24
|
+
});
|
|
25
|
+
logRoleAssistantEvidenceExportSummary(systemKey, evidenceResult, { verbose: options.verbose === true });
|
|
26
|
+
} catch (evidenceErr) {
|
|
27
|
+
logger.log(formatWarningLine(`Role assistant evidence export skipped: ${evidenceErr.message}`));
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async function maybeExportRoleAssistantKnowledgeArtifacts(systemKey, manifest, dataplaneUrl, authConfig, options) {
|
|
32
|
+
try {
|
|
33
|
+
const knowledgeResult = await exportRoleAssistantKnowledge({
|
|
34
|
+
systemKey,
|
|
35
|
+
dataplaneUrl,
|
|
36
|
+
authConfig,
|
|
37
|
+
manifest,
|
|
38
|
+
environment: options.env || options.environment || 'dev',
|
|
39
|
+
pathOptions: options.pathOptions || {}
|
|
40
|
+
});
|
|
41
|
+
logKnowledgeExportSummary(systemKey, knowledgeResult, { verbose: options.verbose === true });
|
|
42
|
+
} catch (knowledgeErr) {
|
|
43
|
+
logger.log(formatWarningLine(`Role assistant knowledge export skipped: ${knowledgeErr.message}`));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async function runRoleAssistantDownloadSidecars(params) {
|
|
48
|
+
const { systemKey, manifest, dataplaneUrl, authConfig, options = {} } = params;
|
|
49
|
+
await maybeExportRoleAssistantEvidenceArtifacts(systemKey, manifest, dataplaneUrl, authConfig, options);
|
|
50
|
+
await maybeExportRoleAssistantKnowledgeArtifacts(systemKey, manifest, dataplaneUrl, authConfig, options);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
module.exports = {
|
|
54
|
+
runRoleAssistantDownloadSidecars
|
|
55
|
+
};
|
|
@@ -32,7 +32,6 @@ const yaml = require('js-yaml');
|
|
|
32
32
|
const { getExternalSystemConfig } = require('../api/external-systems.api');
|
|
33
33
|
const { getDeploymentAuth, requireBearerForDataplanePipeline } = require('../utils/token-manager');
|
|
34
34
|
const { getConfig } = require('../core/config');
|
|
35
|
-
const { getIntegrationPath } = require('../utils/paths');
|
|
36
35
|
const { retemplateConfigurationForDownload, retemplateAllVariableDefinitions } = require('../utils/configuration-env-resolver');
|
|
37
36
|
const { syncRuntimeConfigurationFromDataplane } = require('../utils/runtime-configuration-download');
|
|
38
37
|
const logger = require('../utils/logger');
|
|
@@ -41,10 +40,13 @@ const generator = require('../generator');
|
|
|
41
40
|
const {
|
|
42
41
|
validateSystemType,
|
|
43
42
|
validateDownloadedData,
|
|
43
|
+
sanitizeDownloadedApplication,
|
|
44
|
+
resolveDownloadDestinationPath,
|
|
44
45
|
logDownloadCommandHeader,
|
|
45
46
|
displayDownloadSuccess,
|
|
46
47
|
runConvertToJsonIfRequested
|
|
47
48
|
} = require('./download-helpers');
|
|
49
|
+
const { runRoleAssistantDownloadSidecars } = require('./download-role-assistant');
|
|
48
50
|
|
|
49
51
|
/**
|
|
50
52
|
* Setup authentication and get dataplane URL
|
|
@@ -117,7 +119,11 @@ async function downloadFullManifest(dataplaneUrl, systemKey, authConfig, options
|
|
|
117
119
|
throw new Error('Application configuration not found in download response');
|
|
118
120
|
}
|
|
119
121
|
|
|
120
|
-
return {
|
|
122
|
+
return {
|
|
123
|
+
application: sanitizeDownloadedApplication(application),
|
|
124
|
+
dataSources,
|
|
125
|
+
version
|
|
126
|
+
};
|
|
121
127
|
}
|
|
122
128
|
|
|
123
129
|
/**
|
|
@@ -304,9 +310,8 @@ async function applyRetemplateToSystemFile(systemKey, systemFilePath) {
|
|
|
304
310
|
* @returns {Promise<string>} Final destination path
|
|
305
311
|
* @throws {Error} If processing fails
|
|
306
312
|
*/
|
|
307
|
-
async function processDownloadedSystem(systemKey, manifest, splitOptions = {}) {
|
|
313
|
+
async function processDownloadedSystem(systemKey, manifest, finalPath, splitOptions = {}) {
|
|
308
314
|
const { application, dataSources, version } = manifest;
|
|
309
|
-
const finalPath = getIntegrationPath(systemKey);
|
|
310
315
|
|
|
311
316
|
logger.log(formatProgress('Creating integration directory…'));
|
|
312
317
|
logger.log(metadata(finalPath));
|
|
@@ -331,6 +336,28 @@ async function processDownloadedSystem(systemKey, manifest, splitOptions = {}) {
|
|
|
331
336
|
return finalPath;
|
|
332
337
|
}
|
|
333
338
|
|
|
339
|
+
async function maybeSyncRuntimeConfigurationForDownload(systemKey, manifest, finalPath, dataplaneUrl, authConfig) {
|
|
340
|
+
try {
|
|
341
|
+
const configSync = await syncRuntimeConfigurationFromDataplane({
|
|
342
|
+
dataplaneUrl,
|
|
343
|
+
authConfig,
|
|
344
|
+
systemKey,
|
|
345
|
+
integrationPath: finalPath,
|
|
346
|
+
dataSources: manifest.dataSources
|
|
347
|
+
});
|
|
348
|
+
if (configSync.merged > 0) {
|
|
349
|
+
const nameList = configSync.names.length ? ` (${configSync.names.join(', ')})` : '';
|
|
350
|
+
logger.log(
|
|
351
|
+
formatSuccessLine(
|
|
352
|
+
`Merged ${configSync.merged} runtime configuration variable(s) into env.template${nameList}.`
|
|
353
|
+
)
|
|
354
|
+
);
|
|
355
|
+
}
|
|
356
|
+
} catch (syncErr) {
|
|
357
|
+
logger.log(formatWarningLine(`Runtime configuration sync skipped: ${syncErr.message}`));
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
334
361
|
/**
|
|
335
362
|
* Post-split download steps: governance packs, optional JSON convert, runtime config sync.
|
|
336
363
|
* @param {Object} params
|
|
@@ -348,7 +375,8 @@ async function finalizeDownloadArtifacts({
|
|
|
348
375
|
finalPath,
|
|
349
376
|
dataplaneUrl,
|
|
350
377
|
authConfig,
|
|
351
|
-
format
|
|
378
|
+
format,
|
|
379
|
+
options = {}
|
|
352
380
|
}) {
|
|
353
381
|
const { downloadGovernanceScenarioPacksFromManifest } = require('../lifecycle/scenario-upload');
|
|
354
382
|
await downloadGovernanceScenarioPacksFromManifest(
|
|
@@ -360,25 +388,14 @@ async function finalizeDownloadArtifacts({
|
|
|
360
388
|
if (format === 'json') {
|
|
361
389
|
await runConvertToJsonIfRequested(systemKey);
|
|
362
390
|
}
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
if (configSync.merged > 0) {
|
|
372
|
-
const nameList = configSync.names.length ? ` (${configSync.names.join(', ')})` : '';
|
|
373
|
-
logger.log(
|
|
374
|
-
formatSuccessLine(
|
|
375
|
-
`Merged ${configSync.merged} runtime configuration variable(s) into env.template${nameList}.`
|
|
376
|
-
)
|
|
377
|
-
);
|
|
378
|
-
}
|
|
379
|
-
} catch (syncErr) {
|
|
380
|
-
logger.log(formatWarningLine(`Runtime configuration sync skipped: ${syncErr.message}`));
|
|
381
|
-
}
|
|
391
|
+
await maybeSyncRuntimeConfigurationForDownload(systemKey, manifest, finalPath, dataplaneUrl, authConfig);
|
|
392
|
+
await runRoleAssistantDownloadSidecars({
|
|
393
|
+
systemKey,
|
|
394
|
+
manifest,
|
|
395
|
+
dataplaneUrl,
|
|
396
|
+
authConfig,
|
|
397
|
+
options
|
|
398
|
+
});
|
|
382
399
|
displayDownloadSuccess(systemKey, finalPath, manifest.dataSources.length);
|
|
383
400
|
}
|
|
384
401
|
|
|
@@ -408,10 +425,11 @@ async function downloadExternalSystem(systemKey, options = {}) {
|
|
|
408
425
|
|
|
409
426
|
const manifest = await downloadFullManifest(dataplaneUrl, systemKey, authConfig, options);
|
|
410
427
|
validateAndLogDownloadedData(manifest.application, manifest.dataSources);
|
|
411
|
-
const finalPath =
|
|
428
|
+
const finalPath = resolveDownloadDestinationPath(systemKey, manifest.application);
|
|
412
429
|
await processDownloadedSystem(
|
|
413
430
|
systemKey,
|
|
414
431
|
manifest,
|
|
432
|
+
finalPath,
|
|
415
433
|
await resolveDownloadSplitOptions(finalPath, options)
|
|
416
434
|
);
|
|
417
435
|
await finalizeDownloadArtifacts({
|
|
@@ -420,7 +438,8 @@ async function downloadExternalSystem(systemKey, options = {}) {
|
|
|
420
438
|
finalPath,
|
|
421
439
|
dataplaneUrl,
|
|
422
440
|
authConfig,
|
|
423
|
-
format
|
|
441
|
+
format,
|
|
442
|
+
options
|
|
424
443
|
});
|
|
425
444
|
} catch (error) {
|
|
426
445
|
throw new Error(`Failed to download external system: ${error.message}`);
|
|
@@ -78,7 +78,7 @@ function validateSystemFilesForTest(systemFiles, results) {
|
|
|
78
78
|
* @param {Function} determineDatasourcesToTest - Function to determine datasources to test
|
|
79
79
|
*/
|
|
80
80
|
function validateDatasourceFilesForTest(datasourceFiles, systemFiles, results, options, validateSingleDatasource, determineDatasourcesToTest) {
|
|
81
|
-
const datasourcesToTest = determineDatasourcesToTest(datasourceFiles, options.datasource);
|
|
81
|
+
const datasourcesToTest = determineDatasourcesToTest(datasourceFiles, options.datasource, options);
|
|
82
82
|
const systemKey = systemFiles.length > 0 ? systemFiles[0].data.key : null;
|
|
83
83
|
|
|
84
84
|
for (const datasourceFile of datasourcesToTest) {
|
|
@@ -39,6 +39,20 @@ const { runSystemLevelTest } = require('./test-system-level');
|
|
|
39
39
|
const { shouldUseSystemLevelIntegrationCall } = require('./integration-test-dispatch');
|
|
40
40
|
const { cliOptsSkipPublish } = require('../utils/cli-sync-options');
|
|
41
41
|
|
|
42
|
+
const EMPTY_DATASOURCE_ALLOWED_KINDS = new Set(['enterpriseKnowledge', 'digitalWorker']);
|
|
43
|
+
|
|
44
|
+
function resolvePrimarySystemKind(systemFiles) {
|
|
45
|
+
if (!Array.isArray(systemFiles) || systemFiles.length === 0) {
|
|
46
|
+
return '';
|
|
47
|
+
}
|
|
48
|
+
const kind = systemFiles[0] && systemFiles[0].data ? systemFiles[0].data.systemKind : '';
|
|
49
|
+
return typeof kind === 'string' ? kind.trim() : '';
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function allowEmptyDatasourcesForKind(systemKind) {
|
|
53
|
+
return EMPTY_DATASOURCE_ALLOWED_KINDS.has(String(systemKind || '').trim());
|
|
54
|
+
}
|
|
55
|
+
|
|
42
56
|
/**
|
|
43
57
|
* Loads and parses application config file
|
|
44
58
|
* @async
|
|
@@ -320,11 +334,25 @@ async function testExternalSystem(appName, options = {}) {
|
|
|
320
334
|
|
|
321
335
|
// Load files
|
|
322
336
|
const { variables: _variables, systemFiles, datasourceFiles } = await loadExternalSystemFiles(appName);
|
|
337
|
+
const systemKind = resolvePrimarySystemKind(systemFiles);
|
|
338
|
+
const allowEmptyDatasources = allowEmptyDatasourcesForKind(systemKind);
|
|
323
339
|
|
|
324
340
|
const results = initializeTestResults();
|
|
325
341
|
|
|
326
342
|
validateSystemFilesForTest(systemFiles, results);
|
|
327
|
-
validateDatasourceFilesForTest(
|
|
343
|
+
validateDatasourceFilesForTest(
|
|
344
|
+
datasourceFiles,
|
|
345
|
+
systemFiles,
|
|
346
|
+
results,
|
|
347
|
+
{ ...options, allowEmptyDatasources, systemKindForEmptyDatasources: systemKind },
|
|
348
|
+
validateSingleDatasource,
|
|
349
|
+
determineDatasourcesToTest
|
|
350
|
+
);
|
|
351
|
+
if (allowEmptyDatasources && results.datasourceResults.length === 0) {
|
|
352
|
+
results.warnings.push(
|
|
353
|
+
`No datasources defined; integration validation is N/A for systemKind "${systemKind}".`
|
|
354
|
+
);
|
|
355
|
+
}
|
|
328
356
|
|
|
329
357
|
results.systemKey = systemFiles.length > 0 ? systemFiles[0].data.key : appName;
|
|
330
358
|
results.appName = appName;
|
|
@@ -383,12 +411,15 @@ async function testExternalSystem(appName, options = {}) {
|
|
|
383
411
|
* @returns {Array} Filtered datasource files
|
|
384
412
|
* @throws {Error} If no datasources found
|
|
385
413
|
*/
|
|
386
|
-
function determineDatasourcesToTest(datasourceFiles, datasourceFilter) {
|
|
414
|
+
function determineDatasourcesToTest(datasourceFiles, datasourceFilter, options = {}) {
|
|
387
415
|
const datasourcesToTest = datasourceFilter
|
|
388
416
|
? datasourceFiles.filter(ds => ds.data.key === datasourceFilter || path.basename(ds.path).includes(datasourceFilter))
|
|
389
417
|
: datasourceFiles;
|
|
390
418
|
|
|
391
419
|
if (datasourcesToTest.length === 0) {
|
|
420
|
+
if (options.allowEmptyDatasources === true) {
|
|
421
|
+
return [];
|
|
422
|
+
}
|
|
392
423
|
throw new Error('No datasources found to test');
|
|
393
424
|
}
|
|
394
425
|
|
|
@@ -429,13 +460,18 @@ async function prepareIntegrationTestEnvironment(appName, options) {
|
|
|
429
460
|
}
|
|
430
461
|
|
|
431
462
|
const systemKey = systemFiles[0].data.key;
|
|
463
|
+
const systemKind = resolvePrimarySystemKind(systemFiles);
|
|
464
|
+
const allowEmptyDatasources = allowEmptyDatasourcesForKind(systemKind);
|
|
432
465
|
|
|
433
466
|
// Setup authentication and dataplane URL
|
|
434
467
|
const config = await getConfig();
|
|
435
468
|
const { authConfig, dataplaneUrl } = await setupIntegrationTestAuth(appName, options, config);
|
|
436
469
|
|
|
437
470
|
// Determine datasources to test
|
|
438
|
-
const datasourcesToTest = determineDatasourcesToTest(datasourceFiles, options.datasource
|
|
471
|
+
const datasourcesToTest = determineDatasourcesToTest(datasourceFiles, options.datasource, {
|
|
472
|
+
allowEmptyDatasources,
|
|
473
|
+
systemKindForEmptyDatasources: systemKind
|
|
474
|
+
});
|
|
439
475
|
|
|
440
476
|
// Load custom payload if provided
|
|
441
477
|
const customPayload = await testHelpers.loadCustomPayload(options.payload);
|
|
@@ -276,6 +276,9 @@ function validateBuildFields(build) {
|
|
|
276
276
|
if (typeof build.imageRunBeat === 'string' && build.imageRunBeat.trim()) {
|
|
277
277
|
buildConfig.imageRunBeat = build.imageRunBeat.trim();
|
|
278
278
|
}
|
|
279
|
+
if (typeof build.deployJob === 'string' && build.deployJob.trim()) {
|
|
280
|
+
buildConfig.deployJob = build.deployJob.trim();
|
|
281
|
+
}
|
|
279
282
|
|
|
280
283
|
return Object.keys(buildConfig).length > 0 ? buildConfig : null;
|
|
281
284
|
}
|
package/lib/generator/wizard.js
CHANGED
|
@@ -213,12 +213,21 @@ async function generateWizardFiles(appName, systemConfig, datasourceConfigs, sys
|
|
|
213
213
|
const fmt = format === 'json' ? 'json' : 'yaml';
|
|
214
214
|
const ext = FORMAT_EXT[fmt] || '.yaml';
|
|
215
215
|
const { appPath, finalSystemKey, updatedSystemConfig, updatedDatasourceConfigs } = await prepareWizardContext(appName, systemConfig, datasourceConfigs);
|
|
216
|
+
const newDatasourceFileNames = await writeDatasourceYamlFiles(appPath, finalSystemKey, updatedDatasourceConfigs, fmt);
|
|
217
|
+
const existingDatasourceFileNames = listExistingDatasourceFileNames(appPath, finalSystemKey, ext);
|
|
218
|
+
const datasourceFileNames = [...new Set([...existingDatasourceFileNames, ...newDatasourceFileNames])];
|
|
219
|
+
const existingDatasourceKeys = datasourceFileNames
|
|
220
|
+
.map((name) => datasourceFileNameToKey(name, finalSystemKey, ext))
|
|
221
|
+
.filter(Boolean);
|
|
216
222
|
const systemConfigWithDataSourcesKeys = {
|
|
217
223
|
...updatedSystemConfig,
|
|
218
|
-
dataSources:
|
|
224
|
+
dataSources: [...new Set([
|
|
225
|
+
...(Array.isArray(updatedSystemConfig.dataSources) ? updatedSystemConfig.dataSources : []),
|
|
226
|
+
...existingDatasourceKeys,
|
|
227
|
+
...updatedDatasourceConfigs.map((ds) => ds.key).filter(Boolean)
|
|
228
|
+
])]
|
|
219
229
|
};
|
|
220
230
|
const systemFilePath = await writeSystemYamlFile(appPath, finalSystemKey, systemConfigWithDataSourcesKeys, fmt);
|
|
221
|
-
const datasourceFileNames = await writeDatasourceYamlFiles(appPath, finalSystemKey, updatedDatasourceConfigs, fmt);
|
|
222
231
|
const systemFileName = `${finalSystemKey}-system${ext}`;
|
|
223
232
|
const configFiles = await generateConfigFilesForWizard({
|
|
224
233
|
appPath,
|
|
@@ -234,7 +243,7 @@ async function generateWizardFiles(appName, systemConfig, datasourceConfigs, sys
|
|
|
234
243
|
return {
|
|
235
244
|
appPath,
|
|
236
245
|
systemFilePath,
|
|
237
|
-
datasourceFilePaths:
|
|
246
|
+
datasourceFilePaths: newDatasourceFileNames.map(name => path.join(appPath, name)),
|
|
238
247
|
...configFiles
|
|
239
248
|
};
|
|
240
249
|
} catch (error) {
|
|
@@ -242,6 +251,40 @@ async function generateWizardFiles(appName, systemConfig, datasourceConfigs, sys
|
|
|
242
251
|
}
|
|
243
252
|
}
|
|
244
253
|
|
|
254
|
+
/**
|
|
255
|
+
* List existing datasource files so add-datasource merges instead of replacing.
|
|
256
|
+
* @param {string} appPath
|
|
257
|
+
* @param {string} finalSystemKey
|
|
258
|
+
* @param {string} ext
|
|
259
|
+
* @returns {string[]}
|
|
260
|
+
*/
|
|
261
|
+
function listExistingDatasourceFileNames(appPath, finalSystemKey, ext) {
|
|
262
|
+
const fsSync = require('fs');
|
|
263
|
+
if (!fsSync.existsSync(appPath)) {
|
|
264
|
+
return [];
|
|
265
|
+
}
|
|
266
|
+
const prefix = `${finalSystemKey}-datasource-`;
|
|
267
|
+
return fsSync
|
|
268
|
+
.readdirSync(appPath)
|
|
269
|
+
.filter((name) => name.startsWith(prefix) && name.endsWith(ext));
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Map `systemKey-datasource-companies.json` → `systemKey-companies`.
|
|
274
|
+
* @param {string} fileName
|
|
275
|
+
* @param {string} finalSystemKey
|
|
276
|
+
* @param {string} ext
|
|
277
|
+
* @returns {string|null}
|
|
278
|
+
*/
|
|
279
|
+
function datasourceFileNameToKey(fileName, finalSystemKey, ext) {
|
|
280
|
+
const prefix = `${finalSystemKey}-datasource-`;
|
|
281
|
+
if (!fileName.startsWith(prefix) || !fileName.endsWith(ext)) {
|
|
282
|
+
return null;
|
|
283
|
+
}
|
|
284
|
+
const segment = fileName.slice(prefix.length, fileName.length - ext.length);
|
|
285
|
+
return segment ? `${finalSystemKey}-${segment}` : null;
|
|
286
|
+
}
|
|
287
|
+
|
|
245
288
|
function mergeAppAndExternalIntegration(variables, appName, systemFileName, datasourceFileNames, systemConfig) {
|
|
246
289
|
if (!variables.app) {
|
|
247
290
|
variables.app = {
|
|
@@ -257,10 +300,14 @@ function mergeAppAndExternalIntegration(variables, appName, systemFileName, data
|
|
|
257
300
|
if (!variables.deployment) {
|
|
258
301
|
variables.deployment = { controllerUrl: '', environment: 'dev' };
|
|
259
302
|
}
|
|
303
|
+
const existingDs = Array.isArray(variables.externalIntegration?.dataSources)
|
|
304
|
+
? variables.externalIntegration.dataSources
|
|
305
|
+
: [];
|
|
306
|
+
const mergedDataSources = [...new Set([...existingDs, ...datasourceFileNames])];
|
|
260
307
|
variables.externalIntegration = {
|
|
261
308
|
schemaBasePath: './',
|
|
262
309
|
systems: [systemFileName],
|
|
263
|
-
dataSources:
|
|
310
|
+
dataSources: mergedDataSources,
|
|
264
311
|
autopublish: true,
|
|
265
312
|
version: systemConfig.version || '1.0.0'
|
|
266
313
|
};
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Parse accessControl.abac from local integration datasource files (505.0).
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
'use strict';
|
|
6
|
+
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const { resolveExternalSystemPath } = require('../utils/app-path-resolve');
|
|
10
|
+
const { resolveApplicationConfigPath } = require('../utils/app-config-resolver');
|
|
11
|
+
const { loadConfigFile } = require('../utils/config-format');
|
|
12
|
+
const { discoverIntegrationFiles, buildEffectiveDatasourceFiles } = require('../commands/repair-internal');
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @param {Object|null|undefined} config
|
|
16
|
+
* @returns {{ applicability: 'required'|'notApplicable', rationale: string|null }}
|
|
17
|
+
*/
|
|
18
|
+
function parseAccessControlAbac(config) {
|
|
19
|
+
const access = config && typeof config === 'object' ? config.accessControl : null;
|
|
20
|
+
const abac = access && typeof access === 'object' ? access.abac : null;
|
|
21
|
+
if (!abac || typeof abac !== 'object') {
|
|
22
|
+
return { applicability: 'required', rationale: null };
|
|
23
|
+
}
|
|
24
|
+
const raw = String(abac.applicability || '').trim();
|
|
25
|
+
const applicability = raw === 'notApplicable' ? 'notApplicable' : 'required';
|
|
26
|
+
const rationale =
|
|
27
|
+
typeof abac.rationale === 'string' && abac.rationale.trim()
|
|
28
|
+
? abac.rationale.trim()
|
|
29
|
+
: null;
|
|
30
|
+
return { applicability, rationale };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @param {string} appPath
|
|
35
|
+
* @returns {Object}
|
|
36
|
+
*/
|
|
37
|
+
function loadApplicationVariables(appPath) {
|
|
38
|
+
try {
|
|
39
|
+
const configPath = resolveApplicationConfigPath(appPath);
|
|
40
|
+
if (!fs.existsSync(configPath)) {
|
|
41
|
+
return {};
|
|
42
|
+
}
|
|
43
|
+
return loadConfigFile(configPath) || {};
|
|
44
|
+
} catch {
|
|
45
|
+
return {};
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* @param {string} filePath
|
|
51
|
+
* @param {Map<string, Object>} map
|
|
52
|
+
*/
|
|
53
|
+
function putDatasourceConfig(filePath, map) {
|
|
54
|
+
if (!fs.existsSync(filePath)) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
const parsed = loadConfigFile(filePath);
|
|
59
|
+
const key = parsed && typeof parsed.key === 'string' ? parsed.key.trim() : '';
|
|
60
|
+
if (key) {
|
|
61
|
+
map.set(key, parsed);
|
|
62
|
+
}
|
|
63
|
+
} catch {
|
|
64
|
+
// skip unreadable datasource files
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* @param {string} systemKey
|
|
70
|
+
* @returns {Map<string, Object>}
|
|
71
|
+
*/
|
|
72
|
+
function loadDatasourceConfigsByKey(systemKey) {
|
|
73
|
+
const appPath = resolveExternalSystemPath(systemKey);
|
|
74
|
+
const map = new Map();
|
|
75
|
+
if (!fs.existsSync(appPath)) {
|
|
76
|
+
return map;
|
|
77
|
+
}
|
|
78
|
+
const variables = loadApplicationVariables(appPath);
|
|
79
|
+
const { datasourceFiles: discovered } = discoverIntegrationFiles(appPath);
|
|
80
|
+
const datasourceFiles = buildEffectiveDatasourceFiles(
|
|
81
|
+
appPath,
|
|
82
|
+
discovered,
|
|
83
|
+
variables.externalIntegration?.dataSources
|
|
84
|
+
);
|
|
85
|
+
for (const fileName of datasourceFiles) {
|
|
86
|
+
putDatasourceConfig(path.join(appPath, fileName), map);
|
|
87
|
+
}
|
|
88
|
+
return map;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* @param {string} systemKey
|
|
93
|
+
* @param {string[]} keys
|
|
94
|
+
* @returns {string[]}
|
|
95
|
+
*/
|
|
96
|
+
function filterAbacRequiredDatasourceKeys(systemKey, keys) {
|
|
97
|
+
const configs = loadDatasourceConfigsByKey(systemKey);
|
|
98
|
+
return (keys || []).filter(key => {
|
|
99
|
+
const abac = parseAccessControlAbac(configs.get(key) || null);
|
|
100
|
+
return abac.applicability !== 'notApplicable';
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* @param {string} systemKey
|
|
106
|
+
* @param {string[]} keys
|
|
107
|
+
* @returns {boolean}
|
|
108
|
+
*/
|
|
109
|
+
function allDatasourcesAbacNotApplicable(systemKey, keys) {
|
|
110
|
+
if (!keys || keys.length === 0) {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
return filterAbacRequiredDatasourceKeys(systemKey, keys).length === 0;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
module.exports = {
|
|
117
|
+
parseAccessControlAbac,
|
|
118
|
+
loadDatasourceConfigsByKey,
|
|
119
|
+
filterAbacRequiredDatasourceKeys,
|
|
120
|
+
allDatasourcesAbacNotApplicable
|
|
121
|
+
};
|
|
@@ -21,7 +21,10 @@ function lifecycleHasGovernanceSubjects(options) {
|
|
|
21
21
|
* @returns {boolean}
|
|
22
22
|
*/
|
|
23
23
|
function lifecycleGovernanceNeedsWork(report) {
|
|
24
|
-
|
|
24
|
+
const verdict = report?.governance?.verdict;
|
|
25
|
+
return (
|
|
26
|
+
verdict !== VERDICT.VERIFIED && verdict !== VERDICT.NOT_APPLICABLE
|
|
27
|
+
);
|
|
25
28
|
}
|
|
26
29
|
|
|
27
30
|
/**
|