@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
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
|
};
|
|
@@ -53,6 +53,12 @@ function formatDockerInfrastructureFailure(detail) {
|
|
|
53
53
|
*/
|
|
54
54
|
async function checkDockerAvailability() {
|
|
55
55
|
await ensureDevCertsIfNeededForRemoteDocker();
|
|
56
|
+
try {
|
|
57
|
+
const { ensureDevCertFreshIfDue } = require('../commands/dev-refresh');
|
|
58
|
+
await ensureDevCertFreshIfDue({ quiet: true });
|
|
59
|
+
} catch {
|
|
60
|
+
// Best-effort renew for remote Docker TLS; docker check reports real failures
|
|
61
|
+
}
|
|
56
62
|
try {
|
|
57
63
|
await dockerUtils.ensureDockerAndCompose();
|
|
58
64
|
} catch (error) {
|
|
@@ -181,7 +181,7 @@ function generatePgAdminConfig(infraDir, postgresPassword) {
|
|
|
181
181
|
* @returns {string} Escaped string
|
|
182
182
|
*/
|
|
183
183
|
function escapePgString(s) {
|
|
184
|
-
if (
|
|
184
|
+
if (typeof s !== 'string') return '';
|
|
185
185
|
return s.replace(/'/g, '\'\'');
|
|
186
186
|
}
|
|
187
187
|
|
|
@@ -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
|
/**
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
'use strict';
|
|
9
9
|
|
|
10
|
-
/** @typedef {'VERIFIED'|'FAILED'|'NOT_VERIFIED'} LifecycleVerdict */
|
|
10
|
+
/** @typedef {'VERIFIED'|'FAILED'|'NOT_VERIFIED'|'NOT_APPLICABLE'} LifecycleVerdict */
|
|
11
11
|
|
|
12
12
|
/** @typedef {'BRONZE'|'SILVER'|'GOLD'|'PLATINUM'|'NONE'} CertificationLevel */
|
|
13
13
|
|
|
@@ -16,7 +16,8 @@
|
|
|
16
16
|
const VERDICT = Object.freeze({
|
|
17
17
|
VERIFIED: 'VERIFIED',
|
|
18
18
|
FAILED: 'FAILED',
|
|
19
|
-
NOT_VERIFIED: 'NOT_VERIFIED'
|
|
19
|
+
NOT_VERIFIED: 'NOT_VERIFIED',
|
|
20
|
+
NOT_APPLICABLE: 'NOT_APPLICABLE'
|
|
20
21
|
});
|
|
21
22
|
|
|
22
23
|
const CERTIFICATION_LEVEL = Object.freeze({
|
|
@@ -58,9 +58,13 @@ function displayHeroMetric(label, percent) {
|
|
|
58
58
|
logger.log('');
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
function displayVerdictLine(verdict, verifiedLabel, failedLabel) {
|
|
61
|
+
function displayVerdictLine(verdict, verifiedLabel, failedLabel, notApplicableLabel) {
|
|
62
62
|
if (verdict === VERDICT.VERIFIED) {
|
|
63
63
|
logger.log(formatSuccessParagraph(verifiedLabel));
|
|
64
|
+
} else if (verdict === VERDICT.NOT_APPLICABLE) {
|
|
65
|
+
logger.log(
|
|
66
|
+
formatSuccessParagraph(notApplicableLabel || 'NOT APPLICABLE')
|
|
67
|
+
);
|
|
64
68
|
} else {
|
|
65
69
|
logger.log(formatBlockingError(failedLabel));
|
|
66
70
|
}
|
|
@@ -196,7 +200,12 @@ function displayVerifyGovernanceTTY(systemKey, result, opts = {}) {
|
|
|
196
200
|
logger.log(chalk.white('Enforcement Scenarios'));
|
|
197
201
|
logger.log(chalk.cyan.bold(`${passed}/${total} Passed`));
|
|
198
202
|
logger.log('');
|
|
199
|
-
displayVerdictLine(
|
|
203
|
+
displayVerdictLine(
|
|
204
|
+
result.verdict,
|
|
205
|
+
'GOVERNANCE VERIFIED',
|
|
206
|
+
'GOVERNANCE FAILED',
|
|
207
|
+
'GOVERNANCE NOT APPLICABLE'
|
|
208
|
+
);
|
|
200
209
|
if (opts.details === true) {
|
|
201
210
|
displayGovernanceVerboseDetails(result);
|
|
202
211
|
}
|
|
@@ -209,6 +218,9 @@ function formatPillarLine(label, verdict) {
|
|
|
209
218
|
if (verdict === VERDICT.FAILED) {
|
|
210
219
|
return `${label.padEnd(24)}${failureGlyph()} FAILED`;
|
|
211
220
|
}
|
|
221
|
+
if (verdict === VERDICT.NOT_APPLICABLE) {
|
|
222
|
+
return `${label.padEnd(24)}— NOT APPLICABLE`;
|
|
223
|
+
}
|
|
212
224
|
return `${label.padEnd(24)}— NOT VERIFIED`;
|
|
213
225
|
}
|
|
214
226
|
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* @param {string} bearerToken
|
|
13
|
-
* @returns {{ type: 'bearer', token: string }}
|
|
13
|
+
* @returns {{ type: 'bearer', token: string, preserveBearer: true }}
|
|
14
14
|
*/
|
|
15
15
|
function buildBearerAuthConfig(bearerToken) {
|
|
16
16
|
if (!bearerToken || typeof bearerToken !== 'string') {
|
|
@@ -20,7 +20,8 @@ function buildBearerAuthConfig(bearerToken) {
|
|
|
20
20
|
if (!token) {
|
|
21
21
|
throw new Error('Bearer token is required');
|
|
22
22
|
}
|
|
23
|
-
|
|
23
|
+
// Token-forward: caller JWT must reach dataplane CIP/pipeline unchanged (no API_KEY swap).
|
|
24
|
+
return { type: 'bearer', token, preserveBearer: true };
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
/**
|
|
@@ -40,6 +40,21 @@ const CAPABILITIES = Object.freeze([
|
|
|
40
40
|
{ method: 'POST', route: '/systems/:systemKey/certify/:pillar', handlerId: 'runCertifyPillar', operationType: 'certify', mutating: true },
|
|
41
41
|
{ method: 'GET', route: '/systems/:systemKey/lifecycle', handlerId: 'getLifecycleReport', operationType: 'certify.read', mutating: false },
|
|
42
42
|
{ method: 'POST', route: '/systems/:systemKey/upload', handlerId: 'runUpload', operationType: 'apply.dev', mutating: true },
|
|
43
|
+
{ method: 'POST', route: '/systems/:systemKey/deploy', handlerId: 'runDeploySystem', operationType: 'apply.prod', mutating: true },
|
|
44
|
+
{
|
|
45
|
+
method: 'POST',
|
|
46
|
+
route: '/systems/:systemKey/datasources/:datasourceKey/protection/upload',
|
|
47
|
+
handlerId: 'runProtectionUpload',
|
|
48
|
+
operationType: 'apply.protection',
|
|
49
|
+
mutating: true
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
method: 'POST',
|
|
53
|
+
route: '/systems/:systemKey/datasources/:datasourceKey/protection/create',
|
|
54
|
+
handlerId: 'runProtectionCreate',
|
|
55
|
+
operationType: 'apply.protection',
|
|
56
|
+
mutating: true
|
|
57
|
+
},
|
|
43
58
|
{ method: 'POST', route: '/systems/:systemKey/template/materialize', handlerId: 'materializeTemplate', operationType: 'template', mutating: true },
|
|
44
59
|
{ method: 'GET', route: '/systems/:systemKey/workspace/status', handlerId: 'getWorkspaceStatus', operationType: 'workspace.read', mutating: false },
|
|
45
60
|
{ method: 'POST', route: '/systems/:systemKey/workspace/diff', handlerId: 'runWorkspaceDiff', operationType: 'workspace.read', mutating: false },
|
|
@@ -49,7 +64,11 @@ const CAPABILITIES = Object.freeze([
|
|
|
49
64
|
{ method: 'GET', route: '/systems/:systemKey/repository/status', handlerId: 'getRepositoryStatus', operationType: 'repository.read', mutating: false },
|
|
50
65
|
{ method: 'POST', route: '/systems/:systemKey/repository/dispatch-pipeline', handlerId: 'runRepositoryDispatchPipeline', operationType: 'repository', mutating: true },
|
|
51
66
|
{ method: 'GET', route: '/health', handlerId: 'health', operationType: 'infra', mutating: false },
|
|
52
|
-
{ method: 'GET', route: '/health/ready', handlerId: 'ready', operationType: 'infra', mutating: false }
|
|
67
|
+
{ method: 'GET', route: '/health/ready', handlerId: 'ready', operationType: 'infra', mutating: false },
|
|
68
|
+
{ method: 'GET', route: '/evidence/:roleKey/metadata', handlerId: 'getEvidenceMetadata', operationType: 'evidence.read', mutating: false },
|
|
69
|
+
{ method: 'GET', route: '/evidence/:roleKey/download', handlerId: 'downloadEvidence', operationType: 'evidence.read', mutating: false },
|
|
70
|
+
{ method: 'POST', route: '/evidence/:roleKey/upload', handlerId: 'uploadEvidenceCandidates', operationType: 'evidence.write', mutating: true },
|
|
71
|
+
{ method: 'POST', route: '/evidence/:roleKey/activate', handlerId: 'activateEvidenceCandidates', operationType: 'evidence.activate', mutating: true }
|
|
53
72
|
]);
|
|
54
73
|
|
|
55
74
|
/**
|
|
@@ -22,6 +22,7 @@ function mergeProgrammaticOptions(ctx, options = {}) {
|
|
|
22
22
|
authConfig: auth.authConfig,
|
|
23
23
|
dataplaneUrl: auth.dataplaneUrl,
|
|
24
24
|
environment: auth.environment,
|
|
25
|
+
controllerUrl: ctx.controllerUrl || options.controllerUrl,
|
|
25
26
|
silentResolve: true,
|
|
26
27
|
minimal: options.minimal !== false
|
|
27
28
|
};
|
|
@@ -19,6 +19,21 @@ function resolveEnterpriseMcpSystemKey() {
|
|
|
19
19
|
return (process.env.ENTERPRISE_MCP_SYSTEM_KEY || 'enterprise-integration-lifecycle').trim();
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
/**
|
|
23
|
+
* COM-generated Enterprise MCP tools sometimes use OpenAPI operationId forms
|
|
24
|
+
* (e.g. repository.getrepositorystatus) instead of canonical capability keys
|
|
25
|
+
* (repository.status). Map canonical → published name when present.
|
|
26
|
+
*
|
|
27
|
+
* @type {Record<string, string>}
|
|
28
|
+
*/
|
|
29
|
+
const ENTERPRISE_MCP_TOOL_ALIASES = {
|
|
30
|
+
'repository.status': 'repository.getrepositorystatus',
|
|
31
|
+
'repository.sync': 'repository.runrepositorysync',
|
|
32
|
+
'repository.createReview': 'repository.runrepositorycreatereview',
|
|
33
|
+
'repository.dispatchPipeline': 'repository.runrepositorydispatchpipeline',
|
|
34
|
+
'template.materializeWorkspace': 'template.runwizard'
|
|
35
|
+
};
|
|
36
|
+
|
|
22
37
|
/**
|
|
23
38
|
* @param {string} capabilityKey
|
|
24
39
|
* @returns {{ resourceType: string, toolName: string }}
|
|
@@ -29,9 +44,10 @@ function parseCapabilityKey(capabilityKey) {
|
|
|
29
44
|
if (dotIndex <= 0) {
|
|
30
45
|
throw new Error('capabilityKey must be resourceType.operation form');
|
|
31
46
|
}
|
|
47
|
+
const toolName = ENTERPRISE_MCP_TOOL_ALIASES[key] || key;
|
|
32
48
|
return {
|
|
33
49
|
resourceType: key.slice(0, dotIndex),
|
|
34
|
-
toolName
|
|
50
|
+
toolName
|
|
35
51
|
};
|
|
36
52
|
}
|
|
37
53
|
|
|
@@ -42,7 +58,7 @@ function parseCapabilityKey(capabilityKey) {
|
|
|
42
58
|
* @returns {string}
|
|
43
59
|
*/
|
|
44
60
|
function buildMcpExecutePath(systemKey, resourceType, toolName) {
|
|
45
|
-
return `/api/v1/mcp/${encodeURIComponent(systemKey)}/${encodeURIComponent(resourceType)}/tools/${encodeURIComponent(toolName)}/execute`;
|
|
61
|
+
return `/api/v1/mcp/servers/${encodeURIComponent(systemKey)}/${encodeURIComponent(resourceType)}/tools/${encodeURIComponent(toolName)}/execute`;
|
|
46
62
|
}
|
|
47
63
|
|
|
48
64
|
/**
|
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
const workspaceContext = require('./workspace-context');
|
|
8
8
|
const runUpload = require('./run-upload');
|
|
9
|
+
const runDeploy = require('./run-deploy');
|
|
10
|
+
const runProtection = require('./run-protection');
|
|
9
11
|
const runWizard = require('./run-wizard');
|
|
10
12
|
const runRepair = require('./run-repair');
|
|
11
13
|
const runValidate = require('./run-validate');
|
|
@@ -29,6 +31,8 @@ const enterpriseMcpClient = require('./enterprise-mcp-client');
|
|
|
29
31
|
module.exports = {
|
|
30
32
|
...workspaceContext,
|
|
31
33
|
...runUpload,
|
|
34
|
+
...runDeploy,
|
|
35
|
+
...runProtection,
|
|
32
36
|
...runWizard,
|
|
33
37
|
...runRepair,
|
|
34
38
|
...runValidate,
|
|
@@ -33,7 +33,7 @@ const { runWithWorkspaceContext } = require('./workspace-context');
|
|
|
33
33
|
|
|
34
34
|
/**
|
|
35
35
|
* @param {import('./workspace-context').WorkspaceContext} ctx
|
|
36
|
-
* @param {{ sectionKey: string, datasourceKey?: string, intent: string, patch: Object, mode: string, sectionReadToken
|
|
36
|
+
* @param {{ sectionKey: string, datasourceKey?: string, intent: string, patch: Object, mode: string, sectionReadToken?: string, dryRun?: boolean }} body
|
|
37
37
|
*/
|
|
38
38
|
async function patchManifestSection(ctx, body) {
|
|
39
39
|
return runWithWorkspaceContext(ctx, async() => {
|
|
@@ -43,10 +43,11 @@ async function patchManifestSection(ctx, body) {
|
|
|
43
43
|
|
|
44
44
|
const loaded = loadTargetDocument(ctx, def.target, body.datasourceKey);
|
|
45
45
|
const beforeValue = extractSectionValue(loaded.doc, def);
|
|
46
|
-
|
|
46
|
+
assertSectionReadToken(body, beforeValue);
|
|
47
47
|
|
|
48
48
|
const draft = JSON.parse(JSON.stringify(loaded.doc));
|
|
49
|
-
|
|
49
|
+
const patchValue = normalizeSectionPatch(def, body.patch);
|
|
50
|
+
injectSectionValue(draft, def, patchValue, body.mode === 'replace' ? 'replace' : 'merge');
|
|
50
51
|
validateDraftDocument(def.target, draft);
|
|
51
52
|
|
|
52
53
|
const afterValue = extractSectionValue(draft, def);
|
|
@@ -58,6 +59,47 @@ async function patchManifestSection(ctx, body) {
|
|
|
58
59
|
});
|
|
59
60
|
}
|
|
60
61
|
|
|
62
|
+
/**
|
|
63
|
+
* Scalar single-path sections (resourceType, entityType, syncBridge, …) accept
|
|
64
|
+
* `{ value: <scalar> }` or `{ <leaf>: <scalar> }` because OpenAPI types `patch` as object.
|
|
65
|
+
*
|
|
66
|
+
* @param {import('./manifest-section-registry-data').SectionDefinition} def
|
|
67
|
+
* @param {Object} patch
|
|
68
|
+
* @returns {*}
|
|
69
|
+
*/
|
|
70
|
+
function normalizeSectionPatch(def, patch) {
|
|
71
|
+
if (!def || !Array.isArray(def.paths) || def.paths.length !== 1) {
|
|
72
|
+
return patch;
|
|
73
|
+
}
|
|
74
|
+
if (!patch || typeof patch !== 'object' || Array.isArray(patch)) {
|
|
75
|
+
return patch;
|
|
76
|
+
}
|
|
77
|
+
const keys = Object.keys(patch);
|
|
78
|
+
if (keys.length !== 1) {
|
|
79
|
+
return patch;
|
|
80
|
+
}
|
|
81
|
+
const leaf = def.paths[0].includes('.') ? def.paths[0].split('.').pop() : def.paths[0];
|
|
82
|
+
if (keys[0] === 'value' || keys[0] === leaf) {
|
|
83
|
+
return patch[keys[0]];
|
|
84
|
+
}
|
|
85
|
+
return patch;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* When sectionReadToken is omitted, trust the freshly loaded section value
|
|
90
|
+
* (CLI patch-section parity — plan 496.2). Explicit tokens still verify.
|
|
91
|
+
*
|
|
92
|
+
* @param {Object} body
|
|
93
|
+
* @param {*} beforeValue
|
|
94
|
+
*/
|
|
95
|
+
function assertSectionReadToken(body, beforeValue) {
|
|
96
|
+
const token = typeof body.sectionReadToken === 'string' ? body.sectionReadToken.trim() : '';
|
|
97
|
+
if (!token) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
verifyReadToken({ ...body, sectionReadToken: token }, beforeValue);
|
|
101
|
+
}
|
|
102
|
+
|
|
61
103
|
/**
|
|
62
104
|
* @param {Object} body
|
|
63
105
|
* @param {*} beforeValue
|
|
@@ -162,11 +204,6 @@ function assertPatchRequest(body) {
|
|
|
162
204
|
err.statusCode = 400;
|
|
163
205
|
throw err;
|
|
164
206
|
}
|
|
165
|
-
if (!body.sectionReadToken) {
|
|
166
|
-
const err = new Error('sectionReadToken is required — GET the section first');
|
|
167
|
-
err.statusCode = 400;
|
|
168
|
-
throw err;
|
|
169
|
-
}
|
|
170
207
|
if (body.mode !== 'merge' && body.mode !== 'replace') {
|
|
171
208
|
const err = new Error('mode must be merge or replace');
|
|
172
209
|
err.statusCode = 400;
|
|
@@ -248,5 +285,7 @@ function buildRiskHints(sectionKey, patch, downstream) {
|
|
|
248
285
|
}
|
|
249
286
|
|
|
250
287
|
module.exports = {
|
|
251
|
-
patchManifestSection
|
|
288
|
+
patchManifestSection,
|
|
289
|
+
normalizeSectionPatch,
|
|
290
|
+
assertSectionReadToken
|
|
252
291
|
};
|
|
@@ -226,11 +226,12 @@ const SECTION_DEFINITIONS = Object.freeze({
|
|
|
226
226
|
},
|
|
227
227
|
'datasource.dimensions': {
|
|
228
228
|
target: 'datasource',
|
|
229
|
-
|
|
229
|
+
// Canonical root is top-level `dimensions` (fieldMappings.dimensions removed).
|
|
230
|
+
paths: ['dimensions'],
|
|
230
231
|
mutable: true,
|
|
231
232
|
required: false,
|
|
232
233
|
sourceOfTruth: true,
|
|
233
|
-
repairHooks: [
|
|
234
|
+
repairHooks: []
|
|
234
235
|
},
|
|
235
236
|
'datasource.abac': {
|
|
236
237
|
target: 'datasource',
|
|
@@ -22,6 +22,15 @@ const SCHEMA_DIR = path.join(__dirname, '..', 'schema');
|
|
|
22
22
|
let systemSchemaDoc = null;
|
|
23
23
|
/** @type {Object|null} */
|
|
24
24
|
let datasourceSchemaDoc = null;
|
|
25
|
+
const PROTOTYPE_POLLUTION_KEYS = new Set(['__proto__', 'prototype', 'constructor']);
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @param {string} part
|
|
29
|
+
* @returns {boolean}
|
|
30
|
+
*/
|
|
31
|
+
function isSafePathPart(part) {
|
|
32
|
+
return typeof part === 'string' && part.length > 0 && !PROTOTYPE_POLLUTION_KEYS.has(part);
|
|
33
|
+
}
|
|
25
34
|
|
|
26
35
|
function getSystemSchemaDoc() {
|
|
27
36
|
if (!systemSchemaDoc) {
|
|
@@ -90,10 +99,18 @@ function getPathValue(doc, dottedPath) {
|
|
|
90
99
|
*/
|
|
91
100
|
function setPathValue(doc, dottedPath, value) {
|
|
92
101
|
const parts = dottedPath.split('.');
|
|
102
|
+
for (const part of parts) {
|
|
103
|
+
if (!isSafePathPart(part)) {
|
|
104
|
+
const err = new Error(`Unsafe path segment: ${part}`);
|
|
105
|
+
err.statusCode = 400;
|
|
106
|
+
throw err;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
93
109
|
let current = doc;
|
|
94
110
|
for (let i = 0; i < parts.length - 1; i += 1) {
|
|
95
111
|
const part = parts[i];
|
|
96
|
-
|
|
112
|
+
const next = Object.prototype.hasOwnProperty.call(current, part) ? current[part] : undefined;
|
|
113
|
+
if (next === null || next === undefined || typeof next !== 'object' || Array.isArray(next)) {
|
|
97
114
|
current[part] = {};
|
|
98
115
|
}
|
|
99
116
|
current = current[part];
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenAPI result schemas for deploy and protection apply routes.
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Split from openapi-result-schemas for file-size limits
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const { frozenObject, schemaRef } = require('./openapi-schema-helpers');
|
|
12
|
+
|
|
13
|
+
/** @type {Record<string, Object>} */
|
|
14
|
+
const OPENAPI_APPLY_RESULT_SCHEMAS = {
|
|
15
|
+
DeployResultData: frozenObject(
|
|
16
|
+
{
|
|
17
|
+
deployed: { type: 'boolean' },
|
|
18
|
+
deploymentId: { type: 'string' },
|
|
19
|
+
environment: { type: 'string' },
|
|
20
|
+
systemKey: schemaRef('SystemKey')
|
|
21
|
+
},
|
|
22
|
+
['deployed']
|
|
23
|
+
),
|
|
24
|
+
ProtectionUploadData: frozenObject(
|
|
25
|
+
{
|
|
26
|
+
datasourceKey: schemaRef('DatasourceKey'),
|
|
27
|
+
uploaded: { type: 'boolean' },
|
|
28
|
+
dryRun: { type: 'boolean' }
|
|
29
|
+
},
|
|
30
|
+
['datasourceKey', 'uploaded', 'dryRun']
|
|
31
|
+
),
|
|
32
|
+
ProtectionCreateData: frozenObject(
|
|
33
|
+
{
|
|
34
|
+
datasourceKey: schemaRef('DatasourceKey'),
|
|
35
|
+
created: { type: 'boolean' },
|
|
36
|
+
dryRun: { type: 'boolean' }
|
|
37
|
+
},
|
|
38
|
+
['datasourceKey', 'created', 'dryRun']
|
|
39
|
+
)
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
module.exports = {
|
|
43
|
+
OPENAPI_APPLY_RESULT_SCHEMAS
|
|
44
|
+
};
|