@aifabrix/builder 2.51.0 → 2.51.1

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.
Files changed (162) hide show
  1. package/jest.isolated-projects.js +77 -1
  2. package/jest.projects.js +5 -426
  3. package/lib/api/assistants.api.js +67 -0
  4. package/lib/api/datasources-extended.api.js +6 -6
  5. package/lib/api/evidence-authoring-helpers.js +267 -0
  6. package/lib/api/evidence-authoring.api.js +337 -0
  7. package/lib/api/evidence.api.js +57 -1
  8. package/lib/api/index.js +24 -7
  9. package/lib/api/pipeline.api.js +43 -3
  10. package/lib/api/records-bulk.api.js +28 -3
  11. package/lib/api/types/evidence.types.js +156 -8
  12. package/lib/api/work.api.js +283 -0
  13. package/lib/app/run-deploy-job.js +108 -0
  14. package/lib/app/run-helpers.js +10 -3
  15. package/lib/app/run.js +8 -0
  16. package/lib/channels/add-channel.js +54 -23
  17. package/lib/channels/approval-guides/chatgpt.js +8 -7
  18. package/lib/channels/approval-guides/microsoft-copilot.js +7 -8
  19. package/lib/channels/channel-artifact-generator.js +14 -2
  20. package/lib/channels/channel-credential.js +3 -1
  21. package/lib/channels/channel-probe-evidence.js +79 -0
  22. package/lib/channels/channel-probe.js +265 -13
  23. package/lib/channels/channel-runtime-resolver.js +120 -29
  24. package/lib/channels/channel-status-display.js +44 -0
  25. package/lib/channels/channel-targets.js +7 -0
  26. package/lib/channels/chatgpt-runtime-contract.js +29 -0
  27. package/lib/channels/microsoft-copilot-package.js +280 -0
  28. package/lib/channels/runtime-tool-catalog.js +165 -0
  29. package/lib/cli/index.js +2 -0
  30. package/lib/cli/setup-app.js +4 -0
  31. package/lib/cli/setup-external-system-help.js +8 -2
  32. package/lib/cli/setup-external-system.js +12 -0
  33. package/lib/commands/app-test.js +2 -14
  34. package/lib/commands/datasource-load-export-cli.js +6 -1
  35. package/lib/commands/deploy-gate-failure-details.js +19 -17
  36. package/lib/commands/dev-down.js +2 -6
  37. package/lib/commands/evidence-kind.js +65 -15
  38. package/lib/commands/governance-generate-external.js +56 -21
  39. package/lib/commands/lifecycle-external.js +10 -4
  40. package/lib/commands/repair-datasource-apply.js +10 -1
  41. package/lib/commands/repair-datasource-run.js +4 -2
  42. package/lib/commands/repair-datasource-test-payload.js +80 -19
  43. package/lib/commands/repair-datasource-webhooks-sync-bridge.js +42 -3
  44. package/lib/commands/repair-internal.js +9 -1
  45. package/lib/commands/repair-openapi-sync.js +34 -17
  46. package/lib/commands/role-assistant.js +313 -0
  47. package/lib/commands/upload-data-sync-finalize.js +5 -4
  48. package/lib/commands/upload-sidecar-followups.js +144 -47
  49. package/lib/commands/upload.js +43 -6
  50. package/lib/commands/verify-governance-combined-external.js +73 -9
  51. package/lib/commands/verify-governance-db.js +80 -25
  52. package/lib/commands/verify-governance-external.js +29 -5
  53. package/lib/commands/wizard-core-helpers.js +7 -3
  54. package/lib/commands/wizard-core.js +78 -9
  55. package/lib/datasource/bulk-loader-run-batches.js +4 -2
  56. package/lib/datasource/bulk-loader-service.js +5 -1
  57. package/lib/datasource/datasource-validate-summary.js +2 -2
  58. package/lib/datasource/validate.js +13 -6
  59. package/lib/external-system/deploy-helpers.js +35 -1
  60. package/lib/external-system/deploy.js +23 -10
  61. package/lib/external-system/download-helpers.js +111 -2
  62. package/lib/external-system/download-role-assistant.js +55 -0
  63. package/lib/external-system/download.js +45 -26
  64. package/lib/external-system/test-helpers.js +1 -1
  65. package/lib/external-system/test.js +39 -3
  66. package/lib/generator/builders.js +3 -0
  67. package/lib/generator/wizard.js +51 -4
  68. package/lib/lifecycle/access-control-abac.js +121 -0
  69. package/lib/lifecycle/lifecycle-governance-options.js +4 -1
  70. package/lib/lifecycle/product-model.js +3 -2
  71. package/lib/lifecycle/report-display.js +14 -2
  72. package/lib/programmatic/capability-registry.js +20 -1
  73. package/lib/programmatic/command-options.js +1 -0
  74. package/lib/programmatic/index.js +4 -0
  75. package/lib/programmatic/manifest-patch-section.js +48 -9
  76. package/lib/programmatic/manifest-section-registry-data.js +3 -2
  77. package/lib/programmatic/openapi-apply-result-schemas.js +44 -0
  78. package/lib/programmatic/openapi-component-schemas.js +16 -1
  79. package/lib/programmatic/openapi-description-enricher.js +3 -1
  80. package/lib/programmatic/openapi-descriptions.js +55 -5
  81. package/lib/programmatic/openapi-evidence-schemas.js +161 -0
  82. package/lib/programmatic/openapi-manifest-schemas.js +6 -2
  83. package/lib/programmatic/openapi-operation-bindings.js +99 -0
  84. package/lib/programmatic/openapi-request-schemas.js +36 -1
  85. package/lib/programmatic/openapi-result-schemas.js +1 -1
  86. package/lib/programmatic/openapi-schema-descriptions-certify.js +5 -1
  87. package/lib/programmatic/openapi-schema-descriptions-core.js +1 -1
  88. package/lib/programmatic/openapi-schema-descriptions-evidence.js +156 -0
  89. package/lib/programmatic/openapi-schema-descriptions-manifest.js +4 -3
  90. package/lib/programmatic/openapi-schema-descriptions-operations.js +70 -0
  91. package/lib/programmatic/openapi-spec.js +47 -28
  92. package/lib/programmatic/orchestration-openapi-meta.js +5 -0
  93. package/lib/programmatic/request-timeout.js +3 -0
  94. package/lib/programmatic/route-handler-map.js +89 -2
  95. package/lib/programmatic/run-certify.js +15 -2
  96. package/lib/programmatic/run-deploy.js +74 -0
  97. package/lib/programmatic/run-evidence-authoring.js +80 -0
  98. package/lib/programmatic/run-protection.js +124 -0
  99. package/lib/programmatic/run-template-workspace.js +28 -1
  100. package/lib/programmatic/workspace-context.js +6 -0
  101. package/lib/protection/auth-context.js +48 -6
  102. package/lib/protection/paths.js +22 -0
  103. package/lib/protection/run-protection-create-helpers.js +22 -1
  104. package/lib/protection/run-protection-create.js +1 -1
  105. package/lib/protection/sync-after-upload.js +1 -1
  106. package/lib/role-assistant/evidence-sync.js +450 -0
  107. package/lib/role-assistant/github-workflow.js +96 -0
  108. package/lib/role-assistant/knowledge-sync.js +465 -0
  109. package/lib/role-assistant/settings.js +126 -0
  110. package/lib/role-assistant/test-cases-evaluate.js +170 -0
  111. package/lib/role-assistant/test-cases-honesty.js +184 -0
  112. package/lib/role-assistant/test-cases.js +364 -0
  113. package/lib/role-assistant/test-runner-workhub-answers.js +203 -0
  114. package/lib/role-assistant/test-runner-workhub.js +385 -0
  115. package/lib/role-assistant/test-runner.js +500 -0
  116. package/lib/schema/application-schema.json +16 -2
  117. package/lib/schema/deployment-rules.yaml +1 -0
  118. package/lib/schema/external-datasource.schema.json +38 -4
  119. package/lib/schema/external-system.schema.json +4 -4
  120. package/lib/schema/infra.parameter.yaml +20 -0
  121. package/lib/schema/role-assistant-settings.schema.json +108 -0
  122. package/lib/utils/api.js +52 -27
  123. package/lib/utils/app-path-resolve.js +72 -24
  124. package/lib/utils/authentication-shape.js +3 -1
  125. package/lib/utils/deployment-validation.js +28 -3
  126. package/lib/utils/docker-run-ephemeral.js +55 -0
  127. package/lib/utils/enterprise-knowledge-paths.js +29 -12
  128. package/lib/utils/env-copy-keycloak.js +196 -0
  129. package/lib/utils/env-copy.js +34 -1
  130. package/lib/utils/external-system-readiness-compact-display.js +3 -0
  131. package/lib/utils/help-builder.js +1 -0
  132. package/lib/utils/paths.js +67 -23
  133. package/lib/utils/pipeline-upload-auth-retry.js +15 -3
  134. package/lib/utils/role-assistant-paths.js +98 -0
  135. package/lib/utils/schema-loader.js +41 -0
  136. package/lib/utils/schema-resolver.js +36 -4
  137. package/lib/utils/token-manager.js +38 -29
  138. package/lib/utils/url-declarative-resolve-load-doc.js +38 -1
  139. package/lib/validation/external-manifest-validator.js +31 -8
  140. package/lib/validation/validate-external-file.js +8 -1
  141. package/package.json +2 -1
  142. package/scripts/export-builder-api-evidence.js +1 -1
  143. package/templates/applications/dataplane/application.yaml +23 -15
  144. package/templates/applications/dataplane/env.template +1 -1
  145. package/templates/applications/dataplane/rbac.yaml +14 -0
  146. package/templates/applications/miso-controller/application.yaml +1 -1
  147. package/templates/applications/miso-controller/env.template +3 -1
  148. package/templates/channels/chatgpt/install.template.md.hbs +42 -24
  149. package/templates/channels/chatgpt/integration/README.md +10 -7
  150. package/templates/channels/chatgpt/integration/application.json +2 -2
  151. package/templates/channels/chatgpt/integration/chatgpt-system.json +3 -3
  152. package/templates/channels/chatgpt/integration/env.template +1 -1
  153. package/templates/channels/chatgpt/manifest.template.json.hbs +36 -5
  154. package/templates/channels/microsoft-copilot/ai-plugin.template.json.hbs +28 -0
  155. package/templates/channels/microsoft-copilot/declarative-agent.template.json.hbs +22 -0
  156. package/templates/channels/microsoft-copilot/install.template.md.hbs +32 -22
  157. package/templates/channels/microsoft-copilot/integration/README.md +9 -7
  158. package/templates/channels/microsoft-copilot/integration/application.json +2 -2
  159. package/templates/channels/microsoft-copilot/integration/env.template +1 -1
  160. package/templates/channels/microsoft-copilot/integration/microsoft-copilot-system.json +7 -6
  161. package/templates/channels/microsoft-copilot/manifest.template.json.hbs +34 -6
  162. /package/.cursor/plans/{157.1-security-quality-violations-by-type.csv → Done/157.1-security-quality-violations-by-type.csv} +0 -0
