@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,371 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Role Assistant CLI command group.
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview role-assistant test command with portal deep-link output
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const logger = require('../utils/logger');
|
|
12
|
+
const { handleCommandError } = require('../utils/cli-utils');
|
|
13
|
+
const {
|
|
14
|
+
runLifecycleForExternalSystem,
|
|
15
|
+
resolveLifecycleAuth
|
|
16
|
+
} = require('./lifecycle-external');
|
|
17
|
+
const { lifecycleVerdictFromReport } = require('./lifecycle-command-action');
|
|
18
|
+
const { buildExternalSystemUiUrl } = require('../lifecycle/dataplane-ui-url');
|
|
19
|
+
const { VERDICT } = require('../lifecycle/product-model');
|
|
20
|
+
const { exitCodeFromVerdict } = require('../lifecycle/exit-codes');
|
|
21
|
+
const {
|
|
22
|
+
loadRoleAssistantTestCase,
|
|
23
|
+
evaluateRoleAssistantTestCase
|
|
24
|
+
} = require('../role-assistant/test-cases');
|
|
25
|
+
const {
|
|
26
|
+
isExecutableRoleAssistantCase,
|
|
27
|
+
runRoleAssistantCaseLifecycle,
|
|
28
|
+
mergeCaseExecutionIntoLifecycleResult,
|
|
29
|
+
lifecycleVerdictFromCaseExecution
|
|
30
|
+
} = require('../role-assistant/test-runner');
|
|
31
|
+
const { collectString } = require('./governance');
|
|
32
|
+
const {
|
|
33
|
+
sectionTitle,
|
|
34
|
+
headerKeyValue,
|
|
35
|
+
formatSuccessLine,
|
|
36
|
+
formatSuccessParagraph,
|
|
37
|
+
formatWarningLine,
|
|
38
|
+
formatBlockingError,
|
|
39
|
+
metadata
|
|
40
|
+
} = require('../utils/cli-test-layout-chalk');
|
|
41
|
+
const {
|
|
42
|
+
bareRoleKey,
|
|
43
|
+
roleAssistantSystemKey
|
|
44
|
+
} = require('../utils/role-assistant-paths');
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Bucket a lifecycle step status into ok | failed | skipped | other.
|
|
48
|
+
* @param {string} status
|
|
49
|
+
* @returns {'ok'|'failed'|'skipped'|'other'}
|
|
50
|
+
*/
|
|
51
|
+
function bucketStepStatus(status) {
|
|
52
|
+
const normalized = String(status || 'ok').toLowerCase();
|
|
53
|
+
if (normalized === 'ok' || normalized === 'verified' || normalized === 'passed') {
|
|
54
|
+
return 'ok';
|
|
55
|
+
}
|
|
56
|
+
if (normalized === 'failed' || normalized === 'error') {
|
|
57
|
+
return 'failed';
|
|
58
|
+
}
|
|
59
|
+
if (normalized === 'skipped' || normalized === 'n/a' || normalized === 'not_applicable') {
|
|
60
|
+
return 'skipped';
|
|
61
|
+
}
|
|
62
|
+
return 'other';
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Summarize lifecycle stepsRun rows (API uses step/status/datasourceKey, not pillar).
|
|
67
|
+
* @param {Array<Object|string>} steps
|
|
68
|
+
* @returns {string}
|
|
69
|
+
*/
|
|
70
|
+
function formatStepsRunSummary(steps) {
|
|
71
|
+
const byStep = Object.create(null);
|
|
72
|
+
for (const row of steps) {
|
|
73
|
+
if (!row || typeof row !== 'object') {
|
|
74
|
+
const label = String(row);
|
|
75
|
+
byStep[label] = byStep[label] || { ok: 0, failed: 0, skipped: 0, other: 0 };
|
|
76
|
+
byStep[label].other += 1;
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
const stepName = String(row.step || row.pillar || row.name || 'step').trim() || 'step';
|
|
80
|
+
const status = row.status || (row.success === false ? 'failed' : 'ok');
|
|
81
|
+
byStep[stepName] = byStep[stepName] || { ok: 0, failed: 0, skipped: 0, other: 0 };
|
|
82
|
+
byStep[stepName][bucketStepStatus(status)] += 1;
|
|
83
|
+
}
|
|
84
|
+
return Object.keys(byStep)
|
|
85
|
+
.map((stepName) => {
|
|
86
|
+
const counts = byStep[stepName];
|
|
87
|
+
const parts = [];
|
|
88
|
+
if (counts.ok) parts.push(`${counts.ok} ok`);
|
|
89
|
+
if (counts.failed) parts.push(`${counts.failed} failed`);
|
|
90
|
+
if (counts.skipped) parts.push(`${counts.skipped} skipped`);
|
|
91
|
+
if (counts.other) parts.push(`${counts.other} other`);
|
|
92
|
+
return parts.length > 0 ? `${stepName} (${parts.join(', ')})` : stepName;
|
|
93
|
+
})
|
|
94
|
+
.join('; ');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function roleAssistantHelpAfter() {
|
|
98
|
+
return `
|
|
99
|
+
Examples:
|
|
100
|
+
$ aifabrix role-assistant test customer-support-bot
|
|
101
|
+
$ aifabrix role-assistant test customer-support-bot --case smoke
|
|
102
|
+
$ aifabrix role-assistant test customer-support-bot --case tests/customer-address-change.yaml
|
|
103
|
+
$ aifabrix role-assistant test customer-support-bot --subject-email ops@example.com
|
|
104
|
+
$ aifabrix role-assistant test customer-support-bot --json
|
|
105
|
+
$ aifabrix role-assistant test customer-support-bot --publish --force
|
|
106
|
+
|
|
107
|
+
Notes:
|
|
108
|
+
- Uses the public/running Role Assistant on the dataplane by default (does not publish local datasources).
|
|
109
|
+
- Use \`aifabrix upload <roleKey> --env …\` (or \`--publish\`) when you intentionally refresh the package.
|
|
110
|
+
- Runs lifecycle checks, then prints a portal deep link for full step-by-step status.
|
|
111
|
+
- Case files with input.message/input.content execute Work Hub plan→accept (or work.start when executionPath: intent).
|
|
112
|
+
- answers[] and approvals[] are matched to runtime wait payloads (questionKey/requestKey/waitReason).
|
|
113
|
+
- Use the portal URL for detailed human review while automation reads CLI/JSON output.
|
|
114
|
+
`;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function rawArgsInclude(cmd, flag) {
|
|
118
|
+
const raw = cmd && Array.isArray(cmd.rawArgs) ? cmd.rawArgs : [];
|
|
119
|
+
return raw.includes(flag);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function optionOrFlag(options, key, cmd, ...flags) {
|
|
123
|
+
if (options[key] === true) {
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
return flags.some((flag) => rawArgsInclude(cmd, flag));
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function trimOptionalString(value) {
|
|
130
|
+
return value ? String(value).trim() : '';
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function normalizeRoleAssistantTestOptions(options, cmd) {
|
|
134
|
+
// Role Assistant test uses the public/running digital worker by default.
|
|
135
|
+
// Opt in to publish with --publish (optional --force).
|
|
136
|
+
const wantsPublish = optionOrFlag(options, 'publish', cmd, '--publish');
|
|
137
|
+
return {
|
|
138
|
+
env: options.env || 'dev',
|
|
139
|
+
verbose: optionOrFlag(options, 'verbose', cmd, '-v', '--verbose'),
|
|
140
|
+
debug: optionOrFlag(options, 'debug', cmd, '-d', '--debug'),
|
|
141
|
+
json: optionOrFlag(options, 'json', cmd, '--json'),
|
|
142
|
+
noPublish: !wantsPublish,
|
|
143
|
+
force: optionOrFlag(options, 'force', cmd, '--force'),
|
|
144
|
+
subjectUserId: options.subjectUserId || [],
|
|
145
|
+
subjectEmail: options.subjectEmail || [],
|
|
146
|
+
certificationProfile: options.certificationProfile || 'bronze',
|
|
147
|
+
case: trimOptionalString(options.case),
|
|
148
|
+
testsDir: trimOptionalString(options.testsDir),
|
|
149
|
+
run: true
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function buildRoleAssistantTestEnvelope(roleKey, verdict, portalUrl, result, opts, caseResult = null) {
|
|
154
|
+
const report = result.report || {};
|
|
155
|
+
const envelope = {
|
|
156
|
+
roleKey,
|
|
157
|
+
command: 'role-assistant test',
|
|
158
|
+
verdict,
|
|
159
|
+
portalUrl,
|
|
160
|
+
openApiPublished: result.openApiPublished === true,
|
|
161
|
+
certification: report.certification || null,
|
|
162
|
+
recommendations: Array.isArray(report.recommendations) ? report.recommendations : [],
|
|
163
|
+
warnings: Array.isArray(report.warnings) ? report.warnings : [],
|
|
164
|
+
stepsRun: result.stepsRun || [],
|
|
165
|
+
case: caseResult
|
|
166
|
+
? {
|
|
167
|
+
caseId: caseResult.caseId,
|
|
168
|
+
sourceFile: caseResult.sourceFile,
|
|
169
|
+
passed: caseResult.passed,
|
|
170
|
+
lifecycleState: caseResult.lifecycleState,
|
|
171
|
+
assertions: caseResult.assertions,
|
|
172
|
+
failedAssertions: caseResult.failedAssertions,
|
|
173
|
+
warnings: Array.isArray(caseResult.warnings) ? caseResult.warnings : [],
|
|
174
|
+
execution: caseResult.execution || null
|
|
175
|
+
}
|
|
176
|
+
: null
|
|
177
|
+
};
|
|
178
|
+
if (opts.verbose || opts.debug) {
|
|
179
|
+
envelope.report = report;
|
|
180
|
+
}
|
|
181
|
+
if (opts.debug) {
|
|
182
|
+
envelope.debug = {
|
|
183
|
+
observation: caseResult ? caseResult.observation : null,
|
|
184
|
+
lifecycleResult: result
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
return envelope;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function displayCaseResultSummary(caseResult) {
|
|
191
|
+
if (!caseResult) {
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
logger.log(headerKeyValue('Case:', caseResult.caseId));
|
|
195
|
+
logger.log(headerKeyValue('Case file:', caseResult.sourceFile));
|
|
196
|
+
logger.log(headerKeyValue('Observed state:', caseResult.lifecycleState));
|
|
197
|
+
if (caseResult.execution) {
|
|
198
|
+
logger.log(headerKeyValue('Execution id:', caseResult.execution.processExecutionId || 'n/a'));
|
|
199
|
+
logger.log(headerKeyValue('Final runtime status:', caseResult.execution.finalStatus || 'n/a'));
|
|
200
|
+
}
|
|
201
|
+
if (caseResult.passed) {
|
|
202
|
+
logger.log(formatSuccessLine('Case assertions passed.'));
|
|
203
|
+
const warnings = Array.isArray(caseResult.warnings) ? caseResult.warnings : [];
|
|
204
|
+
for (const row of warnings) {
|
|
205
|
+
logger.log(formatWarningLine(row.message || String(row)));
|
|
206
|
+
}
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
logger.log(formatBlockingError('Case assertions failed.'));
|
|
210
|
+
for (const row of caseResult.failedAssertions) {
|
|
211
|
+
logger.log(formatWarningLine(row.message));
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function displayRoleAssistantTestSummary(roleKey, verdict, portalUrl, result, caseResult = null) {
|
|
216
|
+
logger.log('');
|
|
217
|
+
logger.log(sectionTitle(`${String(roleKey).toUpperCase()} ROLE ASSISTANT TEST`));
|
|
218
|
+
logger.log('');
|
|
219
|
+
logger.log(headerKeyValue('Role key:', roleKey));
|
|
220
|
+
if (portalUrl) {
|
|
221
|
+
logger.log(headerKeyValue('Portal:', portalUrl));
|
|
222
|
+
} else {
|
|
223
|
+
logger.log(formatWarningLine('Portal link unavailable. Configure dataplane public URL and retry.'));
|
|
224
|
+
}
|
|
225
|
+
const verdictMessage =
|
|
226
|
+
verdict === VERDICT.VERIFIED
|
|
227
|
+
? 'Lifecycle checks passed. Open portal for full execution steps and logs.'
|
|
228
|
+
: 'Lifecycle checks are not fully verified. Open portal to inspect blocking steps.';
|
|
229
|
+
if (verdict === VERDICT.VERIFIED) {
|
|
230
|
+
logger.log(formatSuccessParagraph(verdictMessage));
|
|
231
|
+
} else {
|
|
232
|
+
logger.log(formatWarningLine(verdictMessage));
|
|
233
|
+
}
|
|
234
|
+
const steps = Array.isArray(result.stepsRun) ? result.stepsRun : [];
|
|
235
|
+
if (steps.length > 0) {
|
|
236
|
+
logger.log(metadata(`Steps run: ${formatStepsRunSummary(steps)}`));
|
|
237
|
+
}
|
|
238
|
+
displayCaseResultSummary(caseResult);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
async function resolveRoleAssistantCaseResult(roleKey, opts, result, verdict, portalUrl) {
|
|
242
|
+
if (!opts.case) {
|
|
243
|
+
return null;
|
|
244
|
+
}
|
|
245
|
+
const roleCase = loadRoleAssistantTestCase(roleKey, opts.case, {
|
|
246
|
+
testsDir: opts.testsDir || null
|
|
247
|
+
});
|
|
248
|
+
if (!isExecutableRoleAssistantCase(roleCase)) {
|
|
249
|
+
return evaluateRoleAssistantTestCase(roleCase, result, verdict, portalUrl);
|
|
250
|
+
}
|
|
251
|
+
const authContext = await resolveLifecycleAuth(roleKey, {
|
|
252
|
+
...opts,
|
|
253
|
+
run: false,
|
|
254
|
+
noPublish: true
|
|
255
|
+
});
|
|
256
|
+
const executionResult = await runRoleAssistantCaseLifecycle(roleKey, roleCase, authContext, opts);
|
|
257
|
+
const executionVerdict = lifecycleVerdictFromCaseExecution(executionResult, verdict);
|
|
258
|
+
const evaluationInput = mergeCaseExecutionIntoLifecycleResult(result, executionResult);
|
|
259
|
+
const evaluation = evaluateRoleAssistantTestCase(
|
|
260
|
+
roleCase,
|
|
261
|
+
evaluationInput,
|
|
262
|
+
executionVerdict,
|
|
263
|
+
portalUrl
|
|
264
|
+
);
|
|
265
|
+
evaluation.execution = {
|
|
266
|
+
processExecutionId: executionResult.processExecutionId || null,
|
|
267
|
+
finalStatus: executionResult.finalStatus?.status || null,
|
|
268
|
+
waitReason: executionResult.finalStatus?.wait?.waitReason || null,
|
|
269
|
+
interactions: executionResult.interactions || [],
|
|
270
|
+
workResultError: executionResult.workResultError || null
|
|
271
|
+
};
|
|
272
|
+
return evaluation;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function computeRoleAssistantExitCode(verdict, caseResult) {
|
|
276
|
+
if (caseResult) {
|
|
277
|
+
return caseResult.passed ? 0 : 2;
|
|
278
|
+
}
|
|
279
|
+
if (verdict === VERDICT.VERIFIED) {
|
|
280
|
+
return 0;
|
|
281
|
+
}
|
|
282
|
+
return exitCodeFromVerdict(verdict, { partial: verdict === VERDICT.NOT_VERIFIED });
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
async function runRoleAssistantTestAction(roleKey, options, cmd) {
|
|
286
|
+
const opts = normalizeRoleAssistantTestOptions(options, cmd);
|
|
287
|
+
// Dataplane ExternalSystem key is always ra-{roleKey}; bare roleKey is display/settings only.
|
|
288
|
+
const systemKey = roleAssistantSystemKey(roleKey);
|
|
289
|
+
const displayKey = bareRoleKey(roleKey);
|
|
290
|
+
const result = await runLifecycleForExternalSystem(systemKey, opts);
|
|
291
|
+
const verdict = lifecycleVerdictFromReport(result.report || {});
|
|
292
|
+
const portalUrl = buildExternalSystemUiUrl(result.dataplaneUiBaseUrl, systemKey);
|
|
293
|
+
const caseResult = await resolveRoleAssistantCaseResult(systemKey, opts, result, verdict, portalUrl);
|
|
294
|
+
|
|
295
|
+
if (opts.json) {
|
|
296
|
+
logger.log(
|
|
297
|
+
JSON.stringify(
|
|
298
|
+
buildRoleAssistantTestEnvelope(displayKey, verdict, portalUrl, result, opts, caseResult),
|
|
299
|
+
null,
|
|
300
|
+
2
|
|
301
|
+
)
|
|
302
|
+
);
|
|
303
|
+
} else {
|
|
304
|
+
displayRoleAssistantTestSummary(displayKey, verdict, portalUrl, result, caseResult);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
const exitCode = computeRoleAssistantExitCode(verdict, caseResult);
|
|
308
|
+
if (exitCode !== 0) {
|
|
309
|
+
process.exit(exitCode);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
async function roleAssistantTestHandler(roleKey, options, cmd) {
|
|
314
|
+
try {
|
|
315
|
+
await runRoleAssistantTestAction(roleKey, options, cmd);
|
|
316
|
+
} catch (error) {
|
|
317
|
+
handleCommandError(error, 'role-assistant test');
|
|
318
|
+
process.exit(3);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
function setupRoleAssistantCommands(program) {
|
|
323
|
+
const roleAssistant = program
|
|
324
|
+
.command('role-assistant')
|
|
325
|
+
.description('Role Assistant lifecycle and portal workflows');
|
|
326
|
+
|
|
327
|
+
roleAssistant
|
|
328
|
+
.command('test <roleKey>')
|
|
329
|
+
.description('Run role-assistant lifecycle checks and print portal deep link')
|
|
330
|
+
.option('-e, --env <env>', 'Environment: dev, tst, or pro', 'dev')
|
|
331
|
+
.option('--case <caseIdOrPath>', 'Run and evaluate one role-assistant test case')
|
|
332
|
+
.option('--tests-dir <dir>', 'Override role-assistant test case directory')
|
|
333
|
+
.option('-v, --verbose', 'Include full lifecycle report payload in --json output')
|
|
334
|
+
.option('-d, --debug', 'Write debug logs under role-assistant/<roleKey>/logs/')
|
|
335
|
+
.option(
|
|
336
|
+
'--publish',
|
|
337
|
+
'Publish local Role Assistant package before checks (default: use public/running worker)'
|
|
338
|
+
)
|
|
339
|
+
.option('--force', 'Force upload when --publish is set')
|
|
340
|
+
.option(
|
|
341
|
+
'--subject-user-id <id>',
|
|
342
|
+
'Subject user id for governance generate (repeatable)',
|
|
343
|
+
collectString,
|
|
344
|
+
[]
|
|
345
|
+
)
|
|
346
|
+
.option(
|
|
347
|
+
'--subject-email <email>',
|
|
348
|
+
'Subject email for governance generate (repeatable)',
|
|
349
|
+
collectString,
|
|
350
|
+
[]
|
|
351
|
+
)
|
|
352
|
+
.option(
|
|
353
|
+
'--certification-profile <profile>',
|
|
354
|
+
'Certification profile for governance generate (bronze, silver, gold, ...)',
|
|
355
|
+
'bronze'
|
|
356
|
+
)
|
|
357
|
+
.option('--json', 'Machine-readable output envelope')
|
|
358
|
+
.addHelpText('after', roleAssistantHelpAfter())
|
|
359
|
+
.action((roleKey, options, cmd) => roleAssistantTestHandler(roleKey, options, cmd));
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
module.exports = {
|
|
363
|
+
setupRoleAssistantCommands,
|
|
364
|
+
roleAssistantTestHandler,
|
|
365
|
+
runRoleAssistantTestAction,
|
|
366
|
+
normalizeRoleAssistantTestOptions,
|
|
367
|
+
buildRoleAssistantTestEnvelope,
|
|
368
|
+
computeRoleAssistantExitCode,
|
|
369
|
+
resolveRoleAssistantCaseResult,
|
|
370
|
+
formatStepsRunSummary
|
|
371
|
+
};
|
|
@@ -23,12 +23,9 @@ const { syncLocalIfRequested } = require('./test-e2e-external');
|
|
|
23
23
|
*/
|
|
24
24
|
async function runTestGovernanceForExternalSystem(externalSystem, options = {}) {
|
|
25
25
|
const pathsUtil = require('../utils/paths');
|
|
26
|
+
const { assertCertifyExternalWorkspace } = require('../utils/certify-external-workspace');
|
|
26
27
|
const appType = await pathsUtil.detectAppType(externalSystem).catch(() => null);
|
|
27
|
-
|
|
28
|
-
throw new Error(
|
|
29
|
-
'verify-governance applies to external integration folders only (integration/<systemKey>/).'
|
|
30
|
-
);
|
|
31
|
-
}
|
|
28
|
+
assertCertifyExternalWorkspace(appType && appType.baseDir, 'verify-governance');
|
|
32
29
|
|
|
33
30
|
const systemKey = externalSystem;
|
|
34
31
|
const packPath = resolveGovernancePackPath(systemKey, {
|
package/lib/commands/up-miso.js
CHANGED
|
@@ -41,40 +41,73 @@ function parseImageOptions(imageOpts) {
|
|
|
41
41
|
return map;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
* Build run options and run keycloak, then miso-controller
|
|
46
|
-
* @async
|
|
47
|
-
* @param {Object} options - Commander options (image, registry, registryMode)
|
|
48
|
-
*/
|
|
49
|
-
async function runMisoApps(options) {
|
|
50
|
-
const imageMap = parseImageOptions(options.image);
|
|
44
|
+
function buildPlatformCommonRunOpts(options) {
|
|
51
45
|
const useBaseImage = options.base !== false;
|
|
52
|
-
|
|
46
|
+
return {
|
|
53
47
|
registry: options.registry,
|
|
54
48
|
registryMode: options.registryMode,
|
|
55
49
|
skipEnvOutputPath: true,
|
|
56
50
|
skipInfraCheck: true,
|
|
57
51
|
base: useBaseImage,
|
|
58
|
-
skipManifestMetadataLine: true
|
|
52
|
+
skipManifestMetadataLine: true,
|
|
53
|
+
...(options.platformInstall === true ? { silentPoll: true } : {})
|
|
59
54
|
};
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function applyDeferredPublicUrlWarning(runOpts, options) {
|
|
58
|
+
if (typeof options.onDeferredPublicUrlWarning !== 'function') {
|
|
59
|
+
return runOpts;
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
...runOpts,
|
|
63
|
+
deferPublicUrlWarning: true,
|
|
64
|
+
onDeferredPublicUrlWarning: options.onDeferredPublicUrlWarning
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function buildKeycloakRunOpts(options, imageMap) {
|
|
69
|
+
const runOpts = applyDeferredPublicUrlWarning(buildPlatformCommonRunOpts(options), options);
|
|
65
70
|
if (imageMap.keycloak) {
|
|
66
|
-
|
|
71
|
+
runOpts.image = imageMap.keycloak;
|
|
67
72
|
}
|
|
68
|
-
|
|
73
|
+
return runOpts;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function buildMisoControllerRunOpts(options, imageMap) {
|
|
77
|
+
const runOpts = applyDeferredPublicUrlWarning(buildPlatformCommonRunOpts(options), options);
|
|
69
78
|
if (imageMap['miso-controller']) {
|
|
70
|
-
|
|
79
|
+
runOpts.image = imageMap['miso-controller'];
|
|
71
80
|
}
|
|
81
|
+
if (typeof options.onMisoPollText === 'function') {
|
|
82
|
+
runOpts.onPollText = options.onMisoPollText;
|
|
83
|
+
delete runOpts.silentPoll;
|
|
84
|
+
}
|
|
85
|
+
return runOpts;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Build run options and run keycloak, then miso-controller
|
|
90
|
+
* @async
|
|
91
|
+
* @param {Object} options - Commander options (image, registry, registryMode)
|
|
92
|
+
*/
|
|
93
|
+
async function runMisoApps(options) {
|
|
94
|
+
const imageMap = parseImageOptions(options.image);
|
|
95
|
+
const keycloakRunOpts = buildKeycloakRunOpts(options, imageMap);
|
|
96
|
+
const misoRunOpts = buildMisoControllerRunOpts(options, imageMap);
|
|
72
97
|
const { emitSystemBuilderAppManifestLineIfTTY } = require('../utils/manifest-source-emit');
|
|
73
|
-
|
|
74
|
-
|
|
98
|
+
const platformInstall = options.platformInstall === true;
|
|
99
|
+
if (!platformInstall) {
|
|
100
|
+
logger.log(chalk.blue('Starting keycloak...'));
|
|
101
|
+
emitSystemBuilderAppManifestLineIfTTY(logger, 'keycloak');
|
|
102
|
+
}
|
|
75
103
|
await app.runApp('keycloak', keycloakRunOpts);
|
|
76
|
-
|
|
77
|
-
|
|
104
|
+
if (typeof options.onAfterKeycloak === 'function') {
|
|
105
|
+
options.onAfterKeycloak();
|
|
106
|
+
}
|
|
107
|
+
if (!platformInstall) {
|
|
108
|
+
logger.log(chalk.blue('Starting miso-controller...'));
|
|
109
|
+
emitSystemBuilderAppManifestLineIfTTY(logger, 'miso-controller');
|
|
110
|
+
}
|
|
78
111
|
await app.runApp('miso-controller', misoRunOpts);
|
|
79
112
|
}
|
|
80
113
|
|
|
@@ -91,7 +124,9 @@ async function runMisoApps(options) {
|
|
|
91
124
|
* @throws {Error} If infra not up or any step fails
|
|
92
125
|
*/
|
|
93
126
|
async function handleUpMiso(options = {}) {
|
|
94
|
-
|
|
127
|
+
if (options.platformInstall !== true) {
|
|
128
|
+
logger.log(chalk.blue('Starting up-miso (keycloak + miso-controller from images)...\n'));
|
|
129
|
+
}
|
|
95
130
|
await assertDevInfraUp();
|
|
96
131
|
await ensureAppFromTemplate('keycloak');
|
|
97
132
|
await ensureAppFromTemplate('miso-controller');
|
|
@@ -103,8 +138,10 @@ async function handleUpMiso(options = {}) {
|
|
|
103
138
|
patchEnvOutputPathForDeployOnly('miso-controller');
|
|
104
139
|
refreshUrlsLocalRegistryForCurrentProject();
|
|
105
140
|
await runMisoApps(options);
|
|
106
|
-
|
|
107
|
-
|
|
141
|
+
if (options.platformInstall !== true) {
|
|
142
|
+
logger.log(formatSuccessParagraph('up-miso complete. Keycloak and miso-controller are running.') +
|
|
143
|
+
chalk.gray('\n Run onboarding and register Keycloak from the miso-controller repo if needed. Use \'aifabrix up-dataplane\' for dataplane.'));
|
|
144
|
+
}
|
|
108
145
|
}
|
|
109
146
|
|
|
110
147
|
module.exports = { handleUpMiso, parseImageOptions };
|
|
@@ -8,9 +8,18 @@
|
|
|
8
8
|
|
|
9
9
|
const { runPostPublishDataSync } = require('./run-post-publish-data-sync');
|
|
10
10
|
const { runUploadSidecarFollowups } = require('./upload-sidecar-followups');
|
|
11
|
-
const { formatSuccessLine } = require('../utils/cli-test-layout-chalk');
|
|
11
|
+
const { formatSuccessLine, formatWarningLine, metadata } = require('../utils/cli-test-layout-chalk');
|
|
12
12
|
const logger = require('../utils/logger');
|
|
13
|
-
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Internal verify/test --sync / deploy-preflight paths suppress upload banners.
|
|
16
|
+
* Default CLI `aifabrix upload` uses minimal=true but must still announce "unchanged".
|
|
17
|
+
* @param {Object} [options]
|
|
18
|
+
* @returns {boolean}
|
|
19
|
+
*/
|
|
20
|
+
function suppressUnchangedUploadBanner(options = {}) {
|
|
21
|
+
return options.syncMode === true || options.suppressSummary === true;
|
|
22
|
+
}
|
|
14
23
|
|
|
15
24
|
/**
|
|
16
25
|
* @async
|
|
@@ -27,7 +36,7 @@ async function finalizeUploadPublishResult(ctx, payload, options) {
|
|
|
27
36
|
options,
|
|
28
37
|
label: 'Upload data sync'
|
|
29
38
|
});
|
|
30
|
-
return { ...ctx, dataSync };
|
|
39
|
+
return { ...ctx, dataSync, sidecar: ctx.sidecar || null };
|
|
31
40
|
}
|
|
32
41
|
|
|
33
42
|
/**
|
|
@@ -37,18 +46,27 @@ async function finalizeUploadPublishResult(ctx, payload, options) {
|
|
|
37
46
|
*/
|
|
38
47
|
async function finishUnchangedUploadPublication(params) {
|
|
39
48
|
const { systemKey, options, payload, dataplaneUrl, authConfig, environment } = params;
|
|
40
|
-
if (!
|
|
49
|
+
if (!suppressUnchangedUploadBanner(options)) {
|
|
50
|
+
logger.log('');
|
|
41
51
|
logger.log(formatSuccessLine('Config unchanged on dataplane — upload skipped.'));
|
|
52
|
+
logger.log(metadata(`System: ${systemKey}`));
|
|
53
|
+
if (options.probe === true) {
|
|
54
|
+
logger.log(
|
|
55
|
+
formatWarningLine('Probe skipped (nothing published). Use --force to republish, then --probe.')
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
logger.log('');
|
|
42
59
|
}
|
|
43
|
-
await runUploadSidecarFollowups({
|
|
60
|
+
const sidecar = await runUploadSidecarFollowups({
|
|
44
61
|
systemKey,
|
|
45
62
|
options,
|
|
46
63
|
payload,
|
|
47
64
|
dataplaneUrl,
|
|
48
|
-
authConfig
|
|
65
|
+
authConfig,
|
|
66
|
+
environment
|
|
49
67
|
});
|
|
50
68
|
return finalizeUploadPublishResult(
|
|
51
|
-
{ dataplaneUrl, authConfig, environment, uploadSkipped: true },
|
|
69
|
+
{ dataplaneUrl, authConfig, environment, uploadSkipped: true, sidecar },
|
|
52
70
|
payload,
|
|
53
71
|
options
|
|
54
72
|
);
|