# Sigstore Rekor

> Look up software signatures in Sigstore's public transparency log: who signed a release, from which repository and commit, and prove the record is really there.

App · Compliance & Security · 8 actions. Web page: https://docs.lodol.com/docs/integrations/sigstore-rekor

## Actions

### Check the log has not been rewritten

Prove that everything published before some earlier moment is still in the log, unchanged and in the same order. Paste the checkpoint that an earlier run of 'Get the log's current state' returned; this fetches the proof joining that moment to now and recomputes it. A transparency log is only trustworthy because somebody checks this, and almost nobody does - run it on a schedule and keep the newest checkpoint each time. No account or API key required.

**Inputs**

- Saved checkpoint (`checkpoint`, text, required): The block of text an earlier run of "Get the log's current state" returned as its checkpoint. Paste it whole - the log it came from, its size, its root hash and the signature. Everything needed is inside it, so there is nothing else to fill in.

**Outputs**

- `checked_at` (text): When this ran, ISO 8601 in UTC
- `entries_added` (number): How many were appended in between
- `entries_now` (number): How many that tree holds now
- `entries_then` (number): How many entries the checkpoint recorded
- `log_url` (text): The log that answered
- `message` (text): The verdict in one line
- `proof_hashes` (number): How many hashes the proof held
- `root_hash_then` (text): The root hash the checkpoint recorded
- `shard_frozen` (true/false): Whether that tree has since been retired, in which case it can no longer grow at all
- `shard_tree_id` (text): Which of the log's trees it described
- `verified` (true/false): True when the log still contains, unchanged, everything it held at the saved checkpoint

**Example output**

```json
{
  "checked_at": "2026-09-14T00:43:58Z",
  "entries_added": 113634,
  "entries_now": 2701923494,
  "entries_then": 2701809860,
  "log_url": "https://rekor.sigstore.dev",
  "message": "Verified. The log has grown from 2,701,809,860 to 2,701,923,494 entries and everything published before your checkpoint is still there, unchanged - 113,634 entries were appended and nothing was rewritten.",
  "proof_hashes": 17,
  "root_hash_then": "b93fcbb530ccd202c74548fba623233db63473b51c1df4b4d86e85eb1c3a936c",
  "shard_frozen": false,
  "shard_tree_id": "1193050959916656506",
  "verified": true
}
```

### Find an artifact by its checksum

Check whether a file has been signed, and by whom. Paste its SHA-256 - the output of 'shasum -a 256', or the digest out of a container image reference - and this returns every entry in the public Sigstore log that signs it or attests to it, each one decoded down to who signed it, when, and for a build, which repository and commit it came from. Nothing found means the file was never signed with Sigstore, which is an answer worth having. No account or API key required.

**Inputs**

- Checksum (`checksum`, text, required): The SHA-256 of the file, as 64 hexadecimal characters. SHA-1 and SHA-512 work too, and the 'sha256:' prefix is optional - paste the digest however you have it.
- How many to return (`limit`, number): How many entries to return. Most artifacts have one or two; a widely mirrored release can have more. From 1 to 50. Default: `10`.

**Outputs**

- `algorithm` (text): Which hash the checksum turned out to be
- `digest` (text): The checksum, lowercased
- `entries` (list): The matching entries, newest first
- `found` (true/false): Whether anything matched
- `log_url` (text): The log that answered
- `match_count` (number): How many entries matched in total, before the limit
- `matched_on` (text): Which field was searched
- `ordering_note` (text): That caveat spelled out, or empty when everything came back
- `returned` (number): How many came back
- `sampled` (true/false): True when more matched than were returned. The log's search returns matches in no particular order, so what came back is a sample rather than the newest
- `searched_for` (text): The value as it was sent, after normalising
- `signers` (list): Everyone who signed it, without repeats

**Example output**

