@aifabrix/builder 2.44.3 → 2.44.4
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 +12 -1
- package/lib/api/certificates.api.js +21 -3
- 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.test-commands.js +67 -35
- package/lib/cli/setup-utility.js +1 -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.js +1 -2
- package/lib/commands/test-e2e-external.js +5 -6
- package/lib/commands/upload.js +18 -4
- package/lib/commands/wizard-dataplane.js +14 -6
- 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/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/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-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/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/external-system/README.md.hbs +1 -2
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
|
@@ -72,6 +72,9 @@ const defaultProject = {
|
|
|
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-structural.test.js',
|
|
77
|
+
'lib/datasource/log-viewer-structural.test.js',
|
|
75
78
|
'/tests/lib/commands/parameters-validate.test.js',
|
|
76
79
|
'\\\\tests\\\\lib\\\\commands\\\\parameters-validate.test.js',
|
|
77
80
|
'lib/commands/parameters-validate.test.js',
|
|
@@ -190,6 +193,10 @@ 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',
|
|
@@ -222,7 +229,10 @@ const isolatedProjects = [
|
|
|
222
229
|
makeIsolatedProject('datasource-validation-watch', [
|
|
223
230
|
'**/tests/lib/utils/datasource-validation-watch.test.js'
|
|
224
231
|
]),
|
|
225
|
-
makeIsolatedProject('log-viewer', [
|
|
232
|
+
makeIsolatedProject('log-viewer', [
|
|
233
|
+
'**/tests/lib/datasource/log-viewer.test.js',
|
|
234
|
+
'**/tests/lib/datasource/log-viewer-structural.test.js'
|
|
235
|
+
]),
|
|
226
236
|
makeIsolatedProject('datasource-test-run-schema-sync', [
|
|
227
237
|
'**/tests/lib/utils/datasource-test-run-schema-sync.test.js'
|
|
228
238
|
]),
|
|
@@ -285,6 +295,7 @@ const isolatedProjects = [
|
|
|
285
295
|
makeIsolatedProject('generator-validation', ['**/tests/lib/generator/generator-validation.test.js']),
|
|
286
296
|
makeIsolatedProject('secrets-databaselog', ['**/tests/lib/core/secrets-databaselog.test.js']),
|
|
287
297
|
makeIsolatedProject('schema-241-alignment', ['**/tests/lib/validation/schema-241-alignment.test.js']),
|
|
298
|
+
makeIsolatedProject('schema-resolver-order', ['**/tests/lib/utils/schema-resolver-order.test.js']),
|
|
288
299
|
makeIsolatedProject('app-module', ['**/tests/lib/app/app.test.js']),
|
|
289
300
|
makeIsolatedProject('admin-secrets', ['**/tests/lib/core/admin-secrets.test.js'])
|
|
290
301
|
];
|
|
@@ -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
|
|
|
@@ -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}`));
|
|
@@ -54,6 +54,70 @@ 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
|
+
sync: options.sync === 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);
|
|
@@ -64,40 +128,7 @@ async function runTestE2ECommand(appName, options) {
|
|
|
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');
|
|
@@ -190,6 +221,7 @@ function setupInstallTestE2eLintCommands(program) {
|
|
|
190
221
|
}
|
|
191
222
|
|
|
192
223
|
module.exports = {
|
|
193
|
-
setupInstallTestE2eLintCommands
|
|
224
|
+
setupInstallTestE2eLintCommands,
|
|
225
|
+
firstIssuanceFailureHintFromE2eResults
|
|
194
226
|
};
|
|
195
227
|
|
package/lib/cli/setup-utility.js
CHANGED
|
@@ -118,7 +118,7 @@ function setupResolveCommand(program) {
|
|
|
118
118
|
);
|
|
119
119
|
logger.log(`✔ Generated .env file: ${envPath}`);
|
|
120
120
|
if (envOnly) {
|
|
121
|
-
logger.log(chalk.gray(' (env-only mode: validation skipped; no application
|
|
121
|
+
logger.log(chalk.gray(' (env-only mode: validation skipped; no application config file)'));
|
|
122
122
|
} else if (!options.skipValidation) {
|
|
123
123
|
const validate = require('../validation/validate');
|
|
124
124
|
const result = await validate.validateAppOrFile(appName);
|
|
@@ -94,7 +94,7 @@ async function runDatasourceUnifiedTestOnceForWatch(datasourceKey, runOpts, disp
|
|
|
94
94
|
try {
|
|
95
95
|
const result = await runUnifiedDatasourceValidation(datasourceKey, runOpts);
|
|
96
96
|
const exitCode = finalizeUnifiedValidationResult(result, displayOpts);
|
|
97
|
-
await afterUnifiedValidationCertSync(exitCode, datasourceKey, certCliOptions, 'datasource test');
|
|
97
|
+
await afterUnifiedValidationCertSync(exitCode, datasourceKey, certCliOptions, 'datasource test', result.envelope);
|
|
98
98
|
return {
|
|
99
99
|
exitCode,
|
|
100
100
|
envelope: result.envelope
|
|
@@ -121,7 +121,7 @@ async function datasourceTestCommandAction(datasourceKey, options) {
|
|
|
121
121
|
const result = await runUnifiedDatasourceValidation(datasourceKey, runOpts);
|
|
122
122
|
await writeDatasourceTestDebugLogIfRequested(appKey, datasourceKey, result, options);
|
|
123
123
|
const exitCode = finalizeUnifiedValidationResult(result, displayOpts);
|
|
124
|
-
await afterUnifiedValidationCertSync(exitCode, datasourceKey, options, 'datasource test (watch)');
|
|
124
|
+
await afterUnifiedValidationCertSync(exitCode, datasourceKey, options, 'datasource test (watch)', result.envelope);
|
|
125
125
|
return {
|
|
126
126
|
exitCode,
|
|
127
127
|
envelope: result.envelope
|
|
@@ -140,7 +140,7 @@ async function datasourceTestCommandAction(datasourceKey, options) {
|
|
|
140
140
|
}
|
|
141
141
|
}
|
|
142
142
|
const exitCode = finalizeUnifiedValidationResult(result, displayOpts);
|
|
143
|
-
await afterUnifiedValidationCertSync(exitCode, datasourceKey, options, 'datasource test');
|
|
143
|
+
await afterUnifiedValidationCertSync(exitCode, datasourceKey, options, 'datasource test', result.envelope);
|
|
144
144
|
process.exit(exitCode);
|
|
145
145
|
} catch (error) {
|
|
146
146
|
logger.error(formatBlockingError('Datasource test failed:'), error.message);
|
|
@@ -195,7 +195,13 @@ async function runIntegrationOnceForWatch(datasourceKey, integOpts, options, uni
|
|
|
195
195
|
if (unifiedModes) {
|
|
196
196
|
const uni = unifiedCliResultFromIntegrationReturn(result);
|
|
197
197
|
const exitCode = finalizeUnifiedValidationResult(uni, unifiedDisplayOpts);
|
|
198
|
-
await afterUnifiedValidationCertSync(
|
|
198
|
+
await afterUnifiedValidationCertSync(
|
|
199
|
+
exitCode,
|
|
200
|
+
datasourceKey,
|
|
201
|
+
options,
|
|
202
|
+
'datasource test-integration (watch)',
|
|
203
|
+
uni.envelope
|
|
204
|
+
);
|
|
199
205
|
return { exitCode, envelope: uni.envelope };
|
|
200
206
|
}
|
|
201
207
|
displayIntegrationTestResults(
|
|
@@ -211,7 +217,13 @@ async function runIntegrationOnceForWatch(datasourceKey, integOpts, options, uni
|
|
|
211
217
|
warningsAsErrors: unifiedDisplayOpts.warningsAsErrors === true,
|
|
212
218
|
requireCert: unifiedDisplayOpts.requireCert === true
|
|
213
219
|
});
|
|
214
|
-
await afterUnifiedValidationCertSync(
|
|
220
|
+
await afterUnifiedValidationCertSync(
|
|
221
|
+
exitCode,
|
|
222
|
+
datasourceKey,
|
|
223
|
+
options,
|
|
224
|
+
'datasource test-integration (watch)',
|
|
225
|
+
result.datasourceTestRun || null
|
|
226
|
+
);
|
|
215
227
|
return { exitCode, envelope: result.datasourceTestRun || null };
|
|
216
228
|
} catch (err) {
|
|
217
229
|
logger.error(formatBlockingError('Integration test failed:'), err.message);
|
|
@@ -219,49 +231,67 @@ async function runIntegrationOnceForWatch(datasourceKey, integOpts, options, uni
|
|
|
219
231
|
}
|
|
220
232
|
}
|
|
221
233
|
|
|
234
|
+
async function integrationTestCommandActionWatch(datasourceKey, options, integOpts, unifiedDisplayOpts) {
|
|
235
|
+
const { appKey } = await resolveAppKeyForDatasource(datasourceKey, options.app);
|
|
236
|
+
await runDatasourceValidationWatchLoop({
|
|
237
|
+
appKey,
|
|
238
|
+
extraPaths: options.watchPath || [],
|
|
239
|
+
includeApplicationYaml: options.watchApplicationYaml === true,
|
|
240
|
+
watchCi: options.watchCi === true,
|
|
241
|
+
watchFullDiff: options.watchFullDiff === true,
|
|
242
|
+
runOnce: () => runIntegrationOnceForWatch(datasourceKey, integOpts, options, unifiedDisplayOpts)
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
async function integrationTestCommandActionNonWatch(datasourceKey, integOpts, options, unifiedDisplayOpts) {
|
|
247
|
+
const result = await runDatasourceTestIntegration(datasourceKey, integOpts);
|
|
248
|
+
const unifiedModes =
|
|
249
|
+
options.json || options.summary || options.warningsAsErrors || options.requireCert;
|
|
250
|
+
if (unifiedModes) {
|
|
251
|
+
const uni = unifiedCliResultFromIntegrationReturn(result);
|
|
252
|
+
const exitCode = finalizeUnifiedValidationResult(uni, unifiedDisplayOpts);
|
|
253
|
+
await afterUnifiedValidationCertSync(
|
|
254
|
+
exitCode,
|
|
255
|
+
datasourceKey,
|
|
256
|
+
options,
|
|
257
|
+
'datasource test-integration',
|
|
258
|
+
uni.envelope
|
|
259
|
+
);
|
|
260
|
+
process.exit(exitCode);
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
displayIntegrationTestResults(
|
|
264
|
+
{
|
|
265
|
+
systemKey: result.systemKey || 'unknown',
|
|
266
|
+
datasourceResults: [result],
|
|
267
|
+
success: result.success
|
|
268
|
+
},
|
|
269
|
+
options.verbose,
|
|
270
|
+
{ debug: options.debug, runType: 'integration' }
|
|
271
|
+
);
|
|
272
|
+
const integExit = finalizeAfterIntegrationDisplay(result, {
|
|
273
|
+
warningsAsErrors: unifiedDisplayOpts.warningsAsErrors === true,
|
|
274
|
+
requireCert: unifiedDisplayOpts.requireCert === true
|
|
275
|
+
});
|
|
276
|
+
await afterUnifiedValidationCertSync(
|
|
277
|
+
integExit,
|
|
278
|
+
datasourceKey,
|
|
279
|
+
options,
|
|
280
|
+
'datasource test-integration',
|
|
281
|
+
result.datasourceTestRun || null
|
|
282
|
+
);
|
|
283
|
+
process.exit(integExit);
|
|
284
|
+
}
|
|
285
|
+
|
|
222
286
|
async function integrationTestCommandAction(datasourceKey, options) {
|
|
223
287
|
const integOpts = buildIntegrationTestOpts(options);
|
|
224
288
|
const unifiedDisplayOpts = buildIntegrationUnifiedDisplayOpts(options);
|
|
225
289
|
try {
|
|
226
290
|
if (options.watch) {
|
|
227
|
-
|
|
228
|
-
await runDatasourceValidationWatchLoop({
|
|
229
|
-
appKey,
|
|
230
|
-
extraPaths: options.watchPath || [],
|
|
231
|
-
includeApplicationYaml: options.watchApplicationYaml === true,
|
|
232
|
-
watchCi: options.watchCi === true,
|
|
233
|
-
watchFullDiff: options.watchFullDiff === true,
|
|
234
|
-
runOnce: () => runIntegrationOnceForWatch(datasourceKey, integOpts, options, unifiedDisplayOpts)
|
|
235
|
-
});
|
|
236
|
-
return;
|
|
237
|
-
}
|
|
238
|
-
const result = await runDatasourceTestIntegration(datasourceKey, integOpts);
|
|
239
|
-
const unifiedModes =
|
|
240
|
-
options.json || options.summary || options.warningsAsErrors || options.requireCert;
|
|
241
|
-
if (unifiedModes) {
|
|
242
|
-
const exitCode = finalizeUnifiedValidationResult(
|
|
243
|
-
unifiedCliResultFromIntegrationReturn(result),
|
|
244
|
-
unifiedDisplayOpts
|
|
245
|
-
);
|
|
246
|
-
await afterUnifiedValidationCertSync(exitCode, datasourceKey, options, 'datasource test-integration');
|
|
247
|
-
process.exit(exitCode);
|
|
291
|
+
await integrationTestCommandActionWatch(datasourceKey, options, integOpts, unifiedDisplayOpts);
|
|
248
292
|
return;
|
|
249
293
|
}
|
|
250
|
-
|
|
251
|
-
{
|
|
252
|
-
systemKey: result.systemKey || 'unknown',
|
|
253
|
-
datasourceResults: [result],
|
|
254
|
-
success: result.success
|
|
255
|
-
},
|
|
256
|
-
options.verbose,
|
|
257
|
-
{ debug: options.debug, runType: 'integration' }
|
|
258
|
-
);
|
|
259
|
-
const integExit = finalizeAfterIntegrationDisplay(result, {
|
|
260
|
-
warningsAsErrors: unifiedDisplayOpts.warningsAsErrors === true,
|
|
261
|
-
requireCert: unifiedDisplayOpts.requireCert === true
|
|
262
|
-
});
|
|
263
|
-
await afterUnifiedValidationCertSync(integExit, datasourceKey, options, 'datasource test-integration');
|
|
264
|
-
process.exit(integExit);
|
|
294
|
+
await integrationTestCommandActionNonWatch(datasourceKey, integOpts, options, unifiedDisplayOpts);
|
|
265
295
|
} catch (error) {
|
|
266
296
|
logger.error(formatBlockingError('Integration test failed:'), error.message);
|
|
267
297
|
process.exit(4);
|
|
@@ -296,9 +326,8 @@ async function runDatasourceTestE2ECliOnce(datasourceKey, options) {
|
|
|
296
326
|
debug: options.debug,
|
|
297
327
|
verbose: options.verbose,
|
|
298
328
|
async: options.async !== false,
|
|
299
|
-
testCrud: options.testCrud,
|
|
300
|
-
recordId: options.recordId,
|
|
301
329
|
cleanup: options.cleanup,
|
|
330
|
+
runScenarios: options.runScenarios,
|
|
302
331
|
primaryKeyValue: options.primaryKeyValue,
|
|
303
332
|
minVectorHits: options.minVectorHits,
|
|
304
333
|
minProcessed: options.minProcessed,
|
|
@@ -340,8 +369,8 @@ async function runDatasourceTestE2ECliOnce(datasourceKey, options) {
|
|
|
340
369
|
}
|
|
341
370
|
|
|
342
371
|
async function runDatasourceTestE2ECliAction(datasourceKey, options) {
|
|
343
|
-
const { exitCode } = await runDatasourceTestE2ECliOnce(datasourceKey, options);
|
|
344
|
-
await afterUnifiedValidationCertSync(exitCode, datasourceKey, options, 'datasource test-e2e');
|
|
372
|
+
const { exitCode, envelope } = await runDatasourceTestE2ECliOnce(datasourceKey, options);
|
|
373
|
+
await afterUnifiedValidationCertSync(exitCode, datasourceKey, options, 'datasource test-e2e', envelope);
|
|
345
374
|
process.exit(exitCode);
|
|
346
375
|
}
|
|
347
376
|
|
|
@@ -371,7 +400,13 @@ async function e2eTestCommandAction(datasourceKey, capabilityKey, options) {
|
|
|
371
400
|
runOnce: async() => {
|
|
372
401
|
try {
|
|
373
402
|
const r = await runDatasourceTestE2ECliOnce(datasourceKey, mergedOptions);
|
|
374
|
-
await afterUnifiedValidationCertSync(
|
|
403
|
+
await afterUnifiedValidationCertSync(
|
|
404
|
+
r.exitCode,
|
|
405
|
+
datasourceKey,
|
|
406
|
+
mergedOptions,
|
|
407
|
+
'datasource test-e2e (watch)',
|
|
408
|
+
r.envelope
|
|
409
|
+
);
|
|
375
410
|
return r;
|
|
376
411
|
} catch (err) {
|
|
377
412
|
logger.error(formatBlockingError('E2E test failed:'), err.message);
|
|
@@ -166,8 +166,10 @@ function attachDatasourceTestE2eExclusiveOptions(cmd) {
|
|
|
166
166
|
'Minimum record count assertion (e2eOptions.minRecordCount)',
|
|
167
167
|
(v) => parseInt(String(v), 10)
|
|
168
168
|
)
|
|
169
|
-
.option(
|
|
170
|
-
|
|
169
|
+
.option(
|
|
170
|
+
'--no-run-scenarios',
|
|
171
|
+
'Do not expand testPayload.scenarios in capacity step (e2eOptions.runScenarios: false)'
|
|
172
|
+
)
|
|
171
173
|
.option('--no-cleanup', 'Disable cleanup after test (e2eOptions.cleanup: false)')
|
|
172
174
|
.option(
|
|
173
175
|
'--primary-key-value <value|@path>',
|