@floegence/redevplugin-contracts 2.0.9 → 3.0.0
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 +8 -7
- package/dist/index.d.ts +0 -273
- package/dist/index.js +0 -32
- package/dist/release-signing.d.ts +33 -58
- package/dist/release-signing.js +15 -75
- package/package.json +2 -2
- package/dist/contracts.gen.d.ts +0 -535
- package/dist/contracts.gen.js +0 -634
package/dist/release-signing.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
export const rootDelegationSchemaVersion = "redevplugin.release_root_delegation.v1";
|
|
2
2
|
export const packageSignatureSchemaVersion = "redevplugin.package_signature.v1";
|
|
3
|
-
export const
|
|
4
|
-
export const releaseMetadataSchemaVersion = releaseMetadataSchemaVersionV8;
|
|
3
|
+
export const releaseMetadataSchemaVersion = "redevplugin.release_metadata";
|
|
5
4
|
export const sourcePolicySchemaVersion = "redevplugin.release_source_policy.v3";
|
|
6
|
-
export const sourcePolicyPointerSchemaVersion = "redevplugin.release_source_policy_pointer.
|
|
7
|
-
export const revocationSchemaVersion = "redevplugin.release_revocation.
|
|
8
|
-
export const revocationPointerSchemaVersion = "redevplugin.release_revocation_pointer.
|
|
5
|
+
export const sourcePolicyPointerSchemaVersion = "redevplugin.release_source_policy_pointer.v2";
|
|
6
|
+
export const revocationSchemaVersion = "redevplugin.release_revocation.v3";
|
|
7
|
+
export const revocationPointerSchemaVersion = "redevplugin.release_revocation_pointer.v2";
|
|
9
8
|
export const signatureAlgorithmEd25519 = "ed25519";
|
|
10
9
|
export const genesisPreviousDocumentSHA256 = "0".repeat(64);
|
|
11
10
|
export const signingUsages = {
|
|
@@ -41,12 +40,12 @@ const maximumDocumentBytes = 1024 * 1024;
|
|
|
41
40
|
const maximumPatternValueCodeUnits = 4096;
|
|
42
41
|
const signingPrefix = textEncoder.encode("REDEVPLUGIN-SIGNING-V1\0");
|
|
43
42
|
const newIDPattern = /^[a-z][a-z0-9._-]{0,127}$/;
|
|
44
|
-
const
|
|
43
|
+
const releaseIDPattern = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
|
|
45
44
|
const epochPattern = /^(0|[1-9][0-9]*)$/;
|
|
46
45
|
const positiveEpochPattern = /^[1-9][0-9]*$/;
|
|
47
46
|
const sha256Pattern = /^[0-9a-f]{64}$/;
|
|
48
47
|
const prefixedSHA256Pattern = /^sha256:[0-9a-f]{64}$/;
|
|
49
|
-
const
|
|
48
|
+
const packageSHA256Pattern = /^(?:sha256:)?[0-9a-f]{64}$/;
|
|
50
49
|
const artifactRefPattern = /^[A-Za-z0-9._/@+-]+$/;
|
|
51
50
|
const hostnamePattern = /^[A-Za-z0-9](?:[A-Za-z0-9.-]*[A-Za-z0-9])?$/;
|
|
52
51
|
const semverPattern = { test: isCanonicalSemver };
|
|
@@ -259,7 +258,7 @@ function validateSortedIDs(values, minimum, maximum, lower = true) {
|
|
|
259
258
|
if (!Array.isArray(values) || values.length < minimum || values.length > maximum)
|
|
260
259
|
invalidDocument();
|
|
261
260
|
let previous = "";
|
|
262
|
-
const pattern = lower ? newIDPattern :
|
|
261
|
+
const pattern = lower ? newIDPattern : releaseIDPattern;
|
|
263
262
|
for (const value of values) {
|
|
264
263
|
if (!matchesPattern(pattern, value) || compareUTF8(value, previous) <= 0)
|
|
265
264
|
invalidDocument();
|
|
@@ -312,7 +311,7 @@ function validatePackageInput(value) {
|
|
|
312
311
|
exactKeys(value, ["source_id", "channel", "version", "algorithm", "key_id", "publisher_id", "plugin_id", "package_hash", "manifest_hash", "entries_hash", "signed_at"]);
|
|
313
312
|
if (!matchesPattern(newIDPattern, value.source_id) || !matchesPattern(newIDPattern, value.channel) || value.algorithm !== signatureAlgorithmEd25519 || !matchesPattern(newIDPattern, value.key_id))
|
|
314
313
|
invalidDocument();
|
|
315
|
-
if (!matchesPattern(
|
|
314
|
+
if (!matchesPattern(releaseIDPattern, value.publisher_id) || !matchesPattern(releaseIDPattern, value.plugin_id) || !matchesPattern(semverPattern, value.version))
|
|
316
315
|
invalidDocument();
|
|
317
316
|
if (!matchesPattern(prefixedSHA256Pattern, value.package_hash) || !matchesPattern(prefixedSHA256Pattern, value.manifest_hash) || !matchesPattern(prefixedSHA256Pattern, value.entries_hash))
|
|
318
317
|
invalidDocument();
|
|
@@ -347,13 +346,13 @@ function validatePackageSignature(context, value, requireSignature) {
|
|
|
347
346
|
function validateReleaseMetadata(value) {
|
|
348
347
|
assertRecord(value);
|
|
349
348
|
closeReleaseMetadata(value);
|
|
350
|
-
if (
|
|
349
|
+
if (value.schema_version !== releaseMetadataSchemaVersion || !matchesPattern(newIDPattern, value.source_id))
|
|
351
350
|
invalidDocument();
|
|
352
|
-
if (!matchesPattern(
|
|
351
|
+
if (!matchesPattern(releaseIDPattern, value.publisher_id) || !matchesPattern(releaseIDPattern, value.plugin_id) || !matchesPattern(semverPattern, value.version) || !validArtifactRef(value.release_metadata_ref))
|
|
353
352
|
invalidDocument();
|
|
354
353
|
if ((value.distribution_ref.distribution !== "registry_ref" && value.distribution_ref.distribution !== "host_artifact_ref") || !validArtifactRef(value.distribution_ref.artifact_ref))
|
|
355
354
|
invalidDocument();
|
|
356
|
-
if (!
|
|
355
|
+
if (!packageSHA256Pattern.test(value.hashes.package_sha256) || !packageSHA256Pattern.test(value.hashes.manifest_sha256) || !packageSHA256Pattern.test(value.hashes.entries_sha256))
|
|
357
356
|
invalidDocument();
|
|
358
357
|
const metadataSignature = value.release_metadata_signature;
|
|
359
358
|
if (metadataSignature.algorithm !== signatureAlgorithmEd25519 || !matchesPattern(newIDPattern, metadataSignature.key_id) || !validArtifactRef(metadataSignature.signature_ref) || !matchesPattern(epochPattern, metadataSignature.source_policy_epoch) || !matchesPattern(epochPattern, metadataSignature.revocation_epoch))
|
|
@@ -361,41 +360,10 @@ function validateReleaseMetadata(value) {
|
|
|
361
360
|
const packageSignature = value.package_signature;
|
|
362
361
|
if (packageSignature.algorithm !== signatureAlgorithmEd25519 || !matchesPattern(newIDPattern, packageSignature.key_id) || !validArtifactRef(packageSignature.signature_bundle_ref) || !matchesPattern(epochPattern, packageSignature.source_policy_epoch) || !matchesPattern(epochPattern, packageSignature.revocation_epoch))
|
|
363
362
|
invalidDocument();
|
|
364
|
-
if (!matchesPattern(semverPattern, value.compatibility.min_redevplugin_version) || !matchesPattern(semverPattern, value.compatibility.min_runtime_version))
|
|
365
|
-
invalidDocument();
|
|
366
|
-
if (value.compatibility.supported_targets !== undefined) {
|
|
367
|
-
if (!Array.isArray(value.compatibility.supported_targets))
|
|
368
|
-
invalidDocument();
|
|
369
|
-
const allowed = new Set(["darwin/amd64", "darwin/arm64", "linux/amd64", "linux/arm64"]);
|
|
370
|
-
let previous = "";
|
|
371
|
-
for (const target of value.compatibility.supported_targets) {
|
|
372
|
-
if (typeof target !== "string" || !allowed.has(target) || compareUTF8(target, previous) <= 0)
|
|
373
|
-
invalidDocument();
|
|
374
|
-
previous = target;
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
let previousHost = "";
|
|
378
|
-
for (const requirement of value.host_requirements ?? []) {
|
|
379
|
-
if (!matchesPattern(legacyIDPattern, requirement.host_id) || compareUTF8(requirement.host_id, previousHost) <= 0)
|
|
380
|
-
invalidDocument();
|
|
381
|
-
if (requirement.min_host_version !== undefined && !matchesPattern(semverPattern, requirement.min_host_version))
|
|
382
|
-
invalidDocument();
|
|
383
|
-
let previousCapability = "";
|
|
384
|
-
for (const capability of requirement.required_capability_contracts ?? []) {
|
|
385
|
-
if (!matchesPattern(legacyIDPattern, capability.capability_id) || !matchesPattern(semverPattern, capability.capability_version))
|
|
386
|
-
invalidDocument();
|
|
387
|
-
const identity = `${capability.capability_id}\0${capability.capability_version}`;
|
|
388
|
-
if (compareUTF8(identity, previousCapability) <= 0)
|
|
389
|
-
invalidDocument();
|
|
390
|
-
validateCapabilityContractRef(capability.contract);
|
|
391
|
-
previousCapability = identity;
|
|
392
|
-
}
|
|
393
|
-
previousHost = requirement.host_id;
|
|
394
|
-
}
|
|
395
363
|
if (value.release_evidence !== undefined) {
|
|
396
|
-
if (value.release_evidence.notices_sha256 !== undefined && !
|
|
364
|
+
if (value.release_evidence.notices_sha256 !== undefined && !packageSHA256Pattern.test(value.release_evidence.notices_sha256))
|
|
397
365
|
invalidDocument();
|
|
398
|
-
if (value.release_evidence.provenance_sha256 !== undefined && !
|
|
366
|
+
if (value.release_evidence.provenance_sha256 !== undefined && !packageSHA256Pattern.test(value.release_evidence.provenance_sha256))
|
|
399
367
|
invalidDocument();
|
|
400
368
|
if (value.release_evidence.generated_at !== undefined)
|
|
401
369
|
parseCanonicalTime(value.release_evidence.generated_at);
|
|
@@ -412,14 +380,6 @@ function validateReleaseMetadata(value) {
|
|
|
412
380
|
invalidDocument();
|
|
413
381
|
}
|
|
414
382
|
}
|
|
415
|
-
function validReleaseMetadataUIProtocolPair(schemaVersion, uiProtocolVersion) {
|
|
416
|
-
return schemaVersion === releaseMetadataSchemaVersionV8 && uiProtocolVersion === "plugin-ui-v7";
|
|
417
|
-
}
|
|
418
|
-
function validateCapabilityContractRef(value) {
|
|
419
|
-
if (![value.publisher_id, value.contract_id].every((item) => matchesPattern(legacyIDPattern, item)) ||
|
|
420
|
-
!matchesPattern(semverPattern, value.contract_version) || !sha256Pattern.test(value.artifact_sha256))
|
|
421
|
-
invalidDocument();
|
|
422
|
-
}
|
|
423
383
|
function validateSourcePolicy(value, requireSignature) {
|
|
424
384
|
assertRecord(value);
|
|
425
385
|
closeSourcePolicy(value);
|
|
@@ -494,7 +454,7 @@ function validateRevocation(value, requireSignature) {
|
|
|
494
454
|
invalidDocument();
|
|
495
455
|
let previous = "";
|
|
496
456
|
for (const revoked of value.revoked_releases) {
|
|
497
|
-
if (!matchesPattern(
|
|
457
|
+
if (!matchesPattern(releaseIDPattern, revoked.publisher_id) || !matchesPattern(releaseIDPattern, revoked.plugin_id) || !matchesPattern(semverPattern, revoked.version) || !matchesPattern(sha256Pattern, revoked.release_metadata_sha256))
|
|
498
458
|
invalidDocument();
|
|
499
459
|
const identity = `${revoked.publisher_id}\0${revoked.plugin_id}\0${revoked.version}\0${revoked.release_metadata_sha256}`;
|
|
500
460
|
if (compareUTF8(identity, previous) <= 0)
|
|
@@ -546,7 +506,7 @@ function closePackageSignature(value) {
|
|
|
546
506
|
exactOptionalKeys(value, ["schema_version", "algorithm", "key_id", "package_hash", "manifest_hash", "entries_hash", "signature"], ["publisher_id", "plugin_id", "signed_at"]);
|
|
547
507
|
}
|
|
548
508
|
function closeReleaseMetadata(value) {
|
|
549
|
-
exactOptionalKeys(value, ["schema_version", "source_id", "release_metadata_ref", "publisher_id", "plugin_id", "version", "distribution_ref", "hashes", "release_metadata_signature", "package_signature"
|
|
509
|
+
exactOptionalKeys(value, ["schema_version", "source_id", "release_metadata_ref", "publisher_id", "plugin_id", "version", "distribution_ref", "hashes", "release_metadata_signature", "package_signature"], ["release_evidence", "metadata"]);
|
|
550
510
|
for (const [key, keys] of [
|
|
551
511
|
["distribution_ref", ["distribution", "artifact_ref"]],
|
|
552
512
|
["hashes", ["package_sha256", "manifest_sha256", "entries_sha256"]],
|
|
@@ -556,26 +516,6 @@ function closeReleaseMetadata(value) {
|
|
|
556
516
|
assertRecord(value[key]);
|
|
557
517
|
exactKeys(value[key], keys);
|
|
558
518
|
}
|
|
559
|
-
assertRecord(value.compatibility);
|
|
560
|
-
exactOptionalKeys(value.compatibility, ["min_redevplugin_version", "min_runtime_version", "ui_protocol_version"], ["supported_targets"]);
|
|
561
|
-
if (value.host_requirements !== undefined) {
|
|
562
|
-
if (!Array.isArray(value.host_requirements))
|
|
563
|
-
invalidDocument();
|
|
564
|
-
for (const host of value.host_requirements) {
|
|
565
|
-
assertRecord(host);
|
|
566
|
-
exactOptionalKeys(host, ["host_id"], ["min_host_version", "required_capability_contracts"]);
|
|
567
|
-
if (host.required_capability_contracts !== undefined) {
|
|
568
|
-
if (!Array.isArray(host.required_capability_contracts))
|
|
569
|
-
invalidDocument();
|
|
570
|
-
for (const requirement of host.required_capability_contracts) {
|
|
571
|
-
assertRecord(requirement);
|
|
572
|
-
exactKeys(requirement, ["capability_id", "capability_version", "contract"]);
|
|
573
|
-
assertRecord(requirement.contract);
|
|
574
|
-
exactKeys(requirement.contract, ["publisher_id", "contract_id", "contract_version", "artifact_sha256"]);
|
|
575
|
-
}
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
519
|
if (value.release_evidence !== undefined) {
|
|
580
520
|
assertRecord(value.release_evidence);
|
|
581
521
|
exactOptionalKeys(value.release_evidence, [], ["notices_sha256", "provenance_sha256", "generated_at"]);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@floegence/redevplugin-contracts",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
|
+
"description": "Canonical ReDevPlugin release-signing and presentation-evidence APIs",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"repository": {
|