@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
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resource type catalog commands (Controller).
|
|
3
|
+
*
|
|
4
|
+
* Commands:
|
|
5
|
+
* - aifabrix resource-type create
|
|
6
|
+
* - aifabrix resource-type import
|
|
7
|
+
* - aifabrix resource-type get
|
|
8
|
+
* - aifabrix resource-type list
|
|
9
|
+
*
|
|
10
|
+
* @fileoverview Resource type CLI commands
|
|
11
|
+
* @author AI Fabrix Team
|
|
12
|
+
* @version 1.0.0
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
'use strict';
|
|
16
|
+
|
|
17
|
+
const chalk = require('chalk');
|
|
18
|
+
const logger = require('../utils/logger');
|
|
19
|
+
const { resolveControllerUrl } = require('../utils/controller-url');
|
|
20
|
+
const { normalizeControllerUrl, resolveEnvironment } = require('../core/config');
|
|
21
|
+
const { getOrRefreshDeviceToken } = require('../utils/token-manager');
|
|
22
|
+
const {
|
|
23
|
+
readResourceTypeCreateFile,
|
|
24
|
+
readResourceTypeCatalogFile
|
|
25
|
+
} = require('../resolvers/resource-type-file');
|
|
26
|
+
const {
|
|
27
|
+
formatBlockingError,
|
|
28
|
+
formatSuccessLine,
|
|
29
|
+
infoLine,
|
|
30
|
+
headerKeyValue
|
|
31
|
+
} = require('../utils/cli-layout-chalk');
|
|
32
|
+
const {
|
|
33
|
+
listResourceTypes,
|
|
34
|
+
getResourceType,
|
|
35
|
+
createResourceTypeIdempotent
|
|
36
|
+
} = require('../api/resource-types.api');
|
|
37
|
+
|
|
38
|
+
const RESOURCE_TYPE_KEY_PATTERN = /^[a-z][a-z0-9-]*$/;
|
|
39
|
+
|
|
40
|
+
/** Parent help for `aifabrix resource-type -h`. */
|
|
41
|
+
const RESOURCE_TYPE_HELP_AFTER = `
|
|
42
|
+
|
|
43
|
+
Examples:
|
|
44
|
+
$ aifabrix resource-type create --key customer --display-name "Customer"
|
|
45
|
+
$ aifabrix resource-type get customer
|
|
46
|
+
$ aifabrix resource-type list --search customer
|
|
47
|
+
|
|
48
|
+
Per-command help: aifabrix resource-type <command> --help
|
|
49
|
+
`;
|
|
50
|
+
|
|
51
|
+
const RESOURCE_TYPE_IMPORT_HELP_AFTER = `
|
|
52
|
+
|
|
53
|
+
Examples:
|
|
54
|
+
$ aifabrix resource-type import --file ./baseline-resourcetypes.json
|
|
55
|
+
$ aifabrix resource-type import --file /path/to/catalog.json
|
|
56
|
+
|
|
57
|
+
`;
|
|
58
|
+
|
|
59
|
+
const RESOURCE_TYPE_CREATE_HELP_AFTER = `
|
|
60
|
+
|
|
61
|
+
Examples:
|
|
62
|
+
$ aifabrix resource-type create --key customer --display-name "Customer"
|
|
63
|
+
$ aifabrix resource-type create --key deal --display-name "Deal" --category business --default-risk-level medium
|
|
64
|
+
$ aifabrix resource-type create --file ./customer.json
|
|
65
|
+
|
|
66
|
+
`;
|
|
67
|
+
|
|
68
|
+
const RESOURCE_TYPE_GET_HELP_AFTER = `
|
|
69
|
+
|
|
70
|
+
Examples:
|
|
71
|
+
$ aifabrix resource-type get customer
|
|
72
|
+
$ aifabrix resource-type get clx1234567890abcdef
|
|
73
|
+
|
|
74
|
+
`;
|
|
75
|
+
|
|
76
|
+
const RESOURCE_TYPE_LIST_HELP_AFTER = `
|
|
77
|
+
|
|
78
|
+
Examples:
|
|
79
|
+
$ aifabrix resource-type list
|
|
80
|
+
$ aifabrix resource-type list --page 1 --page-size 50
|
|
81
|
+
$ aifabrix resource-type list --search customer
|
|
82
|
+
|
|
83
|
+
`;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* @param {string} raw
|
|
87
|
+
* @returns {string}
|
|
88
|
+
*/
|
|
89
|
+
function requireResourceTypeKey(raw) {
|
|
90
|
+
const key = String(raw || '').trim();
|
|
91
|
+
if (!key) {
|
|
92
|
+
throw new Error('Resource type key is required (--key <key> or --file <path>).');
|
|
93
|
+
}
|
|
94
|
+
if (!RESOURCE_TYPE_KEY_PATTERN.test(key)) {
|
|
95
|
+
throw new Error(
|
|
96
|
+
'Resource type key must start with a lowercase letter and contain only lowercase letters, numbers, and hyphens.'
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
return key;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* @param {Object} options
|
|
104
|
+
* @returns {Promise<{ controllerUrl: string, authConfig: Object }>}
|
|
105
|
+
*/
|
|
106
|
+
async function resolveControllerAndAuth(_options) {
|
|
107
|
+
const controllerUrl = await resolveControllerUrl();
|
|
108
|
+
if (!controllerUrl) {
|
|
109
|
+
throw new Error('Controller URL is required. Run "aifabrix login" first.');
|
|
110
|
+
}
|
|
111
|
+
const normalized = normalizeControllerUrl(controllerUrl);
|
|
112
|
+
const deviceToken = await getOrRefreshDeviceToken(normalized);
|
|
113
|
+
if (!deviceToken || !deviceToken.token) {
|
|
114
|
+
throw new Error(
|
|
115
|
+
`Not authenticated for controller: ${controllerUrl}. ` +
|
|
116
|
+
'Run "aifabrix login" and try again.'
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
return {
|
|
120
|
+
controllerUrl: deviceToken.controller || normalized,
|
|
121
|
+
authConfig: { type: 'bearer', token: deviceToken.token }
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
async function resolveHeaderContext() {
|
|
126
|
+
const env = await resolveEnvironment();
|
|
127
|
+
const controllerUrl = await resolveControllerUrl();
|
|
128
|
+
const normalized = normalizeControllerUrl(controllerUrl);
|
|
129
|
+
return { environment: env || 'dev', controllerUrl: normalized };
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* @param {Object} options
|
|
134
|
+
* @returns {Object}
|
|
135
|
+
*/
|
|
136
|
+
function buildCreatePayload(options) {
|
|
137
|
+
let base = {};
|
|
138
|
+
if (options.file) {
|
|
139
|
+
base = readResourceTypeCreateFile(options.file);
|
|
140
|
+
}
|
|
141
|
+
const payload = { ...base };
|
|
142
|
+
if (options.key) payload.key = options.key;
|
|
143
|
+
if (options.displayName) payload.displayName = options.displayName;
|
|
144
|
+
if (options.description !== undefined) payload.description = options.description;
|
|
145
|
+
if (options.category) payload.category = options.category;
|
|
146
|
+
if (options.defaultRiskLevel) payload.defaultRiskLevel = options.defaultRiskLevel;
|
|
147
|
+
if (options.status) payload.status = options.status;
|
|
148
|
+
payload.key = requireResourceTypeKey(payload.key);
|
|
149
|
+
if (!payload.displayName) {
|
|
150
|
+
throw new Error('displayName is required (--display-name <name> or in --file).');
|
|
151
|
+
}
|
|
152
|
+
return payload;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* @param {Object} response
|
|
157
|
+
* @returns {any}
|
|
158
|
+
*/
|
|
159
|
+
function unwrapControllerData(response) {
|
|
160
|
+
return response?.data?.data ?? response?.data ?? response;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* @param {import('commander').Command} rt
|
|
165
|
+
*/
|
|
166
|
+
/**
|
|
167
|
+
* @param {Object[]} rows
|
|
168
|
+
* @param {string} controllerUrl
|
|
169
|
+
* @param {Object} authConfig
|
|
170
|
+
* @returns {Promise<{ created: number, existed: number, total: number }>}
|
|
171
|
+
*/
|
|
172
|
+
async function importResourceTypeRows(rows, controllerUrl, authConfig) {
|
|
173
|
+
let created = 0;
|
|
174
|
+
let existed = 0;
|
|
175
|
+
for (const row of rows) {
|
|
176
|
+
const payload = { ...row };
|
|
177
|
+
payload.key = requireResourceTypeKey(payload.key);
|
|
178
|
+
const out = await createResourceTypeIdempotent(controllerUrl, authConfig, payload);
|
|
179
|
+
if (out.created) {
|
|
180
|
+
created += 1;
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
existed += 1;
|
|
184
|
+
}
|
|
185
|
+
return { created, existed, total: rows.length };
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function setupResourceTypeImportCommand(rt) {
|
|
189
|
+
rt
|
|
190
|
+
.command('import')
|
|
191
|
+
.description('Import resource types from baseline catalog JSON (idempotent)')
|
|
192
|
+
.addHelpText('after', RESOURCE_TYPE_IMPORT_HELP_AFTER)
|
|
193
|
+
.requiredOption('--file <path>', 'Baseline catalog (resourceTypes[]) or JSON array')
|
|
194
|
+
.action(async(options) => {
|
|
195
|
+
try {
|
|
196
|
+
const { controllerUrl, authConfig } = await resolveControllerAndAuth(options);
|
|
197
|
+
const rows = readResourceTypeCatalogFile(options.file);
|
|
198
|
+
const summary = await importResourceTypeRows(rows, controllerUrl, authConfig);
|
|
199
|
+
logger.log(
|
|
200
|
+
formatSuccessLine(
|
|
201
|
+
`Resource types imported: ${summary.total} total ` +
|
|
202
|
+
`(${summary.created} created, ${summary.existed} already existed)`
|
|
203
|
+
)
|
|
204
|
+
);
|
|
205
|
+
} catch (e) {
|
|
206
|
+
logger.error(formatBlockingError(e.message));
|
|
207
|
+
process.exit(1);
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function setupResourceTypeCreateCommand(rt) {
|
|
213
|
+
rt
|
|
214
|
+
.command('create')
|
|
215
|
+
.description('Create resource type (idempotent; success if it already exists)')
|
|
216
|
+
.addHelpText('after', RESOURCE_TYPE_CREATE_HELP_AFTER)
|
|
217
|
+
.option('--file <path>', 'Read resource type create payload from JSON file')
|
|
218
|
+
.option('--key <key>', 'Catalog key (lowercase letters, digits, hyphens)')
|
|
219
|
+
.option('--display-name <name>', 'Display name')
|
|
220
|
+
.option('--description <text>', 'Description')
|
|
221
|
+
.option(
|
|
222
|
+
'--category <category>',
|
|
223
|
+
'business | collaboration | governance | content | communication | people'
|
|
224
|
+
)
|
|
225
|
+
.option('--default-risk-level <level>', 'low | medium | high | critical')
|
|
226
|
+
.option('--status <status>', 'draft | active | deprecated | retired')
|
|
227
|
+
.action(async(options) => {
|
|
228
|
+
try {
|
|
229
|
+
const { controllerUrl, authConfig } = await resolveControllerAndAuth(options);
|
|
230
|
+
const payload = buildCreatePayload(options);
|
|
231
|
+
const out = await createResourceTypeIdempotent(controllerUrl, authConfig, payload);
|
|
232
|
+
const row = unwrapControllerData(out.response);
|
|
233
|
+
const category = row.category || payload.category || 'business';
|
|
234
|
+
const risk = row.defaultRiskLevel || payload.defaultRiskLevel || 'medium';
|
|
235
|
+
if (out.created) {
|
|
236
|
+
logger.log(
|
|
237
|
+
formatSuccessLine(`Resource type created: ${row.key} (category: ${category}, risk: ${risk})`)
|
|
238
|
+
);
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
logger.log(formatSuccessLine(`Resource type exists: ${row.key} (category: ${category}, risk: ${risk})`));
|
|
242
|
+
logger.log(infoLine('No changes were needed.'));
|
|
243
|
+
} catch (e) {
|
|
244
|
+
logger.error(formatBlockingError(e.message));
|
|
245
|
+
process.exit(1);
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function setupResourceTypeGetCommand(rt) {
|
|
251
|
+
rt
|
|
252
|
+
.command('get <resourceTypeIdOrKey>')
|
|
253
|
+
.description('Get resource type by id or key')
|
|
254
|
+
.addHelpText('after', RESOURCE_TYPE_GET_HELP_AFTER)
|
|
255
|
+
.action(async(resourceTypeIdOrKey, options) => {
|
|
256
|
+
try {
|
|
257
|
+
const { environment, controllerUrl: headerControllerUrl } = await resolveHeaderContext();
|
|
258
|
+
const { controllerUrl, authConfig } = await resolveControllerAndAuth(options);
|
|
259
|
+
const res = await getResourceType(controllerUrl, authConfig, String(resourceTypeIdOrKey).trim());
|
|
260
|
+
const row = unwrapControllerData(res);
|
|
261
|
+
logger.log(
|
|
262
|
+
chalk.bold(`\n🏷️ Resource type in ${environment} environment (${headerControllerUrl}):\n`)
|
|
263
|
+
);
|
|
264
|
+
logger.log(headerKeyValue('Key:', row.key || '—'));
|
|
265
|
+
logger.log(headerKeyValue('Display:', row.displayName || '—'));
|
|
266
|
+
logger.log(headerKeyValue('Category:', row.category || '—'));
|
|
267
|
+
logger.log(headerKeyValue('Default risk:', row.defaultRiskLevel || '—'));
|
|
268
|
+
logger.log(headerKeyValue('Status:', row.status || '—'));
|
|
269
|
+
if (row.description) {
|
|
270
|
+
logger.log(headerKeyValue('Description:', row.description));
|
|
271
|
+
}
|
|
272
|
+
logger.log('');
|
|
273
|
+
} catch (e) {
|
|
274
|
+
logger.error(formatBlockingError(e.message));
|
|
275
|
+
process.exit(1);
|
|
276
|
+
}
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* @param {Array<Object>} items
|
|
282
|
+
* @param {string} environment
|
|
283
|
+
* @param {string} controllerUrl
|
|
284
|
+
*/
|
|
285
|
+
function displayResourceTypeList(items, environment, controllerUrl) {
|
|
286
|
+
logger.log(
|
|
287
|
+
chalk.bold(`\n🏷️ Resource types in ${environment} environment (${controllerUrl}):\n`)
|
|
288
|
+
);
|
|
289
|
+
if (!Array.isArray(items) || items.length === 0) {
|
|
290
|
+
logger.log(chalk.gray(' No resource types found.\n'));
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
const KEY_WIDTH = 22;
|
|
295
|
+
const DISPLAY_WIDTH = 30;
|
|
296
|
+
const CATEGORY_WIDTH = 16;
|
|
297
|
+
const RISK_WIDTH = 10;
|
|
298
|
+
const STATUS_WIDTH = 12;
|
|
299
|
+
const SEP_LEN = KEY_WIDTH + DISPLAY_WIDTH + CATEGORY_WIDTH + RISK_WIDTH + STATUS_WIDTH;
|
|
300
|
+
|
|
301
|
+
const keyCol = 'Key'.padEnd(KEY_WIDTH);
|
|
302
|
+
const displayCol = 'Display'.padEnd(DISPLAY_WIDTH);
|
|
303
|
+
const categoryCol = 'Category'.padEnd(CATEGORY_WIDTH);
|
|
304
|
+
const riskCol = 'Risk'.padEnd(RISK_WIDTH);
|
|
305
|
+
const statusCol = 'Status'.padEnd(STATUS_WIDTH);
|
|
306
|
+
logger.log(chalk.gray(`${keyCol}${displayCol}${categoryCol}${riskCol}${statusCol}`));
|
|
307
|
+
logger.log(chalk.gray('-'.repeat(SEP_LEN)));
|
|
308
|
+
|
|
309
|
+
items.forEach((d) => {
|
|
310
|
+
const key = (d?.key ?? '—').toString().padEnd(KEY_WIDTH);
|
|
311
|
+
const displayName = (d?.displayName ?? '—').toString().padEnd(DISPLAY_WIDTH);
|
|
312
|
+
const category = (d?.category ?? '—').toString().padEnd(CATEGORY_WIDTH);
|
|
313
|
+
const risk = (d?.defaultRiskLevel ?? '—').toString().padEnd(RISK_WIDTH);
|
|
314
|
+
const status = (d?.status ?? '—').toString().padEnd(STATUS_WIDTH);
|
|
315
|
+
logger.log(`${key}${displayName}${category}${risk}${status}`);
|
|
316
|
+
});
|
|
317
|
+
logger.log('');
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
function setupResourceTypeListCommand(rt) {
|
|
321
|
+
rt
|
|
322
|
+
.command('list')
|
|
323
|
+
.description('List resource types')
|
|
324
|
+
.addHelpText('after', RESOURCE_TYPE_LIST_HELP_AFTER)
|
|
325
|
+
.option('--page <n>', 'Page', (v) => parseInt(v, 10))
|
|
326
|
+
.option('--page-size <n>', 'Page size', (v) => parseInt(v, 10))
|
|
327
|
+
.option('--search <text>', 'Search by key/displayName/description')
|
|
328
|
+
.option('--category <category>', 'Filter by category')
|
|
329
|
+
.option('--status <status>', 'Filter by status')
|
|
330
|
+
.action(async(options) => {
|
|
331
|
+
try {
|
|
332
|
+
const { environment, controllerUrl: headerControllerUrl } = await resolveHeaderContext();
|
|
333
|
+
const { controllerUrl, authConfig } = await resolveControllerAndAuth(options);
|
|
334
|
+
const res = await listResourceTypes(controllerUrl, authConfig, {
|
|
335
|
+
page: options.page,
|
|
336
|
+
pageSize: options.pageSize,
|
|
337
|
+
search: options.search,
|
|
338
|
+
category: options.category,
|
|
339
|
+
status: options.status
|
|
340
|
+
});
|
|
341
|
+
const payload = unwrapControllerData(res);
|
|
342
|
+
const items = payload?.data ?? payload ?? [];
|
|
343
|
+
displayResourceTypeList(items, environment, headerControllerUrl);
|
|
344
|
+
} catch (e) {
|
|
345
|
+
logger.error(formatBlockingError(e.message));
|
|
346
|
+
process.exit(1);
|
|
347
|
+
}
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* @param {import('commander').Command} program
|
|
353
|
+
*/
|
|
354
|
+
function setupResourceTypeCommands(program) {
|
|
355
|
+
const rt = program
|
|
356
|
+
.command('resource-type')
|
|
357
|
+
.description('Manage the Controller Resource Type Catalog (COM)')
|
|
358
|
+
.addHelpText('after', RESOURCE_TYPE_HELP_AFTER);
|
|
359
|
+
setupResourceTypeCreateCommand(rt);
|
|
360
|
+
setupResourceTypeImportCommand(rt);
|
|
361
|
+
setupResourceTypeGetCommand(rt);
|
|
362
|
+
setupResourceTypeListCommand(rt);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
module.exports = {
|
|
366
|
+
setupResourceTypeCommands,
|
|
367
|
+
requireResourceTypeKey,
|
|
368
|
+
buildCreatePayload,
|
|
369
|
+
unwrapControllerData,
|
|
370
|
+
importResourceTypeRows
|
|
371
|
+
};
|
|
@@ -263,7 +263,7 @@ async function runUpPlatform(opts = {}) {
|
|
|
263
263
|
if (opts.force === true && opts.skipForceClean !== true) {
|
|
264
264
|
const cleanedApps =
|
|
265
265
|
preflight.skipClean !== true
|
|
266
|
-
? await upCommon.cleanBuilderAppDirs(
|
|
266
|
+
? await upCommon.cleanBuilderAppDirs(upCommon.PLATFORM_BUILDER_CLEAN_APP_KEYS, { silent: true })
|
|
267
267
|
: [];
|
|
268
268
|
forceCleanSummary = { forceSummary: authCtx.forceSummary, cleanedApps };
|
|
269
269
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Setup prompts for platform topology mode (single vs full).
|
|
2
|
+
* Setup prompts for platform topology mode (single vs single-traefik; full via CLI only).
|
|
3
3
|
*
|
|
4
4
|
* @fileoverview Setup platform mode prompt + CLI option normalization
|
|
5
5
|
* @author AI Fabrix Team
|
|
@@ -9,31 +9,43 @@
|
|
|
9
9
|
'use strict';
|
|
10
10
|
|
|
11
11
|
const inquirer = require('inquirer');
|
|
12
|
-
const {
|
|
12
|
+
const {
|
|
13
|
+
normalizeSetupPlatformMode,
|
|
14
|
+
SETUP_PLATFORM_MODE,
|
|
15
|
+
SETUP_PLATFORM_MODE_CLI_VALUES,
|
|
16
|
+
getSetupPlatformModePromptChoices
|
|
17
|
+
} = require('../core/setup-platform-mode');
|
|
13
18
|
|
|
14
19
|
/**
|
|
15
20
|
* Resolve platform mode from CLI options, if provided.
|
|
16
21
|
* @param {Object} [options]
|
|
17
|
-
* @returns {'single'|'full'|null}
|
|
22
|
+
* @returns {'single'|'single-traefik'|'full'|null}
|
|
18
23
|
*/
|
|
19
24
|
function resolvePlatformModeFromOptions(options = {}) {
|
|
20
25
|
const raw = options.platform;
|
|
21
26
|
if (raw === undefined || raw === null || String(raw).trim() === '') {
|
|
22
27
|
return null;
|
|
23
28
|
}
|
|
24
|
-
const normalized = normalizeSetupPlatformMode(raw);
|
|
25
|
-
// Guard: only accept exact canonical values from CLI; reject unexpected to avoid silent typos.
|
|
26
29
|
const rawNorm = String(raw).trim().toLowerCase();
|
|
27
|
-
|
|
28
|
-
|
|
30
|
+
const isCanonical = SETUP_PLATFORM_MODE_CLI_VALUES.includes(rawNorm);
|
|
31
|
+
const isAlias =
|
|
32
|
+
rawNorm === 'ingress' ||
|
|
33
|
+
rawNorm === 'single-ingress' ||
|
|
34
|
+
rawNorm === 'traefik' ||
|
|
35
|
+
rawNorm === 'all' ||
|
|
36
|
+
rawNorm === 'full-platform' ||
|
|
37
|
+
rawNorm === 'platform-full';
|
|
38
|
+
if (!isCanonical && !isAlias) {
|
|
39
|
+
const allowed = SETUP_PLATFORM_MODE_CLI_VALUES.join(', ');
|
|
40
|
+
throw new Error(`--platform must be one of: ${allowed} (example: aifabrix setup --platform single-traefik)`);
|
|
29
41
|
}
|
|
30
|
-
return
|
|
42
|
+
return normalizeSetupPlatformMode(raw);
|
|
31
43
|
}
|
|
32
44
|
|
|
33
45
|
/**
|
|
34
46
|
* @async
|
|
35
47
|
* @param {Object} [options]
|
|
36
|
-
* @returns {Promise<'single'|'full'>}
|
|
48
|
+
* @returns {Promise<'single'|'single-traefik'|'full'>}
|
|
37
49
|
*/
|
|
38
50
|
async function promptSetupPlatformMode(options = {}) {
|
|
39
51
|
const fromCli = resolvePlatformModeFromOptions(options);
|
|
@@ -44,16 +56,7 @@ async function promptSetupPlatformMode(options = {}) {
|
|
|
44
56
|
type: 'list',
|
|
45
57
|
name: 'mode',
|
|
46
58
|
message: 'Platform mode:',
|
|
47
|
-
choices:
|
|
48
|
-
{
|
|
49
|
-
name: 'Single environment — direct ports (no Traefik front door)',
|
|
50
|
-
value: SETUP_PLATFORM_MODE.SINGLE
|
|
51
|
-
},
|
|
52
|
-
{
|
|
53
|
-
name: 'Full platform — Traefik front door + miso/dev/tst/pro (shared infra)',
|
|
54
|
-
value: SETUP_PLATFORM_MODE.FULL
|
|
55
|
-
}
|
|
56
|
-
],
|
|
59
|
+
choices: getSetupPlatformModePromptChoices(),
|
|
57
60
|
default: SETUP_PLATFORM_MODE.SINGLE
|
|
58
61
|
}
|
|
59
62
|
]);
|
|
@@ -62,6 +65,6 @@ async function promptSetupPlatformMode(options = {}) {
|
|
|
62
65
|
|
|
63
66
|
module.exports = {
|
|
64
67
|
resolvePlatformModeFromOptions,
|
|
65
|
-
promptSetupPlatformMode
|
|
68
|
+
promptSetupPlatformMode,
|
|
69
|
+
getSetupPlatformModePromptChoices
|
|
66
70
|
};
|
|
67
|
-
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview verify-trust <systemKey> —
|
|
2
|
+
* @fileoverview verify-trust <systemKey> — dual-confidence AI Trust via dataplane (433.0).
|
|
3
3
|
* @author AI Fabrix Team
|
|
4
|
-
* @version
|
|
4
|
+
* @version 2.0.0
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
'use strict';
|
|
@@ -10,83 +10,20 @@ const chalk = require('chalk');
|
|
|
10
10
|
const logger = require('../utils/logger');
|
|
11
11
|
const { getConfig } = require('../core/config');
|
|
12
12
|
const { setupIntegrationTestAuth } = require('../external-system/test-auth');
|
|
13
|
-
const {
|
|
13
|
+
const { runSystemVerifyTrust } = require('../api/lifecycle.api');
|
|
14
14
|
const {
|
|
15
15
|
resolveExternalIntegrationContext,
|
|
16
16
|
syncLocalIfRequested
|
|
17
17
|
} = require('./test-e2e-external');
|
|
18
18
|
|
|
19
|
-
function pushTrustResult(results, key, trustRun, apiError) {
|
|
20
|
-
const failed =
|
|
21
|
-
apiError ||
|
|
22
|
-
!trustRun ||
|
|
23
|
-
trustRun.trustDecision === 'notTrusted' ||
|
|
24
|
-
trustRun.validationStatus === 'failed';
|
|
25
|
-
results.push({
|
|
26
|
-
key,
|
|
27
|
-
success: !failed,
|
|
28
|
-
error: failed
|
|
29
|
-
? apiError
|
|
30
|
-
? apiError.message || String(apiError)
|
|
31
|
-
: trustRun.summary || 'Trust validation failed'
|
|
32
|
-
: undefined,
|
|
33
|
-
trustRun
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
|
-
|
|
37
19
|
/**
|
|
38
20
|
* @async
|
|
39
|
-
* @param {Object|null} uploadCtx
|
|
40
21
|
* @param {string} externalSystem
|
|
41
22
|
* @param {Object} options
|
|
42
|
-
* @returns {Promise<{
|
|
43
|
-
*/
|
|
44
|
-
async function resolveTrustAuthContext(uploadCtx, externalSystem, options) {
|
|
45
|
-
if (uploadCtx) {
|
|
46
|
-
return { authConfig: uploadCtx.authConfig, dataplaneUrl: uploadCtx.dataplaneUrl };
|
|
47
|
-
}
|
|
48
|
-
const configObj = await getConfig();
|
|
49
|
-
return setupIntegrationTestAuth(
|
|
50
|
-
externalSystem,
|
|
51
|
-
{
|
|
52
|
-
environment: options.env,
|
|
53
|
-
authConfig: options.authConfig,
|
|
54
|
-
dataplaneUrl: options.dataplaneUrl,
|
|
55
|
-
silentResolve: options.silentResolve === true
|
|
56
|
-
},
|
|
57
|
-
configObj
|
|
58
|
-
);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* @async
|
|
63
|
-
* @param {string[]} keys
|
|
64
|
-
* @param {Object} runOpts
|
|
65
|
-
* @param {Array<Object>} results
|
|
66
|
-
*/
|
|
67
|
-
async function runTrustForDatasourceKeys(keys, runOpts, results) {
|
|
68
|
-
for (const key of keys) {
|
|
69
|
-
try {
|
|
70
|
-
const { trustRun, apiError } = await runDatasourceAgentTrust(key, runOpts);
|
|
71
|
-
pushTrustResult(results, key, trustRun, apiError);
|
|
72
|
-
} catch (err) {
|
|
73
|
-
results.push({ key, success: false, error: err.message, trustRun: null });
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* @async
|
|
80
|
-
* @param {string} externalSystem
|
|
81
|
-
* @param {Object} options
|
|
82
|
-
* @returns {Promise<{ success: boolean, results: Array<Object>, systemKey: string }>}
|
|
23
|
+
* @returns {Promise<{ success: boolean, results: Array<Object>, systemKey: string, trustReport?: Object }>}
|
|
83
24
|
*/
|
|
84
25
|
async function runTestTrustForExternalSystem(externalSystem, options = {}) {
|
|
85
|
-
const { systemKey
|
|
86
|
-
if (keys.length === 0) {
|
|
87
|
-
logger.log(chalk.yellow(`No datasources found for ${externalSystem}.`));
|
|
88
|
-
return { success: true, results: [], systemKey };
|
|
89
|
-
}
|
|
26
|
+
const { systemKey } = resolveExternalIntegrationContext(externalSystem);
|
|
90
27
|
|
|
91
28
|
const uploadCtx = await syncLocalIfRequested(systemKey, options);
|
|
92
29
|
if (uploadCtx?.authConfig && uploadCtx?.dataplaneUrl) {
|
|
@@ -95,30 +32,42 @@ async function runTestTrustForExternalSystem(externalSystem, options = {}) {
|
|
|
95
32
|
options.silentResolve = true;
|
|
96
33
|
}
|
|
97
34
|
if (options.revalidate === true) {
|
|
98
|
-
logger.log(chalk.cyan('Forcing revalidation (cache bypass)
|
|
35
|
+
logger.log(chalk.cyan('Forcing revalidation (cache bypass)…'));
|
|
99
36
|
}
|
|
100
37
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
38
|
+
let authConfig = options.authConfig;
|
|
39
|
+
let dataplaneUrl = options.dataplaneUrl;
|
|
40
|
+
if (!authConfig || !dataplaneUrl) {
|
|
41
|
+
const configObj = await getConfig();
|
|
42
|
+
const auth = await setupIntegrationTestAuth(
|
|
43
|
+
externalSystem,
|
|
44
|
+
{
|
|
45
|
+
environment: options.env,
|
|
46
|
+
authConfig: options.authConfig,
|
|
47
|
+
dataplaneUrl: options.dataplaneUrl,
|
|
48
|
+
silentResolve: options.silentResolve === true
|
|
49
|
+
},
|
|
50
|
+
configObj
|
|
51
|
+
);
|
|
52
|
+
authConfig = auth.authConfig;
|
|
53
|
+
dataplaneUrl = auth.dataplaneUrl;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const trustReport = await runSystemVerifyTrust(dataplaneUrl, authConfig, systemKey, {
|
|
57
|
+
forceRevalidate: options.revalidate === true
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
const results = (trustReport.datasourceRows || []).map(row => ({
|
|
61
|
+
key: row.datasourceKey,
|
|
62
|
+
success: trustReport.verdict === 'VERIFIED' || trustReport.verdict !== 'FAILED',
|
|
63
|
+
trustRun: {
|
|
64
|
+
trustDecision: row.trustDecision,
|
|
65
|
+
validationStatus: row.validationStatus
|
|
66
|
+
}
|
|
67
|
+
}));
|
|
68
|
+
|
|
69
|
+
const success = trustReport.verdict === 'VERIFIED';
|
|
70
|
+
return { success, results, systemKey, trustReport };
|
|
122
71
|
}
|
|
123
72
|
|
|
124
73
|
module.exports = {
|
|
@@ -328,6 +328,35 @@ async function ensureAppFromTemplate(appName, opts = {}) {
|
|
|
328
328
|
return primaryCopied;
|
|
329
329
|
}
|
|
330
330
|
|
|
331
|
+
/** Dataplane app key materialized for dataplane install (worker/beat are compose sidecars). */
|
|
332
|
+
const DATAPLANE_BUILDER_APP_KEYS = Object.freeze(['dataplane']);
|
|
333
|
+
|
|
334
|
+
/** Builder dirs removed on up-platform / setup force (includes Celery companions). */
|
|
335
|
+
const PLATFORM_BUILDER_CLEAN_APP_KEYS = Object.freeze([
|
|
336
|
+
'keycloak',
|
|
337
|
+
'miso-controller',
|
|
338
|
+
...DATAPLANE_BUILDER_APP_KEYS
|
|
339
|
+
]);
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Ensure dataplane application manifest exists under the builder root.
|
|
343
|
+
* Worker/beat sidecars are resolved from parent application.yaml at run/compose time.
|
|
344
|
+
*
|
|
345
|
+
* @param {object} [opts]
|
|
346
|
+
* @param {boolean} [opts.silent]
|
|
347
|
+
* @returns {Promise<boolean>} True if any app template was copied
|
|
348
|
+
*/
|
|
349
|
+
async function ensureDataplaneAppsFromTemplate(opts = {}) {
|
|
350
|
+
let anyCopied = false;
|
|
351
|
+
for (const appName of DATAPLANE_BUILDER_APP_KEYS) {
|
|
352
|
+
const copied = await ensureAppFromTemplate(appName, opts);
|
|
353
|
+
if (copied) {
|
|
354
|
+
anyCopied = true;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
return anyCopied;
|
|
358
|
+
}
|
|
359
|
+
|
|
331
360
|
/**
|
|
332
361
|
* Merge builder/packages `application.yaml` into `~/.aifabrix/urls.local.yaml`.
|
|
333
362
|
* Same scan as the end of {@link prepareUrlsLocalRegistryForUpPlatform}; call after platform app
|
|
@@ -354,14 +383,17 @@ async function prepareUrlsLocalRegistryForUpPlatform(opts = {}) {
|
|
|
354
383
|
const templateOpts = { silent: Boolean(opts.silent) };
|
|
355
384
|
await ensureAppFromTemplate('keycloak', templateOpts);
|
|
356
385
|
await ensureAppFromTemplate('miso-controller', templateOpts);
|
|
357
|
-
await
|
|
386
|
+
await ensureDataplaneAppsFromTemplate(templateOpts);
|
|
358
387
|
refreshUrlsLocalRegistryForCurrentProject();
|
|
359
388
|
}
|
|
360
389
|
|
|
361
390
|
module.exports = {
|
|
362
391
|
applyUpPlatformForceConfig,
|
|
363
392
|
cleanBuilderAppDirs,
|
|
393
|
+
DATAPLANE_BUILDER_APP_KEYS,
|
|
394
|
+
PLATFORM_BUILDER_CLEAN_APP_KEYS,
|
|
364
395
|
ensureAppFromTemplate,
|
|
396
|
+
ensureDataplaneAppsFromTemplate,
|
|
365
397
|
patchEnvOutputPathForDeployOnly,
|
|
366
398
|
validateEnvOutputPathFolderOrNull,
|
|
367
399
|
getEnvOutputPathFolder,
|