@aifabrix/builder 2.50.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 (236) hide show
  1. package/.cursor/plans/Done/157.1-security-quality-violations-by-type.csv +374 -0
  2. package/.cursor/rules/assistant-driven-integration-build.mdc +40 -0
  3. package/integration/hubspot-test/create-hubspot.js +1 -16
  4. package/jest.isolated-projects.js +77 -1
  5. package/jest.projects.js +5 -426
  6. package/lib/api/assistants.api.js +67 -0
  7. package/lib/api/datasources-extended.api.js +6 -6
  8. package/lib/api/evidence-authoring-helpers.js +267 -0
  9. package/lib/api/evidence-authoring.api.js +337 -0
  10. package/lib/api/evidence-kinds.api.js +128 -0
  11. package/lib/api/evidence.api.js +57 -1
  12. package/lib/api/index.js +24 -7
  13. package/lib/api/pipeline.api.js +47 -3
  14. package/lib/api/records-bulk.api.js +28 -3
  15. package/lib/api/resource-types.api.js +4 -4
  16. package/lib/api/roles.api.js +121 -0
  17. package/lib/api/types/evidence-kinds.types.js +42 -0
  18. package/lib/api/types/evidence.types.js +156 -8
  19. package/lib/api/types/roles.types.js +36 -0
  20. package/lib/api/work.api.js +283 -0
  21. package/lib/app/certification-verify-rows.js +1 -1
  22. package/lib/app/run-deploy-job.js +108 -0
  23. package/lib/app/run-helpers.js +10 -3
  24. package/lib/app/run.js +8 -0
  25. package/lib/app/show.js +2 -2
  26. package/lib/certification/merge-certification-from-artifact.js +1 -1
  27. package/lib/channels/add-channel.js +54 -23
  28. package/lib/channels/approval-guides/chatgpt.js +8 -7
  29. package/lib/channels/approval-guides/microsoft-copilot.js +7 -8
  30. package/lib/channels/channel-artifact-generator.js +16 -3
  31. package/lib/channels/channel-credential.js +3 -1
  32. package/lib/channels/channel-probe-evidence.js +79 -0
  33. package/lib/channels/channel-probe.js +265 -13
  34. package/lib/channels/channel-runtime-resolver.js +120 -29
  35. package/lib/channels/channel-status-display.js +44 -0
  36. package/lib/channels/channel-targets.js +7 -0
  37. package/lib/channels/chatgpt-runtime-contract.js +29 -0
  38. package/lib/channels/microsoft-copilot-package.js +280 -0
  39. package/lib/channels/runtime-tool-catalog.js +165 -0
  40. package/lib/cli/index.js +6 -0
  41. package/lib/cli/setup-app.js +26 -5
  42. package/lib/cli/setup-dev.js +23 -7
  43. package/lib/cli/setup-external-system-help.js +8 -2
  44. package/lib/cli/setup-external-system.js +12 -0
  45. package/lib/cli/setup-utility-help-after.js +12 -0
  46. package/lib/cli/setup-utility-validate.js +41 -2
  47. package/lib/commands/app-test.js +2 -14
  48. package/lib/commands/datasource-load-export-cli.js +6 -1
  49. package/lib/commands/deploy-gate-failure-details.js +23 -0
  50. package/lib/commands/deploy-gate-orchestrator.js +64 -18
  51. package/lib/commands/dev-cli-handlers.js +6 -3
  52. package/lib/commands/dev-down.js +2 -6
  53. package/lib/commands/dev-init.js +7 -109
  54. package/lib/commands/dev-refresh.js +197 -0
  55. package/lib/commands/evidence-kind.js +478 -0
  56. package/lib/commands/governance-command-action.js +4 -2
  57. package/lib/commands/governance-generate-external.js +56 -21
  58. package/lib/commands/lifecycle-external.js +10 -4
  59. package/lib/commands/repair-datasource-apply.js +10 -1
  60. package/lib/commands/repair-datasource-run.js +4 -2
  61. package/lib/commands/repair-datasource-test-payload.js +80 -19
  62. package/lib/commands/repair-datasource-webhooks-sync-bridge.js +42 -3
  63. package/lib/commands/repair-internal.js +9 -1
  64. package/lib/commands/repair-openapi-export.js +1 -1
  65. package/lib/commands/repair-openapi-sync.js +43 -18
  66. package/lib/commands/resource-type.js +101 -18
  67. package/lib/commands/role-assistant.js +313 -0
  68. package/lib/commands/role.js +452 -0
  69. package/lib/commands/setup.js +1 -1
  70. package/lib/commands/upload-data-sync-finalize.js +5 -4
  71. package/lib/commands/upload-sidecar-followups.js +144 -47
  72. package/lib/commands/upload.js +43 -6
  73. package/lib/commands/validate-json.js +230 -0
  74. package/lib/commands/verify-governance-combined-external.js +73 -9
  75. package/lib/commands/verify-governance-db.js +80 -25
  76. package/lib/commands/verify-governance-external.js +29 -5
  77. package/lib/commands/verify-operations-step-plan.js +78 -40
  78. package/lib/commands/wizard-core-helpers.js +7 -3
  79. package/lib/commands/wizard-core.js +78 -9
  80. package/lib/core/audit-logger.js +1 -1
  81. package/lib/core/secrets-load.js +1 -3
  82. package/lib/datasource/bulk-loader-run-batches.js +4 -2
  83. package/lib/datasource/bulk-loader-service.js +5 -1
  84. package/lib/datasource/capability/relate-operations.js +1 -1
  85. package/lib/datasource/datasource-validate-summary.js +2 -2
  86. package/lib/datasource/validate.js +13 -6
  87. package/lib/external-system/deploy-helpers.js +35 -1
  88. package/lib/external-system/deploy.js +23 -10
  89. package/lib/external-system/download-helpers.js +111 -2
  90. package/lib/external-system/download-role-assistant.js +55 -0
  91. package/lib/external-system/download.js +45 -26
  92. package/lib/external-system/test-helpers.js +1 -1
  93. package/lib/external-system/test.js +39 -3
  94. package/lib/generator/builders.js +3 -0
  95. package/lib/generator/helpers.js +13 -5
  96. package/lib/generator/split-variables.js +9 -3
  97. package/lib/generator/wizard.js +51 -4
  98. package/lib/infrastructure/helpers-docker-check.js +6 -0
  99. package/lib/infrastructure/helpers.js +1 -1
  100. package/lib/lifecycle/access-control-abac.js +121 -0
  101. package/lib/lifecycle/lifecycle-governance-options.js +4 -1
  102. package/lib/lifecycle/product-model.js +3 -2
  103. package/lib/lifecycle/report-display.js +14 -2
  104. package/lib/programmatic/auth-config.js +3 -2
  105. package/lib/programmatic/bearer-auth.js +1 -1
  106. package/lib/programmatic/capability-registry.js +20 -1
  107. package/lib/programmatic/command-options.js +1 -0
  108. package/lib/programmatic/enterprise-mcp-client.js +18 -2
  109. package/lib/programmatic/index.js +4 -0
  110. package/lib/programmatic/manifest-patch-section.js +48 -9
  111. package/lib/programmatic/manifest-section-registry-data.js +3 -2
  112. package/lib/programmatic/manifest-section-registry.js +18 -1
  113. package/lib/programmatic/openapi-apply-result-schemas.js +44 -0
  114. package/lib/programmatic/openapi-component-schemas.js +16 -1
  115. package/lib/programmatic/openapi-description-enricher.js +3 -1
  116. package/lib/programmatic/openapi-descriptions.js +55 -5
  117. package/lib/programmatic/openapi-evidence-schemas.js +161 -0
  118. package/lib/programmatic/openapi-manifest-schemas.js +6 -2
  119. package/lib/programmatic/openapi-operation-bindings.js +99 -0
  120. package/lib/programmatic/openapi-request-schemas.js +36 -1
  121. package/lib/programmatic/openapi-result-schemas.js +29 -12
  122. package/lib/programmatic/openapi-schema-descriptions-certify.js +5 -1
  123. package/lib/programmatic/openapi-schema-descriptions-core.js +6 -3
  124. package/lib/programmatic/openapi-schema-descriptions-evidence.js +156 -0
  125. package/lib/programmatic/openapi-schema-descriptions-manifest.js +4 -3
  126. package/lib/programmatic/openapi-schema-descriptions-operations.js +70 -0
  127. package/lib/programmatic/openapi-schema-helpers.js +16 -1
  128. package/lib/programmatic/openapi-spec.js +48 -29
  129. package/lib/programmatic/orchestration-openapi-meta.js +5 -0
  130. package/lib/programmatic/request-timeout.js +3 -0
  131. package/lib/programmatic/route-handler-map.js +89 -2
  132. package/lib/programmatic/run-certify.js +15 -2
  133. package/lib/programmatic/run-deploy.js +74 -0
  134. package/lib/programmatic/run-evidence-authoring.js +80 -0
  135. package/lib/programmatic/run-protection.js +124 -0
  136. package/lib/programmatic/run-repository-emcp.js +11 -3
  137. package/lib/programmatic/run-template-workspace.js +42 -2
  138. package/lib/programmatic/workspace-context.js +6 -0
  139. package/lib/protection/auth-context.js +48 -6
  140. package/lib/protection/paths.js +22 -0
  141. package/lib/protection/run-protection-create-helpers.js +22 -1
  142. package/lib/protection/run-protection-create.js +1 -1
  143. package/lib/protection/sync-after-upload.js +1 -1
  144. package/lib/resolvers/evidence-kind-file.js +230 -0
  145. package/lib/resolvers/resource-type-file.js +36 -1
  146. package/lib/resolvers/role-file.js +227 -0
  147. package/lib/role-assistant/evidence-sync.js +450 -0
  148. package/lib/role-assistant/github-workflow.js +96 -0
  149. package/lib/role-assistant/knowledge-sync.js +465 -0
  150. package/lib/role-assistant/settings.js +126 -0
  151. package/lib/role-assistant/test-cases-evaluate.js +170 -0
  152. package/lib/role-assistant/test-cases-honesty.js +184 -0
  153. package/lib/role-assistant/test-cases.js +364 -0
  154. package/lib/role-assistant/test-runner-workhub-answers.js +203 -0
  155. package/lib/role-assistant/test-runner-workhub.js +385 -0
  156. package/lib/role-assistant/test-runner.js +500 -0
  157. package/lib/schema/application-schema.json +36 -2
  158. package/lib/schema/deployment-rules.yaml +1 -0
  159. package/lib/schema/external-datasource.schema.json +121 -4
  160. package/lib/schema/external-system.schema.json +20 -6
  161. package/lib/schema/infra.parameter.yaml +45 -1
  162. package/lib/schema/role-assistant-settings.schema.json +108 -0
  163. package/lib/schema/type/credential-field-registry.json +19 -3
  164. package/lib/utils/api.js +52 -21
  165. package/lib/utils/app-path-resolve.js +72 -24
  166. package/lib/utils/app-register-config.js +4 -3
  167. package/lib/utils/authentication-shape.js +3 -1
  168. package/lib/utils/cli-sync-options.js +59 -3
  169. package/lib/utils/cli-utils.js +11 -3
  170. package/lib/utils/deployment-validation.js +28 -3
  171. package/lib/utils/dev-ca-install.js +5 -6
  172. package/lib/utils/dev-config.js +2 -2
  173. package/lib/utils/dev-list-sort.js +145 -0
  174. package/lib/utils/dev-platform-tls.js +0 -63
  175. package/lib/utils/docker-build.js +46 -27
  176. package/lib/utils/docker-daemon-tls-ca.js +1 -1
  177. package/lib/utils/docker-exec.js +91 -6
  178. package/lib/utils/docker-run-ephemeral.js +55 -0
  179. package/lib/utils/enterprise-knowledge-paths.js +29 -12
  180. package/lib/utils/env-copy-keycloak.js +196 -0
  181. package/lib/utils/env-copy.js +35 -4
  182. package/lib/utils/error-formatters/error-parser.js +0 -3
  183. package/lib/utils/external-env-template.js +1 -1
  184. package/lib/utils/external-system-readiness-compact-blocks.js +28 -1
  185. package/lib/utils/external-system-readiness-compact-display.js +3 -0
  186. package/lib/utils/health-check-request.js +2 -3
  187. package/lib/utils/help-builder.js +4 -0
  188. package/lib/utils/image-name.js +22 -4
  189. package/lib/utils/logger.js +37 -4
  190. package/lib/utils/manifest-source-emit.js +1 -1
  191. package/lib/utils/paths.js +98 -26
  192. package/lib/utils/pipeline-upload-auth-retry.js +19 -3
  193. package/lib/utils/postgres-platform-bootstrap.js +24 -17
  194. package/lib/utils/postgres-wipe.js +5 -2
  195. package/lib/utils/remote-dev-auth.js +39 -4
  196. package/lib/utils/resolve-docker-image-ref.js +36 -6
  197. package/lib/utils/role-assistant-paths.js +98 -0
  198. package/lib/utils/schema-loader.js +41 -0
  199. package/lib/utils/schema-resolver.js +36 -4
  200. package/lib/utils/token-manager.js +47 -22
  201. package/lib/utils/upload-sync-options.js +17 -3
  202. package/lib/utils/url-declarative-resolve-load-doc.js +38 -1
  203. package/lib/validation/external-manifest-validator.js +31 -8
  204. package/lib/validation/openapi-contract-surface-validator.js +4 -0
  205. package/lib/validation/validate-external-file.js +8 -1
  206. package/lib/validation/validator.js +6 -5
  207. package/package.json +35 -12
  208. package/scripts/export-builder-api-evidence.js +3 -3
  209. package/scripts/lib/plan-actor.js +2 -2
  210. package/scripts/lib/plan-meta.js +1 -1
  211. package/scripts/lib/plan-parse.js +1 -1
  212. package/scripts/lib/plan-prevalidate-gates.js +12 -1
  213. package/scripts/lib/plan-run-report.js +13 -2
  214. package/scripts/pnpm/lib/resolve-aifabrix-bin.mjs +10 -10
  215. package/templates/applications/dataplane/application.yaml +47 -17
  216. package/templates/applications/dataplane/env.template +28 -9
  217. package/templates/applications/dataplane/rbac.yaml +78 -2
  218. package/templates/applications/miso-controller/application.yaml +10 -1
  219. package/templates/applications/miso-controller/env.template +13 -8
  220. package/templates/applications/miso-controller/rbac.yaml +72 -0
  221. package/templates/channels/chatgpt/install.template.md.hbs +42 -24
  222. package/templates/channels/chatgpt/integration/README.md +10 -7
  223. package/templates/channels/chatgpt/integration/application.json +2 -2
  224. package/templates/channels/chatgpt/integration/chatgpt-system.json +3 -3
  225. package/templates/channels/chatgpt/integration/env.template +1 -1
  226. package/templates/channels/chatgpt/manifest.template.json.hbs +36 -5
  227. package/templates/channels/microsoft-copilot/ai-plugin.template.json.hbs +28 -0
  228. package/templates/channels/microsoft-copilot/declarative-agent.template.json.hbs +22 -0
  229. package/templates/channels/microsoft-copilot/install.template.md.hbs +32 -22
  230. package/templates/channels/microsoft-copilot/integration/README.md +9 -7
  231. package/templates/channels/microsoft-copilot/integration/application.json +2 -2
  232. package/templates/channels/microsoft-copilot/integration/env.template +1 -1
  233. package/templates/channels/microsoft-copilot/integration/microsoft-copilot-system.json +7 -6
  234. package/templates/channels/microsoft-copilot/manifest.template.json.hbs +34 -6
  235. package/templates/channels/slack/integration/slack-system.json +60 -2
  236. package/templates/python/requirements.txt +1 -1
