@fabrika/provider-zerops 0.2.0 → 0.3.2
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/package.json +18 -5
- package/src/api/client.ts +522 -0
- package/src/api/errors.ts +50 -0
- package/src/api/polling.ts +59 -0
- package/src/api/readers.ts +185 -0
- package/src/api/service-env-response.ts +34 -0
- package/src/api/types.ts +602 -0
- package/src/api.ts +29 -1378
- package/src/authoring.ts +7 -10
- package/src/cli-args.ts +2 -6
- package/src/cli.ts +3 -28
- package/src/collaborators.ts +2 -4
- package/src/compile.ts +3 -1
- package/src/control.ts +203 -450
- package/src/descriptor.ts +179 -0
- package/src/index.ts +23 -127
- package/src/installation/admin-options.ts +100 -0
- package/src/installation/admin.ts +123 -0
- package/src/installation/deploy-options.ts +127 -0
- package/src/installation/deploy.ts +668 -0
- package/src/installation/generated/platform-console-schema.ts +41 -0
- package/src/installation/generated/platform-proxy-manifest.ts +72 -0
- package/src/installation/hosts.ts +117 -0
- package/src/installation/index.ts +390 -0
- package/src/installation/init-options.ts +148 -0
- package/src/installation/init.ts +394 -0
- package/src/installation/install-collaborators.ts +27 -0
- package/src/installation/install-environment.ts +193 -0
- package/src/installation/install-options.ts +156 -0
- package/src/installation/install-project.ts +201 -0
- package/src/installation/install-provisioning.ts +185 -0
- package/src/installation/install.ts +262 -0
- package/src/installation/installation-source.ts +42 -0
- package/src/installation/log.ts +77 -0
- package/src/installation/machine-key.ts +65 -0
- package/src/installation/manifest.ts +95 -0
- package/src/installation/placement-options.ts +33 -0
- package/src/installation/platform-source.ts +106 -0
- package/src/installation/platform-upload.ts +34 -0
- package/src/installation/proxy-manifest.ts +113 -0
- package/src/installation/secrets.ts +79 -0
- package/src/installation/sidecar.ts +125 -0
- package/src/installation/source-options.ts +12 -0
- package/src/installation/templates/README.md +116 -0
- package/src/installation/templates/fabrika.ref +1 -0
- package/src/installation/templates/gitignore +3 -0
- package/src/installation/templates/platform.yml +144 -0
- package/src/installation/topology/artifacts.ts +141 -0
- package/src/installation/topology/index.ts +13 -0
- package/src/installation/topology/installation-schemas.ts +225 -0
- package/src/installation/topology/invariants.ts +86 -0
- package/src/installation/topology/setups.ts +442 -0
- package/src/installation/topology/topology.ts +501 -0
- package/src/installation/topology/validate.ts +26 -0
- package/src/installation/upgrade-options.ts +99 -0
- package/src/installation/upgrade-output.ts +31 -0
- package/src/installation/upgrade.ts +373 -0
- package/src/managed-env.ts +113 -0
- package/src/manifest.ts +194 -344
- package/src/namespace/claims.ts +77 -0
- package/src/namespace/codec.ts +179 -0
- package/src/namespace/constants.ts +30 -0
- package/src/namespace/errors.ts +60 -0
- package/src/namespace/manifest.ts +28 -0
- package/src/namespace/operator.ts +151 -0
- package/src/namespace/provisioning.ts +482 -0
- package/src/namespace/proxy-attempt.ts +220 -0
- package/src/namespace/proxy-source.ts +22 -0
- package/src/namespace/topology.ts +115 -0
- package/src/namespace/types.ts +114 -0
- package/src/namespace.ts +34 -1271
- package/src/plan.ts +21 -23
- package/src/provider.ts +266 -241
- package/src/source/constants.ts +11 -0
- package/src/source/port.ts +49 -0
- package/src/source/types.ts +4 -0
- package/src/source/validation.ts +72 -0
- package/src/source.ts +2 -1220
- package/src/types.ts +8 -7
- package/src/version-attempt.ts +18 -0
- package/src/codec.ts +0 -108
- package/src/namespace-command.ts +0 -209
- package/src/source-connection.ts +0 -344
package/src/source.ts
CHANGED
|
@@ -1,1220 +1,2 @@
|
|
|
1
|
-
export
|
|
2
|
-
export
|
|
3
|
-
export const ZEROPS_SOURCE_UPLOAD_PATH = '/v1/source/upload'
|
|
4
|
-
export const ZEROPS_SOURCE_CANCEL_PATH = '/v1/source/cancel'
|
|
5
|
-
export const ZEROPS_SOURCE_WEBHOOK_CONFIGURE_PATH = '/v1/source/github/webhook/configure'
|
|
6
|
-
export const ZEROPS_SOURCE_INSTALLATIONS_VERIFY_PATH = '/v1/source/github/installations/verify'
|
|
7
|
-
export const ZEROPS_SOURCE_PROTOCOL_VERSION_V2 = 2
|
|
8
|
-
export const ZEROPS_SOURCE_RESOLVE_PATH_V2 = '/v2/source/resolve'
|
|
9
|
-
export const ZEROPS_SOURCE_UPLOAD_PATH_V2 = '/v2/source/upload'
|
|
10
|
-
export const ZEROPS_SOURCE_CREDENTIAL_ACTIVATE_PATH_V2 = '/v2/source/credentials/activate'
|
|
11
|
-
export const ZEROPS_SOURCE_CREDENTIAL_STATUS_PATH_V2 = '/v2/source/credentials/status'
|
|
12
|
-
export const ZEROPS_SOURCE_CREDENTIAL_BUNDLE_VERSION_V2 = 2
|
|
13
|
-
export const ZEROPS_SOURCE_CREDENTIAL_ENV_V2_PREFIX = 'GITHUB_APP_CREDENTIALS_V2_'
|
|
14
|
-
|
|
15
|
-
const MAX_ID_LENGTH = 128
|
|
16
|
-
const MAX_REF_LENGTH = 255
|
|
17
|
-
const MAX_UPLOAD_URL_LENGTH = 4096
|
|
18
|
-
const MAX_SOURCE_CREDENTIAL_BUNDLE_BYTES = 72 * 1024
|
|
19
|
-
const MAX_GITHUB_APP_PRIVATE_KEY_LENGTH = 64 * 1024
|
|
20
|
-
const MAX_WEBHOOK_URL_LENGTH = 2048
|
|
21
|
-
const MAX_WEBHOOK_SECRET_LENGTH = 4096
|
|
22
|
-
const MAX_INSTALLATION_REPOSITORIES = 100
|
|
23
|
-
const SHA256_PATTERN = /^[a-f0-9]{64}$/
|
|
24
|
-
const COMMIT_SHA_PATTERN = /^(?:[a-f0-9]{40}|[a-f0-9]{64})$/
|
|
25
|
-
const ID_PATTERN = /^[A-Za-z0-9._:-]+$/
|
|
26
|
-
const GITHUB_OWNER_PATTERN = /^[a-z0-9](?:[a-z0-9-]{0,37}[a-z0-9])?$/
|
|
27
|
-
const GITHUB_REPOSITORY_PATTERN = /^[a-z0-9._-]{1,100}$/
|
|
28
|
-
const GITHUB_APP_ID_PATTERN = /^[1-9][0-9]{0,31}$/
|
|
29
|
-
const GITHUB_APP_SLUG_PATTERN = /^[a-z0-9](?:[a-z0-9-]{0,98}[a-z0-9])?$/
|
|
30
|
-
const GITHUB_LOGIN_PATTERN = /^[A-Za-z0-9](?:[A-Za-z0-9-]{0,98}[A-Za-z0-9])?$/
|
|
31
|
-
|
|
32
|
-
export interface ZeropsSourceCredentialBundleV2 {
|
|
33
|
-
readonly version: typeof ZEROPS_SOURCE_CREDENTIAL_BUNDLE_VERSION_V2
|
|
34
|
-
readonly connectionId: string
|
|
35
|
-
readonly githubAppId: string
|
|
36
|
-
readonly privateKeyPem: string
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export interface ZeropsSourceGitHubAppIdentityV1 {
|
|
40
|
-
readonly id: number
|
|
41
|
-
readonly slug: string
|
|
42
|
-
readonly htmlUrl: string
|
|
43
|
-
readonly public: boolean
|
|
44
|
-
readonly owner: {
|
|
45
|
-
readonly login: string
|
|
46
|
-
readonly type: 'Organization'
|
|
47
|
-
}
|
|
48
|
-
readonly permissions: {
|
|
49
|
-
readonly contents: 'read'
|
|
50
|
-
}
|
|
51
|
-
readonly events: readonly ['push']
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export interface ZeropsSourceCredentialActivateRequestV2 {
|
|
55
|
-
readonly protocolVersion: typeof ZEROPS_SOURCE_PROTOCOL_VERSION_V2
|
|
56
|
-
readonly connectionId: string
|
|
57
|
-
/** Canonical JSON that is byte-identical to the durable source environment value. */
|
|
58
|
-
readonly credentialBundle: string
|
|
59
|
-
readonly credentialSha256: string
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export interface ZeropsSourceCredentialActivateResponseV2 {
|
|
63
|
-
readonly protocolVersion: typeof ZEROPS_SOURCE_PROTOCOL_VERSION_V2
|
|
64
|
-
readonly connectionId: string
|
|
65
|
-
readonly credentialVersion: typeof ZEROPS_SOURCE_CREDENTIAL_BUNDLE_VERSION_V2
|
|
66
|
-
readonly credentialSha256: string
|
|
67
|
-
readonly githubApp: ZeropsSourceGitHubAppIdentityV1
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
export interface ZeropsSourceCredentialStatusRequestV2 {
|
|
71
|
-
readonly protocolVersion: typeof ZEROPS_SOURCE_PROTOCOL_VERSION_V2
|
|
72
|
-
readonly connectionId: string
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export interface ZeropsSourceCredentialAnonymousStatusResponseV2 {
|
|
76
|
-
readonly protocolVersion: typeof ZEROPS_SOURCE_PROTOCOL_VERSION_V2
|
|
77
|
-
readonly connectionId: string
|
|
78
|
-
readonly state: 'anonymous'
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
export interface ZeropsSourceCredentialActiveStatusResponseV2 extends ZeropsSourceCredentialActivateResponseV2 {
|
|
82
|
-
readonly state: 'active'
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
export type ZeropsSourceCredentialStatusResponseV2 =
|
|
86
|
-
| ZeropsSourceCredentialAnonymousStatusResponseV2
|
|
87
|
-
| ZeropsSourceCredentialActiveStatusResponseV2
|
|
88
|
-
|
|
89
|
-
export interface ZeropsSourceWebhookConfigureInput {
|
|
90
|
-
readonly connectionId: string
|
|
91
|
-
readonly credentialSha256: string
|
|
92
|
-
readonly url: string
|
|
93
|
-
readonly secret: string
|
|
94
|
-
readonly signal: AbortSignal
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
export interface ZeropsSourceWebhookConfigureRequestV1 {
|
|
98
|
-
readonly protocolVersion: typeof ZEROPS_SOURCE_PROTOCOL_VERSION
|
|
99
|
-
readonly connectionId: string
|
|
100
|
-
readonly credentialSha256: string
|
|
101
|
-
readonly url: string
|
|
102
|
-
readonly secret: string
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
export interface ZeropsSourceWebhookConfigureResponseV1 {
|
|
106
|
-
readonly protocolVersion: typeof ZEROPS_SOURCE_PROTOCOL_VERSION
|
|
107
|
-
readonly connectionId: string
|
|
108
|
-
readonly credentialSha256: string
|
|
109
|
-
readonly webhook: { readonly url: string; readonly contentType: 'json'; readonly insecureSsl: '0' }
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
export type ZeropsSourceInstallationScopeV1 =
|
|
113
|
-
| { readonly kind: 'organization'; readonly organization: string }
|
|
114
|
-
| { readonly kind: 'repositories'; readonly repositories: readonly ZeropsSourceRepository[] }
|
|
115
|
-
|
|
116
|
-
export interface ZeropsSourceInstallationsVerifyInput {
|
|
117
|
-
readonly connectionId: string
|
|
118
|
-
readonly credentialSha256: string
|
|
119
|
-
readonly scope: ZeropsSourceInstallationScopeV1
|
|
120
|
-
readonly signal: AbortSignal
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
export interface ZeropsSourceInstallationsVerifyRequestV1 {
|
|
124
|
-
readonly protocolVersion: typeof ZEROPS_SOURCE_PROTOCOL_VERSION
|
|
125
|
-
readonly connectionId: string
|
|
126
|
-
readonly credentialSha256: string
|
|
127
|
-
readonly scope: ZeropsSourceInstallationScopeV1
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
export type ZeropsSourceInstallationVerificationV1 =
|
|
131
|
-
| { readonly status: 'missing' }
|
|
132
|
-
| {
|
|
133
|
-
readonly status: 'installed'
|
|
134
|
-
readonly installationId: number
|
|
135
|
-
readonly accountLogin: string
|
|
136
|
-
readonly repositorySelection: 'all' | 'selected'
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
export interface ZeropsSourceInstallationsVerifyResponseV1 {
|
|
140
|
-
readonly protocolVersion: typeof ZEROPS_SOURCE_PROTOCOL_VERSION
|
|
141
|
-
readonly connectionId: string
|
|
142
|
-
readonly credentialSha256: string
|
|
143
|
-
readonly installation: ZeropsSourceInstallationVerificationV1
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
export interface ZeropsSourceRepository {
|
|
147
|
-
owner: string
|
|
148
|
-
name: string
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
export interface ZeropsSourceDescriptor {
|
|
152
|
-
path: 'zerops.yaml'
|
|
153
|
-
sha256: string
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
export interface ZeropsSourceResolveRequestV1 {
|
|
157
|
-
protocolVersion: typeof ZEROPS_SOURCE_PROTOCOL_VERSION
|
|
158
|
-
runId: string
|
|
159
|
-
repository: ZeropsSourceRepository
|
|
160
|
-
requestedRef: string
|
|
161
|
-
expectedCommitSha?: string
|
|
162
|
-
githubInstallationId?: number
|
|
163
|
-
descriptorSha256: string
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
export interface ZeropsSourceResolveResponseV1 {
|
|
167
|
-
protocolVersion: typeof ZEROPS_SOURCE_PROTOCOL_VERSION
|
|
168
|
-
runId: string
|
|
169
|
-
commitSha: string
|
|
170
|
-
descriptorSha256: string
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
export interface ZeropsSourceUploadRequestV1 {
|
|
174
|
-
protocolVersion: typeof ZEROPS_SOURCE_PROTOCOL_VERSION
|
|
175
|
-
runId: string
|
|
176
|
-
appVersionId: string
|
|
177
|
-
repository: ZeropsSourceRepository
|
|
178
|
-
commitSha: string
|
|
179
|
-
githubInstallationId?: number
|
|
180
|
-
uploadUrl: string
|
|
181
|
-
descriptor: ZeropsSourceDescriptor
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
export interface ZeropsSourceUploadResponseV1 {
|
|
185
|
-
protocolVersion: typeof ZEROPS_SOURCE_PROTOCOL_VERSION
|
|
186
|
-
runId: string
|
|
187
|
-
appVersionId: string
|
|
188
|
-
commitSha: string
|
|
189
|
-
descriptorSha256: string
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
export interface ZeropsSourcePrivateBindingV2 {
|
|
193
|
-
readonly connectionId: string
|
|
194
|
-
readonly installationId: number
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
export interface ZeropsSourceResolveRequestV2 {
|
|
198
|
-
readonly protocolVersion: typeof ZEROPS_SOURCE_PROTOCOL_VERSION_V2
|
|
199
|
-
readonly runId: string
|
|
200
|
-
readonly repository: ZeropsSourceRepository
|
|
201
|
-
readonly requestedRef: string
|
|
202
|
-
readonly expectedCommitSha?: string
|
|
203
|
-
readonly privateBinding?: ZeropsSourcePrivateBindingV2
|
|
204
|
-
readonly descriptorSha256: string
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
export interface ZeropsSourceResolveResponseV2 {
|
|
208
|
-
readonly protocolVersion: typeof ZEROPS_SOURCE_PROTOCOL_VERSION_V2
|
|
209
|
-
readonly runId: string
|
|
210
|
-
readonly commitSha: string
|
|
211
|
-
readonly descriptorSha256: string
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
export interface ZeropsSourceUploadRequestV2 {
|
|
215
|
-
readonly protocolVersion: typeof ZEROPS_SOURCE_PROTOCOL_VERSION_V2
|
|
216
|
-
readonly runId: string
|
|
217
|
-
readonly appVersionId: string
|
|
218
|
-
readonly repository: ZeropsSourceRepository
|
|
219
|
-
readonly commitSha: string
|
|
220
|
-
readonly privateBinding?: ZeropsSourcePrivateBindingV2
|
|
221
|
-
readonly uploadUrl: string
|
|
222
|
-
readonly descriptor: ZeropsSourceDescriptor
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
export interface ZeropsSourceUploadResponseV2 {
|
|
226
|
-
readonly protocolVersion: typeof ZEROPS_SOURCE_PROTOCOL_VERSION_V2
|
|
227
|
-
readonly runId: string
|
|
228
|
-
readonly appVersionId: string
|
|
229
|
-
readonly commitSha: string
|
|
230
|
-
readonly descriptorSha256: string
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
export interface ZeropsSourceCancelRequestV1 {
|
|
234
|
-
protocolVersion: typeof ZEROPS_SOURCE_PROTOCOL_VERSION
|
|
235
|
-
runId: string
|
|
236
|
-
appVersionId: string
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
export interface ZeropsSourceCancelResponseV1 {
|
|
240
|
-
protocolVersion: typeof ZEROPS_SOURCE_PROTOCOL_VERSION
|
|
241
|
-
runId: string
|
|
242
|
-
appVersionId: string
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
export interface ZeropsSourceCancelResult {
|
|
246
|
-
runId: string
|
|
247
|
-
appVersionId: string
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
export type ZeropsSourceErrorCode =
|
|
251
|
-
| 'invalid_request'
|
|
252
|
-
| 'unauthorized'
|
|
253
|
-
| 'repository_not_found'
|
|
254
|
-
| 'installation_not_found'
|
|
255
|
-
| 'ref_not_found'
|
|
256
|
-
| 'commit_mismatch'
|
|
257
|
-
| 'descriptor_missing'
|
|
258
|
-
| 'descriptor_mismatch'
|
|
259
|
-
| 'archive_rejected'
|
|
260
|
-
| 'upload_rejected'
|
|
261
|
-
| 'upload_failed'
|
|
262
|
-
| 'credentials_invalid'
|
|
263
|
-
| 'credentials_conflict'
|
|
264
|
-
| 'cancelled'
|
|
265
|
-
| 'internal'
|
|
266
|
-
|
|
267
|
-
export const ZEROPS_SOURCE_ERROR_CODES: readonly ZeropsSourceErrorCode[] = [
|
|
268
|
-
'invalid_request',
|
|
269
|
-
'unauthorized',
|
|
270
|
-
'repository_not_found',
|
|
271
|
-
'installation_not_found',
|
|
272
|
-
'ref_not_found',
|
|
273
|
-
'commit_mismatch',
|
|
274
|
-
'descriptor_missing',
|
|
275
|
-
'descriptor_mismatch',
|
|
276
|
-
'archive_rejected',
|
|
277
|
-
'upload_rejected',
|
|
278
|
-
'upload_failed',
|
|
279
|
-
'credentials_invalid',
|
|
280
|
-
'credentials_conflict',
|
|
281
|
-
'cancelled',
|
|
282
|
-
'internal',
|
|
283
|
-
]
|
|
284
|
-
|
|
285
|
-
export type ZeropsSourceErrorStage =
|
|
286
|
-
| 'authenticate'
|
|
287
|
-
| 'validate'
|
|
288
|
-
| 'resolve'
|
|
289
|
-
| 'archive'
|
|
290
|
-
| 'upload'
|
|
291
|
-
| 'cancel'
|
|
292
|
-
| 'credentials'
|
|
293
|
-
|
|
294
|
-
export const ZEROPS_SOURCE_ERROR_STAGES: readonly ZeropsSourceErrorStage[] = [
|
|
295
|
-
'authenticate',
|
|
296
|
-
'validate',
|
|
297
|
-
'resolve',
|
|
298
|
-
'archive',
|
|
299
|
-
'upload',
|
|
300
|
-
'cancel',
|
|
301
|
-
'credentials',
|
|
302
|
-
]
|
|
303
|
-
|
|
304
|
-
export interface ZeropsSourceErrorEnvelope {
|
|
305
|
-
error: {
|
|
306
|
-
code: ZeropsSourceErrorCode
|
|
307
|
-
stage: ZeropsSourceErrorStage
|
|
308
|
-
retryable: boolean
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
export interface ZeropsSourceResolveInput {
|
|
313
|
-
runId: string
|
|
314
|
-
repository: ZeropsSourceRepository
|
|
315
|
-
requestedRef: string
|
|
316
|
-
expectedCommitSha?: string
|
|
317
|
-
githubInstallationId?: number
|
|
318
|
-
descriptorSha256: string
|
|
319
|
-
signal: AbortSignal
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
export interface ZeropsSourceResolveResult {
|
|
323
|
-
runId: string
|
|
324
|
-
commitSha: string
|
|
325
|
-
descriptorSha256: string
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
export interface ZeropsSourceUploadInput {
|
|
329
|
-
runId: string
|
|
330
|
-
appVersionId: string
|
|
331
|
-
repository: ZeropsSourceRepository
|
|
332
|
-
commitSha: string
|
|
333
|
-
githubInstallationId?: number
|
|
334
|
-
uploadUrl: string
|
|
335
|
-
descriptor: ZeropsSourceDescriptor
|
|
336
|
-
signal: AbortSignal
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
export interface ZeropsSourceResolveInputV2 {
|
|
340
|
-
readonly runId: string
|
|
341
|
-
readonly repository: ZeropsSourceRepository
|
|
342
|
-
readonly requestedRef: string
|
|
343
|
-
readonly expectedCommitSha?: string
|
|
344
|
-
readonly privateBinding?: ZeropsSourcePrivateBindingV2
|
|
345
|
-
readonly descriptorSha256: string
|
|
346
|
-
readonly signal: AbortSignal
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
export interface ZeropsSourceUploadInputV2 {
|
|
350
|
-
readonly runId: string
|
|
351
|
-
readonly appVersionId: string
|
|
352
|
-
readonly repository: ZeropsSourceRepository
|
|
353
|
-
readonly commitSha: string
|
|
354
|
-
readonly privateBinding?: ZeropsSourcePrivateBindingV2
|
|
355
|
-
readonly uploadUrl: string
|
|
356
|
-
readonly descriptor: ZeropsSourceDescriptor
|
|
357
|
-
readonly signal: AbortSignal
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
export interface ZeropsSourceUploadResult {
|
|
361
|
-
runId: string
|
|
362
|
-
appVersionId: string
|
|
363
|
-
commitSha: string
|
|
364
|
-
descriptorSha256: string
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
export interface ZeropsSourceCancelInput {
|
|
368
|
-
runId: string
|
|
369
|
-
appVersionId: string
|
|
370
|
-
signal: AbortSignal
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
export interface ZeropsSourceClient {
|
|
374
|
-
resolve(input: ZeropsSourceResolveInput): Promise<ZeropsSourceResolveResult>
|
|
375
|
-
upload(input: ZeropsSourceUploadInput): Promise<ZeropsSourceUploadResult>
|
|
376
|
-
cancel(input: ZeropsSourceCancelInput): Promise<void>
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
/** Keyed source operations; the unkeyed v1 wire remains the anonymous public-repository path. */
|
|
380
|
-
export interface ZeropsSourceClientV2 {
|
|
381
|
-
resolveV2(input: ZeropsSourceResolveInputV2): Promise<ZeropsSourceResolveResult>
|
|
382
|
-
uploadV2(input: ZeropsSourceUploadInputV2): Promise<ZeropsSourceUploadResult>
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
export interface ZeropsSourceCredentialActivateInput {
|
|
386
|
-
readonly connectionId: string
|
|
387
|
-
readonly credentialBundle: string
|
|
388
|
-
readonly credentialSha256: string
|
|
389
|
-
readonly signal: AbortSignal
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
export interface ZeropsSourceCredentialStatusInput {
|
|
393
|
-
readonly connectionId: string
|
|
394
|
-
readonly signal: AbortSignal
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
/** Credential management is separate from the deploy source client and is composed only in the authenticated admin flow. */
|
|
398
|
-
export interface ZeropsSourceCredentialManager {
|
|
399
|
-
configureWebhook(input: ZeropsSourceWebhookConfigureInput): Promise<ZeropsSourceWebhookConfigureResponseV1>
|
|
400
|
-
verifyInstallations(input: ZeropsSourceInstallationsVerifyInput): Promise<ZeropsSourceInstallationsVerifyResponseV1>
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
/** Keyed credential operations — the only way a private credential reaches `source`. */
|
|
404
|
-
export interface ZeropsSourceCredentialManagerV2 {
|
|
405
|
-
activateV2(input: ZeropsSourceCredentialActivateInput): Promise<ZeropsSourceCredentialActivateResponseV2>
|
|
406
|
-
statusV2(input: ZeropsSourceCredentialStatusInput): Promise<ZeropsSourceCredentialStatusResponseV2>
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
const isRecord = (value: unknown): value is Record<string, unknown> => typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
410
|
-
|
|
411
|
-
const record = (value: unknown, label: string): Record<string, unknown> => {
|
|
412
|
-
if (!isRecord(value)) throw new Error(`${label} must be an object`)
|
|
413
|
-
return value
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
const exactKeys = (value: Record<string, unknown>, allowed: readonly string[], label: string): void => {
|
|
417
|
-
const allowedKeys = new Set(allowed)
|
|
418
|
-
const unknownKey = Object.keys(value).find((key) => !allowedKeys.has(key))
|
|
419
|
-
if (unknownKey !== undefined) throw new Error(`${label} contains an unknown field`)
|
|
420
|
-
const missingKey = allowed.find((key) => !(key in value))
|
|
421
|
-
if (missingKey !== undefined) throw new Error(`${label} is missing field ${missingKey}`)
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
const protocolVersion = (value: Record<string, unknown>, label: string): typeof ZEROPS_SOURCE_PROTOCOL_VERSION => {
|
|
425
|
-
if (value['protocolVersion'] !== ZEROPS_SOURCE_PROTOCOL_VERSION) throw new Error(`${label} has an unsupported protocolVersion`)
|
|
426
|
-
return ZEROPS_SOURCE_PROTOCOL_VERSION
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
const protocolVersionV2 = (value: Record<string, unknown>, label: string): typeof ZEROPS_SOURCE_PROTOCOL_VERSION_V2 => {
|
|
430
|
-
if (value['protocolVersion'] !== ZEROPS_SOURCE_PROTOCOL_VERSION_V2) throw new Error(`${label} has an unsupported protocolVersion`)
|
|
431
|
-
return ZEROPS_SOURCE_PROTOCOL_VERSION_V2
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
const boundedString = (value: unknown, label: string, maximum: number): string => {
|
|
435
|
-
if (typeof value !== 'string' || value.length === 0 || value.length > maximum) {
|
|
436
|
-
throw new Error(`${label} must be a non-empty string of at most ${maximum} characters`)
|
|
437
|
-
}
|
|
438
|
-
return value
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
const identifier = (value: unknown, label: string): string => {
|
|
442
|
-
const parsed = boundedString(value, label, MAX_ID_LENGTH)
|
|
443
|
-
if (!ID_PATTERN.test(parsed)) throw new Error(`${label} contains invalid characters`)
|
|
444
|
-
return parsed
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
const ref = (value: unknown, label: string): string => {
|
|
448
|
-
const parsed = boundedString(value, label, MAX_REF_LENGTH)
|
|
449
|
-
if (COMMIT_SHA_PATTERN.test(parsed)) return parsed
|
|
450
|
-
const hasForbiddenCharacter = [...parsed].some((character) => {
|
|
451
|
-
const code = character.charCodeAt(0)
|
|
452
|
-
return code <= 0x20 || code === 0x7f || '~^:?*[\\'.includes(character)
|
|
453
|
-
})
|
|
454
|
-
const components = parsed.split('/')
|
|
455
|
-
if (
|
|
456
|
-
parsed.startsWith('-')
|
|
457
|
-
|| parsed.trim() !== parsed
|
|
458
|
-
|| parsed === '@'
|
|
459
|
-
|| parsed.includes('..')
|
|
460
|
-
|| parsed.includes('@{')
|
|
461
|
-
|| parsed.includes('//')
|
|
462
|
-
|| parsed.endsWith('/')
|
|
463
|
-
|| parsed.endsWith('.')
|
|
464
|
-
|| hasForbiddenCharacter
|
|
465
|
-
|| components.some((component) => component === '' || component.startsWith('.') || component.endsWith('.lock'))
|
|
466
|
-
) {
|
|
467
|
-
throw new Error(`${label} must be a safe Git ref or lowercase commit digest`)
|
|
468
|
-
}
|
|
469
|
-
return parsed
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
const commitSha = (value: unknown, label: string): string => {
|
|
473
|
-
if (typeof value !== 'string' || !COMMIT_SHA_PATTERN.test(value)) throw new Error(`${label} must be a lowercase 40- or 64-character hex digest`)
|
|
474
|
-
return value
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
const sha256 = (value: unknown, label: string): string => {
|
|
478
|
-
if (typeof value !== 'string' || !SHA256_PATTERN.test(value)) throw new Error(`${label} must be a lowercase 64-character hex digest`)
|
|
479
|
-
return value
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
const sourceCredentialBundleValueV2 = (value: unknown): ZeropsSourceCredentialBundleV2 => {
|
|
483
|
-
const parsed = record(value, 'source credential bundle v2')
|
|
484
|
-
exactKeys(parsed, ['version', 'connectionId', 'githubAppId', 'privateKeyPem'], 'source credential bundle v2')
|
|
485
|
-
if (parsed['version'] !== ZEROPS_SOURCE_CREDENTIAL_BUNDLE_VERSION_V2) {
|
|
486
|
-
throw new Error('source credential bundle v2 has an unsupported version')
|
|
487
|
-
}
|
|
488
|
-
const connectionId = identifier(parsed['connectionId'], 'source credential bundle v2.connectionId')
|
|
489
|
-
const githubAppId = boundedString(parsed['githubAppId'], 'source credential bundle v2.githubAppId', 32)
|
|
490
|
-
if (!GITHUB_APP_ID_PATTERN.test(githubAppId)) throw new Error('source credential bundle v2.githubAppId is invalid')
|
|
491
|
-
const privateKeyPem = boundedString(
|
|
492
|
-
parsed['privateKeyPem'],
|
|
493
|
-
'source credential bundle v2.privateKeyPem',
|
|
494
|
-
MAX_GITHUB_APP_PRIVATE_KEY_LENGTH,
|
|
495
|
-
)
|
|
496
|
-
if (!isCanonicalPrivateKeyPem(privateKeyPem)) throw new Error('source credential bundle v2.privateKeyPem is invalid')
|
|
497
|
-
return { version: ZEROPS_SOURCE_CREDENTIAL_BUNDLE_VERSION_V2, connectionId, githubAppId, privateKeyPem }
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
const isCanonicalPrivateKeyPem = (value: string): boolean => {
|
|
501
|
-
const match = /^-----BEGIN (RSA PRIVATE KEY|PRIVATE KEY)-----\n([A-Za-z0-9+/=\n]+)\n-----END (RSA PRIVATE KEY|PRIVATE KEY)-----\n?$/.exec(value)
|
|
502
|
-
if (match === null || match[1] !== match[3]) return false
|
|
503
|
-
const body = match[2]
|
|
504
|
-
if (body === undefined) return false
|
|
505
|
-
const lines = body.split('\n')
|
|
506
|
-
if (lines.some((line) => line.length === 0 || line.length > 64)) return false
|
|
507
|
-
if (lines.slice(0, -1).some((line) => line.includes('='))) return false
|
|
508
|
-
const encoded = lines.join('')
|
|
509
|
-
if (encoded.length % 4 !== 0 || !/^[A-Za-z0-9+/]+={0,2}$/.test(encoded)) return false
|
|
510
|
-
try {
|
|
511
|
-
const decoded = atob(encoded)
|
|
512
|
-
return decoded.length > 0 && decoded.charCodeAt(0) === 0x30
|
|
513
|
-
} catch {
|
|
514
|
-
return false
|
|
515
|
-
}
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
export function buildZeropsSourceCredentialBundleV2(
|
|
519
|
-
input: Omit<ZeropsSourceCredentialBundleV2, 'version'>,
|
|
520
|
-
): ZeropsSourceCredentialBundleV2 {
|
|
521
|
-
return sourceCredentialBundleValueV2({ version: ZEROPS_SOURCE_CREDENTIAL_BUNDLE_VERSION_V2, ...input })
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
export function serializeZeropsSourceCredentialBundleV2(bundle: ZeropsSourceCredentialBundleV2): string {
|
|
525
|
-
const parsed = sourceCredentialBundleValueV2(bundle)
|
|
526
|
-
return JSON.stringify({
|
|
527
|
-
version: parsed.version,
|
|
528
|
-
connectionId: parsed.connectionId,
|
|
529
|
-
githubAppId: parsed.githubAppId,
|
|
530
|
-
privateKeyPem: parsed.privateKeyPem,
|
|
531
|
-
})
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
export function decodeZeropsSourceCredentialBundleV2(value: unknown): ZeropsSourceCredentialBundleV2 {
|
|
535
|
-
if (typeof value !== 'string' || new TextEncoder().encode(value).byteLength > MAX_SOURCE_CREDENTIAL_BUNDLE_BYTES) {
|
|
536
|
-
throw new Error('source credential bundle v2 must be bounded canonical JSON')
|
|
537
|
-
}
|
|
538
|
-
let decoded: unknown
|
|
539
|
-
try {
|
|
540
|
-
decoded = JSON.parse(value)
|
|
541
|
-
} catch {
|
|
542
|
-
throw new Error('source credential bundle v2 must be bounded canonical JSON')
|
|
543
|
-
}
|
|
544
|
-
const bundle = sourceCredentialBundleValueV2(decoded)
|
|
545
|
-
if (serializeZeropsSourceCredentialBundleV2(bundle) !== value) {
|
|
546
|
-
throw new Error('source credential bundle v2 must be bounded canonical JSON')
|
|
547
|
-
}
|
|
548
|
-
return bundle
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
export async function sha256ZeropsSourceCredentialBundleV2(value: string): Promise<string> {
|
|
552
|
-
decodeZeropsSourceCredentialBundleV2(value)
|
|
553
|
-
const digest = new Uint8Array(await crypto.subtle.digest('SHA-256', new TextEncoder().encode(value)))
|
|
554
|
-
return [...digest].map((byte) => byte.toString(16).padStart(2, '0')).join('')
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
export async function zeropsSourceCredentialEnvV2(connectionId: string): Promise<string> {
|
|
558
|
-
const canonicalConnectionId = identifier(connectionId, 'source credential connectionId')
|
|
559
|
-
const digest = new Uint8Array(await crypto.subtle.digest('SHA-256', new TextEncoder().encode(canonicalConnectionId)))
|
|
560
|
-
return `${ZEROPS_SOURCE_CREDENTIAL_ENV_V2_PREFIX}${[...digest].map((byte) => byte.toString(16).padStart(2, '0')).join('')}`
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
const installationId = (value: unknown, label: string): number => {
|
|
564
|
-
if (typeof value !== 'number' || !Number.isSafeInteger(value) || value <= 0) throw new Error(`${label} must be a positive safe integer`)
|
|
565
|
-
return value
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
const optionalCommitSha = (value: unknown, label: string): string | undefined => value === undefined ? undefined : commitSha(value, label)
|
|
569
|
-
|
|
570
|
-
const optionalInstallationId = (value: unknown, label: string): number | undefined => value === undefined ? undefined : installationId(value, label)
|
|
571
|
-
|
|
572
|
-
const privateBindingV2 = (value: unknown, label: string): ZeropsSourcePrivateBindingV2 => {
|
|
573
|
-
const parsed = record(value, label)
|
|
574
|
-
exactKeys(parsed, ['connectionId', 'installationId'], label)
|
|
575
|
-
return {
|
|
576
|
-
connectionId: identifier(parsed['connectionId'], `${label}.connectionId`),
|
|
577
|
-
installationId: installationId(parsed['installationId'], `${label}.installationId`),
|
|
578
|
-
}
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
const optionalPrivateBindingV2 = (value: unknown, label: string): ZeropsSourcePrivateBindingV2 | undefined =>
|
|
582
|
-
value === undefined ? undefined : privateBindingV2(value, label)
|
|
583
|
-
|
|
584
|
-
const repository = (value: unknown, label: string): ZeropsSourceRepository => {
|
|
585
|
-
const parsed = record(value, label)
|
|
586
|
-
exactKeys(parsed, ['owner', 'name'], label)
|
|
587
|
-
const owner = boundedString(parsed['owner'], `${label}.owner`, 39)
|
|
588
|
-
const name = boundedString(parsed['name'], `${label}.name`, 100)
|
|
589
|
-
if (!GITHUB_OWNER_PATTERN.test(owner)) throw new Error(`${label}.owner must be a normalized lowercase GitHub owner`)
|
|
590
|
-
if (!GITHUB_REPOSITORY_PATTERN.test(name) || name === '.' || name === '..') {
|
|
591
|
-
throw new Error(`${label}.name must be a normalized lowercase GitHub repository name`)
|
|
592
|
-
}
|
|
593
|
-
return { owner, name }
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
const descriptor = (value: unknown, label: string): ZeropsSourceDescriptor => {
|
|
597
|
-
const parsed = record(value, label)
|
|
598
|
-
exactKeys(parsed, ['path', 'sha256'], label)
|
|
599
|
-
if (parsed['path'] !== 'zerops.yaml') throw new Error(`${label}.path must be zerops.yaml`)
|
|
600
|
-
return { path: 'zerops.yaml', sha256: sha256(parsed['sha256'], `${label}.sha256`) }
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
const githubAppIdentity = (value: unknown, label: string): ZeropsSourceGitHubAppIdentityV1 => {
|
|
604
|
-
const parsed = record(value, label)
|
|
605
|
-
exactKeys(parsed, ['id', 'slug', 'htmlUrl', 'public', 'owner', 'permissions', 'events'], label)
|
|
606
|
-
const id = installationId(parsed['id'], `${label}.id`)
|
|
607
|
-
const slug = boundedString(parsed['slug'], `${label}.slug`, 100)
|
|
608
|
-
if (!GITHUB_APP_SLUG_PATTERN.test(slug)) throw new Error(`${label}.slug is invalid`)
|
|
609
|
-
const htmlUrl = boundedString(parsed['htmlUrl'], `${label}.htmlUrl`, 2048)
|
|
610
|
-
let parsedHtmlUrl: URL
|
|
611
|
-
try {
|
|
612
|
-
parsedHtmlUrl = new URL(htmlUrl)
|
|
613
|
-
} catch {
|
|
614
|
-
throw new Error(`${label}.htmlUrl is invalid`)
|
|
615
|
-
}
|
|
616
|
-
if (
|
|
617
|
-
parsedHtmlUrl.protocol !== 'https:' || parsedHtmlUrl.hostname !== 'github.com' || parsedHtmlUrl.port !== ''
|
|
618
|
-
|| parsedHtmlUrl.username !== '' || parsedHtmlUrl.password !== '' || parsedHtmlUrl.search !== '' || parsedHtmlUrl.hash !== ''
|
|
619
|
-
|| parsedHtmlUrl.pathname !== `/apps/${slug}`
|
|
620
|
-
) {
|
|
621
|
-
throw new Error(`${label}.htmlUrl is invalid`)
|
|
622
|
-
}
|
|
623
|
-
if (typeof parsed['public'] !== 'boolean') throw new Error(`${label}.public must be boolean`)
|
|
624
|
-
const owner = record(parsed['owner'], `${label}.owner`)
|
|
625
|
-
exactKeys(owner, ['login', 'type'], `${label}.owner`)
|
|
626
|
-
const login = boundedString(owner['login'], `${label}.owner.login`, 100)
|
|
627
|
-
if (!GITHUB_LOGIN_PATTERN.test(login) || owner['type'] !== 'Organization') throw new Error(`${label}.owner is invalid`)
|
|
628
|
-
const permissions = record(parsed['permissions'], `${label}.permissions`)
|
|
629
|
-
exactKeys(permissions, ['contents'], `${label}.permissions`)
|
|
630
|
-
if (permissions['contents'] !== 'read') throw new Error(`${label}.permissions is invalid`)
|
|
631
|
-
if (!Array.isArray(parsed['events']) || parsed['events'].length !== 1 || parsed['events'][0] !== 'push') {
|
|
632
|
-
throw new Error(`${label}.events is invalid`)
|
|
633
|
-
}
|
|
634
|
-
return {
|
|
635
|
-
id,
|
|
636
|
-
slug,
|
|
637
|
-
htmlUrl,
|
|
638
|
-
public: parsed['public'],
|
|
639
|
-
owner: { login, type: 'Organization' },
|
|
640
|
-
permissions: { contents: 'read' },
|
|
641
|
-
events: ['push'],
|
|
642
|
-
}
|
|
643
|
-
}
|
|
644
|
-
|
|
645
|
-
const optionalFields = (value: Record<string, unknown>, required: readonly string[], optional: readonly string[], label: string): void => {
|
|
646
|
-
const allowed = [...required, ...optional]
|
|
647
|
-
const unknownKey = Object.keys(value).find((key) => !allowed.includes(key))
|
|
648
|
-
if (unknownKey !== undefined) throw new Error(`${label} contains an unknown field`)
|
|
649
|
-
const missingKey = required.find((key) => !(key in value))
|
|
650
|
-
if (missingKey !== undefined) throw new Error(`${label} is missing field ${missingKey}`)
|
|
651
|
-
for (const key of optional) {
|
|
652
|
-
if (key in value && value[key] === undefined) throw new Error(`${label}.${key} must be omitted instead of undefined`)
|
|
653
|
-
}
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
/** Validate only credential-safe URL structure; the source runtime owns the exact Zerops destination allowlist. */
|
|
657
|
-
const uploadUrl = (value: unknown, label: string): string => {
|
|
658
|
-
const candidate = boundedString(value, label, MAX_UPLOAD_URL_LENGTH)
|
|
659
|
-
if (/\s/u.test(candidate) || candidate.includes('#')) throw new Error(`${label} must be a signed HTTPS URL`)
|
|
660
|
-
let parsed: URL
|
|
661
|
-
try {
|
|
662
|
-
parsed = new URL(candidate)
|
|
663
|
-
} catch {
|
|
664
|
-
throw new Error(`${label} must be a signed HTTPS URL`)
|
|
665
|
-
}
|
|
666
|
-
if (
|
|
667
|
-
parsed.protocol !== 'https:'
|
|
668
|
-
|| parsed.username !== ''
|
|
669
|
-
|| parsed.password !== ''
|
|
670
|
-
|| parsed.hash !== ''
|
|
671
|
-
|| parsed.search === ''
|
|
672
|
-
) {
|
|
673
|
-
throw new Error(`${label} must be a signed HTTPS URL without userinfo or fragment`)
|
|
674
|
-
}
|
|
675
|
-
return candidate
|
|
676
|
-
}
|
|
677
|
-
|
|
678
|
-
export function normalizeZeropsSourceRepository(repoUrl: string): ZeropsSourceRepository {
|
|
679
|
-
if (/\s/u.test(repoUrl) || /\p{Cc}/u.test(repoUrl)) {
|
|
680
|
-
throw new Error('source repository URL must be a canonical GitHub repository URL')
|
|
681
|
-
}
|
|
682
|
-
const candidate = repoUrl.startsWith('github.com/') ? `https://${repoUrl}` : repoUrl
|
|
683
|
-
let parsed: URL
|
|
684
|
-
try {
|
|
685
|
-
parsed = new URL(candidate)
|
|
686
|
-
} catch {
|
|
687
|
-
throw new Error('source repository URL must be a canonical GitHub repository URL')
|
|
688
|
-
}
|
|
689
|
-
if (
|
|
690
|
-
parsed.protocol !== 'https:' || parsed.hostname !== 'github.com' || parsed.port !== '' || parsed.username !== '' || parsed.password !== ''
|
|
691
|
-
|| parsed.search !== '' || parsed.hash !== ''
|
|
692
|
-
) {
|
|
693
|
-
throw new Error('source repository URL must be an HTTPS GitHub URL without credentials, port, query, or fragment')
|
|
694
|
-
}
|
|
695
|
-
const segments = parsed.pathname.split('/')
|
|
696
|
-
if (segments.length !== 3 || segments[0] !== '') throw new Error('source repository URL must identify one GitHub repository')
|
|
697
|
-
const owner = segments[1]
|
|
698
|
-
const rawName = segments[2]
|
|
699
|
-
if (owner === undefined || rawName === undefined) throw new Error('source repository URL must identify one GitHub repository')
|
|
700
|
-
const name = rawName.endsWith('.git') ? rawName.slice(0, -4) : rawName
|
|
701
|
-
return repository({ owner: owner.toLowerCase(), name: name.toLowerCase() }, 'source repository')
|
|
702
|
-
}
|
|
703
|
-
|
|
704
|
-
export function decodeZeropsSourceCredentialActivateRequestV2(value: unknown): ZeropsSourceCredentialActivateRequestV2 {
|
|
705
|
-
const parsed = record(value, 'source credential activate request v2')
|
|
706
|
-
exactKeys(
|
|
707
|
-
parsed,
|
|
708
|
-
['protocolVersion', 'connectionId', 'credentialBundle', 'credentialSha256'],
|
|
709
|
-
'source credential activate request v2',
|
|
710
|
-
)
|
|
711
|
-
const connectionId = identifier(parsed['connectionId'], 'source credential activate request v2.connectionId')
|
|
712
|
-
const credentialBundle = boundedString(
|
|
713
|
-
parsed['credentialBundle'],
|
|
714
|
-
'source credential activate request v2.credentialBundle',
|
|
715
|
-
MAX_SOURCE_CREDENTIAL_BUNDLE_BYTES,
|
|
716
|
-
)
|
|
717
|
-
const bundle = decodeZeropsSourceCredentialBundleV2(credentialBundle)
|
|
718
|
-
if (bundle.connectionId !== connectionId) throw new Error('source credential activate request v2 connectionId does not match its bundle')
|
|
719
|
-
return {
|
|
720
|
-
protocolVersion: protocolVersionV2(parsed, 'source credential activate request v2'),
|
|
721
|
-
connectionId,
|
|
722
|
-
credentialBundle,
|
|
723
|
-
credentialSha256: sha256(parsed['credentialSha256'], 'source credential activate request v2.credentialSha256'),
|
|
724
|
-
}
|
|
725
|
-
}
|
|
726
|
-
|
|
727
|
-
export function buildZeropsSourceCredentialActivateRequestV2(
|
|
728
|
-
input: ZeropsSourceCredentialActivateInput,
|
|
729
|
-
): ZeropsSourceCredentialActivateRequestV2 {
|
|
730
|
-
return decodeZeropsSourceCredentialActivateRequestV2({
|
|
731
|
-
protocolVersion: ZEROPS_SOURCE_PROTOCOL_VERSION_V2,
|
|
732
|
-
connectionId: input.connectionId,
|
|
733
|
-
credentialBundle: input.credentialBundle,
|
|
734
|
-
credentialSha256: input.credentialSha256,
|
|
735
|
-
})
|
|
736
|
-
}
|
|
737
|
-
|
|
738
|
-
export function decodeZeropsSourceCredentialActivateResponseV2(value: unknown): ZeropsSourceCredentialActivateResponseV2 {
|
|
739
|
-
const parsed = record(value, 'source credential activate response v2')
|
|
740
|
-
exactKeys(
|
|
741
|
-
parsed,
|
|
742
|
-
['protocolVersion', 'connectionId', 'credentialVersion', 'credentialSha256', 'githubApp'],
|
|
743
|
-
'source credential activate response v2',
|
|
744
|
-
)
|
|
745
|
-
if (parsed['credentialVersion'] !== ZEROPS_SOURCE_CREDENTIAL_BUNDLE_VERSION_V2) {
|
|
746
|
-
throw new Error('source credential activate response v2 has an unsupported credentialVersion')
|
|
747
|
-
}
|
|
748
|
-
return {
|
|
749
|
-
protocolVersion: protocolVersionV2(parsed, 'source credential activate response v2'),
|
|
750
|
-
connectionId: identifier(parsed['connectionId'], 'source credential activate response v2.connectionId'),
|
|
751
|
-
credentialVersion: ZEROPS_SOURCE_CREDENTIAL_BUNDLE_VERSION_V2,
|
|
752
|
-
credentialSha256: sha256(parsed['credentialSha256'], 'source credential activate response v2.credentialSha256'),
|
|
753
|
-
githubApp: githubAppIdentity(parsed['githubApp'], 'source credential activate response v2.githubApp'),
|
|
754
|
-
}
|
|
755
|
-
}
|
|
756
|
-
|
|
757
|
-
export function buildZeropsSourceCredentialActivateResponseV2(
|
|
758
|
-
input: Omit<ZeropsSourceCredentialActivateResponseV2, 'protocolVersion'>,
|
|
759
|
-
): ZeropsSourceCredentialActivateResponseV2 {
|
|
760
|
-
return decodeZeropsSourceCredentialActivateResponseV2({ protocolVersion: ZEROPS_SOURCE_PROTOCOL_VERSION_V2, ...input })
|
|
761
|
-
}
|
|
762
|
-
|
|
763
|
-
export function decodeZeropsSourceCredentialStatusRequestV2(value: unknown): ZeropsSourceCredentialStatusRequestV2 {
|
|
764
|
-
const parsed = record(value, 'source credential status request v2')
|
|
765
|
-
exactKeys(parsed, ['protocolVersion', 'connectionId'], 'source credential status request v2')
|
|
766
|
-
return {
|
|
767
|
-
protocolVersion: protocolVersionV2(parsed, 'source credential status request v2'),
|
|
768
|
-
connectionId: identifier(parsed['connectionId'], 'source credential status request v2.connectionId'),
|
|
769
|
-
}
|
|
770
|
-
}
|
|
771
|
-
|
|
772
|
-
export function buildZeropsSourceCredentialStatusRequestV2(
|
|
773
|
-
input: ZeropsSourceCredentialStatusInput,
|
|
774
|
-
): ZeropsSourceCredentialStatusRequestV2 {
|
|
775
|
-
return decodeZeropsSourceCredentialStatusRequestV2({
|
|
776
|
-
protocolVersion: ZEROPS_SOURCE_PROTOCOL_VERSION_V2,
|
|
777
|
-
connectionId: input.connectionId,
|
|
778
|
-
})
|
|
779
|
-
}
|
|
780
|
-
|
|
781
|
-
export function decodeZeropsSourceCredentialStatusResponseV2(value: unknown): ZeropsSourceCredentialStatusResponseV2 {
|
|
782
|
-
const parsed = record(value, 'source credential status response v2')
|
|
783
|
-
if (parsed['state'] === 'anonymous') {
|
|
784
|
-
exactKeys(parsed, ['protocolVersion', 'connectionId', 'state'], 'source credential status response v2')
|
|
785
|
-
return {
|
|
786
|
-
protocolVersion: protocolVersionV2(parsed, 'source credential status response v2'),
|
|
787
|
-
connectionId: identifier(parsed['connectionId'], 'source credential status response v2.connectionId'),
|
|
788
|
-
state: 'anonymous',
|
|
789
|
-
}
|
|
790
|
-
}
|
|
791
|
-
if (parsed['state'] !== 'active') throw new Error('source credential status response v2.state is invalid')
|
|
792
|
-
exactKeys(
|
|
793
|
-
parsed,
|
|
794
|
-
['protocolVersion', 'connectionId', 'state', 'credentialVersion', 'credentialSha256', 'githubApp'],
|
|
795
|
-
'source credential status response v2',
|
|
796
|
-
)
|
|
797
|
-
const active = decodeZeropsSourceCredentialActivateResponseV2({
|
|
798
|
-
protocolVersion: parsed['protocolVersion'],
|
|
799
|
-
connectionId: parsed['connectionId'],
|
|
800
|
-
credentialVersion: parsed['credentialVersion'],
|
|
801
|
-
credentialSha256: parsed['credentialSha256'],
|
|
802
|
-
githubApp: parsed['githubApp'],
|
|
803
|
-
})
|
|
804
|
-
return { ...active, state: 'active' }
|
|
805
|
-
}
|
|
806
|
-
|
|
807
|
-
export function buildZeropsSourceCredentialStatusResponseV2(
|
|
808
|
-
input:
|
|
809
|
-
| { readonly connectionId: string; readonly state: 'anonymous' }
|
|
810
|
-
| Omit<ZeropsSourceCredentialActiveStatusResponseV2, 'protocolVersion'>,
|
|
811
|
-
): ZeropsSourceCredentialStatusResponseV2 {
|
|
812
|
-
return decodeZeropsSourceCredentialStatusResponseV2({ protocolVersion: ZEROPS_SOURCE_PROTOCOL_VERSION_V2, ...input })
|
|
813
|
-
}
|
|
814
|
-
|
|
815
|
-
const WEBHOOK_PATH = '/webhooks/github'
|
|
816
|
-
|
|
817
|
-
/**
|
|
818
|
-
* Only the Zerops `source` configure wire reaches this, and every Zerops connection appends its own id
|
|
819
|
-
* so one App's deliveries cannot be replayed against another. The bare path is a Cloudflare URL and is
|
|
820
|
-
* refused here (ADR-0039).
|
|
821
|
-
*/
|
|
822
|
-
const isWebhookPath = (pathname: string): boolean => {
|
|
823
|
-
if (!pathname.startsWith(`${WEBHOOK_PATH}/`)) return false
|
|
824
|
-
const connectionId = pathname.slice(WEBHOOK_PATH.length + 1)
|
|
825
|
-
// `ID_PATTERN` has no `%`, so a percent-escape in the path fails here rather than round-tripping.
|
|
826
|
-
return connectionId.length > 0 && connectionId.length <= MAX_ID_LENGTH && ID_PATTERN.test(connectionId)
|
|
827
|
-
}
|
|
828
|
-
|
|
829
|
-
const webhookUrl = (value: unknown, label: string): string => {
|
|
830
|
-
const candidate = boundedString(value, label, MAX_WEBHOOK_URL_LENGTH)
|
|
831
|
-
let parsed: URL
|
|
832
|
-
try {
|
|
833
|
-
parsed = new URL(candidate)
|
|
834
|
-
} catch {
|
|
835
|
-
throw new Error(`${label} must be a secure URL`)
|
|
836
|
-
}
|
|
837
|
-
if (
|
|
838
|
-
parsed.protocol !== 'https:' || parsed.port !== '' || parsed.username !== '' || parsed.password !== '' || parsed.search !== '' || parsed.hash !== ''
|
|
839
|
-
|| !isWebhookPath(parsed.pathname) || parsed.hostname === '' || candidate !== parsed.href
|
|
840
|
-
) throw new Error(`${label} must be an exact secure GitHub webhook URL`)
|
|
841
|
-
return candidate
|
|
842
|
-
}
|
|
843
|
-
|
|
844
|
-
const webhookSecret = (value: unknown, label: string): string => {
|
|
845
|
-
const secret = boundedString(value, label, MAX_WEBHOOK_SECRET_LENGTH)
|
|
846
|
-
if ([...secret].some((character) => character.charCodeAt(0) < 0x20 || character.charCodeAt(0) === 0x7f)) {
|
|
847
|
-
throw new Error(`${label} is invalid`)
|
|
848
|
-
}
|
|
849
|
-
return secret
|
|
850
|
-
}
|
|
851
|
-
|
|
852
|
-
export function decodeZeropsSourceWebhookConfigureRequest(value: unknown): ZeropsSourceWebhookConfigureRequestV1 {
|
|
853
|
-
const parsed = record(value, 'source webhook configure request')
|
|
854
|
-
exactKeys(parsed, ['protocolVersion', 'connectionId', 'credentialSha256', 'url', 'secret'], 'source webhook configure request')
|
|
855
|
-
return {
|
|
856
|
-
protocolVersion: protocolVersion(parsed, 'source webhook configure request'),
|
|
857
|
-
connectionId: identifier(parsed['connectionId'], 'source webhook configure request.connectionId'),
|
|
858
|
-
credentialSha256: sha256(parsed['credentialSha256'], 'source webhook configure request.credentialSha256'),
|
|
859
|
-
url: webhookUrl(parsed['url'], 'source webhook configure request.url'),
|
|
860
|
-
secret: webhookSecret(parsed['secret'], 'source webhook configure request.secret'),
|
|
861
|
-
}
|
|
862
|
-
}
|
|
863
|
-
|
|
864
|
-
export function buildZeropsSourceWebhookConfigureRequest(input: ZeropsSourceWebhookConfigureInput): ZeropsSourceWebhookConfigureRequestV1 {
|
|
865
|
-
return decodeZeropsSourceWebhookConfigureRequest({
|
|
866
|
-
protocolVersion: ZEROPS_SOURCE_PROTOCOL_VERSION,
|
|
867
|
-
connectionId: input.connectionId,
|
|
868
|
-
credentialSha256: input.credentialSha256,
|
|
869
|
-
url: input.url,
|
|
870
|
-
secret: input.secret,
|
|
871
|
-
})
|
|
872
|
-
}
|
|
873
|
-
|
|
874
|
-
export function decodeZeropsSourceWebhookConfigureResponse(value: unknown): ZeropsSourceWebhookConfigureResponseV1 {
|
|
875
|
-
const parsed = record(value, 'source webhook configure response')
|
|
876
|
-
exactKeys(parsed, ['protocolVersion', 'connectionId', 'credentialSha256', 'webhook'], 'source webhook configure response')
|
|
877
|
-
const webhook = record(parsed['webhook'], 'source webhook configure response.webhook')
|
|
878
|
-
exactKeys(webhook, ['url', 'contentType', 'insecureSsl'], 'source webhook configure response.webhook')
|
|
879
|
-
if (webhook['contentType'] !== 'json' || webhook['insecureSsl'] !== '0') throw new Error('source webhook configure response is insecure')
|
|
880
|
-
return {
|
|
881
|
-
protocolVersion: protocolVersion(parsed, 'source webhook configure response'),
|
|
882
|
-
connectionId: identifier(parsed['connectionId'], 'source webhook configure response.connectionId'),
|
|
883
|
-
credentialSha256: sha256(parsed['credentialSha256'], 'source webhook configure response.credentialSha256'),
|
|
884
|
-
webhook: { url: webhookUrl(webhook['url'], 'source webhook configure response.webhook.url'), contentType: 'json', insecureSsl: '0' },
|
|
885
|
-
}
|
|
886
|
-
}
|
|
887
|
-
|
|
888
|
-
export function buildZeropsSourceWebhookConfigureResponse(
|
|
889
|
-
input: Omit<ZeropsSourceWebhookConfigureResponseV1, 'protocolVersion'>,
|
|
890
|
-
): ZeropsSourceWebhookConfigureResponseV1 {
|
|
891
|
-
return decodeZeropsSourceWebhookConfigureResponse({ protocolVersion: ZEROPS_SOURCE_PROTOCOL_VERSION, ...input })
|
|
892
|
-
}
|
|
893
|
-
|
|
894
|
-
const installationScope = (value: unknown, label: string): ZeropsSourceInstallationScopeV1 => {
|
|
895
|
-
const parsed = record(value, label)
|
|
896
|
-
if (parsed['kind'] === 'organization') {
|
|
897
|
-
exactKeys(parsed, ['kind', 'organization'], label)
|
|
898
|
-
const organization = boundedString(parsed['organization'], `${label}.organization`, 39).toLowerCase()
|
|
899
|
-
if (!GITHUB_OWNER_PATTERN.test(organization)) throw new Error(`${label}.organization is invalid`)
|
|
900
|
-
return { kind: 'organization', organization }
|
|
901
|
-
}
|
|
902
|
-
if (parsed['kind'] !== 'repositories') throw new Error(`${label}.kind is invalid`)
|
|
903
|
-
exactKeys(parsed, ['kind', 'repositories'], label)
|
|
904
|
-
if (!Array.isArray(parsed['repositories']) || parsed['repositories'].length === 0 || parsed['repositories'].length > MAX_INSTALLATION_REPOSITORIES) {
|
|
905
|
-
throw new Error(`${label}.repositories is invalid`)
|
|
906
|
-
}
|
|
907
|
-
const repositories = parsed['repositories'].map((entry) => repository(entry, `${label}.repositories entry`))
|
|
908
|
-
const keys = repositories.map((entry) => `${entry.owner}/${entry.name}`)
|
|
909
|
-
if (new Set(keys).size !== keys.length) throw new Error(`${label}.repositories contains a duplicate`)
|
|
910
|
-
return { kind: 'repositories', repositories }
|
|
911
|
-
}
|
|
912
|
-
|
|
913
|
-
export function decodeZeropsSourceInstallationsVerifyRequest(value: unknown): ZeropsSourceInstallationsVerifyRequestV1 {
|
|
914
|
-
const parsed = record(value, 'source installations verify request')
|
|
915
|
-
exactKeys(parsed, ['protocolVersion', 'connectionId', 'credentialSha256', 'scope'], 'source installations verify request')
|
|
916
|
-
return {
|
|
917
|
-
protocolVersion: protocolVersion(parsed, 'source installations verify request'),
|
|
918
|
-
connectionId: identifier(parsed['connectionId'], 'source installations verify request.connectionId'),
|
|
919
|
-
credentialSha256: sha256(parsed['credentialSha256'], 'source installations verify request.credentialSha256'),
|
|
920
|
-
scope: installationScope(parsed['scope'], 'source installations verify request.scope'),
|
|
921
|
-
}
|
|
922
|
-
}
|
|
923
|
-
|
|
924
|
-
export function buildZeropsSourceInstallationsVerifyRequest(
|
|
925
|
-
input: ZeropsSourceInstallationsVerifyInput,
|
|
926
|
-
): ZeropsSourceInstallationsVerifyRequestV1 {
|
|
927
|
-
return decodeZeropsSourceInstallationsVerifyRequest({
|
|
928
|
-
protocolVersion: ZEROPS_SOURCE_PROTOCOL_VERSION,
|
|
929
|
-
connectionId: input.connectionId,
|
|
930
|
-
credentialSha256: input.credentialSha256,
|
|
931
|
-
scope: input.scope,
|
|
932
|
-
})
|
|
933
|
-
}
|
|
934
|
-
|
|
935
|
-
const installationVerification = (value: unknown, label: string): ZeropsSourceInstallationVerificationV1 => {
|
|
936
|
-
const parsed = record(value, label)
|
|
937
|
-
if (parsed['status'] === 'missing') {
|
|
938
|
-
exactKeys(parsed, ['status'], label)
|
|
939
|
-
return { status: 'missing' }
|
|
940
|
-
}
|
|
941
|
-
if (parsed['status'] !== 'installed') throw new Error(`${label}.status is invalid`)
|
|
942
|
-
exactKeys(parsed, ['status', 'installationId', 'accountLogin', 'repositorySelection'], label)
|
|
943
|
-
const accountLogin = boundedString(parsed['accountLogin'], `${label}.accountLogin`, 100)
|
|
944
|
-
if (!GITHUB_LOGIN_PATTERN.test(accountLogin)) throw new Error(`${label}.accountLogin is invalid`)
|
|
945
|
-
const repositorySelection = parsed['repositorySelection']
|
|
946
|
-
if (repositorySelection !== 'all' && repositorySelection !== 'selected') throw new Error(`${label}.repositorySelection is invalid`)
|
|
947
|
-
return {
|
|
948
|
-
status: 'installed',
|
|
949
|
-
installationId: installationId(parsed['installationId'], `${label}.installationId`),
|
|
950
|
-
accountLogin,
|
|
951
|
-
repositorySelection,
|
|
952
|
-
}
|
|
953
|
-
}
|
|
954
|
-
|
|
955
|
-
export function decodeZeropsSourceInstallationsVerifyResponse(value: unknown): ZeropsSourceInstallationsVerifyResponseV1 {
|
|
956
|
-
const parsed = record(value, 'source installations verify response')
|
|
957
|
-
exactKeys(parsed, ['protocolVersion', 'connectionId', 'credentialSha256', 'installation'], 'source installations verify response')
|
|
958
|
-
return {
|
|
959
|
-
protocolVersion: protocolVersion(parsed, 'source installations verify response'),
|
|
960
|
-
connectionId: identifier(parsed['connectionId'], 'source installations verify response.connectionId'),
|
|
961
|
-
credentialSha256: sha256(parsed['credentialSha256'], 'source installations verify response.credentialSha256'),
|
|
962
|
-
installation: installationVerification(parsed['installation'], 'source installations verify response.installation'),
|
|
963
|
-
}
|
|
964
|
-
}
|
|
965
|
-
|
|
966
|
-
export function buildZeropsSourceInstallationsVerifyResponse(
|
|
967
|
-
input: Omit<ZeropsSourceInstallationsVerifyResponseV1, 'protocolVersion'>,
|
|
968
|
-
): ZeropsSourceInstallationsVerifyResponseV1 {
|
|
969
|
-
return decodeZeropsSourceInstallationsVerifyResponse({ protocolVersion: ZEROPS_SOURCE_PROTOCOL_VERSION, ...input })
|
|
970
|
-
}
|
|
971
|
-
|
|
972
|
-
export function decodeZeropsSourceResolveRequest(value: unknown): ZeropsSourceResolveRequestV1 {
|
|
973
|
-
const parsed = record(value, 'source resolve request')
|
|
974
|
-
optionalFields(
|
|
975
|
-
parsed,
|
|
976
|
-
['protocolVersion', 'runId', 'repository', 'requestedRef', 'descriptorSha256'],
|
|
977
|
-
['expectedCommitSha', 'githubInstallationId'],
|
|
978
|
-
'source resolve request',
|
|
979
|
-
)
|
|
980
|
-
const expected = optionalCommitSha(parsed['expectedCommitSha'], 'source resolve request.expectedCommitSha')
|
|
981
|
-
const installation = optionalInstallationId(parsed['githubInstallationId'], 'source resolve request.githubInstallationId')
|
|
982
|
-
return {
|
|
983
|
-
protocolVersion: protocolVersion(parsed, 'source resolve request'),
|
|
984
|
-
runId: identifier(parsed['runId'], 'source resolve request.runId'),
|
|
985
|
-
repository: repository(parsed['repository'], 'source resolve request.repository'),
|
|
986
|
-
requestedRef: ref(parsed['requestedRef'], 'source resolve request.requestedRef'),
|
|
987
|
-
...(expected !== undefined ? { expectedCommitSha: expected } : {}),
|
|
988
|
-
...(installation !== undefined ? { githubInstallationId: installation } : {}),
|
|
989
|
-
descriptorSha256: sha256(parsed['descriptorSha256'], 'source resolve request.descriptorSha256'),
|
|
990
|
-
}
|
|
991
|
-
}
|
|
992
|
-
|
|
993
|
-
export function buildZeropsSourceResolveRequest(input: ZeropsSourceResolveInput): ZeropsSourceResolveRequestV1 {
|
|
994
|
-
return decodeZeropsSourceResolveRequest({
|
|
995
|
-
protocolVersion: ZEROPS_SOURCE_PROTOCOL_VERSION,
|
|
996
|
-
runId: input.runId,
|
|
997
|
-
repository: input.repository,
|
|
998
|
-
requestedRef: input.requestedRef,
|
|
999
|
-
...(input.expectedCommitSha !== undefined ? { expectedCommitSha: input.expectedCommitSha } : {}),
|
|
1000
|
-
...(input.githubInstallationId !== undefined ? { githubInstallationId: input.githubInstallationId } : {}),
|
|
1001
|
-
descriptorSha256: input.descriptorSha256,
|
|
1002
|
-
})
|
|
1003
|
-
}
|
|
1004
|
-
|
|
1005
|
-
export function decodeZeropsSourceResolveResponse(value: unknown): ZeropsSourceResolveResponseV1 {
|
|
1006
|
-
const parsed = record(value, 'source resolve response')
|
|
1007
|
-
exactKeys(parsed, ['protocolVersion', 'runId', 'commitSha', 'descriptorSha256'], 'source resolve response')
|
|
1008
|
-
return {
|
|
1009
|
-
protocolVersion: protocolVersion(parsed, 'source resolve response'),
|
|
1010
|
-
runId: identifier(parsed['runId'], 'source resolve response.runId'),
|
|
1011
|
-
commitSha: commitSha(parsed['commitSha'], 'source resolve response.commitSha'),
|
|
1012
|
-
descriptorSha256: sha256(parsed['descriptorSha256'], 'source resolve response.descriptorSha256'),
|
|
1013
|
-
}
|
|
1014
|
-
}
|
|
1015
|
-
|
|
1016
|
-
export function buildZeropsSourceResolveResponse(result: ZeropsSourceResolveResult): ZeropsSourceResolveResponseV1 {
|
|
1017
|
-
return decodeZeropsSourceResolveResponse({ protocolVersion: ZEROPS_SOURCE_PROTOCOL_VERSION, ...result })
|
|
1018
|
-
}
|
|
1019
|
-
|
|
1020
|
-
export function decodeZeropsSourceUploadRequest(value: unknown): ZeropsSourceUploadRequestV1 {
|
|
1021
|
-
const parsed = record(value, 'source upload request')
|
|
1022
|
-
optionalFields(
|
|
1023
|
-
parsed,
|
|
1024
|
-
['protocolVersion', 'runId', 'appVersionId', 'repository', 'commitSha', 'uploadUrl', 'descriptor'],
|
|
1025
|
-
['githubInstallationId'],
|
|
1026
|
-
'source upload request',
|
|
1027
|
-
)
|
|
1028
|
-
const installation = optionalInstallationId(parsed['githubInstallationId'], 'source upload request.githubInstallationId')
|
|
1029
|
-
return {
|
|
1030
|
-
protocolVersion: protocolVersion(parsed, 'source upload request'),
|
|
1031
|
-
runId: identifier(parsed['runId'], 'source upload request.runId'),
|
|
1032
|
-
appVersionId: identifier(parsed['appVersionId'], 'source upload request.appVersionId'),
|
|
1033
|
-
repository: repository(parsed['repository'], 'source upload request.repository'),
|
|
1034
|
-
commitSha: commitSha(parsed['commitSha'], 'source upload request.commitSha'),
|
|
1035
|
-
...(installation !== undefined ? { githubInstallationId: installation } : {}),
|
|
1036
|
-
uploadUrl: uploadUrl(parsed['uploadUrl'], 'source upload request.uploadUrl'),
|
|
1037
|
-
descriptor: descriptor(parsed['descriptor'], 'source upload request.descriptor'),
|
|
1038
|
-
}
|
|
1039
|
-
}
|
|
1040
|
-
|
|
1041
|
-
export function buildZeropsSourceUploadRequest(input: ZeropsSourceUploadInput): ZeropsSourceUploadRequestV1 {
|
|
1042
|
-
return decodeZeropsSourceUploadRequest({
|
|
1043
|
-
protocolVersion: ZEROPS_SOURCE_PROTOCOL_VERSION,
|
|
1044
|
-
runId: input.runId,
|
|
1045
|
-
appVersionId: input.appVersionId,
|
|
1046
|
-
repository: input.repository,
|
|
1047
|
-
commitSha: input.commitSha,
|
|
1048
|
-
...(input.githubInstallationId !== undefined ? { githubInstallationId: input.githubInstallationId } : {}),
|
|
1049
|
-
uploadUrl: input.uploadUrl,
|
|
1050
|
-
descriptor: input.descriptor,
|
|
1051
|
-
})
|
|
1052
|
-
}
|
|
1053
|
-
|
|
1054
|
-
export function decodeZeropsSourceUploadResponse(value: unknown): ZeropsSourceUploadResponseV1 {
|
|
1055
|
-
const parsed = record(value, 'source upload response')
|
|
1056
|
-
exactKeys(parsed, ['protocolVersion', 'runId', 'appVersionId', 'commitSha', 'descriptorSha256'], 'source upload response')
|
|
1057
|
-
return {
|
|
1058
|
-
protocolVersion: protocolVersion(parsed, 'source upload response'),
|
|
1059
|
-
runId: identifier(parsed['runId'], 'source upload response.runId'),
|
|
1060
|
-
appVersionId: identifier(parsed['appVersionId'], 'source upload response.appVersionId'),
|
|
1061
|
-
commitSha: commitSha(parsed['commitSha'], 'source upload response.commitSha'),
|
|
1062
|
-
descriptorSha256: sha256(parsed['descriptorSha256'], 'source upload response.descriptorSha256'),
|
|
1063
|
-
}
|
|
1064
|
-
}
|
|
1065
|
-
|
|
1066
|
-
export function buildZeropsSourceUploadResponse(result: ZeropsSourceUploadResult): ZeropsSourceUploadResponseV1 {
|
|
1067
|
-
return decodeZeropsSourceUploadResponse({ protocolVersion: ZEROPS_SOURCE_PROTOCOL_VERSION, ...result })
|
|
1068
|
-
}
|
|
1069
|
-
|
|
1070
|
-
export function decodeZeropsSourceResolveRequestV2(value: unknown): ZeropsSourceResolveRequestV2 {
|
|
1071
|
-
const parsed = record(value, 'source resolve request v2')
|
|
1072
|
-
optionalFields(
|
|
1073
|
-
parsed,
|
|
1074
|
-
['protocolVersion', 'runId', 'repository', 'requestedRef', 'descriptorSha256'],
|
|
1075
|
-
['expectedCommitSha', 'privateBinding'],
|
|
1076
|
-
'source resolve request v2',
|
|
1077
|
-
)
|
|
1078
|
-
const expected = optionalCommitSha(parsed['expectedCommitSha'], 'source resolve request v2.expectedCommitSha')
|
|
1079
|
-
const binding = optionalPrivateBindingV2(parsed['privateBinding'], 'source resolve request v2.privateBinding')
|
|
1080
|
-
return {
|
|
1081
|
-
protocolVersion: protocolVersionV2(parsed, 'source resolve request v2'),
|
|
1082
|
-
runId: identifier(parsed['runId'], 'source resolve request v2.runId'),
|
|
1083
|
-
repository: repository(parsed['repository'], 'source resolve request v2.repository'),
|
|
1084
|
-
requestedRef: ref(parsed['requestedRef'], 'source resolve request v2.requestedRef'),
|
|
1085
|
-
...(expected !== undefined ? { expectedCommitSha: expected } : {}),
|
|
1086
|
-
...(binding !== undefined ? { privateBinding: binding } : {}),
|
|
1087
|
-
descriptorSha256: sha256(parsed['descriptorSha256'], 'source resolve request v2.descriptorSha256'),
|
|
1088
|
-
}
|
|
1089
|
-
}
|
|
1090
|
-
|
|
1091
|
-
export function buildZeropsSourceResolveRequestV2(input: ZeropsSourceResolveInputV2): ZeropsSourceResolveRequestV2 {
|
|
1092
|
-
return decodeZeropsSourceResolveRequestV2({
|
|
1093
|
-
protocolVersion: ZEROPS_SOURCE_PROTOCOL_VERSION_V2,
|
|
1094
|
-
runId: input.runId,
|
|
1095
|
-
repository: input.repository,
|
|
1096
|
-
requestedRef: input.requestedRef,
|
|
1097
|
-
...(input.expectedCommitSha !== undefined ? { expectedCommitSha: input.expectedCommitSha } : {}),
|
|
1098
|
-
...(input.privateBinding !== undefined ? { privateBinding: input.privateBinding } : {}),
|
|
1099
|
-
descriptorSha256: input.descriptorSha256,
|
|
1100
|
-
})
|
|
1101
|
-
}
|
|
1102
|
-
|
|
1103
|
-
export function decodeZeropsSourceResolveResponseV2(value: unknown): ZeropsSourceResolveResponseV2 {
|
|
1104
|
-
const parsed = record(value, 'source resolve response v2')
|
|
1105
|
-
exactKeys(parsed, ['protocolVersion', 'runId', 'commitSha', 'descriptorSha256'], 'source resolve response v2')
|
|
1106
|
-
return {
|
|
1107
|
-
protocolVersion: protocolVersionV2(parsed, 'source resolve response v2'),
|
|
1108
|
-
runId: identifier(parsed['runId'], 'source resolve response v2.runId'),
|
|
1109
|
-
commitSha: commitSha(parsed['commitSha'], 'source resolve response v2.commitSha'),
|
|
1110
|
-
descriptorSha256: sha256(parsed['descriptorSha256'], 'source resolve response v2.descriptorSha256'),
|
|
1111
|
-
}
|
|
1112
|
-
}
|
|
1113
|
-
|
|
1114
|
-
export function buildZeropsSourceResolveResponseV2(result: ZeropsSourceResolveResult): ZeropsSourceResolveResponseV2 {
|
|
1115
|
-
return decodeZeropsSourceResolveResponseV2({ protocolVersion: ZEROPS_SOURCE_PROTOCOL_VERSION_V2, ...result })
|
|
1116
|
-
}
|
|
1117
|
-
|
|
1118
|
-
export function decodeZeropsSourceUploadRequestV2(value: unknown): ZeropsSourceUploadRequestV2 {
|
|
1119
|
-
const parsed = record(value, 'source upload request v2')
|
|
1120
|
-
optionalFields(
|
|
1121
|
-
parsed,
|
|
1122
|
-
['protocolVersion', 'runId', 'appVersionId', 'repository', 'commitSha', 'uploadUrl', 'descriptor'],
|
|
1123
|
-
['privateBinding'],
|
|
1124
|
-
'source upload request v2',
|
|
1125
|
-
)
|
|
1126
|
-
const binding = optionalPrivateBindingV2(parsed['privateBinding'], 'source upload request v2.privateBinding')
|
|
1127
|
-
return {
|
|
1128
|
-
protocolVersion: protocolVersionV2(parsed, 'source upload request v2'),
|
|
1129
|
-
runId: identifier(parsed['runId'], 'source upload request v2.runId'),
|
|
1130
|
-
appVersionId: identifier(parsed['appVersionId'], 'source upload request v2.appVersionId'),
|
|
1131
|
-
repository: repository(parsed['repository'], 'source upload request v2.repository'),
|
|
1132
|
-
commitSha: commitSha(parsed['commitSha'], 'source upload request v2.commitSha'),
|
|
1133
|
-
...(binding !== undefined ? { privateBinding: binding } : {}),
|
|
1134
|
-
uploadUrl: uploadUrl(parsed['uploadUrl'], 'source upload request v2.uploadUrl'),
|
|
1135
|
-
descriptor: descriptor(parsed['descriptor'], 'source upload request v2.descriptor'),
|
|
1136
|
-
}
|
|
1137
|
-
}
|
|
1138
|
-
|
|
1139
|
-
export function buildZeropsSourceUploadRequestV2(input: ZeropsSourceUploadInputV2): ZeropsSourceUploadRequestV2 {
|
|
1140
|
-
return decodeZeropsSourceUploadRequestV2({
|
|
1141
|
-
protocolVersion: ZEROPS_SOURCE_PROTOCOL_VERSION_V2,
|
|
1142
|
-
runId: input.runId,
|
|
1143
|
-
appVersionId: input.appVersionId,
|
|
1144
|
-
repository: input.repository,
|
|
1145
|
-
commitSha: input.commitSha,
|
|
1146
|
-
...(input.privateBinding !== undefined ? { privateBinding: input.privateBinding } : {}),
|
|
1147
|
-
uploadUrl: input.uploadUrl,
|
|
1148
|
-
descriptor: input.descriptor,
|
|
1149
|
-
})
|
|
1150
|
-
}
|
|
1151
|
-
|
|
1152
|
-
export function decodeZeropsSourceUploadResponseV2(value: unknown): ZeropsSourceUploadResponseV2 {
|
|
1153
|
-
const parsed = record(value, 'source upload response v2')
|
|
1154
|
-
exactKeys(parsed, ['protocolVersion', 'runId', 'appVersionId', 'commitSha', 'descriptorSha256'], 'source upload response v2')
|
|
1155
|
-
return {
|
|
1156
|
-
protocolVersion: protocolVersionV2(parsed, 'source upload response v2'),
|
|
1157
|
-
runId: identifier(parsed['runId'], 'source upload response v2.runId'),
|
|
1158
|
-
appVersionId: identifier(parsed['appVersionId'], 'source upload response v2.appVersionId'),
|
|
1159
|
-
commitSha: commitSha(parsed['commitSha'], 'source upload response v2.commitSha'),
|
|
1160
|
-
descriptorSha256: sha256(parsed['descriptorSha256'], 'source upload response v2.descriptorSha256'),
|
|
1161
|
-
}
|
|
1162
|
-
}
|
|
1163
|
-
|
|
1164
|
-
export function buildZeropsSourceUploadResponseV2(result: ZeropsSourceUploadResult): ZeropsSourceUploadResponseV2 {
|
|
1165
|
-
return decodeZeropsSourceUploadResponseV2({ protocolVersion: ZEROPS_SOURCE_PROTOCOL_VERSION_V2, ...result })
|
|
1166
|
-
}
|
|
1167
|
-
|
|
1168
|
-
export function decodeZeropsSourceCancelRequest(value: unknown): ZeropsSourceCancelRequestV1 {
|
|
1169
|
-
const parsed = record(value, 'source cancel request')
|
|
1170
|
-
exactKeys(parsed, ['protocolVersion', 'runId', 'appVersionId'], 'source cancel request')
|
|
1171
|
-
return {
|
|
1172
|
-
protocolVersion: protocolVersion(parsed, 'source cancel request'),
|
|
1173
|
-
runId: identifier(parsed['runId'], 'source cancel request.runId'),
|
|
1174
|
-
appVersionId: identifier(parsed['appVersionId'], 'source cancel request.appVersionId'),
|
|
1175
|
-
}
|
|
1176
|
-
}
|
|
1177
|
-
|
|
1178
|
-
export function buildZeropsSourceCancelRequest(input: ZeropsSourceCancelInput): ZeropsSourceCancelRequestV1 {
|
|
1179
|
-
return decodeZeropsSourceCancelRequest({
|
|
1180
|
-
protocolVersion: ZEROPS_SOURCE_PROTOCOL_VERSION,
|
|
1181
|
-
runId: input.runId,
|
|
1182
|
-
appVersionId: input.appVersionId,
|
|
1183
|
-
})
|
|
1184
|
-
}
|
|
1185
|
-
|
|
1186
|
-
export function decodeZeropsSourceCancelResponse(value: unknown): ZeropsSourceCancelResponseV1 {
|
|
1187
|
-
const parsed = record(value, 'source cancel response')
|
|
1188
|
-
exactKeys(parsed, ['protocolVersion', 'runId', 'appVersionId'], 'source cancel response')
|
|
1189
|
-
return {
|
|
1190
|
-
protocolVersion: protocolVersion(parsed, 'source cancel response'),
|
|
1191
|
-
runId: identifier(parsed['runId'], 'source cancel response.runId'),
|
|
1192
|
-
appVersionId: identifier(parsed['appVersionId'], 'source cancel response.appVersionId'),
|
|
1193
|
-
}
|
|
1194
|
-
}
|
|
1195
|
-
|
|
1196
|
-
export function buildZeropsSourceCancelResponse(result: ZeropsSourceCancelResult): ZeropsSourceCancelResponseV1 {
|
|
1197
|
-
return decodeZeropsSourceCancelResponse({ protocolVersion: ZEROPS_SOURCE_PROTOCOL_VERSION, ...result })
|
|
1198
|
-
}
|
|
1199
|
-
|
|
1200
|
-
const includesString = <T extends string>(values: readonly T[], value: unknown): value is T =>
|
|
1201
|
-
typeof value === 'string' && values.some((entry) => entry === value)
|
|
1202
|
-
|
|
1203
|
-
export function decodeZeropsSourceErrorEnvelope(value: unknown): ZeropsSourceErrorEnvelope {
|
|
1204
|
-
const parsed = record(value, 'source error response')
|
|
1205
|
-
exactKeys(parsed, ['error'], 'source error response')
|
|
1206
|
-
const error = record(parsed['error'], 'source error response.error')
|
|
1207
|
-
exactKeys(error, ['code', 'stage', 'retryable'], 'source error response.error')
|
|
1208
|
-
if (!includesString(ZEROPS_SOURCE_ERROR_CODES, error['code'])) throw new Error('source error response.error.code is invalid')
|
|
1209
|
-
if (!includesString(ZEROPS_SOURCE_ERROR_STAGES, error['stage'])) throw new Error('source error response.error.stage is invalid')
|
|
1210
|
-
if (typeof error['retryable'] !== 'boolean') throw new Error('source error response.error.retryable must be boolean')
|
|
1211
|
-
return { error: { code: error['code'], stage: error['stage'], retryable: error['retryable'] } }
|
|
1212
|
-
}
|
|
1213
|
-
|
|
1214
|
-
export function buildZeropsSourceErrorEnvelope(
|
|
1215
|
-
code: ZeropsSourceErrorCode,
|
|
1216
|
-
stage: ZeropsSourceErrorStage,
|
|
1217
|
-
retryable: boolean,
|
|
1218
|
-
): ZeropsSourceErrorEnvelope {
|
|
1219
|
-
return decodeZeropsSourceErrorEnvelope({ error: { code, stage, retryable } })
|
|
1220
|
-
}
|
|
1
|
+
export type { ZeropsSourceRepository } from './source/types'
|
|
2
|
+
export { isZeropsUploadDestination, normalizeZeropsSourceRepository } from './source/validation'
|