@aifabrix/builder 2.46.0 → 2.47.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/.npmrc.token +1 -0
- package/.temp/jest-protection-convert/run-IFN2nv/.protection/hubspot-companies.json +1 -0
- package/.temp/jest-protection-convert/run-IvmKLO/.protection/hubspot-companies.yaml +17 -0
- package/.temp/jest-protection-convert/run-SdvblF/.protection/hubspot-companies.json +1 -0
- package/.temp/jest-protection-convert/run-b51TsW/.protection/hubspot-companies.json +1 -0
- package/.temp/jest-protection-convert/run-fiLmb1/.protection/hubspot-companies.json +1 -0
- package/.temp/jest-protection-convert/run-qYGHMU/.protection/hubspot-companies.yaml +17 -0
- package/.temp/jest-protection-fixtures/hubspot-Mq5re8/hubspot-companies.yaml +17 -0
- package/.temp/jest-protection-fixtures/hubspot-f3u4YL/hubspot-companies.yaml +17 -0
- package/.temp/jest-protection-fixtures/hubspot-iQtd1O/hubspot-companies.yaml +17 -0
- package/.temp/jest-protection-fixtures/hubspot-mdmz5M/hubspot-companies.yaml +17 -0
- package/.temp/jest-protection-fixtures/hubspot-qbKYxQ/hubspot-companies.yaml +17 -0
- package/.temp/jest-protection-fixtures/hubspot-yzlJy6/hubspot-companies.yaml +17 -0
- package/.temp/validation/summary.txt +5 -0
- package/jest.isolated-projects.js +18 -2
- package/jest.projects.js +24 -0
- package/lib/api/dataplane-health.api.js +19 -7
- package/lib/api/lifecycle.api.js +22 -1
- package/lib/api/resource-types.api.js +107 -0
- package/lib/api/runtime-configuration.api.js +72 -0
- package/lib/api/types/resource-types.types.js +45 -0
- package/lib/api/user-groups.api.js +9 -9
- package/lib/api/users.api.js +8 -8
- package/lib/api/wizard.api.js +10 -2
- package/lib/app/down.js +58 -26
- package/lib/app/index.js +2 -2
- package/lib/app/run-resolve-image.js +2 -1
- package/lib/app/run-stop-containers.js +113 -0
- package/lib/app/run.js +1 -31
- package/lib/app/show-display.js +35 -0
- package/lib/app/show.js +32 -1
- package/lib/build/index.js +17 -5
- package/lib/build/miso-controller-npm-sdk-guard.js +25 -0
- package/lib/channels/add-channel.js +348 -0
- package/lib/channels/channel-artifact-generator.js +141 -0
- package/lib/channels/channel-audit.js +101 -0
- package/lib/channels/channel-auth-context.js +37 -0
- package/lib/channels/channel-credential.js +200 -0
- package/lib/channels/channel-display-name.js +64 -0
- package/lib/channels/channel-external-system.js +106 -0
- package/lib/channels/channel-integration-generator.js +274 -0
- package/lib/channels/channel-probe.js +89 -0
- package/lib/channels/channel-runtime-resolver.js +152 -0
- package/lib/channels/channel-status-display.js +141 -0
- package/lib/channels/channel-targets.js +115 -0
- package/lib/cli/index.js +18 -4
- package/lib/cli/infra-guided-auth.js +36 -12
- package/lib/cli/setup-app.js +54 -3
- package/lib/cli/setup-infra-up-dataplane-action.js +2 -2
- package/lib/cli/setup-infra-up-platform-action.js +2 -1
- package/lib/cli/setup-npm.js +59 -0
- package/lib/cli/setup-platform.js +1 -1
- package/lib/cli/setup-secrets.js +1 -1
- package/lib/cli/setup-utility-help-after.js +4 -1
- package/lib/cli/setup-utility-resolve.js +8 -5
- package/lib/commands/app-logs.js +54 -26
- package/lib/commands/app.js +41 -0
- package/lib/commands/auth-status-dataplane-version.js +97 -61
- package/lib/commands/auth-status.js +2 -7
- package/lib/commands/channel.js +58 -0
- package/lib/commands/datasource.js +1 -1
- package/lib/commands/identity-apply-sync.js +49 -8
- package/lib/commands/identity-group-cli.js +66 -26
- package/lib/commands/identity-membership-role-cache.js +58 -37
- package/lib/commands/identity-shared.js +22 -1
- package/lib/commands/identity-user-cli.js +80 -34
- package/lib/commands/login-device.js +11 -3
- package/lib/commands/login.js +8 -3
- package/lib/commands/npm-config.js +103 -0
- package/lib/commands/repair-auth-apply.js +30 -4
- package/lib/commands/repair-auth-config.js +8 -13
- package/lib/commands/repair-datasource-com-v2.js +15 -0
- package/lib/commands/repair-datasource-service-contract.js +206 -0
- package/lib/commands/repair-datasource.js +53 -18
- package/lib/commands/repair-env-template.js +12 -12
- package/lib/commands/repair-openapi-sync.js +26 -4
- package/lib/commands/repair-steps.js +28 -13
- package/lib/commands/repair-system-alignment.js +7 -4
- package/lib/commands/resource-type.js +371 -0
- package/lib/commands/setup-modes.js +1 -1
- package/lib/commands/setup-prompts-platform-mode.js +24 -21
- package/lib/commands/test-trust-external.js +39 -90
- package/lib/commands/up-common.js +33 -1
- package/lib/commands/up-dataplane.js +8 -4
- package/lib/commands/upload.js +24 -3
- package/lib/commands/verify-trust-command-action.js +4 -1
- package/lib/commands/verify-trust-external.js +12 -20
- package/lib/core/config-setup-platform-mode.js +3 -3
- package/lib/core/setup-platform-mode.js +41 -6
- package/lib/datasource/capability/capability-diff-slice.js +2 -2
- package/lib/datasource/capability/capability-manifest.js +254 -0
- package/lib/datasource/capability/capability-resolve.js +3 -4
- package/lib/datasource/capability/copy-operations.js +5 -3
- package/lib/datasource/capability/remove-operations.js +2 -1
- package/lib/datasource/capability/run-capability-copy.js +32 -4
- package/lib/datasource/capability/run-capability-diff.js +3 -3
- package/lib/datasource/capability/run-capability-dimension.js +2 -4
- package/lib/datasource/capability/run-capability-edit.js +4 -7
- package/lib/datasource/capability/run-capability-relate.js +2 -4
- package/lib/datasource/capability/run-capability-remove.js +2 -4
- package/lib/datasource/capability/validate-capability-slice.js +2 -1
- package/lib/datasource/datasource-identifier.js +2 -1
- package/lib/datasource/datasource-validate-display.js +1 -1
- package/lib/datasource/field-reference-validator.js +24 -3
- package/lib/datasource/orphan-profiles-validator.js +98 -0
- package/lib/datasource/validate.js +41 -23
- package/lib/external-system/download-helpers.js +87 -0
- package/lib/external-system/download.js +61 -122
- package/lib/external-system/generator.js +1 -59
- package/lib/external-system/test.js +10 -15
- package/lib/generator/builders.js +11 -1
- package/lib/generator/external-controller-manifest.js +5 -2
- package/lib/generator/split.js +3 -1
- package/lib/generator/wizard.js +1 -28
- package/lib/identity/fk-reference.js +65 -0
- package/lib/identity/identity-apply-core.js +13 -58
- package/lib/identity/identity-apply-phases.js +5 -1
- package/lib/identity/identity-display.js +243 -0
- package/lib/identity/identity-response-helpers.js +52 -0
- package/lib/identity/identity-sync-errors.js +62 -0
- package/lib/identity/resolve-user-id.js +129 -0
- package/lib/identity/username-default.js +31 -0
- package/lib/lifecycle/certification-progress.js +2 -2
- package/lib/lifecycle/report-display-trust.js +70 -0
- package/lib/lifecycle/report-display.js +14 -13
- package/lib/resolvers/datasource-resolver.js +2 -3
- package/lib/resolvers/resource-type-file.js +159 -0
- package/lib/schema/application-schema.json +16 -0
- package/lib/schema/deployment-rules.yaml +2 -1
- package/lib/schema/external-datasource.schema.json +372 -58
- package/lib/schema/external-system.schema.json +331 -2
- package/lib/schema/type/document-storage.json +9 -5
- package/lib/utils/api.js +2 -1
- package/lib/utils/app-run-containers.js +25 -2
- package/lib/utils/authentication-shape.js +224 -0
- package/lib/utils/build-copy.js +36 -5
- package/lib/utils/build-resolve-image.js +66 -12
- package/lib/utils/celery-companion-apps.js +53 -0
- package/lib/utils/cli-utils.js +4 -0
- package/lib/utils/compose-celery-worker.js +23 -0
- package/lib/utils/compose-generate-docker-compose.js +9 -1
- package/lib/utils/configuration-env-resolver.js +36 -0
- package/lib/utils/controller-url.js +4 -1
- package/lib/utils/credential-secrets-env-kv.js +216 -0
- package/lib/utils/credential-secrets-env.js +52 -262
- package/lib/utils/dataplane-resolver.js +4 -115
- package/lib/utils/declarative-url-ports.js +24 -1
- package/lib/utils/dev-platform-tls.js +148 -0
- package/lib/utils/docker-build.js +1 -4
- package/lib/utils/external-env-template.js +10 -3
- package/lib/utils/external-system-validators.js +8 -2
- package/lib/utils/health-check-request.js +114 -0
- package/lib/utils/health-check-url.js +3 -1
- package/lib/utils/health-check.js +1 -113
- package/lib/utils/help-builder.js +3 -0
- package/lib/utils/keycloak-realm-ready.js +5 -1
- package/lib/utils/localhost-public-host.js +31 -0
- package/lib/utils/npm-user-config.js +145 -0
- package/lib/utils/paths.js +25 -0
- package/lib/utils/platform-controller-url.js +58 -4
- package/lib/utils/platform-kv-ref.js +57 -0
- package/lib/utils/runtime-configuration-download.js +189 -0
- package/lib/utils/runtime-configuration-values.js +119 -0
- package/lib/utils/schema-loader.js +19 -4
- package/lib/utils/url-declarative-public-base.js +33 -25
- package/lib/utils/worker-sidecars.js +142 -0
- package/lib/validation/external-manifest-validator.js +2 -0
- package/lib/validation/runtime-configuration-rules.js +98 -0
- package/lib/validation/validate-display-dimensions.js +154 -0
- package/lib/validation/validate-display-sections.js +276 -0
- package/lib/validation/validate-display-steps.js +67 -0
- package/lib/validation/validate-display.js +24 -402
- package/package.json +1 -1
- package/templates/applications/dataplane/application.yaml +5 -0
- package/templates/applications/dataplane/env.template +26 -13
- package/templates/applications/dataplane/rbac.yaml +108 -1
- package/templates/applications/miso-controller/application.yaml +2 -2
- package/templates/applications/miso-controller/env.template +37 -122
- package/templates/applications/miso-controller/rbac.yaml +28 -13
- package/templates/channels/chatgpt/install.template.md.hbs +49 -0
- package/templates/channels/chatgpt/manifest.template.json.hbs +9 -0
- package/templates/channels/microsoft-copilot/install.template.md.hbs +49 -0
- package/templates/channels/microsoft-copilot/manifest.template.json.hbs +8 -0
- package/templates/channels/slack/install.template.md.hbs +49 -0
- package/templates/channels/slack/manifest.template.json.hbs +66 -0
- package/templates/channels/teams-bot/install.template.md.hbs +49 -0
- package/templates/channels/teams-bot/manifest.template.json.hbs +13 -0
- package/templates/channels/web-embed/install.template.md.hbs +49 -0
- package/templates/channels/web-embed/manifest.template.json.hbs +8 -0
- package/templates/python/docker-compose.hbs +56 -0
- package/templates/typescript/docker-compose.hbs +52 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validate exposed.profiles keys against capabilities (346 §13 — no orphan profiles).
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Orphan exposed profile validation for datasource manifests
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const { listCapabilityKeys } = require('./capability/capability-manifest');
|
|
12
|
+
|
|
13
|
+
const FORBIDDEN_ORPHAN_PROFILE_KEYS = new Set(['minimal', 'analytics', 'metadata']);
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @param {string} name
|
|
17
|
+
* @returns {string}
|
|
18
|
+
*/
|
|
19
|
+
function normalizeProfileKey(name) {
|
|
20
|
+
return String(name).trim().toLowerCase();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @param {object} parsed
|
|
25
|
+
* @returns {Set<string>}
|
|
26
|
+
*/
|
|
27
|
+
function operationKeysFromConfig(parsed) {
|
|
28
|
+
const keys = new Set();
|
|
29
|
+
const openapiOps = parsed?.openapi?.operations;
|
|
30
|
+
if (openapiOps && typeof openapiOps === 'object') {
|
|
31
|
+
Object.keys(openapiOps).forEach((k) => keys.add(normalizeProfileKey(k)));
|
|
32
|
+
}
|
|
33
|
+
const cipOps = parsed?.execution?.cip?.operations;
|
|
34
|
+
if (cipOps && typeof cipOps === 'object') {
|
|
35
|
+
Object.keys(cipOps).forEach((k) => keys.add(normalizeProfileKey(k)));
|
|
36
|
+
}
|
|
37
|
+
return keys;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* @param {object} parsed
|
|
42
|
+
* @returns {Set<string>}
|
|
43
|
+
*/
|
|
44
|
+
function allowedExposedProfileKeys(parsed) {
|
|
45
|
+
const allowed = new Set(['default']);
|
|
46
|
+
const capabilityKeys = listCapabilityKeys(parsed?.capabilities).map(normalizeProfileKey);
|
|
47
|
+
if (capabilityKeys.length > 0) {
|
|
48
|
+
capabilityKeys.forEach((k) => allowed.add(k));
|
|
49
|
+
} else {
|
|
50
|
+
operationKeysFromConfig(parsed).forEach((k) => allowed.add(k));
|
|
51
|
+
}
|
|
52
|
+
return allowed;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* @param {object} parsed - Parsed datasource manifest
|
|
57
|
+
* @returns {string[]} Error messages; empty when valid
|
|
58
|
+
*/
|
|
59
|
+
function validateOrphanExposedProfiles(parsed) {
|
|
60
|
+
const errors = [];
|
|
61
|
+
const profiles = parsed?.exposed?.profiles;
|
|
62
|
+
if (!profiles || typeof profiles !== 'object' || Array.isArray(profiles)) {
|
|
63
|
+
return errors;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const allowed = allowedExposedProfileKeys(parsed);
|
|
67
|
+
const orphans = Object.keys(profiles).filter((name) => {
|
|
68
|
+
const normalized = normalizeProfileKey(name);
|
|
69
|
+
return FORBIDDEN_ORPHAN_PROFILE_KEYS.has(normalized) || !allowed.has(normalized);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
if (orphans.length === 0) {
|
|
73
|
+
return errors;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const decorative = orphans.filter((name) =>
|
|
77
|
+
FORBIDDEN_ORPHAN_PROFILE_KEYS.has(normalizeProfileKey(name))
|
|
78
|
+
);
|
|
79
|
+
if (decorative.length > 0) {
|
|
80
|
+
errors.push(
|
|
81
|
+
`exposed.profiles: orphan exposed profiles are forbidden: ${decorative.join(', ')}. ` +
|
|
82
|
+
'Use exposed.profiles.default and one profile per capabilities[].key only.'
|
|
83
|
+
);
|
|
84
|
+
return errors;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
errors.push(
|
|
88
|
+
`exposed.profiles: orphan profile keys must match capabilities[].key or default: ${orphans.join(', ')}. ` +
|
|
89
|
+
`Allowed profile keys: ${[...allowed].sort().join(', ')}.`
|
|
90
|
+
);
|
|
91
|
+
return errors;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
module.exports = {
|
|
95
|
+
FORBIDDEN_ORPHAN_PROFILE_KEYS,
|
|
96
|
+
allowedExposedProfileKeys,
|
|
97
|
+
validateOrphanExposedProfiles
|
|
98
|
+
};
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
const path = require('path');
|
|
12
12
|
const fs = require('fs');
|
|
13
|
+
const { loadConfigFile } = require('../utils/config-format');
|
|
13
14
|
const pathsUtil = require('../utils/paths');
|
|
14
15
|
const {
|
|
15
16
|
datasourceIdentifierMatchesFile,
|
|
@@ -22,7 +23,16 @@ const { validateFieldReferences } = require('./field-reference-validator');
|
|
|
22
23
|
const { validateAbac } = require('./abac-validator');
|
|
23
24
|
const { buildDatasourceValidateSummary } = require('./datasource-validate-summary');
|
|
24
25
|
|
|
25
|
-
const
|
|
26
|
+
const DATASOURCE_CONFIG_EXTENSIONS = new Set(['.json', '.yaml', '.yml']);
|
|
27
|
+
const EXCLUDE_CONFIG_NAMES = new Set([
|
|
28
|
+
'application.json',
|
|
29
|
+
'application.yaml',
|
|
30
|
+
'application.yml',
|
|
31
|
+
'rbac.json',
|
|
32
|
+
'rbac.yaml',
|
|
33
|
+
'package.json',
|
|
34
|
+
'package-lock.json'
|
|
35
|
+
]);
|
|
26
36
|
|
|
27
37
|
/**
|
|
28
38
|
* Resolve identifier to an existing file path, or null.
|
|
@@ -64,11 +74,14 @@ function pickIntegrationAppForDatasourceKey(datasourceKey, appNames) {
|
|
|
64
74
|
* @param {string} fileName
|
|
65
75
|
* @returns {boolean}
|
|
66
76
|
*/
|
|
67
|
-
function
|
|
77
|
+
function shouldScanDatasourceConfigCandidate(fileName) {
|
|
68
78
|
const lower = fileName.toLowerCase();
|
|
69
|
-
|
|
70
|
-
if (
|
|
79
|
+
const ext = path.extname(lower);
|
|
80
|
+
if (!DATASOURCE_CONFIG_EXTENSIONS.has(ext)) return false;
|
|
81
|
+
if (EXCLUDE_CONFIG_NAMES.has(fileName)) return false;
|
|
71
82
|
if (lower.endsWith('-deploy.json') || lower.endsWith('-system.json')) return false;
|
|
83
|
+
if (lower.endsWith('-deploy.yaml') || lower.endsWith('-deploy.yml')) return false;
|
|
84
|
+
if (lower.endsWith('-system.yaml') || lower.endsWith('-system.yml')) return false;
|
|
72
85
|
return true;
|
|
73
86
|
}
|
|
74
87
|
|
|
@@ -86,13 +99,13 @@ function isDatasourceNamedJson(fileName) {
|
|
|
86
99
|
* @param {string} datasourceKey
|
|
87
100
|
* @returns {string[]}
|
|
88
101
|
*/
|
|
89
|
-
function
|
|
102
|
+
function collectConfigPathsMatchingDatasourceKey(dir, scanOrder, datasourceKey) {
|
|
90
103
|
const hits = [];
|
|
91
104
|
for (const name of scanOrder) {
|
|
92
105
|
const full = path.join(dir, name);
|
|
93
106
|
let parsed;
|
|
94
107
|
try {
|
|
95
|
-
parsed =
|
|
108
|
+
parsed = loadConfigFile(full);
|
|
96
109
|
} catch {
|
|
97
110
|
continue;
|
|
98
111
|
}
|
|
@@ -115,14 +128,14 @@ function resolvePathFromIntegrationFolderScan(appName, datasourceKey) {
|
|
|
115
128
|
throw new Error(`Integration folder not found: ${dir}`);
|
|
116
129
|
}
|
|
117
130
|
const entries = fs.readdirSync(dir);
|
|
118
|
-
const
|
|
119
|
-
const prefer =
|
|
120
|
-
const scanOrder = [...prefer, ...
|
|
121
|
-
const hits =
|
|
131
|
+
const configFiles = entries.filter(shouldScanDatasourceConfigCandidate);
|
|
132
|
+
const prefer = configFiles.filter(isDatasourceNamedJson);
|
|
133
|
+
const scanOrder = [...prefer, ...configFiles.filter((f) => !prefer.includes(f))];
|
|
134
|
+
const hits = collectConfigPathsMatchingDatasourceKey(dir, scanOrder, datasourceKey);
|
|
122
135
|
if (hits.length === 0) {
|
|
123
136
|
throw new Error(
|
|
124
|
-
`No datasource
|
|
125
|
-
`Checked: ${scanOrder.length ? scanOrder.join(', ') : '(no JSON candidates)'}`
|
|
137
|
+
`No datasource config matching "${datasourceKey}" under integration/${appName}/. ` +
|
|
138
|
+
`Checked: ${scanOrder.length ? scanOrder.join(', ') : '(no JSON/YAML candidates)'}`
|
|
126
139
|
);
|
|
127
140
|
}
|
|
128
141
|
if (hits.length > 1) {
|
|
@@ -167,7 +180,8 @@ function resolveValidateInputPath(identifier) {
|
|
|
167
180
|
}
|
|
168
181
|
const asFile = tryResolveAsExistingFile(trimmed);
|
|
169
182
|
if (asFile) return asFile;
|
|
170
|
-
|
|
183
|
+
const ext = path.extname(trimmed).toLowerCase();
|
|
184
|
+
if (DATASOURCE_CONFIG_EXTENSIONS.has(ext)) {
|
|
171
185
|
throw new Error(`File not found: ${trimmed}`);
|
|
172
186
|
}
|
|
173
187
|
return resolvePathFromIntegrationDatasourceKey(trimmed);
|
|
@@ -187,6 +201,18 @@ function resolveValidateInputPath(identifier) {
|
|
|
187
201
|
* const result = await validateDatasourceFile('./hubspot-deal.json');
|
|
188
202
|
* // Returns: { valid: true, errors: [], warnings: [], resolvedPath: '...' }
|
|
189
203
|
*/
|
|
204
|
+
function buildParseFailureResult(filePath, error) {
|
|
205
|
+
const message =
|
|
206
|
+
error && error.message ? String(error.message) : 'Invalid config file';
|
|
207
|
+
return {
|
|
208
|
+
valid: false,
|
|
209
|
+
errors: [message],
|
|
210
|
+
warnings: [],
|
|
211
|
+
resolvedPath: filePath,
|
|
212
|
+
summary: null
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
|
|
190
216
|
async function validateDatasourceFile(filePathOrKey) {
|
|
191
217
|
if (!filePathOrKey || typeof filePathOrKey !== 'string') {
|
|
192
218
|
throw new Error('File path is required and must be a string');
|
|
@@ -194,19 +220,11 @@ async function validateDatasourceFile(filePathOrKey) {
|
|
|
194
220
|
|
|
195
221
|
const filePath = resolveValidateInputPath(filePathOrKey.trim());
|
|
196
222
|
|
|
197
|
-
const content = fs.readFileSync(filePath, 'utf8');
|
|
198
223
|
let parsed;
|
|
199
|
-
|
|
200
224
|
try {
|
|
201
|
-
parsed =
|
|
225
|
+
parsed = loadConfigFile(filePath);
|
|
202
226
|
} catch (error) {
|
|
203
|
-
return
|
|
204
|
-
valid: false,
|
|
205
|
-
errors: [`Invalid JSON syntax: ${error.message}`],
|
|
206
|
-
warnings: [],
|
|
207
|
-
resolvedPath: filePath,
|
|
208
|
-
summary: null
|
|
209
|
-
};
|
|
227
|
+
return buildParseFailureResult(filePath, error);
|
|
210
228
|
}
|
|
211
229
|
|
|
212
230
|
const summary = buildDatasourceValidateSummary(parsed);
|
|
@@ -8,8 +8,90 @@
|
|
|
8
8
|
* @version 2.0.0
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
+
const {
|
|
12
|
+
formatSuccessLine,
|
|
13
|
+
formatSuccessParagraph,
|
|
14
|
+
sectionTitle,
|
|
15
|
+
headerKeyValue
|
|
16
|
+
} = require('../utils/cli-test-layout-chalk');
|
|
17
|
+
const logger = require('../utils/logger');
|
|
11
18
|
const { generateExternalReadmeContent } = require('../utils/external-readme');
|
|
12
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Validates system type from downloaded application
|
|
22
|
+
* @param {Object} application - External system configuration
|
|
23
|
+
* @returns {string} System type (openapi, mcp, custom)
|
|
24
|
+
*/
|
|
25
|
+
function validateSystemType(application) {
|
|
26
|
+
if (!application || typeof application !== 'object') {
|
|
27
|
+
throw new Error('Application configuration is required');
|
|
28
|
+
}
|
|
29
|
+
const validTypes = ['openapi', 'mcp', 'custom'];
|
|
30
|
+
const systemType = application.type;
|
|
31
|
+
if (!systemType || !validTypes.includes(systemType)) {
|
|
32
|
+
throw new Error(`Invalid system type: ${systemType}. Must be one of: ${validTypes.join(', ')}`);
|
|
33
|
+
}
|
|
34
|
+
return systemType;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function validateApplicationConfig(application) {
|
|
38
|
+
if (!application || typeof application !== 'object') {
|
|
39
|
+
throw new Error('Application configuration is required');
|
|
40
|
+
}
|
|
41
|
+
if (!application.key || typeof application.key !== 'string') {
|
|
42
|
+
throw new Error('Application key is required');
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function validateDatasourceConfig(datasource, applicationKey) {
|
|
47
|
+
if (!datasource.key || typeof datasource.key !== 'string') {
|
|
48
|
+
throw new Error('Datasource key is required for all datasources');
|
|
49
|
+
}
|
|
50
|
+
if (!datasource.systemKey || typeof datasource.systemKey !== 'string') {
|
|
51
|
+
throw new Error('Datasource systemKey is required for all datasources');
|
|
52
|
+
}
|
|
53
|
+
if (datasource.systemKey !== applicationKey) {
|
|
54
|
+
throw new Error(
|
|
55
|
+
`Datasource systemKey (${datasource.systemKey}) does not match application key (${applicationKey})`
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function validateDownloadedData(application, dataSources) {
|
|
61
|
+
validateApplicationConfig(application);
|
|
62
|
+
if (!Array.isArray(dataSources)) {
|
|
63
|
+
throw new Error('DataSources must be an array');
|
|
64
|
+
}
|
|
65
|
+
for (const datasource of dataSources) {
|
|
66
|
+
validateDatasourceConfig(datasource, application.key);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function logDownloadCommandHeader(systemKey) {
|
|
71
|
+
logger.log('');
|
|
72
|
+
logger.log(sectionTitle('Download'));
|
|
73
|
+
logger.log(headerKeyValue('System:', systemKey));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function displayDownloadSuccess(systemKey, finalPath, datasourceCount) {
|
|
77
|
+
logger.log(
|
|
78
|
+
formatSuccessParagraph(
|
|
79
|
+
`Downloaded ${systemKey} (${datasourceCount} datasource${datasourceCount === 1 ? '' : 's'})`
|
|
80
|
+
)
|
|
81
|
+
);
|
|
82
|
+
logger.log(headerKeyValue('Location:', finalPath));
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async function runConvertToJsonIfRequested(systemKey) {
|
|
86
|
+
const { runConvert } = require('../commands/convert');
|
|
87
|
+
try {
|
|
88
|
+
await runConvert(systemKey, { format: 'json', force: true });
|
|
89
|
+
logger.log(formatSuccessLine('Converted component files to JSON'));
|
|
90
|
+
} catch (convertErr) {
|
|
91
|
+
throw new Error(`Download succeeded but convert to JSON failed: ${convertErr.message}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
13
95
|
/**
|
|
14
96
|
* Generates application.yaml content for downloaded system
|
|
15
97
|
* @param {string} systemKey - System key
|
|
@@ -90,6 +172,11 @@ function generateReadme(systemKey, application, dataSources) {
|
|
|
90
172
|
}
|
|
91
173
|
|
|
92
174
|
module.exports = {
|
|
175
|
+
validateSystemType,
|
|
176
|
+
validateDownloadedData,
|
|
177
|
+
logDownloadCommandHeader,
|
|
178
|
+
displayDownloadSuccess,
|
|
179
|
+
runConvertToJsonIfRequested,
|
|
93
180
|
generateVariablesYaml,
|
|
94
181
|
generateReadme
|
|
95
182
|
};
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
const {
|
|
2
2
|
formatSuccessLine,
|
|
3
|
-
formatSuccessParagraph,
|
|
4
|
-
sectionTitle,
|
|
5
|
-
headerKeyValue,
|
|
6
3
|
metadata,
|
|
7
4
|
formatProgress,
|
|
8
5
|
formatWarningLine
|
|
@@ -36,83 +33,18 @@ const { getExternalSystemConfig } = require('../api/external-systems.api');
|
|
|
36
33
|
const { getDeploymentAuth, requireBearerForDataplanePipeline } = require('../utils/token-manager');
|
|
37
34
|
const { getConfig } = require('../core/config');
|
|
38
35
|
const { getIntegrationPath } = require('../utils/paths');
|
|
39
|
-
const { retemplateConfigurationForDownload } = require('../utils/configuration-env-resolver');
|
|
36
|
+
const { retemplateConfigurationForDownload, retemplateAllVariableDefinitions } = require('../utils/configuration-env-resolver');
|
|
37
|
+
const { syncRuntimeConfigurationFromDataplane } = require('../utils/runtime-configuration-download');
|
|
40
38
|
const logger = require('../utils/logger');
|
|
41
39
|
const { resolveControllerUrl } = require('../utils/controller-url');
|
|
42
40
|
const generator = require('../generator');
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
function validateSystemType(application) {
|
|
51
|
-
if (!application || typeof application !== 'object') {
|
|
52
|
-
throw new Error('Application configuration is required');
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const validTypes = ['openapi', 'mcp', 'custom'];
|
|
56
|
-
const systemType = application.type;
|
|
57
|
-
|
|
58
|
-
if (!systemType || !validTypes.includes(systemType)) {
|
|
59
|
-
throw new Error(`Invalid system type: ${systemType}. Must be one of: ${validTypes.join(', ')}`);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return systemType;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Validates downloaded data structure before writing files
|
|
67
|
-
* @param {Object} application - External system configuration
|
|
68
|
-
* @param {Array} dataSources - Array of datasource configurations
|
|
69
|
-
* @throws {Error} If validation fails
|
|
70
|
-
*/
|
|
71
|
-
/**
|
|
72
|
-
* Validates application configuration
|
|
73
|
-
* @function validateApplicationConfig
|
|
74
|
-
* @param {Object} application - Application configuration
|
|
75
|
-
* @throws {Error} If validation fails
|
|
76
|
-
*/
|
|
77
|
-
function validateApplicationConfig(application) {
|
|
78
|
-
if (!application || typeof application !== 'object') {
|
|
79
|
-
throw new Error('Application configuration is required');
|
|
80
|
-
}
|
|
81
|
-
if (!application.key || typeof application.key !== 'string') {
|
|
82
|
-
throw new Error('Application key is required');
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Validates datasource configuration
|
|
88
|
-
* @function validateDatasourceConfig
|
|
89
|
-
* @param {Object} datasource - Datasource configuration
|
|
90
|
-
* @param {string} applicationKey - Application key
|
|
91
|
-
* @throws {Error} If validation fails
|
|
92
|
-
*/
|
|
93
|
-
function validateDatasourceConfig(datasource, applicationKey) {
|
|
94
|
-
if (!datasource.key || typeof datasource.key !== 'string') {
|
|
95
|
-
throw new Error('Datasource key is required for all datasources');
|
|
96
|
-
}
|
|
97
|
-
if (!datasource.systemKey || typeof datasource.systemKey !== 'string') {
|
|
98
|
-
throw new Error('Datasource systemKey is required for all datasources');
|
|
99
|
-
}
|
|
100
|
-
if (datasource.systemKey !== applicationKey) {
|
|
101
|
-
throw new Error(`Datasource systemKey (${datasource.systemKey}) does not match application key (${applicationKey})`);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
function validateDownloadedData(application, dataSources) {
|
|
106
|
-
validateApplicationConfig(application);
|
|
107
|
-
|
|
108
|
-
if (!Array.isArray(dataSources)) {
|
|
109
|
-
throw new Error('DataSources must be an array');
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
for (const datasource of dataSources) {
|
|
113
|
-
validateDatasourceConfig(datasource, application.key);
|
|
114
|
-
}
|
|
115
|
-
}
|
|
41
|
+
const {
|
|
42
|
+
validateSystemType,
|
|
43
|
+
validateDownloadedData,
|
|
44
|
+
logDownloadCommandHeader,
|
|
45
|
+
displayDownloadSuccess,
|
|
46
|
+
runConvertToJsonIfRequested
|
|
47
|
+
} = require('./download-helpers');
|
|
116
48
|
|
|
117
49
|
/**
|
|
118
50
|
* Setup authentication and get dataplane URL
|
|
@@ -354,10 +286,9 @@ async function applyRetemplateToSystemFile(systemKey, systemFilePath) {
|
|
|
354
286
|
const systemContent = await fs.readFile(systemFilePath, 'utf8');
|
|
355
287
|
const systemObj = yaml.load(systemContent);
|
|
356
288
|
if (!Array.isArray(systemObj?.configuration)) return;
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
}
|
|
289
|
+
retemplateAllVariableDefinitions(systemObj.configuration);
|
|
290
|
+
await retemplateConfigurationForDownload(systemKey, systemObj.configuration);
|
|
291
|
+
await fs.writeFile(systemFilePath, yaml.dump(systemObj, { indent: 2, lineWidth: -1 }), 'utf8');
|
|
361
292
|
}
|
|
362
293
|
|
|
363
294
|
/**
|
|
@@ -397,43 +328,54 @@ async function processDownloadedSystem(systemKey, manifest, splitOptions = {}) {
|
|
|
397
328
|
}
|
|
398
329
|
|
|
399
330
|
/**
|
|
400
|
-
*
|
|
401
|
-
* @param {
|
|
402
|
-
* @param {string}
|
|
403
|
-
* @param {
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
`Downloaded ${systemKey} (${datasourceCount} datasource${datasourceCount === 1 ? '' : 's'})`
|
|
409
|
-
)
|
|
410
|
-
);
|
|
411
|
-
logger.log(headerKeyValue('Location:', finalPath));
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
/**
|
|
415
|
-
* After YAML split, convert integration files to JSON when --format json.
|
|
416
|
-
* @async
|
|
417
|
-
* @param {string} systemKey
|
|
331
|
+
* Post-split download steps: governance packs, optional JSON convert, runtime config sync.
|
|
332
|
+
* @param {Object} params
|
|
333
|
+
* @param {string} params.systemKey
|
|
334
|
+
* @param {Object} params.manifest
|
|
335
|
+
* @param {string} params.finalPath
|
|
336
|
+
* @param {string} params.dataplaneUrl
|
|
337
|
+
* @param {Object} params.authConfig
|
|
338
|
+
* @param {string} params.format
|
|
418
339
|
* @returns {Promise<void>}
|
|
419
340
|
*/
|
|
420
|
-
async function
|
|
421
|
-
|
|
341
|
+
async function finalizeDownloadArtifacts({
|
|
342
|
+
systemKey,
|
|
343
|
+
manifest,
|
|
344
|
+
finalPath,
|
|
345
|
+
dataplaneUrl,
|
|
346
|
+
authConfig,
|
|
347
|
+
format
|
|
348
|
+
}) {
|
|
349
|
+
const { downloadGovernanceScenarioPacksFromManifest } = require('../lifecycle/scenario-upload');
|
|
350
|
+
await downloadGovernanceScenarioPacksFromManifest(
|
|
351
|
+
systemKey,
|
|
352
|
+
manifest,
|
|
353
|
+
dataplaneUrl,
|
|
354
|
+
authConfig
|
|
355
|
+
);
|
|
356
|
+
if (format === 'json') {
|
|
357
|
+
await runConvertToJsonIfRequested(systemKey);
|
|
358
|
+
}
|
|
422
359
|
try {
|
|
423
|
-
await
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
360
|
+
const configSync = await syncRuntimeConfigurationFromDataplane({
|
|
361
|
+
dataplaneUrl,
|
|
362
|
+
authConfig,
|
|
363
|
+
systemKey,
|
|
364
|
+
integrationPath: finalPath,
|
|
365
|
+
dataSources: manifest.dataSources
|
|
366
|
+
});
|
|
367
|
+
if (configSync.merged > 0) {
|
|
368
|
+
const nameList = configSync.names.length ? ` (${configSync.names.join(', ')})` : '';
|
|
369
|
+
logger.log(
|
|
370
|
+
formatSuccessLine(
|
|
371
|
+
`Merged ${configSync.merged} runtime configuration variable(s) into env.template${nameList}.`
|
|
372
|
+
)
|
|
373
|
+
);
|
|
374
|
+
}
|
|
375
|
+
} catch (syncErr) {
|
|
376
|
+
logger.log(formatWarningLine(`Runtime configuration sync skipped: ${syncErr.message}`));
|
|
427
377
|
}
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
/**
|
|
431
|
-
* @param {string} systemKey
|
|
432
|
-
*/
|
|
433
|
-
function logDownloadCommandHeader(systemKey) {
|
|
434
|
-
logger.log('');
|
|
435
|
-
logger.log(sectionTitle('Download'));
|
|
436
|
-
logger.log(headerKeyValue('System:', systemKey));
|
|
378
|
+
displayDownloadSuccess(systemKey, finalPath, manifest.dataSources.length);
|
|
437
379
|
}
|
|
438
380
|
|
|
439
381
|
/**
|
|
@@ -468,17 +410,14 @@ async function downloadExternalSystem(systemKey, options = {}) {
|
|
|
468
410
|
manifest,
|
|
469
411
|
await resolveDownloadSplitOptions(finalPath, options)
|
|
470
412
|
);
|
|
471
|
-
|
|
472
|
-
await downloadGovernanceScenarioPacksFromManifest(
|
|
413
|
+
await finalizeDownloadArtifacts({
|
|
473
414
|
systemKey,
|
|
474
415
|
manifest,
|
|
416
|
+
finalPath,
|
|
475
417
|
dataplaneUrl,
|
|
476
|
-
authConfig
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
await runConvertToJsonIfRequested(systemKey);
|
|
480
|
-
}
|
|
481
|
-
displayDownloadSuccess(systemKey, finalPath, manifest.dataSources.length);
|
|
418
|
+
authConfig,
|
|
419
|
+
format
|
|
420
|
+
});
|
|
482
421
|
} catch (error) {
|
|
483
422
|
throw new Error(`Failed to download external system: ${error.message}`);
|
|
484
423
|
}
|
|
@@ -16,70 +16,12 @@ const handlebars = require('handlebars');
|
|
|
16
16
|
const logger = require('../utils/logger');
|
|
17
17
|
const { resolveApplicationConfigPath } = require('../utils/app-config-resolver');
|
|
18
18
|
const { loadConfigFile, writeConfigFile } = require('../utils/config-format');
|
|
19
|
-
const {
|
|
19
|
+
const { buildAuthenticationFromMethod } = require('../utils/authentication-shape');
|
|
20
20
|
|
|
21
21
|
// Register Handlebars helper for equality check
|
|
22
22
|
handlebars.registerHelper('eq', (a, b) => a === b);
|
|
23
23
|
handlebars.registerHelper('json', (obj) => JSON.stringify(obj));
|
|
24
24
|
|
|
25
|
-
/**
|
|
26
|
-
* Build authentication object per schema authenticationVariablesByMethod.
|
|
27
|
-
* Security values use canonical kv://<systemKey>/<segment> paths (segment from getKvPathSegmentForSecurityKey).
|
|
28
|
-
* @param {string} systemKey - External system key
|
|
29
|
-
* @param {string} authType - Auth method (oauth2, aad, apikey, bearerToken, basic, queryParam, oidc, hmac, none)
|
|
30
|
-
* @returns {{ method: string, variables: Object, security: Object }} Authentication object
|
|
31
|
-
*/
|
|
32
|
-
function buildAuthenticationFromMethod(systemKey, authType) {
|
|
33
|
-
const kvPath = (securityKey) => {
|
|
34
|
-
const segment = getKvPathSegmentForSecurityKey(securityKey);
|
|
35
|
-
return segment ? `kv://${systemKey}/${segment}` : null;
|
|
36
|
-
};
|
|
37
|
-
const method = authType || 'apikey';
|
|
38
|
-
const base = 'https://api.example.com';
|
|
39
|
-
|
|
40
|
-
const authMap = {
|
|
41
|
-
oauth2: {
|
|
42
|
-
variables: { baseUrl: base, tokenUrl: `${base}/oauth/token`, authorizationUrl: `${base}/oauth/authorize` },
|
|
43
|
-
security: { clientId: kvPath('clientId'), clientSecret: kvPath('clientSecret') }
|
|
44
|
-
},
|
|
45
|
-
aad: {
|
|
46
|
-
variables: { baseUrl: base, tokenUrl: 'https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token', tenantId: '{tenant-id}' },
|
|
47
|
-
security: { clientId: kvPath('clientId'), clientSecret: kvPath('clientSecret') }
|
|
48
|
-
},
|
|
49
|
-
apikey: {
|
|
50
|
-
variables: { baseUrl: base, headerName: 'X-API-Key' },
|
|
51
|
-
security: { apiKey: kvPath('apiKey') }
|
|
52
|
-
},
|
|
53
|
-
bearerToken: {
|
|
54
|
-
variables: { baseUrl: base, headerName: 'Authorization', prefix: 'Bearer' },
|
|
55
|
-
security: { token: kvPath('token') }
|
|
56
|
-
},
|
|
57
|
-
basic: {
|
|
58
|
-
variables: { baseUrl: base },
|
|
59
|
-
security: { username: kvPath('username'), password: kvPath('password') }
|
|
60
|
-
},
|
|
61
|
-
queryParam: {
|
|
62
|
-
variables: { baseUrl: base, paramName: 'api_key' },
|
|
63
|
-
security: { paramValue: kvPath('paramValue') }
|
|
64
|
-
},
|
|
65
|
-
oidc: {
|
|
66
|
-
variables: { openIdConfigUrl: 'https://example.com/.well-known/openid-configuration', clientId: 'app-id' },
|
|
67
|
-
security: {}
|
|
68
|
-
},
|
|
69
|
-
hmac: {
|
|
70
|
-
variables: { baseUrl: base, algorithm: 'sha256', signatureHeader: 'X-Signature' },
|
|
71
|
-
security: { signingSecret: kvPath('signingSecret') }
|
|
72
|
-
},
|
|
73
|
-
none: {
|
|
74
|
-
variables: {},
|
|
75
|
-
security: {}
|
|
76
|
-
}
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
const auth = authMap[method] || authMap.apikey;
|
|
80
|
-
return { method, variables: auth.variables, security: auth.security };
|
|
81
|
-
}
|
|
82
|
-
|
|
83
25
|
/** Target extension for format */
|
|
84
26
|
const FORMAT_EXT = { yaml: '.yaml', json: '.json' };
|
|
85
27
|
|