@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
package/lib/cli/setup-infra.js
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
const {
|
|
1
|
+
const {
|
|
2
|
+
formatProgress,
|
|
3
|
+
formatSuccessLine,
|
|
4
|
+
sectionTitle,
|
|
5
|
+
headerKeyValue
|
|
6
|
+
} = require('../utils/cli-test-layout-chalk');
|
|
2
7
|
/**
|
|
3
8
|
* CLI infrastructure command setup (up-infra, up-platform, up-miso, up-dataplane, down-infra, doctor, status, restart).
|
|
4
9
|
*
|
|
@@ -7,30 +12,36 @@ const { formatSuccessLine } = require('../utils/cli-test-layout-chalk');
|
|
|
7
12
|
* @version 2.0.0
|
|
8
13
|
*/
|
|
9
14
|
|
|
10
|
-
const chalk = require('chalk');
|
|
11
15
|
const infra = require('../infrastructure');
|
|
12
16
|
const appLib = require('../app');
|
|
13
|
-
const validator = require('../validation/validator');
|
|
14
17
|
const config = require('../core/config');
|
|
15
18
|
const logger = require('../utils/logger');
|
|
16
|
-
const { handleCommandError
|
|
17
|
-
const { resolveControllerUrl } = require('../utils/controller-url');
|
|
18
|
-
const { handleLogin } = require('../commands/login');
|
|
19
|
+
const { handleCommandError } = require('../utils/cli-utils');
|
|
19
20
|
const { handleUpMiso } = require('../commands/up-miso');
|
|
20
|
-
const {
|
|
21
|
-
const {
|
|
21
|
+
const { cleanBuilderAppDirs } = require('../commands/up-common');
|
|
22
|
+
const { runGuidedUpInfra, runGuidedUpMiso, runGuidedDownInfra } = require('./infra-guided');
|
|
22
23
|
const {
|
|
23
24
|
loadInfraStatusSummary,
|
|
24
25
|
formatInfraStatusTitleLine,
|
|
25
26
|
logInfraStatusConfigurationSummary,
|
|
26
27
|
logPaddedFieldRow
|
|
27
28
|
} = require('../utils/infra-status-display');
|
|
29
|
+
const { runDoctorCheck } = require('./doctor-check');
|
|
30
|
+
const {
|
|
31
|
+
getRestartableInfraServiceNames,
|
|
32
|
+
buildRestartInfraHelpLines
|
|
33
|
+
} = require('../constants/infra-compose-service-names');
|
|
34
|
+
|
|
35
|
+
const {
|
|
36
|
+
computeEffectiveInfraOptionalFlags,
|
|
37
|
+
persistMissingInfraOptionalServiceFlags
|
|
38
|
+
} = require('../utils/infra-optional-service-flags');
|
|
28
39
|
|
|
29
40
|
const UP_INFRA_HELP_AFTER = `
|
|
30
41
|
Typical sequence:
|
|
31
42
|
$ aifabrix up-infra
|
|
32
43
|
$ aifabrix up-platform
|
|
33
|
-
Or: aifabrix up-miso, then aifabrix up-dataplane (login required for dataplane)
|
|
44
|
+
Or: aifabrix up-infra, aifabrix up-miso, then aifabrix up-dataplane (login required for dataplane)
|
|
34
45
|
|
|
35
46
|
Full bootstrap example (Traefik, TLS flag, pgAdmin, catalog overrides — matches shipped defaults in infra.parameter.yaml):
|
|
36
47
|
$ aifabrix up-infra --traefik --tls --adminPassword admin123 --adminEmail admin@aifabrix.dev --userPassword user123 --pgAdmin
|
|
@@ -59,29 +70,14 @@ async function persistTlsEnabledFlag(cfg, value) {
|
|
|
59
70
|
await config.saveConfig(cfg);
|
|
60
71
|
const tlsStr = value ? 'true' : 'false';
|
|
61
72
|
const httpStr = value ? 'false' : 'true';
|
|
62
|
-
logger.log(
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
)
|
|
71
|
-
);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Resolves effective boolean from option vs config.
|
|
76
|
-
* @param {*} optValue - options.traefik | options.pgAdmin | options.redisAdmin
|
|
77
|
-
* @param {*} cfgValue - cfg.traefik | cfg.pgadmin | cfg.redisCommander
|
|
78
|
-
* @param {boolean} defaultWhenUndef - Default when config value is undefined
|
|
79
|
-
* @returns {boolean}
|
|
80
|
-
*/
|
|
81
|
-
function resolveFlag(optValue, cfgValue, defaultWhenUndef = true) {
|
|
82
|
-
if (optValue === true) return true;
|
|
83
|
-
if (optValue === false) return false;
|
|
84
|
-
return cfgValue !== false && (cfgValue === true || defaultWhenUndef);
|
|
73
|
+
logger.log(formatSuccessLine(
|
|
74
|
+
`TLS mode ${value ? 'enabled' : 'disabled'} and saved to config (` +
|
|
75
|
+
'${TLS_ENABLED}=' +
|
|
76
|
+
tlsStr +
|
|
77
|
+
', ${HTTP_ENABLED}=' +
|
|
78
|
+
httpStr +
|
|
79
|
+
' when generating deployment JSON)'
|
|
80
|
+
));
|
|
85
81
|
}
|
|
86
82
|
|
|
87
83
|
/**
|
|
@@ -140,16 +136,18 @@ async function runUpInfraCommand(options) {
|
|
|
140
136
|
await maybePersistTlsFromUpInfra(options, cfg);
|
|
141
137
|
const adminPass = options.adminPassword || options.adminPwd;
|
|
142
138
|
const tlsEnabledEffective = cfg.tlsEnabled === true;
|
|
139
|
+
const effective = computeEffectiveInfraOptionalFlags(cfg, options);
|
|
143
140
|
await infra.startInfra(developerId, {
|
|
144
|
-
traefik:
|
|
145
|
-
pgadmin:
|
|
146
|
-
redisCommander:
|
|
141
|
+
traefik: effective.traefik,
|
|
142
|
+
pgadmin: effective.pgadmin,
|
|
143
|
+
redisCommander: effective.redisCommander,
|
|
147
144
|
adminPassword: adminPass,
|
|
148
145
|
adminPwd: adminPass,
|
|
149
146
|
adminEmail: options.adminEmail,
|
|
150
147
|
userPassword: options.userPassword,
|
|
151
148
|
tlsEnabled: tlsEnabledEffective
|
|
152
149
|
});
|
|
150
|
+
await persistMissingInfraOptionalServiceFlags(cfg, effective);
|
|
153
151
|
}
|
|
154
152
|
|
|
155
153
|
function setupUpInfraCommand(program) {
|
|
@@ -157,6 +155,7 @@ function setupUpInfraCommand(program) {
|
|
|
157
155
|
.description('Start Postgres, Redis; optional pgAdmin, Redis Commander, Traefik')
|
|
158
156
|
.addHelpText('after', UP_INFRA_HELP_AFTER)
|
|
159
157
|
.option('-d, --developer <id>', 'Set developer ID and start infrastructure')
|
|
158
|
+
.option('--verbose', 'Show full orchestration output (default is guided summary)')
|
|
160
159
|
.option('--adminPassword <password>', 'Override {{adminPassword}} defaults (Postgres, pgAdmin, Redis Commander, catalog literals)')
|
|
161
160
|
.option('--adminEmail <email>', 'Override {{adminEmail}} default (e.g. pgAdmin login email)')
|
|
162
161
|
.option('--userPassword <password>', 'Override {{userPassword}} default (e.g. Keycloak default user password)')
|
|
@@ -169,9 +168,28 @@ function setupUpInfraCommand(program) {
|
|
|
169
168
|
.option('--tls', 'Enable TLS mode; save tlsEnabled (${TLS_ENABLED}=true, ${HTTP_ENABLED}=false in application.yaml)')
|
|
170
169
|
.option('--no-tls', 'Disable TLS mode (${TLS_ENABLED}=false, ${HTTP_ENABLED}=true)')
|
|
171
170
|
.action(async(options) => {
|
|
171
|
+
const startedAt = new Date();
|
|
172
|
+
const { recordInfraInstallationCommand } = require('./installation-log-command');
|
|
172
173
|
try {
|
|
173
|
-
|
|
174
|
+
if (!options.verbose) {
|
|
175
|
+
await runGuidedUpInfra(options, runUpInfraCommand);
|
|
176
|
+
} else {
|
|
177
|
+
await runUpInfraCommand(options);
|
|
178
|
+
}
|
|
179
|
+
await recordInfraInstallationCommand({
|
|
180
|
+
command: 'up-infra',
|
|
181
|
+
options,
|
|
182
|
+
startedAt,
|
|
183
|
+
outcome: 'success'
|
|
184
|
+
});
|
|
174
185
|
} catch (error) {
|
|
186
|
+
await recordInfraInstallationCommand({
|
|
187
|
+
command: 'up-infra',
|
|
188
|
+
options,
|
|
189
|
+
startedAt,
|
|
190
|
+
outcome: 'failure',
|
|
191
|
+
error
|
|
192
|
+
});
|
|
175
193
|
handleCommandError(error, 'up-infra');
|
|
176
194
|
process.exit(1);
|
|
177
195
|
}
|
|
@@ -184,34 +202,15 @@ function setupUpPlatformCommand(program) {
|
|
|
184
202
|
.option('-r, --registry <url>', 'Override registry for all apps (e.g. myacr.azurecr.io)')
|
|
185
203
|
.option('--registry-mode <mode>', 'Override registry mode (acr|external)')
|
|
186
204
|
.option('-i, --image <key>=<value>', 'Override image (e.g. keycloak=myreg/k:v1, miso-controller=myreg/m:v1, dataplane=myreg/d:v1); can be repeated', (v, prev) => (prev || []).concat([v]))
|
|
205
|
+
.option('--base', 'Resolve platform images from manifest only (default: true)', true)
|
|
206
|
+
.option('--verbose', 'Show full orchestration output (default is guided installer)')
|
|
187
207
|
.option(
|
|
188
208
|
'-f, --force',
|
|
189
209
|
'Reset CLI auth (clear all device/client tokens, set environment to dev, set default controller URL from developer-id), clean builder/keycloak, builder/miso-controller, builder/dataplane, then re-fetch from templates'
|
|
190
210
|
)
|
|
191
|
-
.action(
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
await applyUpPlatformForceConfig();
|
|
195
|
-
await cleanBuilderAppDirs(['keycloak', 'miso-controller', 'dataplane']);
|
|
196
|
-
}
|
|
197
|
-
await handleUpMiso(options);
|
|
198
|
-
await handleUpDataplane(options);
|
|
199
|
-
} catch (error) {
|
|
200
|
-
if (isAuthenticationError(error)) {
|
|
201
|
-
const controllerUrl = error.controllerUrl || await resolveControllerUrl();
|
|
202
|
-
logger.log(chalk.blue('\nAuthentication required. Running aifabrix login...\n'));
|
|
203
|
-
try {
|
|
204
|
-
await handleLogin({ method: 'device', controller: controllerUrl });
|
|
205
|
-
await handleUpDataplane(options);
|
|
206
|
-
return;
|
|
207
|
-
} catch (loginOrRetryError) {
|
|
208
|
-
handleCommandError(loginOrRetryError, 'up-platform');
|
|
209
|
-
process.exit(1);
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
handleCommandError(error, 'up-platform');
|
|
213
|
-
process.exit(1);
|
|
214
|
-
}
|
|
211
|
+
.action((options) => {
|
|
212
|
+
const { handleUpPlatformCliAction } = require('./setup-infra-up-platform-action');
|
|
213
|
+
return handleUpPlatformCliAction(options);
|
|
215
214
|
});
|
|
216
215
|
}
|
|
217
216
|
|
|
@@ -221,14 +220,41 @@ function setupUpMisoCommand(program) {
|
|
|
221
220
|
.option('-r, --registry <url>', 'Override registry for all apps (e.g. myacr.azurecr.io)')
|
|
222
221
|
.option('--registry-mode <mode>', 'Override registry mode (acr|external)')
|
|
223
222
|
.option('-i, --image <key>=<value>', 'Override image (e.g. keycloak=myreg/k:v1, miso-controller=myreg/m:v1); can be repeated', (v, prev) => (prev || []).concat([v]))
|
|
223
|
+
.option('--base', 'Resolve platform images from manifest only (default: true)', true)
|
|
224
224
|
.option('-f, --force', 'Clean builder/keycloak and builder/miso-controller and re-fetch from templates')
|
|
225
|
+
.option('--verbose', 'Show full orchestration output (default is guided summary)')
|
|
225
226
|
.action(async(options) => {
|
|
227
|
+
const startedAt = new Date();
|
|
228
|
+
const { recordInfraInstallationCommand } = require('./installation-log-command');
|
|
229
|
+
let cleanedAppKeys = [];
|
|
226
230
|
try {
|
|
227
231
|
if (options.force) {
|
|
228
|
-
await cleanBuilderAppDirs(['keycloak', 'miso-controller']);
|
|
232
|
+
const c = await cleanBuilderAppDirs(['keycloak', 'miso-controller']);
|
|
233
|
+
cleanedAppKeys = Array.isArray(c) ? c : [];
|
|
234
|
+
}
|
|
235
|
+
if (!options.verbose) {
|
|
236
|
+
await runGuidedUpMiso(options, handleUpMiso);
|
|
237
|
+
} else {
|
|
238
|
+
await handleUpMiso(options);
|
|
229
239
|
}
|
|
230
|
-
await
|
|
240
|
+
await recordInfraInstallationCommand({
|
|
241
|
+
command: 'up-miso',
|
|
242
|
+
options,
|
|
243
|
+
startedAt,
|
|
244
|
+
outcome: 'success',
|
|
245
|
+
platformAppList: ['keycloak', 'miso-controller'],
|
|
246
|
+
cleanup: cleanedAppKeys.length > 0 ? { cleanedAppKeys } : undefined
|
|
247
|
+
});
|
|
231
248
|
} catch (error) {
|
|
249
|
+
await recordInfraInstallationCommand({
|
|
250
|
+
command: 'up-miso',
|
|
251
|
+
options,
|
|
252
|
+
startedAt,
|
|
253
|
+
outcome: 'failure',
|
|
254
|
+
error,
|
|
255
|
+
platformAppList: ['keycloak', 'miso-controller'],
|
|
256
|
+
cleanup: cleanedAppKeys.length > 0 ? { cleanedAppKeys } : undefined
|
|
257
|
+
});
|
|
232
258
|
handleCommandError(error, 'up-miso');
|
|
233
259
|
process.exit(1);
|
|
234
260
|
}
|
|
@@ -237,33 +263,16 @@ function setupUpMisoCommand(program) {
|
|
|
237
263
|
|
|
238
264
|
function setupUpDataplaneCommand(program) {
|
|
239
265
|
program.command('up-dataplane')
|
|
240
|
-
.description('Register, deploy, run dataplane locally (dev env; login required)')
|
|
266
|
+
.description('Register, deploy, run dataplane locally (dev env; needs up-infra; login required)')
|
|
241
267
|
.option('-r, --registry <url>', 'Override registry for dataplane image')
|
|
242
268
|
.option('--registry-mode <mode>', 'Override registry mode (acr|external)')
|
|
243
269
|
.option('-i, --image <ref>', 'Override dataplane image reference (e.g. myreg/dataplane:latest)')
|
|
270
|
+
.option('--base', 'Resolve dataplane image from manifest only when running locally (default: true)', true)
|
|
244
271
|
.option('-f, --force', 'Clean builder/dataplane and re-fetch from templates')
|
|
245
|
-
.
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
}
|
|
250
|
-
await handleUpDataplane(options);
|
|
251
|
-
} catch (error) {
|
|
252
|
-
if (isAuthenticationError(error)) {
|
|
253
|
-
const controllerUrl = error.controllerUrl || await resolveControllerUrl();
|
|
254
|
-
logger.log(chalk.blue('\nAuthentication required. Running aifabrix login...\n'));
|
|
255
|
-
try {
|
|
256
|
-
await handleLogin({ method: 'device', controller: controllerUrl });
|
|
257
|
-
await handleUpDataplane(options);
|
|
258
|
-
return;
|
|
259
|
-
} catch (loginOrRetryError) {
|
|
260
|
-
handleCommandError(loginOrRetryError, 'up-dataplane');
|
|
261
|
-
process.exit(1);
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
handleCommandError(error, 'up-dataplane');
|
|
265
|
-
process.exit(1);
|
|
266
|
-
}
|
|
272
|
+
.option('--verbose', 'Show full orchestration output (default is guided summary)')
|
|
273
|
+
.action((options) => {
|
|
274
|
+
const { handleUpDataplaneCliAction } = require('./setup-infra-up-dataplane-action');
|
|
275
|
+
return handleUpDataplaneCliAction(options);
|
|
267
276
|
});
|
|
268
277
|
}
|
|
269
278
|
|
|
@@ -271,8 +280,14 @@ function setupDownInfraCommand(program) {
|
|
|
271
280
|
program.command('down-infra [service|app]')
|
|
272
281
|
.description('Stop all infra, or stop one app; use -v to remove volumes')
|
|
273
282
|
.option('-v, --volumes', 'Remove volumes (deletes all data)')
|
|
283
|
+
.option('--verbose', 'Show full orchestration output (default is guided summary)')
|
|
274
284
|
.action(async(appName, options) => {
|
|
275
285
|
try {
|
|
286
|
+
if (!options.verbose) {
|
|
287
|
+
await runGuidedDownInfra(appName, options, infra, appLib);
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
|
|
276
291
|
if (typeof appName === 'string' && appName.trim().length > 0) {
|
|
277
292
|
await appLib.downApp(appName, { volumes: !!options.volumes });
|
|
278
293
|
} else {
|
|
@@ -291,33 +306,7 @@ function setupDoctorCommand(program) {
|
|
|
291
306
|
.description('Check Docker, ports, secrets, and infra health')
|
|
292
307
|
.action(async() => {
|
|
293
308
|
try {
|
|
294
|
-
|
|
295
|
-
logger.log('\n🔍 AI Fabrix Environment Check\n');
|
|
296
|
-
logger.log(`Docker: ${result.docker === 'ok' ? '✔ Running' : '✖ Not available'}`);
|
|
297
|
-
logger.log(`Ports: ${result.ports === 'ok' ? '✔ Available' : '⚠ Some ports in use'}`);
|
|
298
|
-
logger.log(`Secrets: ${result.secrets === 'ok' ? '✔ Configured' : '✖ Missing'}`);
|
|
299
|
-
if (result.recommendations.length > 0) {
|
|
300
|
-
logger.log('\n📋 Recommendations:');
|
|
301
|
-
result.recommendations.forEach(rec => logger.log(` • ${rec}`));
|
|
302
|
-
}
|
|
303
|
-
if (result.docker === 'ok') {
|
|
304
|
-
try {
|
|
305
|
-
const cfg = await config.getConfig();
|
|
306
|
-
const health = await infra.checkInfraHealth(null, {
|
|
307
|
-
pgadmin: cfg.pgadmin !== false,
|
|
308
|
-
redisCommander: cfg.redisCommander !== false,
|
|
309
|
-
traefik: !!cfg.traefik
|
|
310
|
-
});
|
|
311
|
-
logger.log('\n🏥 Infrastructure Health:');
|
|
312
|
-
Object.entries(health).forEach(([service, status]) => {
|
|
313
|
-
const icon = status === 'healthy' ? '✔' : status === 'unknown' ? '❓' : '✖';
|
|
314
|
-
logger.log(` ${icon} ${service}: ${status}`);
|
|
315
|
-
});
|
|
316
|
-
} catch (error) {
|
|
317
|
-
logger.log('\n🏥 Infrastructure: Not running');
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
logger.log('');
|
|
309
|
+
await runDoctorCheck();
|
|
321
310
|
} catch (error) {
|
|
322
311
|
handleCommandError(error, 'doctor');
|
|
323
312
|
process.exit(1);
|
|
@@ -365,19 +354,44 @@ function setupStatusCommand(program) {
|
|
|
365
354
|
});
|
|
366
355
|
}
|
|
367
356
|
|
|
368
|
-
const
|
|
357
|
+
const RESTART_INFRA_SERVICE_NAMES = getRestartableInfraServiceNames();
|
|
358
|
+
|
|
359
|
+
const RESTART_COMMAND_HELP_AFTER = `
|
|
360
|
+
Infra — use these exact Docker Compose service names:
|
|
361
|
+
${buildRestartInfraHelpLines()}
|
|
362
|
+
|
|
363
|
+
Optional services (pgadmin, redis-commander, traefik) only exist if you enabled them when running up-infra.
|
|
364
|
+
|
|
365
|
+
Builder apps (examples):
|
|
366
|
+
keycloak, miso-controller, dataplane
|
|
367
|
+
|
|
368
|
+
Examples:
|
|
369
|
+
$ aifabrix restart postgres
|
|
370
|
+
$ aifabrix restart traefik
|
|
371
|
+
$ aifabrix restart miso-controller
|
|
372
|
+
`;
|
|
369
373
|
|
|
370
374
|
function setupRestartCommand(program) {
|
|
371
375
|
program.command('restart <service|app>')
|
|
372
|
-
.description(
|
|
376
|
+
.description(
|
|
377
|
+
'Restart one infra compose service (postgres, redis, pgadmin, redis-commander, traefik) or a builder app container'
|
|
378
|
+
)
|
|
379
|
+
.addHelpText('after', RESTART_COMMAND_HELP_AFTER)
|
|
373
380
|
.action(async(service) => {
|
|
374
381
|
try {
|
|
375
|
-
if (
|
|
376
|
-
|
|
377
|
-
logger.log(
|
|
382
|
+
if (RESTART_INFRA_SERVICE_NAMES.includes(service)) {
|
|
383
|
+
logger.log('');
|
|
384
|
+
logger.log(sectionTitle('Restart'));
|
|
385
|
+
logger.log(headerKeyValue('Infra service:', service));
|
|
386
|
+
logger.log(formatProgress(`Restarting ${service}…`));
|
|
387
|
+
await infra.restartService(service, { suppressProgressLog: true });
|
|
388
|
+
logger.log(formatSuccessLine(`${service} restarted successfully`));
|
|
378
389
|
} else {
|
|
390
|
+
logger.log('');
|
|
391
|
+
logger.log(sectionTitle('Restart'));
|
|
392
|
+
logger.log(headerKeyValue('Application:', service));
|
|
379
393
|
await appLib.restartApp(service);
|
|
380
|
-
logger.log(
|
|
394
|
+
logger.log(formatSuccessLine(`${service} restarted successfully`));
|
|
381
395
|
}
|
|
382
396
|
} catch (error) {
|
|
383
397
|
handleCommandError(error, 'restart');
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI integration-client command setup (Controller OAuth / API clients).
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Integration client CLI definitions
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 2.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const { handleCommandError } = require('../utils/cli-utils');
|
|
10
|
+
const {
|
|
11
|
+
runIntegrationClientCreate,
|
|
12
|
+
runIntegrationClientList,
|
|
13
|
+
runIntegrationClientRotateSecret,
|
|
14
|
+
runIntegrationClientDelete,
|
|
15
|
+
runIntegrationClientUpdateGroups,
|
|
16
|
+
runIntegrationClientUpdateRedirectUris
|
|
17
|
+
} = require('../commands/integration-client');
|
|
18
|
+
|
|
19
|
+
const HELP_AFTER = `
|
|
20
|
+
Integration clients are machine identities for integrations, CI, Postman OAuth2, or API access.
|
|
21
|
+
Use: list (integration-client:read), create (integration-client:create), rotate-secret,
|
|
22
|
+
update-groups, update-redirect-uris (integration-client:update), delete (integration-client:delete).
|
|
23
|
+
The controller returns a one-time clientSecret on create and rotate-secret—save it immediately;
|
|
24
|
+
it cannot be retrieved again.
|
|
25
|
+
|
|
26
|
+
Examples:
|
|
27
|
+
$ aifabrix integration-client create --key postman --display-name "Postman client" \\
|
|
28
|
+
--redirect-uris https://oauth.pstmn.io/v1/callback --group-names AI-Fabrix-Platform-Admins
|
|
29
|
+
$ aifabrix integration-client list
|
|
30
|
+
$ aifabrix integration-client rotate-secret --id <uuid>
|
|
31
|
+
$ aifabrix integration-client delete --id <uuid>
|
|
32
|
+
$ aifabrix integration-client update-groups --id <uuid> --group-names Group1,Group2
|
|
33
|
+
$ aifabrix integration-client update-redirect-uris --id <uuid> --redirect-uris https://app.example.com/callback
|
|
34
|
+
|
|
35
|
+
Run "aifabrix login" first.`;
|
|
36
|
+
|
|
37
|
+
function parseOptionalInt(val) {
|
|
38
|
+
return (val !== undefined && val !== null) ? parseInt(val, 10) : undefined;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function addCreateCommand(integrationClient) {
|
|
42
|
+
integrationClient.command('create')
|
|
43
|
+
.description('Create an integration client and receive a one-time clientSecret (save it now; it will not be shown again)')
|
|
44
|
+
.option('--controller <url>', 'Controller base URL (default: from config)')
|
|
45
|
+
.option('-k, --key <key>', 'Stable key (lowercase alphanumeric and hyphens; required)')
|
|
46
|
+
.option('-n, --display-name <name>', 'Display name (required)')
|
|
47
|
+
.option('--keycloak-client-id <id>', 'Optional fixed Keycloak client id (when omitted, the server assigns one)')
|
|
48
|
+
.option('--redirect-uris <uris>', 'Comma-separated OAuth2 redirect URIs (required)')
|
|
49
|
+
.option('--group-names <names>', 'Comma-separated group names (optional; omit for OAuth-only clients)')
|
|
50
|
+
.option('-d, --description <description>', 'Optional description')
|
|
51
|
+
.action(async(options) => {
|
|
52
|
+
try {
|
|
53
|
+
await runIntegrationClientCreate({
|
|
54
|
+
controller: options.controller,
|
|
55
|
+
key: options.key,
|
|
56
|
+
displayName: options.displayName,
|
|
57
|
+
keycloakClientId: options.keycloakClientId,
|
|
58
|
+
redirectUris: options.redirectUris,
|
|
59
|
+
groupNames: options.groupNames,
|
|
60
|
+
description: options.description
|
|
61
|
+
});
|
|
62
|
+
} catch (error) {
|
|
63
|
+
handleCommandError(error, 'integration-client create');
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function addListCommand(integrationClient) {
|
|
70
|
+
integrationClient.command('list')
|
|
71
|
+
.description('List integration clients (supports pagination and search)')
|
|
72
|
+
.option('--controller <url>', 'Controller base URL (default: from config)')
|
|
73
|
+
.option('--page <n>', 'Page number')
|
|
74
|
+
.option('--page-size <n>', 'Items per page')
|
|
75
|
+
.option('--search <term>', 'Search term')
|
|
76
|
+
.option('--sort <field>', 'Sort field/direction')
|
|
77
|
+
.option('--filter <expr>', 'Filter expression')
|
|
78
|
+
.action(async(options) => {
|
|
79
|
+
try {
|
|
80
|
+
await runIntegrationClientList({
|
|
81
|
+
controller: options.controller,
|
|
82
|
+
page: parseOptionalInt(options.page),
|
|
83
|
+
pageSize: parseOptionalInt(options.pageSize),
|
|
84
|
+
search: options.search,
|
|
85
|
+
sort: options.sort,
|
|
86
|
+
filter: options.filter
|
|
87
|
+
});
|
|
88
|
+
} catch (error) {
|
|
89
|
+
handleCommandError(error, 'integration-client list');
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function addRotateSecretCommand(integrationClient) {
|
|
96
|
+
integrationClient.command('rotate-secret')
|
|
97
|
+
.description('Rotate (regenerate) secret for an integration client; new secret shown once only')
|
|
98
|
+
.option('--controller <url>', 'Controller base URL (default: from config)')
|
|
99
|
+
.option('--id <uuid>', 'Integration client ID (required)')
|
|
100
|
+
.action(async(options) => {
|
|
101
|
+
try {
|
|
102
|
+
await runIntegrationClientRotateSecret({ controller: options.controller, id: options.id });
|
|
103
|
+
} catch (error) {
|
|
104
|
+
handleCommandError(error, 'integration-client rotate-secret');
|
|
105
|
+
process.exit(1);
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function addDeleteCommand(integrationClient) {
|
|
111
|
+
integrationClient.command('delete')
|
|
112
|
+
.description('Delete (deactivate) an integration client')
|
|
113
|
+
.option('--controller <url>', 'Controller base URL (default: from config)')
|
|
114
|
+
.option('--id <uuid>', 'Integration client ID (required)')
|
|
115
|
+
.action(async(options) => {
|
|
116
|
+
try {
|
|
117
|
+
await runIntegrationClientDelete({ controller: options.controller, id: options.id });
|
|
118
|
+
} catch (error) {
|
|
119
|
+
handleCommandError(error, 'integration-client delete');
|
|
120
|
+
process.exit(1);
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function addUpdateGroupsCommand(integrationClient) {
|
|
126
|
+
integrationClient.command('update-groups')
|
|
127
|
+
.description('Update group assignments for an integration client')
|
|
128
|
+
.option('--controller <url>', 'Controller base URL (default: from config)')
|
|
129
|
+
.option('--id <uuid>', 'Integration client ID (required)')
|
|
130
|
+
.option('--group-names <names>', 'Comma-separated group names (required)')
|
|
131
|
+
.action(async(options) => {
|
|
132
|
+
try {
|
|
133
|
+
await runIntegrationClientUpdateGroups({
|
|
134
|
+
controller: options.controller,
|
|
135
|
+
id: options.id,
|
|
136
|
+
groupNames: options.groupNames
|
|
137
|
+
});
|
|
138
|
+
} catch (error) {
|
|
139
|
+
handleCommandError(error, 'integration-client update-groups');
|
|
140
|
+
process.exit(1);
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function addUpdateRedirectUrisCommand(integrationClient) {
|
|
146
|
+
integrationClient.command('update-redirect-uris')
|
|
147
|
+
.description('Update redirect URIs for an integration client (min 1)')
|
|
148
|
+
.option('--controller <url>', 'Controller base URL (default: from config)')
|
|
149
|
+
.option('--id <uuid>', 'Integration client ID (required)')
|
|
150
|
+
.option('--redirect-uris <uris>', 'Comma-separated redirect URIs (required, min 1)')
|
|
151
|
+
.action(async(options) => {
|
|
152
|
+
try {
|
|
153
|
+
await runIntegrationClientUpdateRedirectUris({
|
|
154
|
+
controller: options.controller,
|
|
155
|
+
id: options.id,
|
|
156
|
+
redirectUris: options.redirectUris
|
|
157
|
+
});
|
|
158
|
+
} catch (error) {
|
|
159
|
+
handleCommandError(error, 'integration-client update-redirect-uris');
|
|
160
|
+
process.exit(1);
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Registers integration-client commands
|
|
167
|
+
* @param {Command} program - Commander program instance
|
|
168
|
+
*/
|
|
169
|
+
function setupIntegrationClientCommands(program) {
|
|
170
|
+
const integrationClient = program
|
|
171
|
+
.command('integration-client')
|
|
172
|
+
.description('OAuth integration clients on Controller (integrations, CI, API access)')
|
|
173
|
+
.addHelpText('after', HELP_AFTER);
|
|
174
|
+
addCreateCommand(integrationClient);
|
|
175
|
+
addListCommand(integrationClient);
|
|
176
|
+
addRotateSecretCommand(integrationClient);
|
|
177
|
+
addDeleteCommand(integrationClient);
|
|
178
|
+
addUpdateGroupsCommand(integrationClient);
|
|
179
|
+
addUpdateRedirectUrisCommand(integrationClient);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
module.exports = { setupIntegrationClientCommands };
|
|
@@ -17,11 +17,30 @@ function setupParametersCommands(program) {
|
|
|
17
17
|
|
|
18
18
|
parameters
|
|
19
19
|
.command('validate')
|
|
20
|
-
.description(
|
|
20
|
+
.description(
|
|
21
|
+
'Validate builder/*/env.template kv:// references against infra.parameter.yaml'
|
|
22
|
+
)
|
|
21
23
|
.option('--catalog <path>', 'Override path to infra.parameter.yaml')
|
|
24
|
+
.option('--verbose', 'Print scanned files and scan summary')
|
|
25
|
+
.addHelpText(
|
|
26
|
+
'after',
|
|
27
|
+
`
|
|
28
|
+
Examples:
|
|
29
|
+
aifabrix parameters validate
|
|
30
|
+
aifabrix parameters validate --verbose
|
|
31
|
+
aifabrix parameters validate --catalog ./lib/schema/infra.parameter.yaml
|
|
32
|
+
|
|
33
|
+
Notes:
|
|
34
|
+
- Scans builder/* apps only (integration/* is intentionally skipped).
|
|
35
|
+
- Extracts kv://KEY references from env.template and checks KEY coverage in the catalog.
|
|
36
|
+
`
|
|
37
|
+
)
|
|
22
38
|
.action(async(opts) => {
|
|
23
39
|
try {
|
|
24
|
-
const result = await handleParametersValidate({
|
|
40
|
+
const result = await handleParametersValidate({
|
|
41
|
+
catalogPath: opts.catalog,
|
|
42
|
+
verbose: Boolean(opts.verbose)
|
|
43
|
+
});
|
|
25
44
|
if (!result.valid) process.exit(1);
|
|
26
45
|
} catch (error) {
|
|
27
46
|
handleCommandError(error, 'parameters validate');
|