@aifabrix/builder 2.51.0 → 2.51.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/jest.isolated-projects.js +77 -1
- package/jest.projects.js +5 -426
- package/lib/api/assistants.api.js +67 -0
- package/lib/api/datasources-extended.api.js +6 -6
- package/lib/api/evidence-authoring-helpers.js +267 -0
- package/lib/api/evidence-authoring.api.js +337 -0
- package/lib/api/evidence.api.js +57 -1
- package/lib/api/index.js +24 -7
- package/lib/api/pipeline.api.js +43 -3
- package/lib/api/records-bulk.api.js +28 -3
- package/lib/api/types/evidence.types.js +156 -8
- package/lib/api/work.api.js +283 -0
- package/lib/app/run-deploy-job.js +108 -0
- package/lib/app/run-helpers.js +10 -3
- package/lib/app/run.js +8 -0
- package/lib/channels/add-channel.js +54 -23
- package/lib/channels/approval-guides/chatgpt.js +8 -7
- package/lib/channels/approval-guides/microsoft-copilot.js +7 -8
- package/lib/channels/channel-artifact-generator.js +14 -2
- package/lib/channels/channel-credential.js +3 -1
- package/lib/channels/channel-probe-evidence.js +79 -0
- package/lib/channels/channel-probe.js +265 -13
- package/lib/channels/channel-runtime-resolver.js +120 -29
- package/lib/channels/channel-status-display.js +44 -0
- package/lib/channels/channel-targets.js +7 -0
- package/lib/channels/chatgpt-runtime-contract.js +29 -0
- package/lib/channels/microsoft-copilot-package.js +280 -0
- package/lib/channels/runtime-tool-catalog.js +165 -0
- package/lib/cli/index.js +2 -0
- package/lib/cli/setup-app.js +4 -0
- package/lib/cli/setup-external-system-help.js +8 -2
- package/lib/cli/setup-external-system.js +12 -0
- package/lib/commands/app-test.js +2 -14
- package/lib/commands/datasource-load-export-cli.js +6 -1
- package/lib/commands/deploy-gate-failure-details.js +19 -17
- package/lib/commands/dev-down.js +2 -6
- package/lib/commands/evidence-kind.js +65 -15
- package/lib/commands/governance-generate-external.js +56 -21
- package/lib/commands/lifecycle-external.js +10 -4
- package/lib/commands/repair-datasource-apply.js +10 -1
- package/lib/commands/repair-datasource-run.js +4 -2
- package/lib/commands/repair-datasource-test-payload.js +80 -19
- package/lib/commands/repair-datasource-webhooks-sync-bridge.js +42 -3
- package/lib/commands/repair-internal.js +9 -1
- package/lib/commands/repair-openapi-sync.js +34 -17
- package/lib/commands/role-assistant.js +313 -0
- package/lib/commands/upload-data-sync-finalize.js +5 -4
- package/lib/commands/upload-sidecar-followups.js +144 -47
- package/lib/commands/upload.js +43 -6
- package/lib/commands/verify-governance-combined-external.js +73 -9
- package/lib/commands/verify-governance-db.js +80 -25
- package/lib/commands/verify-governance-external.js +29 -5
- package/lib/commands/wizard-core-helpers.js +7 -3
- package/lib/commands/wizard-core.js +78 -9
- package/lib/datasource/bulk-loader-run-batches.js +4 -2
- package/lib/datasource/bulk-loader-service.js +5 -1
- package/lib/datasource/datasource-validate-summary.js +2 -2
- package/lib/datasource/validate.js +13 -6
- package/lib/external-system/deploy-helpers.js +35 -1
- package/lib/external-system/deploy.js +23 -10
- package/lib/external-system/download-helpers.js +111 -2
- package/lib/external-system/download-role-assistant.js +55 -0
- package/lib/external-system/download.js +45 -26
- package/lib/external-system/test-helpers.js +1 -1
- package/lib/external-system/test.js +39 -3
- package/lib/generator/builders.js +3 -0
- package/lib/generator/wizard.js +51 -4
- package/lib/lifecycle/access-control-abac.js +121 -0
- package/lib/lifecycle/lifecycle-governance-options.js +4 -1
- package/lib/lifecycle/product-model.js +3 -2
- package/lib/lifecycle/report-display.js +14 -2
- package/lib/programmatic/capability-registry.js +20 -1
- package/lib/programmatic/command-options.js +1 -0
- package/lib/programmatic/index.js +4 -0
- package/lib/programmatic/manifest-patch-section.js +48 -9
- package/lib/programmatic/manifest-section-registry-data.js +3 -2
- package/lib/programmatic/openapi-apply-result-schemas.js +44 -0
- package/lib/programmatic/openapi-component-schemas.js +16 -1
- package/lib/programmatic/openapi-description-enricher.js +3 -1
- package/lib/programmatic/openapi-descriptions.js +55 -5
- package/lib/programmatic/openapi-evidence-schemas.js +161 -0
- package/lib/programmatic/openapi-manifest-schemas.js +6 -2
- package/lib/programmatic/openapi-operation-bindings.js +99 -0
- package/lib/programmatic/openapi-request-schemas.js +36 -1
- package/lib/programmatic/openapi-result-schemas.js +1 -1
- package/lib/programmatic/openapi-schema-descriptions-certify.js +5 -1
- package/lib/programmatic/openapi-schema-descriptions-core.js +1 -1
- package/lib/programmatic/openapi-schema-descriptions-evidence.js +156 -0
- package/lib/programmatic/openapi-schema-descriptions-manifest.js +4 -3
- package/lib/programmatic/openapi-schema-descriptions-operations.js +70 -0
- package/lib/programmatic/openapi-spec.js +47 -28
- package/lib/programmatic/orchestration-openapi-meta.js +5 -0
- package/lib/programmatic/request-timeout.js +3 -0
- package/lib/programmatic/route-handler-map.js +89 -2
- package/lib/programmatic/run-certify.js +15 -2
- package/lib/programmatic/run-deploy.js +74 -0
- package/lib/programmatic/run-evidence-authoring.js +80 -0
- package/lib/programmatic/run-protection.js +124 -0
- package/lib/programmatic/run-template-workspace.js +28 -1
- package/lib/programmatic/workspace-context.js +6 -0
- package/lib/protection/auth-context.js +48 -6
- package/lib/protection/paths.js +22 -0
- package/lib/protection/run-protection-create-helpers.js +22 -1
- package/lib/protection/run-protection-create.js +1 -1
- package/lib/protection/sync-after-upload.js +1 -1
- package/lib/role-assistant/evidence-sync.js +450 -0
- package/lib/role-assistant/github-workflow.js +96 -0
- package/lib/role-assistant/knowledge-sync.js +465 -0
- package/lib/role-assistant/settings.js +126 -0
- package/lib/role-assistant/test-cases-evaluate.js +170 -0
- package/lib/role-assistant/test-cases-honesty.js +184 -0
- package/lib/role-assistant/test-cases.js +364 -0
- package/lib/role-assistant/test-runner-workhub-answers.js +203 -0
- package/lib/role-assistant/test-runner-workhub.js +385 -0
- package/lib/role-assistant/test-runner.js +500 -0
- package/lib/schema/application-schema.json +16 -2
- package/lib/schema/deployment-rules.yaml +1 -0
- package/lib/schema/external-datasource.schema.json +38 -4
- package/lib/schema/external-system.schema.json +4 -4
- package/lib/schema/infra.parameter.yaml +20 -0
- package/lib/schema/role-assistant-settings.schema.json +108 -0
- package/lib/utils/api.js +52 -27
- package/lib/utils/app-path-resolve.js +72 -24
- package/lib/utils/authentication-shape.js +3 -1
- package/lib/utils/deployment-validation.js +28 -3
- package/lib/utils/docker-run-ephemeral.js +55 -0
- package/lib/utils/enterprise-knowledge-paths.js +29 -12
- package/lib/utils/env-copy-keycloak.js +196 -0
- package/lib/utils/env-copy.js +34 -1
- package/lib/utils/external-system-readiness-compact-display.js +3 -0
- package/lib/utils/help-builder.js +1 -0
- package/lib/utils/paths.js +67 -23
- package/lib/utils/pipeline-upload-auth-retry.js +15 -3
- package/lib/utils/role-assistant-paths.js +98 -0
- package/lib/utils/schema-loader.js +41 -0
- package/lib/utils/schema-resolver.js +36 -4
- package/lib/utils/token-manager.js +38 -29
- package/lib/utils/url-declarative-resolve-load-doc.js +38 -1
- package/lib/validation/external-manifest-validator.js +31 -8
- package/lib/validation/validate-external-file.js +8 -1
- package/package.json +2 -1
- package/scripts/export-builder-api-evidence.js +1 -1
- package/templates/applications/dataplane/application.yaml +23 -15
- package/templates/applications/dataplane/env.template +1 -1
- package/templates/applications/dataplane/rbac.yaml +14 -0
- package/templates/applications/miso-controller/application.yaml +1 -1
- package/templates/applications/miso-controller/env.template +3 -1
- package/templates/channels/chatgpt/install.template.md.hbs +42 -24
- package/templates/channels/chatgpt/integration/README.md +10 -7
- package/templates/channels/chatgpt/integration/application.json +2 -2
- package/templates/channels/chatgpt/integration/chatgpt-system.json +3 -3
- package/templates/channels/chatgpt/integration/env.template +1 -1
- package/templates/channels/chatgpt/manifest.template.json.hbs +36 -5
- package/templates/channels/microsoft-copilot/ai-plugin.template.json.hbs +28 -0
- package/templates/channels/microsoft-copilot/declarative-agent.template.json.hbs +22 -0
- package/templates/channels/microsoft-copilot/install.template.md.hbs +32 -22
- package/templates/channels/microsoft-copilot/integration/README.md +9 -7
- package/templates/channels/microsoft-copilot/integration/application.json +2 -2
- package/templates/channels/microsoft-copilot/integration/env.template +1 -1
- package/templates/channels/microsoft-copilot/integration/microsoft-copilot-system.json +7 -6
- package/templates/channels/microsoft-copilot/manifest.template.json.hbs +34 -6
- /package/.cursor/plans/{157.1-security-quality-violations-by-type.csv → Done/157.1-security-quality-violations-by-type.csv} +0 -0
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "aifabrix://schema/role-assistant-settings",
|
|
4
|
+
"title": "Role Assistant Settings",
|
|
5
|
+
"description": "Schema for role-assistant.yaml used by digitalWorker packages.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": [
|
|
8
|
+
"apiVersion",
|
|
9
|
+
"version",
|
|
10
|
+
"kind",
|
|
11
|
+
"roleKey"
|
|
12
|
+
],
|
|
13
|
+
"additionalProperties": false,
|
|
14
|
+
"properties": {
|
|
15
|
+
"apiVersion": {
|
|
16
|
+
"type": "string",
|
|
17
|
+
"const": "aifabrix.ai/v1"
|
|
18
|
+
},
|
|
19
|
+
"version": {
|
|
20
|
+
"type": "string",
|
|
21
|
+
"pattern": "^\\d+\\.\\d+\\.\\d+$"
|
|
22
|
+
},
|
|
23
|
+
"kind": {
|
|
24
|
+
"type": "string",
|
|
25
|
+
"const": "RoleAssistantSettings"
|
|
26
|
+
},
|
|
27
|
+
"roleKey": {
|
|
28
|
+
"type": "string",
|
|
29
|
+
"pattern": "^[a-z0-9-_]+$"
|
|
30
|
+
},
|
|
31
|
+
"dev": {
|
|
32
|
+
"$ref": "#/$defs/environmentSettings"
|
|
33
|
+
},
|
|
34
|
+
"tst": {
|
|
35
|
+
"$ref": "#/$defs/environmentSettings"
|
|
36
|
+
},
|
|
37
|
+
"pro": {
|
|
38
|
+
"$ref": "#/$defs/environmentSettings"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"$defs": {
|
|
42
|
+
"environmentSettings": {
|
|
43
|
+
"type": "object",
|
|
44
|
+
"additionalProperties": false,
|
|
45
|
+
"properties": {
|
|
46
|
+
"runtime": {
|
|
47
|
+
"$ref": "#/$defs/runtime"
|
|
48
|
+
},
|
|
49
|
+
"debug": {
|
|
50
|
+
"$ref": "#/$defs/debug"
|
|
51
|
+
},
|
|
52
|
+
"knowledge": {
|
|
53
|
+
"$ref": "#/$defs/knowledge"
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
"runtime": {
|
|
58
|
+
"type": "object",
|
|
59
|
+
"additionalProperties": false,
|
|
60
|
+
"properties": {
|
|
61
|
+
"provider": {
|
|
62
|
+
"type": "string"
|
|
63
|
+
},
|
|
64
|
+
"model": {
|
|
65
|
+
"type": "string"
|
|
66
|
+
},
|
|
67
|
+
"temperature": {
|
|
68
|
+
"type": "number",
|
|
69
|
+
"minimum": 0,
|
|
70
|
+
"maximum": 2
|
|
71
|
+
},
|
|
72
|
+
"maxLoops": {
|
|
73
|
+
"type": "integer",
|
|
74
|
+
"minimum": 1,
|
|
75
|
+
"maximum": 1000
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
"debug": {
|
|
80
|
+
"type": "object",
|
|
81
|
+
"additionalProperties": false,
|
|
82
|
+
"properties": {
|
|
83
|
+
"enabled": {
|
|
84
|
+
"type": "boolean"
|
|
85
|
+
},
|
|
86
|
+
"includeRuntimeLog": {
|
|
87
|
+
"type": "boolean"
|
|
88
|
+
},
|
|
89
|
+
"includePromptTrace": {
|
|
90
|
+
"type": "boolean"
|
|
91
|
+
},
|
|
92
|
+
"includeCapabilityTrace": {
|
|
93
|
+
"type": "boolean"
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
"knowledge": {
|
|
98
|
+
"type": "object",
|
|
99
|
+
"additionalProperties": false,
|
|
100
|
+
"properties": {
|
|
101
|
+
"documentStorageKey": {
|
|
102
|
+
"type": "string",
|
|
103
|
+
"pattern": "^[a-z0-9-_]+$"
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
package/lib/utils/api.js
CHANGED
|
@@ -381,12 +381,11 @@ function extractControllerUrl(url) {
|
|
|
381
381
|
return match ? match[1] : url;
|
|
382
382
|
}
|
|
383
383
|
}
|
|
384
|
-
|
|
385
384
|
/**
|
|
386
|
-
* Set auth header on headers object: Bearer for user token, x-client-token for
|
|
385
|
+
* Set auth header on headers object: Bearer for user token, x-client-token for app token.
|
|
387
386
|
* @param {Object} headers - Headers object to mutate
|
|
388
387
|
* @param {string} token - Token value
|
|
389
|
-
* @param {string} authType - 'bearer'
|
|
388
|
+
* @param {string} authType - 'bearer' | 'client-token'
|
|
390
389
|
*/
|
|
391
390
|
function setAuthHeader(headers, token, authType) {
|
|
392
391
|
if (!token) return;
|
|
@@ -396,7 +395,6 @@ function setAuthHeader(headers, token, authType) {
|
|
|
396
395
|
headers['Authorization'] = `Bearer ${token}`;
|
|
397
396
|
}
|
|
398
397
|
}
|
|
399
|
-
|
|
400
398
|
/**
|
|
401
399
|
* Make an authenticated API call with user token (Bearer) or application token (x-client-token).
|
|
402
400
|
* Automatically refreshes device token on 401 when user Bearer was used.
|
|
@@ -408,7 +406,48 @@ function setAuthHeader(headers, token, authType) {
|
|
|
408
406
|
* @param {string} [tokenOrAuthConfig.controller] - Controller URL for token refresh (if object)
|
|
409
407
|
* @returns {Promise<Object>} Response object
|
|
410
408
|
*/
|
|
411
|
-
|
|
409
|
+
/**
|
|
410
|
+
* Retry once after device-token refresh on 401 (Bearer only; never for client-token/preserveBearer).
|
|
411
|
+
* @param {Object} response
|
|
412
|
+
* @param {string} url
|
|
413
|
+
* @param {Object} options
|
|
414
|
+
* @param {Object} headers
|
|
415
|
+
* @param {string|null} authControllerUrl
|
|
416
|
+
* @returns {Promise<Object>}
|
|
417
|
+
*/
|
|
418
|
+
async function retryApiCallAfterDeviceTokenRefresh(
|
|
419
|
+
response,
|
|
420
|
+
url,
|
|
421
|
+
options,
|
|
422
|
+
headers,
|
|
423
|
+
authControllerUrl
|
|
424
|
+
) {
|
|
425
|
+
try {
|
|
426
|
+
const { forceRefreshDeviceToken } = require('./token-manager');
|
|
427
|
+
const refreshedToken = await forceRefreshDeviceToken(
|
|
428
|
+
authControllerUrl || extractControllerUrl(url)
|
|
429
|
+
);
|
|
430
|
+
if (refreshedToken?.token) {
|
|
431
|
+
headers.Authorization = `Bearer ${refreshedToken.token}`;
|
|
432
|
+
return await makeApiCall(url, { ...options, headers });
|
|
433
|
+
}
|
|
434
|
+
const authError =
|
|
435
|
+
'Authentication failed: Token expired and refresh failed. Please login again using: aifabrix login';
|
|
436
|
+
return { ...response, error: authError, formattedError: authError };
|
|
437
|
+
} catch (refreshError) {
|
|
438
|
+
const authError = `Authentication failed: ${refreshError.message || String(refreshError)}. Please login again using: aifabrix login`;
|
|
439
|
+
return { ...response, error: authError, formattedError: authError };
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
function shouldRefreshBearerOn401(response, authType, tokenOrAuthConfig) {
|
|
443
|
+
return (
|
|
444
|
+
!response.success &&
|
|
445
|
+
response.status === 401 &&
|
|
446
|
+
authType !== 'client-token' &&
|
|
447
|
+
!(typeof tokenOrAuthConfig === 'object' && tokenOrAuthConfig?.preserveBearer)
|
|
448
|
+
);
|
|
449
|
+
}
|
|
450
|
+
|
|
412
451
|
async function authenticatedApiCall(url, options = {}, tokenOrAuthConfig) {
|
|
413
452
|
const isStringToken = typeof tokenOrAuthConfig === 'string';
|
|
414
453
|
const token = isStringToken ? tokenOrAuthConfig : tokenOrAuthConfig?.token;
|
|
@@ -426,32 +465,18 @@ async function authenticatedApiCall(url, options = {}, tokenOrAuthConfig) {
|
|
|
426
465
|
headers
|
|
427
466
|
});
|
|
428
467
|
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
try {
|
|
438
|
-
const { forceRefreshDeviceToken } = require('./token-manager');
|
|
439
|
-
const refreshedToken = await forceRefreshDeviceToken(authControllerUrl || extractControllerUrl(url));
|
|
440
|
-
if (refreshedToken?.token) {
|
|
441
|
-
headers['Authorization'] = `Bearer ${refreshedToken.token}`;
|
|
442
|
-
return await makeApiCall(url, { ...options, headers });
|
|
443
|
-
}
|
|
444
|
-
const authError = 'Authentication failed: Token expired and refresh failed. Please login again using: aifabrix login';
|
|
445
|
-
return { ...response, error: authError, formattedError: authError };
|
|
446
|
-
} catch (refreshError) {
|
|
447
|
-
const authError = `Authentication failed: ${refreshError.message || String(refreshError)}. Please login again using: aifabrix login`;
|
|
448
|
-
return { ...response, error: authError, formattedError: authError };
|
|
449
|
-
}
|
|
468
|
+
if (shouldRefreshBearerOn401(response, authType, tokenOrAuthConfig)) {
|
|
469
|
+
return retryApiCallAfterDeviceTokenRefresh(
|
|
470
|
+
response,
|
|
471
|
+
url,
|
|
472
|
+
options,
|
|
473
|
+
headers,
|
|
474
|
+
authControllerUrl
|
|
475
|
+
);
|
|
450
476
|
}
|
|
451
477
|
|
|
452
478
|
return response;
|
|
453
479
|
}
|
|
454
|
-
|
|
455
480
|
const {
|
|
456
481
|
initiateDeviceCodeFlow,
|
|
457
482
|
pollDeviceCodeToken,
|
|
@@ -15,6 +15,11 @@ const {
|
|
|
15
15
|
SYSTEM_KIND_ENTERPRISE_KNOWLEDGE,
|
|
16
16
|
getEnterpriseKnowledgePath
|
|
17
17
|
} = require('./enterprise-knowledge-paths');
|
|
18
|
+
const {
|
|
19
|
+
WORKSPACE_ROLE_ASSISTANT,
|
|
20
|
+
SYSTEM_KIND_DIGITAL_WORKER,
|
|
21
|
+
getRoleAssistantPath
|
|
22
|
+
} = require('./role-assistant-paths');
|
|
18
23
|
|
|
19
24
|
const WORKSPACE_INTEGRATION = 'integration';
|
|
20
25
|
|
|
@@ -62,10 +67,14 @@ function normalizeWorkspaceOverride(raw) {
|
|
|
62
67
|
return null;
|
|
63
68
|
}
|
|
64
69
|
const v = String(raw).trim().toLowerCase();
|
|
65
|
-
if (
|
|
70
|
+
if (
|
|
71
|
+
v === WORKSPACE_INTEGRATION ||
|
|
72
|
+
v === WORKSPACE_ENTERPRISE_KNOWLEDGE ||
|
|
73
|
+
v === WORKSPACE_ROLE_ASSISTANT
|
|
74
|
+
) {
|
|
66
75
|
return v;
|
|
67
76
|
}
|
|
68
|
-
throw new Error(`Unknown workspace "${raw}". Use integration or
|
|
77
|
+
throw new Error(`Unknown workspace "${raw}". Use integration, enterprise-knowledge, or role-assistant.`);
|
|
69
78
|
}
|
|
70
79
|
|
|
71
80
|
function workspacePair(appPath, baseDir) {
|
|
@@ -76,47 +85,84 @@ function resolveFromWorkspaceOverride(workspaceOverride, appName, getIntegration
|
|
|
76
85
|
if (workspaceOverride === WORKSPACE_ENTERPRISE_KNOWLEDGE) {
|
|
77
86
|
return workspacePair(getEnterpriseKnowledgePath(appName), WORKSPACE_ENTERPRISE_KNOWLEDGE);
|
|
78
87
|
}
|
|
88
|
+
if (workspaceOverride === WORKSPACE_ROLE_ASSISTANT) {
|
|
89
|
+
return workspacePair(getRoleAssistantPath(appName), WORKSPACE_ROLE_ASSISTANT);
|
|
90
|
+
}
|
|
79
91
|
if (workspaceOverride === WORKSPACE_INTEGRATION) {
|
|
80
92
|
return workspacePair(getIntegrationPath(appName), WORKSPACE_INTEGRATION);
|
|
81
93
|
}
|
|
82
94
|
return null;
|
|
83
95
|
}
|
|
84
96
|
|
|
85
|
-
function
|
|
86
|
-
const kind =
|
|
87
|
-
explicitKind ||
|
|
88
|
-
readSystemKindFromAppDir(ekPath, appName) ||
|
|
89
|
-
readSystemKindFromAppDir(intPath, appName);
|
|
97
|
+
function resolveWorkspaceFromSystemKind(kind, ekPath, intPath, roleAssistantPath) {
|
|
90
98
|
if (kind === SYSTEM_KIND_ENTERPRISE_KNOWLEDGE) {
|
|
91
99
|
return workspacePair(ekPath, WORKSPACE_ENTERPRISE_KNOWLEDGE);
|
|
92
100
|
}
|
|
101
|
+
if (kind === SYSTEM_KIND_DIGITAL_WORKER) {
|
|
102
|
+
return workspacePair(roleAssistantPath, WORKSPACE_ROLE_ASSISTANT);
|
|
103
|
+
}
|
|
93
104
|
return workspacePair(intPath, WORKSPACE_INTEGRATION);
|
|
94
105
|
}
|
|
95
106
|
|
|
96
|
-
function
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
107
|
+
function resolveAmbiguousWorkspace(ekPath, intPath, roleAssistantPath, explicitKind, appName) {
|
|
108
|
+
const kind =
|
|
109
|
+
explicitKind ||
|
|
110
|
+
readSystemKindFromAppDir(roleAssistantPath, appName) ||
|
|
111
|
+
readSystemKindFromAppDir(ekPath, appName) ||
|
|
112
|
+
readSystemKindFromAppDir(intPath, appName);
|
|
113
|
+
return resolveWorkspaceFromSystemKind(kind, ekPath, intPath, roleAssistantPath);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function resolveFromExistingPaths(paths, existence, explicitKind, appName) {
|
|
117
|
+
const { ekPath, intPath, roleAssistantPath } = paths;
|
|
118
|
+
const { ekExists, intExists, roleAssistantExists } = existence;
|
|
119
|
+
const existingCount = [ekExists, intExists, roleAssistantExists].filter(Boolean).length;
|
|
120
|
+
if (existingCount === 1) {
|
|
121
|
+
if (ekExists) {
|
|
122
|
+
return workspacePair(ekPath, WORKSPACE_ENTERPRISE_KNOWLEDGE);
|
|
123
|
+
}
|
|
124
|
+
if (roleAssistantExists) {
|
|
125
|
+
return workspacePair(roleAssistantPath, WORKSPACE_ROLE_ASSISTANT);
|
|
126
|
+
}
|
|
101
127
|
return workspacePair(intPath, WORKSPACE_INTEGRATION);
|
|
102
128
|
}
|
|
103
|
-
if (
|
|
104
|
-
return resolveAmbiguousWorkspace(ekPath, intPath, explicitKind, appName);
|
|
129
|
+
if (existingCount > 1) {
|
|
130
|
+
return resolveAmbiguousWorkspace(ekPath, intPath, roleAssistantPath, explicitKind, appName);
|
|
105
131
|
}
|
|
106
|
-
const kind =
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
132
|
+
const kind =
|
|
133
|
+
explicitKind ||
|
|
134
|
+
readSystemKindFromAppDir(roleAssistantPath, appName) ||
|
|
135
|
+
readSystemKindFromAppDir(ekPath, appName) ||
|
|
136
|
+
readSystemKindFromAppDir(intPath, appName);
|
|
137
|
+
return resolveWorkspaceFromSystemKind(kind, ekPath, intPath, roleAssistantPath);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function resolveFromExistingPathsBackwardCompatible(
|
|
141
|
+
ekPath,
|
|
142
|
+
intPath,
|
|
143
|
+
roleAssistantPath,
|
|
144
|
+
explicitKind,
|
|
145
|
+
appName
|
|
146
|
+
) {
|
|
147
|
+
return resolveFromExistingPaths(
|
|
148
|
+
{ ekPath, intPath, roleAssistantPath },
|
|
149
|
+
{
|
|
150
|
+
ekExists: isExistingDirectory(ekPath),
|
|
151
|
+
intExists: isExistingDirectory(intPath),
|
|
152
|
+
roleAssistantExists: isExistingDirectory(roleAssistantPath)
|
|
153
|
+
},
|
|
154
|
+
explicitKind,
|
|
155
|
+
appName
|
|
156
|
+
);
|
|
111
157
|
}
|
|
112
158
|
|
|
113
159
|
/**
|
|
114
160
|
* Resolves authoring tree for an external system or Enterprise Knowledge anchor.
|
|
115
161
|
* @param {string} appName - App or anchor key
|
|
116
162
|
* @param {Object} [options]
|
|
117
|
-
* @param {string} [options.workspace] - integration | enterprise-knowledge
|
|
163
|
+
* @param {string} [options.workspace] - integration | enterprise-knowledge | role-assistant
|
|
118
164
|
* @param {string} [options.systemKind] - Explicit systemKind override
|
|
119
|
-
* @returns {{ appPath: string, baseDir: 'integration' | 'enterprise-knowledge' }}
|
|
165
|
+
* @returns {{ appPath: string, baseDir: 'integration' | 'enterprise-knowledge' | 'role-assistant' }}
|
|
120
166
|
*/
|
|
121
167
|
function resolveAppWorkspace(appName, options = {}) {
|
|
122
168
|
if (!appName || typeof appName !== 'string') {
|
|
@@ -137,11 +183,11 @@ function resolveAppWorkspace(appName, options = {}) {
|
|
|
137
183
|
|
|
138
184
|
const ekPath = getEnterpriseKnowledgePath(appName);
|
|
139
185
|
const intPath = getIntegrationPath(appName);
|
|
140
|
-
|
|
186
|
+
const roleAssistantPath = getRoleAssistantPath(appName);
|
|
187
|
+
return resolveFromExistingPathsBackwardCompatible(
|
|
141
188
|
ekPath,
|
|
142
189
|
intPath,
|
|
143
|
-
|
|
144
|
-
isExistingDirectory(intPath),
|
|
190
|
+
roleAssistantPath,
|
|
145
191
|
explicitKind,
|
|
146
192
|
appName
|
|
147
193
|
);
|
|
@@ -160,7 +206,9 @@ function resolveExternalSystemPath(appName, options = {}) {
|
|
|
160
206
|
module.exports = {
|
|
161
207
|
WORKSPACE_INTEGRATION,
|
|
162
208
|
WORKSPACE_ENTERPRISE_KNOWLEDGE,
|
|
209
|
+
WORKSPACE_ROLE_ASSISTANT,
|
|
163
210
|
SYSTEM_KIND_ENTERPRISE_KNOWLEDGE,
|
|
211
|
+
SYSTEM_KIND_DIGITAL_WORKER,
|
|
164
212
|
readSystemKindFromAppDir,
|
|
165
213
|
normalizeWorkspaceOverride,
|
|
166
214
|
resolveAppWorkspace,
|
|
@@ -64,7 +64,9 @@ function buildFlatCredentialTemplate(systemKey, authType) {
|
|
|
64
64
|
security: { clientId: kvPath('clientId'), clientSecret: kvPath('clientSecret') }
|
|
65
65
|
},
|
|
66
66
|
apikey: {
|
|
67
|
-
|
|
67
|
+
// Match credential-field-registry placeholders (Authorization + Bearer).
|
|
68
|
+
// Integrations that need a literal custom header set headerName after repair.
|
|
69
|
+
variables: { baseUrl: base, headerName: 'Authorization', prefix: 'Bearer' },
|
|
68
70
|
security: { apiKey: kvPath('apiKey') }
|
|
69
71
|
},
|
|
70
72
|
bearerToken: {
|
|
@@ -8,6 +8,27 @@
|
|
|
8
8
|
* @version 2.0.0
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* True when URL is http to a Docker Compose service DNS name (single hostname label).
|
|
13
|
+
* Example: http://miso-controller:3000/miso — used by builder-api in compose, not public HTTP.
|
|
14
|
+
*
|
|
15
|
+
* @param {string} url
|
|
16
|
+
* @returns {boolean}
|
|
17
|
+
*/
|
|
18
|
+
function isDockerComposeServiceHttpUrl(url) {
|
|
19
|
+
try {
|
|
20
|
+
const parsed = new URL(url);
|
|
21
|
+
if (parsed.protocol !== 'http:') {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
const host = parsed.hostname || '';
|
|
25
|
+
// Compose DNS: one label, no dots (miso-controller, dataplane, …)
|
|
26
|
+
return Boolean(host) && !host.includes('.') && host !== 'localhost';
|
|
27
|
+
} catch {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
11
32
|
/**
|
|
12
33
|
* Validates and sanitizes controller URL
|
|
13
34
|
* Enforces HTTPS-only communication for security
|
|
@@ -20,9 +41,13 @@ function validateControllerUrl(url) {
|
|
|
20
41
|
throw new Error('Controller URL is required and must be a string');
|
|
21
42
|
}
|
|
22
43
|
|
|
23
|
-
//
|
|
24
|
-
|
|
25
|
-
|
|
44
|
+
// HTTPS required in public networks; allow localhost and compose-service HTTP for local Docker
|
|
45
|
+
const allowedHttp =
|
|
46
|
+
url.startsWith('http://localhost') || isDockerComposeServiceHttpUrl(url);
|
|
47
|
+
if (!url.startsWith('https://') && !allowedHttp) {
|
|
48
|
+
throw new Error(
|
|
49
|
+
'Controller URL must use HTTPS (https://), http://localhost, or a Docker Compose service HTTP URL'
|
|
50
|
+
);
|
|
26
51
|
}
|
|
27
52
|
|
|
28
53
|
// Basic URL format validation
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ephemeral docker run (--rm) for one-shot commands (test, install, deployJob).
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Shared docker run --rm helper
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 2.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const { spawn } = require('child_process');
|
|
10
|
+
const { getDockerExecEnv } = require('./remote-docker-env');
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Run a shell command in an ephemeral container; optional --env-file / --network / bind mounts.
|
|
14
|
+
* Attach to the developer infra bridge when the command needs compose DNS
|
|
15
|
+
* (e.g. hostname `postgres` in DATABASE_URL).
|
|
16
|
+
* @param {string} fullImage - Image:tag
|
|
17
|
+
* @param {string} cmd - Shell command (passed to sh -c)
|
|
18
|
+
* @param {string|null} [envFilePath] - Path for docker run --env-file
|
|
19
|
+
* @param {{ network?: string|null, volumeMounts?: Array<{ host: string, container: string }> }} [options]
|
|
20
|
+
* @returns {Promise<number>} Exit code
|
|
21
|
+
*/
|
|
22
|
+
async function runDockerRunEphemeral(fullImage, cmd, envFilePath = null, options = {}) {
|
|
23
|
+
const dockerEnv = await getDockerExecEnv();
|
|
24
|
+
const network =
|
|
25
|
+
options && typeof options.network === 'string' && options.network.trim()
|
|
26
|
+
? options.network.trim()
|
|
27
|
+
: null;
|
|
28
|
+
const volumeMounts = Array.isArray(options?.volumeMounts) ? options.volumeMounts : [];
|
|
29
|
+
return new Promise((resolve) => {
|
|
30
|
+
const args = ['run', '--rm'];
|
|
31
|
+
if (network) {
|
|
32
|
+
args.push('--network', network);
|
|
33
|
+
}
|
|
34
|
+
if (envFilePath) {
|
|
35
|
+
args.push('--env-file', envFilePath);
|
|
36
|
+
}
|
|
37
|
+
for (const mount of volumeMounts) {
|
|
38
|
+
const host = typeof mount?.host === 'string' ? mount.host.trim() : '';
|
|
39
|
+
const container = typeof mount?.container === 'string' ? mount.container.trim() : '';
|
|
40
|
+
if (host && container) {
|
|
41
|
+
args.push('-v', `${host}:${container}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
args.push(fullImage, 'sh', '-c', cmd);
|
|
45
|
+
const proc = spawn('docker', args, {
|
|
46
|
+
stdio: 'inherit',
|
|
47
|
+
shell: false,
|
|
48
|
+
env: dockerEnv
|
|
49
|
+
});
|
|
50
|
+
proc.on('close', (code) => resolve(code !== null ? code : 1));
|
|
51
|
+
proc.on('error', () => resolve(1));
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
module.exports = { runDockerRunEphemeral };
|
|
@@ -62,8 +62,22 @@ function getEnterpriseKnowledgeRoot() {
|
|
|
62
62
|
return path.join(getMaterializationParent(), WORKSPACE_ENTERPRISE_KNOWLEDGE);
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
+
function isExistingDirectory(disk, dirPath) {
|
|
66
|
+
try {
|
|
67
|
+
if (!dirPath || !disk.existsSync(dirPath)) {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
const st = disk.statSync(dirPath);
|
|
71
|
+
return Boolean(st && typeof st.isDirectory === 'function' && st.isDirectory());
|
|
72
|
+
} catch {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
65
77
|
/**
|
|
66
|
-
* Resolves enterprise-knowledge/<anchorKey
|
|
78
|
+
* Resolves enterprise-knowledge/<anchorKey>.
|
|
79
|
+
* Prefer an existing cwd or materialization folder; when `cwd/enterprise-knowledge/` exists and
|
|
80
|
+
* neither copy exists yet, return the cwd path (download/create target).
|
|
67
81
|
* @param {string} anchorKey - Enterprise Knowledge anchor key
|
|
68
82
|
* @returns {string}
|
|
69
83
|
*/
|
|
@@ -71,19 +85,22 @@ function getEnterpriseKnowledgePath(anchorKey) {
|
|
|
71
85
|
if (!anchorKey || typeof anchorKey !== 'string') {
|
|
72
86
|
throw new Error('Anchor key is required and must be a string');
|
|
73
87
|
}
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
}
|
|
88
|
+
const disk = nodeFs();
|
|
89
|
+
const cwdRoot = getCwdEnterpriseKnowledgeRoot();
|
|
90
|
+
const matApp = path.join(getMaterializationParent(), WORKSPACE_ENTERPRISE_KNOWLEDGE, anchorKey);
|
|
91
|
+
if (cwdRoot) {
|
|
92
|
+
const cwdApp = path.join(cwdRoot, anchorKey);
|
|
93
|
+
if (isExistingDirectory(disk, cwdApp)) {
|
|
94
|
+
return cwdApp;
|
|
82
95
|
}
|
|
83
|
-
} catch {
|
|
84
|
-
// ignore
|
|
85
96
|
}
|
|
86
|
-
|
|
97
|
+
if (isExistingDirectory(disk, matApp)) {
|
|
98
|
+
return matApp;
|
|
99
|
+
}
|
|
100
|
+
if (cwdRoot) {
|
|
101
|
+
return path.join(cwdRoot, anchorKey);
|
|
102
|
+
}
|
|
103
|
+
return matApp;
|
|
87
104
|
}
|
|
88
105
|
|
|
89
106
|
function isEnterpriseKnowledgeDirectory(disk, fullPath) {
|