@@ -0,0 +1,156 @@
1
+ /**
2
+ * OpenAPI schema descriptions — Evidence authoring (162.0).
3
+ *
4
+ * @fileoverview Request/result models for BTA Evidence APIs
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ /** @type {Record<string, Object>} */
12
+ const EVIDENCE_SCHEMA_DESCRIPTIONS = {
13
+ EvidenceUploadRow: {
14
+ _schema: 'One Evidence candidate row proposed for upload.',
15
+ key: 'Stable Evidence key when known.',
16
+ resourceType: 'Catalog resource type key this Evidence applies to.',
17
+ roleKey: 'Role Assistant key; must match the selected Role Assistant.',
18
+ kindKey: 'Evidence kind key from live metadata.',
19
+ kindVersion: 'Evidence kind version from live metadata.',
20
+ title: 'Short Evidence title.',
21
+ description: 'Optional longer description.',
22
+ when: 'Condition describing when this Evidence applies.',
23
+ expectedBehavior: 'Required expected behavior text.',
24
+ aspect: 'Optional Evidence aspect label.',
25
+ order: 'Optional display or priority order.',
26
+ status: 'Lifecycle status; upload persists as candidate.'
27
+ },
28
+ EvidenceUploadRequest: {
29
+ _schema: 'Upload one or many Evidence candidates for technical certification.',
30
+ roleKey: 'Selected Role Assistant key for authoring scope.',
31
+ rows: 'Evidence candidate rows to load, validate, and certify.',
32
+ comment: 'Optional certification comment applied to valid rows.'
33
+ },
34
+ EvidenceActivateRequest: {
35
+ _schema: 'Activate human-approved certified Evidence candidates.',
36
+ evidenceIds: 'Evidence ids or keys approved for activation.'
37
+ },
38
+ EvidenceKindSummary: {
39
+ _schema: 'Evidence kind available for authoring.',
40
+ key: 'Evidence kind key.',
41
+ version: 'Evidence kind version.',
42
+ displayName: 'Human-readable kind name.',
43
+ purpose: 'Kind purpose summary when present.'
44
+ },
45
+ EvidenceResourceTypeSummary: {
46
+ _schema: 'Resource type available for Evidence scoping.',
47
+ key: 'Resource type catalog key.',
48
+ displayName: 'Human-readable resource type name.',
49
+ category: 'Resource type category when present.'
50
+ },
51
+ EvidenceAuthoringConstraints: {
52
+ _schema: 'Certification and activation constraints for authoring.',
53
+ certification: 'Technical certification prerequisites.',
54
+ activation: 'Human-gate activation prerequisites.'
55
+ },
56
+ EvidenceAuthoringMetadataData: {
57
+ _schema: 'Authoritative Evidence authoring structure for a Role Assistant.',
58
+ roleKey: 'Selected Role Assistant key.',
59
+ evidenceKinds: 'Live Evidence kinds and versions.',
60
+ aspects: 'Distinct aspects already used by this Role Assistant.',
61
+ resourceTypes: 'Catalog resource types available for scoping.',
62
+ assistantCapabilities: 'Capability keys from the Role Assistant.',
63
+ writableFields: 'Fields the authoring API accepts on upload rows.',
64
+ requiredFields: 'Fields required on every upload row.',
65
+ constraints: 'Certification and activation constraints.'
66
+ },
67
+ EvidenceRowProjection: {
68
+ _schema: 'Evidence row projection returned by download/upload/activate.',
69
+ id: 'Dataplane Evidence id.',
70
+ key: 'Stable Evidence key when present.',
71
+ resourceType: 'Resource type key.',
72
+ roleKey: 'Role Assistant key.',
73
+ kindKey: 'Evidence kind key.',
74
+ kindVersion: 'Evidence kind version.',
75
+ title: 'Evidence title.',
76
+ description: 'Optional description.',
77
+ when: 'When condition text.',
78
+ expectedBehavior: 'Expected behavior text.',
79
+ aspect: 'Aspect label when present.',
80
+ order: 'Order value.',
81
+ status: 'Lifecycle status.',
82
+ fingerprint: 'Content fingerprint when present.'
83
+ },
84
+ EvidenceDownloadData: {
85
+ _schema: 'Existing Evidence for the selected Role Assistant.',
86
+ roleKey: 'Selected Role Assistant key.',
87
+ count: 'Number of Evidence rows returned.',
88
+ data: 'Evidence rows matching the download filters.'
89
+ },
90
+ EvidenceUploadItemOutcome: {
91
+ _schema: 'Per-row upload, validation, or certification outcome.',
92
+ rowIndex: 'Zero-based index in the upload rows array.',
93
+ evidenceId: 'Resolved Evidence id when available.',
94
+ evidenceRef: 'Evidence reference used for lifecycle calls.',
95
+ status: 'Outcome status label.',
96
+ message: 'Human-readable outcome message.',
97
+ issues: 'Validation or certification issues for the row.'
98
+ },
99
+ EvidenceUploadData: {
100
+ _schema: 'Upload result after load, validate, and certify (never activate).',
101
+ roleKey: 'Selected Role Assistant key.',
102
+ inserted: 'Rows inserted by bulk load.',
103
+ updated: 'Rows updated by bulk load.',
104
+ accepted: 'Rows accepted after technical certification.',
105
+ rejected: 'Rows rejected by validation or certification.',
106
+ warnings: 'Non-fatal row warnings.',
107
+ certified: 'Rows that completed technical certification.',
108
+ readyToActivate: 'True when at least one certified inactive row is ready.'
109
+ },
110
+ EvidenceActivateItemOutcome: {
111
+ _schema: 'Per-id activation outcome.',
112
+ evidenceId: 'Requested Evidence id or key.',
113
+ result: 'Activated Evidence projection when successful.',
114
+ error: 'Error message when activation failed.',
115
+ status: 'HTTP or API status code when activation failed.'
116
+ },
117
+ EvidenceActivateData: {
118
+ _schema: 'Activation result for one or many Evidence ids.',
119
+ requested: 'Number of unique Evidence ids requested.',
120
+ activated: 'Successfully activated Evidence outcomes.',
121
+ failed: 'Failed activation outcomes.',
122
+ success: 'True when every requested id activated.'
123
+ },
124
+ EvidenceAuthoringMetadataResponse: {
125
+ _schema: '200 response envelope for getEvidenceMetadata.',
126
+ success: 'Always true for successful builder-api JSON responses.',
127
+ data: 'Typed payload; see EvidenceAuthoringMetadataData.',
128
+ correlationId: 'UUID correlating logs for this request.',
129
+ requestId: 'Optional per-request UUID when emitted by the server.'
130
+ },
131
+ EvidenceDownloadResponse: {
132
+ _schema: '200 response envelope for downloadEvidence.',
133
+ success: 'Always true for successful builder-api JSON responses.',
134
+ data: 'Typed payload; see EvidenceDownloadData.',
135
+ correlationId: 'UUID correlating logs for this request.',
136
+ requestId: 'Optional per-request UUID when emitted by the server.'
137
+ },
138
+ EvidenceUploadResponse: {
139
+ _schema: '200 response envelope for uploadEvidenceCandidates.',
140
+ success: 'Always true for successful builder-api JSON responses.',
141
+ data: 'Typed payload; see EvidenceUploadData.',
142
+ correlationId: 'UUID correlating logs for this request.',
143
+ requestId: 'Optional per-request UUID when emitted by the server.'
144
+ },
145
+ EvidenceActivateResponse: {
146
+ _schema: '200 response envelope for activateEvidenceCandidates.',
147
+ success: 'Always true for successful builder-api JSON responses.',
148
+ data: 'Typed payload; see EvidenceActivateData.',
149
+ correlationId: 'UUID correlating logs for this request.',
150
+ requestId: 'Optional per-request UUID when emitted by the server.'
151
+ }
152
+ };
153
+
154
+ module.exports = {
155
+ EVIDENCE_SCHEMA_DESCRIPTIONS
156
+ };
@@ -37,11 +37,12 @@ const MANIFEST_SCHEMA_DESCRIPTIONS = {
37
37
  assumptions: 'Assumptions recorded during quality scoring.'
38
38
  },
