@aifabrix/builder 2.45.0 → 2.45.5
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/.cursor/rules/docs-rules.mdc +3 -1
- package/integration/hubspot-test/test-artifacts/wizard-hubspot-credential-real.yaml +1 -1
- package/integration/hubspot-test/test-artifacts/wizard-hubspot-env-vars.yaml +1 -1
- package/integration/hubspot-test/wizard-hubspot-e2e.yaml +1 -1
- package/jest.projects.js +44 -1
- package/lib/api/agent-metadata-validation.api.js +93 -0
- package/lib/api/audit-api-helpers.js +68 -0
- package/lib/api/audit.api.js +119 -0
- package/lib/api/auth-cache.api.js +44 -0
- package/lib/api/certificates.api.js +4 -4
- package/lib/api/credential.api.js +2 -2
- package/lib/api/dataplane-health.api.js +137 -0
- package/lib/api/dataplane-sync.api.js +27 -0
- package/lib/api/datasources-core.api.js +21 -18
- package/lib/api/datasources-extended.api.js +22 -22
- package/lib/api/dimensions.api.js +3 -0
- package/lib/api/external-systems.api.js +13 -13
- package/lib/api/governance-scenarios.api.js +39 -0
- package/lib/api/groups.api.js +79 -0
- package/lib/api/index.js +45 -2
- package/lib/api/pipeline.api.js +4 -4
- package/lib/api/protection.api.js +157 -0
- package/lib/api/records-bulk.api.js +30 -0
- package/lib/api/records-search-parse.js +49 -0
- package/lib/api/records-search.api.js +29 -0
- package/lib/api/types/agent-metadata-validation.types.js +67 -0
- package/lib/api/types/audit.types.js +72 -0
- package/lib/api/types/dataplane-health.types.js +27 -0
- package/lib/api/types/dimensions.types.js +2 -0
- package/lib/api/types/governance-scenarios.types.js +39 -0
- package/lib/api/types/protection.types.js +69 -0
- package/lib/api/types/records-bulk.types.js +35 -0
- package/lib/api/types/records-search.types.js +28 -0
- package/lib/api/user-groups.api.js +50 -0
- package/lib/api/users.api.js +95 -0
- package/lib/api/validation-run.api.js +3 -3
- package/lib/api/validation-runner.js +3 -3
- package/lib/api/wizard-platform.api.js +3 -3
- package/lib/api/wizard.api.js +21 -21
- package/lib/app/deploy.js +34 -19
- package/lib/cli/index.js +4 -2
- package/lib/cli/infra-guided.js +22 -3
- package/lib/cli/setup-app.help.js +50 -2
- package/lib/cli/setup-app.js +33 -24
- package/lib/cli/setup-app.test-commands.js +80 -21
- package/lib/cli/setup-auth.js +30 -3
- package/lib/cli/setup-external-system.js +37 -3
- package/lib/cli/setup-utility-help-after.js +45 -0
- package/lib/cli/setup-utility-resolve.js +2 -2
- package/lib/cli/setup-utility.js +99 -81
- package/lib/commands/auth-status-dataplane-version.js +231 -0
- package/lib/commands/auth-status-display.js +94 -0
- package/lib/commands/auth-status.js +70 -6
- package/lib/commands/credential-push.js +10 -5
- package/lib/commands/datasource-load-export-cli.js +178 -0
- package/lib/commands/datasource-test-trust-cli.js +114 -0
- package/lib/commands/datasource-unified-test-cli.js +25 -17
- package/lib/commands/datasource-unified-test-cli.options.js +18 -3
- package/lib/commands/datasource-unified-test-e2e-cli-helpers.js +5 -5
- package/lib/commands/datasource-verify-audit-cli.js +96 -0
- package/lib/commands/datasource.js +68 -1
- package/lib/commands/dimension-value.js +43 -13
- package/lib/commands/dimension.js +38 -7
- package/lib/commands/identity-apply-sync.js +131 -0
- package/lib/commands/identity-group-cli.js +146 -0
- package/lib/commands/identity-membership-role-cache.js +175 -0
- package/lib/commands/identity-shared.js +94 -0
- package/lib/commands/identity-user-cli.js +158 -0
- package/lib/commands/identity.js +43 -0
- package/lib/commands/login.js +46 -16
- package/lib/commands/protection-cli-leaves.js +286 -0
- package/lib/commands/protection.js +50 -0
- package/lib/commands/repair.js +13 -3
- package/lib/commands/test-e2e-external.js +40 -9
- package/lib/commands/test-governance-cli-options.js +47 -0
- package/lib/commands/test-governance-command-action.js +55 -0
- package/lib/commands/test-governance-external.js +88 -0
- package/lib/commands/test-trust-cli-options.js +32 -0
- package/lib/commands/test-trust-command-action.js +118 -0
- package/lib/commands/test-trust-external.js +127 -0
- package/lib/commands/upload.js +34 -13
- package/lib/commands/wizard-core.js +3 -0
- package/lib/core/config-device-dataplane.js +185 -0
- package/lib/datasource/agent-trust-debug-log.js +45 -0
- package/lib/datasource/agent-trust-fetch.js +115 -0
- package/lib/datasource/agent-trust-map.js +101 -0
- package/lib/datasource/agent-trust-mock.js +44 -0
- package/lib/datasource/agent-trust-run.js +93 -0
- package/lib/datasource/agent-trust-timeout.js +25 -0
- package/lib/datasource/audit-evidence-display.js +80 -0
- package/lib/datasource/audit-evidence-extract-debug.js +103 -0
- package/lib/datasource/audit-evidence-extract.js +177 -0
- package/lib/datasource/audit-evidence-matrix-rows.js +158 -0
- package/lib/datasource/audit-evidence-operation-aliases.js +63 -0
- package/lib/datasource/audit-evidence-poll.js +109 -0
- package/lib/datasource/audit-evidence-run.js +177 -0
- package/lib/datasource/audit-evidence-verify-helpers.js +167 -0
- package/lib/datasource/audit-evidence-verify-matrix.js +177 -0
- package/lib/datasource/audit-evidence-verify.js +108 -0
- package/lib/datasource/bulk-loader-run-batches.js +88 -0
- package/lib/datasource/bulk-loader-service-retry.js +52 -0
- package/lib/datasource/bulk-loader-service.js +127 -0
- package/lib/datasource/capability/run-capability-dimension.js +2 -1
- package/lib/datasource/datasource-exporter-resolve.js +82 -0
- package/lib/datasource/datasource-exporter-service.js +144 -0
- package/lib/datasource/datasource-identifier.js +148 -0
- package/lib/datasource/datasource-load-export-context.js +92 -0
- package/lib/datasource/integration-context.js +6 -4
- package/lib/datasource/local-data-paths.js +145 -0
- package/lib/datasource/log-cleaner.js +241 -0
- package/lib/datasource/log-viewer.js +111 -6
- package/lib/datasource/record-file-parser.js +85 -0
- package/lib/datasource/record-mapper.js +129 -0
- package/lib/datasource/resolve-app.js +74 -55
- package/lib/datasource/test-e2e.js +26 -2
- package/lib/datasource/unified-validation-run-resolve.js +45 -12
- package/lib/datasource/unified-validation-run.js +43 -17
- package/lib/datasource/validate.js +37 -20
- package/lib/external-system/test-system-level.js +25 -4
- package/lib/external-system/test.js +3 -1
- package/lib/governance/governance-pack-loader.js +70 -0
- package/lib/governance/governance-run-display.js +119 -0
- package/lib/identity/identity-apply-core.js +108 -0
- package/lib/identity/identity-apply-phases.js +244 -0
- package/lib/identity/identity-apply-service.js +77 -0
- package/lib/identity/identity-csv-parser.js +114 -0
- package/lib/internal/fs-real-sync.js +29 -1
- package/lib/protection/auth-context.js +45 -0
- package/lib/protection/convert-batch.js +90 -0
- package/lib/protection/load.js +41 -0
- package/lib/protection/paths.js +158 -0
- package/lib/protection/preflight-datasource-ready.js +46 -0
- package/lib/protection/protection-create-probe-lines.js +142 -0
- package/lib/protection/protection-create-probes.js +95 -0
- package/lib/protection/protection-create-scaffold.js +281 -0
- package/lib/protection/protection-display-helpers.js +445 -0
- package/lib/protection/protection-display.js +215 -0
- package/lib/protection/protection-preset-registry.js +97 -0
- package/lib/protection/report-exit.js +62 -0
- package/lib/protection/resolve.js +202 -0
- package/lib/protection/run-commands-validate.js +130 -0
- package/lib/protection/run-commands.js +216 -0
- package/lib/protection/run-protection-create-helpers.js +134 -0
- package/lib/protection/run-protection-create-probes-flow.js +43 -0
- package/lib/protection/run-protection-create.js +191 -0
- package/lib/protection/scope.js +22 -0
- package/lib/protection/sync-after-upload.js +64 -0
- package/lib/protection/upload-batch.js +127 -0
- package/lib/protection/validate-batch.js +113 -0
- package/lib/protection/validate-local.js +65 -0
- package/lib/resolvers/dimension-file.js +29 -4
- package/lib/schema/external-datasource.schema.json +47 -13
- package/lib/schema/flag-map-validation-run.json +2 -2
- package/lib/schema/protection.schema.json +374 -0
- package/lib/schema/type/credential-field-registry.json +636 -0
- package/lib/schema/wizard-config.schema.json +1 -1
- package/lib/utils/agent-trust-run-display.js +231 -0
- package/lib/utils/agent-trust-run-exit.js +59 -0
- package/lib/utils/agent-trust-wait-ui.js +94 -0
- package/lib/utils/cli-exit-codes.js +30 -0
- package/lib/utils/cli-sync-options.js +33 -0
- package/lib/utils/credential-push-ui.js +90 -0
- package/lib/utils/dataplane-cli-version-gate.js +202 -0
- package/lib/utils/dataplane-cli-version-help.js +74 -0
- package/lib/utils/datasource-export-display.js +137 -0
- package/lib/utils/datasource-load-display.js +174 -0
- package/lib/utils/datasource-load-export-ui.js +120 -0
- package/lib/utils/datasource-test-run-capability-scope.js +3 -3
- package/lib/utils/datasource-test-run-display.js +3 -3
- package/lib/utils/datasource-test-run-tty-log.js +5 -1
- package/lib/utils/help-builder.js +30 -24
- package/lib/utils/manifest-source-emit.js +22 -0
- package/lib/utils/semver-compare.js +127 -0
- package/lib/utils/upload-pipeline-ui.js +91 -0
- package/lib/utils/validation-poll-ui.js +14 -7
- package/lib/validation/wizard-config-validator.js +58 -19
- package/package.json +1 -1
- package/templates/applications/dataplane/env.template +13 -1
- package/templates/applications/dataplane/rbac.yaml +4 -0
- package/templates/external-system/README.md.hbs +56 -8
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview Single-capability CLI contract when
|
|
2
|
+
* @fileoverview Single-capability CLI contract when positional [capabilityKey] is set.
|
|
3
3
|
* @author AI Fabrix Team
|
|
4
4
|
* @version 2.0.0
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* @param {Object|null|undefined} envelope - DatasourceTestRun-like
|
|
9
|
-
* @param {string|undefined|null} requestedCapabilityKey - From
|
|
9
|
+
* @param {string|undefined|null} requestedCapabilityKey - From positional [capabilityKey]
|
|
10
10
|
* @returns {{ violated: boolean, message?: string, count?: number }}
|
|
11
11
|
*/
|
|
12
12
|
function analyzeCapabilityScope(envelope, requestedCapabilityKey) {
|
|
@@ -34,7 +34,7 @@ function analyzeCapabilityScope(envelope, requestedCapabilityKey) {
|
|
|
34
34
|
return {
|
|
35
35
|
violated: true,
|
|
36
36
|
count: caps.length,
|
|
37
|
-
message: `Capabilities scope: with
|
|
37
|
+
message: `Capabilities scope: with capabilityKey "${key}", expected a single row in capabilities[]; server returned ${caps.length} (${preview}${suffix}).`
|
|
38
38
|
};
|
|
39
39
|
}
|
|
40
40
|
|
|
@@ -98,7 +98,7 @@ function colorStepLine(ok, body) {
|
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
/**
|
|
101
|
-
* Normalize
|
|
101
|
+
* Normalize positional [capabilityKey] for matching envelope.capabilities[].key
|
|
102
102
|
* @param {*} focusCapabilityKey
|
|
103
103
|
* @returns {string} trimmed or ''
|
|
104
104
|
*/
|
|
@@ -354,7 +354,7 @@ function pickExecutiveVerdictLine(envelope) {
|
|
|
354
354
|
}
|
|
355
355
|
|
|
356
356
|
/**
|
|
357
|
-
* Plan §3.9: explicit line when E2E has no capability rows (skipped when
|
|
357
|
+
* Plan §3.9: explicit line when E2E has no capability rows (skipped when capability drill-down is active).
|
|
358
358
|
* @param {string[]} lines
|
|
359
359
|
* @param {Object} envelope
|
|
360
360
|
* @param {{ focusCapabilityKey?: string }} [options]
|
|
@@ -428,7 +428,7 @@ function formatDatasourceTestRunSummary(envelope, options = {}) {
|
|
|
428
428
|
* focusCapabilityKey?: string,
|
|
429
429
|
* includeRefs?: boolean,
|
|
430
430
|
* includeDebugExecutionSummary?: boolean
|
|
431
|
-
* }} [options] - When focusCapabilityKey set (
|
|
431
|
+
* }} [options] - When focusCapabilityKey set (positional [capabilityKey]), append single-cap block (plan §2.3).
|
|
432
432
|
* includeDebugExecutionSummary: show dataplane `debug.executionSummary` in header (TTY debug appendix uses CLI `--debug`).
|
|
433
433
|
* @returns {string}
|
|
434
434
|
*/
|
|
@@ -49,7 +49,11 @@ function printDatasourceTestRunForTTY(envelope, options = {}) {
|
|
|
49
49
|
includeDebugExecutionSummary: Boolean(mode)
|
|
50
50
|
};
|
|
51
51
|
if (options.json) {
|
|
52
|
-
|
|
52
|
+
const payload =
|
|
53
|
+
options.auditEvidenceVerification && typeof options.auditEvidenceVerification === 'object'
|
|
54
|
+
? { ...envelope, auditEvidenceVerification: options.auditEvidenceVerification }
|
|
55
|
+
: envelope;
|
|
56
|
+
logger.log(JSON.stringify(payload));
|
|
53
57
|
return;
|
|
54
58
|
}
|
|
55
59
|
if (options.summary) {
|
|
@@ -26,10 +26,10 @@ const CATEGORIES = [
|
|
|
26
26
|
{ name: 'up-platform' },
|
|
27
27
|
{ name: 'up-miso' },
|
|
28
28
|
{ name: 'up-dataplane' },
|
|
29
|
-
{ name: 'down-infra', term: 'down-infra [service|
|
|
29
|
+
{ name: 'down-infra', term: 'down-infra [service|appKey]' },
|
|
30
30
|
{ name: 'doctor' },
|
|
31
31
|
{ name: 'status' },
|
|
32
|
-
{ name: 'restart', term: 'restart <service|
|
|
32
|
+
{ name: 'restart', term: 'restart <service|appKey>' }
|
|
33
33
|
]
|
|
34
34
|
},
|
|
35
35
|
{
|
|
@@ -43,23 +43,22 @@ const CATEGORIES = [
|
|
|
43
43
|
{
|
|
44
44
|
name: 'Applications (Create & Develop)',
|
|
45
45
|
commands: [
|
|
46
|
-
{ name: 'create', term: 'create <
|
|
47
|
-
{ name: '
|
|
48
|
-
{ name: '
|
|
49
|
-
{ name: '
|
|
50
|
-
{ name: '
|
|
51
|
-
{ name: '
|
|
52
|
-
{ name: '
|
|
53
|
-
{ name: '
|
|
54
|
-
{ name: '
|
|
55
|
-
{ name: 'dockerfile', term: 'dockerfile <app>' }
|
|
46
|
+
{ name: 'create', term: 'create <appKey|systemKey>' },
|
|
47
|
+
{ name: 'build', term: 'build <appKey>' },
|
|
48
|
+
{ name: 'run', term: 'run <appKey>' },
|
|
49
|
+
{ name: 'shell', term: 'shell <appKey>' },
|
|
50
|
+
{ name: 'install', term: 'install <appKey>' },
|
|
51
|
+
{ name: 'lint', term: 'lint <appKey>' },
|
|
52
|
+
{ name: 'logs', term: 'logs <appKey>' },
|
|
53
|
+
{ name: 'stop', term: 'stop <appKey>' },
|
|
54
|
+
{ name: 'dockerfile', term: 'dockerfile <appKey>' }
|
|
56
55
|
]
|
|
57
56
|
},
|
|
58
57
|
{
|
|
59
58
|
name: 'Deployment',
|
|
60
59
|
commands: [
|
|
61
|
-
{ name: 'push', term: 'push <
|
|
62
|
-
{ name: 'deploy', term: 'deploy <
|
|
60
|
+
{ name: 'push', term: 'push <appKey>' },
|
|
61
|
+
{ name: 'deploy', term: 'deploy <appKey|systemKey>' }
|
|
63
62
|
]
|
|
64
63
|
},
|
|
65
64
|
{
|
|
@@ -80,12 +79,12 @@ const CATEGORIES = [
|
|
|
80
79
|
{
|
|
81
80
|
name: 'Configuration & Validation',
|
|
82
81
|
commands: [
|
|
83
|
-
{ name: 'resolve', term: 'resolve <
|
|
84
|
-
{ name: 'json', term: 'json <
|
|
85
|
-
{ name: 'split-json', term: 'split-json <
|
|
86
|
-
{ name: 'convert', term: 'convert <
|
|
87
|
-
{ name: 'show', term: 'show <
|
|
88
|
-
{ name: 'validate', term: 'validate
|
|
82
|
+
{ name: 'resolve', term: 'resolve <appKey|systemKey>' },
|
|
83
|
+
{ name: 'json', term: 'json <appKey|systemKey>' },
|
|
84
|
+
{ name: 'split-json', term: 'split-json <appKey|systemKey>' },
|
|
85
|
+
{ name: 'convert', term: 'convert <appKey|systemKey>' },
|
|
86
|
+
{ name: 'show', term: 'show <appKey|systemKey>' },
|
|
87
|
+
{ name: 'validate', term: 'validate [appKey|systemKey|file]' },
|
|
89
88
|
{ name: 'parameters', term: 'parameters validate' },
|
|
90
89
|
{ name: 'diff', term: 'diff <file1> <file2>' }
|
|
91
90
|
]
|
|
@@ -93,16 +92,23 @@ const CATEGORIES = [
|
|
|
93
92
|
{
|
|
94
93
|
name: 'External Systems',
|
|
95
94
|
commands: [
|
|
95
|
+
{ name: 'wizard', term: 'wizard [systemKey]' },
|
|
96
96
|
{ name: 'download', term: 'download <systemKey>' },
|
|
97
97
|
{ name: 'upload', term: 'upload <systemKey>' },
|
|
98
98
|
{ name: 'delete', term: 'delete <systemKey>' },
|
|
99
99
|
{ name: 'repair', term: 'repair <systemKey>' },
|
|
100
100
|
{ name: 'datasource' },
|
|
101
|
+
{ name: 'datasource load', term: 'datasource load <datasourceKey>' },
|
|
102
|
+
{ name: 'datasource export', term: 'datasource export <datasourceKey>' },
|
|
101
103
|
{ name: 'dimension' },
|
|
102
|
-
{ name: 'dimension
|
|
103
|
-
{ name: '
|
|
104
|
-
{ name: '
|
|
105
|
-
{ name: 'test
|
|
104
|
+
{ name: 'dimension value', term: 'dimension value <command>' },
|
|
105
|
+
{ name: 'identity' },
|
|
106
|
+
{ name: 'protection' },
|
|
107
|
+
{ name: 'test', term: 'test <appKey|systemKey>' },
|
|
108
|
+
{ name: 'test-e2e', term: 'test-e2e <appKey|systemKey>' },
|
|
109
|
+
{ name: 'test-governance', term: 'test-governance <appKey|systemKey>' },
|
|
110
|
+
{ name: 'test-trust', term: 'test-trust <appKey|systemKey>' },
|
|
111
|
+
{ name: 'test-integration', term: 'test-integration <appKey|systemKey>' }
|
|
106
112
|
]
|
|
107
113
|
},
|
|
108
114
|
{
|
|
@@ -151,8 +151,30 @@ function emitAllPlatformSystemManifestLinesIfTTY(logger, opts = {}) {
|
|
|
151
151
|
}
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
+
/**
|
|
155
|
+
* Integration load/export manifest line (plan 144).
|
|
156
|
+
*
|
|
157
|
+
* @param {{ tier?: string, configPath?: string, labelPrefix?: string }} opts
|
|
158
|
+
* @returns {void}
|
|
159
|
+
*/
|
|
160
|
+
function emitManifestSourceMetadata(opts = {}) {
|
|
161
|
+
if (!isStdoutTty()) return;
|
|
162
|
+
const log = require('./logger');
|
|
163
|
+
const tier = opts.tier && typeof opts.tier === 'string' ? opts.tier : 'resolved';
|
|
164
|
+
const configPath =
|
|
165
|
+
opts.configPath && typeof opts.configPath === 'string' ? opts.configPath : '';
|
|
166
|
+
const labelPrefix =
|
|
167
|
+
opts.labelPrefix && typeof opts.labelPrefix === 'string' ? opts.labelPrefix : '';
|
|
168
|
+
const tierLabel = tier === 'int' ? 'integration' : humanTierLabel(tier);
|
|
169
|
+
const line = labelPrefix
|
|
170
|
+
? metadata(`${labelPrefix} — ${tierLabel} — ${configPath}`)
|
|
171
|
+
: formatManifestSourceMetadataLine({ tier: tierLabel, configPath });
|
|
172
|
+
log.log(line);
|
|
173
|
+
}
|
|
174
|
+
|
|
154
175
|
module.exports = {
|
|
155
176
|
emitManifestMetadataLineIfTTY,
|
|
177
|
+
emitManifestSourceMetadata,
|
|
156
178
|
emitSystemBuilderAppManifestLineIfTTY,
|
|
157
179
|
emitAllPlatformSystemManifestLinesIfTTY,
|
|
158
180
|
formatManifestSourceMetadataLine,
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal semver comparator (no `semver` npm dependency).
|
|
3
|
+
*
|
|
4
|
+
* Supports `MAJOR.MINOR.PATCH` and optional prerelease suffix
|
|
5
|
+
* `-<prerelease>` (e.g. `2.45.0-beta.1`). Optional leading `v` is tolerated.
|
|
6
|
+
* Prerelease versions always rank **before** the same MAJOR.MINOR.PATCH
|
|
7
|
+
* without a prerelease (semver §11.3).
|
|
8
|
+
*
|
|
9
|
+
* @fileoverview Internal semver compare for Builder CLI compatibility gate
|
|
10
|
+
* @author AI Fabrix Team
|
|
11
|
+
* @version 2.0.0
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
'use strict';
|
|
15
|
+
|
|
16
|
+
const SEMVER_PATTERN = /^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z][-0-9A-Za-z.]*))?$/;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Parse a semver-like string into a comparable structure.
|
|
20
|
+
* @param {string} input - Version string (e.g. "2.45.0" or "v2.45.0-beta.1")
|
|
21
|
+
* @returns {{ major:number, minor:number, patch:number, prerelease:string[] }|null}
|
|
22
|
+
* Parsed parts or null when input does not match the supported grammar
|
|
23
|
+
*/
|
|
24
|
+
function parseSemver(input) {
|
|
25
|
+
if (typeof input !== 'string') {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
const match = SEMVER_PATTERN.exec(input.trim());
|
|
29
|
+
if (!match) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
const [, major, minor, patch, prerelease] = match;
|
|
33
|
+
return {
|
|
34
|
+
major: Number(major),
|
|
35
|
+
minor: Number(minor),
|
|
36
|
+
patch: Number(patch),
|
|
37
|
+
prerelease: prerelease ? prerelease.split('.') : []
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Check whether a string is a supported semver (incl. optional prerelease).
|
|
43
|
+
* @param {string} input
|
|
44
|
+
* @returns {boolean}
|
|
45
|
+
*/
|
|
46
|
+
function isValidSemver(input) {
|
|
47
|
+
return parseSemver(input) !== null;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Compare two prerelease identifier arrays per semver §11.4.
|
|
52
|
+
* @private
|
|
53
|
+
* @param {string[]} a
|
|
54
|
+
* @param {string[]} b
|
|
55
|
+
* @returns {-1|0|1}
|
|
56
|
+
*/
|
|
57
|
+
function comparePrereleaseIds(a, b) {
|
|
58
|
+
const len = Math.max(a.length, b.length);
|
|
59
|
+
for (let i = 0; i < len; i += 1) {
|
|
60
|
+
if (a[i] === undefined) return -1;
|
|
61
|
+
if (b[i] === undefined) return 1;
|
|
62
|
+
const aNum = /^\d+$/.test(a[i]);
|
|
63
|
+
const bNum = /^\d+$/.test(b[i]);
|
|
64
|
+
if (aNum && bNum) {
|
|
65
|
+
const diff = Number(a[i]) - Number(b[i]);
|
|
66
|
+
if (diff !== 0) return diff > 0 ? 1 : -1;
|
|
67
|
+
} else if (aNum) {
|
|
68
|
+
return -1;
|
|
69
|
+
} else if (bNum) {
|
|
70
|
+
return 1;
|
|
71
|
+
} else if (a[i] !== b[i]) {
|
|
72
|
+
return a[i] > b[i] ? 1 : -1;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return 0;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Compare two semver strings.
|
|
80
|
+
*
|
|
81
|
+
* @param {string} a
|
|
82
|
+
* @param {string} b
|
|
83
|
+
* @returns {-1|0|1} `-1` when `a < b`, `0` when equal, `1` when `a > b`
|
|
84
|
+
* @throws {Error} When either argument is not a valid semver
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* compareSemver('2.44.0', '2.45.0') === -1
|
|
88
|
+
* compareSemver('2.45.0', '2.45.0') === 0
|
|
89
|
+
* compareSemver('2.45.0-beta.1', '2.45.0') === -1
|
|
90
|
+
*/
|
|
91
|
+
function compareSemver(a, b) {
|
|
92
|
+
const parsedA = parseSemver(a);
|
|
93
|
+
const parsedB = parseSemver(b);
|
|
94
|
+
if (!parsedA) throw new Error(`Invalid semver: "${a}"`);
|
|
95
|
+
if (!parsedB) throw new Error(`Invalid semver: "${b}"`);
|
|
96
|
+
|
|
97
|
+
if (parsedA.major !== parsedB.major) return parsedA.major > parsedB.major ? 1 : -1;
|
|
98
|
+
if (parsedA.minor !== parsedB.minor) return parsedA.minor > parsedB.minor ? 1 : -1;
|
|
99
|
+
if (parsedA.patch !== parsedB.patch) return parsedA.patch > parsedB.patch ? 1 : -1;
|
|
100
|
+
|
|
101
|
+
// §11.3 — Prerelease has lower precedence than the same MAJOR.MINOR.PATCH release.
|
|
102
|
+
if (parsedA.prerelease.length === 0 && parsedB.prerelease.length === 0) return 0;
|
|
103
|
+
if (parsedA.prerelease.length === 0) return 1;
|
|
104
|
+
if (parsedB.prerelease.length === 0) return -1;
|
|
105
|
+
|
|
106
|
+
return comparePrereleaseIds(parsedA.prerelease, parsedB.prerelease);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Convenience: true when `current >= required`.
|
|
111
|
+
* Returns `true` when `required` is empty/null/undefined (no enforcement).
|
|
112
|
+
* @param {string} current
|
|
113
|
+
* @param {string} [required]
|
|
114
|
+
* @returns {boolean}
|
|
115
|
+
* @throws {Error} If either provided value is not valid semver
|
|
116
|
+
*/
|
|
117
|
+
function isAtLeast(current, required) {
|
|
118
|
+
if (required === undefined || required === null || required === '') return true;
|
|
119
|
+
return compareSemver(current, required) >= 0;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
module.exports = {
|
|
123
|
+
parseSemver,
|
|
124
|
+
isValidSemver,
|
|
125
|
+
compareSemver,
|
|
126
|
+
isAtLeast
|
|
127
|
+
};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Progress line + optional ora spinner for dataplane pipeline upload/publish.
|
|
3
|
+
* @author AI Fabrix Team
|
|
4
|
+
* @version 1.1.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
'use strict';
|
|
8
|
+
|
|
9
|
+
const chalk = require('chalk');
|
|
10
|
+
const logger = require('./logger');
|
|
11
|
+
const { formatProgress } = require('./cli-test-layout-chalk');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @param {Object} [options]
|
|
15
|
+
* @param {boolean} [options.json] - When true, skip progress line and spinner
|
|
16
|
+
* @returns {boolean}
|
|
17
|
+
*/
|
|
18
|
+
function shouldShowUploadPipelineProgress(options = {}) {
|
|
19
|
+
return options.json !== true;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @param {Object} [options]
|
|
24
|
+
* @returns {boolean}
|
|
25
|
+
*/
|
|
26
|
+
function shouldUseUploadPipelineSpinner(options = {}) {
|
|
27
|
+
if (!shouldShowUploadPipelineProgress(options)) {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
return Boolean(process && process.stdout && process.stdout.isTTY);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Plain label for spinner / progress (no glyph).
|
|
35
|
+
* @param {string} systemKey
|
|
36
|
+
* @returns {string}
|
|
37
|
+
*/
|
|
38
|
+
function buildUploadPipelineSpinnerLabel(systemKey) {
|
|
39
|
+
const key = systemKey && String(systemKey).trim() ? String(systemKey).trim() : 'integration';
|
|
40
|
+
return `Publishing ${key} to dataplane…`;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @param {string} systemKey
|
|
45
|
+
* @returns {string}
|
|
46
|
+
*/
|
|
47
|
+
function buildUploadPipelineProgressText(systemKey) {
|
|
48
|
+
return formatProgress(buildUploadPipelineSpinnerLabel(systemKey));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Run pipeline upload + OpenAPI sync with visible progress (⏳ line or ora with label on TTY).
|
|
53
|
+
*
|
|
54
|
+
* @async
|
|
55
|
+
* @param {Function} work - Zero-arg async function (publish + follow-up I/O)
|
|
56
|
+
* @param {Object} [opts]
|
|
57
|
+
* @param {string} [opts.systemKey]
|
|
58
|
+
* @param {boolean} [opts.json]
|
|
59
|
+
* @returns {Promise<*>}
|
|
60
|
+
*/
|
|
61
|
+
async function runWithUploadPipelineSpinner(work, opts = {}) {
|
|
62
|
+
if (!shouldShowUploadPipelineProgress(opts)) {
|
|
63
|
+
return work();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (!shouldUseUploadPipelineSpinner(opts)) {
|
|
67
|
+
logger.log(buildUploadPipelineProgressText(opts.systemKey));
|
|
68
|
+
return work();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const ora = require('ora');
|
|
72
|
+
const label = buildUploadPipelineSpinnerLabel(opts.systemKey);
|
|
73
|
+
const spinner = ora({
|
|
74
|
+
text: chalk.white(label),
|
|
75
|
+
spinner: 'dots'
|
|
76
|
+
}).start();
|
|
77
|
+
|
|
78
|
+
try {
|
|
79
|
+
return await work();
|
|
80
|
+
} finally {
|
|
81
|
+
spinner.stop();
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
module.exports = {
|
|
86
|
+
shouldShowUploadPipelineProgress,
|
|
87
|
+
shouldUseUploadPipelineSpinner,
|
|
88
|
+
buildUploadPipelineSpinnerLabel,
|
|
89
|
+
buildUploadPipelineProgressText,
|
|
90
|
+
runWithUploadPipelineSpinner
|
|
91
|
+
};
|
|
@@ -23,10 +23,12 @@ function shouldUseValidationPollSpinner() {
|
|
|
23
23
|
* @param {number} deadlineMs - Wall-clock deadline (Date.now() + remaining budget)
|
|
24
24
|
* @returns {string}
|
|
25
25
|
*/
|
|
26
|
-
function buildValidationPollSpinnerText(envelope, attemptIndex, deadlineMs) {
|
|
26
|
+
function buildValidationPollSpinnerText(envelope, attemptIndex, deadlineMs, subject) {
|
|
27
27
|
const remainingSec = Math.max(0, Math.ceil((deadlineMs - Date.now()) / 1000));
|
|
28
|
+
const label =
|
|
29
|
+
subject && String(subject).trim() ? String(subject).trim() : 'validation run';
|
|
28
30
|
if (!envelope || typeof envelope !== 'object') {
|
|
29
|
-
return `Waiting for
|
|
31
|
+
return `Waiting for ${label}… starting (budget ~${remainingSec}s)`;
|
|
30
32
|
}
|
|
31
33
|
const c =
|
|
32
34
|
envelope.reportCompleteness !== undefined && envelope.reportCompleteness !== null
|
|
@@ -34,26 +36,29 @@ function buildValidationPollSpinnerText(envelope, attemptIndex, deadlineMs) {
|
|
|
34
36
|
: '?';
|
|
35
37
|
const st =
|
|
36
38
|
envelope.status !== undefined && envelope.status !== null ? String(envelope.status) : '?';
|
|
37
|
-
return `Waiting for
|
|
39
|
+
return `Waiting for ${label}… completeness=${c} status=${st} (poll ${attemptIndex + 1} · ~${remainingSec}s left)`;
|
|
38
40
|
}
|
|
39
41
|
|
|
40
42
|
const NON_TTY_THROTTLE_MS = 5000;
|
|
41
43
|
|
|
42
44
|
/**
|
|
43
45
|
* @param {number} deadlineMs - Absolute deadline for poll budget display
|
|
46
|
+
* @param {Object} [opts]
|
|
47
|
+
* @param {string} [opts.subject] - Datasource key or label shown in poll text
|
|
44
48
|
* @returns {{ usesSpinner: boolean, onPollProgress: Function, finish: () => void }}
|
|
45
49
|
*/
|
|
46
|
-
function createValidationPollHandlers(deadlineMs) {
|
|
50
|
+
function createValidationPollHandlers(deadlineMs, opts = {}) {
|
|
51
|
+
const subject = opts.subject;
|
|
47
52
|
if (shouldUseValidationPollSpinner()) {
|
|
48
53
|
const ora = require('ora');
|
|
49
54
|
const spinner = ora({
|
|
50
|
-
text: buildValidationPollSpinnerText(null, 0, deadlineMs),
|
|
55
|
+
text: buildValidationPollSpinnerText(null, 0, deadlineMs, subject),
|
|
51
56
|
spinner: 'dots'
|
|
52
57
|
}).start();
|
|
53
58
|
return {
|
|
54
59
|
usesSpinner: true,
|
|
55
60
|
onPollProgress: (envelope, attemptIndex, _meta) => {
|
|
56
|
-
spinner.text = buildValidationPollSpinnerText(envelope, attemptIndex, deadlineMs);
|
|
61
|
+
spinner.text = buildValidationPollSpinnerText(envelope, attemptIndex, deadlineMs, subject);
|
|
57
62
|
},
|
|
58
63
|
finish: () => {
|
|
59
64
|
spinner.stop();
|
|
@@ -68,7 +73,9 @@ function createValidationPollHandlers(deadlineMs) {
|
|
|
68
73
|
const now = Date.now();
|
|
69
74
|
if (now - lastNonTtyLogAt < NON_TTY_THROTTLE_MS) return;
|
|
70
75
|
lastNonTtyLogAt = now;
|
|
71
|
-
logger.log(
|
|
76
|
+
logger.log(
|
|
77
|
+
chalk.gray(buildValidationPollSpinnerText(envelope, attemptIndex, deadlineMs, subject))
|
|
78
|
+
);
|
|
72
79
|
},
|
|
73
80
|
finish: () => {}
|
|
74
81
|
};
|
|
@@ -164,36 +164,73 @@ function validateWizardConfigSchema(config) {
|
|
|
164
164
|
};
|
|
165
165
|
}
|
|
166
166
|
|
|
167
|
+
/**
|
|
168
|
+
* Candidate bases for relative openapi-file paths (first existing wins).
|
|
169
|
+
* @param {string} configPath - Path to wizard.yaml
|
|
170
|
+
* @returns {string[]}
|
|
171
|
+
*/
|
|
172
|
+
function wizardOpenApiFilePathCandidates(filePath, configPath) {
|
|
173
|
+
const raw = String(filePath || '').trim();
|
|
174
|
+
if (!raw) {
|
|
175
|
+
return [];
|
|
176
|
+
}
|
|
177
|
+
if (path.isAbsolute(raw)) {
|
|
178
|
+
return [path.resolve(raw)];
|
|
179
|
+
}
|
|
180
|
+
const configDir = path.dirname(path.resolve(configPath));
|
|
181
|
+
return [...new Set([
|
|
182
|
+
path.resolve(process.cwd(), raw),
|
|
183
|
+
path.resolve(configDir, raw)
|
|
184
|
+
])];
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Resolve openapi-file path for wizard config (absolute path).
|
|
189
|
+
* Relative paths: process.cwd() first, then wizard.yaml directory.
|
|
190
|
+
* @param {string} filePath
|
|
191
|
+
* @param {string} configPath
|
|
192
|
+
* @returns {Promise<string>}
|
|
193
|
+
*/
|
|
194
|
+
async function resolveWizardOpenApiFilePath(filePath, configPath) {
|
|
195
|
+
const candidates = wizardOpenApiFilePathCandidates(filePath, configPath);
|
|
196
|
+
if (candidates.length === 0) {
|
|
197
|
+
return '';
|
|
198
|
+
}
|
|
199
|
+
for (const candidate of candidates) {
|
|
200
|
+
try {
|
|
201
|
+
await fs.access(candidate);
|
|
202
|
+
return candidate;
|
|
203
|
+
} catch (error) {
|
|
204
|
+
if (error.code !== 'ENOENT') {
|
|
205
|
+
throw error;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return candidates[0];
|
|
210
|
+
}
|
|
211
|
+
|
|
167
212
|
/**
|
|
168
213
|
* Validate file path exists (for openapi-file source type)
|
|
169
214
|
* @function validateFilePath
|
|
170
215
|
* @param {string} filePath - Path to validate
|
|
171
|
-
* @param {string}
|
|
172
|
-
* @returns {Promise<Object>} Validation result with valid flag and
|
|
216
|
+
* @param {string} configPath - Path to wizard.yaml (relative paths resolve from cwd, then config dir)
|
|
217
|
+
* @returns {Promise<Object>} Validation result with valid flag, errors, and resolvedPath
|
|
173
218
|
*/
|
|
174
|
-
async function validateFilePath(filePath,
|
|
175
|
-
const
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
: path.resolve(baseDir, filePath);
|
|
179
|
-
if (!path.isAbsolute(filePath)) {
|
|
180
|
-
const baseWithSep = baseDir.endsWith(path.sep) ? baseDir : `${baseDir}${path.sep}`;
|
|
181
|
-
if (!resolvedPath.startsWith(baseWithSep)) {
|
|
182
|
-
return {
|
|
183
|
-
valid: false,
|
|
184
|
-
errors: [`OpenAPI file path must be within: ${baseDir}`]
|
|
185
|
-
};
|
|
186
|
-
}
|
|
219
|
+
async function validateFilePath(filePath, configPath) {
|
|
220
|
+
const resolvedPath = await resolveWizardOpenApiFilePath(filePath, configPath);
|
|
221
|
+
if (!resolvedPath) {
|
|
222
|
+
return { valid: false, errors: ['OpenAPI file path is required'], resolvedPath: '' };
|
|
187
223
|
}
|
|
188
224
|
try {
|
|
189
225
|
await fs.access(resolvedPath);
|
|
190
226
|
} catch (error) {
|
|
191
227
|
return {
|
|
192
228
|
valid: false,
|
|
193
|
-
errors: [`OpenAPI file not found: ${resolvedPath}`]
|
|
229
|
+
errors: [`OpenAPI file not found: ${resolvedPath}`],
|
|
230
|
+
resolvedPath
|
|
194
231
|
};
|
|
195
232
|
}
|
|
196
|
-
return { valid: true, errors: [] };
|
|
233
|
+
return { valid: true, errors: [], resolvedPath };
|
|
197
234
|
}
|
|
198
235
|
|
|
199
236
|
/**
|
|
@@ -229,10 +266,11 @@ function validateSchemaAndResolveEnvVars(config, shouldResolveEnvVars) {
|
|
|
229
266
|
async function performSemanticValidations(config, configPath, validateFilePaths) {
|
|
230
267
|
const errors = [];
|
|
231
268
|
if (validateFilePaths && config.source?.type === 'openapi-file' && config.source?.filePath) {
|
|
232
|
-
const
|
|
233
|
-
const fileResult = await validateFilePath(config.source.filePath, basePath);
|
|
269
|
+
const fileResult = await validateFilePath(config.source.filePath, configPath);
|
|
234
270
|
if (!fileResult.valid) {
|
|
235
271
|
errors.push(...fileResult.errors);
|
|
272
|
+
} else if (fileResult.resolvedPath) {
|
|
273
|
+
config.source.filePath = fileResult.resolvedPath;
|
|
236
274
|
}
|
|
237
275
|
}
|
|
238
276
|
if (config.mode === 'add-datasource' && !config.systemIdOrKey) {
|
|
@@ -296,6 +334,7 @@ module.exports = {
|
|
|
296
334
|
wizardConfigExists,
|
|
297
335
|
validateWizardConfig,
|
|
298
336
|
validateWizardConfigSchema,
|
|
337
|
+
resolveWizardOpenApiFilePath,
|
|
299
338
|
resolveEnvVar,
|
|
300
339
|
resolveEnvVarsInObject,
|
|
301
340
|
formatValidationErrors,
|
package/package.json
CHANGED
|
@@ -21,7 +21,7 @@ LOG_FORMAT=json
|
|
|
21
21
|
# Production with persistent logs: use /mnt/data/logs/app.log and mount a volume at /mnt/data.
|
|
22
22
|
LOG_FILE_PATH=/mnt/data/logs/app.log
|
|
23
23
|
# If true, run without Redis/Celery (single process)
|
|
24
|
-
LOCAL_MODE=
|
|
24
|
+
LOCAL_MODE=true
|
|
25
25
|
|
|
26
26
|
# When API_KEY is set, a matching Bearer token bypasses OAuth2 validation
|
|
27
27
|
# Same kv:// as miso-controller API_KEY so pipeline Bearer bypass uses one secrets.local entry
|
|
@@ -30,6 +30,9 @@ API_KEY=kv://miso-controller-secrets-apiKeyVault
|
|
|
30
30
|
# API Configuration
|
|
31
31
|
API_V1_STR=/api/v1
|
|
32
32
|
VERSION=1.9.5
|
|
33
|
+
# Minimum supported aifabrix-builder CLI semver (advertised on /health and /api/v1/health; empty = no gate)
|
|
34
|
+
# MIN_BUILDER_CLI_VERSION=2.45.0
|
|
35
|
+
MIN_BUILDER_CLI_VERSION=2.45.0
|
|
33
36
|
# Base URL for the dataplane web server (used for default OAuth2 callback URL when redirectUri is omitted)
|
|
34
37
|
# url:// resolves after kv://; includes front-door path from application.yaml (e.g. /data)
|
|
35
38
|
DATAPLANE_WEB_SERVER_URL=url://public
|
|
@@ -165,6 +168,15 @@ RBAC_EXPLAIN_MODE_ENABLED=false
|
|
|
165
168
|
# validates only (no second DB write). Default false.
|
|
166
169
|
AUDIT_ASYNC_SHADOW_ENQUEUE=false
|
|
167
170
|
|
|
171
|
+
# Policy Library management HTTP API gate. When false (default), management
|
|
172
|
+
# routes are not registered (404): /api/v1/policies/*, /api/v1/external/{key}/policies,
|
|
173
|
+
# /api/v1/users/{id}/policies, /api/v1/groups/{id}/policies, IDE /validate/policy and
|
|
174
|
+
# /simulate/policy-impact/{datasourceKey}. ABAC runtime evaluation is unaffected.
|
|
175
|
+
# Set to true for local dev when iterating on policy CRUD APIs.
|
|
176
|
+
# Policy Library management HTTP APIs (default false → routes not registered, 404).
|
|
177
|
+
# Set true for local dev policy CRUD; pair with VITE_POLICY_MANAGEMENT_ENABLED=true in app-ui.
|
|
178
|
+
POLICY_MANAGEMENT_API_ENABLED=false
|
|
179
|
+
|
|
168
180
|
# =============================================================================
|
|
169
181
|
# OBSERVABILITY CONFIGURATION
|
|
170
182
|
# =============================================================================
|
|
@@ -280,6 +280,10 @@ permissions:
|
|
|
280
280
|
- name: "record:search"
|
|
281
281
|
roles: ["aifabrix-platform-admin", "aifabrix-security-admin", "aifabrix-deployment-admin", "aifabrix-compliance-admin", "aifabrix-developer", "aifabrix-observer"]
|
|
282
282
|
description: "Search records"
|
|
283
|
+
|
|
284
|
+
- name: "governance:evaluate"
|
|
285
|
+
roles: ["aifabrix-platform-admin", "aifabrix-security-admin", "aifabrix-developer"]
|
|
286
|
+
description: "Run governance scenario acceptance (subject impersonation for ABAC proof)"
|
|
283
287
|
|
|
284
288
|
# IDE simulation operations
|
|
285
289
|
- name: "dataplane:abac-simulate"
|