Skip to content

CEP about serving sigstore attestations in Conda repositories#142

Draft
wolfv wants to merge 5 commits intoconda:mainfrom
wolfv:serving-attestations
Draft

CEP about serving sigstore attestations in Conda repositories#142
wolfv wants to merge 5 commits intoconda:mainfrom
wolfv:serving-attestations

Conversation

@wolfv
Copy link
Copy Markdown
Contributor

@wolfv wolfv commented Dec 10, 2025

This CEP adds specifications how to serve sigstore attestations in Conda repositories.

A preview implementation is available on beta.prefix.dev under the following URL:

https://beta.prefix.dev/wolf-channel/linux-64/signed-package-1.2.1-hb0f4dca_0.conda.v0.sigs

@wolfv wolfv marked this pull request as draft December 10, 2025 16:13
Comment thread cep-xxxx-serving-attestations.md Outdated

This proposal is fully backwards compatible:

1. **Existing channels**: No changes required; clients will receive `404` for `.sigs` endpoints
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this correct? In the section HTTP Status Codes above we specify:

| 404 Not Found | The package does not exist (distinct from "no attestations") |

(...) Channels MUST return 404 Not Found only when the underlying package does not exist.

Won't new clients who request the .sigs file from an old/existing channel receive 404 and interpret it as "the package does not exist", when instead it should be "no attestations available for that package"?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this thread can be resolved

Comment thread cep-xxxx-serving-attestations.md Outdated

3. **Works with existing infrastructure**: The sidecar file approach integrates naturally with static file hosting, CDNs, and mirrors.

4. **Follows ecosystem conventions**: Similar approaches are used by PyPI ([Integrity API][PyPI Integrity]), npm ([provenance attestations][npm provenance]), and RubyGems.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this thread can be resolved