39
39
  ManifestPatchSectionRequest: {
40
- _schema: 'Governed patch body; requires prior GET sectionReadToken.',
40
+ _schema: 'Governed patch body; intent required. sectionReadToken optional (auto re-read when omitted).',
41
41
  intent: 'Why this patch is made — audit and repair hints.',
42
42
  patch: 'Section-scoped merge or replace payload.',
43
43
  mode: 'Merge into existing section value or replace entirely.',
44
- sectionReadToken: 'Token from prior GET; stale token returns 409.',
44
+ sectionReadToken:
45
+ 'Optional token from prior GET. When omitted, server re-reads before write. Stale token returns 409.',
45
46
  dryRun: 'Validate patch without writing files.'
46
47
  },
47
48
  ManifestRepairRequest: {
@@ -68,7 +69,7 @@ const MANIFEST_SCHEMA_DESCRIPTIONS = {
68
69
  },
69
70
  repairHooks: 'Suggested repair hook names after patch.',
70
71
  recommendedNextActions: 'Agent-facing next steps (validate, repair, ask user).',
71
- sectionReadToken: 'Opaque token required for PATCH; obtained from this GET.',
72
+ sectionReadToken: 'Opaque token for optimistic concurrency on PATCH; optional when PATCH auto-refreshes.',
72
73
  quality: 'Deterministic quality score and blocking issues.'
73
74
  },
