@spottoai/types-package 1.0.2-beta.360 → 1.0.2-beta.364
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 +38 -0
- package/dist/azure/billingArtifactCanonicalization.d.ts +3 -1
- package/dist/azure/billingArtifactCanonicalization.d.ts.map +1 -1
- package/dist/azure/billingArtifactCanonicalization.js +123 -43
- package/dist/azure/billingArtifactCanonicalization.js.map +1 -1
- package/dist/azure/billingArtifactGeneration.d.ts +53 -1
- package/dist/azure/billingArtifactGeneration.d.ts.map +1 -1
- package/dist/azure/billingArtifactGeneration.js +190 -25
- package/dist/azure/billingArtifactGeneration.js.map +1 -1
- package/dist/azure/billingArtifactLimits.d.ts +19 -0
- package/dist/azure/billingArtifactLimits.d.ts.map +1 -0
- package/dist/azure/billingArtifactLimits.js +22 -0
- package/dist/azure/billingArtifactLimits.js.map +1 -0
- package/dist/azure/billingPlots.d.ts +26 -3
- package/dist/azure/billingPlots.d.ts.map +1 -1
- package/dist/azure/billingPlots.js +257 -10
- package/dist/azure/billingPlots.js.map +1 -1
- package/dist/azure/views.d.ts +60 -0
- package/dist/azure/views.d.ts.map +1 -1
- package/dist/azure/views.js +280 -4
- package/dist/azure/views.js.map +1 -1
- package/dist/common/artifactControlData.d.ts +16 -2
- package/dist/common/artifactControlData.d.ts.map +1 -1
- package/dist/common/artifactControlData.js +129 -23
- package/dist/common/artifactControlData.js.map +1 -1
- package/dist/esm/azure/billingArtifactCanonicalization.js +121 -42
- package/dist/esm/azure/billingArtifactGeneration.js +186 -25
- package/dist/esm/azure/billingArtifactLimits.js +18 -0
- package/dist/esm/azure/billingPlots.js +253 -10
- package/dist/esm/azure/views.js +278 -4
- package/dist/esm/common/artifactControlData.js +127 -22
- package/dist/esm/index.js +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/package.json +4 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"artifactControlData.js","sourceRoot":"","sources":["../../src/common/artifactControlData.ts"],"names":[],"mappings":";;;AAAA,MAAM,0BAA0B,GAAG,IAAI,GAAG,CAAC;IACzC,YAAY;IACZ,WAAW;IACX,aAAa;IACb,QAAQ;IACR,eAAe;IACf,cAAc;IACd,kBAAkB;IAClB,YAAY;IACZ,aAAa;IACb,UAAU;IACV,cAAc;IACd,UAAU;IACV,QAAQ;IACR,uBAAuB;IACvB,OAAO;CACR,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"artifactControlData.js","sourceRoot":"","sources":["../../src/common/artifactControlData.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ARTIFACT_CONTROL_DATA_MAX_VISITED_NODES, allowedArtifactReferenceField, containsForbiddenArtifactControlData, } from '../common/artifactControlData.js';
|
|
1
2
|
const hasOwn = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
|
|
2
3
|
const isRecord = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
3
4
|
const requirePlainRecord = (value, name) => {
|
|
@@ -158,6 +159,47 @@ const projectPublicationDecision = (value) => {
|
|
|
158
159
|
issues: issues.map(projectIssue),
|
|
159
160
|
};
|
|
160
161
|
};
|
|
162
|
+
const projectPromotionEvaluation = (value) => {
|
|
163
|
+
const source = requirePlainRecord(value, 'Billing promotion observation evaluation');
|
|
164
|
+
const projected = {
|
|
165
|
+
comparison: readDataProperty(source, 'comparison'),
|
|
166
|
+
projectedOutcome: readDataProperty(source, 'projectedOutcome'),
|
|
167
|
+
};
|
|
168
|
+
selectOptional(source, projected, 'outputDigestRelation');
|
|
169
|
+
return projected;
|
|
170
|
+
};
|
|
171
|
+
const projectPromotionObservation = (value) => {
|
|
172
|
+
const source = requirePlainRecord(value, 'Billing promotion observation');
|
|
173
|
+
const observationDigest = readDataProperty(source, 'observationDigest');
|
|
174
|
+
if (typeof observationDigest !== 'string')
|
|
175
|
+
throw new TypeError('Billing promotion observation requires an observationDigest string.');
|
|
176
|
+
const projected = {
|
|
177
|
+
schemaVersion: readDataProperty(source, 'schemaVersion'),
|
|
178
|
+
documentType: readDataProperty(source, 'documentType'),
|
|
179
|
+
authority: readDataProperty(source, 'authority'),
|
|
180
|
+
publicationMode: readDataProperty(source, 'publicationMode'),
|
|
181
|
+
processingState: readDataProperty(source, 'processingState'),
|
|
182
|
+
subscriptionId: readDataProperty(source, 'subscriptionId'),
|
|
183
|
+
generationId: readDataProperty(source, 'generationId'),
|
|
184
|
+
ownership: projectOwnership(readDataProperty(source, 'ownership')),
|
|
185
|
+
revision: projectRevision(readDataProperty(source, 'revision')),
|
|
186
|
+
messageId: readDataProperty(source, 'messageId'),
|
|
187
|
+
correlationId: readDataProperty(source, 'correlationId'),
|
|
188
|
+
inputManifestPath: readDataProperty(source, 'inputManifestPath'),
|
|
189
|
+
inputManifestDigest: readDataProperty(source, 'inputManifestDigest'),
|
|
190
|
+
outputManifestPath: readDataProperty(source, 'outputManifestPath'),
|
|
191
|
+
outputManifestDigest: readDataProperty(source, 'outputManifestDigest'),
|
|
192
|
+
evaluation: projectPromotionEvaluation(readDataProperty(source, 'evaluation')),
|
|
193
|
+
observedAt: readDataProperty(source, 'observedAt'),
|
|
194
|
+
};
|
|
195
|
+
if (containsForbiddenArtifactControlData(projected, [
|
|
196
|
+
...allowedArtifactReferenceField(projected, 'inputManifestPath'),
|
|
197
|
+
...allowedArtifactReferenceField(projected, 'outputManifestPath'),
|
|
198
|
+
])) {
|
|
199
|
+
throw new TypeError('Billing promotion observation contains forbidden control data.');
|
|
200
|
+
}
|
|
201
|
+
return projected;
|
|
202
|
+
};
|
|
161
203
|
const projectBinding = (subscriptionId, generationId, ownership, revision, inputManifestDigest, publicationDecision) => ({
|
|
162
204
|
kind: 'billing-analysis-output',
|
|
163
205
|
schemaVersion: 1,
|
|
@@ -180,68 +222,103 @@ export const projectBillingOutputBindingV1FromMetadata = (metadata) => {
|
|
|
180
222
|
};
|
|
181
223
|
const canonicalizeJson = (value) => {
|
|
182
224
|
const active = new Set();
|
|
183
|
-
const
|
|
184
|
-
|
|
185
|
-
|
|
225
|
+
const fragments = [];
|
|
226
|
+
const pending = [{ kind: 'value', value }];
|
|
227
|
+
let visitedContainerCount = 0;
|
|
228
|
+
while (pending.length > 0) {
|
|
229
|
+
const frame = pending.pop();
|
|
230
|
+
if (frame === undefined)
|
|
231
|
+
break;
|
|
232
|
+
if (frame.kind === 'fragment') {
|
|
233
|
+
fragments.push(frame.value);
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
if (frame.kind === 'leave') {
|
|
237
|
+
active.delete(frame.value);
|
|
238
|
+
continue;
|
|
239
|
+
}
|
|
240
|
+
const candidate = frame.value;
|
|
241
|
+
if (candidate === null || typeof candidate === 'boolean') {
|
|
242
|
+
fragments.push(JSON.stringify(candidate));
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
186
245
|
if (typeof candidate === 'string') {
|
|
187
246
|
if (hasUnpairedSurrogate(candidate))
|
|
188
247
|
throw new TypeError('Canonical JSON rejects invalid Unicode surrogate data.');
|
|
189
|
-
|
|
248
|
+
fragments.push(JSON.stringify(candidate));
|
|
249
|
+
continue;
|
|
190
250
|
}
|
|
191
251
|
if (typeof candidate === 'number') {
|
|
192
252
|
if (!Number.isFinite(candidate) || Object.is(candidate, -0) || (Number.isInteger(candidate) && !Number.isSafeInteger(candidate))) {
|
|
193
253
|
throw new TypeError('Canonical JSON requires finite, safe, non-negative-zero numbers.');
|
|
194
254
|
}
|
|
195
|
-
|
|
255
|
+
fragments.push(JSON.stringify(candidate));
|
|
256
|
+
continue;
|
|
196
257
|
}
|
|
197
258
|
if (typeof candidate !== 'object' || candidate === undefined)
|
|
198
259
|
throw new TypeError('Canonical JSON rejects non-JSON values.');
|
|
260
|
+
visitedContainerCount += 1;
|
|
261
|
+
if (visitedContainerCount > ARTIFACT_CONTROL_DATA_MAX_VISITED_NODES) {
|
|
262
|
+
throw new TypeError('Canonical JSON exceeds its 100000-container limit.');
|
|
263
|
+
}
|
|
199
264
|
if (active.has(candidate))
|
|
200
265
|
throw new TypeError('Canonical JSON rejects cyclic values.');
|
|
201
266
|
active.add(candidate);
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
}
|
|
211
|
-
const values = [];
|
|
212
|
-
for (let index = 0; index < candidate.length; index += 1) {
|
|
213
|
-
if (!hasOwn(candidate, index))
|
|
214
|
-
throw new TypeError('Canonical JSON rejects sparse arrays.');
|
|
215
|
-
const descriptor = Object.getOwnPropertyDescriptor(candidate, String(index));
|
|
216
|
-
if (descriptor === undefined || !('value' in descriptor) || !descriptor.enumerable || descriptor.value === undefined) {
|
|
217
|
-
throw new TypeError('Canonical JSON array entries must be enumerable JSON values.');
|
|
218
|
-
}
|
|
219
|
-
values.push(serialize(descriptor.value));
|
|
220
|
-
}
|
|
221
|
-
return `[${values.join(',')}]`;
|
|
267
|
+
pending.push({ kind: 'leave', value: candidate });
|
|
268
|
+
if (Array.isArray(candidate)) {
|
|
269
|
+
if (Object.getPrototypeOf(candidate) !== Array.prototype)
|
|
270
|
+
throw new TypeError('Canonical JSON requires plain arrays.');
|
|
271
|
+
const ownKeys = Reflect.ownKeys(candidate);
|
|
272
|
+
if (ownKeys.some(key => typeof key === 'symbol') ||
|
|
273
|
+
ownKeys.some(key => typeof key === 'string' && key !== 'length' && !/^(0|[1-9]\d*)$/.test(key))) {
|
|
274
|
+
throw new TypeError('Canonical JSON arrays cannot contain custom properties.');
|
|
222
275
|
}
|
|
223
|
-
const
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
const entries = [];
|
|
229
|
-
for (const key of Object.getOwnPropertyNames(candidate).sort()) {
|
|
230
|
-
if (hasUnpairedSurrogate(key))
|
|
231
|
-
throw new TypeError('Canonical JSON rejects invalid Unicode property names.');
|
|
232
|
-
const descriptor = Object.getOwnPropertyDescriptor(candidate, key);
|
|
276
|
+
const values = [];
|
|
277
|
+
for (let index = 0; index < candidate.length; index += 1) {
|
|
278
|
+
if (!hasOwn(candidate, index))
|
|
279
|
+
throw new TypeError('Canonical JSON rejects sparse arrays.');
|
|
280
|
+
const descriptor = Object.getOwnPropertyDescriptor(candidate, String(index));
|
|
233
281
|
if (descriptor === undefined || !('value' in descriptor) || !descriptor.enumerable || descriptor.value === undefined) {
|
|
234
|
-
throw new TypeError('Canonical JSON
|
|
282
|
+
throw new TypeError('Canonical JSON array entries must be enumerable JSON values.');
|
|
235
283
|
}
|
|
236
|
-
|
|
284
|
+
values.push(descriptor.value);
|
|
237
285
|
}
|
|
238
|
-
|
|
286
|
+
fragments.push('[');
|
|
287
|
+
pending.push({ kind: 'fragment', value: ']' });
|
|
288
|
+
for (let index = values.length - 1; index >= 0; index -= 1) {
|
|
289
|
+
pending.push({ kind: 'value', value: values[index] });
|
|
290
|
+
if (index > 0)
|
|
291
|
+
pending.push({ kind: 'fragment', value: ',' });
|
|
292
|
+
}
|
|
293
|
+
continue;
|
|
294
|
+
}
|
|
295
|
+
const prototype = Object.getPrototypeOf(candidate);
|
|
296
|
+
if (prototype !== Object.prototype && prototype !== null)
|
|
297
|
+
throw new TypeError('Canonical JSON requires plain objects.');
|
|
298
|
+
if (Object.getOwnPropertySymbols(candidate).length > 0)
|
|
299
|
+
throw new TypeError('Canonical JSON rejects symbol properties.');
|
|
300
|
+
const entries = [];
|
|
301
|
+
for (const key of Object.getOwnPropertyNames(candidate).sort()) {
|
|
302
|
+
if (hasUnpairedSurrogate(key))
|
|
303
|
+
throw new TypeError('Canonical JSON rejects invalid Unicode property names.');
|
|
304
|
+
const descriptor = Object.getOwnPropertyDescriptor(candidate, key);
|
|
305
|
+
if (descriptor === undefined || !('value' in descriptor) || !descriptor.enumerable || descriptor.value === undefined) {
|
|
306
|
+
throw new TypeError('Canonical JSON object fields must be enumerable JSON values.');
|
|
307
|
+
}
|
|
308
|
+
entries.push({ key, value: descriptor.value });
|
|
239
309
|
}
|
|
240
|
-
|
|
241
|
-
|
|
310
|
+
fragments.push('{');
|
|
311
|
+
pending.push({ kind: 'fragment', value: '}' });
|
|
312
|
+
for (let index = entries.length - 1; index >= 0; index -= 1) {
|
|
313
|
+
const entry = entries[index];
|
|
314
|
+
pending.push({ kind: 'value', value: entry.value });
|
|
315
|
+
pending.push({
|
|
316
|
+
kind: 'fragment',
|
|
317
|
+
value: `${index > 0 ? ',' : ''}${JSON.stringify(entry.key)}:`,
|
|
318
|
+
});
|
|
242
319
|
}
|
|
243
|
-
}
|
|
244
|
-
return
|
|
320
|
+
}
|
|
321
|
+
return fragments.join('');
|
|
245
322
|
};
|
|
246
323
|
const withoutManifestDigest = (manifest) => {
|
|
247
324
|
const prototype = Object.getPrototypeOf(manifest);
|
|
@@ -277,5 +354,7 @@ export const canonicalizeBillingOutputBindingV1 = (binding) => {
|
|
|
277
354
|
export const canonicalizeBillingAnalyzerInputManifestV2ForDigest = (manifest) => canonicalizeJson(withoutManifestDigest(manifest));
|
|
278
355
|
/** Returns the canonical output-manifest digest preimage, excluding only top-level manifestDigest. */
|
|
279
356
|
export const canonicalizeBillingAnalyzerOutputManifestV2ForDigest = (manifest) => canonicalizeJson(withoutManifestDigest(manifest));
|
|
357
|
+
/** Returns the exact promotion-observation digest preimage, excluding observationDigest and additive fields. */
|
|
358
|
+
export const canonicalizeBillingAnalysisPromotionObservationV1ForDigest = (observation) => canonicalizeJson(projectPromotionObservation(observation));
|
|
280
359
|
/** Returns the RFC 8785/JCS-compatible canonical JSON string for a validated JSON value. */
|
|
281
360
|
export const canonicalizeBillingArtifactJson = (value) => canonicalizeJson(value);
|
|
@@ -1,11 +1,34 @@
|
|
|
1
1
|
import { isArtifactOwnershipBinding, isEnforceableArtifactOwnershipBinding, } from '../common/artifactEvidence.js';
|
|
2
2
|
import { isArtifactRevisionVector, isStrictLogicalArtifactReference } from '../common/artifactEvidenceValidation.js';
|
|
3
|
-
import { allowedArtifactIdentityField, allowedArtifactReferenceField, containsForbiddenArtifactControlData, } from '../common/artifactControlData.js';
|
|
3
|
+
import { ARTIFACT_CONTROL_DATA_MAX_VISITED_NODES, allowedArtifactIdentityField, allowedArtifactReferenceField, allowedArtifactTraversalField, containsForbiddenArtifactControlData, } from '../common/artifactControlData.js';
|
|
4
4
|
import { isBillingCompletedArtifactPublicationDecision } from './billingArtifactEvidence.js';
|
|
5
|
+
import { BILLING_ARTIFACT_OBJECT_LIMITS_V1 } from './billingArtifactLimits.js';
|
|
6
|
+
/** Stable diagnostic-only suffix for the latest successfully enqueued observe input. */
|
|
7
|
+
export const BILLING_ANALYZER_INPUT_OBSERVATION_POINTER_RELATIVE_PATH = 'history/billing/analyzer-inputs/latest-enqueued.json';
|
|
5
8
|
const BILLING_BASES = new Set(['actual', 'amortized']);
|
|
6
9
|
const COVERAGE_VERDICTS = new Set(['complete', 'partial', 'none', 'unknown']);
|
|
7
10
|
const DATE_BASES = new Set(['utc', 'billing-calendar', 'company-local']);
|
|
8
11
|
const CONTENT_ENCODINGS = new Set(['identity', 'gzip']);
|
|
12
|
+
const OBSERVATION_COMPARISONS = new Set([
|
|
13
|
+
'authority-absent',
|
|
14
|
+
'newer',
|
|
15
|
+
'equal',
|
|
16
|
+
'older',
|
|
17
|
+
'incomparable',
|
|
18
|
+
'newer-ownership',
|
|
19
|
+
'older-ownership',
|
|
20
|
+
'unenforceable',
|
|
21
|
+
]);
|
|
22
|
+
const OBSERVATION_PROJECTED_OUTCOMES = new Map([
|
|
23
|
+
['authority-absent', 'would-promote'],
|
|
24
|
+
['newer', 'would-promote'],
|
|
25
|
+
['newer-ownership', 'would-promote'],
|
|
26
|
+
['equal', 'would-be-idempotent'],
|
|
27
|
+
['older', 'would-be-superseded'],
|
|
28
|
+
['older-ownership', 'would-be-superseded'],
|
|
29
|
+
['incomparable', 'would-quarantine'],
|
|
30
|
+
['unenforceable', 'not-enforceable'],
|
|
31
|
+
]);
|
|
9
32
|
const SHA256_PATTERN = /^[a-f0-9]{64}$/;
|
|
10
33
|
const isRecord = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
11
34
|
const isNonEmptyString = (value) => typeof value === 'string' && value.trim() === value && value.length > 0;
|
|
@@ -25,7 +48,23 @@ const isCanonicalIsoTimestamp = (value) => {
|
|
|
25
48
|
};
|
|
26
49
|
const hasControlCharacters = (value) => Array.from(value).some(character => character.charCodeAt(0) < 32 || character.charCodeAt(0) === 127);
|
|
27
50
|
const allowedDescriptorPaths = (descriptors) => Array.isArray(descriptors) ? descriptors.flatMap(descriptor => allowedArtifactReferenceField(descriptor, 'path')) : [];
|
|
51
|
+
const containsForbiddenBillingArtifactControlData = (value, allowedReferenceFields = []) => containsForbiddenArtifactControlData(value, allowedReferenceFields, {
|
|
52
|
+
requireAllowedFieldTraversalContext: true,
|
|
53
|
+
});
|
|
28
54
|
const isPathSegment = (value) => isNonEmptyString(value) && !/[\\/?#%]/.test(value) && !hasControlCharacters(value) && value !== '.' && value !== '..';
|
|
55
|
+
/** Builds the diagnostic-only latest-enqueued observation path for one safe subscription segment. */
|
|
56
|
+
export const buildBillingAnalyzerInputObservationPointerPath = (subscriptionId) => {
|
|
57
|
+
if (!isPathSegment(subscriptionId))
|
|
58
|
+
throw new TypeError('subscriptionId must be a safe path segment');
|
|
59
|
+
return `subscriptions/${subscriptionId}/${BILLING_ANALYZER_INPUT_OBSERVATION_POINTER_RELATIVE_PATH}`;
|
|
60
|
+
};
|
|
61
|
+
/** Validates the exact diagnostic-only latest-enqueued observation logical path. */
|
|
62
|
+
export const isBillingAnalyzerInputObservationPointerPath = (value) => {
|
|
63
|
+
if (!isStrictLogicalArtifactReference(value))
|
|
64
|
+
return false;
|
|
65
|
+
const match = /^subscriptions\/([^/]+)\/history\/billing\/analyzer-inputs\/latest-enqueued\.json$/.exec(value);
|
|
66
|
+
return match !== null && isPathSegment(match[1]);
|
|
67
|
+
};
|
|
29
68
|
const inputGenerationPrefix = (subscriptionId, generationId) => `subscriptions/${subscriptionId}/history/billing/analyzer-inputs/generations/${generationId}/`;
|
|
30
69
|
const inputManifestPath = (subscriptionId, generationId) => `${inputGenerationPrefix(subscriptionId, generationId)}manifest.json`;
|
|
31
70
|
const outputGenerationPrefix = (subscriptionId, generationId) => `subscriptions/${subscriptionId}/billing/generations/${generationId}/`;
|
|
@@ -45,6 +84,9 @@ const hasMatchingIdentity = (subscriptionId, generationId, ownership, revision,
|
|
|
45
84
|
return !enforceable || isEnforceableArtifactOwnershipBinding(ownership);
|
|
46
85
|
};
|
|
47
86
|
const isSha256 = (value) => typeof value === 'string' && SHA256_PATTERN.test(value);
|
|
87
|
+
const hasDiagnosticObservationDiscriminant = (value) => value.authority === 'diagnostic-only' ||
|
|
88
|
+
(value.publicationMode === 'observe' &&
|
|
89
|
+
(value.documentType === 'billing-analyzer-input-observation-pointer' || value.documentType === 'billing-analysis-promotion-observation'));
|
|
48
90
|
const isRequestedPeriod = (value) => {
|
|
49
91
|
if (!isRecord(value) ||
|
|
50
92
|
!isCanonicalIsoTimestamp(value.fromInclusive) ||
|
|
@@ -65,6 +107,7 @@ const isInputObjectDescriptor = (value, subscriptionId, generationId) => {
|
|
|
65
107
|
isNonEmptyString(value.etag) &&
|
|
66
108
|
isSha256(value.sha256) &&
|
|
67
109
|
isPositiveInteger(value.byteCount) &&
|
|
110
|
+
value.byteCount <= BILLING_ARTIFACT_OBJECT_LIMITS_V1.inputObjectStoredBytes &&
|
|
68
111
|
isNonNegativeInteger(value.rowCount) &&
|
|
69
112
|
isStringIn(value.basis, BILLING_BASES) &&
|
|
70
113
|
(value.currencyCode === undefined || isNonEmptyString(value.currencyCode)) &&
|
|
@@ -74,31 +117,76 @@ const isOutputArtifactDescriptor = (value, subscriptionId, generationId) => {
|
|
|
74
117
|
if (!isRecord(value))
|
|
75
118
|
return false;
|
|
76
119
|
const prefix = outputGenerationPrefix(subscriptionId, generationId);
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
value.
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
120
|
+
if (!isGenerationPath(value.path, prefix, outputManifestPath(subscriptionId, generationId)) ||
|
|
121
|
+
!isPathSegment(value.name) ||
|
|
122
|
+
!((value.name === 'metadata.json' &&
|
|
123
|
+
value.path === `${prefix}metadata.json` &&
|
|
124
|
+
isNonNegativeInteger(value.byteLength) &&
|
|
125
|
+
value.byteLength <= BILLING_ARTIFACT_OBJECT_LIMITS_V1.metadataStoredBytes) ||
|
|
126
|
+
(value.name !== 'metadata.json' &&
|
|
127
|
+
value.path === `${prefix}plots/${value.name}` &&
|
|
128
|
+
isNonNegativeInteger(value.byteLength) &&
|
|
129
|
+
value.byteLength <= BILLING_ARTIFACT_OBJECT_LIMITS_V1.plotStoredBytes))) {
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
return value.mediaType === 'application/json' && isStringIn(value.contentEncoding, CONTENT_ENCODINGS) && isSha256(value.sha256);
|
|
83
133
|
};
|
|
84
134
|
const isJsonMetadata = (value) => {
|
|
85
135
|
if (!isRecord(value))
|
|
86
136
|
return false;
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
137
|
+
const pending = [{ kind: 'visit', value }];
|
|
138
|
+
const activeContainers = new WeakSet();
|
|
139
|
+
const completedContainers = new WeakSet();
|
|
140
|
+
let visitedNodeCount = 0;
|
|
141
|
+
while (pending.length > 0) {
|
|
142
|
+
const candidate = pending.pop();
|
|
143
|
+
if (candidate.kind === 'leave') {
|
|
144
|
+
activeContainers.delete(candidate.container);
|
|
145
|
+
completedContainers.add(candidate.container);
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
if (candidate.value === null || typeof candidate.value === 'string' || typeof candidate.value === 'boolean' || isFiniteNumber(candidate.value)) {
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
if (Array.isArray(candidate.value)) {
|
|
152
|
+
visitedNodeCount += 1;
|
|
153
|
+
if (visitedNodeCount > ARTIFACT_CONTROL_DATA_MAX_VISITED_NODES)
|
|
154
|
+
return false;
|
|
155
|
+
if (activeContainers.has(candidate.value))
|
|
156
|
+
return false;
|
|
157
|
+
if (completedContainers.has(candidate.value))
|
|
158
|
+
continue;
|
|
159
|
+
activeContainers.add(candidate.value);
|
|
160
|
+
pending.push({ kind: 'leave', container: candidate.value });
|
|
161
|
+
for (let index = candidate.value.length - 1; index >= 0; index -= 1) {
|
|
162
|
+
pending.push({ kind: 'visit', value: candidate.value[index] });
|
|
163
|
+
}
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
if (!isRecord(candidate.value) || Object.getPrototypeOf(candidate.value) !== Object.prototype)
|
|
167
|
+
return false;
|
|
168
|
+
visitedNodeCount += 1;
|
|
169
|
+
if (visitedNodeCount > ARTIFACT_CONTROL_DATA_MAX_VISITED_NODES)
|
|
170
|
+
return false;
|
|
171
|
+
if (activeContainers.has(candidate.value))
|
|
172
|
+
return false;
|
|
173
|
+
if (completedContainers.has(candidate.value))
|
|
174
|
+
continue;
|
|
175
|
+
activeContainers.add(candidate.value);
|
|
176
|
+
pending.push({ kind: 'leave', container: candidate.value });
|
|
177
|
+
for (const child of Object.values(candidate.value))
|
|
178
|
+
pending.push({ kind: 'visit', value: child });
|
|
179
|
+
}
|
|
180
|
+
return true;
|
|
97
181
|
};
|
|
98
182
|
/** Validates one immutable billing analyzer input manifest without performing I/O. */
|
|
99
183
|
export const isBillingAnalyzerInputManifestV2 = (value) => {
|
|
100
184
|
if (!isRecord(value) ||
|
|
101
|
-
|
|
185
|
+
containsForbiddenBillingArtifactControlData(value, [
|
|
186
|
+
...allowedArtifactIdentityField(value, 'publicationKey'),
|
|
187
|
+
...allowedArtifactTraversalField(value, 'inputs'),
|
|
188
|
+
...allowedDescriptorPaths(value.inputs),
|
|
189
|
+
])) {
|
|
102
190
|
return false;
|
|
103
191
|
}
|
|
104
192
|
if (value.schemaVersion !== 2 || value.status !== 'completed')
|
|
@@ -117,7 +205,7 @@ export const isBillingAnalyzerInputManifestV2 = (value) => {
|
|
|
117
205
|
const periodKeys = value.requestedPeriods.map(period => `${period.fromInclusive}\n${period.throughExclusive}\n${period.dateBasis}\n${period.timeZone ?? ''}\n${period.basis}`);
|
|
118
206
|
if (!hasUniqueValues(periodKeys))
|
|
119
207
|
return false;
|
|
120
|
-
if (!Array.isArray(value.inputs) || value.inputs.length === 0)
|
|
208
|
+
if (!Array.isArray(value.inputs) || value.inputs.length === 0 || value.inputs.length > BILLING_ARTIFACT_OBJECT_LIMITS_V1.maxInputObjects)
|
|
121
209
|
return false;
|
|
122
210
|
if (!value.inputs.every(input => isInputObjectDescriptor(input, value.subscriptionId, value.generationId)))
|
|
123
211
|
return false;
|
|
@@ -125,7 +213,9 @@ export const isBillingAnalyzerInputManifestV2 = (value) => {
|
|
|
125
213
|
};
|
|
126
214
|
/** Validates the enforceable current pointer for one published analyzer input generation. */
|
|
127
215
|
export const isBillingAnalyzerInputCurrentPointerV1 = (value) => {
|
|
128
|
-
if (!isRecord(value) ||
|
|
216
|
+
if (!isRecord(value) ||
|
|
217
|
+
hasDiagnosticObservationDiscriminant(value) ||
|
|
218
|
+
containsForbiddenBillingArtifactControlData(value, allowedArtifactReferenceField(value, 'manifestPath')))
|
|
129
219
|
return false;
|
|
130
220
|
if (value.schemaVersion !== 1 || value.status !== 'completed')
|
|
131
221
|
return false;
|
|
@@ -138,7 +228,7 @@ export const isBillingAnalyzerInputCurrentPointerV1 = (value) => {
|
|
|
138
228
|
};
|
|
139
229
|
/** Validates the V2 queue envelope and its immutable input-manifest binding. */
|
|
140
230
|
export const isBillingAnalyzerRequestV2 = (value) => {
|
|
141
|
-
if (!isRecord(value) ||
|
|
231
|
+
if (!isRecord(value) || containsForbiddenBillingArtifactControlData(value, allowedArtifactReferenceField(value, 'inputManifestPath')))
|
|
142
232
|
return false;
|
|
143
233
|
if (value.schemaVersion !== 2 || (value.publicationMode !== 'observe' && value.publicationMode !== 'enforce'))
|
|
144
234
|
return false;
|
|
@@ -157,11 +247,32 @@ export const isBillingAnalyzerRequestV2 = (value) => {
|
|
|
157
247
|
return false;
|
|
158
248
|
return value.displayMetadata === undefined || isJsonMetadata(value.displayMetadata);
|
|
159
249
|
};
|
|
250
|
+
/** Validates a diagnostic-only latest-enqueued pointer; it is never customer authority. */
|
|
251
|
+
export const isBillingAnalyzerInputObservationPointerV1 = (value) => {
|
|
252
|
+
if (!isRecord(value) || containsForbiddenBillingArtifactControlData(value, allowedArtifactReferenceField(value, 'inputManifestPath')))
|
|
253
|
+
return false;
|
|
254
|
+
if (value.schemaVersion !== 1 ||
|
|
255
|
+
value.documentType !== 'billing-analyzer-input-observation-pointer' ||
|
|
256
|
+
value.authority !== 'diagnostic-only' ||
|
|
257
|
+
value.publicationMode !== 'observe' ||
|
|
258
|
+
value.inputState !== 'enqueued') {
|
|
259
|
+
return false;
|
|
260
|
+
}
|
|
261
|
+
if (!hasMatchingIdentity(value.subscriptionId, value.generationId, value.ownership, value.revision, false))
|
|
262
|
+
return false;
|
|
263
|
+
return (isStrictLogicalArtifactReference(value.inputManifestPath) &&
|
|
264
|
+
value.inputManifestPath === inputManifestPath(value.subscriptionId, value.generationId) &&
|
|
265
|
+
isSha256(value.inputManifestDigest) &&
|
|
266
|
+
isSha256(value.messageId) &&
|
|
267
|
+
isNonEmptyString(value.correlationId) &&
|
|
268
|
+
isCanonicalIsoTimestamp(value.enqueuedAt));
|
|
269
|
+
};
|
|
160
270
|
/** Validates an immutable analyzer output manifest and its exact input binding. */
|
|
161
271
|
export const isBillingAnalyzerOutputManifestV2 = (value) => {
|
|
162
272
|
if (!isRecord(value) ||
|
|
163
|
-
|
|
273
|
+
containsForbiddenBillingArtifactControlData(value, [
|
|
164
274
|
...allowedArtifactReferenceField(value, 'inputManifestPath'),
|
|
275
|
+
...allowedArtifactTraversalField(value, 'artifacts'),
|
|
165
276
|
...allowedDescriptorPaths(value.artifacts),
|
|
166
277
|
])) {
|
|
167
278
|
return false;
|
|
@@ -195,16 +306,16 @@ export const isBillingAnalyzerOutputManifestV2 = (value) => {
|
|
|
195
306
|
publicationDecisionReferencesDigest(value.publicationDecision, new Set([...outputDerivedDigests].filter(digest => digest !== value.inputManifestDigest)))) {
|
|
196
307
|
return false;
|
|
197
308
|
}
|
|
198
|
-
if (
|
|
309
|
+
if (value.artifacts.filter(artifact => artifact.name === 'metadata.json').length !== 1)
|
|
199
310
|
return false;
|
|
200
|
-
}
|
|
201
311
|
return (isBillingCompletedArtifactPublicationDecision(value.publicationDecision, value.generationId, value.inputManifestDigest) &&
|
|
202
312
|
isCanonicalIsoTimestamp(value.completedAt));
|
|
203
313
|
};
|
|
204
314
|
/** Validates the sole promoted authority pointer for completed billing analysis. */
|
|
205
315
|
export const isBillingAnalysisCurrentPointerV1 = (value) => {
|
|
206
316
|
if (!isRecord(value) ||
|
|
207
|
-
|
|
317
|
+
hasDiagnosticObservationDiscriminant(value) ||
|
|
318
|
+
containsForbiddenBillingArtifactControlData(value, [
|
|
208
319
|
...allowedArtifactReferenceField(value, 'inputManifestPath'),
|
|
209
320
|
...allowedArtifactReferenceField(value, 'outputManifestPath'),
|
|
210
321
|
])) {
|
|
@@ -227,3 +338,53 @@ export const isBillingAnalysisCurrentPointerV1 = (value) => {
|
|
|
227
338
|
return (isBillingCompletedArtifactPublicationDecision(value.publicationDecision, value.generationId, value.inputManifestDigest) &&
|
|
228
339
|
isCanonicalIsoTimestamp(value.completedAt));
|
|
229
340
|
};
|
|
341
|
+
/** Validates an immutable diagnostic-only promotion evaluation. */
|
|
342
|
+
export const isBillingAnalysisPromotionObservationV1 = (value) => {
|
|
343
|
+
if (!isRecord(value) ||
|
|
344
|
+
containsForbiddenBillingArtifactControlData(value, [
|
|
345
|
+
...allowedArtifactReferenceField(value, 'inputManifestPath'),
|
|
346
|
+
...allowedArtifactReferenceField(value, 'outputManifestPath'),
|
|
347
|
+
])) {
|
|
348
|
+
return false;
|
|
349
|
+
}
|
|
350
|
+
if (value.schemaVersion !== 1 ||
|
|
351
|
+
value.documentType !== 'billing-analysis-promotion-observation' ||
|
|
352
|
+
value.authority !== 'diagnostic-only' ||
|
|
353
|
+
value.publicationMode !== 'observe' ||
|
|
354
|
+
value.processingState !== 'succeeded') {
|
|
355
|
+
return false;
|
|
356
|
+
}
|
|
357
|
+
if (!hasMatchingIdentity(value.subscriptionId, value.generationId, value.ownership, value.revision, false))
|
|
358
|
+
return false;
|
|
359
|
+
if (!isStrictLogicalArtifactReference(value.inputManifestPath) ||
|
|
360
|
+
value.inputManifestPath !== inputManifestPath(value.subscriptionId, value.generationId) ||
|
|
361
|
+
!isStrictLogicalArtifactReference(value.outputManifestPath) ||
|
|
362
|
+
value.outputManifestPath !== outputManifestPath(value.subscriptionId, value.generationId)) {
|
|
363
|
+
return false;
|
|
364
|
+
}
|
|
365
|
+
if (!isSha256(value.inputManifestDigest) ||
|
|
366
|
+
!isSha256(value.outputManifestDigest) ||
|
|
367
|
+
!isSha256(value.observationDigest) ||
|
|
368
|
+
!isSha256(value.messageId) ||
|
|
369
|
+
!isNonEmptyString(value.correlationId) ||
|
|
370
|
+
!isCanonicalIsoTimestamp(value.observedAt) ||
|
|
371
|
+
!isRecord(value.evaluation) ||
|
|
372
|
+
!isStringIn(value.evaluation.comparison, OBSERVATION_COMPARISONS)) {
|
|
373
|
+
return false;
|
|
374
|
+
}
|
|
375
|
+
const hasOwnershipEpoch = value.ownership.ownershipEpochRevision !== undefined;
|
|
376
|
+
const outputDigestRelation = value.evaluation.outputDigestRelation;
|
|
377
|
+
if (outputDigestRelation !== undefined && outputDigestRelation !== 'same' && outputDigestRelation !== 'different')
|
|
378
|
+
return false;
|
|
379
|
+
if (!hasOwnershipEpoch) {
|
|
380
|
+
return (outputDigestRelation === undefined && value.evaluation.comparison === 'unenforceable' && value.evaluation.projectedOutcome === 'not-enforceable');
|
|
381
|
+
}
|
|
382
|
+
if (value.evaluation.comparison === 'equal') {
|
|
383
|
+
return outputDigestRelation === 'different'
|
|
384
|
+
? value.evaluation.projectedOutcome === 'would-quarantine'
|
|
385
|
+
: value.evaluation.projectedOutcome === 'would-be-idempotent';
|
|
386
|
+
}
|
|
387
|
+
return (outputDigestRelation === undefined &&
|
|
388
|
+
value.evaluation.comparison !== 'unenforceable' &&
|
|
389
|
+
OBSERVATION_PROJECTED_OUTCOMES.get(value.evaluation.comparison) === value.evaluation.projectedOutcome);
|
|
390
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* V1 billing artifact object limits in bytes.
|
|
3
|
+
*
|
|
4
|
+
* `StoredBytes` limits apply to the exact persisted object before content
|
|
5
|
+
* decoding. `DecodedBytes` limits apply after decoding or decompression.
|
|
6
|
+
*/
|
|
7
|
+
export const BILLING_ARTIFACT_OBJECT_LIMITS_V1 = Object.freeze({
|
|
8
|
+
pointerStoredBytes: 64 * 1024,
|
|
9
|
+
observationStoredBytes: 64 * 1024,
|
|
10
|
+
manifestStoredBytes: 1024 * 1024,
|
|
11
|
+
metadataStoredBytes: 4 * 1024 * 1024,
|
|
12
|
+
metadataDecodedBytes: 16 * 1024 * 1024,
|
|
13
|
+
plotStoredBytes: 32 * 1024 * 1024,
|
|
14
|
+
plotDecodedBytes: 128 * 1024 * 1024,
|
|
15
|
+
inputObjectStoredBytes: 32 * 1024 * 1024,
|
|
16
|
+
inputObjectDecodedBytes: 128 * 1024 * 1024,
|
|
17
|
+
maxInputObjects: 12,
|
|
18
|
+
});
|