@aifabrix/builder 2.44.5 → 2.45.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 +8 -4
- package/.cursor/rules/project-rules.mdc +1 -1
- package/README.md +15 -23
- package/integration/hubspot-test/README.md +2 -0
- package/integration/hubspot-test/test.js +5 -3
- package/jest.projects.js +104 -2
- package/lib/api/controller-health.api.js +49 -0
- package/lib/api/dimension-values.api.js +82 -0
- package/lib/api/dimensions.api.js +114 -0
- package/lib/api/external-systems.api.js +1 -0
- package/lib/api/integration-clients.api.js +168 -0
- package/lib/api/types/dimension-values.types.js +28 -0
- package/lib/api/types/dimensions.types.js +31 -0
- package/lib/api/types/integration-clients.types.js +45 -0
- package/lib/api/validation-runner.js +46 -25
- package/lib/app/deploy-config.js +11 -1
- package/lib/app/deploy-status-display.js +3 -3
- package/lib/app/deploy.js +36 -14
- package/lib/app/display.js +15 -11
- package/lib/app/helpers.js +3 -3
- package/lib/app/index.js +3 -3
- package/lib/app/push.js +46 -23
- package/lib/app/register.js +7 -6
- package/lib/app/restart-display.js +126 -0
- package/lib/app/rotate-secret.js +7 -6
- package/lib/app/run-container-start.js +12 -6
- package/lib/app/run-env-compose.js +30 -1
- package/lib/app/run-helpers.js +58 -19
- package/lib/app/run-reload-sync.js +148 -0
- package/lib/app/run-resolve-image.js +51 -1
- package/lib/app/run.js +148 -74
- package/lib/app/show-display.js +7 -0
- package/lib/app/show.js +87 -5
- package/lib/build/index.js +83 -49
- package/lib/cli/doctor-check.js +117 -0
- package/lib/cli/index.js +8 -2
- package/lib/cli/infra-guided.js +460 -0
- package/lib/cli/installation-log-command.js +73 -0
- package/lib/cli/setup-app.js +31 -3
- package/lib/cli/setup-auth.js +98 -27
- package/lib/cli/setup-dev-path-commands.js +50 -3
- package/lib/cli/setup-infra-up-dataplane-action.js +111 -0
- package/lib/cli/setup-infra-up-platform-action.js +131 -0
- package/lib/cli/setup-infra.js +132 -118
- package/lib/cli/setup-integration-client.js +182 -0
- package/lib/cli/setup-parameters.js +21 -2
- package/lib/cli/setup-platform.js +102 -0
- package/lib/cli/setup-secrets.js +18 -6
- package/lib/cli/setup-utility-resolve.js +132 -0
- package/lib/cli/setup-utility.js +143 -84
- package/lib/commands/app-logs.js +81 -33
- package/lib/commands/auth-config.js +116 -18
- package/lib/commands/datasource-capability-dimension-cli.js +128 -0
- package/lib/commands/datasource-capability-output.js +29 -0
- package/lib/commands/datasource-capability-relate-cli.js +140 -0
- package/lib/commands/datasource-capability.js +411 -0
- package/lib/commands/datasource-unified-test-cli.options.js +1 -1
- package/lib/commands/datasource.js +53 -13
- package/lib/commands/dev-down.js +3 -3
- package/lib/commands/dev-infra-gate.js +32 -0
- package/lib/commands/dev-init.js +13 -7
- package/lib/commands/dimension-value.js +179 -0
- package/lib/commands/dimension.js +330 -0
- package/lib/commands/integration-client.js +430 -0
- package/lib/commands/login-device.js +65 -30
- package/lib/commands/login.js +21 -10
- package/lib/commands/parameters-validate.js +78 -13
- package/lib/commands/repair-datasource-auto-rbac.js +166 -0
- package/lib/commands/repair-datasource-keys.js +10 -5
- package/lib/commands/repair-datasource.js +19 -7
- package/lib/commands/repair-env-template.js +4 -1
- package/lib/commands/repair-openapi-sync.js +172 -0
- package/lib/commands/repair-persist.js +102 -0
- package/lib/commands/repair-rbac-extract.js +27 -0
- package/lib/commands/repair-rbac-migrate.js +186 -0
- package/lib/commands/repair-rbac.js +214 -31
- package/lib/commands/repair-system-alignment.js +246 -0
- package/lib/commands/repair-system-permissions.js +168 -0
- package/lib/commands/repair.js +120 -338
- package/lib/commands/secure.js +1 -1
- package/lib/commands/setup-modes.js +468 -0
- package/lib/commands/setup-prompts.js +421 -0
- package/lib/commands/setup.js +254 -0
- package/lib/commands/teardown.js +277 -0
- package/lib/commands/up-common.js +113 -19
- package/lib/commands/up-dataplane.js +44 -19
- package/lib/commands/up-miso.js +18 -18
- package/lib/commands/upload.js +111 -23
- package/lib/commands/wizard-core-helpers.js +14 -11
- package/lib/commands/wizard-core.js +6 -5
- package/lib/commands/wizard-dataplane.js +2 -2
- package/lib/commands/wizard-entity-selection.js +4 -3
- package/lib/commands/wizard-headless.js +2 -1
- package/lib/commands/wizard.js +2 -1
- package/lib/constants/infra-compose-service-names.js +40 -0
- package/lib/core/audit-logger.js +1 -34
- package/lib/core/config-admin-email.js +56 -0
- package/lib/core/config-normalize.js +60 -0
- package/lib/core/config-registered-controller-urls.js +54 -0
- package/lib/core/config.js +33 -50
- package/lib/core/env-reader.js +16 -3
- package/lib/core/secrets-admin-env.js +101 -0
- package/lib/core/secrets-ensure-infra.js +34 -1
- package/lib/core/secrets-ensure.js +88 -66
- package/lib/core/secrets-env-content.js +428 -0
- package/lib/core/secrets-env-declarative-expand.js +170 -0
- package/lib/core/secrets-env-write.js +29 -1
- package/lib/core/secrets-load.js +252 -0
- package/lib/core/secrets-names.js +32 -0
- package/lib/core/secrets.js +17 -757
- package/lib/datasource/capability/basic-exposure.js +76 -0
- package/lib/datasource/capability/capability-diff-slice.js +41 -0
- package/lib/datasource/capability/capability-key.js +34 -0
- package/lib/datasource/capability/capability-resolve.js +172 -0
- package/lib/datasource/capability/capability-storage-keys.js +22 -0
- package/lib/datasource/capability/copy-operations.js +348 -0
- package/lib/datasource/capability/copy-test-payload.js +139 -0
- package/lib/datasource/capability/create-operations.js +235 -0
- package/lib/datasource/capability/dimension-operations.js +151 -0
- package/lib/datasource/capability/dimension-validate.js +219 -0
- package/lib/datasource/capability/json-pointer.js +31 -0
- package/lib/datasource/capability/reference-rewrite.js +51 -0
- package/lib/datasource/capability/relate-operations.js +325 -0
- package/lib/datasource/capability/relate-validate.js +219 -0
- package/lib/datasource/capability/remove-operations.js +275 -0
- package/lib/datasource/capability/run-capability-copy.js +152 -0
- package/lib/datasource/capability/run-capability-diff.js +135 -0
- package/lib/datasource/capability/run-capability-dimension.js +291 -0
- package/lib/datasource/capability/run-capability-edit.js +377 -0
- package/lib/datasource/capability/run-capability-relate.js +193 -0
- package/lib/datasource/capability/run-capability-remove.js +105 -0
- package/lib/datasource/capability/templates/minimal-fetch.json +18 -0
- package/lib/datasource/capability/validate-capability-slice.js +35 -0
- package/lib/datasource/list.js +136 -23
- package/lib/datasource/log-viewer.js +2 -4
- package/lib/datasource/unified-validation-run.js +51 -16
- package/lib/datasource/validate.js +53 -1
- package/lib/deployment/deploy-poll-ui.js +60 -0
- package/lib/deployment/deployer-status.js +29 -3
- package/lib/deployment/deployer.js +48 -30
- package/lib/deployment/environment.js +7 -2
- package/lib/deployment/poll-interval.js +72 -0
- package/lib/deployment/push.js +11 -9
- package/lib/external-system/deploy.js +9 -2
- package/lib/external-system/download.js +61 -32
- package/lib/external-system/sync-deploy-manifest.js +33 -0
- package/lib/infrastructure/index.js +49 -19
- package/lib/infrastructure/orphan-infra-docker-teardown.js +177 -0
- package/lib/internal/node-fs.js +2 -0
- package/lib/parameters/infra-kv-discovery.js +29 -4
- package/lib/parameters/infra-parameter-catalog.js +6 -3
- package/lib/parameters/infra-parameter-validate.js +67 -19
- package/lib/resolvers/datasource-resolver.js +53 -0
- package/lib/resolvers/dimension-file.js +52 -0
- package/lib/resolvers/manifest-resolver.js +133 -0
- package/lib/schema/application-schema.json +4 -0
- package/lib/schema/external-datasource.schema.json +183 -53
- package/lib/schema/external-system.schema.json +23 -10
- package/lib/schema/infra.parameter.yaml +26 -1
- package/lib/schema/wizard-config.schema.json +1 -1
- package/lib/utils/aifabrix-config-dir-walk.js +40 -0
- package/lib/utils/aifabrix-runtime-config-dir.js +26 -3
- package/lib/utils/app-config-resolver.js +24 -1
- package/lib/utils/app-run-containers.js +2 -2
- package/lib/utils/applications-config-defaults.js +206 -0
- package/lib/utils/auth-config-validator.js +2 -12
- package/lib/utils/bash-secret-env.js +59 -0
- package/lib/utils/cli-secrets-error-format.js +78 -0
- package/lib/utils/cli-test-layout-chalk.js +31 -9
- package/lib/utils/cli-utils.js +4 -36
- package/lib/utils/compose-generate-docker-compose.js +111 -6
- package/lib/utils/compose-generator.js +17 -8
- package/lib/utils/controller-url.js +50 -7
- package/lib/utils/datasource-test-run-display.js +8 -0
- package/lib/utils/dev-hosts-helper.js +3 -2
- package/lib/utils/dev-init-ssh-merge.js +2 -1
- package/lib/utils/docker-build.js +17 -9
- package/lib/utils/docker-reload-mount.js +127 -0
- package/lib/utils/env-copy.js +99 -14
- package/lib/utils/env-template.js +5 -1
- package/lib/utils/external-readme.js +71 -2
- package/lib/utils/external-system-local-test-tty.js +3 -2
- package/lib/utils/external-system-readiness-core.js +45 -12
- package/lib/utils/external-system-readiness-deploy-display.js +3 -3
- package/lib/utils/external-system-readiness-display-internals.js +33 -3
- package/lib/utils/external-system-readiness-display.js +10 -1
- package/lib/utils/file-upload.js +40 -3
- package/lib/utils/health-check-db-init.js +107 -0
- package/lib/utils/health-check-public-warn.js +69 -0
- package/lib/utils/health-check-url.js +28 -10
- package/lib/utils/health-check.js +139 -107
- package/lib/utils/help-builder.js +5 -1
- package/lib/utils/image-name.js +34 -7
- package/lib/utils/infra-optional-service-flags.js +69 -0
- package/lib/utils/installation-log-core.js +282 -0
- package/lib/utils/installation-log-record.js +237 -0
- package/lib/utils/installation-log.js +123 -0
- package/lib/utils/integration-file-backup.js +74 -0
- package/lib/utils/log-redaction.js +105 -0
- package/lib/utils/manifest-location.js +164 -0
- package/lib/utils/manifest-source-emit.js +162 -0
- package/lib/utils/mutagen-install.js +30 -3
- package/lib/utils/paths.js +308 -76
- package/lib/utils/postgres-wipe.js +212 -0
- package/lib/utils/register-aifabrix-shell-env.js +15 -0
- package/lib/utils/remote-dev-auth.js +21 -5
- package/lib/utils/remote-docker-env.js +9 -1
- package/lib/utils/remote-secrets-loader.js +49 -4
- package/lib/utils/resolve-docker-image-ref.js +9 -3
- package/lib/utils/run-cli-flags.js +29 -0
- package/lib/utils/secrets-ancestor-paths.js +47 -0
- package/lib/utils/secrets-canonical.js +10 -3
- package/lib/utils/secrets-helpers.js +17 -10
- package/lib/utils/secrets-kv-refs.js +42 -0
- package/lib/utils/secrets-kv-scope.js +19 -2
- package/lib/utils/secrets-materialize-local.js +134 -0
- package/lib/utils/secrets-path.js +26 -13
- package/lib/utils/secrets-utils.js +20 -10
- package/lib/utils/system-builder-root.js +42 -0
- package/lib/utils/url-declarative-public-base.js +80 -12
- package/lib/utils/url-declarative-resolve-build-urls.js +238 -0
- package/lib/utils/url-declarative-resolve-build.js +24 -388
- package/lib/utils/url-declarative-resolve-expand-token.js +189 -0
- package/lib/utils/url-declarative-resolve-load-doc.js +12 -3
- package/lib/utils/url-declarative-resolve-surface-state.js +102 -0
- package/lib/utils/url-declarative-resolve.js +47 -7
- package/lib/utils/url-declarative-runtime-base-path.js +52 -0
- package/lib/utils/url-declarative-vdir-inactive-env.js +2 -1
- package/lib/utils/urls-local-registry-scan.js +103 -0
- package/lib/utils/urls-local-registry.js +158 -76
- package/lib/utils/validation-poll-ui.js +81 -0
- package/lib/utils/validation-run-poll.js +29 -5
- package/lib/utils/with-muted-logger.js +53 -0
- package/package.json +3 -1
- package/templates/applications/dataplane/application.yaml +5 -1
- package/templates/applications/dataplane/rbac.yaml +10 -10
- package/templates/applications/keycloak/env.template +8 -6
- package/templates/applications/miso-controller/application.yaml +9 -0
- package/templates/applications/miso-controller/env.template +27 -29
- package/templates/applications/miso-controller/rbac.yaml +9 -9
- package/templates/external-system/README.md.hbs +83 -123
- package/.npmrc.token +0 -1
- package/.nyc_output/55e9d034-ddab-4579-a706-e02a91d75c91.json +0 -1
- package/.nyc_output/processinfo/55e9d034-ddab-4579-a706-e02a91d75c91.json +0 -1
- package/.nyc_output/processinfo/index.json +0 -1
- package/lib/api/service-users.api.js +0 -150
- package/lib/api/types/service-users.types.js +0 -65
- package/lib/cli/setup-service-user.js +0 -187
- package/lib/commands/service-user.js +0 -429
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Optional infra compose flags (Traefik, pgAdmin, Redis Commander) for config.yaml ↔ startInfra.
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Effective flag resolution + backfill missing keys after up-infra / setup
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const config = require('../core/config');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Resolves effective boolean from CLI option vs config.
|
|
15
|
+
* @param {*} optValue - options.traefik | options.pgAdmin | options.redisAdmin
|
|
16
|
+
* @param {*} cfgValue - cfg.traefik | cfg.pgadmin | cfg.redisCommander
|
|
17
|
+
* @param {boolean} defaultWhenUndef - Default when config value is undefined
|
|
18
|
+
* @returns {boolean}
|
|
19
|
+
*/
|
|
20
|
+
function resolveInfraOptionalFlag(optValue, cfgValue, defaultWhenUndef = true) {
|
|
21
|
+
if (optValue === true) return true;
|
|
22
|
+
if (optValue === false) return false;
|
|
23
|
+
return cfgValue !== false && (cfgValue === true || defaultWhenUndef);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Effective optional infra service flags (same resolution as up-infra → startInfra).
|
|
28
|
+
*
|
|
29
|
+
* @param {Object} cfg - Config from {@link config.getConfig}
|
|
30
|
+
* @param {Object} [options] - Commander options (omit for setup-modes)
|
|
31
|
+
* @returns {{ traefik: boolean, pgadmin: boolean, redisCommander: boolean }}
|
|
32
|
+
*/
|
|
33
|
+
function computeEffectiveInfraOptionalFlags(cfg, options = {}) {
|
|
34
|
+
return {
|
|
35
|
+
traefik: resolveInfraOptionalFlag(options.traefik, cfg.traefik, false),
|
|
36
|
+
pgadmin: resolveInfraOptionalFlag(options.pgAdmin, cfg.pgadmin, true),
|
|
37
|
+
redisCommander: resolveInfraOptionalFlag(options.redisAdmin, cfg.redisCommander, true)
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Writes `traefik` / `pgadmin` / `redisCommander` when missing so config matches compose defaults.
|
|
43
|
+
*
|
|
44
|
+
* @param {Object} cfg - Mutable config (updated when save runs)
|
|
45
|
+
* @param {{ traefik: boolean, pgadmin: boolean, redisCommander: boolean }} effective
|
|
46
|
+
* @returns {Promise<void>}
|
|
47
|
+
*/
|
|
48
|
+
async function persistMissingInfraOptionalServiceFlags(cfg, effective) {
|
|
49
|
+
const keys = ['traefik', 'pgadmin', 'redisCommander'];
|
|
50
|
+
const merged = { ...cfg };
|
|
51
|
+
let dirty = false;
|
|
52
|
+
for (const k of keys) {
|
|
53
|
+
if (typeof merged[k] === 'undefined') {
|
|
54
|
+
merged[k] = effective[k];
|
|
55
|
+
dirty = true;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (!dirty) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
await config.saveConfig(merged);
|
|
62
|
+
Object.assign(cfg, merged);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
module.exports = {
|
|
66
|
+
resolveInfraOptionalFlag,
|
|
67
|
+
computeEffectiveInfraOptionalFlags,
|
|
68
|
+
persistMissingInfraOptionalServiceFlags
|
|
69
|
+
};
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared helpers for installation.log (no append I/O).
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview installation log core utilities
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 2.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const fsSync = require('fs');
|
|
12
|
+
const path = require('path');
|
|
13
|
+
const paths = require('./paths');
|
|
14
|
+
const { maskSensitiveData } = require('./log-redaction');
|
|
15
|
+
const { loadConfigFile } = require('./config-format');
|
|
16
|
+
const { resolveDockerImageRef } = require('./resolve-docker-image-ref');
|
|
17
|
+
const { parseImageOptions } = require('../commands/up-miso');
|
|
18
|
+
|
|
19
|
+
let opCounter = 0;
|
|
20
|
+
let opDay = '';
|
|
21
|
+
|
|
22
|
+
let cachedCliVersion = null;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @returns {string}
|
|
26
|
+
*/
|
|
27
|
+
function getCliVersion() {
|
|
28
|
+
if (cachedCliVersion) {
|
|
29
|
+
return cachedCliVersion;
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
const pkgPath = path.join(__dirname, '..', '..', 'package.json');
|
|
33
|
+
const raw = fsSync.readFileSync(pkgPath, 'utf8');
|
|
34
|
+
const pkg = JSON.parse(raw);
|
|
35
|
+
cachedCliVersion = typeof pkg.version === 'string' ? pkg.version : 'unknown';
|
|
36
|
+
} catch {
|
|
37
|
+
cachedCliVersion = 'unknown';
|
|
38
|
+
}
|
|
39
|
+
return cachedCliVersion;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @returns {string} e.g. op_20260513_001
|
|
44
|
+
*/
|
|
45
|
+
function createOperationId() {
|
|
46
|
+
const d = new Date();
|
|
47
|
+
const day = d.toISOString().slice(0, 10).replace(/-/g, '');
|
|
48
|
+
if (day !== opDay) {
|
|
49
|
+
opDay = day;
|
|
50
|
+
opCounter = 0;
|
|
51
|
+
}
|
|
52
|
+
opCounter += 1;
|
|
53
|
+
return `op_${day}_${String(opCounter).padStart(3, '0')}`;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* @param {string} ref
|
|
58
|
+
* @returns {string}
|
|
59
|
+
*/
|
|
60
|
+
function stripDockerDigest(ref) {
|
|
61
|
+
if (!ref || typeof ref !== 'string') {
|
|
62
|
+
return ref;
|
|
63
|
+
}
|
|
64
|
+
return ref.replace(/@sha256:[a-f0-9]+$/i, '');
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* @param {string|undefined} url
|
|
69
|
+
* @returns {string|undefined}
|
|
70
|
+
*/
|
|
71
|
+
function sanitizeUrl(url) {
|
|
72
|
+
if (!url || typeof url !== 'string') {
|
|
73
|
+
return undefined;
|
|
74
|
+
}
|
|
75
|
+
try {
|
|
76
|
+
const u = new URL(url);
|
|
77
|
+
u.username = '';
|
|
78
|
+
u.password = '';
|
|
79
|
+
let s = u.toString();
|
|
80
|
+
if (s.endsWith('/')) {
|
|
81
|
+
s = s.slice(0, -1);
|
|
82
|
+
}
|
|
83
|
+
return s;
|
|
84
|
+
} catch {
|
|
85
|
+
return maskSensitiveData(url);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* @param {Object} [options]
|
|
91
|
+
* @returns {'interactive'|'automation'}
|
|
92
|
+
*/
|
|
93
|
+
function resolveLogMode(options = {}) {
|
|
94
|
+
const assume =
|
|
95
|
+
options.yes === true ||
|
|
96
|
+
options.assumeYes === true ||
|
|
97
|
+
process.env.CI === 'true' ||
|
|
98
|
+
process.env.CI === '1';
|
|
99
|
+
if (assume) {
|
|
100
|
+
return 'automation';
|
|
101
|
+
}
|
|
102
|
+
if (process.stdin && process.stdin.isTTY && process.stdout && process.stdout.isTTY) {
|
|
103
|
+
return 'interactive';
|
|
104
|
+
}
|
|
105
|
+
return 'automation';
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* @param {boolean|undefined} optVal
|
|
110
|
+
* @returns {boolean}
|
|
111
|
+
*/
|
|
112
|
+
function cliBoolExplicit(optVal) {
|
|
113
|
+
return optVal === true || optVal === false;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* @param {string} label
|
|
118
|
+
* @param {boolean} value
|
|
119
|
+
* @param {boolean} fromCli
|
|
120
|
+
* @returns {string}
|
|
121
|
+
*/
|
|
122
|
+
function infraLine(label, value, fromCli) {
|
|
123
|
+
const src = fromCli ? 'cli override' : 'config';
|
|
124
|
+
return ` ${label}: ${value} (${src})`;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* @param {Object} cfg
|
|
129
|
+
* @param {Object} options
|
|
130
|
+
* @returns {{ lines: string[] }}
|
|
131
|
+
*/
|
|
132
|
+
function buildInfraSectionLines(cfg, options = {}) {
|
|
133
|
+
const { computeEffectiveInfraOptionalFlags } = require('./infra-optional-service-flags');
|
|
134
|
+
const effective = computeEffectiveInfraOptionalFlags(cfg, options);
|
|
135
|
+
const tls = cfg.tlsEnabled === true;
|
|
136
|
+
const tlsFromCli = cliBoolExplicit(options.tls);
|
|
137
|
+
const lines = [
|
|
138
|
+
'Infra',
|
|
139
|
+
infraLine('traefik', effective.traefik, cliBoolExplicit(options.traefik)),
|
|
140
|
+
infraLine('tlsEnabled', tls, tlsFromCli),
|
|
141
|
+
infraLine('pgAdmin', effective.pgadmin, cliBoolExplicit(options.pgAdmin)),
|
|
142
|
+
infraLine('redisCommander', effective.redisCommander, cliBoolExplicit(options.redisAdmin))
|
|
143
|
+
];
|
|
144
|
+
return { lines };
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* @param {string} appName
|
|
149
|
+
* @returns {Object|null}
|
|
150
|
+
*/
|
|
151
|
+
function loadBuilderAppVariables(appName) {
|
|
152
|
+
try {
|
|
153
|
+
const dir = paths.getBuilderPath(appName);
|
|
154
|
+
if (!fsSync.existsSync(dir)) {
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
const configPath = paths.resolveApplicationConfigPath(dir);
|
|
158
|
+
return loadConfigFile(configPath) || {};
|
|
159
|
+
} catch {
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* @param {string} appName
|
|
166
|
+
* @param {Object} map
|
|
167
|
+
* @param {Object} runOpts
|
|
168
|
+
* @returns {void}
|
|
169
|
+
*/
|
|
170
|
+
function applyParsedImageMapToRunOpts(appName, map, runOpts) {
|
|
171
|
+
if (appName === 'keycloak' && map.keycloak) {
|
|
172
|
+
runOpts.image = map.keycloak;
|
|
173
|
+
}
|
|
174
|
+
if (appName === 'miso-controller' && map['miso-controller']) {
|
|
175
|
+
runOpts.image = map['miso-controller'];
|
|
176
|
+
}
|
|
177
|
+
if (appName === 'dataplane' && map.dataplane) {
|
|
178
|
+
runOpts.image = map.dataplane;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* @param {string} appName
|
|
184
|
+
* @param {Object} options
|
|
185
|
+
* @returns {Object}
|
|
186
|
+
*/
|
|
187
|
+
function buildImageResolveOpts(appName, options) {
|
|
188
|
+
const runOpts = {
|
|
189
|
+
registry: options.registry || undefined,
|
|
190
|
+
base: options.base !== false
|
|
191
|
+
};
|
|
192
|
+
const imageList = options.image;
|
|
193
|
+
if (Array.isArray(imageList)) {
|
|
194
|
+
applyParsedImageMapToRunOpts(appName, parseImageOptions(imageList), runOpts);
|
|
195
|
+
} else if (typeof imageList === 'string' && imageList.trim()) {
|
|
196
|
+
const t = imageList.trim();
|
|
197
|
+
if (!t.includes('=') && appName === 'dataplane') {
|
|
198
|
+
runOpts.image = t;
|
|
199
|
+
} else if (t.includes('=')) {
|
|
200
|
+
applyParsedImageMapToRunOpts(appName, parseImageOptions([t]), runOpts);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return runOpts;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* @param {string} imageRef
|
|
208
|
+
* @returns {string}
|
|
209
|
+
*/
|
|
210
|
+
function imageRefForLog(imageRef) {
|
|
211
|
+
return stripDockerDigest(String(imageRef).trim());
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* @param {string} appName
|
|
216
|
+
* @param {Object} options
|
|
217
|
+
* @returns {string}
|
|
218
|
+
*/
|
|
219
|
+
function resolveAppImageDisplay(appName, options) {
|
|
220
|
+
const variables = loadBuilderAppVariables(appName);
|
|
221
|
+
if (!variables) {
|
|
222
|
+
return 'unknown';
|
|
223
|
+
}
|
|
224
|
+
try {
|
|
225
|
+
const runOpts = buildImageResolveOpts(appName, options);
|
|
226
|
+
const { imageName, imageTag } = resolveDockerImageRef(appName, variables, runOpts);
|
|
227
|
+
return imageRefForLog(`${imageName}:${imageTag}`);
|
|
228
|
+
} catch {
|
|
229
|
+
return 'unknown';
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* @param {string[]} appNames
|
|
235
|
+
* @param {Object} options
|
|
236
|
+
* @returns {Record<string,string>}
|
|
237
|
+
*/
|
|
238
|
+
function collectPlatformAppImages(appNames, options = {}) {
|
|
239
|
+
/** @type {Record<string,string>} */
|
|
240
|
+
const out = {};
|
|
241
|
+
for (const app of appNames) {
|
|
242
|
+
out[app] = resolveAppImageDisplay(app, options);
|
|
243
|
+
}
|
|
244
|
+
return out;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* @param {Record<string,string>} platformApps
|
|
249
|
+
* @returns {string}
|
|
250
|
+
*/
|
|
251
|
+
function derivePlatformVersion(platformApps) {
|
|
252
|
+
const tags = new Set();
|
|
253
|
+
for (const ref of Object.values(platformApps)) {
|
|
254
|
+
if (!ref || ref === 'unknown') {
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
const noDig = stripDockerDigest(ref);
|
|
258
|
+
const idx = noDig.lastIndexOf(':');
|
|
259
|
+
if (idx <= 0 || idx >= noDig.length - 1) {
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
const tag = noDig.slice(idx + 1);
|
|
263
|
+
if (!tag.includes('/')) {
|
|
264
|
+
tags.add(tag);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
if (tags.size === 0) {
|
|
268
|
+
return 'unknown';
|
|
269
|
+
}
|
|
270
|
+
return [...tags].sort().join('|');
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
module.exports = {
|
|
274
|
+
getCliVersion,
|
|
275
|
+
createOperationId,
|
|
276
|
+
stripDockerDigest,
|
|
277
|
+
sanitizeUrl,
|
|
278
|
+
resolveLogMode,
|
|
279
|
+
buildInfraSectionLines,
|
|
280
|
+
collectPlatformAppImages,
|
|
281
|
+
derivePlatformVersion
|
|
282
|
+
};
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build deterministic installation.log record lines (no I/O).
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview installation record body formatting
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 2.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const config = require('../core/config');
|
|
12
|
+
const { maskSensitiveData } = require('./log-redaction');
|
|
13
|
+
const {
|
|
14
|
+
createOperationId,
|
|
15
|
+
getCliVersion,
|
|
16
|
+
collectPlatformAppImages,
|
|
17
|
+
derivePlatformVersion,
|
|
18
|
+
buildInfraSectionLines,
|
|
19
|
+
resolveLogMode,
|
|
20
|
+
sanitizeUrl
|
|
21
|
+
} = require('./installation-log-core');
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @param {string[]} lines
|
|
25
|
+
* @param {string} isoHeader
|
|
26
|
+
* @returns {void}
|
|
27
|
+
*/
|
|
28
|
+
function pushTopBanner(lines, isoHeader) {
|
|
29
|
+
lines.push('='.repeat(80));
|
|
30
|
+
lines.push(`INSTALLATION ${isoHeader}`);
|
|
31
|
+
lines.push('-'.repeat(80));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @param {string[]} lines
|
|
36
|
+
* @param {Object} payload
|
|
37
|
+
* @param {Object} identity
|
|
38
|
+
* @returns {void}
|
|
39
|
+
*/
|
|
40
|
+
function pushIdentityCore(lines, payload, identity) {
|
|
41
|
+
const { startedAt, completedAt, developerId, mode, platformVersion, durationSec } = identity;
|
|
42
|
+
lines.push('recordVersion: 1');
|
|
43
|
+
lines.push(`operationId: ${createOperationId()}`);
|
|
44
|
+
lines.push(`command: ${payload.command}`);
|
|
45
|
+
lines.push(`outcome: ${payload.outcome}`);
|
|
46
|
+
lines.push(`durationSec: ${durationSec}`);
|
|
47
|
+
lines.push(`cliVersion: ${getCliVersion()}`);
|
|
48
|
+
lines.push(`platformVersion: ${platformVersion}`);
|
|
49
|
+
lines.push(`developerId: ${developerId}`);
|
|
50
|
+
lines.push(`mode: ${mode}`);
|
|
51
|
+
lines.push(`startedAt: ${startedAt.toISOString()}`);
|
|
52
|
+
lines.push(`completedAt: ${completedAt.toISOString()}`);
|
|
53
|
+
|
|
54
|
+
if (payload.setupMode) {
|
|
55
|
+
lines.push(`setupMode: ${payload.setupMode}`);
|
|
56
|
+
}
|
|
57
|
+
if (payload.upPlatformForce) {
|
|
58
|
+
lines.push('upPlatformForce: true');
|
|
59
|
+
}
|
|
60
|
+
lines.push('');
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* @param {string[]} lines
|
|
65
|
+
* @param {Object} payload
|
|
66
|
+
* @param {Object} identity
|
|
67
|
+
* @param {Date} identity.startedAt
|
|
68
|
+
* @param {Date} identity.completedAt
|
|
69
|
+
* @param {string} identity.developerId
|
|
70
|
+
* @param {string} identity.mode
|
|
71
|
+
* @param {string} identity.platformVersion
|
|
72
|
+
* @returns {void}
|
|
73
|
+
*/
|
|
74
|
+
function pushHeaderAndIdentity(lines, payload, identity) {
|
|
75
|
+
const { startedAt, completedAt } = identity;
|
|
76
|
+
const durationSec = Math.round(
|
|
77
|
+
Math.max(0, completedAt.getTime() - startedAt.getTime()) / 1000
|
|
78
|
+
);
|
|
79
|
+
const isoHeader = completedAt.toISOString();
|
|
80
|
+
pushTopBanner(lines, isoHeader);
|
|
81
|
+
pushIdentityCore(lines, payload, { ...identity, durationSec });
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* @param {string[]} lines
|
|
86
|
+
* @param {Object} payload
|
|
87
|
+
* @returns {void}
|
|
88
|
+
*/
|
|
89
|
+
function pushInfraBlock(lines, payload) {
|
|
90
|
+
if (!payload.infra || !payload.infra.cfg) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const { lines: infraLines } = buildInfraSectionLines(payload.infra.cfg, payload.infra.options || {});
|
|
94
|
+
lines.push(...infraLines);
|
|
95
|
+
lines.push('');
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* @param {string[]} lines
|
|
100
|
+
* @param {Record<string,string>|undefined} platformApps
|
|
101
|
+
* @returns {void}
|
|
102
|
+
*/
|
|
103
|
+
function pushPlatformAppsBlock(lines, platformApps) {
|
|
104
|
+
if (!platformApps || Object.keys(platformApps).length === 0) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
lines.push('Platform Apps');
|
|
108
|
+
for (const key of Object.keys(platformApps).sort()) {
|
|
109
|
+
lines.push(` ${key}: ${platformApps[key]}`);
|
|
110
|
+
}
|
|
111
|
+
lines.push('');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* @param {string[]} lines
|
|
116
|
+
* @param {Object} payload
|
|
117
|
+
* @returns {void}
|
|
118
|
+
*/
|
|
119
|
+
function pushConfigBlock(lines, payload) {
|
|
120
|
+
const cfgExtra = payload.configExtra || {};
|
|
121
|
+
const hasConfig =
|
|
122
|
+
cfgExtra.controllerUrl ||
|
|
123
|
+
cfgExtra.adminEmail === 'set' ||
|
|
124
|
+
cfgExtra.adminEmail === 'unset';
|
|
125
|
+
if (!hasConfig) {
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
lines.push('Config');
|
|
129
|
+
if (cfgExtra.controllerUrl) {
|
|
130
|
+
lines.push(` controllerUrl: ${sanitizeUrl(cfgExtra.controllerUrl)}`);
|
|
131
|
+
}
|
|
132
|
+
if (cfgExtra.adminEmail === 'set' || cfgExtra.adminEmail === 'unset') {
|
|
133
|
+
lines.push(` adminEmail: ${cfgExtra.adminEmail}`);
|
|
134
|
+
}
|
|
135
|
+
lines.push('');
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* @param {string[]} lines
|
|
140
|
+
* @param {Object} payload
|
|
141
|
+
* @returns {void}
|
|
142
|
+
*/
|
|
143
|
+
function pushCleanupBlock(lines, payload) {
|
|
144
|
+
const cleanup = payload.cleanup;
|
|
145
|
+
if (!cleanup || typeof cleanup !== 'object' || Object.keys(cleanup).length === 0) {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
lines.push('Cleanup');
|
|
149
|
+
if (cleanup.volumesRemoved !== undefined) {
|
|
150
|
+
lines.push(` volumesRemoved: ${cleanup.volumesRemoved}`);
|
|
151
|
+
}
|
|
152
|
+
if (cleanup.configPreserved !== undefined) {
|
|
153
|
+
lines.push(` configPreserved: ${cleanup.configPreserved}`);
|
|
154
|
+
}
|
|
155
|
+
if (Array.isArray(cleanup.cleanedAppKeys) && cleanup.cleanedAppKeys.length > 0) {
|
|
156
|
+
lines.push(` cleanedAppKeys: ${cleanup.cleanedAppKeys.sort().join(', ')}`);
|
|
157
|
+
}
|
|
158
|
+
lines.push('');
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* @param {string[]} lines
|
|
163
|
+
* @param {Object} payload
|
|
164
|
+
* @returns {void}
|
|
165
|
+
*/
|
|
166
|
+
function pushErrorSection(lines, payload) {
|
|
167
|
+
if (payload.outcome !== 'failure' || !payload.error) {
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
const msg =
|
|
171
|
+
typeof payload.error.message === 'string'
|
|
172
|
+
? payload.error.message
|
|
173
|
+
: String(payload.error);
|
|
174
|
+
lines.push('Error');
|
|
175
|
+
lines.push(` message: ${maskSensitiveData(msg)}`);
|
|
176
|
+
if (payload.errorCode) {
|
|
177
|
+
lines.push(` code: ${maskSensitiveData(String(payload.errorCode))}`);
|
|
178
|
+
}
|
|
179
|
+
lines.push('');
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* @param {Object} payload
|
|
184
|
+
* @returns {Promise<Object>}
|
|
185
|
+
*/
|
|
186
|
+
async function resolvePlatformContextForRecord(payload) {
|
|
187
|
+
const completedAt = payload.completedAt || new Date();
|
|
188
|
+
const startedAt = payload.startedAt || completedAt;
|
|
189
|
+
const options = payload.options || {};
|
|
190
|
+
const mode = resolveLogMode(options);
|
|
191
|
+
|
|
192
|
+
let developerId = 'unknown';
|
|
193
|
+
try {
|
|
194
|
+
const id = await config.getDeveloperId();
|
|
195
|
+
developerId = id === null || id === undefined ? 'unknown' : String(id);
|
|
196
|
+
} catch {
|
|
197
|
+
// ignore
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
let platformApps = payload.platformApps;
|
|
201
|
+
if (!platformApps && Array.isArray(payload.platformAppList) && payload.platformAppList.length > 0) {
|
|
202
|
+
platformApps = collectPlatformAppImages(payload.platformAppList, options);
|
|
203
|
+
}
|
|
204
|
+
const platformVersion =
|
|
205
|
+
payload.platformVersion ||
|
|
206
|
+
(platformApps ? derivePlatformVersion(platformApps) : 'unknown');
|
|
207
|
+
|
|
208
|
+
return { completedAt, startedAt, mode, developerId, platformApps, platformVersion };
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* @param {Object} payload
|
|
213
|
+
* @returns {Promise<string[]>}
|
|
214
|
+
*/
|
|
215
|
+
async function buildInstallationRecordLines(payload) {
|
|
216
|
+
const ctx = await resolvePlatformContextForRecord(payload);
|
|
217
|
+
const lines = [];
|
|
218
|
+
pushHeaderAndIdentity(lines, payload, {
|
|
219
|
+
startedAt: ctx.startedAt,
|
|
220
|
+
completedAt: ctx.completedAt,
|
|
221
|
+
developerId: ctx.developerId,
|
|
222
|
+
mode: ctx.mode,
|
|
223
|
+
platformVersion: ctx.platformVersion
|
|
224
|
+
});
|
|
225
|
+
pushInfraBlock(lines, payload);
|
|
226
|
+
pushPlatformAppsBlock(lines, ctx.platformApps);
|
|
227
|
+
pushConfigBlock(lines, payload);
|
|
228
|
+
pushCleanupBlock(lines, payload);
|
|
229
|
+
pushErrorSection(lines, payload);
|
|
230
|
+
lines.push('='.repeat(80));
|
|
231
|
+
lines.push('');
|
|
232
|
+
return lines;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
module.exports = {
|
|
236
|
+
buildInstallationRecordLines
|
|
237
|
+
};
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Append-only operational log for platform install / infra commands.
|
|
3
|
+
* One record per top-level CLI command; no secrets; deterministic section order.
|
|
4
|
+
*
|
|
5
|
+
* @fileoverview installation.log writer beside config.yaml
|
|
6
|
+
* @author AI Fabrix Team
|
|
7
|
+
* @version 2.0.0
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
'use strict';
|
|
11
|
+
|
|
12
|
+
const fs = require('fs').promises;
|
|
13
|
+
const path = require('path');
|
|
14
|
+
const paths = require('./paths');
|
|
15
|
+
const config = require('../core/config');
|
|
16
|
+
const logger = require('./logger');
|
|
17
|
+
const { buildInstallationRecordLines } = require('./installation-log-record');
|
|
18
|
+
const { sanitizeUrl } = require('./installation-log-core');
|
|
19
|
+
|
|
20
|
+
const INSTALLATION_LOG = 'installation.log';
|
|
21
|
+
/** Rotate when log exceeds this size; keep .1 and .2 backups. */
|
|
22
|
+
const MAX_LOG_BYTES = 10 * 1024 * 1024;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @param {string} logPath
|
|
26
|
+
* @param {number} [maxBytes]
|
|
27
|
+
* @returns {Promise<void>}
|
|
28
|
+
*/
|
|
29
|
+
async function rotateInstallationLogIfNeeded(logPath, maxBytes = MAX_LOG_BYTES) {
|
|
30
|
+
let st;
|
|
31
|
+
try {
|
|
32
|
+
st = await fs.stat(logPath);
|
|
33
|
+
} catch (e) {
|
|
34
|
+
if (e && e.code === 'ENOENT') {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
throw e;
|
|
38
|
+
}
|
|
39
|
+
if (st.size < maxBytes) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const dir = path.dirname(logPath);
|
|
43
|
+
const base = path.basename(logPath);
|
|
44
|
+
const p2 = path.join(dir, `${base}.2`);
|
|
45
|
+
const p1 = path.join(dir, `${base}.1`);
|
|
46
|
+
try {
|
|
47
|
+
await fs.unlink(p2);
|
|
48
|
+
} catch {
|
|
49
|
+
// ignore
|
|
50
|
+
}
|
|
51
|
+
try {
|
|
52
|
+
await fs.rename(p1, p2);
|
|
53
|
+
} catch {
|
|
54
|
+
// ignore
|
|
55
|
+
}
|
|
56
|
+
try {
|
|
57
|
+
await fs.rename(logPath, p1);
|
|
58
|
+
} catch {
|
|
59
|
+
// ignore
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* @param {Object} payload
|
|
65
|
+
* @returns {Promise<void>}
|
|
66
|
+
*/
|
|
67
|
+
async function appendInstallationRecord(payload) {
|
|
68
|
+
const lines = await buildInstallationRecordLines(payload);
|
|
69
|
+
const body = lines.join('\n');
|
|
70
|
+
const logDir = paths.getAifabrixSystemDir();
|
|
71
|
+
const logPath = path.join(logDir, INSTALLATION_LOG);
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
await fs.mkdir(logDir, { recursive: true });
|
|
75
|
+
await rotateInstallationLogIfNeeded(logPath);
|
|
76
|
+
await fs.appendFile(logPath, body, 'utf8');
|
|
77
|
+
} catch (err) {
|
|
78
|
+
logger.warn(`installation.log: could not append (${err && err.message ? err.message : err})`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* @returns {Promise<string|undefined>}
|
|
84
|
+
*/
|
|
85
|
+
async function resolveControllerUrlForLog() {
|
|
86
|
+
try {
|
|
87
|
+
const { resolveControllerUrl } = require('./controller-url');
|
|
88
|
+
const u = await resolveControllerUrl();
|
|
89
|
+
return sanitizeUrl(u);
|
|
90
|
+
} catch {
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* @returns {Promise<'set'|'unset'>}
|
|
97
|
+
*/
|
|
98
|
+
async function resolveAdminEmailPresence() {
|
|
99
|
+
try {
|
|
100
|
+
const e = await config.getAdminEmail();
|
|
101
|
+
return e && String(e).trim() ? 'set' : 'unset';
|
|
102
|
+
} catch {
|
|
103
|
+
return 'unset';
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const core = require('./installation-log-core');
|
|
108
|
+
|
|
109
|
+
module.exports = {
|
|
110
|
+
appendInstallationRecord,
|
|
111
|
+
createOperationId: core.createOperationId,
|
|
112
|
+
stripDockerDigest: core.stripDockerDigest,
|
|
113
|
+
collectPlatformAppImages: core.collectPlatformAppImages,
|
|
114
|
+
derivePlatformVersion: core.derivePlatformVersion,
|
|
115
|
+
resolveControllerUrlForLog,
|
|
116
|
+
resolveAdminEmailPresence,
|
|
117
|
+
buildInfraSectionLines: core.buildInfraSectionLines,
|
|
118
|
+
resolveLogMode: core.resolveLogMode,
|
|
119
|
+
getCliVersion: core.getCliVersion,
|
|
120
|
+
rotateInstallationLogIfNeeded,
|
|
121
|
+
INSTALLATION_LOG,
|
|
122
|
+
MAX_LOG_BYTES
|
|
123
|
+
};
|