@aifabrix/builder 2.55.0 → 2.55.2
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/lib/agent-kit/host-approve.js +48 -6
- package/lib/agent-kit/init.js +2 -2
- package/lib/agent-kit/remote-prompts.js +46 -13
- package/lib/agent-kit/run.js +1 -1
- package/lib/agent-kit/start.js +310 -0
- package/lib/app/deploy.js +7 -4
- package/lib/app/offer-create-from-template.js +184 -0
- package/lib/cli/setup-app.js +8 -1
- package/lib/cli/setup-auth.js +11 -2
- package/lib/commands/agent-kit-help.js +74 -4
- package/lib/commands/agent-kit.js +83 -12
- package/lib/commands/auth-status-user.js +99 -0
- package/lib/commands/auth-status.js +14 -4
- package/lib/commands/datasource-load-export-cli.js +7 -2
- package/lib/commands/datasource-test-trust-cli.js +5 -1
- package/lib/commands/governance-command-action.js +5 -4
- package/lib/commands/identity-membership-role-cache.js +6 -1
- package/lib/commands/lifecycle-command-action.js +16 -15
- package/lib/commands/login-credentials.js +8 -3
- package/lib/commands/login-device.js +14 -5
- package/lib/commands/login.js +14 -1
- package/lib/commands/logout.js +50 -15
- package/lib/commands/role-assistant.js +24 -12
- package/lib/commands/verify-governance-command-action.js +9 -7
- package/lib/commands/verify-operations-command-action.js +9 -8
- package/lib/commands/verify-trust-command-action.js +6 -5
- package/lib/external-system/download.js +1 -2
- package/lib/generator/helpers.js +12 -1
- package/lib/integration-definition/apply-static-enterprise.js +5 -2
- package/lib/role-assistant/knowledge-sync-settings-push.js +172 -0
- package/lib/role-assistant/knowledge-sync.js +9 -126
- package/lib/role-assistant/test-cases-evaluate.js +12 -1
- package/lib/role-assistant/test-cases-evidence.js +44 -5
- package/lib/role-assistant/test-cases-lifecycle.js +9 -3
- package/lib/role-assistant/test-runner.js +3 -0
- package/lib/schema/infra-parameter.schema.json +51 -3
- package/lib/schema/infra.parameter.yaml +476 -40
- package/lib/schema/type/document-storage.json +1 -1
- package/lib/utils/api-required-permissions.js +271 -0
- package/lib/utils/api.js +16 -13
- package/lib/utils/cli-json-exit.js +41 -0
- package/lib/utils/cli-utils.js +23 -5
- package/lib/utils/controller-url.js +78 -4
- package/lib/utils/deployment-errors.js +15 -0
- package/lib/utils/deployment-validation-helpers.js +4 -1
- package/lib/utils/device-code.js +31 -10
- package/lib/utils/error-formatters/error-parser.js +16 -1
- package/lib/utils/error-formatters/permission-errors.js +19 -5
- package/lib/utils/keycloak-realm-ready.js +5 -2
- package/lib/utils/logger.js +1 -0
- package/lib/utils/paths.js +26 -5
- package/lib/utils/secrets-helpers.js +2 -2
- package/lib/utils/write-stream-and-wait.js +63 -0
- package/package.json +20 -6
- package/templates/agent-kit/agent-kit.yaml +1 -1
- package/templates/agent-kit/instructions/AGENTKIT.md +25 -4
- package/templates/agent-kit/instructions/root.AGENTS.md +1 -1
- package/templates/agent-kit/skills/aifabrix-connected-system/SKILL.md +2 -1
- package/templates/agent-kit/skills/aifabrix-connected-system/references/delivery-gates.md +1 -1
- package/templates/agent-kit/skills/aifabrix-plan/SKILL.md +2 -1
- package/templates/agent-kit/skills/aifabrix-prove/SKILL.md +1 -0
- package/templates/agent-kit/skills/aifabrix-role-assistant/SKILL.md +1 -0
- package/templates/agent-kit/skills/shared/hosts.md +13 -26
- package/templates/agent-kit/skills/shared/login.md +16 -0
- package/templates/agent-kit/workspace/README.md +1 -1
- package/templates/applications/dataplane/application.yaml +1 -2
- package/templates/applications/dataplane/env.template +5 -5
- package/templates/applications/miso-controller/application.yaml +21 -2
- package/templates/applications/miso-controller/env.template +89 -17
- package/templates/applications/miso-controller/rbac.yaml +5 -0
|
@@ -34,6 +34,7 @@ const {
|
|
|
34
34
|
displayStoredClientTokensSection,
|
|
35
35
|
tryResolveClientTokenAuth
|
|
36
36
|
} = require('./auth-status-client-tokens');
|
|
37
|
+
const { parseAuthUserResponse } = require('./auth-status-user');
|
|
37
38
|
|
|
38
39
|
/**
|
|
39
40
|
* Format expiration date for display
|
|
@@ -71,11 +72,13 @@ async function checkDeviceToken(controllerUrl) {
|
|
|
71
72
|
const response = await getAuthUser(controllerUrl, authConfig);
|
|
72
73
|
|
|
73
74
|
if (response.success && response.data) {
|
|
75
|
+
const parsed = parseAuthUserResponse(response, deviceToken.token);
|
|
74
76
|
return {
|
|
75
77
|
type: 'Device Token',
|
|
76
78
|
token: deviceToken.token,
|
|
77
|
-
authenticated:
|
|
78
|
-
user:
|
|
79
|
+
authenticated: parsed.authenticated,
|
|
80
|
+
user: parsed.user,
|
|
81
|
+
username: parsed.username,
|
|
79
82
|
expiresAt: deviceToken.expiresAt
|
|
80
83
|
};
|
|
81
84
|
}
|
|
@@ -113,11 +116,13 @@ async function validateClientToken(token, controllerUrl, environment, appName, e
|
|
|
113
116
|
const response = await getAuthUser(controllerUrl, authConfig);
|
|
114
117
|
|
|
115
118
|
if (response.success && response.data) {
|
|
119
|
+
const parsed = parseAuthUserResponse(response, token);
|
|
116
120
|
return {
|
|
117
121
|
type: 'Client Token',
|
|
118
122
|
token: token,
|
|
119
|
-
authenticated:
|
|
120
|
-
user:
|
|
123
|
+
authenticated: parsed.authenticated,
|
|
124
|
+
user: parsed.user,
|
|
125
|
+
username: parsed.username,
|
|
121
126
|
expiresAt: expiresAt,
|
|
122
127
|
appName: appName
|
|
123
128
|
};
|
|
@@ -185,6 +190,11 @@ function displayTokenInfo(tokenInfo) {
|
|
|
185
190
|
logger.log(` Status: ${statusIcon} ${statusText}`);
|
|
186
191
|
logger.log(` Token Type: ${chalk.cyan(tokenInfo.type)}`);
|
|
187
192
|
|
|
193
|
+
if (tokenInfo.authenticated) {
|
|
194
|
+
const username = tokenInfo.username || (tokenInfo.user && tokenInfo.user.username);
|
|
195
|
+
logger.log(` User: ${username ? chalk.cyan(username) : chalk.gray('—')}`);
|
|
196
|
+
}
|
|
197
|
+
|
|
188
198
|
if (tokenInfo.appName) {
|
|
189
199
|
logger.log(` Application: ${chalk.cyan(tokenInfo.appName)}`);
|
|
190
200
|
}
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
'use strict';
|
|
8
8
|
|
|
9
9
|
const logger = require('../utils/logger');
|
|
10
|
+
const { writeJsonEnvelopeAndExit } = require('../utils/cli-json-exit');
|
|
10
11
|
const { formatBlockingError } = require('../utils/cli-test-layout-chalk');
|
|
11
12
|
const { runDatasourceLoad } = require('../datasource/bulk-loader-service');
|
|
12
13
|
const { runDatasourceExport } = require('../datasource/datasource-exporter-service');
|
|
@@ -82,7 +83,9 @@ async function datasourceLoadAction(datasourceKey, options) {
|
|
|
82
83
|
|
|
83
84
|
if (options.json) {
|
|
84
85
|
const { context: _ctx, ...payload } = result;
|
|
85
|
-
|
|
86
|
+
// exitCode 0 — write and resolve, never exit here; this action always
|
|
87
|
+
// exits unconditionally below with the real computed code.
|
|
88
|
+
await writeJsonEnvelopeAndExit(payload, 0);
|
|
86
89
|
} else {
|
|
87
90
|
displayDatasourceLoadTTY(result, { environment: options.env, verbose: options.verbose });
|
|
88
91
|
}
|
|
@@ -112,7 +115,9 @@ async function datasourceExportAction(datasourceKey, options) {
|
|
|
112
115
|
|
|
113
116
|
if (options.json) {
|
|
114
117
|
const { context: _ctx, ...payload } = result;
|
|
115
|
-
|
|
118
|
+
// exitCode 0 — write and resolve, never exit here; this action always
|
|
119
|
+
// exits unconditionally below with the real computed code.
|
|
120
|
+
await writeJsonEnvelopeAndExit(payload, 0);
|
|
116
121
|
} else {
|
|
117
122
|
displayDatasourceExportTTY(result, { environment: options.env, verbose: options.verbose });
|
|
118
123
|
}
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
'use strict';
|
|
8
8
|
|
|
9
9
|
const logger = require('../utils/logger');
|
|
10
|
+
const { writeJsonEnvelopeAndExit } = require('../utils/cli-json-exit');
|
|
10
11
|
const { formatBlockingError } = require('../utils/cli-test-layout-chalk');
|
|
11
12
|
const { runDatasourceAgentTrust } = require('../datasource/agent-trust-run');
|
|
12
13
|
const { writeTrustDebugLogAndPrint } = require('../datasource/agent-trust-debug-log');
|
|
@@ -52,7 +53,10 @@ async function finalizeDatasourceVerifyTrust(datasourceKey, options, result) {
|
|
|
52
53
|
strict: options.strict === true
|
|
53
54
|
};
|
|
54
55
|
if (options.json) {
|
|
55
|
-
|
|
56
|
+
// exitCode 0 here means "write and resolve, never exit" — the real exit
|
|
57
|
+
// code is decided below and the caller exits unconditionally, even on
|
|
58
|
+
// success, so process.exit() must stay solely the caller's job.
|
|
59
|
+
await writeJsonEnvelopeAndExit(result.trustRun, 0);
|
|
56
60
|
} else if (options.summary) {
|
|
57
61
|
const tr = result.trustRun;
|
|
58
62
|
logger.log(
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
const logger = require('../utils/logger');
|
|
8
8
|
const { handleCommandError } = require('../utils/cli-utils');
|
|
9
|
+
const { writeJsonEnvelopeAndExit } = require('../utils/cli-json-exit');
|
|
9
10
|
const { runGovernanceGenerateForExternalSystem } = require('./governance-generate-external');
|
|
10
11
|
const { runGovernanceVerifyForExternalSystem } = require('./governance-verify-external');
|
|
11
12
|
const { runGovernanceUploadForExternalSystem } = require('./governance-upload-external');
|
|
@@ -75,12 +76,12 @@ async function governanceVerifyHandler(systemKey, options, cmd) {
|
|
|
75
76
|
try {
|
|
76
77
|
const opts = normalizeGovernanceOptions(options, cmd);
|
|
77
78
|
const result = await runGovernanceVerifyForExternalSystem(systemKey, opts);
|
|
79
|
+
const exitCode = exitCodeFromVerdict(result.verdict);
|
|
78
80
|
if (opts.json) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
displayVerifyGovernanceTTY(result.systemKey, result, { details: opts.verbose });
|
|
81
|
+
await writeJsonEnvelopeAndExit(buildJsonEnvelope(result, opts.verbose), exitCode);
|
|
82
|
+
return;
|
|
82
83
|
}
|
|
83
|
-
|
|
84
|
+
displayVerifyGovernanceTTY(result.systemKey, result, { details: opts.verbose });
|
|
84
85
|
if (exitCode !== 0) {
|
|
85
86
|
process.exit(exitCode);
|
|
86
87
|
}
|
|
@@ -35,7 +35,12 @@ const ROLE_LIST_COLUMNS = [
|
|
|
35
35
|
label: 'Groups',
|
|
36
36
|
width: 44,
|
|
37
37
|
value: (r) => {
|
|
38
|
-
const groups = Array.isArray(r.groups)
|
|
38
|
+
const groups = Array.isArray(r.groups)
|
|
39
|
+
? r.groups.filter(Boolean)
|
|
40
|
+
: (r.mappings || [])
|
|
41
|
+
.filter((mapping) => mapping?.isActive !== false)
|
|
42
|
+
.map((mapping) => mapping?.groupName)
|
|
43
|
+
.filter(Boolean);
|
|
39
44
|
return groups.length > 0 ? groups.join(', ') : '—';
|
|
40
45
|
}
|
|
41
46
|
}
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
'use strict';
|
|
8
8
|
|
|
9
|
-
const logger = require('../utils/logger');
|
|
10
9
|
const { handleCommandError } = require('../utils/cli-utils');
|
|
10
|
+
const { writeJsonEnvelopeAndExit } = require('../utils/cli-json-exit');
|
|
11
11
|
const { cliOptsSkipPublish } = require('../utils/cli-sync-options');
|
|
12
12
|
const { runLifecycleForExternalSystem } = require('./lifecycle-external');
|
|
13
13
|
const { displayLifecycleReportTTY } = require('../lifecycle/report-display');
|
|
@@ -65,6 +65,12 @@ async function runLifecycleCommandAction(appName, options, cmd) {
|
|
|
65
65
|
const result = await runLifecycleForExternalSystem(appName, opts);
|
|
66
66
|
const report = result.report;
|
|
67
67
|
|
|
68
|
+
const pillarVerdict = lifecycleVerdictFromReport(report);
|
|
69
|
+
const exitCode =
|
|
70
|
+
pillarVerdict === VERDICT.VERIFIED
|
|
71
|
+
? 0
|
|
72
|
+
: exitCodeFromVerdict(pillarVerdict, { partial: pillarVerdict === VERDICT.NOT_VERIFIED });
|
|
73
|
+
|
|
68
74
|
if (opts.json) {
|
|
69
75
|
const envelope = {
|
|
70
76
|
systemKey: result.systemKey,
|
|
@@ -82,22 +88,17 @@ async function runLifecycleCommandAction(appName, options, cmd) {
|
|
|
82
88
|
if (opts.verbose) {
|
|
83
89
|
envelope.datasources = report.datasources;
|
|
84
90
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
displayLifecycleReportTTY(result.systemKey, report, {
|
|
88
|
-
details: opts.verbose,
|
|
89
|
-
openApiPublished: result.openApiPublished === true,
|
|
90
|
-
certificationProgress: result.certificationProgress ?? null,
|
|
91
|
-
dataplaneUrl: result.dataplaneUrl ?? null,
|
|
92
|
-
dataplaneUiBaseUrl: result.dataplaneUiBaseUrl ?? null
|
|
93
|
-
});
|
|
91
|
+
await writeJsonEnvelopeAndExit(envelope, exitCode);
|
|
92
|
+
return;
|
|
94
93
|
}
|
|
95
94
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
95
|
+
displayLifecycleReportTTY(result.systemKey, report, {
|
|
96
|
+
details: opts.verbose,
|
|
97
|
+
openApiPublished: result.openApiPublished === true,
|
|
98
|
+
certificationProgress: result.certificationProgress ?? null,
|
|
99
|
+
dataplaneUrl: result.dataplaneUrl ?? null,
|
|
100
|
+
dataplaneUiBaseUrl: result.dataplaneUiBaseUrl ?? null
|
|
101
|
+
});
|
|
101
102
|
if (exitCode !== 0) {
|
|
102
103
|
process.exit(exitCode);
|
|
103
104
|
}
|
|
@@ -15,6 +15,7 @@ const { getToken } = require('../api/auth.api');
|
|
|
15
15
|
const { formatApiError } = require('../utils/api-error-handler');
|
|
16
16
|
const { loadClientCredentials } = require('../utils/token-manager');
|
|
17
17
|
const logger = require('../utils/logger');
|
|
18
|
+
const { writeStreamAndWait } = require('../utils/write-stream-and-wait');
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* Tries to load credentials from secrets file
|
|
@@ -136,7 +137,7 @@ function handleLoginError(response, appName) {
|
|
|
136
137
|
* @param {Object} response - API response
|
|
137
138
|
* @returns {Object} Token data object
|
|
138
139
|
*/
|
|
139
|
-
function extractTokenData(response) {
|
|
140
|
+
async function extractTokenData(response) {
|
|
140
141
|
// OpenAPI spec response: { success: boolean, token: string, expiresIn: number, expiresAt: string, ... }
|
|
141
142
|
// Handle both flat and nested response structures (some APIs wrap in data field)
|
|
142
143
|
// If response.data exists, use it; otherwise use response directly
|
|
@@ -146,7 +147,10 @@ function extractTokenData(response) {
|
|
|
146
147
|
if (!responseData || !responseData.token) {
|
|
147
148
|
logger.error(formatBlockingError('Invalid response: missing token'));
|
|
148
149
|
if (responseData) {
|
|
149
|
-
|
|
150
|
+
await writeStreamAndWait(
|
|
151
|
+
process.stderr,
|
|
152
|
+
`${chalk.gray(`Response structure: ${JSON.stringify(responseData, null, 2)}`)}\n`
|
|
153
|
+
);
|
|
150
154
|
}
|
|
151
155
|
process.exit(1);
|
|
152
156
|
}
|
|
@@ -190,9 +194,10 @@ async function handleCredentialsLogin(controllerUrl, appName, clientId, clientSe
|
|
|
190
194
|
|
|
191
195
|
if (!response.success) {
|
|
192
196
|
handleLoginError(response, appName);
|
|
197
|
+
return;
|
|
193
198
|
}
|
|
194
199
|
|
|
195
|
-
const responseData = extractTokenData(response);
|
|
200
|
+
const responseData = await extractTokenData(response);
|
|
196
201
|
const expiresAt = calculateTokenExpiration(responseData);
|
|
197
202
|
|
|
198
203
|
return {
|
|
@@ -15,6 +15,7 @@ const ora = require('ora');
|
|
|
15
15
|
const { setCurrentEnvironment, saveDeviceToken, setControllerUrl } = require('../core/config');
|
|
16
16
|
const { initiateDeviceCodeFlow } = require('../api/auth.api');
|
|
17
17
|
const { pollDeviceCodeToken, displayDeviceCodeInfo } = require('../utils/api');
|
|
18
|
+
const { resolveDeviceVisitUrl } = require('../utils/device-code');
|
|
18
19
|
const logger = require('../utils/logger');
|
|
19
20
|
const { formatSuccessLine } = require('../utils/cli-layout-chalk');
|
|
20
21
|
|
|
@@ -42,6 +43,10 @@ async function getEnvironmentKey(environment) {
|
|
|
42
43
|
return envKey;
|
|
43
44
|
}
|
|
44
45
|
|
|
46
|
+
if (!process.stdin || process.stdin.isTTY === false) {
|
|
47
|
+
return 'dev';
|
|
48
|
+
}
|
|
49
|
+
|
|
45
50
|
const envPrompt = await inquirer.prompt([{
|
|
46
51
|
type: 'input',
|
|
47
52
|
name: 'environment',
|
|
@@ -255,10 +260,8 @@ function logDeviceFlowError(deviceError, opts) {
|
|
|
255
260
|
}
|
|
256
261
|
|
|
257
262
|
function printCompactDeviceUrl(deviceCodeResponse) {
|
|
258
|
-
const visitUrl =
|
|
259
|
-
|
|
260
|
-
`${deviceCodeResponse.verification_uri}?user_code=${deviceCodeResponse.user_code}`;
|
|
261
|
-
logger.log('\nOpen browser to authenticate:');
|
|
263
|
+
const visitUrl = resolveDeviceVisitUrl(deviceCodeResponse);
|
|
264
|
+
logger.log('\nOpen this URL to authenticate:');
|
|
262
265
|
logger.log(chalk.yellow(`${visitUrl}\n`));
|
|
263
266
|
}
|
|
264
267
|
|
|
@@ -289,7 +292,13 @@ async function handleDeviceCodeLogin(controllerUrl, environment, online, scope,
|
|
|
289
292
|
const deviceCodeResponse = convertDeviceCodeResponse(apiResponse);
|
|
290
293
|
|
|
291
294
|
if (!opts.compact) {
|
|
292
|
-
displayDeviceCodeInfo(
|
|
295
|
+
displayDeviceCodeInfo(
|
|
296
|
+
deviceCodeResponse.user_code,
|
|
297
|
+
deviceCodeResponse.verification_uri,
|
|
298
|
+
logger,
|
|
299
|
+
chalk,
|
|
300
|
+
deviceCodeResponse.verification_uri_complete
|
|
301
|
+
);
|
|
293
302
|
} else {
|
|
294
303
|
printCompactDeviceUrl(deviceCodeResponse);
|
|
295
304
|
}
|
package/lib/commands/login.js
CHANGED
|
@@ -16,9 +16,13 @@ const { setCurrentEnvironment, saveClientToken, setControllerUrl } = require('..
|
|
|
16
16
|
const logger = require('../utils/logger');
|
|
17
17
|
const { handleCredentialsLogin } = require('./login-credentials');
|
|
18
18
|
const { handleDeviceCodeLogin } = require('./login-device');
|
|
19
|
-
const { resolveControllerUrl } = require('../utils/controller-url');
|
|
19
|
+
const { resolveControllerUrl, discoverControllerBaseUrl } = require('../utils/controller-url');
|
|
20
20
|
const { tryRefreshDataplaneVersionAfterLogin } = require('./auth-status-dataplane-version');
|
|
21
21
|
|
|
22
|
+
function isInteractiveStdin() {
|
|
23
|
+
return Boolean(process.stdin && process.stdin.isTTY);
|
|
24
|
+
}
|
|
25
|
+
|
|
22
26
|
/**
|
|
23
27
|
* Determine and validate authentication method
|
|
24
28
|
* @async
|
|
@@ -34,6 +38,10 @@ async function determineAuthMethod(method) {
|
|
|
34
38
|
return method;
|
|
35
39
|
}
|
|
36
40
|
|
|
41
|
+
if (!isInteractiveStdin()) {
|
|
42
|
+
return 'device';
|
|
43
|
+
}
|
|
44
|
+
|
|
37
45
|
const authMethod = await inquirer.prompt([{
|
|
38
46
|
type: 'list',
|
|
39
47
|
name: 'method',
|
|
@@ -86,6 +94,8 @@ async function normalizeControllerUrl(options) {
|
|
|
86
94
|
controllerUrl = await resolveControllerUrl();
|
|
87
95
|
}
|
|
88
96
|
controllerUrl = String(controllerUrl).trim().replace(/\/+$/, '');
|
|
97
|
+
const inputUrl = controllerUrl;
|
|
98
|
+
controllerUrl = await discoverControllerBaseUrl(controllerUrl);
|
|
89
99
|
if (!options.skipControllerUrlPersist) {
|
|
90
100
|
const persistUrl = options.tokenControllerUrl
|
|
91
101
|
? String(options.tokenControllerUrl).trim().replace(/\/+$/, '')
|
|
@@ -93,6 +103,9 @@ async function normalizeControllerUrl(options) {
|
|
|
93
103
|
await setControllerUrl(persistUrl);
|
|
94
104
|
}
|
|
95
105
|
if (!options.compact) {
|
|
106
|
+
if (controllerUrl !== inputUrl) {
|
|
107
|
+
logger.log(chalk.gray(`Using controller ${controllerUrl}`));
|
|
108
|
+
}
|
|
96
109
|
logger.log(chalk.gray(`Controller URL: ${controllerUrl}`));
|
|
97
110
|
}
|
|
98
111
|
return controllerUrl;
|
package/lib/commands/logout.js
CHANGED
|
@@ -132,11 +132,54 @@ async function clearClientTokens(options) {
|
|
|
132
132
|
return 0;
|
|
133
133
|
}
|
|
134
134
|
|
|
135
|
+
function normalizeTokenType(value) {
|
|
136
|
+
const type = value && String(value).toLowerCase();
|
|
137
|
+
if (type && type !== 'device' && type !== 'client') {
|
|
138
|
+
throw new Error('--type must be either "device" or "client"');
|
|
139
|
+
}
|
|
140
|
+
return type;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function validateLogoutOptionCombination(options, type) {
|
|
144
|
+
if (options.app && !options.environment) {
|
|
145
|
+
throw new Error('--app requires --environment option');
|
|
146
|
+
}
|
|
147
|
+
if (type === 'client' && options.controller) {
|
|
148
|
+
throw new Error('--controller can only be used with --type device');
|
|
149
|
+
}
|
|
150
|
+
if (type === 'device' && (options.environment || options.app)) {
|
|
151
|
+
throw new Error('--environment and --app can only be used with --type client');
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function validateLogoutSelectors(options) {
|
|
156
|
+
if ('controller' in options && options.controller !== undefined && options.controller !== null) {
|
|
157
|
+
validateControllerUrl(options.controller);
|
|
158
|
+
}
|
|
159
|
+
if ('environment' in options && options.environment !== undefined && options.environment !== null) {
|
|
160
|
+
validateEnvironmentKey(options.environment);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Validate logout option combinations and normalize the token type.
|
|
166
|
+
* @param {Object} options - Raw logout options
|
|
167
|
+
* @returns {Object} Validated options with a normalized type
|
|
168
|
+
* @throws {Error} If an option or option combination is invalid
|
|
169
|
+
*/
|
|
170
|
+
function normalizeLogoutOptions(options) {
|
|
171
|
+
const type = normalizeTokenType(options.type);
|
|
172
|
+
validateLogoutOptionCombination(options, type);
|
|
173
|
+
validateLogoutSelectors(options);
|
|
174
|
+
return { ...options, type };
|
|
175
|
+
}
|
|
176
|
+
|
|
135
177
|
/**
|
|
136
178
|
* Handle logout command action
|
|
137
179
|
* @async
|
|
138
180
|
* @function handleLogout
|
|
139
181
|
* @param {Object} options - Logout options
|
|
182
|
+
* @param {string} [options.type] - Token type to clear (device or client)
|
|
140
183
|
* @param {string} [options.controller] - Clear device tokens for specific controller
|
|
141
184
|
* @param {string} [options.environment] - Clear client tokens for specific environment
|
|
142
185
|
* @param {string} [options.app] - Clear client tokens for specific app (requires --environment)
|
|
@@ -147,24 +190,17 @@ async function handleLogout(options) {
|
|
|
147
190
|
const configPath = CONFIG_FILE;
|
|
148
191
|
logger.log(chalk.blue('\n🔓 Clearing authentication tokens...\n'));
|
|
149
192
|
|
|
150
|
-
|
|
151
|
-
if (options.app && !options.environment) {
|
|
152
|
-
throw new Error('--app requires --environment option');
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
if ('controller' in options && options.controller !== undefined && options.controller !== null) {
|
|
156
|
-
validateControllerUrl(options.controller);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
if ('environment' in options && options.environment !== undefined && options.environment !== null) {
|
|
160
|
-
validateEnvironmentKey(options.environment);
|
|
161
|
-
}
|
|
193
|
+
const normalizedOptions = normalizeLogoutOptions(options);
|
|
162
194
|
|
|
163
195
|
// Clear device tokens
|
|
164
|
-
const deviceTokensCleared =
|
|
196
|
+
const deviceTokensCleared = normalizedOptions.type === 'client'
|
|
197
|
+
? 0
|
|
198
|
+
: await clearDeviceTokens(normalizedOptions);
|
|
165
199
|
|
|
166
200
|
// Clear client tokens
|
|
167
|
-
const clientTokensCleared =
|
|
201
|
+
const clientTokensCleared = normalizedOptions.type === 'device'
|
|
202
|
+
? 0
|
|
203
|
+
: await clearClientTokens(normalizedOptions);
|
|
168
204
|
|
|
169
205
|
// Summary
|
|
170
206
|
const totalCleared = deviceTokensCleared + clientTokensCleared;
|
|
@@ -178,4 +214,3 @@ async function handleLogout(options) {
|
|
|
178
214
|
}
|
|
179
215
|
|
|
180
216
|
module.exports = { handleLogout };
|
|
181
|
-
|
|
@@ -64,7 +64,8 @@ Subcommands:
|
|
|
64
64
|
copy <roleKey> Capture one Work Hub execution as a local YAML test case
|
|
65
65
|
|
|
66
66
|
Package workspace (top-level commands — same digital-worker package):
|
|
67
|
-
download / validate / upload
|
|
67
|
+
download / validate / upload ra-<roleKey> Manage role-assistant/ra-<roleKey>/
|
|
68
|
+
upload publishes settings and sidecars; operator Make available is a separate action
|
|
68
69
|
|
|
69
70
|
Examples:
|
|
70
71
|
$ aifabrix role-assistant test customer-support-bot
|
|
@@ -72,11 +73,11 @@ Examples:
|
|
|
72
73
|
$ aifabrix role-assistant test customer-support-bot --list-cases
|
|
73
74
|
$ aifabrix role-assistant test customer-support-bot --env tst --json
|
|
74
75
|
$ aifabrix role-assistant copy customer-support-bot --suite 001 --reference a9f09fb8-d9eb-477f-8bb4-59e670fc82a4
|
|
75
|
-
$ aifabrix upload customer-support-bot --env dev
|
|
76
|
+
$ aifabrix upload ra-customer-support-bot --env dev
|
|
76
77
|
$ aifabrix test ra-customer-support-bot
|
|
77
78
|
|
|
78
79
|
Notes:
|
|
79
|
-
-
|
|
80
|
+
- role-assistant test/copy use bare <roleKey>; top-level package commands use ra-<roleKey>.
|
|
80
81
|
- test uses the public/running worker by default; pass --publish (or upload) to refresh from local files.
|
|
81
82
|
- copy writes tests/<suite>/<caseId>.yaml from a Work Hub execution id; it does not publish.
|
|
82
83
|
- See: aifabrix role-assistant test -h
|
|
@@ -267,19 +268,30 @@ async function runRoleAssistantTestAction(roleKey, options, cmd) {
|
|
|
267
268
|
const portalUrl = buildExternalSystemUiUrl(result.dataplaneUiBaseUrl, systemKey);
|
|
268
269
|
const caseResult = await resolveSelectedCaseResults(systemKey, opts, result, verdict, portalUrl);
|
|
269
270
|
|
|
271
|
+
const exitCode = computeRoleAssistantExitCode(verdict, caseResult);
|
|
272
|
+
|
|
270
273
|
if (opts.json) {
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
274
|
+
// Large piped stdout writes on Linux are non-blocking; exiting right
|
|
275
|
+
// after console.log() can truncate the JSON before the OS write
|
|
276
|
+
// completes. Wait for the write to flush before exiting non-zero.
|
|
277
|
+
const payload = JSON.stringify(
|
|
278
|
+
logger.sanitizeValue(
|
|
279
|
+
buildRoleAssistantTestEnvelope(displayKey, verdict, portalUrl, result, opts, caseResult)
|
|
280
|
+
),
|
|
281
|
+
null,
|
|
282
|
+
2
|
|
277
283
|
);
|
|
278
|
-
|
|
279
|
-
|
|
284
|
+
return new Promise((resolve) => {
|
|
285
|
+
process.stdout.write(`${payload}\n`, () => {
|
|
286
|
+
if (exitCode !== 0) {
|
|
287
|
+
process.exit(exitCode);
|
|
288
|
+
}
|
|
289
|
+
resolve(exitCode);
|
|
290
|
+
});
|
|
291
|
+
});
|
|
280
292
|
}
|
|
281
293
|
|
|
282
|
-
|
|
294
|
+
displayRoleAssistantTestSummary(displayKey, verdict, portalUrl, result, caseResult);
|
|
283
295
|
if (exitCode !== 0) {
|
|
284
296
|
process.exit(exitCode);
|
|
285
297
|
}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
const logger = require('../utils/logger');
|
|
8
8
|
const { handleCommandError } = require('../utils/cli-utils');
|
|
9
|
+
const { writeJsonEnvelopeAndExit } = require('../utils/cli-json-exit');
|
|
9
10
|
const { runVerifyGovernanceCombined } = require('./verify-governance-combined-external');
|
|
10
11
|
const { normalizeTestGovernanceCliOptions } = require('./test-governance-cli-options');
|
|
11
12
|
const { displayVerifyGovernanceTTY } = require('../lifecycle/report-display');
|
|
@@ -33,16 +34,17 @@ async function runVerifyGovernanceCommandAction(appName, options, cmd) {
|
|
|
33
34
|
const opts = normalizeVerifyGovernanceCliOptions(options, cmd);
|
|
34
35
|
const result = await runVerifyGovernanceCombined(appName, opts);
|
|
35
36
|
|
|
37
|
+
const exitCode = exitCodeFromVerdict(result.verdict);
|
|
38
|
+
|
|
36
39
|
if (opts.json) {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
if (opts.verbose && !opts.pack && typeof result.generated === 'number' && result.generated > 0) {
|
|
40
|
-
logger.log(formatSuccessLine(`Generated packs for ${result.generated} datasource(s)`));
|
|
41
|
-
}
|
|
42
|
-
displayVerifyGovernanceTTY(result.systemKey, result, { details: opts.verbose });
|
|
40
|
+
await writeJsonEnvelopeAndExit(buildJsonEnvelope(result, opts.verbose), exitCode);
|
|
41
|
+
return;
|
|
43
42
|
}
|
|
44
43
|
|
|
45
|
-
|
|
44
|
+
if (opts.verbose && !opts.pack && typeof result.generated === 'number' && result.generated > 0) {
|
|
45
|
+
logger.log(formatSuccessLine(`Generated packs for ${result.generated} datasource(s)`));
|
|
46
|
+
}
|
|
47
|
+
displayVerifyGovernanceTTY(result.systemKey, result, { details: opts.verbose });
|
|
46
48
|
if (exitCode !== 0) {
|
|
47
49
|
process.exit(exitCode);
|
|
48
50
|
}
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
'use strict';
|
|
8
8
|
|
|
9
|
-
const logger = require('../utils/logger');
|
|
10
9
|
const { handleCommandError } = require('../utils/cli-utils');
|
|
10
|
+
const { writeJsonEnvelopeAndExit } = require('../utils/cli-json-exit');
|
|
11
11
|
const { cliOptsSkipPublish } = require('../utils/cli-sync-options');
|
|
12
12
|
const { runVerifyOperationsForExternalSystem } = require('./verify-operations-external');
|
|
13
13
|
const { displayVerifyOperationsTTY } = require('../lifecycle/report-display');
|
|
@@ -37,16 +37,17 @@ async function runVerifyOperationsCommandAction(appName, options, cmd) {
|
|
|
37
37
|
const opts = normalizeVerifyOperationsCliOptions(options, cmd);
|
|
38
38
|
const result = await runVerifyOperationsForExternalSystem(appName, opts);
|
|
39
39
|
|
|
40
|
+
const exitCode = exitCodeFromVerdict(result.verdict);
|
|
41
|
+
|
|
40
42
|
if (opts.json) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
displayVerifyOperationsTTY(appName, result, {
|
|
44
|
-
details: opts.verbose,
|
|
45
|
-
warnings: result.warnings
|
|
46
|
-
});
|
|
43
|
+
await writeJsonEnvelopeAndExit(buildJsonEnvelope(result, opts.verbose), exitCode);
|
|
44
|
+
return;
|
|
47
45
|
}
|
|
48
46
|
|
|
49
|
-
|
|
47
|
+
displayVerifyOperationsTTY(appName, result, {
|
|
48
|
+
details: opts.verbose,
|
|
49
|
+
warnings: result.warnings
|
|
50
|
+
});
|
|
50
51
|
if (exitCode !== 0) {
|
|
51
52
|
process.exit(exitCode);
|
|
52
53
|
}
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
'use strict';
|
|
8
8
|
|
|
9
|
-
const logger = require('../utils/logger');
|
|
10
9
|
const { handleCommandError } = require('../utils/cli-utils');
|
|
10
|
+
const { writeJsonEnvelopeAndExit } = require('../utils/cli-json-exit');
|
|
11
11
|
const { runVerifyTrustForExternalSystem } = require('./verify-trust-external');
|
|
12
12
|
const { normalizeTestTrustCliOptions } = require('./test-trust-cli-options');
|
|
13
13
|
const { displayVerifyTrustTTY } = require('../lifecycle/report-display');
|
|
@@ -30,6 +30,8 @@ async function runVerifyTrustCommandAction(appName, options, cmd) {
|
|
|
30
30
|
timeout: opts.timeout
|
|
31
31
|
});
|
|
32
32
|
|
|
33
|
+
const exitCode = exitCodeFromVerdict(result.verdict);
|
|
34
|
+
|
|
33
35
|
if (opts.json) {
|
|
34
36
|
const envelope = buildJsonEnvelope(
|
|
35
37
|
{
|
|
@@ -44,12 +46,11 @@ async function runVerifyTrustCommandAction(appName, options, cmd) {
|
|
|
44
46
|
},
|
|
45
47
|
opts.details || opts.verbose
|
|
46
48
|
);
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
displayVerifyTrustTTY(result.systemKey, result, { details: opts.verbose || opts.details });
|
|
49
|
+
await writeJsonEnvelopeAndExit(envelope, exitCode);
|
|
50
|
+
return;
|
|
50
51
|
}
|
|
51
52
|
|
|
52
|
-
|
|
53
|
+
displayVerifyTrustTTY(result.systemKey, result, { details: opts.verbose || opts.details });
|
|
53
54
|
if (exitCode !== 0) {
|
|
54
55
|
process.exit(exitCode);
|
|
55
56
|
}
|
|
@@ -74,9 +74,8 @@ async function setupAuthenticationAndDataplane(systemKey, _options, _config) {
|
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
const { resolveDataplaneUrl } = require('../utils/dataplane-resolver');
|
|
77
|
-
|
|
77
|
+
// discoverDataplaneUrl already logs progress and success
|
|
78
78
|
const dataplaneUrl = await resolveDataplaneUrl(controllerUrl, environment, authConfig);
|
|
79
|
-
logger.log(formatSuccessLine(`Dataplane URL: ${dataplaneUrl}`));
|
|
80
79
|
|
|
81
80
|
return { authConfig, dataplaneUrl };
|
|
82
81
|
}
|
package/lib/generator/helpers.js
CHANGED
|
@@ -234,6 +234,18 @@ function determineVariableLocation(value, key) {
|
|
|
234
234
|
required = true;
|
|
235
235
|
}
|
|
236
236
|
|
|
237
|
+
if (location === 'keyvault' && value.startsWith('kv://')) {
|
|
238
|
+
try {
|
|
239
|
+
const { getInfraParameterCatalog } = require('../parameters/infra-parameter-catalog');
|
|
240
|
+
const entry = getInfraParameterCatalog().findEntryForKey(value.slice('kv://'.length));
|
|
241
|
+
if (entry?.scope === 'infra' && entry.generator?.type === 'emptyAllowed') {
|
|
242
|
+
required = false;
|
|
243
|
+
}
|
|
244
|
+
} catch {
|
|
245
|
+
// Keep the conservative required=true default when the catalog is unavailable.
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
237
249
|
return { location, required };
|
|
238
250
|
}
|
|
239
251
|
|
|
@@ -344,4 +356,3 @@ module.exports = {
|
|
|
344
356
|
validatePortalInput,
|
|
345
357
|
parseEnvironmentVariables
|
|
346
358
|
};
|
|
347
|
-
|
|
@@ -52,12 +52,12 @@ function setRecordFetch(op) {
|
|
|
52
52
|
let found = false;
|
|
53
53
|
for (const step of steps) {
|
|
54
54
|
if (step && step.fetch && typeof step.fetch === 'object') {
|
|
55
|
-
step.fetch
|
|
55
|
+
step.fetch = { source: 'record' };
|
|
56
56
|
found = true;
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
59
|
if (!found) {
|
|
60
|
-
steps.unshift({ fetch: { source: 'record'
|
|
60
|
+
steps.unshift({ fetch: { source: 'record' } });
|
|
61
61
|
if (!steps.some((row) => row && row.output)) {
|
|
62
62
|
steps.push({ output: { mode: 'records' } });
|
|
63
63
|
}
|
|
@@ -87,6 +87,9 @@ function ensureRecordCapability(body, capKey) {
|
|
|
87
87
|
if (!ops[capKey] || typeof ops[capKey] !== 'object') {
|
|
88
88
|
ops[capKey] = { enabled: true, description: `Local ${capKey}`, steps: [] };
|
|
89
89
|
}
|
|
90
|
+
if (capKey === 'create' || capKey === 'update') {
|
|
91
|
+
ops[capKey].shape = capKey;
|
|
92
|
+
}
|
|
90
93
|
setRecordFetch(/** @type {Record<string, unknown>} */ (ops[capKey]));
|
|
91
94
|
}
|
|
92
95
|
|