Documentation
Using GRC Store
A short orientation for browsing, pulling, publishing, and verifying artifacts with grcli.
Browsing
The Search page lists every catalog the registry holds,
deduplicated to one row per (namespace, catalog_id) with the
latest non-yanked version as the representative. Filter by kind from the dropdown, or
search by title, summary, and author from the search box.
Each catalog page shows its full release history. Each release page surfaces the pull command, the manifest digest, and the layer + config blob.
The grcli CLI
grcli is the command-line client for grc.store — it validates,
publishes, pulls, and verifies Gemara bundles. It is also the only way to
publish: the registry accepts only pushes that carry their own provenance, so there is
no upload form. Build it from source (pre-built binaries will follow):
$git clone https://github.com/revanite-io/grcli && cd grcli && make build
Move ./bin/grcli onto your $PATH,
then sign in once. login runs the OIDC device flow — it prints
a URL and short code to authorize in any browser, then stores the token locally and
reuses it:
$grcli login grcli login targets this hub by default; pass
--url <hub> for a private deployment. From GitHub Actions
no login is needed — grcli uses the workflow's own OIDC token for secret-less trusted
publishing, once an org admin has registered the repository as a trusted publisher.
Pulling
Every artifact is a single-artifact Gemara OCI bundle, content-addressed by its
manifest digest. Pull and unpack a release with grcli — it
discovers the registry from the hub, mints the pull token reads require
(no login needed for public reads), and writes the artifact
file(s) plus a bundle.json (manifest + provenance) into
--output (default ./grcli-unpacked):
$grcli unpack --repository <namespace>/<catalog_id> --tag <version>
The exact command for a release is shown on its detail page with a copy button. The
OCI manifest is also reachable over HTTP at
GET /v1/catalogs/{namespace}/{catalog_id}/versions/{version}/manifest.
Publishing
Publishing is grcli-only — the registry accepts only pushes that carry their own provenance (signature + attestation), so there is no upload form. After signing in, validate the bundle locally, then publish it:
$grcli validate <bundle>.yaml $grcli publish <bundle>.yaml
grcli reads the version from the bundle's metadata.version,
signs and pushes it to the registry, and the hub indexes it. You may publish if EITHER
you hold the write:<Type> realm role for the artifact type
(granted across all namespaces by the gemara-writer composite),
OR you are a member of the publishing organization (org membership grants publish
authority to that namespace regardless of role). The two paths OR — a member of
finos-ccc can publish controls under
finos-ccc with or without a
write:ControlCatalog role.
The hub validates that metadata.author.id and
metadata.id match the URL coordinate, mints a registry token
scoped to the namespaces you own, stores the bundle content-addressed, and records the
manifest digest. Re-publishing the same body at the same version is idempotent;
publishing a different body at an existing version is rejected — versions are immutable,
so bump metadata.version per release. Every catalog page links
to a per-catalog publish helper with the exact commands.
Verifying
Bundles are signed at the registry layer with
Sigstore cosign; signatures live next to the
artifact in the registry, not in the bundle bytes. grcli verify
checks a remote release against either a public key or a keyless identity:
$grcli verify --registry <registry> --repository <namespace>/<catalog_id> --tag <version> --cosign-key <key>.pub
...or keyless, against the publisher's GitHub Actions workflow identity (the
(identity, issuer) pair the publisher shares):
$grcli verify --registry <registry> --repository <namespace>/<catalog_id> --tag <version> --certificate-identity <workflow-url> --certificate-oidc-issuer https://token.actions.githubusercontent.com Yanking
Only the gemara-admin realm role can yank a version
(ADR-0019's writer-cannot-tombstone invariant — namespace members and
write:<Type> holders can publish but cannot retract).
The underlying manifest stays in the registry, but subsequent fetches for the body
return a "tombstoned" response so consumers know not to rely on it. Yanking does not
delete content; it signals "do not use."