@@ -0,0 +1,313 @@
1
+ /**
2
+ * Role Assistant CLI command group.
3
+ *
4
+ * @fileoverview role-assistant test command with portal deep-link output
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const logger = require('../utils/logger');
12
+ const { handleCommandError } = require('../utils/cli-utils');
13
+ const {
14
+ runLifecycleForExternalSystem,
15
+ resolveLifecycleAuth
16
+ } = require('./lifecycle-external');
17
+ const { lifecycleVerdictFromReport } = require('./lifecycle-command-action');
18
+ const { buildExternalSystemUiUrl } = require('../lifecycle/dataplane-ui-url');
19
+ const { VERDICT } = require('../lifecycle/product-model');
20
+ const { exitCodeFromVerdict } = require('../lifecycle/exit-codes');
21
+ const {
22
+ loadRoleAssistantTestCase,
23
+ evaluateRoleAssistantTestCase
24
+ } = require('../role-assistant/test-cases');
25
+ const {
26
+ isExecutableRoleAssistantCase,
27
+ runRoleAssistantCaseLifecycle,
28
+ mergeCaseExecutionIntoLifecycleResult,
29
+ lifecycleVerdictFromCaseExecution
30
+ } = require('../role-assistant/test-runner');
31
+ const { collectString } = require('./governance');
32
+ const {
33
+ sectionTitle,
34
+ headerKeyValue,
35
+ formatSuccessLine,
36
+ formatSuccessParagraph,
37
+ formatWarningLine,
38
+ formatBlockingError,
39
+ metadata
40
+ } = require('../utils/cli-test-layout-chalk');
41
+
42
+ function roleAssistantHelpAfter() {
43
+ return `
44
+ Examples:
45
+ $ aifabrix role-assistant test customer-support-bot
46
+ $ aifabrix role-assistant test customer-support-bot --case smoke
47
+ $ aifabrix role-assistant test customer-support-bot --case tests/customer-address-change.yaml
48
+ $ aifabrix role-assistant test customer-support-bot --subject-email ops@example.com
49
+ $ aifabrix role-assistant test customer-support-bot --json
50
+ $ aifabrix role-assistant test customer-support-bot --publish --force
51
+
52
+ Notes:
53
+ - Uses the public/running Role Assistant on the dataplane by default (does not publish local datasources).
54
+ - Use \`aifabrix upload <roleKey> --env …\` (or \`--publish\`) when you intentionally refresh the package.
55
+ - Runs lifecycle checks, then prints a portal deep link for full step-by-step status.
56
+ - Case files with input.message/input.content execute Work Hub plan→accept (or work.start when executionPath: intent).
57
+ - answers[] and approvals[] are matched to runtime wait payloads (questionKey/requestKey/waitReason).
58
+ - Use the portal URL for detailed human review while automation reads CLI/JSON output.
59
+ `;
60
+ }
61
+
62
+ function rawArgsInclude(cmd, flag) {
63
+ const raw = cmd && Array.isArray(cmd.rawArgs) ? cmd.rawArgs : [];
64
+ return raw.includes(flag);
65
+ }
66
+
67
+ function optionOrFlag(options, key, cmd, ...flags) {
68
+ if (options[key] === true) {
69
+ return true;
70
+ }
71
+ return flags.some((flag) => rawArgsInclude(cmd, flag));
72
+ }
73
+
74
+ function trimOptionalString(value) {
75
+ return value ? String(value).trim() : '';
76
+ }
77
+
78
+ function normalizeRoleAssistantTestOptions(options, cmd) {
79
+ // Role Assistant test uses the public/running digital worker by default.
80
+ // Opt in to publish with --publish (optional --force).
81
+ const wantsPublish = optionOrFlag(options, 'publish', cmd, '--publish');
82
+ return {
83
+ env: options.env || 'dev',
84
+ verbose: optionOrFlag(options, 'verbose', cmd, '-v', '--verbose'),
85
+ debug: optionOrFlag(options, 'debug', cmd, '-d', '--debug'),
86
+ json: optionOrFlag(options, 'json', cmd, '--json'),
87
+ noPublish: !wantsPublish,
88
+ force: optionOrFlag(options, 'force', cmd, '--force'),
89
+ subjectUserId: options.subjectUserId || [],
90
+ subjectEmail: options.subjectEmail || [],
91
+ certificationProfile: options.certificationProfile || 'bronze',
92
+ case: trimOptionalString(options.case),
93
+ testsDir: trimOptionalString(options.testsDir),
94
+ run: true
95
+ };
96
+ }
97
+
98
+ function buildRoleAssistantTestEnvelope(roleKey, verdict, portalUrl, result, opts, caseResult = null) {
99
+ const report = result.report || {};
100
+ const envelope = {
101
+ roleKey,
102
+ command: 'role-assistant test',
103
+ verdict,
104
+ portalUrl,
105
+ openApiPublished: result.openApiPublished === true,
106
+ certification: report.certification || null,
107
+ recommendations: Array.isArray(report.recommendations) ? report.recommendations : [],
108
+ warnings: Array.isArray(report.warnings) ? report.warnings : [],
109
+ stepsRun: result.stepsRun || [],
110
+ case: caseResult
111
+ ? {
112
+ caseId: caseResult.caseId,
113
+ sourceFile: caseResult.sourceFile,
114
+ passed: caseResult.passed,
115
+ lifecycleState: caseResult.lifecycleState,
116
+ assertions: caseResult.assertions,
117
+ failedAssertions: caseResult.failedAssertions,
118
+ warnings: Array.isArray(caseResult.warnings) ? caseResult.warnings : [],
119
+ execution: caseResult.execution || null
120
+ }
121
+ : null
122
+ };
123
+ if (opts.verbose || opts.debug) {
124
+ envelope.report = report;
125
+ }
126
+ if (opts.debug) {
127
+ envelope.debug = {
128
+ observation: caseResult ? caseResult.observation : null,
129
+ lifecycleResult: result
130
+ };
131
+ }
132
+ return envelope;
133
+ }
134
+
135
+ function displayCaseResultSummary(caseResult) {
136
+ if (!caseResult) {
137
+ return;
138
+ }
139
+ logger.log(headerKeyValue('Case:', caseResult.caseId));
140
+ logger.log(headerKeyValue('Case file:', caseResult.sourceFile));
141
+ logger.log(headerKeyValue('Observed state:', caseResult.lifecycleState));
142
+ if (caseResult.execution) {
143
+ logger.log(headerKeyValue('Execution id:', caseResult.execution.processExecutionId || 'n/a'));
144
+ logger.log(headerKeyValue('Final runtime status:', caseResult.execution.finalStatus || 'n/a'));
145
+ }
146
+ if (caseResult.passed) {
147
+ logger.log(formatSuccessLine('Case assertions passed.'));
148
+ const warnings = Array.isArray(caseResult.warnings) ? caseResult.warnings : [];
149
+ for (const row of warnings) {
150
+ logger.log(formatWarningLine(row.message || String(row)));
151
+ }
152
+ return;
153
+ }
154
+ logger.log(formatBlockingError('Case assertions failed.'));
155
+ for (const row of caseResult.failedAssertions) {
156
+ logger.log(formatWarningLine(row.message));
157
+ }
158
+ }
159
+
160
+ function displayRoleAssistantTestSummary(roleKey, verdict, portalUrl, result, caseResult = null) {
161
+ logger.log('');
162
+ logger.log(sectionTitle(`${String(roleKey).toUpperCase()} ROLE ASSISTANT TEST`));
163
+ logger.log('');
164
+ logger.log(headerKeyValue('Role key:', roleKey));
165
+ if (portalUrl) {
166
+ logger.log(headerKeyValue('Portal:', portalUrl));
167
+ } else {
168
+ logger.log(formatWarningLine('Portal link unavailable. Configure dataplane public URL and retry.'));
169
+ }
170
+ const verdictMessage =
171
+ verdict === VERDICT.VERIFIED
172
+ ? 'Lifecycle checks passed. Open portal for full execution steps and logs.'
173
+ : 'Lifecycle checks are not fully verified. Open portal to inspect blocking steps.';
174
+ if (verdict === VERDICT.VERIFIED) {
175
+ logger.log(formatSuccessParagraph(verdictMessage));
176
+ } else {
177
+ logger.log(formatWarningLine(verdictMessage));
178
+ }
179
+ const steps = Array.isArray(result.stepsRun) ? result.stepsRun : [];
180
+ if (steps.length > 0) {
181
+ const labels = steps.map((row) => (row && row.pillar ? row.pillar : String(row)));
182
+ logger.log(metadata(`Steps run: ${labels.join(', ')}`));
183
+ }
184
+ displayCaseResultSummary(caseResult);
185
+ }
186
+
187
+ async function resolveRoleAssistantCaseResult(roleKey, opts, result, verdict, portalUrl) {
188
+ if (!opts.case) {
189
+ return null;
190
+ }
191
+ const roleCase = loadRoleAssistantTestCase(roleKey, opts.case, {
192
+ testsDir: opts.testsDir || null
193
+ });
194
+ if (!isExecutableRoleAssistantCase(roleCase)) {
195
+ return evaluateRoleAssistantTestCase(roleCase, result, verdict, portalUrl);
196
+ }
197
+ const authContext = await resolveLifecycleAuth(roleKey, {
198
+ ...opts,
199
+ run: false,
200
+ noPublish: true
201
+ });
202
+ const executionResult = await runRoleAssistantCaseLifecycle(roleKey, roleCase, authContext, opts);
203
+ const executionVerdict = lifecycleVerdictFromCaseExecution(executionResult, verdict);
204
+ const evaluationInput = mergeCaseExecutionIntoLifecycleResult(result, executionResult);
205
+ const evaluation = evaluateRoleAssistantTestCase(
206
+ roleCase,
207
+ evaluationInput,
208
+ executionVerdict,
209
+ portalUrl
210
+ );
211
+ evaluation.execution = {
212
+ processExecutionId: executionResult.processExecutionId || null,
213
+ finalStatus: executionResult.finalStatus?.status || null,
214
+ waitReason: executionResult.finalStatus?.wait?.waitReason || null,
215
+ interactions: executionResult.interactions || [],
216
+ workResultError: executionResult.workResultError || null
217
+ };
218
+ return evaluation;
219
+ }
220
+
221
+ function computeRoleAssistantExitCode(verdict, caseResult) {
222
+ if (caseResult) {
223
+ return caseResult.passed ? 0 : 2;
224
+ }
225
+ if (verdict === VERDICT.VERIFIED) {
226
+ return 0;
227
+ }
228
+ return exitCodeFromVerdict(verdict, { partial: verdict === VERDICT.NOT_VERIFIED });
229
+ }
230
+
231
+ async function runRoleAssistantTestAction(roleKey, options, cmd) {
232
+ const opts = normalizeRoleAssistantTestOptions(options, cmd);
233
+ const result = await runLifecycleForExternalSystem(roleKey, opts);
234
+ const verdict = lifecycleVerdictFromReport(result.report || {});
235
+ const portalUrl = buildExternalSystemUiUrl(result.dataplaneUiBaseUrl, roleKey);
236
+ const caseResult = await resolveRoleAssistantCaseResult(roleKey, opts, result, verdict, portalUrl);
237
+
238
+ if (opts.json) {
239
+ logger.log(
240
+ JSON.stringify(
241
+ buildRoleAssistantTestEnvelope(roleKey, verdict, portalUrl, result, opts, caseResult),
242
+ null,
243
+ 2
244
+ )
245
+ );
246
+ } else {
247
+ displayRoleAssistantTestSummary(roleKey, verdict, portalUrl, result, caseResult);
248
+ }
249
+
250
+ const exitCode = computeRoleAssistantExitCode(verdict, caseResult);
251
+ if (exitCode !== 0) {
252
+ process.exit(exitCode);
253
+ }
254
+ }
255
+
256
+ async function roleAssistantTestHandler(roleKey, options, cmd) {
257
+ try {
258
+ await runRoleAssistantTestAction(roleKey, options, cmd);
259
+ } catch (error) {
260
+ handleCommandError(error, 'role-assistant test');
261
+ process.exit(3);
262
+ }
263
+ }
264
+
265
+ function setupRoleAssistantCommands(program) {
266
+ const roleAssistant = program
267
+ .command('role-assistant')
268
+ .description('Role Assistant lifecycle and portal workflows');
269
+
270
+ roleAssistant
271
+ .command('test <roleKey>')
272
+ .description('Run role-assistant lifecycle checks and print portal deep link')
273
+ .option('-e, --env <env>', 'Environment: dev, tst, or pro', 'dev')
274
+ .option('--case <caseIdOrPath>', 'Run and evaluate one role-assistant test case')
275
+ .option('--tests-dir <dir>', 'Override role-assistant test case directory')
276
+ .option('-v, --verbose', 'Include full lifecycle report payload in --json output')
277
+ .option('-d, --debug', 'Write debug logs under role-assistant/<roleKey>/logs/')
278
+ .option(
279
+ '--publish',
280
+ 'Publish local Role Assistant package before checks (default: use public/running worker)'
281
+ )
282
+ .option('--force', 'Force upload when --publish is set')
283
+ .option(
284
+ '--subject-user-id <id>',
285
+ 'Subject user id for governance generate (repeatable)',
286
+ collectString,
287
+ []
288
+ )
289
+ .option(
290
+ '--subject-email <email>',
291
+ 'Subject email for governance generate (repeatable)',
292
+ collectString,
293
+ []
294
+ )
295
+ .option(
296
+ '--certification-profile <profile>',
297
+ 'Certification profile for governance generate (bronze, silver, gold, ...)',
298
+ 'bronze'
299
+ )
300
+ .option('--json', 'Machine-readable output envelope')
301
+ .addHelpText('after', roleAssistantHelpAfter())
302
+ .action((roleKey, options, cmd) => roleAssistantTestHandler(roleKey, options, cmd));
303
+ }
304
+
305
+ module.exports = {
306
+ setupRoleAssistantCommands,
307
+ roleAssistantTestHandler,
308
+ runRoleAssistantTestAction,
309
+ normalizeRoleAssistantTestOptions,
310
+ buildRoleAssistantTestEnvelope,
311
+ computeRoleAssistantExitCode,
312
+ resolveRoleAssistantCaseResult
313
+ };
@@ -27,7 +27,7 @@ async function finalizeUploadPublishResult(ctx, payload, options) {
27
27
  options,
28
28
  label: 'Upload data sync'
29
29
  });
30
- return { ...ctx, dataSync };
30
+ return { ...ctx, dataSync, sidecar: ctx.sidecar || null };
31
31
  }
32
32
 
33
33
  /**
@@ -40,15 +40,16 @@ async function finishUnchangedUploadPublication(params) {
40
40
  if (!isQuietMinimalSync(options)) {
41
41
  logger.log(formatSuccessLine('Config unchanged on dataplane — upload skipped.'));
42
42
  }
43
- await runUploadSidecarFollowups({
43
+ const sidecar = await runUploadSidecarFollowups({
44
44
  systemKey,
45
45
  options,
46
46
  payload,
47
47
  dataplaneUrl,
48
- authConfig
48
+ authConfig,
49
+ environment
49
50
  });
50
51
  return finalizeUploadPublishResult(
51
- { dataplaneUrl, authConfig, environment, uploadSkipped: true },
52
+ { dataplaneUrl, authConfig, environment, uploadSkipped: true, sidecar },
52
53
  payload,
53
54
  options
54
55
  );
@@ -12,22 +12,123 @@ const { unwrapPublicationResult, isPublicationUnchanged } = require('../utils/ex
12
12
  const { logUploadReadinessSummary } = require('../utils/external-system-readiness-display');
13
13
  const { isQuietMinimalSync } = require('../utils/upload-sync-options');
14
14
 
15
+ function buildRoleAssistantModel(payload) {
16
+ return {
17
+ application: payload?.application,
18
+ dataSources: payload?.dataSources || []
19
+ };
20
+ }
21
+
22
+ function buildRoleAssistantSyncContext(ctx, model) {
23
+ // Controller deploy env (e.g. miso) ≠ role-assistant.yaml section (dev|tst|pro).
24
+ const { resolveRoleAssistantSettingsEnvKey } = require('../role-assistant/knowledge-sync');
25
+ const raEnv = resolveRoleAssistantSettingsEnvKey(
26
+ (ctx.options && (ctx.options.env || ctx.options.roleAssistantEnv)) || 'dev'
27
+ );
28
+ return {
29
+ systemKey: ctx.systemKey,
30
+ dataplaneUrl: ctx.dataplaneUrl,
31
+ authConfig: ctx.authConfig,
32
+ model,
33
+ environment: raEnv,
34
+ pathOptions: ctx.options.pathOptions || {},
35
+ dryRun: ctx.options.dryRun === true
36
+ };
37
+ }
38
+
39
+ async function runGovernanceSidecar(ctx, sidecar, quietSidecar) {
40
+ try {
41
+ const { uploadGovernanceScenarioPacks } = require('../lifecycle/scenario-upload');
42
+ const uploaded = await uploadGovernanceScenarioPacks(ctx.systemKey, ctx.dataplaneUrl, ctx.authConfig, {
43
+ silent: quietSidecar
44
+ });
45
+ sidecar.governance = { uploaded: Number(uploaded || 0) };
46
+ } catch (err) {
47
+ sidecar.governance = { skipped: true, reason: err.message || String(err) };
48
+ if (!quietSidecar) {
49
+ logger.log(formatWarningLine(`Governance scenario upload skipped: ${err.message}`));
50
+ }
51
+ }
52
+ }
53
+
54
+ async function runEvidenceSidecar(ctx, model, sidecar, quietSidecar) {
55
+ const { importRoleAssistantEvidence, logRoleAssistantEvidenceImportSummary } = require('../role-assistant/evidence-sync');
56
+ const result = await importRoleAssistantEvidence(buildRoleAssistantSyncContext(ctx, model));
57
+ sidecar.evidence = result;
58
+ if (!quietSidecar) {
59
+ logRoleAssistantEvidenceImportSummary(ctx.systemKey, result, { verbose: ctx.options.verbose === true });
60
+ }
61
+ }
62
+
63
+ async function runKnowledgeSidecar(ctx, model, sidecar, quietSidecar) {
64
+ const {
65
+ importRoleAssistantKnowledge,
66
+ logKnowledgeImportSummary,
67
+ pushRoleAssistantDocumentStorageSettings,
68
+ logDocumentStorageSettingsPushSummary
69
+ } = require('../role-assistant/knowledge-sync');
70
+ const syncCtx = buildRoleAssistantSyncContext(ctx, model);
71
+ try {
72
+ const settingsResult = await pushRoleAssistantDocumentStorageSettings(syncCtx);
73
+ sidecar.documentStorageSettings = settingsResult;
74
+ if (!quietSidecar) {
75
+ logDocumentStorageSettingsPushSummary(ctx.systemKey, settingsResult, {
76
+ verbose: ctx.options.verbose === true
77
+ });
78
+ }
79
+ } catch (err) {
80
+ sidecar.documentStorageSettings = {
81
+ skipped: true,
82
+ reason: err.message || String(err)
83
+ };
84
+ if (!quietSidecar) {
85
+ logger.log(
86
+ formatWarningLine(
87
+ `Knowledge document storage settings update failed: ${err.message}`
88
+ )
89
+ );
90
+ }
91
+ throw err;
92
+ }
93
+ try {
94
+ const result = await importRoleAssistantKnowledge(syncCtx);
95
+ sidecar.knowledge = result;
96
+ if (!quietSidecar) {
97
+ logKnowledgeImportSummary(ctx.systemKey, result, { verbose: ctx.options.verbose === true });
98
+ }
99
+ } catch (err) {
100
+ sidecar.knowledge = { skipped: true, reason: err.message || String(err) };
101
+ if (!quietSidecar) {
102
+ logger.log(formatWarningLine(`Role assistant knowledge sync skipped: ${err.message}`));
103
+ }
104
+ }
105
+ }
106
+
15
107
  /**
16
108
  * Sidecar follow-ups that are independent of pipeline publish hash (scenario packs).
17
109
  * @param {Object} ctx
18
110
  * @returns {Promise<void>}
19
111
  */
