python-sbom 0.1.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- python_sbom-0.1.1/.git_archival.txt +3 -0
- python_sbom-0.1.1/.gitattributes +3 -0
- python_sbom-0.1.1/.github/CODEOWNERS +1 -0
- python_sbom-0.1.1/.github/CONTRIBUTING.md +18 -0
- python_sbom-0.1.1/.github/FUNDING.yaml +2 -0
- python_sbom-0.1.1/.github/SECURITY.md +47 -0
- python_sbom-0.1.1/.github/THREAT_MODEL.md +78 -0
- python_sbom-0.1.1/.github/dependabot.yaml +30 -0
- python_sbom-0.1.1/.github/release.yaml +5 -0
- python_sbom-0.1.1/.github/workflows/check.yaml +62 -0
- python_sbom-0.1.1/.github/workflows/codeql.yaml +22 -0
- python_sbom-0.1.1/.github/workflows/news.yaml +30 -0
- python_sbom-0.1.1/.github/workflows/prepare-release.yaml +34 -0
- python_sbom-0.1.1/.github/workflows/release.yaml +56 -0
- python_sbom-0.1.1/.github/workflows/scorecard.yaml +26 -0
- python_sbom-0.1.1/.github/workflows/upgrade-release-tools.yaml +17 -0
- python_sbom-0.1.1/.gitignore +6 -0
- python_sbom-0.1.1/.pre-commit-config.yaml +88 -0
- python_sbom-0.1.1/.python-sbom-revision +1 -0
- python_sbom-0.1.1/.readthedocs.yaml +8 -0
- python_sbom-0.1.1/CONTRIBUTING.md +5 -0
- python_sbom-0.1.1/LICENSE +18 -0
- python_sbom-0.1.1/PKG-INFO +95 -0
- python_sbom-0.1.1/README.md +51 -0
- python_sbom-0.1.1/bench/__init__.py +1 -0
- python_sbom-0.1.1/bench/__main__.py +337 -0
- python_sbom-0.1.1/bench/_cases.py +238 -0
- python_sbom-0.1.1/bench/_fixtures.py +319 -0
- python_sbom-0.1.1/docs/__init__.py +1 -0
- python_sbom-0.1.1/docs/_static/changelog-toc.css +12 -0
- python_sbom-0.1.1/docs/changelog.d/.gitkeep +0 -0
- python_sbom-0.1.1/docs/changelog.rst +35 -0
- python_sbom-0.1.1/docs/cli.rst +5 -0
- python_sbom-0.1.1/docs/conf.py +133 -0
- python_sbom-0.1.1/docs/contributing.rst +118 -0
- python_sbom-0.1.1/docs/explanation.rst +130 -0
- python_sbom-0.1.1/docs/extend.rst +113 -0
- python_sbom-0.1.1/docs/index.rst +43 -0
- python_sbom-0.1.1/docs/py_api.rst +87 -0
- python_sbom-0.1.1/docs/usage.rst +177 -0
- python_sbom-0.1.1/hatch_build.py +45 -0
- python_sbom-0.1.1/pylock.toml +3124 -0
- python_sbom-0.1.1/pyproject.toml +277 -0
- python_sbom-0.1.1/src/python_sbom/__init__.py +46 -0
- python_sbom-0.1.1/src/python_sbom/__main__.py +10 -0
- python_sbom-0.1.1/src/python_sbom/_cli/__init__.py +1 -0
- python_sbom-0.1.1/src/python_sbom/_cli/_archive.py +38 -0
- python_sbom-0.1.1/src/python_sbom/_cli/_embed.py +28 -0
- python_sbom-0.1.1/src/python_sbom/_cli/_main.py +28 -0
- python_sbom-0.1.1/src/python_sbom/_cli/_parser.py +144 -0
- python_sbom-0.1.1/src/python_sbom/_cli/_spdx.py +61 -0
- python_sbom-0.1.1/src/python_sbom/_cli/_validate.py +40 -0
- python_sbom-0.1.1/src/python_sbom/_collect/__init__.py +1 -0
- python_sbom-0.1.1/src/python_sbom/_collect/_archive.py +94 -0
- python_sbom-0.1.1/src/python_sbom/_collect/_content.py +109 -0
- python_sbom-0.1.1/src/python_sbom/_collect/_facts.py +155 -0
- python_sbom-0.1.1/src/python_sbom/_collect/_revision.py +93 -0
- python_sbom-0.1.1/src/python_sbom/_collect/_settings.py +82 -0
- python_sbom-0.1.1/src/python_sbom/_collect/_source.py +54 -0
- python_sbom-0.1.1/src/python_sbom/_collect/_wheel.py +55 -0
- python_sbom-0.1.1/src/python_sbom/_errors.py +15 -0
- python_sbom-0.1.1/src/python_sbom/_formats/__init__.py +1 -0
- python_sbom-0.1.1/src/python_sbom/_formats/_json.py +18 -0
- python_sbom-0.1.1/src/python_sbom/_formats/_spdx.py +263 -0
- python_sbom-0.1.1/src/python_sbom/_generate/__init__.py +1 -0
- python_sbom-0.1.1/src/python_sbom/_generate/_archive.py +84 -0
- python_sbom-0.1.1/src/python_sbom/_generate/_embed.py +74 -0
- python_sbom-0.1.1/src/python_sbom/_model/__init__.py +1 -0
- python_sbom-0.1.1/src/python_sbom/_model/_archive.py +117 -0
- python_sbom-0.1.1/src/python_sbom/_model/_bom.py +137 -0
- python_sbom-0.1.1/src/python_sbom/_model/_components.py +182 -0
- python_sbom-0.1.1/src/python_sbom/_model/_content.py +128 -0
- python_sbom-0.1.1/src/python_sbom/_model/_document.py +100 -0
- python_sbom-0.1.1/src/python_sbom/_model/_graph.py +64 -0
- python_sbom-0.1.1/src/python_sbom/_model/_identity.py +53 -0
- python_sbom-0.1.1/src/python_sbom/_model/_inputs.py +141 -0
- python_sbom-0.1.1/src/python_sbom/_model/_iri.py +96 -0
- python_sbom-0.1.1/src/python_sbom/_model/_licenses.py +58 -0
- python_sbom-0.1.1/src/python_sbom/_model/_markers.py +61 -0
- python_sbom-0.1.1/src/python_sbom/_model/_metadata.py +100 -0
- python_sbom-0.1.1/src/python_sbom/_model/_names.py +90 -0
- python_sbom-0.1.1/src/python_sbom/_model/_tools.py +48 -0
- python_sbom-0.1.1/src/python_sbom/_model/_types.py +281 -0
- python_sbom-0.1.1/src/python_sbom/_model/_wheel.py +89 -0
- python_sbom-0.1.1/src/python_sbom/_validate/__init__.py +1 -0
- python_sbom-0.1.1/src/python_sbom/_validate/_artifact.py +55 -0
- python_sbom-0.1.1/src/python_sbom/_validate/_document.py +221 -0
- python_sbom-0.1.1/src/python_sbom/_validate/_licenses.py +104 -0
- python_sbom-0.1.1/src/python_sbom/_validate/_limits.py +27 -0
- python_sbom-0.1.1/src/python_sbom/_validate/_schemas.py +124 -0
- python_sbom-0.1.1/src/python_sbom/_validate/schemas/LICENSE +201 -0
- python_sbom-0.1.1/src/python_sbom/_validate/schemas/bom-1.6.schema.json +5699 -0
- python_sbom-0.1.1/src/python_sbom/_validate/schemas/jsf-0.82.schema.json +240 -0
- python_sbom-0.1.1/src/python_sbom/_validate/schemas/spdx.schema.json +1662 -0
- python_sbom-0.1.1/src/python_sbom/_wheel/__init__.py +1 -0
- python_sbom-0.1.1/src/python_sbom/_wheel/_bundled.py +142 -0
- python_sbom-0.1.1/src/python_sbom/_wheel/_reader.py +59 -0
- python_sbom-0.1.1/src/python_sbom/_wheel/_record.py +55 -0
- python_sbom-0.1.1/src/python_sbom/_wheel/_write.py +103 -0
- python_sbom-0.1.1/src/python_sbom/_wheel/_zip.py +94 -0
- python_sbom-0.1.1/src/python_sbom/hatch/__init__.py +9 -0
- python_sbom-0.1.1/src/python_sbom/hatch/_hook.py +150 -0
- python_sbom-0.1.1/src/python_sbom/hatch/hooks.py +18 -0
- python_sbom-0.1.1/src/python_sbom/py.typed +0 -0
- python_sbom-0.1.1/src/python_sbom/version.py +24 -0
- python_sbom-0.1.1/tests/_cli/conftest.py +34 -0
- python_sbom-0.1.1/tests/_cli/test_archive.py +134 -0
- python_sbom-0.1.1/tests/_cli/test_embed.py +97 -0
- python_sbom-0.1.1/tests/_cli/test_main.py +49 -0
- python_sbom-0.1.1/tests/_cli/test_parser.py +27 -0
- python_sbom-0.1.1/tests/_cli/test_spdx.py +102 -0
- python_sbom-0.1.1/tests/_cli/test_validate.py +63 -0
- python_sbom-0.1.1/tests/_collect/test_archive.py +31 -0
- python_sbom-0.1.1/tests/_collect/test_content.py +145 -0
- python_sbom-0.1.1/tests/_collect/test_facts.py +254 -0
- python_sbom-0.1.1/tests/_collect/test_revision.py +197 -0
- python_sbom-0.1.1/tests/_collect/test_settings.py +80 -0
- python_sbom-0.1.1/tests/_collect/test_source.py +80 -0
- python_sbom-0.1.1/tests/_collect/test_wheel.py +112 -0
- python_sbom-0.1.1/tests/_formats/test_spdx.py +305 -0
- python_sbom-0.1.1/tests/_generate/pinned/embed-members.json +100 -0
- python_sbom-0.1.1/tests/_generate/pinned/embed.cdx.json +583 -0
- python_sbom-0.1.1/tests/_generate/test_archive.py +299 -0
- python_sbom-0.1.1/tests/_generate/test_embed.py +149 -0
- python_sbom-0.1.1/tests/_model/test_bom.py +395 -0
- python_sbom-0.1.1/tests/_model/test_components.py +436 -0
- python_sbom-0.1.1/tests/_model/test_content.py +34 -0
- python_sbom-0.1.1/tests/_model/test_document.py +146 -0
- python_sbom-0.1.1/tests/_model/test_identity.py +56 -0
- python_sbom-0.1.1/tests/_model/test_iri.py +47 -0
- python_sbom-0.1.1/tests/_model/test_licenses.py +28 -0
- python_sbom-0.1.1/tests/_model/test_markers.py +72 -0
- python_sbom-0.1.1/tests/_model/test_metadata.py +115 -0
- python_sbom-0.1.1/tests/_model/test_tools.py +66 -0
- python_sbom-0.1.1/tests/_seeder/LICENSE +3 -0
- python_sbom-0.1.1/tests/_seeder/hatch_build.py +49 -0
- python_sbom-0.1.1/tests/_seeder/pyproject.toml +29 -0
- python_sbom-0.1.1/tests/_seeder/src/seeder/__init__.py +0 -0
- python_sbom-0.1.1/tests/_seeder/src/seeder/embed/__init__.py +10 -0
- python_sbom-0.1.1/tests/_validate/test_artifact.py +156 -0
- python_sbom-0.1.1/tests/_validate/test_document.py +325 -0
- python_sbom-0.1.1/tests/_validate/test_licenses.py +144 -0
- python_sbom-0.1.1/tests/_validate/test_schemas.py +220 -0
- python_sbom-0.1.1/tests/_wheel/test_bundled.py +281 -0
- python_sbom-0.1.1/tests/_wheel/test_reader.py +36 -0
- python_sbom-0.1.1/tests/_wheel/test_record.py +45 -0
- python_sbom-0.1.1/tests/_wheel/test_write.py +290 -0
- python_sbom-0.1.1/tests/_wheel/test_zip.py +82 -0
- python_sbom-0.1.1/tests/conftest.py +196 -0
- python_sbom-0.1.1/tests/hatch/conftest.py +79 -0
- python_sbom-0.1.1/tests/hatch/test_hook.py +246 -0
- python_sbom-0.1.1/tests/test_no_hatchling.py +14 -0
- python_sbom-0.1.1/tests/test_public_api.py +151 -0
- python_sbom-0.1.1/tests/test_version.py +9 -0
- python_sbom-0.1.1/tox.toml +163 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
* @gaborbernat
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Add a `docs/changelog.d/+short-name.<type>.rst` fragment for a change that affects package users. Choose a unique short
|
|
4
|
+
name; the release workflow links the fragment to its merged squash pull request and credits the human author. A pull
|
|
5
|
+
request number is not needed in the filename.
|
|
6
|
+
|
|
7
|
+
Use `feature` for Added, `change` for Changes, `bugfix` for Fixed, and `doc` for Documentation. Use `breaking`,
|
|
8
|
+
`security`, `performance`, `deprecation`, `removal`, or `packaging` only when the change affects users in that way. A
|
|
9
|
+
supported Python version added or removed is a `feature` and results in a minor release.
|
|
10
|
+
|
|
11
|
+
Use `skip news` for internal maintenance without a user-facing change. The label may be added after opening the pull
|
|
12
|
+
request. Dependabot and maintenance bot pull requests without a fragment receive it automatically; a bot pull request
|
|
13
|
+
with a fragment still needs the news check to pass. For a change written by more than one person, put all human authors
|
|
14
|
+
in a `by` credit. Do not list bots or reviewers.
|
|
15
|
+
|
|
16
|
+
The documentation preview shows fragments under Unreleased. The versioned `docs/changelog.rst` changes only during
|
|
17
|
+
release preparation. The release workflow chooses a version from the fragment types, runs `prek` on the assembled
|
|
18
|
+
changelog, and publishes GitHub notes from the tagged changelog after PyPI succeeds.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Security policy
|
|
2
|
+
|
|
3
|
+
python-sbom writes a CycloneDX SBOM into wheels, from a hatchling build hook or from `python-sbom embed`, which rewrites
|
|
4
|
+
a wheel another build backend built. `python-sbom archive` describes another zip archive a project publishes, such as a
|
|
5
|
+
zipapp, and `python-sbom spdx` and `validate` render or check an SBOM. This policy says how to report a security problem
|
|
6
|
+
and how we decide whether a report is one.
|
|
7
|
+
|
|
8
|
+
## Reporting a vulnerability
|
|
9
|
+
|
|
10
|
+
**Do not open a public issue for a security problem.** Use
|
|
11
|
+
[GitHub's private vulnerability reporting](https://github.com/tox-dev/python-sbom/security/advisories/new). If neither
|
|
12
|
+
works for you, email [gaborjbernat@gmail.com](mailto:gaborjbernat@gmail.com).
|
|
13
|
+
|
|
14
|
+
Include what the attacker controls and what they gain, the steps or a proof of concept, and the versions and platform
|
|
15
|
+
you tested. Write the report yourself; unreviewed tool or model output takes longer to triage.
|
|
16
|
+
|
|
17
|
+
## What to expect
|
|
18
|
+
|
|
19
|
+
Volunteers maintain python-sbom, with no on-call rotation. We aim to acknowledge a report within **5 working days** and
|
|
20
|
+
assess it within **15 working days**. Fixes are developed in a private fork attached to the draft advisory, ship in a
|
|
21
|
+
new release, and the advisory, with a CVE requested through GitHub, goes out with that release. The default embargo is
|
|
22
|
+
**90 days** from the report; we agree any change with the reporter. We credit reporters in the advisory under the name
|
|
23
|
+
they choose, or not at all. There is no bug bounty.
|
|
24
|
+
|
|
25
|
+
## Supported versions
|
|
26
|
+
|
|
27
|
+
Only the latest release receives fixes. Confirm the problem reproduces on it before reporting.
|
|
28
|
+
|
|
29
|
+
## Vulnerability or bug
|
|
30
|
+
|
|
31
|
+
A report is a vulnerability when an attacker who controls only an input that the [threat model](THREAT_MODEL.md) lists
|
|
32
|
+
as untrusted breaks a guarantee python-sbom makes. A report that first needs control of something the threat model
|
|
33
|
+
trusts, such as the project source, its `pyproject.toml` or the build environment, is a bug: we fix it in the open and
|
|
34
|
+
publish no advisory. Classify by who supplies the dangerous input, not by how bad the outcome sounds.
|
|
35
|
+
|
|
36
|
+
**In scope**
|
|
37
|
+
|
|
38
|
+
- A wheel bundled in a wheel or in an archive given to `python-sbom archive`, or an SBOM given to `python-sbom spdx` or
|
|
39
|
+
`validate`, that makes python-sbom write outside its output file or the wheel or archive it rewrites, or run code.
|
|
40
|
+
- An SBOM that misstates what a wheel holds in a way its inputs cannot explain, such as a wrong hash.
|
|
41
|
+
|
|
42
|
+
**Out of scope**
|
|
43
|
+
|
|
44
|
+
- Anything hatchling's own build trusts.
|
|
45
|
+
- Vulnerabilities in the packages an SBOM lists; report those to their projects.
|
|
46
|
+
|
|
47
|
+
If you cannot tell which side a finding falls on, report it privately and we will decide.
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Threat model
|
|
2
|
+
|
|
3
|
+
This model says what python-sbom trusts, where untrusted input enters, and which guarantees hold at each boundary, so a
|
|
4
|
+
report can be classified as a vulnerability or a bug. [SECURITY.md](SECURITY.md) covers reporting; if the two disagree,
|
|
5
|
+
SECURITY.md wins and we fix this file.
|
|
6
|
+
|
|
7
|
+
## How python-sbom works
|
|
8
|
+
|
|
9
|
+
The build hook runs inside a hatchling wheel build. It reads the wheel's core metadata, the project's license files, the
|
|
10
|
+
wheels the project bundles and the installed distributions of the build environment, and writes a CycloneDX document
|
|
11
|
+
that it writes into the built wheel. `python-sbom embed` does the same for a wheel another backend built,
|
|
12
|
+
`python-sbom archive` describes another zip archive such as a zipapp, and `python-sbom spdx` and `validate` read
|
|
13
|
+
CycloneDX documents and write or check them.
|
|
14
|
+
|
|
15
|
+
```mermaid
|
|
16
|
+
flowchart LR
|
|
17
|
+
project[("Project source, pyproject.toml<br/>(trusted)")] --> hook["python-sbom"]
|
|
18
|
+
env[("Build environment<br/>(trusted)")] --> hook
|
|
19
|
+
bundled[("Bundled wheels<br/>(third-party content)")] -->|"metadata, RECORD, vendor list"| hook
|
|
20
|
+
sbom[("SBOM files given to spdx, validate")] -->|"untrusted JSON"| hook
|
|
21
|
+
hook --> wheel[("Wheel")]
|
|
22
|
+
classDef trusted fill:#cfe4ff,stroke:#1f6feb,color:#0b1f3a;
|
|
23
|
+
classDef boundary fill:#ffe3a3,stroke:#d29200,color:#3a2c00;
|
|
24
|
+
class project,env,hook,wheel trusted;
|
|
25
|
+
class bundled,sbom boundary;
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Trusted
|
|
29
|
+
|
|
30
|
+
An attacker who controls any of these already has what python-sbom could give them:
|
|
31
|
+
|
|
32
|
+
- The project source, its `pyproject.toml`, the build hook script, and the module the `content-provider` option or
|
|
33
|
+
`--content-provider` names: python-sbom imports that module from the project directory, so `embed` and `archive` run
|
|
34
|
+
code from `--root`.
|
|
35
|
+
- The git checkout that tracks the project, whose `HEAD` python-sbom reads. A repository that merely contains the
|
|
36
|
+
project directory is not trusted: git is used only when it tracks the project, and runs with `core.fsmonitor` off.
|
|
37
|
+
- The build environment and the build backend.
|
|
38
|
+
- The wheel handed to `python-sbom embed` and the archive handed to `python-sbom archive`, which the project's own build
|
|
39
|
+
produced.
|
|
40
|
+
|
|
41
|
+
## Untrusted inputs
|
|
42
|
+
|
|
43
|
+
| Input | Comes from | What python-sbom guarantees |
|
|
44
|
+
| --------------------------------------- | ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
45
|
+
| 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. |
|
|
46
|
+
| `_vendor/vendor.txt` of bundled wheels | Upstream projects | Each line must pin one exact version, or the build fails. |
|
|
47
|
+
| 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. |
|
|
48
|
+
|
|
49
|
+
## Threats and controls
|
|
50
|
+
|
|
51
|
+
| STRIDE | Threat | Control |
|
|
52
|
+
| ---------------------- | ---------------------------------------------------------- | ------------------------------------------------------------- |
|
|
53
|
+
| Tampering | A bundled wheel's metadata injects JSON into the document. | The document is serialized with `json.dumps`. |
|
|
54
|
+
| Tampering | A bundled wheel changes and the SBOM still lists it. | Each bundled wheel is hashed from its bytes at build time. |
|
|
55
|
+
| Elevation of privilege | A bundled wheel runs code during the build. | Wheels are read as zip archives; nothing in them is imported. |
|
|
56
|
+
|
|
57
|
+
## Release chain
|
|
58
|
+
|
|
59
|
+
Releases run on the shared [tox-dev/github-workflows](https://github.com/tox-dev/github-workflows) pipeline. A release
|
|
60
|
+
App, not a person, pushes the release commit and tag; the build installs its tools from a hash-checked `pylock.toml`
|
|
61
|
+
resolved with a seven-day upload cooldown by default; PyPI receives the files through
|
|
62
|
+
[trusted publishing](https://docs.pypi.org/trusted-publishers/) with attestations, and the GitHub Release is immutable.
|
|
63
|
+
Every workflow pins third-party actions to a commit SHA.
|
|
64
|
+
|
|
65
|
+
## Severity
|
|
66
|
+
|
|
67
|
+
- **High:** a bundled wheel or SBOM file that makes python-sbom run code or write outside its output.
|
|
68
|
+
- **Medium:** an SBOM that misstates a hash, a license or the contents of a wheel.
|
|
69
|
+
- **Low:** a crash on a malformed bundled wheel or SBOM file instead of a clean error.
|
|
70
|
+
|
|
71
|
+
## Accepted risks
|
|
72
|
+
|
|
73
|
+
- The SBOM reports what the build environment holds; it does not check that environment against a lock.
|
|
74
|
+
|
|
75
|
+
## Keeping this current
|
|
76
|
+
|
|
77
|
+
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
|
|
78
|
+
an advisory is published.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
multi-ecosystem-groups:
|
|
3
|
+
dependencies:
|
|
4
|
+
schedule:
|
|
5
|
+
interval: weekly
|
|
6
|
+
day: tuesday
|
|
7
|
+
labels:
|
|
8
|
+
- dependencies
|
|
9
|
+
- skip news
|
|
10
|
+
updates:
|
|
11
|
+
- package-ecosystem: github-actions
|
|
12
|
+
directory: /
|
|
13
|
+
patterns:
|
|
14
|
+
- '*'
|
|
15
|
+
multi-ecosystem-group: dependencies
|
|
16
|
+
labels:
|
|
17
|
+
- dependencies
|
|
18
|
+
- skip news
|
|
19
|
+
cooldown:
|
|
20
|
+
default-days: 7
|
|
21
|
+
- package-ecosystem: pre-commit
|
|
22
|
+
directory: /
|
|
23
|
+
patterns:
|
|
24
|
+
- '*'
|
|
25
|
+
multi-ecosystem-group: dependencies
|
|
26
|
+
labels:
|
|
27
|
+
- dependencies
|
|
28
|
+
- skip news
|
|
29
|
+
cooldown:
|
|
30
|
+
default-days: 7
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
name: 🧪 check
|
|
2
|
+
on:
|
|
3
|
+
workflow_dispatch:
|
|
4
|
+
push:
|
|
5
|
+
branches: ["main"]
|
|
6
|
+
pull_request:
|
|
7
|
+
types: [opened, synchronize, reopened]
|
|
8
|
+
schedule:
|
|
9
|
+
- cron: "27 8 * * *"
|
|
10
|
+
concurrency:
|
|
11
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
12
|
+
cancel-in-progress: true
|
|
13
|
+
permissions:
|
|
14
|
+
contents: read
|
|
15
|
+
jobs:
|
|
16
|
+
test:
|
|
17
|
+
name: 🧪 test
|
|
18
|
+
if: github.event_name != 'schedule' || github.repository == 'tox-dev/python-sbom'
|
|
19
|
+
uses: tox-dev/github-workflows/.github/workflows/check.yaml@0c4cffd63033d38196319524d101caae1eef925b # 6.7.2
|
|
20
|
+
permissions:
|
|
21
|
+
contents: read
|
|
22
|
+
with:
|
|
23
|
+
include: |
|
|
24
|
+
[
|
|
25
|
+
{"env": "3.15", "python": "3.15"},
|
|
26
|
+
{"env": "3.14", "python": "3.14"},
|
|
27
|
+
{"env": "3.13", "python": "3.13"},
|
|
28
|
+
{"env": "3.12", "python": "3.12"},
|
|
29
|
+
{"env": "3.11", "python": "3.11"},
|
|
30
|
+
{"env": "3.15", "python": "3.15", "os": "windows-2025"},
|
|
31
|
+
{"env": "3.11", "python": "3.11", "os": "windows-2025"},
|
|
32
|
+
{"env": "3.15", "python": "3.15", "os": "macos-26"},
|
|
33
|
+
{"env": "dev"},
|
|
34
|
+
{"env": "docs"},
|
|
35
|
+
{"env": "fix"},
|
|
36
|
+
{"env": "type"},
|
|
37
|
+
{"env": "pkg_meta"}
|
|
38
|
+
]
|
|
39
|
+
release:
|
|
40
|
+
name: 🏷️ Release dry run
|
|
41
|
+
uses: $/.github/workflows/prepare-release.yaml
|
|
42
|
+
permissions:
|
|
43
|
+
contents: read
|
|
44
|
+
pull-requests: read
|
|
45
|
+
with:
|
|
46
|
+
dry-run: true
|
|
47
|
+
hooks:
|
|
48
|
+
name: 🧹 Hooks under the cooldown
|
|
49
|
+
uses: tox-dev/github-workflows/.github/workflows/cooled-hooks.yaml@0c4cffd63033d38196319524d101caae1eef925b # 6.7.2
|
|
50
|
+
permissions:
|
|
51
|
+
contents: read
|
|
52
|
+
gate:
|
|
53
|
+
name: 🚦 ${{ github.event_name == 'pull_request' && 'Required checks pass' || 'Non-PR checks pass' }}
|
|
54
|
+
if: ${{ !cancelled() }} # codespell:ignore cancelled
|
|
55
|
+
needs: [test, release, hooks]
|
|
56
|
+
runs-on: ubuntu-26.04
|
|
57
|
+
permissions: {}
|
|
58
|
+
steps:
|
|
59
|
+
- name: 🚦 Require all needed jobs to pass
|
|
60
|
+
uses: tox-dev/github-workflows/required-checks@0c4cffd63033d38196319524d101caae1eef925b # 6.7.2
|
|
61
|
+
with:
|
|
62
|
+
needs: ${{ toJSON(needs) }}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
name: 🛡️ CodeQL
|
|
2
|
+
on:
|
|
3
|
+
workflow_dispatch:
|
|
4
|
+
push:
|
|
5
|
+
branches: ["main"]
|
|
6
|
+
pull_request:
|
|
7
|
+
schedule:
|
|
8
|
+
- cron: "35 8 * * 2"
|
|
9
|
+
concurrency:
|
|
10
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
11
|
+
cancel-in-progress: true
|
|
12
|
+
permissions: {}
|
|
13
|
+
jobs:
|
|
14
|
+
analyze:
|
|
15
|
+
name: 🛡️ Analyze
|
|
16
|
+
uses: tox-dev/github-workflows/.github/workflows/codeql.yaml@0c4cffd63033d38196319524d101caae1eef925b # 6.7.2
|
|
17
|
+
permissions:
|
|
18
|
+
contents: read
|
|
19
|
+
security-events: write
|
|
20
|
+
with:
|
|
21
|
+
languages: '["actions","python"]'
|
|
22
|
+
paths-ignore: '["tests"]'
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
name: Changelog
|
|
2
|
+
on:
|
|
3
|
+
pull_request:
|
|
4
|
+
types: [opened, reopened, synchronize, labeled, unlabeled]
|
|
5
|
+
permissions:
|
|
6
|
+
contents: read
|
|
7
|
+
pull-requests: read
|
|
8
|
+
jobs:
|
|
9
|
+
changelog:
|
|
10
|
+
name: 📝 News fragment
|
|
11
|
+
runs-on: ubuntu-26.04
|
|
12
|
+
steps:
|
|
13
|
+
- name: 📥 Checkout code
|
|
14
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
15
|
+
with:
|
|
16
|
+
fetch-depth: 0
|
|
17
|
+
persist-credentials: false
|
|
18
|
+
- name: 🐍 Install uv
|
|
19
|
+
uses: astral-sh/setup-uv@68559e99cc807c1eb7e9238fd43a15bba460eec2 # v10.3.3
|
|
20
|
+
with:
|
|
21
|
+
version: latest-known
|
|
22
|
+
python-version: "3.15"
|
|
23
|
+
enable-cache: false
|
|
24
|
+
- name: 📦 Install locked release tools
|
|
25
|
+
uses: tox-dev/github-workflows/install-locked-tools@0c4cffd63033d38196319524d101caae1eef925b # 6.7.2
|
|
26
|
+
with:
|
|
27
|
+
groups: release-news
|
|
28
|
+
venv: ${{ runner.temp }}/release-tools
|
|
29
|
+
- name: 🔍 Validate changelog fragments
|
|
30
|
+
uses: tox-dev/github-workflows/validate-news@0c4cffd63033d38196319524d101caae1eef925b # 6.7.2
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
name: Prepare release
|
|
2
|
+
on:
|
|
3
|
+
workflow_dispatch:
|
|
4
|
+
inputs:
|
|
5
|
+
bump:
|
|
6
|
+
description: Version bump strategy
|
|
7
|
+
required: true
|
|
8
|
+
type: choice
|
|
9
|
+
options:
|
|
10
|
+
- auto
|
|
11
|
+
- major
|
|
12
|
+
- minor
|
|
13
|
+
- patch
|
|
14
|
+
default: auto
|
|
15
|
+
workflow_call:
|
|
16
|
+
inputs:
|
|
17
|
+
dry-run:
|
|
18
|
+
description: Assemble the release without pushing, for the pull request gate
|
|
19
|
+
type: boolean
|
|
20
|
+
required: true
|
|
21
|
+
permissions: {}
|
|
22
|
+
jobs:
|
|
23
|
+
prepare:
|
|
24
|
+
name: 🏷️ Prepare Towncrier release
|
|
25
|
+
uses: tox-dev/github-workflows/.github/workflows/prepare-towncrier-release.yaml@0c4cffd63033d38196319524d101caae1eef925b # 6.7.2
|
|
26
|
+
permissions:
|
|
27
|
+
contents: read
|
|
28
|
+
pull-requests: read
|
|
29
|
+
with:
|
|
30
|
+
bump: ${{ inputs.bump || 'auto' }}
|
|
31
|
+
dry-run: ${{ inputs.dry-run == true }}
|
|
32
|
+
release-auth-deployment: false
|
|
33
|
+
secrets:
|
|
34
|
+
RELEASE_APP_PRIVATE_KEY: ${{ secrets.RELEASE_APP_PRIVATE_KEY }}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
name: Release to PyPI
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
tags: ["*"]
|
|
5
|
+
permissions:
|
|
6
|
+
contents: read
|
|
7
|
+
concurrency:
|
|
8
|
+
group: release-${{ github.ref }}
|
|
9
|
+
cancel-in-progress: false
|
|
10
|
+
jobs:
|
|
11
|
+
build:
|
|
12
|
+
name: 🏗️ Build
|
|
13
|
+
uses: tox-dev/github-workflows/.github/workflows/validate-python-release.yaml@0c4cffd63033d38196319524d101caae1eef925b # 6.7.2
|
|
14
|
+
permissions:
|
|
15
|
+
contents: read
|
|
16
|
+
notes:
|
|
17
|
+
name: 📝 Render GitHub Release notes
|
|
18
|
+
uses: tox-dev/github-workflows/.github/workflows/release-notes.yaml@0c4cffd63033d38196319524d101caae1eef925b # 6.7.2
|
|
19
|
+
permissions:
|
|
20
|
+
contents: read
|
|
21
|
+
with:
|
|
22
|
+
tag: ${{ github.ref_name }}
|
|
23
|
+
changelog: docs/changelog.rst
|
|
24
|
+
artifact-url: https://pypi.org/project/python-sbom/${{ github.ref_name }}/
|
|
25
|
+
publish:
|
|
26
|
+
name: 🚀 Publish to PyPI
|
|
27
|
+
needs: [build, notes]
|
|
28
|
+
runs-on: ubuntu-26.04
|
|
29
|
+
environment:
|
|
30
|
+
name: release
|
|
31
|
+
url: https://pypi.org/project/python-sbom/${{ github.ref_name }}
|
|
32
|
+
permissions:
|
|
33
|
+
id-token: write
|
|
34
|
+
steps:
|
|
35
|
+
- name: 📩 Download distributions
|
|
36
|
+
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
|
|
37
|
+
with:
|
|
38
|
+
artifact-ids: ${{ needs.build.outputs.distributions-artifact-id }}
|
|
39
|
+
path: dist/
|
|
40
|
+
- name: 🚀 Publish to PyPI
|
|
41
|
+
uses: pypa/gh-action-pypi-publish@7245906fb61fa33a13554f9d5fb856fe61758086 # v1.14.3
|
|
42
|
+
with:
|
|
43
|
+
attestations: true
|
|
44
|
+
packages-dir: dist
|
|
45
|
+
release:
|
|
46
|
+
name: 🚀 Publish GitHub Release
|
|
47
|
+
needs: [build, publish, notes]
|
|
48
|
+
uses: tox-dev/github-workflows/.github/workflows/github-release.yaml@0c4cffd63033d38196319524d101caae1eef925b # 6.7.2
|
|
49
|
+
permissions:
|
|
50
|
+
contents: write
|
|
51
|
+
with:
|
|
52
|
+
project: python-sbom
|
|
53
|
+
version: ${{ github.ref_name }}
|
|
54
|
+
tag: ${{ github.ref_name }}
|
|
55
|
+
artifact-pattern: python-package-distributions
|
|
56
|
+
notes-artifact-id: ${{ needs.notes.outputs.artifact-id }}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
name: 🛡️ scorecard
|
|
2
|
+
on:
|
|
3
|
+
branch_protection_rule:
|
|
4
|
+
schedule:
|
|
5
|
+
- cron: "43 8 * * 2"
|
|
6
|
+
push:
|
|
7
|
+
branches: ["main"]
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
concurrency:
|
|
10
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
11
|
+
cancel-in-progress: true
|
|
12
|
+
permissions: {}
|
|
13
|
+
jobs:
|
|
14
|
+
analysis:
|
|
15
|
+
name: 🛡️ Scorecard analysis
|
|
16
|
+
if: github.repository == 'tox-dev/python-sbom'
|
|
17
|
+
permissions:
|
|
18
|
+
actions: read # read workflow runs for the Packaging check
|
|
19
|
+
checks: read # read check runs for the CI-Tests and SAST checks
|
|
20
|
+
contents: read # check out and scan the repository
|
|
21
|
+
id-token: write # authenticate the results published to the scorecard API
|
|
22
|
+
issues: read # read issue activity for the Maintained check
|
|
23
|
+
pull-requests: read # read reviews for the Code-Review check
|
|
24
|
+
security-events: write # upload the SARIF results to code scanning
|
|
25
|
+
statuses: read # read commit statuses for the CI-Tests check
|
|
26
|
+
uses: tox-dev/github-workflows/.github/workflows/scorecard.yaml@0c4cffd63033d38196319524d101caae1eef925b # 6.7.2
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
name: Upgrade release tools
|
|
2
|
+
on:
|
|
3
|
+
workflow_dispatch:
|
|
4
|
+
schedule:
|
|
5
|
+
- cron: "51 8 * * 2"
|
|
6
|
+
permissions: {}
|
|
7
|
+
concurrency:
|
|
8
|
+
group: upgrade-release-tools
|
|
9
|
+
cancel-in-progress: false
|
|
10
|
+
jobs:
|
|
11
|
+
upgrade:
|
|
12
|
+
name: 🔀 Upgrade release tools
|
|
13
|
+
uses: tox-dev/github-workflows/.github/workflows/upgrade-release-tools.yaml@0c4cffd63033d38196319524d101caae1eef925b # 6.7.2
|
|
14
|
+
permissions:
|
|
15
|
+
contents: read
|
|
16
|
+
secrets:
|
|
17
|
+
RELEASE_APP_PRIVATE_KEY: ${{ secrets.RELEASE_APP_PRIVATE_KEY }}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# prek runs lower priorities first and equal ones concurrently, so hooks sharing a priority never write the same file;
|
|
2
|
+
# pre-commit ignores the key and runs hooks in file order.
|
|
3
|
+
ci:
|
|
4
|
+
autoupdate_schedule: quarterly
|
|
5
|
+
default_language_version:
|
|
6
|
+
python: python3.15
|
|
7
|
+
# the CycloneDX schema files ship byte for byte as upstream released them
|
|
8
|
+
exclude: ^src/python_sbom/_validate/schemas/
|
|
9
|
+
repos:
|
|
10
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
11
|
+
rev: 3e8a8703264a2f4a69428a0aa4dcb512790b2c8c # frozen: v6.0.0
|
|
12
|
+
hooks:
|
|
13
|
+
- id: end-of-file-fixer
|
|
14
|
+
priority: 0
|
|
15
|
+
- id: trailing-whitespace
|
|
16
|
+
priority: 1
|
|
17
|
+
- repo: https://github.com/python-jsonschema/check-jsonschema
|
|
18
|
+
rev: a76b92851fc9eede9f9bc4073eb55202f34eb0df # frozen: 0.39.0
|
|
19
|
+
hooks:
|
|
20
|
+
- id: check-github-workflows
|
|
21
|
+
priority: 6
|
|
22
|
+
args: ["--verbose"]
|
|
23
|
+
- repo: https://github.com/codespell-project/codespell
|
|
24
|
+
rev: 57b21406f092110c18776e39b0bda50d37c945c8 # frozen: v2.4.3
|
|
25
|
+
hooks:
|
|
26
|
+
- id: codespell
|
|
27
|
+
priority: 6
|
|
28
|
+
- repo: https://github.com/tox-dev/tox-toml-fmt
|
|
29
|
+
rev: "5125f601c3e134347288c3d42f3b34298b7cf1be" # frozen: v1.11.1
|
|
30
|
+
hooks:
|
|
31
|
+
- id: tox-toml-fmt
|
|
32
|
+
priority: 2
|
|
33
|
+
- repo: https://github.com/tox-dev/pyproject-fmt
|
|
34
|
+
rev: "50e0f3aee9dc5747a5f173f79a7417403c18dda6" # frozen: v2.30.3
|
|
35
|
+
hooks:
|
|
36
|
+
- id: pyproject-fmt
|
|
37
|
+
priority: 2
|
|
38
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
39
|
+
rev: "25bcf95026b96e2dd3c0aec3090c3d6ef6ca2e6c" # frozen: v0.17.3
|
|
40
|
+
hooks:
|
|
41
|
+
- id: ruff-check
|
|
42
|
+
priority: 3
|
|
43
|
+
args: ["--fix", "--unsafe-fixes", "--exit-non-zero-on-fix"]
|
|
44
|
+
- repo: https://github.com/gaborbernat/simplint-pre-commit
|
|
45
|
+
rev: "c8719dca99c13381570bc69f8955c9448fc271b7" # frozen: v0.7.1
|
|
46
|
+
hooks:
|
|
47
|
+
- id: simplint
|
|
48
|
+
priority: 4
|
|
49
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
50
|
+
rev: "25bcf95026b96e2dd3c0aec3090c3d6ef6ca2e6c" # frozen: v0.17.3
|
|
51
|
+
hooks:
|
|
52
|
+
- id: ruff-format
|
|
53
|
+
priority: 5
|
|
54
|
+
- repo: https://github.com/google/yamlfmt
|
|
55
|
+
rev: "21ca5323a9c87ee37a434e0ca908efc0a89daa07" # frozen: v0.21.0
|
|
56
|
+
hooks:
|
|
57
|
+
- id: yamlfmt
|
|
58
|
+
priority: 2
|
|
59
|
+
- repo: https://github.com/executablebooks/mdformat
|
|
60
|
+
rev: 82912cdaea4fb830f751504486a7879c70526547 # frozen: 1.0.0
|
|
61
|
+
hooks:
|
|
62
|
+
- id: mdformat
|
|
63
|
+
priority: 2
|
|
64
|
+
args: ["--wrap", "120"]
|
|
65
|
+
additional_dependencies:
|
|
66
|
+
- mdformat-gfm==1.0.0
|
|
67
|
+
- mdformat-ruff==0.1.3
|
|
68
|
+
- repo: https://github.com/LilSpazJoekp/docstrfmt
|
|
69
|
+
rev: c1813841673cdcd6cf602dde1edb78a5d5e45235 # frozen: v2.2.1
|
|
70
|
+
hooks:
|
|
71
|
+
- id: docstrfmt
|
|
72
|
+
priority: 2
|
|
73
|
+
files: ^docs/(changelog|contributing)[.]rst$
|
|
74
|
+
args: ["-l", "120", "--preserve-adornments"]
|
|
75
|
+
additional_dependencies:
|
|
76
|
+
- "sphinx==9.2.0"
|
|
77
|
+
- repo: https://github.com/zizmorcore/zizmor-pre-commit
|
|
78
|
+
rev: c92afdf2c6ca336aaa8f39e2bd8d48f62dbd8e1f # frozen: v1.31.1
|
|
79
|
+
hooks:
|
|
80
|
+
- id: zizmor
|
|
81
|
+
priority: 6
|
|
82
|
+
args: ["--min-severity", "high"]
|
|
83
|
+
- repo: meta
|
|
84
|
+
hooks:
|
|
85
|
+
- id: check-hooks-apply
|
|
86
|
+
priority: 6
|
|
87
|
+
- id: check-useless-excludes
|
|
88
|
+
priority: 6
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
node: 0880f77d5e60335f23d569ad6a85e4b626990d84
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
Permission is hereby granted, free of charge, to any person obtaining a
|
|
2
|
+
copy of this software and associated documentation files (the
|
|
3
|
+
"Software"), to deal in the Software without restriction, including
|
|
4
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
5
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
6
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
7
|
+
the following conditions:
|
|
8
|
+
|
|
9
|
+
The above copyright notice and this permission notice shall be included
|
|
10
|
+
in all copies or substantial portions of the Software.
|
|
11
|
+
|
|
12
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
13
|
+
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
14
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
15
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
16
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
17
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
18
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|