Skip to content
Merged
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
40 changes: 40 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# .github/workflows/ci.yml
name: CI
on:
push:
branches: [feature/initial-design]
pull_request:
branches: [main]

jobs:
ci:
name: "pyCosign CI Pipeline | (Python ${{ matrix.python-version }})"
strategy:
matrix:
python-version: ["3.10"]
poetry-version: ["2.1.3"]
os: [ubuntu-22.04]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install poetry
uses: abatilo/actions-poetry@v4
- name: Setup a local virtual environment (if no poetry.toml file)
run: |
poetry config virtualenvs.create true --local
poetry config virtualenvs.in-project true --local
- uses: actions/cache@v3
name: Define a cache for the virtual environment based on the dependencies lock file
with:
path: ./.venv
key: venv-${{ hashFiles('poetry.lock') }}
- name: Install the project dependencies
run: poetry install
- name: Run Black in check mode
run: poetry run black --check --verbose pycosign
- name: Run Isort in check mode
run: poetry run isort --verbose pycosign
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

149 changes: 149 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
# Contributing to pyCosign

First off, **thank you for taking the time to contribute!**
The following guidelines help keep the project consistent and maintainable.

---

## Table of Contents
1. [Code of Conduct](#code-of-conduct)
2. [Getting Started](#getting-started)
3. [Branching & Workflow](#branching--workflow)
4. [Commit Conventions](#commit-conventions)
5. [Developer Certificate of Origin (DCO)](#developer-certificate-of-origin-dco)
6. [Coding Style](#coding-style)
7. [Testing](#testing)
8. [Pull-Request Checklist](#pull-request-checklist)
9. [Release Process](#release-process)

---

## Code of Conduct
We follow the [Contributor Covenant](https://www.contributor-covenant.org/version/2/1/code_of_conduct/) v2.1.
Please be respectful and inclusive in all interactions.

---

### Getting Started (Poetry)

```bash
# clone
git clone https://github.com/your-org/pycosign.git
cd pycosign

# install Poetry (if not already)
curl -sSL https://install.python-poetry.org | python3 -

# create & activate venv + install deps
poetry install --with dev

# drop into project shell
poetry shell

# install git hooks
pre-commit install

*Poetry automatically selects Python ≥ 3.10 on your system or the one specified in pyproject.toml. All dev tools—ruff, black, mypy, pytest, invoke—are declared under [tool.poetry.group.dev].*

### Prerequisites

| Tool | Required Version | Notes |
|------------------|------------------|-------|
| **Poetry** | 1.8 or newer | Dependency & virtual-env manager |
| **Python** | 3.10 – 3.12 | Poetry will auto-select within this range |
| **cosign CLI** | ≥ 2.2 | `brew install sigstore/tap/cosign` or download release binary |
| **plantuml** | _optional_ | Render `.puml` diagrams locally (`brew install plantuml`) |
| **Docker** | _optional_ | Quick PlantUML preview, OCI registry tests |

## Branching & Workflow

* **`main`** — always releasable; tagged releases are cut from here.
* **Feature branches** — name `feature/<short-topic>` (e.g., `feature/registry-push`).
* **Bug-fix branches** — name `bugfix/<issue-#>` (e.g., `bugfix/42-null-sig-path`).
* **Documentation-only branches** — name `docs/<topic>`.

Workflow:

1. Create an **Issue** if one doesn’t exist.
2. Branch from `main` with the naming rules above.
3. Work locally in a Poetry shell:
```bash
poetry shell
git checkout -b feature/my-cool-thing
```
4. Keep commits small, descriptive, and signed (`git commit -s`).
5. Push to your fork / to the repo: `git push -u origin feature/my-cool-thing`.
6. Open a **pull request** against `main`. GitHub Actions will run:
* lint → test → type-check → coverage → packaging checks.
7. Address review comments; squash-merge once approved.
> **Tip:** Use `git rebase -i main` to keep history clean before opening the PR.

## Commit Conventions

We follow **Conventional Commits**:
```bash
feature(signer): add --push flag for sign-blob
bugfix(verifier): handle missing Rekor bundle gracefully
docs: update README diagrams
```

## Developer Certificate of Origin (DCO)

By submitting a PR you certify you have the right to submit the work under the project’s [MIT license](LICENSE).
Sign your commits:

```bash
git commit -s -m "bugfix: correct typo"
```
The `-s` flag adds the required `Signed-off-by` line.

## Coding Style

* **ruff** for linting (`black`, `isort`, `flake8` rules)
* Docstrings follow **Google style**.

Run all checks:

* **black** for formatting (PEP 8 compliant).
```bash
poetry run black --verbose pycosign
```

* **isort** your imports, so you don't have to.
```bash
poetry run isort --verbose pycosign
```

## Testing

* **pytest** with **pytest-asyncio** for async routines.
* 90%+ coverage target.

```bash
pytest -q
```
CI will fail if coverage drops below the threshold.

## Pull-Request Checklist

Before requesting a review, make sure you can check **every** box below:

- [ ] **Issue linked** (e.g., “Closes #123”) or marked N/A for trivial docs fixes.
- [ ] **Unit / integration tests** added or updated; `poetry run pytest` passes locally.
- [ ] **Docs updated** (`README`, `docs/`, or inline docstrings) if behavior changed.
- [ ] **Changelog entry** added under `## [Unreleased]` in `CHANGELOG.md`.
- [ ] `pre-commit run --all-files` passes (ruff, black, mypy, etc.).
- [ ] All commits are **signed** (`git commit -s`) to satisfy the DCO.
- [ ] PR title follows **Conventional Commits** (e.g., `feat(verifier): add policy flag`).
- [ ] CI status is green (GitHub Actions).

> 🔒 PRs without a Signed-off-by line will be blocked by the DCO GitHub check.

## Release Process

1. Merge all features into `main`.
2. Bump version with `bumpver update --push-tag`.
3. GitHub Action builds sdist & wheels and uploads to PyPI.
4. Draft release notes in `CHANGELOG.md`.

Happy hacking! 💙
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2025 interwebshack
Copyright (c) 2025 **pyCosign contributors**

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
100 changes: 99 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,100 @@
# pyCosign
Python Wrapper for Sigstor Cosign

> A Pythonic façade around the **Sigstore `cosign` CLI** — sign, attest, and verify artifacts from pure Python or the command line.

[![Build](https://img.shields.io/github/actions/workflow/status/interwebshack/pycosign/ci.yml?branch=main)](https://github.com/interwebshack/pycosign/actions)
[![License](https://img.shields.io/github/license/interwebshack/pycosign)](LICENSE)

---

## Table of Contents
1. [Motivation](#motivation)
2. [Features](#features)
3. [Quick Start](#quick-start)
4. [CLI Examples](#cli-examples)
5. [Library Usage](#library-usage)
6. [Documentation](#documentation)
7. [Contributing](#contributing)
8. [License](#license)

---

## Motivation
`cosign` is the gold-standard CLI for software signing, but orchestration in Python projects often requires boilerplate subprocess calls, error parsing, and registry plumbing. **pyCosign** wraps those concerns in a class-based API with async support—letting you focus on *why* you sign, not *how*.

---

## Features
* 📜 **Sign, verify, attest** files or OCI artifacts
* 🔑 **Key sources**: PEM file, Fulcio keyless, HSM / PKCS #11
* 🌐 **Storage targets**: Local filesystem, OCI registry, Rekor log
* ⚡ **Async orchestration** for batch pipelines
* 📝 **Rich logging** and typed return objects (`Signature`, `VerificationResult`, `Attestation`)
* 🐍 Python 3.10+ & MIT-licensed

---

## Quick Start

```bash
# install cosign (v2.2+) first
brew install sigstore/tap/cosign # macOS example

# install pyCosign
pip install pycosign
```

Create a signature for hello.tgz:

```bash
pycosign sign-blob --key cosign.key ./hello.tgz # → hello.tgz.sig
```

Verify it:

```bash
pycosign verify-blob --signature hello.tgz.sig ./hello.tgz
```

---

## CLI Examples

| Task | Command |
|------|---------|
| **Sign OCI image** | `pycosign sign registry.local/hello:1.0` |
| **Sign local file → push signature to registry** | `pycosign sign-blob --push registry.local/hello:1.0 ./hello.tgz` |
| **Attest local file with SPDX SBOM** | `pycosign attest-blob --predicate sbom.json ./hello.tgz` |
| **Verify local file with detached `.sig`** | `pycosign verify-blob --signature hello.tgz.sig ./hello.tgz` |
| **Verify attestation bundle offline** | `pycosign verify-attestation --type https://spdx.dev/Document --signature hello.tgz.att ./hello.tgz` |

>See `pycosign --help` for the full option matrix.

## Library Usage

```python
from pycosign import Signer, Verifier, KeyManager

signer = Signer(key_manager=KeyManager.from_key_file("cosign.key"))
sig_obj = signer.sign_blob_local("hello.tgz")
print(sig_obj.sig_path) # Path('hello.tgz.sig')

verifier = Verifier()
result = verifier.verify_local("hello.tgz", sig_obj.sig_path)
assert result.verified
```

Async batch signing example in `/examples/async_batch.py`.

## Documentation

* **Design Specification** - high-level architecture & diagrams
→ [pyCosign/documentation/design_specification.md](./documentation/design_specification.md)
* **Signing · Attesting · Verifying Primer** - conceptual deep-dive with sample artifacts
→ [pyCosign/documentation/signing-attesting-verifying.md](./documentation/signing-attesting-verifying.md)

## Contributing
Bug reports, feature requests, and PRs are welcome! Please see `[CONTRIBUTING.md](CONTRIBUTING.md)` for the workflow, coding style, and DCO sign-off requirements.

## License
Released under the [MIT License](LICENSE).
Loading