```json
{
  "algorithm": "sha256",
  "digest": "20ac9dda4f46161dbfec1e395ac0eedec7ae323106aafc6a5bf766eb763fe41c",
  "entries": [
    {
      "artifact_digest": "sha256:20ac9dda4f46161dbfec1e395ac0eedec7ae323106aafc6a5bf766eb763fe41c",
      "entry_id": "108e9186e8c5677aad33982fe2e968181b0527564df04e1d536ec0570791870a70bb8074dd8f78b9",
      "identity_kind": "email",
      "integrated_at": "2025-10-28T06:44:33Z",
      "issuer": "https://accounts.google.com",
      "issuer_name": "Google",
      "kind": "hashedrekord",
      "kind_label": "Artifact signature",
      "log_index": 647892280,
      "shard_tree_id": "1193050959916656506",
      "signed_by": "release@example.com",
      "signer_count": 1,
      "summary": "release@example.com, vouched for by Google",
      "url": "https://search.sigstore.dev/?uuid=108e9186e8c5677aad33982fe2e968181b0527564df04e1d536ec0570791870a70bb8074dd8f78b9",
      "what_was_signed": "an artifact with digest sha256:20ac9dda4f46161dbfec1e395ac0eedec7ae323106aafc6a5bf766eb763fe41c"
    }
  ],
  "found": true,
  "log_url": "https://rekor.sigstore.dev",
  "match_count": 1,
  "matched_on": "checksum",
  "ordering_note": "",
  "returned": 1,
  "sampled": false,
  "searched_for": "sha256:20ac9dda4f46161dbfec1e395ac0eedec7ae323106aafc6a5bf766eb763fe41c",
  "signers": [
    "release@example.com"
  ]
}
```

### Find what a signer has published

See everything one identity has signed. That identity is either an email address, for a person who signed interactively, or the identity URL of a build workflow - the form GitHub Actions uses, ending in the git ref the build ran on. Useful for watching a release pipeline: run it on a schedule and you will see what your own workflow published, and anything published in its name that you did not expect. No account or API key required.

**Inputs**

- Signer (`identity`, text, required): The email address, or the workflow identity URL. Matched exactly and in full, because that is all the log's index can do - a workflow identity has to include the '@' and the git ref at the end of it. Every entry this integration returns carries the identity that signed it under 'signed_by', in exactly the form this field wants.
- How many to return (`limit`, number): How many entries to return. A busy workflow can have tens of thousands in the log, and the log's search returns them in no particular order, so a larger number gives a bigger sample rather than a more recent one - the result always says how many matched in total. From 1 to 50. Default: `10`.

**Outputs**

- `entries` (list): The matching entries, newest first
- `found` (true/false): Whether anything matched
- `identity` (text): The identity that was searched for
- `identity_kind` (text): 'email' or 'identity' - which of the log's two index fields the search used
- `log_url` (text): The log that answered
- `match_count` (number): How many entries matched in total, before the limit
- `matched_on` (text): Which field was searched
- `normalised` (true/false): Whether the value was tidied before searching, such as a trailing slash removed
- `ordering_note` (text): That caveat spelled out, or empty when everything came back
- `returned` (number): How many came back
- `sampled` (true/false): True when more matched than were returned. The log's search returns matches in no particular order, so what came back is a sample rather than the newest
- `searched_for` (text): The value as it was sent, after normalising

**Example output**

```json
{
  "entries": [
    {
      "entry_id": "108e9186e8c5677afe975549c9911f1a66c3e0fe6019269f09621eb1c2621e9f73f98f696f81c3cf",
      "identity_kind": "workflow",
      "integrated_at": "2026-06-21T05:53:51Z",
      "issuer": "https://token.actions.githubusercontent.com",
      "issuer_name": "GitHub Actions",
      "kind": "dsse",
      "kind_label": "DSSE envelope",
      "log_index": 1892581158,
      "shard_tree_id": "1193050959916656506",
      "signed_by": "https://github.com/slsa-framework/slsa-github-generator/.github/workflows/builder_go_slsa3.yml@refs/tags/v2.0.0",
      "signer_count": 1,
      "summary": "builder_go_slsa3.yml in slsa-framework/slsa-github-generator (tag v2.0.0), vouched for by GitHub Actions",
      "url": "https://search.sigstore.dev/?uuid=108e9186e8c5677afe975549c9911f1a66c3e0fe6019269f09621eb1c2621e9f73f98f696f81c3cf",
      "what_was_signed": "a DSSE envelope whose payload hashes to sha256:a68e7e8299219fa3e7f97c900f363803bbd32acb8aa2df1cac1b46632e15a58b"
    }
  ],
  "found": true,
  "identity": "https://github.com/slsa-framework/slsa-github-generator/.github/workflows/builder_go_slsa3.yml@refs/tags/v2.0.0",
  "identity_kind": "identity",
  "log_url": "https://rekor.sigstore.dev",
  "match_count": 18413,
  "matched_on": "identity",
  "normalised": false,
  "ordering_note": "The log's search returns matches in no particular order, so these 1 are a sample of the 18413 that matched, not the most recent.",
  "returned": 1,
  "sampled": true,
  "searched_for": "https://github.com/slsa-framework/slsa-github-generator/.github/workflows/builder_go_slsa3.yml@refs/tags/v2.0.0"
}
```

