@tiangong-lca/cli 0.0.25 → 0.0.26

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.
@@ -0,0 +1,524 @@
1
+ import { CliError } from './errors.js';
2
+ import { computePlanSha256, isJsonObject, sha256Json, sha256Text, stableJsonText, } from './dataset-maintenance-contract.js';
3
+ import { PROTECTED_EXECUTION_CONTRACT, PROTECTED_EXECUTION_COUNTS, assertProtectedFreezeMatchesPlan, computeProtectedApprovalIdentitySha256, computeProtectedFreezeSha256, parseProtectedApproval, parseProtectedFreeze, protectedDerivativeBaselineSetSha256, protectedPlanSetHashes, } from './dataset-maintenance-protected-contract.js';
4
+ export const PROTECTED_PREPARATION_CONTRACT = {
5
+ approval_request_schema: 'dataset-alias-execution-approval-request.v1',
6
+ };
7
+ export const PROTECTED_PRODUCTION_PROJECT_REF = 'qgzvkongdjqiiamzbbts';
8
+ export const PROTECTED_PREPARATION_REJECTED_PLAN_SHA256 = [
9
+ '813a201ded0443c79639cfbdb8f5a2fad8a8781ef6edd3ec7019e9a45f5f33ce',
10
+ '673331422e8dceeb7975984b07276f057b37e8d6de789d7f030ec29f3be29629',
11
+ '7fdf7e2755599d426e31a9955985d54d5b7cef1adeaa7a10dcc7186353a6c3a8',
12
+ ];
13
+ const SHA256 = /^[a-f0-9]{64}$/u;
14
+ function fail(message) {
15
+ throw new CliError(message, {
16
+ code: 'DATASET_MAINTENANCE_PROTECTED_PREPARATION_INVALID',
17
+ exitCode: 2,
18
+ });
19
+ }
20
+ function exactKeys(value, expected, label) {
21
+ const actual = Object.keys(value).sort();
22
+ const wanted = [...expected].sort();
23
+ if (actual.length !== wanted.length || actual.some((key, index) => key !== wanted[index])) {
24
+ fail(`${label} must contain exactly: ${wanted.join(', ')}.`);
25
+ }
26
+ }
27
+ function token(value, label) {
28
+ if (typeof value !== 'string' || !value || value.trim() !== value) {
29
+ fail(`${label} must be a non-empty canonical string.`);
30
+ }
31
+ return value;
32
+ }
33
+ function exactText(value, label) {
34
+ if (typeof value !== 'string' || value.length === 0) {
35
+ fail(`${label} must be a non-empty byte-exact string.`);
36
+ }
37
+ return value;
38
+ }
39
+ function hash(value, label) {
40
+ const digest = token(value, label);
41
+ if (!SHA256.test(digest))
42
+ fail(`${label} must be a lowercase SHA-256 digest.`);
43
+ return digest;
44
+ }
45
+ export function assertProtectedPreparationPlanSha256(value, label = 'plan_sha256') {
46
+ const digest = hash(value, label);
47
+ if (PROTECTED_PREPARATION_REJECTED_PLAN_SHA256.includes(digest)) {
48
+ fail(`${label} is a historical superseded plan and cannot be prepared or approved.`);
49
+ }
50
+ return digest;
51
+ }
52
+ export function assertProtectedProductionProjectRef(value) {
53
+ const projectRef = token(value, 'project_ref');
54
+ if (projectRef !== PROTECTED_PRODUCTION_PROJECT_REF) {
55
+ fail('Protected BAFU preparation and commit are restricted to the production project.');
56
+ }
57
+ return projectRef;
58
+ }
59
+ function canonicalTimestamp(value, label) {
60
+ const timestamp = token(value, label);
61
+ const parsed = Date.parse(timestamp);
62
+ if (!Number.isFinite(parsed) || new Date(parsed).toISOString() !== timestamp) {
63
+ fail(`${label} must be a canonical ISO timestamp.`);
64
+ }
65
+ return timestamp;
66
+ }
67
+ function timestamp(value, label) {
68
+ const result = token(value, label);
69
+ if (!Number.isFinite(Date.parse(result)))
70
+ fail(`${label} must be an ISO timestamp.`);
71
+ return result;
72
+ }
73
+ function account(value, label) {
74
+ if (!isJsonObject(value))
75
+ fail(`${label} must be an object.`);
76
+ exactKeys(value, ['user_id', 'email'], label);
77
+ return {
78
+ user_id: token(value.user_id, `${label}.user_id`),
79
+ email: token(value.email, `${label}.email`),
80
+ };
81
+ }
82
+ function planBinding(value) {
83
+ if (!isJsonObject(value))
84
+ fail('plan must be an object.');
85
+ exactKeys(value, ['plan_file_sha256', 'plan_sha256', 'operation_id'], 'plan');
86
+ return {
87
+ plan_file_sha256: hash(value.plan_file_sha256, 'plan.plan_file_sha256'),
88
+ plan_sha256: assertProtectedPreparationPlanSha256(value.plan_sha256, 'plan.plan_sha256'),
89
+ operation_id: token(value.operation_id, 'plan.operation_id'),
90
+ };
91
+ }
92
+ function freezeSets(value) {
93
+ if (!isJsonObject(value))
94
+ fail('sets must be an object.');
95
+ const keys = [
96
+ 'alias_plan_request_sha256',
97
+ 'before_hash_set_sha256',
98
+ 'desired_hash_set_sha256',
99
+ 'exchange_rewrite_set_sha256',
100
+ 'support_snapshot_set_sha256',
101
+ 'derivative_baseline_set_sha256',
102
+ 'derivative_target_set_sha256',
103
+ 'toolchain_evidence_sha256',
104
+ ];
105
+ exactKeys(value, keys, 'sets');
106
+ return Object.fromEntries(keys.map((key) => [key, hash(value[key], `sets.${key}`)]));
107
+ }
108
+ function expectedCounts(value) {
109
+ if (!isJsonObject(value))
110
+ fail('expected must be an object.');
111
+ const keys = Object.keys(PROTECTED_EXECUTION_COUNTS);
112
+ exactKeys(value, keys, 'expected');
113
+ for (const [key, expected] of Object.entries(PROTECTED_EXECUTION_COUNTS)) {
114
+ if (value[key] !== expected)
115
+ fail(`expected.${key} must equal ${expected}.`);
116
+ }
117
+ return PROTECTED_EXECUTION_COUNTS;
118
+ }
119
+ function freezePolicy(value) {
120
+ if (!isJsonObject(value))
121
+ fail('policy must be an object.');
122
+ const keys = [
123
+ 'state_code_changes',
124
+ 'save_draft',
125
+ 'deletes',
126
+ 'rebuild_derivatives',
127
+ 'unitgroup_actions',
128
+ 'person_distance_actions',
129
+ 'max_admit_posts',
130
+ 'automatic_retry',
131
+ ];
132
+ exactKeys(value, keys, 'policy');
133
+ if (value.state_code_changes !== 0 ||
134
+ value.save_draft !== 0 ||
135
+ value.deletes !== 0 ||
136
+ value.rebuild_derivatives !== 0 ||
137
+ value.unitgroup_actions !== 0 ||
138
+ value.person_distance_actions !== 0 ||
139
+ value.max_admit_posts !== 1 ||
140
+ value.automatic_retry !== false) {
141
+ fail('policy must preserve the one-shot owner-draft execution boundary.');
142
+ }
143
+ return {
144
+ state_code_changes: 0,
145
+ save_draft: 0,
146
+ deletes: 0,
147
+ rebuild_derivatives: 0,
148
+ unitgroup_actions: 0,
149
+ person_distance_actions: 0,
150
+ max_admit_posts: 1,
151
+ automatic_retry: false,
152
+ };
153
+ }
154
+ function canonicalArtifact(value) {
155
+ const canonicalFileText = `${stableJsonText(value)}\n`;
156
+ return {
157
+ value,
158
+ canonical_file_text: canonicalFileText,
159
+ file_sha256: sha256Text(canonicalFileText),
160
+ };
161
+ }
162
+ function approvalRequestCore(freeze, freezeFileSha256, approvedAtUtc) {
163
+ assertProtectedPreparationPlanSha256(freeze.plan.plan_sha256, 'freeze.plan.plan_sha256');
164
+ const freezeFileDigest = hash(freezeFileSha256, 'freeze_file_sha256');
165
+ if (freezeFileDigest !== canonicalArtifact(freeze).file_sha256) {
166
+ fail('freeze_file_sha256 does not match the canonical freeze artifact bytes.');
167
+ }
168
+ return {
169
+ schema_version: PROTECTED_PREPARATION_CONTRACT.approval_request_schema,
170
+ approved_at_utc: canonicalTimestamp(approvedAtUtc, 'approved_at_utc'),
171
+ environment: 'production',
172
+ project_ref: assertProtectedProductionProjectRef(freeze.project_ref),
173
+ account: freeze.account,
174
+ target_visibility: 'owner_draft',
175
+ plan: freeze.plan,
176
+ freeze_file_sha256: freezeFileDigest,
177
+ freeze_sha256: freeze.freeze_sha256,
178
+ sets: freeze.sets,
179
+ expected: PROTECTED_EXECUTION_COUNTS,
180
+ policy: freeze.policy,
181
+ };
182
+ }
183
+ export function renderProtectedApprovalText(core, requestSha256) {
184
+ const requestHash = hash(requestSha256, 'request_sha256');
185
+ return [
186
+ 'BAFU protected owner-draft execution approval request',
187
+ `schema_version=${core.schema_version}`,
188
+ `approved_at_utc=${core.approved_at_utc}`,
189
+ `request_sha256=${requestHash}`,
190
+ `environment=${core.environment}`,
191
+ `project_ref=${core.project_ref}`,
192
+ `account_email=${core.account.email}`,
193
+ `account_user_id=${core.account.user_id}`,
194
+ `target_visibility=${core.target_visibility}`,
195
+ `plan_sha256=${core.plan.plan_sha256}`,
196
+ `operation_id=${core.plan.operation_id}`,
197
+ `plan_file_sha256=${core.plan.plan_file_sha256}`,
198
+ `freeze_file_sha256=${core.freeze_file_sha256}`,
199
+ `freeze_sha256=${core.freeze_sha256}`,
200
+ `alias_plan_request_sha256=${core.sets.alias_plan_request_sha256}`,
201
+ `before_hash_set_sha256=${core.sets.before_hash_set_sha256}`,
202
+ `desired_hash_set_sha256=${core.sets.desired_hash_set_sha256}`,
203
+ `exchange_rewrite_set_sha256=${core.sets.exchange_rewrite_set_sha256}`,
204
+ `support_snapshot_set_sha256=${core.sets.support_snapshot_set_sha256}`,
205
+ `derivative_baseline_set_sha256=${core.sets.derivative_baseline_set_sha256}`,
206
+ `derivative_target_set_sha256=${core.sets.derivative_target_set_sha256}`,
207
+ `toolchain_evidence_sha256=${core.sets.toolchain_evidence_sha256}`,
208
+ `action_count=${core.expected.action_count}`,
209
+ `batch_count=${core.expected.batch_count}`,
210
+ `exchange_count=${core.expected.exchange_count}`,
211
+ `amount_field_count=${core.expected.amount_field_count}`,
212
+ `unrelated_exchange_count=${core.expected.unrelated_exchange_count}`,
213
+ `audit_count=${core.expected.audit_count}`,
214
+ `flowproperty_count=${core.expected.flowproperty_count}`,
215
+ `flow_count=${core.expected.flow_count}`,
216
+ `process_count=${core.expected.process_count}`,
217
+ `derivative_target_count=${core.expected.derivative_target_count}`,
218
+ `state_code_changes=${core.policy.state_code_changes}`,
219
+ `save_draft=${core.policy.save_draft}`,
220
+ `deletes=${core.policy.deletes}`,
221
+ `rebuild_derivatives=${core.policy.rebuild_derivatives}`,
222
+ `unitgroup_actions=${core.policy.unitgroup_actions}`,
223
+ `person_distance_actions=${core.policy.person_distance_actions}`,
224
+ `max_admit_posts=${core.policy.max_admit_posts}`,
225
+ `automatic_retry=${String(core.policy.automatic_retry)}`,
226
+ 'Approve only by returning this text byte-for-byte without edits.',
227
+ '',
228
+ ].join('\n');
229
+ }
230
+ export function parseProtectedApprovalRequest(value) {
231
+ if (!isJsonObject(value))
232
+ fail('Approval request must be an object.');
233
+ exactKeys(value, [
234
+ 'schema_version',
235
+ 'approved_at_utc',
236
+ 'environment',
237
+ 'project_ref',
238
+ 'account',
239
+ 'target_visibility',
240
+ 'plan',
241
+ 'freeze_file_sha256',
242
+ 'freeze_sha256',
243
+ 'sets',
244
+ 'expected',
245
+ 'policy',
246
+ 'request_sha256',
247
+ 'approval_text',
248
+ 'approval_text_sha256',
249
+ ], 'approval_request');
250
+ if (value.schema_version !== PROTECTED_PREPARATION_CONTRACT.approval_request_schema ||
251
+ value.environment !== 'production' ||
252
+ value.target_visibility !== 'owner_draft') {
253
+ fail('Approval request must be the production owner-draft v1 contract.');
254
+ }
255
+ const core = {
256
+ schema_version: PROTECTED_PREPARATION_CONTRACT.approval_request_schema,
257
+ approved_at_utc: canonicalTimestamp(value.approved_at_utc, 'approved_at_utc'),
258
+ environment: 'production',
259
+ project_ref: token(value.project_ref, 'project_ref'),
260
+ account: account(value.account, 'account'),
261
+ target_visibility: 'owner_draft',
262
+ plan: planBinding(value.plan),
263
+ freeze_file_sha256: hash(value.freeze_file_sha256, 'freeze_file_sha256'),
264
+ freeze_sha256: hash(value.freeze_sha256, 'freeze_sha256'),
265
+ sets: freezeSets(value.sets),
266
+ expected: expectedCounts(value.expected),
267
+ policy: freezePolicy(value.policy),
268
+ };
269
+ const requestSha256 = hash(value.request_sha256, 'request_sha256');
270
+ if (sha256Json(core) !== requestSha256) {
271
+ fail('request_sha256 does not match the canonical approval-request core.');
272
+ }
273
+ const approvalText = exactText(value.approval_text, 'approval_text');
274
+ const expectedText = renderProtectedApprovalText(core, requestSha256);
275
+ if (approvalText !== expectedText) {
276
+ fail('approval_text is not the byte-exact canonical request text.');
277
+ }
278
+ const approvalTextSha256 = hash(value.approval_text_sha256, 'approval_text_sha256');
279
+ if (sha256Text(approvalText) !== approvalTextSha256) {
280
+ fail('approval_text_sha256 does not match the byte-exact approval text.');
281
+ }
282
+ return {
283
+ ...core,
284
+ request_sha256: requestSha256,
285
+ approval_text: approvalText,
286
+ approval_text_sha256: approvalTextSha256,
287
+ };
288
+ }
289
+ function assertAliasPlanRequest(plan, value) {
290
+ if (value.schema_version !== 'dataset-alias-plan.v1' ||
291
+ value.plan_sha256 !== plan.plan_sha256 ||
292
+ value.operation_id !== plan.operation_id ||
293
+ value.target_visibility !== 'owner_draft' ||
294
+ !Array.isArray(value.batches) ||
295
+ value.batches.length !== 2) {
296
+ fail('Alias plan request does not bind the exact owner-draft maintenance plan.');
297
+ }
298
+ const dimensions = ['time', 'length_time'];
299
+ for (const [index, batch] of value.batches.entries()) {
300
+ if (!isJsonObject(batch) ||
301
+ batch.plan_sha256 !== plan.plan_sha256 ||
302
+ batch.operation_id !== plan.operation_id ||
303
+ batch.target_visibility !== 'owner_draft' ||
304
+ batch.dimension !== dimensions[index]) {
305
+ fail('Alias plan request batches must be exact ordered plan-bound time/length_time batches.');
306
+ }
307
+ }
308
+ }
309
+ export function deriveProtectedDerivativeSnapshotTargets(plan, expectedAccount) {
310
+ const preparedAccount = account(expectedAccount, 'account');
311
+ assertProtectedPreparationPlanSha256(plan.plan_sha256, 'plan.plan_sha256');
312
+ if (plan.operation !== 'merge-support-aliases' ||
313
+ plan.status !== 'ready' ||
314
+ plan.target_mode !== 'owner_draft' ||
315
+ plan.blockers.length !== 0 ||
316
+ plan.account.user_id !== preparedAccount.user_id ||
317
+ plan.account.email !== preparedAccount.email ||
318
+ computePlanSha256(plan) !== plan.plan_sha256) {
319
+ fail('Derivative target derivation requires the exact canonical owner-draft plan and account.');
320
+ }
321
+ const actions = plan.actions
322
+ .filter((action) => action.table === 'flows' || action.table === 'processes')
323
+ .sort((left, right) => left.table.localeCompare(right.table) ||
324
+ left.id.localeCompare(right.id) ||
325
+ left.version.localeCompare(right.version));
326
+ if (actions.length !== PROTECTED_EXECUTION_COUNTS.derivative_target_count ||
327
+ actions.filter((action) => action.table === 'flows').length !==
328
+ PROTECTED_EXECUTION_COUNTS.flow_count ||
329
+ actions.filter((action) => action.table === 'processes').length !==
330
+ PROTECTED_EXECUTION_COUNTS.process_count ||
331
+ actions.some((action) => action.expected_user_id !== preparedAccount.user_id || action.expected_state_code !== 0)) {
332
+ fail('Plan derivative targets must contain exactly 23 owner-draft flows and 27 processes.');
333
+ }
334
+ const targets = actions.map((action) => ({
335
+ table: action.table,
336
+ id: action.id,
337
+ version: action.version,
338
+ user_id: action.expected_user_id,
339
+ state_code: 0,
340
+ }));
341
+ const keys = targets.map((target) => `${target.table}\u0000${target.id}\u0000${target.version}`);
342
+ if (new Set(keys).size !== targets.length) {
343
+ fail('Plan derivative targets must not contain duplicate table/id/version identities.');
344
+ }
345
+ return targets;
346
+ }
347
+ function derivativeTargets(options) {
348
+ const actions = deriveProtectedDerivativeSnapshotTargets(options.plan, options.account);
349
+ if (options.snapshots.length !== actions.length) {
350
+ fail('Derivative actions and snapshots must form one exact 50-target set without duplicates.');
351
+ }
352
+ return actions.map((action, index) => {
353
+ const snapshot = options.snapshots[index];
354
+ if (!isJsonObject(snapshot) ||
355
+ snapshot.schema_version !== 'dataset-derivative-snapshot.v1' ||
356
+ snapshot.table !== action.table ||
357
+ snapshot.id !== action.id ||
358
+ snapshot.version !== action.version ||
359
+ snapshot.user_id !== action.user_id ||
360
+ snapshot.state_code !== 0) {
361
+ fail(`Derivative snapshot ${index} does not match the stable target order and identity.`);
362
+ }
363
+ exactKeys(snapshot, [
364
+ 'schema_version',
365
+ 'table',
366
+ 'id',
367
+ 'version',
368
+ 'user_id',
369
+ 'state_code',
370
+ 'modified_at',
371
+ 'json_sha256',
372
+ 'json_ordered_sha256',
373
+ 'extracted_text_sha256',
374
+ 'extracted_md_sha256',
375
+ 'embedding_ft_sha256',
376
+ 'embedding_ft_at',
377
+ 'snapshot_sha256',
378
+ ], `derivativeSnapshots[${index}]`);
379
+ timestamp(snapshot.modified_at, `derivativeSnapshots[${index}].modified_at`);
380
+ const jsonSha256 = hash(snapshot.json_sha256, `derivativeSnapshots[${index}].json_sha256`);
381
+ const jsonOrderedSha256 = hash(snapshot.json_ordered_sha256, `derivativeSnapshots[${index}].json_ordered_sha256`);
382
+ if (jsonSha256 !== jsonOrderedSha256) {
383
+ fail(`Derivative snapshot ${index} json and json_ordered hashes are inconsistent.`);
384
+ }
385
+ hash(snapshot.extracted_text_sha256, `derivativeSnapshots[${index}].extracted_text_sha256`);
386
+ if (snapshot.extracted_md_sha256 !== null) {
387
+ hash(snapshot.extracted_md_sha256, `derivativeSnapshots[${index}].extracted_md_sha256`);
388
+ }
389
+ if (snapshot.embedding_ft_sha256 !== null) {
390
+ hash(snapshot.embedding_ft_sha256, `derivativeSnapshots[${index}].embedding_ft_sha256`);
391
+ }
392
+ if (snapshot.embedding_ft_at !== null) {
393
+ timestamp(snapshot.embedding_ft_at, `derivativeSnapshots[${index}].embedding_ft_at`);
394
+ }
395
+ const snapshotSha256 = hash(snapshot.snapshot_sha256, `derivativeSnapshots[${index}].snapshot_sha256`);
396
+ return {
397
+ table: action.table,
398
+ id: action.id,
399
+ version: action.version,
400
+ user_id: action.user_id,
401
+ state_code: 0,
402
+ baseline_snapshot_sha256: snapshotSha256,
403
+ };
404
+ });
405
+ }
406
+ export function buildProtectedFreeze(options) {
407
+ const planFileSha256 = hash(options.planFileSha256, 'planFileSha256');
408
+ const toolchainEvidenceSha256 = hash(options.toolchainEvidenceSha256, 'toolchainEvidenceSha256');
409
+ const preparedAccount = account(options.account, 'account');
410
+ assertProtectedPreparationPlanSha256(options.plan.plan_sha256, 'plan.plan_sha256');
411
+ if (options.plan.operation !== 'merge-support-aliases' ||
412
+ options.plan.status !== 'ready' ||
413
+ options.plan.target_mode !== 'owner_draft' ||
414
+ options.plan.blockers.length !== 0 ||
415
+ options.plan.account.user_id !== preparedAccount.user_id ||
416
+ options.plan.account.email !== preparedAccount.email ||
417
+ computePlanSha256(options.plan) !== options.plan.plan_sha256) {
418
+ fail('Freeze builder requires the exact canonical ready owner-draft plan and account.');
419
+ }
420
+ assertAliasPlanRequest(options.plan, options.aliasPlanRequest);
421
+ const aliasPlanRequestSha256 = sha256Json(options.aliasPlanRequest);
422
+ const targets = derivativeTargets({
423
+ plan: options.plan,
424
+ account: preparedAccount,
425
+ snapshots: options.derivativeSnapshots,
426
+ });
427
+ const planSets = protectedPlanSetHashes(options.plan);
428
+ const candidate = {
429
+ schema_version: PROTECTED_EXECUTION_CONTRACT.freeze_schema,
430
+ environment: 'production',
431
+ project_ref: assertProtectedProductionProjectRef(options.projectRef),
432
+ account: preparedAccount,
433
+ target_visibility: 'owner_draft',
434
+ plan: {
435
+ plan_file_sha256: planFileSha256,
436
+ plan_sha256: options.plan.plan_sha256,
437
+ operation_id: options.plan.operation_id,
438
+ },
439
+ sets: {
440
+ ...planSets,
441
+ alias_plan_request_sha256: aliasPlanRequestSha256,
442
+ derivative_baseline_set_sha256: protectedDerivativeBaselineSetSha256(targets),
443
+ toolchain_evidence_sha256: toolchainEvidenceSha256,
444
+ },
445
+ expected: PROTECTED_EXECUTION_COUNTS,
446
+ derivative_targets: targets,
447
+ policy: {
448
+ state_code_changes: 0,
449
+ save_draft: 0,
450
+ deletes: 0,
451
+ rebuild_derivatives: 0,
452
+ unitgroup_actions: 0,
453
+ person_distance_actions: 0,
454
+ max_admit_posts: 1,
455
+ automatic_retry: false,
456
+ },
457
+ freeze_sha256: '',
458
+ };
459
+ candidate.freeze_sha256 = computeProtectedFreezeSha256(candidate);
460
+ const freeze = parseProtectedFreeze(candidate);
461
+ assertProtectedFreezeMatchesPlan({
462
+ plan: options.plan,
463
+ planFileSha256,
464
+ aliasPlanRequestSha256,
465
+ freeze,
466
+ });
467
+ return {
468
+ ...canonicalArtifact(freeze),
469
+ alias_plan_request_sha256: aliasPlanRequestSha256,
470
+ };
471
+ }
472
+ export function buildProtectedApprovalRequest(options) {
473
+ const freeze = parseProtectedFreeze(options.freeze);
474
+ const core = approvalRequestCore(freeze, options.freezeFileSha256, options.approvedAtUtc);
475
+ const requestSha256 = sha256Json(core);
476
+ const approvalText = renderProtectedApprovalText(core, requestSha256);
477
+ const request = parseProtectedApprovalRequest({
478
+ ...core,
479
+ request_sha256: requestSha256,
480
+ approval_text: approvalText,
481
+ approval_text_sha256: sha256Text(approvalText),
482
+ });
483
+ return canonicalArtifact(request);
484
+ }
485
+ export function sealProtectedApproval(options) {
486
+ const request = parseProtectedApprovalRequest(options.approvalRequest);
487
+ const freeze = parseProtectedFreeze(options.freeze);
488
+ assertProtectedProductionProjectRef(freeze.project_ref);
489
+ const freezeFileSha256 = hash(options.freezeFileSha256, 'freezeFileSha256');
490
+ const approveRequestSha256 = hash(options.approveRequestSha256, 'approveRequestSha256');
491
+ const approveTextSha256 = hash(options.approveTextSha256, 'approveTextSha256');
492
+ const approvedAtUtc = canonicalTimestamp(options.approvedAtUtc, 'approvedAtUtc');
493
+ if (options.humanApprovalText !== request.approval_text ||
494
+ approveRequestSha256 !== request.request_sha256 ||
495
+ approveTextSha256 !== request.approval_text_sha256 ||
496
+ options.confirmAccountEmail !== request.account.email ||
497
+ approvedAtUtc !== request.approved_at_utc) {
498
+ fail('Explicit human approval does not match the byte-exact request, hashes, account, or approved timestamp.');
499
+ }
500
+ const expectedCore = approvalRequestCore(freeze, freezeFileSha256, request.approved_at_utc);
501
+ if (sha256Json(expectedCore) !== request.request_sha256) {
502
+ fail('Approval request does not bind the supplied freeze file, plan, account, or toolchain.');
503
+ }
504
+ const approval = {
505
+ schema_version: PROTECTED_EXECUTION_CONTRACT.approval_schema,
506
+ approved_at_utc: request.approved_at_utc,
507
+ environment: 'production',
508
+ project_ref: freeze.project_ref,
509
+ account: freeze.account,
510
+ target_visibility: 'owner_draft',
511
+ plan_sha256: freeze.plan.plan_sha256,
512
+ operation_id: freeze.plan.operation_id,
513
+ plan_file_sha256: freeze.plan.plan_file_sha256,
514
+ freeze_file_sha256: freezeFileSha256,
515
+ freeze_sha256: freeze.freeze_sha256,
516
+ approval_text_sha256: request.approval_text_sha256,
517
+ max_admit_posts: 1,
518
+ automatic_retry: false,
519
+ approval_identity_sha256: '',
520
+ };
521
+ approval.approval_identity_sha256 = computeProtectedApprovalIdentitySha256(approval);
522
+ return canonicalArtifact(parseProtectedApproval(approval));
523
+ }
524
+ //# sourceMappingURL=dataset-maintenance-protected-preparation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dataset-maintenance-protected-preparation.js","sourceRoot":"","sources":["../../../src/lib/dataset-maintenance-protected-preparation.ts"],"names":[],"mappings":"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","sourcesContent":["import { CliError } from './errors.js';\nimport {\n computePlanSha256,\n isJsonObject,\n sha256Json,\n sha256Text,\n stableJsonText,\n type DatasetMaintenancePlan,\n type JsonObject,\n} from './dataset-maintenance-contract.js';\nimport {\n PROTECTED_EXECUTION_CONTRACT,\n PROTECTED_EXECUTION_COUNTS,\n assertProtectedFreezeMatchesPlan,\n computeProtectedApprovalIdentitySha256,\n computeProtectedFreezeSha256,\n parseProtectedApproval,\n parseProtectedFreeze,\n protectedDerivativeBaselineSetSha256,\n protectedPlanSetHashes,\n type DatasetMaintenanceProtectedApproval,\n type DatasetMaintenanceProtectedFreeze,\n type ProtectedDerivativeSnapshot,\n type ProtectedDerivativeTarget,\n} from './dataset-maintenance-protected-contract.js';\n\nexport const PROTECTED_PREPARATION_CONTRACT = {\n approval_request_schema: 'dataset-alias-execution-approval-request.v1',\n} as const;\n\nexport const PROTECTED_PRODUCTION_PROJECT_REF = 'qgzvkongdjqiiamzbbts' as const;\n\nexport const PROTECTED_PREPARATION_REJECTED_PLAN_SHA256 = [\n '813a201ded0443c79639cfbdb8f5a2fad8a8781ef6edd3ec7019e9a45f5f33ce',\n '673331422e8dceeb7975984b07276f057b37e8d6de789d7f030ec29f3be29629',\n '7fdf7e2755599d426e31a9955985d54d5b7cef1adeaa7a10dcc7186353a6c3a8',\n] as const;\n\nconst SHA256 = /^[a-f0-9]{64}$/u;\n\ntype ProtectedApprovalRequestCore = {\n schema_version: typeof PROTECTED_PREPARATION_CONTRACT.approval_request_schema;\n approved_at_utc: string;\n environment: 'production';\n project_ref: string;\n account: { user_id: string; email: string };\n target_visibility: 'owner_draft';\n plan: DatasetMaintenanceProtectedFreeze['plan'];\n freeze_file_sha256: string;\n freeze_sha256: string;\n sets: DatasetMaintenanceProtectedFreeze['sets'];\n expected: typeof PROTECTED_EXECUTION_COUNTS;\n policy: DatasetMaintenanceProtectedFreeze['policy'];\n};\n\nexport type DatasetMaintenanceProtectedApprovalRequest = ProtectedApprovalRequestCore & {\n request_sha256: string;\n approval_text: string;\n approval_text_sha256: string;\n};\n\nexport type CanonicalProtectedArtifact<T> = {\n value: T;\n canonical_file_text: string;\n file_sha256: string;\n};\n\nexport type BuiltProtectedFreeze = CanonicalProtectedArtifact<DatasetMaintenanceProtectedFreeze> & {\n alias_plan_request_sha256: string;\n};\n\nexport type BuiltProtectedApprovalRequest =\n CanonicalProtectedArtifact<DatasetMaintenanceProtectedApprovalRequest>;\n\nexport type BuiltProtectedApproval =\n CanonicalProtectedArtifact<DatasetMaintenanceProtectedApproval>;\n\nexport type ProtectedDerivativeSnapshotTarget = Omit<\n ProtectedDerivativeTarget,\n 'baseline_snapshot_sha256'\n>;\n\nfunction fail(message: string): never {\n throw new CliError(message, {\n code: 'DATASET_MAINTENANCE_PROTECTED_PREPARATION_INVALID',\n exitCode: 2,\n });\n}\n\nfunction exactKeys(value: JsonObject, expected: readonly string[], label: string): void {\n const actual = Object.keys(value).sort();\n const wanted = [...expected].sort();\n if (actual.length !== wanted.length || actual.some((key, index) => key !== wanted[index])) {\n fail(`${label} must contain exactly: ${wanted.join(', ')}.`);\n }\n}\n\nfunction token(value: unknown, label: string): string {\n if (typeof value !== 'string' || !value || value.trim() !== value) {\n fail(`${label} must be a non-empty canonical string.`);\n }\n return value;\n}\n\nfunction exactText(value: unknown, label: string): string {\n if (typeof value !== 'string' || value.length === 0) {\n fail(`${label} must be a non-empty byte-exact string.`);\n }\n return value;\n}\n\nfunction hash(value: unknown, label: string): string {\n const digest = token(value, label);\n if (!SHA256.test(digest)) fail(`${label} must be a lowercase SHA-256 digest.`);\n return digest;\n}\n\nexport function assertProtectedPreparationPlanSha256(\n value: unknown,\n label = 'plan_sha256',\n): string {\n const digest = hash(value, label);\n if ((PROTECTED_PREPARATION_REJECTED_PLAN_SHA256 as readonly string[]).includes(digest)) {\n fail(`${label} is a historical superseded plan and cannot be prepared or approved.`);\n }\n return digest;\n}\n\nexport function assertProtectedProductionProjectRef(value: unknown): string {\n const projectRef = token(value, 'project_ref');\n if (projectRef !== PROTECTED_PRODUCTION_PROJECT_REF) {\n fail('Protected BAFU preparation and commit are restricted to the production project.');\n }\n return projectRef;\n}\n\nfunction canonicalTimestamp(value: unknown, label: string): string {\n const timestamp = token(value, label);\n const parsed = Date.parse(timestamp);\n if (!Number.isFinite(parsed) || new Date(parsed).toISOString() !== timestamp) {\n fail(`${label} must be a canonical ISO timestamp.`);\n }\n return timestamp;\n}\n\nfunction timestamp(value: unknown, label: string): string {\n const result = token(value, label);\n if (!Number.isFinite(Date.parse(result))) fail(`${label} must be an ISO timestamp.`);\n return result;\n}\n\nfunction account(value: unknown, label: string): { user_id: string; email: string } {\n if (!isJsonObject(value)) fail(`${label} must be an object.`);\n exactKeys(value, ['user_id', 'email'], label);\n return {\n user_id: token(value.user_id, `${label}.user_id`),\n email: token(value.email, `${label}.email`),\n };\n}\n\nfunction planBinding(value: unknown): DatasetMaintenanceProtectedFreeze['plan'] {\n if (!isJsonObject(value)) fail('plan must be an object.');\n exactKeys(value, ['plan_file_sha256', 'plan_sha256', 'operation_id'], 'plan');\n return {\n plan_file_sha256: hash(value.plan_file_sha256, 'plan.plan_file_sha256'),\n plan_sha256: assertProtectedPreparationPlanSha256(value.plan_sha256, 'plan.plan_sha256'),\n operation_id: token(value.operation_id, 'plan.operation_id'),\n };\n}\n\nfunction freezeSets(value: unknown): DatasetMaintenanceProtectedFreeze['sets'] {\n if (!isJsonObject(value)) fail('sets must be an object.');\n const keys = [\n 'alias_plan_request_sha256',\n 'before_hash_set_sha256',\n 'desired_hash_set_sha256',\n 'exchange_rewrite_set_sha256',\n 'support_snapshot_set_sha256',\n 'derivative_baseline_set_sha256',\n 'derivative_target_set_sha256',\n 'toolchain_evidence_sha256',\n ] as const;\n exactKeys(value, keys, 'sets');\n return Object.fromEntries(\n keys.map((key) => [key, hash(value[key], `sets.${key}`)]),\n ) as DatasetMaintenanceProtectedFreeze['sets'];\n}\n\nfunction expectedCounts(value: unknown): typeof PROTECTED_EXECUTION_COUNTS {\n if (!isJsonObject(value)) fail('expected must be an object.');\n const keys = Object.keys(PROTECTED_EXECUTION_COUNTS);\n exactKeys(value, keys, 'expected');\n for (const [key, expected] of Object.entries(PROTECTED_EXECUTION_COUNTS)) {\n if (value[key] !== expected) fail(`expected.${key} must equal ${expected}.`);\n }\n return PROTECTED_EXECUTION_COUNTS;\n}\n\nfunction freezePolicy(value: unknown): DatasetMaintenanceProtectedFreeze['policy'] {\n if (!isJsonObject(value)) fail('policy must be an object.');\n const keys = [\n 'state_code_changes',\n 'save_draft',\n 'deletes',\n 'rebuild_derivatives',\n 'unitgroup_actions',\n 'person_distance_actions',\n 'max_admit_posts',\n 'automatic_retry',\n ] as const;\n exactKeys(value, keys, 'policy');\n if (\n value.state_code_changes !== 0 ||\n value.save_draft !== 0 ||\n value.deletes !== 0 ||\n value.rebuild_derivatives !== 0 ||\n value.unitgroup_actions !== 0 ||\n value.person_distance_actions !== 0 ||\n value.max_admit_posts !== 1 ||\n value.automatic_retry !== false\n ) {\n fail('policy must preserve the one-shot owner-draft execution boundary.');\n }\n return {\n state_code_changes: 0,\n save_draft: 0,\n deletes: 0,\n rebuild_derivatives: 0,\n unitgroup_actions: 0,\n person_distance_actions: 0,\n max_admit_posts: 1,\n automatic_retry: false,\n };\n}\n\nfunction canonicalArtifact<T>(value: T): CanonicalProtectedArtifact<T> {\n const canonicalFileText = `${stableJsonText(value)}\\n`;\n return {\n value,\n canonical_file_text: canonicalFileText,\n file_sha256: sha256Text(canonicalFileText),\n };\n}\n\nfunction approvalRequestCore(\n freeze: DatasetMaintenanceProtectedFreeze,\n freezeFileSha256: string,\n approvedAtUtc: string,\n): ProtectedApprovalRequestCore {\n assertProtectedPreparationPlanSha256(freeze.plan.plan_sha256, 'freeze.plan.plan_sha256');\n const freezeFileDigest = hash(freezeFileSha256, 'freeze_file_sha256');\n if (freezeFileDigest !== canonicalArtifact(freeze).file_sha256) {\n fail('freeze_file_sha256 does not match the canonical freeze artifact bytes.');\n }\n return {\n schema_version: PROTECTED_PREPARATION_CONTRACT.approval_request_schema,\n approved_at_utc: canonicalTimestamp(approvedAtUtc, 'approved_at_utc'),\n environment: 'production',\n project_ref: assertProtectedProductionProjectRef(freeze.project_ref),\n account: freeze.account,\n target_visibility: 'owner_draft',\n plan: freeze.plan,\n freeze_file_sha256: freezeFileDigest,\n freeze_sha256: freeze.freeze_sha256,\n sets: freeze.sets,\n expected: PROTECTED_EXECUTION_COUNTS,\n policy: freeze.policy,\n };\n}\n\nexport function renderProtectedApprovalText(\n core: ProtectedApprovalRequestCore,\n requestSha256: string,\n): string {\n const requestHash = hash(requestSha256, 'request_sha256');\n return [\n 'BAFU protected owner-draft execution approval request',\n `schema_version=${core.schema_version}`,\n `approved_at_utc=${core.approved_at_utc}`,\n `request_sha256=${requestHash}`,\n `environment=${core.environment}`,\n `project_ref=${core.project_ref}`,\n `account_email=${core.account.email}`,\n `account_user_id=${core.account.user_id}`,\n `target_visibility=${core.target_visibility}`,\n `plan_sha256=${core.plan.plan_sha256}`,\n `operation_id=${core.plan.operation_id}`,\n `plan_file_sha256=${core.plan.plan_file_sha256}`,\n `freeze_file_sha256=${core.freeze_file_sha256}`,\n `freeze_sha256=${core.freeze_sha256}`,\n `alias_plan_request_sha256=${core.sets.alias_plan_request_sha256}`,\n `before_hash_set_sha256=${core.sets.before_hash_set_sha256}`,\n `desired_hash_set_sha256=${core.sets.desired_hash_set_sha256}`,\n `exchange_rewrite_set_sha256=${core.sets.exchange_rewrite_set_sha256}`,\n `support_snapshot_set_sha256=${core.sets.support_snapshot_set_sha256}`,\n `derivative_baseline_set_sha256=${core.sets.derivative_baseline_set_sha256}`,\n `derivative_target_set_sha256=${core.sets.derivative_target_set_sha256}`,\n `toolchain_evidence_sha256=${core.sets.toolchain_evidence_sha256}`,\n `action_count=${core.expected.action_count}`,\n `batch_count=${core.expected.batch_count}`,\n `exchange_count=${core.expected.exchange_count}`,\n `amount_field_count=${core.expected.amount_field_count}`,\n `unrelated_exchange_count=${core.expected.unrelated_exchange_count}`,\n `audit_count=${core.expected.audit_count}`,\n `flowproperty_count=${core.expected.flowproperty_count}`,\n `flow_count=${core.expected.flow_count}`,\n `process_count=${core.expected.process_count}`,\n `derivative_target_count=${core.expected.derivative_target_count}`,\n `state_code_changes=${core.policy.state_code_changes}`,\n `save_draft=${core.policy.save_draft}`,\n `deletes=${core.policy.deletes}`,\n `rebuild_derivatives=${core.policy.rebuild_derivatives}`,\n `unitgroup_actions=${core.policy.unitgroup_actions}`,\n `person_distance_actions=${core.policy.person_distance_actions}`,\n `max_admit_posts=${core.policy.max_admit_posts}`,\n `automatic_retry=${String(core.policy.automatic_retry)}`,\n 'Approve only by returning this text byte-for-byte without edits.',\n '',\n ].join('\\n');\n}\n\nexport function parseProtectedApprovalRequest(\n value: unknown,\n): DatasetMaintenanceProtectedApprovalRequest {\n if (!isJsonObject(value)) fail('Approval request must be an object.');\n exactKeys(\n value,\n [\n 'schema_version',\n 'approved_at_utc',\n 'environment',\n 'project_ref',\n 'account',\n 'target_visibility',\n 'plan',\n 'freeze_file_sha256',\n 'freeze_sha256',\n 'sets',\n 'expected',\n 'policy',\n 'request_sha256',\n 'approval_text',\n 'approval_text_sha256',\n ],\n 'approval_request',\n );\n if (\n value.schema_version !== PROTECTED_PREPARATION_CONTRACT.approval_request_schema ||\n value.environment !== 'production' ||\n value.target_visibility !== 'owner_draft'\n ) {\n fail('Approval request must be the production owner-draft v1 contract.');\n }\n const core: ProtectedApprovalRequestCore = {\n schema_version: PROTECTED_PREPARATION_CONTRACT.approval_request_schema,\n approved_at_utc: canonicalTimestamp(value.approved_at_utc, 'approved_at_utc'),\n environment: 'production',\n project_ref: token(value.project_ref, 'project_ref'),\n account: account(value.account, 'account'),\n target_visibility: 'owner_draft',\n plan: planBinding(value.plan),\n freeze_file_sha256: hash(value.freeze_file_sha256, 'freeze_file_sha256'),\n freeze_sha256: hash(value.freeze_sha256, 'freeze_sha256'),\n sets: freezeSets(value.sets),\n expected: expectedCounts(value.expected),\n policy: freezePolicy(value.policy),\n };\n const requestSha256 = hash(value.request_sha256, 'request_sha256');\n if (sha256Json(core) !== requestSha256) {\n fail('request_sha256 does not match the canonical approval-request core.');\n }\n const approvalText = exactText(value.approval_text, 'approval_text');\n const expectedText = renderProtectedApprovalText(core, requestSha256);\n if (approvalText !== expectedText) {\n fail('approval_text is not the byte-exact canonical request text.');\n }\n const approvalTextSha256 = hash(value.approval_text_sha256, 'approval_text_sha256');\n if (sha256Text(approvalText) !== approvalTextSha256) {\n fail('approval_text_sha256 does not match the byte-exact approval text.');\n }\n return {\n ...core,\n request_sha256: requestSha256,\n approval_text: approvalText,\n approval_text_sha256: approvalTextSha256,\n };\n}\n\nfunction assertAliasPlanRequest(plan: DatasetMaintenancePlan, value: JsonObject): void {\n if (\n value.schema_version !== 'dataset-alias-plan.v1' ||\n value.plan_sha256 !== plan.plan_sha256 ||\n value.operation_id !== plan.operation_id ||\n value.target_visibility !== 'owner_draft' ||\n !Array.isArray(value.batches) ||\n value.batches.length !== 2\n ) {\n fail('Alias plan request does not bind the exact owner-draft maintenance plan.');\n }\n const dimensions = ['time', 'length_time'];\n for (const [index, batch] of value.batches.entries()) {\n if (\n !isJsonObject(batch) ||\n batch.plan_sha256 !== plan.plan_sha256 ||\n batch.operation_id !== plan.operation_id ||\n batch.target_visibility !== 'owner_draft' ||\n batch.dimension !== dimensions[index]\n ) {\n fail('Alias plan request batches must be exact ordered plan-bound time/length_time batches.');\n }\n }\n}\n\nexport function deriveProtectedDerivativeSnapshotTargets(\n plan: DatasetMaintenancePlan,\n expectedAccount: { user_id: string; email: string },\n): ProtectedDerivativeSnapshotTarget[] {\n const preparedAccount = account(expectedAccount, 'account');\n assertProtectedPreparationPlanSha256(plan.plan_sha256, 'plan.plan_sha256');\n if (\n plan.operation !== 'merge-support-aliases' ||\n plan.status !== 'ready' ||\n plan.target_mode !== 'owner_draft' ||\n plan.blockers.length !== 0 ||\n plan.account.user_id !== preparedAccount.user_id ||\n plan.account.email !== preparedAccount.email ||\n computePlanSha256(plan) !== plan.plan_sha256\n ) {\n fail('Derivative target derivation requires the exact canonical owner-draft plan and account.');\n }\n const actions = plan.actions\n .filter((action) => action.table === 'flows' || action.table === 'processes')\n .sort(\n (left, right) =>\n left.table.localeCompare(right.table) ||\n left.id.localeCompare(right.id) ||\n left.version.localeCompare(right.version),\n );\n if (\n actions.length !== PROTECTED_EXECUTION_COUNTS.derivative_target_count ||\n actions.filter((action) => action.table === 'flows').length !==\n PROTECTED_EXECUTION_COUNTS.flow_count ||\n actions.filter((action) => action.table === 'processes').length !==\n PROTECTED_EXECUTION_COUNTS.process_count ||\n actions.some(\n (action) =>\n action.expected_user_id !== preparedAccount.user_id || action.expected_state_code !== 0,\n )\n ) {\n fail('Plan derivative targets must contain exactly 23 owner-draft flows and 27 processes.');\n }\n const targets = actions.map((action) => ({\n table: action.table as 'flows' | 'processes',\n id: action.id,\n version: action.version,\n user_id: action.expected_user_id,\n state_code: 0 as const,\n }));\n const keys = targets.map((target) => `${target.table}\\u0000${target.id}\\u0000${target.version}`);\n if (new Set(keys).size !== targets.length) {\n fail('Plan derivative targets must not contain duplicate table/id/version identities.');\n }\n return targets;\n}\n\nfunction derivativeTargets(options: {\n plan: DatasetMaintenancePlan;\n account: { user_id: string; email: string };\n snapshots: ProtectedDerivativeSnapshot[];\n}): ProtectedDerivativeTarget[] {\n const actions = deriveProtectedDerivativeSnapshotTargets(options.plan, options.account);\n if (options.snapshots.length !== actions.length) {\n fail('Derivative actions and snapshots must form one exact 50-target set without duplicates.');\n }\n return actions.map((action, index) => {\n const snapshot: unknown = options.snapshots[index];\n if (\n !isJsonObject(snapshot) ||\n snapshot.schema_version !== 'dataset-derivative-snapshot.v1' ||\n snapshot.table !== action.table ||\n snapshot.id !== action.id ||\n snapshot.version !== action.version ||\n snapshot.user_id !== action.user_id ||\n snapshot.state_code !== 0\n ) {\n fail(`Derivative snapshot ${index} does not match the stable target order and identity.`);\n }\n exactKeys(\n snapshot,\n [\n 'schema_version',\n 'table',\n 'id',\n 'version',\n 'user_id',\n 'state_code',\n 'modified_at',\n 'json_sha256',\n 'json_ordered_sha256',\n 'extracted_text_sha256',\n 'extracted_md_sha256',\n 'embedding_ft_sha256',\n 'embedding_ft_at',\n 'snapshot_sha256',\n ],\n `derivativeSnapshots[${index}]`,\n );\n timestamp(snapshot.modified_at, `derivativeSnapshots[${index}].modified_at`);\n const jsonSha256 = hash(snapshot.json_sha256, `derivativeSnapshots[${index}].json_sha256`);\n const jsonOrderedSha256 = hash(\n snapshot.json_ordered_sha256,\n `derivativeSnapshots[${index}].json_ordered_sha256`,\n );\n if (jsonSha256 !== jsonOrderedSha256) {\n fail(`Derivative snapshot ${index} json and json_ordered hashes are inconsistent.`);\n }\n hash(snapshot.extracted_text_sha256, `derivativeSnapshots[${index}].extracted_text_sha256`);\n if (snapshot.extracted_md_sha256 !== null) {\n hash(snapshot.extracted_md_sha256, `derivativeSnapshots[${index}].extracted_md_sha256`);\n }\n if (snapshot.embedding_ft_sha256 !== null) {\n hash(snapshot.embedding_ft_sha256, `derivativeSnapshots[${index}].embedding_ft_sha256`);\n }\n if (snapshot.embedding_ft_at !== null) {\n timestamp(snapshot.embedding_ft_at, `derivativeSnapshots[${index}].embedding_ft_at`);\n }\n const snapshotSha256 = hash(\n snapshot.snapshot_sha256,\n `derivativeSnapshots[${index}].snapshot_sha256`,\n );\n return {\n table: action.table,\n id: action.id,\n version: action.version,\n user_id: action.user_id,\n state_code: 0,\n baseline_snapshot_sha256: snapshotSha256,\n };\n });\n}\n\nexport function buildProtectedFreeze(options: {\n plan: DatasetMaintenancePlan;\n planFileSha256: string;\n aliasPlanRequest: JsonObject;\n projectRef: string;\n account: { user_id: string; email: string };\n toolchainEvidenceSha256: string;\n derivativeSnapshots: ProtectedDerivativeSnapshot[];\n}): BuiltProtectedFreeze {\n const planFileSha256 = hash(options.planFileSha256, 'planFileSha256');\n const toolchainEvidenceSha256 = hash(options.toolchainEvidenceSha256, 'toolchainEvidenceSha256');\n const preparedAccount = account(options.account, 'account');\n assertProtectedPreparationPlanSha256(options.plan.plan_sha256, 'plan.plan_sha256');\n if (\n options.plan.operation !== 'merge-support-aliases' ||\n options.plan.status !== 'ready' ||\n options.plan.target_mode !== 'owner_draft' ||\n options.plan.blockers.length !== 0 ||\n options.plan.account.user_id !== preparedAccount.user_id ||\n options.plan.account.email !== preparedAccount.email ||\n computePlanSha256(options.plan) !== options.plan.plan_sha256\n ) {\n fail('Freeze builder requires the exact canonical ready owner-draft plan and account.');\n }\n assertAliasPlanRequest(options.plan, options.aliasPlanRequest);\n const aliasPlanRequestSha256 = sha256Json(options.aliasPlanRequest);\n const targets = derivativeTargets({\n plan: options.plan,\n account: preparedAccount,\n snapshots: options.derivativeSnapshots,\n });\n const planSets = protectedPlanSetHashes(options.plan);\n const candidate: DatasetMaintenanceProtectedFreeze = {\n schema_version: PROTECTED_EXECUTION_CONTRACT.freeze_schema,\n environment: 'production',\n project_ref: assertProtectedProductionProjectRef(options.projectRef),\n account: preparedAccount,\n target_visibility: 'owner_draft',\n plan: {\n plan_file_sha256: planFileSha256,\n plan_sha256: options.plan.plan_sha256,\n operation_id: options.plan.operation_id,\n },\n sets: {\n ...planSets,\n alias_plan_request_sha256: aliasPlanRequestSha256,\n derivative_baseline_set_sha256: protectedDerivativeBaselineSetSha256(targets),\n toolchain_evidence_sha256: toolchainEvidenceSha256,\n },\n expected: PROTECTED_EXECUTION_COUNTS,\n derivative_targets: targets,\n policy: {\n state_code_changes: 0,\n save_draft: 0,\n deletes: 0,\n rebuild_derivatives: 0,\n unitgroup_actions: 0,\n person_distance_actions: 0,\n max_admit_posts: 1,\n automatic_retry: false,\n },\n freeze_sha256: '',\n };\n candidate.freeze_sha256 = computeProtectedFreezeSha256(candidate);\n const freeze = parseProtectedFreeze(candidate);\n assertProtectedFreezeMatchesPlan({\n plan: options.plan,\n planFileSha256,\n aliasPlanRequestSha256,\n freeze,\n });\n return {\n ...canonicalArtifact(freeze),\n alias_plan_request_sha256: aliasPlanRequestSha256,\n };\n}\n\nexport function buildProtectedApprovalRequest(options: {\n freeze: DatasetMaintenanceProtectedFreeze;\n freezeFileSha256: string;\n approvedAtUtc: string;\n}): BuiltProtectedApprovalRequest {\n const freeze = parseProtectedFreeze(options.freeze);\n const core = approvalRequestCore(freeze, options.freezeFileSha256, options.approvedAtUtc);\n const requestSha256 = sha256Json(core);\n const approvalText = renderProtectedApprovalText(core, requestSha256);\n const request = parseProtectedApprovalRequest({\n ...core,\n request_sha256: requestSha256,\n approval_text: approvalText,\n approval_text_sha256: sha256Text(approvalText),\n });\n return canonicalArtifact(request);\n}\n\nexport function sealProtectedApproval(options: {\n approvalRequest: unknown;\n freeze: DatasetMaintenanceProtectedFreeze;\n freezeFileSha256: string;\n humanApprovalText: string;\n approveRequestSha256: string;\n approveTextSha256: string;\n approvedAtUtc: string;\n confirmAccountEmail: string;\n}): BuiltProtectedApproval {\n const request = parseProtectedApprovalRequest(options.approvalRequest);\n const freeze = parseProtectedFreeze(options.freeze);\n assertProtectedProductionProjectRef(freeze.project_ref);\n const freezeFileSha256 = hash(options.freezeFileSha256, 'freezeFileSha256');\n const approveRequestSha256 = hash(options.approveRequestSha256, 'approveRequestSha256');\n const approveTextSha256 = hash(options.approveTextSha256, 'approveTextSha256');\n const approvedAtUtc = canonicalTimestamp(options.approvedAtUtc, 'approvedAtUtc');\n if (\n options.humanApprovalText !== request.approval_text ||\n approveRequestSha256 !== request.request_sha256 ||\n approveTextSha256 !== request.approval_text_sha256 ||\n options.confirmAccountEmail !== request.account.email ||\n approvedAtUtc !== request.approved_at_utc\n ) {\n fail(\n 'Explicit human approval does not match the byte-exact request, hashes, account, or approved timestamp.',\n );\n }\n const expectedCore = approvalRequestCore(freeze, freezeFileSha256, request.approved_at_utc);\n if (sha256Json(expectedCore) !== request.request_sha256) {\n fail('Approval request does not bind the supplied freeze file, plan, account, or toolchain.');\n }\n const approval: DatasetMaintenanceProtectedApproval = {\n schema_version: PROTECTED_EXECUTION_CONTRACT.approval_schema,\n approved_at_utc: request.approved_at_utc,\n environment: 'production',\n project_ref: freeze.project_ref,\n account: freeze.account,\n target_visibility: 'owner_draft',\n plan_sha256: freeze.plan.plan_sha256,\n operation_id: freeze.plan.operation_id,\n plan_file_sha256: freeze.plan.plan_file_sha256,\n freeze_file_sha256: freezeFileSha256,\n freeze_sha256: freeze.freeze_sha256,\n approval_text_sha256: request.approval_text_sha256,\n max_admit_posts: 1,\n automatic_retry: false,\n approval_identity_sha256: '',\n };\n approval.approval_identity_sha256 = computeProtectedApprovalIdentitySha256(approval);\n return canonicalArtifact(parseProtectedApproval(approval));\n}\n"]}