@floegence/redevplugin-contracts 2.0.10 → 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.
@@ -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 releaseMetadataSchemaVersionV8 = "redevplugin.release_metadata.v8";
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.v1";
7
- export const revocationSchemaVersion = "redevplugin.release_revocation.v2";
8
- export const revocationPointerSchemaVersion = "redevplugin.release_revocation_pointer.v1";
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 legacyIDPattern = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
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 legacySHA256Pattern = /^(?:sha256:)?[0-9a-f]{64}$/;
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 : legacyIDPattern;
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(legacyIDPattern, value.publisher_id) || !matchesPattern(legacyIDPattern, value.plugin_id) || !matchesPattern(semverPattern, value.version))
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 (!validReleaseMetadataUIProtocolPair(value.schema_version, value.compatibility.ui_protocol_version) || !matchesPattern(newIDPattern, value.source_id))
349
+ if (value.schema_version !== releaseMetadataSchemaVersion || !matchesPattern(newIDPattern, value.source_id))
351
350
  invalidDocument();
352
- if (!matchesPattern(legacyIDPattern, value.publisher_id) || !matchesPattern(legacyIDPattern, value.plugin_id) || !matchesPattern(semverPattern, value.version) || !validArtifactRef(value.release_metadata_ref))
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 (!legacySHA256Pattern.test(value.hashes.package_sha256) || !legacySHA256Pattern.test(value.hashes.manifest_sha256) || !legacySHA256Pattern.test(value.hashes.entries_sha256))
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 && !legacySHA256Pattern.test(value.release_evidence.notices_sha256))
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 && !legacySHA256Pattern.test(value.release_evidence.provenance_sha256))
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(legacyIDPattern, revoked.publisher_id) || !matchesPattern(legacyIDPattern, revoked.plugin_id) || !matchesPattern(semverPattern, revoked.version) || !matchesPattern(sha256Pattern, revoked.release_metadata_sha256))
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", "compatibility"], ["host_requirements", "release_evidence", "metadata"]);
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": "2.0.10",
4
- "description": "Embedded ReDevPlugin machine contracts and canonical release-signing APIs",
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": {