@aifabrix/builder 2.51.0 → 2.52.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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-container-start.js +4 -0
- package/lib/app/run-deploy-job.js +216 -0
- package/lib/app/run-env-compose.js +32 -0
- package/lib/app/run-env-recovery.js +35 -0
- package/lib/app/run-helpers.js +15 -9
- package/lib/app/run.js +18 -2
- package/lib/channels/add-channel.js +54 -23
- package/lib/channels/approval-guides/chatgpt.js +13 -9
- 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 +25 -1
- 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/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.js +4 -0
- package/lib/cli/setup-app.test-commands.js +59 -28
- package/lib/cli/setup-external-system-help.js +8 -2
- package/lib/cli/setup-external-system.js +62 -12
- package/lib/commands/app-test.js +2 -14
- package/lib/commands/channel-add-setup.js +8 -2
- package/lib/commands/channel.js +16 -5
- package/lib/commands/datasource-load-export-cli.js +6 -1
- package/lib/commands/deploy-gate-failure-details.js +19 -17
- package/lib/commands/deploy-gate-orchestrator.js +3 -2
- 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/governance-verify-external.js +2 -5
- package/lib/commands/lifecycle-external.js +21 -8
- 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 +371 -0
- 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 +25 -7
- 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 +31 -10
- 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/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-identifier.js +4 -3
- package/lib/datasource/datasource-validate-summary.js +2 -2
- 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/datasource/validate.js +13 -6
- package/lib/external-system/deploy-helpers.js +39 -1
- package/lib/external-system/deploy.js +25 -11
- 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-system-level.js +21 -3
- package/lib/external-system/test.js +43 -7
- package/lib/generator/builders.js +12 -15
- 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-markdown-frontmatter.js +75 -0
- package/lib/role-assistant/knowledge-sync.js +485 -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 +221 -0
- package/lib/role-assistant/test-runner-workhub.js +399 -0
- package/lib/role-assistant/test-runner.js +500 -0
- package/lib/schema/application-schema.json +24 -28
- 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/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/certify-external-workspace.js +40 -0
- package/lib/utils/deployment-validation.js +28 -3
- package/lib/utils/docker-run-ephemeral.js +115 -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/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 +80 -38
- package/lib/utils/pipeline-upload-auth-retry.js +15 -3
- package/lib/utils/role-assistant-paths.js +160 -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/upload-sync-options.js +7 -4
- package/lib/utils/url-declarative-resolve-load-doc.js +38 -1
- package/lib/validation/external-manifest-validator.js +31 -8
- package/lib/validation/reserved-system-key-prefixes.js +56 -0
- package/lib/validation/validate-external-file.js +8 -1
- package/lib/validation/validate.js +54 -19
- package/package.json +2 -1
- package/scripts/export-builder-api-evidence.js +1 -1
- package/templates/applications/builder-api/application.yaml +3 -3
- package/templates/applications/dataplane/application.yaml +24 -17
- package/templates/applications/dataplane/env.template +2 -2
- package/templates/applications/dataplane/rbac.yaml +24 -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 +17 -2
- package/templates/channels/chatgpt/install.template.md.hbs +82 -26
- package/templates/channels/chatgpt/integration/README.md +11 -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/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/.cursor/plans/{157.1-security-quality-violations-by-type.csv → Done/157.1-security-quality-violations-by-type.csv} +0 -0
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Role Assistant workspace path helpers.
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Paths under role-assistant/ for Role Assistant packages
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.1.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const path = require('path');
|
|
12
|
+
const os = require('os');
|
|
13
|
+
const { nodeFs } = require('../internal/node-fs');
|
|
14
|
+
|
|
15
|
+
const WORKSPACE_ROLE_ASSISTANT = 'role-assistant';
|
|
16
|
+
const SYSTEM_KIND_DIGITAL_WORKER = 'digitalWorker';
|
|
17
|
+
const ROLE_ASSISTANT_SYSTEM_PREFIX = 'ra-';
|
|
18
|
+
|
|
19
|
+
function getMaterializationParent() {
|
|
20
|
+
const work = process.env.AIFABRIX_WORK;
|
|
21
|
+
if (work && typeof work === 'string' && work.trim()) {
|
|
22
|
+
return path.resolve(work.trim());
|
|
23
|
+
}
|
|
24
|
+
if (process.env.AIFABRIX_HOME && typeof process.env.AIFABRIX_HOME === 'string') {
|
|
25
|
+
return path.resolve(process.env.AIFABRIX_HOME.trim());
|
|
26
|
+
}
|
|
27
|
+
return path.join(os.homedir(), '.aifabrix');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function getCwdRoleAssistantRoot() {
|
|
31
|
+
const p = path.join(path.resolve(process.cwd()), WORKSPACE_ROLE_ASSISTANT);
|
|
32
|
+
try {
|
|
33
|
+
const disk = nodeFs();
|
|
34
|
+
if (disk.existsSync(p)) {
|
|
35
|
+
const st = disk.statSync(p);
|
|
36
|
+
if (st && typeof st.isDirectory === 'function' && st.isDirectory()) {
|
|
37
|
+
return p;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
} catch {
|
|
41
|
+
// ignore
|
|
42
|
+
}
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function getRoleAssistantRoot() {
|
|
47
|
+
const cwdRoot = getCwdRoleAssistantRoot();
|
|
48
|
+
if (cwdRoot) {
|
|
49
|
+
return cwdRoot;
|
|
50
|
+
}
|
|
51
|
+
return path.join(getMaterializationParent(), WORKSPACE_ROLE_ASSISTANT);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function isExistingDirectory(disk, dirPath) {
|
|
55
|
+
try {
|
|
56
|
+
if (!dirPath || !disk.existsSync(dirPath)) {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
const st = disk.statSync(dirPath);
|
|
60
|
+
return Boolean(st && typeof st.isDirectory === 'function' && st.isDirectory());
|
|
61
|
+
} catch {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
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.
|
|
125
|
+
* @param {string} roleKey
|
|
126
|
+
* @returns {string}
|
|
127
|
+
*/
|
|
128
|
+
function getRoleAssistantPath(roleKey) {
|
|
129
|
+
if (!roleKey || typeof roleKey !== 'string') {
|
|
130
|
+
throw new Error('Role key is required and must be a string');
|
|
131
|
+
}
|
|
132
|
+
const disk = nodeFs();
|
|
133
|
+
const folders = roleAssistantFolderCandidates(roleKey);
|
|
134
|
+
const preferred = roleAssistantSystemKey(roleKey);
|
|
135
|
+
const cwdRoot = getCwdRoleAssistantRoot();
|
|
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;
|
|
143
|
+
}
|
|
144
|
+
if (cwdRoot) {
|
|
145
|
+
return path.join(cwdRoot, preferred);
|
|
146
|
+
}
|
|
147
|
+
return path.join(matRoot, preferred);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
module.exports = {
|
|
151
|
+
WORKSPACE_ROLE_ASSISTANT,
|
|
152
|
+
SYSTEM_KIND_DIGITAL_WORKER,
|
|
153
|
+
ROLE_ASSISTANT_SYSTEM_PREFIX,
|
|
154
|
+
getCwdRoleAssistantRoot,
|
|
155
|
+
getRoleAssistantRoot,
|
|
156
|
+
getRoleAssistantPath,
|
|
157
|
+
bareRoleKey,
|
|
158
|
+
roleAssistantSystemKey,
|
|
159
|
+
roleAssistantFolderCandidates
|
|
160
|
+
};
|
|
@@ -18,6 +18,7 @@ const addFormats = require('ajv-formats');
|
|
|
18
18
|
// These are reset when module is reloaded (for testing)
|
|
19
19
|
let externalSystemValidator = null;
|
|
20
20
|
let externalDataSourceValidator = null;
|
|
21
|
+
let roleAssistantSettingsValidator = null;
|
|
21
22
|
|
|
22
23
|
/**
|
|
23
24
|
* Reset validators cache (for testing)
|
|
@@ -26,6 +27,7 @@ let externalDataSourceValidator = null;
|
|
|
26
27
|
function resetValidators() {
|
|
27
28
|
externalSystemValidator = null;
|
|
28
29
|
externalDataSourceValidator = null;
|
|
30
|
+
roleAssistantSettingsValidator = null;
|
|
29
31
|
}
|
|
30
32
|
|
|
31
33
|
/**
|
|
@@ -138,6 +140,38 @@ function loadExternalDataSourceSchema() {
|
|
|
138
140
|
return externalDataSourceValidator;
|
|
139
141
|
}
|
|
140
142
|
|
|
143
|
+
/**
|
|
144
|
+
* Loads and compiles role-assistant settings schema.
|
|
145
|
+
* @function loadRoleAssistantSettingsSchema
|
|
146
|
+
* @returns {Function}
|
|
147
|
+
*/
|
|
148
|
+
function loadRoleAssistantSettingsSchema() {
|
|
149
|
+
if (roleAssistantSettingsValidator) {
|
|
150
|
+
return roleAssistantSettingsValidator;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const schemaPath = path.join(__dirname, '..', 'schema', 'role-assistant-settings.schema.json');
|
|
154
|
+
let schema;
|
|
155
|
+
try {
|
|
156
|
+
const schemaContent = fsRealSync.readFileSync(schemaPath, 'utf8');
|
|
157
|
+
schema = JSON.parse(schemaContent);
|
|
158
|
+
} catch (error) {
|
|
159
|
+
try {
|
|
160
|
+
schema = require('../schema/role-assistant-settings.schema.json');
|
|
161
|
+
} catch {
|
|
162
|
+
if (error && error.code === 'ENOENT') {
|
|
163
|
+
throw new Error(`Role assistant settings schema not found: ${schemaPath}`);
|
|
164
|
+
}
|
|
165
|
+
throw new Error(`Invalid JSON in role-assistant-settings.schema.json: ${error.message}`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const ajv = new Ajv({ allErrors: true, strict: false, strictSchema: false });
|
|
170
|
+
addFormats(ajv);
|
|
171
|
+
roleAssistantSettingsValidator = ajv.compile(schema);
|
|
172
|
+
return roleAssistantSettingsValidator;
|
|
173
|
+
}
|
|
174
|
+
|
|
141
175
|
/**
|
|
142
176
|
* Detect schema type from $id field
|
|
143
177
|
* @param {Object} parsed - Parsed JSON object
|
|
@@ -157,6 +191,9 @@ function detectFromId(parsed) {
|
|
|
157
191
|
if (parsed.$id.includes('application-schema')) {
|
|
158
192
|
return 'application';
|
|
159
193
|
}
|
|
194
|
+
if (parsed.$id.includes('role-assistant-settings')) {
|
|
195
|
+
return 'role-assistant-settings';
|
|
196
|
+
}
|
|
160
197
|
|
|
161
198
|
return null;
|
|
162
199
|
}
|
|
@@ -239,6 +276,9 @@ function detectFromApplicationFields(parsed) {
|
|
|
239
276
|
*/
|
|
240
277
|
function detectFromFilename(filePath) {
|
|
241
278
|
const fileName = path.basename(filePath).toLowerCase();
|
|
279
|
+
if (fileName === 'role-assistant.yaml' || fileName === 'role-assistant.yml') {
|
|
280
|
+
return 'role-assistant-settings';
|
|
281
|
+
}
|
|
242
282
|
if (fileName.includes('external-system') || fileName.includes('external_system')) {
|
|
243
283
|
return 'external-system';
|
|
244
284
|
}
|
|
@@ -347,6 +387,7 @@ function detectSchemaType(filePath, content) {
|
|
|
347
387
|
module.exports = {
|
|
348
388
|
loadExternalSystemSchema,
|
|
349
389
|
loadExternalDataSourceSchema,
|
|
390
|
+
loadRoleAssistantSettingsSchema,
|
|
350
391
|
registerExternalDatasourceAjvDependencies,
|
|
351
392
|
detectSchemaType,
|
|
352
393
|
detectSchemaTypeFromParsed,
|
|
@@ -175,6 +175,18 @@ function resolveDatasourceFiles(schemaBasePath, datasourceFiles) {
|
|
|
175
175
|
return datasourceFiles.map(fileName => resolveSingleExternalFile(schemaBasePath, fileName, 'datasource'));
|
|
176
176
|
}
|
|
177
177
|
|
|
178
|
+
function resolveRoleAssistantSettingsFile(appPath) {
|
|
179
|
+
const yamlPath = path.join(appPath, 'role-assistant.yaml');
|
|
180
|
+
if (fs.existsSync(yamlPath)) {
|
|
181
|
+
return resolveSingleExternalFile(appPath, 'role-assistant.yaml', 'role-assistant-settings');
|
|
182
|
+
}
|
|
183
|
+
const ymlPath = path.join(appPath, 'role-assistant.yml');
|
|
184
|
+
if (fs.existsSync(ymlPath)) {
|
|
185
|
+
return resolveSingleExternalFile(appPath, 'role-assistant.yml', 'role-assistant-settings');
|
|
186
|
+
}
|
|
187
|
+
return resolveSingleExternalFile(appPath, 'role-assistant.yaml', 'role-assistant-settings');
|
|
188
|
+
}
|
|
189
|
+
|
|
178
190
|
/**
|
|
179
191
|
* @param {string} schemaBasePath
|
|
180
192
|
* @param {string[]} systemFileNames
|
|
@@ -282,6 +294,21 @@ async function loadAndValidateVariables(appPath) {
|
|
|
282
294
|
}
|
|
283
295
|
}
|
|
284
296
|
|
|
297
|
+
function readSystemKindFromFirstSystemFile(schemaBasePath, systemFileNames) {
|
|
298
|
+
if (!systemFileNames.length) {
|
|
299
|
+
return '';
|
|
300
|
+
}
|
|
301
|
+
try {
|
|
302
|
+
const firstSystemPath = path.join(schemaBasePath, systemFileNames[0]);
|
|
303
|
+
const parsedSystem = loadConfigFile(firstSystemPath);
|
|
304
|
+
return parsedSystem && typeof parsedSystem.systemKind === 'string'
|
|
305
|
+
? parsedSystem.systemKind
|
|
306
|
+
: '';
|
|
307
|
+
} catch {
|
|
308
|
+
return '';
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
285
312
|
async function resolveExternalFiles(appName, options = {}) {
|
|
286
313
|
if (!appName || typeof appName !== 'string') {
|
|
287
314
|
throw new Error('App name is required and must be a string');
|
|
@@ -295,15 +322,20 @@ async function resolveExternalFiles(appName, options = {}) {
|
|
|
295
322
|
}
|
|
296
323
|
|
|
297
324
|
const schemaBasePath = await resolveSchemaBasePath(appName, options);
|
|
298
|
-
const
|
|
325
|
+
const systemFileNames = variables.externalIntegration.systems || [];
|
|
326
|
+
const systemFiles = resolveSystemFiles(schemaBasePath, systemFileNames);
|
|
327
|
+
const systemKind = readSystemKindFromFirstSystemFile(schemaBasePath, systemFileNames);
|
|
299
328
|
const orderedNames = orderDatasourceFileNamesBySystemKeys(
|
|
300
329
|
schemaBasePath,
|
|
301
|
-
|
|
330
|
+
systemFileNames,
|
|
302
331
|
variables.externalIntegration.dataSources || []
|
|
303
332
|
);
|
|
304
333
|
const datasourceFiles = resolveDatasourceFiles(schemaBasePath, orderedNames);
|
|
305
|
-
|
|
306
|
-
|
|
334
|
+
const extraFiles = [];
|
|
335
|
+
if (String(systemKind).trim() === 'digitalWorker') {
|
|
336
|
+
extraFiles.push(resolveRoleAssistantSettingsFile(appPath));
|
|
337
|
+
}
|
|
338
|
+
return [...systemFiles, ...datasourceFiles, ...extraFiles];
|
|
307
339
|
}
|
|
308
340
|
|
|
309
341
|
module.exports = {
|
|
@@ -408,53 +408,62 @@ function applyLabDataplaneApiKeyBearer(authConfig) {
|
|
|
408
408
|
return authConfig;
|
|
409
409
|
}
|
|
410
410
|
|
|
411
|
+
function looksLikeJwtBearer(token) {
|
|
412
|
+
const existing = token ? String(token) : '';
|
|
413
|
+
return existing.split('.').length === 3 && existing.length > 80;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
function preferClientCredentialsDeploymentAuth() {
|
|
417
|
+
return String(process.env.AIFABRIX_DEPLOYMENT_AUTH || '').toLowerCase() === 'client-credentials';
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* @param {Object} authConfig
|
|
422
|
+
* @returns {boolean} true when a substitution was applied
|
|
423
|
+
*/
|
|
424
|
+
function trySubstituteEnvApiKeyBearer(authConfig) {
|
|
425
|
+
if (!process.env.API_KEY) {
|
|
426
|
+
return false;
|
|
427
|
+
}
|
|
428
|
+
const apiKey = String(process.env.API_KEY);
|
|
429
|
+
if (authConfig.type === 'bearer' && authConfig.token !== apiKey) {
|
|
430
|
+
authConfig.token = apiKey;
|
|
431
|
+
return true;
|
|
432
|
+
}
|
|
433
|
+
if (authConfig.type === 'client-token') {
|
|
434
|
+
authConfig.type = 'bearer';
|
|
435
|
+
authConfig.token = apiKey;
|
|
436
|
+
return true;
|
|
437
|
+
}
|
|
438
|
+
if (!authConfig.token) {
|
|
439
|
+
authConfig.type = 'bearer';
|
|
440
|
+
authConfig.token = apiKey;
|
|
441
|
+
return true;
|
|
442
|
+
}
|
|
443
|
+
return false;
|
|
444
|
+
}
|
|
445
|
+
|
|
411
446
|
function requireBearerForDataplanePipeline(authConfig) {
|
|
412
447
|
if (!authConfig || typeof authConfig !== 'object') {
|
|
413
448
|
return;
|
|
414
449
|
}
|
|
415
|
-
|
|
416
450
|
if (authConfig.type === 'client-token' && authConfig.token) {
|
|
417
451
|
return;
|
|
418
452
|
}
|
|
419
|
-
|
|
420
453
|
// Token-forward (builder-api / bearerForward): never substitute lab API_KEY for the caller JWT.
|
|
421
454
|
if (authConfig.preserveBearer && authConfig.token) {
|
|
422
455
|
return;
|
|
423
456
|
}
|
|
424
|
-
|
|
425
|
-
const preferAppClientToken =
|
|
426
|
-
String(process.env.AIFABRIX_DEPLOYMENT_AUTH || '').toLowerCase() === 'client-credentials';
|
|
427
|
-
|
|
428
|
-
const existing = authConfig.token ? String(authConfig.token) : '';
|
|
429
|
-
const looksLikeJwt = existing.split('.').length === 3 && existing.length > 80;
|
|
430
457
|
// Enterprise path: keep a real OAuth JWT; do not overwrite with process.env.API_KEY.
|
|
431
|
-
if (
|
|
458
|
+
if (looksLikeJwtBearer(authConfig.token)) {
|
|
432
459
|
return;
|
|
433
460
|
}
|
|
434
|
-
|
|
435
|
-
if (!preferAppClientToken && process.env.API_KEY) {
|
|
436
|
-
const apiKey = String(process.env.API_KEY);
|
|
437
|
-
if (authConfig.type === 'bearer' && authConfig.token !== apiKey) {
|
|
438
|
-
authConfig.token = apiKey;
|
|
439
|
-
return;
|
|
440
|
-
}
|
|
441
|
-
if (authConfig.type === 'client-token') {
|
|
442
|
-
authConfig.type = 'bearer';
|
|
443
|
-
authConfig.token = apiKey;
|
|
444
|
-
return;
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
if (authConfig.token) {
|
|
461
|
+
if (!preferClientCredentialsDeploymentAuth() && trySubstituteEnvApiKeyBearer(authConfig)) {
|
|
449
462
|
return;
|
|
450
463
|
}
|
|
451
|
-
|
|
452
|
-
if (!preferAppClientToken && process.env.API_KEY) {
|
|
453
|
-
authConfig.type = 'bearer';
|
|
454
|
-
authConfig.token = String(process.env.API_KEY);
|
|
464
|
+
if (authConfig.token) {
|
|
455
465
|
return;
|
|
456
466
|
}
|
|
457
|
-
|
|
458
467
|
if (authConfig.clientId || authConfig.clientSecret) {
|
|
459
468
|
throw new Error(
|
|
460
469
|
'Dataplane pipeline endpoints require OAuth2 (Bearer token) or x-client-token. ' +
|
|
@@ -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;
|
|
@@ -25,6 +25,42 @@ function tryReadApplicationYamlAt(cfgPath) {
|
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
/**
|
|
29
|
+
* @param {unknown} value
|
|
30
|
+
* @returns {boolean}
|
|
31
|
+
*/
|
|
32
|
+
function isPositivePortValue(value) {
|
|
33
|
+
if (typeof value === 'number' && value > 0) {
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
return typeof value === 'string' && /^\d+$/.test(String(value).trim());
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* True when a manifest can authoritatively supply listen/port for url:// expansion.
|
|
41
|
+
* External-system `application.json` (upload payload) has no HTTP listen port — using it
|
|
42
|
+
* for `url://builder-api-internal` falls through to {@link DECLARATIVE_URL_INFRA_DEFAULTS}
|
|
43
|
+
* (3000) and breaks Docker CIP against the real builder-api container (3005).
|
|
44
|
+
*
|
|
45
|
+
* @param {object|null|undefined} doc
|
|
46
|
+
* @returns {boolean}
|
|
47
|
+
*/
|
|
48
|
+
function isDeclarativeUrlPortAuthorityDoc(doc) {
|
|
49
|
+
if (!doc || typeof doc !== 'object') {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
if ((doc.app && doc.app.type) === 'external') {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
if (doc.externalIntegration && typeof doc.externalIntegration === 'object') {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
return (
|
|
59
|
+
isPositivePortValue(doc.port) ||
|
|
60
|
+
isPositivePortValue(doc.build && doc.build.containerPort)
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
28
64
|
/**
|
|
29
65
|
* Candidate paths for cross-app url:// resolution (low → high priority).
|
|
30
66
|
* Platform system apps prefer materialized `~/.aifabrix-work|home/builder` over CLI package `builder/` stubs.
|
|
@@ -83,7 +119,7 @@ function loadApplicationYamlDocForUrlResolve(appKey, ctx, pathsUtil) {
|
|
|
83
119
|
if (appKey === current && ctx.variablesPath) {
|
|
84
120
|
const vp = path.resolve(String(ctx.variablesPath));
|
|
85
121
|
const fromVars = tryReadApplicationYamlAt(vp);
|
|
86
|
-
if (fromVars) {
|
|
122
|
+
if (isDeclarativeUrlPortAuthorityDoc(fromVars)) {
|
|
87
123
|
return fromVars;
|
|
88
124
|
}
|
|
89
125
|
}
|
|
@@ -105,5 +141,6 @@ function loadApplicationYamlDocForUrlResolve(appKey, ctx, pathsUtil) {
|
|
|
105
141
|
|
|
106
142
|
module.exports = {
|
|
107
143
|
collectApplicationYamlPathsForUrlResolve,
|
|
144
|
+
isDeclarativeUrlPortAuthorityDoc,
|
|
108
145
|
loadApplicationYamlDocForUrlResolve
|
|
109
146
|
};
|
|
@@ -217,6 +217,36 @@ function validateDatasourceSystemKeyAlignment(manifest, errors) {
|
|
|
217
217
|
});
|
|
218
218
|
}
|
|
219
219
|
|
|
220
|
+
/**
|
|
221
|
+
* Vendor OpenAPI contract surface is for Connected Systems. Role Assistants
|
|
222
|
+
* (digitalWorker) promote settings + Evidence — skip blocking OpenAPI vendor checks.
|
|
223
|
+
* @param {Object} manifest
|
|
224
|
+
* @param {Object} options
|
|
225
|
+
* @param {string[]} errors
|
|
226
|
+
* @param {string[]} warnings
|
|
227
|
+
*/
|
|
228
|
+
function applyExternalContractSurfaceChecks(manifest, options, errors, warnings) {
|
|
229
|
+
if (manifest.type !== 'external' || !Array.isArray(manifest.dataSources) || !manifest.system?.key) {
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
const appPath = options.appPath;
|
|
233
|
+
if (typeof appPath !== 'string' || !appPath) {
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
const systemKind =
|
|
237
|
+
typeof manifest.system.systemKind === 'string' ? manifest.system.systemKind.trim() : '';
|
|
238
|
+
if (systemKind === 'digitalWorker') {
|
|
239
|
+
warnings.push(
|
|
240
|
+
'Role Assistant (digitalWorker): vendor OpenAPI contract checks skipped ' +
|
|
241
|
+
'(settings + evidence path; run repair --api only when binding vendor OpenAPI).'
|
|
242
|
+
);
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
const contract = validateAppContractSurface(appPath, manifest.system.key, manifest.dataSources);
|
|
246
|
+
errors.push(...contract.errors);
|
|
247
|
+
warnings.push(...contract.warnings);
|
|
248
|
+
}
|
|
249
|
+
|
|
220
250
|
/**
|
|
221
251
|
* Validates controller deployment manifest for external systems
|
|
222
252
|
* Validates manifest structure and inline system/dataSources against their schemas
|
|
@@ -251,14 +281,7 @@ async function validateControllerManifest(manifest, options = {}) {
|
|
|
251
281
|
validateDatasources(manifest, ajv, externalDatasourceSchema, errors, warnings);
|
|
252
282
|
validateDatasourceSystemKeyAlignment(manifest, errors);
|
|
253
283
|
errors.push(...validateManifestRuntimeConfiguration(manifest));
|
|
254
|
-
|
|
255
|
-
const appPath = options.appPath;
|
|
256
|
-
if (typeof appPath === 'string' && appPath) {
|
|
257
|
-
const contract = validateAppContractSurface(appPath, manifest.system.key, manifest.dataSources);
|
|
258
|
-
errors.push(...contract.errors);
|
|
259
|
-
warnings.push(...contract.warnings);
|
|
260
|
-
}
|
|
261
|
-
}
|
|
284
|
+
applyExternalContractSurfaceChecks(manifest, options, errors, warnings);
|
|
262
285
|
validateConditionalRequirements(manifest, errors, warnings);
|
|
263
286
|
validateRequiredFields(manifest, errors);
|
|
264
287
|
|
|
@@ -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
|
+
};
|
|
@@ -10,7 +10,11 @@
|
|
|
10
10
|
|
|
11
11
|
const fs = require('fs');
|
|
12
12
|
const yaml = require('js-yaml');
|
|
13
|
-
const {
|
|
13
|
+
const {
|
|
14
|
+
loadExternalSystemSchema,
|
|
15
|
+
loadExternalDataSourceSchema,
|
|
16
|
+
loadRoleAssistantSettingsSchema
|
|
17
|
+
} = require('../utils/schema-loader');
|
|
14
18
|
const { formatValidationErrors } = require('../utils/error-formatter');
|
|
15
19
|
const { validateFieldReferences } = require('../datasource/field-reference-validator');
|
|
16
20
|
const { validateAbac } = require('../datasource/abac-validator');
|
|
@@ -53,6 +57,9 @@ function getValidatorForType(normalizedType) {
|
|
|
53
57
|
if (normalizedType === 'datasource') {
|
|
54
58
|
return loadExternalDataSourceSchema();
|
|
55
59
|
}
|
|
60
|
+
if (normalizedType === 'role-assistant-settings') {
|
|
61
|
+
return loadRoleAssistantSettingsSchema();
|
|
62
|
+
}
|
|
56
63
|
throw new Error(`Unknown file type: ${normalizedType}`);
|
|
57
64
|
}
|
|
58
65
|
|