Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
109 commits
Select commit Hold shift + click to select a range
9eeadc0
oocodegen: Produce correct slot URI for locally defined attributes.
gouttegd Jun 26, 2026
25604e8
Merge branch 'main' into fix-3677
gouttegd Jul 7, 2026
c40dfa4
fix(shaclgen): emit sh:minCount/maxCount 0 for zero cardinality values
jdsika Jul 3, 2026
fbb75ad
Merge branch 'main' into fix-3677
gouttegd Jul 9, 2026
9f55739
Update Community-Meetings.md with July prez title
sagehrke Jul 14, 2026
d9bfd93
ci: scope CVE audit to PRs that change dependencies
amc-corey-cox Jul 15, 2026
eddafa3
ci: scope CVE audit to real dependency changes on every event
amc-corey-cox Jul 15, 2026
c60cfe6
Merge branch 'main' into ci-scope-dep-audit
amc-corey-cox Jul 15, 2026
043f677
ci: report unowned-CVE audit findings via a rolling tracking issue
amc-corey-cox Jul 15, 2026
5fb9fdc
Merge branch 'ci-scope-dep-audit' of github.com:linkml/linkml into ci…
amc-corey-cox Jul 15, 2026
db380ae
ci: drop scheduled tracking-issue job
amc-corey-cox Jul 15, 2026
af6368b
style: ruff import grouping in uv_lock_deps_changed.py
amc-corey-cox Jul 15, 2026
309149d
Merge branch 'main' into fix-3677
kevinschaper Jul 16, 2026
48d25c5
build(deps-dev): bump sphinxcontrib-mermaid from 1.0.0 to 2.0.3
dependabot[bot] Jul 16, 2026
20b3bfa
fix(test_rdflib_dumper): fix test_output_prefixes isolation and sdo/s…
Silvanoc Jul 13, 2026
e4e4a36
refactor(test_rdflib_dumper): replace remaining turtle string asserti…
Silvanoc Jul 13, 2026
1f4ba8e
test(rdflib_dumper): detect premature namespace cache bug for importe…
Silvanoc Jul 13, 2026
c7a9eeb
fix(rdflib_dumper): call imports_closure() before namespaces() to loa…
Silvanoc Jul 13, 2026
f29ae95
Merge branch 'main' into ci-scope-dep-audit
amc-corey-cox Jul 16, 2026
573e1c3
Mark non-required enum slots as nullable in JSON Schema output
kevinschaper Jul 16, 2026
c6f87a5
fix(oogen): update abstract signature (#3775)
noelmcloughlin Jul 17, 2026
7a60df7
feat(javagen): add javabundle dataclass, serialize and render (#3756)
noelmcloughlin Jul 17, 2026
c85d8f1
Merge branch 'main' into fix-3749
amc-corey-cox Jul 17, 2026
977890b
test(rdflib_loader): add dump-load round-trip test
Silvanoc Jul 17, 2026
31676d8
fix(rdflib_loader): fix symmetric to previous dumper fix
Silvanoc Jul 17, 2026
1288dbb
Merge pull request #3750 from linkml/fix-3749
Silvanoc Jul 17, 2026
c9a164f
Update metamodel test fixtures from linkml-model
amc-corey-cox Jul 20, 2026
e2d7899
Merge pull request #3720 from linkml/update-metamodel-fixtures
matentzn Jul 20, 2026
860586b
fix(jsonschema): ignore default_schema if boolean constraint
Silvanoc Jun 9, 2026
40c68bf
Merge pull request #3619 from linkml/fix-3618
pkalita-lbl Jul 21, 2026
db43592
Merge branch 'main' into sagehrke-patch-4
matentzn Jul 22, 2026
79187b4
Merge branch 'main' into ci-scope-dep-audit
matentzn Jul 22, 2026
a347249
Merge pull request #3769 from linkml/ci-scope-dep-audit
matentzn Jul 22, 2026
fe67902
Merge branch 'main' into sagehrke-patch-4
matentzn Jul 22, 2026
6128e21
build(deps): bump pyasn1 from 0.6.3 to 0.6.4
dependabot[bot] Jul 22, 2026
58e206b
Merge pull request #3766 from linkml/sagehrke-patch-4
matentzn Jul 22, 2026
ab30701
Merge branch 'main' into fix-3677
gouttegd Jul 23, 2026
8e443f1
Update get_class_slot_range() in pydanticgen to exclude abstract clas…
colinrsmall Jul 23, 2026
acd1e77
test: update 'biolink modeling langage' strings
noelmcloughlin Jul 27, 2026
8ad0f7c
Update tests/input/ImportMaps.md
noelmcloughlin Jul 28, 2026
ad2024f
Merge pull request #3810 from noelmcloughlin/quick
matentzn Jul 28, 2026
20a1465
Extend sqlvalidation generator to process rules from schema (#3325)
FlorianK13 Jul 29, 2026
b1f865a
docs: update feature dashboard from compliance tests
kevinschaper Jul 29, 2026
e5d97c4
Add @gouttegd as "code owner" for the Java generator. (#3817)
gouttegd Jul 29, 2026
5e33746
build(deps): bump the github-actions group across 1 directory with 11…
dependabot[bot] Aug 1, 2026
35fcdbc
doc: Update the documentation about the Java generator.
gouttegd Jul 30, 2026
ceb72d1
Merge pull request #3825 from linkml/dependabot/github_actions/github…
matentzn Aug 5, 2026
71bddcf
Merge branch 'main' into auto/update-feature-dashboard
matentzn Aug 5, 2026
2219ae6
Merge pull request #3789 from linkml/dependabot/uv/pyasn1-0.6.4
matentzn Aug 5, 2026
de82371
Merge pull request #3746 from linkml/dependabot/uv/sphinxcontrib-merm…
matentzn Aug 5, 2026
4ddc727
Merge branch 'main' into fix/shaclgen-maxcount-zero
turbomam Aug 5, 2026
b90c5bc
Merge pull request #3773 from linkml/auto/update-feature-dashboard
matentzn Aug 5, 2026
3a38968
Merge branch 'main' into fix/shaclgen-maxcount-zero
turbomam Aug 5, 2026
ee91123
Require core team approval for LinkML PRs
matentzn Jul 23, 2026
c8b9bac
Merge pull request #3792 from linkml/core-team-approval
matentzn Aug 6, 2026
7186ea4
Merge branch 'main' into fix/shaclgen-maxcount-zero
turbomam Aug 7, 2026
1639634
fix(runtime): sync vendored meta.yaml with upstream linkml-model
amc-corey-cox Aug 7, 2026
54f8e55
chore(deps): unblock the dependabot queue
amc-corey-cox Aug 7, 2026
78ae3f9
build(deps): bump the patch-updates group across 1 directory with 2 u…
dependabot[bot] Aug 7, 2026
c8441d6
build(deps-dev): bump ipykernel from 7.1.0 to 7.3.0 (#3740)
dependabot[bot] Aug 7, 2026
c52ab09
build(deps-dev): bump tox-uv from 1.29.0 to 1.36.0 (#3741)
dependabot[bot] Aug 7, 2026
3c57807
build(deps-dev): bump pytest-cov from 7.0.0 to 7.1.0 (#3742)
dependabot[bot] Aug 7, 2026
2c7fe43
build(deps-dev): bump furo from 2025.9.25 to 2025.12.19
dependabot[bot] Aug 7, 2026
1e69b5b
build(deps): bump curies from 0.12.3 to 0.14.4 (#3747)
dependabot[bot] Aug 7, 2026
ad637de
Merge branch 'main' into fix-3677
matentzn Aug 10, 2026
6cb1a3d
Merge pull request #3678 from gouttegd/fix-3677
matentzn Aug 10, 2026
36f5350
Add Codeownership for Java, Zod and OpenAPI
matentzn Aug 10, 2026
c3a2db5
javagen: Misc fixes to documentation.
gouttegd Aug 10, 2026
89566df
fix(openapigen): replace raw schema with schemaview provided one
Silvanoc Jul 14, 2026
851d53b
style(openapigen): align variable names with openapi wording
Silvanoc Jul 15, 2026
0e8a322
feat(openapigen): support LinkML types as OpenAPI schemas
Silvanoc Jul 14, 2026
6ad45d5
test(openapigen): test linkml types as openapi schema
Silvanoc Jul 15, 2026
05f7e91
feat(openapigen): avoid template modification
Silvanoc Jul 15, 2026
ef2909b
fix(openapigen): more replace raw schema with schemaview provided one
Silvanoc Jul 30, 2026
4b3ba2f
refactor(openapigen): improve code readability
Silvanoc Jul 30, 2026
49fd032
fix: minor review comments
Aug 8, 2026
66cc4c6
Apply suggestion from @matentzn
matentzn Aug 11, 2026
1187da4
Update Community-Meetings.md
sagehrke Aug 11, 2026
d49c66f
Update Community-Meetings.md
sagehrke Aug 11, 2026
821a7a6
Update Community-Meetings.md
sagehrke Aug 11, 2026
fee9668
Update codeowners.md
matentzn Aug 11, 2026
901fbc4
Merge branch 'main' into codeowners-openapi-java-zod
matentzn Aug 11, 2026
bbddbf5
Merge pull request #3873 from linkml/codeowners-openapi-java-zod
matentzn Aug 11, 2026
c6f0f2f
Merge branch 'main' into fix-openapigen
matentzn Aug 12, 2026
bed601c
Merge branch 'main' into update-javagen-doc
matentzn Aug 12, 2026
9982195
Merge pull request #3765 from linkml/fix-openapigen
matentzn Aug 12, 2026
97cecc3
Merge branch 'main' into update-javagen-doc
gouttegd Aug 12, 2026
e9b7cdd
Merge pull request #3822 from gouttegd/update-javagen-doc
matentzn Aug 12, 2026
e27c0a0
tests: diverting from model `main` only raises warning (#3709)
Silvanoc Aug 12, 2026
65bc9bf
fix(ci): eliminate two intermittent test failures (#3885)
amc-corey-cox Aug 12, 2026
dd7c81a
build(deps): update jsonschema[format] requirement from >=4.0.0 to >=…
dependabot[bot] Aug 13, 2026
70c6628
build(deps-dev): bump sphinx-rtd-theme from 3.0.2 to 3.1.0
dependabot[bot] Aug 13, 2026
ffd3715
build(deps): bump jsonschema from 4.24.1 to 4.26.0 (#3863)
dependabot[bot] Aug 13, 2026
f308404
build(deps-dev): bump numpydantic from 1.7.0 to 1.10.0 (#3865)
dependabot[bot] Aug 13, 2026
2b6bc3e
ci: cancel superseded runs on the same pull request
amc-corey-cox Aug 13, 2026
4edefab
build(deps): bump the patch-updates group across 1 directory with 3 u…
dependabot[bot] Aug 13, 2026
fffd9a7
build(deps-dev): bump typedb-driver from 3.8.1 to 3.12.1
dependabot[bot] Aug 13, 2026
7ea78d2
build(deps): bump rdflib from 7.2.1 to 7.6.0 (#3870)
dependabot[bot] Aug 13, 2026
1cba7f4
build(deps-dev): bump coverage from 7.11.0 to 7.15.4 (#3864)
dependabot[bot] Aug 13, 2026
2ef89c8
build(deps-dev): bump pandera from 0.26.1 to 0.32.1 (#3869)
dependabot[bot] Aug 13, 2026
ea9989e
build(deps): bump the github-actions group with 3 updates (#3889)
dependabot[bot] Aug 13, 2026
9036f5e
build(deps-dev): bump sphinxcontrib-programoutput from 0.18 to 0.20
dependabot[bot] Aug 13, 2026
1361cf1
Update Community-Meetings.md
matentzn Aug 14, 2026
787057b
Merge pull request #3877 from linkml/sagehrke-patch-4
matentzn Aug 14, 2026
137eb17
build(deps): check for updates daily instead of weekly (#3891)
amc-corey-cox Aug 14, 2026
5e1f368
build(deps): bump the patch-updates group with 2 updates (#3892)
dependabot[bot] Aug 14, 2026
a6e0101
build(deps-dev): bump sphinxcontrib-mermaid from 2.0.3 to 2.1.0 (#3894)
dependabot[bot] Aug 14, 2026
1f89350
feat(gen-shacl): generate sh:sparql constraints from LinkML rules (#3…
jdsika Aug 14, 2026
c206fe2
Merge branch 'main' into fix/shaclgen-maxcount-zero
amc-corey-cox Aug 14, 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
41 changes: 36 additions & 5 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -1,19 +1,31 @@
# LinkML CODEOWNERS — DRAFT (see linkml/linkml#3140)
#
# Opt-in model: no default (`*`) rule. Paths not listed here have no required
# CODEOWNER and are reviewed normally. Rules only appear where someone has
# explicitly volunteered to steward an area.
# Default model: all paths require core-team approval unless a more specific
# CODEOWNER rule applies. Later rules override earlier ones (last match wins),
# so per-subsystem rules below take precedence over the default for their paths.
#
# Process for adding rules: docs/maintainers/codeowners.md
# Later rules override earlier ones for matched paths.

# --- Default: require core-team approval everywhere ---
* @linkml/core-team

# --- CODEOWNERS and governance docs ---
/.github/CODEOWNERS @linkml/core-team
/docs/maintainers/contributor-hierarchy.md @linkml/core-team
/docs/maintainers/codeowners.md @linkml/core-team
/docs/maintainers/generator-governance.md @linkml/core-team

# --- Per-subsystem ownership (opt-in) ---
# --- Per-subsystem ownership (overrides the default for these paths) ---

# javagen
#
# EXPERIMENT: delegated self-contained area, see
# docs/maintainers/codeowners.md#experiment-delegating-self-contained-areas

/docs/generators/java.rst @gouttegd @noelmcloughlin
/packages/linkml/src/linkml/generators/javagen.py @gouttegd @noelmcloughlin
/packages/linkml/src/linkml/generators/javagen/ @gouttegd @noelmcloughlin
/tests/linkml/test_generators/test_javagen.py @gouttegd @noelmcloughlin

# pydanticgen:
/packages/linkml/src/linkml/generators/pydanticgen/ @sneakers-the-rat @kevinschaper
Expand All @@ -29,3 +41,22 @@
/docs/generators/yarrrml.rst @Ostrzyciel @lapkinvladimir
/packages/linkml/src/linkml/generators/yarrrmlgen.py @Ostrzyciel @lapkinvladimir
/tests/linkml/test_generators/test_yarrrmlgen.py @Ostrzyciel @lapkinvladimir

# openapigen:
#
# EXPERIMENT: delegated self-contained area, see
# docs/maintainers/codeowners.md#experiment-delegating-self-contained-areas
# @Silvanoc and @noelmcloughlin jointly own the OpenAPI generator and can
# review each other's changes and merge them without core-team approval.

/docs/generators/openapi.rst @Silvanoc @noelmcloughlin
/packages/linkml/src/linkml/generators/openapigen.py @Silvanoc @noelmcloughlin
/tests/linkml/test_generators/test_openapigen.py @Silvanoc @noelmcloughlin
/tests/linkml/test_generators/input/openapi/ @Silvanoc @noelmcloughlin
/tests/linkml/test_scripts/test_gen_openapi.py @Silvanoc @noelmcloughlin

# zodgen:
/docs/generators/zod.rst @linkml/core-team @noelmcloughlin
/packages/linkml/src/linkml/generators/zodgen.py @linkml/core-team @noelmcloughlin
/packages/linkml/src/linkml/generators/zod_ifabsent_processor.py @linkml/core-team @noelmcloughlin
/tests/linkml/test_generators/test_zodgen.py @linkml/core-team @noelmcloughlin
9 changes: 6 additions & 3 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@ updates:

- package-ecosystem: "uv"
directory: "/"
# Daily refills the three open slots as they drain, rather than once a week.
# The limit below, not the interval, is what bounds concurrent CI load.
schedule:
interval: "weekly"
day: "sunday"
interval: "daily"
groups:
# Individual pull requests for major/minor updates and grouped for patch updates
patch-updates:
Expand All @@ -31,7 +32,9 @@ updates:
- "*"
update-types:
- "patch"
open-pull-requests-limit: 10
# Bounds rebase storms: every open PR runs the full matrix, and dependabot
# rebases all of them when main moves.
open-pull-requests-limit: 3
# Wait 7 days after a release before opening an update PR, giving time for
# malware/CVE advisories to surface (mirrors the uv `exclude-newer` cooldown).
cooldown:
Expand Down
57 changes: 42 additions & 15 deletions .github/scripts/check_links.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import random
import re
import sys
import time
from collections import defaultdict
from datetime import datetime, timedelta
from pathlib import Path
Expand Down Expand Up @@ -139,24 +140,19 @@ def needs_check(url: str, cache: dict[str, dict], ttl_days: int, jitter_days: in
return True


def check_url(url: str, timeout: int = 10) -> tuple[str, str]:
"""
Check a URL and return (status, error_message).
TRANSIENT_STATUSES = {"timeout", "connection_error"}
"""Failures that say the network misbehaved, not that the link is dead.

Don't follow redirects - accept 3xx as valid (the redirect itself is the response).
This avoids false failures when redirect targets have bot protection.
A dead link answers with 404. A dropped connection or a timeout is weather, and
retrying clears it -- so these are retried before being reported.
"""

RETRY_ATTEMPTS = 3
RETRY_BACKOFF_SECONDS = 2

Returns:
Tuple of (status_code_or_error, error_message_or_empty)
"""
# Self-referencing repo URLs: verify the file exists locally
repo_match = REPO_FILE_PATTERN.match(url)
if repo_match:
path = Path(repo_match.group(1))
if path.exists():
return "200", ""
return "404", f"Local path not found: {path}"

def _attempt_url(url: str, timeout: int) -> tuple[str, str]:
"""Make a single request and classify the outcome. See ``check_url``."""
try:
response = requests.head(
url,
Expand Down Expand Up @@ -184,6 +180,37 @@ def check_url(url: str, timeout: int = 10) -> tuple[str, str]:
return "error", str(e)


def check_url(url: str, timeout: int = 10) -> tuple[str, str]:
"""
Check a URL and return (status, error_message).

Don't follow redirects - accept 3xx as valid (the redirect itself is the response).
This avoids false failures when redirect targets have bot protection.

Transient network failures are retried up to ``RETRY_ATTEMPTS`` times with a
linear backoff, so a single dropped connection is not reported as a broken link.

Returns:
Tuple of (status_code_or_error, error_message_or_empty)
"""
# Self-referencing repo URLs: verify the file exists locally
repo_match = REPO_FILE_PATTERN.match(url)
if repo_match:
path = Path(repo_match.group(1))
if path.exists():
return "200", ""
return "404", f"Local path not found: {path}"

for attempt in range(1, RETRY_ATTEMPTS + 1):
status, message = _attempt_url(url, timeout)
if status not in TRANSIENT_STATUSES or attempt == RETRY_ATTEMPTS:
return status, message
time.sleep(RETRY_BACKOFF_SECONDS * attempt)

# Unreachable: the loop always returns on its final attempt.
raise AssertionError("retry loop exited without returning")


def main():
parser = argparse.ArgumentParser(description="Check links in documentation with caching and rate limiting.")
parser.add_argument(
Expand Down
68 changes: 68 additions & 0 deletions .github/scripts/uv_lock_deps_changed.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#!/usr/bin/env python3
"""Decide whether the resolved ``uv.lock`` dependency set changed between refs.

``uv.lock`` is regenerated non-deterministically: reordering, hashes, and
metadata can differ between two lockfiles that resolve to exactly the same
packages. ``uv audit`` only cares about the multiset of ``(name, version)``
pairs, so this script compares that set between a base ref and ``HEAD`` and
prints ``true`` only when it actually differs.

Usage:
uv_lock_deps_changed.py <base_ref>

Prints ``true`` when the resolved ``(name, version)`` set at ``HEAD`` differs
from the one at ``<base_ref>`` (or when the lockfile is absent at either ref),
otherwise ``false``.
"""

from __future__ import annotations

import subprocess
import sys

import tomllib


def package_set(ref: str) -> set[tuple[str, str | None]] | None:
"""Return the ``{(name, version)}`` set from ``uv.lock`` at ``ref``.

Args:
ref: A git ref (SHA, branch, ``HEAD``) to read ``uv.lock`` from.

Returns:
The set of ``(name, version)`` tuples for every locked package, or
``None`` if ``uv.lock`` does not exist at ``ref``.
"""
result = subprocess.run(
["git", "show", f"{ref}:uv.lock"],
capture_output=True,
text=True,
)
if result.returncode != 0:
return None
data = tomllib.loads(result.stdout)
return {(pkg["name"], pkg.get("version")) for pkg in data.get("package", [])}


def resolved_set_changed(base_ref: str) -> bool:
"""Return whether the resolved dependency set differs between refs.

Args:
base_ref: The ref to compare ``HEAD`` against.

Returns:
``True`` if the ``(name, version)`` set differs, or if ``uv.lock`` is
missing at either ref; ``False`` when the sets are identical.
"""
base = package_set(base_ref)
head = package_set("HEAD")
return base is None or head is None or base != head


def main() -> None:
"""Print ``true``/``false`` for the base ref given as the sole argument."""
print("true" if resolved_set_changed(sys.argv[1]) else "false")


if __name__ == "__main__":
main()
14 changes: 10 additions & 4 deletions .github/workflows/check-external-links.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
name: Check Sphinx external links
env:
UV_VERSION: "0.11.21"
concurrency:
# Cancel superseded runs on the same PR. github.ref is refs/pull/<n>/merge,
# so each PR is its own group and never cancels another's runs.
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

on:
push:
branches: [main]
Expand All @@ -14,23 +20,23 @@ jobs:
timeout-minutes: 30
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v7

- name: Set up Python 3.
uses: actions/setup-python@v6.2.0
uses: actions/setup-python@v7.0.0
with:
python-version: "3.12"

- name: Install uv
uses: astral-sh/setup-uv@v8.2.0
uses: astral-sh/setup-uv@v9.0.0
with:
version: ${{ env.UV_VERSION }}

- name: Install dependencies
run: uv pip install --system requests

- name: Restore link cache
uses: actions/cache@v5
uses: actions/cache@v6
with:
path: .github/link-cache.csv
key: link-cache-${{ github.run_id }}
Expand Down
77 changes: 67 additions & 10 deletions .github/workflows/dependency-audit.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ env:
UV_PREVIEW: "1" # Enables the preview uv audit and malware engines
UV_MALWARE_CHECK: "1" # Automatically blocks malicious installs on sync/run

concurrency:
# Cancel superseded runs on the same PR. github.ref is refs/pull/<n>/merge,
# so each PR is its own group and never cancels another's runs.
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

on:
push:
branches:
Expand All @@ -24,30 +30,81 @@ jobs:

steps:
- name: Check out repository
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
# Full history so we can diff against a base ref to see whether the
# resolved dependency set changed (see "Detect dependency changes").
fetch-depth: 0

# Pin uv to a known-good, recent release.
- name: Install uv and setup uv caching
uses: astral-sh/setup-uv@v8.2.0
uses: astral-sh/setup-uv@v9.0.0
with:
version: ${{ env.UV_VERSION }}
enable-cache: true

- name: Set up Python
uses: actions/setup-python@v6.2.0
uses: actions/setup-python@v7.0.0
id: setup-python
with:
python-version: 3.13

# Step 1: Run uv audit to check for vulnerabilities (CVEs)
# The CVE audit reflects the state of the *upstream advisory database*,
# not the change under test: a newly-published advisory against an
# already-pinned package would otherwise turn every open PR — and the next
# innocent merge to main — red, regardless of whether it touched deps.
#
# GHSA-6w46-j5rx-g56g (pytest predictable tmpdir path) is fixed only in
# pytest 9.0.3, but pytest 9 removed the private _pytest.assertion.util
# ._diff_text API that tests/conftest.py depends on. We pin pytest <9
# (see packages/linkml/pyproject.toml) and ignore this single test-only,
# low-risk advisory until conftest is migrated to stdlib difflib.
# So gate the audit on whether the change actually altered dependencies,
# relative to each event's natural base:
# * pull_request -> the PR base
# * push (main) -> the commit before the push (github.event.before)
# * merge_group -> the queue base
# * otherwise (workflow_dispatch, first/force push) -> audit
#
# A pyproject.toml change is always a real dependency change. uv.lock is
# regenerated non-deterministically, so a textual change there is only
# treated as real if the resolved (name, version) set actually differs.
- name: Detect dependency changes
id: deps
shell: bash
run: |
set -euo pipefail
case "${{ github.event_name }}" in
pull_request) base="${{ github.event.pull_request.base.sha }}" ;;
merge_group) base="${{ github.event.merge_group.base_sha }}" ;;
push) base="${{ github.event.before }}" ;;
*) base="" ;;
esac

zero="0000000000000000000000000000000000000000"
if [ -z "$base" ] || [ "$base" = "$zero" ] || ! git cat-file -e "$base^{commit}" 2>/dev/null; then
echo "No comparable base ref for '${{ github.event_name }}'; auditing."
echo "changed=true" >> "$GITHUB_OUTPUT"
exit 0
fi

changed_files="$(git diff --name-only "$base...HEAD")"

if grep -qE '(^|/)pyproject\.toml$' <<<"$changed_files"; then
echo "pyproject.toml changed; auditing."
echo "changed=true" >> "$GITHUB_OUTPUT"
elif grep -qE '(^|/)uv\.lock$' <<<"$changed_files"; then
changed="$(python3 .github/scripts/uv_lock_deps_changed.py "$base")"
if [ "$changed" = "true" ]; then
echo "uv.lock resolved dependency set changed; auditing."
else
echo "uv.lock changed but the resolved dependency set is identical; skipping audit."
fi
echo "changed=$changed" >> "$GITHUB_OUTPUT"
else
echo "No dependency files changed; skipping audit."
echo "changed=false" >> "$GITHUB_OUTPUT"
fi

# Step 1: Run uv audit to check for vulnerabilities (CVEs)
- name: Audit lockfile for CVEs
run: uv audit --ignore GHSA-6w46-j5rx-g56g
if: steps.deps.outputs.changed == 'true'
run: uv audit

# Step 2: Run a sync. If a package contains known malware,
# the OSV-lookup triggers an immediate, non-zero failure exit.
Expand Down
Loading
Loading