@aifabrix/builder 2.51.0 → 2.52.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (198) 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-container-start.js +4 -0
  14. package/lib/app/run-deploy-job.js +216 -0
  15. package/lib/app/run-env-compose.js +32 -0
  16. package/lib/app/run-env-recovery.js +35 -0
  17. package/lib/app/run-helpers.js +15 -9
  18. package/lib/app/run.js +18 -2
  19. package/lib/channels/add-channel.js +54 -23
  20. package/lib/channels/approval-guides/chatgpt.js +13 -9
  21. package/lib/channels/approval-guides/microsoft-copilot.js +7 -8
  22. package/lib/channels/channel-artifact-generator.js +14 -2
  23. package/lib/channels/channel-credential.js +3 -1
  24. package/lib/channels/channel-probe-evidence.js +79 -0
  25. package/lib/channels/channel-probe.js +265 -13
  26. package/lib/channels/channel-runtime-resolver.js +120 -29
  27. package/lib/channels/channel-status-display.js +44 -0
  28. package/lib/channels/channel-targets.js +25 -1
  29. package/lib/channels/chatgpt-runtime-contract.js +29 -0
  30. package/lib/channels/microsoft-copilot-package.js +280 -0
  31. package/lib/channels/runtime-tool-catalog.js +165 -0
  32. package/lib/cli/index.js +2 -0
  33. package/lib/cli/infra-guided-footers.js +1 -1
  34. package/lib/cli/infra-guided-public-url-warn.js +55 -0
  35. package/lib/cli/infra-guided.js +65 -56
  36. package/lib/cli/setup-app.help.js +4 -0
  37. package/lib/cli/setup-app.js +4 -0
  38. package/lib/cli/setup-app.test-commands.js +59 -28
  39. package/lib/cli/setup-external-system-help.js +8 -2
  40. package/lib/cli/setup-external-system.js +62 -12
  41. package/lib/commands/app-test.js +2 -14
  42. package/lib/commands/channel-add-setup.js +8 -2
  43. package/lib/commands/channel.js +16 -5
  44. package/lib/commands/datasource-load-export-cli.js +6 -1
  45. package/lib/commands/deploy-gate-failure-details.js +19 -17
  46. package/lib/commands/deploy-gate-orchestrator.js +3 -2
  47. package/lib/commands/dev-down.js +2 -6
  48. package/lib/commands/evidence-kind.js +65 -15
  49. package/lib/commands/governance-generate-external.js +56 -21
  50. package/lib/commands/governance-verify-external.js +2 -5
  51. package/lib/commands/lifecycle-external.js +21 -8
  52. package/lib/commands/repair-datasource-apply.js +10 -1
  53. package/lib/commands/repair-datasource-run.js +4 -2
  54. package/lib/commands/repair-datasource-test-payload.js +80 -19
  55. package/lib/commands/repair-datasource-webhooks-sync-bridge.js +42 -3
  56. package/lib/commands/repair-internal.js +9 -1
  57. package/lib/commands/repair-openapi-sync.js +34 -17
  58. package/lib/commands/role-assistant.js +371 -0
  59. package/lib/commands/test-governance-external.js +2 -5
  60. package/lib/commands/up-miso.js +61 -24
  61. package/lib/commands/upload-data-sync-finalize.js +25 -7
  62. package/lib/commands/upload-sidecar-followups.js +144 -47
  63. package/lib/commands/upload.js +43 -6
  64. package/lib/commands/verify-governance-combined-external.js +73 -9
  65. package/lib/commands/verify-governance-db.js +80 -25
  66. package/lib/commands/verify-governance-external.js +31 -10
  67. package/lib/commands/verify-operations-external.js +2 -5
  68. package/lib/commands/verify-operations-step-plan.js +31 -0
  69. package/lib/commands/verify-trust-command-action.js +2 -5
  70. package/lib/commands/wizard-core-helpers.js +7 -3
  71. package/lib/commands/wizard-core.js +78 -9
  72. package/lib/datasource/bulk-loader-run-batches.js +4 -2
  73. package/lib/datasource/bulk-loader-service.js +5 -1
  74. package/lib/datasource/datasource-identifier.js +4 -3
  75. package/lib/datasource/datasource-validate-summary.js +2 -2
  76. package/lib/datasource/integration-context.js +3 -3
  77. package/lib/datasource/resolve-app.js +90 -8
  78. package/lib/datasource/test-e2e.js +2 -2
  79. package/lib/datasource/unified-validation-run-body.js +15 -1
  80. package/lib/datasource/unified-validation-run-resolve.js +2 -2
  81. package/lib/datasource/validate.js +13 -6
  82. package/lib/external-system/deploy-helpers.js +39 -1
  83. package/lib/external-system/deploy.js +25 -11
  84. package/lib/external-system/download-helpers.js +111 -2
  85. package/lib/external-system/download-role-assistant.js +55 -0
  86. package/lib/external-system/download.js +45 -26
  87. package/lib/external-system/test-helpers.js +1 -1
  88. package/lib/external-system/test-system-level.js +21 -3
  89. package/lib/external-system/test.js +43 -7
  90. package/lib/generator/builders.js +12 -15
  91. package/lib/generator/wizard.js +51 -4
  92. package/lib/lifecycle/access-control-abac.js +121 -0
  93. package/lib/lifecycle/lifecycle-governance-options.js +4 -1
  94. package/lib/lifecycle/product-model.js +3 -2
  95. package/lib/lifecycle/report-display.js +14 -2
  96. package/lib/programmatic/capability-registry.js +20 -1
  97. package/lib/programmatic/command-options.js +1 -0
  98. package/lib/programmatic/index.js +4 -0
  99. package/lib/programmatic/manifest-patch-section.js +48 -9
  100. package/lib/programmatic/manifest-section-registry-data.js +3 -2
  101. package/lib/programmatic/openapi-apply-result-schemas.js +44 -0
  102. package/lib/programmatic/openapi-component-schemas.js +16 -1
  103. package/lib/programmatic/openapi-description-enricher.js +3 -1
  104. package/lib/programmatic/openapi-descriptions.js +55 -5
  105. package/lib/programmatic/openapi-evidence-schemas.js +161 -0
  106. package/lib/programmatic/openapi-manifest-schemas.js +6 -2
  107. package/lib/programmatic/openapi-operation-bindings.js +99 -0
  108. package/lib/programmatic/openapi-request-schemas.js +36 -1
  109. package/lib/programmatic/openapi-result-schemas.js +1 -1
  110. package/lib/programmatic/openapi-schema-descriptions-certify.js +5 -1
  111. package/lib/programmatic/openapi-schema-descriptions-core.js +1 -1
  112. package/lib/programmatic/openapi-schema-descriptions-evidence.js +156 -0
  113. package/lib/programmatic/openapi-schema-descriptions-manifest.js +4 -3
  114. package/lib/programmatic/openapi-schema-descriptions-operations.js +70 -0
  115. package/lib/programmatic/openapi-spec.js +47 -28
  116. package/lib/programmatic/orchestration-openapi-meta.js +5 -0
  117. package/lib/programmatic/request-timeout.js +3 -0
  118. package/lib/programmatic/route-handler-map.js +89 -2
  119. package/lib/programmatic/run-certify.js +15 -2
  120. package/lib/programmatic/run-deploy.js +74 -0
  121. package/lib/programmatic/run-evidence-authoring.js +80 -0
  122. package/lib/programmatic/run-protection.js +124 -0
  123. package/lib/programmatic/run-template-workspace.js +28 -1
  124. package/lib/programmatic/workspace-context.js +6 -0
  125. package/lib/protection/auth-context.js +48 -6
  126. package/lib/protection/paths.js +22 -0
  127. package/lib/protection/run-protection-create-helpers.js +22 -1
  128. package/lib/protection/run-protection-create.js +1 -1
  129. package/lib/protection/sync-after-upload.js +1 -1
  130. package/lib/role-assistant/evidence-sync.js +450 -0
  131. package/lib/role-assistant/github-workflow.js +96 -0
  132. package/lib/role-assistant/knowledge-markdown-frontmatter.js +75 -0
  133. package/lib/role-assistant/knowledge-sync.js +485 -0
  134. package/lib/role-assistant/settings.js +126 -0
  135. package/lib/role-assistant/test-cases-evaluate.js +170 -0
  136. package/lib/role-assistant/test-cases-honesty.js +184 -0
  137. package/lib/role-assistant/test-cases.js +364 -0
  138. package/lib/role-assistant/test-runner-workhub-answers.js +221 -0
  139. package/lib/role-assistant/test-runner-workhub.js +399 -0
  140. package/lib/role-assistant/test-runner.js +500 -0
  141. package/lib/schema/application-schema.json +24 -28
  142. package/lib/schema/deployment-rules.yaml +1 -0
  143. package/lib/schema/external-datasource.schema.json +38 -4
  144. package/lib/schema/external-system.schema.json +4 -4
  145. package/lib/schema/role-assistant-settings.schema.json +108 -0
  146. package/lib/utils/api.js +52 -27
  147. package/lib/utils/app-path-resolve.js +72 -24
  148. package/lib/utils/authentication-shape.js +3 -1
  149. package/lib/utils/certify-external-workspace.js +40 -0
  150. package/lib/utils/deployment-validation.js +28 -3
  151. package/lib/utils/docker-run-ephemeral.js +115 -0
  152. package/lib/utils/enterprise-knowledge-paths.js +29 -12
  153. package/lib/utils/env-copy-keycloak.js +196 -0
  154. package/lib/utils/env-copy.js +34 -1
  155. package/lib/utils/external-system-readiness-compact-display.js +3 -0
  156. package/lib/utils/health-check-public-warn.js +31 -13
  157. package/lib/utils/health-check.js +11 -1
  158. package/lib/utils/help-builder.js +1 -0
  159. package/lib/utils/paths.js +80 -38
  160. package/lib/utils/pipeline-upload-auth-retry.js +15 -3
  161. package/lib/utils/role-assistant-paths.js +160 -0
  162. package/lib/utils/schema-loader.js +41 -0
  163. package/lib/utils/schema-resolver.js +36 -4
  164. package/lib/utils/token-manager.js +38 -29
  165. package/lib/utils/upload-sync-options.js +7 -4
  166. package/lib/utils/url-declarative-resolve-load-doc.js +38 -1
  167. package/lib/validation/external-manifest-validator.js +31 -8
  168. package/lib/validation/reserved-system-key-prefixes.js +56 -0
  169. package/lib/validation/validate-external-file.js +8 -1
  170. package/lib/validation/validate.js +54 -19
  171. package/package.json +2 -1
  172. package/scripts/export-builder-api-evidence.js +1 -1
  173. package/templates/applications/builder-api/application.yaml +3 -3
  174. package/templates/applications/dataplane/application.yaml +24 -17
  175. package/templates/applications/dataplane/env.template +2 -2
  176. package/templates/applications/dataplane/rbac.yaml +24 -10
  177. package/templates/applications/keycloak/application.yaml +2 -2
  178. package/templates/applications/keycloak/env.template +5 -2
  179. package/templates/applications/miso-controller/application.yaml +3 -3
  180. package/templates/applications/miso-controller/env.template +17 -2
  181. package/templates/channels/chatgpt/install.template.md.hbs +82 -26
  182. package/templates/channels/chatgpt/integration/README.md +11 -7
  183. package/templates/channels/chatgpt/integration/application.json +2 -2
  184. package/templates/channels/chatgpt/integration/chatgpt-system.json +3 -3
  185. package/templates/channels/chatgpt/integration/env.template +1 -1
  186. package/templates/channels/chatgpt/manifest.template.json.hbs +36 -5
  187. package/templates/channels/microsoft-copilot/ai-plugin.template.json.hbs +28 -0
  188. package/templates/channels/microsoft-copilot/declarative-agent.template.json.hbs +22 -0
  189. package/templates/channels/microsoft-copilot/install.template.md.hbs +32 -22
  190. package/templates/channels/microsoft-copilot/integration/README.md +9 -7
  191. package/templates/channels/microsoft-copilot/integration/application.json +2 -2
  192. package/templates/channels/microsoft-copilot/integration/env.template +1 -1
  193. package/templates/channels/microsoft-copilot/integration/microsoft-copilot-system.json +7 -6
  194. package/templates/channels/microsoft-copilot/manifest.template.json.hbs +34 -6
  195. package/templates/channels/slack/install.template.md.hbs +6 -1
  196. package/templates/python/docker-compose.hbs +10 -0
  197. package/templates/typescript/docker-compose.hbs +10 -0
  198. /package/.cursor/plans/{157.1-security-quality-violations-by-type.csv → Done/157.1-security-quality-violations-by-type.csv} +0 -0