Comment thread cep-xxxx-serving-attestations.md Outdated
]
```

Each element in the array MUST be a valid [Sigstore Bundle] as defined by the Sigstore specification. The bundle format supports multiple versions; implementations SHOULD support at least bundle versions v0.2 and v0.3.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know if we should specify bundle versions here. This CEP defines the how to serve attestations (format, location) so that clients can access them. But IMHO, the bundle itself should be a black box to this CEP, other than "each element must be a valid sigstore bundle" I don't think we should go into internals (which are covered by CEP 27)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this thread can be resolved

Comment thread cep-xxxx-serving-attestations.md Outdated
| Status Code | Meaning |
|-------------|---------|
| `200 OK` | Attestations returned successfully (may be empty array) |
| `404 Not Found` | The package does not exist (distinct from "no attestations") |
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding more context from my older comment about this being backwards compatible:
I think 404 should have the meaning "the package does not exist AND/OR the channel does not support attestations".
Otherwise (new) clients communicating with (old) channels could try to retrieve the .sigs file, see 404, and interpret "the package does not exist", where the reality is that the channel does not support yet this CEP

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this thread can be resolved

Comment thread cep-xxxx-serving-attestations.md Outdated
Comment on lines +169 to +175
A package MAY have multiple attestations from different sources. Common scenarios include:

| Source | Purpose |
|--------|---------|
| Build system (e.g., GitHub Actions) | Proves the package was built from specific source code |
| Channel operator | Proves the channel accepted and published the package |
| Third-party auditor | Proves the package passed security review |
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would remove the "common scenarios" here, or maybe reword it as a list of examples of potential future usecases.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this has not been addressed yet

Comment on lines +183 to +184
1. Fetch and cache `.sigs` files alongside packages
2. Serve cached attestations without modification
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can attestations for a file be uploaded post-facto? If not, might that be a future feature? (like the example above, where a third party auditor might review and upload and attestation after the artifact is publicly available)

If so, this section should account for how mirrors should update changed .sigs files. Is there a way for mirrors (or any client) to detect such changes?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As we discussed in Brussels we want to add the SHA256 of the signatures file to the repodata which would make it possible for the mirrors to detect changes.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this thread can be resolved

Comment thread cep-xxxx-serving-attestations.md Outdated

Clients implementing attestation verification SHOULD follow this workflow:

1. **Download package** from the channel (or use the SHA256 sum from the repodata.json)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or use the SHA256 sum from the repodata.json

What's the usecase for this? The client should always hash the package itself for verification. If, as a first step, it only uses the hash from the repodata.json to verify the attestation then before installing it should also check that the downloaded file matches that hash. Is that the case now?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this thread can be resolved

Comment thread cep-xxxx-serving-attestations.md Outdated
Comment on lines +197 to +201
3. **Verify each attestation** according to the client's trust policy:
- Verify the Sigstore bundle signature
- Verify the certificate chain to Fulcio root
- Verify the transparency log inclusion proof
- Verify the in-toto subject matches the downloaded package
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would not put this here, I would just refer to the verification process specified in CEP 27

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this thread can be resolved

Comment thread cep-xxxx-serving-attestations.md Outdated
Comment on lines +223 to +229
| Setting | Values | Behavior |
|---------|--------|----------|
| `enabled` | `true`/`false` | Enable or disable attestation fetching and verification |
| `require` | `error` | Fail if attestations are missing or invalid |
| | `warn` | Log warning but continue if attestations are missing or invalid |
| | `ignore` | Silently continue (still verify if attestations exist) |
| `trusted_identities` | List of patterns | Only accept attestations from matching Sigstore identities |
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this practical? I could see the usecase for a private channel where all artifacts are uploaded by the same trusted identity, but in the general usecase there will be one identity per package, so it doesn't make sense to list them all here (rather than relying on a lockfile with identities). I don't think we should require this of the clients, instead we might want to require the clients supporting identities in lockfiles.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your proposal would be to do some kind of TOFU from the lockfile? Ie. warn / error when an identity changes?

I think for a lot of channels, the publishers are much more homogenous vs. PyPI. E.g. one could at least choose the Github organization with wildcard, or even the repository for an entire channel (e.g. see the rust-forge: https://github.com/wolfv/rust-forge)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this thread can be resolved

### Offline and Air-gapped Environments

For offline verification, clients MAY cache `.sigs` files alongside packages in local repositories
The Sigstore bundle format is self-contained and supports offline verification once the Sigstore trust root is available locally.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should mention here that the trust root should be updated periodically, since part of its security guarantees come from the fact that target/keys can be revoked

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this thread can be resolved

Comment thread cep-xxxx-serving-attestations.md Outdated
Comment on lines +240 to +264
The security of this scheme depends on:

1. **Sigstore infrastructure**: Fulcio CA, Rekor transparency log, and their availability
2. **Identity binding**: OIDC providers correctly authenticating signing identities
3. **Client trust policy**: Correctly configured trusted identities
4. **TLS security**: Secure transport when fetching attestations

### Threat Mitigations

| Threat | Mitigation |
|--------|------------|
| Forged attestations | Sigstore signatures are cryptographically verified against Fulcio certificates |
| Tampered attestations | Rekor transparency log provides tamper evidence |
| Replay attacks | In-toto subject binds attestation to specific artifact hash |
| Removed attestations | Rekor log entries are permanent; monitors can detect removal |
| Compromised signing identity | Transparency log enables detection; trust policy limits blast radius |

### Limitations

This scheme does NOT protect against:

1. Legitimate signers publishing malicious packages
2. Compromise of the Sigstore infrastructure itself
3. Incorrect client trust policies
4. Attacks before attestation was added to the package
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure we should rehash the security model here (which should be covered by CEP 27).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this thread can be resolved

Copy link
Copy Markdown

@evankanderson evankanderson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I swung by, since this got posted to the OpenSSF #general channel, and I was curious. Feel free to disregard.


1. **Enables client verification**: Clients can fetch attestations alongside packages and verify them before installation.

2. **Supports multiple attestations**: A single package may have multiple attestations (e.g., from the build system, from the channel on upload, from third-party auditors).
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While this CEP describes the endpoint as "RESTful", it seems like it may be a read-only endpoint?

If you want to support additional attestations from third-parties, you'll need to figure out access control for users "vouching" for other packages. That seems like a diversion from the main goal of this CEP, so it might be worth calling out third-party auditors as a future capability that you don't want to prevent.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While this CEP describes the endpoint as "RESTful", it seems like it may be a read-only endpoint?

These are not in contradiction, right?

If you want to support additional attestations from third-parties, you'll need to figure out access control for users "vouching" for other packages. That seems like a diversion from the main goal of this CEP, so it might be worth calling out third-party auditors as a future capability that you don't want to prevent.

Not necessarily? A third party could generate attestations, and a channel admin could upload them to their respective packages, without giving access to the third party. This section is characterizing the distribution mechanism, the "attestations from third-party auditors" is just an example of a type of attestation that may exist.

Comment on lines +159 to +161
"attestations": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570"
}
```
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm assuming this is because of the discussion here: https://github.com/conda/ceps/pull/142/changes#r2816839339

It might be worth a sentence here to suggest the rationale:

Suggested change
"attestations": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570"
}
```
"attestations": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570"
}
\```
The signatures hash enables mirrors to detect and re-fetch signature bundles as they are added to the repo.

(GitHub suggestions can't include the close-block, so I had to escape it. 😢 )

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1


Each attestation in the response MUST comply with [CEP 27]. Specifically:

1. The in-toto statement's `subject[0].name` MUST match the artifact filename.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this need to be subject[0].name? I'm imagining that I might have a CI process which produces an attestation for all the artifacts produced in a single attestation, so I have N+1 outputs, rather than 2N outputs. Should 1. and 2. be changed to "One of the attestation subjects MUST match as follows: (a) subject[N].name MUST match the artifact filename AND (b) `subject[N].digest.sha256 MUST match the SHA256 hash of the artifact"?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason for this is that having one attestation per artifact makes things simpler from a verification POV, and also prevents certain footguns (more context here)

