@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
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview CLI action for `aifabrix test-trust` (plan 143).
|
|
3
|
+
* @author AI Fabrix Team
|
|
4
|
+
* @version 1.0.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
'use strict';
|
|
8
|
+
|
|
9
|
+
const chalk = require('chalk');
|
|
10
|
+
const logger = require('../utils/logger');
|
|
11
|
+
const { handleCommandError } = require('../utils/cli-utils');
|
|
12
|
+
const { runTestTrustForExternalSystem } = require('./test-trust-external');
|
|
13
|
+
const {
|
|
14
|
+
displaySystemTrustRollupTTY,
|
|
15
|
+
displayAgentTrustRunTTY
|
|
16
|
+
} = require('../utils/agent-trust-run-display');
|
|
17
|
+
const { computeSystemExitCodeFromTrustRows } = require('../utils/agent-trust-run-exit');
|
|
18
|
+
const { writeTrustDebugLogAndPrint } = require('../datasource/agent-trust-debug-log');
|
|
19
|
+
const { normalizeTestTrustCliOptions } = require('./test-trust-cli-options');
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @async
|
|
23
|
+
* @param {string} appName
|
|
24
|
+
* @param {Object} options
|
|
25
|
+
*/
|
|
26
|
+
async function writeSystemTrustDebugLogs(appName, results, options) {
|
|
27
|
+
if (!options.debug) return;
|
|
28
|
+
logger.log('');
|
|
29
|
+
logger.log(chalk.gray('Debug logs:'));
|
|
30
|
+
for (const row of results) {
|
|
31
|
+
await writeTrustDebugLogAndPrint(appName, row.key, {
|
|
32
|
+
request: {
|
|
33
|
+
datasourceKey: row.key,
|
|
34
|
+
revalidate: options.revalidate === true,
|
|
35
|
+
noSync: options.noSync === true
|
|
36
|
+
},
|
|
37
|
+
response: row.trustRun,
|
|
38
|
+
error: row.error || null
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function displaySystemTrustResults(systemKey, appName, results, options) {
|
|
44
|
+
if (options.json) {
|
|
45
|
+
logger.log(JSON.stringify(results, null, 2));
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
if (options.summary) {
|
|
49
|
+
for (const row of results) {
|
|
50
|
+
const tr = row.trustRun;
|
|
51
|
+
const line = tr
|
|
52
|
+
? `${row.key}: ${tr.trustDecision} (${tr.validationStatus})`
|
|
53
|
+
: `${row.key}: fail (${row.error || 'error'})`;
|
|
54
|
+
logger.log(line);
|
|
55
|
+
}
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const displayOpts = {
|
|
60
|
+
strict: options.strict === true,
|
|
61
|
+
showCache: options.verbose === true || options.revalidate === true
|
|
62
|
+
};
|
|
63
|
+
displaySystemTrustRollupTTY(systemKey || appName, results, displayOpts);
|
|
64
|
+
|
|
65
|
+
if (!options.verbose) return;
|
|
66
|
+
|
|
67
|
+
for (const row of results) {
|
|
68
|
+
if (!row.trustRun) continue;
|
|
69
|
+
displayAgentTrustRunTTY(row.trustRun, {
|
|
70
|
+
environment: options.env,
|
|
71
|
+
verbose: true,
|
|
72
|
+
noSync: options.noSync === true,
|
|
73
|
+
strict: options.strict === true
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async function runTestTrustCommandAction(appName, options, cmd) {
|
|
79
|
+
const opts = normalizeTestTrustCliOptions(options, cmd);
|
|
80
|
+
const pathsUtil = require('../utils/paths');
|
|
81
|
+
const appType = await pathsUtil.detectAppType(appName).catch(() => null);
|
|
82
|
+
if (!appType || appType.baseDir !== 'integration') {
|
|
83
|
+
throw new Error(
|
|
84
|
+
'test-trust applies to external integration folders only (integration/<systemKey>/).'
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
const { success, results, systemKey } = await runTestTrustForExternalSystem(appName, {
|
|
88
|
+
env: opts.env,
|
|
89
|
+
verbose: opts.verbose,
|
|
90
|
+
debug: opts.debug,
|
|
91
|
+
noSync: opts.noSync === true,
|
|
92
|
+
revalidate: opts.revalidate === true,
|
|
93
|
+
summary: opts.summary === true,
|
|
94
|
+
timeout: opts.timeout
|
|
95
|
+
});
|
|
96
|
+
displaySystemTrustResults(systemKey, appName, results, opts);
|
|
97
|
+
await writeSystemTrustDebugLogs(appName, results, opts);
|
|
98
|
+
const exitCode = computeSystemExitCodeFromTrustRows(results, {
|
|
99
|
+
warningsAsErrors: opts.warningsAsErrors === true,
|
|
100
|
+
strict: opts.strict === true
|
|
101
|
+
});
|
|
102
|
+
if (exitCode !== 0) process.exit(exitCode);
|
|
103
|
+
if (!success) process.exit(1);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async function testTrustCommandHandler(appName, options, cmd) {
|
|
107
|
+
try {
|
|
108
|
+
await runTestTrustCommandAction(appName, options, cmd);
|
|
109
|
+
} catch (error) {
|
|
110
|
+
handleCommandError(error, 'test-trust');
|
|
111
|
+
process.exit(3);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
module.exports = {
|
|
116
|
+
runTestTrustCommandAction,
|
|
117
|
+
testTrustCommandHandler
|
|
118
|
+
};
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview test-trust <systemKey> — semantic agent metadata validation for all datasources.
|
|
3
|
+
* @author AI Fabrix Team
|
|
4
|
+
* @version 1.0.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
'use strict';
|
|
8
|
+
|
|
9
|
+
const chalk = require('chalk');
|
|
10
|
+
const logger = require('../utils/logger');
|
|
11
|
+
const { cliOptsSkipSync } = require('../utils/cli-sync-options');
|
|
12
|
+
const { getConfig } = require('../core/config');
|
|
13
|
+
const { setupIntegrationTestAuth } = require('../external-system/test-auth');
|
|
14
|
+
const { runDatasourceAgentTrust } = require('../datasource/agent-trust-run');
|
|
15
|
+
const { resolveExternalIntegrationContext } = require('./test-e2e-external');
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @param {string} systemKey
|
|
19
|
+
* @param {Object} options
|
|
20
|
+
* @returns {Promise<{ authConfig: Object, dataplaneUrl: string }|null>}
|
|
21
|
+
*/
|
|
22
|
+
async function syncLocalIfRequested(systemKey, options) {
|
|
23
|
+
if (cliOptsSkipSync(options)) return null;
|
|
24
|
+
const { uploadExternalSystem } = require('./upload');
|
|
25
|
+
logger.log(chalk.cyan('Syncing local config to dataplane…'));
|
|
26
|
+
const uploadCtx = await uploadExternalSystem(systemKey, {
|
|
27
|
+
minimal: true,
|
|
28
|
+
verbose: !!options.verbose
|
|
29
|
+
});
|
|
30
|
+
logger.log(chalk.green('✔ Sync complete'));
|
|
31
|
+
return uploadCtx && uploadCtx.dataplaneUrl && uploadCtx.authConfig ? uploadCtx : null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function pushTrustResult(results, key, trustRun, apiError) {
|
|
35
|
+
const failed =
|
|
36
|
+
apiError ||
|
|
37
|
+
!trustRun ||
|
|
38
|
+
trustRun.trustDecision === 'notTrusted' ||
|
|
39
|
+
trustRun.validationStatus === 'failed';
|
|
40
|
+
results.push({
|
|
41
|
+
key,
|
|
42
|
+
success: !failed,
|
|
43
|
+
error: failed
|
|
44
|
+
? apiError
|
|
45
|
+
? apiError.message || String(apiError)
|
|
46
|
+
: trustRun.summary || 'Trust validation failed'
|
|
47
|
+
: undefined,
|
|
48
|
+
trustRun
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* @async
|
|
54
|
+
* @param {Object|null} uploadCtx
|
|
55
|
+
* @param {string} externalSystem
|
|
56
|
+
* @param {Object} options
|
|
57
|
+
* @returns {Promise<{ authConfig: Object, dataplaneUrl: string }>}
|
|
58
|
+
*/
|
|
59
|
+
async function resolveTrustAuthContext(uploadCtx, externalSystem, options) {
|
|
60
|
+
if (uploadCtx) {
|
|
61
|
+
return { authConfig: uploadCtx.authConfig, dataplaneUrl: uploadCtx.dataplaneUrl };
|
|
62
|
+
}
|
|
63
|
+
const configObj = await getConfig();
|
|
64
|
+
return setupIntegrationTestAuth(externalSystem, { environment: options.env }, configObj);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* @async
|
|
69
|
+
* @param {string[]} keys
|
|
70
|
+
* @param {Object} runOpts
|
|
71
|
+
* @param {Array<Object>} results
|
|
72
|
+
*/
|
|
73
|
+
async function runTrustForDatasourceKeys(keys, runOpts, results) {
|
|
74
|
+
for (const key of keys) {
|
|
75
|
+
try {
|
|
76
|
+
const { trustRun, apiError } = await runDatasourceAgentTrust(key, runOpts);
|
|
77
|
+
pushTrustResult(results, key, trustRun, apiError);
|
|
78
|
+
} catch (err) {
|
|
79
|
+
results.push({ key, success: false, error: err.message, trustRun: null });
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* @async
|
|
86
|
+
* @param {string} externalSystem
|
|
87
|
+
* @param {Object} options
|
|
88
|
+
* @returns {Promise<{ success: boolean, results: Array<Object>, systemKey: string }>}
|
|
89
|
+
*/
|
|
90
|
+
async function runTestTrustForExternalSystem(externalSystem, options = {}) {
|
|
91
|
+
const { systemKey, keys } = resolveExternalIntegrationContext(externalSystem);
|
|
92
|
+
if (keys.length === 0) {
|
|
93
|
+
logger.log(chalk.yellow(`No datasources found for ${externalSystem}.`));
|
|
94
|
+
return { success: true, results: [], systemKey };
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const uploadCtx = await syncLocalIfRequested(systemKey, options);
|
|
98
|
+
if (options.revalidate === true) {
|
|
99
|
+
logger.log(chalk.cyan('Forcing revalidation (cache bypass) for each datasource…'));
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const { authConfig, dataplaneUrl } = await resolveTrustAuthContext(
|
|
103
|
+
uploadCtx,
|
|
104
|
+
externalSystem,
|
|
105
|
+
options
|
|
106
|
+
);
|
|
107
|
+
const results = [];
|
|
108
|
+
await runTrustForDatasourceKeys(
|
|
109
|
+
keys,
|
|
110
|
+
{
|
|
111
|
+
app: externalSystem,
|
|
112
|
+
environment: options.env,
|
|
113
|
+
noSync: true,
|
|
114
|
+
revalidate: options.revalidate === true,
|
|
115
|
+
summary: options.summary === true,
|
|
116
|
+
timeout: options.timeout,
|
|
117
|
+
authConfig,
|
|
118
|
+
dataplaneUrl
|
|
119
|
+
},
|
|
120
|
+
results
|
|
121
|
+
);
|
|
122
|
+
return { success: results.every(r => r.success), results, systemKey };
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
module.exports = {
|
|
126
|
+
runTestTrustForExternalSystem
|
|
127
|
+
};
|
package/lib/commands/upload.js
CHANGED
|
@@ -25,6 +25,8 @@ const { getDeploymentAuth, requireBearerForDataplanePipeline } = require('../uti
|
|
|
25
25
|
const { resolveDataplaneUrl } = require('../utils/dataplane-resolver');
|
|
26
26
|
const { getIntegrationPath } = require('../utils/paths');
|
|
27
27
|
const { pushCredentialSecrets } = require('../utils/credential-secrets-env');
|
|
28
|
+
const { runWithCredentialPushSpinner } = require('../utils/credential-push-ui');
|
|
29
|
+
const { runWithUploadPipelineSpinner } = require('../utils/upload-pipeline-ui');
|
|
28
30
|
const {
|
|
29
31
|
buildResolvedEnvMapForIntegration,
|
|
30
32
|
resolveConfigurationValues,
|
|
@@ -49,6 +51,7 @@ const {
|
|
|
49
51
|
const { maybeSyncSystemCertificationFromDataplane } = require('../certification/sync-system-certification');
|
|
50
52
|
const { cliOptsSkipCertSync } = require('../certification/cli-cert-sync-skip');
|
|
51
53
|
const { maybeSyncOpenApiFilesForMcp } = require('./repair-openapi-sync');
|
|
54
|
+
const { assertDataplaneCliVersionCompatible } = require('../utils/dataplane-cli-version-gate');
|
|
52
55
|
|
|
53
56
|
/**
|
|
54
57
|
* Validates system-key format (same as download).
|
|
@@ -170,13 +173,17 @@ async function resolvePayloadConfiguration(systemKey, payload) {
|
|
|
170
173
|
* @param {string} systemKey - System key
|
|
171
174
|
* @param {Object} payload - Upload payload
|
|
172
175
|
*/
|
|
173
|
-
async function pushAndLogCredentialSecrets(dataplaneUrl, authConfig, systemKey, payload) {
|
|
176
|
+
async function pushAndLogCredentialSecrets(dataplaneUrl, authConfig, systemKey, payload, uiOpts = {}) {
|
|
174
177
|
const envFilePath = path.join(getIntegrationPath(systemKey), '.env');
|
|
175
|
-
const pushResult = await
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
178
|
+
const pushResult = await runWithCredentialPushSpinner(
|
|
179
|
+
() =>
|
|
180
|
+
pushCredentialSecrets(dataplaneUrl, authConfig, {
|
|
181
|
+
envFilePath,
|
|
182
|
+
appName: systemKey,
|
|
183
|
+
payload
|
|
184
|
+
}),
|
|
185
|
+
{ systemKey, json: uiOpts.json === true }
|
|
186
|
+
);
|
|
180
187
|
if (pushResult.pushed > 0) {
|
|
181
188
|
const keyList = pushResult.keys?.length ? ` (${pushResult.keys.join(', ')})` : '';
|
|
182
189
|
logger.log(
|
|
@@ -364,8 +371,13 @@ async function handlePublicationAndFollowups(ctx) {
|
|
|
364
371
|
* @param {Object} payload
|
|
365
372
|
*/
|
|
366
373
|
async function runUploadPublishAndSummary(systemKey, options, manifest, payload) {
|
|
367
|
-
const { dataplaneUrl, authConfig, environment } = await resolveDataplaneAndAuth(systemKey
|
|
374
|
+
const { dataplaneUrl, authConfig, environment } = await resolveDataplaneAndAuth(systemKey, {
|
|
375
|
+
silent: options.silentResolve === true
|
|
376
|
+
});
|
|
368
377
|
requireBearerForDataplanePipeline(authConfig);
|
|
378
|
+
const controllerUrl = await resolveControllerUrl();
|
|
379
|
+
// Plan 142.0: gate dataplane API entrypoints by the dataplane-advertised minimum Builder CLI version.
|
|
380
|
+
await assertDataplaneCliVersionCompatible(dataplaneUrl, { controllerUrl });
|
|
369
381
|
logger.log('');
|
|
370
382
|
logger.log(sectionTitle('Target'));
|
|
371
383
|
logger.log(SEP);
|
|
@@ -375,10 +387,18 @@ async function runUploadPublishAndSummary(systemKey, options, manifest, payload)
|
|
|
375
387
|
if (options.verbose) {
|
|
376
388
|
await maybeRunVerboseServerValidation(dataplaneUrl, authConfig, payload);
|
|
377
389
|
}
|
|
378
|
-
await pushAndLogCredentialSecrets(dataplaneUrl, authConfig, systemKey, payload
|
|
390
|
+
await pushAndLogCredentialSecrets(dataplaneUrl, authConfig, systemKey, payload, {
|
|
391
|
+
json: options.json === true
|
|
392
|
+
});
|
|
379
393
|
|
|
380
|
-
const rawRes = await
|
|
381
|
-
|
|
394
|
+
const rawRes = await runWithUploadPipelineSpinner(
|
|
395
|
+
async() => {
|
|
396
|
+
const res = await runUploadValidatePublish(dataplaneUrl, authConfig, payload);
|
|
397
|
+
await logAndSyncLocalOpenApiForUpload(systemKey, manifest);
|
|
398
|
+
return res;
|
|
399
|
+
},
|
|
400
|
+
{ systemKey, json: options.json === true }
|
|
401
|
+
);
|
|
382
402
|
await handlePublicationAndFollowups({
|
|
383
403
|
systemKey,
|
|
384
404
|
options,
|
|
@@ -389,6 +409,7 @@ async function runUploadPublishAndSummary(systemKey, options, manifest, payload)
|
|
|
389
409
|
authConfig,
|
|
390
410
|
rawRes
|
|
391
411
|
});
|
|
412
|
+
return { dataplaneUrl, authConfig, environment };
|
|
392
413
|
}
|
|
393
414
|
|
|
394
415
|
/**
|
|
@@ -400,7 +421,7 @@ async function runUploadPublishAndSummary(systemKey, options, manifest, payload)
|
|
|
400
421
|
* @param {boolean} [options.probe] - POST validation/run after publish
|
|
401
422
|
* @param {number} [options.probeTimeout] - Probe timeout ms (default 120000)
|
|
402
423
|
* @param {boolean} [options.minimal] - Short summary only
|
|
403
|
-
* @returns {Promise<void>}
|
|
424
|
+
* @returns {Promise<{ dataplaneUrl: string, authConfig: Object, environment: string }|void>}
|
|
404
425
|
* @throws {Error} If validation or API calls fail
|
|
405
426
|
*/
|
|
406
427
|
async function uploadExternalSystem(systemKey, options = {}) {
|
|
@@ -417,9 +438,9 @@ async function uploadExternalSystem(systemKey, options = {}) {
|
|
|
417
438
|
logger.log(
|
|
418
439
|
chalk.gray(` System: ${manifest.key}, version: ${payload.version}, datasources: ${payload.dataSources.length}`)
|
|
419
440
|
);
|
|
420
|
-
return;
|
|
441
|
+
return undefined;
|
|
421
442
|
}
|
|
422
|
-
|
|
443
|
+
return runUploadPublishAndSummary(systemKey, options, manifest, payload);
|
|
423
444
|
}
|
|
424
445
|
|
|
425
446
|
module.exports = {
|
|
@@ -525,6 +525,9 @@ async function setupDataplaneAndAuth(options, appName) {
|
|
|
525
525
|
' aifabrix login'
|
|
526
526
|
);
|
|
527
527
|
}
|
|
528
|
+
// Plan 142.0: gate wizard dataplane calls by the dataplane-advertised minimum Builder CLI version.
|
|
529
|
+
const { assertDataplaneCliVersionCompatible } = require('../utils/dataplane-cli-version-gate');
|
|
530
|
+
await assertDataplaneCliVersionCompatible(dataplaneUrl, { controllerUrl });
|
|
528
531
|
return { dataplaneUrl, authConfig };
|
|
529
532
|
}
|
|
530
533
|
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persist dataplane version metadata under `device.<controllerUrl>` in
|
|
3
|
+
* `~/.aifabrix/config.yaml` for the Builder CLI compatibility gate (plan 142.0).
|
|
4
|
+
*
|
|
5
|
+
* Only public dataplane fields are written here. Token / refresh-token entries
|
|
6
|
+
* on the same device entry are preserved untouched.
|
|
7
|
+
*
|
|
8
|
+
* Schema additions (kebab-case, matching `developer-id` style):
|
|
9
|
+
* - `dataplane-version` ← health `version`
|
|
10
|
+
* - `dataplane-min-cli-version` ← health `minBuilderCliVersion` (omitted when not enforced)
|
|
11
|
+
* - `dataplane-checked-at` ← ISO timestamp for cache TTL (default 5 min)
|
|
12
|
+
*
|
|
13
|
+
* @fileoverview Cache dataplane health under existing `device.<controllerUrl>` entry
|
|
14
|
+
* @author AI Fabrix Team
|
|
15
|
+
* @version 2.0.0
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
'use strict';
|
|
19
|
+
|
|
20
|
+
const { getConfig, saveConfig, normalizeControllerUrl } = require('./config');
|
|
21
|
+
|
|
22
|
+
const DEFAULT_CACHE_TTL_MS = 5 * 60 * 1000;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Resolve the device entry key matching `controllerUrl`, taking URL
|
|
26
|
+
* normalization into account so callers do not need to worry about trailing
|
|
27
|
+
* slashes or scheme differences.
|
|
28
|
+
* @private
|
|
29
|
+
* @param {Object} deviceMap - `config.device` map
|
|
30
|
+
* @param {string} normalizedUrl
|
|
31
|
+
* @returns {string|null} The key under `config.device` or null when missing
|
|
32
|
+
*/
|
|
33
|
+
function findDeviceKey(deviceMap, normalizedUrl) {
|
|
34
|
+
if (!deviceMap || typeof deviceMap !== 'object') return null;
|
|
35
|
+
if (deviceMap[normalizedUrl]) return normalizedUrl;
|
|
36
|
+
for (const storedUrl of Object.keys(deviceMap)) {
|
|
37
|
+
if (normalizeControllerUrl(storedUrl) === normalizedUrl) {
|
|
38
|
+
return storedUrl;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Read the dataplane cache currently persisted under `device.<controllerUrl>`.
|
|
46
|
+
*
|
|
47
|
+
* @async
|
|
48
|
+
* @param {string} controllerUrl
|
|
49
|
+
* @returns {Promise<{
|
|
50
|
+
* version?: string,
|
|
51
|
+
* minBuilderCliVersion?: string,
|
|
52
|
+
* checkedAt?: string
|
|
53
|
+
* }|null>} The cached snapshot, or null when no entry exists
|
|
54
|
+
* @throws {Error} If controllerUrl is missing
|
|
55
|
+
*/
|
|
56
|
+
async function getDeviceDataplaneVersions(controllerUrl) {
|
|
57
|
+
if (!controllerUrl || typeof controllerUrl !== 'string') {
|
|
58
|
+
throw new Error('controllerUrl is required and must be a string');
|
|
59
|
+
}
|
|
60
|
+
const config = await getConfig();
|
|
61
|
+
const normalizedUrl = normalizeControllerUrl(controllerUrl);
|
|
62
|
+
const key = findDeviceKey(config.device, normalizedUrl);
|
|
63
|
+
if (!key) return null;
|
|
64
|
+
const entry = config.device[key];
|
|
65
|
+
if (!entry || typeof entry !== 'object') return null;
|
|
66
|
+
const snapshot = {};
|
|
67
|
+
if (typeof entry['dataplane-version'] === 'string') {
|
|
68
|
+
snapshot.version = entry['dataplane-version'];
|
|
69
|
+
}
|
|
70
|
+
if (typeof entry['dataplane-min-cli-version'] === 'string') {
|
|
71
|
+
snapshot.minBuilderCliVersion = entry['dataplane-min-cli-version'];
|
|
72
|
+
}
|
|
73
|
+
if (typeof entry['dataplane-checked-at'] === 'string') {
|
|
74
|
+
snapshot.checkedAt = entry['dataplane-checked-at'];
|
|
75
|
+
}
|
|
76
|
+
if (Object.keys(snapshot).length === 0) return null;
|
|
77
|
+
return snapshot;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Apply the `dataplane-version` field to a device entry in-place.
|
|
82
|
+
* @private
|
|
83
|
+
* @param {Object} entry
|
|
84
|
+
* @param {string|null|undefined} version
|
|
85
|
+
*/
|
|
86
|
+
function applyDataplaneVersionField(entry, version) {
|
|
87
|
+
if (typeof version === 'string' && version.trim()) {
|
|
88
|
+
entry['dataplane-version'] = version.trim();
|
|
89
|
+
} else if (version === null || version === '') {
|
|
90
|
+
delete entry['dataplane-version'];
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Apply the `dataplane-min-cli-version` field to a device entry in-place.
|
|
96
|
+
* Treat absent / empty as "no enforcement" → clear the cached floor so an
|
|
97
|
+
* older value never lingers after the operator removes the env variable.
|
|
98
|
+
* @private
|
|
99
|
+
* @param {Object} entry
|
|
100
|
+
* @param {string|null|undefined} minCli
|
|
101
|
+
*/
|
|
102
|
+
function applyMinCliField(entry, minCli) {
|
|
103
|
+
if (typeof minCli === 'string' && minCli.trim()) {
|
|
104
|
+
entry['dataplane-min-cli-version'] = minCli.trim();
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
if (minCli === null || minCli === '' || minCli === undefined) {
|
|
108
|
+
delete entry['dataplane-min-cli-version'];
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Compute the timestamp persisted as `dataplane-checked-at`.
|
|
114
|
+
* @private
|
|
115
|
+
* @param {string|undefined} checkedAt
|
|
116
|
+
* @returns {string} ISO timestamp
|
|
117
|
+
*/
|
|
118
|
+
function resolveCheckedAt(checkedAt) {
|
|
119
|
+
if (typeof checkedAt === 'string' && checkedAt.trim()) {
|
|
120
|
+
return checkedAt.trim();
|
|
121
|
+
}
|
|
122
|
+
return new Date().toISOString();
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Persist dataplane version metadata under the device entry for `controllerUrl`.
|
|
127
|
+
*
|
|
128
|
+
* Token / refresh-token entries are preserved; only the `dataplane-*` keys are
|
|
129
|
+
* written. When `versions.minBuilderCliVersion` is empty/undefined the cache
|
|
130
|
+
* key is removed (dataplane does not enforce a minimum).
|
|
131
|
+
*
|
|
132
|
+
* @async
|
|
133
|
+
* @param {string} controllerUrl - Controller URL (will be normalized)
|
|
134
|
+
* @param {{
|
|
135
|
+
* version?: string,
|
|
136
|
+
* minBuilderCliVersion?: string|null,
|
|
137
|
+
* checkedAt?: string
|
|
138
|
+
* }} versions
|
|
139
|
+
* @returns {Promise<void>}
|
|
140
|
+
* @throws {Error} If controllerUrl is missing
|
|
141
|
+
*/
|
|
142
|
+
async function updateDeviceDataplaneVersions(controllerUrl, versions = {}) {
|
|
143
|
+
if (!controllerUrl || typeof controllerUrl !== 'string') {
|
|
144
|
+
throw new Error('controllerUrl is required and must be a string');
|
|
145
|
+
}
|
|
146
|
+
const config = await getConfig();
|
|
147
|
+
if (!config.device || typeof config.device !== 'object') {
|
|
148
|
+
config.device = {};
|
|
149
|
+
}
|
|
150
|
+
const normalizedUrl = normalizeControllerUrl(controllerUrl);
|
|
151
|
+
const key = findDeviceKey(config.device, normalizedUrl) || normalizedUrl;
|
|
152
|
+
if (!config.device[key] || typeof config.device[key] !== 'object') {
|
|
153
|
+
config.device[key] = {};
|
|
154
|
+
}
|
|
155
|
+
const entry = config.device[key];
|
|
156
|
+
|
|
157
|
+
applyDataplaneVersionField(entry, versions.version);
|
|
158
|
+
applyMinCliField(entry, versions.minBuilderCliVersion);
|
|
159
|
+
entry['dataplane-checked-at'] = resolveCheckedAt(versions.checkedAt);
|
|
160
|
+
|
|
161
|
+
await saveConfig(config);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* True when the cached snapshot is older than the configured TTL (or missing).
|
|
166
|
+
*
|
|
167
|
+
* @param {{checkedAt?: string}|null} snapshot
|
|
168
|
+
* @param {number} [ttlMs] - TTL in milliseconds (defaults to 5 minutes)
|
|
169
|
+
* @param {Date|number} [now] - Override "now" for tests
|
|
170
|
+
* @returns {boolean}
|
|
171
|
+
*/
|
|
172
|
+
function isCacheStale(snapshot, ttlMs = DEFAULT_CACHE_TTL_MS, now = Date.now()) {
|
|
173
|
+
if (!snapshot || !snapshot.checkedAt) return true;
|
|
174
|
+
const checkedAtMs = Date.parse(snapshot.checkedAt);
|
|
175
|
+
if (Number.isNaN(checkedAtMs)) return true;
|
|
176
|
+
const reference = typeof now === 'number' ? now : now.getTime();
|
|
177
|
+
return reference - checkedAtMs >= ttlMs;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
module.exports = {
|
|
181
|
+
getDeviceDataplaneVersions,
|
|
182
|
+
updateDeviceDataplaneVersions,
|
|
183
|
+
isCacheStale,
|
|
184
|
+
DEFAULT_CACHE_TTL_MS
|
|
185
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Debug log writer for agent trust CLI runs (plan 143).
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
'use strict';
|
|
6
|
+
|
|
7
|
+
const chalk = require('chalk');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const logger = require('../utils/logger');
|
|
10
|
+
const { getIntegrationPath } = require('../utils/paths');
|
|
11
|
+
const { writeTestLog } = require('../utils/test-log-writer');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @async
|
|
15
|
+
* @param {string} appKey - Integration folder key
|
|
16
|
+
* @param {string} datasourceKey
|
|
17
|
+
* @param {Object} payload
|
|
18
|
+
* @returns {Promise<string|null>} Log path or null when skipped
|
|
19
|
+
*/
|
|
20
|
+
async function writeTrustDebugLog(appKey, datasourceKey, payload) {
|
|
21
|
+
const logPath = await writeTestLog(
|
|
22
|
+
appKey,
|
|
23
|
+
payload,
|
|
24
|
+
`test-trust-${datasourceKey}`,
|
|
25
|
+
path.dirname(getIntegrationPath(appKey))
|
|
26
|
+
);
|
|
27
|
+
return logPath;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @async
|
|
32
|
+
* @param {string} appKey
|
|
33
|
+
* @param {string} datasourceKey
|
|
34
|
+
* @param {Object} payload
|
|
35
|
+
*/
|
|
36
|
+
async function writeTrustDebugLogAndPrint(appKey, datasourceKey, payload) {
|
|
37
|
+
const logPath = await writeTrustDebugLog(appKey, datasourceKey, payload);
|
|
38
|
+
logger.log(chalk.gray(` Debug log: ${logPath}`));
|
|
39
|
+
return logPath;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
module.exports = {
|
|
43
|
+
writeTrustDebugLog,
|
|
44
|
+
writeTrustDebugLogAndPrint
|
|
45
|
+
};
|