@aifabrix/builder 2.46.0 → 2.47.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.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 +16 -4
- 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-platform.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/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/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/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/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/help-builder.js +2 -0
- package/lib/utils/paths.js +25 -0
- package/lib/utils/platform-controller-url.js +2 -1
- 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/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
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
* @version 2.0.0
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
const fs = require('fs');
|
|
10
9
|
const path = require('path');
|
|
10
|
+
const { readDatasourceConfigFile } = require('./run-capability-copy');
|
|
11
11
|
const { resolveValidateInputPath } = require('../validate');
|
|
12
12
|
const { normalizeCapabilityKey } = require('./capability-key');
|
|
13
13
|
const { extractCapabilitySliceForDiff } = require('./capability-diff-slice');
|
|
@@ -108,8 +108,8 @@ function resolveProfileKeys(opts) {
|
|
|
108
108
|
function runCapabilityDiff(opts) {
|
|
109
109
|
const pathA = resolveValidateInputPath(opts.fileA.trim());
|
|
110
110
|
const pathB = resolveValidateInputPath(opts.fileB.trim());
|
|
111
|
-
const docA =
|
|
112
|
-
const docB =
|
|
111
|
+
const docA = readDatasourceConfigFile(pathA);
|
|
112
|
+
const docB = readDatasourceConfigFile(pathB);
|
|
113
113
|
|
|
114
114
|
const { capA, capB } = resolveCapabilityKeys(opts);
|
|
115
115
|
const { profA, profB } = resolveProfileKeys(opts);
|
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
|
|
9
9
|
'use strict';
|
|
10
10
|
|
|
11
|
-
const fs = require('fs');
|
|
12
11
|
const { resolveControllerUrl } = require('../../utils/controller-url');
|
|
13
12
|
const { normalizeControllerUrl } = require('../../core/config');
|
|
14
13
|
const { getOrRefreshDeviceToken } = require('../../utils/token-manager');
|
|
@@ -19,7 +18,7 @@ const {
|
|
|
19
18
|
} = require('../validate');
|
|
20
19
|
const { applyCapabilityDimension } = require('./dimension-operations');
|
|
21
20
|
const { validateDimensionSemantics } = require('./dimension-validate');
|
|
22
|
-
const { writeBackup, atomicWriteJson } = require('./run-capability-copy');
|
|
21
|
+
const { writeBackup, atomicWriteJson, readDatasourceConfigFile } = require('./run-capability-copy');
|
|
23
22
|
const { tryResolveDatasourceKeyToLocalPath, readJsonFile } = require('../../resolvers/datasource-resolver');
|
|
24
23
|
const { tryFetchDatasourceConfig } = require('../../resolvers/manifest-resolver');
|
|
25
24
|
|
|
@@ -231,8 +230,7 @@ function applyBindingAndValidateSchema({ parsed, opts, semanticWarnings, remoteF
|
|
|
231
230
|
async function runCapabilityDimension(rawOpts) {
|
|
232
231
|
const opts = normalizeRunOptions(rawOpts);
|
|
233
232
|
const resolvedPath = resolveValidateInputPath(opts.fileOrKey);
|
|
234
|
-
const
|
|
235
|
-
const parsed = JSON.parse(raw);
|
|
233
|
+
const parsed = readDatasourceConfigFile(resolvedPath);
|
|
236
234
|
|
|
237
235
|
const systemKeyForAuth = resolveSystemKeyForAuth(parsed);
|
|
238
236
|
const { remoteTargetsByKey, remoteFetchMeta } = await loadRemoteTargetsByKey({
|
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
* @version 2.0.0
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
const fs = require('fs');
|
|
10
9
|
const { execSync } = require('child_process');
|
|
11
10
|
const inquirer = require('inquirer');
|
|
12
11
|
const {
|
|
@@ -19,7 +18,8 @@ const {
|
|
|
19
18
|
resolveSingleOpsKey,
|
|
20
19
|
resolveProfileKeyForLogical
|
|
21
20
|
} = require('./capability-resolve');
|
|
22
|
-
const { writeBackup, atomicWriteJson } = require('./run-capability-copy');
|
|
21
|
+
const { writeBackup, atomicWriteJson, readDatasourceConfigFile } = require('./run-capability-copy');
|
|
22
|
+
const { listCapabilityKeys } = require('./capability-manifest');
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
25
|
* @typedef {object} RunCapabilityEditOpts
|
|
@@ -35,10 +35,7 @@ const { writeBackup, atomicWriteJson } = require('./run-capability-copy');
|
|
|
35
35
|
* @returns {string[]}
|
|
36
36
|
*/
|
|
37
37
|
function collectCapabilityKeys(doc) {
|
|
38
|
-
const s = new Set();
|
|
39
|
-
if (Array.isArray(doc.capabilities)) {
|
|
40
|
-
doc.capabilities.forEach((c) => s.add(String(c)));
|
|
41
|
-
}
|
|
38
|
+
const s = new Set(listCapabilityKeys(doc.capabilities));
|
|
42
39
|
if (doc.openapi?.operations) {
|
|
43
40
|
Object.keys(doc.openapi.operations).forEach((k) => s.add(k));
|
|
44
41
|
}
|
|
@@ -351,7 +348,7 @@ async function runCapabilityEdit(opts) {
|
|
|
351
348
|
throw new Error('capability edit requires an interactive terminal (TTY). Use a terminal or SSH with -t.');
|
|
352
349
|
}
|
|
353
350
|
const resolvedPath = resolveValidateInputPath(opts.fileOrKey.trim());
|
|
354
|
-
const doc =
|
|
351
|
+
const doc = readDatasourceConfigFile(resolvedPath);
|
|
355
352
|
const { capKey, section, profileKey } = await resolveEditTargets(doc, opts);
|
|
356
353
|
const initial = getEditableJson(doc, capKey, section, profileKey);
|
|
357
354
|
const body = await promptEditorJson(initial);
|
|
@@ -6,14 +6,13 @@
|
|
|
6
6
|
* @version 2.0.0
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
const fs = require('fs');
|
|
10
9
|
const {
|
|
11
10
|
resolveValidateInputPath,
|
|
12
11
|
validateDatasourceParsed
|
|
13
12
|
} = require('../validate');
|
|
14
13
|
const { applyCapabilityRelate } = require('./relate-operations');
|
|
15
14
|
const { validateRelateSemantics } = require('./relate-validate');
|
|
16
|
-
const { writeBackup, atomicWriteJson } = require('./run-capability-copy');
|
|
15
|
+
const { writeBackup, atomicWriteJson, readDatasourceConfigFile } = require('./run-capability-copy');
|
|
17
16
|
const { tryResolveDatasourceKeyToLocalPath, readJsonFile } = require('../../resolvers/datasource-resolver');
|
|
18
17
|
const { tryFetchDatasourceConfig } = require('../../resolvers/manifest-resolver');
|
|
19
18
|
|
|
@@ -134,8 +133,7 @@ function applyRelateAndValidateSchema(parsed, opts, semanticWarnings, remoteVali
|
|
|
134
133
|
*/
|
|
135
134
|
async function runCapabilityRelate(opts) {
|
|
136
135
|
const resolvedPath = resolveValidateInputPath(opts.fileOrKey.trim());
|
|
137
|
-
const
|
|
138
|
-
const parsed = JSON.parse(raw);
|
|
136
|
+
const parsed = readDatasourceConfigFile(resolvedPath);
|
|
139
137
|
|
|
140
138
|
const targetDocLocal = loadTargetDocLocal(opts.targetDatasource);
|
|
141
139
|
const systemKeyForAuth = resolveSystemKeyForAuth(parsed);
|
|
@@ -6,14 +6,13 @@
|
|
|
6
6
|
* @version 2.0.0
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
const fs = require('fs');
|
|
10
9
|
const {
|
|
11
10
|
resolveValidateInputPath,
|
|
12
11
|
validateDatasourceParsed
|
|
13
12
|
} = require('../validate');
|
|
14
13
|
const { normalizeCapabilityKey } = require('./capability-key');
|
|
15
14
|
const { applyCapabilityRemove } = require('./remove-operations');
|
|
16
|
-
const { writeBackup, atomicWriteJson } = require('./run-capability-copy');
|
|
15
|
+
const { writeBackup, atomicWriteJson, readDatasourceConfigFile } = require('./run-capability-copy');
|
|
17
16
|
|
|
18
17
|
/**
|
|
19
18
|
* @param {{ valid: boolean, errors: string[] }} validation
|
|
@@ -67,8 +66,7 @@ function makeRemoveResult(resolvedPath, capability, result, validation, dryRun,
|
|
|
67
66
|
*/
|
|
68
67
|
async function runCapabilityRemove(opts) {
|
|
69
68
|
const resolvedPath = resolveValidateInputPath(opts.fileOrKey.trim());
|
|
70
|
-
const
|
|
71
|
-
const parsed = JSON.parse(raw);
|
|
69
|
+
const parsed = readDatasourceConfigFile(resolvedPath);
|
|
72
70
|
|
|
73
71
|
const capability = normalizeCapabilityKey(opts.capability, 'Capability (--capability)');
|
|
74
72
|
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
const { normalizeCapabilityKey } = require('./capability-key');
|
|
10
|
+
const { capabilitiesIncludes } = require('./capability-manifest');
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Lists structural locations where a capability key should appear.
|
|
@@ -18,7 +19,7 @@ const { normalizeCapabilityKey } = require('./capability-key');
|
|
|
18
19
|
function checkCapabilitySlices(parsed, rawKey) {
|
|
19
20
|
const key = normalizeCapabilityKey(rawKey, 'capability');
|
|
20
21
|
const missing = [];
|
|
21
|
-
if (!
|
|
22
|
+
if (!capabilitiesIncludes(parsed.capabilities, key)) {
|
|
22
23
|
missing.push(`capabilities[] (missing "${key}")`);
|
|
23
24
|
}
|
|
24
25
|
if (!parsed.openapi?.operations?.[key]) {
|
|
@@ -38,7 +38,8 @@ function datasourceIdentifierMatchesFile(identifier, fileRef, parsed) {
|
|
|
38
38
|
if (stem === id) {
|
|
39
39
|
return true;
|
|
40
40
|
}
|
|
41
|
-
|
|
41
|
+
const lowerId = id.toLowerCase();
|
|
42
|
+
if (`${stem}.json` === lowerId || `${stem}.yaml` === lowerId || `${stem}.yml` === lowerId) {
|
|
42
43
|
return true;
|
|
43
44
|
}
|
|
44
45
|
return false;
|
|
@@ -30,7 +30,7 @@ function logHeaderAndIdentity(result, trimmed, showMapping) {
|
|
|
30
30
|
const { resolvedPath, summary } = result;
|
|
31
31
|
logger.log('');
|
|
32
32
|
logger.log(sectionTitle('Datasource validation'));
|
|
33
|
-
logger.log(metadata('Offline — JSON schema and integration wiring'));
|
|
33
|
+
logger.log(metadata('Offline — YAML/JSON schema and integration wiring'));
|
|
34
34
|
logger.log('');
|
|
35
35
|
if (summary) {
|
|
36
36
|
logger.log(` ${headerKeyValue('Key:', summary.key)}`);
|
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
* @version 2.0.0
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
+
const { validateOrphanExposedProfiles } = require('./orphan-profiles-validator');
|
|
14
|
+
|
|
13
15
|
/**
|
|
14
16
|
* Set of attribute names plus root dimension keys valid for field references.
|
|
15
17
|
* Used for primaryKey (schema allows dimension keys or attributes) and other paths (attributes only).
|
|
@@ -40,16 +42,34 @@ function checkPrimaryKey(parsed, attributesAndDimensions, errors) {
|
|
|
40
42
|
});
|
|
41
43
|
}
|
|
42
44
|
|
|
45
|
+
/** @returns {Set<string>} */
|
|
46
|
+
function profileReferenceSet(parsed) {
|
|
47
|
+
if (parsed?.entityType === 'serviceContract') {
|
|
48
|
+
const schema = parsed?.exposed?.schema;
|
|
49
|
+
if (schema && typeof schema === 'object' && !Array.isArray(schema)) {
|
|
50
|
+
return new Set(
|
|
51
|
+
Object.keys(schema).filter(key => typeof key === 'string' && key !== '')
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return new Set(Object.keys(parsed?.fieldMappings?.attributes ?? {}));
|
|
56
|
+
}
|
|
57
|
+
|
|
43
58
|
/** @param {string[]} errors */
|
|
44
|
-
function checkExposedProfiles(parsed,
|
|
59
|
+
function checkExposedProfiles(parsed, _attrSet, errors) {
|
|
45
60
|
const profiles = parsed?.exposed?.profiles;
|
|
46
61
|
if (!profiles || typeof profiles !== 'object' || Array.isArray(profiles)) return;
|
|
62
|
+
const profileRefSet = profileReferenceSet(parsed);
|
|
63
|
+
const referenceLabel =
|
|
64
|
+
parsed?.entityType === 'serviceContract'
|
|
65
|
+
? 'exposed.schema'
|
|
66
|
+
: 'fieldMappings.attributes';
|
|
47
67
|
Object.entries(profiles).forEach(([profileName, fields]) => {
|
|
48
68
|
if (!Array.isArray(fields)) return;
|
|
49
69
|
fields.forEach((field, idx) => {
|
|
50
|
-
if (typeof field === 'string' && !
|
|
70
|
+
if (typeof field === 'string' && !profileRefSet.has(field)) {
|
|
51
71
|
errors.push(
|
|
52
|
-
`exposed.profiles.${profileName}[${idx}]: field '${field}' does not exist in
|
|
72
|
+
`exposed.profiles.${profileName}[${idx}]: field '${field}' does not exist in ${referenceLabel}. Add the attribute or remove the reference.`
|
|
53
73
|
);
|
|
54
74
|
}
|
|
55
75
|
});
|
|
@@ -121,6 +141,7 @@ function validateFieldReferences(parsed) {
|
|
|
121
141
|
|
|
122
142
|
checkPrimaryKey(parsed, attributesAndDimensions, errors);
|
|
123
143
|
checkExposedProfiles(parsed, attrSet, errors);
|
|
144
|
+
errors.push(...validateOrphanExposedProfiles(parsed));
|
|
124
145
|
if (normalizedAttributes.length === 0) return errors;
|
|
125
146
|
|
|
126
147
|
checkIndexingAndValidation(parsed, normalizedAttributes, errors);
|
|
@@ -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
|
};
|