@aifabrix/builder 2.51.1 → 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.
- 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/approval-guides/chatgpt.js +12 -9
- package/lib/channels/channel-targets.js +18 -1
- package/lib/channels/chatgpt-runtime-contract.js +1 -1
- 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 +65 -56
- 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/commands/channel-add-setup.js +8 -2
- package/lib/commands/channel.js +16 -5
- package/lib/commands/deploy-gate-orchestrator.js +3 -2
- package/lib/commands/governance-verify-external.js +2 -5
- package/lib/commands/lifecycle-external.js +14 -7
- package/lib/commands/role-assistant.js +66 -8
- 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/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/role-assistant/knowledge-markdown-frontmatter.js +75 -0
- package/lib/role-assistant/knowledge-sync.js +25 -5
- package/lib/role-assistant/test-runner-workhub-answers.js +44 -26
- package/lib/role-assistant/test-runner-workhub.js +21 -7
- package/lib/schema/application-schema.json +10 -28
- package/lib/schema/infra.parameter.yaml +0 -20
- package/lib/utils/certify-external-workspace.js +40 -0
- 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/paths.js +13 -15
- package/lib/utils/role-assistant-paths.js +76 -14
- 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/templates/applications/builder-api/application.yaml +3 -3
- package/templates/applications/dataplane/application.yaml +3 -4
- package/templates/applications/dataplane/env.template +2 -2
- 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 +3 -3
- package/templates/applications/miso-controller/env.template +16 -3
- package/templates/channels/chatgpt/install.template.md.hbs +75 -37
- package/templates/channels/chatgpt/integration/README.md +3 -2
- package/templates/channels/chatgpt/manifest.template.json.hbs +3 -3
- package/templates/channels/slack/install.template.md.hbs +6 -1
- package/templates/python/docker-compose.hbs +10 -0
- package/templates/typescript/docker-compose.hbs +10 -0
package/lib/utils/paths.js
CHANGED
|
@@ -1022,23 +1022,17 @@ async function getResolveAppPath(appName, options = {}) {
|
|
|
1022
1022
|
return { appPath: result.appPath, envOnly: false };
|
|
1023
1023
|
}
|
|
1024
1024
|
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
* @param {string} cwd - Resolved process.cwd()
|
|
1028
|
-
* @param {ReturnType<typeof nodeFs>} disk
|
|
1029
|
-
* @returns {string|null}
|
|
1030
|
-
*/
|
|
1031
|
-
function tryIntegrationAppKeyAtWalkStep(walkDir, cwd, disk) {
|
|
1032
|
-
const integrationDir = path.join(walkDir, 'integration');
|
|
1025
|
+
function tryAuthoringAppKeyAtWalkStep(walkDir, cwd, disk, folderName) {
|
|
1026
|
+
const authoringDir = path.join(walkDir, folderName);
|
|
1033
1027
|
try {
|
|
1034
|
-
if (!disk.existsSync(
|
|
1028
|
+
if (!disk.existsSync(authoringDir)) {
|
|
1035
1029
|
return null;
|
|
1036
1030
|
}
|
|
1037
|
-
const
|
|
1038
|
-
if (cwd !==
|
|
1031
|
+
const rootNorm = path.resolve(authoringDir);
|
|
1032
|
+
if (cwd !== rootNorm && !cwd.startsWith(rootNorm + path.sep)) {
|
|
1039
1033
|
return null;
|
|
1040
1034
|
}
|
|
1041
|
-
const rel = path.relative(
|
|
1035
|
+
const rel = path.relative(rootNorm, cwd);
|
|
1042
1036
|
if (!rel || rel.startsWith('..') || path.isAbsolute(rel)) {
|
|
1043
1037
|
return null;
|
|
1044
1038
|
}
|
|
@@ -1049,16 +1043,20 @@ function tryIntegrationAppKeyAtWalkStep(walkDir, cwd, disk) {
|
|
|
1049
1043
|
}
|
|
1050
1044
|
|
|
1051
1045
|
/**
|
|
1052
|
-
* Resolve app folder name when cwd is under
|
|
1046
|
+
* Resolve app folder name when cwd is under integration/, role-assistant/, or
|
|
1047
|
+
* enterprise-knowledge/<systemKey>/.
|
|
1053
1048
|
* Walks up from cwd (does not use {@link getIntegrationBuilderBaseDir}) so detection still works
|
|
1054
|
-
* when the canonical base is config/home but the shell is inside a checkout's
|
|
1049
|
+
* when the canonical base is config/home but the shell is inside a checkout's tree.
|
|
1055
1050
|
*/
|
|
1056
1051
|
function resolveIntegrationAppKeyFromCwd() {
|
|
1057
1052
|
const cwd = path.resolve(process.cwd());
|
|
1058
1053
|
const disk = nodeFs();
|
|
1059
1054
|
let p = cwd;
|
|
1060
1055
|
for (let i = 0; i < 64; i += 1) {
|
|
1061
|
-
const key =
|
|
1056
|
+
const key =
|
|
1057
|
+
tryAuthoringAppKeyAtWalkStep(p, cwd, disk, 'integration') ||
|
|
1058
|
+
tryAuthoringAppKeyAtWalkStep(p, cwd, disk, 'role-assistant') ||
|
|
1059
|
+
tryAuthoringAppKeyAtWalkStep(p, cwd, disk, 'enterprise-knowledge');
|
|
1062
1060
|
if (key) {
|
|
1063
1061
|
return key;
|
|
1064
1062
|
}
|
|
@@ -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
|
};
|
|
@@ -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
|
@@ -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.20
|
|
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
|
|
@@ -44,7 +44,7 @@ API_KEY_BYPASS_ROLES=full-access
|
|
|
44
44
|
|
|
45
45
|
# API Configuration
|
|
46
46
|
API_V1_STR=/api/v1
|
|
47
|
-
VERSION=2.0.
|
|
47
|
+
VERSION=2.0.20
|
|
48
48
|
# Minimum supported aifabrix-builder CLI semver (advertised on /health and /api/v1/health; empty = no gate)
|
|
49
49
|
# MIN_BUILDER_CLI_VERSION=2.45.0
|
|
50
50
|
MIN_BUILDER_CLI_VERSION=2.45.5
|
|
@@ -284,7 +284,7 @@ VALIDATION_AUTO_ISSUE_INTEGRATION_CERTIFICATE=true
|
|
|
284
284
|
CIP_EXECUTION_MAX_RESPONSE_SIZE_MB=100.0
|
|
285
285
|
CIP_EXECUTION_MAX_RECORDS=100000
|
|
286
286
|
CIP_EXECUTION_OPERATION_TIMEOUT=300.0
|
|
287
|
-
CIP_EXECUTION_HTTP_TIMEOUT=
|
|
287
|
+
CIP_EXECUTION_HTTP_TIMEOUT=120.0
|
|
288
288
|
CIP_EXECUTION_MAX_RETRIES=3
|
|
289
289
|
CIP_EXECUTION_RETRY_BACKOFF_FACTOR=2.0
|
|
290
290
|
CIP_EXECUTION_RETRY_INITIAL_DELAY=1.0
|
|
@@ -5,47 +5,47 @@
|
|
|
5
5
|
# MisoClient validates environment access automatically based on user/application permissions.
|
|
6
6
|
|
|
7
7
|
roles:
|
|
8
|
-
- name: "
|
|
8
|
+
- name: "Platform Admin"
|
|
9
9
|
value: "aifabrix-platform-admin"
|
|
10
10
|
description: "Full platform infrastructure management and enterprise controller access"
|
|
11
11
|
groups: ["AI-Fabrix-Platform-Admins"]
|
|
12
12
|
|
|
13
|
-
- name: "
|
|
13
|
+
- name: "Security Admin"
|
|
14
14
|
value: "aifabrix-security-admin"
|
|
15
15
|
description: "Security and compliance management for enterprise controller"
|
|
16
16
|
groups: ["AI-Fabrix-Security-Admins"]
|
|
17
17
|
|
|
18
|
-
- name: "
|
|
18
|
+
- name: "Deployment Admin"
|
|
19
19
|
value: "aifabrix-deployment-admin"
|
|
20
20
|
description: "Application deployment orchestration and environment management"
|
|
21
21
|
groups: ["AI-Fabrix-Deployment-Admins"]
|
|
22
22
|
|
|
23
|
-
- name: "
|
|
23
|
+
- name: "Compliance Admin"
|
|
24
24
|
value: "aifabrix-compliance-admin"
|
|
25
25
|
description: "ISO 27001 compliance monitoring and audit management"
|
|
26
26
|
groups: ["AI-Fabrix-Compliance-Admins"]
|
|
27
27
|
|
|
28
|
-
- name: "
|
|
28
|
+
- name: "Developer"
|
|
29
29
|
value: "aifabrix-developer"
|
|
30
30
|
description: "Developer access to deploy applications via CI pipelines"
|
|
31
31
|
groups: ["AI-Fabrix-Developers"]
|
|
32
32
|
|
|
33
|
-
- name: "
|
|
34
|
-
value: "
|
|
33
|
+
- name: "Business Transformation"
|
|
34
|
+
value: "business-transformation"
|
|
35
35
|
description: "Built-in assistant: business intention → governed Connected Systems via Runtime and builder-api"
|
|
36
36
|
groups: ["AI-Fabrix-Business-Transformation"]
|
|
37
37
|
|
|
38
|
-
- name: "
|
|
38
|
+
- name: "Observer"
|
|
39
39
|
value: "aifabrix-observer"
|
|
40
40
|
description: "Read-only access to monitoring, logs, and compliance reports"
|
|
41
41
|
groups: ["AI-Fabrix-Observers"]
|
|
42
42
|
|
|
43
|
-
- name: "AI
|
|
43
|
+
- name: "AI Trust Operator"
|
|
44
44
|
value: "aifabrix-ai-trust-operator"
|
|
45
45
|
description: "Run AI Trust access evaluation and explain visibility for governed users"
|
|
46
46
|
groups: ["AI-Fabrix-AI-Trust-Operators"]
|
|
47
47
|
|
|
48
|
-
- name: "
|
|
48
|
+
- name: "External System Discoverer"
|
|
49
49
|
value: "aifabrix-external-system-discoverer"
|
|
50
50
|
description: "Discover business context for external systems via REST and MCP"
|
|
51
51
|
groups: ["AI-Fabrix-External-System-Discoverers"]
|
|
@@ -10,8 +10,8 @@ app:
|
|
|
10
10
|
image:
|
|
11
11
|
name: aifabrix/keycloak
|
|
12
12
|
tag: 'latest'
|
|
13
|
-
registry:
|
|
14
|
-
registryMode:
|
|
13
|
+
registry: aifabrixacr.azurecr.io
|
|
14
|
+
registryMode: external
|
|
15
15
|
|
|
16
16
|
# Port Configuration (base for host; host port = 8082 + developer_id*100 from ~/.aifabrix/config.yaml)
|
|
17
17
|
port: 8082
|
|
@@ -9,11 +9,14 @@
|
|
|
9
9
|
KC_BOOTSTRAP_ADMIN_USERNAME=admin
|
|
10
10
|
KC_BOOTSTRAP_ADMIN_PASSWORD=kv://keycloak-admin-passwordKeyVault
|
|
11
11
|
KC_HOSTNAME_STRICT=false
|
|
12
|
-
|
|
12
|
+
# Follows tlsEnabled in ~/.aifabrix/config.yaml (same as ${TLS_ENABLED}).
|
|
13
|
+
# Traefik/edge HTTPS on → true (proxy forwards HTTP to Keycloak :8080).
|
|
14
|
+
# Single container without HTTPS (tlsEnabled false) → false.
|
|
15
|
+
KC_HTTP_ENABLED=${TLS_ENABLED}
|
|
13
16
|
# When Traefik + frontDoorRouting.enabled are on, same vdir as url://public. If the front door is off, env generation
|
|
14
17
|
# rewrites url://vdir-public to "/" before expansion (empty path is invalid — Keycloak 26 SRCFG00040).
|
|
15
18
|
# Docker-only templates may use url://vdir-internal instead.
|
|
16
|
-
KC_HTTP_RELATIVE_PATH
|
|
19
|
+
KC_HTTP_RELATIVE_PATH=/auth
|
|
17
20
|
|
|
18
21
|
# =============================================================================
|
|
19
22
|
# HOSTNAME / ISSUER (Docker vs localhost)
|
|
@@ -4,7 +4,7 @@ app:
|
|
|
4
4
|
displayName: 'Miso Controller'
|
|
5
5
|
description: 'Miso is the AI Fabrix in-tenant controller and portal layer for securely operating enterprise AI apps inside a customer’s Azure tenant. It provides Entra ID SSO, RBAC, audit logs, environment/app configuration via schemas, and safe secret handling via Key Vault references—ensuring governance, traceability, and predictable UX across portal, SDK, and CLI.'
|
|
6
6
|
type: webapp
|
|
7
|
-
version: '2.0.
|
|
7
|
+
version: '2.0.20'
|
|
8
8
|
|
|
9
9
|
# Image Configuration
|
|
10
10
|
# Set tag to match your build (e.g. aifabrix build miso-controller -t 1.0.0 then tag: 1.0.0)
|
|
@@ -12,8 +12,8 @@ app:
|
|
|
12
12
|
image:
|
|
13
13
|
name: aifabrix/miso-controller
|
|
14
14
|
tag: latest
|
|
15
|
-
registry:
|
|
16
|
-
registryMode:
|
|
15
|
+
registry: aifabrixacr.azurecr.io
|
|
16
|
+
registryMode: external
|
|
17
17
|
|
|
18
18
|
# Port Configuration (container port; host port = 3000 + developer_id*100 from ~/.aifabrix/config.yaml)
|
|
19
19
|
port: 3000
|
|
@@ -49,6 +49,10 @@ ONBOARDING_ADMIN_EMAIL=kv://miso-controller-admin-emailKeyVault
|
|
|
49
49
|
# When true, supersedes ONBOARDING_CREATE_DEV_ENV for which extra environments are created
|
|
50
50
|
ONBOARDING_FULL_PLATFORM=false
|
|
51
51
|
|
|
52
|
+
# When true, run Azure env deploy for onboarding envs (SDK modules). Default false —
|
|
53
|
+
# Marketplace already provisions infra; TA owns customer env deploy.
|
|
54
|
+
ONBOARDING_CREATE_MISO_ENV=false
|
|
55
|
+
|
|
52
56
|
# Set to true to create both miso and dev environments during onboarding
|
|
53
57
|
# When false (default), only the miso environment is created (ignored when ONBOARDING_FULL_PLATFORM=true)
|
|
54
58
|
ONBOARDING_CREATE_DEV_ENV=true
|
|
@@ -236,6 +240,14 @@ SKIP_DB_REDEPLOY=true
|
|
|
236
240
|
# Bootstrap (SKIP_FIRST_TIME_SETUP=false) is separate from the activation wizard.
|
|
237
241
|
DEPLOYMENT=database
|
|
238
242
|
|
|
243
|
+
# Dev/test: open /tenant-activation on Platform Apps (last step). Default false.
|
|
244
|
+
# Does not skip server-side TA — use only when env is already activated/deployed.
|
|
245
|
+
TA_SKIP_TO_APP_DEPLOY=false
|
|
246
|
+
|
|
247
|
+
# Dev/test: show TA Entra "Completing setup" countdown (120s cap). Default false.
|
|
248
|
+
# Exposed to UI via GET /api/v1/tenant/status → showTaCountdown (restart controller after change).
|
|
249
|
+
SHOW_TA_COUNT_DOWN=false
|
|
250
|
+
|
|
239
251
|
# =============================================================================
|
|
240
252
|
# SECURITY & ENCRYPTION
|
|
241
253
|
# =============================================================================
|
|
@@ -287,9 +299,10 @@ ENTRA_GRAPH_DELEGATED_REDIRECT_URI=https://aifabrix-pro-mori-web-we.azurewebsite
|
|
|
287
299
|
# =============================================================================
|
|
288
300
|
# MORI SERVICE CONFIGURATION
|
|
289
301
|
# =============================================================================
|
|
290
|
-
|
|
291
|
-
#
|
|
292
|
-
#
|
|
302
|
+
# Shared Mori (handoff poll + Entra callback). Local `url://mori-controller-public`
|
|
303
|
+
# only works when a local Mori app is registered and running for this developer.
|
|
304
|
+
# MORI_CALLBACK_API_KEY must be the same secret as Mori MORI_CONTROLLER_CALLBACK_API_KEY
|
|
305
|
+
# (both resolve from kv://mori-callback-api-keyKeyVault — do not generate separate values).
|
|
293
306
|
MORI_BASE_URL=https://aifabrix-pro-mori-web-we.azurewebsites.net
|
|
294
307
|
MORI_AUTH_METHOD=kv://mori-controller-auth-methodKeyVault
|
|
295
308
|
MORI_CALLBACK_API_KEY=kv://mori-callback-api-keyKeyVault
|