@@ -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
@@ -10,6 +10,56 @@ const {
10
10
  buildSubjectsFromOptions,
11
11
  resolveGovernanceIntegrationContext
12
12
  } = require('./governance-cli-shared');
13
+ const { VERDICT } = require('../lifecycle/product-model');
14
+ const {
15
+ allDatasourcesAbacNotApplicable,
16
+ filterAbacRequiredDatasourceKeys
17
+ } = require('../lifecycle/access-control-abac');
18
+ const { runSystemLifecycle } = require('../api/lifecycle.api');
19
+
20
+ /**
21
+ * @param {string} resolvedKey
22
+ * @param {string[]} keys
23
+ * @param {Object} [extra]
24
+ * @returns {Object}
25
+ */
26
+ function buildNotApplicableGovernanceResult(resolvedKey, keys, extra = {}) {
27
+ return {
28
+ systemKey: resolvedKey,
29
+ command: 'verify-governance',
30
+ verdict: VERDICT.NOT_APPLICABLE,
31
+ policyCoveragePercent: 100,
32
+ dimensionCoveragePercent: 100,
33
+ enforcementScenarios: { passed: 0, total: 0 },
34
+ datasourceRows: keys.map(datasourceKey => ({
35
+ datasourceKey,
36
+ verdict: VERDICT.NOT_APPLICABLE
37
+ })),
38
+ ...extra
39
+ };
40
+ }
41
+
42
+ /**
43
+ * @param {string} dataplaneUrl
44
+ * @param {Object} authConfig
45
+ * @param {string} resolvedKey
46
+ * @param {string[]} keys
47
+ * @param {Object} [extra]
48
+ * @returns {Promise<Object>}
49
+ */
50
+ async function closeAllGovernanceAsNotApplicable(
51
+ dataplaneUrl,
52
+ authConfig,
53
+ resolvedKey,
54
+ keys,
55
+ extra = {}
56
+ ) {
57
+ await runSystemLifecycle(dataplaneUrl, authConfig, resolvedKey, {
58
+ steps: ['governance'],
59
+ datasourceKeys: keys
60
+ });
61
+ return buildNotApplicableGovernanceResult(resolvedKey, keys, extra);
62
+ }
13
63
 