### Find what a signing key has published

See everything signed with one key, for projects that sign with their own key rather than with a Sigstore identity - PGP releases, SSH-signed tags, minisign, and packages from Alpine and RPM. Paste the public key and say which kind it is. Entries signed this way record that the key signed, not who holds it, which is the difference between key signing and Sigstore's keyless signing. No account or API key required.

**Inputs**

- Public key (`public_key`, text, required): The public key itself, pasted whole. Whatever the project publishes: a PGP block, a line from an authorized_keys file, a PEM certificate, or the contents of a minisign .pub file.
- Key format (`key_format`, text, required): What kind of key it is. The log indexes each format separately, so this has to match what the key actually is. One of: `pgp` (PGP - an armoured block beginning BEGIN PGP PUBLIC KEY), `x509` (X.509 - a PEM certificate or public key), `ssh` (SSH - a line beginning ssh-ed25519, ssh-rsa or similar), `minisign` (minisign - the contents of a .pub file), `tuf` (TUF - a key from a TUF root). Default: `pgp`.
- How many to return (`limit`, number): How many entries to return. A key used by a package repository can have thousands in the log. From 1 to 50. Default: `10`.

**Outputs**

- `entries` (list): The matching entries, newest first
- `found` (true/false): Whether anything matched
- `key_format` (text): The format that was searched
- `log_url` (text): The log that answered
- `match_count` (number): How many entries matched in total, before the limit
- `matched_on` (text): Which field was searched
- `ordering_note` (text): That caveat spelled out, or empty when everything came back
- `returned` (number): How many came back
- `sampled` (true/false): True when more matched than were returned. The log's search returns matches in no particular order, so what came back is a sample rather than the newest
- `searched_for` (text): The value as it was sent, after normalising

**Example output**

```json
{
  "entries": [],
  "found": true,
  "key_format": "pgp",
  "log_url": "https://rekor.sigstore.dev",
  "match_count": 0,
  "matched_on": "pgp public key",
  "ordering_note": "",
  "returned": 0,
  "sampled": false,
  "searched_for": "a pgp key"
}
```

### Get a log entry

Read one entry in full. Everything the log holds about it, decoded: what was signed, who signed it and who vouched for them, when the log accepted it, the whole signing certificate with the repository, commit, workflow run and runner behind it, and the entry's own record as the log stored it. Takes either the entry's identifier or its position in the log. No account or API key required.

**Inputs**

- Entry (`entry`, text, required): Which entry to read. Paste either its identifier - the long hexadecimal string Sigstore's tools and the search site call a UUID - or its position in the log, which is a plain number. Whichever you have works; there is no need to say which kind it is.

**Outputs**

- `entry` (object): The entry, or null when there is none
- `found` (true/false): Whether the log holds such an entry
- `log_url` (text): The log that answered
- `looked_up` (text): What was asked for
- `looked_up_by` (text): 'entry identifier' or 'log position' - which kind of value it turned out to be
- `message` (text): The entry in one line
- `raw_entry` (object): The record exactly as the log stored it, for a field this integration does not name by itself - a JAR's manifest, an RPM's headers, a TUF root

**Example output**

