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
24 changes: 20 additions & 4 deletions .github/workflows/pre-commit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,32 @@ jobs:
with:
persist-credentials: false
# `uv` brings its own Python and is required by both:
# - the per-project prek hooks under
# `tools/{vulnogram/generate-cve-json,gmail/oauth-draft}/`,
# which invoke `uv run --directory ...` for ruff / mypy /
# pytest;
# - the four `workspace-*` prek hooks in
# `.pre-commit-config.yaml`, which call
# `tools/dev/run-workspace-check.sh` to iterate over every
# workspace member declared in the root pyproject's
# `[tool.uv.workspace] members` list and invoke ruff /
# mypy / pytest in each via `uv run --directory`;
# - the `uv tool install prek` step below.
# Minimum uv version is pinned in the root `pyproject.toml`
# (`[tool.uv] required-version`).
- uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
with:
enable-cache: true
# Sync the uv workspace with the dev group so that
# `ruff`, `mypy`, and `pytest` (declared at workspace root)
# are present in the shared `.venv`. The `workspace-*` hooks
# in `.pre-commit-config.yaml` call
# `tools/dev/run-workspace-check.sh`, which invokes
# `uv run --directory <member> <check>`; without the explicit
# sync, the auto-sync uv runs on `uv run` only resolves
# member runtime deps and the dev tools are missing.
- name: Sync workspace (installs ruff / mypy / pytest from root dev group)
# `--all-packages` is required — without it `uv sync` only
# installs the root project's deps, and the root has
# `package = false` so member packages and their
# `[project.scripts]` entry points would be skipped.
run: uv sync --all-packages --group dev
# Install prek via uv (rather than via the `j178/prek-action`
# action) so the `[tool.uv] exclude-newer` cooldown in the
# root `pyproject.toml` applies to the prek install as well.
Expand Down
17 changes: 13 additions & 4 deletions .github/workflows/sandbox-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,18 @@ jobs:
- uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
with:
enable-cache: true
# `--project` (not `--directory`) so the linter runs from the
# repository root; the default arguments resolve
# Sync the workspace so `sandbox-lint` (a workspace member's
# `[project.scripts]` entry) ends up on the shared venv's PATH.
# `--all-packages` is required — without it `uv sync` only
# installs the root project's deps, and the root has
# `package = false` so no member packages (and no member
# script entry-points) get installed.
- name: Sync workspace
run: uv sync --all-packages --group dev
# `sandbox-lint` is the workspace member's CLI entry point;
# after sync it is available directly via `uv run` from the
# repo root, which is what the linter expects so
# `.claude/settings.json` and `tools/sandbox-lint/expected.json`
# relative to cwd.
# resolve relative to cwd.
- name: Run sandbox-lint
run: uv run --project tools/sandbox-lint --group dev sandbox-lint
run: uv run sandbox-lint
109 changes: 79 additions & 30 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,40 +26,78 @@ on: # yamllint disable-line rule:truthy
permissions: {}

