Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
Red Hat Tech Preview release, based on upstream [sigstore/model-transparency](https://github.com/sigstore/model-transparency) v1.1.1.

### Added
- Added support for signing and verifying OCI model manifests directly without requiring model files on disk. OCI manifest JSON files can be detected and signed, or verified against. When verifying local files against signatures created from OCI manifests, the tool automatically matches files by path using `org.opencontainers.image.title` annotations (ORAS-style), enabling cross-verification between OCI images and local model directories.
- Added support for signing and verifying OCI model manifests directly without requiring model files on disk. OCI manifest JSON files can be detected and signed, or verified against.
- Added OCI image signing and verification. Sign and verify container images directly in registries using `model_signing sign sigstore quay.io/user/model:latest`. Supports both OCI 1.1 Referrers API and tag-based attachment.
- Added smart target detection for CLI commands. The tool auto-detects the target type: if the path exists locally, it is signed/verified as a file; otherwise, it is treated as an OCI image reference.
- Added `--local-model` option to verify that local files match a signed image's layer digests.
- Added `sign_image()` and `verify_image()` methods to the Python API.
- Added the `digest` subcommand to compute and print a model's digest. This enables other tools to easily pair the attestations with a model directory.
- Package renamed to `rh-model-signing` for Red Hat distribution.
- Added `rh_model_signing` CLI entry point (in addition to `model_signing`).
Expand Down
88 changes: 53 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,66 +215,84 @@ Similarly, for key verification, we can use

#### Signing and Verifying OCI Images

The tool supports signing and verifying OCI model images directly from their manifest without requiring the model files on disk. This is useful for signing images in registries without pulling them.

**Signing from OCI Manifest:**
The tool supports signing and verifying OCI container images directly from
registries. Signatures are automatically attached to the registry.

```bash
# Get the OCI manifest (from skopeo inspect --raw)
[...]$ skopeo inspect --raw docker://quay.io/user/model:latest > manifest.json
# Sign with Sigstore
[...]$ model_signing sign sigstore quay.io/user/model:latest

# Sign with EC key
[...]$ model_signing sign key quay.io/user/model:latest --private-key key.pem
```

Registry authentication uses your existing credentials from `~/.docker/config.json`
or podman's `auth.json`.

# Sign using the manifest
[...]$ model_signing sign manifest.json
By default, signatures are attached using the OCI 1.1 Referrers API. For older
registries, use `--attachment-mode tag`:

```bash
[...]$ model_signing sign sigstore quay.io/user/model:latest --attachment-mode tag
```

**Verifying OCI Images:**
Use `--output-mode` to control where signatures are written:

```bash
# Write signature to file only (no registry attachment)
[...]$ model_signing sign sigstore quay.io/user/model:latest \
--output-mode file --signature model.sig

# Attach to registry AND write to file
[...]$ model_signing sign sigstore quay.io/user/model:latest \
--output-mode both --signature model.sig
```

You can verify in two ways:
To verify:

1. **Against the OCI manifest** (no files needed):
```bash
[...]$ model_signing verify manifest.json \
--signature model.sig \
# Verify Sigstore signature
[...]$ model_signing verify sigstore quay.io/user/model:latest \
--identity user@example.com \
--identity_provider https://accounts.google.com
--identity-provider https://accounts.google.com

# Verify key-based signature
[...]$ model_signing verify key quay.io/user/model:latest --public-key key.pub
```

2. **Against local model files** (automatically detects OCI layer signatures):
You can also verify that local files match a signed image:

```bash
[...]$ model_signing verify model_dir \
--signature model.sig \
[...]$ model_signing verify sigstore quay.io/user/model:latest \
--identity user@example.com \
--identity_provider https://accounts.google.com
--identity-provider https://accounts.google.com \
--local-model ./downloaded-model
```

The tool automatically detects OCI manifest signatures and matches files by path using `org.opencontainers.image.title` annotations (ORAS-style). For multi-layer images, verification against local files attempts to match individual files by path.
The tool auto-detects the target type: if the path exists locally, it is treated
as a file; otherwise, it is treated as an OCI image reference.

**Python API:**
##### Python API

```python
import json
from model_signing import hashing, signing, verifying

# Sign from OCI manifest
with open("manifest.json") as f:
oci_data = json.load(f)
import model_signing

manifest = hashing.create_manifest_from_oci_layers(oci_data)
signing.Config().use_sigstore_signer().sign_from_manifest(
manifest, "model.sig"
# Sign an image
model_signing.signing.Config().use_sigstore_signer().sign_image(
"quay.io/user/model:latest"
)

# Verify from OCI manifest
verifying.Config().use_sigstore_verifier(
# Verify an image
model_signing.verifying.Config().use_sigstore_verifier(
identity="user@example.com",
oidc_issuer="https://accounts.google.com"
).verify_from_oci_manifest(oci_data, "model.sig")
).verify_image("quay.io/user/model:latest")

# Or verify from local files (automatically handles OCI signatures)
verifying.Config().use_sigstore_verifier(
# Verify image and check local files match
model_signing.verifying.Config().use_sigstore_verifier(
identity="user@example.com",
oidc_issuer="https://accounts.google.com"
).verify("model_dir", "model.sig")
).verify_image("quay.io/user/model:latest", local_model_path="./model_dir")
```

#### Signing with PKCS #11 URIs
Expand Down Expand Up @@ -451,7 +469,7 @@ The same verification configuration can be used to verify multiple models:
```python
import model_signing

verifying_config = model_signing.signing.Config().use_elliptic_key_verifier(
verifying_config = model_signing.verifying.Config().use_elliptic_key_verifier(
public_key="key.pub"
)

Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ dependencies = [
"click",
"cryptography",
"in-toto-attestation",
"oras>=0.2.30",
"sigstore>=4.0",
"sigstore-models>=0.0.5",
"typing_extensions",
Expand Down
Loading
Loading