```json
{
  "entry": {
    "entry_id": "108e9186e8c5677afe975549c9911f1a66c3e0fe6019269f09621eb1c2621e9f73f98f696f81c3cf",
    "identity_kind": "workflow",
    "integrated_at": "2026-06-21T05:53:51Z",
    "issuer": "https://token.actions.githubusercontent.com",
    "issuer_name": "GitHub Actions",
    "kind": "dsse",
    "kind_label": "DSSE envelope",
    "log_index": 1892581158,
    "shard_tree_id": "1193050959916656506",
    "signed_by": "https://github.com/slsa-framework/slsa-github-generator/.github/workflows/builder_go_slsa3.yml@refs/tags/v2.0.0",
    "signer_count": 1,
    "summary": "builder_go_slsa3.yml in slsa-framework/slsa-github-generator (tag v2.0.0), vouched for by GitHub Actions",
    "url": "https://search.sigstore.dev/?uuid=108e9186e8c5677afe975549c9911f1a66c3e0fe6019269f09621eb1c2621e9f73f98f696f81c3cf",
    "what_was_signed": "a DSSE envelope whose payload hashes to sha256:a68e7e8299219fa3e7f97c900f363803bbd32acb8aa2df1cac1b46632e15a58b"
  },
  "found": true,
  "log_url": "https://rekor.sigstore.dev",
  "looked_up": "1892581158",
  "looked_up_by": "log position",
  "message": "DSSE envelope #1,892,581,158, added 2026-06-21 05:53:51 UTC. builder_go_slsa3.yml in slsa-framework/slsa-github-generator (tag v2.0.0), vouched for by GitHub Actions"
}
```

### Get the log's current state

Read how big the public Sigstore log is right now, the root hash of its tree, the public key it signs with, and its checkpoint - the short signed statement of its size and root. Save that checkpoint. Handing it back to 'Check the log has not been rewritten' on a later run is what proves nothing published in between was altered or removed. No account or API key required.

**Inputs**: None.

**Outputs**

- `checkpoint` (text): The log's signed statement of its size and root. This is the value to save and hand back later
- `checkpoint_log` (text): Which log signed that checkpoint
- `keep_this` (text): What the checkpoint is for
- `log_url` (text): The log that answered
- `message` (text): The log's size in one line
- `public_key` (text): The PEM public key the log signs with
- `read_at` (text): When this was read, ISO 8601 in UTC
- `retired_shards` (number): How many of those are frozen
- `root_hash` (text): The root of that tree's Merkle tree
- `shards` (list): Every tree the log has had. It starts a new one periodically and freezes the old, which is why an entry's position and its position within its own tree are different numbers
- `total_entries` (number): Every entry the log has ever held, across all of its trees
- `tree_id` (text): The tree new entries are going into
- `tree_size` (number): How many entries that tree holds

**Example output**

```json
{
  "checkpoint": "rekor.sigstore.dev - 1193050959916656506\n2701923494\nG2jd6RFAWNXNOdEP2p+9KqhthcOcYU6Lv3NAb7a0NLk=\n\n\u2014 rekor.sigstore.dev wNI9ajBFAiEA+HWgHpxEAOSuCVGjWbqitI6jDwzkYVcc619IS31k2LgCICUuPkr1LP8xDX42C7n0CSCeVYnvTUD1jxmFV7Uqngy+",
  "checkpoint_log": "rekor.sigstore.dev",
  "keep_this": "Save the checkpoint. Handing it back to 'Check the log has not been rewritten' on a later run proves that everything published up to this moment is still there, unchanged.",
  "log_url": "https://rekor.sigstore.dev",
  "message": "The Sigstore transparency log holds 2,823,827,756 entries. Its current shard is at 2,701,923,494.",
  "public_key": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE2G2Y+2tabdTV5BcGiBIx0a9fAFwr\nkBbmLSGtks4L3qX6yYY0zufBnhC8Ur/iy55GhWP/9A/bY2LhC30M9+RYtw==\n-----END PUBLIC KEY-----",
  "read_at": "2026-09-14T00:43:58Z",
  "retired_shards": 2,
  "root_hash": "1b68dde9114058d5cd39d10fda9fbd2aa86d85c39c614e8bbf73406fb6b434b9",
  "shards": [
    {
      "active": false,
      "root_hash": "4d006aa46efcb607dd51d900b1213754c50cc9251c3405c6c2561d9d6a2f3239",
      "tree_id": "3904496407287907110",
      "tree_size": 4163431
    },
    {
      "active": true,
      "root_hash": "1b68dde9114058d5cd39d10fda9fbd2aa86d85c39c614e8bbf73406fb6b434b9",
      "tree_id": "1193050959916656506",
      "tree_size": 2701923494
    }
  ],
  "total_entries": 2823827756,
  "tree_id": "1193050959916656506",
  "tree_size": 2701923494
}
```