jobs:
# Per-project pytest matrix. Each Python project under tools/ has its
# own `pyproject.toml` + `uv.lock`, with pytest declared in the `dev`
# dependency group. Running them as separate matrix jobs surfaces
# per-project pass/fail in the CI checks list, which is easier to
# triage than the bundled `pytest` lines inside the `prek` workflow's
# output. The `prek` workflow still exercises pytest as a hook, so
# this workflow is the visible signal — not the gate.
# Discover workspace members from the root pyproject.toml so the
# pytest matrix below is data-driven — adding a new tool is a
# one-line edit to `[tool.uv.workspace] members` and the matrix
# picks it up automatically.
members:
name: list-workspace-members
runs-on: ubuntu-latest
permissions:
contents: read
outputs:
members: ${{ steps.list.outputs.members }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- id: list
# Emit the workspace members as a JSON array of {name,path}
# objects so the matrix below can both label jobs by name
# AND pass the path to `uv run --directory`. The `pytest`
# filter mirrors the auto-discovery rule in
# `tools/dev/run-workspace-check.sh`: only members with a
# `[tool.pytest.ini_options]` section get pytest jobs, and
# an explicit `[tool.steward.checks] skip = [..., "pytest"]`
# opts out.
run: |
members=$(python3 <<'PY'
import json
import sys
import tomllib

with open("pyproject.toml", "rb") as f:
root = tomllib.load(f)
paths = root["tool"]["uv"]["workspace"]["members"]

out = []
for path in paths:
with open(f"{path}/pyproject.toml", "rb") as f:
data = tomllib.load(f)
tool = data.get("tool", {})
if "ini_options" not in tool.get("pytest", {}):
continue
skip = tool.get("steward", {}).get("checks", {}).get("skip", [])
if "pytest" in skip:
continue
out.append({"name": path.split("/")[-1], "path": path})
# Sort for deterministic CI ordering.
out.sort(key=lambda x: x["name"])
print(json.dumps(out))
PY
)
echo "members=${members}" >> "$GITHUB_OUTPUT"
echo "Discovered workspace members for pytest matrix:"
echo "${members}" | python3 -m json.tool

# Per-member pytest matrix. Each Python project under tools/ that
# is a uv-workspace member with a `[tool.pytest.ini_options]`
# section gets its own job. Running them as separate matrix jobs
# surfaces per-project pass/fail in the CI checks list, which is
# easier to triage than the bundled `workspace-pytest` line inside
# the `prek` workflow's output. The `prek` workflow still
# exercises pytest as a hook, so this workflow is the visible
# signal — not the gate.
pytest:
name: "pytest (${{ matrix.project.name }})"
runs-on: ubuntu-latest
needs: members
permissions:
contents: read
strategy:
fail-fast: false
matrix:
project:
- name: oauth-draft
path: tools/gmail/oauth-draft
- name: generate-cve-json
path: tools/cve-tool-vulnogram/generate-cve-json
- name: skill-and-tool-validator
path: tools/skill-and-tool-validator
- name: privacy-llm-checker
path: tools/privacy-llm/checker
- name: privacy-llm-redactor
path: tools/privacy-llm/redactor
- name: vulnogram-oauth-api
path: tools/cve-tool-vulnogram/oauth-api
- name: sandbox-lint
path: tools/sandbox-lint
- name: agent-isolation
path: tools/agent-isolation
- name: jira
path: tools/jira
project: ${{ fromJSON(needs.members.outputs.members) }}
# GitHub Actions log viewer renders ANSI colour escapes; without
# an attached TTY most tools default to monochrome. `FORCE_COLOR`
# is the de-facto signal honoured by uv, ruff, mypy, and pytest's
Expand All @@ -74,17 +112,28 @@ jobs:
with:
persist-credentials: false
# uv brings its own Python and reads each project's
# `pyproject.toml` + `uv.lock`. Minimum uv version is enforced
# by the root `pyproject.toml`'s `[tool.uv] required-version`.
# `pyproject.toml` + the workspace `uv.lock`. Minimum uv
# version is enforced by the root `pyproject.toml`'s
# `[tool.uv] required-version`.
- uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
with:
enable-cache: true
- name: Sync workspace (installs ruff / mypy / pytest from root dev group)
# Dev-group deps live in the root pyproject (`[dependency-groups]
# dev`) and only land in the shared workspace `.venv` when an
# explicit `--group dev` sync runs. `--all-packages` ensures
# every workspace member is installed too (the root has
# `package = false`, so without it members and their
# `[project.scripts]` entry points would be skipped).
run: uv sync --all-packages --group dev
- name: Run pytest
# `--directory` (not `--project`) — both move uv's project
# context, but `--directory` also changes cwd, which pytest
# needs because each project's `pyproject.toml` declares
# `testpaths = ["tests"]` relative to its own root.
run: uv run --directory ${{ matrix.project.path }} --group dev pytest --color=yes
# `testpaths = ["tests"]` relative to its own root. No
# `--group` flag here because the sync above already
# installed the dev tools into the shared workspace venv.
run: uv run --directory ${{ matrix.project.path }} pytest --color=yes

# Umbrella status check. `.asf.yaml`'s `required_status_checks`
# cannot use patterns or wildcards (GitHub's branch-protection and
Expand Down
Loading
Loading