@aifabrix/builder 2.51.1 → 2.52.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.
- package/jest.isolated-projects.js +25 -2
- package/jest.projects.js +4 -1
- package/lib/api/datasources-extended.api.js +8 -8
- package/lib/api/keycloak.api.js +92 -0
- package/lib/api/token-providers.api.js +77 -0
- package/lib/api/types/keycloak.types.js +23 -0
- package/lib/api/types/token-providers.types.js +65 -0
- package/lib/app/down.js +16 -1
- package/lib/app/run-container-start.js +4 -0
- package/lib/app/run-deploy-job.js +135 -27
- package/lib/app/run-env-compose.js +32 -0
- package/lib/app/run-env-recovery.js +35 -0
- package/lib/app/run-helpers.js +5 -6
- package/lib/app/run.js +11 -3
- package/lib/channels/add-channel.js +126 -19
- package/lib/channels/approval-guides/chatgpt.js +12 -9
- package/lib/channels/approval-guides/microsoft-copilot.js +16 -12
- package/lib/channels/channel-add-ensure.js +128 -0
- package/lib/channels/channel-artifact-generator.js +11 -1
- package/lib/channels/channel-branding.js +94 -0
- package/lib/channels/channel-credential.js +8 -0
- package/lib/channels/channel-discovery.js +330 -0
- package/lib/channels/channel-external-system.js +1 -1
- package/lib/channels/channel-runtime-resolver.js +103 -14
- package/lib/channels/channel-status-display.js +7 -1
- package/lib/channels/channel-targets.js +18 -1
- package/lib/channels/chatgpt-runtime-contract.js +1 -1
- package/lib/channels/microsoft-copilot-channel-add.js +138 -0
- package/lib/channels/microsoft-copilot-entra-sso-form.js +180 -0
- package/lib/channels/microsoft-copilot-entra-sso.js +264 -0
- package/lib/channels/microsoft-copilot-icons.js +74 -0
- package/lib/channels/microsoft-copilot-limits.js +84 -0
- package/lib/channels/microsoft-copilot-package.js +130 -49
- package/lib/channels/microsoft-copilot-validate.js +197 -0
- package/lib/cli/index.js +2 -0
- package/lib/cli/infra-guided-footers.js +1 -1
- package/lib/cli/infra-guided-public-url-warn.js +55 -0
- package/lib/cli/infra-guided.js +78 -62
- package/lib/cli/setup-app.help.js +4 -0
- package/lib/cli/setup-app.test-commands.js +59 -28
- package/lib/cli/setup-external-system.js +50 -12
- package/lib/cli/setup-infra.js +31 -4
- package/lib/commands/channel-add-setup.js +35 -10
- package/lib/commands/channel.js +27 -12
- package/lib/commands/deploy-gate-orchestrator.js +3 -2
- package/lib/commands/governance-verify-external.js +2 -5
- package/lib/commands/integration-definition.js +158 -0
- package/lib/commands/lifecycle-external.js +14 -7
- package/lib/commands/repair-auth-apply.js +19 -5
- package/lib/commands/repair-datasource-sync-operations.js +4 -1
- package/lib/commands/role-assistant-test-output.js +200 -0
- package/lib/commands/role-assistant.js +131 -114
- package/lib/commands/test-governance-external.js +2 -5
- package/lib/commands/up-miso.js +61 -24
- package/lib/commands/upload-data-sync-finalize.js +20 -3
- package/lib/commands/verify-governance-external.js +2 -5
- package/lib/commands/verify-operations-external.js +2 -5
- package/lib/commands/verify-operations-step-plan.js +31 -0
- package/lib/commands/verify-trust-command-action.js +2 -5
- package/lib/datasource/capability/capability-resolve.js +15 -5
- package/lib/datasource/capability/copy-operations.js +14 -4
- package/lib/datasource/datasource-identifier.js +4 -3
- package/lib/datasource/integration-context.js +3 -3
- package/lib/datasource/resolve-app.js +90 -8
- package/lib/datasource/test-e2e.js +2 -2
- package/lib/datasource/unified-validation-run-body.js +15 -1
- package/lib/datasource/unified-validation-run-resolve.js +2 -2
- package/lib/external-system/deploy-helpers.js +9 -5
- package/lib/external-system/deploy.js +2 -1
- package/lib/external-system/test-system-level.js +21 -3
- package/lib/external-system/test.js +4 -4
- package/lib/generator/builders.js +9 -15
- package/lib/infrastructure/index.js +19 -4
- package/lib/integration-definition/apply.js +478 -0
- package/lib/integration-definition/canonical-json.js +51 -0
- package/lib/integration-definition/emit-suite-bid.js +94 -0
- package/lib/integration-definition/enrich-crm-field-mappings.js +240 -0
- package/lib/integration-definition/enrich-openapi-operations.js +434 -0
- package/lib/integration-definition/from-discovery.js +339 -0
- package/lib/integration-definition/hash.js +37 -0
- package/lib/integration-definition/index.js +37 -0
- package/lib/integration-definition/openapi-enrichment/hubspot-crm-companies.json +205 -0
- package/lib/integration-definition/resource-type-catalog.js +59 -0
- package/lib/integration-definition/system-kind-enum.js +40 -0
- package/lib/integration-definition/validate.js +148 -0
- package/lib/programmatic/builder-api-request.js +5 -1
- package/lib/programmatic/builder-help-governance.js +3 -2
- package/lib/programmatic/capability-registry.js +19 -0
- package/lib/programmatic/openapi-component-schemas.js +6 -1
- package/lib/programmatic/openapi-descriptions.js +40 -0
- package/lib/programmatic/openapi-envelope-examples.js +269 -0
- package/lib/programmatic/openapi-operation-bindings.js +45 -0
- package/lib/programmatic/openapi-request-schemas.js +14 -0
- package/lib/programmatic/openapi-result-schemas-overflow.js +101 -0
- package/lib/programmatic/openapi-result-schemas.js +46 -99
- package/lib/programmatic/openapi-schema-descriptions-core.js +7 -4
- package/lib/programmatic/openapi-schema-descriptions-help.js +1 -1
- package/lib/programmatic/openapi-schema-descriptions-operations.js +24 -0
- package/lib/programmatic/openapi-schema-helpers.js +9 -9
- package/lib/programmatic/openapi-spec.js +11 -1
- package/lib/programmatic/orchestration-openapi-meta.js +10 -0
- package/lib/programmatic/route-handler-map.js +29 -1
- package/lib/programmatic/run-channel-package.js +236 -0
- package/lib/programmatic/run-integration-definition.js +69 -0
- package/lib/role-assistant/knowledge-markdown-frontmatter.js +75 -0
- package/lib/role-assistant/knowledge-sync-logging.js +58 -0
- package/lib/role-assistant/knowledge-sync.js +104 -89
- package/lib/role-assistant/test-cases-bid.js +155 -0
- package/lib/role-assistant/test-cases-evaluate.js +9 -1
- package/lib/role-assistant/test-cases-honesty.js +24 -10
- package/lib/role-assistant/test-cases.js +28 -0
- package/lib/role-assistant/test-runner-bid-apply.js +122 -0
- package/lib/role-assistant/test-runner-bid-document.js +278 -0
- package/lib/role-assistant/test-runner-workhub-answers.js +289 -46
- package/lib/role-assistant/test-runner-workhub.js +121 -25
- package/lib/role-assistant/test-suite.js +119 -0
- package/lib/schema/application-schema.json +64 -32
- package/lib/schema/external-datasource.schema.json +103 -17
- package/lib/schema/external-system.schema.json +54 -3
- package/lib/schema/infra.parameter.yaml +0 -20
- package/lib/schema/integration-definition.schema.json +195 -0
- package/lib/utils/authentication-shape.js +6 -0
- package/lib/utils/certify-external-workspace.js +40 -0
- package/lib/utils/docker-build.js +3 -3
- package/lib/utils/docker-run-ephemeral.js +77 -17
- package/lib/utils/health-check-public-warn.js +31 -13
- package/lib/utils/health-check.js +11 -1
- package/lib/utils/help-builder.js +1 -0
- package/lib/utils/paths.js +13 -15
- package/lib/utils/promote-dev-docker-image.js +97 -18
- package/lib/utils/role-assistant-paths.js +76 -14
- package/lib/utils/transient-developer-id.js +28 -0
- package/lib/utils/upload-sync-options.js +7 -4
- package/lib/validation/reserved-system-key-prefixes.js +56 -0
- package/lib/validation/validate.js +54 -19
- package/package.json +1 -1
- package/scripts/pnpm/af.mjs +24 -9
- package/scripts/pnpm/help.mjs +1 -1
- package/templates/applications/builder-api/application.yaml +3 -3
- package/templates/applications/dataplane/application.yaml +5 -5
- package/templates/applications/dataplane/env.template +8 -7
- package/templates/applications/dataplane/rbac.yaml +10 -10
- package/templates/applications/keycloak/application.yaml +2 -2
- package/templates/applications/keycloak/env.template +5 -2
- package/templates/applications/miso-controller/application.yaml +25 -11
- package/templates/applications/miso-controller/env.template +24 -5
- package/templates/channels/README.md +11 -1
- package/templates/channels/brand/color-192.png +0 -0
- package/templates/channels/brand/dark/128.png +0 -0
- package/templates/channels/brand/dark/192.png +0 -0
- package/templates/channels/brand/dark/256.png +0 -0
- package/templates/channels/brand/dark/32.png +0 -0
- package/templates/channels/brand/dark/512.png +0 -0
- package/templates/channels/brand/dark/64.png +0 -0
- package/templates/channels/brand/light/128.png +0 -0
- package/templates/channels/brand/light/192.png +0 -0
- package/templates/channels/brand/light/256.png +0 -0
- package/templates/channels/brand/light/32.png +0 -0
- package/templates/channels/brand/light/512.png +0 -0
- package/templates/channels/brand/light/64.png +0 -0
- package/templates/channels/brand/mono-white/128.png +0 -0
- package/templates/channels/brand/mono-white/192.png +0 -0
- package/templates/channels/brand/mono-white/256.png +0 -0
- package/templates/channels/brand/mono-white/32.png +0 -0
- package/templates/channels/brand/mono-white/512.png +0 -0
- package/templates/channels/brand/mono-white/64.png +0 -0
- package/templates/channels/brand/outline-32.png +0 -0
- package/templates/channels/chatgpt/install.template.md.hbs +76 -36
- package/templates/channels/chatgpt/integration/README.md +4 -4
- package/templates/channels/chatgpt/integration/chatgpt-system.json +1 -16
- package/templates/channels/chatgpt/manifest.template.json.hbs +3 -3
- package/templates/channels/microsoft-copilot/ai-plugin.template.json.hbs +10 -16
- package/templates/channels/microsoft-copilot/declarative-agent.template.json.hbs +5 -3
- package/templates/channels/microsoft-copilot/entra-sso-registration.template.md.hbs +27 -0
- package/templates/channels/microsoft-copilot/install.template.md.hbs +39 -20
- package/templates/channels/microsoft-copilot/integration/README.md +2 -3
- package/templates/channels/microsoft-copilot/integration/microsoft-copilot-system.json +1 -22
- package/templates/channels/microsoft-copilot/manifest.template.json.hbs +7 -7
- package/templates/channels/microsoft-copilot/oauth-plugin-vault-required.template.md.hbs +11 -0
- package/templates/channels/slack/install.template.md.hbs +6 -1
- package/templates/channels/slack/integration/README.md +2 -4
- package/templates/channels/teams-bot/install.template.md.hbs +4 -0
- package/templates/channels/teams-bot/integration/README.md +3 -5
- package/templates/channels/web-embed/integration/web-embed-system.json +1 -16
- package/templates/python/docker-compose.hbs +10 -0
- package/templates/typescript/docker-compose.hbs +10 -0
- /package/.cursor/plans/{Done → Archive}/157.1-security-quality-violations-by-type.csv +0 -0
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Promote a developer-scoped local Docker image to the manifest base repository (tag only).
|
|
3
3
|
*
|
|
4
|
-
* @fileoverview Used by `aifabrix build --base --from-dev` and dev-promote workflows
|
|
4
|
+
* @fileoverview Used by `aifabrix build --base --from-dev` and dev-promote workflows.
|
|
5
|
+
* Promote always applies two base tags: `main` (floating) and the version tag (TAG / package version).
|
|
5
6
|
* @author AI Fabrix Team
|
|
6
|
-
* @version 1.
|
|
7
|
+
* @version 1.1.0
|
|
7
8
|
*/
|
|
8
9
|
|
|
9
10
|
'use strict';
|
|
@@ -15,6 +16,9 @@ const { execWithDockerEnv } = require('./docker-exec');
|
|
|
15
16
|
const logger = require('./logger');
|
|
16
17
|
const { formatSuccessLine } = require('./cli-test-layout-chalk');
|
|
17
18
|
|
|
19
|
+
/** Floating base tag applied on every promote alongside the version tag. */
|
|
20
|
+
const PROMOTE_MAIN_TAG = 'main';
|
|
21
|
+
|
|
18
22
|
/**
|
|
19
23
|
* @param {string} value
|
|
20
24
|
* @returns {string}
|
|
@@ -61,6 +65,33 @@ async function dockerTagImageRef(sourceRef, targetRef) {
|
|
|
61
65
|
await execWithDockerEnv(`docker tag ${shellQuote(sourceRef)} ${shellQuote(targetRef)}`);
|
|
62
66
|
}
|
|
63
67
|
|
|
68
|
+
/**
|
|
69
|
+
* Version tag for promote (not floating aliases).
|
|
70
|
+
* @param {Object} options
|
|
71
|
+
* @returns {string}
|
|
72
|
+
*/
|
|
73
|
+
function resolvePromoteVersionTag(options = {}) {
|
|
74
|
+
const raw = String(options.tag || '').trim();
|
|
75
|
+
if (!raw || raw === 'latest' || raw === PROMOTE_MAIN_TAG) {
|
|
76
|
+
return 'latest';
|
|
77
|
+
}
|
|
78
|
+
return raw;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Base tags to apply on promote: version first, then `main` when distinct.
|
|
83
|
+
* @param {Object} options
|
|
84
|
+
* @returns {string[]}
|
|
85
|
+
*/
|
|
86
|
+
function resolvePromoteBaseTags(options = {}) {
|
|
87
|
+
const versionTag = resolvePromoteVersionTag(options);
|
|
88
|
+
const tags = [versionTag];
|
|
89
|
+
if (versionTag !== PROMOTE_MAIN_TAG) {
|
|
90
|
+
tags.push(PROMOTE_MAIN_TAG);
|
|
91
|
+
}
|
|
92
|
+
return tags;
|
|
93
|
+
}
|
|
94
|
+
|
|
64
95
|
/**
|
|
65
96
|
* @param {string} appName
|
|
66
97
|
* @param {Object} variables
|
|
@@ -69,7 +100,7 @@ async function dockerTagImageRef(sourceRef, targetRef) {
|
|
|
69
100
|
* @returns {Promise<{ devRef: string, baseRef: string, devTag: string, baseTag: string }>}
|
|
70
101
|
*/
|
|
71
102
|
async function resolveDevAndBaseImageRefs(appName, variables, developerId, options) {
|
|
72
|
-
const baseTag = options
|
|
103
|
+
const baseTag = resolvePromoteVersionTag(options);
|
|
73
104
|
const devTag = options.fromDevTag || 'latest';
|
|
74
105
|
const { buildImageName: baseName } = await resolveBuildDockerTagNames(appName, variables, developerId, {
|
|
75
106
|
...options,
|
|
@@ -93,31 +124,68 @@ async function resolveDevAndBaseImageRefs(appName, variables, developerId, optio
|
|
|
93
124
|
* @param {Object} appConfig
|
|
94
125
|
* @param {string|number} developerId
|
|
95
126
|
* @param {Object} options
|
|
96
|
-
* @returns {Promise<{
|
|
127
|
+
* @returns {Promise<{
|
|
128
|
+
* devRef: string,
|
|
129
|
+
* baseRef: string,
|
|
130
|
+
* baseName: string,
|
|
131
|
+
* baseTags: string[]
|
|
132
|
+
* }|null>}
|
|
97
133
|
*/
|
|
98
134
|
async function resolvePromoteSourceAndTargetRefs(appName, appConfig, developerId, options) {
|
|
99
|
-
const
|
|
135
|
+
const baseTags = resolvePromoteBaseTags(options);
|
|
136
|
+
const versionTag = baseTags[0];
|
|
100
137
|
const devTagCandidates = ['latest'];
|
|
101
|
-
if (
|
|
102
|
-
devTagCandidates.push(
|
|
138
|
+
if (versionTag !== 'latest' && !devTagCandidates.includes(versionTag)) {
|
|
139
|
+
devTagCandidates.push(versionTag);
|
|
103
140
|
}
|
|
104
141
|
for (const fromDevTag of devTagCandidates) {
|
|
105
142
|
const refs = await resolveDevAndBaseImageRefs(appName, appConfig, developerId, {
|
|
106
143
|
...options,
|
|
144
|
+
tag: versionTag,
|
|
107
145
|
fromDevTag
|
|
108
146
|
});
|
|
109
147
|
if (await dockerImageRefExists(refs.devRef)) {
|
|
110
|
-
|
|
148
|
+
const baseName = refs.baseRef.slice(0, refs.baseRef.lastIndexOf(':'));
|
|
149
|
+
return {
|
|
150
|
+
devRef: refs.devRef,
|
|
151
|
+
baseRef: refs.baseRef,
|
|
152
|
+
baseName,
|
|
153
|
+
baseTags
|
|
154
|
+
};
|
|
111
155
|
}
|
|
112
156
|
}
|
|
113
157
|
return null;
|
|
114
158
|
}
|
|
115
159
|
|
|
160
|
+
/**
|
|
161
|
+
* @param {string} baseName
|
|
162
|
+
* @param {string[]} baseTags
|
|
163
|
+
* @param {string|null} devId
|
|
164
|
+
* @returns {Promise<boolean>} true when every target already matches dev image id
|
|
165
|
+
*/
|
|
166
|
+
async function allBaseTagsMatchDev(baseName, baseTags, devId) {
|
|
167
|
+
if (!devId) {
|
|
168
|
+
return false;
|
|
169
|
+
}
|
|
170
|
+
for (const tag of baseTags) {
|
|
171
|
+
const ref = `${baseName}:${tag}`;
|
|
172
|
+
if (!(await dockerImageRefExists(ref))) {
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
const baseId = await readDockerImageId(ref);
|
|
176
|
+
if (!baseId || baseId !== devId) {
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return true;
|
|
181
|
+
}
|
|
182
|
+
|
|
116
183
|
/**
|
|
117
184
|
* Tag developer-scoped image as manifest base when present locally.
|
|
185
|
+
* Always applies the version tag and `main`.
|
|
118
186
|
* @param {string} appName
|
|
119
187
|
* @param {Object} options - build options (`base`, `tag`, `registry`, `fromDev`)
|
|
120
|
-
* @returns {Promise<string|null>} base image ref when promoted
|
|
188
|
+
* @returns {Promise<string|null>} primary base image ref (version) when promoted; null when missing
|
|
121
189
|
*/
|
|
122
190
|
async function tryPromoteDevImageToBase(appName, options = {}) {
|
|
123
191
|
if (options.base !== true) {
|
|
@@ -135,19 +203,27 @@ async function tryPromoteDevImageToBase(appName, options = {}) {
|
|
|
135
203
|
if (!resolved) {
|
|
136
204
|
return null;
|
|
137
205
|
}
|
|
138
|
-
const { devRef, baseRef } = resolved;
|
|
206
|
+
const { devRef, baseRef, baseName, baseTags } = resolved;
|
|
139
207
|
|
|
140
208
|
const devId = await readDockerImageId(devRef);
|
|
141
|
-
if (await
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
209
|
+
if (await allBaseTagsMatchDev(baseName, baseTags, devId)) {
|
|
210
|
+
logger.log(
|
|
211
|
+
formatSuccessLine(
|
|
212
|
+
`Base image already matches dev build: ${baseTags.map((t) => `${baseName}:${t}`).join(', ')}`
|
|
213
|
+
)
|
|
214
|
+
);
|
|
215
|
+
return baseRef;
|
|
147
216
|
}
|
|
148
217
|
|
|
149
|
-
|
|
150
|
-
|
|
218
|
+
for (const tag of baseTags) {
|
|
219
|
+
const targetRef = `${baseName}:${tag}`;
|
|
220
|
+
await dockerTagImageRef(devRef, targetRef);
|
|
221
|
+
}
|
|
222
|
+
logger.log(
|
|
223
|
+
formatSuccessLine(
|
|
224
|
+
`Promoted dev image to base (tag only): ${baseTags.map((t) => `${baseName}:${t}`).join(', ')}`
|
|
225
|
+
)
|
|
226
|
+
);
|
|
151
227
|
return baseRef;
|
|
152
228
|
}
|
|
153
229
|
|
|
@@ -160,10 +236,13 @@ function shouldAttemptDevPromote(options) {
|
|
|
160
236
|
}
|
|
161
237
|
|
|
162
238
|
module.exports = {
|
|
239
|
+
PROMOTE_MAIN_TAG,
|
|
163
240
|
tryPromoteDevImageToBase,
|
|
164
241
|
shouldAttemptDevPromote,
|
|
165
242
|
resolveDevAndBaseImageRefs,
|
|
166
243
|
resolvePromoteSourceAndTargetRefs,
|
|
244
|
+
resolvePromoteBaseTags,
|
|
245
|
+
resolvePromoteVersionTag,
|
|
167
246
|
dockerImageRefExists,
|
|
168
247
|
readDockerImageId,
|
|
169
248
|
dockerTagImageRef
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @fileoverview Paths under role-assistant/ for Role Assistant packages
|
|
5
5
|
* @author AI Fabrix Team
|
|
6
|
-
* @version 1.
|
|
6
|
+
* @version 1.1.0
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
'use strict';
|
|
@@ -14,6 +14,7 @@ const { nodeFs } = require('../internal/node-fs');
|
|
|
14
14
|
|
|
15
15
|
const WORKSPACE_ROLE_ASSISTANT = 'role-assistant';
|
|
16
16
|
const SYSTEM_KIND_DIGITAL_WORKER = 'digitalWorker';
|
|
17
|
+
const ROLE_ASSISTANT_SYSTEM_PREFIX = 'ra-';
|
|
17
18
|
|
|
18
19
|
function getMaterializationParent() {
|
|
19
20
|
const work = process.env.AIFABRIX_WORK;
|
|
@@ -63,7 +64,64 @@ function isExistingDirectory(disk, dirPath) {
|
|
|
63
64
|
}
|
|
64
65
|
|
|
65
66
|
/**
|
|
66
|
-
*
|
|
67
|
+
* Bare business roleKey (strips leading ra- if present).
|
|
68
|
+
* @param {string} roleKeyOrSystemKey
|
|
69
|
+
* @returns {string}
|
|
70
|
+
*/
|
|
71
|
+
function bareRoleKey(roleKeyOrSystemKey) {
|
|
72
|
+
const raw = String(roleKeyOrSystemKey || '').trim();
|
|
73
|
+
if (raw.toLowerCase().startsWith(ROLE_ASSISTANT_SYSTEM_PREFIX)) {
|
|
74
|
+
return raw.slice(ROLE_ASSISTANT_SYSTEM_PREFIX.length);
|
|
75
|
+
}
|
|
76
|
+
return raw;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Folder / ExternalSystem key for a Role Assistant: ra-{roleKey}.
|
|
81
|
+
* @param {string} roleKeyOrSystemKey
|
|
82
|
+
* @returns {string}
|
|
83
|
+
*/
|
|
84
|
+
function roleAssistantSystemKey(roleKeyOrSystemKey) {
|
|
85
|
+
const bare = bareRoleKey(roleKeyOrSystemKey);
|
|
86
|
+
if (!bare) {
|
|
87
|
+
return '';
|
|
88
|
+
}
|
|
89
|
+
return `${ROLE_ASSISTANT_SYSTEM_PREFIX}${bare}`;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Candidate folder names under role-assistant/ (prefer ra-, then legacy bare).
|
|
94
|
+
* @param {string} roleKeyOrSystemKey
|
|
95
|
+
* @returns {string[]}
|
|
96
|
+
*/
|
|
97
|
+
function roleAssistantFolderCandidates(roleKeyOrSystemKey) {
|
|
98
|
+
const withRa = roleAssistantSystemKey(roleKeyOrSystemKey);
|
|
99
|
+
const bare = bareRoleKey(roleKeyOrSystemKey);
|
|
100
|
+
const out = [];
|
|
101
|
+
if (withRa) {
|
|
102
|
+
out.push(withRa);
|
|
103
|
+
}
|
|
104
|
+
if (bare && bare !== withRa) {
|
|
105
|
+
out.push(bare);
|
|
106
|
+
}
|
|
107
|
+
return out;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function firstExistingUnderRoot(disk, root, folderNames) {
|
|
111
|
+
if (!root) {
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
for (const name of folderNames) {
|
|
115
|
+
const candidate = path.join(root, name);
|
|
116
|
+
if (isExistingDirectory(disk, candidate)) {
|
|
117
|
+
return candidate;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Resolves role-assistant/ra-{roleKey} (preferred) or legacy bare folder.
|
|
67
125
|
* @param {string} roleKey
|
|
68
126
|
* @returns {string}
|
|
69
127
|
*/
|
|
@@ -72,27 +130,31 @@ function getRoleAssistantPath(roleKey) {
|
|
|
72
130
|
throw new Error('Role key is required and must be a string');
|
|
73
131
|
}
|
|
74
132
|
const disk = nodeFs();
|
|
133
|
+
const folders = roleAssistantFolderCandidates(roleKey);
|
|
134
|
+
const preferred = roleAssistantSystemKey(roleKey);
|
|
75
135
|
const cwdRoot = getCwdRoleAssistantRoot();
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
if (isExistingDirectory(disk, matPath)) {
|
|
84
|
-
return matPath;
|
|
136
|
+
const matRoot = path.join(getMaterializationParent(), WORKSPACE_ROLE_ASSISTANT);
|
|
137
|
+
|
|
138
|
+
const existing =
|
|
139
|
+
firstExistingUnderRoot(disk, cwdRoot, folders) ||
|
|
140
|
+
firstExistingUnderRoot(disk, matRoot, folders);
|
|
141
|
+
if (existing) {
|
|
142
|
+
return existing;
|
|
85
143
|
}
|
|
86
144
|
if (cwdRoot) {
|
|
87
|
-
return path.join(cwdRoot,
|
|
145
|
+
return path.join(cwdRoot, preferred);
|
|
88
146
|
}
|
|
89
|
-
return
|
|
147
|
+
return path.join(matRoot, preferred);
|
|
90
148
|
}
|
|
91
149
|
|
|
92
150
|
module.exports = {
|
|
93
151
|
WORKSPACE_ROLE_ASSISTANT,
|
|
94
152
|
SYSTEM_KIND_DIGITAL_WORKER,
|
|
153
|
+
ROLE_ASSISTANT_SYSTEM_PREFIX,
|
|
95
154
|
getCwdRoleAssistantRoot,
|
|
96
155
|
getRoleAssistantRoot,
|
|
97
|
-
getRoleAssistantPath
|
|
156
|
+
getRoleAssistantPath,
|
|
157
|
+
bareRoleKey,
|
|
158
|
+
roleAssistantSystemKey,
|
|
159
|
+
roleAssistantFolderCandidates
|
|
98
160
|
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transient developer-id override for CLI commands (does not persist config).
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Resolve optional --developer-id / --developer without setDeveloperId
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
'use strict';
|
|
8
|
+
|
|
9
|
+
const { validateAndNormalizeDeveloperId } = require('../core/config-normalize');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Resolve optional CLI developer override (transient — does not persist).
|
|
13
|
+
* Prefers developerId (--developer-id) over developer (-d/--developer).
|
|
14
|
+
*
|
|
15
|
+
* @param {Object} [options] - Commander options
|
|
16
|
+
* @returns {string|undefined} Normalized digit string, or undefined to use config
|
|
17
|
+
*/
|
|
18
|
+
function resolveTransientDeveloperIdFromOptions(options) {
|
|
19
|
+
const raw = options && (options.developerId ?? options.developer);
|
|
20
|
+
if (raw === undefined || raw === null || raw === '') {
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
return validateAndNormalizeDeveloperId(raw);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
module.exports = {
|
|
27
|
+
resolveTransientDeveloperIdFromOptions
|
|
28
|
+
};
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* @param {Object} [options] - CLI options from test / sync callers
|
|
13
|
-
* @returns {{ minimal: true, verbose: boolean, silentResolve:
|
|
13
|
+
* @returns {{ minimal: true, verbose: boolean, silentResolve: boolean, syncMode: boolean, force?: true, authConfig?: Object, dataplaneUrl?: string, environment?: string }}
|
|
14
14
|
*/
|
|
15
15
|
function buildMinimalUploadSyncOptions(options = {}) {
|
|
16
16
|
const deployPreflight = options.uploadContext === 'deploy-preflight';
|
|
@@ -18,11 +18,14 @@ function buildMinimalUploadSyncOptions(options = {}) {
|
|
|
18
18
|
minimal: true,
|
|
19
19
|
// CLI -v on verify-* / test-* is for run output, not preflight upload banners.
|
|
20
20
|
verbose: false,
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
// Deploy preflight should match `af upload` progress (URL + Publishing spinner).
|
|
22
|
+
// Verify/test --sync stays silent so parent command owns the progress line.
|
|
23
|
+
silentResolve: !deployPreflight,
|
|
24
|
+
syncMode: !deployPreflight,
|
|
23
25
|
skipDataSync: true,
|
|
26
|
+
// Explicit suppress wins; deploy-preflight never suppresses the Publishing spinner.
|
|
24
27
|
suppressPipelineSpinner:
|
|
25
|
-
options.suppressPipelineSpinner === true
|
|
28
|
+
options.suppressPipelineSpinner === true && !deployPreflight
|
|
26
29
|
};
|
|
27
30
|
if (options.force === true) {
|
|
28
31
|
out.force = true;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Frozen ExternalSystem key prefixes (Role Assistant / Enterprise Knowledge).
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Reject hand-authored ra-/ek- keys under integration/
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const RESERVED_SYSTEM_KEY_PREFIXES = ['ra-', 'ek-'];
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @param {string|null|undefined} systemKey
|
|
15
|
+
* @returns {boolean}
|
|
16
|
+
*/
|
|
17
|
+
function hasReservedPlatformSystemKeyPrefix(systemKey) {
|
|
18
|
+
const normalized = String(systemKey || '')
|
|
19
|
+
.trim()
|
|
20
|
+
.toLowerCase();
|
|
21
|
+
if (!normalized) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
return RESERVED_SYSTEM_KEY_PREFIXES.some((prefix) => normalized.startsWith(prefix));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Connected Systems under integration/ must not use reserved prefixes.
|
|
29
|
+
* Role Assistant packages live under role-assistant/ra-*.
|
|
30
|
+
*
|
|
31
|
+
* @param {string|null|undefined} systemKey
|
|
32
|
+
* @param {string|null|undefined} workspaceBaseDir - integration | role-assistant | …
|
|
33
|
+
* @returns {string|null} Error message or null when allowed
|
|
34
|
+
*/
|
|
35
|
+
function reservedSystemKeyError(systemKey, workspaceBaseDir) {
|
|
36
|
+
if (!hasReservedPlatformSystemKeyPrefix(systemKey)) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
const workspace = String(workspaceBaseDir || '')
|
|
40
|
+
.trim()
|
|
41
|
+
.toLowerCase();
|
|
42
|
+
if (workspace === 'role-assistant' || workspace === 'enterprise-knowledge') {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
return (
|
|
46
|
+
`System key '${systemKey}' uses a reserved prefix (ra- or ek-). ` +
|
|
47
|
+
'Role Assistant packages use role-assistant/ra-{roleKey}/; ' +
|
|
48
|
+
'Enterprise Knowledge uses ek- keys from platform generators only.'
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
module.exports = {
|
|
53
|
+
RESERVED_SYSTEM_KEY_PREFIXES,
|
|
54
|
+
hasReservedPlatformSystemKeyPrefix,
|
|
55
|
+
reservedSystemKeyError
|
|
56
|
+
};
|
|
@@ -22,6 +22,7 @@ const { generateControllerManifest } = require('../generator/external-controller
|
|
|
22
22
|
const { validateControllerManifest } = require('./external-manifest-validator');
|
|
23
23
|
const { runExternalValidateWithOptionalCertSync } = require('./validate-external-cert-sync');
|
|
24
24
|
const { validateExternalFile } = require('./validate-external-file');
|
|
25
|
+
const { reservedSystemKeyError } = require('./reserved-system-key-prefixes');
|
|
25
26
|
|
|
26
27
|
/**
|
|
27
28
|
* Validates a file path (detects type and validates)
|
|
@@ -276,6 +277,52 @@ async function validateManifestStep(appName, options = {}) {
|
|
|
276
277
|
}
|
|
277
278
|
}
|
|
278
279
|
|
|
280
|
+
/**
|
|
281
|
+
* Early-fail payload when system key uses a reserved prefix.
|
|
282
|
+
* @param {string} reservedError
|
|
283
|
+
* @param {string} appPath
|
|
284
|
+
* @returns {Object}
|
|
285
|
+
*/
|
|
286
|
+
function reservedSystemKeyValidationResult(reservedError, appPath) {
|
|
287
|
+
return {
|
|
288
|
+
valid: false,
|
|
289
|
+
errors: [reservedError],
|
|
290
|
+
warnings: [],
|
|
291
|
+
steps: {
|
|
292
|
+
application: { valid: false, errors: [reservedError], warnings: [] },
|
|
293
|
+
components: { valid: true, errors: [], warnings: [], files: [], skipped: true },
|
|
294
|
+
manifest: { valid: true, errors: [], warnings: [], skipped: true }
|
|
295
|
+
},
|
|
296
|
+
appPath
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Aggregate step results into the complete validation response.
|
|
302
|
+
* @param {Object} steps
|
|
303
|
+
* @param {string} appPath
|
|
304
|
+
* @returns {Object}
|
|
305
|
+
*/
|
|
306
|
+
function aggregateExternalValidationSteps(steps, appPath) {
|
|
307
|
+
const allErrors = [
|
|
308
|
+
...steps.application.errors,
|
|
309
|
+
...steps.components.errors,
|
|
310
|
+
...steps.manifest.errors
|
|
311
|
+
];
|
|
312
|
+
const allWarnings = [
|
|
313
|
+
...steps.application.warnings,
|
|
314
|
+
...steps.components.warnings,
|
|
315
|
+
...steps.manifest.warnings
|
|
316
|
+
];
|
|
317
|
+
return {
|
|
318
|
+
valid: allErrors.length === 0,
|
|
319
|
+
errors: allErrors,
|
|
320
|
+
warnings: allWarnings,
|
|
321
|
+
steps,
|
|
322
|
+
appPath
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
|
|
279
326
|
/**
|
|
280
327
|
* Validates external system completely (components + full manifest)
|
|
281
328
|
* Performs step-by-step validation: application config → components → full manifest
|
|
@@ -295,7 +342,12 @@ async function validateExternalSystemComplete(appName, options = {}) {
|
|
|
295
342
|
throw new Error('App name is required and must be a string');
|
|
296
343
|
}
|
|
297
344
|
|
|
298
|
-
const { appPath } = await detectAppType(appName, options);
|
|
345
|
+
const { appPath, baseDir } = await detectAppType(appName, options);
|
|
346
|
+
const reservedError = reservedSystemKeyError(appName, baseDir);
|
|
347
|
+
if (reservedError) {
|
|
348
|
+
return reservedSystemKeyValidationResult(reservedError, appPath);
|
|
349
|
+
}
|
|
350
|
+
|
|
299
351
|
const steps = {
|
|
300
352
|
application: { valid: false, errors: [], warnings: [] },
|
|
301
353
|
components: { valid: false, errors: [], warnings: [], files: [] },
|
|
@@ -303,14 +355,9 @@ async function validateExternalSystemComplete(appName, options = {}) {
|
|
|
303
355
|
};
|
|
304
356
|
|
|
305
357
|
const externalOptions = { ...options };
|
|
306
|
-
|
|
307
|
-
// Step 1: Validate Application Config
|
|
308
358
|
steps.application = await validateApplicationStep(appName, externalOptions);
|
|
309
|
-
|
|
310
|
-
// Step 2: Validate Individual Components
|
|
311
359
|
steps.components = await validateComponentsStep(appName, externalOptions);
|
|
312
360
|
|
|
313
|
-
// If components have errors, return early (don't validate manifest)
|
|
314
361
|
if (!steps.components.valid) {
|
|
315
362
|
steps.manifest = { valid: true, errors: [], warnings: [], skipped: true };
|
|
316
363
|
return {
|
|
@@ -322,20 +369,8 @@ async function validateExternalSystemComplete(appName, options = {}) {
|
|
|
322
369
|
};
|
|
323
370
|
}
|
|
324
371
|
|
|
325
|
-
// Step 3 & 4: Generate and Validate Full Manifest (only if Step 2 passes)
|
|
326
372
|
steps.manifest = await validateManifestStep(appName, { ...externalOptions, appPath });
|
|
327
|
-
|
|
328
|
-
// Aggregate Results
|
|
329
|
-
const allErrors = [...steps.application.errors, ...steps.components.errors, ...steps.manifest.errors];
|
|
330
|
-
const allWarnings = [...steps.application.warnings, ...steps.components.warnings, ...steps.manifest.warnings];
|
|
331
|
-
|
|
332
|
-
return {
|
|
333
|
-
valid: allErrors.length === 0,
|
|
334
|
-
errors: allErrors,
|
|
335
|
-
warnings: allWarnings,
|
|
336
|
-
steps,
|
|
337
|
-
appPath
|
|
338
|
-
};
|
|
373
|
+
return aggregateExternalValidationSteps(steps, appPath);
|
|
339
374
|
}
|
|
340
375
|
|
|
341
376
|
async function validateAppOrFile(appOrFile, options = {}) {
|
package/package.json
CHANGED
package/scripts/pnpm/af.mjs
CHANGED
|
@@ -4,9 +4,13 @@
|
|
|
4
4
|
* Usage: pnpm run af <subcommand> | npm run af -- <subcommand>
|
|
5
5
|
*/
|
|
6
6
|
import { spawn } from 'node:child_process';
|
|
7
|
+
import { readFileSync } from 'node:fs';
|
|
8
|
+
import { dirname, join } from 'node:path';
|
|
9
|
+
import { fileURLToPath } from 'node:url';
|
|
7
10
|
import { resolveAifabrixBin } from './lib/resolve-aifabrix-bin.mjs';
|
|
8
11
|
|
|
9
12
|
const AIFABRIX_BIN = resolveAifabrixBin();
|
|
13
|
+
const REPO_ROOT = join(dirname(fileURLToPath(import.meta.url)), '../..');
|
|
10
14
|
|
|
11
15
|
const USAGE = `Usage: pnpm run af <subcommand>
|
|
12
16
|
|
|
@@ -19,7 +23,7 @@ Subcommands:
|
|
|
19
23
|
ba-build aifabrix build builder-api
|
|
20
24
|
dev-build ba-build then ba-run (local Docker image)
|
|
21
25
|
dev-reload Docker live reload (spinner + URL + .temp/dev-reload.log)
|
|
22
|
-
dev-promote build --base --from-dev + run --base (
|
|
26
|
+
dev-promote build --base --from-dev + run --base (tags main + version; TAG=2.52.0 or package.json)
|
|
23
27
|
`;
|
|
24
28
|
|
|
25
29
|
const COMMANDS = {
|
|
@@ -36,10 +40,20 @@ async function runDevBuild() {
|
|
|
36
40
|
await runCommand(COMMANDS['ba-run']);
|
|
37
41
|
}
|
|
38
42
|
|
|
43
|
+
function readPackageVersion() {
|
|
44
|
+
try {
|
|
45
|
+
const pkg = JSON.parse(readFileSync(join(REPO_ROOT, 'package.json'), 'utf8'));
|
|
46
|
+
const version = String(pkg.version || '').trim();
|
|
47
|
+
return version || null;
|
|
48
|
+
} catch {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
39
53
|
function resolvePromoteTag() {
|
|
40
54
|
const fromArg = process.argv[3];
|
|
41
|
-
const tag = (process.env.TAG || fromArg || '').trim();
|
|
42
|
-
if (!tag || tag === 'latest') {
|
|
55
|
+
const tag = (process.env.TAG || fromArg || readPackageVersion() || '').trim();
|
|
56
|
+
if (!tag || tag === 'latest' || tag === 'main') {
|
|
43
57
|
return null;
|
|
44
58
|
}
|
|
45
59
|
return tag;
|
|
@@ -47,13 +61,14 @@ function resolvePromoteTag() {
|
|
|
47
61
|
|
|
48
62
|
async function runDevPromote() {
|
|
49
63
|
const tag = resolvePromoteTag();
|
|
50
|
-
if (tag) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
64
|
+
if (!tag) {
|
|
65
|
+
throw new Error(
|
|
66
|
+
'dev-promote requires a version tag. Set TAG=x.y.z or ensure package.json has "version".'
|
|
67
|
+
);
|
|
54
68
|
}
|
|
55
|
-
|
|
56
|
-
await runCommand([AIFABRIX_BIN, '
|
|
69
|
+
// Promote applies both :main and :<version>; run uses the version tag.
|
|
70
|
+
await runCommand([AIFABRIX_BIN, 'build', 'builder-api', '--base', '--from-dev', '--tag', tag]);
|
|
71
|
+
await runCommand([AIFABRIX_BIN, 'run', 'builder-api', '--base', '--tag', tag]);
|
|
57
72
|
}
|
|
58
73
|
|
|
59
74
|
function runCommand(args) {
|
package/scripts/pnpm/help.mjs
CHANGED
|
@@ -25,7 +25,7 @@ const publicSections = [
|
|
|
25
25
|
|
|
26
26
|
const advancedLines = [
|
|
27
27
|
'--- Advanced (help -- --all) ---',
|
|
28
|
-
'dev-build / dev-promote / af ba-*',
|
|
28
|
+
'dev-build / dev-promote (tags main + version) / af ba-*',
|
|
29
29
|
'build:ci → lint + schema-sync + flags + test:ci (same as GitHub)',
|
|
30
30
|
'sync-json → publish builder/builder-api → templates/',
|
|
31
31
|
'test:154 → builder-api scoped Jest + arch grep',
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
app:
|
|
3
3
|
key: builder-api
|
|
4
4
|
displayName: 'AI Fabrix Builder API'
|
|
5
|
-
description: '
|
|
5
|
+
description: 'Business Transformation services — HTTP orchestration for connected-system workspace lifecycle via Dataplane Enterprise MCP and governance APIs.'
|
|
6
6
|
type: webapp
|
|
7
7
|
language: typescript
|
|
8
8
|
version: 1.0.0
|
|
@@ -11,8 +11,8 @@ app:
|
|
|
11
11
|
image:
|
|
12
12
|
name: aifabrix/builder-api
|
|
13
13
|
tag: latest
|
|
14
|
-
registry:
|
|
15
|
-
registryMode:
|
|
14
|
+
registry: aifabrixacr.azurecr.io
|
|
15
|
+
registryMode: external
|
|
16
16
|
|
|
17
17
|
# Port Configuration (container port; host port = port + developer_id * 100)
|
|
18
18
|
port: 3005
|
|
@@ -5,16 +5,15 @@ app:
|
|
|
5
5
|
description: "AI Fabrix Dataplane is a secure, in-tenant integration and automation layer that supplies governed, normalized, and explainable enterprise data to AI agents. Using CIP as a declarative standard, it enforces RBAC and ABAC, executes integrations, and exposes trusted data via MCP and OpenAPI."
|
|
6
6
|
type: webapp
|
|
7
7
|
language: python # Explicitly specify Python language
|
|
8
|
-
version: 2.0.
|
|
9
|
-
|
|
8
|
+
version: 2.0.26
|
|
10
9
|
# Image Configuration
|
|
11
10
|
# Set tag to match your build (example: aifabrix build dataplane -t 1.0.0).
|
|
12
11
|
# Registry is required so the controller can pull the image (avoids docker-not-found on the controller host).
|
|
13
12
|
image:
|
|
14
13
|
name: aifabrix/dataplane
|
|
15
14
|
tag: latest
|
|
16
|
-
registry:
|
|
17
|
-
registryMode:
|
|
15
|
+
registry: aifabrixacr.azurecr.io
|
|
16
|
+
registryMode: external
|
|
18
17
|
|
|
19
18
|
# Port Configuration
|
|
20
19
|
port: 3001
|
|
@@ -89,7 +88,8 @@ build:
|
|
|
89
88
|
# - MISO_*, KEYCLOAK_* → auto-generated during Azure install
|
|
90
89
|
# - AI params / provider secrets → LLM external systems + secret store
|
|
91
90
|
# (never product OPENAI_* / AZURE_OPENAI_*). ≥2 providers →
|
|
92
|
-
# ENTERPRISE_LLM_DEFAULT_SELECTOR (portal
|
|
91
|
+
# ENTERPRISE_LLM_DEFAULT_SELECTOR (portal/env deploy default); Environment
|
|
92
|
+
# Settings ai.llmProvider overrides without redeploy.
|
|
93
93
|
# - ENVIRONMENT → set by deployment target
|
|
94
94
|
|
|
95
95
|
configuration:
|