@aifabrix/builder 2.45.5 → 2.46.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.cursor/rules/cli-layout.mdc +2 -0
- package/.cursor/rules/cli-product-neutral.mdc +43 -0
- package/.cursor/rules/project-rules.mdc +1 -0
- package/README.md +43 -17
- 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/jest.config.default.js +2 -1
- package/jest.config.isolated.js +2 -1
- package/jest.global-live-fabrix-hooks.js +36 -0
- package/jest.isolated-projects.js +130 -0
- package/jest.projects.js +41 -136
- package/lib/api/api-response-errors.js +124 -0
- package/lib/api/governance-scenario-pack.api.js +159 -0
- package/lib/api/index.js +43 -3
- package/lib/api/lifecycle.api.js +77 -0
- package/lib/api/pipeline.api.js +3 -1
- package/lib/api/records-bulk.api.js +14 -1
- package/lib/api/validation-runner.js +3 -1
- package/lib/app/deploy-config.js +4 -1
- package/lib/app/down.js +20 -1
- package/lib/app/push.js +4 -5
- package/lib/app/register.js +7 -4
- package/lib/app/run-env-compose.js +84 -30
- package/lib/build/index.js +5 -0
- package/lib/certification/sync-system-certification.js +13 -6
- package/lib/cli/index.js +4 -0
- package/lib/cli/infra-guided-auth.js +109 -0
- package/lib/cli/infra-guided.js +84 -81
- package/lib/cli/setup-app.help.js +0 -31
- package/lib/cli/setup-app.js +28 -2
- package/lib/cli/setup-app.test-commands.js +5 -57
- package/lib/cli/setup-auth.js +25 -0
- package/lib/cli/setup-certification-commands.js +147 -0
- package/lib/cli/setup-certification.help.js +141 -0
- package/lib/cli/setup-environment.js +19 -2
- package/lib/cli/setup-external-system-help.js +62 -0
- package/lib/cli/setup-external-system.js +25 -3
- package/lib/cli/setup-infra.js +9 -1
- package/lib/cli/setup-platform.js +6 -1
- package/lib/cli/setup-secrets.js +33 -1
- package/lib/cli/setup-utility-help-after.js +22 -2
- package/lib/cli/setup-utility-repair.js +198 -0
- package/lib/cli/setup-utility-resolve.js +40 -4
- package/lib/cli/setup-utility-validate.js +197 -0
- package/lib/cli/setup-utility.js +4 -239
- package/lib/commands/auth-status-client-tokens.js +214 -0
- package/lib/commands/auth-status-dataplane-version.js +58 -20
- package/lib/commands/auth-status.js +41 -47
- package/lib/commands/datasource-test-trust-cli.js +27 -23
- package/lib/commands/datasource-unified-test-cli.js +6 -3
- package/lib/commands/datasource-unified-test-cli.options.js +5 -1
- package/lib/commands/datasource.js +7 -7
- package/lib/commands/dev-show-display.js +8 -1
- package/lib/commands/governance-cli-shared.js +94 -0
- package/lib/commands/governance-command-action.js +132 -0
- package/lib/commands/governance-download-external.js +34 -0
- package/lib/commands/governance-generate-external.js +71 -0
- package/lib/commands/governance-upload-external.js +36 -0
- package/lib/commands/governance-verify-external.js +64 -0
- package/lib/commands/governance.js +144 -0
- package/lib/commands/lifecycle-command-action.js +123 -0
- package/lib/commands/lifecycle-external.js +268 -0
- package/lib/commands/login.js +11 -2
- package/lib/commands/repair-auth-apply.js +127 -0
- package/lib/commands/repair-changed-files.js +41 -0
- package/lib/commands/repair-datasource-keys.js +4 -1
- package/lib/commands/repair-datasource-run.js +59 -0
- package/lib/commands/repair-datasource-test-payload.js +259 -0
- package/lib/commands/repair-datasource.js +1 -51
- package/lib/commands/repair-env-template.js +64 -13
- package/lib/commands/repair-external-run.js +216 -0
- package/lib/commands/repair-openapi-sync.js +23 -0
- package/lib/commands/repair-persist.js +4 -0
- package/lib/commands/repair-rbac.js +52 -1
- package/lib/commands/repair-steps.js +145 -0
- package/lib/commands/repair.js +29 -296
- package/lib/commands/secrets-get.js +184 -0
- package/lib/commands/secrets-remove-all.js +3 -1
- package/lib/commands/setup-image-refresh.js +146 -0
- package/lib/commands/setup-modes.js +158 -162
- package/lib/commands/setup-platform-auth.js +76 -0
- package/lib/commands/setup-prompts-admin.js +244 -0
- package/lib/commands/setup-prompts-platform-mode.js +67 -0
- package/lib/commands/setup-prompts-validators.js +36 -0
- package/lib/commands/setup-prompts.js +24 -76
- package/lib/commands/setup-run-context.js +45 -0
- package/lib/commands/setup-spinners.js +39 -0
- package/lib/commands/setup.js +27 -5
- package/lib/commands/teardown.js +39 -0
- package/lib/commands/test-e2e-external.js +24 -8
- package/lib/commands/test-governance-external.js +3 -24
- package/lib/commands/test-trust-external.js +20 -21
- package/lib/commands/up-common.js +25 -13
- package/lib/commands/up-dataplane.js +50 -13
- package/lib/commands/upload-publish-context.js +75 -0
- package/lib/commands/upload-sidecar-followups.js +89 -0
- package/lib/commands/upload.js +90 -108
- package/lib/commands/verify-governance-combined-external.js +61 -0
- package/lib/commands/verify-governance-command-action.js +64 -0
- package/lib/commands/verify-governance-db.js +102 -0
- package/lib/commands/verify-governance-external.js +77 -0
- package/lib/commands/verify-governance-result-builders.js +71 -0
- package/lib/commands/verify-operations-command-action.js +68 -0
- package/lib/commands/verify-operations-external.js +268 -0
- package/lib/commands/verify-operations-persist.js +75 -0
- package/lib/commands/verify-operations-step-plan.js +68 -0
- package/lib/commands/verify-operations-steps.js +111 -0
- package/lib/commands/verify-trust-command-action.js +70 -0
- package/lib/commands/verify-trust-external.js +67 -0
- package/lib/commands/wizard-config-normalizer.js +43 -23
- package/lib/commands/wizard-core.js +2 -0
- package/lib/core/admin-password-generator.js +38 -0
- package/lib/core/admin-secrets-bundle.js +111 -0
- package/lib/core/admin-secrets-env-overlay.js +62 -0
- package/lib/core/admin-secrets.js +32 -4
- package/lib/core/config-attach-extensions.js +3 -0
- package/lib/core/config-platform-controller.js +44 -0
- package/lib/core/config-setup-installation-profile.js +42 -0
- package/lib/core/config-setup-platform-mode.js +46 -0
- package/lib/core/config.js +46 -36
- package/lib/core/secrets-admin-env.js +6 -2
- package/lib/core/secrets-ensure.js +4 -0
- package/lib/core/secrets-env-content.js +54 -48
- package/lib/core/secrets-env-write.js +10 -1
- package/lib/core/secrets-infra-placeholder-sync.js +2 -0
- package/lib/core/setup-installation-profile.js +43 -0
- package/lib/core/setup-platform-mode.js +55 -0
- package/lib/datasource/agent-trust-debug-log.js +1 -1
- package/lib/datasource/agent-trust-run.js +5 -3
- package/lib/datasource/audit-evidence-extract-debug.js +30 -18
- package/lib/datasource/audit-evidence-extract.js +7 -4
- package/lib/datasource/audit-evidence-verify-matrix.js +54 -26
- package/lib/datasource/bulk-loader-run-batches.js +15 -3
- package/lib/datasource/datasource-load-export-context.js +3 -0
- package/lib/datasource/log-cleaner.js +2 -2
- package/lib/datasource/log-viewer.js +8 -8
- package/lib/datasource/test-e2e.js +4 -1
- package/lib/datasource/unified-validation-run-body.js +3 -1
- package/lib/datasource/unified-validation-run.js +5 -2
- package/lib/deployment/environment-poll-status.js +138 -0
- package/lib/deployment/environment.js +42 -34
- package/lib/external-system/download.js +21 -20
- package/lib/external-system/generator.js +5 -1
- package/lib/external-system/integration-auth-context.js +45 -0
- package/lib/external-system/test-auth.js +12 -5
- package/lib/external-system/test.js +6 -6
- package/lib/generator/external-controller-manifest.js +15 -0
- package/lib/governance/governance-cli-errors.js +96 -0
- package/lib/governance/governance-download-display.js +38 -0
- package/lib/governance/governance-run-display.js +215 -25
- package/lib/infrastructure/admin-secrets-apply.js +84 -0
- package/lib/infrastructure/admin-secrets-ensure.js +130 -0
- package/lib/infrastructure/admin-secrets-resolve.js +95 -0
- package/lib/infrastructure/admin-secrets-sync.js +91 -0
- package/lib/infrastructure/helpers.js +23 -129
- package/lib/infrastructure/index.js +5 -6
- package/lib/infrastructure/orphan-infra-docker-teardown.js +11 -5
- package/lib/lifecycle/certification-progress.js +231 -0
- package/lib/lifecycle/dataplane-ui-url.js +145 -0
- package/lib/lifecycle/exit-codes.js +24 -0
- package/lib/lifecycle/json-envelope.js +25 -0
- package/lib/lifecycle/lifecycle-governance-options.js +51 -0
- package/lib/lifecycle/logger-quiet.js +29 -0
- package/lib/lifecycle/open-api-published.js +59 -0
- package/lib/lifecycle/operations-readiness-metrics.js +101 -0
- package/lib/lifecycle/product-model.js +196 -0
- package/lib/lifecycle/report-display.js +471 -0
- package/lib/lifecycle/scenario-upload.js +191 -0
- package/lib/lifecycle/verify-step-progress.js +87 -0
- package/lib/parameters/infra-kv-discovery.js +27 -2
- package/lib/protection/auth-context.js +10 -4
- package/lib/schema/application-schema.json +1 -1
- package/lib/schema/datasource-test-run.schema.json +89 -6
- package/lib/schema/external-datasource.schema.json +2636 -2622
- package/lib/schema/external-system.schema.json +1089 -761
- package/lib/schema/infra.parameter.yaml +45 -0
- package/lib/schema/type/credential-field-registry.json +103 -97
- package/lib/utils/aifabrix-test-runtime-guard.js +125 -0
- package/lib/utils/api.js +55 -31
- package/lib/utils/app-relative-path-env.js +112 -0
- package/lib/utils/cli-secrets-error-format.js +83 -21
- package/lib/utils/cli-utils.js +16 -4
- package/lib/utils/compose-generate-docker-compose.js +4 -0
- package/lib/utils/compose-traefik-ingress-base.js +16 -1
- package/lib/utils/config-secrets-path.js +46 -0
- package/lib/utils/controller-url.js +88 -1
- package/lib/utils/credential-secrets-env.js +137 -9
- package/lib/utils/dataplane-resolver.js +129 -2
- package/lib/utils/declarative-url-ports.js +3 -3
- package/lib/utils/deployment-auth-mode.js +41 -0
- package/lib/utils/developer-volume-id.js +33 -0
- package/lib/utils/env-copy.js +14 -9
- package/lib/utils/env-kv-orphan-lines.js +43 -0
- package/lib/utils/error-formatters/network-errors.js +13 -4
- package/lib/utils/external-env-template.js +1 -0
- package/lib/utils/external-system-readiness-core.js +10 -0
- package/lib/utils/external-system-readiness-display.js +80 -23
- package/lib/utils/health-check.js +4 -1
- package/lib/utils/help-builder.js +11 -8
- package/lib/utils/keycloak-realm-ready.js +101 -0
- package/lib/utils/load-cip-capacity-display-config.js +61 -15
- package/lib/utils/manifest-source-emit.js +2 -0
- package/lib/utils/pipeline-upload-auth-retry.js +82 -0
- package/lib/utils/platform-controller-url.js +156 -0
- package/lib/utils/postgres-platform-bootstrap.js +199 -0
- package/lib/utils/postgres-wipe.js +9 -2
- package/lib/utils/resolve-env-mode.js +47 -0
- package/lib/utils/secrets-generator.js +31 -25
- package/lib/utils/secrets-missing-error.js +164 -0
- package/lib/utils/service-url-label.js +81 -0
- package/lib/utils/setup-quiet-output.js +25 -0
- package/lib/utils/template-helpers.js +15 -0
- package/lib/utils/token-manager-client-credentials.js +201 -0
- package/lib/utils/token-manager-messages.js +8 -0
- package/lib/utils/token-manager-refresh.js +12 -2
- package/lib/utils/token-manager.js +86 -105
- package/lib/utils/upload-pipeline-ui.js +12 -5
- package/lib/utils/upload-sync-options.js +42 -0
- package/lib/utils/url-declarative-public-base.js +21 -3
- package/lib/utils/url-declarative-vdir-inactive-env.js +14 -4
- package/lib/utils/validation-poll-ui.js +8 -0
- package/lib/utils/validation-run-stage.js +45 -0
- package/package.json +1 -1
- package/templates/applications/dataplane/application.yaml +2 -1
- package/templates/applications/dataplane/env.template +24 -1
- package/templates/applications/miso-controller/env.template +16 -0
- package/templates/external-system/README.md.hbs +74 -17
- package/templates/python/docker-compose.hbs +19 -18
- package/templates/typescript/docker-compose.hbs +18 -17
- package/lib/commands/test-governance-command-action.js +0 -55
- package/lib/commands/test-trust-command-action.js +0 -118
package/lib/core/config.js
CHANGED
|
@@ -9,14 +9,24 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
const fs = require('fs').promises;
|
|
12
|
-
const path = require('path');
|
|
13
12
|
const yaml = require('js-yaml');
|
|
14
|
-
const os = require('os');
|
|
15
13
|
const { encryptToken, decryptToken, isTokenEncrypted } = require('../utils/token-encryption');
|
|
16
14
|
const { ensureSecureFilePermissions, ensureSecureDirPermissions } = require('../utils/secure-file-permissions');
|
|
17
15
|
const { getRuntimeConfigDir, getRuntimeConfigFile } = require('./config-runtime-paths');
|
|
18
16
|
const { getAdminEmailFromConfig, setAdminEmailInConfig } = require('./config-admin-email');
|
|
17
|
+
const {
|
|
18
|
+
getSetupInstallationProfileFromConfig,
|
|
19
|
+
setSetupInstallationProfileInConfig
|
|
20
|
+
} = require('./config-setup-installation-profile');
|
|
21
|
+
const {
|
|
22
|
+
getSetupPlatformModeFromConfig,
|
|
23
|
+
setSetupPlatformModeInConfig
|
|
24
|
+
} = require('./config-setup-platform-mode');
|
|
19
25
|
const { getRegisteredControllerUrlsWithLoader } = require('./config-registered-controller-urls');
|
|
26
|
+
const {
|
|
27
|
+
getPlatformControllerUrlFromConfig,
|
|
28
|
+
setPlatformControllerUrlInConfig
|
|
29
|
+
} = require('./config-platform-controller');
|
|
20
30
|
const { normalizeControllerUrl, validateAndNormalizeDeveloperId } = require('./config-normalize');
|
|
21
31
|
// Avoid importing paths.js here to prevent circular dependency; use shared runtime config dir helper.
|
|
22
32
|
// Config location: AIFABRIX_CONFIG dirname → AIFABRIX_HOME (with ~/.aifabrix fallback when config lives there) → ~/.aifabrix
|
|
@@ -34,6 +44,9 @@ function applyConfigDefaults(config) {
|
|
|
34
44
|
if (typeof config.environment === 'undefined') {
|
|
35
45
|
config.environment = 'dev';
|
|
36
46
|
}
|
|
47
|
+
if (typeof config.setupPlatformMode === 'undefined') {
|
|
48
|
+
config.setupPlatformMode = 'single';
|
|
49
|
+
}
|
|
37
50
|
// Ensure environments object exists
|
|
38
51
|
if (typeof config.environments !== 'object' || config.environments === null) {
|
|
39
52
|
config.environments = {};
|
|
@@ -59,6 +72,7 @@ function getDefaultConfig() {
|
|
|
59
72
|
return {
|
|
60
73
|
'developer-id': '0',
|
|
61
74
|
environment: 'dev',
|
|
75
|
+
setupPlatformMode: 'single',
|
|
62
76
|
controller: undefined,
|
|
63
77
|
environments: {},
|
|
64
78
|
device: {},
|
|
@@ -230,6 +244,12 @@ async function setAdminEmail(email) {
|
|
|
230
244
|
return setAdminEmailInConfig(getConfig, saveConfig, email);
|
|
231
245
|
}
|
|
232
246
|
|
|
247
|
+
/** @returns {Promise<'dev'|'pro'>} */
|
|
248
|
+
const getSetupInstallationProfile = () => getSetupInstallationProfileFromConfig(getConfig);
|
|
249
|
+
/** @param {unknown} profile @returns {Promise<'dev'|'pro'>} */
|
|
250
|
+
const setSetupInstallationProfile = (profile) =>
|
|
251
|
+
setSetupInstallationProfileInConfig(getConfig, saveConfig, profile);
|
|
252
|
+
|
|
233
253
|
/**
|
|
234
254
|
* Whether Traefik is enabled (`traefik: true` in config; infra compose includes the proxy).
|
|
235
255
|
* @returns {Promise<boolean>}
|
|
@@ -259,6 +279,21 @@ async function setCurrentEnvironment(environment) {
|
|
|
259
279
|
await saveConfig(config);
|
|
260
280
|
}
|
|
261
281
|
|
|
282
|
+
/**
|
|
283
|
+
* @returns {Promise<'single'|'full'>}
|
|
284
|
+
*/
|
|
285
|
+
async function getSetupPlatformMode() {
|
|
286
|
+
return getSetupPlatformModeFromConfig(getConfig);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* @param {unknown} mode
|
|
291
|
+
* @returns {Promise<'single'|'full'>}
|
|
292
|
+
*/
|
|
293
|
+
async function setSetupPlatformMode(mode) {
|
|
294
|
+
return setSetupPlatformModeInConfig(getConfig, saveConfig, mode);
|
|
295
|
+
}
|
|
296
|
+
|
|
262
297
|
/**
|
|
263
298
|
* Set controller URL in configuration
|
|
264
299
|
* @async
|
|
@@ -392,38 +427,11 @@ async function setSecretsEncryptionKey(key) {
|
|
|
392
427
|
*/
|
|
393
428
|
async function ensureSecretsEncryptionKey() {
|
|
394
429
|
const { ensureSecretsEncryptionKey: run } = require('./ensure-encryption-key');
|
|
430
|
+
const { createSecretsPathFunctions } = require('../utils/config-secrets-path');
|
|
431
|
+
const { getSecretsPath } = createSecretsPathFunctions(getConfig, saveConfig);
|
|
395
432
|
await run({ getSecretsEncryptionKey, setSecretsEncryptionKey, getSecretsPath });
|
|
396
433
|
}
|
|
397
434
|
|
|
398
|
-
/**
|
|
399
|
-
* Expand leading ~ to home directory so config paths like ~/.aifabrix/secrets.local.yaml resolve correctly.
|
|
400
|
-
* @param {string} filePath - Path that may start with ~ or ~/
|
|
401
|
-
* @returns {string} Path with ~ expanded, or unchanged if no leading ~
|
|
402
|
-
*/
|
|
403
|
-
function expandTilde(filePath) {
|
|
404
|
-
if (!filePath || typeof filePath !== 'string') return filePath;
|
|
405
|
-
if (filePath === '~') return os.homedir();
|
|
406
|
-
if (filePath.startsWith('~/') || filePath.startsWith('~' + path.sep)) {
|
|
407
|
-
return path.join(os.homedir(), filePath.slice(2));
|
|
408
|
-
}
|
|
409
|
-
return filePath;
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
async function getSecretsPath() {
|
|
413
|
-
const config = await getConfig();
|
|
414
|
-
const raw = config['aifabrix-secrets'] || config['secrets-path'] || null;
|
|
415
|
-
return raw ? expandTilde(raw) : null;
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
async function setSecretsPath(secretsPath) {
|
|
419
|
-
if (typeof secretsPath !== 'string') {
|
|
420
|
-
throw new Error('Secrets path is required and must be a string');
|
|
421
|
-
}
|
|
422
|
-
const config = await getConfig();
|
|
423
|
-
config['aifabrix-secrets'] = secretsPath.trim() || undefined;
|
|
424
|
-
await saveConfig(config);
|
|
425
|
-
}
|
|
426
|
-
|
|
427
435
|
// Create exports object
|
|
428
436
|
const exportsObj = {
|
|
429
437
|
getConfig,
|
|
@@ -436,6 +444,10 @@ const exportsObj = {
|
|
|
436
444
|
getTlsEnabled,
|
|
437
445
|
getAdminEmail,
|
|
438
446
|
setAdminEmail,
|
|
447
|
+
getSetupInstallationProfile,
|
|
448
|
+
setSetupInstallationProfile,
|
|
449
|
+
getSetupPlatformMode,
|
|
450
|
+
setSetupPlatformMode,
|
|
439
451
|
getTraefikEnabled,
|
|
440
452
|
setCurrentEnvironment,
|
|
441
453
|
resolveEnvironment,
|
|
@@ -446,11 +458,11 @@ const exportsObj = {
|
|
|
446
458
|
getSecretsEncryptionKey,
|
|
447
459
|
setSecretsEncryptionKey,
|
|
448
460
|
ensureSecretsEncryptionKey,
|
|
449
|
-
getSecretsPath,
|
|
450
|
-
setSecretsPath,
|
|
451
461
|
normalizeControllerUrl,
|
|
452
462
|
setControllerUrl,
|
|
453
463
|
getControllerUrl,
|
|
464
|
+
getPlatformControllerUrl: () => getPlatformControllerUrlFromConfig(getConfig),
|
|
465
|
+
setPlatformControllerUrl: (url) => setPlatformControllerUrlInConfig(getConfig, saveConfig, normalizeControllerUrl, url),
|
|
454
466
|
getRegisteredControllerUrls,
|
|
455
467
|
get CONFIG_DIR() {
|
|
456
468
|
return getRuntimeConfigDir();
|
|
@@ -460,9 +472,7 @@ const exportsObj = {
|
|
|
460
472
|
}
|
|
461
473
|
};
|
|
462
474
|
|
|
463
|
-
//
|
|
464
|
-
// After getConfig() or getDeveloperId() is called, config.developerId will be available
|
|
465
|
-
// Developer ID: 0 = default infra, > 0 = developer-specific
|
|
475
|
+
// Developer ID: 0 = default infra, > 0 = developer-specific (getter after getConfig loads cache)
|
|
466
476
|
Object.defineProperty(exportsObj, 'developerId', {
|
|
467
477
|
get() {
|
|
468
478
|
return cachedDeveloperId !== null ? cachedDeveloperId : '0'; // Default to "0" if not loaded yet
|
|
@@ -20,6 +20,7 @@ const {
|
|
|
20
20
|
const { createDefaultSecrets } = require('../utils/secrets-generator');
|
|
21
21
|
const pathsUtil = require('../utils/paths');
|
|
22
22
|
const { loadSecrets } = require('./secrets-load');
|
|
23
|
+
const { formatAdminEnvLine } = require('./admin-secrets');
|
|
23
24
|
|
|
24
25
|
/**
|
|
25
26
|
* Writes admin env key-value pairs to content; encrypts values when encryption key is set.
|
|
@@ -34,7 +35,7 @@ async function formatAdminSecretsContent(adminObj) {
|
|
|
34
35
|
for (const [k, v] of Object.entries(adminObj)) {
|
|
35
36
|
const value = (v === null || v === undefined) ? '' : String(v).replace(/\n/g, ' ').trim();
|
|
36
37
|
const valueToWrite = encryptionKey ? encryptSecret(value, encryptionKey) : value;
|
|
37
|
-
lines.push(
|
|
38
|
+
lines.push(formatAdminEnvLine(k, valueToWrite));
|
|
38
39
|
}
|
|
39
40
|
return lines.join('\n');
|
|
40
41
|
}
|
|
@@ -76,7 +77,10 @@ function buildLocalAdminSecretsObject(secrets, infraDefaults) {
|
|
|
76
77
|
PGADMIN_DEFAULT_PASSWORD: postgresPassword,
|
|
77
78
|
REDIS_HOST: 'local:redis:6379:0:',
|
|
78
79
|
REDIS_COMMANDER_USER: 'admin',
|
|
79
|
-
REDIS_COMMANDER_PASSWORD: postgresPassword
|
|
80
|
+
REDIS_COMMANDER_PASSWORD: postgresPassword,
|
|
81
|
+
KEYCLOAK_ADMIN_USERNAME: 'admin',
|
|
82
|
+
KEYCLOAK_ADMIN_PASSWORD: postgresPassword,
|
|
83
|
+
PLATFORM_ADMIN_PASSWORD: postgresPassword
|
|
80
84
|
};
|
|
81
85
|
}
|
|
82
86
|
|
|
@@ -204,6 +204,8 @@ function summarizeSecretsStoreForLog(target) {
|
|
|
204
204
|
*/
|
|
205
205
|
function logNewSecretValuesWritten(added, target) {
|
|
206
206
|
if (!Array.isArray(added) || added.length === 0) return;
|
|
207
|
+
const { isSetupQuietOutput } = require('../utils/setup-quiet-output');
|
|
208
|
+
if (isSetupQuietOutput()) return;
|
|
207
209
|
const where = summarizeSecretsStoreForLog(target);
|
|
208
210
|
logger.log(
|
|
209
211
|
formatSuccessLine(
|
|
@@ -352,6 +354,8 @@ async function ensureSecretsFromEnvTemplate(envTemplatePathOrContent, options =
|
|
|
352
354
|
* @returns {Promise<void>}
|
|
353
355
|
*/
|
|
354
356
|
async function writeSecretToStoreFile(filePath, key, strValue) {
|
|
357
|
+
const { assertWritableSecretsPathForTests } = require('../utils/aifabrix-test-runtime-guard');
|
|
358
|
+
assertWritableSecretsPathForTests(filePath);
|
|
355
359
|
const existing = loadExistingSecrets(filePath);
|
|
356
360
|
const encryptionKey = await config.getSecretsEncryptionKey();
|
|
357
361
|
let valueToWrite = strValue;
|
|
@@ -15,7 +15,6 @@ const config = require('./config');
|
|
|
15
15
|
const {
|
|
16
16
|
interpolateEnvVars,
|
|
17
17
|
collectMissingSecrets,
|
|
18
|
-
formatMissingSecretsFileInfo,
|
|
19
18
|
replaceKvInContent,
|
|
20
19
|
loadEnvTemplate,
|
|
21
20
|
adjustLocalEnvPortsInContent,
|
|
@@ -43,6 +42,8 @@ const {
|
|
|
43
42
|
rewriteDockerManifestPublicPortEnvLine
|
|
44
43
|
} = require('../utils/docker-manifest-public-port');
|
|
45
44
|
const { loadSecrets } = require('./secrets-load');
|
|
45
|
+
const { buildMissingSecretsErrorMessage } = require('../utils/secrets-missing-error');
|
|
46
|
+
const { commentOrphanKvEnvLines } = require('../utils/env-kv-orphan-lines');
|
|
46
47
|
|
|
47
48
|
/**
|
|
48
49
|
* Resolves kv:// references in environment template
|
|
@@ -54,10 +55,24 @@ const { loadSecrets } = require('./secrets-load');
|
|
|
54
55
|
* @param {string} [environment='local'] - Environment context (docker/local)
|
|
55
56
|
* @param {Object|string|null} [secretsFilePaths] - Paths object with userPath and buildPath, or string path (for backward compatibility)
|
|
56
57
|
* @param {string} [appName] - Application name (optional, for error messages)
|
|
58
|
+
* @param {Object|null} [resolveOpts] - Scoped kv (`envKey`, `effective`) and/or `envTemplatePath` for error hints
|
|
57
59
|
* @returns {Promise<string>} Resolved environment content
|
|
58
60
|
* @throws {Error} If kv:// reference cannot be resolved
|
|
59
61
|
*/
|
|
60
|
-
async function resolveKvReferences(
|
|
62
|
+
async function resolveKvReferences(
|
|
63
|
+
envTemplate,
|
|
64
|
+
secrets,
|
|
65
|
+
environment = 'local',
|
|
66
|
+
secretsFilePaths = null,
|
|
67
|
+
appName = null,
|
|
68
|
+
resolveOpts = null
|
|
69
|
+
) {
|
|
70
|
+
const envTemplatePath =
|
|
71
|
+
resolveOpts && typeof resolveOpts === 'object' ? resolveOpts.envTemplatePath || null : null;
|
|
72
|
+
const scopedKv =
|
|
73
|
+
resolveOpts && typeof resolveOpts === 'object' && (resolveOpts.envKey !== undefined || resolveOpts.effective !== undefined)
|
|
74
|
+
? { envKey: resolveOpts.envKey, effective: resolveOpts.effective }
|
|
75
|
+
: null;
|
|
61
76
|
const os = require('os');
|
|
62
77
|
|
|
63
78
|
let developerId = null;
|
|
@@ -77,9 +92,16 @@ async function resolveKvReferences(envTemplate, secrets, environment = 'local',
|
|
|
77
92
|
const resolved = interpolateEnvVars(envTemplate, envVars);
|
|
78
93
|
const missing = collectMissingSecrets(resolved, secrets, scopedKv);
|
|
79
94
|
if (missing.length > 0) {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
95
|
+
throw new Error(
|
|
96
|
+
buildMissingSecretsErrorMessage({
|
|
97
|
+
missing,
|
|
98
|
+
secrets,
|
|
99
|
+
secretsFilePaths,
|
|
100
|
+
appName,
|
|
101
|
+
envTemplatePath,
|
|
102
|
+
envTemplate
|
|
103
|
+
})
|
|
104
|
+
);
|
|
83
105
|
}
|
|
84
106
|
return replaceKvInContent(resolved, secrets, envVars, scopedKv);
|
|
85
107
|
}
|
|
@@ -178,7 +200,11 @@ async function generateEnvContent(appName, secretsPath, environment = 'local', f
|
|
|
178
200
|
const secrets = await loadSecrets(secretsPath, appName);
|
|
179
201
|
const { runEnvKey, effective } = await buildScopedKvContext(appPath, options);
|
|
180
202
|
const scopedKv = { envKey: runEnvKey, effective };
|
|
181
|
-
let resolved = await resolveKvReferences(template, secrets, environment, secretsPaths, appName,
|
|
203
|
+
let resolved = await resolveKvReferences(template, secrets, environment, secretsPaths, appName, {
|
|
204
|
+
envKey: runEnvKey,
|
|
205
|
+
effective,
|
|
206
|
+
envTemplatePath: templatePath
|
|
207
|
+
});
|
|
182
208
|
if (!secretsPath) {
|
|
183
209
|
await materializeResolvedKvSecretsToUserLocal(template, secrets, scopedKv, options);
|
|
184
210
|
}
|
|
@@ -227,42 +253,6 @@ function parseEnvContentToMap(content) {
|
|
|
227
253
|
return map;
|
|
228
254
|
}
|
|
229
255
|
|
|
230
|
-
/**
|
|
231
|
-
* Merges new .env content with existing .env: newly resolved content wins for keys it
|
|
232
|
-
* defines (so project secrets take effect when re-running). Keys only in existing .env
|
|
233
|
-
* are appended so manual additions are kept.
|
|
234
|
-
*
|
|
235
|
-
* @param {string} newContent - Newly generated .env content (from template + loadSecrets)
|
|
236
|
-
* @param {Object.<string, string>} existingMap - Existing key-to-value map from current .env
|
|
237
|
-
* @returns {string} Merged content: new values for keys in newContent, plus extra existing keys
|
|
238
|
-
*/
|
|
239
|
-
function mergeEnvContentPreservingExisting(newContent, existingMap) {
|
|
240
|
-
const lines = newContent.split(/\r?\n/);
|
|
241
|
-
const newKeys = new Set();
|
|
242
|
-
const out = [];
|
|
243
|
-
for (const line of lines) {
|
|
244
|
-
const trimmed = line.trim();
|
|
245
|
-
if (!trimmed || trimmed.startsWith('#')) {
|
|
246
|
-
out.push(line);
|
|
247
|
-
continue;
|
|
248
|
-
}
|
|
249
|
-
const eq = trimmed.indexOf('=');
|
|
250
|
-
if (eq > 0) {
|
|
251
|
-
const key = trimmed.substring(0, eq).trim();
|
|
252
|
-
newKeys.add(key);
|
|
253
|
-
}
|
|
254
|
-
out.push(line);
|
|
255
|
-
}
|
|
256
|
-
if (existingMap && Object.keys(existingMap).length > 0) {
|
|
257
|
-
for (const key of Object.keys(existingMap)) {
|
|
258
|
-
if (!newKeys.has(key)) {
|
|
259
|
-
out.push(`${key}=${existingMap[key]}`);
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
return out.join('\n');
|
|
264
|
-
}
|
|
265
|
-
|
|
266
256
|
/**
|
|
267
257
|
* Merges a key-value map into existing .env file content, preserving comments and blank lines.
|
|
268
258
|
* For each KEY=value line in existing content, replaces value with newMap[KEY] when the key exists
|
|
@@ -320,15 +310,27 @@ function mergeEnvMapIntoContent(existingContent, newMap, options = {}) {
|
|
|
320
310
|
|
|
321
311
|
/**
|
|
322
312
|
* Resolves content to write for .env: merges with existing file when present.
|
|
313
|
+
* Uses {@link mergeEnvMapIntoContent} so new template keys are appended and comments in the
|
|
314
|
+
* existing file are preserved (unlike a full replace).
|
|
315
|
+
*
|
|
323
316
|
* @param {string} resolved - Newly generated content
|
|
324
317
|
* @param {string} pathToPreserve - Path to existing .env to merge from (or null)
|
|
318
|
+
* @param {Object} [options]
|
|
319
|
+
* @param {boolean} [options.freshEnv=false] - When true, write full resolved content (no merge)
|
|
325
320
|
* @returns {string} Content to write
|
|
326
321
|
*/
|
|
327
|
-
function resolveEnvContentToWrite(resolved, pathToPreserve) {
|
|
328
|
-
if (!pathToPreserve || !fs.existsSync(pathToPreserve))
|
|
322
|
+
function resolveEnvContentToWrite(resolved, pathToPreserve, options = {}) {
|
|
323
|
+
if (options.freshEnv === true || !pathToPreserve || !fs.existsSync(pathToPreserve)) {
|
|
324
|
+
return resolved;
|
|
325
|
+
}
|
|
329
326
|
const existingContent = fs.readFileSync(pathToPreserve, 'utf8');
|
|
330
|
-
const
|
|
331
|
-
|
|
327
|
+
const resolvedMap = parseEnvContentToMap(resolved);
|
|
328
|
+
let merged = mergeEnvMapIntoContent(existingContent, resolvedMap, { appendMissingFromNewMap: true });
|
|
329
|
+
if (options.pruneOrphanKv === true) {
|
|
330
|
+
const { content: pruned } = commentOrphanKvEnvLines(merged, new Set(Object.keys(resolvedMap)));
|
|
331
|
+
merged = pruned;
|
|
332
|
+
}
|
|
333
|
+
return merged;
|
|
332
334
|
}
|
|
333
335
|
|
|
334
336
|
/**
|
|
@@ -381,14 +383,18 @@ function resolveEnvContentToWrite(resolved, pathToPreserve) {
|
|
|
381
383
|
async function writeResolvedEnv({ appName, envPath, resolved, variablesPath, secretsPath, opts }) {
|
|
382
384
|
const preservePath = opts.preserveFromPath !== undefined && opts.preserveFromPath !== null ? opts.preserveFromPath : null;
|
|
383
385
|
const pathToPreserve = preservePath !== null ? preservePath : envPath;
|
|
384
|
-
const toWrite = resolveEnvContentToWrite(resolved, pathToPreserve
|
|
386
|
+
const toWrite = resolveEnvContentToWrite(resolved, pathToPreserve, {
|
|
387
|
+
freshEnv: opts.freshEnv === true,
|
|
388
|
+
pruneOrphanKv: opts.envOnly === true && opts.freshEnv !== true
|
|
389
|
+
});
|
|
385
390
|
fs.writeFileSync(envPath, toWrite, { mode: 0o600 });
|
|
386
391
|
|
|
387
392
|
if (!opts.skipOutputPath) {
|
|
388
393
|
const { processEnvVariables } = require('../utils/env-copy');
|
|
389
394
|
await processEnvVariables(envPath, variablesPath, appName, secretsPath, {
|
|
390
395
|
preferLocalEnvOutputPath: opts.preferLocalEnvOutputPath === true,
|
|
391
|
-
appPath: opts.appPath || null
|
|
396
|
+
appPath: opts.appPath || null,
|
|
397
|
+
freshEnv: opts.freshEnv === true
|
|
392
398
|
});
|
|
393
399
|
}
|
|
394
400
|
return envPath;
|
|
@@ -207,7 +207,16 @@ async function resolveAndGetEnvMap(appName, options = {}) {
|
|
|
207
207
|
let content = await secrets.generateEnvContent(appName, secretsPath, environment, force);
|
|
208
208
|
content = await injectRegistryTokens(content, secretsPath, appName);
|
|
209
209
|
content = await injectBashPrefixedExportLines(content, secretsPath, appName);
|
|
210
|
-
|
|
210
|
+
const map = parseEnvContentToMap(content);
|
|
211
|
+
try {
|
|
212
|
+
const adminSecrets = require('./admin-secrets');
|
|
213
|
+
const { applyAdminSecretsPlatformOverlay } = require('./admin-secrets-env-overlay');
|
|
214
|
+
const adminObj = await adminSecrets.readAndDecryptAdminSecrets();
|
|
215
|
+
applyAdminSecretsPlatformOverlay(map, adminObj);
|
|
216
|
+
} catch {
|
|
217
|
+
// admin-secrets.env optional until up-infra/setup
|
|
218
|
+
}
|
|
219
|
+
return map;
|
|
211
220
|
}
|
|
212
221
|
|
|
213
222
|
module.exports = { resolveAndWriteEnvFile, resolveAndGetEnvMap };
|
|
@@ -43,6 +43,8 @@ async function syncLiteralKvSecretsFromCliOverrides(
|
|
|
43
43
|
const val = ipc.generateValueFromCatalogEntry(key, entry, crypto, placeholderContext);
|
|
44
44
|
await setSecretInStore(key, val);
|
|
45
45
|
}
|
|
46
|
+
const { isSetupQuietOutput } = require('../utils/setup-quiet-output');
|
|
47
|
+
if (isSetupQuietOutput()) return;
|
|
46
48
|
logger.log(
|
|
47
49
|
`Updated ${keys.length} secret(s) in store (catalog literals using {{${placeholder}}}).`
|
|
48
50
|
);
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Setup installation profile identifiers (`dev` / `pro`).
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Normalization for setup wizard profile (local install, not login environment)
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
/** @enum {string} */
|
|
12
|
+
const INSTALLATION_PROFILE = Object.freeze({
|
|
13
|
+
DEV: 'dev',
|
|
14
|
+
PRO: 'pro'
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @param {unknown} value
|
|
19
|
+
* @returns {'dev'|'pro'}
|
|
20
|
+
*/
|
|
21
|
+
function normalizeInstallationProfile(value) {
|
|
22
|
+
const raw = String(value ?? '')
|
|
23
|
+
.trim()
|
|
24
|
+
.toLowerCase();
|
|
25
|
+
if (raw === INSTALLATION_PROFILE.PRO || raw === 'production') {
|
|
26
|
+
return INSTALLATION_PROFILE.PRO;
|
|
27
|
+
}
|
|
28
|
+
return INSTALLATION_PROFILE.DEV;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @param {unknown} value
|
|
33
|
+
* @returns {boolean}
|
|
34
|
+
*/
|
|
35
|
+
function isProInstallationProfile(value) {
|
|
36
|
+
return normalizeInstallationProfile(value) === INSTALLATION_PROFILE.PRO;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
module.exports = {
|
|
40
|
+
INSTALLATION_PROFILE,
|
|
41
|
+
normalizeInstallationProfile,
|
|
42
|
+
isProInstallationProfile
|
|
43
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Setup platform topology mode (`single` | `full`).
|
|
3
|
+
*
|
|
4
|
+
* This is distinct from `setupInstallationProfile` (dev/pro password bundle) and from
|
|
5
|
+
* the login/run environment (`dev` | `tst` | `pro`).
|
|
6
|
+
*
|
|
7
|
+
* @fileoverview Setup platform mode normalization and defaults
|
|
8
|
+
* @author AI Fabrix Team
|
|
9
|
+
* @version 1.0.0
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
'use strict';
|
|
13
|
+
|
|
14
|
+
/** @enum {string} */
|
|
15
|
+
const SETUP_PLATFORM_MODE = Object.freeze({
|
|
16
|
+
SINGLE: 'single',
|
|
17
|
+
FULL: 'full'
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @param {unknown} value
|
|
22
|
+
* @returns {'single'|'full'}
|
|
23
|
+
*/
|
|
24
|
+
function normalizeSetupPlatformMode(value) {
|
|
25
|
+
const raw = String(value ?? '')
|
|
26
|
+
.trim()
|
|
27
|
+
.toLowerCase();
|
|
28
|
+
if (raw === SETUP_PLATFORM_MODE.FULL) return SETUP_PLATFORM_MODE.FULL;
|
|
29
|
+
if (raw === 'all' || raw === 'full-platform' || raw === 'platform-full') return SETUP_PLATFORM_MODE.FULL;
|
|
30
|
+
return SETUP_PLATFORM_MODE.SINGLE;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Derived config flags for a chosen platform mode.
|
|
35
|
+
*
|
|
36
|
+
* - single: direct ports, no front door ingress
|
|
37
|
+
* - full: enable Traefik ingress + env-scoped resources
|
|
38
|
+
*
|
|
39
|
+
* @param {'single'|'full'} mode
|
|
40
|
+
* @returns {{ traefik: boolean, useEnvironmentScopedResources: boolean }}
|
|
41
|
+
*/
|
|
42
|
+
function flagsForSetupPlatformMode(mode) {
|
|
43
|
+
const m = normalizeSetupPlatformMode(mode);
|
|
44
|
+
return {
|
|
45
|
+
traefik: m === SETUP_PLATFORM_MODE.FULL,
|
|
46
|
+
useEnvironmentScopedResources: m === SETUP_PLATFORM_MODE.FULL
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
module.exports = {
|
|
51
|
+
SETUP_PLATFORM_MODE,
|
|
52
|
+
normalizeSetupPlatformMode,
|
|
53
|
+
flagsForSetupPlatformMode
|
|
54
|
+
};
|
|
55
|
+
|
|
@@ -21,7 +21,7 @@ async function writeTrustDebugLog(appKey, datasourceKey, payload) {
|
|
|
21
21
|
const logPath = await writeTestLog(
|
|
22
22
|
appKey,
|
|
23
23
|
payload,
|
|
24
|
-
`
|
|
24
|
+
`verify-trust-${datasourceKey}`,
|
|
25
25
|
path.dirname(getIntegrationPath(appKey))
|
|
26
26
|
);
|
|
27
27
|
return logPath;
|
|
@@ -14,14 +14,15 @@ const { setupIntegrationTestAuth } = require('../external-system/test-auth');
|
|
|
14
14
|
const { resolveAppKeyForDatasource } = require('./resolve-app');
|
|
15
15
|
const { getSystemKeyFromAppKey } = require('./integration-context');
|
|
16
16
|
const { requireBearerForDataplanePipeline } = require('../utils/token-manager');
|
|
17
|
+
const { buildMinimalUploadSyncOptions } = require('../utils/upload-sync-options');
|
|
17
18
|
const { fetchTrustRunFromDataplane } = require('./agent-trust-fetch');
|
|
18
19
|
|
|
19
|
-
async function maybeSyncBeforeTrust({ noSync, authConfig, systemKey }) {
|
|
20
|
+
async function maybeSyncBeforeTrust({ noSync, authConfig, systemKey, options = {} }) {
|
|
20
21
|
if (noSync === true) return;
|
|
21
22
|
requireBearerForDataplanePipeline(authConfig);
|
|
22
23
|
logger.log(chalk.cyan('Syncing local config to dataplane…'));
|
|
23
24
|
const { uploadExternalSystem } = require('../commands/upload');
|
|
24
|
-
await uploadExternalSystem(systemKey,
|
|
25
|
+
await uploadExternalSystem(systemKey, buildMinimalUploadSyncOptions(options));
|
|
25
26
|
logger.log(formatSuccessLine('Sync complete'));
|
|
26
27
|
}
|
|
27
28
|
|
|
@@ -67,7 +68,8 @@ async function runDatasourceAgentTrust(datasourceKey, options = {}) {
|
|
|
67
68
|
await maybeSyncBeforeTrust({
|
|
68
69
|
noSync: options.noSync === true,
|
|
69
70
|
authConfig,
|
|
70
|
-
systemKey
|
|
71
|
+
systemKey,
|
|
72
|
+
options
|
|
71
73
|
});
|
|
72
74
|
|
|
73
75
|
try {
|
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
'use strict';
|
|
8
8
|
|
|
9
|
+
const { parseCapacityDetailKey } = require('../utils/load-cip-capacity-display-config');
|
|
10
|
+
|
|
9
11
|
/**
|
|
10
12
|
* @param {Array<*>} ids
|
|
11
13
|
* @returns {string[]}
|
|
@@ -67,32 +69,42 @@ function executionIdsFromDebugEnvelope(envelope) {
|
|
|
67
69
|
}
|
|
68
70
|
|
|
69
71
|
/**
|
|
70
|
-
* CIP operation names from capacity step (insert, update, list, …).
|
|
71
72
|
* @param {Object|null|undefined} envelope
|
|
72
|
-
* @returns {
|
|
73
|
+
* @returns {Object|null}
|
|
73
74
|
*/
|
|
74
|
-
function
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
75
|
+
function getCapacityStepFromEnvelope(envelope) {
|
|
76
|
+
const asyncDbg = envelope && envelope.debug && envelope.debug.e2eAsyncDebug;
|
|
77
|
+
if (!asyncDbg || !Array.isArray(asyncDbg.stepDebug)) return null;
|
|
78
|
+
return asyncDbg.stepDebug.find(s => s && s.name === 'capacity') || null;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Operation names from CIP capacity evidence keys (`capacity:<op>#<index>`), without product aliases.
|
|
83
|
+
* @param {*} details
|
|
84
|
+
* @returns {Set<string>}
|
|
85
|
+
*/
|
|
86
|
+
function collectCipOpsFromCapabilityDetails(details) {
|
|
80
87
|
const ops = new Set();
|
|
81
|
-
|
|
82
|
-
if (!Array.isArray(details)) return [];
|
|
88
|
+
if (!Array.isArray(details)) return ops;
|
|
83
89
|
for (const ds of details) {
|
|
84
90
|
if (!ds || !Array.isArray(ds.capabilityDetails)) continue;
|
|
85
91
|
for (const item of ds.capabilityDetails) {
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
if (m && m[1]) {
|
|
89
|
-
let op = m[1] === 'updateBasic' ? 'updatebasic' : m[1].toLowerCase();
|
|
90
|
-
if (op === 'create') op = 'insert';
|
|
91
|
-
ops.add(op);
|
|
92
|
-
}
|
|
92
|
+
const parsed = parseCapacityDetailKey(item && item.key);
|
|
93
|
+
if (parsed && parsed.op) ops.add(parsed.op);
|
|
93
94
|
}
|
|
94
95
|
}
|
|
95
|
-
return
|
|
96
|
+
return ops;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* CIP operation names from capacity step (insert, update, list, …).
|
|
101
|
+
* @param {Object|null|undefined} envelope
|
|
102
|
+
* @returns {string[]}
|
|
103
|
+
*/
|
|
104
|
+
function cipOperationsFromDebugEnvelope(envelope) {
|
|
105
|
+
const capStep = getCapacityStepFromEnvelope(envelope);
|
|
106
|
+
if (!capStep || !capStep.evidence) return [];
|
|
107
|
+
return [...collectCipOpsFromCapabilityDetails(capStep.evidence.datasources)];
|
|
96
108
|
}
|
|
97
109
|
|
|
98
110
|
module.exports = {
|
|
@@ -16,6 +16,7 @@ const {
|
|
|
16
16
|
cipOperationsFromDebugEnvelope,
|
|
17
17
|
dedupeIds: dedupeIdsFromDebug
|
|
18
18
|
} = require('./audit-evidence-extract-debug');
|
|
19
|
+
const loadCipCapacityDisplayConfig = require('../utils/load-cip-capacity-display-config');
|
|
19
20
|
|
|
20
21
|
/** @param {Array<*>} ids @returns {string[]} */
|
|
21
22
|
function dedupeIds(ids) {
|
|
@@ -88,14 +89,16 @@ function correlationIdFromEnvelope(envelope) {
|
|
|
88
89
|
function expectedOperationsFromEnvelope(envelope) {
|
|
89
90
|
const fromCapacity = cipOperationsFromDebugEnvelope(envelope);
|
|
90
91
|
if (fromCapacity.length) return fromCapacity;
|
|
92
|
+
const { standardOrder } = loadCipCapacityDisplayConfig.getCipCapacityDisplayConfig();
|
|
93
|
+
const allowed = new Set(
|
|
94
|
+
(standardOrder || []).map(op => String(op).trim().toLowerCase()).filter(Boolean)
|
|
95
|
+
);
|
|
91
96
|
const ops = new Set();
|
|
92
97
|
const caps = envelope && Array.isArray(envelope.capabilities) ? envelope.capabilities : [];
|
|
93
98
|
for (const cap of caps) {
|
|
94
99
|
if (!cap || cap.status === 'skipped' || !cap.key) continue;
|
|
95
|
-
const key = String(cap.key).trim();
|
|
96
|
-
if (
|
|
97
|
-
ops.add(key === 'create' ? 'insert' : key);
|
|
98
|
-
}
|
|
100
|
+
const key = String(cap.key).trim().toLowerCase();
|
|
101
|
+
if (allowed.has(key)) ops.add(key);
|
|
99
102
|
}
|
|
100
103
|
const integration = envelope && envelope.integration;
|
|
101
104
|
if (integration && integration.sync && integration.sync.status === 'ok') {
|