@aifabrix/builder 2.43.0 → 2.44.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/anchor-docs.mdc +15 -0
- package/README.md +1 -1
- package/anchor-docs/README.md +10 -0
- package/anchor-docs/_TEMPLATE +24 -0
- package/bin/aifabrix.js +13 -4
- package/integration/hubspot-test/README.md +31 -0
- package/integration/hubspot-test/create-hubspot.js +5 -5
- package/integration/hubspot-test/hubspot-test-datasource-company.json +58 -462
- package/integration/hubspot-test/hubspot-test-datasource-contact.json +61 -555
- package/integration/hubspot-test/hubspot-test-datasource-deal.json +63 -506
- package/integration/hubspot-test/hubspot-test-datasource-users.json +42 -83
- package/integration/hubspot-test/hubspot-test-deploy.json +3 -3
- package/integration/hubspot-test/test-dataplane-down-tests.js +1 -7
- package/integration/hubspot-test/test-dataplane-down.js +3 -3
- package/integration/hubspot-test/test.js +35 -43
- package/integration/hubspot-test/wizard-hubspot-test-headless.yaml +23 -0
- package/integration/roundtrip-test-local/README.md +144 -0
- package/integration/roundtrip-test-local/application.yaml +13 -0
- package/integration/roundtrip-test-local/env.template +15 -0
- package/integration/roundtrip-test-local/roundtrip-test-local-datasource-roundtrip-test-company.yaml +14 -0
- package/integration/roundtrip-test-local/roundtrip-test-local-deploy.json +61 -0
- package/integration/roundtrip-test-local/roundtrip-test-local-system.yaml +25 -0
- package/integration/roundtrip-test-local2/README.md +144 -0
- package/integration/roundtrip-test-local2/application.yaml +13 -0
- package/integration/roundtrip-test-local2/env.template +15 -0
- package/integration/roundtrip-test-local2/roundtrip-test-local2-datasource-company.yaml +31 -0
- package/integration/roundtrip-test-local2/roundtrip-test-local2-deploy.json +86 -0
- package/integration/roundtrip-test-local2/roundtrip-test-local2-system.yaml +25 -0
- package/integration/test/wizard.yaml +8 -0
- package/jest.config.default.js +10 -0
- package/jest.config.integration.fixtures.js +22 -0
- package/jest.config.integration.js +21 -18
- package/jest.config.isolated.js +10 -0
- package/jest.projects.js +288 -0
- package/lib/api/datasources-core.api.js +3 -3
- package/lib/api/dev-mtls-request.js +110 -0
- package/lib/api/dev-server-https.js +145 -0
- package/lib/api/dev.api.js +133 -144
- package/lib/api/index.js +0 -1
- package/lib/api/pipeline.api.js +67 -20
- package/lib/api/types/dev.types.js +4 -3
- package/lib/api/types/pipeline.types.js +8 -5
- package/lib/api/types/validation-run.types.js +56 -0
- package/lib/api/validation-run.api.js +99 -0
- package/lib/api/validation-runner.js +99 -0
- package/lib/app/config.js +1 -1
- package/lib/app/deploy-status-display.js +2 -2
- package/lib/app/deploy.js +7 -6
- package/lib/app/display.js +2 -1
- package/lib/app/dockerfile.js +3 -2
- package/lib/app/down.js +2 -1
- package/lib/app/helpers.js +6 -5
- package/lib/app/index.js +27 -8
- package/lib/app/list.js +7 -6
- package/lib/app/push.js +4 -3
- package/lib/app/register.js +16 -7
- package/lib/app/rotate-secret.js +14 -13
- package/lib/app/run-container-start.js +184 -0
- package/lib/app/run-docker-fallback.js +108 -0
- package/lib/app/run-env-compose.js +30 -42
- package/lib/app/run-helpers.js +49 -126
- package/lib/app/run-infra-requirements.js +30 -0
- package/lib/app/run-resolve-image.js +21 -0
- package/lib/app/run.js +74 -21
- package/lib/app/show-display.js +1 -1
- package/lib/app/show.js +1 -1
- package/lib/build/index.js +13 -10
- package/lib/cli/index.js +2 -0
- package/lib/cli/setup-app.help.js +67 -0
- package/lib/cli/setup-app.js +57 -121
- package/lib/cli/setup-app.test-commands.js +179 -0
- package/lib/cli/setup-auth.js +19 -5
- package/lib/cli/setup-credential-deployment.js +22 -8
- package/lib/cli/setup-dev-path-commands.js +124 -0
- package/lib/cli/setup-dev.js +170 -113
- package/lib/cli/setup-environment.js +7 -1
- package/lib/cli/setup-external-system.js +62 -22
- package/lib/cli/setup-infra.js +126 -47
- package/lib/cli/setup-parameters.js +32 -0
- package/lib/cli/setup-secrets.js +106 -8
- package/lib/cli/setup-service-user.js +1 -1
- package/lib/cli/setup-utility.js +36 -20
- package/lib/commands/app-down.js +5 -7
- package/lib/commands/app-install.js +14 -7
- package/lib/commands/app-logs.js +13 -10
- package/lib/commands/app-shell.js +4 -1
- package/lib/commands/app-test.js +25 -19
- package/lib/commands/app.js +22 -10
- package/lib/commands/auth-config.js +6 -6
- package/lib/commands/auth-status.js +4 -3
- package/lib/commands/credential-env.js +4 -3
- package/lib/commands/credential-list.js +5 -4
- package/lib/commands/credential-push.js +4 -3
- package/lib/commands/datasource-unified-test-cli.js +495 -0
- package/lib/commands/datasource-unified-test-cli.options.js +149 -0
- package/lib/commands/datasource-validation-cli.js +129 -0
- package/lib/commands/datasource.js +105 -98
- package/lib/commands/deployment-list.js +6 -5
- package/lib/commands/dev-cli-handlers.js +122 -18
- package/lib/commands/dev-down.js +4 -3
- package/lib/commands/dev-init.js +231 -116
- package/lib/commands/dev-show-display.js +473 -0
- package/lib/commands/login-credentials.js +3 -2
- package/lib/commands/login-device.js +4 -3
- package/lib/commands/login.js +5 -4
- package/lib/commands/logout.js +8 -7
- package/lib/commands/parameters-validate.js +54 -0
- package/lib/commands/repair-datasource.js +314 -68
- package/lib/commands/repair-env-template.js +2 -2
- package/lib/commands/repair.js +21 -3
- package/lib/commands/secrets-list.js +23 -12
- package/lib/commands/secrets-remove-all.js +220 -0
- package/lib/commands/secrets-remove.js +21 -12
- package/lib/commands/secrets-set.js +21 -12
- package/lib/commands/secrets-validate.js +4 -4
- package/lib/commands/secure.js +10 -9
- package/lib/commands/service-user.js +26 -25
- package/lib/commands/test-e2e-external.js +27 -1
- package/lib/commands/up-common.js +3 -2
- package/lib/commands/up-dataplane.js +29 -16
- package/lib/commands/up-miso.js +19 -29
- package/lib/commands/upload.js +138 -39
- package/lib/commands/wizard-core-helpers.js +1 -1
- package/lib/commands/wizard-dataplane.js +4 -3
- package/lib/commands/wizard-helpers.js +3 -3
- package/lib/commands/wizard.js +2 -2
- package/lib/core/admin-secrets.js +14 -5
- package/lib/core/audit-logger.js +12 -4
- package/lib/core/config-attach-extensions.js +46 -0
- package/lib/core/config-runtime-paths.js +29 -0
- package/lib/core/config.js +55 -56
- package/lib/core/diff.js +3 -2
- package/lib/core/ensure-encryption-key.js +1 -1
- package/lib/core/secrets-ensure-infra.js +77 -0
- package/lib/core/secrets-ensure.js +120 -64
- package/lib/core/secrets-env-write.js +35 -7
- package/lib/core/secrets-infra-placeholder-sync.js +61 -0
- package/lib/core/secrets.js +200 -37
- package/lib/core/templates-env.js +4 -3
- package/lib/datasource/abac-validator.js +1 -10
- package/lib/datasource/deploy.js +75 -53
- package/lib/datasource/field-reference-validator.js +9 -6
- package/lib/datasource/integration-context.js +63 -0
- package/lib/datasource/list.js +8 -7
- package/lib/datasource/log-viewer.js +84 -53
- package/lib/datasource/resolve-app.js +4 -4
- package/lib/datasource/test-e2e.js +95 -146
- package/lib/datasource/test-integration.js +114 -122
- package/lib/datasource/unified-validation-run-body.js +65 -0
- package/lib/datasource/unified-validation-run-post.js +23 -0
- package/lib/datasource/unified-validation-run-resolve.js +43 -0
- package/lib/datasource/unified-validation-run.js +92 -0
- package/lib/datasource/validate.js +157 -13
- package/lib/deployment/deployer.js +4 -3
- package/lib/deployment/environment.js +7 -6
- package/lib/deployment/push.js +17 -8
- package/lib/external-system/delete.js +4 -3
- package/lib/external-system/deploy.js +131 -53
- package/lib/external-system/download-helpers.js +1 -1
- package/lib/external-system/download.js +7 -6
- package/lib/external-system/generator.js +92 -6
- package/lib/external-system/integration-test-dispatch.js +26 -0
- package/lib/external-system/test-execution.js +5 -1
- package/lib/external-system/test-helpers.js +0 -4
- package/lib/external-system/test-system-level-helpers.js +110 -0
- package/lib/external-system/test-system-level.js +83 -44
- package/lib/external-system/test.js +59 -8
- package/lib/generator/builders.js +23 -11
- package/lib/generator/deploy-manifest-azure-kv.js +81 -0
- package/lib/generator/external.js +16 -4
- package/lib/generator/helpers.js +58 -3
- package/lib/generator/index.js +4 -0
- package/lib/generator/split-readme.js +12 -7
- package/lib/generator/split-variables.js +2 -1
- package/lib/generator/split.js +1 -1
- package/lib/generator/wizard-readme.js +3 -3
- package/lib/generator/wizard.js +8 -8
- package/lib/infrastructure/compose.js +60 -6
- package/lib/infrastructure/helpers.js +201 -29
- package/lib/infrastructure/index.js +28 -17
- package/lib/infrastructure/services.js +21 -15
- package/lib/internal/fs-real-sync.js +104 -0
- package/lib/internal/node-fs.js +98 -0
- package/lib/parameters/database-secret-values.js +173 -0
- package/lib/parameters/infra-kv-discovery.js +121 -0
- package/lib/parameters/infra-parameter-catalog.js +458 -0
- package/lib/parameters/infra-parameter-validate.js +64 -0
- package/lib/schema/application-schema.json +37 -17
- package/lib/schema/datasource-test-run.schema.json +493 -0
- package/lib/schema/deployment-rules.yaml +102 -63
- package/lib/schema/external-datasource.schema.json +1200 -442
- package/lib/schema/external-system.schema.json +181 -5
- package/lib/schema/flag-map-validation-run.json +31 -0
- package/lib/schema/infra-parameter.schema.json +106 -0
- package/lib/schema/infra.parameter.yaml +421 -0
- package/lib/schema/type/credential-auth-templates.json +40 -0
- package/lib/schema/type/document-storage.json +213 -0
- package/lib/schema/type/message-service.json +123 -0
- package/lib/schema/type/vector-store.json +88 -0
- package/lib/utils/aifabrix-runtime-config-dir.js +132 -0
- package/lib/utils/api-error-handler.js +2 -2
- package/lib/utils/api.js +49 -14
- package/lib/utils/app-register-api.js +3 -2
- package/lib/utils/app-register-auth.js +1 -1
- package/lib/utils/app-register-config.js +4 -4
- package/lib/utils/app-register-display.js +3 -2
- package/lib/utils/app-register-validator.js +3 -2
- package/lib/utils/app-run-containers.js +26 -22
- package/lib/utils/app-scoped-config.js +31 -0
- package/lib/utils/app-service-env-from-builder.js +164 -0
- package/lib/utils/build-copy.js +1 -1
- package/lib/utils/build-helpers.js +20 -20
- package/lib/utils/build-resolve-image.js +165 -0
- package/lib/utils/cli-layout-chalk.js +8 -0
- package/lib/utils/cli-test-layout-chalk.js +267 -0
- package/lib/utils/cli-utils.js +88 -11
- package/lib/utils/compose-db-passwords.js +138 -0
- package/lib/utils/compose-generate-docker-compose.js +216 -0
- package/lib/utils/compose-generator.js +197 -291
- package/lib/utils/compose-miso-env.js +18 -0
- package/lib/utils/compose-traefik-ingress-base.js +158 -0
- package/lib/utils/config-paths.js +166 -7
- package/lib/utils/config-scoped-resources-preference.js +41 -0
- package/lib/utils/controller-deployment-outcome.js +68 -0
- package/lib/utils/credential-display.js +2 -2
- package/lib/utils/dataplane-pipeline-warning.js +4 -3
- package/lib/utils/datasource-test-run-capability-scope.js +43 -0
- package/lib/utils/datasource-test-run-debug-display.js +137 -0
- package/lib/utils/datasource-test-run-debug-slice.js +93 -0
- package/lib/utils/datasource-test-run-display.js +442 -0
- package/lib/utils/datasource-test-run-exit.js +58 -0
- package/lib/utils/datasource-test-run-legacy-adapter.js +93 -0
- package/lib/utils/datasource-test-run-report-version.js +51 -0
- package/lib/utils/datasource-test-run-schema-sync.js +59 -0
- package/lib/utils/datasource-test-run-tty-log.js +81 -0
- package/lib/utils/datasource-validation-watch.js +266 -0
- package/lib/utils/declarative-url-ports.js +47 -0
- package/lib/utils/derive-env-key-from-client-id.js +41 -0
- package/lib/utils/dev-ca-install.js +185 -23
- package/lib/utils/dev-cert-helper.js +266 -17
- package/lib/utils/dev-hosts-helper.js +307 -0
- package/lib/utils/dev-init-cert-hints.js +37 -0
- package/lib/utils/dev-init-health-messages.js +52 -0
- package/lib/utils/dev-init-resolve.js +86 -0
- package/lib/utils/dev-init-ssh-merge.js +65 -0
- package/lib/utils/dev-ssh-config-helper.js +196 -0
- package/lib/utils/dev-user-groups.js +93 -0
- package/lib/utils/docker-build.js +42 -17
- package/lib/utils/docker-exec.js +28 -0
- package/lib/utils/docker-manifest-public-port.js +116 -0
- package/lib/utils/docker-not-running-hint.js +52 -0
- package/lib/utils/docker.js +98 -11
- package/lib/utils/ensure-dev-certs-for-remote-docker.js +192 -0
- package/lib/utils/env-config-loader.js +10 -91
- package/lib/utils/env-copy.js +19 -10
- package/lib/utils/env-map.js +35 -8
- package/lib/utils/env-template.js +2 -2
- package/lib/utils/environment-scoped-resources.js +144 -0
- package/lib/utils/error-formatter.js +92 -13
- package/lib/utils/error-formatters/http-status-errors.js +6 -5
- package/lib/utils/error-formatters/network-errors.js +2 -1
- package/lib/utils/error-formatters/permission-errors.js +2 -1
- package/lib/utils/error-formatters/validation-errors.js +2 -1
- package/lib/utils/external-readme.js +8 -1
- package/lib/utils/external-system-display.js +234 -136
- package/lib/utils/external-system-local-test-tty.js +389 -0
- package/lib/utils/external-system-readiness-core.js +377 -0
- package/lib/utils/external-system-readiness-deploy-display.js +270 -0
- package/lib/utils/external-system-readiness-display-internals.js +150 -0
- package/lib/utils/external-system-readiness-display.js +186 -0
- package/lib/utils/external-system-test-helpers.js +24 -6
- package/lib/utils/external-system-validators.js +30 -12
- package/lib/utils/health-check-url.js +119 -0
- package/lib/utils/health-check.js +59 -25
- package/lib/utils/help-builder.js +11 -8
- package/lib/utils/image-version.js +4 -8
- package/lib/utils/infra-containers.js +4 -7
- package/lib/utils/infra-env-defaults.js +162 -0
- package/lib/utils/infra-status-display.js +167 -0
- package/lib/utils/infra-status.js +16 -8
- package/lib/utils/local-secrets.js +3 -4
- package/lib/utils/paths.js +134 -47
- package/lib/utils/port-resolver.js +10 -23
- package/lib/utils/redis-env-scope.js +62 -0
- package/lib/utils/register-aifabrix-shell-env.js +204 -0
- package/lib/utils/remote-builder-validation.js +99 -0
- package/lib/utils/remote-dev-auth.js +117 -21
- package/lib/utils/remote-docker-env.js +67 -15
- package/lib/utils/remote-secrets-loader.js +13 -4
- package/lib/utils/resolve-docker-image-ref.js +124 -0
- package/lib/utils/schema-loader.js +22 -9
- package/lib/utils/secrets-bash-kv.js +25 -0
- package/lib/utils/secrets-generator.js +169 -49
- package/lib/utils/secrets-helpers.js +70 -59
- package/lib/utils/secrets-kv-scope.js +60 -0
- package/lib/utils/secrets-utils.js +32 -38
- package/lib/utils/secrets-validation.js +3 -1
- package/lib/utils/secrets-yaml-preserve.js +109 -0
- package/lib/utils/ssh-key-helper.js +4 -2
- package/lib/utils/template-helpers.js +2 -2
- package/lib/utils/test-log-writer.js +3 -3
- package/lib/utils/token-manager.js +1 -2
- package/lib/utils/url-declarative-public-base.js +188 -0
- package/lib/utils/url-declarative-resolve-build.js +493 -0
- package/lib/utils/url-declarative-resolve-load-doc.js +51 -0
- package/lib/utils/url-declarative-resolve.js +220 -0
- package/lib/utils/url-declarative-token-parse.js +74 -0
- package/lib/utils/url-declarative-url-flags.js +50 -0
- package/lib/utils/url-declarative-vdir-inactive-env.js +99 -0
- package/lib/utils/url-public-path-prefix.js +34 -0
- package/lib/utils/urls-local-registry.js +220 -0
- package/lib/utils/validation-report-tty-kit.js +77 -0
- package/lib/utils/validation-run-poll.js +89 -0
- package/lib/utils/validation-run-post-retry.js +73 -0
- package/lib/utils/validation-run-request.js +98 -0
- package/lib/utils/variable-transformer.js +21 -4
- package/lib/utils/yaml-preserve.js +33 -14
- package/lib/validation/datasource-warnings.js +56 -0
- package/lib/validation/env-template-auth.js +1 -1
- package/lib/validation/external-manifest-validator.js +27 -7
- package/lib/validation/validate-display.js +37 -31
- package/lib/validation/validate.js +4 -13
- package/lib/validation/validator-unresolved-placeholders.js +98 -0
- package/lib/validation/validator.js +22 -65
- package/lib/validation/wizard-config-validator.js +2 -1
- package/package.json +7 -3
- package/scripts/check-datasource-test-run-schema-sync.js +34 -0
- package/scripts/diagnose-cli.js +150 -0
- package/scripts/install-local.js +304 -55
- package/templates/README.md +15 -2
- package/templates/applications/dataplane/application.yaml +52 -2
- package/templates/applications/dataplane/env.template +75 -17
- package/templates/applications/dataplane/rbac.yaml +8 -0
- package/templates/applications/keycloak/application.yaml +9 -1
- package/templates/applications/keycloak/env.template +15 -6
- package/templates/applications/miso-controller/application.yaml +10 -2
- package/templates/applications/miso-controller/env.template +42 -12
- package/templates/applications/miso-controller/rbac.yaml +5 -0
- package/templates/external-system/README.md.hbs +20 -7
- package/templates/external-system/deploy.js.hbs +5 -5
- package/templates/external-system/external-datasource.yaml.hbs +197 -118
- package/templates/infra/compose.yaml.hbs +20 -4
- package/templates/python/docker-compose.hbs +16 -0
- package/templates/typescript/docker-compose.hbs +16 -0
- package/lib/api/external-test.api.js +0 -111
- package/lib/schema/env-config.yaml +0 -60
package/lib/api/dev.api.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview Builder Server (dev) API – issue-cert, settings, users, SSH keys, secrets.
|
|
3
3
|
* First call: issue-cert is public (no client cert). All other routes require client certificate:
|
|
4
|
-
* when clientKeyPem is provided, requests use mTLS (TLS client cert)
|
|
4
|
+
* when clientKeyPem is provided and the URL is https, requests use mTLS (TLS client cert).
|
|
5
|
+
* For http:// URLs, mTLS is impossible; the same routes use X-Client-Cert only (same as when no key is passed).
|
|
5
6
|
* @author AI Fabrix Team
|
|
6
7
|
* @version 2.0.0
|
|
7
8
|
*/
|
|
8
9
|
|
|
9
|
-
const https = require('https');
|
|
10
10
|
const { makeApiCall } = require('../utils/api');
|
|
11
|
-
|
|
12
|
-
const
|
|
11
|
+
const { httpsJsonRequest, DEFAULT_TIMEOUT_MS, shouldUseMtlsForUrl } = require('./dev-server-https');
|
|
12
|
+
const { requestWithClientCert } = require('./dev-mtls-request');
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* Encode PEM for use in X-Client-Cert header. HTTP header values must not contain newlines;
|
|
@@ -46,20 +46,48 @@ function buildUrl(baseUrl, path) {
|
|
|
46
46
|
return `${baseUrl}${p}`;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
function isHttpOrHttpsUrl(value) {
|
|
50
|
+
return typeof value === 'string' && (value.startsWith('http://') || value.startsWith('https://'));
|
|
51
|
+
}
|
|
52
|
+
|
|
49
53
|
/**
|
|
50
|
-
*
|
|
54
|
+
* Full URL for shared-secrets collection (GET list / POST add). DELETE uses this base + /:key.
|
|
55
|
+
* When secretsEndpointUrl is set (config aifabrix-secrets), uses it; if it is only a host base (path /), appends /api/dev/secrets.
|
|
56
|
+
* @param {string} serverUrl - Builder Server base URL
|
|
57
|
+
* @param {string} [secretsEndpointUrl] - Optional secrets API URL from config
|
|
58
|
+
* @returns {string}
|
|
59
|
+
*/
|
|
60
|
+
function resolveSecretsEndpoint(serverUrl, secretsEndpointUrl) {
|
|
61
|
+
if (secretsEndpointUrl && isHttpOrHttpsUrl(secretsEndpointUrl)) {
|
|
62
|
+
const normalized = normalizeBaseUrl(secretsEndpointUrl);
|
|
63
|
+
let u;
|
|
64
|
+
try {
|
|
65
|
+
u = new URL(normalized);
|
|
66
|
+
} catch {
|
|
67
|
+
return buildUrl(normalizeBaseUrl(serverUrl), '/api/dev/secrets');
|
|
68
|
+
}
|
|
69
|
+
if (u.pathname === '/' || u.pathname === '') {
|
|
70
|
+
return buildUrl(normalized, '/api/dev/secrets');
|
|
71
|
+
}
|
|
72
|
+
return normalized;
|
|
73
|
+
}
|
|
74
|
+
return buildUrl(normalizeBaseUrl(serverUrl), '/api/dev/secrets');
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Builder Server request via global fetch (public CAs only).
|
|
51
79
|
* @param {string} url - Full URL
|
|
52
|
-
* @param {Object}
|
|
53
|
-
* @returns {Promise<Object>}
|
|
80
|
+
* @param {Object} rest - method, headers, body
|
|
81
|
+
* @returns {Promise<Object>}
|
|
54
82
|
*/
|
|
55
|
-
async function
|
|
83
|
+
async function requestViaFetchApi(url, rest) {
|
|
56
84
|
const fetchOptions = {
|
|
57
|
-
method:
|
|
58
|
-
headers: { 'Content-Type': 'application/json', ...
|
|
85
|
+
method: rest.method || 'GET',
|
|
86
|
+
headers: { 'Content-Type': 'application/json', ...rest.headers },
|
|
59
87
|
signal: AbortSignal.timeout(DEFAULT_TIMEOUT_MS)
|
|
60
88
|
};
|
|
61
|
-
if (
|
|
62
|
-
fetchOptions.body = typeof
|
|
89
|
+
if (rest.body !== undefined) {
|
|
90
|
+
fetchOptions.body = typeof rest.body === 'string' ? rest.body : JSON.stringify(rest.body);
|
|
63
91
|
}
|
|
64
92
|
const result = await makeApiCall(url, fetchOptions);
|
|
65
93
|
if (!result.success) {
|
|
@@ -67,103 +95,36 @@ async function request(url, options = {}) {
|
|
|
67
95
|
const err = new Error(msg);
|
|
68
96
|
err.status = result.status;
|
|
69
97
|
err.errorData = result.errorData;
|
|
98
|
+
if (result.originalError) {
|
|
99
|
+
err.cause = result.originalError;
|
|
100
|
+
}
|
|
70
101
|
throw err;
|
|
71
102
|
}
|
|
72
103
|
return result.data;
|
|
73
104
|
}
|
|
74
105
|
|
|
75
106
|
/**
|
|
76
|
-
*
|
|
107
|
+
* Make request to Builder Server. Throws on !success with message from response or error.
|
|
108
|
+
* When options.serverCaPem is set, uses Node https with merged CA (Node ignores Windows user ROOT for fetch).
|
|
77
109
|
* @param {string} url - Full URL
|
|
78
|
-
* @param {Object} options -
|
|
79
|
-
* @
|
|
80
|
-
* @param {string} keyPem - PEM client key
|
|
81
|
-
* @returns {{ urlObj: URL, method: string, headers: Object, body: string|undefined, agent: https.Agent }}
|
|
82
|
-
*/
|
|
83
|
-
function buildMtlsRequestOptions(url, options, certPem, keyPem) {
|
|
84
|
-
const urlObj = new URL(url);
|
|
85
|
-
const method = (options.method || 'GET').toUpperCase();
|
|
86
|
-
const headers = { 'Content-Type': 'application/json', ...options.headers };
|
|
87
|
-
let body = options.body;
|
|
88
|
-
if (body !== undefined && typeof body !== 'string') {
|
|
89
|
-
body = JSON.stringify(body);
|
|
90
|
-
}
|
|
91
|
-
if (body) {
|
|
92
|
-
headers['Content-Length'] = Buffer.byteLength(body, 'utf8');
|
|
93
|
-
}
|
|
94
|
-
const tlsOptions = { cert: certPem, key: keyPem, rejectUnauthorized: true };
|
|
95
|
-
const agent = new https.Agent(tlsOptions);
|
|
96
|
-
return { urlObj, method, headers, body, agent, tlsOptions };
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Handle mTLS response: collect body, parse JSON, resolve or reject.
|
|
101
|
-
* @param {import('http').IncomingMessage} res - HTTP response
|
|
102
|
-
* @param {Function} resolve - Promise resolve
|
|
103
|
-
* @param {Function} reject - Promise reject
|
|
110
|
+
* @param {Object} options - Fetch options (method, headers, body, serverCaPem)
|
|
111
|
+
* @returns {Promise<Object>} result.data when success
|
|
104
112
|
*/
|
|
105
|
-
function
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
let data;
|
|
113
|
+
async function request(url, options = {}) {
|
|
114
|
+
const { serverCaPem, ...rest } = options;
|
|
115
|
+
const pem = serverCaPem && typeof serverCaPem === 'string' && serverCaPem.trim() ? serverCaPem.trim() : null;
|
|
116
|
+
let useMergedCaHttps = false;
|
|
117
|
+
if (pem) {
|
|
111
118
|
try {
|
|
112
|
-
|
|
119
|
+
useMergedCaHttps = new URL(url).protocol === 'https:';
|
|
113
120
|
} catch {
|
|
114
|
-
|
|
115
|
-
}
|
|
116
|
-
if (res.statusCode < 200 || res.statusCode >= 300) {
|
|
117
|
-
const msg = (data && (data.message || data.error)) || res.statusMessage || `Request failed (${res.statusCode})`;
|
|
118
|
-
const err = new Error(msg);
|
|
119
|
-
err.status = res.statusCode;
|
|
120
|
-
err.errorData = data;
|
|
121
|
-
reject(err);
|
|
122
|
-
} else {
|
|
123
|
-
resolve(data);
|
|
121
|
+
useMergedCaHttps = false;
|
|
124
122
|
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
* is presented in the TLS handshake. Also sends X-Client-Cert header for backends that read it.
|
|
131
|
-
* @param {string} url - Full URL (https only)
|
|
132
|
-
* @param {Object} options - { method, headers, body }
|
|
133
|
-
* @param {string} certPem - PEM-encoded client certificate
|
|
134
|
-
* @param {string} keyPem - PEM-encoded client private key
|
|
135
|
-
* @returns {Promise<Object>} response data when success
|
|
136
|
-
*/
|
|
137
|
-
function requestWithCertImpl(url, options, certPem, keyPem) {
|
|
138
|
-
return new Promise((resolve, reject) => {
|
|
139
|
-
const urlObj = new URL(url);
|
|
140
|
-
if (urlObj.protocol !== 'https:') {
|
|
141
|
-
reject(new Error('mTLS request requires https URL'));
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
144
|
-
const { method, headers, body, agent, tlsOptions } = buildMtlsRequestOptions(url, options, certPem, keyPem);
|
|
145
|
-
const req = https.request(
|
|
146
|
-
{
|
|
147
|
-
hostname: urlObj.hostname,
|
|
148
|
-
port: urlObj.port || 443,
|
|
149
|
-
path: urlObj.pathname + urlObj.search,
|
|
150
|
-
method,
|
|
151
|
-
headers,
|
|
152
|
-
agent,
|
|
153
|
-
...tlsOptions
|
|
154
|
-
},
|
|
155
|
-
(res) => handleMtlsResponse(res, resolve, reject)
|
|
156
|
-
);
|
|
157
|
-
req.on('error', reject);
|
|
158
|
-
req.setTimeout(DEFAULT_TIMEOUT_MS, () => {
|
|
159
|
-
req.destroy();
|
|
160
|
-
reject(new Error(`Request timed out after ${DEFAULT_TIMEOUT_MS}ms`));
|
|
161
|
-
});
|
|
162
|
-
if (body) {
|
|
163
|
-
req.write(body, 'utf8');
|
|
164
|
-
}
|
|
165
|
-
req.end();
|
|
166
|
-
});
|
|
123
|
+
}
|
|
124
|
+
if (pem && useMergedCaHttps) {
|
|
125
|
+
return httpsJsonRequest(url, rest, pem);
|
|
126
|
+
}
|
|
127
|
+
return requestViaFetchApi(url, rest);
|
|
167
128
|
}
|
|
168
129
|
|
|
169
130
|
/**
|
|
@@ -171,44 +132,47 @@ function requestWithCertImpl(url, options, certPem, keyPem) {
|
|
|
171
132
|
* @requiresPermission {BuilderServer} Public (no auth required)
|
|
172
133
|
* @param {string} serverUrl - Builder Server base URL
|
|
173
134
|
* @param {Object} body - IssueCertDto: developerId, pin, csr
|
|
135
|
+
* @param {string} [serverCaPem] - Dev root CA PEM when Node must trust a private CA (e.g. after install-ca)
|
|
174
136
|
* @returns {Promise<Object>} IssueCertResponseDto: certificate, validDays, validNotAfter
|
|
175
137
|
*/
|
|
176
|
-
async function issueCert(serverUrl, body) {
|
|
138
|
+
async function issueCert(serverUrl, body, serverCaPem) {
|
|
177
139
|
const base = normalizeBaseUrl(serverUrl);
|
|
178
|
-
return request(buildUrl(base, '/api/dev/issue-cert'), { method: 'POST', body });
|
|
140
|
+
return request(buildUrl(base, '/api/dev/issue-cert'), { method: 'POST', body, serverCaPem });
|
|
179
141
|
}
|
|
180
142
|
|
|
181
143
|
/**
|
|
182
144
|
* Get health. GET /health (public)
|
|
183
145
|
* @requiresPermission {BuilderServer} Public (no auth required)
|
|
184
146
|
* @param {string} serverUrl - Builder Server base URL
|
|
147
|
+
* @param {string} [serverCaPem] - Dev root CA PEM when verifying a private CA
|
|
185
148
|
* @returns {Promise<Object>} HealthResponseDto: status, checks (dataDir, encryptionKey, ca, users, tokens)
|
|
186
149
|
*/
|
|
187
|
-
async function getHealth(serverUrl) {
|
|
150
|
+
async function getHealth(serverUrl, serverCaPem) {
|
|
188
151
|
const base = normalizeBaseUrl(serverUrl);
|
|
189
|
-
return request(buildUrl(base, '/health'));
|
|
152
|
+
return request(buildUrl(base, '/health'), { method: 'GET', serverCaPem });
|
|
190
153
|
}
|
|
191
154
|
|
|
192
155
|
/**
|
|
193
156
|
* Get developer settings (cert-authenticated). GET /api/dev/settings
|
|
194
|
-
* When clientKeyPem is provided, uses mTLS
|
|
157
|
+
* When clientKeyPem is provided and server URL is https, uses mTLS; otherwise X-Client-Cert header only.
|
|
195
158
|
* @requiresPermission {BuilderServer} Client certificate (X-Client-Cert or mTLS)
|
|
196
159
|
* @param {string} serverUrl - Builder Server base URL
|
|
197
160
|
* @param {string} clientCertPem - PEM-encoded client certificate
|
|
198
161
|
* @param {string} [clientKeyPem] - PEM-encoded client private key (enables mTLS when provided)
|
|
162
|
+
* @param {string} [serverCaPem] - Dev root CA PEM for server certificate verification
|
|
199
163
|
* @returns {Promise<Object>} SettingsResponseDto
|
|
200
164
|
*/
|
|
201
|
-
async function getSettings(serverUrl, clientCertPem, clientKeyPem) {
|
|
165
|
+
async function getSettings(serverUrl, clientCertPem, clientKeyPem, serverCaPem) {
|
|
202
166
|
if (!clientCertPem || typeof clientCertPem !== 'string') {
|
|
203
167
|
throw new Error('Client certificate PEM is required for getSettings');
|
|
204
168
|
}
|
|
205
169
|
const base = normalizeBaseUrl(serverUrl);
|
|
206
170
|
const url = buildUrl(base, '/api/dev/settings');
|
|
207
171
|
const reqOptions = { method: 'GET', headers: { 'X-Client-Cert': encodeCertForHeader(clientCertPem) } };
|
|
208
|
-
if (
|
|
209
|
-
return
|
|
172
|
+
if (shouldUseMtlsForUrl(url, clientKeyPem)) {
|
|
173
|
+
return requestWithClientCert(url, reqOptions, clientCertPem, clientKeyPem, serverCaPem);
|
|
210
174
|
}
|
|
211
|
-
return request(url, reqOptions);
|
|
175
|
+
return request(url, { ...reqOptions, serverCaPem });
|
|
212
176
|
}
|
|
213
177
|
|
|
214
178
|
/**
|
|
@@ -216,13 +180,15 @@ async function getSettings(serverUrl, clientCertPem, clientKeyPem) {
|
|
|
216
180
|
* @requiresPermission {BuilderServer} Client certificate (X-Client-Cert)
|
|
217
181
|
* @param {string} serverUrl - Builder Server base URL
|
|
218
182
|
* @param {string} clientCertPem - PEM client certificate
|
|
183
|
+
* @param {string} [serverCaPem] - Dev root CA PEM
|
|
219
184
|
* @returns {Promise<Object[]>} Array of UserResponseDto (empty when none)
|
|
220
185
|
*/
|
|
221
|
-
async function listUsers(serverUrl, clientCertPem) {
|
|
186
|
+
async function listUsers(serverUrl, clientCertPem, serverCaPem) {
|
|
222
187
|
const base = normalizeBaseUrl(serverUrl);
|
|
223
188
|
const data = await request(buildUrl(base, '/api/dev/users'), {
|
|
224
189
|
method: 'GET',
|
|
225
|
-
headers: { 'X-Client-Cert': encodeCertForHeader(clientCertPem) }
|
|
190
|
+
headers: { 'X-Client-Cert': encodeCertForHeader(clientCertPem) },
|
|
191
|
+
serverCaPem
|
|
226
192
|
});
|
|
227
193
|
return Array.isArray(data) ? data : [];
|
|
228
194
|
}
|
|
@@ -232,15 +198,17 @@ async function listUsers(serverUrl, clientCertPem) {
|
|
|
232
198
|
* @requiresPermission {BuilderServer} Client certificate (X-Client-Cert)
|
|
233
199
|
* @param {string} serverUrl - Builder Server base URL
|
|
234
200
|
* @param {string} clientCertPem - PEM client certificate
|
|
235
|
-
* @param {Object} body - CreateUserDto: developerId, name, email, optional groups
|
|
201
|
+
* @param {Object} body - CreateUserDto: developerId, name, email, optional groups (admin | secret-manager | developer | docker)
|
|
202
|
+
* @param {string} [serverCaPem] - Dev root CA PEM
|
|
236
203
|
* @returns {Promise<Object>} UserResponseDto
|
|
237
204
|
*/
|
|
238
|
-
async function createUser(serverUrl, clientCertPem, body) {
|
|
205
|
+
async function createUser(serverUrl, clientCertPem, body, serverCaPem) {
|
|
239
206
|
const base = normalizeBaseUrl(serverUrl);
|
|
240
207
|
return request(buildUrl(base, '/api/dev/users'), {
|
|
241
208
|
method: 'POST',
|
|
242
209
|
headers: { 'X-Client-Cert': encodeCertForHeader(clientCertPem) },
|
|
243
|
-
body
|
|
210
|
+
body,
|
|
211
|
+
serverCaPem
|
|
244
212
|
});
|
|
245
213
|
}
|
|
246
214
|
|
|
@@ -250,15 +218,17 @@ async function createUser(serverUrl, clientCertPem, body) {
|
|
|
250
218
|
* @param {string} serverUrl - Builder Server base URL
|
|
251
219
|
* @param {string} clientCertPem - PEM client certificate
|
|
252
220
|
* @param {string} id - Developer ID
|
|
253
|
-
* @param {Object} body - UpdateUserDto: at least one of name, email, groups
|
|
221
|
+
* @param {Object} body - UpdateUserDto: at least one of name, email, groups (same group tokens as create)
|
|
222
|
+
* @param {string} [serverCaPem] - Dev root CA PEM
|
|
254
223
|
* @returns {Promise<Object>} UserResponseDto
|
|
255
224
|
*/
|
|
256
|
-
async function updateUser(serverUrl, clientCertPem, id, body) {
|
|
225
|
+
async function updateUser(serverUrl, clientCertPem, id, body, serverCaPem) {
|
|
257
226
|
const base = normalizeBaseUrl(serverUrl);
|
|
258
227
|
return request(buildUrl(base, `/api/dev/users/${encodeURIComponent(id)}`), {
|
|
259
228
|
method: 'PATCH',
|
|
260
229
|
headers: { 'X-Client-Cert': encodeCertForHeader(clientCertPem) },
|
|
261
|
-
body
|
|
230
|
+
body,
|
|
231
|
+
serverCaPem
|
|
262
232
|
});
|
|
263
233
|
}
|
|
264
234
|
|
|
@@ -268,13 +238,15 @@ async function updateUser(serverUrl, clientCertPem, id, body) {
|
|
|
268
238
|
* @param {string} serverUrl - Builder Server base URL
|
|
269
239
|
* @param {string} clientCertPem - PEM client certificate
|
|
270
240
|
* @param {string} id - Developer ID
|
|
241
|
+
* @param {string} [serverCaPem] - Dev root CA PEM
|
|
271
242
|
* @returns {Promise<Object>} DeletedResponseDto
|
|
272
243
|
*/
|
|
273
|
-
async function deleteUser(serverUrl, clientCertPem, id) {
|
|
244
|
+
async function deleteUser(serverUrl, clientCertPem, id, serverCaPem) {
|
|
274
245
|
const base = normalizeBaseUrl(serverUrl);
|
|
275
246
|
return request(buildUrl(base, `/api/dev/users/${encodeURIComponent(id)}`), {
|
|
276
247
|
method: 'DELETE',
|
|
277
|
-
headers: { 'X-Client-Cert': encodeCertForHeader(clientCertPem) }
|
|
248
|
+
headers: { 'X-Client-Cert': encodeCertForHeader(clientCertPem) },
|
|
249
|
+
serverCaPem
|
|
278
250
|
});
|
|
279
251
|
}
|
|
280
252
|
|
|
@@ -284,13 +256,15 @@ async function deleteUser(serverUrl, clientCertPem, id) {
|
|
|
284
256
|
* @param {string} serverUrl - Builder Server base URL
|
|
285
257
|
* @param {string} clientCertPem - PEM client certificate
|
|
286
258
|
* @param {string} id - Developer ID
|
|
259
|
+
* @param {string} [serverCaPem] - Dev root CA PEM
|
|
287
260
|
* @returns {Promise<Object>} CreatePinResponseDto: pin, expiresAt
|
|
288
261
|
*/
|
|
289
|
-
async function createPin(serverUrl, clientCertPem, id) {
|
|
262
|
+
async function createPin(serverUrl, clientCertPem, id, serverCaPem) {
|
|
290
263
|
const base = normalizeBaseUrl(serverUrl);
|
|
291
264
|
return request(buildUrl(base, `/api/dev/users/${encodeURIComponent(id)}/pin`), {
|
|
292
265
|
method: 'POST',
|
|
293
|
-
headers: { 'X-Client-Cert': encodeCertForHeader(clientCertPem) }
|
|
266
|
+
headers: { 'X-Client-Cert': encodeCertForHeader(clientCertPem) },
|
|
267
|
+
serverCaPem
|
|
294
268
|
});
|
|
295
269
|
}
|
|
296
270
|
|
|
@@ -300,29 +274,32 @@ async function createPin(serverUrl, clientCertPem, id) {
|
|
|
300
274
|
* @param {string} serverUrl - Builder Server base URL
|
|
301
275
|
* @param {string} clientCertPem - PEM client certificate
|
|
302
276
|
* @param {string} id - Developer ID
|
|
277
|
+
* @param {string} [serverCaPem] - Dev root CA PEM
|
|
303
278
|
* @returns {Promise<Object[]>} Array of SshKeyItemDto
|
|
304
279
|
*/
|
|
305
|
-
async function listSshKeys(serverUrl, clientCertPem, id) {
|
|
280
|
+
async function listSshKeys(serverUrl, clientCertPem, id, serverCaPem) {
|
|
306
281
|
const base = normalizeBaseUrl(serverUrl);
|
|
307
282
|
const data = await request(buildUrl(base, `/api/dev/users/${encodeURIComponent(id)}/ssh-keys`), {
|
|
308
283
|
method: 'GET',
|
|
309
|
-
headers: { 'X-Client-Cert': encodeCertForHeader(clientCertPem) }
|
|
284
|
+
headers: { 'X-Client-Cert': encodeCertForHeader(clientCertPem) },
|
|
285
|
+
serverCaPem
|
|
310
286
|
});
|
|
311
287
|
return Array.isArray(data) ? data : [];
|
|
312
288
|
}
|
|
313
289
|
|
|
314
290
|
/**
|
|
315
291
|
* Add SSH public key for developer. POST /api/dev/users/:id/ssh-keys
|
|
316
|
-
* When clientKeyPem is provided, uses mTLS
|
|
292
|
+
* When clientKeyPem is provided and server URL is https, uses mTLS; otherwise X-Client-Cert header only.
|
|
317
293
|
* @requiresPermission {BuilderServer} Client certificate (X-Client-Cert or mTLS)
|
|
318
294
|
* @param {string} serverUrl - Builder Server base URL
|
|
319
295
|
* @param {string} clientCertPem - PEM client certificate
|
|
320
296
|
* @param {string} id - Developer ID
|
|
321
297
|
* @param {Object} body - AddSshKeyDto: publicKey, optional label
|
|
322
298
|
* @param {string} [clientKeyPem] - PEM-encoded client private key (enables mTLS when provided)
|
|
299
|
+
* @param {string} [serverCaPem] - Dev root CA PEM
|
|
323
300
|
* @returns {Promise<Object>} SshKeyItemDto
|
|
324
301
|
*/
|
|
325
|
-
async function addSshKey(serverUrl, clientCertPem, id, body, clientKeyPem) {
|
|
302
|
+
async function addSshKey(serverUrl, clientCertPem, id, body, clientKeyPem, serverCaPem) {
|
|
326
303
|
const base = normalizeBaseUrl(serverUrl);
|
|
327
304
|
const url = buildUrl(base, `/api/dev/users/${encodeURIComponent(id)}/ssh-keys`);
|
|
328
305
|
const reqOptions = {
|
|
@@ -330,10 +307,10 @@ async function addSshKey(serverUrl, clientCertPem, id, body, clientKeyPem) {
|
|
|
330
307
|
headers: { 'X-Client-Cert': encodeCertForHeader(clientCertPem) },
|
|
331
308
|
body
|
|
332
309
|
};
|
|
333
|
-
if (
|
|
334
|
-
return
|
|
310
|
+
if (shouldUseMtlsForUrl(url, clientKeyPem)) {
|
|
311
|
+
return requestWithClientCert(url, reqOptions, clientCertPem, clientKeyPem, serverCaPem);
|
|
335
312
|
}
|
|
336
|
-
return request(url, reqOptions);
|
|
313
|
+
return request(url, { ...reqOptions, serverCaPem });
|
|
337
314
|
}
|
|
338
315
|
|
|
339
316
|
/**
|
|
@@ -343,62 +320,73 @@ async function addSshKey(serverUrl, clientCertPem, id, body, clientKeyPem) {
|
|
|
343
320
|
* @param {string} clientCertPem - PEM client certificate
|
|
344
321
|
* @param {string} id - Developer ID
|
|
345
322
|
* @param {string} fingerprint - Key fingerprint
|
|
323
|
+
* @param {string} [serverCaPem] - Dev root CA PEM
|
|
346
324
|
* @returns {Promise<Object>} DeletedResponseDto
|
|
347
325
|
*/
|
|
348
|
-
async function removeSshKey(serverUrl, clientCertPem, id, fingerprint) {
|
|
326
|
+
async function removeSshKey(serverUrl, clientCertPem, id, fingerprint, serverCaPem) {
|
|
349
327
|
const base = normalizeBaseUrl(serverUrl);
|
|
350
328
|
return request(buildUrl(base, `/api/dev/users/${encodeURIComponent(id)}/ssh-keys/${encodeURIComponent(fingerprint)}`), {
|
|
351
329
|
method: 'DELETE',
|
|
352
|
-
headers: { 'X-Client-Cert': encodeCertForHeader(clientCertPem) }
|
|
330
|
+
headers: { 'X-Client-Cert': encodeCertForHeader(clientCertPem) },
|
|
331
|
+
serverCaPem
|
|
353
332
|
});
|
|
354
333
|
}
|
|
355
334
|
|
|
356
335
|
/**
|
|
357
|
-
* List secrets. GET /api/dev/secrets
|
|
336
|
+
* List secrets. GET shared-secrets endpoint (default {serverUrl}/api/dev/secrets, or secretsEndpointUrl from config).
|
|
358
337
|
* @requiresPermission {BuilderServer} Client certificate (X-Client-Cert)
|
|
359
338
|
* @param {string} serverUrl - Builder Server base URL
|
|
360
339
|
* @param {string} clientCertPem - PEM client certificate
|
|
340
|
+
* @param {string} [serverCaPem] - Dev root CA PEM
|
|
341
|
+
* @param {string} [secretsEndpointUrl] - Optional full or base secrets URL (aifabrix-secrets when https)
|
|
361
342
|
* @returns {Promise<Object[]>} Array of SecretItemDto: name, value
|
|
362
343
|
*/
|
|
363
|
-
async function listSecrets(serverUrl, clientCertPem) {
|
|
364
|
-
const
|
|
365
|
-
const data = await request(
|
|
344
|
+
async function listSecrets(serverUrl, clientCertPem, serverCaPem, secretsEndpointUrl) {
|
|
345
|
+
const endpoint = resolveSecretsEndpoint(serverUrl, secretsEndpointUrl);
|
|
346
|
+
const data = await request(endpoint, {
|
|
366
347
|
method: 'GET',
|
|
367
|
-
headers: { 'X-Client-Cert': encodeCertForHeader(clientCertPem) }
|
|
348
|
+
headers: { 'X-Client-Cert': encodeCertForHeader(clientCertPem) },
|
|
349
|
+
serverCaPem
|
|
368
350
|
});
|
|
369
351
|
return Array.isArray(data) ? data : [];
|
|
370
352
|
}
|
|
371
353
|
|
|
372
354
|
/**
|
|
373
|
-
* Add or update secret. POST
|
|
355
|
+
* Add or update secret. POST shared-secrets endpoint.
|
|
374
356
|
* @requiresPermission {BuilderServer} Client certificate (X-Client-Cert)
|
|
375
357
|
* @param {string} serverUrl - Builder Server base URL
|
|
376
358
|
* @param {string} clientCertPem - PEM client certificate
|
|
377
359
|
* @param {Object} body - AddSecretDto: key, value
|
|
360
|
+
* @param {string} [serverCaPem] - Dev root CA PEM
|
|
361
|
+
* @param {string} [secretsEndpointUrl] - Optional secrets URL from config (aifabrix-secrets when https)
|
|
378
362
|
* @returns {Promise<Object>} AddSecretResponseDto
|
|
379
363
|
*/
|
|
380
|
-
async function addSecret(serverUrl, clientCertPem, body) {
|
|
381
|
-
const
|
|
382
|
-
return request(
|
|
364
|
+
async function addSecret(serverUrl, clientCertPem, body, serverCaPem, secretsEndpointUrl) {
|
|
365
|
+
const endpoint = resolveSecretsEndpoint(serverUrl, secretsEndpointUrl);
|
|
366
|
+
return request(endpoint, {
|
|
383
367
|
method: 'POST',
|
|
384
368
|
headers: { 'X-Client-Cert': encodeCertForHeader(clientCertPem) },
|
|
385
|
-
body
|
|
369
|
+
body,
|
|
370
|
+
serverCaPem
|
|
386
371
|
});
|
|
387
372
|
}
|
|
388
373
|
|
|
389
374
|
/**
|
|
390
|
-
* Delete secret by key. DELETE
|
|
375
|
+
* Delete secret by key. DELETE {endpoint}/:key
|
|
391
376
|
* @requiresPermission {BuilderServer} Client certificate (X-Client-Cert)
|
|
392
377
|
* @param {string} serverUrl - Builder Server base URL
|
|
393
378
|
* @param {string} clientCertPem - PEM client certificate
|
|
394
379
|
* @param {string} key - Secret key
|
|
380
|
+
* @param {string} [serverCaPem] - Dev root CA PEM
|
|
381
|
+
* @param {string} [secretsEndpointUrl] - Optional secrets URL from config (aifabrix-secrets when https)
|
|
395
382
|
* @returns {Promise<Object>} DeleteSecretResponseDto
|
|
396
383
|
*/
|
|
397
|
-
async function deleteSecret(serverUrl, clientCertPem, key) {
|
|
398
|
-
const
|
|
399
|
-
return request(buildUrl(
|
|
384
|
+
async function deleteSecret(serverUrl, clientCertPem, key, serverCaPem, secretsEndpointUrl) {
|
|
385
|
+
const endpoint = resolveSecretsEndpoint(serverUrl, secretsEndpointUrl);
|
|
386
|
+
return request(buildUrl(endpoint, `/${encodeURIComponent(key)}`), {
|
|
400
387
|
method: 'DELETE',
|
|
401
|
-
headers: { 'X-Client-Cert': encodeCertForHeader(clientCertPem) }
|
|
388
|
+
headers: { 'X-Client-Cert': encodeCertForHeader(clientCertPem) },
|
|
389
|
+
serverCaPem
|
|
402
390
|
});
|
|
403
391
|
}
|
|
404
392
|
|
|
@@ -419,5 +407,6 @@ module.exports = {
|
|
|
419
407
|
deleteSecret,
|
|
420
408
|
normalizeBaseUrl,
|
|
421
409
|
buildUrl,
|
|
422
|
-
encodeCertForHeader
|
|
410
|
+
encodeCertForHeader,
|
|
411
|
+
resolveSecretsEndpoint
|
|
423
412
|
};
|
package/lib/api/index.js
CHANGED
package/lib/api/pipeline.api.js
CHANGED
|
@@ -5,6 +5,33 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
const { ApiClient } = require('./index');
|
|
8
|
+
const { postValidationRunAndOptionalPoll } = require('./validation-runner');
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @param {Object} opts
|
|
12
|
+
* @param {'externalSystem'|'externalDataSource'} opts.validationScope
|
|
13
|
+
* @param {string} opts.systemKey
|
|
14
|
+
* @param {string} [opts.datasourceKey]
|
|
15
|
+
* @param {Object} [opts.testData]
|
|
16
|
+
* @returns {Object}
|
|
17
|
+
*/
|
|
18
|
+
function buildValidationRunPayloadTestBody({ validationScope, systemKey, datasourceKey, testData = {} }) {
|
|
19
|
+
const body = {
|
|
20
|
+
validationScope,
|
|
21
|
+
runType: 'test',
|
|
22
|
+
systemIdOrKey: systemKey
|
|
23
|
+
};
|
|
24
|
+
if (testData.payloadTemplate !== undefined && testData.payloadTemplate !== null) {
|
|
25
|
+
body.payloadTemplate = testData.payloadTemplate;
|
|
26
|
+
}
|
|
27
|
+
if (testData.includeDebug === true) {
|
|
28
|
+
body.includeDebug = true;
|
|
29
|
+
}
|
|
30
|
+
if (validationScope === 'externalDataSource') {
|
|
31
|
+
body.datasourceKey = datasourceKey;
|
|
32
|
+
}
|
|
33
|
+
return body;
|
|
34
|
+
}
|
|
8
35
|
|
|
9
36
|
/**
|
|
10
37
|
* Validate deployment configuration
|
|
@@ -127,8 +154,10 @@ async function validatePipelineConfig(dataplaneUrl, authConfig, { config }) {
|
|
|
127
154
|
}
|
|
128
155
|
|
|
129
156
|
/**
|
|
130
|
-
* Test external system (all datasources) via
|
|
131
|
-
* POST /api/v1/
|
|
157
|
+
* Test external system (all datasources) via unified validation API
|
|
158
|
+
* POST /api/v1/validation/run (validationScope=externalSystem, runType=test).
|
|
159
|
+
* Omits **payloadTemplate** unless `testData.payloadTemplate` is set so the dataplane runs the
|
|
160
|
+
* validation-engine path (not payload-template-only). Pass `payloadTemplate` explicitly for template tests.
|
|
132
161
|
* @requiresPermission {Dataplane} external-system:publish. Auth: Bearer or x-client-token only.
|
|
133
162
|
* @async
|
|
134
163
|
* @function testSystemViaPipeline
|
|
@@ -144,17 +173,27 @@ async function validatePipelineConfig(dataplaneUrl, authConfig, { config }) {
|
|
|
144
173
|
* @throws {Error} If test fails
|
|
145
174
|
*/
|
|
146
175
|
async function testSystemViaPipeline(dataplaneUrl, systemKey, authConfig, testData = {}, options = {}) {
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
}
|
|
152
|
-
|
|
176
|
+
const body = buildValidationRunPayloadTestBody({
|
|
177
|
+
validationScope: 'externalSystem',
|
|
178
|
+
systemKey,
|
|
179
|
+
testData
|
|
180
|
+
});
|
|
181
|
+
const timeoutMs = Number.isFinite(options.timeout) ? options.timeout : 30000;
|
|
182
|
+
const res = await postValidationRunAndOptionalPoll({
|
|
183
|
+
dataplaneUrl,
|
|
184
|
+
authConfig,
|
|
185
|
+
body,
|
|
186
|
+
timeoutMs,
|
|
187
|
+
useAsync: true,
|
|
188
|
+
noAsync: false
|
|
189
|
+
});
|
|
190
|
+
if (res.apiError) return res.apiError;
|
|
191
|
+
return { success: true, data: res.envelope, status: 200 };
|
|
153
192
|
}
|
|
154
193
|
|
|
155
194
|
/**
|
|
156
|
-
* Test datasource via
|
|
157
|
-
* POST /api/v1/
|
|
195
|
+
* Test datasource via unified validation API
|
|
196
|
+
* POST /api/v1/validation/run (validationScope=externalDataSource, datasourceKeys, payloadTemplate)
|
|
158
197
|
* Supports client credentials for CI/CD.
|
|
159
198
|
* @requiresPermission {Dataplane} external-system:publish or external-data-source:read. Auth: Bearer or x-client-token only.
|
|
160
199
|
* @async
|
|
@@ -172,15 +211,23 @@ async function testSystemViaPipeline(dataplaneUrl, systemKey, authConfig, testDa
|
|
|
172
211
|
* @throws {Error} If test fails
|
|
173
212
|
*/
|
|
174
213
|
async function testDatasourceViaPipeline({ dataplaneUrl, systemKey, datasourceKey, authConfig, testData, options = {} }) {
|
|
175
|
-
const
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
214
|
+
const body = buildValidationRunPayloadTestBody({
|
|
215
|
+
validationScope: 'externalDataSource',
|
|
216
|
+
systemKey,
|
|
217
|
+
datasourceKey,
|
|
218
|
+
testData
|
|
219
|
+
});
|
|
220
|
+
const timeoutMs = Number.isFinite(options.timeout) ? options.timeout : 30000;
|
|
221
|
+
const res = await postValidationRunAndOptionalPoll({
|
|
222
|
+
dataplaneUrl,
|
|
223
|
+
authConfig,
|
|
224
|
+
body,
|
|
225
|
+
timeoutMs,
|
|
226
|
+
useAsync: true,
|
|
227
|
+
noAsync: false
|
|
228
|
+
});
|
|
229
|
+
if (res.apiError) return res.apiError;
|
|
230
|
+
return { success: true, data: res.envelope, status: 200 };
|
|
184
231
|
}
|
|
185
232
|
|
|
186
233
|
/**
|
|
@@ -195,7 +242,7 @@ async function testDatasourceViaPipeline({ dataplaneUrl, systemKey, datasourceKe
|
|
|
195
242
|
* @param {Object} authConfig - Authentication configuration (must include token for Bearer; client id/secret rejected)
|
|
196
243
|
* @param {Object} payload - { version, application, dataSources }; optional status (default "draft")
|
|
197
244
|
* @param {string} [payload.status="draft"] - "draft" or "published"; Builder uses "draft"
|
|
198
|
-
* @returns {Promise<Object>}
|
|
245
|
+
* @returns {Promise<Object>} API envelope `{ success, data }` where `data` is PublicationResult (uploadId, system, datasources, generateMcpContract, …)
|
|
199
246
|
* @throws {Error} If upload fails
|
|
200
247
|
*/
|
|
201
248
|
async function uploadApplicationViaPipeline(dataplaneUrl, authConfig, payload) {
|
|
@@ -27,10 +27,11 @@
|
|
|
27
27
|
* @typedef {Object} SettingsResponseDto
|
|
28
28
|
* @property {string} user-mutagen-folder - Server path to workspace root (no app segment)
|
|
29
29
|
* @property {string} secrets-encryption - Encryption key (hex)
|
|
30
|
-
* @property {string} aifabrix-secrets -
|
|
30
|
+
* @property {string} aifabrix-secrets - Local filesystem path or https URL for shared secrets (file vs remote API)
|
|
31
31
|
* @property {string} aifabrix-env-config - Env config path
|
|
32
32
|
* @property {string} remote-server - Builder-server base URL
|
|
33
33
|
* @property {string} docker-endpoint - Docker API endpoint
|
|
34
|
+
* @property {boolean} [docker-tls-skip-verify] - When true and ca.pem is absent, Docker uses DOCKER_TLS_VERIFY=0; if ca.pem exists, daemon is always verified
|
|
34
35
|
* @property {string} sync-ssh-user - SSH user for Mutagen
|
|
35
36
|
* @property {string} sync-ssh-host - SSH host for Mutagen
|
|
36
37
|
*/
|
|
@@ -44,7 +45,7 @@
|
|
|
44
45
|
* @property {string} createdAt - ISO 8601
|
|
45
46
|
* @property {boolean} certificateIssued - Whether cert was issued
|
|
46
47
|
* @property {string} [certificateValidNotAfter] - Cert validity end (optional)
|
|
47
|
-
* @property {string[]} groups - Access groups (admin, secret-manager, developer)
|
|
48
|
+
* @property {string[]} groups - Access groups (admin, secret-manager, developer, docker)
|
|
48
49
|
*/
|
|
49
50
|
|
|
50
51
|
/**
|
|
@@ -53,7 +54,7 @@
|
|
|
53
54
|
* @property {string} developerId - Unique developer ID (numeric string)
|
|
54
55
|
* @property {string} name - Display name
|
|
55
56
|
* @property {string} email - Email
|
|
56
|
-
* @property {string[]} [groups] - Default [developer]
|
|
57
|
+
* @property {string[]} [groups] - Default [developer]; tokens: admin, secret-manager, developer, docker
|
|
57
58
|
*/
|
|
58
59
|
|
|
59
60
|
/**
|