### List the newest entries

Read back from the newest entry in the log, newest first, to see what the world is signing right now - each one decoded down to who signed it and what. Filter by the kind of record, or ask only for entries added after some moment. The log takes roughly a hundred entries a second, so a step reads a bounded window of the newest ones and always says how far back it reached. No account or API key required.

**Inputs**

- How many to return (`count`, number): How many of the newest matching entries to return. From 1 to 50. Default: `10`.
- Kinds of entry (`kinds`, text): Only records of these kinds. Most of the log is artifact signatures and DSSE envelopes; the rest are rare. Choose none for every kind. One or more of: `hashedrekord` (Artifact signature - a file signed directly (the commonest)), `dsse` (DSSE envelope - a signed attestation about something built), `intoto` (in-toto attestation - build provenance), `rekord` (Artifact signature carrying the signed content), `cose` (COSE envelope), `alpine` (Alpine package), `helm` (Helm chart), `jar` (Java archive (JAR)), `rpm` (RPM package), `tuf` (TUF repository metadata), `rfc3161` (RFC 3161 timestamp).
- Only entries added after (`added_after`, date and time): Stop reading once the entries get older than this. Leave empty to simply take the newest. The log moves fast enough that a time more than a few minutes ago will reach the end of one step's window first, and the result says when that happened.

**Outputs**

- `added_after` (text): The cutoff asked for, if any
- `entries` (list): The matching entries, newest first
- `kinds_filtered` (list): The kinds asked for, if any
- `log_url` (text): The log that answered
- `message` (text): What came back, in one line
- `reached_back_to` (text): The oldest moment this step saw, ISO 8601 in UTC
- `returned` (number): How many came back
- `scanned` (number): How many of the log's newest entries were read to find them
- `stopped_because` (text): Why the scan stopped where it did
- `total_entries` (number): How many entries the log holds in total

**Example output**

```json
{
  "added_after": "",
  "entries": [
    {
      "entry_id": "108e9186e8c5677afe975549c9911f1a66c3e0fe6019269f09621eb1c2621e9f73f98f696f81c3cf",
      "identity_kind": "workflow",
      "integrated_at": "2026-06-21T05:53:51Z",
      "issuer": "https://token.actions.githubusercontent.com",
      "issuer_name": "GitHub Actions",
      "kind": "dsse",
      "kind_label": "DSSE envelope",
      "log_index": 1892581158,
      "shard_tree_id": "1193050959916656506",
      "signed_by": "https://github.com/slsa-framework/slsa-github-generator/.github/workflows/builder_go_slsa3.yml@refs/tags/v2.0.0",
      "signer_count": 1,
      "summary": "builder_go_slsa3.yml in slsa-framework/slsa-github-generator (tag v2.0.0), vouched for by GitHub Actions",
      "url": "https://search.sigstore.dev/?uuid=108e9186e8c5677afe975549c9911f1a66c3e0fe6019269f09621eb1c2621e9f73f98f696f81c3cf",
      "what_was_signed": "a DSSE envelope whose payload hashes to sha256:a68e7e8299219fa3e7f97c900f363803bbd32acb8aa2df1cac1b46632e15a58b"
    },
    {
      "artifact_digest": "sha256:20ac9dda4f46161dbfec1e395ac0eedec7ae323106aafc6a5bf766eb763fe41c",
      "entry_id": "108e9186e8c5677aad33982fe2e968181b0527564df04e1d536ec0570791870a70bb8074dd8f78b9",
      "identity_kind": "email",
      "integrated_at": "2025-10-28T06:44:33Z",
      "issuer": "https://accounts.google.com",
      "issuer_name": "Google",
      "kind": "hashedrekord",
      "kind_label": "Artifact signature",
      "log_index": 647892280,
      "shard_tree_id": "1193050959916656506",
      "signed_by": "release@example.com",
      "signer_count": 1,
      "summary": "release@example.com, vouched for by Google",
      "url": "https://search.sigstore.dev/?uuid=108e9186e8c5677aad33982fe2e968181b0527564df04e1d536ec0570791870a70bb8074dd8f78b9",
      "what_was_signed": "an artifact with digest sha256:20ac9dda4f46161dbfec1e395ac0eedec7ae323106aafc6a5bf766eb763fe41c"
    }
  ],
  "kinds_filtered": [
    "dsse",
    "hashedrekord"
  ],
  "log_url": "https://rekor.sigstore.dev",
  "message": "2 of the newest entries in a log of 2,823,827,756, read back from entry 2,823,827,755.",
  "reached_back_to": "2026-09-14T00:43:58Z",
  "returned": 2,
  "scanned": 10,
  "stopped_because": "found everything you asked for",
  "total_entries": 2823827756
}
```

