@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,286 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Protection subcommand registration (keeps setupProtectionCommands under line limit).
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
'use strict';
|
|
6
|
+
|
|
7
|
+
const logger = require('../utils/logger');
|
|
8
|
+
const { resolveProtectionArgument } = require('../protection/resolve');
|
|
9
|
+
const {
|
|
10
|
+
runProtectionValidate,
|
|
11
|
+
runProtectionUpload,
|
|
12
|
+
runProtectionList,
|
|
13
|
+
runProtectionShow,
|
|
14
|
+
runProtectionDelete
|
|
15
|
+
} = require('../protection/run-commands');
|
|
16
|
+
const { runProtectionCreate } = require('../protection/run-protection-create');
|
|
17
|
+
|
|
18
|
+
const SHARED_OPTS = [
|
|
19
|
+
['-e, --env <environment>', 'Environment key'],
|
|
20
|
+
['-v, --verbose', 'Verbose output']
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
const PROTECTION_CREATE_HELP_AFTER = `
|
|
24
|
+
|
|
25
|
+
Examples:
|
|
26
|
+
$ aifabrix protection create hubspot-companies --type country-sales
|
|
27
|
+
$ aifabrix protection create hr-persons --type department-manager
|
|
28
|
+
$ aifabrix protection create erp-projects --type project-team
|
|
29
|
+
$ aifabrix protection create hubspot-companies --dimension-key country --dry-run
|
|
30
|
+
$ aifabrix protection create hubspot-companies --type country-sales --force
|
|
31
|
+
|
|
32
|
+
Preset types:
|
|
33
|
+
country-sales, department-manager, customer-team, project-team, static-region, owner-direct
|
|
34
|
+
`;
|
|
35
|
+
|
|
36
|
+
const PROTECTION_VALIDATE_HELP_AFTER = `
|
|
37
|
+
|
|
38
|
+
Examples:
|
|
39
|
+
$ aifabrix protection validate hubspot-companies
|
|
40
|
+
$ aifabrix protection validate hubspot-companies --simulate
|
|
41
|
+
$ aifabrix protection validate hubspot-companies --warnings-as-errors
|
|
42
|
+
$ aifabrix protection validate hubspot-companies --json
|
|
43
|
+
`;
|
|
44
|
+
|
|
45
|
+
const PROTECTION_UPLOAD_HELP_AFTER = `
|
|
46
|
+
|
|
47
|
+
Examples:
|
|
48
|
+
$ aifabrix protection upload hubspot-companies
|
|
49
|
+
$ aifabrix protection upload hubspot-companies --dry-run
|
|
50
|
+
$ aifabrix protection upload hubspot-companies --no-sync
|
|
51
|
+
`;
|
|
52
|
+
|
|
53
|
+
const PROTECTION_LIST_HELP_AFTER = `
|
|
54
|
+
|
|
55
|
+
Examples:
|
|
56
|
+
$ aifabrix protection list
|
|
57
|
+
$ aifabrix protection list --page 1 --page-size 50
|
|
58
|
+
$ aifabrix protection list --filter enabled:eq:true
|
|
59
|
+
$ aifabrix protection list --json
|
|
60
|
+
`;
|
|
61
|
+
|
|
62
|
+
const PROTECTION_SHOW_HELP_AFTER = `
|
|
63
|
+
|
|
64
|
+
Examples:
|
|
65
|
+
$ aifabrix protection show hubspot-companies
|
|
66
|
+
$ aifabrix protection show hubspot-companies -v
|
|
67
|
+
$ aifabrix protection show hubspot-companies --json
|
|
68
|
+
`;
|
|
69
|
+
|
|
70
|
+
const PROTECTION_DELETE_HELP_AFTER = `
|
|
71
|
+
|
|
72
|
+
Examples:
|
|
73
|
+
$ aifabrix protection delete hubspot-companies
|
|
74
|
+
$ aifabrix protection delete hubspot-companies --yes
|
|
75
|
+
`;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* @param {import('commander').Command} cmd
|
|
79
|
+
* @param {string} name
|
|
80
|
+
* @param {string} description
|
|
81
|
+
* @param {Function} action
|
|
82
|
+
* @param {Array<[string, string]>} extraOpts
|
|
83
|
+
* @param {string} helpAfter
|
|
84
|
+
*/
|
|
85
|
+
function addProtectionLeaf(cmd, name, description, action, extraOpts = [], helpAfter = '') {
|
|
86
|
+
const leaf = cmd.command(name).description(description);
|
|
87
|
+
for (const [flags, desc] of [...SHARED_OPTS, ...extraOpts]) {
|
|
88
|
+
leaf.option(flags, desc);
|
|
89
|
+
}
|
|
90
|
+
if (helpAfter) {
|
|
91
|
+
leaf.addHelpText('after', helpAfter);
|
|
92
|
+
}
|
|
93
|
+
leaf.action(async(datasourceKey, options) => {
|
|
94
|
+
try {
|
|
95
|
+
const code = await action(datasourceKey, options);
|
|
96
|
+
if (code && code !== 0) process.exit(code);
|
|
97
|
+
} catch (err) {
|
|
98
|
+
const { formatBlockingError } = require('../utils/cli-test-layout-chalk');
|
|
99
|
+
logger.error(formatBlockingError(err.message || String(err)));
|
|
100
|
+
process.exit(1);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* @param {import('commander').Command} protection
|
|
107
|
+
*/
|
|
108
|
+
function registerProtectionCreate(protection) {
|
|
109
|
+
const leaf = protection
|
|
110
|
+
.command('create <datasourceKey>')
|
|
111
|
+
.description(
|
|
112
|
+
'Probe dataplane datasource + Controller dimension, then scaffold under integration/.protection/'
|
|
113
|
+
);
|
|
114
|
+
for (const [flags, desc] of SHARED_OPTS) {
|
|
115
|
+
leaf.option(flags, desc);
|
|
116
|
+
}
|
|
117
|
+
leaf
|
|
118
|
+
.option('--type <type>', 'Preset type (country-sales, department-manager, customer-team, project-team, static-region, owner-direct)')
|
|
119
|
+
.option('--dimension-key <key>', 'Dimension catalog key (inferred from --type when omitted)')
|
|
120
|
+
.option('--field <name>', 'Metadata field used by preset value templates when needed')
|
|
121
|
+
.option('--fk-name <name>', 'FK binding name in expressions (default: same as dimension key)')
|
|
122
|
+
.option('--protection-key <key>', 'metadata.key (default: <datasource>-<dimension>-access)')
|
|
123
|
+
.option('--display-name <text>', 'metadata.displayName')
|
|
124
|
+
.option('--rule-key <key>', 'Rule key inside spec.rules[0]')
|
|
125
|
+
.option('--principal-expression <expr>', 'Group principal expression (default: Sales {{fk.<fk>.metadata.iso3}} Users)')
|
|
126
|
+
.option('--value-expression <expr>', 'Grant valueExpression (default: {{fk.<fk>.metadata.iso2}})')
|
|
127
|
+
.option('--dry-run', 'Print YAML to stdout; do not write file')
|
|
128
|
+
.option('--force', 'Overwrite existing integration/.protection/<datasourceKey> manifest')
|
|
129
|
+
.option('--disabled', 'Set spec.enabled to false', false)
|
|
130
|
+
.addHelpText('after', PROTECTION_CREATE_HELP_AFTER)
|
|
131
|
+
.action(async(datasourceKey, options) => {
|
|
132
|
+
try {
|
|
133
|
+
const code = await runProtectionCreate(datasourceKey, {
|
|
134
|
+
...options,
|
|
135
|
+
dryRun: options.dryRun === true,
|
|
136
|
+
force: options.force === true,
|
|
137
|
+
verbose: options.verbose === true,
|
|
138
|
+
disabled: options.disabled === true
|
|
139
|
+
}, logger);
|
|
140
|
+
if (code && code !== 0) process.exit(code);
|
|
141
|
+
} catch (err) {
|
|
142
|
+
const { formatBlockingError } = require('../utils/cli-test-layout-chalk');
|
|
143
|
+
if (Array.isArray(err.probeLines)) {
|
|
144
|
+
for (const line of err.probeLines) {
|
|
145
|
+
logger.log(line);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
logger.error(formatBlockingError(err.message || String(err)));
|
|
149
|
+
process.exit(1);
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* @param {import('commander').Command} protection
|
|
156
|
+
*/
|
|
157
|
+
function registerProtectionValidate(protection) {
|
|
158
|
+
addProtectionLeaf(
|
|
159
|
+
protection,
|
|
160
|
+
'validate <datasourceKey>',
|
|
161
|
+
'Validate protection manifest (local schema + dataplane)',
|
|
162
|
+
async(datasourceKey, options) => {
|
|
163
|
+
const resolved = resolveProtectionArgument(datasourceKey);
|
|
164
|
+
return runProtectionValidate(resolved.datasourceKey, resolved.manifest, {
|
|
165
|
+
...options,
|
|
166
|
+
manifestPath: resolved.manifestPath,
|
|
167
|
+
warningsAsErrors: options.warningsAsErrors === true,
|
|
168
|
+
simulate: options.simulate === true,
|
|
169
|
+
json: options.json === true,
|
|
170
|
+
verbose: options.verbose === true
|
|
171
|
+
}, logger);
|
|
172
|
+
},
|
|
173
|
+
[
|
|
174
|
+
['--json', 'Output dataplane report as JSON'],
|
|
175
|
+
['--warnings-as-errors', 'Pass strict=true to dataplane validate'],
|
|
176
|
+
['--simulate', 'Run simulate after validate passes']
|
|
177
|
+
],
|
|
178
|
+
PROTECTION_VALIDATE_HELP_AFTER
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* @param {import('commander').Command} protection
|
|
184
|
+
*/
|
|
185
|
+
function registerProtectionUpload(protection) {
|
|
186
|
+
addProtectionLeaf(
|
|
187
|
+
protection,
|
|
188
|
+
'upload <datasourceKey>',
|
|
189
|
+
'Validate and upload protection manifest to dataplane',
|
|
190
|
+
async(datasourceKey, options) => {
|
|
191
|
+
const resolved = resolveProtectionArgument(datasourceKey);
|
|
192
|
+
return runProtectionUpload(resolved.datasourceKey, resolved.manifest, {
|
|
193
|
+
...options,
|
|
194
|
+
manifestPath: resolved.manifestPath,
|
|
195
|
+
warningsAsErrors: options.warningsAsErrors === true,
|
|
196
|
+
dryRun: options.dryRun === true,
|
|
197
|
+
noSync: options.noSync === true,
|
|
198
|
+
verbose: options.verbose === true
|
|
199
|
+
}, logger);
|
|
200
|
+
},
|
|
201
|
+
[
|
|
202
|
+
['--dry-run', 'Validate only; no upload or sync'],
|
|
203
|
+
['--no-sync', 'Skip datasource sync after upload']
|
|
204
|
+
],
|
|
205
|
+
PROTECTION_UPLOAD_HELP_AFTER
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* @param {import('commander').Command} protection
|
|
211
|
+
*/
|
|
212
|
+
function registerProtectionList(protection) {
|
|
213
|
+
const leaf = protection.command('list').description('List deployed protection manifests on dataplane');
|
|
214
|
+
for (const [flags, desc] of SHARED_OPTS) {
|
|
215
|
+
leaf.option(flags, desc);
|
|
216
|
+
}
|
|
217
|
+
leaf
|
|
218
|
+
.option('--json', 'Output paginated list as JSON')
|
|
219
|
+
.option('--page <n>', 'Page (1-based)', (v) => parseInt(v, 10))
|
|
220
|
+
.option('--page-size <n>', 'Page size', (v) => parseInt(v, 10))
|
|
221
|
+
.option('--filter <expr>', 'Filter (e.g. enabled:eq:true)')
|
|
222
|
+
.addHelpText('after', PROTECTION_LIST_HELP_AFTER)
|
|
223
|
+
.action(async(options) => {
|
|
224
|
+
try {
|
|
225
|
+
const code = await runProtectionList(
|
|
226
|
+
{
|
|
227
|
+
...options,
|
|
228
|
+
json: options.json === true,
|
|
229
|
+
verbose: options.verbose === true
|
|
230
|
+
},
|
|
231
|
+
logger
|
|
232
|
+
);
|
|
233
|
+
if (code && code !== 0) process.exit(code);
|
|
234
|
+
} catch (err) {
|
|
235
|
+
const { formatBlockingError } = require('../utils/cli-test-layout-chalk');
|
|
236
|
+
logger.error(formatBlockingError(err.message || String(err)));
|
|
237
|
+
process.exit(1);
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* @param {import('commander').Command} protection
|
|
244
|
+
*/
|
|
245
|
+
function registerProtectionShow(protection) {
|
|
246
|
+
addProtectionLeaf(
|
|
247
|
+
protection,
|
|
248
|
+
'show <datasourceKey>',
|
|
249
|
+
'Show deployed protection state from dataplane',
|
|
250
|
+
async(datasourceKey, options) =>
|
|
251
|
+
runProtectionShow(datasourceKey, {
|
|
252
|
+
...options,
|
|
253
|
+
json: options.json === true,
|
|
254
|
+
verbose: options.verbose === true
|
|
255
|
+
}, logger),
|
|
256
|
+
[['--json', 'Output merged manifest + status as JSON']],
|
|
257
|
+
PROTECTION_SHOW_HELP_AFTER
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* @param {import('commander').Command} protection
|
|
263
|
+
*/
|
|
264
|
+
function registerProtectionDelete(protection) {
|
|
265
|
+
addProtectionLeaf(
|
|
266
|
+
protection,
|
|
267
|
+
'delete <datasourceKey>',
|
|
268
|
+
'Delete deployed protection for datasource',
|
|
269
|
+
async(datasourceKey, options) =>
|
|
270
|
+
runProtectionDelete(datasourceKey, {
|
|
271
|
+
...options,
|
|
272
|
+
yes: options.yes === true
|
|
273
|
+
}, logger),
|
|
274
|
+
[['--yes', 'Skip confirmation prompt']],
|
|
275
|
+
PROTECTION_DELETE_HELP_AFTER
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
module.exports = {
|
|
280
|
+
registerProtectionCreate,
|
|
281
|
+
registerProtectionValidate,
|
|
282
|
+
registerProtectionUpload,
|
|
283
|
+
registerProtectionList,
|
|
284
|
+
registerProtectionShow,
|
|
285
|
+
registerProtectionDelete
|
|
286
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Protection manifest CLI commands.
|
|
3
|
+
* @author AI Fabrix Team
|
|
4
|
+
* @version 1.0.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
'use strict';
|
|
8
|
+
|
|
9
|
+
const {
|
|
10
|
+
registerProtectionCreate,
|
|
11
|
+
registerProtectionValidate,
|
|
12
|
+
registerProtectionUpload,
|
|
13
|
+
registerProtectionList,
|
|
14
|
+
registerProtectionShow,
|
|
15
|
+
registerProtectionDelete
|
|
16
|
+
} = require('./protection-cli-leaves');
|
|
17
|
+
|
|
18
|
+
const PROTECTION_HELP_AFTER = `
|
|
19
|
+
|
|
20
|
+
Examples:
|
|
21
|
+
$ aifabrix protection create hubspot-companies --type country-sales
|
|
22
|
+
$ aifabrix protection validate hubspot-companies --simulate
|
|
23
|
+
$ aifabrix protection upload hubspot-companies --dry-run
|
|
24
|
+
$ aifabrix protection list
|
|
25
|
+
$ aifabrix protection show hubspot-companies
|
|
26
|
+
$ aifabrix protection delete hubspot-companies --yes
|
|
27
|
+
|
|
28
|
+
Per-command help: aifabrix protection <command> --help
|
|
29
|
+
`;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @param {import('commander').Command} program
|
|
33
|
+
*/
|
|
34
|
+
function setupProtectionCommands(program) {
|
|
35
|
+
const protection = program
|
|
36
|
+
.command('protection')
|
|
37
|
+
.description('Manage protection manifests in integration/.protection/ (repo root)')
|
|
38
|
+
.addHelpText('after', PROTECTION_HELP_AFTER);
|
|
39
|
+
|
|
40
|
+
registerProtectionCreate(protection);
|
|
41
|
+
registerProtectionValidate(protection);
|
|
42
|
+
registerProtectionUpload(protection);
|
|
43
|
+
registerProtectionList(protection);
|
|
44
|
+
registerProtectionShow(protection);
|
|
45
|
+
registerProtectionDelete(protection);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
module.exports = {
|
|
49
|
+
setupProtectionCommands
|
|
50
|
+
};
|
package/lib/commands/repair.js
CHANGED
|
@@ -125,11 +125,21 @@ function applyAuthMethod(ctx) {
|
|
|
125
125
|
const existingAuth = ctx.systemParsed.authentication || ctx.systemParsed.auth || {};
|
|
126
126
|
const { buildAuthenticationFromMethod } = require('../external-system/generator');
|
|
127
127
|
const newAuth = buildAuthenticationFromMethod(ctx.systemKey, method);
|
|
128
|
-
const existingVars =
|
|
129
|
-
|
|
128
|
+
const existingVars =
|
|
129
|
+
existingAuth.variables && typeof existingAuth.variables === 'object'
|
|
130
|
+
? existingAuth.variables
|
|
131
|
+
: {};
|
|
132
|
+
// When switching auth method, keep only connectivity fields from the wizard draft.
|
|
133
|
+
// Do not let OAuth-era variables (tokenUrl, scope, headerName, …) override the new method.
|
|
134
|
+
const mergedVariables = { ...newAuth.variables };
|
|
135
|
+
for (const key of ['baseUrl', 'testEndpoint']) {
|
|
136
|
+
if (existingVars[key] !== undefined && existingVars[key] !== null) {
|
|
137
|
+
mergedVariables[key] = existingVars[key];
|
|
138
|
+
}
|
|
139
|
+
}
|
|
130
140
|
ctx.systemParsed.authentication = {
|
|
131
141
|
...newAuth,
|
|
132
|
-
variables:
|
|
142
|
+
variables: mergedVariables
|
|
133
143
|
};
|
|
134
144
|
if (existingAuth.displayName !== undefined) {
|
|
135
145
|
ctx.systemParsed.authentication.displayName = existingAuth.displayName;
|
|
@@ -18,6 +18,9 @@ const { resolveApplicationConfigPath } = require('../utils/app-config-resolver')
|
|
|
18
18
|
const { loadConfigFile } = require('../utils/config-format');
|
|
19
19
|
const { discoverIntegrationFiles, buildEffectiveDatasourceFiles } = require('./repair-internal');
|
|
20
20
|
const { runDatasourceTestE2E } = require('../datasource/test-e2e');
|
|
21
|
+
const { cliOptsSkipSync } = require('../utils/cli-sync-options');
|
|
22
|
+
const { getConfig } = require('../core/config');
|
|
23
|
+
const { setupIntegrationTestAuth } = require('../external-system/test-auth');
|
|
21
24
|
|
|
22
25
|
/**
|
|
23
26
|
* Derives datasource key from filename when file has no key (same logic as repair).
|
|
@@ -89,17 +92,18 @@ function getDatasourceKeys(appPath, configPath, variables, systemKey, systemPars
|
|
|
89
92
|
* unless ``options.noSync`` is true.
|
|
90
93
|
* @param {string} systemKey
|
|
91
94
|
* @param {Object} options
|
|
92
|
-
* @returns {Promise<
|
|
95
|
+
* @returns {Promise<{ authConfig: Object, dataplaneUrl: string, environment?: string }|null>}
|
|
93
96
|
*/
|
|
94
97
|
async function syncLocalIfRequested(systemKey, options) {
|
|
95
|
-
if (options
|
|
98
|
+
if (cliOptsSkipSync(options)) return null;
|
|
96
99
|
logger.log(chalk.cyan('Syncing local config to dataplane…'));
|
|
97
100
|
const { uploadExternalSystem } = require('./upload');
|
|
98
|
-
await uploadExternalSystem(systemKey, {
|
|
101
|
+
const uploadCtx = await uploadExternalSystem(systemKey, {
|
|
99
102
|
verbose: !!options.verbose,
|
|
100
103
|
minimal: true
|
|
101
104
|
});
|
|
102
105
|
logger.log(formatSuccessLine('Sync complete'));
|
|
106
|
+
return uploadCtx && uploadCtx.dataplaneUrl && uploadCtx.authConfig ? uploadCtx : null;
|
|
103
107
|
}
|
|
104
108
|
|
|
105
109
|
/* eslint-disable max-lines-per-function, max-statements -- Load context, then loop over keys */
|
|
@@ -116,7 +120,12 @@ async function syncLocalIfRequested(systemKey, options) {
|
|
|
116
120
|
* @param {boolean} [options.noSync] - When true, skip upload (E2E uses dataplane config already deployed)
|
|
117
121
|
* @returns {Promise<{ success: boolean, results: Array<{ key: string, success: boolean, error?: string }> }>}
|
|
118
122
|
*/
|
|
119
|
-
|
|
123
|
+
/**
|
|
124
|
+
* Resolve integration folder, system key, and datasource keys for system-level tests.
|
|
125
|
+
* @param {string} externalSystem
|
|
126
|
+
* @returns {{ systemKey: string, keys: string[] }}
|
|
127
|
+
*/
|
|
128
|
+
function resolveExternalIntegrationContext(externalSystem) {
|
|
120
129
|
if (!externalSystem || typeof externalSystem !== 'string') {
|
|
121
130
|
throw new Error('External system name is required');
|
|
122
131
|
}
|
|
@@ -140,9 +149,9 @@ async function runTestE2EForExternalSystem(externalSystem, options = {}) {
|
|
|
140
149
|
);
|
|
141
150
|
const systemPath = path.join(appPath, systemFiles[0]);
|
|
142
151
|
const systemParsed = loadConfigFile(systemPath);
|
|
143
|
-
const systemKey =
|
|
152
|
+
const systemKey =
|
|
153
|
+
systemParsed.key ||
|
|
144
154
|
path.basename(systemFiles[0], path.extname(systemFiles[0])).replace(/-system$/, '');
|
|
145
|
-
|
|
146
155
|
const keys = getDatasourceKeys(
|
|
147
156
|
appPath,
|
|
148
157
|
configPath,
|
|
@@ -151,12 +160,30 @@ async function runTestE2EForExternalSystem(externalSystem, options = {}) {
|
|
|
151
160
|
systemParsed,
|
|
152
161
|
datasourceFiles
|
|
153
162
|
);
|
|
163
|
+
return { systemKey, keys };
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
async function runTestE2EForExternalSystem(externalSystem, options = {}) {
|
|
167
|
+
const { systemKey, keys } = resolveExternalIntegrationContext(externalSystem);
|
|
154
168
|
if (keys.length === 0) {
|
|
155
169
|
logger.log(chalk.yellow(`No datasources found for ${externalSystem}. Add datasource files and run aifabrix repair.`));
|
|
156
170
|
return { success: true, results: [] };
|
|
157
171
|
}
|
|
158
172
|
|
|
159
|
-
await syncLocalIfRequested(systemKey, options);
|
|
173
|
+
const uploadCtx = await syncLocalIfRequested(systemKey, options);
|
|
174
|
+
|
|
175
|
+
let authConfig;
|
|
176
|
+
let dataplaneUrl;
|
|
177
|
+
if (uploadCtx) {
|
|
178
|
+
({ authConfig, dataplaneUrl } = uploadCtx);
|
|
179
|
+
} else {
|
|
180
|
+
const configObj = await getConfig();
|
|
181
|
+
({ authConfig, dataplaneUrl } = await setupIntegrationTestAuth(
|
|
182
|
+
externalSystem,
|
|
183
|
+
{ environment: options.env },
|
|
184
|
+
configObj
|
|
185
|
+
));
|
|
186
|
+
}
|
|
160
187
|
|
|
161
188
|
const results = [];
|
|
162
189
|
const opts = {
|
|
@@ -164,7 +191,9 @@ async function runTestE2EForExternalSystem(externalSystem, options = {}) {
|
|
|
164
191
|
environment: options.env,
|
|
165
192
|
debug: options.debug,
|
|
166
193
|
verbose: options.verbose,
|
|
167
|
-
async: options.async !== false
|
|
194
|
+
async: options.async !== false,
|
|
195
|
+
authConfig,
|
|
196
|
+
dataplaneUrl
|
|
168
197
|
};
|
|
169
198
|
for (const key of keys) {
|
|
170
199
|
try {
|
|
@@ -187,5 +216,7 @@ async function runTestE2EForExternalSystem(externalSystem, options = {}) {
|
|
|
187
216
|
|
|
188
217
|
module.exports = {
|
|
189
218
|
runTestE2EForExternalSystem,
|
|
190
|
-
getDatasourceKeys
|
|
219
|
+
getDatasourceKeys,
|
|
220
|
+
resolveExternalIntegrationContext,
|
|
221
|
+
syncLocalIfRequested
|
|
191
222
|
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Normalize test-governance Commander flags
|
|
3
|
+
* @author AI Fabrix Team
|
|
4
|
+
* @version 1.0.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
'use strict';
|
|
8
|
+
|
|
9
|
+
const { cliOptsSkipSync } = require('../utils/cli-sync-options');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @param {string[]} [raw]
|
|
13
|
+
* @param {string[]} [fallback]
|
|
14
|
+
* @returns {string[]|undefined}
|
|
15
|
+
*/
|
|
16
|
+
function collectScenarioIds(raw, fallback) {
|
|
17
|
+
const list = Array.isArray(raw) && raw.length > 0 ? raw : fallback;
|
|
18
|
+
if (!list || list.length === 0) {
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
return list.map(id => String(id).trim()).filter(Boolean);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @param {Object} options
|
|
26
|
+
* @param {import('commander').Command} [cmd]
|
|
27
|
+
* @returns {Object}
|
|
28
|
+
*/
|
|
29
|
+
function normalizeTestGovernanceCliOptions(options, cmd) {
|
|
30
|
+
const raw = cmd && Array.isArray(cmd.rawArgs) ? cmd.rawArgs : [];
|
|
31
|
+
const has = flag => raw.includes(flag);
|
|
32
|
+
return {
|
|
33
|
+
...options,
|
|
34
|
+
env: options.env || 'dev',
|
|
35
|
+
verbose: options.verbose === true || has('-v') || has('--verbose'),
|
|
36
|
+
json: options.json === true || has('--json'),
|
|
37
|
+
noSync: cliOptsSkipSync(options, cmd),
|
|
38
|
+
pack: options.pack,
|
|
39
|
+
app: options.app,
|
|
40
|
+
scenarioIds: collectScenarioIds(options.scenario)
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
module.exports = {
|
|
45
|
+
normalizeTestGovernanceCliOptions,
|
|
46
|
+
collectScenarioIds
|
|
47
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview CLI action for `aifabrix test-governance` (plan 406)
|
|
3
|
+
* @author AI Fabrix Team
|
|
4
|
+
* @version 1.0.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
'use strict';
|
|
8
|
+
|
|
9
|
+
const { handleCommandError } = require('../utils/cli-utils');
|
|
10
|
+
const { runTestGovernanceForExternalSystem } = require('./test-governance-external');
|
|
11
|
+
const { normalizeTestGovernanceCliOptions } = require('./test-governance-cli-options');
|
|
12
|
+
const {
|
|
13
|
+
displayGovernanceRunTTY,
|
|
14
|
+
printGovernanceRunJson,
|
|
15
|
+
exitCodeFromGovernanceSummary
|
|
16
|
+
} = require('../governance/governance-run-display');
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @async
|
|
20
|
+
* @param {string} appName
|
|
21
|
+
* @param {Object} options
|
|
22
|
+
* @param {import('commander').Command} [cmd]
|
|
23
|
+
*/
|
|
24
|
+
async function runTestGovernanceCommandAction(appName, options, cmd) {
|
|
25
|
+
const opts = normalizeTestGovernanceCliOptions(options, cmd);
|
|
26
|
+
const { result, packPath, systemKey } = await runTestGovernanceForExternalSystem(appName, opts);
|
|
27
|
+
|
|
28
|
+
if (opts.json) {
|
|
29
|
+
printGovernanceRunJson(result);
|
|
30
|
+
} else {
|
|
31
|
+
displayGovernanceRunTTY(systemKey, result, {
|
|
32
|
+
verbose: opts.verbose,
|
|
33
|
+
packPath
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const exitCode = exitCodeFromGovernanceSummary(result.summary);
|
|
38
|
+
if (exitCode !== 0) {
|
|
39
|
+
process.exit(exitCode);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async function testGovernanceCommandHandler(appName, options, cmd) {
|
|
44
|
+
try {
|
|
45
|
+
await runTestGovernanceCommandAction(appName, options, cmd);
|
|
46
|
+
} catch (error) {
|
|
47
|
+
handleCommandError(error, 'test-governance');
|
|
48
|
+
process.exit(3);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
module.exports = {
|
|
53
|
+
runTestGovernanceCommandAction,
|
|
54
|
+
testGovernanceCommandHandler
|
|
55
|
+
};
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview test-governance — run governance scenario pack via dataplane API
|
|
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 { runGovernanceScenarios } = require('../api/governance-scenarios.api');
|
|
15
|
+
const {
|
|
16
|
+
resolveGovernancePackPath,
|
|
17
|
+
loadGovernancePackYaml
|
|
18
|
+
} = require('../governance/governance-pack-loader');
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @param {string} systemKey
|
|
22
|
+
* @param {Object} options
|
|
23
|
+
* @returns {Promise<{ authConfig: Object, dataplaneUrl: string }|null>}
|
|
24
|
+
*/
|
|
25
|
+
async function syncLocalIfRequested(systemKey, options) {
|
|
26
|
+
if (cliOptsSkipSync(options)) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
const { uploadExternalSystem } = require('./upload');
|
|
30
|
+
logger.log(chalk.cyan('Syncing local config to dataplane…'));
|
|
31
|
+
const uploadCtx = await uploadExternalSystem(systemKey, {
|
|
32
|
+
minimal: true,
|
|
33
|
+
verbose: !!options.verbose
|
|
34
|
+
});
|
|
35
|
+
logger.log(chalk.green('✔ Sync complete'));
|
|
36
|
+
return uploadCtx && uploadCtx.dataplaneUrl && uploadCtx.authConfig ? uploadCtx : null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @async
|
|
41
|
+
* @param {string} externalSystem
|
|
42
|
+
* @param {Object} options
|
|
43
|
+
* @returns {Promise<{ result: Object, packPath: string, systemKey: string }>}
|
|
44
|
+
*/
|
|
45
|
+
async function runTestGovernanceForExternalSystem(externalSystem, options = {}) {
|
|
46
|
+
const pathsUtil = require('../utils/paths');
|
|
47
|
+
const appType = await pathsUtil.detectAppType(externalSystem).catch(() => null);
|
|
48
|
+
if (!appType || appType.baseDir !== 'integration') {
|
|
49
|
+
throw new Error(
|
|
50
|
+
'test-governance applies to external integration folders only (integration/<systemKey>/).'
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const systemKey = externalSystem;
|
|
55
|
+
const packPath = resolveGovernancePackPath(systemKey, {
|
|
56
|
+
pack: options.pack,
|
|
57
|
+
app: options.app
|
|
58
|
+
});
|
|
59
|
+
const pack = loadGovernancePackYaml(packPath);
|
|
60
|
+
|
|
61
|
+
const uploadCtx = await syncLocalIfRequested(systemKey, options);
|
|
62
|
+
|
|
63
|
+
let authConfig;
|
|
64
|
+
let dataplaneUrl;
|
|
65
|
+
if (uploadCtx) {
|
|
66
|
+
({ authConfig, dataplaneUrl } = uploadCtx);
|
|
67
|
+
} else {
|
|
68
|
+
const configObj = await getConfig();
|
|
69
|
+
({ authConfig, dataplaneUrl } = await setupIntegrationTestAuth(
|
|
70
|
+
externalSystem,
|
|
71
|
+
{ environment: options.env },
|
|
72
|
+
configObj
|
|
73
|
+
));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const body = {
|
|
77
|
+
systemKey,
|
|
78
|
+
pack,
|
|
79
|
+
scenarios: options.scenarioIds
|
|
80
|
+
};
|
|
81
|
+
const result = await runGovernanceScenarios(dataplaneUrl, authConfig, body);
|
|
82
|
+
return { result, packPath, systemKey };
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
module.exports = {
|
|
86
|
+
runTestGovernanceForExternalSystem,
|
|
87
|
+
syncLocalIfRequested
|
|
88
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Normalize test-trust Commander flags (defensive for -d/-v/--revalidate).
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
'use strict';
|
|
6
|
+
|
|
7
|
+
const { cliOptsSkipSync } = require('../utils/cli-sync-options');
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @param {Object} options - Commander-parsed options
|
|
11
|
+
* @param {import('commander').Command} [cmd]
|
|
12
|
+
* @returns {Object}
|
|
13
|
+
*/
|
|
14
|
+
function normalizeTestTrustCliOptions(options, cmd) {
|
|
15
|
+
const raw = cmd && Array.isArray(cmd.rawArgs) ? cmd.rawArgs : [];
|
|
16
|
+
const has = flag => raw.includes(flag);
|
|
17
|
+
return {
|
|
18
|
+
...options,
|
|
19
|
+
debug: options.debug === true || has('-d') || has('--debug'),
|
|
20
|
+
verbose: options.verbose === true || has('-v') || has('--verbose'),
|
|
21
|
+
revalidate: options.revalidate === true || has('--revalidate'),
|
|
22
|
+
noSync: cliOptsSkipSync(options, cmd),
|
|
23
|
+
strict: options.strict === true || has('--strict'),
|
|
24
|
+
summary: options.summary === true || has('--summary'),
|
|
25
|
+
json: options.json === true || has('--json'),
|
|
26
|
+
warningsAsErrors: options.warningsAsErrors === true || has('--warnings-as-errors')
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
module.exports = {
|
|
31
|
+
normalizeTestTrustCliOptions
|
|
32
|
+
};
|