Skip to content

Commit 866cfd2

Browse files
Merge pull request #1 from interwebshack/feature/initial-design
Feature/initial design
2 parents 78be928 + c06383c commit 866cfd2

35 files changed

Lines changed: 1500 additions & 2 deletions

.github/workflows/ci.yml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# .github/workflows/ci.yml
2+
name: CI
3+
on:
4+
push:
5+
branches: [feature/initial-design]
6+
pull_request:
7+
branches: [main]
8+
9+
jobs:
10+
ci:
11+
name: "pyCosign CI Pipeline | (Python ${{ matrix.python-version }})"
12+
strategy:
13+
matrix:
14+
python-version: ["3.10"]
15+
poetry-version: ["2.1.3"]
16+
os: [ubuntu-22.04]
17+
runs-on: ${{ matrix.os }}
18+
steps:
19+
- uses: actions/checkout@v4
20+
- name: Set up Python
21+
uses: actions/setup-python@v5
22+
with:
23+
python-version: ${{ matrix.python-version }}
24+
- name: Install poetry
25+
uses: abatilo/actions-poetry@v4
26+
- name: Setup a local virtual environment (if no poetry.toml file)
27+
run: |
28+
poetry config virtualenvs.create true --local
29+
poetry config virtualenvs.in-project true --local
30+
- uses: actions/cache@v3
31+
name: Define a cache for the virtual environment based on the dependencies lock file
32+
with:
33+
path: ./.venv
34+
key: venv-${{ hashFiles('poetry.lock') }}
35+
- name: Install the project dependencies
36+
run: poetry install
37+
- name: Run Black in check mode
38+
run: poetry run black --check --verbose pycosign
39+
- name: Run Isort in check mode
40+
run: poetry run isort --verbose pycosign

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Changelog
2+
3+
All notable changes to this project will be documented in this file.
4+
5+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7+

