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
9 changes: 9 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
version: 2
updates:
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
groups:
actions:
patterns: ["*"]
132 changes: 10 additions & 122 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,131 +2,19 @@ name: CI

on:
push:
branches: [main, dev, deployment-readiness-audit]
branches: [main, dev, 'production/**']
pull_request:
branches: [main, dev]
merge_group:
workflow_dispatch:

jobs:
deployment-readiness:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Install uv
uses: astral-sh/setup-uv@v5

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"

- name: Install dependencies
run: uv sync --frozen

- name: Validate lockfile
run: uv lock --check

- name: Lint
run: uv run ruff check .

- name: Run tests
run: uv run pytest -v

- name: Build package
run: uv build

- name: Installed package smoke
run: |
WHEEL="$(ls "$PWD"/dist/trialmatchai-*.whl | head -n 1)"
mkdir -p /tmp/trialmatchai-installed-smoke
cd /tmp/trialmatchai-installed-smoke
uv run --python 3.11 --isolated --with "$WHEEL" python - <<'PY'
from pathlib import Path
from trialmatchai.config.config_loader import load_config

cfg = load_config()
assert Path(cfg["entity_extraction"]["schema_path"]).exists()
assert cfg["paths"]["output_dir"].endswith("results")
PY
permissions:
contents: read

- name: CLI help smoke
run: |
WHEEL="$(ls dist/trialmatchai-*.whl | head -n 1)"
uv run --python 3.11 --isolated --with "$WHEEL" trialmatchai --help
for cmd in pipeline healthcheck bootstrap-data index build-concepts update-registry \
import-patient build run e2e trec finetune; do
uv run --python 3.11 --isolated --with "$WHEEL" trialmatchai "$cmd" --help
done
concurrency:
group: ci-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

- name: Secret scan
run: uv run pre-commit run gitleaks --all-files

- name: Dependency audit
# vllm==0.23.0 (pins torch 2.11.0) and its transitive diskcache 5.6.3 are hard-pinned
# for the inference stack. The advisories below were newly published against those exact
# pinned versions and list NO fixed version, so there is nothing to upgrade to. Revisit
# and drop these ignores once vllm / diskcache ship patched releases.
run: >-
uv run pip-audit --progress-spinner off
--ignore-vuln CVE-2025-3000
--ignore-vuln CVE-2025-69872
--ignore-vuln CVE-2026-53923
--ignore-vuln CVE-2026-54236
--ignore-vuln CVE-2026-12491
--ignore-vuln CVE-2026-54235
--ignore-vuln CVE-2026-54233

ml-extras-smoke:
# Installs the optional ML extras (CPU-only) and imports the local-model
# surface that the default job never touches, so a broken import or wrong
# transformers/gliner API call is caught instead of shipping silently.
# Non-blocking: it exercises heavy third-party deps (torch/gliner) whose
# availability we don't gate releases on; failures show up as a signal
# without failing the workflow.
continue-on-error: true
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Install uv
uses: astral-sh/setup-uv@v5

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"

- name: Install with entity extra (CPU)
run: uv sync --extra entity

- name: Import ML surface
run: |
uv run python - <<'PY'
import importlib

# The entity extra's heavy libs must import cleanly in the resolved
# environment (catches a bad transformers API or a torch pin conflict).
for lib in ("torch", "transformers", "gliner", "gliner2"):
importlib.import_module(lib)
print(f"imported {lib}")

# The package's local-model modules must import with extras present.
modules = [
"trialmatchai.entities.recognizers",
"trialmatchai.models.embedding.text_embedder",
"trialmatchai.models.llm.llm_reranker",
"trialmatchai.models.llm.vllm_loader",
"trialmatchai.matching.eligibility_reasoning_vllm",
"trialmatchai.finetuning.cot",
"trialmatchai.finetuning.reranker",
"trialmatchai.finetuning.ner",
]
for name in modules:
importlib.import_module(name)
print(f"imported {name}")
PY
jobs:
verification:
uses: ./.github/workflows/verify.yml
18 changes: 12 additions & 6 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,31 @@ concurrency:
jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v5
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
with:
persist-credentials: false
- uses: astral-sh/setup-uv@e58605a9b6da7c637471fab8847a5e5a6b8df081 # v5
with:
version: "0.11.24"
- name: Set up Python
uses: actions/setup-python@v5
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: "3.11"
- name: Build docs (strict)
run: uv run --group docs mkdocs build --strict
run: uv run --frozen --group docs mkdocs build --strict
- name: Upload Pages artifact
if: github.ref == 'refs/heads/main'
uses: actions/upload-pages-artifact@v3
uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa # v3
with:
path: site

deploy:
# PRs and other branches only build (validate) above; main publishes.
if: github.ref == 'refs/heads/main'
needs: build
timeout-minutes: 10
runs-on: ubuntu-latest
permissions:
pages: write # deploy to Pages
Expand All @@ -50,4 +56,4 @@ jobs:
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4
62 changes: 36 additions & 26 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,44 +1,54 @@
name: Release

# Publishes trialmatchai to PyPI when a GitHub Release is published.
# Uses PyPI Trusted Publishing (OIDC) — no API token is stored in the repo.
# One-time setup on PyPI: add a Trusted Publisher for this repo + workflow +
# the `pypi` environment (https://docs.pypi.org/trusted-publishers/).

on:
release:
types: [published]
workflow_dispatch: {}

permissions:
contents: read

concurrency:
group: pypi-release
cancel-in-progress: false

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v5
- name: Build sdist + wheel
run: uv build
- name: Check the built metadata
run: uvx twine check dist/*
- uses: actions/upload-artifact@v4
with:
name: dist
path: dist/
verification:
uses: ./.github/workflows/verify.yml
with:
release_tag: ${{ github.event.release.tag_name }}

pypi-publish:
needs: build
needs: verification
runs-on: ubuntu-latest
timeout-minutes: 15
environment: pypi
permissions:
id-token: write # required for PyPI Trusted Publishing (OIDC)
contents: read
id-token: write
attestations: write
steps:
- uses: actions/download-artifact@v4
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
with:
persist-credentials: false
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
name: dist
name: trialmatchai-dist-${{ github.sha }}
path: dist/
- uses: astral-sh/setup-uv@v5
- name: Publish to PyPI
run: uv publish --trusted-publishing always
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: "3.11"
- uses: astral-sh/setup-uv@e58605a9b6da7c637471fab8847a5e5a6b8df081 # v5
with:
version: "0.11.24"
- name: Verify the tested artifacts
env:
PYTHONPATH: src
run: python -m trialmatchai artifacts verify dist/SHA256SUMS --require-exact --json
- uses: actions/attest-build-provenance@43d14bc2b83dec42d39ecae14e916627a18bb661 # v3
with:
subject-path: |
dist/*.whl
dist/*.tar.gz
dist/SHA256SUMS
- name: Publish the tested distributions with OIDC
run: uv publish dist/*.whl dist/*.tar.gz --trusted-publishing always
Loading
Loading