@tiangong-lca/cli 0.0.24 → 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.
- package/README.md +66 -5
- package/dist/src/cli.js +484 -5
- package/dist/src/cli.js.map +1 -1
- package/dist/src/lib/dataset-maintenance-alias-request.js +99 -0
- package/dist/src/lib/dataset-maintenance-alias-request.js.map +1 -0
- package/dist/src/lib/dataset-maintenance-apply.js +12 -367
- package/dist/src/lib/dataset-maintenance-apply.js.map +1 -1
- package/dist/src/lib/dataset-maintenance-protected-artifacts.js +100 -0
- package/dist/src/lib/dataset-maintenance-protected-artifacts.js.map +1 -0
- package/dist/src/lib/dataset-maintenance-protected-before.js +284 -0
- package/dist/src/lib/dataset-maintenance-protected-before.js.map +1 -0
- package/dist/src/lib/dataset-maintenance-protected-contract.js +918 -0
- package/dist/src/lib/dataset-maintenance-protected-contract.js.map +1 -0
- package/dist/src/lib/dataset-maintenance-protected-freeze.js +230 -0
- package/dist/src/lib/dataset-maintenance-protected-freeze.js.map +1 -0
- package/dist/src/lib/dataset-maintenance-protected-preparation.js +524 -0
- package/dist/src/lib/dataset-maintenance-protected-preparation.js.map +1 -0
- package/dist/src/lib/dataset-maintenance-protected-run.js +667 -0
- package/dist/src/lib/dataset-maintenance-protected-run.js.map +1 -0
- package/dist/src/lib/dataset-maintenance-protected-seal.js +160 -0
- package/dist/src/lib/dataset-maintenance-protected-seal.js.map +1 -0
- package/dist/src/lib/dataset-maintenance-protected-toolchain.js +86 -0
- package/dist/src/lib/dataset-maintenance-protected-toolchain.js.map +1 -0
- package/dist/src/lib/dataset-maintenance-protected-verify.js +435 -0
- package/dist/src/lib/dataset-maintenance-protected-verify.js.map +1 -0
- package/dist/src/lib/dataset-maintenance-remote.js +116 -2
- package/dist/src/lib/dataset-maintenance-remote.js.map +1 -1
- package/package.json +1 -1
package/dist/src/cli.js
CHANGED
|
@@ -56,6 +56,9 @@ import { runDatasetClassificationApply, runDatasetClassificationAudit, runDatase
|
|
|
56
56
|
import { runDatasetMaintenanceClearAccount, } from './lib/dataset-maintenance-clear-account.js';
|
|
57
57
|
import { runDatasetMaintenancePlan } from './lib/dataset-maintenance-plan.js';
|
|
58
58
|
import { runDatasetMaintenanceApply } from './lib/dataset-maintenance-apply.js';
|
|
59
|
+
import { freezeDatasetMaintenanceProtected } from './lib/dataset-maintenance-protected-freeze.js';
|
|
60
|
+
import { runDatasetMaintenanceProtected } from './lib/dataset-maintenance-protected-run.js';
|
|
61
|
+
import { sealDatasetMaintenanceProtectedApproval } from './lib/dataset-maintenance-protected-seal.js';
|
|
59
62
|
import { runDatasetMaintenanceVerify } from './lib/dataset-maintenance-verify.js';
|
|
60
63
|
import { runDatasetSourceUploadAttachments, } from './lib/dataset-source-upload-attachments.js';
|
|
61
64
|
function renderMainHelp(dotEnvStatus) {
|
|
@@ -131,6 +134,8 @@ Examples:
|
|
|
131
134
|
tiangong-lca dataset references rewrite --input ./rows.jsonl --from flow:<old-id>@<old-version> --to flow:<new-id>@<new-version> --out-dir /abs/path/to/dataset-rewrite
|
|
132
135
|
tiangong-lca dataset maintenance clear-account --out-dir /abs/path/to/account-clear --json
|
|
133
136
|
tiangong-lca dataset maintenance plan --scope ./maintenance-scope.json --operation merge-support-aliases --out-dir /abs/path/to/dataset-maintenance
|
|
137
|
+
tiangong-lca dataset maintenance freeze-protected --plan ./maintenance-plan.json --toolchain-evidence ./toolchain.json --expected-project-ref <production-ref> --confirm bafudata@126.com --out-dir /abs/path/to/protected-freeze
|
|
138
|
+
tiangong-lca dataset maintenance run-protected --plan ./maintenance-plan.json --freeze ./protected-execution-seal.json --approval ./protected-approval.json --out-dir /abs/path/to/protected-run --status-only
|
|
134
139
|
tiangong-lca lifecyclemodel auto-build --input ./lifecyclemodel-auto-build.request.json --out-dir /abs/path/to/lifecyclemodel-run
|
|
135
140
|
tiangong-lca lifecyclemodel validate-build --run-dir /abs/path/to/lifecyclemodel-run
|
|
136
141
|
tiangong-lca lifecyclemodel publish-build --run-dir /abs/path/to/lifecyclemodel-run
|
|
@@ -283,6 +288,9 @@ Implemented Subcommands:
|
|
|
283
288
|
maintenance clear-account Dry-run or clear current authenticated account-owned dataset rows through RLS
|
|
284
289
|
maintenance plan Build an immutable, RLS-visible row-level maintenance plan
|
|
285
290
|
maintenance apply Execute an explicitly approved maintenance plan through current-user RLS
|
|
291
|
+
maintenance freeze-protected Read and freeze one exact production owner-draft plan without admitting or mutating it
|
|
292
|
+
maintenance seal-protected-approval Record byte-exact human approval entirely offline
|
|
293
|
+
maintenance run-protected Run or inspect one sealed, one-shot production maintenance execution
|
|
286
294
|
maintenance verify Read back affected rows and references against the immutable plan
|
|
287
295
|
|
|
288
296
|
Examples:
|
|
@@ -310,21 +318,31 @@ Examples:
|
|
|
310
318
|
tiangong-lca dataset references refresh-remote --input ./rows.jsonl --out ./rows.refreshed.jsonl --out-dir ./dataset-reference-refresh --help
|
|
311
319
|
tiangong-lca dataset maintenance clear-account --out-dir ./account-clear --json --help
|
|
312
320
|
tiangong-lca dataset maintenance plan --scope ./maintenance-scope.json --operation merge-support-aliases --out-dir ./dataset-maintenance --help
|
|
321
|
+
tiangong-lca dataset maintenance freeze-protected --help
|
|
322
|
+
tiangong-lca dataset maintenance seal-protected-approval --help
|
|
323
|
+
tiangong-lca dataset maintenance run-protected --help
|
|
313
324
|
`.trim();
|
|
314
325
|
}
|
|
315
326
|
function renderDatasetMaintenanceHelp() {
|
|
316
327
|
return `Usage:
|
|
317
|
-
tiangong-lca dataset maintenance <clear-account|plan|apply|verify> [options]
|
|
328
|
+
tiangong-lca dataset maintenance <clear-account|plan|apply|freeze-protected|seal-protected-approval|run-protected|verify> [options]
|
|
318
329
|
|
|
319
330
|
Actions:
|
|
320
331
|
clear-account Dry-run or delete current authenticated account-owned lifecyclemodels, processes, flows, sources, and contacts.
|
|
321
332
|
plan Build an immutable maintenance plan from a scope manifest, visible remote snapshot, dependency impact report, and intended operation.
|
|
322
|
-
apply Execute or durably admit an approved plan through current-user RLS and platform dataset command paths
|
|
333
|
+
apply Execute or durably admit an ordinary approved plan through current-user RLS and platform dataset command paths.
|
|
334
|
+
freeze-protected Re-read the exact production owner-draft census/support/50 derivatives and generate an unapproved freeze request.
|
|
335
|
+
seal-protected-approval Record a byte-exact human response into an approval artifact with no authentication or network access.
|
|
336
|
+
run-protected Run or inspect one sealed production execution with one-shot admission and terminal derivative proof.
|
|
323
337
|
verify Re-fetch rows, references, or derivative request state and report passed, pending, or failed independently of apply.
|
|
324
338
|
|
|
325
339
|
Safety:
|
|
326
|
-
plan and
|
|
340
|
+
plan, verify, and freeze-protected are read-only; seal-protected-approval is local-only.
|
|
327
341
|
apply is commit-only and requires --commit, the exact plan SHA-256 via --approve-plan, and the current account email via --confirm.
|
|
342
|
+
A sealed production merge-support-aliases execution must use run-protected; apply is not its fallback.
|
|
343
|
+
freeze-protected is production-only and never calls preflight, gate, admission, execution, or mutation RPCs.
|
|
344
|
+
seal-protected-approval only records the exact human-approved bytes; it never authenticates, connects, or submits execution.
|
|
345
|
+
run-protected is production-only: authenticated owner context plus server-side actor/user_id/state_code=0 and exact-plan closure fences protect writes; RLS remains a defense on public and independent-read surfaces. It never falls back to dev, a legacy alias RPC, or a second admission POST.
|
|
328
346
|
|
|
329
347
|
Required Artifact Contract:
|
|
330
348
|
- maintenance-plan.json
|
|
@@ -334,13 +352,17 @@ Required Artifact Contract:
|
|
|
334
352
|
- dry-run-report.json
|
|
335
353
|
- commit-report.json
|
|
336
354
|
- readback-verify-report.json
|
|
355
|
+
run-protected uses a separate immutable protected-execution seal, submission marker, append-only status ledger, and terminal report.
|
|
337
356
|
|
|
338
357
|
Examples:
|
|
339
358
|
tiangong-lca dataset maintenance clear-account --out-dir ./account-clear --json
|
|
340
359
|
tiangong-lca dataset maintenance clear-account --commit --confirm user@example.com --out-dir ./account-clear
|
|
341
|
-
tiangong-lca dataset maintenance plan --scope ./maintenance-scope.json --operation
|
|
360
|
+
tiangong-lca dataset maintenance plan --scope ./maintenance-scope.json --operation repair-references --out-dir ./dataset-maintenance
|
|
342
361
|
tiangong-lca dataset maintenance plan --scope ./derivative-rebuild-scope.json --operation rebuild-derivatives --out-dir ./derivative-rebuild
|
|
343
362
|
tiangong-lca dataset maintenance apply --plan ./dataset-maintenance/maintenance-plan.json --commit --approve-plan <sha256> --confirm user@example.com
|
|
363
|
+
tiangong-lca dataset maintenance freeze-protected --plan ./maintenance-plan.json --toolchain-evidence ./toolchain.json --expected-project-ref <production-ref> --confirm bafudata@126.com --out-dir ./protected-freeze
|
|
364
|
+
tiangong-lca dataset maintenance seal-protected-approval --freeze ./protected-freeze/protected-execution-freeze.json --approval-request ./protected-freeze/protected-approval-request.json --human-approval ./human-approval.txt --approve-freeze-file <sha256> --approve-request <sha256> --approve-text <sha256> --confirm bafudata@126.com --approved-at <iso> --out-dir ./protected-approval
|
|
365
|
+
tiangong-lca dataset maintenance run-protected --plan ./maintenance-plan.json --freeze ./protected-execution-seal.json --approval ./protected-approval.json --out-dir ./protected-run --status-only
|
|
344
366
|
tiangong-lca dataset maintenance verify --plan ./dataset-maintenance/maintenance-plan.json --out-dir ./dataset-maintenance/verify
|
|
345
367
|
`.trim();
|
|
346
368
|
}
|
|
@@ -373,6 +395,7 @@ Behavior:
|
|
|
373
395
|
Commit-only. The command rejects dry-run mode, a missing --commit flag, a plan hash mismatch,
|
|
374
396
|
or a confirmation email that does not match the current authenticated account.
|
|
375
397
|
For rebuild-derivatives, success means guarded admission is queued; it never means derivatives completed.
|
|
398
|
+
Sealed production merge-support-aliases executions must use run-protected; this command is not a fallback.
|
|
376
399
|
|
|
377
400
|
Options:
|
|
378
401
|
--plan <file> Immutable maintenance-plan.json
|
|
@@ -386,6 +409,102 @@ Options:
|
|
|
386
409
|
Outputs include approval-record.json and commit-report.json alongside an append-only action or admission ledger.
|
|
387
410
|
`.trim();
|
|
388
411
|
}
|
|
412
|
+
function renderDatasetMaintenanceFreezeProtectedHelp() {
|
|
413
|
+
return `Usage:
|
|
414
|
+
tiangong-lca dataset maintenance freeze-protected --plan <file> --toolchain-evidence <file> --expected-project-ref <ref> --confirm <email> --out-dir <dir> [options]
|
|
415
|
+
|
|
416
|
+
Behavior:
|
|
417
|
+
Authenticates directly to the explicitly confirmed production project and re-reads the complete
|
|
418
|
+
owner-draft account census, six support snapshots, projected reference closure, and the stable
|
|
419
|
+
23-flow + 27-process derivative snapshot set. It writes a canonical protected freeze and an
|
|
420
|
+
unapproved byte-exact human approval request. It never emits an approval artifact.
|
|
421
|
+
|
|
422
|
+
Required:
|
|
423
|
+
--plan <file> Ready owner-draft merge-support-aliases maintenance plan
|
|
424
|
+
--toolchain-evidence <file> Canonical released DB/CLI/root-integration evidence
|
|
425
|
+
--expected-project-ref <ref> Explicit production Supabase project ref
|
|
426
|
+
--confirm <email> Exact authenticated owner email
|
|
427
|
+
--out-dir <dir> New private immutable artifact directory
|
|
428
|
+
|
|
429
|
+
Options:
|
|
430
|
+
--page-size <n> Complete account scan page size, 1-5000
|
|
431
|
+
--timeout-ms <n> Positive authentication/read timeout in milliseconds
|
|
432
|
+
--json Print compact JSON
|
|
433
|
+
-h, --help
|
|
434
|
+
|
|
435
|
+
Remote safety:
|
|
436
|
+
This command uses only authenticated table reads and cmd_dataset_derivative_rebuild_snapshot.
|
|
437
|
+
Preflight, gate, admission, execution, save-draft, delete, state change, and all mutation calls are zero.
|
|
438
|
+
`.trim();
|
|
439
|
+
}
|
|
440
|
+
function renderDatasetMaintenanceSealProtectedApprovalHelp() {
|
|
441
|
+
return `Usage:
|
|
442
|
+
tiangong-lca dataset maintenance seal-protected-approval --freeze <file> --approval-request <file> --human-approval <file> --approve-freeze-file <sha256> --approve-request <sha256> --approve-text <sha256> --confirm <email> --approved-at <iso> --out-dir <dir> [options]
|
|
443
|
+
|
|
444
|
+
Behavior:
|
|
445
|
+
Records a human-provided approval text only when every UTF-8 byte, freeze-file hash, request hash,
|
|
446
|
+
text hash, account, and canonical timestamp matches the unapproved request. It writes the approval
|
|
447
|
+
artifact needed by a later, separate run-protected command; it does not submit that execution.
|
|
448
|
+
|
|
449
|
+
Required:
|
|
450
|
+
--freeze <file> Canonical protected freeze generated by freeze-protected
|
|
451
|
+
--approval-request <file> Canonical unapproved approval request JSON
|
|
452
|
+
--human-approval <file> Human-returned text, read byte-for-byte without trimming
|
|
453
|
+
--approve-freeze-file <sha256> Explicit SHA-256 of the exact freeze file bytes
|
|
454
|
+
--approve-request <sha256> Explicit request identity SHA-256
|
|
455
|
+
--approve-text <sha256> Explicit byte-exact approval text SHA-256
|
|
456
|
+
--confirm <email> Exact frozen account email
|
|
457
|
+
--approved-at <iso> Exact approval-authority timestamp already embedded in the request
|
|
458
|
+
--out-dir <dir> New private immutable artifact directory
|
|
459
|
+
|
|
460
|
+
Options:
|
|
461
|
+
--json Print compact JSON
|
|
462
|
+
-h, --help
|
|
463
|
+
|
|
464
|
+
Offline safety:
|
|
465
|
+
This command receives no environment or HTTP client and performs zero authentication, network,
|
|
466
|
+
database, preflight, gate, admission, execution, or mutation calls.
|
|
467
|
+
`.trim();
|
|
468
|
+
}
|
|
469
|
+
function renderDatasetMaintenanceRunProtectedHelp() {
|
|
470
|
+
return `Usage:
|
|
471
|
+
tiangong-lca dataset maintenance run-protected --plan <file> --freeze <file> --approval <file> --out-dir <dir> --commit --approve-execution <sha256> --confirm <email> [options]
|
|
472
|
+
tiangong-lca dataset maintenance run-protected --plan <file> --freeze <file> --approval <file> --out-dir <dir> --status-only [options]
|
|
473
|
+
|
|
474
|
+
Behavior:
|
|
475
|
+
Runs one sealed, server-dispatched production maintenance execution fenced to the authenticated actor's
|
|
476
|
+
exact owner-draft target set, or reads durable status through an auth.uid-, actor-, and plan-fenced RPC
|
|
477
|
+
without admitting work; only the independent table readback uses RLS.
|
|
478
|
+
Commit and status-only modes are mutually exclusive. The commit path validates the full private
|
|
479
|
+
before-state, accepts only server-derived gates within the 180-second preflight window, writes an immutable
|
|
480
|
+
local submission marker, and sends at most one admission POST. After a marker or ambiguous response,
|
|
481
|
+
use --status-only; the command never retries admission or falls back to dev or the legacy alias RPC.
|
|
482
|
+
|
|
483
|
+
Required in both modes:
|
|
484
|
+
--plan <file> Immutable maintenance-plan.json
|
|
485
|
+
--freeze <file> Protected production execution seal/freeze artifact
|
|
486
|
+
--approval <file> Exact human-approval binding artifact
|
|
487
|
+
--out-dir <dir> Private protected-run artifact directory
|
|
488
|
+
|
|
489
|
+
Commit-only guards:
|
|
490
|
+
--commit Submit the sealed execution exactly once
|
|
491
|
+
--approve-execution <sha256> Exact approved execution identity SHA-256
|
|
492
|
+
--confirm <email> Current authenticated account email
|
|
493
|
+
|
|
494
|
+
Recovery:
|
|
495
|
+
--status-only Read/poll and independently verify the sealed request; never preflight or admit
|
|
496
|
+
|
|
497
|
+
Options:
|
|
498
|
+
--wait-seconds <n> Maximum terminal-status wait in seconds; 0 performs one status read
|
|
499
|
+
--poll-ms <n> Positive polling interval in milliseconds; default 10000
|
|
500
|
+
--page-size <n> Requested RLS readback page size, 1-5000
|
|
501
|
+
--timeout-ms <n> Positive request timeout in milliseconds
|
|
502
|
+
--json Print compact JSON
|
|
503
|
+
-h, --help
|
|
504
|
+
|
|
505
|
+
Only a terminal passed proof exits successfully. pending, failed, and indeterminate return non-zero.
|
|
506
|
+
`.trim();
|
|
507
|
+
}
|
|
389
508
|
function renderDatasetMaintenanceVerifyHelp() {
|
|
390
509
|
return `Usage:
|
|
391
510
|
tiangong-lca dataset maintenance verify --plan <file> [options]
|
|
@@ -3040,6 +3159,19 @@ function parseDatasetMaintenancePositiveInteger(value, flagName) {
|
|
|
3040
3159
|
}
|
|
3041
3160
|
return Number.parseInt(value.trim(), 10);
|
|
3042
3161
|
}
|
|
3162
|
+
function parseDatasetMaintenanceNonNegativeInteger(value, flagName) {
|
|
3163
|
+
if (typeof value !== 'string') {
|
|
3164
|
+
return undefined;
|
|
3165
|
+
}
|
|
3166
|
+
if (!/^\d+$/u.test(value.trim())) {
|
|
3167
|
+
throw new CliError(`${flagName} must be a non-negative integer.`, {
|
|
3168
|
+
code: 'DATASET_MAINTENANCE_INTEGER_INVALID',
|
|
3169
|
+
exitCode: 2,
|
|
3170
|
+
details: { flag: flagName, value },
|
|
3171
|
+
});
|
|
3172
|
+
}
|
|
3173
|
+
return Number.parseInt(value.trim(), 10);
|
|
3174
|
+
}
|
|
3043
3175
|
function parseDatasetMaintenancePlanFlags(args) {
|
|
3044
3176
|
let values;
|
|
3045
3177
|
try {
|
|
@@ -3126,6 +3258,134 @@ function parseDatasetMaintenanceApplyFlags(args) {
|
|
|
3126
3258
|
dryRun: Boolean(values['dry-run']),
|
|
3127
3259
|
};
|
|
3128
3260
|
}
|
|
3261
|
+
function parseDatasetMaintenanceFreezeProtectedFlags(args) {
|
|
3262
|
+
let values;
|
|
3263
|
+
try {
|
|
3264
|
+
({ values } = parseArgs({
|
|
3265
|
+
args,
|
|
3266
|
+
allowPositionals: false,
|
|
3267
|
+
strict: true,
|
|
3268
|
+
options: {
|
|
3269
|
+
help: { type: 'boolean', short: 'h' },
|
|
3270
|
+
json: { type: 'boolean' },
|
|
3271
|
+
plan: { type: 'string' },
|
|
3272
|
+
'toolchain-evidence': { type: 'string' },
|
|
3273
|
+
'out-dir': { type: 'string' },
|
|
3274
|
+
'expected-project-ref': { type: 'string' },
|
|
3275
|
+
confirm: { type: 'string' },
|
|
3276
|
+
'page-size': { type: 'string' },
|
|
3277
|
+
'timeout-ms': { type: 'string' },
|
|
3278
|
+
},
|
|
3279
|
+
}));
|
|
3280
|
+
}
|
|
3281
|
+
catch (error) {
|
|
3282
|
+
throw new CliError(String(error), {
|
|
3283
|
+
code: 'INVALID_ARGS',
|
|
3284
|
+
exitCode: 2,
|
|
3285
|
+
});
|
|
3286
|
+
}
|
|
3287
|
+
return {
|
|
3288
|
+
help: Boolean(values.help),
|
|
3289
|
+
json: Boolean(values.json),
|
|
3290
|
+
planPath: typeof values.plan === 'string' ? values.plan : '',
|
|
3291
|
+
toolchainEvidencePath: typeof values['toolchain-evidence'] === 'string' ? values['toolchain-evidence'] : '',
|
|
3292
|
+
outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : '',
|
|
3293
|
+
expectedProjectRef: typeof values['expected-project-ref'] === 'string' ? values['expected-project-ref'] : '',
|
|
3294
|
+
confirm: typeof values.confirm === 'string' ? values.confirm : '',
|
|
3295
|
+
pageSize: parseDatasetMaintenancePositiveInteger(values['page-size'], '--page-size'),
|
|
3296
|
+
timeoutMs: parseDatasetMaintenancePositiveInteger(values['timeout-ms'], '--timeout-ms'),
|
|
3297
|
+
};
|
|
3298
|
+
}
|
|
3299
|
+
function parseDatasetMaintenanceSealProtectedApprovalFlags(args) {
|
|
3300
|
+
let values;
|
|
3301
|
+
try {
|
|
3302
|
+
({ values } = parseArgs({
|
|
3303
|
+
args,
|
|
3304
|
+
allowPositionals: false,
|
|
3305
|
+
strict: true,
|
|
3306
|
+
options: {
|
|
3307
|
+
help: { type: 'boolean', short: 'h' },
|
|
3308
|
+
json: { type: 'boolean' },
|
|
3309
|
+
freeze: { type: 'string' },
|
|
3310
|
+
'approval-request': { type: 'string' },
|
|
3311
|
+
'human-approval': { type: 'string' },
|
|
3312
|
+
'out-dir': { type: 'string' },
|
|
3313
|
+
'approve-freeze-file': { type: 'string' },
|
|
3314
|
+
'approve-request': { type: 'string' },
|
|
3315
|
+
'approve-text': { type: 'string' },
|
|
3316
|
+
confirm: { type: 'string' },
|
|
3317
|
+
'approved-at': { type: 'string' },
|
|
3318
|
+
},
|
|
3319
|
+
}));
|
|
3320
|
+
}
|
|
3321
|
+
catch (error) {
|
|
3322
|
+
throw new CliError(String(error), {
|
|
3323
|
+
code: 'INVALID_ARGS',
|
|
3324
|
+
exitCode: 2,
|
|
3325
|
+
});
|
|
3326
|
+
}
|
|
3327
|
+
return {
|
|
3328
|
+
help: Boolean(values.help),
|
|
3329
|
+
json: Boolean(values.json),
|
|
3330
|
+
freezePath: typeof values.freeze === 'string' ? values.freeze : '',
|
|
3331
|
+
approvalRequestPath: typeof values['approval-request'] === 'string' ? values['approval-request'] : '',
|
|
3332
|
+
humanApprovalPath: typeof values['human-approval'] === 'string' ? values['human-approval'] : '',
|
|
3333
|
+
outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : '',
|
|
3334
|
+
approveFreezeFile: typeof values['approve-freeze-file'] === 'string' ? values['approve-freeze-file'] : '',
|
|
3335
|
+
approveRequest: typeof values['approve-request'] === 'string' ? values['approve-request'] : '',
|
|
3336
|
+
approveText: typeof values['approve-text'] === 'string' ? values['approve-text'] : '',
|
|
3337
|
+
confirm: typeof values.confirm === 'string' ? values.confirm : '',
|
|
3338
|
+
approvedAtUtc: typeof values['approved-at'] === 'string' ? values['approved-at'] : '',
|
|
3339
|
+
};
|
|
3340
|
+
}
|
|
3341
|
+
function parseDatasetMaintenanceProtectedFlags(args) {
|
|
3342
|
+
let values;
|
|
3343
|
+
try {
|
|
3344
|
+
({ values } = parseArgs({
|
|
3345
|
+
args,
|
|
3346
|
+
allowPositionals: false,
|
|
3347
|
+
strict: true,
|
|
3348
|
+
options: {
|
|
3349
|
+
help: { type: 'boolean', short: 'h' },
|
|
3350
|
+
json: { type: 'boolean' },
|
|
3351
|
+
plan: { type: 'string' },
|
|
3352
|
+
freeze: { type: 'string' },
|
|
3353
|
+
approval: { type: 'string' },
|
|
3354
|
+
'out-dir': { type: 'string' },
|
|
3355
|
+
commit: { type: 'boolean' },
|
|
3356
|
+
'status-only': { type: 'boolean' },
|
|
3357
|
+
'approve-execution': { type: 'string' },
|
|
3358
|
+
confirm: { type: 'string' },
|
|
3359
|
+
'wait-seconds': { type: 'string' },
|
|
3360
|
+
'poll-ms': { type: 'string' },
|
|
3361
|
+
'page-size': { type: 'string' },
|
|
3362
|
+
'timeout-ms': { type: 'string' },
|
|
3363
|
+
},
|
|
3364
|
+
}));
|
|
3365
|
+
}
|
|
3366
|
+
catch (error) {
|
|
3367
|
+
throw new CliError(String(error), {
|
|
3368
|
+
code: 'INVALID_ARGS',
|
|
3369
|
+
exitCode: 2,
|
|
3370
|
+
});
|
|
3371
|
+
}
|
|
3372
|
+
return {
|
|
3373
|
+
help: Boolean(values.help),
|
|
3374
|
+
json: Boolean(values.json),
|
|
3375
|
+
planPath: typeof values.plan === 'string' ? values.plan : '',
|
|
3376
|
+
freezePath: typeof values.freeze === 'string' ? values.freeze : '',
|
|
3377
|
+
approvalPath: typeof values.approval === 'string' ? values.approval : '',
|
|
3378
|
+
outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : '',
|
|
3379
|
+
commit: Boolean(values.commit),
|
|
3380
|
+
statusOnly: Boolean(values['status-only']),
|
|
3381
|
+
approveExecution: typeof values['approve-execution'] === 'string' ? values['approve-execution'] : undefined,
|
|
3382
|
+
confirm: typeof values.confirm === 'string' ? values.confirm : undefined,
|
|
3383
|
+
waitSeconds: parseDatasetMaintenanceNonNegativeInteger(values['wait-seconds'], '--wait-seconds'),
|
|
3384
|
+
pollMs: parseDatasetMaintenancePositiveInteger(values['poll-ms'], '--poll-ms'),
|
|
3385
|
+
pageSize: parseDatasetMaintenancePositiveInteger(values['page-size'], '--page-size'),
|
|
3386
|
+
timeoutMs: parseDatasetMaintenancePositiveInteger(values['timeout-ms'], '--timeout-ms'),
|
|
3387
|
+
};
|
|
3388
|
+
}
|
|
3129
3389
|
function parseDatasetMaintenanceVerifyFlags(args) {
|
|
3130
3390
|
let values;
|
|
3131
3391
|
try {
|
|
@@ -4905,6 +5165,9 @@ export async function executeCli(argv, deps) {
|
|
|
4905
5165
|
const datasetMaintenanceClearAccountImpl = deps.runDatasetMaintenanceClearAccountImpl ?? runDatasetMaintenanceClearAccount;
|
|
4906
5166
|
const datasetMaintenancePlanImpl = deps.runDatasetMaintenancePlanImpl ?? runDatasetMaintenancePlan;
|
|
4907
5167
|
const datasetMaintenanceApplyImpl = deps.runDatasetMaintenanceApplyImpl ?? runDatasetMaintenanceApply;
|
|
5168
|
+
const datasetMaintenanceProtectedFreezeImpl = deps.freezeDatasetMaintenanceProtectedImpl ?? freezeDatasetMaintenanceProtected;
|
|
5169
|
+
const datasetMaintenanceProtectedImpl = deps.runDatasetMaintenanceProtectedImpl ?? runDatasetMaintenanceProtected;
|
|
5170
|
+
const datasetMaintenanceProtectedApprovalSealImpl = deps.sealDatasetMaintenanceProtectedApprovalImpl ?? sealDatasetMaintenanceProtectedApproval;
|
|
4908
5171
|
const datasetMaintenanceVerifyImpl = deps.runDatasetMaintenanceVerifyImpl ?? runDatasetMaintenanceVerify;
|
|
4909
5172
|
const datasetSourceUploadAttachmentsImpl = deps.runDatasetSourceUploadAttachmentsImpl ?? runDatasetSourceUploadAttachments;
|
|
4910
5173
|
if (flags.version) {
|
|
@@ -5617,6 +5880,222 @@ export async function executeCli(argv, deps) {
|
|
|
5617
5880
|
stderr: '',
|
|
5618
5881
|
};
|
|
5619
5882
|
}
|
|
5883
|
+
if (action === 'freeze-protected') {
|
|
5884
|
+
const datasetFlags = parseDatasetMaintenanceFreezeProtectedFlags(commandArgs.slice(1));
|
|
5885
|
+
if (datasetFlags.help) {
|
|
5886
|
+
return {
|
|
5887
|
+
exitCode: 0,
|
|
5888
|
+
stdout: `${renderDatasetMaintenanceFreezeProtectedHelp()}\n`,
|
|
5889
|
+
stderr: '',
|
|
5890
|
+
};
|
|
5891
|
+
}
|
|
5892
|
+
if (!datasetFlags.planPath) {
|
|
5893
|
+
throw new CliError('dataset maintenance freeze-protected requires --plan.', {
|
|
5894
|
+
code: 'DATASET_MAINTENANCE_PROTECTED_PLAN_REQUIRED',
|
|
5895
|
+
exitCode: 2,
|
|
5896
|
+
});
|
|
5897
|
+
}
|
|
5898
|
+
if (!datasetFlags.toolchainEvidencePath) {
|
|
5899
|
+
throw new CliError('dataset maintenance freeze-protected requires --toolchain-evidence.', {
|
|
5900
|
+
code: 'DATASET_MAINTENANCE_PROTECTED_TOOLCHAIN_REQUIRED',
|
|
5901
|
+
exitCode: 2,
|
|
5902
|
+
});
|
|
5903
|
+
}
|
|
5904
|
+
if (!datasetFlags.expectedProjectRef) {
|
|
5905
|
+
throw new CliError('dataset maintenance freeze-protected requires --expected-project-ref.', {
|
|
5906
|
+
code: 'DATASET_MAINTENANCE_PROTECTED_PROJECT_REF_REQUIRED',
|
|
5907
|
+
exitCode: 2,
|
|
5908
|
+
});
|
|
5909
|
+
}
|
|
5910
|
+
if (!datasetFlags.confirm) {
|
|
5911
|
+
throw new CliError('dataset maintenance freeze-protected requires --confirm.', {
|
|
5912
|
+
code: 'DATASET_MAINTENANCE_PROTECTED_CONFIRM_REQUIRED',
|
|
5913
|
+
exitCode: 2,
|
|
5914
|
+
});
|
|
5915
|
+
}
|
|
5916
|
+
if (!datasetFlags.outDir) {
|
|
5917
|
+
throw new CliError('dataset maintenance freeze-protected requires --out-dir.', {
|
|
5918
|
+
code: 'DATASET_MAINTENANCE_PROTECTED_OUT_DIR_REQUIRED',
|
|
5919
|
+
exitCode: 2,
|
|
5920
|
+
});
|
|
5921
|
+
}
|
|
5922
|
+
const report = await datasetMaintenanceProtectedFreezeImpl({
|
|
5923
|
+
planPath: datasetFlags.planPath,
|
|
5924
|
+
toolchainEvidencePath: datasetFlags.toolchainEvidencePath,
|
|
5925
|
+
outDir: datasetFlags.outDir,
|
|
5926
|
+
expectedProjectRef: datasetFlags.expectedProjectRef,
|
|
5927
|
+
confirm: datasetFlags.confirm,
|
|
5928
|
+
cliVersion: loadCliPackageVersion(import.meta.url),
|
|
5929
|
+
pageSize: datasetFlags.pageSize,
|
|
5930
|
+
timeoutMs: datasetFlags.timeoutMs,
|
|
5931
|
+
env: deps.env,
|
|
5932
|
+
fetchImpl: deps.fetchImpl,
|
|
5933
|
+
});
|
|
5934
|
+
return {
|
|
5935
|
+
exitCode: 0,
|
|
5936
|
+
stdout: stringifyJson(report, datasetFlags.json),
|
|
5937
|
+
stderr: '',
|
|
5938
|
+
};
|
|
5939
|
+
}
|
|
5940
|
+
if (action === 'seal-protected-approval') {
|
|
5941
|
+
const datasetFlags = parseDatasetMaintenanceSealProtectedApprovalFlags(commandArgs.slice(1));
|
|
5942
|
+
if (datasetFlags.help) {
|
|
5943
|
+
return {
|
|
5944
|
+
exitCode: 0,
|
|
5945
|
+
stdout: `${renderDatasetMaintenanceSealProtectedApprovalHelp()}\n`,
|
|
5946
|
+
stderr: '',
|
|
5947
|
+
};
|
|
5948
|
+
}
|
|
5949
|
+
if (!datasetFlags.freezePath) {
|
|
5950
|
+
throw new CliError('dataset maintenance seal-protected-approval requires --freeze.', {
|
|
5951
|
+
code: 'DATASET_MAINTENANCE_PROTECTED_FREEZE_REQUIRED',
|
|
5952
|
+
exitCode: 2,
|
|
5953
|
+
});
|
|
5954
|
+
}
|
|
5955
|
+
if (!datasetFlags.approvalRequestPath) {
|
|
5956
|
+
throw new CliError('dataset maintenance seal-protected-approval requires --approval-request.', {
|
|
5957
|
+
code: 'DATASET_MAINTENANCE_PROTECTED_APPROVAL_REQUEST_REQUIRED',
|
|
5958
|
+
exitCode: 2,
|
|
5959
|
+
});
|
|
5960
|
+
}
|
|
5961
|
+
if (!datasetFlags.humanApprovalPath) {
|
|
5962
|
+
throw new CliError('dataset maintenance seal-protected-approval requires --human-approval.', {
|
|
5963
|
+
code: 'DATASET_MAINTENANCE_PROTECTED_HUMAN_APPROVAL_REQUIRED',
|
|
5964
|
+
exitCode: 2,
|
|
5965
|
+
});
|
|
5966
|
+
}
|
|
5967
|
+
if (!datasetFlags.approveFreezeFile) {
|
|
5968
|
+
throw new CliError('dataset maintenance seal-protected-approval requires --approve-freeze-file.', {
|
|
5969
|
+
code: 'DATASET_MAINTENANCE_PROTECTED_FREEZE_CONFIRMATION_REQUIRED',
|
|
5970
|
+
exitCode: 2,
|
|
5971
|
+
});
|
|
5972
|
+
}
|
|
5973
|
+
if (!datasetFlags.approveRequest) {
|
|
5974
|
+
throw new CliError('dataset maintenance seal-protected-approval requires --approve-request.', {
|
|
5975
|
+
code: 'DATASET_MAINTENANCE_PROTECTED_REQUEST_CONFIRMATION_REQUIRED',
|
|
5976
|
+
exitCode: 2,
|
|
5977
|
+
});
|
|
5978
|
+
}
|
|
5979
|
+
if (!datasetFlags.approveText) {
|
|
5980
|
+
throw new CliError('dataset maintenance seal-protected-approval requires --approve-text.', {
|
|
5981
|
+
code: 'DATASET_MAINTENANCE_PROTECTED_TEXT_CONFIRMATION_REQUIRED',
|
|
5982
|
+
exitCode: 2,
|
|
5983
|
+
});
|
|
5984
|
+
}
|
|
5985
|
+
if (!datasetFlags.confirm) {
|
|
5986
|
+
throw new CliError('dataset maintenance seal-protected-approval requires --confirm.', {
|
|
5987
|
+
code: 'DATASET_MAINTENANCE_PROTECTED_CONFIRM_REQUIRED',
|
|
5988
|
+
exitCode: 2,
|
|
5989
|
+
});
|
|
5990
|
+
}
|
|
5991
|
+
if (!datasetFlags.approvedAtUtc) {
|
|
5992
|
+
throw new CliError('dataset maintenance seal-protected-approval requires --approved-at.', {
|
|
5993
|
+
code: 'DATASET_MAINTENANCE_PROTECTED_APPROVED_AT_REQUIRED',
|
|
5994
|
+
exitCode: 2,
|
|
5995
|
+
});
|
|
5996
|
+
}
|
|
5997
|
+
if (!datasetFlags.outDir) {
|
|
5998
|
+
throw new CliError('dataset maintenance seal-protected-approval requires --out-dir.', {
|
|
5999
|
+
code: 'DATASET_MAINTENANCE_PROTECTED_OUT_DIR_REQUIRED',
|
|
6000
|
+
exitCode: 2,
|
|
6001
|
+
});
|
|
6002
|
+
}
|
|
6003
|
+
const report = await datasetMaintenanceProtectedApprovalSealImpl({
|
|
6004
|
+
freezePath: datasetFlags.freezePath,
|
|
6005
|
+
approvalRequestPath: datasetFlags.approvalRequestPath,
|
|
6006
|
+
humanApprovalPath: datasetFlags.humanApprovalPath,
|
|
6007
|
+
outDir: datasetFlags.outDir,
|
|
6008
|
+
approveFreezeFile: datasetFlags.approveFreezeFile,
|
|
6009
|
+
approveRequest: datasetFlags.approveRequest,
|
|
6010
|
+
approveText: datasetFlags.approveText,
|
|
6011
|
+
confirm: datasetFlags.confirm,
|
|
6012
|
+
approvedAtUtc: datasetFlags.approvedAtUtc,
|
|
6013
|
+
});
|
|
6014
|
+
return {
|
|
6015
|
+
exitCode: 0,
|
|
6016
|
+
stdout: stringifyJson(report, datasetFlags.json),
|
|
6017
|
+
stderr: '',
|
|
6018
|
+
};
|
|
6019
|
+
}
|
|
6020
|
+
if (action === 'run-protected') {
|
|
6021
|
+
const datasetFlags = parseDatasetMaintenanceProtectedFlags(commandArgs.slice(1));
|
|
6022
|
+
if (datasetFlags.help) {
|
|
6023
|
+
return {
|
|
6024
|
+
exitCode: 0,
|
|
6025
|
+
stdout: `${renderDatasetMaintenanceRunProtectedHelp()}\n`,
|
|
6026
|
+
stderr: '',
|
|
6027
|
+
};
|
|
6028
|
+
}
|
|
6029
|
+
if (!datasetFlags.planPath) {
|
|
6030
|
+
throw new CliError('dataset maintenance run-protected requires --plan.', {
|
|
6031
|
+
code: 'DATASET_MAINTENANCE_PROTECTED_PLAN_REQUIRED',
|
|
6032
|
+
exitCode: 2,
|
|
6033
|
+
});
|
|
6034
|
+
}
|
|
6035
|
+
if (!datasetFlags.freezePath) {
|
|
6036
|
+
throw new CliError('dataset maintenance run-protected requires --freeze.', {
|
|
6037
|
+
code: 'DATASET_MAINTENANCE_PROTECTED_FREEZE_REQUIRED',
|
|
6038
|
+
exitCode: 2,
|
|
6039
|
+
});
|
|
6040
|
+
}
|
|
6041
|
+
if (!datasetFlags.approvalPath) {
|
|
6042
|
+
throw new CliError('dataset maintenance run-protected requires --approval.', {
|
|
6043
|
+
code: 'DATASET_MAINTENANCE_PROTECTED_APPROVAL_FILE_REQUIRED',
|
|
6044
|
+
exitCode: 2,
|
|
6045
|
+
});
|
|
6046
|
+
}
|
|
6047
|
+
if (!datasetFlags.outDir) {
|
|
6048
|
+
throw new CliError('dataset maintenance run-protected requires --out-dir.', {
|
|
6049
|
+
code: 'DATASET_MAINTENANCE_PROTECTED_OUT_DIR_REQUIRED',
|
|
6050
|
+
exitCode: 2,
|
|
6051
|
+
});
|
|
6052
|
+
}
|
|
6053
|
+
if (datasetFlags.commit && datasetFlags.statusOnly) {
|
|
6054
|
+
throw new CliError('Cannot pass both --commit and --status-only.', {
|
|
6055
|
+
code: 'DATASET_MAINTENANCE_PROTECTED_MODE_CONFLICT',
|
|
6056
|
+
exitCode: 2,
|
|
6057
|
+
});
|
|
6058
|
+
}
|
|
6059
|
+
if (!datasetFlags.commit && !datasetFlags.statusOnly) {
|
|
6060
|
+
throw new CliError('dataset maintenance run-protected requires either --commit or --status-only.', {
|
|
6061
|
+
code: 'DATASET_MAINTENANCE_PROTECTED_MODE_REQUIRED',
|
|
6062
|
+
exitCode: 2,
|
|
6063
|
+
});
|
|
6064
|
+
}
|
|
6065
|
+
if (datasetFlags.commit && !datasetFlags.approveExecution) {
|
|
6066
|
+
throw new CliError('dataset maintenance run-protected requires --approve-execution <sha256> with --commit.', {
|
|
6067
|
+
code: 'DATASET_MAINTENANCE_PROTECTED_APPROVAL_REQUIRED',
|
|
6068
|
+
exitCode: 2,
|
|
6069
|
+
});
|
|
6070
|
+
}
|
|
6071
|
+
if (datasetFlags.commit && !datasetFlags.confirm) {
|
|
6072
|
+
throw new CliError('dataset maintenance run-protected requires --confirm <email> with --commit.', {
|
|
6073
|
+
code: 'DATASET_MAINTENANCE_PROTECTED_CONFIRM_REQUIRED',
|
|
6074
|
+
exitCode: 2,
|
|
6075
|
+
});
|
|
6076
|
+
}
|
|
6077
|
+
const report = await datasetMaintenanceProtectedImpl({
|
|
6078
|
+
planPath: datasetFlags.planPath,
|
|
6079
|
+
freezePath: datasetFlags.freezePath,
|
|
6080
|
+
approvalPath: datasetFlags.approvalPath,
|
|
6081
|
+
outDir: datasetFlags.outDir,
|
|
6082
|
+
commit: datasetFlags.commit,
|
|
6083
|
+
statusOnly: datasetFlags.statusOnly,
|
|
6084
|
+
approveExecution: datasetFlags.approveExecution,
|
|
6085
|
+
confirm: datasetFlags.confirm,
|
|
6086
|
+
waitSeconds: datasetFlags.waitSeconds,
|
|
6087
|
+
pollMs: datasetFlags.pollMs,
|
|
6088
|
+
pageSize: datasetFlags.pageSize,
|
|
6089
|
+
timeoutMs: datasetFlags.timeoutMs,
|
|
6090
|
+
env: deps.env,
|
|
6091
|
+
fetchImpl: deps.fetchImpl,
|
|
6092
|
+
});
|
|
6093
|
+
return {
|
|
6094
|
+
exitCode: report.status === 'passed' ? 0 : 1,
|
|
6095
|
+
stdout: stringifyJson(report, datasetFlags.json),
|
|
6096
|
+
stderr: '',
|
|
6097
|
+
};
|
|
6098
|
+
}
|
|
5620
6099
|
if (action === 'verify') {
|
|
5621
6100
|
const datasetFlags = parseDatasetMaintenanceVerifyFlags(commandArgs.slice(1));
|
|
5622
6101
|
if (datasetFlags.help) {
|
|
@@ -5646,7 +6125,7 @@ export async function executeCli(argv, deps) {
|
|
|
5646
6125
|
stderr: '',
|
|
5647
6126
|
};
|
|
5648
6127
|
}
|
|
5649
|
-
throw new CliError("dataset maintenance action must be 'clear-account', 'plan', 'apply', or 'verify'.", {
|
|
6128
|
+
throw new CliError("dataset maintenance action must be 'clear-account', 'plan', 'apply', 'freeze-protected', 'seal-protected-approval', 'run-protected', or 'verify'.", {
|
|
5650
6129
|
code: 'DATASET_MAINTENANCE_ACTION_INVALID',
|
|
5651
6130
|
exitCode: 2,
|
|
5652
6131
|
});
|