CONTRIBUTING.md

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
# Contributing to pyCosign
2+
3+
First off, **thank you for taking the time to contribute!**
4+
The following guidelines help keep the project consistent and maintainable.
5+
6+
---
7+
8+
## Table of Contents
9+
1. [Code of Conduct](#code-of-conduct)
10+
2. [Getting Started](#getting-started)
11+
3. [Branching & Workflow](#branching--workflow)
12+
4. [Commit Conventions](#commit-conventions)
13+
5. [Developer Certificate of Origin (DCO)](#developer-certificate-of-origin-dco)
14+
6. [Coding Style](#coding-style)
15+
7. [Testing](#testing)
16+
8. [Pull-Request Checklist](#pull-request-checklist)
17+
9. [Release Process](#release-process)
18+
19+
---
20+
21+
## Code of Conduct
22+
We follow the [Contributor Covenant](https://www.contributor-covenant.org/version/2/1/code_of_conduct/) v2.1.
23+
Please be respectful and inclusive in all interactions.
24+
25+
---
26+
27+
### Getting Started (Poetry)
28+
29+
```bash
30+
# clone
31+
git clone https://github.com/your-org/pycosign.git
32+
cd pycosign
33+
34+
# install Poetry (if not already)
35+
curl -sSL https://install.python-poetry.org | python3 -
36+
37+
# create & activate venv + install deps
38+
poetry install --with dev
39+
40+
# drop into project shell
41+
poetry shell
42+
43+
# install git hooks
44+
pre-commit install
45+
46+
*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].*
47+
48+
### Prerequisites
49+
50+
| Tool | Required Version | Notes |
51+
|------------------|------------------|-------|
52+
| **Poetry** | 1.8 or newer | Dependency & virtual-env manager |
53+
| **Python** | 3.10 – 3.12 | Poetry will auto-select within this range |
54+
| **cosign CLI** | ≥ 2.2 | `brew install sigstore/tap/cosign` or download release binary |
55+
| **plantuml** | _optional_ | Render `.puml` diagrams locally (`brew install plantuml`) |
56+
| **Docker** | _optional_ | Quick PlantUML preview, OCI registry tests |
57+
58+
## Branching & Workflow
59+
60+
* **`main`** — always releasable; tagged releases are cut from here.
61+
* **Feature branches** — name `feature/<short-topic>` (e.g., `feature/registry-push`).
62+
* **Bug-fix branches** — name `bugfix/<issue-#>` (e.g., `bugfix/42-null-sig-path`).
63+
* **Documentation-only branches** — name `docs/<topic>`.
64+
65+
Workflow:
66+
67+
1. Create an **Issue** if one doesn’t exist.
68+
2. Branch from `main` with the naming rules above.
69+
3. Work locally in a Poetry shell:
70+
```bash
71+
poetry shell
72+
git checkout -b feature/my-cool-thing
73+
```
74+
4. Keep commits small, descriptive, and signed (`git commit -s`).
75+
5. Push to your fork / to the repo: `git push -u origin feature/my-cool-thing`.
76+
6. Open a **pull request** against `main`. GitHub Actions will run:
77+
* lint → test → type-check → coverage → packaging checks.
78+
7. Address review comments; squash-merge once approved.
79+
> **Tip:** Use `git rebase -i main` to keep history clean before opening the PR.
80+
81+
## Commit Conventions
82+
83+
We follow **Conventional Commits**:
84+
```bash
85+
feature(signer): add --push flag for sign-blob
86+
bugfix(verifier): handle missing Rekor bundle gracefully
87+
docs: update README diagrams
88+
```
89+
90+
## Developer Certificate of Origin (DCO)
91+
92+
By submitting a PR you certify you have the right to submit the work under the project’s [MIT license](LICENSE).
93+
Sign your commits:
94+
95+
```bash
96+
git commit -s -m "bugfix: correct typo"
97+
```
98+
The `-s` flag adds the required `Signed-off-by` line.
99+
100+
## Coding Style
101+
102+
* **ruff** for linting (`black`, `isort`, `flake8` rules)
103+
* Docstrings follow **Google style**.
104+
105+
Run all checks:
106+
107+
* **black** for formatting (PEP 8 compliant).
108+
```bash
109+
poetry run black --verbose pycosign
110+
```
111+
112+
* **isort** your imports, so you don't have to.
113+
```bash
114+
poetry run isort --verbose pycosign
115+
```
116+
117+
## Testing
118+
119+
* **pytest** with **pytest-asyncio** for async routines.
120+
* 90%+ coverage target.
121+
122+
```bash
123+
pytest -q
124+
```
125+
CI will fail if coverage drops below the threshold.
126+
127+
## Pull-Request Checklist
128+
129+
Before requesting a review, make sure you can check **every** box below:
130+
131+
- [ ] **Issue linked** (e.g., “Closes #123”) or marked N/A for trivial docs fixes.
132+
- [ ] **Unit / integration tests** added or updated; `poetry run pytest` passes locally.
133+
- [ ] **Docs updated** (`README`, `docs/`, or inline docstrings) if behavior changed.
134+
- [ ] **Changelog entry** added under `## [Unreleased]` in `CHANGELOG.md`.
135+
- [ ] `pre-commit run --all-files` passes (ruff, black, mypy, etc.).
136+
- [ ] All commits are **signed** (`git commit -s`) to satisfy the DCO.
137+
- [ ] PR title follows **Conventional Commits** (e.g., `feat(verifier): add policy flag`).
138+
- [ ] CI status is green (GitHub Actions).
139+
140+
> 🔒 PRs without a Signed-off-by line will be blocked by the DCO GitHub check.
141+
142+
## Release Process
143+
144+
1. Merge all features into `main`.
145+
2. Bump version with `bumpver update --push-tag`.
146+
3. GitHub Action builds sdist & wheels and uploads to PyPI.
147+
4. Draft release notes in `CHANGELOG.md`.
148+
149+
Happy hacking! 💙

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2025 interwebshack
3+
Copyright (c) 2025 **pyCosign contributors**
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

README.md

Lines changed: 99 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,100 @@
11
# pyCosign
2-
Python Wrapper for Sigstor Cosign
2+
3+
> A Pythonic façade around the **Sigstore `cosign` CLI** — sign, attest, and verify artifacts from pure Python or the command line.
4+
5+
[![Build](https://img.shields.io/github/actions/workflow/status/interwebshack/pycosign/ci.yml?branch=main)](https://github.com/interwebshack/pycosign/actions)
6+
[![License](https://img.shields.io/github/license/interwebshack/pycosign)](LICENSE)
7+
8+
---
9+
10+
## Table of Contents
11+
1. [Motivation](#motivation)
12+
2. [Features](#features)
13+
3. [Quick Start](#quick-start)
14+
4. [CLI Examples](#cli-examples)
15+
5. [Library Usage](#library-usage)
16+
6. [Documentation](#documentation)
17+
7. [Contributing](#contributing)
18+
8. [License](#license)
19+
20+
---
21+
22+
## Motivation
23+
`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*.
24+
25+
---
26+
27+
## Features
28+
* 📜 **Sign, verify, attest** files or OCI artifacts
29+
* 🔑 **Key sources**: PEM file, Fulcio keyless, HSM / PKCS #11
30+
* 🌐 **Storage targets**: Local filesystem, OCI registry, Rekor log
31+
***Async orchestration** for batch pipelines
32+
* 📝 **Rich logging** and typed return objects (`Signature`, `VerificationResult`, `Attestation`)
33+
* 🐍 Python 3.10+ & MIT-licensed
34+
35+
---
36+
37+
## Quick Start
38+
39+
```bash
40+
# install cosign (v2.2+) first
41+
brew install sigstore/tap/cosign # macOS example
42+
43+
# install pyCosign
44+
pip install pycosign
45+
```
46+
47+
Create a signature for hello.tgz:
48+
49+
```bash
50+
pycosign sign-blob --key cosign.key ./hello.tgz # → hello.tgz.sig
51+
```
52+
53+
Verify it:
54+
55+
```bash
56+
pycosign verify-blob --signature hello.tgz.sig ./hello.tgz
57+
```
58+
59+
---
60+
61+
## CLI Examples
62+
63+
| Task | Command |
64+
|------|---------|
65+
| **Sign OCI image** | `pycosign sign registry.local/hello:1.0` |
66+
| **Sign local file → push signature to registry** | `pycosign sign-blob --push registry.local/hello:1.0 ./hello.tgz` |
67+
| **Attest local file with SPDX SBOM** | `pycosign attest-blob --predicate sbom.json ./hello.tgz` |
68+
| **Verify local file with detached `.sig`** | `pycosign verify-blob --signature hello.tgz.sig ./hello.tgz` |
69+
| **Verify attestation bundle offline** | `pycosign verify-attestation --type https://spdx.dev/Document --signature hello.tgz.att ./hello.tgz` |
70+
71+
>See `pycosign --help` for the full option matrix.
72+
73+
## Library Usage
74+
75+
```python
76+
from pycosign import Signer, Verifier, KeyManager
77+
78+
signer = Signer(key_manager=KeyManager.from_key_file("cosign.key"))
79+
sig_obj = signer.sign_blob_local("hello.tgz")
80+
print(sig_obj.sig_path) # Path('hello.tgz.sig')
81+
82+
verifier = Verifier()
83+
result = verifier.verify_local("hello.tgz", sig_obj.sig_path)
84+
assert result.verified
85+
```
86+
87+
Async batch signing example in `/examples/async_batch.py`.
88+
89+
## Documentation
90+
91+
* **Design Specification** - high-level architecture & diagrams
92+
[pyCosign/documentation/design_specification.md](./documentation/design_specification.md)
93+
* **Signing · Attesting · Verifying Primer** - conceptual deep-dive with sample artifacts
94+
[pyCosign/documentation/signing-attesting-verifying.md](./documentation/signing-attesting-verifying.md)
95+
96+
## Contributing
97+
Bug reports, feature requests, and PRs are welcome! Please see `[CONTRIBUTING.md](CONTRIBUTING.md)` for the workflow, coding style, and DCO sign-off requirements.
98+
99+
## License
100+
Released under the [MIT License](LICENSE).

0 commit comments

Comments
 (0)