Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
115 commits
Select commit Hold shift + click to select a range
5513268
🔧 build: add project tooling and policies
gaborbernat Nov 7, 2026
5c0a18b
✨ feat: add the PEP 770 SBOM build hook
gaborbernat Nov 7, 2026
041efed
👷 ci: add check, release and security workflows
gaborbernat Nov 7, 2026
a692292
📝 docs: pin the first release in the example
gaborbernat Nov 7, 2026
b57cafb
♻️ refactor: split into private modules, add embed
gaborbernat Nov 7, 2026
6b77aea
📝 docs: add the Read the Docs site
gaborbernat Nov 7, 2026
6092cc2
🔧 build: adopt the bump-deps-index tooling
gaborbernat Nov 7, 2026
522b147
🚚 refactor: rename the project to python-sbom
gaborbernat Nov 7, 2026
993f1a7
🐛 fix: hash absolute build scripts on Windows
gaborbernat Nov 7, 2026
1120300
👷 ci: trim the check matrix to 13 jobs
gaborbernat Nov 7, 2026
2c0a899
✅ test: build the bundled seed wheel at test time
gaborbernat Nov 7, 2026
f91c1c9
♻️ refactor: split the core from the hatch backend
gaborbernat Nov 7, 2026
e9efe48
🔒 build: relock for the hatch extra and docs deps
gaborbernat Nov 7, 2026
9f55e4a
♻️ refactor: rebuild around one SBOM pipeline
gaborbernat Nov 7, 2026
c4bc75c
📦 build: embed the project's own SBOM
gaborbernat Nov 7, 2026
2891f8a
📝 docs: document providers and the pipeline
gaborbernat Nov 7, 2026
26b526e
🔧 chore: align repository files with conventions
gaborbernat Nov 7, 2026
c45b6ef
♻️ refactor: break the CLI options import cycle
gaborbernat Nov 7, 2026
af0e85f
🐛 fix: import TypeIs only when type checking
gaborbernat Nov 7, 2026
5238152
♻️ refactor: shrink the API to the provider seam
gaborbernat Nov 7, 2026
ab7d9f0
📝 docs: document providers and the archive command
gaborbernat Nov 7, 2026
d4ebc94
🔧 chore: follow bump-deps-index tooling
gaborbernat Nov 7, 2026
86def47
📝 docs: match the virtualenv example to its patch
gaborbernat Nov 7, 2026
6e4335e
🚧 wip: adopt libraries, cap validation, bench
gaborbernat Nov 7, 2026
764f69a
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 7, 2026
3bdd22e
♻️ refactor: parse dist-info files with installer
gaborbernat Nov 7, 2026
2d87c0d
🔒 build: lock dep-logic
gaborbernat Nov 7, 2026
0c4aba6
✅ test: pin embed output byte for byte
gaborbernat Nov 7, 2026
95af3d1
⏪ revert: evaluate markers without dep-logic
gaborbernat Nov 7, 2026
ed0130b
⚡ perf: read build-env RECORDs directly
gaborbernat Nov 7, 2026
ff8e0fc
⚡ perf: copy wheel members without recompressing
gaborbernat Nov 7, 2026
d89b69a
📝 docs: say why the CycloneDX model is our own
gaborbernat Nov 7, 2026
f986ea0
♻️ refactor: parse core metadata with packaging
gaborbernat Nov 7, 2026
778cd1b
⚡ perf: finish the pyperf benchmark harness
gaborbernat Nov 7, 2026
2832b0c
🔒 build: lock the bench dependency group
gaborbernat Nov 7, 2026
d901f72
🐛 fix(bench): keep hostile documents at their count
gaborbernat Nov 7, 2026
2bdde37
⚡ perf: check uniqueItems in one pass
gaborbernat Nov 7, 2026
be210dc
⚡ perf: settle most iri-reference checks by regex
gaborbernat Nov 7, 2026
cfe70dc
⚡ perf: validate the schema with jsonschema-rs
gaborbernat Nov 7, 2026
9749e0e
📦 build: ship the CycloneDX schema files
gaborbernat Nov 7, 2026
60381fc
✨ feat: raise the default component cap to 100,000
gaborbernat Nov 7, 2026
2ca7b51
⚡ perf: count components before loading the validator
gaborbernat Nov 7, 2026
e7dcf48
📝 docs: add the performance changelog fragment
gaborbernat Nov 7, 2026
0033c11
🐛 fix: compress the SBOM archive --embed adds
gaborbernat Nov 7, 2026
ad06520
⚡ perf: parse only the metadata headers
gaborbernat Nov 7, 2026
fa8c3fd
⚡ perf: verify bundled wheels in parallel
gaborbernat Nov 7, 2026
0dcafe6
⚡ perf: copy the wheel through the process
gaborbernat Nov 7, 2026
e5213ad
⚡ perf: match uv cache files without a regex
gaborbernat Nov 7, 2026
f014f18
⚡ perf: load the hook's wheel code only for wheels
gaborbernat Nov 7, 2026
286033c
⚡ perf: load each command's modules when it runs
gaborbernat Nov 7, 2026
7114bfe
📝 docs: wrap comments and prose at 120
gaborbernat Nov 7, 2026
edb4357
♻️ refactor: build every artifact's SBOM in one place
gaborbernat Nov 7, 2026
9faebb2
🐛 fix: fail the build on contributions validate rejects
gaborbernat Nov 7, 2026
83e18c8
♻️ refactor: resolve the content provider in one place
gaborbernat Nov 7, 2026
94ffd78
✅ test: check member types in the API closure
gaborbernat Nov 7, 2026
06c6f74
🐛 fix: read archives from the zip, not the disk
gaborbernat Nov 7, 2026
09c0aa4
♻️ refactor: write every zip entry one way
gaborbernat Nov 7, 2026
53a236e
📦 build: declare the schemas' Apache-2.0 license
gaborbernat Nov 7, 2026
744e8f7
✅ test: validate the built wheel's own SBOM
gaborbernat Nov 7, 2026
a8a6897
📝 docs(changelog): fold validation into feature
gaborbernat Nov 7, 2026
fee1ec2
📝 docs(security): name python-sbom archive
gaborbernat Nov 7, 2026
6daa53e
📝 docs(extend): show the tested seeder hook
gaborbernat Nov 7, 2026
4a3d379
📝 docs(extend): read RECORD to list files
gaborbernat Nov 7, 2026
f48e640
📝 docs(contributing): explain updating the schemas
gaborbernat Nov 7, 2026
9fce8b9
📝 docs(contributing): describe the benchmarks
gaborbernat Nov 7, 2026
7ca9c92
📝 docs(explanation): drop the drifting SBOM size
gaborbernat Nov 7, 2026
3929e46
📝 docs(explanation): split the architecture intro
gaborbernat Nov 7, 2026
75ca33b
📝 docs(bench): explain why _once stays apart
gaborbernat Nov 7, 2026
5b9bb66
🐛 fix: keep requirements if packaging's tree moves
gaborbernat Nov 7, 2026
286ee5c
🐛 fix: copy the Keywords header as declared
gaborbernat Nov 7, 2026
66ec241
♻️ refactor: share one JSON alias and text cap
gaborbernat Nov 7, 2026
7648ccb
🐛 fix: blame the JSON parser for deep nesting
gaborbernat Nov 7, 2026
ab339fb
🐛 fix: report a broken validate extra as missing
gaborbernat Nov 7, 2026
760c7af
🐛 fix: tie the SBOM size limit to the component cap
gaborbernat Nov 7, 2026
bba7956
🐛 fix: report an SBOM that is not UTF-8
gaborbernat Nov 7, 2026
9a61125
⚡ perf: check the SPDX rendering in linear time
gaborbernat Nov 7, 2026
6e12241
♻️ refactor(model): share one component walker
gaborbernat Nov 7, 2026
f1ae1ea
✅ test(content): check the falsy provider is falsy
gaborbernat Nov 7, 2026
316278c
♻️ refactor(model): rename the namespace params
gaborbernat Nov 7, 2026
e3f91fe
♻️ refactor: move revision_reader to _collect
gaborbernat Nov 7, 2026
c5d5ea5
♻️ refactor: drop parameters callers fill alike
gaborbernat Nov 7, 2026
5035b7a
♻️ refactor: unnest the double-loop comprehensions
gaborbernat Nov 7, 2026
9bc21af
🎨 style: keep suppressions within 120 columns
gaborbernat Nov 7, 2026
cf5d589
✅ test(bom): parametrize the bundled supplier
gaborbernat Nov 7, 2026
16d9ad7
✅ test(embed): pin the Python version with mocker
gaborbernat Nov 7, 2026
1263180
🐛 fix(model): link files at the built commit
gaborbernat Nov 7, 2026
eb3cd2b
🐛 fix(model): encode URLs validate would reject
gaborbernat Nov 7, 2026
4331139
♻️ refactor: walk components the same way in validate
gaborbernat Nov 7, 2026
76676dd
♻️ refactor: give each command its own module
gaborbernat Nov 7, 2026
5ddcba2
📝 docs(cli): describe the spdx command
gaborbernat Nov 7, 2026
0b53ee0
🐛 fix: refuse a --max-components below one
gaborbernat Nov 7, 2026
1aea9a3
📝 docs(cli): say the component cap sets the size
gaborbernat Nov 7, 2026
13dcb69
🐛 fix: report unreadable spdx input without a trace
gaborbernat Nov 7, 2026
0d4fd8e
🐛 fix: read the source revision once per build
gaborbernat Nov 7, 2026
18810cf
🐛 fix: remove the sdist revision file after the build
gaborbernat Nov 7, 2026
b9bb91a
🎨 style: fit the hook's suppressions in 120 columns
gaborbernat Nov 7, 2026
9395d00
🐛 fix: record the revision in python-sbom's own sdist
gaborbernat Nov 7, 2026
a935e88
✅ test: check one behaviour per CLI and hook test
gaborbernat Nov 7, 2026
09c3254
⚡ perf: keep validation out of --help and --version
gaborbernat Nov 7, 2026
b3728af
♻️ refactor: raise one error class
gaborbernat Nov 7, 2026
952da4c
📝 docs: redraw the architecture from the imports
gaborbernat Nov 7, 2026
e1919d4
🐛 fix: pass the docs and coverage checks
gaborbernat Nov 7, 2026
8112d47
🐛 fix: normalize every pypi purl name
gaborbernat Nov 7, 2026
9ea289b
⚡ perf: load the license parser only for a policy
gaborbernat Nov 7, 2026
84412c7
⚡ perf: stack only containers in the census
gaborbernat Nov 7, 2026
1425769
⚡ perf: read build-env WHEEL and requirements once
gaborbernat Nov 7, 2026
f189bf1
✨ feat: deflate the SBOM archive --embed adds
gaborbernat Nov 7, 2026
9b29173
🧪 test(spdx): nest deep enough for every stack
gaborbernat Nov 7, 2026
aab7c01
♻️ refactor: give archive the wheel's layering
gaborbernat Nov 7, 2026
4b05ac0
♻️ refactor: move bundled wheel checks into _wheel
gaborbernat Nov 7, 2026
eb528e9
♻️ refactor: name bundled wheels while reading them
gaborbernat Nov 7, 2026
dd1eb38
♻️ refactor: ask providers in component order
gaborbernat Nov 7, 2026
79f8dde
🐛 fix(archive): refuse or describe odd bundled layouts
gaborbernat Nov 7, 2026
e8ca8f6
♻️ refactor: share artifact reads and graph rules
gaborbernat Nov 7, 2026
0d98857
⬆️ ci: pin github-workflows 6.7.2
gaborbernat Nov 8, 2026
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
3 changes: 3 additions & 0 deletions .git_archival.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node: $Format:%H$
node-date: $Format:%cI$
describe-name: $Format:%(describe:tags=true,match=*[0-9]*)$
3 changes: 3 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.git_archival.txt export-subst
tests/_generate/pinned/** -text
src/python_sbom/_validate/schemas/** -text
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* @gaborbernat
18 changes: 18 additions & 0 deletions .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Contributing

Add a `docs/changelog.d/+short-name.<type>.rst` fragment for a change that affects package users. Choose a unique short
name; the release workflow links the fragment to its merged squash pull request and credits the human author. A pull
request number is not needed in the filename.

Use `feature` for Added, `change` for Changes, `bugfix` for Fixed, and `doc` for Documentation. Use `breaking`,
`security`, `performance`, `deprecation`, `removal`, or `packaging` only when the change affects users in that way. A
supported Python version added or removed is a `feature` and results in a minor release.

Use `skip news` for internal maintenance without a user-facing change. The label may be added after opening the pull
request. Dependabot and maintenance bot pull requests without a fragment receive it automatically; a bot pull request
with a fragment still needs the news check to pass. For a change written by more than one person, put all human authors
in a `by` credit. Do not list bots or reviewers.

The documentation preview shows fragments under Unreleased. The versioned `docs/changelog.rst` changes only during
release preparation. The release workflow chooses a version from the fragment types, runs `prek` on the assembled
changelog, and publishes GitHub notes from the tagged changelog after PyPI succeeds.
2 changes: 2 additions & 0 deletions .github/FUNDING.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
github: gaborbernat
thanks_dev: u/gh/gaborbernat
47 changes: 47 additions & 0 deletions .github/SECURITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Security policy

python-sbom writes a CycloneDX SBOM into wheels, from a hatchling build hook or from `python-sbom embed`, which rewrites
a wheel another build backend built. `python-sbom archive` describes another zip archive a project publishes, such as a
zipapp, and `python-sbom spdx` and `validate` render or check an SBOM. This policy says how to report a security problem
and how we decide whether a report is one.

## Reporting a vulnerability

**Do not open a public issue for a security problem.** Use
[GitHub's private vulnerability reporting](https://github.com/tox-dev/python-sbom/security/advisories/new). If neither
works for you, email [gaborjbernat@gmail.com](mailto:gaborjbernat@gmail.com).

Include what the attacker controls and what they gain, the steps or a proof of concept, and the versions and platform
you tested. Write the report yourself; unreviewed tool or model output takes longer to triage.

## What to expect

Volunteers maintain python-sbom, with no on-call rotation. We aim to acknowledge a report within **5 working days** and
assess it within **15 working days**. Fixes are developed in a private fork attached to the draft advisory, ship in a
new release, and the advisory, with a CVE requested through GitHub, goes out with that release. The default embargo is
**90 days** from the report; we agree any change with the reporter. We credit reporters in the advisory under the name
they choose, or not at all. There is no bug bounty.

## Supported versions

Only the latest release receives fixes. Confirm the problem reproduces on it before reporting.

## Vulnerability or bug

A report is a vulnerability when an attacker who controls only an input that the [threat model](THREAT_MODEL.md) lists
as untrusted breaks a guarantee python-sbom makes. A report that first needs control of something the threat model
trusts, such as the project source, its `pyproject.toml` or the build environment, is a bug: we fix it in the open and
publish no advisory. Classify by who supplies the dangerous input, not by how bad the outcome sounds.

**In scope**

- A wheel bundled in a wheel or in an archive given to `python-sbom archive`, or an SBOM given to `python-sbom spdx` or
`validate`, that makes python-sbom write outside its output file or the wheel or archive it rewrites, or run code.
- An SBOM that misstates what a wheel holds in a way its inputs cannot explain, such as a wrong hash.

**Out of scope**

- Anything hatchling's own build trusts.
- Vulnerabilities in the packages an SBOM lists; report those to their projects.

If you cannot tell which side a finding falls on, report it privately and we will decide.
78 changes: 78 additions & 0 deletions .github/THREAT_MODEL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Threat model

This model says what python-sbom trusts, where untrusted input enters, and which guarantees hold at each boundary, so a
report can be classified as a vulnerability or a bug. [SECURITY.md](SECURITY.md) covers reporting; if the two disagree,
SECURITY.md wins and we fix this file.

## How python-sbom works

The build hook runs inside a hatchling wheel build. It reads the wheel's core metadata, the project's license files, the
wheels the project bundles and the installed distributions of the build environment, and writes a CycloneDX document
that it writes into the built wheel. `python-sbom embed` does the same for a wheel another backend built,
`python-sbom archive` describes another zip archive such as a zipapp, and `python-sbom spdx` and `validate` read
CycloneDX documents and write or check them.

```mermaid
flowchart LR
project[("Project source, pyproject.toml<br/>(trusted)")] --> hook["python-sbom"]
env[("Build environment<br/>(trusted)")] --> hook
bundled[("Bundled wheels<br/>(third-party content)")] -->|"metadata, RECORD, vendor list"| hook
sbom[("SBOM files given to spdx, validate")] -->|"untrusted JSON"| hook
hook --> wheel[("Wheel")]
classDef trusted fill:#cfe4ff,stroke:#1f6feb,color:#0b1f3a;
classDef boundary fill:#ffe3a3,stroke:#d29200,color:#3a2c00;
class project,env,hook,wheel trusted;
class bundled,sbom boundary;
```

## Trusted

An attacker who controls any of these already has what python-sbom could give them:

- The project source, its `pyproject.toml`, the build hook script, and the module the `content-provider` option or
`--content-provider` names: python-sbom imports that module from the project directory, so `embed` and `archive` run
code from `--root`.
- The git checkout that tracks the project, whose `HEAD` python-sbom reads. A repository that merely contains the
project directory is not trusted: git is used only when it tracks the project, and runs with `core.fsmonitor` off.
- The build environment and the build backend.
- The wheel handed to `python-sbom embed` and the archive handed to `python-sbom archive`, which the project's own build
produced.

## Untrusted inputs

| Input | Comes from | What python-sbom guarantees |
| --------------------------------------- | ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Metadata and `RECORD` of bundled wheels | Upstream projects | Read as text with capped sizes, copied as JSON strings; every member is checked against its `RECORD` row, duplicate members are refused, nothing is executed. |
| `_vendor/vendor.txt` of bundled wheels | Upstream projects | Each line must pin one exact version, or the build fails. |
| SBOM files given to `spdx`, `validate` | Whoever produced the file | Parsed as JSON only, with sizes capped by the component cap; `validate` refuses nesting past 128 levels and reports problems instead of raising them; `spdx` reports input too deep to parse as an error and writes the one file named on the command line. |

## Threats and controls

| STRIDE | Threat | Control |
| ---------------------- | ---------------------------------------------------------- | ------------------------------------------------------------- |
| Tampering | A bundled wheel's metadata injects JSON into the document. | The document is serialized with `json.dumps`. |
| Tampering | A bundled wheel changes and the SBOM still lists it. | Each bundled wheel is hashed from its bytes at build time. |
| Elevation of privilege | A bundled wheel runs code during the build. | Wheels are read as zip archives; nothing in them is imported. |

## Release chain

Releases run on the shared [tox-dev/github-workflows](https://github.com/tox-dev/github-workflows) pipeline. A release
App, not a person, pushes the release commit and tag; the build installs its tools from a hash-checked `pylock.toml`
resolved with a seven-day upload cooldown by default; PyPI receives the files through
[trusted publishing](https://docs.pypi.org/trusted-publishers/) with attestations, and the GitHub Release is immutable.
Every workflow pins third-party actions to a commit SHA.

## Severity

- **High:** a bundled wheel or SBOM file that makes python-sbom run code or write outside its output.
- **Medium:** an SBOM that misstates a hash, a license or the contents of a wheel.
- **Low:** a crash on a malformed bundled wheel or SBOM file instead of a clean error.

## Accepted risks

- The SBOM reports what the build environment holds; it does not check that environment against a lock.

## Keeping this current

Revisit this model when python-sbom gains a new input, a new way to run code, or a new place it writes to, and whenever
an advisory is published.
30 changes: 30 additions & 0 deletions .github/dependabot.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
version: 2
multi-ecosystem-groups:
dependencies:
schedule:
interval: weekly
day: tuesday
labels:
- dependencies
- skip news
updates:
- package-ecosystem: github-actions
directory: /
patterns:
- '*'
multi-ecosystem-group: dependencies
labels:
- dependencies
- skip news
cooldown:
default-days: 7
- package-ecosystem: pre-commit
directory: /
patterns:
- '*'
multi-ecosystem-group: dependencies
labels:
- dependencies
- skip news
cooldown:
default-days: 7
5 changes: 5 additions & 0 deletions .github/release.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
changelog:
exclude:
authors:
- dependabot[bot]
- pre-commit-ci[bot]
62 changes: 62 additions & 0 deletions .github/workflows/check.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
name: 🧪 check
on:
workflow_dispatch:
push:
branches: ["main"]
pull_request:
types: [opened, synchronize, reopened]
schedule:
- cron: "27 8 * * *"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
test:
name: 🧪 test
if: github.event_name != 'schedule' || github.repository == 'tox-dev/python-sbom'
uses: tox-dev/github-workflows/.github/workflows/check.yaml@0c4cffd63033d38196319524d101caae1eef925b # 6.7.2
permissions:
contents: read
with:
include: |
[
{"env": "3.15", "python": "3.15"},
{"env": "3.14", "python": "3.14"},
{"env": "3.13", "python": "3.13"},
{"env": "3.12", "python": "3.12"},
{"env": "3.11", "python": "3.11"},
{"env": "3.15", "python": "3.15", "os": "windows-2025"},
{"env": "3.11", "python": "3.11", "os": "windows-2025"},
{"env": "3.15", "python": "3.15", "os": "macos-26"},
{"env": "dev"},
{"env": "docs"},
{"env": "fix"},
{"env": "type"},
{"env": "pkg_meta"}
]
release:
name: 🏷️ Release dry run
uses: $/.github/workflows/prepare-release.yaml
permissions:
contents: read
pull-requests: read
with:
dry-run: true
hooks:
name: 🧹 Hooks under the cooldown
uses: tox-dev/github-workflows/.github/workflows/cooled-hooks.yaml@0c4cffd63033d38196319524d101caae1eef925b # 6.7.2
permissions:
contents: read
gate:
name: 🚦 ${{ github.event_name == 'pull_request' && 'Required checks pass' || 'Non-PR checks pass' }}
if: ${{ !cancelled() }} # codespell:ignore cancelled
needs: [test, release, hooks]
runs-on: ubuntu-26.04
permissions: {}
steps:
- name: 🚦 Require all needed jobs to pass
uses: tox-dev/github-workflows/required-checks@0c4cffd63033d38196319524d101caae1eef925b # 6.7.2
with:
needs: ${{ toJSON(needs) }}
22 changes: 22 additions & 0 deletions .github/workflows/codeql.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: 🛡️ CodeQL
on:
workflow_dispatch:
push:
branches: ["main"]
pull_request:
schedule:
- cron: "35 8 * * 2"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions: {}
jobs:
analyze:
name: 🛡️ Analyze
uses: tox-dev/github-workflows/.github/workflows/codeql.yaml@0c4cffd63033d38196319524d101caae1eef925b # 6.7.2
permissions:
contents: read
security-events: write
with:
languages: '["actions","python"]'
paths-ignore: '["tests"]'
30 changes: 30 additions & 0 deletions .github/workflows/news.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: Changelog
on:
pull_request:
types: [opened, reopened, synchronize, labeled, unlabeled]
permissions:
contents: read
pull-requests: read
jobs:
changelog:
name: 📝 News fragment
runs-on: ubuntu-26.04
steps:
- name: 📥 Checkout code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
persist-credentials: false
- name: 🐍 Install uv
uses: astral-sh/setup-uv@68559e99cc807c1eb7e9238fd43a15bba460eec2 # v10.3.3
with:
version: latest-known
python-version: "3.15"
enable-cache: false
- name: 📦 Install locked release tools
uses: tox-dev/github-workflows/install-locked-tools@0c4cffd63033d38196319524d101caae1eef925b # 6.7.2
with:
groups: release-news
venv: ${{ runner.temp }}/release-tools
- name: 🔍 Validate changelog fragments
uses: tox-dev/github-workflows/validate-news@0c4cffd63033d38196319524d101caae1eef925b # 6.7.2
34 changes: 34 additions & 0 deletions .github/workflows/prepare-release.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: Prepare release
on:
workflow_dispatch:
inputs:
bump:
description: Version bump strategy
required: true
type: choice
options:
- auto
- major
- minor
- patch
default: auto
workflow_call:
inputs:
dry-run:
description: Assemble the release without pushing, for the pull request gate
type: boolean
required: true
permissions: {}
jobs:
prepare:
name: 🏷️ Prepare Towncrier release
uses: tox-dev/github-workflows/.github/workflows/prepare-towncrier-release.yaml@0c4cffd63033d38196319524d101caae1eef925b # 6.7.2
permissions:
contents: read
pull-requests: read
with:
bump: ${{ inputs.bump || 'auto' }}
dry-run: ${{ inputs.dry-run == true }}
release-auth-deployment: false
secrets:
RELEASE_APP_PRIVATE_KEY: ${{ secrets.RELEASE_APP_PRIVATE_KEY }}
Loading
Loading