MacCrabRave
Documentation

Catalog JSON API

Signed catalog resources, verification, and current compatibility constraints

Rave publishes a static catalog index, per-plugin entries, and a revocation list. Each of those JSON documents has a detached Ed25519 signature. Release archives have their own publisher signature inside the bundle. Public keys, schemas, and website pages are not themselves covered by those document signatures.

Base URL

https://rave.maccrab.com/

The CLI’s explicit --catalog-base option changes the metadata transport base. It does not change the pinned key or rewrite artifact URLs inside signed entries. The current entry schema requires release URLs at https://rave.maccrab.com/; a complete enterprise mirror is planned.

Resource map

PathPurposeFormat
/catalog.jsonPlugin indexCatalog schema
/catalog.json.sigIndex signatureRaw 64-byte Ed25519 signature
/catalog/<id>.jsonPer-plugin versions, vetting, and digestsEntry schema
/catalog/<id>.json.sigEntry signatureRaw 64-byte Ed25519 signature
/revocations.jsonPlugin version revocations and serialRevocation schema
/revocations.json.sigRevocation-list signatureRaw 64-byte Ed25519 signature
/keys/catalog.pubPublished catalog public keyRaw 32-byte key
/keys/catalog.fingerprintPublic-key SHA-256Hex string
/releases/<tag>/<id>.maccrabplugin.zipPublished plugin archiveFlat plugin directory in ZIP
/schemas/<name>.jsonSchema definitionsJSON Schema 2020-12
/kits/<id>.json, .json.sigPlanned kit definitions/signaturesKit schema; none published

See current status for the available version and its limitations. Resource definitions for kits do not imply available kit installation.

Signature verification

Catalog document signatures cover their exact file bytes, with no JSON normalization or envelope. Load a trusted catalog key before fetching metadata:

from pathlib import Path
from urllib.request import urlopen
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey

# catalog.pub must already come from an authenticated distribution or
# have a fingerprint confirmed through a separately authenticated source.
key = Ed25519PublicKey.from_public_bytes(Path("catalog.pub").read_bytes())
base = "https://rave.maccrab.com/"
with urlopen(base + "catalog.json", timeout=30) as response:
    catalog = response.read()
with urlopen(base + "catalog.json.sig", timeout=30) as response:
    signature = response.read()
key.verify(signature, catalog)

This illustrates the signature primitive, not a complete network client. Production clients also need bounded responses, URL/redirect policy, schema validation, rollback state, compatibility checks, and revocation handling. Fetching a key and its fingerprint from the metadata origin alone does not independently establish that origin’s identity.

The same primitive verifies each signed entry and revocation list. The archive’s publisher signature uses a different signed payload and key. See verification for a worked archive example and the distinction between content integrity, publisher trust, and runtime admission.

Index and entry facts

The current index uses schema_version: "1", a catalog_serial, a generation timestamp, and a plugins object keyed by plugin ID. Each summary carries display and compatibility metadata, current version, channel, trust tier, runtime token, and publisher-key fingerprint. Detail consumers fetch the corresponding signed entry.

The wire value runtime: "tierB" identifies the external plugin format. It does not establish App Sandbox or no-network enforcement. Published MacCrab v1.21.5 executes first-party plugins unsandboxed after Developer ID and host-team validation, with the host’s privileges including granted Full Disk Access. UIs must describe the actual execution path, separately from requested/declared behavior.

FieldMeaning and limits
idPlugin identity; must agree with the entry path and manifest.
schema_versionRequired on the index. Optional in the current entry schema and absent from the current signed Posture Pro entry. Missing historical facts should remain “not recorded.”
signer_identityHuman-readable publisher label; not sufficient for key trust.
signer_public_key_sha256SHA-256 of the publisher’s raw 32-byte Ed25519 key, endorsed by verified catalog metadata.
current_versionDefault version selected from the entry’s version records.
versions.<v>.tagRecorded release tag used in URL construction.
versions.<v>.source_commitRecorded source revision; an accessible source and exact rebuild are still required for independent reproducibility.
versions.<v>.artifact_sha256Raw archive SHA-256.
versions.<v>.manifest_sha256Exact manifest-byte SHA-256.
versions.<v>.signature_sha256Raw publisher-signature file SHA-256.
versions.<v>.canonical_tree_sha256Normalized archive digest. A match alone does not prove a source rebuild.
versions.<v>.reproducibilityverified or not_applicable; distinguish absent historical values. Posture Pro 0.3.1 records not_applicable.
versions.<v>.vettingRecorded check labels, policy commit, and version-specific vetted_at timestamp.
release_url_templateURL template with {tag} and {file}; current schema pins the official origin.
metadata.min_maccrab_versionEntry-wide minimum app version; enforced on installation.
metadata.max_maccrab_version, metadata.min_macosDeclared compatibility fields; current clients do not enforce every field, including the OS floor. Do not rely on an ignored field to exclude unsupported hosts.
statusactive, pre-release, unreachable_temporary, unreachable_extended, archived, or revoked.

The current contract has no per-version compatibility fields or architecture restriction. MacCrab supports Intel, but Posture Pro 0.3.1’s published archive is arm64-only. Supporting a future archive requires both compatible client admission and qualification of the actual host/artifact combination.

Install resolution

A complete installation must:

  1. Fetch and verify the index and per-plugin entry against the trusted catalog key, enforcing rollback and publication state.
  2. Resolve the requested ID/version, check applicable compatibility and publisher trust, and fetch/verify current revocations.
  3. Reject a matching exact-version, all-versions, or inclusive version-range revocation.
  4. Expand release_url_template using the selected record’s tag and <plugin-id>.maccrabplugin.zip.
  5. Apply the client’s download-origin/redirect policy and verify the raw archive digest.
  6. Validate the extracted bundle, manifest identity, pinned publisher key, and signature before committing the install.

The app’s install link carries only a plugin ID and still requires confirmation; see the URL contract. Current app capability descriptions are not yet derived from the exact version’s manifest, so the listing’s access disclosures remain important.

Revocation and freshness

The index’s catalog_serial and revocation list’s serial are signed monotonic counters. A client with recorded serial N rejects a subsequently fetched valid document whose serial is lower than N. Publication must advance the relevant counter when signed state changes.

Serial checks protect against rollback relative to recorded history. They do not prove the first document received is current. Likewise, a successful fetch today does not establish a recent signed issue date. The current app’s revocation freshness display tracks fetch time; do not describe it as signed expiry enforcement.

Development rehearsals and schema changes

Local catalog-key overrides, loopback transport, and release-URL rewrites are development seams. They are not supported production trust-configuration instructions and must not be presented as an enterprise deployment procedure.

Current schemas use additionalProperties: false; new fields are not automatically compatible with all validators or readers. Schema, generator, verifier, and client changes must be introduced together with tested compatibility behavior. New required constraints need supporting readers and a published enforcing host before dependent plugins are activated. A future format path or expiry policy is a design decision, not an already implemented guarantee.