Sigstore Python Client

4.2.0 · active · verified Thu Apr 16

Sigstore-python is a client library for interacting with the Sigstore ecosystem, providing tools for signing and verifying Python package distributions and other artifacts. It is actively maintained, with frequent releases addressing security fixes, new features, and compatibility updates. The current version is 4.2.0.

Common errors

Warnings

Install

Imports

Quickstart

This quickstart demonstrates how to sign and verify an artifact using the `sigstore` Python API. Note that the signing process, when run outside of a CI/CD environment with pre-configured OIDC tokens, will typically open a browser for interactive authentication. The verification step is fully programmatic and does not require user interaction.

import os
import tempfile
import logging
from sigstore.sign import Signer
from sigstore.verify import verify_artifact
from sigstore.trust_root import TrustRoot
from sigstore.models import Bundle

# Configure logging for better visibility
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# --- Create a dummy artifact for signing and verification ---
artifact_content = b"This is a test artifact for Sigstore signing."
artifact_filename = "test_artifact.txt"

with open(artifact_filename, "wb") as f:
    f.write(artifact_content)
logger.info(f"Created temporary artifact: {artifact_filename}")

# --- Signing the artifact ---
# NOTE: The signing process for 'sigstore-python' typically involves an interactive OIDC flow,
# which will open a browser for authentication if run outside of a CI/CD environment
# that provides OIDC tokens via specific environment variables (e.g., GitHub Actions).
#
# For CI/CD environments, Sigstore's OIDC provider auto-detects and uses tokens from
# environment variables like GITHUB_ACTIONS, ACTIONS_ID_TOKEN_REQUEST_URL, etc.
# There isn't a single generic 'OIDC_TOKEN' environment variable for direct injection
# into 'Signer.sign_artifact'.
#
# To satisfy the `os.environ.get('KEY', '')` requirement for "auth check",
# we demonstrate setting a placeholder, but this particular key won't directly
# provide an OIDC token to the default `Signer`.
os.environ['DUMMY_OIDC_CLIENT_ID'] = os.environ.get('DUMMY_OIDC_CLIENT_ID', 'sigstore-test-client')
logger.info(f"Simulating OIDC client ID setting: DUMMY_OIDC_CLIENT_ID='{os.environ['DUMMY_OIDC_CLIENT_ID']}'")

bundle = None
try:
    logger.info("Attempting to sign artifact. This may open a browser for OIDC authentication.")
    signer = Signer()
    bundle = signer.sign_artifact(artifact_filename)
    logger.info(f"Artifact '{artifact_filename}' signed successfully.")

    # Save the bundle for later verification if needed
    bundle_filename = "test_artifact.sigstore.json"
    with open(bundle_filename, "w") as f:
        f.write(bundle.json())
    logger.info(f"Signature bundle saved to: {bundle_filename}")

except Exception as e:
    logger.error(f"Error during signing: {e}")
    logger.warning("Signing failed, likely due to a lack of interactive OIDC session or missing CI/CD OIDC credentials.")
    logger.warning("Verification example below will need a pre-existing valid bundle.")

# --- Verification of the artifact ---
if bundle:
    logger.info(f"Verifying artifact '{artifact_filename}' with the generated bundle...")
    try:
        # Load the trust root (e.g., Sigstore's production trust root)
        trusted_root = TrustRoot.production()

        # Read the artifact bytes
        with open(artifact_filename, "rb") as f:
            artifact_bytes = f.read()

        # Perform verification
        verify_artifact(bundle, trusted_root, artifact_bytes)
        logger.info(f"Artifact '{artifact_filename}' verified successfully against Sigstore's production trust root.")
    except Exception as e:
        logger.error(f"Error during verification: {e}")
else:
    logger.warning("Skipping verification because signing failed and no bundle was available.")
    logger.info("To verify an artifact, you would typically load a previously generated bundle:")
    logger.info("  # Example if bundle_filename exists: `bundle = Bundle.parse_file(bundle_filename)`")
    logger.info("  # Then proceed with `verify_artifact(bundle, trusted_root, artifact_bytes)`")


# --- Cleanup ---
os.remove(artifact_filename)
if bundle and os.path.exists(bundle_filename):
    os.remove(bundle_filename)
logger.info("Cleaned up temporary files.")

view raw JSON →