14
64
  /**
15
65
  * @async
@@ -23,22 +73,32 @@ async function runVerifyGovernanceCombined(systemKey, options = {}) {
23
73
  }
24
74
 
25
75
  const subjects = buildSubjectsFromOptions(options);
76
+ const { resolvedKey, keys, authConfig, dataplaneUrl } =
77
+ await resolveGovernanceIntegrationContext(systemKey, options);
78
+
26
79
  if (subjects.length === 0) {
27
- throw new Error(
28
- 'At least one --subject-user-id or --subject-email is required for verify-governance'
29
- );
80
+ if (!allDatasourcesAbacNotApplicable(resolvedKey, keys)) {
81
+ throw new Error(
82
+ 'At least one --subject-user-id or --subject-email is required for verify-governance'
83
+ );
84
+ }
85
+ return closeAllGovernanceAsNotApplicable(dataplaneUrl, authConfig, resolvedKey, keys);
30
86
  }
31
87
 
32
- const { resolvedKey, authConfig, dataplaneUrl } = await resolveGovernanceIntegrationContext(
33
- systemKey,
34
- options
35
- );
88
+ const requiredKeys = filterAbacRequiredDatasourceKeys(resolvedKey, keys);
89
+ if (requiredKeys.length === 0) {
90
+ return closeAllGovernanceAsNotApplicable(dataplaneUrl, authConfig, resolvedKey, keys, {
91
+ generated: 0,
92
+ generateResults: []
93
+ });
94
+ }
36
95
 
37
96
  const pipelineOpts = {
38
97
  ...options,
39
98
  noPublish: true,
40
99
  authConfig,
41
- dataplaneUrl
100
+ dataplaneUrl,
101
+ datasourceKeys: requiredKeys
42
102
  };
43
103
 
44
104
  const generateResult = await runGovernanceGenerateForExternalSystem(
@@ -46,7 +106,11 @@ async function runVerifyGovernanceCombined(systemKey, options = {}) {
46
106
  pipelineOpts
47
107
  );
48
108
 
49
- const verifyResult = await runVerifyGovernanceForExternalSystem(resolvedKey, pipelineOpts);
109
+ // Verify all datasources so notApplicable keys close as NOT_APPLICABLE.
110
+ const verifyResult = await runVerifyGovernanceForExternalSystem(resolvedKey, {
111
+ ...pipelineOpts,
112
+ datasourceKeys: keys
113
+ });
50
114
 
51
115
  return {
52
116
  ...verifyResult,
@@ -27,6 +27,58 @@ function attachUploadAuthToOptions(options, uploadCtx) {
27
27
  options.silentResolve = true;
28
28
  }
29
29
 
30
+ /**
31
+ * @param {string} key
32
+ * @param {Object|null} config
33
+ * @returns {Object}
34
+ */
35
+ function buildNotApplicableGovernanceRow(key, config) {
36
+ const {
37
+ parseAccessControlAbac
38
+ } = require('../lifecycle/access-control-abac');
39
+ const abac = parseAccessControlAbac(config);
40
+ return {
41
+ datasourceKey: key,
42
+ verdict: VERDICT.NOT_APPLICABLE,
43
+ scenarios: { passed: 0, total: 0 },
44
+ policyCoveragePercent: 100,
45
+ dimensionCoveragePercent: 100,
46
+ rationale: abac.rationale
47
+ };
48
+ }
49
+
50
+ /**
51
+ * @param {string} key
52
+ * @param {Object} ctx
53
+ * @returns {Promise<Object|null>}
54
+ */
55
+ async function runRequiredGovernanceDatasource(key, ctx) {
56
+ try {
57
+ const packRow = await getDatasourceGovernancePack(ctx.dataplaneUrl, ctx.authConfig, key);
58
+ if (!packRow || !packRow.pack) {
59
+ return null;
60
+ }
61
+ const result = await runDatasourceGovernanceScenarios(ctx.dataplaneUrl, ctx.authConfig, key);
62
+ const summary = result.summary || {};
63
+ return {
64
+ datasourceKey: key,
65
+ verdict: summary.failed > 0 ? VERDICT.FAILED : VERDICT.VERIFIED,
66
+ scenarios: { passed: summary.passed || 0, total: summary.total || 0 },
67
+ policyCoveragePercent: result.policyCoveragePercent ?? 100,
68
+ dimensionCoveragePercent: result.dimensionCoveragePercent ?? 100,
69
+ packDocument: packRow.pack,
70
+ result
71
+ };
72
+ } catch (err) {
73
+ return {
74
+ datasourceKey: key,
75
+ verdict: VERDICT.FAILED,
76
+ error: err.message,
77
+ scenarios: { passed: 0, total: 0 }
78
+ };
79
+ }
80
+ }
81
+
30
82
  /**
31
83
  * @async
32
84
  * @param {string[]} keys
@@ -35,35 +87,27 @@ function attachUploadAuthToOptions(options, uploadCtx) {
35
87
  * @returns {Promise<Array>}
36
88
  */