### Verify an entry is really in the log

Prove that a record is genuinely in the transparency log, rather than take the log's word for it. Three things are checked here, from the log's own published root hash: that the entry's contents match the identifier it was asked for, that hashing it together with its proof reproduces the root of the log's tree, and that the root the proof used is the one the log signed. Every check comes back with the numbers behind it. Use this before acting on a signature that matters. No account or API key required.

**Inputs**

- Entry (`entry`, text, required): Which entry to read. Paste either its identifier - the long hexadecimal string Sigstore's tools and the search site call a UUID - or its position in the log, which is a plain number. Whichever you have works; there is no need to say which kind it is.

**Outputs**

- `checked_against` (object): The tree the proof was made against
- `checks` (list): Each check, and whether it held
- `entry` (object): The entry that was checked
- `found` (true/false): Whether the log holds such an entry at all
- `log_url` (text): The log that answered
- `message` (text): The verdict in one line
- `signature_not_checked` (text): What this deliberately does not claim
- `verified` (true/false): Whether every check held

**Example output**

```json
{
  "checked_against": {
    "index_in_shard": 1770676896,
    "proof_hashes": 29,
    "root_hash": "1b68dde9114058d5cd39d10fda9fbd2aa86d85c39c614e8bbf73406fb6b434b9",
    "shard_tree_id": "1193050959916656506",
    "tree_size": 2701923902
  },
  "checks": [
    {
      "check": "The entry's contents match its identifier",
      "detail": "The entry body hashes to fe975549c9911f1a66c3e0fe6019269f09621eb1c2621e9f73f98f696f81c3cf, which is the last 64 characters of the entry identifier.",
      "passed": true
    },
    {
      "check": "The entry is in the log's Merkle tree",
      "detail": "Hashing the entry together with the 29 hashes in its proof reproduces the root of a tree of 2,701,923,902 entries.",
      "passed": true
    },
    {
      "check": "The proof is against the log's own signed checkpoint",
      "detail": "The checkpoint signed by rekor.sigstore.dev states the same root at 2,701,923,902 entries.",
      "passed": true
    }
  ],
  "entry": {
    "entry_id": "108e9186e8c5677afe975549c9911f1a66c3e0fe6019269f09621eb1c2621e9f73f98f696f81c3cf",
    "identity_kind": "workflow",
    "integrated_at": "2026-06-21T05:53:51Z",
    "issuer": "https://token.actions.githubusercontent.com",
    "issuer_name": "GitHub Actions",
    "kind": "dsse",
    "kind_label": "DSSE envelope",
    "log_index": 1892581158,
    "shard_tree_id": "1193050959916656506",
    "signed_by": "https://github.com/slsa-framework/slsa-github-generator/.github/workflows/builder_go_slsa3.yml@refs/tags/v2.0.0",
    "signer_count": 1,
    "summary": "builder_go_slsa3.yml in slsa-framework/slsa-github-generator (tag v2.0.0), vouched for by GitHub Actions",
    "url": "https://search.sigstore.dev/?uuid=108e9186e8c5677afe975549c9911f1a66c3e0fe6019269f09621eb1c2621e9f73f98f696f81c3cf",
    "what_was_signed": "a DSSE envelope whose payload hashes to sha256:a68e7e8299219fa3e7f97c900f363803bbd32acb8aa2df1cac1b46632e15a58b"
  },
  "found": true,
  "log_url": "https://rekor.sigstore.dev",
  "message": "Verified. Entry #1,892,581,158 is in the Sigstore transparency log, proved against a tree of 2,701,923,902 entries. builder_go_slsa3.yml in slsa-framework/slsa-github-generator (tag v2.0.0), vouched for by GitHub Actions",
  "verified": true
}
```
