Skip to content
Closed
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
14 changes: 14 additions & 0 deletions template/.github/workflows/ci.yml.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,20 @@ jobs:
run: pixi run lint
env:
CLICOLOR_FORCE: 1

conda-deny:
name: Verify Software License Compliance
timeout-minutes: 30
runs-on: ubuntu-latest
steps:
- name: Check out branch
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Set up pixi
uses: prefix-dev/setup-pixi@9dabb60412d3d2d967a8d682f7ce01317af40514 # v0.11.0
- name: Run conda-deny
run: pixi run conda-deny-check
env:
CLICOLOR_FORCE: 1
{%- endraw %}

pytest:
Expand Down
15 changes: 15 additions & 0 deletions template/README.md.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,18 @@ cd {{ project_slug }}
pixi run pre-commit-install
pixi run test
```

## Dependency licenses

CI runs [conda-deny](https://github.com/Quantco/conda-deny) to check dependency
licenses across all environments and platforms in `pixi.lock`. Run it locally with:

```bash
pixi run conda-deny-check
```

The starter allowlist in `[tool.conda-deny]` in `pixi.toml` covers the generated
development and test environments, including their runtime dependencies.
Review and customize it for your project's license policy. Dependencies with
unlisted or missing licenses fail the check. The local project itself is excluded;
set and review its license separately.
36 changes: 36 additions & 0 deletions template/pixi.toml.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,12 @@ tombi = "*"
pre-commit-hooks = "*"
typos = "*"
zizmor = "*"
conda-deny = "*"

[feature.lint.tasks]
pre-commit-install = "lefthook install"
lint = "lefthook run pre-commit --all-files"
conda-deny-check = "conda-deny check"
{%- if minimal_python_version <= "py310" %}

[feature.py310.dependencies]
Expand Down Expand Up @@ -94,3 +96,37 @@ py313 = ["py313", "test"]
{%- if minimal_python_version <= "py314" %}
py314 = ["py314", "test"]
{%- endif %}

[tool.conda-deny]
# Starter allowlist for the generated development and test environments.
# Review this list for your project before adding dependencies.
safe-licenses = [
"0BSD",
"AFL-2.1",
"Apache-2.0",
"Apache-2.0 WITH LLVM-exception",
"BSD-2-Clause",
"BSD-3-Clause",
"EPL-2.0",
"GPL-3.0-only",
"GPL-3.0-only WITH GCC-exception-3.1",
"ISC",
"LGPL-2.1-only",
"LGPL-2.1-or-later",
"LGPL-3.0-only",
"MIT",
"MPL-2.0",
"PSF-2.0",
"Python-2.0",
"TCL",
"X11",
"Zlib",
"blessing",
"bzip2-1.0.6",
"LicenseRef-Public-Domain",
# Windows runtime dependencies distributed through conda-forge.
"LicenseRef-MicrosoftVisualCpp2015-2022Runtime",
"LicenseRef-MicrosoftWindowsSDK10",
]
# Exclude the local project; this check covers third-party dependencies.
ignore-packages = [{ package = "{{ project_slug }}" }]
19 changes: 19 additions & 0 deletions tests/test_template.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import subprocess
import tomllib

import pytest
from ruamel.yaml import YAML


def test_generation(generated_project, project_slug):
Expand Down Expand Up @@ -106,3 +108,20 @@ def test_minimal_python_version(generate_project, minimal_python_version: str):
else:
assert env not in pixi_toml
assert env not in ci


def test_conda_deny(generated_project):
manifest = tomllib.loads((generated_project / "pixi.toml").read_text())
lint = manifest["feature"]["lint"]
assert "conda-deny" in lint["dependencies"]
task = lint["tasks"]["conda-deny-check"]
assert task == "conda-deny check"
policy = manifest["tool"]["conda-deny"]
assert "MIT" in policy["safe-licenses"]
assert policy["ignore-packages"] == [{"package": manifest["workspace"]["name"]}]
workflow = YAML(typ="safe").load(
(generated_project / ".github/workflows/ci.yml").read_text()
)
job = workflow["jobs"]["conda-deny"]
assert "if" not in job
assert any(step.get("run") == "pixi run conda-deny-check" for step in job["steps"])
Loading