37
89
  async function runGovernanceForDatasourceKeys(keys, ctx, progress = {}) {
90
+ const {
91
+ filterAbacRequiredDatasourceKeys,
92
+ loadDatasourceConfigsByKey
93
+ } = require('../lifecycle/access-control-abac');
94
+ const configs = loadDatasourceConfigsByKey(ctx.systemKey || '');
95
+ const required = new Set(
96
+ filterAbacRequiredDatasourceKeys(ctx.systemKey || '', keys)
97
+ );
38
98
  const rows = [];
39
99
  for (let index = 0; index < keys.length; index += 1) {
40
100
  const key = keys[index];
41
101
  if (typeof progress.setLabel === 'function') {
42
102
  progress.setLabel(`Running governance scenarios: ${key} (${index + 1}/${keys.length})`);
43
103
  }
44
- try {
45
- const packRow = await getDatasourceGovernancePack(ctx.dataplaneUrl, ctx.authConfig, key);
46
- if (!packRow || !packRow.pack) {
47
- continue;
48
- }
49
- const result = await runDatasourceGovernanceScenarios(ctx.dataplaneUrl, ctx.authConfig, key);
50
- const summary = result.summary || {};
51
- rows.push({
52
- datasourceKey: key,
53
- verdict: summary.failed > 0 ? VERDICT.FAILED : VERDICT.VERIFIED,
54
- scenarios: { passed: summary.passed || 0, total: summary.total || 0 },
55
- policyCoveragePercent: result.policyCoveragePercent ?? 100,
56
- dimensionCoveragePercent: result.dimensionCoveragePercent ?? 100,
57
- packDocument: packRow.pack,
58
- result
59
- });
60
- } catch (err) {
61
- rows.push({
62
- datasourceKey: key,
63
- verdict: VERDICT.FAILED,
64
- error: err.message,
65
- scenarios: { passed: 0, total: 0 }
66
- });
104
+ if (!required.has(key)) {
105
+ rows.push(buildNotApplicableGovernanceRow(key, configs.get(key) || null));
106
+ continue;
107
+ }
108
+ const row = await runRequiredGovernanceDatasource(key, ctx);
109
+ if (row) {
110
+ rows.push(row);
67
111
  }
68
112
  }
69
113
  return rows;
@@ -76,7 +120,12 @@ async function runGovernanceForDatasourceKeys(keys, ctx, progress = {}) {
76
120
  * @returns {Promise<Object>}
77
121
  */
78
122
  async function runVerifyGovernanceFromDbPacks(systemKey, options) {
79
- const { systemKey: resolvedKey, keys } = resolveExternalIntegrationContext(systemKey);
123
+ const { systemKey: resolvedKey, keys: discoveredKeys } =
124
+ resolveExternalIntegrationContext(systemKey);
125
+ const keys =
126
+ Array.isArray(options.datasourceKeys) && options.datasourceKeys.length
127
+ ? options.datasourceKeys
128
+ : discoveredKeys;
80
129
  if (keys.length === 0) {
81
130
  return { resolvedKey, datasourceRows: [] };
82
131
  }
@@ -87,10 +136,16 @@ async function runVerifyGovernanceFromDbPacks(systemKey, options) {
87
136
  }
88
137
 
89
138
  const { authConfig, dataplaneUrl } = await resolveIntegrationAuth(resolvedKey, options);
139
+ options.authConfig = authConfig;
140
+ options.dataplaneUrl = dataplaneUrl;
90
141
  const datasourceRows = await runWithVerifyStepProgress(
91
142
  'Running governance scenarios',
92
143
  async(progress) =>
93
- runGovernanceForDatasourceKeys(keys, { authConfig, dataplaneUrl }, progress),
144
+ runGovernanceForDatasourceKeys(
145
+ keys,
146
+ { authConfig, dataplaneUrl, systemKey: resolvedKey },
147
+ progress
148
+ ),
94
149
  options
95
150
  );
96
151
  return { resolvedKey, datasourceRows };
@@ -8,7 +8,7 @@
8
8
 
9
9
  const { runTestGovernanceForExternalSystem } = require('./test-governance-external');
10
10
  const { runVerifyGovernanceFromDbPacks } = require('./verify-governance-db');
11
- const { VERDICT, verdictFromPassed } = require('../lifecycle/product-model');
11
+ const { VERDICT } = require('../lifecycle/product-model');
12
12
  const {
13
13
  sumEnforcementScenarios,
14
14
  aggregateCoverage,
@@ -20,14 +20,26 @@ const {
20
20
  * @returns {{ passed: number, total: number }}
21
21
  */
22
22
  function buildDbPackResult(resolvedKey, datasourceRows) {
23
- const allVerified = datasourceRows.every(r => r.verdict === VERDICT.VERIFIED);
23
+ const hasFailed = datasourceRows.some(r => r.verdict === VERDICT.FAILED);
24
+ const allNa =
25
+ datasourceRows.length > 0
26
+ && datasourceRows.every(r => r.verdict === VERDICT.NOT_APPLICABLE);
27
+ const allClosed = datasourceRows.every(
28
+ r => r.verdict === VERDICT.VERIFIED || r.verdict === VERDICT.NOT_APPLICABLE
29
+ );
30
+ let verdict = VERDICT.FAILED;
31
+ if (allNa) {
32
+ verdict = VERDICT.NOT_APPLICABLE;
33
+ } else if (allClosed && !hasFailed) {
34
+ verdict = VERDICT.VERIFIED;
35
+ }
24
36
  const coverage = aggregateCoverage(datasourceRows);
25
37
  return {
26
38
  systemKey: resolvedKey,
27
39
  command: 'verify-governance',
28
- verdict: verdictFromPassed(allVerified),
29
- policyCoveragePercent: coverage.policy ?? (allVerified ? 100 : 0),
30
- dimensionCoveragePercent: coverage.dimension ?? (allVerified ? 100 : 0),
40
+ verdict,
41
+ policyCoveragePercent: coverage.policy ?? (allClosed ? 100 : 0),
42
+ dimensionCoveragePercent: coverage.dimension ?? (allClosed ? 100 : 0),
31
43
  enforcementScenarios: sumEnforcementScenarios(datasourceRows),
32
44
  datasourceRows
33
45
  };
@@ -41,12 +53,9 @@ function buildDbPackResult(resolvedKey, datasourceRows) {
41
53
  */
42
54
  async function runVerifyGovernanceForExternalSystem(systemKey, options = {}) {
43
55
  const pathsUtil = require('../utils/paths');
56
+ const { assertCertifyExternalWorkspace } = require('../utils/certify-external-workspace');
44
57
  const appType = await pathsUtil.detectAppType(systemKey).catch(() => null);
45
- if (!appType || appType.baseDir !== 'integration') {
46
- throw new Error(
47
- 'verify-governance applies to external integration folders only (integration/<systemKey>/).'
48
- );
49
- }
58
+ assertCertifyExternalWorkspace(appType && appType.baseDir, 'verify-governance');
50
59
 
51
60
  if (options.pack) {
52
61
  const runPayload = await runTestGovernanceForExternalSystem(systemKey, options);
@@ -66,6 +75,18 @@ async function runVerifyGovernanceForExternalSystem(systemKey, options = {}) {
66
75
  };
67
76
  }
68
77
 
78
+ const naKeys = datasourceRows
79
+ .filter(row => row.verdict === VERDICT.NOT_APPLICABLE)
80
+ .map(row => row.datasourceKey)
81
+ .filter(Boolean);
82
+ if (naKeys.length > 0 && options.authConfig && options.dataplaneUrl) {
83
+ const { runSystemLifecycle } = require('../api/lifecycle.api');
84
+ await runSystemLifecycle(options.dataplaneUrl, options.authConfig, resolvedKey, {
85
+ steps: ['governance'],
86
+ datasourceKeys: naKeys
87
+ });
88
+ }
89
+
69
90
  return buildDbPackResult(resolvedKey, datasourceRows);
70
91
  }
71
92
 
@@ -162,12 +162,9 @@ async function buildOperationsResult({
162
162
  */
163
163
  async function assertIntegrationExternalSystem(systemKey) {
164
164
  const pathsUtil = require('../utils/paths');
165
+ const { assertCertifyExternalWorkspace } = require('../utils/certify-external-workspace');
165
166
  const appType = await pathsUtil.detectAppType(systemKey).catch(() => null);
166
- if (!appType || appType.baseDir !== 'integration') {
167
- throw new Error(
168
- 'verify-operations applies to external integration folders only (integration/<systemKey>/).'
169
- );
170
- }
167
+ assertCertifyExternalWorkspace(appType && appType.baseDir, 'verify-operations');
171
168
  }
172
169
 
173
170
  /**