orizu 0.5.26 → 0.5.28
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 +19 -0
- package/dist/artifacts-git-runtime.d.ts +34 -0
- package/dist/artifacts-git-runtime.d.ts.map +1 -0
- package/dist/artifacts-git-runtime.js +312 -0
- package/dist/cloudflare-artifacts-git-remote.d.ts +5 -0
- package/dist/cloudflare-artifacts-git-remote.d.ts.map +1 -0
- package/dist/cloudflare-artifacts-git-remote.js +21 -0
- package/dist/dataset-transfer-download.d.ts +2 -0
- package/dist/dataset-transfer-download.d.ts.map +1 -0
- package/dist/dataset-transfer-download.js +66 -0
- package/dist/dataset-transfer-policy.d.ts +2 -0
- package/dist/dataset-transfer-policy.d.ts.map +1 -0
- package/dist/dataset-transfer-policy.js +8 -0
- package/dist/dataset-transfer-upload.d.ts +42 -0
- package/dist/dataset-transfer-upload.d.ts.map +1 -0
- package/dist/dataset-transfer-upload.js +110 -0
- package/dist/git-credential.d.ts.map +1 -1
- package/dist/git-credential.js +1 -1
- package/dist/git-recovery-environment.d.ts +1 -0
- package/dist/git-recovery-environment.d.ts.map +1 -1
- package/dist/git-recovery-environment.js +1 -1
- package/dist/help.d.ts.map +1 -1
- package/dist/help.js +44 -11
- package/dist/hosted-boot.d.ts +75 -2
- package/dist/hosted-boot.d.ts.map +1 -1
- package/dist/hosted-boot.js +585 -102
- package/dist/hosted-bootstrap.d.ts +2 -0
- package/dist/hosted-bootstrap.d.ts.map +1 -1
- package/dist/hosted-bootstrap.js +12 -3
- package/dist/hosted-harness-opencode.d.ts +8 -9
- package/dist/hosted-harness-opencode.d.ts.map +1 -1
- package/dist/hosted-harness-opencode.js +126 -24
- package/dist/hosted-harness.d.ts +3 -0
- package/dist/hosted-harness.d.ts.map +1 -1
- package/dist/hosted-harness.js +4 -1
- package/dist/hosted-harvest.d.ts +30 -9
- package/dist/hosted-harvest.d.ts.map +1 -1
- package/dist/hosted-harvest.js +222 -28
- package/dist/hosted-loop-lifecycle.d.ts +15 -3
- package/dist/hosted-loop-lifecycle.d.ts.map +1 -1
- package/dist/hosted-loop-lifecycle.js +6 -4
- package/dist/hosted-loop.d.ts +47 -7
- package/dist/hosted-loop.d.ts.map +1 -1
- package/dist/hosted-loop.js +310 -64
- package/dist/hosted-question-limits.d.ts +7 -0
- package/dist/hosted-question-limits.d.ts.map +1 -0
- package/dist/hosted-question-limits.js +6 -0
- package/dist/hosted-question.d.ts +27 -0
- package/dist/hosted-question.d.ts.map +1 -0
- package/dist/hosted-question.js +118 -0
- package/dist/hosted-run-event-sink.d.ts +10 -5
- package/dist/hosted-run-event-sink.d.ts.map +1 -1
- package/dist/hosted-run-event-sink.js +12 -8
- package/dist/hosted-runtime-assets.d.ts +16 -7
- package/dist/hosted-runtime-assets.d.ts.map +1 -1
- package/dist/hosted-runtime-assets.js +40 -12
- package/dist/hosted-session-cli.d.ts.map +1 -1
- package/dist/hosted-session-cli.js +10 -19
- package/dist/http.d.ts +1 -1
- package/dist/http.d.ts.map +1 -1
- package/dist/http.js +10 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +113 -92
- package/dist/instruction-set-gepa-launch.d.ts +1 -1
- package/dist/instruction-set-gepa-launch.d.ts.map +1 -1
- package/dist/instruction-set-gepa-launch.js +5 -3
- package/dist/instruction-set-loader.d.ts.map +1 -1
- package/dist/instruction-set-loader.js +63 -2
- package/dist/instruction-set-lock/index.d.ts +51 -0
- package/dist/instruction-set-lock/index.d.ts.map +1 -0
- package/dist/instruction-set-lock/index.js +459 -0
- package/dist/instruction-set-lock/schema.v1.d.ts +136 -0
- package/dist/instruction-set-lock/schema.v1.d.ts.map +1 -0
- package/dist/instruction-set-lock/schema.v1.js +155 -0
- package/dist/instruction-set-provenance.d.ts +26 -0
- package/dist/instruction-set-provenance.d.ts.map +1 -0
- package/dist/instruction-set-provenance.js +68 -0
- package/dist/instruction-set-sync/helpers.d.ts +22 -0
- package/dist/instruction-set-sync/helpers.d.ts.map +1 -0
- package/dist/instruction-set-sync/helpers.js +677 -0
- package/dist/instruction-set-sync/index.d.ts +60 -0
- package/dist/instruction-set-sync/index.d.ts.map +1 -0
- package/dist/instruction-set-sync/index.js +689 -0
- package/dist/instruction-set-update/index.d.ts +42 -0
- package/dist/instruction-set-update/index.d.ts.map +1 -0
- package/dist/instruction-set-update/index.js +445 -0
- package/dist/instruction-set-verify/index.d.ts +27 -0
- package/dist/instruction-set-verify/index.d.ts.map +1 -0
- package/dist/instruction-set-verify/index.js +865 -0
- package/dist/instruction-sets-cli.d.ts +1 -4
- package/dist/instruction-sets-cli.d.ts.map +1 -1
- package/dist/instruction-sets-cli.js +220 -109
- package/dist/model-config-fields.d.ts +35 -0
- package/dist/model-config-fields.d.ts.map +1 -0
- package/dist/model-config-fields.js +28 -0
- package/dist/optimizations-list-cli.d.ts.map +1 -1
- package/dist/optimizations-list-cli.js +7 -4
- package/dist/score-format.d.ts +2 -0
- package/dist/score-format.d.ts.map +1 -0
- package/dist/score-format.js +18 -0
- package/dist/workbench-repo-contract.d.ts +65 -0
- package/dist/workbench-repo-contract.d.ts.map +1 -0
- package/dist/workbench-repo-contract.js +250 -0
- package/dist/workspace-bootstrap-job.d.ts +45 -0
- package/dist/workspace-bootstrap-job.d.ts.map +1 -0
- package/dist/workspace-bootstrap-job.js +431 -0
- package/dist/workspace-bootstrap-seed.d.ts +74 -0
- package/dist/workspace-bootstrap-seed.d.ts.map +1 -0
- package/dist/workspace-bootstrap-seed.js +209 -0
- package/package.json +4 -3
- package/src/artifacts-git-runtime.ts +360 -0
- package/src/cloudflare-artifacts-git-remote.ts +24 -0
- package/src/dataset-transfer-download.ts +61 -0
- package/src/dataset-transfer-policy.ts +8 -0
- package/src/dataset-transfer-upload.ts +145 -0
- package/src/git-credential.ts +1 -2
- package/src/git-recovery-environment.ts +1 -1
- package/src/help.ts +44 -11
- package/src/hosted-boot.ts +644 -109
- package/src/hosted-bootstrap.ts +14 -3
- package/src/hosted-harness-opencode.ts +130 -28
- package/src/hosted-harness.ts +4 -1
- package/src/hosted-harvest.ts +258 -33
- package/src/hosted-loop-lifecycle.ts +19 -5
- package/src/hosted-loop.ts +340 -68
- package/src/hosted-question-limits.ts +6 -0
- package/src/hosted-question.ts +145 -0
- package/src/hosted-run-event-sink.ts +24 -12
- package/src/hosted-runtime-assets.ts +51 -11
- package/src/hosted-session-cli.ts +10 -24
- package/src/http.ts +10 -4
- package/src/index.ts +108 -134
- package/src/instruction-set-gepa-launch.ts +4 -4
- package/src/instruction-set-loader.ts +53 -2
- package/src/instruction-set-lock/index.ts +561 -0
- package/src/instruction-set-lock/schema.v1.json +141 -0
- package/src/instruction-set-lock/schema.v1.ts +155 -0
- package/src/instruction-set-provenance.ts +89 -0
- package/src/instruction-set-sync/helpers.ts +707 -0
- package/src/instruction-set-sync/index.ts +791 -0
- package/src/instruction-set-update/index.ts +488 -0
- package/src/instruction-set-verify/index.ts +1067 -0
- package/src/instruction-sets-cli.ts +226 -114
- package/src/model-config-fields.ts +31 -0
- package/src/optimizations-list-cli.ts +7 -4
- package/src/score-format.ts +16 -0
- package/src/workbench-repo-contract.ts +314 -0
- package/src/workspace-bootstrap-job.ts +611 -0
- package/src/workspace-bootstrap-seed.ts +350 -0
- package/vendor/orizu-gepa/src/orizu_gepa_connector/instruction_set_loader.py +46 -2
- package/vendor/skills/orizu/SKILL.md +4 -2
- package/vendor/skills/orizu/flows/promote.md +4 -0
- package/vendor/skills/orizu/references/assess-and-plan.md +1 -1
- package/vendor/skills/orizu/references/authority-map.md +1 -1
- package/vendor/skills/orizu/references/cli-reference.md +151 -35
- package/vendor/skills/orizu/references/instructions-after-prompts.md +3 -3
- package/vendor/skills/orizu/references/migrate-existing-gepa-setup.md +5 -6
- package/vendor/skills/orizu/references/migrate-hand-rolled-instruction-layout.md +252 -0
- package/vendor/skills/orizu/references/optimization-reports.md +5 -4
- package/vendor/skills/orizu/references/optimization-with-gepa.md +1 -1
- package/vendor/skills/orizu/references/orizu-in-your-codebase.md +195 -0
- package/vendor/skills/orizu/references/primer.md +4 -2
- package/vendor/skills/orizu/references/prompt-control-plane.md +33 -29
- package/vendor/skills/orizu/references/vocabulary.md +1 -1
|
@@ -0,0 +1,611 @@
|
|
|
1
|
+
/** Agent-free synthetic workspace bootstrap. Account-level provider authority
|
|
2
|
+
* stays in the isolated broker; this process receives one scoped credential
|
|
3
|
+
* at a time and revokes it before continuing. */
|
|
4
|
+
import { mkdir, mkdtemp, rm } from 'node:fs/promises'
|
|
5
|
+
import { tmpdir } from 'node:os'
|
|
6
|
+
import { join } from 'node:path'
|
|
7
|
+
|
|
8
|
+
import { CLOUDFLARE_ARTIFACTS_HOST_PATTERN } from './cloudflare-artifacts-git-remote.js'
|
|
9
|
+
import {
|
|
10
|
+
buildSyntheticWorkspaceSeed,
|
|
11
|
+
buildSeedWorktree,
|
|
12
|
+
verifySeedClone,
|
|
13
|
+
} from './workspace-bootstrap-seed.js'
|
|
14
|
+
import {
|
|
15
|
+
createEphemeralAskPass,
|
|
16
|
+
defaultGitRunner,
|
|
17
|
+
type GitAuth,
|
|
18
|
+
type GitRunner,
|
|
19
|
+
} from './artifacts-git-runtime.js'
|
|
20
|
+
import { assertSecureTokenTransport } from './http.js'
|
|
21
|
+
|
|
22
|
+
export const WORKSPACE_BOOTSTRAP_JOB_CAPABILITY = 'workspace-bootstrap-job:v1'
|
|
23
|
+
export const WORKSPACE_BOOTSTRAP_NAMESPACE = 'orizu-workbench-dev'
|
|
24
|
+
|
|
25
|
+
const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i
|
|
26
|
+
const CALLBACK_ATTEMPTS = 3
|
|
27
|
+
// The coordinator's eight-minute wall must still leave time for bounded seed
|
|
28
|
+
// preparation, revocation, failure reporting, and an independent readback.
|
|
29
|
+
// These are intentionally local to the hosted one-shot, never the legacy
|
|
30
|
+
// script's longer migration/repository budgets.
|
|
31
|
+
export const WORKSPACE_BOOTSTRAP_PUSH_TIMEOUT_MS = 120_000
|
|
32
|
+
export const WORKSPACE_BOOTSTRAP_VERIFICATION_CLONE_TIMEOUT_MS = 120_000
|
|
33
|
+
|
|
34
|
+
export const WORKSPACE_BOOTSTRAP_FAILURE_CODES = [
|
|
35
|
+
'scope_refused',
|
|
36
|
+
'provider_unavailable',
|
|
37
|
+
'create_uncertain',
|
|
38
|
+
'readback_failed',
|
|
39
|
+
'credentials_pending',
|
|
40
|
+
'bootstrap_interrupted',
|
|
41
|
+
] as const
|
|
42
|
+
|
|
43
|
+
export type WorkspaceBootstrapFailureCode = (typeof WORKSPACE_BOOTSTRAP_FAILURE_CODES)[number]
|
|
44
|
+
export type WorkspaceBootstrapJobFetch = (url: string, init?: RequestInit) => Promise<Response>
|
|
45
|
+
|
|
46
|
+
export interface WorkspaceBootstrapJobEnv {
|
|
47
|
+
bootSecret: string
|
|
48
|
+
intentId: string
|
|
49
|
+
attemptId: string
|
|
50
|
+
coordinatorUrl: string
|
|
51
|
+
baseUrl: string
|
|
52
|
+
/** Derived by the coordinator from its pinned operator account id. */
|
|
53
|
+
expectedGitHost: string
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface WorkspaceBootstrapJobCommandIo {
|
|
57
|
+
print: (line: string) => void
|
|
58
|
+
printErr?: (line: string) => void
|
|
59
|
+
json?: boolean
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
interface WorkspaceBootstrapSpec {
|
|
63
|
+
intentId: string
|
|
64
|
+
attemptId: string
|
|
65
|
+
team: { id: string; slug: string }
|
|
66
|
+
project: { id: string; slug: string; name: string | null }
|
|
67
|
+
repository: {
|
|
68
|
+
provider: 'cloudflare_artifacts'
|
|
69
|
+
repositoryId: string
|
|
70
|
+
remote: string
|
|
71
|
+
}
|
|
72
|
+
expectedSeedSha?: string
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
interface WorkspaceBootstrapCredential {
|
|
76
|
+
remote: string
|
|
77
|
+
username: 'x'
|
|
78
|
+
password: string
|
|
79
|
+
tokenId: string
|
|
80
|
+
expiresAt: string
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
interface VerifiedResult {
|
|
84
|
+
state: 'verified'
|
|
85
|
+
seedCommitSha: string
|
|
86
|
+
contentBytes: number
|
|
87
|
+
fileCount: number
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
interface FailedResult {
|
|
91
|
+
state: 'failed'
|
|
92
|
+
diagnostic: WorkspaceBootstrapFailureCode
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
type WorkspaceBootstrapControlResult = VerifiedResult | FailedResult
|
|
96
|
+
|
|
97
|
+
export interface WorkspaceBootstrapJobRunResult {
|
|
98
|
+
reported: boolean
|
|
99
|
+
state: 'verified' | 'failed'
|
|
100
|
+
diagnostic: WorkspaceBootstrapFailureCode | null
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
class WorkspaceBootstrapFailure extends Error {
|
|
104
|
+
readonly diagnostic: WorkspaceBootstrapFailureCode
|
|
105
|
+
|
|
106
|
+
constructor(diagnostic: WorkspaceBootstrapFailureCode) {
|
|
107
|
+
super(diagnostic)
|
|
108
|
+
this.name = 'WorkspaceBootstrapFailure'
|
|
109
|
+
this.diagnostic = diagnostic
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function isObject(value: unknown): value is Record<string, unknown> {
|
|
114
|
+
return Boolean(value) && typeof value === 'object' && !Array.isArray(value)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function isLoopbackOrigin(value: string): boolean {
|
|
118
|
+
try {
|
|
119
|
+
const host = new URL(value).hostname
|
|
120
|
+
return host === 'localhost' || host === '127.0.0.1' || host === '::1'
|
|
121
|
+
} catch {
|
|
122
|
+
return false
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export function resolveWorkspaceBootstrapJobEnv(
|
|
127
|
+
env: Record<string, string | undefined>
|
|
128
|
+
):
|
|
129
|
+
| { ok: true; value: WorkspaceBootstrapJobEnv }
|
|
130
|
+
| { ok: false; missing: string[]; invalid: string[] } {
|
|
131
|
+
const names = [
|
|
132
|
+
'ORIZU_BOOT_SECRET',
|
|
133
|
+
'ORIZU_WORKSPACE_BOOTSTRAP_INTENT_ID',
|
|
134
|
+
'ORIZU_WORKSPACE_BOOTSTRAP_ATTEMPT_ID',
|
|
135
|
+
'ORIZU_COORDINATOR_URL',
|
|
136
|
+
'ORIZU_BASE_URL',
|
|
137
|
+
'ORIZU_WORKSPACE_BOOTSTRAP_GIT_HOST',
|
|
138
|
+
] as const
|
|
139
|
+
const values = Object.fromEntries(names.map((name) => [name, env[name]?.trim() ?? ''])) as Record<
|
|
140
|
+
(typeof names)[number],
|
|
141
|
+
string
|
|
142
|
+
>
|
|
143
|
+
const missing = names.filter((name) => values[name].length === 0)
|
|
144
|
+
if (missing.length > 0) return { ok: false, missing: [...missing], invalid: [] }
|
|
145
|
+
|
|
146
|
+
const invalid: string[] = []
|
|
147
|
+
for (const name of ['ORIZU_COORDINATOR_URL', 'ORIZU_BASE_URL'] as const) {
|
|
148
|
+
try {
|
|
149
|
+
const parsed = new URL(values[name])
|
|
150
|
+
if (parsed.username || parsed.password) throw new Error('userinfo')
|
|
151
|
+
assertSecureTokenTransport(values[name])
|
|
152
|
+
} catch {
|
|
153
|
+
invalid.push(name)
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
if (!UUID_PATTERN.test(values.ORIZU_WORKSPACE_BOOTSTRAP_INTENT_ID))
|
|
157
|
+
invalid.push('ORIZU_WORKSPACE_BOOTSTRAP_INTENT_ID')
|
|
158
|
+
if (!UUID_PATTERN.test(values.ORIZU_WORKSPACE_BOOTSTRAP_ATTEMPT_ID))
|
|
159
|
+
invalid.push('ORIZU_WORKSPACE_BOOTSTRAP_ATTEMPT_ID')
|
|
160
|
+
const host = values.ORIZU_WORKSPACE_BOOTSTRAP_GIT_HOST.toLowerCase()
|
|
161
|
+
const localHostAllowed =
|
|
162
|
+
isLoopbackOrigin(values.ORIZU_COORDINATOR_URL) &&
|
|
163
|
+
isLoopbackOrigin(values.ORIZU_BASE_URL) &&
|
|
164
|
+
(host === 'localhost' || host === '127.0.0.1')
|
|
165
|
+
if (!CLOUDFLARE_ARTIFACTS_HOST_PATTERN.test(host) && !localHostAllowed) {
|
|
166
|
+
invalid.push('ORIZU_WORKSPACE_BOOTSTRAP_GIT_HOST')
|
|
167
|
+
}
|
|
168
|
+
if (invalid.length > 0) return { ok: false, missing: [], invalid }
|
|
169
|
+
return {
|
|
170
|
+
ok: true,
|
|
171
|
+
value: {
|
|
172
|
+
bootSecret: values.ORIZU_BOOT_SECRET,
|
|
173
|
+
intentId: values.ORIZU_WORKSPACE_BOOTSTRAP_INTENT_ID,
|
|
174
|
+
attemptId: values.ORIZU_WORKSPACE_BOOTSTRAP_ATTEMPT_ID,
|
|
175
|
+
coordinatorUrl: values.ORIZU_COORDINATOR_URL.replace(/\/+$/, ''),
|
|
176
|
+
baseUrl: values.ORIZU_BASE_URL.replace(/\/+$/, ''),
|
|
177
|
+
expectedGitHost: host,
|
|
178
|
+
},
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export function assertWorkspaceBootstrapRemote(remote: string, expectedGitHost: string): void {
|
|
183
|
+
let parsed: URL
|
|
184
|
+
try {
|
|
185
|
+
parsed = new URL(remote)
|
|
186
|
+
} catch {
|
|
187
|
+
throw new WorkspaceBootstrapFailure('scope_refused')
|
|
188
|
+
}
|
|
189
|
+
const local =
|
|
190
|
+
(expectedGitHost === 'localhost' || expectedGitHost === '127.0.0.1') &&
|
|
191
|
+
parsed.hostname === expectedGitHost
|
|
192
|
+
if (
|
|
193
|
+
parsed.protocol !== 'https:' ||
|
|
194
|
+
parsed.hostname !== expectedGitHost ||
|
|
195
|
+
parsed.username.length > 0 ||
|
|
196
|
+
parsed.password.length > 0 ||
|
|
197
|
+
parsed.search.length > 0 ||
|
|
198
|
+
parsed.hash.length > 0 ||
|
|
199
|
+
(!local && parsed.port.length > 0) ||
|
|
200
|
+
!new RegExp(`^/git/${WORKSPACE_BOOTSTRAP_NAMESPACE}/[A-Za-z0-9][A-Za-z0-9._-]*\\.git$`).test(
|
|
201
|
+
parsed.pathname
|
|
202
|
+
)
|
|
203
|
+
) {
|
|
204
|
+
throw new WorkspaceBootstrapFailure('scope_refused')
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
async function postJson(
|
|
209
|
+
url: string,
|
|
210
|
+
token: string,
|
|
211
|
+
body: object,
|
|
212
|
+
fetchImpl: WorkspaceBootstrapJobFetch
|
|
213
|
+
): Promise<Response> {
|
|
214
|
+
return fetchImpl(url, {
|
|
215
|
+
method: 'POST',
|
|
216
|
+
redirect: 'error',
|
|
217
|
+
headers: {
|
|
218
|
+
Authorization: `Bearer ${token}`,
|
|
219
|
+
'Content-Type': 'application/json',
|
|
220
|
+
},
|
|
221
|
+
body: JSON.stringify(body),
|
|
222
|
+
})
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
async function exchangeJobToken(
|
|
226
|
+
env: WorkspaceBootstrapJobEnv,
|
|
227
|
+
fetchImpl: WorkspaceBootstrapJobFetch,
|
|
228
|
+
sleep: (ms: number) => Promise<void>
|
|
229
|
+
): Promise<string> {
|
|
230
|
+
const url = `${env.coordinatorUrl}/workspace-bootstrap-jobs/${encodeURIComponent(env.intentId)}/claim`
|
|
231
|
+
for (let attempt = 0; attempt < CALLBACK_ATTEMPTS; attempt += 1) {
|
|
232
|
+
try {
|
|
233
|
+
const response = await postJson(url, env.bootSecret, { attemptId: env.attemptId }, fetchImpl)
|
|
234
|
+
if (response.status === 401 || response.status === 403 || response.status === 409) {
|
|
235
|
+
throw new WorkspaceBootstrapFailure('scope_refused')
|
|
236
|
+
}
|
|
237
|
+
if (response.ok) {
|
|
238
|
+
const value: unknown = await response.json().catch(() => null)
|
|
239
|
+
if (
|
|
240
|
+
isObject(value) &&
|
|
241
|
+
typeof value.jobToken === 'string' &&
|
|
242
|
+
value.jobToken.length > 0 &&
|
|
243
|
+
value.attemptId === env.attemptId &&
|
|
244
|
+
typeof value.expiresAt === 'string'
|
|
245
|
+
) {
|
|
246
|
+
return value.jobToken
|
|
247
|
+
}
|
|
248
|
+
throw new WorkspaceBootstrapFailure('scope_refused')
|
|
249
|
+
}
|
|
250
|
+
} catch (error) {
|
|
251
|
+
if (error instanceof WorkspaceBootstrapFailure) throw error
|
|
252
|
+
}
|
|
253
|
+
if (attempt < CALLBACK_ATTEMPTS - 1) await sleep(250 * 2 ** attempt)
|
|
254
|
+
}
|
|
255
|
+
throw new WorkspaceBootstrapFailure('provider_unavailable')
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
function parseSpec(value: unknown, env: WorkspaceBootstrapJobEnv): WorkspaceBootstrapSpec {
|
|
259
|
+
if (
|
|
260
|
+
!isObject(value) ||
|
|
261
|
+
value.intentId !== env.intentId ||
|
|
262
|
+
value.attemptId !== env.attemptId ||
|
|
263
|
+
!isObject(value.team) ||
|
|
264
|
+
!isObject(value.project) ||
|
|
265
|
+
!isObject(value.repository) ||
|
|
266
|
+
typeof value.team.id !== 'string' ||
|
|
267
|
+
typeof value.team.slug !== 'string' ||
|
|
268
|
+
typeof value.project.id !== 'string' ||
|
|
269
|
+
typeof value.project.slug !== 'string' ||
|
|
270
|
+
(value.project.name !== null && typeof value.project.name !== 'string') ||
|
|
271
|
+
value.repository.provider !== 'cloudflare_artifacts' ||
|
|
272
|
+
typeof value.repository.repositoryId !== 'string' ||
|
|
273
|
+
value.repository.repositoryId.length === 0 ||
|
|
274
|
+
typeof value.repository.remote !== 'string' ||
|
|
275
|
+
(value.expectedSeedSha !== undefined &&
|
|
276
|
+
(typeof value.expectedSeedSha !== 'string' || !/^[0-9a-f]{40}$/.test(value.expectedSeedSha)))
|
|
277
|
+
) {
|
|
278
|
+
throw new WorkspaceBootstrapFailure('scope_refused')
|
|
279
|
+
}
|
|
280
|
+
assertWorkspaceBootstrapRemote(value.repository.remote, env.expectedGitHost)
|
|
281
|
+
return value as unknown as WorkspaceBootstrapSpec
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
async function fetchSpec(
|
|
285
|
+
env: WorkspaceBootstrapJobEnv,
|
|
286
|
+
token: string,
|
|
287
|
+
fetchImpl: WorkspaceBootstrapJobFetch
|
|
288
|
+
): Promise<WorkspaceBootstrapSpec> {
|
|
289
|
+
let response: Response
|
|
290
|
+
try {
|
|
291
|
+
response = await postJson(
|
|
292
|
+
`${env.baseUrl}/api/internal/hosted-workspace-bootstrap/${encodeURIComponent(env.intentId)}/spec`,
|
|
293
|
+
token,
|
|
294
|
+
{ attemptId: env.attemptId },
|
|
295
|
+
fetchImpl
|
|
296
|
+
)
|
|
297
|
+
} catch {
|
|
298
|
+
throw new WorkspaceBootstrapFailure('provider_unavailable')
|
|
299
|
+
}
|
|
300
|
+
if (response.status === 401 || response.status === 403 || response.status === 409)
|
|
301
|
+
throw new WorkspaceBootstrapFailure('scope_refused')
|
|
302
|
+
if (!response.ok) throw new WorkspaceBootstrapFailure('provider_unavailable')
|
|
303
|
+
return parseSpec(await response.json().catch(() => null), env)
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
function parseCredential(
|
|
307
|
+
value: unknown,
|
|
308
|
+
expectedRemote: string,
|
|
309
|
+
expectedGitHost: string
|
|
310
|
+
): WorkspaceBootstrapCredential {
|
|
311
|
+
if (
|
|
312
|
+
!isObject(value) ||
|
|
313
|
+
value.remote !== expectedRemote ||
|
|
314
|
+
value.username !== 'x' ||
|
|
315
|
+
typeof value.password !== 'string' ||
|
|
316
|
+
value.password.length < 16 ||
|
|
317
|
+
typeof value.tokenId !== 'string' ||
|
|
318
|
+
value.tokenId.length === 0 ||
|
|
319
|
+
typeof value.expiresAt !== 'string' ||
|
|
320
|
+
!Number.isFinite(Date.parse(value.expiresAt))
|
|
321
|
+
) {
|
|
322
|
+
throw new WorkspaceBootstrapFailure('scope_refused')
|
|
323
|
+
}
|
|
324
|
+
assertWorkspaceBootstrapRemote(value.remote, expectedGitHost)
|
|
325
|
+
return value as unknown as WorkspaceBootstrapCredential
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
async function fetchCredential(
|
|
329
|
+
env: WorkspaceBootstrapJobEnv,
|
|
330
|
+
token: string,
|
|
331
|
+
remote: string,
|
|
332
|
+
scope: 'write' | 'read',
|
|
333
|
+
fetchImpl: WorkspaceBootstrapJobFetch
|
|
334
|
+
): Promise<WorkspaceBootstrapCredential> {
|
|
335
|
+
let response: Response
|
|
336
|
+
try {
|
|
337
|
+
response = await postJson(
|
|
338
|
+
`${env.baseUrl}/api/internal/hosted-workspace-bootstrap/${encodeURIComponent(env.intentId)}/credential`,
|
|
339
|
+
token,
|
|
340
|
+
{ scope },
|
|
341
|
+
fetchImpl
|
|
342
|
+
)
|
|
343
|
+
} catch {
|
|
344
|
+
throw new WorkspaceBootstrapFailure('provider_unavailable')
|
|
345
|
+
}
|
|
346
|
+
if (response.status === 401 || response.status === 403 || response.status === 409)
|
|
347
|
+
throw new WorkspaceBootstrapFailure('scope_refused')
|
|
348
|
+
if (!response.ok) throw new WorkspaceBootstrapFailure('provider_unavailable')
|
|
349
|
+
return parseCredential(await response.json().catch(() => null), remote, env.expectedGitHost)
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
async function revokeCredential(
|
|
353
|
+
env: WorkspaceBootstrapJobEnv,
|
|
354
|
+
token: string,
|
|
355
|
+
tokenId: string,
|
|
356
|
+
fetchImpl: WorkspaceBootstrapJobFetch
|
|
357
|
+
): Promise<void> {
|
|
358
|
+
let response: Response
|
|
359
|
+
try {
|
|
360
|
+
response = await postJson(
|
|
361
|
+
`${env.baseUrl}/api/internal/hosted-workspace-bootstrap/${encodeURIComponent(env.intentId)}/revoke`,
|
|
362
|
+
token,
|
|
363
|
+
{ tokenId },
|
|
364
|
+
fetchImpl
|
|
365
|
+
)
|
|
366
|
+
} catch {
|
|
367
|
+
throw new WorkspaceBootstrapFailure('credentials_pending')
|
|
368
|
+
}
|
|
369
|
+
const value: unknown = response.ok ? await response.json().catch(() => null) : null
|
|
370
|
+
if (!response.ok || !isObject(value) || value.revoked !== true) {
|
|
371
|
+
throw new WorkspaceBootstrapFailure('credentials_pending')
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
async function withScopedCredential<T>(input: {
|
|
376
|
+
env: WorkspaceBootstrapJobEnv
|
|
377
|
+
token: string
|
|
378
|
+
remote: string
|
|
379
|
+
scope: 'write' | 'read'
|
|
380
|
+
root: string
|
|
381
|
+
fetchImpl: WorkspaceBootstrapJobFetch
|
|
382
|
+
operation: (auth: GitAuth) => Promise<T>
|
|
383
|
+
}): Promise<T> {
|
|
384
|
+
const credential = await fetchCredential(
|
|
385
|
+
input.env,
|
|
386
|
+
input.token,
|
|
387
|
+
input.remote,
|
|
388
|
+
input.scope,
|
|
389
|
+
input.fetchImpl
|
|
390
|
+
)
|
|
391
|
+
let result: T | undefined
|
|
392
|
+
let operationError: unknown
|
|
393
|
+
try {
|
|
394
|
+
const askPass = await createEphemeralAskPass(join(input.root, `${input.scope}-credential`))
|
|
395
|
+
try {
|
|
396
|
+
result = await input.operation({
|
|
397
|
+
askPassPath: askPass.path,
|
|
398
|
+
token: credential.password,
|
|
399
|
+
})
|
|
400
|
+
} catch (error) {
|
|
401
|
+
operationError = error
|
|
402
|
+
} finally {
|
|
403
|
+
await askPass.dispose()
|
|
404
|
+
}
|
|
405
|
+
} catch (error) {
|
|
406
|
+
operationError = error
|
|
407
|
+
}
|
|
408
|
+
// Revocation wins over the Git error: uncertain authority is the most
|
|
409
|
+
// safety-relevant recoverable state.
|
|
410
|
+
await revokeCredential(input.env, input.token, credential.tokenId, input.fetchImpl)
|
|
411
|
+
if (operationError) throw operationError
|
|
412
|
+
return result as T
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
function requireGitOk(
|
|
416
|
+
result: { exitCode: number },
|
|
417
|
+
diagnostic: WorkspaceBootstrapFailureCode
|
|
418
|
+
): void {
|
|
419
|
+
if (result.exitCode !== 0) throw new WorkspaceBootstrapFailure(diagnostic)
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
async function reportControlResult(
|
|
423
|
+
env: WorkspaceBootstrapJobEnv,
|
|
424
|
+
token: string,
|
|
425
|
+
result: WorkspaceBootstrapControlResult,
|
|
426
|
+
fetchImpl: WorkspaceBootstrapJobFetch,
|
|
427
|
+
sleep: (ms: number) => Promise<void>
|
|
428
|
+
): Promise<boolean> {
|
|
429
|
+
const url = `${env.baseUrl}/api/internal/hosted-workspace-bootstrap/${encodeURIComponent(env.intentId)}/result`
|
|
430
|
+
for (let attempt = 0; attempt < CALLBACK_ATTEMPTS; attempt += 1) {
|
|
431
|
+
try {
|
|
432
|
+
const response = await postJson(url, token, result, fetchImpl)
|
|
433
|
+
// Only an authoritative 2xx receipt proves this exact attempt/result was
|
|
434
|
+
// recorded. A generic 409 can describe stale or conflicting state.
|
|
435
|
+
if (response.ok) return true
|
|
436
|
+
} catch {
|
|
437
|
+
/* retry */
|
|
438
|
+
}
|
|
439
|
+
if (attempt < CALLBACK_ATTEMPTS - 1) await sleep(250 * 2 ** attempt)
|
|
440
|
+
}
|
|
441
|
+
return false
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
async function reportCoordinatorResult(
|
|
445
|
+
env: WorkspaceBootstrapJobEnv,
|
|
446
|
+
result: WorkspaceBootstrapControlResult,
|
|
447
|
+
fetchImpl: WorkspaceBootstrapJobFetch,
|
|
448
|
+
sleep: (ms: number) => Promise<void>
|
|
449
|
+
): Promise<boolean> {
|
|
450
|
+
const url = `${env.coordinatorUrl}/workspace-bootstrap-jobs/${encodeURIComponent(env.intentId)}/result`
|
|
451
|
+
const body =
|
|
452
|
+
result.state === 'verified'
|
|
453
|
+
? { state: 'verified', seedCommitSha: result.seedCommitSha }
|
|
454
|
+
: result
|
|
455
|
+
for (let attempt = 0; attempt < CALLBACK_ATTEMPTS; attempt += 1) {
|
|
456
|
+
try {
|
|
457
|
+
const response = await postJson(url, env.bootSecret, body, fetchImpl)
|
|
458
|
+
if (response.ok) return true
|
|
459
|
+
} catch {
|
|
460
|
+
/* retry */
|
|
461
|
+
}
|
|
462
|
+
if (attempt < CALLBACK_ATTEMPTS - 1) await sleep(250 * 2 ** attempt)
|
|
463
|
+
}
|
|
464
|
+
return false
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
export interface RunWorkspaceBootstrapJobOptions {
|
|
468
|
+
env: WorkspaceBootstrapJobEnv
|
|
469
|
+
fetchImpl?: WorkspaceBootstrapJobFetch
|
|
470
|
+
runGit?: GitRunner
|
|
471
|
+
sleep?: (ms: number) => Promise<void>
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
export async function runWorkspaceBootstrapJob(
|
|
475
|
+
options: RunWorkspaceBootstrapJobOptions
|
|
476
|
+
): Promise<WorkspaceBootstrapJobRunResult> {
|
|
477
|
+
const { env } = options
|
|
478
|
+
const fetchImpl = options.fetchImpl ?? (globalThis.fetch as WorkspaceBootstrapJobFetch)
|
|
479
|
+
const runGit = options.runGit ?? defaultGitRunner
|
|
480
|
+
const sleep = options.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)))
|
|
481
|
+
let jobToken: string | null = null
|
|
482
|
+
let controlResult: WorkspaceBootstrapControlResult = {
|
|
483
|
+
state: 'failed',
|
|
484
|
+
diagnostic: 'bootstrap_interrupted',
|
|
485
|
+
}
|
|
486
|
+
let root: string | null = null
|
|
487
|
+
|
|
488
|
+
try {
|
|
489
|
+
jobToken = await exchangeJobToken(env, fetchImpl, sleep)
|
|
490
|
+
const spec = await fetchSpec(env, jobToken, fetchImpl)
|
|
491
|
+
const files = buildSyntheticWorkspaceSeed({
|
|
492
|
+
team: spec.team,
|
|
493
|
+
project: spec.project,
|
|
494
|
+
})
|
|
495
|
+
root = await mkdtemp(join(tmpdir(), 'orizu-workspace-bootstrap-'))
|
|
496
|
+
const worktree = join(root, 'seed')
|
|
497
|
+
const seedCommitSha = await buildSeedWorktree({
|
|
498
|
+
runGit,
|
|
499
|
+
worktree,
|
|
500
|
+
files,
|
|
501
|
+
commitMessage: 'chore: seed synthetic hosted workspace',
|
|
502
|
+
})
|
|
503
|
+
if (spec.expectedSeedSha && spec.expectedSeedSha !== seedCommitSha) {
|
|
504
|
+
throw new WorkspaceBootstrapFailure('bootstrap_interrupted')
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
await withScopedCredential({
|
|
508
|
+
env,
|
|
509
|
+
token: jobToken,
|
|
510
|
+
remote: spec.repository.remote,
|
|
511
|
+
scope: 'write',
|
|
512
|
+
root,
|
|
513
|
+
fetchImpl,
|
|
514
|
+
operation: async (auth) => {
|
|
515
|
+
const pushed = await runGit(['push', spec.repository.remote, 'HEAD:refs/heads/main'], {
|
|
516
|
+
cwd: worktree,
|
|
517
|
+
auth,
|
|
518
|
+
timeoutMs: WORKSPACE_BOOTSTRAP_PUSH_TIMEOUT_MS,
|
|
519
|
+
})
|
|
520
|
+
requireGitOk(pushed, 'create_uncertain')
|
|
521
|
+
},
|
|
522
|
+
})
|
|
523
|
+
|
|
524
|
+
const cloneDir = join(root, 'verification-clone')
|
|
525
|
+
await withScopedCredential({
|
|
526
|
+
env,
|
|
527
|
+
token: jobToken,
|
|
528
|
+
remote: spec.repository.remote,
|
|
529
|
+
scope: 'read',
|
|
530
|
+
root,
|
|
531
|
+
fetchImpl,
|
|
532
|
+
operation: async (auth) => {
|
|
533
|
+
await mkdir(root as string, { recursive: true })
|
|
534
|
+
const cloned = await runGit(
|
|
535
|
+
['clone', '--branch', 'main', '--single-branch', spec.repository.remote, cloneDir],
|
|
536
|
+
{
|
|
537
|
+
cwd: root as string,
|
|
538
|
+
auth,
|
|
539
|
+
timeoutMs: WORKSPACE_BOOTSTRAP_VERIFICATION_CLONE_TIMEOUT_MS,
|
|
540
|
+
}
|
|
541
|
+
)
|
|
542
|
+
requireGitOk(cloned, 'readback_failed')
|
|
543
|
+
try {
|
|
544
|
+
await verifySeedClone({
|
|
545
|
+
runGit,
|
|
546
|
+
cloneDir,
|
|
547
|
+
files,
|
|
548
|
+
expectedSha: seedCommitSha,
|
|
549
|
+
})
|
|
550
|
+
} catch {
|
|
551
|
+
throw new WorkspaceBootstrapFailure('readback_failed')
|
|
552
|
+
}
|
|
553
|
+
},
|
|
554
|
+
})
|
|
555
|
+
|
|
556
|
+
controlResult = {
|
|
557
|
+
state: 'verified',
|
|
558
|
+
seedCommitSha,
|
|
559
|
+
contentBytes: files.reduce((sum, file) => sum + file.bytes.byteLength, 0),
|
|
560
|
+
fileCount: files.length,
|
|
561
|
+
}
|
|
562
|
+
} catch (error) {
|
|
563
|
+
controlResult = {
|
|
564
|
+
state: 'failed',
|
|
565
|
+
diagnostic:
|
|
566
|
+
error instanceof WorkspaceBootstrapFailure ? error.diagnostic : 'bootstrap_interrupted',
|
|
567
|
+
}
|
|
568
|
+
} finally {
|
|
569
|
+
if (root) await rm(root, { recursive: true, force: true })
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
const controlReported = jobToken
|
|
573
|
+
? await reportControlResult(env, jobToken, controlResult, fetchImpl, sleep)
|
|
574
|
+
: false
|
|
575
|
+
const effectiveResult: WorkspaceBootstrapControlResult =
|
|
576
|
+
controlResult.state === 'verified' && !controlReported
|
|
577
|
+
? { state: 'failed', diagnostic: 'bootstrap_interrupted' }
|
|
578
|
+
: controlResult
|
|
579
|
+
const coordinatorReported = await reportCoordinatorResult(env, effectiveResult, fetchImpl, sleep)
|
|
580
|
+
return {
|
|
581
|
+
reported: controlReported && coordinatorReported,
|
|
582
|
+
state: effectiveResult.state,
|
|
583
|
+
diagnostic: effectiveResult.state === 'failed' ? effectiveResult.diagnostic : null,
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
export async function workspaceBootstrapJobCommand(
|
|
588
|
+
args: readonly string[],
|
|
589
|
+
io: WorkspaceBootstrapJobCommandIo
|
|
590
|
+
): Promise<number> {
|
|
591
|
+
if (args.includes('--capability-check')) {
|
|
592
|
+
io.print(WORKSPACE_BOOTSTRAP_JOB_CAPABILITY)
|
|
593
|
+
return 0
|
|
594
|
+
}
|
|
595
|
+
const resolved = resolveWorkspaceBootstrapJobEnv(process.env)
|
|
596
|
+
if (!resolved.ok) {
|
|
597
|
+
const detail =
|
|
598
|
+
resolved.missing.length > 0
|
|
599
|
+
? `missing required env: ${resolved.missing.join(', ')}`
|
|
600
|
+
: `invalid or insecure env: ${resolved.invalid.join(', ')}`
|
|
601
|
+
io.printErr?.(`workspace-bootstrap-job: ${detail}`)
|
|
602
|
+
return 1
|
|
603
|
+
}
|
|
604
|
+
const result = await runWorkspaceBootstrapJob({ env: resolved.value })
|
|
605
|
+
io.print(
|
|
606
|
+
io.json
|
|
607
|
+
? JSON.stringify(result)
|
|
608
|
+
: `workspace-bootstrap-job finished: ${result.state}${result.diagnostic ? ` (${result.diagnostic})` : ''}`
|
|
609
|
+
)
|
|
610
|
+
return result.reported ? 0 : 1
|
|
611
|
+
}
|