@aifabrix/builder 2.60.0 → 2.62.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/README.md +14 -11
- package/docs/README.md +80 -0
- package/docs/builder-help/evidence-patterns.json +155 -0
- package/docs/builder-help/golden-examples/crm-company.json +30 -0
- package/docs/builder-help/golden-examples/crm-deal.json +29 -0
- package/docs/builder-help/golden-examples/document-storage-keyed-get.json +85 -0
- package/docs/builder-help/golden-examples/document-storage.json +30 -0
- package/docs/builder-help/golden-examples/meeting-transcript.json +29 -0
- package/docs/builder-help/golden-examples/repository-template.json +29 -0
- package/docs/builder-help/golden-examples/service-ticket.json +29 -0
- package/docs/builder-help/platform-roles.json +98 -0
- package/docs/builder-help/resource-type-catalog.json +402 -0
- package/lib/api/applications.api.js +22 -2
- package/lib/api/bootstrap-snapshot.api.js +115 -0
- package/lib/api/configuration.api.js +131 -0
- package/lib/api/system-secrets.api.js +72 -0
- package/lib/app/deploy.js +14 -5
- package/lib/app/run-docker-fallback.js +6 -1
- package/lib/app/run-env-compose.js +5 -6
- package/lib/app/run-helpers.js +2 -1
- package/lib/app/run-parameter-sync.js +142 -0
- package/lib/app/run.js +6 -4
- package/lib/build/docker-build-args.js +5 -2
- package/lib/build/index.js +3 -2
- package/lib/build/standard-docker-build.js +6 -2
- package/lib/channels/channel-artifact-generator.js +13 -3
- package/lib/cli/infra-guided-footers.js +10 -8
- package/lib/cli/infra-guided.js +30 -10
- package/lib/cli/setup-app.js +5 -0
- package/lib/cli/setup-environment.js +156 -0
- package/lib/cli/setup-infra-up-platform-action.js +14 -1
- package/lib/cli/setup-platform.js +2 -0
- package/lib/commands/auth-config.js +2 -0
- package/lib/commands/datasource-capability-upsert-cli.js +112 -0
- package/lib/commands/datasource-capability.js +4 -2
- package/lib/commands/env-secret-context.js +113 -0
- package/lib/commands/env-secret-list.js +200 -0
- package/lib/commands/env-secret-push-confirm.js +54 -0
- package/lib/commands/env-secret-push-run.js +227 -0
- package/lib/commands/env-secret-push.js +168 -0
- package/lib/commands/login.js +4 -0
- package/lib/commands/repair-datasource-apply.js +5 -1
- package/lib/commands/repair-datasource-keyed-document.js +122 -0
- package/lib/commands/repair-datasource-legacy.js +94 -0
- package/lib/commands/repair-datasource-run.js +1 -0
- package/lib/commands/setup-image-refresh.js +26 -0
- package/lib/commands/setup-modes.js +8 -9
- package/lib/commands/setup-prompts-platform-mode.js +34 -0
- package/lib/commands/setup-prompts.js +2 -180
- package/lib/commands/setup.js +3 -0
- package/lib/commands/up-builder-api.js +24 -8
- package/lib/commands/up-common.js +16 -1
- package/lib/commands/up-dataplane-bootstrap.js +70 -14
- package/lib/commands/up-dataplane-credentials.js +21 -0
- package/lib/commands/up-dataplane.js +37 -18
- package/lib/commands/up-integration-server.js +112 -0
- package/lib/commands/verify-operations-skip-e2e.js +25 -1
- package/lib/commands/verify-operations-steps.js +13 -1
- package/lib/commands/wizard-config-normalizer.js +12 -5
- package/lib/commands/wizard-core.js +5 -157
- package/lib/commands/wizard-file-saving.js +163 -0
- package/lib/core/admin-secrets-env-overlay.js +8 -3
- package/lib/core/env-platform-expand.js +5 -1
- package/lib/core/environment-access-policy.js +121 -0
- package/lib/core/environment-mode-policy.js +177 -0
- package/lib/core/local-env-overrides.js +149 -0
- package/lib/core/secrets-ensure.js +4 -2
- package/lib/core/secrets-env-content.js +17 -10
- package/lib/core/secrets-env-write.js +11 -4
- package/lib/core/secrets-load.js +4 -2
- package/lib/datasource/binary-documents-validator.js +190 -0
- package/lib/datasource/capability/capability-manifest.js +1 -0
- package/lib/datasource/capability/run-capability-upsert.js +202 -0
- package/lib/datasource/capability/upsert-ingredients.js +291 -0
- package/lib/datasource/capability/upsert-operations.js +138 -0
- package/lib/datasource/capability/upsert-test-scaffold.js +189 -0
- package/lib/datasource/validate.js +12 -5
- package/lib/deployment/installation/index.js +14 -1
- package/lib/deployment/installation/infra-catalog.js +3 -0
- package/lib/deployment/installation/local-environment-stage.js +285 -0
- package/lib/deployment/installation/local-installation.js +76 -0
- package/lib/deployment/installation/stage-input.js +5 -1
- package/lib/generator/builders.js +3 -1
- package/lib/generator/index.js +3 -0
- package/lib/generator/split-variables.js +2 -2
- package/lib/lifecycle/product-model.js +4 -3
- package/lib/lifecycle/report-display.js +3 -2
- package/lib/parameters/database-adoption.js +125 -0
- package/lib/parameters/infra-parameter-catalog.js +1 -1
- package/lib/parameters/physical-database-naming.js +136 -0
- package/lib/parameters/physical-secret-name.js +194 -0
- package/lib/parameters/rsa-secret-values.js +165 -0
- package/lib/programmatic/builder-help-enterprise-sync-fabrix.js +1 -1
- package/lib/programmatic/builder-help-governance.js +1 -1
- package/lib/programmatic/builder-help.js +1 -1
- package/lib/programmatic/run-channel-install-artifacts.js +28 -2
- package/lib/programmatic/run-channel-package.js +3 -1
- package/lib/programmatic/workspace-context.js +37 -2
- package/lib/role-assistant/test-runner-workhub-answers.js +4 -1
- package/lib/role-assistant/test-runner-workhub-missing-fields.js +42 -0
- package/lib/role-assistant/test-runner-workhub-wait-stop.js +94 -0
- package/lib/role-assistant/test-runner-workhub.js +28 -19
- package/lib/schema/application-schema.json +14 -2
- package/lib/schema/external-datasource.schema.json +23 -3
- package/lib/schema/infra.parameter.yaml +440 -56
- package/lib/schema/infrastructure-schema.json +213 -120
- package/lib/utils/compose-generate-docker-compose.js +9 -14
- package/lib/utils/compose-generator.js +4 -7
- package/lib/utils/compose-miso-env.js +2 -2
- package/lib/utils/compose-traefik-ingress-base.js +3 -4
- package/lib/utils/datasource-binary-evidence.js +92 -0
- package/lib/utils/datasource-test-run-capability-scope.js +44 -1
- package/lib/utils/datasource-test-run-debug-display.js +2 -0
- package/lib/utils/datasource-test-run-display.js +8 -2
- package/lib/utils/datasource-test-run-issue-guidance.js +176 -0
- package/lib/utils/datasource-test-run-tty-log.js +2 -0
- package/lib/utils/declarative-url-ports.js +3 -0
- package/lib/utils/env-copy.js +11 -10
- package/lib/utils/env-environment-file-paths.js +105 -0
- package/lib/utils/environment-scoped-resources.js +48 -14
- package/lib/utils/external-system-system-test-tty.js +3 -2
- package/lib/utils/image-tags.js +2 -2
- package/lib/utils/paths-system-builder-keys.js +7 -1
- package/lib/utils/paths.js +7 -2
- package/lib/utils/platform-kv-ref.js +1 -1
- package/lib/utils/postgres-platform-bootstrap.js +35 -1
- package/lib/utils/prepare-local-data-mount.js +58 -0
- package/lib/utils/redis-env-scope.js +21 -1
- package/lib/utils/registry-auth-sources.js +154 -0
- package/lib/utils/registry-credentials.js +131 -14
- package/lib/utils/secrets-generator.js +30 -21
- package/lib/utils/secrets-helpers.js +5 -8
- package/lib/utils/secrets-kv-scope.js +127 -28
- package/lib/utils/secrets-materialize-local.js +9 -0
- package/lib/utils/secrets-missing-error.js +35 -1
- package/lib/utils/system-secret-mapping.js +125 -0
- package/lib/utils/test-log-writer.js +2 -1
- package/lib/utils/token-manager.js +14 -8
- package/lib/utils/url-public-path-prefix.js +6 -10
- package/lib/validation/external-manifest-validator.js +5 -0
- package/lib/validation/openapi-contract-surface-validator.js +3 -1
- package/lib/validation/validate-external-file.js +5 -1
- package/package.json +6 -4
- package/templates/agent-kit/agent-kit.yaml +1 -1
- package/templates/agent-kit/skills/aifabrix-connected-system/SKILL.md +2 -1
- package/templates/agent-kit/skills/aifabrix-connected-system/references/delivery-gates.md +15 -0
- package/templates/agent-kit/skills/aifabrix-plan/SKILL.md +3 -2
- package/templates/agent-kit/skills/aifabrix-prove/SKILL.md +6 -2
- package/templates/agent-kit/skills/aifabrix-prove/references/evidence-lifecycle.md +22 -0
- package/templates/agent-kit/skills/aifabrix-role-assistant/SKILL.md +7 -1
- package/templates/agent-kit/skills/aifabrix-role-assistant/references/testing-playbook.md +117 -0
- package/templates/agent-kit/skills/shared/interaction.md +83 -0
- package/templates/agent-kit/skills/shared/status.md +3 -12
- package/templates/applications/builder-api/application.yaml +1 -1
- package/templates/applications/builder-api/env.template +5 -1
- package/templates/applications/dataplane/application.yaml +2 -2
- package/templates/applications/dataplane/env.template +10 -12
- package/templates/applications/integration-server/application.yaml +91 -0
- package/templates/applications/integration-server/env.template +215 -0
- package/templates/applications/keycloak/application.yaml +6 -1
- package/templates/applications/mirrored-templates.json +52 -0
- package/templates/applications/miso-controller/application.yaml +116 -2
- package/templates/applications/miso-controller/env.template +62 -17
- package/templates/applications/miso-controller/rbac.yaml +17 -0
- package/templates/external-system/external-datasource.yaml.hbs +7 -1
- package/templates/marketplace/createUiDefinition.json +52 -4
- package/templates/marketplace/main.json +88 -10
- package/templates/python/docker-compose.hbs +1 -1
- package/templates/agent-kit/skills/aifabrix-plan/references/interaction.md +0 -41
- /package/{lib/programmatic/help-content → docs/builder-help/content}/channel-onboarding.md +0 -0
- /package/{lib/programmatic/help-content → docs/builder-help/content}/cip-overview.md +0 -0
- /package/{lib/programmatic/help-content → docs/builder-help/content}/connected-system-ui.md +0 -0
- /package/{lib/programmatic/help-content → docs/builder-help/content}/dimensions-guide.md +0 -0
- /package/{lib/programmatic/help-content → docs/builder-help/content}/enterprise-sync-fabrix.md +0 -0
- /package/{lib/programmatic/help-content → docs/builder-help/content}/overview.md +0 -0
- /package/{lib/programmatic/help-content → docs/builder-help/content}/subscription-guide.md +0 -0
- /package/{lib/programmatic/help-content → docs/builder-help/content}/workflow.md +0 -0
|
@@ -331,12 +331,16 @@ const DATAPLANE_BUILDER_APP_KEYS = Object.freeze(['dataplane']);
|
|
|
331
331
|
/** Builder API platform app key (154.2). */
|
|
332
332
|
const BUILDER_API_APP_KEYS = Object.freeze(['builder-api']);
|
|
333
333
|
|
|
334
|
+
/** Optional integration server platform app key. */
|
|
335
|
+
const INTEGRATION_SERVER_APP_KEYS = Object.freeze(['integration-server']);
|
|
336
|
+
|
|
334
337
|
/** Builder dirs removed on up-platform / setup force (includes Celery companions). */
|
|
335
338
|
const PLATFORM_BUILDER_CLEAN_APP_KEYS = Object.freeze([
|
|
336
339
|
'keycloak',
|
|
337
340
|
'miso-controller',
|
|
338
341
|
...DATAPLANE_BUILDER_APP_KEYS,
|
|
339
|
-
...BUILDER_API_APP_KEYS
|
|
342
|
+
...BUILDER_API_APP_KEYS,
|
|
343
|
+
...INTEGRATION_SERVER_APP_KEYS
|
|
340
344
|
]);
|
|
341
345
|
|
|
342
346
|
/**
|
|
@@ -375,6 +379,15 @@ async function ensureBuilderApiAppsFromTemplate(opts = {}) {
|
|
|
375
379
|
return anyCopied;
|
|
376
380
|
}
|
|
377
381
|
|
|
382
|
+
/**
|
|
383
|
+
* Ensure the optional integration server manifest exists under the system builder root.
|
|
384
|
+
* @param {object} [opts]
|
|
385
|
+
* @returns {Promise<boolean>}
|
|
386
|
+
*/
|
|
387
|
+
async function ensureIntegrationServerAppsFromTemplate(opts = {}) {
|
|
388
|
+
return ensureAppFromTemplate(INTEGRATION_SERVER_APP_KEYS[0], opts);
|
|
389
|
+
}
|
|
390
|
+
|
|
378
391
|
/**
|
|
379
392
|
* Merge builder/packages `application.yaml` into `~/.aifabrix/urls.local.yaml`.
|
|
380
393
|
* Same scan as the end of {@link prepareUrlsLocalRegistryForUpPlatform}; call after platform app
|
|
@@ -410,10 +423,12 @@ module.exports = {
|
|
|
410
423
|
applyUpPlatformForceConfig,
|
|
411
424
|
cleanBuilderAppDirs,
|
|
412
425
|
BUILDER_API_APP_KEYS,
|
|
426
|
+
INTEGRATION_SERVER_APP_KEYS,
|
|
413
427
|
DATAPLANE_BUILDER_APP_KEYS,
|
|
414
428
|
PLATFORM_BUILDER_CLEAN_APP_KEYS,
|
|
415
429
|
ensureAppFromTemplate,
|
|
416
430
|
ensureBuilderApiAppsFromTemplate,
|
|
431
|
+
ensureIntegrationServerAppsFromTemplate,
|
|
417
432
|
ensureDataplaneAppsFromTemplate,
|
|
418
433
|
patchEnvOutputPathForDeployOnly,
|
|
419
434
|
validateEnvOutputPathFolderOrNull,
|
|
@@ -19,8 +19,12 @@ const {
|
|
|
19
19
|
extractAppConfiguration
|
|
20
20
|
} = require('../utils/app-register-config');
|
|
21
21
|
const { buildRegistrationData, saveLocalCredentials, applyLocalhostPortAdjustment } = require('../app/register');
|
|
22
|
-
const { loadDataplanePipelineCredentialsFromSecretsFile } = require('./up-dataplane-credentials');
|
|
23
22
|
const { formatSuccessLine } = require('../utils/cli-test-layout-chalk');
|
|
23
|
+
const { getToken } = require('../api/auth.api');
|
|
24
|
+
const { updateApplicationSelfStatus } = require('../api/applications.api');
|
|
25
|
+
const { tokenFrom } = require('../app/run-parameter-sync');
|
|
26
|
+
const { resolveDeclarativeShowUrlsForApp } = require('../core/secrets-env-declarative-expand');
|
|
27
|
+
const pathsUtil = require('../utils/paths');
|
|
24
28
|
|
|
25
29
|
const ENCRYPTION_VAULT_KEYS = [
|
|
26
30
|
'miso-controller-secrets-encryptionKeyVault',
|
|
@@ -87,6 +91,68 @@ async function canUseBootstrapProvision(options = {}) {
|
|
|
87
91
|
return Boolean(encryptionKey);
|
|
88
92
|
}
|
|
89
93
|
|
|
94
|
+
/**
|
|
95
|
+
* Persist canonical declarative URLs before Dataplane takes its bootstrap snapshot.
|
|
96
|
+
* @param {string} controllerUrl
|
|
97
|
+
* @param {string} environmentKey
|
|
98
|
+
* @param {{clientId: string, clientSecret: string}} credentials
|
|
99
|
+
* @param {number} containerPort
|
|
100
|
+
* @returns {Promise<void>}
|
|
101
|
+
*/
|
|
102
|
+
async function syncDataplaneApplicationUrls(controllerUrl, environmentKey, credentials, containerPort) {
|
|
103
|
+
const appPath = pathsUtil.getBuilderPath('dataplane');
|
|
104
|
+
const variablesPath = pathsUtil.resolveApplicationConfigPath(appPath);
|
|
105
|
+
const urls = await resolveDeclarativeShowUrlsForApp('dataplane', appPath, variablesPath, 'docker');
|
|
106
|
+
if (!urls) {
|
|
107
|
+
throw new Error('Could not resolve canonical Dataplane public and internal URLs');
|
|
108
|
+
}
|
|
109
|
+
const tokenResponse = await getToken(credentials.clientId, credentials.clientSecret, controllerUrl);
|
|
110
|
+
const response = await updateApplicationSelfStatus(
|
|
111
|
+
controllerUrl,
|
|
112
|
+
environmentKey,
|
|
113
|
+
{ type: 'client-token', token: tokenFrom(tokenResponse) },
|
|
114
|
+
{ status: 'deploying', url: urls.publicUrl, internalUrl: urls.internalUrl, port: containerPort }
|
|
115
|
+
);
|
|
116
|
+
if (!response?.success) {
|
|
117
|
+
throw new Error('Controller rejected canonical Dataplane public and internal URLs');
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async function handleBootstrapResponse(responseData, controllerUrl, environmentKey, containerPort) {
|
|
122
|
+
if (responseData.credentials && responseData.credentials.clientSecret) {
|
|
123
|
+
await saveLocalCredentials(responseData, controllerUrl);
|
|
124
|
+
await syncDataplaneApplicationUrls(
|
|
125
|
+
controllerUrl,
|
|
126
|
+
environmentKey,
|
|
127
|
+
responseData.credentials,
|
|
128
|
+
containerPort
|
|
129
|
+
);
|
|
130
|
+
logger.log(formatSuccessLine('Dataplane bootstrap credentials saved locally'));
|
|
131
|
+
const { waitForDataplaneCredentials } = require('./up-dataplane-credentials');
|
|
132
|
+
if (!(await waitForDataplaneCredentials(controllerUrl))) {
|
|
133
|
+
throw new Error(
|
|
134
|
+
'Dataplane bootstrap credentials were issued but the controller did not accept them in time. ' +
|
|
135
|
+
'The deploy that follows gets one attempt, so it would fail with a less specific error. ' +
|
|
136
|
+
'Retry the command; if it persists, check the controller is serving /api/v1/auth/token.'
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
if (responseData.status === 'already_provisioned') {
|
|
142
|
+
logger.log(formatSuccessLine('Dataplane already provisioned (bootstrap idempotent)'));
|
|
143
|
+
const { credentialsAcceptToken } = require('./up-dataplane-credentials');
|
|
144
|
+
if (await credentialsAcceptToken(controllerUrl)) return;
|
|
145
|
+
throw new Error(
|
|
146
|
+
'Dataplane is registered on the controller but local pipeline credentials are missing or ' +
|
|
147
|
+
'not accepted by it. Run: aifabrix login && aifabrix app rotate-secret dataplane'
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
throw new Error(
|
|
151
|
+
'Dataplane bootstrap returned no credentials and no "already_provisioned" status ' +
|
|
152
|
+
`(status: ${responseData.status || 'none'}). The controller may be a version this CLI does not support.`
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
|
|
90
156
|
/**
|
|
91
157
|
* Register dataplane via bootstrap endpoint (idempotent).
|
|
92
158
|
* @async
|
|
@@ -107,6 +173,7 @@ async function bootstrapDataplaneApplication(options, controllerUrl, environment
|
|
|
107
173
|
|
|
108
174
|
const { variables } = await loadVariablesYaml('dataplane');
|
|
109
175
|
const appConfig = await extractAppConfiguration(variables, 'dataplane', options);
|
|
176
|
+
const containerPort = appConfig.port;
|
|
110
177
|
await applyLocalhostPortAdjustment(appConfig, controllerUrl, options);
|
|
111
178
|
|
|
112
179
|
const imageOverride = options.image || buildDataplaneImageRefFn(options);
|
|
@@ -126,24 +193,13 @@ async function bootstrapDataplaneApplication(options, controllerUrl, environment
|
|
|
126
193
|
registrationData
|
|
127
194
|
);
|
|
128
195
|
|
|
129
|
-
|
|
130
|
-
await saveLocalCredentials(responseData, controllerUrl);
|
|
131
|
-
logger.log(formatSuccessLine('Dataplane bootstrap credentials saved locally'));
|
|
132
|
-
} else if (responseData.status === 'already_provisioned') {
|
|
133
|
-
logger.log(formatSuccessLine('Dataplane already provisioned (bootstrap idempotent)'));
|
|
134
|
-
const localCredentials = await loadDataplanePipelineCredentialsFromSecretsFile();
|
|
135
|
-
if (!localCredentials) {
|
|
136
|
-
throw new Error(
|
|
137
|
-
'Dataplane is registered on the controller but pipeline credentials are missing locally. ' +
|
|
138
|
-
'Run fresh setup with volume wipe, or: aifabrix login && aifabrix app rotate-secret dataplane'
|
|
139
|
-
);
|
|
140
|
-
}
|
|
141
|
-
}
|
|
196
|
+
await handleBootstrapResponse(responseData, controllerUrl, environmentKey, containerPort);
|
|
142
197
|
}
|
|
143
198
|
|
|
144
199
|
module.exports = {
|
|
145
200
|
canUseBootstrapProvision,
|
|
146
201
|
resolveBootstrapEncryptionKey,
|
|
147
202
|
bootstrapDataplaneApplication,
|
|
203
|
+
syncDataplaneApplicationUrls,
|
|
148
204
|
pickBootstrapEncryptionKeyFromSecrets
|
|
149
205
|
};
|
|
@@ -193,8 +193,29 @@ async function alignDataplaneCredentialsAfterDeploy(options, controllerUrl) {
|
|
|
193
193
|
}
|
|
194
194
|
}
|
|
195
195
|
|
|
196
|
+
/**
|
|
197
|
+
* Wait until a freshly bootstrapped pair is accepted, before anything depends on it.
|
|
198
|
+
*
|
|
199
|
+
* The Controller can answer the bootstrap call before the pipeline client is usable, and
|
|
200
|
+
* the deploy that follows gets one attempt against one URL: validateDeployment retries only
|
|
201
|
+
* on a 5xx, so a 401 from a client that is not published yet ends the install. The align
|
|
202
|
+
* step already tolerates this, with 15 attempts across three bases, but it runs after the
|
|
203
|
+
* deploy — the forgiving check after the unforgiving one.
|
|
204
|
+
*
|
|
205
|
+
* @async
|
|
206
|
+
* @param {string} controllerUrl
|
|
207
|
+
* @param {Object} [retry] - Overrides for the bootstrap probe budget
|
|
208
|
+
* @returns {Promise<boolean>} True once the pair is accepted
|
|
209
|
+
*/
|
|
210
|
+
async function waitForDataplaneCredentials(controllerUrl, retry = {}) {
|
|
211
|
+
const { maxAttempts, delayMs } = resolveCredentialProbeRetry({ useBootstrap: true, credentialProbeRetry: retry });
|
|
212
|
+
return credentialsAcceptTokenWithRetry(controllerUrl, maxAttempts, delayMs);
|
|
213
|
+
}
|
|
214
|
+
|
|
196
215
|
module.exports = {
|
|
197
216
|
alignDataplaneCredentialsAfterDeploy,
|
|
217
|
+
waitForDataplaneCredentials,
|
|
218
|
+
credentialsAcceptTokenWithRetry,
|
|
198
219
|
probeDataplaneClientToken,
|
|
199
220
|
credentialsAcceptToken,
|
|
200
221
|
loadDataplanePipelineCredentialsFromSecretsFile,
|
|
@@ -227,6 +227,9 @@ async function deployDataplaneToController(options) {
|
|
|
227
227
|
image: imageOverride,
|
|
228
228
|
registryMode: options.registryMode,
|
|
229
229
|
envKey: options.envKey ? String(options.envKey).trim().toLowerCase() : undefined,
|
|
230
|
+
// The bootstrap path has no device login, so it sets client-credentials explicitly.
|
|
231
|
+
// Dropping it here left the deploy in 'auto' mode.
|
|
232
|
+
deploymentAuth: options.deploymentAuth,
|
|
230
233
|
// Guided up-platform already shows a top-level spinner for the dataplane step.
|
|
231
234
|
// Avoid nested deploy polling spinners/logs.
|
|
232
235
|
silentPoll: options.platformInstall === true
|
|
@@ -266,7 +269,8 @@ function emitDataplaneManifestLineFromBuilder() {
|
|
|
266
269
|
}
|
|
267
270
|
|
|
268
271
|
function computeDataplanePortOverride(runEnvKey, developerIdNum) {
|
|
269
|
-
|
|
272
|
+
const { isScopedRunEnvironmentKey } = require('../utils/environment-scoped-resources');
|
|
273
|
+
if (!isScopedRunEnvironmentKey(runEnvKey)) {
|
|
270
274
|
return undefined;
|
|
271
275
|
}
|
|
272
276
|
return dataplaneDockerHostPort(3001, developerIdNum, runEnvKey);
|
|
@@ -355,6 +359,37 @@ async function provisionAndDeployDataplane(options, environmentKey, controllerUr
|
|
|
355
359
|
* @returns {Promise<void>}
|
|
356
360
|
* @throws {Error} If infra not up, controller unavailable, not logged in, environment not dev, or any step fails
|
|
357
361
|
*/
|
|
362
|
+
/**
|
|
363
|
+
* Run options for the local dataplane container.
|
|
364
|
+
*
|
|
365
|
+
* A guided platform install already shows one spinner for the whole dataplane step, so it
|
|
366
|
+
* either forwards its own progress callback or asks for silence; a standalone run prints
|
|
367
|
+
* normally.
|
|
368
|
+
*
|
|
369
|
+
* @param {Object} options - Command options
|
|
370
|
+
* @param {string} runEnvKey - Resolved run environment
|
|
371
|
+
* @param {number|undefined} portOverride - Resolved port override
|
|
372
|
+
* @returns {Object} Options for app.runApp
|
|
373
|
+
*/
|
|
374
|
+
function buildDataplaneRunOptions(options, runEnvKey, portOverride) {
|
|
375
|
+
const runAppOpts = {
|
|
376
|
+
skipEnvOutputPath: true,
|
|
377
|
+
env: runEnvKey,
|
|
378
|
+
port: portOverride,
|
|
379
|
+
registry: options.registry || undefined,
|
|
380
|
+
base: options.base !== false,
|
|
381
|
+
skipManifestMetadataLine: true
|
|
382
|
+
};
|
|
383
|
+
if (options.platformInstall === true) {
|
|
384
|
+
if (typeof options.onPollText === 'function') {
|
|
385
|
+
runAppOpts.onPollText = options.onPollText;
|
|
386
|
+
} else {
|
|
387
|
+
runAppOpts.silentPoll = true;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
return runAppOpts;
|
|
391
|
+
}
|
|
392
|
+
|
|
358
393
|
async function handleUpDataplane(options = {}) {
|
|
359
394
|
if (options.platformInstall !== true) {
|
|
360
395
|
logger.log(chalk.blue('Starting up-dataplane (register/rotate, deploy, then run dataplane locally)...\n'));
|
|
@@ -386,23 +421,7 @@ async function handleUpDataplane(options = {}) {
|
|
|
386
421
|
);
|
|
387
422
|
|
|
388
423
|
const { runEnvKey, portOverride } = await computeDataplaneRunOverrides(options);
|
|
389
|
-
|
|
390
|
-
const runAppOpts = {
|
|
391
|
-
skipEnvOutputPath: true,
|
|
392
|
-
env: runEnvKey,
|
|
393
|
-
port: portOverride,
|
|
394
|
-
registry: options.registry || undefined,
|
|
395
|
-
base: options.base !== false,
|
|
396
|
-
skipManifestMetadataLine: true
|
|
397
|
-
};
|
|
398
|
-
if (options.platformInstall === true) {
|
|
399
|
-
if (typeof options.onPollText === 'function') {
|
|
400
|
-
runAppOpts.onPollText = options.onPollText;
|
|
401
|
-
} else {
|
|
402
|
-
runAppOpts.silentPoll = true;
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
await app.runApp('dataplane', runAppOpts);
|
|
424
|
+
await app.runApp('dataplane', buildDataplaneRunOptions(options, runEnvKey, portOverride));
|
|
406
425
|
|
|
407
426
|
if (options.platformInstall !== true) {
|
|
408
427
|
logger.log(formatSuccessParagraph('up-dataplane complete. Dataplane is registered, deployed in dev, and running locally.'));
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Install the optional Integration Server as a miso-only platform application.
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Integration Server setup phase
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
'use strict';
|
|
8
|
+
|
|
9
|
+
const app = require('../app');
|
|
10
|
+
const config = require('../core/config');
|
|
11
|
+
const { generateEnvFile } = require('../core/secrets');
|
|
12
|
+
const pathsUtil = require('../utils/paths');
|
|
13
|
+
const { loadConfigFile } = require('../utils/config-format');
|
|
14
|
+
const { resolveDockerImageRef } = require('../utils/resolve-docker-image-ref');
|
|
15
|
+
const { callBootstrapApi } = require('../utils/app-bootstrap-api');
|
|
16
|
+
const { loadVariablesYaml, extractAppConfiguration } = require('../utils/app-register-config');
|
|
17
|
+
const { buildRegistrationData, saveLocalCredentials, applyLocalhostPortAdjustment } = require('../app/register');
|
|
18
|
+
const { publishedHostPort, parseDeveloperIdNum } = require('../utils/declarative-url-ports');
|
|
19
|
+
const { resolveBootstrapEncryptionKey } = require('./up-dataplane-bootstrap');
|
|
20
|
+
const { resolveUpBuilderApiControllerContext } = require('./up-builder-api-provision');
|
|
21
|
+
const {
|
|
22
|
+
ensureIntegrationServerAppsFromTemplate,
|
|
23
|
+
refreshUrlsLocalRegistryForCurrentProject
|
|
24
|
+
} = require('./up-common');
|
|
25
|
+
const { resolveLocalOnboardingApps } = require('../core/local-env-overrides');
|
|
26
|
+
|
|
27
|
+
const APP_KEY = 'integration-server';
|
|
28
|
+
const ENVIRONMENT_KEY = 'miso';
|
|
29
|
+
|
|
30
|
+
async function isIntegrationServerSelected() {
|
|
31
|
+
const cfg = await config.getConfig();
|
|
32
|
+
return resolveLocalOnboardingApps(cfg).includes(APP_KEY);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function resolveIntegrationServerImageRef(options = {}) {
|
|
36
|
+
const appPath = pathsUtil.getBuilderPath(APP_KEY);
|
|
37
|
+
const manifestPath = pathsUtil.resolveApplicationConfigPath(appPath);
|
|
38
|
+
const variables = loadConfigFile(manifestPath) || {};
|
|
39
|
+
const { imageName, imageTag } = resolveDockerImageRef(APP_KEY, variables, {
|
|
40
|
+
registry: options.registry
|
|
41
|
+
});
|
|
42
|
+
return `${imageName}:${imageTag}`;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async function bootstrapIntegrationServer(options, controllerUrl) {
|
|
46
|
+
const encryptionKey = await resolveBootstrapEncryptionKey();
|
|
47
|
+
if (!encryptionKey) {
|
|
48
|
+
throw new Error('Bootstrap encryption key is unavailable for Integration Server installation.');
|
|
49
|
+
}
|
|
50
|
+
const { variables } = await loadVariablesYaml(APP_KEY);
|
|
51
|
+
const appConfig = await extractAppConfiguration(variables, APP_KEY, options);
|
|
52
|
+
await applyLocalhostPortAdjustment(appConfig, controllerUrl, options);
|
|
53
|
+
const image = options.image || resolveIntegrationServerImageRef(options);
|
|
54
|
+
const registrationData = buildRegistrationData(appConfig, {
|
|
55
|
+
image,
|
|
56
|
+
imageOverride: image,
|
|
57
|
+
registryMode: options.registryMode,
|
|
58
|
+
envKey: ENVIRONMENT_KEY
|
|
59
|
+
});
|
|
60
|
+
const response = await callBootstrapApi(
|
|
61
|
+
controllerUrl,
|
|
62
|
+
encryptionKey,
|
|
63
|
+
ENVIRONMENT_KEY,
|
|
64
|
+
registrationData
|
|
65
|
+
);
|
|
66
|
+
if (!response.credentials || !response.credentials.clientSecret) {
|
|
67
|
+
throw new Error('Integration Server bootstrap did not return its existing credentials.');
|
|
68
|
+
}
|
|
69
|
+
await saveLocalCredentials(response, controllerUrl);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async function runIntegrationServer(options) {
|
|
73
|
+
await generateEnvFile(APP_KEY, null, 'local', true);
|
|
74
|
+
const developerId = parseDeveloperIdNum(await config.getDeveloperId());
|
|
75
|
+
await app.runApp(APP_KEY, {
|
|
76
|
+
env: ENVIRONMENT_KEY,
|
|
77
|
+
registry: options.registry,
|
|
78
|
+
registryMode: options.registryMode,
|
|
79
|
+
image: options.image,
|
|
80
|
+
port: publishedHostPort(3006, developerId),
|
|
81
|
+
skipEnvOutputPath: true,
|
|
82
|
+
skipInfraCheck: true,
|
|
83
|
+
skipManifestMetadataLine: true,
|
|
84
|
+
silentPoll: true
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async function handleUpIntegrationServer(options = {}) {
|
|
89
|
+
await ensureIntegrationServerAppsFromTemplate({ silent: true });
|
|
90
|
+
refreshUrlsLocalRegistryForCurrentProject();
|
|
91
|
+
const context = await resolveUpBuilderApiControllerContext(options, ENVIRONMENT_KEY);
|
|
92
|
+
if (!context.useBootstrap) {
|
|
93
|
+
throw new Error('Integration Server installation requires local bootstrap provisioning.');
|
|
94
|
+
}
|
|
95
|
+
await bootstrapIntegrationServer(options, context.controllerUrl);
|
|
96
|
+
const image = options.image || resolveIntegrationServerImageRef(options);
|
|
97
|
+
await app.deployApp(APP_KEY, {
|
|
98
|
+
image,
|
|
99
|
+
imageOverride: image,
|
|
100
|
+
registryMode: options.registryMode,
|
|
101
|
+
envKey: ENVIRONMENT_KEY,
|
|
102
|
+
deploymentAuth: 'client-credentials',
|
|
103
|
+
silentPoll: true
|
|
104
|
+
});
|
|
105
|
+
await runIntegrationServer({ ...options, image });
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
module.exports = {
|
|
109
|
+
handleUpIntegrationServer,
|
|
110
|
+
isIntegrationServerSelected,
|
|
111
|
+
resolveIntegrationServerImageRef
|
|
112
|
+
};
|
|
@@ -105,7 +105,8 @@ function shouldSkipE2eForStaticPackage(systemKey, options) {
|
|
|
105
105
|
if (storage.length === 0) {
|
|
106
106
|
return false;
|
|
107
107
|
}
|
|
108
|
-
return storage.every((ds) =>
|
|
108
|
+
return storage.every((ds) => !isKeyedDocumentDatasource(ds) &&
|
|
109
|
+
String(ds.syncBridge || 'disabled').toLowerCase() === 'disabled');
|
|
109
110
|
} catch {
|
|
110
111
|
return false;
|
|
111
112
|
}
|
|
@@ -124,7 +125,30 @@ function shouldSkipOperationsE2e(systemKey, options) {
|
|
|
124
125
|
|| shouldSkipE2eForStaticPackage(systemKey, options);
|
|
125
126
|
}
|
|
126
127
|
|
|
128
|
+
/** @param {Object} ds @returns {boolean} */
|
|
129
|
+
function isKeyedDocumentDatasource(ds) {
|
|
130
|
+
const ops = ds?.execution?.cip?.operations;
|
|
131
|
+
return ds?.entityType === 'documentStorage' && !ops?.list &&
|
|
132
|
+
!ds.openapi?.operations?.list && !ds.capabilities?.some(cap => (cap.key || cap) === 'list') &&
|
|
133
|
+
Array.isArray(ops?.get?.steps) && ops.get.steps.some(step => step?.output?.mode === 'documents');
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** @param {string} systemKey @param {Object} options @returns {string[]} */
|
|
137
|
+
function keyedDocumentDatasourceKeys(systemKey, options) {
|
|
138
|
+
if (options.skipE2e === true || options.minimal === true) return [];
|
|
139
|
+
try {
|
|
140
|
+
const { resolveAppWorkspace } = require('../utils/app-path-resolve');
|
|
141
|
+
const { appPath } = resolveAppWorkspace(systemKey, options);
|
|
142
|
+
const storage = loadStorageDatasources(appPath);
|
|
143
|
+
return storage.length && storage.every(isKeyedDocumentDatasource) ? storage.map(ds => ds.key) : [];
|
|
144
|
+
} catch {
|
|
145
|
+
return [];
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
127
149
|
module.exports = {
|
|
150
|
+
isKeyedDocumentDatasource,
|
|
151
|
+
keyedDocumentDatasourceKeys,
|
|
128
152
|
shouldSkipOperationsE2e,
|
|
129
153
|
shouldSkipE2eForRoleAssistant,
|
|
130
154
|
shouldSkipE2eForStaticPackage
|
|
@@ -4,6 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
'use strict';
|
|
6
6
|
|
|
7
|
+
const { keyedDocumentDatasourceKeys } = require('./verify-operations-skip-e2e');
|
|
8
|
+
const { hasAllKeyedDocumentPersistence } = require('../utils/datasource-binary-evidence');
|
|
9
|
+
|
|
7
10
|
const { syncLocalIfRequested } = require('./test-e2e-external');
|
|
8
11
|
const { cliOptsSkipPublish } = require('../utils/cli-sync-options');
|
|
9
12
|
const { buildOperationsVerifyStepPlan } = require('./verify-operations-step-plan');
|
|
@@ -99,10 +102,19 @@ async function runOperationsVerifySteps(systemKey, options) {
|
|
|
99
102
|
}
|
|
100
103
|
}
|
|
101
104
|
|
|
105
|
+
const keyedKeys = keyedDocumentDatasourceKeys(systemKey, options);
|
|
102
106
|
const e2eLabel = STEP_PROGRESS.e2e;
|
|
103
107
|
stepResults.e2e = await runWithVerifyStepProgress(
|
|
104
108
|
e2eLabel,
|
|
105
|
-
async(progress) =>
|
|
109
|
+
async(progress) => {
|
|
110
|
+
const result = await plan.e2e.run(progress);
|
|
111
|
+
if (keyedKeys.length) {
|
|
112
|
+
stepResults.keyedDocumentGet = true;
|
|
113
|
+
stepResults.documentPersistence = hasAllKeyedDocumentPersistence(result, keyedKeys);
|
|
114
|
+
return plan.e2e.ok(result) && stepResults.documentPersistence;
|
|
115
|
+
}
|
|
116
|
+
return plan.e2e.ok(result);
|
|
117
|
+
},
|
|
106
118
|
options
|
|
107
119
|
);
|
|
108
120
|
return { stepResults, hardFailure: !stepResults.e2e, stoppedEarly: false };
|
|
@@ -4,7 +4,11 @@
|
|
|
4
4
|
* @version 2.0.0
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
const
|
|
7
|
+
const { repairKeyedDocument } = require('./repair-datasource-keyed-document');
|
|
8
|
+
|
|
9
|
+
const { repairLegacyDatasource } = require('./repair-datasource-legacy');
|
|
10
|
+
|
|
11
|
+
const ENTITY_TYPE_FALLBACK = 'recordStorage';
|
|
8
12
|
const VALID_ENTITY_TYPES = new Set([
|
|
9
13
|
'document-storage',
|
|
10
14
|
'documentStorage',
|
|
@@ -14,6 +18,7 @@ const VALID_ENTITY_TYPES = new Set([
|
|
|
14
18
|
'recordStorage',
|
|
15
19
|
'message-service',
|
|
16
20
|
'messageService',
|
|
21
|
+
'serviceContract',
|
|
17
22
|
'none'
|
|
18
23
|
]);
|
|
19
24
|
const VALID_PORTAL_FIELDS = new Set(['text', 'textarea', 'select', 'json', 'boolean', 'number']);
|
|
@@ -56,7 +61,7 @@ function normalizeCipOutputModes(datasourceConfig) {
|
|
|
56
61
|
for (const operation of Object.values(operations)) {
|
|
57
62
|
if (!operation || !Array.isArray(operation.steps)) continue;
|
|
58
63
|
for (const step of operation.steps) {
|
|
59
|
-
if (step?.output?.mode && step.output.mode
|
|
64
|
+
if (step?.output?.mode && !['records', 'documents'].includes(step.output.mode)) {
|
|
60
65
|
step.output.mode = 'records';
|
|
61
66
|
}
|
|
62
67
|
}
|
|
@@ -80,15 +85,17 @@ function normalizeWizardTestPayload(datasourceConfig) {
|
|
|
80
85
|
* @param {Object} datasourceConfig - Datasource config
|
|
81
86
|
* @returns {Object} Normalized config
|
|
82
87
|
*/
|
|
83
|
-
function normalizeDatasourceConfig(datasourceConfig) {
|
|
88
|
+
function normalizeDatasourceConfig(datasourceConfig, openapiSpec) {
|
|
84
89
|
if (!datasourceConfig || typeof datasourceConfig !== 'object') {
|
|
85
90
|
return datasourceConfig;
|
|
86
91
|
}
|
|
87
92
|
if (datasourceConfig.entityType && !VALID_ENTITY_TYPES.has(datasourceConfig.entityType)) {
|
|
88
93
|
datasourceConfig.entityType = ENTITY_TYPE_FALLBACK;
|
|
89
94
|
}
|
|
95
|
+
repairLegacyDatasource(datasourceConfig);
|
|
90
96
|
normalizePortalInput(datasourceConfig);
|
|
91
97
|
normalizeCipOutputModes(datasourceConfig);
|
|
98
|
+
repairKeyedDocument(datasourceConfig, { openapiSpec });
|
|
92
99
|
normalizeWizardTestPayload(datasourceConfig);
|
|
93
100
|
return datasourceConfig;
|
|
94
101
|
}
|
|
@@ -100,10 +107,10 @@ function normalizeDatasourceConfig(datasourceConfig) {
|
|
|
100
107
|
* @param {Object|Object[]} datasourceConfigs - Datasource config(s)
|
|
101
108
|
* @returns {{ systemConfig: Object, datasourceConfigs: Object[] }} Normalized configs
|
|
102
109
|
*/
|
|
103
|
-
function normalizeWizardConfigs(systemConfig, datasourceConfigs) {
|
|
110
|
+
function normalizeWizardConfigs(systemConfig, datasourceConfigs, openapiSpec) {
|
|
104
111
|
const normalizedSystem = normalizeSystemConfig(systemConfig);
|
|
105
112
|
const configs = Array.isArray(datasourceConfigs) ? datasourceConfigs : [datasourceConfigs];
|
|
106
|
-
const normalizedDatasources = configs.map(normalizeDatasourceConfig);
|
|
113
|
+
const normalizedDatasources = configs.map(config => normalizeDatasourceConfig(config, openapiSpec));
|
|
107
114
|
return { systemConfig: normalizedSystem, datasourceConfigs: normalizedDatasources };
|
|
108
115
|
}
|
|
109
116
|
|