c2pa-azure-py
Sign files with C2PA content credentials using the Azure Trusted Signing service.
The project ships in two forms from a single codebase:
- A Python library (
c2pa_azure) you can import in your own apps. - A standalone CLI (
c2pa-azure-sign) you can run from the shell or a container.
Installation
From source
git clone https://github.com/duggaraju/c2pa-azure-py.git
cd c2pa-azure-py
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install . # add -e for an editable/dev install
As a dependency in another project
pip install c2pa-azure # once published to PyPI
# or directly from a Git ref:
pip install git+https://github.com/duggaraju/c2pa-azure-py.git
Authentication
Sign in to Azure before running. Any credential supported by
DefaultAzureCredential
will work (Azure CLI, Managed Identity, environment variables, etc.).
az login
# In WSL or headless environments:
az login --use-device-code
CLI usage
c2pa-azure-sign \
-i path/to/input.jpg \
-o path/to/output.jpg \
-e https://<region>.codesigning.azure.net/ \
-a <trusted-signing-account> \
-c <certificate-profile>
Equivalent invocation without an entry-point script:
python -m c2pa_azure -i input.jpg -o output.jpg -e https://... -a acct -c profile
Optional flags:
| Flag | Description |
|---|---|
-m, --manifest |
Path to a manifest JSON file, or an inline manifest string. Defaults to the bundled manifest.json. |
-s, --settings |
Path to a C2PA settings TOML file. |
-f, --force |
Overwrite the output file if it already exists (default: on). |
Library usage
from azure.identity import DefaultAzureCredential
from c2pa import Builder, ContextBuilder
from c2pa_azure import AzureSigner, TrustedSigningClient, TrustedSigningSettings
credential = DefaultAzureCredential()
settings = TrustedSigningSettings(
certificate_profile="my-cert-profile",
service_account="my-trusted-signing-account",
endpoint="https://eus.codesigning.azure.net/",
)
client = TrustedSigningClient(credential, settings)
azure_signer = AzureSigner(client)
signer = azure_signer.to_c2pa_signer()
manifest = """
{
"claim_generator": "my_app/1.0.0",
"title": "My Signed Image",
"assertions": [
{ "label": "stds.schema-org.CreativeWork",
"data": { "@context": "https://schema.org", "@type": "CreativeWork",
"author": [{ "@type": "Person", "name": "Jane Doe" }] } }
]
}
"""
context = ContextBuilder().with_signer(signer).build()
builder = Builder(manifest, context)
builder.sign_file("input.jpg", "output.jpg")
Loading the bundled manifest
from importlib.resources import files
from c2pa_azure import AzureSigner, TrustedSigningSettings
manifest = files("c2pa_azure.data").joinpath("manifest.json").read_text()
Calling the low-level Trusted Signing client
from azure.identity import DefaultAzureCredential
from c2pa_azure import TrustedSigningClient, TrustedSigningSettings
settings = TrustedSigningSettings(
"profile", "account", "https://eus.codesigning.azure.net/"
)
client = TrustedSigningClient(DefaultAzureCredential(), settings)
azure_signer = AzureSigner(client)
cert_chain_p7b = client.get_certificate_chain()
signature = azure_signer(b"<data to hash and sign>")
Invoking the CLI from Python
from c2pa_azure.cli import main
exit_code = main([
"-i", "input.jpg",
"-o", "output.jpg",
"-e", "https://eus.codesigning.azure.net/",
"-a", "my-account",
"-c", "my-cert-profile",
])
Docker
docker build -t c2pa-azure .
docker run --rm \
-v "$PWD:/data" \
-e AZURE_CLIENT_ID -e AZURE_TENANT_ID -e AZURE_CLIENT_SECRET \
c2pa-azure \
-i /data/input.jpg -o /data/output.jpg \
-e https://<region>.codesigning.azure.net/ \
-a <account> -c <certificate-profile>
Project layout
src/c2pa_azure/
├── __init__.py # public API: AzureSigner, TrustedSigningClient, TrustedSigningSettings
├── __main__.py # enables `python -m c2pa_azure`
├── cli.py # argparse entry point (c2pa-azure-sign)
├── signer.py # AzureSigner
├── trusted_signing.py # TrustedSigningClient + TrustedSigningSettings
└── data/ # bundled manifest.json and settings.json
Development
pip install -e ".[dev]"
pytest
python -m build # produces dist/*.whl and dist/*.tar.gz
Load local module in editable mode (debugging)
When debugging changes in src/c2pa_azure, install this repo in editable mode so imports resolve to your local source tree:
python -m venv .venv
source .venv/bin/activate
python -m pip install -e ".[dev]"
python -c "import c2pa_azure; print(c2pa_azure.__file__)"
The printed path should point to this checkout (not a site-packages wheel install).
Release a new Python package version
Dependabot opens c2pa-python updates separately. Its pull-request workflow
copies the pinned dependency version from requirements.txt to the project
version, __version__, and the package's minimum c2pa-python requirement.
After that pull request is merged into master, the Release workflow builds the
distributions, publishes them to PyPI, and creates the matching GitHub Release.
The workflow verifies all version declarations before publishing. Configure a
PyPI trusted publisher for .github/workflows/release.yml and the pypi GitHub
environment before the first automatic release. A matching manually published
GitHub Release remains supported for recovery or one-off releases.
License
This project is licensed under the MIT License. See the LICENSE file for details.
Metadata
Release files for c2pa-azure 0.38.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| c2pa_azure-0.38.0.tar.gz | 12.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| c2pa_azure-0.38.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 28.3 kB
Release files / c2pa_azure-0.38.0.tar.gz
| Download URL | c2pa_azure-0.38.0.tar.gz |
|---|---|
| Size | 12.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f185f4c318035c67fe8ddbe4c37ee3052310de8375e165fe4ee4a0ab49e82179
|
|
BLAKE2b-256 checksum How to use checksums |
f42ce08846cd395d93122b3d35927359abb6c767979db304ab40552c537ce952
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 5, 2026.
Transparency logRelease files / c2pa_azure-0.38.0-py3-none-any.whl
| Download URL | c2pa_azure-0.38.0-py3-none-any.whl |
|---|---|
| Size | 15.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
6e30950a44eb9fa3c6c438fabd7b7173228abe4554272a09c5b009da4c536820
|
|
BLAKE2b-256 checksum How to use checksums |
00fe13900f3930faf22a32a6b7642ca88e9a0a0b08e87967892de5e8bf32ab82
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 5, 2026.
Transparency log