@aifabrix/builder 2.44.3 → 2.44.5
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 -1
- package/integration/roundtrip-test-local/README.md +1 -2
- package/integration/roundtrip-test-local2/README.md +1 -2
- package/jest.projects.js +31 -15
- package/lib/api/certificates.api.js +21 -3
- package/lib/api/types/wizard.types.js +2 -1
- package/lib/certification/post-unified-cert-sync.js +13 -2
- package/lib/certification/sync-after-external-command.js +6 -3
- package/lib/certification/sync-system-certification.js +60 -14
- package/lib/cli/setup-app.help.js +1 -1
- package/lib/cli/setup-app.test-commands.js +75 -39
- package/lib/cli/setup-infra.js +6 -2
- package/lib/cli/setup-utility.js +20 -1
- package/lib/commands/datasource-unified-test-cli.js +81 -46
- package/lib/commands/datasource-unified-test-cli.options.js +4 -2
- package/lib/commands/datasource.js +3 -31
- package/lib/commands/repair-datasource-keys.js +1 -1
- package/lib/commands/repair-datasource-openapi.js +57 -0
- package/lib/commands/repair-datasource.js +5 -0
- package/lib/commands/repair-internal.js +2 -4
- package/lib/commands/repair-rbac.js +25 -2
- package/lib/commands/repair.js +2 -19
- package/lib/commands/test-e2e-external.js +9 -9
- package/lib/commands/up-common.js +25 -0
- package/lib/commands/upload.js +18 -4
- package/lib/commands/wizard-core.js +53 -11
- package/lib/commands/wizard-dataplane.js +14 -6
- package/lib/commands/wizard-entity-selection.js +71 -14
- package/lib/commands/wizard-headless.js +5 -2
- package/lib/commands/wizard-helpers.js +13 -1
- package/lib/commands/wizard.js +208 -60
- package/lib/datasource/datasource-validate-display.js +162 -0
- package/lib/datasource/datasource-validate-summary.js +194 -0
- package/lib/datasource/test-e2e.js +65 -37
- package/lib/datasource/unified-validation-run-body.js +1 -2
- package/lib/datasource/validate.js +14 -6
- package/lib/external-system/test.js +12 -8
- package/lib/generator/external-controller-manifest.js +12 -2
- package/lib/generator/wizard-prompts.js +7 -1
- package/lib/generator/wizard.js +34 -0
- package/lib/schema/cip-capacity-display.fallback.json +7 -0
- package/lib/schema/datasource-test-run.schema.json +79 -1
- package/lib/schema/external-datasource.schema.json +94 -2
- package/lib/schema/flag-map-validation-run.json +1 -2
- package/lib/schema/type/document-storage.json +83 -3
- package/lib/schema/wizard-config.schema.json +1 -1
- package/lib/utils/configuration-env-resolver.js +38 -0
- package/lib/utils/dataplane-resolver.js +3 -2
- package/lib/utils/datasource-test-run-capacity-operations.js +149 -0
- package/lib/utils/datasource-test-run-debug-display.js +143 -1
- package/lib/utils/datasource-test-run-display.js +46 -33
- package/lib/utils/datasource-test-run-tty-log.js +6 -2
- package/lib/utils/datasource-test-run-tty-meta-lines.js +123 -0
- package/lib/utils/error-formatter.js +32 -2
- package/lib/utils/external-readme.js +47 -3
- package/lib/utils/external-system-readiness-core.js +39 -0
- package/lib/utils/external-system-readiness-deploy-display.js +2 -3
- package/lib/utils/external-system-readiness-display-internals.js +3 -2
- package/lib/utils/external-system-system-test-tty.js +33 -9
- package/lib/utils/external-system-validators.js +62 -5
- package/lib/utils/load-cip-capacity-display-config.js +130 -0
- package/lib/utils/paths.js +10 -3
- package/lib/utils/schema-resolver.js +98 -2
- package/lib/utils/urls-local-registry.js +52 -10
- package/lib/utils/validation-run-poll.js +15 -4
- package/lib/utils/validation-run-request.js +4 -6
- package/lib/validation/dimension-display-helpers.js +60 -0
- package/lib/validation/validate-display-log-helpers.js +39 -0
- package/lib/validation/validate-display.js +89 -83
- package/package.json +1 -1
- package/templates/applications/miso-controller/env.template +6 -6
- package/templates/external-system/README.md.hbs +58 -32
package/.npmrc.token
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
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
|
|
@@ -123,8 +123,7 @@ Options:
|
|
|
123
123
|
-e, --env <env> Environment: dev, tst, or pro
|
|
124
124
|
-v, --verbose Show detailed step output and poll progress
|
|
125
125
|
--debug Include debug output and write log to integration/roundtrip-test-local/logs/
|
|
126
|
-
--
|
|
127
|
-
--record-id <id> Record ID for test (body recordId)
|
|
126
|
+
--no-run-scenarios Skip expanding testPayload.scenarios in capacity step
|
|
128
127
|
--no-cleanup Disable cleanup after test (body cleanup: false)
|
|
129
128
|
--primary-key-value <value|@path> Primary key value or path to JSON file (e.g. @pk.json) for body primaryKeyValue
|
|
130
129
|
--no-async Use sync mode (no polling); single POST, no asyncRun
|
|
@@ -123,8 +123,7 @@ Options:
|
|
|
123
123
|
-e, --env <env> Environment: dev, tst, or pro
|
|
124
124
|
-v, --verbose Show detailed step output and poll progress
|
|
125
125
|
--debug Include debug output and write log to integration/roundtrip-test-local2/logs/
|
|
126
|
-
--
|
|
127
|
-
--record-id <id> Record ID for test (body recordId)
|
|
126
|
+
--no-run-scenarios Skip expanding testPayload.scenarios in capacity step
|
|
128
127
|
--no-cleanup Disable cleanup after test (body cleanup: false)
|
|
129
128
|
--primary-key-value <value|@path> Primary key value or path to JSON file (e.g. @pk.json) for body primaryKeyValue
|
|
130
129
|
--no-async Use sync mode (no polling); single POST, no asyncRun
|
package/jest.projects.js
CHANGED
|
@@ -57,21 +57,28 @@ const defaultProject = {
|
|
|
57
57
|
'/tests/lib/utils/cli-utils.test.js',
|
|
58
58
|
'/tests/lib/utils/external-system-display.test.js',
|
|
59
59
|
'/tests/lib/utils/dev-hosts-helper.test.js',
|
|
60
|
-
'/tests/lib/utils/
|
|
60
|
+
'/tests/lib/utils/register-aifabrix-shell-env.test.js',
|
|
61
61
|
'/tests/lib/utils/datasource-validation-watch.test.js',
|
|
62
62
|
'\\\\tests\\\\lib\\\\utils\\\\cli-utils.test.js',
|
|
63
63
|
'\\\\tests\\\\lib\\\\utils\\\\external-system-display.test.js',
|
|
64
64
|
'\\\\tests\\\\lib\\\\utils\\\\dev-hosts-helper.test.js',
|
|
65
|
-
'\\\\tests\\\\lib\\\\utils\\\\
|
|
65
|
+
'\\\\tests\\\\lib\\\\utils\\\\register-aifabrix-shell-env.test.js',
|
|
66
66
|
'\\\\tests\\\\lib\\\\utils\\\\datasource-validation-watch.test.js',
|
|
67
67
|
'lib/utils/dev-hosts-helper.test.js',
|
|
68
|
-
'lib/utils/
|
|
68
|
+
'lib/utils/register-aifabrix-shell-env.test.js',
|
|
69
69
|
'lib/utils/datasource-validation-watch.test.js',
|
|
70
70
|
'dev-hosts-helper\\.test\\.js',
|
|
71
|
-
'
|
|
71
|
+
'register-aifabrix-shell-env\\.test\\.js',
|
|
72
72
|
'/tests/lib/datasource/log-viewer.test.js',
|
|
73
73
|
'\\\\tests\\\\lib\\\\datasource\\\\log-viewer.test.js',
|
|
74
74
|
'lib/datasource/log-viewer.test.js',
|
|
75
|
+
'/tests/lib/datasource/log-viewer-structural.test.js',
|
|
76
|
+
'/tests/lib/datasource/log-viewer-run.test.js',
|
|
77
|
+
'\\\\tests\\\\lib\\\\datasource\\\\log-viewer-structural.test.js',
|
|
78
|
+
'\\\\tests\\\\lib\\\\datasource\\\\log-viewer-run.test.js',
|
|
79
|
+
'lib/datasource/log-viewer-structural.test.js',
|
|
80
|
+
'lib/datasource/log-viewer-run.test.js',
|
|
81
|
+
'log-viewer-run\\.test\\.js',
|
|
75
82
|
'/tests/lib/commands/parameters-validate.test.js',
|
|
76
83
|
'\\\\tests\\\\lib\\\\commands\\\\parameters-validate.test.js',
|
|
77
84
|
'lib/commands/parameters-validate.test.js',
|
|
@@ -150,10 +157,6 @@ const defaultProject = {
|
|
|
150
157
|
'\\\\tests\\\\lib\\\\utils\\\\paths-app-listing.test.js',
|
|
151
158
|
'lib/utils/paths-app-listing.test.js',
|
|
152
159
|
'paths-app-listing\\.test\\.js',
|
|
153
|
-
'/tests/lib/utils/url-declarative-truth-table-124.test.js',
|
|
154
|
-
'\\\\tests\\\\lib\\\\utils\\\\url-declarative-truth-table-124.test.js',
|
|
155
|
-
'lib/utils/url-declarative-truth-table-124.test.js',
|
|
156
|
-
'url-declarative-truth-table-124\\.test\\.js',
|
|
157
160
|
'/tests/lib/generator/generator-external-rbac.test.js',
|
|
158
161
|
'\\\\tests\\\\lib\\\\generator\\\\generator-external-rbac.test.js',
|
|
159
162
|
'lib/generator/generator-external-rbac.test.js',
|
|
@@ -190,9 +193,17 @@ const defaultProject = {
|
|
|
190
193
|
'\\\\tests\\\\lib\\\\validation\\\\schema-241-alignment.test.js',
|
|
191
194
|
'lib/validation/schema-241-alignment.test.js',
|
|
192
195
|
'schema-241-alignment\\.test\\.js',
|
|
196
|
+
'/tests/lib/utils/schema-resolver-order.test.js',
|
|
197
|
+
'\\\\tests\\\\lib\\\\utils\\\\schema-resolver-order.test.js',
|
|
198
|
+
'lib/utils/schema-resolver-order.test.js',
|
|
199
|
+
'schema-resolver-order\\.test\\.js',
|
|
193
200
|
'/tests/lib/app/app.test.js',
|
|
194
201
|
'\\\\tests\\\\lib\\\\app\\\\app.test.js',
|
|
195
202
|
'lib/app/app.test.js',
|
|
203
|
+
'/tests/lib/templates/application-frontdoor-paths.contract.test.js',
|
|
204
|
+
'\\\\tests\\\\lib\\\\templates\\\\application-frontdoor-paths.contract.test.js',
|
|
205
|
+
'lib/templates/application-frontdoor-paths.contract.test.js',
|
|
206
|
+
'application-frontdoor-paths\\.contract\\.test\\.js',
|
|
196
207
|
'/tests/lib/core/admin-secrets.test.js',
|
|
197
208
|
'\\\\tests\\\\lib\\\\core\\\\admin-secrets.test.js',
|
|
198
209
|
'lib/core/admin-secrets.test.js'
|
|
@@ -214,21 +225,28 @@ const isolatedProjects = [
|
|
|
214
225
|
makeIsolatedProject('cli-utils', ['**/tests/lib/utils/cli-utils.test.js']),
|
|
215
226
|
makeIsolatedProject('external-system-display', ['**/tests/lib/utils/external-system-display.test.js']),
|
|
216
227
|
makeIsolatedProject('dev-hosts-helper', ['**/tests/lib/utils/dev-hosts-helper.test.js']),
|
|
217
|
-
makeIsolatedProject('declarative-url-matrix-d-reload', [
|
|
218
|
-
'**/tests/lib/utils/declarative-url-matrix-d-reload.test.js'
|
|
219
|
-
]),
|
|
220
228
|
makeIsolatedProject('parameters-validate', ['**/tests/lib/commands/parameters-validate.test.js']),
|
|
221
229
|
makeIsolatedProject('paths-app-listing', ['**/tests/lib/utils/paths-app-listing.test.js']),
|
|
222
230
|
makeIsolatedProject('datasource-validation-watch', [
|
|
223
231
|
'**/tests/lib/utils/datasource-validation-watch.test.js'
|
|
224
232
|
]),
|
|
225
|
-
makeIsolatedProject('log-viewer', [
|
|
233
|
+
makeIsolatedProject('log-viewer', [
|
|
234
|
+
'**/tests/lib/datasource/log-viewer.test.js',
|
|
235
|
+
'**/tests/lib/datasource/log-viewer-structural.test.js',
|
|
236
|
+
'**/tests/lib/datasource/log-viewer-run.test.js'
|
|
237
|
+
]),
|
|
238
|
+
makeIsolatedProject('register-aifabrix-shell-env', [
|
|
239
|
+
'**/tests/lib/utils/register-aifabrix-shell-env.test.js'
|
|
240
|
+
]),
|
|
226
241
|
makeIsolatedProject('datasource-test-run-schema-sync', [
|
|
227
242
|
'**/tests/lib/utils/datasource-test-run-schema-sync.test.js'
|
|
228
243
|
]),
|
|
229
244
|
makeIsolatedProject('infra-platform-contract', [
|
|
230
245
|
'**/tests/lib/parameters/infra-platform-contract.test.js'
|
|
231
246
|
]),
|
|
247
|
+
makeIsolatedProject('application-frontdoor-paths-contract', [
|
|
248
|
+
'**/tests/lib/templates/application-frontdoor-paths.contract.test.js'
|
|
249
|
+
]),
|
|
232
250
|
makeIsolatedProject('database-secret-values', [
|
|
233
251
|
'**/tests/lib/parameters/database-secret-values.test.js'
|
|
234
252
|
]),
|
|
@@ -273,9 +291,6 @@ const isolatedProjects = [
|
|
|
273
291
|
makeIsolatedProject('helpers-ensure-admin-secrets', [
|
|
274
292
|
'**/tests/lib/infrastructure/helpers-ensure-admin-secrets.test.js'
|
|
275
293
|
]),
|
|
276
|
-
makeIsolatedProject('url-declarative-truth-table-124', [
|
|
277
|
-
'**/tests/lib/utils/url-declarative-truth-table-124.test.js'
|
|
278
|
-
]),
|
|
279
294
|
makeIsolatedProject('secrets-generator', ['**/tests/lib/utils/secrets-generator.test.js']),
|
|
280
295
|
makeIsolatedProject('app-uncovered-lines', ['**/tests/lib/app/app-uncovered-lines.test.js']),
|
|
281
296
|
makeIsolatedProject('ensure-dev-certs-for-remote-docker', [
|
|
@@ -285,6 +300,7 @@ const isolatedProjects = [
|
|
|
285
300
|
makeIsolatedProject('generator-validation', ['**/tests/lib/generator/generator-validation.test.js']),
|
|
286
301
|
makeIsolatedProject('secrets-databaselog', ['**/tests/lib/core/secrets-databaselog.test.js']),
|
|
287
302
|
makeIsolatedProject('schema-241-alignment', ['**/tests/lib/validation/schema-241-alignment.test.js']),
|
|
303
|
+
makeIsolatedProject('schema-resolver-order', ['**/tests/lib/utils/schema-resolver-order.test.js']),
|
|
288
304
|
makeIsolatedProject('app-module', ['**/tests/lib/app/app.test.js']),
|
|
289
305
|
makeIsolatedProject('admin-secrets', ['**/tests/lib/core/admin-secrets.test.js'])
|
|
290
306
|
];
|
|
@@ -5,6 +5,24 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
const { ApiClient } = require('./index');
|
|
8
|
+
const { normalizeDataplaneAuth } = require('./validation-run.api');
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @param {Object} authConfig
|
|
12
|
+
* @returns {Object}
|
|
13
|
+
*/
|
|
14
|
+
function dataplaneAuthForBearerGet(authConfig) {
|
|
15
|
+
if (!authConfig || typeof authConfig !== 'object') {
|
|
16
|
+
return authConfig;
|
|
17
|
+
}
|
|
18
|
+
if (authConfig.token || authConfig.clientId) {
|
|
19
|
+
return authConfig;
|
|
20
|
+
}
|
|
21
|
+
if (authConfig.apiKey) {
|
|
22
|
+
return { ...authConfig, token: authConfig.apiKey, type: authConfig.type || 'bearer' };
|
|
23
|
+
}
|
|
24
|
+
return normalizeDataplaneAuth(authConfig);
|
|
25
|
+
}
|
|
8
26
|
|
|
9
27
|
/**
|
|
10
28
|
* Get active trusted integration certificate for a datasource.
|
|
@@ -18,7 +36,7 @@ const { ApiClient } = require('./index');
|
|
|
18
36
|
* @returns {Promise<Object>} API envelope `{ success, data?, status, ... }`
|
|
19
37
|
*/
|
|
20
38
|
async function getActiveIntegrationCertificate(dataplaneUrl, authConfig, systemKey, datasourceKey) {
|
|
21
|
-
const client = new ApiClient(dataplaneUrl, authConfig);
|
|
39
|
+
const client = new ApiClient(dataplaneUrl, dataplaneAuthForBearerGet(authConfig));
|
|
22
40
|
const path = `/api/v1/systems/${encodeURIComponent(systemKey)}/datasources/${encodeURIComponent(
|
|
23
41
|
datasourceKey
|
|
24
42
|
)}/certificates/active`;
|
|
@@ -36,7 +54,7 @@ async function getActiveIntegrationCertificate(dataplaneUrl, authConfig, systemK
|
|
|
36
54
|
* @returns {Promise<Object>}
|
|
37
55
|
*/
|
|
38
56
|
async function listIntegrationCertificates(dataplaneUrl, authConfig, params = {}) {
|
|
39
|
-
const client = new ApiClient(dataplaneUrl, authConfig);
|
|
57
|
+
const client = new ApiClient(dataplaneUrl, dataplaneAuthForBearerGet(authConfig));
|
|
40
58
|
return await client.get('/api/v1/certificates', { params });
|
|
41
59
|
}
|
|
42
60
|
|
|
@@ -51,7 +69,7 @@ async function listIntegrationCertificates(dataplaneUrl, authConfig, params = {}
|
|
|
51
69
|
* @returns {Promise<Object>}
|
|
52
70
|
*/
|
|
53
71
|
async function verifyIntegrationCertificate(dataplaneUrl, authConfig, body) {
|
|
54
|
-
const client = new ApiClient(dataplaneUrl, authConfig);
|
|
72
|
+
const client = new ApiClient(dataplaneUrl, dataplaneAuthForBearerGet(authConfig));
|
|
55
73
|
return await client.post('/api/v1/certificates/verify', { body: body || {} });
|
|
56
74
|
}
|
|
57
75
|
|
|
@@ -260,12 +260,13 @@
|
|
|
260
260
|
* @property {string} [source.serverUrl] - MCP server URL (for mcp-server)
|
|
261
261
|
* @property {string} [source.token] - MCP token (for mcp-server, supports ${ENV_VAR})
|
|
262
262
|
* @property {string} [source.platform] - Known platform (for known-platform)
|
|
263
|
+
* @property {string} [source.entityName] - Entity from discover-entities (openapi-file / openapi-url); skips interactive Step 4.5 when valid
|
|
263
264
|
* @property {Object} [credential] - Credential configuration
|
|
264
265
|
* @property {string} credential.action - Action ('create' | 'select' | 'skip')
|
|
265
266
|
* @property {string} [credential.credentialIdOrKey] - Credential ID/key (for select)
|
|
266
267
|
* @property {Object} [credential.config] - Credential config (for create)
|
|
267
268
|
* @property {Object} [preferences] - Generation preferences
|
|
268
|
-
* @property {string} [preferences.intent] - User intent (any descriptive text)
|
|
269
|
+
* @property {string} [preferences.intent] - User intent (any descriptive text, max 1000 chars)
|
|
269
270
|
* @property {string} [preferences.fieldOnboardingLevel] - Field level ('full' | 'standard' | 'minimal')
|
|
270
271
|
* @property {boolean} [preferences.enableOpenAPIGeneration] - Enable OpenAPI generation
|
|
271
272
|
* @property {boolean} [preferences.enableMCP] - Enable MCP
|
|
@@ -10,6 +10,7 @@ const chalk = require('chalk');
|
|
|
10
10
|
const logger = require('../utils/logger');
|
|
11
11
|
const { trySyncCertificationFromDataplaneForExternalApp } = require('./sync-after-external-command');
|
|
12
12
|
const { cliOptsSkipCertSync } = require('./cli-cert-sync-skip');
|
|
13
|
+
const { resolveDebugDisplayMode } = require('../utils/datasource-test-run-debug-display');
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* @async
|
|
@@ -17,14 +18,24 @@ const { cliOptsSkipCertSync } = require('./cli-cert-sync-skip');
|
|
|
17
18
|
* @param {string} datasourceKey
|
|
18
19
|
* @param {Object} options - CLI flags (app, noCertSync)
|
|
19
20
|
* @param {string} label - Log label
|
|
21
|
+
* @param {Object|null} [envelope] - Last DatasourceTestRun (optional); used for certificateIssuance failed hint
|
|
20
22
|
* @returns {Promise<void>}
|
|
21
23
|
*/
|
|
22
|
-
async function afterUnifiedValidationCertSync(exitCode, datasourceKey, options, label) {
|
|
24
|
+
async function afterUnifiedValidationCertSync(exitCode, datasourceKey, options, label, envelope = null) {
|
|
23
25
|
if (exitCode !== 0 || cliOptsSkipCertSync(options)) return;
|
|
24
26
|
try {
|
|
25
27
|
const { resolveAppKeyForDatasource } = require('../datasource/resolve-app');
|
|
26
28
|
const { appKey } = await resolveAppKeyForDatasource(datasourceKey, options.app);
|
|
27
|
-
|
|
29
|
+
let issuanceFailureHint = null;
|
|
30
|
+
if (envelope && envelope.certificateIssuance && envelope.certificateIssuance.status === 'failed') {
|
|
31
|
+
const ci = envelope.certificateIssuance;
|
|
32
|
+
issuanceFailureHint = [ci.reasonCode, ci.message].filter(Boolean).join(': ');
|
|
33
|
+
}
|
|
34
|
+
const verboseCertHints = resolveDebugDisplayMode(options.debug) !== null;
|
|
35
|
+
await trySyncCertificationFromDataplaneForExternalApp(appKey, label, {
|
|
36
|
+
issuanceFailureHint,
|
|
37
|
+
verboseCertHints
|
|
38
|
+
});
|
|
28
39
|
} catch (e) {
|
|
29
40
|
logger.log(chalk.yellow(`⚠ Certification sync (${label}) skipped: ${e.message}`));
|
|
30
41
|
}
|
|
@@ -16,9 +16,10 @@ const logger = require('../utils/logger');
|
|
|
16
16
|
* @async
|
|
17
17
|
* @param {string} appKey - Integration / system key
|
|
18
18
|
* @param {string} label - Short label for logs (e.g. "validate", "datasource test")
|
|
19
|
+
* @param {Object} [extra] - Optional `{ issuanceFailureHint }` from last DatasourceTestRun.certificateIssuance (failed)
|
|
19
20
|
* @returns {Promise<void>}
|
|
20
21
|
*/
|
|
21
|
-
async function trySyncCertificationFromDataplaneForExternalApp(appKey, label) {
|
|
22
|
+
async function trySyncCertificationFromDataplaneForExternalApp(appKey, label, extra = {}) {
|
|
22
23
|
try {
|
|
23
24
|
const { detectAppType } = require('../utils/paths');
|
|
24
25
|
const t = await detectAppType(appKey).catch(() => null);
|
|
@@ -29,7 +30,7 @@ async function trySyncCertificationFromDataplaneForExternalApp(appKey, label) {
|
|
|
29
30
|
const { maybeSyncSystemCertificationFromDataplane } = require('./sync-system-certification');
|
|
30
31
|
|
|
31
32
|
validateSystemKeyFormat(appKey);
|
|
32
|
-
const { dataplaneUrl, authConfig } = await resolveDataplaneAndAuth(appKey);
|
|
33
|
+
const { dataplaneUrl, authConfig } = await resolveDataplaneAndAuth(appKey, { silent: true });
|
|
33
34
|
if (!authConfig.token) {
|
|
34
35
|
logger.log(chalk.gray(`Certification sync (${label}) skipped: no Bearer token (run aifabrix login).`));
|
|
35
36
|
return;
|
|
@@ -42,7 +43,9 @@ async function trySyncCertificationFromDataplaneForExternalApp(appKey, label) {
|
|
|
42
43
|
systemKey: manifest.key,
|
|
43
44
|
dataplaneUrl,
|
|
44
45
|
authConfig,
|
|
45
|
-
datasourceKeys: dsKeys
|
|
46
|
+
datasourceKeys: dsKeys,
|
|
47
|
+
issuanceFailureHint: extra && extra.issuanceFailureHint ? String(extra.issuanceFailureHint).trim() : null,
|
|
48
|
+
verboseCertHints: extra && extra.verboseCertHints === true
|
|
46
49
|
});
|
|
47
50
|
} catch (e) {
|
|
48
51
|
logger.log(chalk.yellow(`⚠ Certification sync (${label}) skipped: ${e.message}`));
|
|
@@ -84,15 +84,43 @@ function tryWriteSystemCertification(systemFilePath, systemObj, nextCert) {
|
|
|
84
84
|
/**
|
|
85
85
|
* @param {Object|null} chosen
|
|
86
86
|
* @param {'no_active'|'no_public_key'} detail
|
|
87
|
+
* @param {string|null} [issuanceFailureHint] - From last DatasourceTestRun.certificateIssuance when status failed
|
|
88
|
+
* @param {boolean} [verboseCertHints] - Extra gray lines and auto-issue detail (CLI `--debug`)
|
|
87
89
|
*/
|
|
88
|
-
function logSkippedCertification(chosen, detail) {
|
|
90
|
+
function logSkippedCertification(chosen, detail, issuanceFailureHint, verboseCertHints = false) {
|
|
89
91
|
if (detail === 'no_active' || !chosen) {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
)
|
|
92
|
+
const hint = issuanceFailureHint && String(issuanceFailureHint).trim();
|
|
93
|
+
const certNotPassed =
|
|
94
|
+
hint &&
|
|
95
|
+
(hint.includes('CERTIFICATION_NOT_PASSED') ||
|
|
96
|
+
hint.toLowerCase().includes('certification did not pass'));
|
|
97
|
+
if (certNotPassed) {
|
|
98
|
+
logger.log(
|
|
99
|
+
chalk.yellow(
|
|
100
|
+
'⚠ Certification not written: no active integration certificate because certification did not pass on the dataplane issuance validation pass.'
|
|
101
|
+
)
|
|
102
|
+
);
|
|
103
|
+
if (verboseCertHints) {
|
|
104
|
+
logger.log(
|
|
105
|
+
chalk.gray(
|
|
106
|
+
' E2E can be green for every datasource while auto-issue still fails: issuance re-validates the whole system before signing.'
|
|
107
|
+
)
|
|
108
|
+
);
|
|
109
|
+
if (hint) {
|
|
110
|
+
logger.log(chalk.gray(` Auto-issue detail: ${hint}`));
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
} else {
|
|
114
|
+
logger.log(
|
|
115
|
+
chalk.yellow(
|
|
116
|
+
'⚠ Certification not written: dataplane has no active trusted certificate for this system/datasource scope yet. ' +
|
|
117
|
+
'Fix auto-issue or signing (see hint), or run unified validation then upload or run cert sync again.'
|
|
118
|
+
)
|
|
119
|
+
);
|
|
120
|
+
if (hint && verboseCertHints) {
|
|
121
|
+
logger.log(chalk.gray(` Auto-issue detail: ${hint}`));
|
|
122
|
+
}
|
|
123
|
+
}
|
|
96
124
|
return;
|
|
97
125
|
}
|
|
98
126
|
logger.log(
|
|
@@ -111,13 +139,19 @@ function logSkippedCertification(chosen, detail) {
|
|
|
111
139
|
* @param {string} params.dataplaneUrl
|
|
112
140
|
* @param {Object} params.authConfig
|
|
113
141
|
* @param {string[]} params.datasourceKeys
|
|
142
|
+
* @param {boolean} [params.verboseCertHints]
|
|
114
143
|
* @returns {Promise<{ written: boolean, reason?: string }>}
|
|
115
144
|
*/
|
|
116
145
|
async function syncSystemCertificationFromDataplane(params) {
|
|
117
|
-
const { systemKey, dataplaneUrl, authConfig, datasourceKeys } = params;
|
|
146
|
+
const { systemKey, dataplaneUrl, authConfig, datasourceKeys, issuanceFailureHint, verboseCertHints } = params;
|
|
118
147
|
const resolved = resolvePrimarySystemFilePath(systemKey);
|
|
119
148
|
if (!resolved) return { written: false, reason: 'no_system_file' };
|
|
120
|
-
|
|
149
|
+
const hasBearerLike =
|
|
150
|
+
authConfig &&
|
|
151
|
+
typeof authConfig === 'object' &&
|
|
152
|
+
((typeof authConfig.token === 'string' && authConfig.token.trim()) ||
|
|
153
|
+
(typeof authConfig.apiKey === 'string' && authConfig.apiKey.trim()));
|
|
154
|
+
if (!dataplaneUrl || !authConfig || !hasBearerLike) {
|
|
121
155
|
return { written: false, reason: 'no_auth' };
|
|
122
156
|
}
|
|
123
157
|
|
|
@@ -137,7 +171,7 @@ async function syncSystemCertificationFromDataplane(params) {
|
|
|
137
171
|
const nextCert = buildCertificationFromArtifact(chosen, existing);
|
|
138
172
|
if (!nextCert) {
|
|
139
173
|
const detail = chosen ? 'no_public_key' : 'no_active';
|
|
140
|
-
logSkippedCertification(chosen, detail);
|
|
174
|
+
logSkippedCertification(chosen, detail, issuanceFailureHint, verboseCertHints === true);
|
|
141
175
|
return { written: false, reason: 'incomplete_certification', detail };
|
|
142
176
|
}
|
|
143
177
|
|
|
@@ -154,7 +188,8 @@ async function syncSystemCertificationFromDataplane(params) {
|
|
|
154
188
|
* @param {boolean} [params.noCertSync]
|
|
155
189
|
* @returns {Promise<void>}
|
|
156
190
|
*/
|
|
157
|
-
function logCertificationSyncNotWritten(r, label) {
|
|
191
|
+
function logCertificationSyncNotWritten(r, label, verboseCertHints = false) {
|
|
192
|
+
if (r && r.reason === 'incomplete_certification' && !verboseCertHints) return;
|
|
158
193
|
const prefix = label ? ` (${label})` : '';
|
|
159
194
|
const map = {
|
|
160
195
|
no_system_file: `No *-system* file found under integration folder for this key${prefix}.`,
|
|
@@ -168,21 +203,32 @@ function logCertificationSyncNotWritten(r, label) {
|
|
|
168
203
|
}
|
|
169
204
|
|
|
170
205
|
async function maybeSyncSystemCertificationFromDataplane(params) {
|
|
171
|
-
const {
|
|
206
|
+
const {
|
|
207
|
+
label,
|
|
208
|
+
noCertSync,
|
|
209
|
+
systemKey,
|
|
210
|
+
dataplaneUrl,
|
|
211
|
+
authConfig,
|
|
212
|
+
datasourceKeys,
|
|
213
|
+
issuanceFailureHint,
|
|
214
|
+
verboseCertHints
|
|
215
|
+
} = params;
|
|
172
216
|
if (noCertSync === true) return;
|
|
173
217
|
try {
|
|
174
218
|
const r = await syncSystemCertificationFromDataplane({
|
|
175
219
|
systemKey,
|
|
176
220
|
dataplaneUrl,
|
|
177
221
|
authConfig,
|
|
178
|
-
datasourceKeys
|
|
222
|
+
datasourceKeys,
|
|
223
|
+
issuanceFailureHint,
|
|
224
|
+
verboseCertHints
|
|
179
225
|
});
|
|
180
226
|
if (r.written) {
|
|
181
227
|
logger.log(
|
|
182
228
|
chalk.gray(`Updated certification block from dataplane${label ? ` (${label})` : ''} in system file.`)
|
|
183
229
|
);
|
|
184
230
|
} else if (r.reason) {
|
|
185
|
-
logCertificationSyncNotWritten(r, label);
|
|
231
|
+
logCertificationSyncNotWritten(r, label, verboseCertHints === true);
|
|
186
232
|
}
|
|
187
233
|
} catch (e) {
|
|
188
234
|
logger.log(chalk.yellow(`⚠ Certification sync skipped: ${e.message}`));
|
|
@@ -56,7 +56,7 @@ Examples:
|
|
|
56
56
|
Notes:
|
|
57
57
|
- To run E2E for one datasource, use:
|
|
58
58
|
aifabrix datasource test-e2e <datasourceKey>
|
|
59
|
-
-
|
|
59
|
+
- External integration: local system and datasource files are published to the dataplane before E2E (same as upload). Use --no-sync to exercise only config already deployed. The old --sync flag is a no-op (kept for scripts).
|
|
60
60
|
`;
|
|
61
61
|
|
|
62
62
|
module.exports = {
|
|
@@ -54,50 +54,81 @@ function setupTestCommand(program) {
|
|
|
54
54
|
});
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
/**
|
|
58
|
+
* First failed `certificateIssuance` across E2E datasource rows (for cert-sync hint).
|
|
59
|
+
* @param {Array<{ key?: string, datasourceTestRun?: { certificateIssuance?: { status?: string, reasonCode?: string, message?: string } } }>} results
|
|
60
|
+
* @returns {string|null}
|
|
61
|
+
*/
|
|
62
|
+
function firstIssuanceFailureHintFromE2eResults(results) {
|
|
63
|
+
const failed = [];
|
|
64
|
+
for (const row of results || []) {
|
|
65
|
+
const ci = row.datasourceTestRun && row.datasourceTestRun.certificateIssuance;
|
|
66
|
+
if (ci && ci.status === 'failed') {
|
|
67
|
+
failed.push({ key: row.key, ci });
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (failed.length === 0) return null;
|
|
71
|
+
const firstRc = failed[0].ci.reasonCode;
|
|
72
|
+
const sameAll = failed.every(f => f.ci.reasonCode === firstRc);
|
|
73
|
+
if (sameAll && failed.length > 1) {
|
|
74
|
+
const parts = [firstRc, failed[0].ci.message].filter(Boolean);
|
|
75
|
+
return `${parts.join(': ')} (${failed.length} datasource scopes; first: ${failed[0].key})`;
|
|
76
|
+
}
|
|
77
|
+
const parts = [failed[0].ci.reasonCode, failed[0].ci.message].filter(Boolean);
|
|
78
|
+
return `[${failed[0].key}] ${parts.join(': ')}`.trim();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* External integration E2E: run, display, exit on aggregate, optional cert sync.
|
|
83
|
+
* @param {string} appName
|
|
84
|
+
* @param {Object} options
|
|
85
|
+
* @returns {Promise<void>}
|
|
86
|
+
*/
|
|
87
|
+
async function runExternalIntegrationE2EAndCertSync(appName, options) {
|
|
88
|
+
const { runTestE2EForExternalSystem } = require('../commands/test-e2e-external');
|
|
89
|
+
const { success, results } = await runTestE2EForExternalSystem(appName, {
|
|
90
|
+
env: options.env,
|
|
91
|
+
debug: options.debug,
|
|
92
|
+
verbose: options.verbose,
|
|
93
|
+
async: options.async !== false,
|
|
94
|
+
noSync: options.noSync === true
|
|
95
|
+
});
|
|
96
|
+
const { displayIntegrationTestResults } = require('../utils/external-system-display');
|
|
97
|
+
const datasourceResults = results.map(r => ({
|
|
98
|
+
key: r.key,
|
|
99
|
+
success: r.success,
|
|
100
|
+
error: r.error,
|
|
101
|
+
skipped: false,
|
|
102
|
+
datasourceTestRun: r.datasourceTestRun
|
|
103
|
+
}));
|
|
104
|
+
displayIntegrationTestResults(
|
|
105
|
+
{ systemKey: appName, success, datasourceResults },
|
|
106
|
+
options.verbose,
|
|
107
|
+
{ debug: options.debug, runType: 'e2e' }
|
|
108
|
+
);
|
|
109
|
+
const { computeSystemExitCodeFromDatasourceRows } = require('../utils/datasource-test-run-exit');
|
|
110
|
+
const exitCode = computeSystemExitCodeFromDatasourceRows(datasourceResults, {
|
|
111
|
+
warningsAsErrors: options.warningsAsErrors === true,
|
|
112
|
+
requireCert: options.requireCert === true
|
|
113
|
+
});
|
|
114
|
+
if (exitCode !== 0) process.exit(exitCode);
|
|
115
|
+
if (cliOptsSkipCertSync(options)) return;
|
|
116
|
+
const { trySyncCertificationFromDataplaneForExternalApp } = require('../certification/sync-after-external-command');
|
|
117
|
+
const issuanceFailureHint = firstIssuanceFailureHintFromE2eResults(results);
|
|
118
|
+
await trySyncCertificationFromDataplaneForExternalApp(appName, 'test-e2e', { issuanceFailureHint });
|
|
119
|
+
}
|
|
120
|
+
|
|
57
121
|
async function runTestE2ECommand(appName, options) {
|
|
58
122
|
const pathsUtil = require('../utils/paths');
|
|
59
123
|
const appType = await pathsUtil.detectAppType(appName).catch(() => null);
|
|
60
|
-
if (options.
|
|
124
|
+
if (options.noSync === true && appType && appType.baseDir === 'builder') {
|
|
61
125
|
throw new Error(
|
|
62
|
-
'Option --sync applies only to external integration E2E (integration/<systemKey>/). ' +
|
|
63
|
-
'Remove --sync for builder app E2E
|
|
126
|
+
'Option --no-sync applies only to external integration E2E (integration/<systemKey>/). ' +
|
|
127
|
+
'Remove --no-sync for builder app E2E.'
|
|
64
128
|
);
|
|
65
129
|
}
|
|
66
130
|
if (appType && appType.baseDir === 'integration') {
|
|
67
|
-
|
|
68
|
-
const { success, results } = await runTestE2EForExternalSystem(appName, {
|
|
69
|
-
env: options.env,
|
|
70
|
-
debug: options.debug,
|
|
71
|
-
verbose: options.verbose,
|
|
72
|
-
async: options.async !== false,
|
|
73
|
-
sync: options.sync === true
|
|
74
|
-
});
|
|
75
|
-
const { displayIntegrationTestResults } = require('../utils/external-system-display');
|
|
76
|
-
const datasourceResults = results.map(r => ({
|
|
77
|
-
key: r.key,
|
|
78
|
-
success: r.success,
|
|
79
|
-
error: r.error,
|
|
80
|
-
skipped: false,
|
|
81
|
-
datasourceTestRun: r.datasourceTestRun
|
|
82
|
-
}));
|
|
83
|
-
displayIntegrationTestResults(
|
|
84
|
-
{
|
|
85
|
-
systemKey: appName,
|
|
86
|
-
success,
|
|
87
|
-
datasourceResults
|
|
88
|
-
},
|
|
89
|
-
options.verbose,
|
|
90
|
-
{ debug: options.debug, runType: 'e2e' }
|
|
91
|
-
);
|
|
92
|
-
const { computeSystemExitCodeFromDatasourceRows } = require('../utils/datasource-test-run-exit');
|
|
93
|
-
const exitCode = computeSystemExitCodeFromDatasourceRows(datasourceResults, {
|
|
94
|
-
warningsAsErrors: options.warningsAsErrors === true,
|
|
95
|
-
requireCert: options.requireCert === true
|
|
96
|
-
});
|
|
97
|
-
if (exitCode !== 0) process.exit(exitCode);
|
|
98
|
-
if (cliOptsSkipCertSync(options)) return;
|
|
99
|
-
const { trySyncCertificationFromDataplaneForExternalApp } = require('../certification/sync-after-external-command');
|
|
100
|
-
await trySyncCertificationFromDataplaneForExternalApp(appName, 'test-e2e');
|
|
131
|
+
await runExternalIntegrationE2EAndCertSync(appName, options);
|
|
101
132
|
return;
|
|
102
133
|
}
|
|
103
134
|
const { runAppTestE2e } = require('../commands/app-test');
|
|
@@ -135,7 +166,11 @@ function setupTestE2eCommand(program) {
|
|
|
135
166
|
.option('-d, --debug', 'Include debug output and write log to integration/<systemKey>/logs/')
|
|
136
167
|
.option(
|
|
137
168
|
'--sync',
|
|
138
|
-
'
|
|
169
|
+
'(Deprecated; no-op.) Local integration files are published before E2E by default; use --no-sync to skip.'
|
|
170
|
+
)
|
|
171
|
+
.option(
|
|
172
|
+
'--no-sync',
|
|
173
|
+
'Skip publishing local integration files; E2E uses the system config already on the dataplane (external integration only)'
|
|
139
174
|
)
|
|
140
175
|
.option('--warnings-as-errors', 'Treat aggregate warn as failure (exit 1)')
|
|
141
176
|
.option('--require-cert', 'Require certification passed on every datasource (exit 2 if not)')
|
|
@@ -190,6 +225,7 @@ function setupInstallTestE2eLintCommands(program) {
|
|
|
190
225
|
}
|
|
191
226
|
|
|
192
227
|
module.exports = {
|
|
193
|
-
setupInstallTestE2eLintCommands
|
|
228
|
+
setupInstallTestE2eLintCommands,
|
|
229
|
+
firstIssuanceFailureHintFromE2eResults
|
|
194
230
|
};
|
|
195
231
|
|
package/lib/cli/setup-infra.js
CHANGED
|
@@ -18,7 +18,7 @@ const { resolveControllerUrl } = require('../utils/controller-url');
|
|
|
18
18
|
const { handleLogin } = require('../commands/login');
|
|
19
19
|
const { handleUpMiso } = require('../commands/up-miso');
|
|
20
20
|
const { handleUpDataplane } = require('../commands/up-dataplane');
|
|
21
|
-
const { cleanBuilderAppDirs } = require('../commands/up-common');
|
|
21
|
+
const { applyUpPlatformForceConfig, cleanBuilderAppDirs } = require('../commands/up-common');
|
|
22
22
|
const {
|
|
23
23
|
loadInfraStatusSummary,
|
|
24
24
|
formatInfraStatusTitleLine,
|
|
@@ -184,10 +184,14 @@ function setupUpPlatformCommand(program) {
|
|
|
184
184
|
.option('-r, --registry <url>', 'Override registry for all apps (e.g. myacr.azurecr.io)')
|
|
185
185
|
.option('--registry-mode <mode>', 'Override registry mode (acr|external)')
|
|
186
186
|
.option('-i, --image <key>=<value>', 'Override image (e.g. keycloak=myreg/k:v1, miso-controller=myreg/m:v1, dataplane=myreg/d:v1); can be repeated', (v, prev) => (prev || []).concat([v]))
|
|
187
|
-
.option(
|
|
187
|
+
.option(
|
|
188
|
+
'-f, --force',
|
|
189
|
+
'Reset CLI auth (clear all device/client tokens, set environment to dev, set default controller URL from developer-id), clean builder/keycloak, builder/miso-controller, builder/dataplane, then re-fetch from templates'
|
|
190
|
+
)
|
|
188
191
|
.action(async(options) => {
|
|
189
192
|
try {
|
|
190
193
|
if (options.force) {
|
|
194
|
+
await applyUpPlatformForceConfig();
|
|
191
195
|
await cleanBuilderAppDirs(['keycloak', 'miso-controller', 'dataplane']);
|
|
192
196
|
}
|
|
193
197
|
await handleUpMiso(options);
|
package/lib/cli/setup-utility.js
CHANGED
|
@@ -30,6 +30,24 @@ Examples:
|
|
|
30
30
|
$ aifabrix validate --builder
|
|
31
31
|
`;
|
|
32
32
|
|
|
33
|
+
const REPAIR_HELP_AFTER = `
|
|
34
|
+
Examples:
|
|
35
|
+
$ aifabrix repair hubspot-demo
|
|
36
|
+
Align manifest, system/datasource files, RBAC extract, env.template, and deploy JSON under integration/<systemKey>/.
|
|
37
|
+
|
|
38
|
+
$ aifabrix repair hubspot-demo --dry-run
|
|
39
|
+
Show what would change without writing files.
|
|
40
|
+
|
|
41
|
+
$ aifabrix repair hubspot-demo --auth oauth2
|
|
42
|
+
Set authentication method; updates the system file and env.template (oauth2, aad, apikey, basic, …).
|
|
43
|
+
|
|
44
|
+
$ aifabrix repair hubspot-demo --rbac --expose --sync --test
|
|
45
|
+
Optional datasource fixes: RBAC roles/permissions, exposed.schema from attributes, default sync block, testPayload stubs.
|
|
46
|
+
|
|
47
|
+
$ aifabrix repair hubspot-demo --doc
|
|
48
|
+
Regenerate README.md from the current deployment manifest only (other drift fixes unchanged).
|
|
49
|
+
`;
|
|
50
|
+
|
|
33
51
|
/**
|
|
34
52
|
* Resolve app path and type for split-json (integration first, then builder).
|
|
35
53
|
*
|
|
@@ -118,7 +136,7 @@ function setupResolveCommand(program) {
|
|
|
118
136
|
);
|
|
119
137
|
logger.log(`✔ Generated .env file: ${envPath}`);
|
|
120
138
|
if (envOnly) {
|
|
121
|
-
logger.log(chalk.gray(' (env-only mode: validation skipped; no application
|
|
139
|
+
logger.log(chalk.gray(' (env-only mode: validation skipped; no application config file)'));
|
|
122
140
|
} else if (!options.skipValidation) {
|
|
123
141
|
const validate = require('../validation/validate');
|
|
124
142
|
const result = await validate.validateAppOrFile(appName);
|
|
@@ -185,6 +203,7 @@ function setupRepairCommand(program) {
|
|
|
185
203
|
.option('--expose', 'Set exposed.schema on each datasource from all fieldMappings.attributes keys (metadata.<key>); removes deprecated exposed.attributes if present')
|
|
186
204
|
.option('--sync', 'Add default sync section to datasources that lack it')
|
|
187
205
|
.option('--test', 'Generate testPayload.payloadTemplate and testPayload.expectedResult from attributes')
|
|
206
|
+
.addHelpText('after', REPAIR_HELP_AFTER)
|
|
188
207
|
.action(async(appName, options) => {
|
|
189
208
|
try {
|
|
190
209
|
const { repairExternalIntegration } = require('../commands/repair');
|