74
75
  ManifestPatchResultData: {
@@ -73,6 +73,36 @@ const OPERATIONS_SCHEMA_DESCRIPTIONS = {
73
73
  force: 'When true, upload even when validation reports non-blocking issues.',
74
74
  probe: 'When true, perform connectivity probe before upload.'
75
75
  },
76
+ DeployRequest: {
77
+ _schema: 'Optional flags for controller Deploy (CLI aifabrix deploy parity).',
78
+ gate: 'Optional pre-promote gates (comma-separated: operations, trust, governance, full).',
79
+ subjectEmail: 'Subject email for governance gate when gate includes governance or full.',
80
+ probe: 'When true, run dataplane probe checks after deploy.',
81
+ sync: 'When true, force full datasource data sync after deploy.',
82
+ verbose: 'When true, expand deploy summary output.'
83
+ },
84
+ ProtectionUploadRequest: {
85
+ _schema: 'Optional flags for protection upload (CLI protection upload parity).',
86
+ dryRun: 'When true, validate only; do not upload or sync.',
87
+ sync: 'When true, force full datasource data sync after upload.',
88
+ verbose: 'When true, emit verbose protection logs.'
89
+ },
90
+ ProtectionCreateRequest: {
91
+ _schema: 'Optional flags for protection create (CLI protection create parity).',
92
+ type: 'Preset type (for example country-sales).',
93
+ dimensionKey: 'Dimension catalog key when not inferred from type.',
94
+ field: 'Metadata field used by preset value templates.',
95
+ fkName: 'FK binding name in expressions.',
96
+ protectionKey: 'metadata.key override.',
97
+ displayName: 'metadata.displayName override.',
98
+ ruleKey: 'Rule key inside spec.rules[0].',
99
+ principalExpression: 'Group principal expression override.',
100
+ valueExpression: 'Grant valueExpression override.',
101
+ dryRun: 'When true, print scaffold without writing the file.',
102
+ force: 'When true, overwrite an existing local protection manifest.',
103
+ verbose: 'When true, emit verbose probe logs.',
104
+ disabled: 'When true, set spec.enabled to false.'
105
+ },
76
106
  TestRequest: {
77
107
  _schema: 'Optional test ladder options; runType may also be passed as query param.',
78
108
  runType: 'Test stage: unit, integration (default), or e2e.',
@@ -267,6 +297,46 @@ const OPERATIONS_SCHEMA_DESCRIPTIONS = {
267
297
  correlationId: 'UUID correlating logs for this request.',
268
298
  requestId: 'Optional per-request UUID when emitted by the server.'
269
299
  },
300
+ DeployResultData: {
301
+ _schema: 'Controller deploy outcome summary.',
302
+ deployed: 'True when controller deploy completed without gate failure.',
303
+ deploymentId: 'Controller deployment id when returned.',
304
+ environment: 'Target environment key.',
305
+ systemKey: 'Deployed integration system key.'
306
+ },
307
+ DeployResultResponse: {
308
+ _schema: '200 response envelope for runDeploySystem.',
309
+ success: 'Always true for successful builder-api JSON responses.',
310
+ data: 'Typed payload; see DeployResultData.',
311
+ correlationId: 'UUID correlating logs for this request.',
312
+ requestId: 'Optional per-request UUID when emitted by the server.'
313
+ },
314
+ ProtectionUploadData: {
315
+ _schema: 'Protection upload outcome.',
316
+ datasourceKey: 'Datasource key whose protection manifest was uploaded.',
317
+ uploaded: 'True when the manifest was published (false on dryRun).',
318
+ dryRun: 'True when validate-only dry run was requested.'
319
+ },
320
+ ProtectionUploadResponse: {
321
+ _schema: '200 response envelope for runProtectionUpload.',
322
+ success: 'Always true for successful builder-api JSON responses.',
323
+ data: 'Typed payload; see ProtectionUploadData.',
324
+ correlationId: 'UUID correlating logs for this request.',
325
+ requestId: 'Optional per-request UUID when emitted by the server.'
326
+ },
327
+ ProtectionCreateData: {
328
+ _schema: 'Protection create outcome.',
329
+ datasourceKey: 'Datasource key for the scaffolded protection manifest.',
330
+ created: 'True when the local manifest was written (false on dryRun).',
331
+ dryRun: 'True when scaffold was not written to disk.'
332
+ },
333
+ ProtectionCreateResponse: {
334
+ _schema: '200 response envelope for runProtectionCreate.',
335
+ success: 'Always true for successful builder-api JSON responses.',
336
+ data: 'Typed payload; see ProtectionCreateData.',
337
+ correlationId: 'UUID correlating logs for this request.',
338
+ requestId: 'Optional per-request UUID when emitted by the server.'
339
+ },
270
340
  TestResultResponse: {
271
341
  _schema: '200 response envelope for runTest.',
272
342
  success: 'Always true for successful builder-api JSON responses.',
@@ -41,7 +41,15 @@ function stringArraySchema() {
41
41
  * @returns {Object}
42
42
  */
43
43
  function buildSuccessEnvelopeSchema(dataSchemaName) {
44
- return frozenObject(
44
+ const dataExamples = {
45
+ HealthData: { status: 'ok' },
46
+ ReadyData: { status: 'ready', dataplaneUrl: 'http://localhost:3601' },
47
+ ListSystemsData: { systems: [] },
48
+ EmptyResultData: {},
49
+ WorkspaceStatusData: { status: 'ready' },
50
+ RepositoryStatusData: { status: 'ready' }
51
+ };
52
+ const schema = frozenObject(
45
53
  {
46
54
  success: { type: 'boolean', enum: [true] },
47
55
  data: schemaRef(dataSchemaName),
@@ -50,6 +58,13 @@ function buildSuccessEnvelopeSchema(dataSchemaName) {
50
58
  },
51
59
  ['success', 'data', 'correlationId']
52
60
  );
61
+ schema.example = {
62
+ success: true,
63
+ data: dataExamples[dataSchemaName] || {},
64
+ correlationId: '00000000-0000-4000-8000-000000000001',
65
+ requestId: '00000000-0000-4000-8000-000000000002'
66
+ };
67
+ return schema;
53
68
  }
54
69
 
55
70
  /**
@@ -47,7 +47,7 @@ function problemResponseContent(description) {
47
47
  description,
48
48
  content: {
49
49
  'application/problem+json': {
50
- schema: { $ref: '#/components/schemas/ProblemDetails' }
50
+ schema: { $ref: '#/components/schemas/ProblemDetail' }
51
51
  }
52
52
  }
53
53
  };
@@ -83,6 +83,7 @@ function requiresBearerAuth(handlerId) {
83
83
  function applyOperationDurationHints(capability, operation) {
84
84
  const durationByHandler = {
85
85
  runUpload: Number(process.env.MAX_UPLOAD_TIMEOUT_MS || 300000),
86
+ runDeploySystem: Number(process.env.MAX_DEPLOY_TIMEOUT_MS || 300000),
86
87
  runTest: Number(process.env.MAX_TEST_E2E_TIMEOUT_MS || 120000),
87
88
  runCertifyPillar: Number(process.env.MAX_CERTIFY_TIMEOUT_MS || 120000)
88
89
  };
@@ -133,6 +134,49 @@ function buildOperationObject(capability) {
133
134
  return operation;
134
135
  }
135
136
 
137
+ /**
138
+ * @returns {Object[]}
139
+ */
140
+ function buildOpenApiTags() {
141
+ return [
142
+ { name: 'workspace', description: 'Per-user integration workspaces (list, create, manifest, status, diff).' },
143
+ { name: 'build', description: 'Wizard generation and manifest repair.' },
144
+ { name: 'manifest', description: 'Governed section get/patch/repair for LLM and MCP workflows.' },
145
+ { name: 'validate', description: 'Local AJV validation and preview-upload (no Dataplane mutation).' },
146
+ { name: 'test', description: 'Unit, integration, and e2e test ladder.' },
147
+ { name: 'certify', description: 'Verify operations/trust/governance and lifecycle certification.' },
148
+ { name: 'apply', description: 'Dev Dataplane upload (requires external-system:publish).' },
149
+ { name: 'template', description: 'Enterprise MCP template.materializeWorkspace and workspace reset.' },
150
+ { name: 'repository', description: 'Enterprise MCP repository.sync, createReview, status, dispatchPipeline.' },
151
+ { name: 'infra', description: 'Liveness and readiness probes (no authentication).' },
152
+ {
153
+ name: 'evidence',
154
+ description:
155
+ 'BTA-facing Evidence authoring: metadata, download, upload (validate+certify), and human-gated activate.'
156
+ }
157
+ ];
158
+ }
159
+
160
+ /**
161
+ * @returns {Object}
162
+ */
163
+ function buildOpenApiInfo() {
164
+ return {
165
+ title: 'AI Fabrix Builder API',
166
+ version: '1.0.0',
167
+ description:
168
+ 'Workspace orchestration for external-system dev publish. Repository and template operations delegate to Enterprise MCP (154.1). Successful JSON responses use `{ success, data, correlationId, requestId? }` with `application/json`. Errors use RFC 7807 Problem Details (`application/problem+json`) aligned with miso-controller and dataplane.',
169
+ 'x-aifabrix': {
170
+ redocUrl: '/api/docs',
171
+ contractTier: 'public',
172
+ mcpGenerationReady: true,
173
+ rbacPreset: 'platform',
174
+ datasourceSplitMode: 'per-tag',
175
+ orchestrationDatasourceTags: listOrchestrationDatasourceTags()
176
+ }
177
+ };
178
+ }
179
+
136
180
  /**
137
181
  * @param {Object} [options]
138
182
  * @param {string} [options.publicBaseUrl]
@@ -148,39 +192,14 @@ function buildOpenApiSpec(options = {}) {
148
192
  if (!paths[pathKey]) {
149
193
  paths[pathKey] = {};
150
194
  }
151
- const method = capability.method.toLowerCase();
152
- paths[pathKey][method] = buildOperationObject(capability);
195
+ paths[pathKey][capability.method.toLowerCase()] = buildOperationObject(capability);
153
196
  }
154
197
 
155
198
  return {
156
199
  openapi: '3.0.3',
157
- info: {
158
- title: 'AI Fabrix Builder API',
159
- version: '1.0.0',
160
- description:
161
- 'Workspace orchestration for external-system dev publish. Repository and template operations delegate to Enterprise MCP (154.1). Successful JSON responses use `{ success, data, correlationId, requestId? }` with `application/json`. Errors use RFC 7807 Problem Details (`application/problem+json`) aligned with miso-controller and dataplane.',
162
- 'x-aifabrix': {
163
- redocUrl: '/api/docs',
164
- contractTier: 'public',
165
- mcpGenerationReady: true,
166
- rbacPreset: 'platform',
167
- datasourceSplitMode: 'per-tag',
168
- orchestrationDatasourceTags: listOrchestrationDatasourceTags()
169
- }
170
- },
200
+ info: buildOpenApiInfo(),
171
201
  servers: [{ url: serverUrl, description: 'Builder API public base URL' }],
172
- tags: [
173
- { name: 'workspace', description: 'Per-user integration workspaces (list, create, manifest, status, diff).' },
174
- { name: 'build', description: 'Wizard generation and manifest repair.' },
175
- { name: 'manifest', description: 'Governed section get/patch/repair for LLM and MCP workflows.' },
176
- { name: 'validate', description: 'Local AJV validation and preview-upload (no Dataplane mutation).' },
177
- { name: 'test', description: 'Unit, integration, and e2e test ladder.' },
178
- { name: 'certify', description: 'Verify operations/trust/governance and lifecycle certification.' },
179
- { name: 'apply', description: 'Dev Dataplane upload (requires external-system:publish).' },
180
- { name: 'template', description: 'Enterprise MCP template.materializeWorkspace and workspace reset.' },
181
- { name: 'repository', description: 'Enterprise MCP repository.sync, createReview, status, dispatchPipeline.' },
182
- { name: 'infra', description: 'Liveness and readiness probes (no authentication).' }
183
- ],
202
+ tags: buildOpenApiTags(),
184
203
  components: {
185
204
  securitySchemes: {
186
205
  bearerAuth: {
@@ -66,6 +66,11 @@ const ORCHESTRATION_TAG_CATALOG = Object.freeze({
66
66
  resourceType: 'channel',
67
67
  permissionClass: 'infra',
68
68
  displayName: 'Infrastructure'
69
+ },
70
+ evidence: {
71
+ resourceType: 'role-evidence',
72
+ permissionClass: 'evidence',
73
+ displayName: 'Evidence'
69
74
  }
70
75
  });
71
76
 
@@ -16,6 +16,9 @@ function getTimeoutMsForHandler(handlerId) {
16
16
  if (handlerId === 'runUpload') {
17
17
  return Number(process.env.MAX_UPLOAD_TIMEOUT_MS || 300000);
18
18
  }
19
+ if (handlerId === 'runDeploySystem') {
20
+ return Number(process.env.MAX_DEPLOY_TIMEOUT_MS || 300000);
21
+ }
19
22
  if (handlerId === 'runTest') {
20
23
  return Number(process.env.MAX_TEST_E2E_TIMEOUT_MS || 120000);
21
24
  }
@@ -14,6 +14,8 @@ const { runWizard } = require('./run-wizard');
14
14
  const { runRepair } = require('./run-repair');
15
15
  const { runValidate } = require('./run-validate');
16
16
  const { runPreviewUpload, runUpload } = require('./run-upload');
17
+ const { runDeploySystem } = require('./run-deploy');
18
+ const { runProtectionUpload, runProtectionCreate } = require('./run-protection');
17
19
  const { runTest } = require('./run-test');
18
20
  const { runCertifyPillar } = require('./run-certify');
19
21
  const { getLifecycleReport } = require('./run-lifecycle');
@@ -32,6 +34,12 @@ const {
32
34
  const { getManifestSection, listManifestSections } = require('./manifest-get-section');
33
35
  const { patchManifestSection } = require('./manifest-patch-section');
34
36
  const { runManifestRepair } = require('./manifest-repair');
37
+ const {
38
+ getEvidenceMetadata,
39
+ downloadEvidence,
40
+ uploadEvidenceCandidates,
41
+ activateEvidenceCandidates
42
+ } = require('./run-evidence-authoring');
35
43
 
36
44
  /** @type {Record<string, Function>} */
37
45
  const HANDLER_MAP = {
@@ -108,6 +116,36 @@ const HANDLER_MAP = {
108
116
  probe: body.probe === true,
109
117
  minimal: true
110
118
  }),
119
+ runDeploySystem: (params, auth, body) =>
120
+ runDeploySystem(buildContext(auth, params.systemKey), {
121
+ gate: body.gate,
122
+ subjectEmail: body.subjectEmail,
123
+ probe: body.probe === true,
124
+ sync: body.sync === true,
125
+ verbose: body.verbose === true
126
+ }),
127
+ runProtectionUpload: (params, auth, body) =>
128
+ runProtectionUpload(buildContext(auth, params.systemKey), params.datasourceKey, {
129
+ dryRun: body.dryRun === true,
130
+ sync: body.sync === true,
131
+ verbose: body.verbose === true
132
+ }),
133
+ runProtectionCreate: (params, auth, body) =>
134
+ runProtectionCreate(buildContext(auth, params.systemKey), params.datasourceKey, {
135
+ type: body.type,
136
+ dimensionKey: body.dimensionKey,
137
+ field: body.field,
138
+ fkName: body.fkName,
139
+ protectionKey: body.protectionKey,
140
+ displayName: body.displayName,
141
+ ruleKey: body.ruleKey,
142
+ principalExpression: body.principalExpression,
143
+ valueExpression: body.valueExpression,
144
+ dryRun: body.dryRun === true,
145
+ force: body.force === true,
146
+ verbose: body.verbose === true,
147
+ disabled: body.disabled === true
148
+ }),
111
149
  runTest: (params, auth, body, query) =>
112
150
  runTest(buildContext(auth, params.systemKey), {
113
151
  runType: body.runType || query.runType || 'integration',
@@ -117,7 +155,10 @@ const HANDLER_MAP = {
117
155
  runCertifyPillar(buildContext(auth, params.systemKey), params.pillar, {
118
156
  noPublish: body.noPublish === true,
119
157
  pack: body.pack,
120
- body: body.lifecycleBody
158
+ body: body.lifecycleBody,
159
+ subjectEmails: _certifySubjectEmails(body),
160
+ subjectUserIds: _stringList(body.subjectUserIds),
161
+ certificationProfile: body.certificationProfile
121
162
  }),
122
163
  getLifecycleReport: (params, auth, _body, query) =>
123
164
  getLifecycleReport(buildContext(auth, params.systemKey), {
@@ -137,7 +178,53 @@ const HANDLER_MAP = {
137
178
  runRepositoryDispatchPipeline: (params, auth, body) =>
138
179
  runRepositoryDispatchPipeline(buildContext(auth, params.systemKey), body),
139
180
  health: () => ({ status: 'ok' }),
140
- ready: () => ({ status: 'ready', dataplaneUrl: process.env.DATAPLANE_URL || null })
181
+ ready: () => ({ status: 'ready', dataplaneUrl: process.env.DATAPLANE_URL || null }),
182
+ getEvidenceMetadata: (params, auth) =>
183
+ getEvidenceMetadata(buildContext(auth, '_evidence'), params.roleKey),
184
+ downloadEvidence: (params, auth, _body, query) =>
185
+ downloadEvidence(buildContext(auth, '_evidence'), {
186
+ roleKey: params.roleKey,
187
+ resourceType: query.resourceType,
188
+ status: query.status,
189
+ kindKey: query.kindKey,
190
+ aspect: query.aspect,
191
+ search: query.search,
192
+ genericOnly: query.genericOnly === 'true',
193
+ limit: query.limit,
194
+ offset: query.offset
195
+ }),
196
+ uploadEvidenceCandidates: (params, auth, body) =>
197
+ uploadEvidenceCandidates(buildContext(auth, '_evidence'), {
198
+ ...(body && typeof body === 'object' ? body : {}),
199
+ roleKey: (body && body.roleKey) || params.roleKey
200
+ }),
201
+ activateEvidenceCandidates: (_params, auth, body) =>
202
+ activateEvidenceCandidates(buildContext(auth, '_evidence'), body)
141
203
  };
142
204
 
205
+ /**
206
+ * @param {unknown} value
207
+ * @returns {string[]}
208
+ */
209
+ function _stringList(value) {
210
+ if (!Array.isArray(value)) {
211
+ return [];
212
+ }
213
+ return value.map(item => String(item || '').trim()).filter(Boolean);
214
+ }
215
+
216
+ /**
217
+ * Normalize subject emails from CertifyRequest (singular or list).
218
+ * @param {Object} body
219
+ * @returns {string[]}
220
+ */
221
+ function _certifySubjectEmails(body) {
222
+ const fromList = _stringList(body && body.subjectEmails);
223
+ const single = body && body.subjectEmail ? String(body.subjectEmail).trim() : '';
224
+ if (single && !fromList.includes(single)) {
225
+ return [single, ...fromList];
226
+ }
227
+ return fromList;
228
+ }
229
+
143
230
  module.exports = { HANDLER_MAP };
@@ -11,6 +11,7 @@
11
11
  const { runVerifyOperationsForExternalSystem } = require('../commands/verify-operations-external');
12
12
  const { runVerifyTrustForExternalSystem } = require('../commands/verify-trust-external');
13
13
  const { runVerifyGovernanceForExternalSystem } = require('../commands/verify-governance-external');
14
+ const { runVerifyGovernanceCombined } = require('../commands/verify-governance-combined-external');
14
15
  const { runSystemLifecycle } = require('../api/lifecycle.api');
15
16
  const { runWithWorkspaceContext } = require('./workspace-context');
16
17
  const { mergeProgrammaticOptions } = require('./command-options');
@@ -45,7 +46,7 @@ async function runCertifyPillar(ctx, pillar, options = {}) {
45
46
  } else if (pillar === 'trust') {
46
47
  result = await runVerifyTrustForExternalSystem(ctx.systemKey, merged);
47
48
  } else if (pillar === 'governance') {
48
- result = await runVerifyGovernanceForExternalSystem(ctx.systemKey, merged);
49
+ result = await runGovernanceCertify(ctx.systemKey, merged);
49
50
  } else {
50
51
  result = await runSystemLifecycle(merged.dataplaneUrl, merged.authConfig, ctx.systemKey, options.body || {});
51
52
  }
@@ -54,4 +55,16 @@ async function runCertifyPillar(ctx, pillar, options = {}) {
54
55
  });
55
56
  }
56
57
 
57
- module.exports = { runCertifyPillar, PILLARS };
58
+ /**
59
+ * Governance certify: generate packs (subjects required) then verify, unless pack override.
60
+ * @param {string} systemKey
61
+ * @param {Object} options
62
+ */
63
+ async function runGovernanceCertify(systemKey, options) {
64
+ if (options.pack) {
65
+ return runVerifyGovernanceForExternalSystem(systemKey, options);
66
+ }
67
+ return runVerifyGovernanceCombined(systemKey, options);
68
+ }
69
+
70
+ module.exports = { runCertifyPillar, runGovernanceCertify, PILLARS };
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Programmatic deploy wrapper — CLI deploy parity for builder-api.
3
+ *
4
+ * @fileoverview runDeploySystem for POST /systems/:systemKey/deploy
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const { deployExternalSystem } = require('../external-system/deploy');
12
+ const { runWithWorkspaceContext } = require('./workspace-context');
13
+ const { mergeProgrammaticOptions } = require('./command-options');
14
+ const { touchWorkspaceMeta } = require('./workspace-meta');
15
+
16
+ /**
17
+ * @param {unknown} gate
18
+ * @returns {string|undefined}
19
+ */
20
+ function normalizeGate(gate) {
21
+ if (gate === null || gate === undefined || gate === '') {
22
+ return undefined;
23
+ }
24
+ if (typeof gate === 'string') {
25
+ return gate.trim() || undefined;
26
+ }
27
+ return undefined;
28
+ }
29
+
30
+ /**
31
+ * Map gateFailure / deploy errors to Problem Details status codes.
32
+ * @param {Error & { gateFailure?: boolean, statusCode?: number }} err
33
+ */
34
+ function attachDeployStatus(err) {
35
+ if (err && err.gateFailure === true && !err.statusCode) {
36
+ err.statusCode = 422;
37
+ }
38
+ return err;
39
+ }
40
+
41
+ /**
42
+ * @param {import('./workspace-context').WorkspaceContext} ctx
43
+ * @param {Object} [options]
44
+ * @param {string} [options.gate] - Same as CLI --gate (operations,trust,governance,full)
45
+ * @param {string} [options.subjectEmail]
46
+ * @param {boolean} [options.probe]
47
+ * @param {boolean} [options.sync]
48
+ * @param {boolean} [options.verbose]
49
+ * @returns {Promise<Object>}
50
+ */
51
+ async function runDeploySystem(ctx, options = {}) {
52
+ const merged = mergeProgrammaticOptions(ctx, {
53
+ ...options,
54
+ gate: normalizeGate(options.gate),
55
+ subjectEmail: options.subjectEmail,
56
+ probe: options.probe === true,
57
+ sync: options.sync === true,
58
+ verbose: options.verbose === true
59
+ });
60
+ return runWithWorkspaceContext(ctx, async() => {
61
+ try {
62
+ const result = await deployExternalSystem(ctx.systemKey, merged);
63
+ touchWorkspaceMeta(ctx, { lastOperation: 'deploy' });
64
+ return result && typeof result === 'object' ? result : { deployed: true };
65
+ } catch (err) {
66
+ throw attachDeployStatus(err);
67
+ }
68
+ });
69
+ }
70
+
71
+ module.exports = {
72
+ runDeploySystem,
73
+ normalizeGate
74
+ };