@tiangong-lca/cli 0.0.28 → 0.0.30
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 +90 -2
- package/dist/src/cli.js +553 -4
- package/dist/src/cli.js.map +1 -1
- package/dist/src/lib/dataset-command.js +11 -0
- package/dist/src/lib/dataset-command.js.map +1 -1
- package/dist/src/lib/dataset-maintenance-contract.js.map +1 -1
- package/dist/src/lib/dataset-maintenance-flow-identity-approval-claim.js +175 -0
- package/dist/src/lib/dataset-maintenance-flow-identity-approval-claim.js.map +1 -0
- package/dist/src/lib/dataset-maintenance-flow-identity-capture.js +511 -0
- package/dist/src/lib/dataset-maintenance-flow-identity-capture.js.map +1 -0
- package/dist/src/lib/dataset-maintenance-flow-identity-command.js +26 -0
- package/dist/src/lib/dataset-maintenance-flow-identity-command.js.map +1 -0
- package/dist/src/lib/dataset-maintenance-flow-identity-contract.js +784 -0
- package/dist/src/lib/dataset-maintenance-flow-identity-contract.js.map +1 -0
- package/dist/src/lib/dataset-maintenance-flow-identity-execution-contract.js +1317 -0
- package/dist/src/lib/dataset-maintenance-flow-identity-execution-contract.js.map +1 -0
- package/dist/src/lib/dataset-maintenance-flow-identity-freeze.js +342 -0
- package/dist/src/lib/dataset-maintenance-flow-identity-freeze.js.map +1 -0
- package/dist/src/lib/dataset-maintenance-flow-identity-plan.js +900 -0
- package/dist/src/lib/dataset-maintenance-flow-identity-plan.js.map +1 -0
- package/dist/src/lib/dataset-maintenance-flow-identity-recovery.js +688 -0
- package/dist/src/lib/dataset-maintenance-flow-identity-recovery.js.map +1 -0
- package/dist/src/lib/dataset-maintenance-flow-identity-run.js +1369 -0
- package/dist/src/lib/dataset-maintenance-flow-identity-run.js.map +1 -0
- package/dist/src/lib/dataset-maintenance-flow-identity-seal.js +144 -0
- package/dist/src/lib/dataset-maintenance-flow-identity-seal.js.map +1 -0
- package/dist/src/lib/dataset-maintenance-flow-identity-verify.js +377 -0
- package/dist/src/lib/dataset-maintenance-flow-identity-verify.js.map +1 -0
- package/dist/src/lib/dataset-maintenance-flow-identity-wire.js +178 -0
- package/dist/src/lib/dataset-maintenance-flow-identity-wire.js.map +1 -0
- package/dist/src/lib/dataset-maintenance-remote.js +156 -10
- package/dist/src/lib/dataset-maintenance-remote.js.map +1 -1
- package/dist/src/lib/dataset-save-draft-run.js +667 -0
- package/dist/src/lib/dataset-save-draft-run.js.map +1 -1
- package/dist/src/lib/http.js.map +1 -1
- package/dist/src/lib/lca-release.js +683 -0
- package/dist/src/lib/lca-release.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,511 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import { computeFlowIdentityCaptureEvidenceSha256, computeFlowIdentityCaptureSha256, parseFlowIdentityCapture, parseFlowIdentityPolicy, parseFlowIdentityReviewLedger, } from './dataset-maintenance-flow-identity-contract.js';
|
|
4
|
+
import { buildFlowIdentityCaptureRequest, buildFlowIdentitySemantics, flowType, } from './dataset-maintenance-flow-identity-plan.js';
|
|
5
|
+
import { materializePrivateArtifactDirectoryAtomically, readProtectedJsonArtifact, writePrivateImmutableJson, } from './dataset-maintenance-protected-artifacts.js';
|
|
6
|
+
import { parseProtectedToolchainEvidence } from './dataset-maintenance-protected-toolchain.js';
|
|
7
|
+
import { attestMaintenanceFlowIdentityCapture, fetchMaintenanceAccountTableRows, fetchMaintenanceExactRows, isMaintenanceRpcDomainFailure, resolveMaintenanceRemoteContext, } from './dataset-maintenance-remote.js';
|
|
8
|
+
import { isJsonObject, sha256Json, snapshotRemoteRow, stableJsonText, } from './dataset-maintenance-contract.js';
|
|
9
|
+
import { flowIdentityRestrictedSha256 } from './dataset-maintenance-flow-identity-wire.js';
|
|
10
|
+
import { validateFlowPayload } from './flow-payload-validation.js';
|
|
11
|
+
import { validateProcessPayload } from './process-payload-validation.js';
|
|
12
|
+
import { CliError } from './errors.js';
|
|
13
|
+
const HASH = /^[a-f0-9]{64}$/u;
|
|
14
|
+
const UUID = /^[a-f0-9]{8}-[a-f0-9]{4}-[1-5][a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$/u;
|
|
15
|
+
const VERSION = /^\d{2}\.\d{2}\.\d{3}$/u;
|
|
16
|
+
const DEFAULT_DEPENDENCIES = {
|
|
17
|
+
resolveContext: resolveMaintenanceRemoteContext,
|
|
18
|
+
fetchAccountTableRows: fetchMaintenanceAccountTableRows,
|
|
19
|
+
fetchExactRows: fetchMaintenanceExactRows,
|
|
20
|
+
attest: attestMaintenanceFlowIdentityCapture,
|
|
21
|
+
materialize: materializePrivateArtifactDirectoryAtomically,
|
|
22
|
+
};
|
|
23
|
+
function fail(message, code = 'DATASET_FLOW_IDENTITY_CAPTURE_INVALID') {
|
|
24
|
+
throw new CliError(message, { code, exitCode: 1 });
|
|
25
|
+
}
|
|
26
|
+
function exactKeys(value, keys) {
|
|
27
|
+
const actual = Object.keys(value).sort();
|
|
28
|
+
const expected = [...keys].sort();
|
|
29
|
+
return actual.length === expected.length && actual.every((key, index) => key === expected[index]);
|
|
30
|
+
}
|
|
31
|
+
function readCanonical(filePath, label) {
|
|
32
|
+
const artifact = readProtectedJsonArtifact({ filePath, label });
|
|
33
|
+
if (artifact.text !== `${stableJsonText(artifact.value)}\n`) {
|
|
34
|
+
fail(`${label} must be canonical JSON with one trailing newline.`);
|
|
35
|
+
}
|
|
36
|
+
return artifact;
|
|
37
|
+
}
|
|
38
|
+
export function parseFlowIdentityPrerequisites(value) {
|
|
39
|
+
if (!isJsonObject(value) ||
|
|
40
|
+
!isJsonObject(value.step2) ||
|
|
41
|
+
!isJsonObject(value.issue29_target1) ||
|
|
42
|
+
!isJsonObject(value.issue29_target2) ||
|
|
43
|
+
!exactKeys(value, ['schema_version', 'step2', 'issue29_target1', 'issue29_target2']) ||
|
|
44
|
+
!exactKeys(value.step2, ['readback_sha256', 'completed_at_utc', 'status']) ||
|
|
45
|
+
!exactKeys(value.issue29_target1, ['readback_sha256', 'completed_at_utc', 'status']) ||
|
|
46
|
+
!exactKeys(value.issue29_target2, ['readback_sha256', 'completed_at_utc', 'status'])) {
|
|
47
|
+
fail('Flow identity prerequisites are invalid.');
|
|
48
|
+
}
|
|
49
|
+
const parsed = value;
|
|
50
|
+
if (parsed.schema_version !== 'dataset-flow-identity-prerequisites.v2' ||
|
|
51
|
+
parsed.step2.status !== 'passed' ||
|
|
52
|
+
parsed.issue29_target1.status !== 'passed' ||
|
|
53
|
+
parsed.issue29_target2.status !== 'passed' ||
|
|
54
|
+
!HASH.test(parsed.step2.readback_sha256) ||
|
|
55
|
+
!HASH.test(parsed.issue29_target1.readback_sha256) ||
|
|
56
|
+
!HASH.test(parsed.issue29_target2.readback_sha256) ||
|
|
57
|
+
!Number.isFinite(Date.parse(parsed.step2.completed_at_utc)) ||
|
|
58
|
+
!Number.isFinite(Date.parse(parsed.issue29_target1.completed_at_utc)) ||
|
|
59
|
+
!Number.isFinite(Date.parse(parsed.issue29_target2.completed_at_utc))) {
|
|
60
|
+
fail('Flow identity prerequisites do not prove passed Step 2 and issue #29 readbacks.');
|
|
61
|
+
}
|
|
62
|
+
return parsed;
|
|
63
|
+
}
|
|
64
|
+
function snapshot(row) {
|
|
65
|
+
if (!row.user_id ||
|
|
66
|
+
row.state_code === null ||
|
|
67
|
+
!row.modified_at ||
|
|
68
|
+
!row.json_ordered ||
|
|
69
|
+
!row.json ||
|
|
70
|
+
sha256Json(row.json) !== sha256Json(row.json_ordered)) {
|
|
71
|
+
fail('A capture row is incomplete or its json/json_ordered columns differ.');
|
|
72
|
+
}
|
|
73
|
+
return snapshotRemoteRow({
|
|
74
|
+
table: row.table,
|
|
75
|
+
id: row.id,
|
|
76
|
+
version: row.version,
|
|
77
|
+
user_id: row.user_id,
|
|
78
|
+
state_code: row.state_code,
|
|
79
|
+
modified_at: row.modified_at,
|
|
80
|
+
json_ordered: row.json_ordered,
|
|
81
|
+
model_id: row.model_id,
|
|
82
|
+
rule_verification: row.rule_verification,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
function identity(id, version) {
|
|
86
|
+
return `${id}\u0000${version}`;
|
|
87
|
+
}
|
|
88
|
+
function referenceIdentity(value) {
|
|
89
|
+
if (!isJsonObject(value) ||
|
|
90
|
+
typeof value['@refObjectId'] !== 'string' ||
|
|
91
|
+
typeof value['@version'] !== 'string' ||
|
|
92
|
+
!UUID.test(value['@refObjectId']) ||
|
|
93
|
+
!VERSION.test(value['@version'])) {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
return { id: value['@refObjectId'], version: value['@version'] };
|
|
97
|
+
}
|
|
98
|
+
function arrayOfObjects(value) {
|
|
99
|
+
const values = Array.isArray(value) ? value : isJsonObject(value) ? [value] : [];
|
|
100
|
+
if (!values.every(isJsonObject))
|
|
101
|
+
fail('A flow support collection is malformed.');
|
|
102
|
+
return values;
|
|
103
|
+
}
|
|
104
|
+
function flowPropertyClaim(payload) {
|
|
105
|
+
const root = isJsonObject(payload.flowDataSet) ? payload.flowDataSet : null;
|
|
106
|
+
const information = isJsonObject(root?.flowInformation) ? root.flowInformation : null;
|
|
107
|
+
const quantitative = isJsonObject(information?.quantitativeReference)
|
|
108
|
+
? information.quantitativeReference
|
|
109
|
+
: null;
|
|
110
|
+
const properties = isJsonObject(root?.flowProperties) ? root.flowProperties : null;
|
|
111
|
+
const referenceInternalId = quantitative?.referenceToReferenceFlowProperty;
|
|
112
|
+
const property = arrayOfObjects(properties?.flowProperty).find((entry) => entry['@dataSetInternalID'] === referenceInternalId);
|
|
113
|
+
const claim = referenceIdentity(property?.referenceToFlowPropertyDataSet);
|
|
114
|
+
if (!claim)
|
|
115
|
+
fail('A mapped flow lacks an exact reference flow-property identity.');
|
|
116
|
+
return claim;
|
|
117
|
+
}
|
|
118
|
+
function unitGroupClaim(payload) {
|
|
119
|
+
const root = isJsonObject(payload.flowPropertyDataSet) ? payload.flowPropertyDataSet : null;
|
|
120
|
+
const information = isJsonObject(root?.flowPropertiesInformation)
|
|
121
|
+
? root.flowPropertiesInformation
|
|
122
|
+
: null;
|
|
123
|
+
const quantitative = isJsonObject(information?.quantitativeReference)
|
|
124
|
+
? information.quantitativeReference
|
|
125
|
+
: null;
|
|
126
|
+
const claim = referenceIdentity(quantitative?.referenceToReferenceUnitGroup);
|
|
127
|
+
if (!claim)
|
|
128
|
+
fail('A captured flow property lacks an exact unit-group identity.');
|
|
129
|
+
return claim;
|
|
130
|
+
}
|
|
131
|
+
function processReferencesReviewedSource(row, reviewed) {
|
|
132
|
+
const root = isJsonObject(row.json_ordered?.processDataSet)
|
|
133
|
+
? row.json_ordered.processDataSet
|
|
134
|
+
: null;
|
|
135
|
+
const exchanges = isJsonObject(root?.exchanges) ? root.exchanges : null;
|
|
136
|
+
const values = Array.isArray(exchanges?.exchange)
|
|
137
|
+
? exchanges.exchange
|
|
138
|
+
: isJsonObject(exchanges?.exchange)
|
|
139
|
+
? [exchanges.exchange]
|
|
140
|
+
: [];
|
|
141
|
+
for (const value of values) {
|
|
142
|
+
if (!isJsonObject(value))
|
|
143
|
+
fail('A captured process has a malformed exchange collection.');
|
|
144
|
+
const reference = referenceIdentity(value.referenceToFlowDataSet);
|
|
145
|
+
if (!reference)
|
|
146
|
+
fail('A captured process exchange has a malformed flow reference.');
|
|
147
|
+
if (reviewed.has(identity(reference.id, reference.version)))
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
async function fetchUniqueRows(options) {
|
|
153
|
+
const rows = [];
|
|
154
|
+
for (let offset = 0; offset < options.identities.length; offset += options.concurrency) {
|
|
155
|
+
const chunk = options.identities.slice(offset, offset + options.concurrency);
|
|
156
|
+
const fetched = await Promise.all(chunk.map(async (claim) => {
|
|
157
|
+
const result = await options.dependencies.fetchExactRows({
|
|
158
|
+
context: options.context,
|
|
159
|
+
table: claim.table,
|
|
160
|
+
id: claim.id,
|
|
161
|
+
version: claim.version,
|
|
162
|
+
includeJson: true,
|
|
163
|
+
});
|
|
164
|
+
const visible = result.rows.filter((row) => options.publicOnly
|
|
165
|
+
? row.state_code === 100 && row.user_id !== options.actorUserId
|
|
166
|
+
: row.state_code === 100 ||
|
|
167
|
+
(row.state_code === 0 && row.user_id === options.actorUserId));
|
|
168
|
+
if (visible.length !== 1) {
|
|
169
|
+
fail('A capture target/support identity is missing, duplicated, or outside visibility.');
|
|
170
|
+
}
|
|
171
|
+
return snapshot(visible[0]);
|
|
172
|
+
}));
|
|
173
|
+
rows.push(...fetched);
|
|
174
|
+
}
|
|
175
|
+
return rows.sort((left, right) => `${left.table}\u0000${identity(left.id, left.version)}`.localeCompare(`${right.table}\u0000${identity(right.id, right.version)}`));
|
|
176
|
+
}
|
|
177
|
+
function validateInputs(options) {
|
|
178
|
+
const concurrency = options.readConcurrency ?? 5;
|
|
179
|
+
if (!UUID.test(options.requestId))
|
|
180
|
+
fail('capture request ID must be a canonical UUID.');
|
|
181
|
+
if (!options.operationId.trim() || Buffer.byteLength(options.operationId, 'utf8') > 512) {
|
|
182
|
+
fail('capture operation ID must be a non-empty token of at most 512 UTF-8 bytes.');
|
|
183
|
+
}
|
|
184
|
+
if (!Number.isInteger(concurrency) || concurrency < 1 || concurrency > 5) {
|
|
185
|
+
fail('capture read concurrency must be an integer between 1 and 5.');
|
|
186
|
+
}
|
|
187
|
+
if (!options.sdkVersion.trim())
|
|
188
|
+
fail('capture SDK version is required.');
|
|
189
|
+
return { concurrency };
|
|
190
|
+
}
|
|
191
|
+
async function executeCapture(options, dependencies) {
|
|
192
|
+
const { concurrency } = validateInputs(options);
|
|
193
|
+
if (existsSync(path.resolve(options.outDir))) {
|
|
194
|
+
fail('Capture output directory already exists; protected capture artifacts are immutable.');
|
|
195
|
+
}
|
|
196
|
+
const policyArtifact = readCanonical(options.policyPath, 'Flow identity compatibility policy');
|
|
197
|
+
const reviewArtifact = readCanonical(options.reviewLedgerPath, 'Flow identity review ledger');
|
|
198
|
+
const prerequisitesArtifact = readCanonical(options.prerequisitesPath, 'Flow identity prerequisites');
|
|
199
|
+
const toolchainArtifact = readCanonical(options.toolchainEvidencePath, 'Protected toolchain evidence');
|
|
200
|
+
const policy = parseFlowIdentityPolicy(policyArtifact.value);
|
|
201
|
+
const review = parseFlowIdentityReviewLedger(reviewArtifact.value);
|
|
202
|
+
const prerequisites = parseFlowIdentityPrerequisites(prerequisitesArtifact.value);
|
|
203
|
+
if (policy.evidence_resolution_sha256 !== review.review_evidence_sha256) {
|
|
204
|
+
fail('Compatibility policy does not bind the review ledger.');
|
|
205
|
+
}
|
|
206
|
+
parseProtectedToolchainEvidence(toolchainArtifact.value, {
|
|
207
|
+
projectRef: options.expectedProjectRef,
|
|
208
|
+
cliVersion: options.cliVersion,
|
|
209
|
+
});
|
|
210
|
+
const capturedAt = options.now ?? new Date();
|
|
211
|
+
if (Date.parse(prerequisites.step2.completed_at_utc) > capturedAt.getTime() ||
|
|
212
|
+
Date.parse(prerequisites.issue29_target1.completed_at_utc) > capturedAt.getTime() ||
|
|
213
|
+
Date.parse(prerequisites.issue29_target2.completed_at_utc) > capturedAt.getTime()) {
|
|
214
|
+
fail('Capture time precedes a required passed prerequisite.');
|
|
215
|
+
}
|
|
216
|
+
const context = await dependencies.resolveContext({
|
|
217
|
+
env: options.env,
|
|
218
|
+
fetchImpl: options.fetchImpl,
|
|
219
|
+
timeoutMs: options.timeoutMs,
|
|
220
|
+
now: options.now,
|
|
221
|
+
});
|
|
222
|
+
if (context.project_ref !== options.expectedProjectRef ||
|
|
223
|
+
context.account.email.trim().toLowerCase() !== options.confirm.trim().toLowerCase()) {
|
|
224
|
+
fail('Authenticated production project/account does not match capture confirmation.');
|
|
225
|
+
}
|
|
226
|
+
const [flowCensus, processCensus] = await Promise.all([
|
|
227
|
+
dependencies.fetchAccountTableRows({
|
|
228
|
+
context,
|
|
229
|
+
userId: context.account.user_id,
|
|
230
|
+
table: 'flows',
|
|
231
|
+
stateCode: 0,
|
|
232
|
+
includeJson: true,
|
|
233
|
+
pageSize: options.pageSize,
|
|
234
|
+
}),
|
|
235
|
+
dependencies.fetchAccountTableRows({
|
|
236
|
+
context,
|
|
237
|
+
userId: context.account.user_id,
|
|
238
|
+
table: 'processes',
|
|
239
|
+
stateCode: 0,
|
|
240
|
+
includeJson: true,
|
|
241
|
+
pageSize: options.pageSize,
|
|
242
|
+
}),
|
|
243
|
+
]);
|
|
244
|
+
const reviewed = new Set(review.entries.map((entry) => identity(entry.source.id, entry.source.version)));
|
|
245
|
+
const elementary = flowCensus.rows.filter((row) => row.json_ordered && flowType(row.json_ordered) === 'Elementary flow');
|
|
246
|
+
const observed = new Set(elementary.map((row) => identity(row.id, row.version)));
|
|
247
|
+
if (elementary.length !== 305 ||
|
|
248
|
+
observed.size !== 305 ||
|
|
249
|
+
[...reviewed].some((key) => !observed.has(key)) ||
|
|
250
|
+
[...observed].some((key) => !reviewed.has(key))) {
|
|
251
|
+
fail('Authenticated owner-draft Elementary-flow census is not the exact 305-row review universe.');
|
|
252
|
+
}
|
|
253
|
+
const sourceRows = elementary
|
|
254
|
+
.map(snapshot)
|
|
255
|
+
.sort((left, right) => identity(left.id, left.version).localeCompare(identity(right.id, right.version)));
|
|
256
|
+
const fullProcessRows = processCensus.rows
|
|
257
|
+
.map(snapshot)
|
|
258
|
+
.sort((left, right) => identity(left.id, left.version).localeCompare(identity(right.id, right.version)));
|
|
259
|
+
const processRows = fullProcessRows.filter((row) => processReferencesReviewedSource(row, reviewed));
|
|
260
|
+
const processScanProof = {
|
|
261
|
+
...processCensus.completeness,
|
|
262
|
+
row_identity_set_sha256: sha256Json(fullProcessRows.map((row) => ({ id: row.id, version: row.version }))),
|
|
263
|
+
row_snapshot_set_sha256: sha256Json(fullProcessRows.map((row) => ({
|
|
264
|
+
id: row.id,
|
|
265
|
+
version: row.version,
|
|
266
|
+
row_sha256: row.row_sha256,
|
|
267
|
+
}))),
|
|
268
|
+
};
|
|
269
|
+
const targetClaims = [
|
|
270
|
+
...new Map(review.entries
|
|
271
|
+
.filter((entry) => entry.disposition === 'map_public')
|
|
272
|
+
.map((entry) => [
|
|
273
|
+
identity(entry.target.id, entry.target.version),
|
|
274
|
+
{
|
|
275
|
+
table: 'flows',
|
|
276
|
+
id: entry.target.id,
|
|
277
|
+
version: entry.target.version,
|
|
278
|
+
},
|
|
279
|
+
])).values(),
|
|
280
|
+
];
|
|
281
|
+
const targetRows = await fetchUniqueRows({
|
|
282
|
+
identities: targetClaims,
|
|
283
|
+
context,
|
|
284
|
+
actorUserId: context.account.user_id,
|
|
285
|
+
publicOnly: true,
|
|
286
|
+
concurrency,
|
|
287
|
+
dependencies,
|
|
288
|
+
});
|
|
289
|
+
const fpClaims = [
|
|
290
|
+
...new Map([
|
|
291
|
+
...sourceRows.filter((row) => review.entries.some((entry) => entry.disposition === 'map_public' &&
|
|
292
|
+
entry.source.id === row.id &&
|
|
293
|
+
entry.source.version === row.version)),
|
|
294
|
+
...targetRows,
|
|
295
|
+
].map((row) => {
|
|
296
|
+
const claim = flowPropertyClaim(row.json_ordered);
|
|
297
|
+
return [
|
|
298
|
+
identity(claim.id, claim.version),
|
|
299
|
+
{
|
|
300
|
+
table: 'flowproperties',
|
|
301
|
+
...claim,
|
|
302
|
+
},
|
|
303
|
+
];
|
|
304
|
+
})).values(),
|
|
305
|
+
];
|
|
306
|
+
const flowPropertyRows = await fetchUniqueRows({
|
|
307
|
+
identities: fpClaims,
|
|
308
|
+
context,
|
|
309
|
+
actorUserId: context.account.user_id,
|
|
310
|
+
publicOnly: false,
|
|
311
|
+
concurrency,
|
|
312
|
+
dependencies,
|
|
313
|
+
});
|
|
314
|
+
const unitGroupClaims = [
|
|
315
|
+
...new Map(flowPropertyRows.map((row) => {
|
|
316
|
+
const claim = unitGroupClaim(row.json_ordered);
|
|
317
|
+
return [identity(claim.id, claim.version), { table: 'unitgroups', ...claim }];
|
|
318
|
+
})).values(),
|
|
319
|
+
];
|
|
320
|
+
const unitGroupRows = await fetchUniqueRows({
|
|
321
|
+
identities: unitGroupClaims,
|
|
322
|
+
context,
|
|
323
|
+
actorUserId: context.account.user_id,
|
|
324
|
+
publicOnly: false,
|
|
325
|
+
concurrency,
|
|
326
|
+
dependencies,
|
|
327
|
+
});
|
|
328
|
+
const supportRows = [...flowPropertyRows, ...unitGroupRows].sort((left, right) => `${left.table}\u0000${identity(left.id, left.version)}`.localeCompare(`${right.table}\u0000${identity(right.id, right.version)}`));
|
|
329
|
+
const capture = {
|
|
330
|
+
schema_version: 'dataset-flow-identity-live-capture.v2',
|
|
331
|
+
captured_at_utc: capturedAt.toISOString(),
|
|
332
|
+
environment: 'production',
|
|
333
|
+
project_ref: context.project_ref,
|
|
334
|
+
account: {
|
|
335
|
+
user_id: context.account.user_id,
|
|
336
|
+
email: context.account.email.trim().toLowerCase(),
|
|
337
|
+
},
|
|
338
|
+
prerequisites: {
|
|
339
|
+
step2_readback_sha256: prerequisites.step2.readback_sha256,
|
|
340
|
+
step2_completed_at_utc: prerequisites.step2.completed_at_utc,
|
|
341
|
+
issue29_target1_readback_sha256: prerequisites.issue29_target1.readback_sha256,
|
|
342
|
+
issue29_target1_completed_at_utc: prerequisites.issue29_target1.completed_at_utc,
|
|
343
|
+
issue29_target2_readback_sha256: prerequisites.issue29_target2.readback_sha256,
|
|
344
|
+
issue29_target2_completed_at_utc: prerequisites.issue29_target2.completed_at_utc,
|
|
345
|
+
},
|
|
346
|
+
sdk: { package: '@tiangong-lca/tidas-sdk', version: options.sdkVersion.trim() },
|
|
347
|
+
artifact_evidence: {
|
|
348
|
+
review_ledger_sha256: review.ledger_sha256,
|
|
349
|
+
live_capture_artifact_sha256: '',
|
|
350
|
+
toolchain_evidence_sha256: toolchainArtifact.file_sha256,
|
|
351
|
+
},
|
|
352
|
+
completeness: {
|
|
353
|
+
schema_version: 'dataset-flow-identity-capture-completeness.v2',
|
|
354
|
+
source_count: 305,
|
|
355
|
+
target_count: targetRows.length,
|
|
356
|
+
support_count: supportRows.length,
|
|
357
|
+
owner_draft_process_count: fullProcessRows.length,
|
|
358
|
+
owner_draft_process_scan: processScanProof,
|
|
359
|
+
},
|
|
360
|
+
source_rows: sourceRows,
|
|
361
|
+
target_rows: targetRows,
|
|
362
|
+
support_rows: supportRows,
|
|
363
|
+
process_rows: processRows,
|
|
364
|
+
capture_request: {},
|
|
365
|
+
attestation: {},
|
|
366
|
+
capture_artifact_sha256: '',
|
|
367
|
+
};
|
|
368
|
+
capture.artifact_evidence.live_capture_artifact_sha256 =
|
|
369
|
+
computeFlowIdentityCaptureEvidenceSha256(capture);
|
|
370
|
+
const validation = {
|
|
371
|
+
validateFlow: options.validation?.validateFlow ?? validateFlowPayload,
|
|
372
|
+
validateProcess: options.validation?.validateProcess ?? validateProcessPayload,
|
|
373
|
+
};
|
|
374
|
+
const semantics = buildFlowIdentitySemantics({ policy, review, capture, validation });
|
|
375
|
+
capture.capture_request = buildFlowIdentityCaptureRequest({
|
|
376
|
+
requestId: options.requestId,
|
|
377
|
+
operationId: options.operationId,
|
|
378
|
+
policy,
|
|
379
|
+
capture,
|
|
380
|
+
mappings: semantics.mappings,
|
|
381
|
+
processTemplates: semantics.processTemplates,
|
|
382
|
+
protectedClosure: semantics.protectedClosure,
|
|
383
|
+
});
|
|
384
|
+
const requestSha256 = flowIdentityRestrictedSha256(capture.capture_request);
|
|
385
|
+
const materializeIndeterminate = (error, rawResponse) => {
|
|
386
|
+
const preferred = path.resolve(options.outDir);
|
|
387
|
+
const recoveryDir = existsSync(preferred)
|
|
388
|
+
? `${preferred}.indeterminate-${options.requestId}`
|
|
389
|
+
: preferred;
|
|
390
|
+
dependencies.materialize(recoveryDir, (staging) => {
|
|
391
|
+
writePrivateImmutableJson(path.join(staging, 'flow-identity-capture-request.json'), capture.capture_request);
|
|
392
|
+
if (rawResponse) {
|
|
393
|
+
writePrivateImmutableJson(path.join(staging, 'flow-identity-capture-raw-response.json'), rawResponse);
|
|
394
|
+
}
|
|
395
|
+
writePrivateImmutableJson(path.join(staging, 'flow-identity-capture-indeterminate.json'), {
|
|
396
|
+
schema_version: 'dataset-flow-identity-capture-indeterminate.v2',
|
|
397
|
+
status: 'indeterminate',
|
|
398
|
+
request_id: options.requestId,
|
|
399
|
+
capture_request_sha256: requestSha256,
|
|
400
|
+
post_attempt_count: 1,
|
|
401
|
+
automatic_retry: false,
|
|
402
|
+
normal_capture_rerun_allowed: false,
|
|
403
|
+
recovery: 'operator_exact_request_status_or_replay_required',
|
|
404
|
+
error: String(error),
|
|
405
|
+
});
|
|
406
|
+
});
|
|
407
|
+
};
|
|
408
|
+
const materializeRejected = (rawResponse) => {
|
|
409
|
+
dependencies.materialize(path.resolve(options.outDir), (staging) => {
|
|
410
|
+
writePrivateImmutableJson(path.join(staging, 'flow-identity-capture-request.json'), capture.capture_request);
|
|
411
|
+
writePrivateImmutableJson(path.join(staging, 'flow-identity-capture-domain-rejection.json'), {
|
|
412
|
+
schema_version: 'dataset-flow-identity-capture-domain-rejection.v1',
|
|
413
|
+
status: 'rejected',
|
|
414
|
+
request_id: options.requestId,
|
|
415
|
+
capture_request_sha256: requestSha256,
|
|
416
|
+
post_attempt_count: 1,
|
|
417
|
+
automatic_retry: false,
|
|
418
|
+
same_request_replay_allowed: false,
|
|
419
|
+
recovery: 'new_request_and_output_directory_required',
|
|
420
|
+
response: rawResponse,
|
|
421
|
+
});
|
|
422
|
+
});
|
|
423
|
+
};
|
|
424
|
+
let rawAttestation;
|
|
425
|
+
try {
|
|
426
|
+
rawAttestation = await dependencies.attest({
|
|
427
|
+
context,
|
|
428
|
+
request: capture.capture_request,
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
catch (error) {
|
|
432
|
+
materializeIndeterminate(error);
|
|
433
|
+
throw error;
|
|
434
|
+
}
|
|
435
|
+
if (isMaintenanceRpcDomainFailure(rawAttestation)) {
|
|
436
|
+
materializeRejected(rawAttestation);
|
|
437
|
+
throw new CliError(typeof rawAttestation.message === 'string'
|
|
438
|
+
? rawAttestation.message
|
|
439
|
+
: 'Flow identity capture was rejected by the database.', {
|
|
440
|
+
code: rawAttestation.code,
|
|
441
|
+
exitCode: 1,
|
|
442
|
+
details: rawAttestation,
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
try {
|
|
446
|
+
capture.attestation = rawAttestation;
|
|
447
|
+
capture.capture_artifact_sha256 = computeFlowIdentityCaptureSha256(capture);
|
|
448
|
+
const parsed = parseFlowIdentityCapture(capture);
|
|
449
|
+
const generatedAt = options.now ?? new Date();
|
|
450
|
+
const artifactPaths = {
|
|
451
|
+
request: path.join(path.resolve(options.outDir), 'flow-identity-capture-request.json'),
|
|
452
|
+
attestation: path.join(path.resolve(options.outDir), 'flow-identity-capture-attestation.json'),
|
|
453
|
+
live_capture: path.join(path.resolve(options.outDir), 'flow-identity-live-capture.json'),
|
|
454
|
+
report: path.join(path.resolve(options.outDir), 'flow-identity-capture-report.json'),
|
|
455
|
+
};
|
|
456
|
+
const report = {
|
|
457
|
+
schema_version: 'dataset-flow-identity-capture-report.v2',
|
|
458
|
+
generated_at_utc: generatedAt.toISOString(),
|
|
459
|
+
status: 'captured',
|
|
460
|
+
environment: 'production',
|
|
461
|
+
project_ref: parsed.project_ref,
|
|
462
|
+
actor: parsed.account,
|
|
463
|
+
operation_id: parsed.attestation.operation_id,
|
|
464
|
+
request_id: parsed.capture_request.request_id,
|
|
465
|
+
receipt_id: parsed.attestation.receipt_id,
|
|
466
|
+
receipt_proof_sha256: parsed.attestation.receipt_proof_sha256,
|
|
467
|
+
capture_request_sha256: parsed.attestation.capture_request_sha256,
|
|
468
|
+
live_capture_evidence_core_sha256: parsed.artifact_evidence.live_capture_artifact_sha256,
|
|
469
|
+
capture_artifact_sha256: parsed.capture_artifact_sha256,
|
|
470
|
+
counts: {
|
|
471
|
+
sources: 305,
|
|
472
|
+
targets: parsed.target_rows.length,
|
|
473
|
+
supports: parsed.support_rows.length,
|
|
474
|
+
owner_draft_processes: parsed.completeness.owner_draft_process_count,
|
|
475
|
+
mappings: semantics.mappings.length,
|
|
476
|
+
affected_processes: semantics.processTemplates.length,
|
|
477
|
+
rewrites: semantics.processTemplates.reduce((sum, template) => sum + template.process.rewrite_count, 0),
|
|
478
|
+
},
|
|
479
|
+
calls: {
|
|
480
|
+
capture_attest: 1,
|
|
481
|
+
scope_preflight: 0,
|
|
482
|
+
process_rewrite: 0,
|
|
483
|
+
scope_finalize: 0,
|
|
484
|
+
automatic_retry: false,
|
|
485
|
+
},
|
|
486
|
+
artifacts: artifactPaths,
|
|
487
|
+
};
|
|
488
|
+
dependencies.materialize(options.outDir, (staging) => {
|
|
489
|
+
writePrivateImmutableJson(path.join(staging, path.basename(artifactPaths.request)), parsed.capture_request);
|
|
490
|
+
writePrivateImmutableJson(path.join(staging, path.basename(artifactPaths.attestation)), parsed.attestation);
|
|
491
|
+
writePrivateImmutableJson(path.join(staging, path.basename(artifactPaths.live_capture)), parsed);
|
|
492
|
+
writePrivateImmutableJson(path.join(staging, path.basename(artifactPaths.report)), report);
|
|
493
|
+
});
|
|
494
|
+
return report;
|
|
495
|
+
}
|
|
496
|
+
catch (error) {
|
|
497
|
+
materializeIndeterminate(error, rawAttestation);
|
|
498
|
+
throw error;
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
export async function captureFlowIdentity(options) {
|
|
502
|
+
return executeCapture(options, DEFAULT_DEPENDENCIES);
|
|
503
|
+
}
|
|
504
|
+
export const __testInternals = {
|
|
505
|
+
executeCapture,
|
|
506
|
+
flowPropertyClaim,
|
|
507
|
+
parseFlowIdentityPrerequisites,
|
|
508
|
+
snapshot,
|
|
509
|
+
unitGroupClaim,
|
|
510
|
+
};
|
|
511
|
+
//# sourceMappingURL=dataset-maintenance-flow-identity-capture.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dataset-maintenance-flow-identity-capture.js","sourceRoot":"","sources":["../../../src/lib/dataset-maintenance-flow-identity-capture.ts"],"names":[],"mappings":"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","sourcesContent":["import path from 'node:path';\nimport { existsSync } from 'node:fs';\nimport {\n computeFlowIdentityCaptureEvidenceSha256,\n computeFlowIdentityCaptureSha256,\n parseFlowIdentityCapture,\n parseFlowIdentityPolicy,\n parseFlowIdentityReviewLedger,\n type FlowIdentityLiveCapture,\n} from './dataset-maintenance-flow-identity-contract.js';\nimport {\n buildFlowIdentityCaptureRequest,\n buildFlowIdentitySemantics,\n flowType,\n type ValidationDeps,\n} from './dataset-maintenance-flow-identity-plan.js';\nimport {\n materializePrivateArtifactDirectoryAtomically,\n readProtectedJsonArtifact,\n writePrivateImmutableJson,\n} from './dataset-maintenance-protected-artifacts.js';\nimport { parseProtectedToolchainEvidence } from './dataset-maintenance-protected-toolchain.js';\nimport {\n attestMaintenanceFlowIdentityCapture,\n fetchMaintenanceAccountTableRows,\n fetchMaintenanceExactRows,\n isMaintenanceRpcDomainFailure,\n resolveMaintenanceRemoteContext,\n type DatasetMaintenanceRemoteContext,\n} from './dataset-maintenance-remote.js';\nimport {\n isJsonObject,\n sha256Json,\n snapshotRemoteRow,\n stableJsonText,\n type DatasetMaintenanceRemoteRow,\n type DatasetMaintenanceRowSnapshot,\n type JsonObject,\n} from './dataset-maintenance-contract.js';\nimport { flowIdentityRestrictedSha256 } from './dataset-maintenance-flow-identity-wire.js';\nimport { validateFlowPayload } from './flow-payload-validation.js';\nimport { validateProcessPayload } from './process-payload-validation.js';\nimport { CliError } from './errors.js';\nimport type { FetchLike } from './http.js';\n\nconst HASH = /^[a-f0-9]{64}$/u;\nconst UUID = /^[a-f0-9]{8}-[a-f0-9]{4}-[1-5][a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$/u;\nconst VERSION = /^\\d{2}\\.\\d{2}\\.\\d{3}$/u;\n\nexport type FlowIdentityPrerequisites = {\n schema_version: 'dataset-flow-identity-prerequisites.v2';\n step2: {\n readback_sha256: string;\n completed_at_utc: string;\n status: 'passed';\n };\n issue29_target1: {\n readback_sha256: string;\n completed_at_utc: string;\n status: 'passed';\n };\n issue29_target2: {\n readback_sha256: string;\n completed_at_utc: string;\n status: 'passed';\n };\n};\n\nexport type CaptureFlowIdentityOptions = {\n policyPath: string;\n reviewLedgerPath: string;\n prerequisitesPath: string;\n toolchainEvidencePath: string;\n requestId: string;\n operationId: string;\n expectedProjectRef: string;\n confirm: string;\n cliVersion: string;\n sdkVersion: string;\n outDir: string;\n pageSize?: number;\n readConcurrency?: number;\n timeoutMs?: number;\n env: NodeJS.ProcessEnv;\n fetchImpl: FetchLike;\n now?: Date;\n validation?: Partial<ValidationDeps>;\n};\n\nexport type FlowIdentityCaptureReport = {\n schema_version: 'dataset-flow-identity-capture-report.v2';\n generated_at_utc: string;\n status: 'captured';\n environment: 'production';\n project_ref: string;\n actor: { user_id: string; email: string };\n operation_id: string;\n request_id: string;\n receipt_id: string;\n receipt_proof_sha256: string;\n capture_request_sha256: string;\n live_capture_evidence_core_sha256: string;\n capture_artifact_sha256: string;\n counts: {\n sources: 305;\n targets: number;\n supports: number;\n owner_draft_processes: number;\n mappings: number;\n affected_processes: number;\n rewrites: number;\n };\n calls: {\n capture_attest: 1;\n scope_preflight: 0;\n process_rewrite: 0;\n scope_finalize: 0;\n automatic_retry: false;\n };\n artifacts: {\n request: string;\n attestation: string;\n live_capture: string;\n report: string;\n };\n};\n\ntype CaptureDependencies = {\n resolveContext: typeof resolveMaintenanceRemoteContext;\n fetchAccountTableRows: typeof fetchMaintenanceAccountTableRows;\n fetchExactRows: typeof fetchMaintenanceExactRows;\n attest: typeof attestMaintenanceFlowIdentityCapture;\n materialize: typeof materializePrivateArtifactDirectoryAtomically;\n};\n\nconst DEFAULT_DEPENDENCIES: CaptureDependencies = {\n resolveContext: resolveMaintenanceRemoteContext,\n fetchAccountTableRows: fetchMaintenanceAccountTableRows,\n fetchExactRows: fetchMaintenanceExactRows,\n attest: attestMaintenanceFlowIdentityCapture,\n materialize: materializePrivateArtifactDirectoryAtomically,\n};\n\nfunction fail(message: string, code = 'DATASET_FLOW_IDENTITY_CAPTURE_INVALID'): never {\n throw new CliError(message, { code, exitCode: 1 });\n}\n\nfunction exactKeys(value: JsonObject, keys: readonly string[]): boolean {\n const actual = Object.keys(value).sort();\n const expected = [...keys].sort();\n return actual.length === expected.length && actual.every((key, index) => key === expected[index]);\n}\n\nfunction readCanonical(filePath: string, label: string) {\n const artifact = readProtectedJsonArtifact({ filePath, label });\n if (artifact.text !== `${stableJsonText(artifact.value)}\\n`) {\n fail(`${label} must be canonical JSON with one trailing newline.`);\n }\n return artifact;\n}\n\nexport function parseFlowIdentityPrerequisites(value: unknown): FlowIdentityPrerequisites {\n if (\n !isJsonObject(value) ||\n !isJsonObject(value.step2) ||\n !isJsonObject(value.issue29_target1) ||\n !isJsonObject(value.issue29_target2) ||\n !exactKeys(value, ['schema_version', 'step2', 'issue29_target1', 'issue29_target2']) ||\n !exactKeys(value.step2, ['readback_sha256', 'completed_at_utc', 'status']) ||\n !exactKeys(value.issue29_target1, ['readback_sha256', 'completed_at_utc', 'status']) ||\n !exactKeys(value.issue29_target2, ['readback_sha256', 'completed_at_utc', 'status'])\n ) {\n fail('Flow identity prerequisites are invalid.');\n }\n const parsed = value as FlowIdentityPrerequisites;\n if (\n parsed.schema_version !== 'dataset-flow-identity-prerequisites.v2' ||\n parsed.step2.status !== 'passed' ||\n parsed.issue29_target1.status !== 'passed' ||\n parsed.issue29_target2.status !== 'passed' ||\n !HASH.test(parsed.step2.readback_sha256) ||\n !HASH.test(parsed.issue29_target1.readback_sha256) ||\n !HASH.test(parsed.issue29_target2.readback_sha256) ||\n !Number.isFinite(Date.parse(parsed.step2.completed_at_utc)) ||\n !Number.isFinite(Date.parse(parsed.issue29_target1.completed_at_utc)) ||\n !Number.isFinite(Date.parse(parsed.issue29_target2.completed_at_utc))\n ) {\n fail('Flow identity prerequisites do not prove passed Step 2 and issue #29 readbacks.');\n }\n return parsed;\n}\n\nfunction snapshot(row: DatasetMaintenanceRemoteRow): DatasetMaintenanceRowSnapshot {\n if (\n !row.user_id ||\n row.state_code === null ||\n !row.modified_at ||\n !row.json_ordered ||\n !row.json ||\n sha256Json(row.json) !== sha256Json(row.json_ordered)\n ) {\n fail('A capture row is incomplete or its json/json_ordered columns differ.');\n }\n return snapshotRemoteRow({\n table: row.table,\n id: row.id,\n version: row.version,\n user_id: row.user_id,\n state_code: row.state_code,\n modified_at: row.modified_at,\n json_ordered: row.json_ordered,\n model_id: row.model_id,\n rule_verification: row.rule_verification,\n });\n}\n\nfunction identity(id: string, version: string): string {\n return `${id}\\u0000${version}`;\n}\n\nfunction referenceIdentity(value: unknown): { id: string; version: string } | null {\n if (\n !isJsonObject(value) ||\n typeof value['@refObjectId'] !== 'string' ||\n typeof value['@version'] !== 'string' ||\n !UUID.test(value['@refObjectId']) ||\n !VERSION.test(value['@version'])\n ) {\n return null;\n }\n return { id: value['@refObjectId'], version: value['@version'] };\n}\n\nfunction arrayOfObjects(value: unknown): JsonObject[] {\n const values = Array.isArray(value) ? value : isJsonObject(value) ? [value] : [];\n if (!values.every(isJsonObject)) fail('A flow support collection is malformed.');\n return values;\n}\n\nfunction flowPropertyClaim(payload: JsonObject): { id: string; version: string } {\n const root = isJsonObject(payload.flowDataSet) ? payload.flowDataSet : null;\n const information = isJsonObject(root?.flowInformation) ? root.flowInformation : null;\n const quantitative = isJsonObject(information?.quantitativeReference)\n ? information.quantitativeReference\n : null;\n const properties = isJsonObject(root?.flowProperties) ? root.flowProperties : null;\n const referenceInternalId = quantitative?.referenceToReferenceFlowProperty;\n const property = arrayOfObjects(properties?.flowProperty).find(\n (entry) => entry['@dataSetInternalID'] === referenceInternalId,\n );\n const claim = referenceIdentity(property?.referenceToFlowPropertyDataSet);\n if (!claim) fail('A mapped flow lacks an exact reference flow-property identity.');\n return claim;\n}\n\nfunction unitGroupClaim(payload: JsonObject): { id: string; version: string } {\n const root = isJsonObject(payload.flowPropertyDataSet) ? payload.flowPropertyDataSet : null;\n const information = isJsonObject(root?.flowPropertiesInformation)\n ? root.flowPropertiesInformation\n : null;\n const quantitative = isJsonObject(information?.quantitativeReference)\n ? information.quantitativeReference\n : null;\n const claim = referenceIdentity(quantitative?.referenceToReferenceUnitGroup);\n if (!claim) fail('A captured flow property lacks an exact unit-group identity.');\n return claim;\n}\n\nfunction processReferencesReviewedSource(\n row: DatasetMaintenanceRowSnapshot,\n reviewed: ReadonlySet<string>,\n): boolean {\n const root = isJsonObject(row.json_ordered?.processDataSet)\n ? row.json_ordered.processDataSet\n : null;\n const exchanges = isJsonObject(root?.exchanges) ? root.exchanges : null;\n const values = Array.isArray(exchanges?.exchange)\n ? exchanges.exchange\n : isJsonObject(exchanges?.exchange)\n ? [exchanges.exchange]\n : [];\n for (const value of values) {\n if (!isJsonObject(value)) fail('A captured process has a malformed exchange collection.');\n const reference = referenceIdentity(value.referenceToFlowDataSet);\n if (!reference) fail('A captured process exchange has a malformed flow reference.');\n if (reviewed.has(identity(reference.id, reference.version))) return true;\n }\n return false;\n}\n\nasync function fetchUniqueRows(options: {\n identities: Array<{\n table: 'flows' | 'flowproperties' | 'unitgroups';\n id: string;\n version: string;\n }>;\n context: DatasetMaintenanceRemoteContext;\n actorUserId: string;\n publicOnly: boolean;\n concurrency: number;\n dependencies: CaptureDependencies;\n}): Promise<DatasetMaintenanceRowSnapshot[]> {\n const rows: DatasetMaintenanceRowSnapshot[] = [];\n for (let offset = 0; offset < options.identities.length; offset += options.concurrency) {\n const chunk = options.identities.slice(offset, offset + options.concurrency);\n const fetched = await Promise.all(\n chunk.map(async (claim) => {\n const result = await options.dependencies.fetchExactRows({\n context: options.context,\n table: claim.table,\n id: claim.id,\n version: claim.version,\n includeJson: true,\n });\n const visible = result.rows.filter((row) =>\n options.publicOnly\n ? row.state_code === 100 && row.user_id !== options.actorUserId\n : row.state_code === 100 ||\n (row.state_code === 0 && row.user_id === options.actorUserId),\n );\n if (visible.length !== 1) {\n fail('A capture target/support identity is missing, duplicated, or outside visibility.');\n }\n return snapshot(visible[0]!);\n }),\n );\n rows.push(...fetched);\n }\n return rows.sort((left, right) =>\n `${left.table}\\u0000${identity(left.id, left.version)}`.localeCompare(\n `${right.table}\\u0000${identity(right.id, right.version)}`,\n ),\n );\n}\n\nfunction validateInputs(options: CaptureFlowIdentityOptions): { concurrency: number } {\n const concurrency = options.readConcurrency ?? 5;\n if (!UUID.test(options.requestId)) fail('capture request ID must be a canonical UUID.');\n if (!options.operationId.trim() || Buffer.byteLength(options.operationId, 'utf8') > 512) {\n fail('capture operation ID must be a non-empty token of at most 512 UTF-8 bytes.');\n }\n if (!Number.isInteger(concurrency) || concurrency < 1 || concurrency > 5) {\n fail('capture read concurrency must be an integer between 1 and 5.');\n }\n if (!options.sdkVersion.trim()) fail('capture SDK version is required.');\n return { concurrency };\n}\n\nasync function executeCapture(\n options: CaptureFlowIdentityOptions,\n dependencies: CaptureDependencies,\n): Promise<FlowIdentityCaptureReport> {\n const { concurrency } = validateInputs(options);\n if (existsSync(path.resolve(options.outDir))) {\n fail('Capture output directory already exists; protected capture artifacts are immutable.');\n }\n const policyArtifact = readCanonical(options.policyPath, 'Flow identity compatibility policy');\n const reviewArtifact = readCanonical(options.reviewLedgerPath, 'Flow identity review ledger');\n const prerequisitesArtifact = readCanonical(\n options.prerequisitesPath,\n 'Flow identity prerequisites',\n );\n const toolchainArtifact = readCanonical(\n options.toolchainEvidencePath,\n 'Protected toolchain evidence',\n );\n const policy = parseFlowIdentityPolicy(policyArtifact.value);\n const review = parseFlowIdentityReviewLedger(reviewArtifact.value);\n const prerequisites = parseFlowIdentityPrerequisites(prerequisitesArtifact.value);\n if (policy.evidence_resolution_sha256 !== review.review_evidence_sha256) {\n fail('Compatibility policy does not bind the review ledger.');\n }\n parseProtectedToolchainEvidence(toolchainArtifact.value, {\n projectRef: options.expectedProjectRef,\n cliVersion: options.cliVersion,\n });\n const capturedAt = options.now ?? new Date();\n if (\n Date.parse(prerequisites.step2.completed_at_utc) > capturedAt.getTime() ||\n Date.parse(prerequisites.issue29_target1.completed_at_utc) > capturedAt.getTime() ||\n Date.parse(prerequisites.issue29_target2.completed_at_utc) > capturedAt.getTime()\n ) {\n fail('Capture time precedes a required passed prerequisite.');\n }\n const context = await dependencies.resolveContext({\n env: options.env,\n fetchImpl: options.fetchImpl,\n timeoutMs: options.timeoutMs,\n now: options.now,\n });\n if (\n context.project_ref !== options.expectedProjectRef ||\n context.account.email.trim().toLowerCase() !== options.confirm.trim().toLowerCase()\n ) {\n fail('Authenticated production project/account does not match capture confirmation.');\n }\n const [flowCensus, processCensus] = await Promise.all([\n dependencies.fetchAccountTableRows({\n context,\n userId: context.account.user_id,\n table: 'flows',\n stateCode: 0,\n includeJson: true,\n pageSize: options.pageSize,\n }),\n dependencies.fetchAccountTableRows({\n context,\n userId: context.account.user_id,\n table: 'processes',\n stateCode: 0,\n includeJson: true,\n pageSize: options.pageSize,\n }),\n ]);\n const reviewed = new Set(\n review.entries.map((entry) => identity(entry.source.id, entry.source.version)),\n );\n const elementary = flowCensus.rows.filter(\n (row) => row.json_ordered && flowType(row.json_ordered) === 'Elementary flow',\n );\n const observed = new Set(elementary.map((row) => identity(row.id, row.version)));\n if (\n elementary.length !== 305 ||\n observed.size !== 305 ||\n [...reviewed].some((key) => !observed.has(key)) ||\n [...observed].some((key) => !reviewed.has(key))\n ) {\n fail(\n 'Authenticated owner-draft Elementary-flow census is not the exact 305-row review universe.',\n );\n }\n const sourceRows = elementary\n .map(snapshot)\n .sort((left, right) =>\n identity(left.id, left.version).localeCompare(identity(right.id, right.version)),\n );\n const fullProcessRows = processCensus.rows\n .map(snapshot)\n .sort((left, right) =>\n identity(left.id, left.version).localeCompare(identity(right.id, right.version)),\n );\n const processRows = fullProcessRows.filter((row) =>\n processReferencesReviewedSource(row, reviewed),\n );\n const processScanProof: JsonObject = {\n ...(processCensus.completeness as unknown as JsonObject),\n row_identity_set_sha256: sha256Json(\n fullProcessRows.map((row) => ({ id: row.id, version: row.version })),\n ),\n row_snapshot_set_sha256: sha256Json(\n fullProcessRows.map((row) => ({\n id: row.id,\n version: row.version,\n row_sha256: row.row_sha256,\n })),\n ),\n };\n const targetClaims = [\n ...new Map(\n review.entries\n .filter((entry) => entry.disposition === 'map_public')\n .map((entry) => [\n identity(entry.target!.id, entry.target!.version),\n {\n table: 'flows' as const,\n id: entry.target!.id,\n version: entry.target!.version,\n },\n ]),\n ).values(),\n ];\n const targetRows = await fetchUniqueRows({\n identities: targetClaims,\n context,\n actorUserId: context.account.user_id,\n publicOnly: true,\n concurrency,\n dependencies,\n });\n const fpClaims = [\n ...new Map(\n [\n ...sourceRows.filter((row) =>\n review.entries.some(\n (entry) =>\n entry.disposition === 'map_public' &&\n entry.source.id === row.id &&\n entry.source.version === row.version,\n ),\n ),\n ...targetRows,\n ].map((row) => {\n const claim = flowPropertyClaim(row.json_ordered!);\n return [\n identity(claim.id, claim.version),\n {\n table: 'flowproperties' as const,\n ...claim,\n },\n ];\n }),\n ).values(),\n ];\n const flowPropertyRows = await fetchUniqueRows({\n identities: fpClaims,\n context,\n actorUserId: context.account.user_id,\n publicOnly: false,\n concurrency,\n dependencies,\n });\n const unitGroupClaims = [\n ...new Map(\n flowPropertyRows.map((row) => {\n const claim = unitGroupClaim(row.json_ordered!);\n return [identity(claim.id, claim.version), { table: 'unitgroups' as const, ...claim }];\n }),\n ).values(),\n ];\n const unitGroupRows = await fetchUniqueRows({\n identities: unitGroupClaims,\n context,\n actorUserId: context.account.user_id,\n publicOnly: false,\n concurrency,\n dependencies,\n });\n const supportRows = [...flowPropertyRows, ...unitGroupRows].sort((left, right) =>\n `${left.table}\\u0000${identity(left.id, left.version)}`.localeCompare(\n `${right.table}\\u0000${identity(right.id, right.version)}`,\n ),\n );\n const capture: FlowIdentityLiveCapture = {\n schema_version: 'dataset-flow-identity-live-capture.v2',\n captured_at_utc: capturedAt.toISOString(),\n environment: 'production',\n project_ref: context.project_ref,\n account: {\n user_id: context.account.user_id,\n email: context.account.email.trim().toLowerCase(),\n },\n prerequisites: {\n step2_readback_sha256: prerequisites.step2.readback_sha256,\n step2_completed_at_utc: prerequisites.step2.completed_at_utc,\n issue29_target1_readback_sha256: prerequisites.issue29_target1.readback_sha256,\n issue29_target1_completed_at_utc: prerequisites.issue29_target1.completed_at_utc,\n issue29_target2_readback_sha256: prerequisites.issue29_target2.readback_sha256,\n issue29_target2_completed_at_utc: prerequisites.issue29_target2.completed_at_utc,\n },\n sdk: { package: '@tiangong-lca/tidas-sdk', version: options.sdkVersion.trim() },\n artifact_evidence: {\n review_ledger_sha256: review.ledger_sha256,\n live_capture_artifact_sha256: '',\n toolchain_evidence_sha256: toolchainArtifact.file_sha256,\n },\n completeness: {\n schema_version: 'dataset-flow-identity-capture-completeness.v2',\n source_count: 305,\n target_count: targetRows.length,\n support_count: supportRows.length,\n owner_draft_process_count: fullProcessRows.length,\n owner_draft_process_scan: processScanProof,\n },\n source_rows: sourceRows,\n target_rows: targetRows,\n support_rows: supportRows,\n process_rows: processRows,\n capture_request: {} as FlowIdentityLiveCapture['capture_request'],\n attestation: {} as FlowIdentityLiveCapture['attestation'],\n capture_artifact_sha256: '',\n };\n capture.artifact_evidence.live_capture_artifact_sha256 =\n computeFlowIdentityCaptureEvidenceSha256(capture);\n const validation: ValidationDeps = {\n validateFlow: options.validation?.validateFlow ?? validateFlowPayload,\n validateProcess: options.validation?.validateProcess ?? validateProcessPayload,\n };\n const semantics = buildFlowIdentitySemantics({ policy, review, capture, validation });\n capture.capture_request = buildFlowIdentityCaptureRequest({\n requestId: options.requestId,\n operationId: options.operationId,\n policy,\n capture,\n mappings: semantics.mappings,\n processTemplates: semantics.processTemplates,\n protectedClosure: semantics.protectedClosure,\n });\n const requestSha256 = flowIdentityRestrictedSha256(\n capture.capture_request as unknown as JsonObject,\n );\n const materializeIndeterminate = (error: unknown, rawResponse?: JsonObject): void => {\n const preferred = path.resolve(options.outDir);\n const recoveryDir = existsSync(preferred)\n ? `${preferred}.indeterminate-${options.requestId}`\n : preferred;\n dependencies.materialize(recoveryDir, (staging) => {\n writePrivateImmutableJson(\n path.join(staging, 'flow-identity-capture-request.json'),\n capture.capture_request,\n );\n if (rawResponse) {\n writePrivateImmutableJson(\n path.join(staging, 'flow-identity-capture-raw-response.json'),\n rawResponse,\n );\n }\n writePrivateImmutableJson(path.join(staging, 'flow-identity-capture-indeterminate.json'), {\n schema_version: 'dataset-flow-identity-capture-indeterminate.v2',\n status: 'indeterminate',\n request_id: options.requestId,\n capture_request_sha256: requestSha256,\n post_attempt_count: 1,\n automatic_retry: false,\n normal_capture_rerun_allowed: false,\n recovery: 'operator_exact_request_status_or_replay_required',\n error: String(error),\n });\n });\n };\n const materializeRejected = (rawResponse: JsonObject): void => {\n dependencies.materialize(path.resolve(options.outDir), (staging) => {\n writePrivateImmutableJson(\n path.join(staging, 'flow-identity-capture-request.json'),\n capture.capture_request,\n );\n writePrivateImmutableJson(path.join(staging, 'flow-identity-capture-domain-rejection.json'), {\n schema_version: 'dataset-flow-identity-capture-domain-rejection.v1',\n status: 'rejected',\n request_id: options.requestId,\n capture_request_sha256: requestSha256,\n post_attempt_count: 1,\n automatic_retry: false,\n same_request_replay_allowed: false,\n recovery: 'new_request_and_output_directory_required',\n response: rawResponse,\n });\n });\n };\n let rawAttestation: JsonObject;\n try {\n rawAttestation = await dependencies.attest({\n context,\n request: capture.capture_request as unknown as JsonObject,\n });\n } catch (error) {\n materializeIndeterminate(error);\n throw error;\n }\n if (isMaintenanceRpcDomainFailure(rawAttestation)) {\n materializeRejected(rawAttestation);\n throw new CliError(\n typeof rawAttestation.message === 'string'\n ? rawAttestation.message\n : 'Flow identity capture was rejected by the database.',\n {\n code: rawAttestation.code,\n exitCode: 1,\n details: rawAttestation,\n },\n );\n }\n try {\n capture.attestation = rawAttestation as FlowIdentityLiveCapture['attestation'];\n capture.capture_artifact_sha256 = computeFlowIdentityCaptureSha256(capture);\n const parsed = parseFlowIdentityCapture(capture);\n const generatedAt = options.now ?? new Date();\n const artifactPaths = {\n request: path.join(path.resolve(options.outDir), 'flow-identity-capture-request.json'),\n attestation: path.join(\n path.resolve(options.outDir),\n 'flow-identity-capture-attestation.json',\n ),\n live_capture: path.join(path.resolve(options.outDir), 'flow-identity-live-capture.json'),\n report: path.join(path.resolve(options.outDir), 'flow-identity-capture-report.json'),\n };\n const report: FlowIdentityCaptureReport = {\n schema_version: 'dataset-flow-identity-capture-report.v2',\n generated_at_utc: generatedAt.toISOString(),\n status: 'captured',\n environment: 'production',\n project_ref: parsed.project_ref,\n actor: parsed.account,\n operation_id: parsed.attestation.operation_id,\n request_id: parsed.capture_request.request_id,\n receipt_id: parsed.attestation.receipt_id,\n receipt_proof_sha256: parsed.attestation.receipt_proof_sha256,\n capture_request_sha256: parsed.attestation.capture_request_sha256,\n live_capture_evidence_core_sha256: parsed.artifact_evidence.live_capture_artifact_sha256,\n capture_artifact_sha256: parsed.capture_artifact_sha256,\n counts: {\n sources: 305,\n targets: parsed.target_rows.length,\n supports: parsed.support_rows.length,\n owner_draft_processes: parsed.completeness.owner_draft_process_count,\n mappings: semantics.mappings.length,\n affected_processes: semantics.processTemplates.length,\n rewrites: semantics.processTemplates.reduce(\n (sum, template) => sum + template.process.rewrite_count,\n 0,\n ),\n },\n calls: {\n capture_attest: 1,\n scope_preflight: 0,\n process_rewrite: 0,\n scope_finalize: 0,\n automatic_retry: false,\n },\n artifacts: artifactPaths,\n };\n dependencies.materialize(options.outDir, (staging) => {\n writePrivateImmutableJson(\n path.join(staging, path.basename(artifactPaths.request)),\n parsed.capture_request,\n );\n writePrivateImmutableJson(\n path.join(staging, path.basename(artifactPaths.attestation)),\n parsed.attestation,\n );\n writePrivateImmutableJson(\n path.join(staging, path.basename(artifactPaths.live_capture)),\n parsed,\n );\n writePrivateImmutableJson(path.join(staging, path.basename(artifactPaths.report)), report);\n });\n return report;\n } catch (error) {\n materializeIndeterminate(error, rawAttestation);\n throw error;\n }\n}\n\nexport async function captureFlowIdentity(\n options: CaptureFlowIdentityOptions,\n): Promise<FlowIdentityCaptureReport> {\n return executeCapture(options, DEFAULT_DEPENDENCIES);\n}\n\nexport const __testInternals = {\n executeCapture,\n flowPropertyClaim,\n parseFlowIdentityPrerequisites,\n snapshot,\n unitGroupClaim,\n};\n"]}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { readProtectedJsonArtifact } from './dataset-maintenance-protected-artifacts.js';
|
|
2
|
+
import { stableJsonText } from './dataset-maintenance-contract.js';
|
|
3
|
+
import { runFlowIdentityPlan, } from './dataset-maintenance-flow-identity-plan.js';
|
|
4
|
+
import { CliError } from './errors.js';
|
|
5
|
+
function readCanonical(filePath, label) {
|
|
6
|
+
const artifact = readProtectedJsonArtifact({ filePath, label });
|
|
7
|
+
if (artifact.text !== `${stableJsonText(artifact.value)}\n`) {
|
|
8
|
+
throw new CliError(`${label} must be canonical JSON with one trailing newline.`, {
|
|
9
|
+
code: 'DATASET_FLOW_IDENTITY_ARTIFACT_NONCANONICAL',
|
|
10
|
+
exitCode: 2,
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
return artifact.value;
|
|
14
|
+
}
|
|
15
|
+
export function runFlowIdentityPlanFromFiles(options) {
|
|
16
|
+
return runFlowIdentityPlan({
|
|
17
|
+
policy: readCanonical(options.policyPath, 'Flow identity compatibility policy'),
|
|
18
|
+
reviewLedger: readCanonical(options.reviewLedgerPath, 'Flow identity review ledger'),
|
|
19
|
+
liveCapture: readCanonical(options.liveCapturePath, 'Flow identity live capture'),
|
|
20
|
+
outDir: options.outDir,
|
|
21
|
+
now: options.now,
|
|
22
|
+
validation: options.validation,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
export const __testInternals = { readCanonical };
|
|
26
|
+
//# sourceMappingURL=dataset-maintenance-flow-identity-command.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dataset-maintenance-flow-identity-command.js","sourceRoot":"","sources":["../../../src/lib/dataset-maintenance-flow-identity-command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,MAAM,8CAA8C,CAAC;AACzF,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACnE,OAAO,EACL,mBAAmB,GAEpB,MAAM,6CAA6C,CAAC;AACrD,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAWvC,SAAS,aAAa,CAAC,QAAgB,EAAE,KAAa;IACpD,MAAM,QAAQ,GAAG,yBAAyB,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;IAChE,IAAI,QAAQ,CAAC,IAAI,KAAK,GAAG,cAAc,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QAC5D,MAAM,IAAI,QAAQ,CAAC,GAAG,KAAK,oDAAoD,EAAE;YAC/E,IAAI,EAAE,6CAA6C;YACnD,QAAQ,EAAE,CAAC;SACZ,CAAC,CAAC;IACL,CAAC;IACD,OAAO,QAAQ,CAAC,KAAK,CAAC;AACxB,CAAC;AAED,MAAM,UAAU,4BAA4B,CAAC,OAA4C;IACvF,OAAO,mBAAmB,CAAC;QACzB,MAAM,EAAE,aAAa,CAAC,OAAO,CAAC,UAAU,EAAE,oCAAoC,CAAC;QAC/E,YAAY,EAAE,aAAa,CAAC,OAAO,CAAC,gBAAgB,EAAE,6BAA6B,CAAC;QACpF,WAAW,EAAE,aAAa,CAAC,OAAO,CAAC,eAAe,EAAE,4BAA4B,CAAC;QACjF,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,UAAU,EAAE,OAAO,CAAC,UAAU;KAC/B,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,MAAM,eAAe,GAAG,EAAE,aAAa,EAAE,CAAC","sourcesContent":["import { readProtectedJsonArtifact } from './dataset-maintenance-protected-artifacts.js';\nimport { stableJsonText } from './dataset-maintenance-contract.js';\nimport {\n runFlowIdentityPlan,\n type RunFlowIdentityPlanOptions,\n} from './dataset-maintenance-flow-identity-plan.js';\nimport { CliError } from './errors.js';\n\nexport type RunFlowIdentityPlanFromFilesOptions = {\n policyPath: string;\n reviewLedgerPath: string;\n liveCapturePath: string;\n outDir: string;\n now?: Date;\n validation?: RunFlowIdentityPlanOptions['validation'];\n};\n\nfunction readCanonical(filePath: string, label: string): unknown {\n const artifact = readProtectedJsonArtifact({ filePath, label });\n if (artifact.text !== `${stableJsonText(artifact.value)}\\n`) {\n throw new CliError(`${label} must be canonical JSON with one trailing newline.`, {\n code: 'DATASET_FLOW_IDENTITY_ARTIFACT_NONCANONICAL',\n exitCode: 2,\n });\n }\n return artifact.value;\n}\n\nexport function runFlowIdentityPlanFromFiles(options: RunFlowIdentityPlanFromFilesOptions) {\n return runFlowIdentityPlan({\n policy: readCanonical(options.policyPath, 'Flow identity compatibility policy'),\n reviewLedger: readCanonical(options.reviewLedgerPath, 'Flow identity review ledger'),\n liveCapture: readCanonical(options.liveCapturePath, 'Flow identity live capture'),\n outDir: options.outDir,\n now: options.now,\n validation: options.validation,\n });\n}\n\nexport const __testInternals = { readCanonical };\n"]}
|