Comment on lines +228 to +230
| `require` | `error` | Fail if attestations are missing or invalid |
| | `warn` | Log warning but continue if attestations are missing or invalid |
| | `ignore` | Silently continue (still verify if attestations exist) |
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a default value for require (or the other settings)? In the example, require is omitted for the "foobar" repository.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I vote for making the 3 fields mandatory, with no default values


1. **Download package** from the channel
2. **Fetch attestations** from `<package_url>.sigs`
3. **Verify each attestation** against the configuration.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make explicit that the verification process is defined in CEP-27

For offline verification, clients MAY cache `.sigs` files alongside packages in local repositories.
The Sigstore bundle format is self-contained and supports offline verification once the Sigstore trust root is available locally.

Note: clients MUST periodically update the sigstore trust root to ensure no keys were revoked.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the reason is more general, it's to ensure the client doesn't miss any trust root changes (which could be key revocation, but also new keys added)

Comment thread cep-xxxx-serving-attestations.md Outdated

This proposal is fully backwards compatible:

1. **Existing channels**: No changes required; clients will receive `404` for `.sigs` endpoints
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this thread can be resolved

Comment thread cep-xxxx-serving-attestations.md Outdated

3. **Works with existing infrastructure**: The sidecar file approach integrates naturally with static file hosting, CDNs, and mirrors.

4. **Follows ecosystem conventions**: Similar approaches are used by PyPI ([Integrity API][PyPI Integrity]), npm ([provenance attestations][npm provenance]), and RubyGems.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this thread can be resolved

Comment thread cep-xxxx-serving-attestations.md Outdated
]
```

Each element in the array MUST be a valid [Sigstore Bundle] as defined by the Sigstore specification. The bundle format supports multiple versions; implementations SHOULD support at least bundle versions v0.2 and v0.3.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this thread can be resolved

Comment thread cep-xxxx-serving-attestations.md Outdated

Clients implementing attestation verification SHOULD follow this workflow:

1. **Download package** from the channel (or use the SHA256 sum from the repodata.json)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this thread can be resolved

Comment thread cep-xxxx-serving-attestations.md Outdated
Comment on lines +197 to +201
3. **Verify each attestation** according to the client's trust policy:
- Verify the Sigstore bundle signature
- Verify the certificate chain to Fulcio root
- Verify the transparency log inclusion proof
- Verify the in-toto subject matches the downloaded package
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this thread can be resolved

Comment thread cep-xxxx-serving-attestations.md Outdated
Comment on lines +223 to +229
| Setting | Values | Behavior |
|---------|--------|----------|
| `enabled` | `true`/`false` | Enable or disable attestation fetching and verification |
| `require` | `error` | Fail if attestations are missing or invalid |
| | `warn` | Log warning but continue if attestations are missing or invalid |
| | `ignore` | Silently continue (still verify if attestations exist) |
| `trusted_identities` | List of patterns | Only accept attestations from matching Sigstore identities |
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this thread can be resolved

### Offline and Air-gapped Environments

For offline verification, clients MAY cache `.sigs` files alongside packages in local repositories
The Sigstore bundle format is self-contained and supports offline verification once the Sigstore trust root is available locally.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this thread can be resolved

Comment thread cep-xxxx-serving-attestations.md Outdated
Comment on lines +240 to +264
The security of this scheme depends on:

1. **Sigstore infrastructure**: Fulcio CA, Rekor transparency log, and their availability
2. **Identity binding**: OIDC providers correctly authenticating signing identities
3. **Client trust policy**: Correctly configured trusted identities
4. **TLS security**: Secure transport when fetching attestations

### Threat Mitigations

| Threat | Mitigation |
|--------|------------|
| Forged attestations | Sigstore signatures are cryptographically verified against Fulcio certificates |
| Tampered attestations | Rekor transparency log provides tamper evidence |
| Replay attacks | In-toto subject binds attestation to specific artifact hash |
| Removed attestations | Rekor log entries are permanent; monitors can detect removal |
| Compromised signing identity | Transparency log enables detection; trust policy limits blast radius |

### Limitations

This scheme does NOT protect against:

1. Legitimate signers publishing malicious packages
2. Compromise of the Sigstore infrastructure itself
3. Incorrect client trust policies
4. Attacks before attestation was added to the package
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this thread can be resolved

| --------------- | ------------------------------------------------------------ |
| `200 OK` | Attestations returned successfully (may be empty array) |

Channels that support attestations MUST always return `200 OK` with an empty array `[]`, even when the package does not exist.
Copy link
Copy Markdown
Contributor

@facutuesca facutuesca Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My previous comment was about the ambiguity of defining a 404 error on the .sigs endpoint as "this package does not exist", when channels that don't implement this CEP would return 404 on the .sigs endpoint for every package.

I think we should return 404 when the package does not exist, but define the meaning of 404 as:

  • For channels implementing this CEP, 404 means the package does not exist
  • For channels not implementing this CEP, .sigs always returns 404

and make it clear that clients should not use the .sigs endpoint to determine if a package exists or not

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants