@wirebench/engine 2.2.1 → 3.1.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 +134 -1
- package/dist/account/schema.d.ts +34 -0
- package/dist/account/schema.js +29 -0
- package/dist/assert/callback.d.ts +76 -0
- package/dist/assert/callback.js +320 -0
- package/dist/assert/capture-source.d.ts +50 -0
- package/dist/assert/capture-source.js +89 -0
- package/dist/assert/check.d.ts +8 -0
- package/dist/assert/check.js +18 -0
- package/dist/assert/header.d.ts +5 -0
- package/dist/assert/header.js +48 -0
- package/dist/assert/index.d.ts +2 -2
- package/dist/assert/index.js +12 -0
- package/dist/assert/match.d.ts +6 -0
- package/dist/assert/match.js +13 -4
- package/dist/assert/model.d.ts +110 -3
- package/dist/assert/model.js +16 -1
- package/dist/assert/schema.d.ts +194 -1
- package/dist/assert/schema.js +154 -12
- package/dist/assert/status-names.d.ts +9 -0
- package/dist/assert/status-names.js +27 -0
- package/dist/assert/status.d.ts +4 -1
- package/dist/assert/status.js +27 -3
- package/dist/asyncapi/browser.d.ts +7 -0
- package/dist/asyncapi/browser.js +6 -0
- package/dist/asyncapi/frame-check-worker-host.d.ts +44 -0
- package/dist/asyncapi/frame-check-worker-host.js +175 -0
- package/dist/asyncapi/frame-check-worker.d.ts +12 -0
- package/dist/asyncapi/frame-check-worker.js +25 -0
- package/dist/asyncapi/frame-check.d.ts +25 -0
- package/dist/asyncapi/frame-check.js +78 -0
- package/dist/asyncapi/import.d.ts +25 -0
- package/dist/asyncapi/import.js +34 -0
- package/dist/asyncapi/map.d.ts +40 -0
- package/dist/asyncapi/map.js +230 -0
- package/dist/asyncapi/model.d.ts +84 -0
- package/dist/asyncapi/model.js +7 -0
- package/dist/asyncapi/normalise-2.d.ts +13 -0
- package/dist/asyncapi/normalise-2.js +113 -0
- package/dist/asyncapi/normalise-3.d.ts +14 -0
- package/dist/asyncapi/normalise-3.js +133 -0
- package/dist/asyncapi/parse.d.ts +31 -0
- package/dist/asyncapi/parse.js +85 -0
- package/dist/asyncapi/read.d.ts +35 -0
- package/dist/asyncapi/read.js +186 -0
- package/dist/asyncapi/security.d.ts +14 -0
- package/dist/asyncapi/security.js +55 -0
- package/dist/asyncapi/update.d.ts +53 -0
- package/dist/asyncapi/update.js +220 -0
- package/dist/errors.d.ts +16 -0
- package/dist/errors.js +22 -0
- package/dist/grpc/events.d.ts +22 -0
- package/dist/grpc/events.js +1 -0
- package/dist/grpc/expand.d.ts +1 -1
- package/dist/grpc/expand.js +15 -5
- package/dist/grpc/files.d.ts +271 -0
- package/dist/grpc/files.js +62 -0
- package/dist/grpc/model.d.ts +11 -1
- package/dist/grpc/module.d.ts +2 -0
- package/dist/grpc/module.js +13 -0
- package/dist/grpc/run.d.ts +73 -0
- package/dist/grpc/run.js +407 -0
- package/dist/grpc/script-types.d.ts +8 -0
- package/dist/grpc/script-types.js +149 -0
- package/dist/grpc/scripting.d.ts +34 -0
- package/dist/grpc/scripting.js +147 -0
- package/dist/grpc/send-input.d.ts +46 -0
- package/dist/grpc/send-input.js +42 -0
- package/dist/grpc/send.d.ts +2 -2
- package/dist/grpc/status.d.ts +9 -2
- package/dist/grpc/status.js +11 -24
- package/dist/grpc/storage.d.ts +9 -0
- package/dist/grpc/storage.js +167 -0
- package/dist/{rest/auth.d.ts → http/auth/apply-auth.d.ts} +4 -4
- package/dist/{rest/auth.js → http/auth/apply-auth.js} +1 -1
- package/dist/http/auth/apply.d.ts +1 -1
- package/dist/{rest → http/auth}/oauth2.d.ts +2 -2
- package/dist/{rest → http/auth}/oauth2.js +1 -1
- package/dist/http/auth/send-auth.d.ts +57 -0
- package/dist/http/auth/send-auth.js +7 -0
- package/dist/http/client.js +150 -8
- package/dist/http/cookies.d.ts +79 -0
- package/dist/http/cookies.js +81 -0
- package/dist/http/curl.d.ts +4 -14
- package/dist/http/curl.js +4 -154
- package/dist/http/decompress.d.ts +7 -0
- package/dist/http/decompress.js +23 -1
- package/dist/http/document-fetch.d.ts +42 -0
- package/dist/http/document-fetch.js +207 -0
- package/dist/http/entries.d.ts +27 -0
- package/dist/http/entries.js +16 -0
- package/dist/http/escape.d.ts +18 -0
- package/dist/http/escape.js +30 -0
- package/dist/http/fetch-document.d.ts +28 -0
- package/dist/{wsdl/fetch.js → http/fetch-document.js} +8 -16
- package/dist/http/media-type.d.ts +9 -0
- package/dist/http/media-type.js +12 -0
- package/dist/http/transcript-cap.d.ts +26 -0
- package/dist/http/transcript-cap.js +36 -0
- package/dist/http/types.d.ts +59 -0
- package/dist/http/webhook-signature.d.ts +81 -0
- package/dist/http/webhook-signature.js +227 -0
- package/dist/import-detect.d.ts +2 -2
- package/dist/import-detect.js +10 -1
- package/dist/index.d.ts +207 -55
- package/dist/index.js +129 -32
- package/dist/json/cursor.d.ts +2 -0
- package/dist/json/cursor.js +1 -0
- package/dist/json/pointer-range.d.ts +18 -0
- package/dist/json/pointer-range.js +157 -0
- package/dist/json/schema/model.d.ts +59 -0
- package/dist/json/schema/model.js +8 -0
- package/dist/json/schema/parse-text.d.ts +16 -0
- package/dist/json/schema/parse-text.js +37 -0
- package/dist/{rest/openapi → json/schema}/refs.d.ts +2 -2
- package/dist/{rest/openapi → json/schema}/refs.js +3 -3
- package/dist/{rest/openapi → json/schema}/sample.d.ts +4 -0
- package/dist/{rest/openapi → json/schema}/sample.js +2 -2
- package/dist/json/schema/source.d.ts +21 -0
- package/dist/json/schema/source.js +8 -0
- package/dist/json/schema-validate.d.ts +49 -0
- package/dist/json/schema-validate.js +557 -0
- package/dist/{wss/keystore → keystore}/index.js +1 -1
- package/dist/{wss/keystore → keystore}/pem.js +1 -1
- package/dist/{wss/keystore → keystore}/pkcs12.js +1 -1
- package/dist/project/attachments-cache.d.ts +3 -1
- package/dist/{wsdl → project}/cache-naming.js +1 -1
- package/dist/project/endpoints.d.ts +18 -8
- package/dist/project/endpoints.js +21 -6
- package/dist/project/environments.d.ts +7 -5
- package/dist/project/history.d.ts +105 -9
- package/dist/project/history.js +195 -23
- package/dist/project/inherit.d.ts +7 -0
- package/dist/project/inherit.js +9 -0
- package/dist/project/keystores.d.ts +1 -1
- package/dist/project/load-helpers.d.ts +89 -0
- package/dist/project/load-helpers.js +177 -0
- package/dist/project/load.d.ts +30 -4
- package/dist/project/load.js +168 -545
- package/dist/project/managed-files.d.ts +36 -0
- package/dist/project/managed-files.js +97 -0
- package/dist/project/migrate.d.ts +2 -2
- package/dist/project/migrate.js +2 -2
- package/dist/project/model.d.ts +92 -14
- package/dist/project/model.js +50 -4
- package/dist/project/paths.d.ts +10 -1
- package/dist/project/paths.js +10 -1
- package/dist/project/preferences.d.ts +11 -2
- package/dist/project/preferences.js +5 -1
- package/dist/project/properties.d.ts +31 -17
- package/dist/project/properties.js +89 -70
- package/dist/project/request-location.d.ts +20 -0
- package/dist/project/request-location.js +62 -0
- package/dist/project/save.d.ts +12 -2
- package/dist/project/save.js +186 -141
- package/dist/project/schema-parts.d.ts +337 -0
- package/dist/project/schema-parts.js +248 -0
- package/dist/project/schema.d.ts +72 -928
- package/dist/project/schema.js +17 -466
- package/dist/project/sequence-guards.d.ts +43 -0
- package/dist/project/sequence-guards.js +109 -0
- package/dist/project/serialize-helpers.d.ts +60 -0
- package/dist/project/serialize-helpers.js +108 -0
- package/dist/project/serialize.d.ts +7 -8
- package/dist/project/serialize.js +34 -293
- package/dist/protocol/features.d.ts +51 -0
- package/dist/protocol/features.js +64 -0
- package/dist/protocol/index.d.ts +7 -0
- package/dist/protocol/index.js +4 -0
- package/dist/protocol/module.d.ts +247 -0
- package/dist/protocol/module.js +48 -0
- package/dist/protocol/registry.d.ts +42 -0
- package/dist/protocol/registry.js +47 -0
- package/dist/protocols.d.ts +77 -0
- package/dist/protocols.js +40 -0
- package/dist/redact/index.d.ts +12 -1
- package/dist/redact/index.js +55 -7
- package/dist/redact/literal.d.ts +10 -0
- package/dist/redact/literal.js +110 -12
- package/dist/rest/body.d.ts +2 -10
- package/dist/rest/body.js +3 -25
- package/dist/rest/browser.d.ts +4 -0
- package/dist/rest/browser.js +5 -0
- package/dist/rest/contract-check-worker-host.d.ts +36 -0
- package/dist/rest/contract-check-worker-host.js +158 -0
- package/dist/rest/contract-check-worker.d.ts +7 -0
- package/dist/rest/contract-check-worker.js +28 -0
- package/dist/rest/contract-check.d.ts +43 -0
- package/dist/rest/contract-check.js +217 -0
- package/dist/rest/cookie-jar.d.ts +62 -0
- package/dist/rest/cookie-jar.js +262 -0
- package/dist/rest/cookies.d.ts +6 -22
- package/dist/rest/cookies.js +6 -42
- package/dist/rest/curl.js +5 -1
- package/dist/rest/events.d.ts +12 -0
- package/dist/rest/events.js +1 -0
- package/dist/rest/expand.d.ts +6 -1
- package/dist/rest/expand.js +29 -11
- package/dist/rest/files.d.ts +439 -0
- package/dist/rest/files.js +107 -0
- package/dist/rest/json-form.d.ts +97 -0
- package/dist/rest/json-form.js +396 -0
- package/dist/rest/model.d.ts +35 -24
- package/dist/rest/model.js +6 -9
- package/dist/rest/module.d.ts +2 -0
- package/dist/rest/module.js +13 -0
- package/dist/rest/openapi/cache.d.ts +7 -2
- package/dist/rest/openapi/cache.js +2 -2
- package/dist/rest/openapi/import.d.ts +11 -16
- package/dist/rest/openapi/import.js +6 -2
- package/dist/rest/openapi/map.d.ts +38 -1
- package/dist/rest/openapi/map.js +151 -41
- package/dist/rest/openapi/match.d.ts +20 -0
- package/dist/rest/openapi/match.js +117 -0
- package/dist/rest/openapi/model.d.ts +33 -45
- package/dist/rest/openapi/parse.d.ts +3 -12
- package/dist/rest/openapi/parse.js +138 -67
- package/dist/rest/openapi/responses.d.ts +23 -0
- package/dist/rest/openapi/responses.js +59 -0
- package/dist/rest/openapi/runtime-expression.d.ts +69 -0
- package/dist/rest/openapi/runtime-expression.js +213 -0
- package/dist/rest/openapi/update.d.ts +116 -0
- package/dist/rest/openapi/update.js +456 -0
- package/dist/rest/postman/map.d.ts +1 -0
- package/dist/rest/postman/map.js +66 -4
- package/dist/rest/postman/model.d.ts +9 -0
- package/dist/rest/postman/parse.js +33 -10
- package/dist/rest/response.d.ts +2 -23
- package/dist/rest/response.js +3 -75
- package/dist/rest/run.d.ts +56 -0
- package/dist/rest/run.js +395 -0
- package/dist/rest/script-types.d.ts +7 -0
- package/dist/rest/script-types.js +83 -0
- package/dist/rest/scripting.d.ts +38 -0
- package/dist/rest/scripting.js +282 -0
- package/dist/rest/send-input.d.ts +54 -0
- package/dist/rest/send-input.js +73 -0
- package/dist/rest/send.d.ts +77 -4
- package/dist/rest/send.js +128 -7
- package/dist/rest/sse-transcript.d.ts +25 -0
- package/dist/rest/sse-transcript.js +95 -0
- package/dist/rest/sse.d.ts +43 -0
- package/dist/rest/sse.js +195 -0
- package/dist/rest/storage.d.ts +26 -0
- package/dist/rest/storage.js +262 -0
- package/dist/rest/url.d.ts +10 -4
- package/dist/rest/url.js +38 -5
- package/dist/run/baseline-update.d.ts +35 -0
- package/dist/run/baseline-update.js +97 -0
- package/dist/run/baseline.d.ts +42 -0
- package/dist/run/baseline.js +93 -0
- package/dist/run/context.d.ts +86 -0
- package/dist/run/context.js +31 -0
- package/dist/run/current-values.d.ts +32 -0
- package/dist/run/current-values.js +43 -0
- package/dist/run/event-queue.d.ts +14 -0
- package/dist/run/event-queue.js +46 -0
- package/dist/run/exchange.d.ts +62 -0
- package/dist/run/exchange.js +65 -0
- package/dist/run/host.d.ts +89 -0
- package/dist/run/host.js +1 -0
- package/dist/run/index.d.ts +20 -7
- package/dist/run/index.js +12 -4
- package/dist/run/oauth2-token.d.ts +42 -0
- package/dist/run/oauth2-token.js +92 -0
- package/dist/run/open.d.ts +12 -0
- package/dist/run/open.js +16 -0
- package/dist/run/run.d.ts +124 -4
- package/dist/run/run.js +293 -134
- package/dist/run/scope.d.ts +11 -0
- package/dist/run/scope.js +26 -0
- package/dist/run/script-support.d.ts +53 -0
- package/dist/run/script-support.js +68 -0
- package/dist/run/secret-needs.d.ts +11 -4
- package/dist/run/secret-needs.js +48 -96
- package/dist/run/select.d.ts +34 -25
- package/dist/run/select.js +45 -54
- package/dist/run/send-helpers.d.ts +93 -0
- package/dist/run/send-helpers.js +255 -0
- package/dist/run/tree.d.ts +50 -0
- package/dist/run/tree.js +54 -0
- package/dist/script/api/postman.d.ts +10 -0
- package/dist/script/api/postman.js +264 -0
- package/dist/script/api/prelude.d.ts +20 -0
- package/dist/script/api/prelude.js +215 -0
- package/dist/script/apply.d.ts +44 -0
- package/dist/script/apply.js +120 -0
- package/dist/script/check/host.d.ts +41 -0
- package/dist/script/check/host.js +143 -0
- package/dist/script/check/service.d.ts +52 -0
- package/dist/script/check/service.js +195 -0
- package/dist/script/check/worker.d.ts +1 -0
- package/dist/script/check/worker.js +40 -0
- package/dist/script/index.d.ts +16 -0
- package/dist/script/index.js +10 -0
- package/dist/script/lookup.d.ts +10 -0
- package/dist/script/lookup.js +23 -0
- package/dist/script/model.d.ts +82 -0
- package/dist/script/model.js +18 -0
- package/dist/script/props.d.ts +8 -0
- package/dist/script/props.js +28 -0
- package/dist/script/request-scripts.d.ts +83 -0
- package/dist/script/request-scripts.js +160 -0
- package/dist/script/run.d.ts +47 -0
- package/dist/script/run.js +146 -0
- package/dist/script/sandbox/execute.d.ts +26 -0
- package/dist/script/sandbox/execute.js +212 -0
- package/dist/script/sandbox/host-api.d.ts +27 -0
- package/dist/script/sandbox/host-api.js +101 -0
- package/dist/script/sandbox/host.d.ts +18 -0
- package/dist/script/sandbox/host.js +172 -0
- package/dist/script/sandbox/model.d.ts +69 -0
- package/dist/script/sandbox/model.js +24 -0
- package/dist/script/sandbox/worker.d.ts +1 -0
- package/dist/script/sandbox/worker.js +20 -0
- package/dist/script/send.d.ts +27 -0
- package/dist/script/send.js +76 -0
- package/dist/script/strip.d.ts +5 -0
- package/dist/script/strip.js +43 -0
- package/dist/script/types/api.d.ts +38 -0
- package/dist/script/types/api.js +113 -0
- package/dist/script/types/json-schema.d.ts +26 -0
- package/dist/script/types/json-schema.js +206 -0
- package/dist/secrets/env-names.d.ts +9 -1
- package/dist/secrets/env-names.js +17 -1
- package/dist/secrets/resolve.d.ts +44 -4
- package/dist/secrets/resolve.js +58 -1
- package/dist/secrets/scan/apply.d.ts +36 -0
- package/dist/secrets/scan/apply.js +194 -0
- package/dist/secrets/scan/rules.d.ts +32 -0
- package/dist/secrets/scan/rules.js +346 -0
- package/dist/secrets/scan/scan.d.ts +6 -0
- package/dist/secrets/scan/scan.js +57 -0
- package/dist/secrets/scan/walk.d.ts +70 -0
- package/dist/secrets/scan/walk.js +156 -0
- package/dist/secrets/secret-refs.d.ts +8 -0
- package/dist/secrets/secret-refs.js +25 -0
- package/dist/secrets/secret-token.d.ts +17 -0
- package/dist/secrets/secret-token.js +25 -0
- package/dist/sequence/file.d.ts +169 -0
- package/dist/sequence/file.js +237 -0
- package/dist/sequence/index.d.ts +7 -0
- package/dist/sequence/index.js +5 -0
- package/dist/sequence/load.d.ts +32 -0
- package/dist/sequence/load.js +56 -0
- package/dist/sequence/model.d.ts +115 -0
- package/dist/sequence/model.js +53 -0
- package/dist/sequence/run.d.ts +131 -0
- package/dist/sequence/run.js +191 -0
- package/dist/sequence/transfer.d.ts +24 -0
- package/dist/sequence/transfer.js +75 -0
- package/dist/server-api/audit.d.ts +455 -0
- package/dist/server-api/audit.js +186 -0
- package/dist/server-api/ci-tokens.d.ts +50 -0
- package/dist/server-api/ci-tokens.js +35 -0
- package/dist/server-api/hooks.d.ts +337 -0
- package/dist/server-api/hooks.js +152 -0
- package/dist/server-api/identity.d.ts +210 -0
- package/dist/server-api/identity.js +115 -0
- package/dist/server-api/licensing.d.ts +80 -0
- package/dist/server-api/licensing.js +53 -0
- package/dist/server-api/live.d.ts +132 -0
- package/dist/server-api/live.js +102 -0
- package/dist/server-api/meta.d.ts +31 -0
- package/dist/server-api/meta.js +21 -0
- package/dist/server-api/sync.d.ts +179 -0
- package/dist/server-api/sync.js +124 -0
- package/dist/server-api/teams.d.ts +306 -0
- package/dist/server-api/teams.js +113 -0
- package/dist/snapshot/diff.d.ts +30 -0
- package/dist/snapshot/diff.js +75 -0
- package/dist/snapshot/format.d.ts +17 -0
- package/dist/snapshot/format.js +40 -0
- package/dist/snapshot/golden-file.d.ts +45 -0
- package/dist/snapshot/golden-file.js +173 -0
- package/dist/snapshot/ignore.d.ts +14 -0
- package/dist/snapshot/ignore.js +79 -0
- package/dist/snapshot/index.d.ts +9 -0
- package/dist/snapshot/index.js +9 -0
- package/dist/snapshot/json-diff.d.ts +3 -0
- package/dist/snapshot/json-diff.js +93 -0
- package/dist/snapshot/xml-diff.d.ts +10 -0
- package/dist/snapshot/xml-diff.js +194 -0
- package/dist/soap/auth.d.ts +26 -0
- package/dist/soap/auth.js +54 -0
- package/dist/soap/curl.d.ts +20 -0
- package/dist/soap/curl.js +161 -0
- package/dist/soap/expand.d.ts +24 -0
- package/dist/soap/expand.js +95 -0
- package/dist/soap/files.d.ts +384 -0
- package/dist/soap/files.js +114 -0
- package/dist/soap/form-request.d.ts +13 -0
- package/dist/soap/form-request.js +2 -2
- package/dist/soap/generate.d.ts +12 -0
- package/dist/{generate.js → soap/generate.js} +4 -4
- package/dist/{import.d.ts → soap/import.d.ts} +4 -4
- package/dist/{import.js → soap/import.js} +13 -13
- package/dist/soap/json-operation.d.ts +35 -0
- package/dist/soap/json-operation.js +225 -0
- package/dist/soap/legacy-project/env-refs.d.ts +19 -0
- package/dist/soap/legacy-project/env-refs.js +105 -0
- package/dist/soap/legacy-project/map.d.ts +2 -2
- package/dist/soap/legacy-project/map.js +6 -0
- package/dist/soap/mime/multipart.d.ts +2 -2
- package/dist/soap/mime/multipart.js +2 -5
- package/dist/soap/mime/send-pipeline.d.ts +1 -1
- package/dist/soap/mime/send-pipeline.js +1 -1
- package/dist/soap/mime/types.d.ts +1 -3
- package/dist/soap/module.d.ts +2 -0
- package/dist/soap/module.js +13 -0
- package/dist/soap/namespace-scope.js +1 -1
- package/dist/soap/operations.d.ts +12 -0
- package/dist/{operations.js → soap/operations.js} +4 -4
- package/dist/soap/run.d.ts +70 -0
- package/dist/soap/run.js +549 -0
- package/dist/soap/script-types.d.ts +65 -0
- package/dist/soap/script-types.js +379 -0
- package/dist/soap/scripting.d.ts +45 -0
- package/dist/soap/scripting.js +221 -0
- package/dist/soap/send-input.d.ts +61 -0
- package/dist/{send-options.js → soap/send-input.js} +5 -109
- package/dist/{send.d.ts → soap/send.d.ts} +1 -1
- package/dist/{send.js → soap/send.js} +28 -12
- package/dist/soap/storage.d.ts +9 -0
- package/dist/soap/storage.js +237 -0
- package/dist/soap/transforms.d.ts +3 -12
- package/dist/soap/transforms.js +3 -14
- package/dist/{types.d.ts → soap/types.d.ts} +34 -84
- package/dist/sync/git-cli.d.ts +202 -0
- package/dist/sync/git-cli.js +684 -0
- package/dist/sync/three-way-merge.d.ts +41 -0
- package/dist/sync/three-way-merge.js +85 -0
- package/dist/sync/tree-paths.d.ts +34 -0
- package/dist/sync/tree-paths.js +131 -0
- package/dist/team-secrets/envelope.d.ts +10 -0
- package/dist/team-secrets/envelope.js +121 -0
- package/dist/team-secrets/errors.d.ts +26 -0
- package/dist/team-secrets/errors.js +27 -0
- package/dist/team-secrets/index.d.ts +14 -0
- package/dist/team-secrets/index.js +8 -0
- package/dist/team-secrets/keys.d.ts +52 -0
- package/dist/team-secrets/keys.js +158 -0
- package/dist/team-secrets/log.d.ts +48 -0
- package/dist/team-secrets/log.js +175 -0
- package/dist/team-secrets/resolve-conflict.d.ts +7 -0
- package/dist/team-secrets/resolve-conflict.js +14 -0
- package/dist/team-secrets/schema.d.ts +97 -0
- package/dist/team-secrets/schema.js +157 -0
- package/dist/team-secrets/sign.d.ts +24 -0
- package/dist/team-secrets/sign.js +71 -0
- package/dist/team-secrets/vault.d.ts +49 -0
- package/dist/team-secrets/vault.js +148 -0
- package/dist/validate/wsi/run-message.d.ts +2 -2
- package/dist/validate/wsi/run-message.js +1 -1
- package/dist/validate/wsi/run-wsdl.d.ts +2 -2
- package/dist/validate/wsi/run-wsdl.js +1 -1
- package/dist/validate/wsi/types.d.ts +1 -1
- package/dist/webhooks/model.d.ts +138 -0
- package/dist/webhooks/model.js +150 -0
- package/dist/workspace/commit-message.d.ts +1 -1
- package/dist/workspace/commit-message.js +6 -1
- package/dist/workspace/environments.d.ts +11 -4
- package/dist/workspace/environments.js +12 -0
- package/dist/workspace/index.d.ts +3 -3
- package/dist/workspace/index.js +2 -2
- package/dist/workspace/paths.d.ts +5 -2
- package/dist/workspace/paths.js +5 -2
- package/dist/workspace/schema.d.ts +7 -3
- package/dist/workspace/schema.js +24 -3
- package/dist/workspace/share.d.ts +30 -11
- package/dist/workspace/share.js +32 -6
- package/dist/ws/call.d.ts +1 -1
- package/dist/ws/call.js +2 -2
- package/dist/ws/connect.d.ts +60 -0
- package/dist/ws/connect.js +131 -0
- package/dist/ws/events.d.ts +17 -0
- package/dist/ws/events.js +1 -0
- package/dist/ws/expand.d.ts +1 -1
- package/dist/ws/expand.js +1 -1
- package/dist/ws/files.d.ts +284 -0
- package/dist/ws/files.js +71 -0
- package/dist/ws/history-entry.d.ts +44 -0
- package/dist/ws/history-entry.js +93 -0
- package/dist/ws/model.d.ts +44 -3
- package/dist/ws/model.js +3 -0
- package/dist/ws/module.d.ts +2 -0
- package/dist/ws/module.js +11 -0
- package/dist/ws/run.d.ts +63 -0
- package/dist/ws/run.js +470 -0
- package/dist/ws/session.d.ts +18 -0
- package/dist/ws/session.js +52 -25
- package/dist/ws/storage.d.ts +9 -0
- package/dist/ws/storage.js +176 -0
- package/dist/ws/transcript.d.ts +3 -4
- package/dist/ws/transcript.js +26 -17
- package/dist/ws/url.d.ts +1 -1
- package/dist/wsdl/cache.js +1 -1
- package/dist/wsdl/docs-generator.d.ts +3 -3
- package/dist/wsdl/docs-generator.js +1 -1
- package/dist/wsdl/export-definition.js +1 -1
- package/dist/wsdl/qname.d.ts +2 -5
- package/dist/wsdl/resolver.d.ts +4 -11
- package/dist/wsdl/resolver.js +3 -3
- package/dist/wsdl/update-definition.d.ts +5 -5
- package/dist/wsdl/update-definition.js +6 -6
- package/dist/wss/apply.js +1 -1
- package/dist/{project/wss-configs.d.ts → wss/configs.d.ts} +2 -2
- package/dist/{project/wss-configs.js → wss/configs.js} +2 -2
- package/dist/wss/incoming/decrypt.d.ts +1 -1
- package/dist/wss/incoming/index.js +1 -1
- package/dist/wss/incoming/verify.d.ts +1 -1
- package/dist/wss/incoming/verify.js +1 -1
- package/dist/wss/key-identifiers.js +1 -1
- package/dist/wss/model.d.ts +1 -1
- package/dist/wss/outgoing/encryption.d.ts +1 -1
- package/dist/wss/outgoing/signature.d.ts +1 -1
- package/dist/xml/decode.d.ts +15 -0
- package/dist/xml/decode.js +22 -0
- package/dist/xml/entitize.d.ts +17 -0
- package/dist/xml/entitize.js +19 -0
- package/dist/xml/index.d.ts +1 -1
- package/dist/xml/index.js +1 -1
- package/dist/xml/locate.d.ts +39 -0
- package/dist/xml/locate.js +117 -0
- package/dist/xml/qname.d.ts +12 -0
- package/dist/xml/qname.js +8 -0
- package/dist/xpath/evaluate-async.d.ts +19 -0
- package/dist/xpath/evaluate-async.js +31 -11
- package/dist/xpath/evaluate.d.ts +1 -1
- package/dist/xpath/namespaces.js +1 -1
- package/dist/xpath/worker.d.ts +11 -5
- package/dist/xpath/worker.js +24 -7
- package/dist/xsd/form-model.d.ts +19 -2
- package/dist/xsd/form-model.js +14 -2
- package/dist/xsd/json-bridge.d.ts +152 -0
- package/dist/xsd/json-bridge.js +1213 -0
- package/dist/xsd/locate.d.ts +2 -30
- package/dist/xsd/locate.js +1 -109
- package/dist/xsd/xml-scan.d.ts +2 -0
- package/dist/xsd/xml-scan.js +1 -1
- package/dist/xsd/xml-writer.d.ts +2 -0
- package/dist/xsd/xml-writer.js +4 -0
- package/package.json +12 -1
- package/dist/generate.d.ts +0 -12
- package/dist/operations.d.ts +0 -12
- package/dist/run/effective-auth.d.ts +0 -10
- package/dist/run/effective-auth.js +0 -19
- package/dist/run/prepare.d.ts +0 -43
- package/dist/run/prepare.js +0 -280
- package/dist/send-options.d.ts +0 -141
- package/dist/wsdl/fetch.d.ts +0 -13
- /package/dist/{soap → http}/charset.d.ts +0 -0
- /package/dist/{soap → http}/charset.js +0 -0
- /package/dist/{wsdl → http}/ref-policy.d.ts +0 -0
- /package/dist/{wsdl → http}/ref-policy.js +0 -0
- /package/dist/{wss/keystore → keystore}/certificate.d.ts +0 -0
- /package/dist/{wss/keystore → keystore}/certificate.js +0 -0
- /package/dist/{wss/keystore → keystore}/index.d.ts +0 -0
- /package/dist/{wss/keystore → keystore}/model.d.ts +0 -0
- /package/dist/{wss/keystore → keystore}/model.js +0 -0
- /package/dist/{wss/keystore → keystore}/pem.d.ts +0 -0
- /package/dist/{wss/keystore → keystore}/pkcs12.d.ts +0 -0
- /package/dist/{wsdl → project}/cache-naming.d.ts +0 -0
- /package/dist/{types.js → soap/types.js} +0 -0
- /package/dist/{soap → xml}/prefixes.d.ts +0 -0
- /package/dist/{soap → xml}/prefixes.js +0 -0
|
@@ -0,0 +1,684 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A small, Electron-free wrapper around the system `git` executable: discovery ({@link findGit}),
|
|
3
|
+
* a hardened {@link GitCli.run}, error mapping and remote URL validation ({@link assertRemoteUrl}).
|
|
4
|
+
*
|
|
5
|
+
* This file must never import `electron` — `SyncService` and Wirebench Server's commit store run it
|
|
6
|
+
* in plain Node, and `ipc/git.ts` is the only place that bridges it to Electron.
|
|
7
|
+
*
|
|
8
|
+
* Git is never bundled: it is found on the machine it runs on, or the user is asked to locate
|
|
9
|
+
* it (`git.locate`). Every invocation goes through {@link GitCli.run}, which never opens a
|
|
10
|
+
* shell, never prompts, never runs a hook, and refuses any subcommand outside
|
|
11
|
+
* {@link GIT_SUBCOMMANDS} before a process is even spawned. A `GitCli` the server builds with
|
|
12
|
+
* `{ plumbing: true }` also accepts {@link GIT_PLUMBING_SUBCOMMANDS}; the desktop never does.
|
|
13
|
+
*/
|
|
14
|
+
import { execFile } from 'node:child_process';
|
|
15
|
+
import { promisify } from 'node:util';
|
|
16
|
+
import { WirebenchError } from '../errors.js';
|
|
17
|
+
/**
|
|
18
|
+
* The only git subcommands `GitCli.run` will spawn. A `-`-prefixed first argument, or any
|
|
19
|
+
* subcommand not on this list, is refused before a process is spawned — see `run`.
|
|
20
|
+
*/
|
|
21
|
+
export const GIT_SUBCOMMANDS = [
|
|
22
|
+
'--version',
|
|
23
|
+
'init',
|
|
24
|
+
'clone',
|
|
25
|
+
'add',
|
|
26
|
+
'commit',
|
|
27
|
+
'fetch',
|
|
28
|
+
'merge',
|
|
29
|
+
'push',
|
|
30
|
+
'status',
|
|
31
|
+
'diff',
|
|
32
|
+
'show',
|
|
33
|
+
'rev-list',
|
|
34
|
+
'rev-parse',
|
|
35
|
+
'log',
|
|
36
|
+
'checkout',
|
|
37
|
+
'remote',
|
|
38
|
+
'config',
|
|
39
|
+
'symbolic-ref',
|
|
40
|
+
'var',
|
|
41
|
+
'rm',
|
|
42
|
+
];
|
|
43
|
+
/**
|
|
44
|
+
* Git plumbing, for Wirebench Server's commit store only (server-sync spec §3.3, R1): it builds
|
|
45
|
+
* commits in a bare repository, with no working tree. This is a second list rather than a longer
|
|
46
|
+
* {@link GIT_SUBCOMMANDS}, so the desktop's allow-list does not grow. Only a `GitCli` constructed
|
|
47
|
+
* with `{ plumbing: true }`, or returned by {@link GitCli.withPlumbing}, accepts these.
|
|
48
|
+
*/
|
|
49
|
+
export const GIT_PLUMBING_SUBCOMMANDS = [
|
|
50
|
+
'ls-tree',
|
|
51
|
+
'cat-file',
|
|
52
|
+
'merge-base',
|
|
53
|
+
'diff-tree',
|
|
54
|
+
'read-tree',
|
|
55
|
+
'hash-object',
|
|
56
|
+
'update-index',
|
|
57
|
+
'write-tree',
|
|
58
|
+
'commit-tree',
|
|
59
|
+
'update-ref',
|
|
60
|
+
];
|
|
61
|
+
/**
|
|
62
|
+
* The only variables a caller may set per call ({@link GitRunOptions.env}): the commit store's
|
|
63
|
+
* private index file, and the author and committer of the commit it writes. Anything else
|
|
64
|
+
* (`GIT_DIR`, `GIT_CONFIG_*`, `GIT_SSH_COMMAND`, `GIT_EXEC_PATH`, `PATH`) could point git somewhere
|
|
65
|
+
* else or make it run a program, so it is refused.
|
|
66
|
+
*/
|
|
67
|
+
export const GIT_CALL_ENV = [
|
|
68
|
+
'GIT_INDEX_FILE',
|
|
69
|
+
'GIT_AUTHOR_NAME',
|
|
70
|
+
'GIT_AUTHOR_EMAIL',
|
|
71
|
+
'GIT_AUTHOR_DATE',
|
|
72
|
+
'GIT_COMMITTER_NAME',
|
|
73
|
+
'GIT_COMMITTER_EMAIL',
|
|
74
|
+
'GIT_COMMITTER_DATE',
|
|
75
|
+
];
|
|
76
|
+
const execFileAsync = promisify(execFile);
|
|
77
|
+
/** Bytes above which `execFile`'s buffered stdout/stderr is truncated (16 MiB), unless a call says otherwise. */
|
|
78
|
+
const MAX_BUFFER = 16 * 1024 * 1024;
|
|
79
|
+
/** The code Node gives an `execFile` whose output passed `maxBuffer`; it has already killed git. */
|
|
80
|
+
const MAX_BUFFER_EXCEEDED = 'ERR_CHILD_PROCESS_STDIO_MAXBUFFER';
|
|
81
|
+
/** Output as text: a string as is, a Buffer decoded as UTF-8. */
|
|
82
|
+
function asText(output) {
|
|
83
|
+
return typeof output === 'string' ? output : output.toString('utf8');
|
|
84
|
+
}
|
|
85
|
+
/** Output as bytes: a Buffer as is, a string encoded as UTF-8 (a fake runner may answer with text). */
|
|
86
|
+
function asBuffer(output) {
|
|
87
|
+
return typeof output === 'string' ? Buffer.from(output, 'utf8') : output;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* The default {@link Runner}: `execFile`, resolving `{ exitCode }` instead of rejecting on it. It
|
|
91
|
+
* always reads raw bytes and decodes stdout itself when text was asked for. That way there is one
|
|
92
|
+
* spawn path, and a blob is never decoded before the caller sees it.
|
|
93
|
+
*/
|
|
94
|
+
const defaultRunner = async (file, args, options) => {
|
|
95
|
+
const pending = execFileAsync(file, args, {
|
|
96
|
+
cwd: options.cwd,
|
|
97
|
+
env: options.env,
|
|
98
|
+
timeout: options.timeoutMs,
|
|
99
|
+
windowsHide: true,
|
|
100
|
+
maxBuffer: options.maxBuffer,
|
|
101
|
+
encoding: 'buffer',
|
|
102
|
+
});
|
|
103
|
+
if (options.input !== undefined) {
|
|
104
|
+
const stdin = pending.child.stdin;
|
|
105
|
+
// git may exit before reading all its input (a bad argument or object id), and the exit code
|
|
106
|
+
// already says why. An EPIPE here must not become an unhandled 'error' event, which would bring
|
|
107
|
+
// down the process.
|
|
108
|
+
stdin?.on('error', () => undefined);
|
|
109
|
+
stdin?.end(options.input);
|
|
110
|
+
}
|
|
111
|
+
const output = (stdout) => options.encoding === 'buffer' ? stdout : stdout.toString('utf8');
|
|
112
|
+
try {
|
|
113
|
+
const { stdout, stderr } = await pending;
|
|
114
|
+
return { stdout: output(stdout), stderr: stderr.toString('utf8'), exitCode: 0 };
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
const nodeError = error;
|
|
118
|
+
// ENOENT/EACCES mean the executable could not be spawned at all — not "git ran and failed" —
|
|
119
|
+
// so this must still reject, per the contract above. So must a maxBuffer overflow: git was
|
|
120
|
+
// killed part-way, and its truncated output must not pass for an answer.
|
|
121
|
+
if (nodeError.code === 'ENOENT' || nodeError.code === 'EACCES' || nodeError.code === MAX_BUFFER_EXCEEDED) {
|
|
122
|
+
throw error;
|
|
123
|
+
}
|
|
124
|
+
if (nodeError.killed === true || (nodeError.signal !== null && nodeError.signal !== undefined)) {
|
|
125
|
+
// A timeout kill: `killed`/a real signal name. A normal non-zero exit sets `signal: null`
|
|
126
|
+
// (not `undefined`) and `killed: false` — checking `!== undefined` alone misclassified
|
|
127
|
+
// every ordinary failure as a timeout.
|
|
128
|
+
throw error;
|
|
129
|
+
}
|
|
130
|
+
const exitCode = typeof nodeError.code === 'number' ? nodeError.code : 1;
|
|
131
|
+
return {
|
|
132
|
+
stdout: output(nodeError.stdout ?? Buffer.alloc(0)),
|
|
133
|
+
stderr: nodeError.stderr?.toString('utf8') ?? '',
|
|
134
|
+
exitCode,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
/** Parses `git version 2.39.2 (Apple Git-143)` (or `... 2.42.0.windows.1`) → the version string. */
|
|
139
|
+
export function parseGitVersion(stdout) {
|
|
140
|
+
const match = /git version (\S+)/.exec(stdout);
|
|
141
|
+
return match?.[1];
|
|
142
|
+
}
|
|
143
|
+
/** Compares two dot-separated version strings numerically, ignoring trailing non-numeric parts. */
|
|
144
|
+
function compareVersions(a, b) {
|
|
145
|
+
const toParts = (version) => version
|
|
146
|
+
.split('.')
|
|
147
|
+
.map((part) => Number.parseInt(part, 10))
|
|
148
|
+
.map((n) => (Number.isNaN(n) ? 0 : n));
|
|
149
|
+
const partsA = toParts(a);
|
|
150
|
+
const partsB = toParts(b);
|
|
151
|
+
const length = Math.max(partsA.length, partsB.length);
|
|
152
|
+
for (let i = 0; i < length; i += 1) {
|
|
153
|
+
const diff = (partsA[i] ?? 0) - (partsB[i] ?? 0);
|
|
154
|
+
if (diff !== 0) {
|
|
155
|
+
return diff;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return 0;
|
|
159
|
+
}
|
|
160
|
+
/** The minimum git version `findGit` accepts; older candidates are skipped. */
|
|
161
|
+
const MINIMUM_VERSION = '2.20.0';
|
|
162
|
+
/** How long a discovery probe (`git --version`) may take before it is abandoned. */
|
|
163
|
+
const PROBE_TIMEOUT_MS = 5_000;
|
|
164
|
+
/** Platform-specific fallback locations, tried after `configuredPath` and the `PATH` entries. */
|
|
165
|
+
function platformDefaultCandidates(platform, env) {
|
|
166
|
+
if (platform === 'darwin') {
|
|
167
|
+
return ['/usr/bin/git', '/opt/homebrew/bin/git', '/usr/local/bin/git'];
|
|
168
|
+
}
|
|
169
|
+
if (platform === 'win32') {
|
|
170
|
+
const programFiles = env['ProgramFiles'];
|
|
171
|
+
const localAppData = env['LocalAppData'];
|
|
172
|
+
const candidates = [];
|
|
173
|
+
if (programFiles !== undefined) {
|
|
174
|
+
candidates.push(`${programFiles}\\Git\\cmd\\git.exe`);
|
|
175
|
+
}
|
|
176
|
+
if (localAppData !== undefined) {
|
|
177
|
+
candidates.push(`${localAppData}\\Programs\\Git\\cmd\\git.exe`);
|
|
178
|
+
}
|
|
179
|
+
return candidates;
|
|
180
|
+
}
|
|
181
|
+
return ['/usr/bin/git'];
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Splits `PATH` into per-entry git candidates for `platform` (`;` on win32, `:` elsewhere).
|
|
185
|
+
* Hard-coded rather than `node:path`'s own `delimiter`, which reflects the *host* OS this
|
|
186
|
+
* process runs on — not the `platform` a caller is asking `findGit` to probe for (a unit test
|
|
187
|
+
* on a Linux/macOS CI runner still exercises the win32 candidate list).
|
|
188
|
+
*/
|
|
189
|
+
function pathCandidates(platform, env) {
|
|
190
|
+
const raw = env['PATH'] ?? env['Path'] ?? '';
|
|
191
|
+
const delimiter = platform === 'win32' ? ';' : ':';
|
|
192
|
+
const entries = raw.split(delimiter).filter((entry) => entry.length > 0);
|
|
193
|
+
const exeName = platform === 'win32' ? 'git.exe' : 'git';
|
|
194
|
+
const join = platform === 'win32' ? '\\' : '/';
|
|
195
|
+
return entries.map((entry) => (entry.endsWith(join) ? `${entry}${exeName}` : `${entry}${join}${exeName}`));
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Finds a usable system git: the configured path first, then every `PATH` entry, then a
|
|
199
|
+
* platform default. The first candidate whose `--version` probe exits 0 with a parsable,
|
|
200
|
+
* sufficiently recent version wins; every other outcome (spawn failure, non-zero exit, unparsable
|
|
201
|
+
* output, too old) just skips to the next candidate.
|
|
202
|
+
*/
|
|
203
|
+
export async function findGit(options) {
|
|
204
|
+
const env = options.env ?? process.env;
|
|
205
|
+
const platform = options.platform ?? process.platform;
|
|
206
|
+
const run = options.run ?? defaultRunner;
|
|
207
|
+
const candidates = [
|
|
208
|
+
...(options.configuredPath !== undefined ? [options.configuredPath] : []),
|
|
209
|
+
...pathCandidates(platform, env),
|
|
210
|
+
...platformDefaultCandidates(platform, env),
|
|
211
|
+
];
|
|
212
|
+
for (const candidate of candidates) {
|
|
213
|
+
if (options.exists !== undefined && !options.exists(candidate)) {
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
let result;
|
|
217
|
+
try {
|
|
218
|
+
result = await run(candidate, ['--version'], {
|
|
219
|
+
env,
|
|
220
|
+
timeoutMs: PROBE_TIMEOUT_MS,
|
|
221
|
+
encoding: 'utf8',
|
|
222
|
+
maxBuffer: MAX_BUFFER,
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
catch {
|
|
226
|
+
// Could not spawn at all (ENOENT/EACCES, or a fake run() that throws) — not usable.
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
if (result.exitCode !== 0) {
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
const version = parseGitVersion(asText(result.stdout));
|
|
233
|
+
if (version === undefined) {
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
if (compareVersions(version, MINIMUM_VERSION) < 0) {
|
|
237
|
+
console.debug(`findGit: skipping "${candidate}" — version ${version} is below the minimum ${MINIMUM_VERSION}`);
|
|
238
|
+
continue;
|
|
239
|
+
}
|
|
240
|
+
return { path: candidate, version };
|
|
241
|
+
}
|
|
242
|
+
return undefined;
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* `user@host:path` remotes (the scp-like syntax `assertRemoteUrl` accepts alongside URL
|
|
246
|
+
* schemes), captured so the user/host parts can be checked for a leading `-` individually.
|
|
247
|
+
*/
|
|
248
|
+
const SCP_LIKE_REMOTE = /^([\w.-]+)@([\w.-]+):([^\s]+)$/;
|
|
249
|
+
/** A literal `scheme://` prefix — deliberately not matching a scheme-only form like `https:x`. */
|
|
250
|
+
const SCHEME_PREFIX = /^([a-zA-Z][a-zA-Z0-9+.-]*):\/\//;
|
|
251
|
+
/** Schemes `assertRemoteUrl` accepts (compared case-insensitively). */
|
|
252
|
+
const ALLOWED_SCHEMES = ['https:', 'ssh:', 'file:'];
|
|
253
|
+
/** Any whitespace or C0/DEL control character. */
|
|
254
|
+
const WHITESPACE_OR_CONTROL = /[\s\x00-\x1f\x7f]/;
|
|
255
|
+
/** The scheme (or `'scp-like'`/`'unknown'`) named in a refusal's `details`, never the URL itself. */
|
|
256
|
+
function schemeLabel(trimmed) {
|
|
257
|
+
if (SCP_LIKE_REMOTE.test(trimmed)) {
|
|
258
|
+
return 'scp-like';
|
|
259
|
+
}
|
|
260
|
+
const bareScheme = /^([a-zA-Z][a-zA-Z0-9+.-]*):/.exec(trimmed);
|
|
261
|
+
if (bareScheme === null) {
|
|
262
|
+
return 'unknown';
|
|
263
|
+
}
|
|
264
|
+
return bareScheme[1].toLowerCase();
|
|
265
|
+
}
|
|
266
|
+
/** Decodes a percent-encoded user/host component; `undefined` on a malformed `%` sequence. */
|
|
267
|
+
function safeDecode(component) {
|
|
268
|
+
try {
|
|
269
|
+
return decodeURIComponent(component);
|
|
270
|
+
}
|
|
271
|
+
catch {
|
|
272
|
+
return undefined;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Refuses anything that is not a literal `https://`, `ssh://` or `file://` URL (scheme
|
|
277
|
+
* case-insensitive) or a `user@host:path` remote, trims and returns the accepted value
|
|
278
|
+
* otherwise. In particular refuses: an empty string; whitespace or control characters anywhere
|
|
279
|
+
* in the trimmed value; a value starting with `-` (which `git` — or a shell a transport helper
|
|
280
|
+
* invokes — would parse as a flag); `ext::…` (git's "run an arbitrary command" transport); a
|
|
281
|
+
* scheme-only form with no `//` (`https:x`, `file:/etc/r`, `ssh:-oProxyCommand=…`); and —
|
|
282
|
+
* crucially — a *user or host* starting with `-` once fully parsed out of the authority
|
|
283
|
+
* (`user@host[:port]`, `[bracketed-IPv6-host]`, `%`-decoded) and off the scp-like form's
|
|
284
|
+
* `user@host:`, closing bypasses a leading-`-` check on the whole string alone would miss:
|
|
285
|
+
* `ssh://git@-oProxyCommand=x/y`, `ssh://[-oProxyCommand=x]/y`, `ssh://%2doProxyCommand=x/y`
|
|
286
|
+
* (git percent-decodes the host), `https://user@-host/y`. A malformed `%` sequence in the user
|
|
287
|
+
* or host is refused outright rather than passed through undecoded.
|
|
288
|
+
*
|
|
289
|
+
* The error `details` carry only the scheme (or `'scp-like'`) — never the URL, which may embed
|
|
290
|
+
* credentials — and the message stays generic for the same reason.
|
|
291
|
+
*/
|
|
292
|
+
export function assertRemoteUrl(url) {
|
|
293
|
+
const trimmed = url.trim();
|
|
294
|
+
const fail = () => {
|
|
295
|
+
throw new WirebenchError('git-remote-refused', 'This remote URL is not allowed: use https://, ssh://, file:// or user@host:path.', { details: { scheme: schemeLabel(trimmed) } });
|
|
296
|
+
};
|
|
297
|
+
if (trimmed.length === 0 || WHITESPACE_OR_CONTROL.test(trimmed) || trimmed.startsWith('-')) {
|
|
298
|
+
fail();
|
|
299
|
+
}
|
|
300
|
+
if (trimmed.toLowerCase().startsWith('ext::')) {
|
|
301
|
+
fail();
|
|
302
|
+
}
|
|
303
|
+
/** Refuses when `raw` (a user or host component, still percent-encoded) is disallowed. */
|
|
304
|
+
const checkComponent = (raw) => {
|
|
305
|
+
const decoded = safeDecode(raw);
|
|
306
|
+
if (decoded === undefined || decoded.startsWith('-') || WHITESPACE_OR_CONTROL.test(decoded)) {
|
|
307
|
+
fail();
|
|
308
|
+
}
|
|
309
|
+
};
|
|
310
|
+
const scpMatch = SCP_LIKE_REMOTE.exec(trimmed);
|
|
311
|
+
if (scpMatch !== null) {
|
|
312
|
+
const [, user, host] = scpMatch;
|
|
313
|
+
checkComponent(user);
|
|
314
|
+
checkComponent(host);
|
|
315
|
+
return trimmed;
|
|
316
|
+
}
|
|
317
|
+
const schemeMatch = SCHEME_PREFIX.exec(trimmed);
|
|
318
|
+
if (schemeMatch === null) {
|
|
319
|
+
// No literal `scheme://` — refuses `https:x`, `file:/etc/r`, `ssh:-oProxyCommand=…`, `x/y`.
|
|
320
|
+
fail();
|
|
321
|
+
}
|
|
322
|
+
const scheme = `${schemeMatch[1].toLowerCase()}:`;
|
|
323
|
+
if (!ALLOWED_SCHEMES.includes(scheme)) {
|
|
324
|
+
fail();
|
|
325
|
+
}
|
|
326
|
+
// The authority is everything after `scheme://` up to the first `/` (or the whole remainder
|
|
327
|
+
// when there is no path) — empty for `file:///path`, which stays accepted.
|
|
328
|
+
const afterScheme = trimmed.slice(schemeMatch[0].length);
|
|
329
|
+
const slashIndex = afterScheme.indexOf('/');
|
|
330
|
+
const authority = slashIndex === -1 ? afterScheme : afterScheme.slice(0, slashIndex);
|
|
331
|
+
if (authority.length > 0) {
|
|
332
|
+
const atIndex = authority.lastIndexOf('@');
|
|
333
|
+
const userinfo = atIndex === -1 ? undefined : authority.slice(0, atIndex);
|
|
334
|
+
const hostAndPort = atIndex === -1 ? authority : authority.slice(atIndex + 1);
|
|
335
|
+
let host;
|
|
336
|
+
if (hostAndPort.startsWith('[')) {
|
|
337
|
+
// A bracketed IPv6 host (`[::1]` or `[::1]:22`) — a `:port` outside the brackets, if any,
|
|
338
|
+
// is not itself a place a flag-like value could hide.
|
|
339
|
+
const closeBracket = hostAndPort.indexOf(']');
|
|
340
|
+
if (closeBracket === -1) {
|
|
341
|
+
fail();
|
|
342
|
+
}
|
|
343
|
+
host = hostAndPort.slice(1, closeBracket);
|
|
344
|
+
}
|
|
345
|
+
else {
|
|
346
|
+
const colonIndex = hostAndPort.indexOf(':');
|
|
347
|
+
host = colonIndex === -1 ? hostAndPort : hostAndPort.slice(0, colonIndex);
|
|
348
|
+
}
|
|
349
|
+
if (userinfo !== undefined) {
|
|
350
|
+
checkComponent(userinfo);
|
|
351
|
+
}
|
|
352
|
+
checkComponent(host);
|
|
353
|
+
}
|
|
354
|
+
return trimmed;
|
|
355
|
+
}
|
|
356
|
+
/** Any character `assertBranchName` refuses outright, wherever it appears in the name. */
|
|
357
|
+
const BRANCH_FORBIDDEN_CHARS = /[\s\x00-\x1f\x7f~^:?*[\\]/;
|
|
358
|
+
/**
|
|
359
|
+
* Refuses a branch name that could be read as a flag by `git` (a leading `-`) or that git itself
|
|
360
|
+
* would refuse as a ref name, and returns it otherwise. In particular refuses: empty; a leading
|
|
361
|
+
* `-`; whitespace or control characters; `~^:?*[` or a backslash anywhere; `..` or `@{` anywhere
|
|
362
|
+
* (git's own ref-name restrictions); a leading, trailing, or doubled `/`; a trailing `.lock` or
|
|
363
|
+
* `.`; any `/`-separated component starting with `.`; and the bare name `@`.
|
|
364
|
+
*
|
|
365
|
+
* Every `GitBackend` method that builds a git argument or ref expression from a (renderer-
|
|
366
|
+
* settable) branch name calls this first — see git-backend.ts.
|
|
367
|
+
*/
|
|
368
|
+
export function assertBranchName(name) {
|
|
369
|
+
const fail = () => {
|
|
370
|
+
throw new WirebenchError('git-branch-refused', 'This branch name is not allowed.', { details: {} });
|
|
371
|
+
};
|
|
372
|
+
if (name.length === 0 ||
|
|
373
|
+
name.startsWith('-') ||
|
|
374
|
+
BRANCH_FORBIDDEN_CHARS.test(name) ||
|
|
375
|
+
name.includes('..') ||
|
|
376
|
+
name.includes('@{') ||
|
|
377
|
+
name.startsWith('/') ||
|
|
378
|
+
name.endsWith('/') ||
|
|
379
|
+
name.includes('//') ||
|
|
380
|
+
name.endsWith('.lock') ||
|
|
381
|
+
name.endsWith('.') ||
|
|
382
|
+
name === '@' ||
|
|
383
|
+
name.split('/').some((part) => part.startsWith('.'))) {
|
|
384
|
+
fail();
|
|
385
|
+
}
|
|
386
|
+
return name;
|
|
387
|
+
}
|
|
388
|
+
/** Regexes classifying git's stderr for `run`'s error mapping. */
|
|
389
|
+
const AUTH_FAILED_PATTERN = /Authentication failed|could not read Username|Permission denied \(publickey|Host key verification failed|terminal prompts disabled|Invalid username or password/i;
|
|
390
|
+
const OFFLINE_PATTERN = /Could not resolve host|unable to access|Connection (refused|timed out)|Network is unreachable|Could not read from remote repository/i;
|
|
391
|
+
/** Bytes of stderr kept in error `details` (2 KiB from the end). */
|
|
392
|
+
const STDERR_DETAIL_BYTES = 2 * 1024;
|
|
393
|
+
/** Strips `user:token@` userinfo from any `https://`-style URL argument, for safe error details. */
|
|
394
|
+
function redactArg(arg) {
|
|
395
|
+
return arg.replace(/^(https?:\/\/)[^/@]+@/i, '$1');
|
|
396
|
+
}
|
|
397
|
+
/** Default timeout for a `GitCli.run` call, when the caller does not name one. */
|
|
398
|
+
const DEFAULT_TIMEOUT_MS = 60_000;
|
|
399
|
+
/** `ssh -o BatchMode=yes`, the default `GitCli` sets only when nothing else already names an SSH transport. */
|
|
400
|
+
const DEFAULT_GIT_SSH_COMMAND = 'ssh -o BatchMode=yes';
|
|
401
|
+
/**
|
|
402
|
+
* Runs the system git found by {@link findGit}, with every hardening constraint the plan
|
|
403
|
+
* requires: no shell, no prompt, no hooks, a fixed subcommand allow-list, and error `details`
|
|
404
|
+
* that never carry the environment or a credential-bearing URL.
|
|
405
|
+
*/
|
|
406
|
+
export class GitCli {
|
|
407
|
+
version;
|
|
408
|
+
path;
|
|
409
|
+
hooksDir;
|
|
410
|
+
runner;
|
|
411
|
+
extraEnv;
|
|
412
|
+
/** Whether {@link GIT_PLUMBING_SUBCOMMANDS} are allowed as well: only for the server's commit store. */
|
|
413
|
+
plumbing;
|
|
414
|
+
/**
|
|
415
|
+
* Memoised `git config --get core.sshCommand` lookups, one per distinct `cwd` a caller has
|
|
416
|
+
* `run()` with (the `cwd`-less key included) — a repository-local `core.sshCommand` only
|
|
417
|
+
* applies inside that repository, and a cwd-less run must never pick up a *different*
|
|
418
|
+
* repository's local config. `undefined` (the resolved value) covers "unset" too.
|
|
419
|
+
*/
|
|
420
|
+
sshCommandConfigByCwd = new Map();
|
|
421
|
+
constructor(location, options) {
|
|
422
|
+
this.path = location.path;
|
|
423
|
+
this.version = location.version;
|
|
424
|
+
this.hooksDir = options.hooksDir;
|
|
425
|
+
this.runner = options.run ?? defaultRunner;
|
|
426
|
+
this.extraEnv = options.env ?? {};
|
|
427
|
+
this.plumbing = options.plumbing ?? false;
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* A copy with the same location, hooks dir, runner and env that also accepts
|
|
431
|
+
* {@link GIT_PLUMBING_SUBCOMMANDS}. The server's commit store calls this on `ctx.git`. The desktop
|
|
432
|
+
* never does, because it never runs git for a server share (server-sync spec §3.3, §6). The copy
|
|
433
|
+
* shares nothing mutable with the original, only the `core.sshCommand` lookups it repeats.
|
|
434
|
+
*/
|
|
435
|
+
withPlumbing() {
|
|
436
|
+
return new GitCli({ path: this.path, version: this.version }, { hooksDir: this.hooksDir, run: this.runner, env: this.extraEnv, plumbing: true });
|
|
437
|
+
}
|
|
438
|
+
/** Whether `subcommand` is on this instance's allow-list(s). */
|
|
439
|
+
allows(subcommand) {
|
|
440
|
+
return (GIT_SUBCOMMANDS.includes(subcommand) ||
|
|
441
|
+
(this.plumbing && GIT_PLUMBING_SUBCOMMANDS.includes(subcommand)));
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* Reads `core.sshCommand` for `cwd` once (cached per `cwd`, including a cached "unset"), via
|
|
445
|
+
* the same runner every other invocation uses. Exit code 1 (and any other failure) means
|
|
446
|
+
* unset.
|
|
447
|
+
*/
|
|
448
|
+
queryCoreSshCommand(cwd) {
|
|
449
|
+
const cached = this.sshCommandConfigByCwd.get(cwd);
|
|
450
|
+
if (cached !== undefined) {
|
|
451
|
+
return cached;
|
|
452
|
+
}
|
|
453
|
+
const lookup = (async () => {
|
|
454
|
+
try {
|
|
455
|
+
const env = { ...process.env, ...this.extraEnv, GIT_TERMINAL_PROMPT: '0' };
|
|
456
|
+
const result = await this.runner(this.path, ['config', '--get', 'core.sshCommand'], {
|
|
457
|
+
...(cwd !== undefined ? { cwd } : {}),
|
|
458
|
+
env,
|
|
459
|
+
timeoutMs: DEFAULT_TIMEOUT_MS,
|
|
460
|
+
encoding: 'utf8',
|
|
461
|
+
maxBuffer: MAX_BUFFER,
|
|
462
|
+
});
|
|
463
|
+
if (result.exitCode !== 0) {
|
|
464
|
+
return undefined;
|
|
465
|
+
}
|
|
466
|
+
const value = asText(result.stdout).trim();
|
|
467
|
+
return value.length > 0 ? value : undefined;
|
|
468
|
+
}
|
|
469
|
+
catch {
|
|
470
|
+
return undefined;
|
|
471
|
+
}
|
|
472
|
+
})();
|
|
473
|
+
this.sshCommandConfigByCwd.set(cwd, lookup);
|
|
474
|
+
return lookup;
|
|
475
|
+
}
|
|
476
|
+
async run(cwd, args, options) {
|
|
477
|
+
const subcommand = args[0];
|
|
478
|
+
if (!this.allows(subcommand ?? '')) {
|
|
479
|
+
throw new WirebenchError('git-failed', `"${subcommand ?? ''}" is not an allowed git subcommand.`, {
|
|
480
|
+
details: { args: args.map(redactArg) },
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
const callEnv = options?.env ?? {};
|
|
484
|
+
const refusedKeys = Object.keys(callEnv).filter((key) => !GIT_CALL_ENV.includes(key));
|
|
485
|
+
if (refusedKeys.length > 0) {
|
|
486
|
+
// Key names only: a value could be anything the caller had to hand.
|
|
487
|
+
throw new WirebenchError('git-failed', `git ${subcommand ?? ''} may not set ${refusedKeys.join(', ')}.`, {
|
|
488
|
+
details: { args: args.map(redactArg), env: refusedKeys },
|
|
489
|
+
});
|
|
490
|
+
}
|
|
491
|
+
const mergedEnv = { ...process.env, ...this.extraEnv };
|
|
492
|
+
// The `ssh -o BatchMode=yes` default only applies when nothing else already names an SSH
|
|
493
|
+
// transport: an explicit `GIT_SSH_COMMAND`/`GIT_SSH` (from the process or this instance's
|
|
494
|
+
// own `env`) is left exactly as `mergedEnv` already carries it, and `core.sshCommand` is
|
|
495
|
+
// consulted (once per `cwd`, cached) only when neither env var is set — read with this same
|
|
496
|
+
// `cwd` so a repository-local value in the tree being operated on is honoured, and a
|
|
497
|
+
// cwd-less run never picks up some other repository's local config.
|
|
498
|
+
let sshCommandDefault;
|
|
499
|
+
if (mergedEnv['GIT_SSH_COMMAND'] === undefined && mergedEnv['GIT_SSH'] === undefined) {
|
|
500
|
+
const configured = await this.queryCoreSshCommand(cwd);
|
|
501
|
+
if (configured === undefined) {
|
|
502
|
+
sshCommandDefault = DEFAULT_GIT_SSH_COMMAND;
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
const env = {
|
|
506
|
+
...mergedEnv,
|
|
507
|
+
// The call's own variables go under the hardening keys, so those always win.
|
|
508
|
+
...callEnv,
|
|
509
|
+
GIT_TERMINAL_PROMPT: '0',
|
|
510
|
+
GIT_ASKPASS: '',
|
|
511
|
+
LC_ALL: 'C',
|
|
512
|
+
...(sshCommandDefault !== undefined ? { GIT_SSH_COMMAND: sshCommandDefault } : {}),
|
|
513
|
+
};
|
|
514
|
+
const fullArgs = [
|
|
515
|
+
'-c',
|
|
516
|
+
'core.autocrlf=false',
|
|
517
|
+
'-c',
|
|
518
|
+
'merge.conflictstyle=merge',
|
|
519
|
+
'-c',
|
|
520
|
+
`core.hooksPath=${this.hooksDir}`,
|
|
521
|
+
...args,
|
|
522
|
+
];
|
|
523
|
+
const timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
524
|
+
const encoding = options?.stdout ?? 'utf8';
|
|
525
|
+
let result;
|
|
526
|
+
try {
|
|
527
|
+
result = await this.runner(this.path, fullArgs, {
|
|
528
|
+
...(cwd !== undefined ? { cwd } : {}),
|
|
529
|
+
env,
|
|
530
|
+
timeoutMs,
|
|
531
|
+
encoding,
|
|
532
|
+
maxBuffer: options?.maxBuffer ?? MAX_BUFFER,
|
|
533
|
+
...(options?.input !== undefined ? { input: options.input } : {}),
|
|
534
|
+
});
|
|
535
|
+
}
|
|
536
|
+
catch (error) {
|
|
537
|
+
const nodeError = error;
|
|
538
|
+
if (nodeError.code === 'ENOENT' || nodeError.code === 'EACCES') {
|
|
539
|
+
throw new WirebenchError('git-not-found', 'The configured git executable could not be run.', {
|
|
540
|
+
details: { args: args.map(redactArg) },
|
|
541
|
+
cause: error,
|
|
542
|
+
});
|
|
543
|
+
}
|
|
544
|
+
if (nodeError.code === MAX_BUFFER_EXCEEDED) {
|
|
545
|
+
throw new WirebenchError('git-failed', `git ${subcommand ?? ''} produced more output than this call allows.`, {
|
|
546
|
+
details: { args: args.map(redactArg), outputTooLarge: true },
|
|
547
|
+
cause: error,
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
if (nodeError.killed === true || (nodeError.signal !== null && nodeError.signal !== undefined)) {
|
|
551
|
+
throw new WirebenchError('git-failed', `git ${subcommand ?? ''} timed out.`, {
|
|
552
|
+
details: { args: args.map(redactArg), timedOut: true },
|
|
553
|
+
cause: error,
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
throw new WirebenchError('git-failed', 'git could not be run.', {
|
|
557
|
+
details: { args: args.map(redactArg) },
|
|
558
|
+
cause: error,
|
|
559
|
+
});
|
|
560
|
+
}
|
|
561
|
+
if (result.exitCode !== 0) {
|
|
562
|
+
const stderr = result.stderr.slice(-STDERR_DETAIL_BYTES);
|
|
563
|
+
const details = { args: args.map(redactArg), exitCode: result.exitCode, stderr: stderr.trim() };
|
|
564
|
+
if (AUTH_FAILED_PATTERN.test(result.stderr)) {
|
|
565
|
+
throw new WirebenchError('git-auth-failed', 'git could not authenticate with the remote.', { details });
|
|
566
|
+
}
|
|
567
|
+
if (OFFLINE_PATTERN.test(result.stderr)) {
|
|
568
|
+
throw new WirebenchError('git-offline', 'git could not reach the remote.', { details });
|
|
569
|
+
}
|
|
570
|
+
throw new WirebenchError('git-failed', `git ${subcommand ?? ''} failed.`, { details });
|
|
571
|
+
}
|
|
572
|
+
return {
|
|
573
|
+
stdout: encoding === 'buffer' ? asBuffer(result.stdout) : asText(result.stdout),
|
|
574
|
+
stderr: result.stderr,
|
|
575
|
+
};
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
/**
|
|
579
|
+
* The only keys a repository's local config (`.git/config`) may set before the app runs git in a
|
|
580
|
+
* repository it did not create itself: what `init`/`clone` write, what the app writes (`remote add`,
|
|
581
|
+
* the identity dialog's `user.name`/`user.email`) and a few harmless line-ending/fetch/pull settings.
|
|
582
|
+
* Lower-case; `*` is a subsection, any non-empty string (it may contain dots). Everything else —
|
|
583
|
+
* `extensions.*`, `include*`, `url.*`, `protocol.*`, `gpg.*`, `commit.gpgsign`, `remote.*.pushurl`,
|
|
584
|
+
* any `core.*` not named here — is refused: git has too many ways to run a program for a list of
|
|
585
|
+
* refused keys to be trusted.
|
|
586
|
+
*/
|
|
587
|
+
const ALLOWED_LOCAL_CONFIG_KEYS = [
|
|
588
|
+
'core.repositoryformatversion',
|
|
589
|
+
'core.filemode',
|
|
590
|
+
'core.bare',
|
|
591
|
+
'core.logallrefupdates',
|
|
592
|
+
'core.ignorecase',
|
|
593
|
+
'core.precomposeunicode',
|
|
594
|
+
'core.symlinks',
|
|
595
|
+
'core.autocrlf',
|
|
596
|
+
'core.safecrlf',
|
|
597
|
+
'core.eol',
|
|
598
|
+
'core.quotepath',
|
|
599
|
+
'core.longpaths',
|
|
600
|
+
'core.checkstat',
|
|
601
|
+
'core.trustctime',
|
|
602
|
+
'user.name',
|
|
603
|
+
'user.email',
|
|
604
|
+
'remote.*.url',
|
|
605
|
+
'remote.*.fetch',
|
|
606
|
+
'remote.*.tagopt',
|
|
607
|
+
'remote.*.prune',
|
|
608
|
+
'branch.*.remote',
|
|
609
|
+
'branch.*.merge',
|
|
610
|
+
'branch.*.rebase',
|
|
611
|
+
'pull.rebase',
|
|
612
|
+
'pull.ff',
|
|
613
|
+
'fetch.prune',
|
|
614
|
+
'init.defaultbranch',
|
|
615
|
+
'gc.auto',
|
|
616
|
+
];
|
|
617
|
+
const ALLOWED_LOCAL_CONFIG_PATTERNS = ALLOWED_LOCAL_CONFIG_KEYS.map((key) => new RegExp(`^${key.replaceAll('.', '\\.').replaceAll('*', '.+')}$`, 's'));
|
|
618
|
+
/** A `remote.<name>.url` key, whose value is checked with {@link assertRemoteUrl} as well. */
|
|
619
|
+
const REMOTE_URL_KEY = /^remote\..+\.url$/is;
|
|
620
|
+
/** The keys of `names` (git config key names) off the local-config allow-list, compared case-insensitively. */
|
|
621
|
+
export function refusedLocalConfigKeys(names) {
|
|
622
|
+
return names.filter((name) => {
|
|
623
|
+
const key = name.toLowerCase();
|
|
624
|
+
return !ALLOWED_LOCAL_CONFIG_PATTERNS.some((pattern) => pattern.test(key));
|
|
625
|
+
});
|
|
626
|
+
}
|
|
627
|
+
/** Splits git's `-z` output into its NUL-terminated records. */
|
|
628
|
+
function nulRecords(stdout) {
|
|
629
|
+
return stdout.split('\0').filter((record) => record.length > 0);
|
|
630
|
+
}
|
|
631
|
+
/** Whether `error` is git refusing to run a `--local` read outside a repository. */
|
|
632
|
+
function isNotARepository(error) {
|
|
633
|
+
if (!(error instanceof WirebenchError)) {
|
|
634
|
+
return false;
|
|
635
|
+
}
|
|
636
|
+
const details = error.details;
|
|
637
|
+
return (details?.exitCode === 128 &&
|
|
638
|
+
typeof details.stderr === 'string' &&
|
|
639
|
+
/not a git repository|can only be used inside a git repository/i.test(details.stderr));
|
|
640
|
+
}
|
|
641
|
+
/**
|
|
642
|
+
* Refuses a repository whose `.git/config` sets any key off the allow-list (see
|
|
643
|
+
* {@link refusedLocalConfigKeys}), or a `remote.*.url` value {@link assertRemoteUrl} refuses, with
|
|
644
|
+
* `git-config-refused` and `details.keys` naming the keys (never a URL). A folder that is not a
|
|
645
|
+
* repository is `git-not-a-repository`. Run before any other git command in a repository the app
|
|
646
|
+
* did not `clone` or `init` itself.
|
|
647
|
+
*/
|
|
648
|
+
export async function assertSafeLocalConfig(git, cwd) {
|
|
649
|
+
let names;
|
|
650
|
+
try {
|
|
651
|
+
names = nulRecords((await git.run(cwd, ['config', '--local', '--list', '--name-only', '-z'])).stdout);
|
|
652
|
+
}
|
|
653
|
+
catch (error) {
|
|
654
|
+
if (isNotARepository(error)) {
|
|
655
|
+
throw new WirebenchError('git-not-a-repository', 'This folder is not a git repository.', { cause: error });
|
|
656
|
+
}
|
|
657
|
+
throw error;
|
|
658
|
+
}
|
|
659
|
+
const keys = refusedLocalConfigKeys(names);
|
|
660
|
+
/** `assertRemoteUrl`'s own messages, which never echo the URL (they may suggest its file:// form). */
|
|
661
|
+
const urlHints = [];
|
|
662
|
+
if (names.some((name) => REMOTE_URL_KEY.test(name))) {
|
|
663
|
+
const { stdout } = await git.run(cwd, ['config', '--local', '-z', '--get-regexp', '^remote\\..*\\.url$']);
|
|
664
|
+
for (const record of nulRecords(stdout)) {
|
|
665
|
+
const newline = record.indexOf('\n');
|
|
666
|
+
const key = newline === -1 ? record : record.slice(0, newline);
|
|
667
|
+
const value = newline === -1 ? '' : record.slice(newline + 1);
|
|
668
|
+
try {
|
|
669
|
+
assertRemoteUrl(value);
|
|
670
|
+
}
|
|
671
|
+
catch (error) {
|
|
672
|
+
keys.push(key);
|
|
673
|
+
if (error instanceof Error && !urlHints.includes(error.message)) {
|
|
674
|
+
urlHints.push(error.message);
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
const unique = [...new Set(keys)];
|
|
680
|
+
if (unique.length > 0) {
|
|
681
|
+
const them = unique.length === 1 ? 'it' : 'them';
|
|
682
|
+
throw new WirebenchError('git-config-refused', `This repository's .git/config sets ${unique.join(', ')}, which Wirebench does not allow in a repository it did not create. Remove ${them} from the repository's .git/config, or move ${them} to your global git config.${urlHints.length > 0 ? ` ${urlHints.join(' ')}` : ''}`, { details: { keys: unique } });
|
|
683
|
+
}
|
|
684
|
+
}
|