20
112
  async function runUploadSidecarFollowups(ctx) {
21
- const { systemKey, options, dataplaneUrl, authConfig } = ctx;
22
- const quietSidecar = isQuietMinimalSync(options);
113
+ const sidecar = {
114
+ governance: null,
115
+ evidence: null,
116
+ knowledge: null,
117
+ documentStorageSettings: null
118
+ };
119
+ const quietSidecar = isQuietMinimalSync(ctx.options);
120
+ const model = buildRoleAssistantModel(ctx.payload);
121
+ await runGovernanceSidecar(ctx, sidecar, quietSidecar);
23
122
  try {
24
- const { uploadGovernanceScenarioPacks } = require('../lifecycle/scenario-upload');
25
- await uploadGovernanceScenarioPacks(systemKey, dataplaneUrl, authConfig, { silent: quietSidecar });
123
+ await runEvidenceSidecar(ctx, model, sidecar, quietSidecar);
26
124
  } catch (err) {
27
- if (!quietSidecar) {
28
- logger.log(formatWarningLine(`Governance scenario upload skipped: ${err.message}`));
125
+ if (err && err.evidenceSummary) {
126
+ sidecar.evidence = err.evidenceSummary;
29
127
  }
128
+ throw err;
30
129
  }
130
+ await runKnowledgeSidecar(ctx, model, sidecar, quietSidecar);
131
+ return sidecar;
31
132
  }
32
133
 
33
134
  /**
@@ -54,61 +155,57 @@ async function resolveUploadProbeData(ctx, maybeRunUploadProbeFn) {
54
155
  return { probeData: null, compact };
55
156
  }
56
157
 
158
+ function logUploadSummary(ctx, publication, probeData) {
159
+ if (ctx.options.suppressSummary === true) {
160
+ return;
161
+ }
162
+ logUploadReadinessSummary({
163
+ environment: ctx.environment,
164
+ dataplaneUrl: ctx.dataplaneUrl,
165
+ systemKey: ctx.systemKey,
166
+ publication,
167
+ manifest: ctx.manifest,
168
+ minimal: !!ctx.options.minimal,
169
+ willProbe: false,
170
+ credentialPush: ctx.credentialPush,
171
+ configPush: ctx.configPush,
172
+ forcePublish: ctx.options.force === true,
173
+ probeData
174
+ });
175
+ }
176
+
177
+ async function runProbeAfterSummary(ctx, maybeRunUploadProbe, compact) {
178
+ if (ctx.options.probe && !compact) {
179
+ await maybeRunUploadProbe(ctx.dataplaneUrl, ctx.systemKey, ctx.authConfig, ctx.options.probeTimeout, {
180
+ compact: false
181
+ });
182
+ }
183
+ }
184
+
185
+ async function runSidecarAndWrap(ctx) {
186
+ const sidecar = await runUploadSidecarFollowups(ctx);
187
+ return { sidecar };
188
+ }
189
+
57
190
  /**
58
191
  * @param {Object} ctx
59
192
  * @param {Function} maybeRunUploadProbe
60
193
  * @returns {Promise<void>}
61
194
  */
62
195
  async function handlePublicationAndFollowups(ctx, maybeRunUploadProbe) {
63
- const {
64
- systemKey,
65
- options,
66
- manifest,
67
- payload,
68
- environment,
69
- dataplaneUrl,
70
- authConfig,
71
- rawRes,
72
- credentialPush,
73
- configPush
74
- } = ctx;
75
- const publication = unwrapPublicationResult(rawRes);
196
+ const publication = unwrapPublicationResult(ctx.rawRes);
76
197
  if (!publication) {
77
198
  throw new Error(
78
199
  'Unexpected response from dataplane upload: missing publication result (uploadId/system/datasources).'
79
200
  );
80
201
  }
81
202
  if (isPublicationUnchanged(publication)) {
82
- await runUploadSidecarFollowups({ systemKey, options, payload, dataplaneUrl, authConfig });
83
- return;
203
+ return runSidecarAndWrap(ctx);
84
204
  }
85
-
86
- const suppressSummary = options.suppressSummary === true;
87
205
  const { probeData, compact } = await resolveUploadProbeData(ctx, maybeRunUploadProbe);
88
-
89
- if (!suppressSummary) {
90
- logUploadReadinessSummary({
91
- environment,
92
- dataplaneUrl,
93
- systemKey,
94
- publication,
95
- manifest,
96
- minimal: !!options.minimal,
97
- willProbe: false,
98
- credentialPush,
99
- configPush,
100
- forcePublish: options.force === true,
101
- probeData
102
- });
103
- }
104
-
105
- if (options.probe && !compact) {
106
- await maybeRunUploadProbe(dataplaneUrl, systemKey, authConfig, options.probeTimeout, {
107
- compact: false
108
- });
109
- }
110
-
111
- await runUploadSidecarFollowups({ systemKey, options, payload, dataplaneUrl, authConfig });
206
+ logUploadSummary(ctx, publication, probeData);
207
+ await runProbeAfterSummary(ctx, maybeRunUploadProbe, compact);
208
+ return runSidecarAndWrap(ctx);
112
209
  }
113
210
 
114
211
  module.exports = {
@@ -47,6 +47,12 @@ const { syncDeployJsonFromSources } = require('../external-system/sync-deploy-ma
47
47
  const { handlePublicationAndFollowups } = require('./upload-sidecar-followups');
48
48
  const { finalizeUploadPublishResult, finishUnchangedUploadPublication } = require('./upload-data-sync-finalize');
49
49
  const { pushAndLogCredentialSecrets } = require('./upload-credential-push-log');
50
+ const {
51
+ SYSTEM_KIND_DIGITAL_WORKER,
52
+ readRoleAssistantSettings,
53
+ resolveRoleAssistantSettingsVersion,
54
+ resolveRoleAssistantEnvironmentSettings
55
+ } = require('../role-assistant/settings');
50
56
 
51
57
  /**
52
58
  * Validates system-key format (same as download).
@@ -123,14 +129,24 @@ async function resolveDataplaneAndAuth(systemKey, opts = {}) {
123
129
  * @param {string} dataplaneUrl - Dataplane base URL
124
130
  * @param {Object} authConfig - Auth config
125
131
  * @param {Object} payload - { version, application, dataSources, status: "draft" }
132
+ * @param {string} systemKey
133
+ * @param {Object} [options]
134
+ * @param {number|string} [options.timeoutMs]
126
135
  * @returns {Promise<Object>} Raw API response envelope
127
136
  */
128
- async function runUploadValidatePublish(dataplaneUrl, authConfig, payload, systemKey) {
137
+ async function runUploadValidatePublish(
138
+ dataplaneUrl,
139
+ authConfig,
140
+ payload,
141
+ systemKey,
142
+ options = {}
143
+ ) {
129
144
  const res = await uploadApplicationViaPipelineWithAuthRetry(
130
145
  dataplaneUrl,
131
146
  authConfig,
132
147
  payload,
133
- systemKey
148
+ systemKey,
149
+ { timeoutMs: options.timeoutMs }
134
150
  );
135
151
  if (res?.success === false) {
136
152
  throw new Error(formatApiError(res, dataplaneUrl));
@@ -231,6 +247,14 @@ async function buildValidatedUploadManifestPayload(systemKey, opts = {}) {
231
247
  force: opts.force === true,
232
248
  status: opts.uploadStatus === 'published' ? 'published' : 'draft'
233
249
  });
250
+ if (String(manifest?.system?.systemKind || '').trim() === SYSTEM_KIND_DIGITAL_WORKER) {
251
+ const settings = readRoleAssistantSettings(systemKey, { required: true, pathOptions });
252
+ resolveRoleAssistantEnvironmentSettings(settings, opts.env || 'dev', { required: true });
253
+ const settingsVersion = resolveRoleAssistantSettingsVersion(settings);
254
+ if (settingsVersion) {
255
+ payload.version = settingsVersion;
256
+ }
257
+ }
234
258
  await resolvePayloadConfiguration(systemKey, payload, pathOptions);
235
259
  return { manifest, payload };
236
260
  }
@@ -264,7 +288,10 @@ async function logAndSyncLocalOpenApiForUpload(systemKey, manifest, uploadContex
264
288
  systemKey,
265
289
  datasourceFiles,
266
290
  dataplaneUrl: uploadContext.dataplaneUrl,
267
- authConfig: uploadContext.authConfig
291
+ authConfig: uploadContext.authConfig,
292
+ // Always replace SpecFile rows keyed by openapi.documentKey so vendor/full
293
+ // specs are not left missing while only thin internal:* slices remain.
294
+ force: true
268
295
  });
269
296
  if (!uploadContext.quiet) {
270
297
  for (const line of openapiSyncLines) {
@@ -293,7 +320,7 @@ async function completeUploadAfterPublish(systemKey, options, manifest, payload,
293
320
  pathOptions: options.pathOptions,
294
321
  quiet: quietCompact
295
322
  });
296
- await handlePublicationAndFollowups(
323
+ const followupResult = await handlePublicationAndFollowups(
297
324
  {
298
325
  systemKey,
299
326
  options,
@@ -309,7 +336,13 @@ async function completeUploadAfterPublish(systemKey, options, manifest, payload,
309
336
  maybeRunUploadProbe
310
337
  );
311
338
  return finalizeUploadPublishResult(
312
- { dataplaneUrl: ctx.dataplaneUrl, authConfig: ctx.authConfig, environment: ctx.environment, uploadSkipped: false },
339
+ {
340
+ dataplaneUrl: ctx.dataplaneUrl,
341
+ authConfig: ctx.authConfig,
342
+ environment: ctx.environment,
343
+ uploadSkipped: false,
344
+ sidecar: followupResult?.sidecar || null
345
+ },
313
346
  payload,
314
347
  options
315
348
  );
@@ -331,7 +364,10 @@ async function runUploadPublishAndSummary(systemKey, options, manifest, payload)
331
364
  payload
332
365
  );
333
366
  const rawRes = await runWithUploadPipelineSpinner(
334
- async() => runUploadValidatePublish(dataplaneUrl, authConfig, payload, systemKey),
367
+ async() =>
368
+ runUploadValidatePublish(dataplaneUrl, authConfig, payload, systemKey, {
369
+ timeoutMs: options.timeoutMs
370
+ }),
335
371
  {
336
372
  systemKey,
337
373
  json: options.json === true,
@@ -367,6 +403,7 @@ async function runUploadPublishAndSummary(systemKey, options, manifest, payload)
367
403
  * @param {boolean} [options.verbose] - Expanded summary and server-side pipeline validate warnings
368
404
  * @param {boolean} [options.probe] - POST validation/run after publish
369
405
  * @param {number} [options.probeTimeout] - Probe timeout ms (default 120000)
406
+ * @param {number} [options.timeoutMs] - Pipeline publish timeout ms (HTTP + dataplane; default 300000)
370
407
  * @param {boolean} [options.minimal] - Short summary (default: compact unless --verbose)
371
408
  * @returns {Promise<{ dataplaneUrl: string, authConfig: Object, environment: string }|void>}
372
409
  * @throws {Error} If validation or API calls fail