fix(shaclgen): emit sh:maxCount 0 for zero maximum_cardinality #2
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Audit dependencies | |
| permissions: | |
| contents: read | |
| # Global environment variables applied to all steps | |
| env: | |
| UV_VERSION: "0.11.21" | |
| UV_PREVIEW: "1" # Enables the preview uv audit and malware engines | |
| UV_MALWARE_CHECK: "1" # Automatically blocks malicious installs on sync/run | |
| on: | |
| push: | |
| branches: | |
| - main | |
| pull_request: | |
| merge_group: | |
| workflow_dispatch: | |
| jobs: | |
| security-check: | |
| name: Validate Dependencies | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Check out repository | |
| 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@v9.0.0 | |
| with: | |
| version: ${{ env.UV_VERSION }} | |
| enable-cache: true | |
| - name: Set up Python | |
| uses: actions/setup-python@v7.0.0 | |
| id: setup-python | |
| with: | |
| python-version: 3.13 | |
| # 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. | |
| # | |
| # 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) | |
| # | |
| # 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. | |
| - name: Audit lockfile for CVEs | |
| if: steps.deps.outputs.changed == 'true' | |
| run: uv audit --ignore GHSA-6w46-j5rx-g56g | |
| # Step 2: Run a sync. If a package contains known malware, | |
| # the OSV-lookup triggers an immediate, non-zero failure exit. | |
| # | |
| # NOTE: The malware gate only blocks malware that has *already* been | |
| # published as an OSV advisory. There is a window between a malicious | |
| # upload and its advisory. That gap is covered by uv's dependency | |
| # cooldown (`exclude-newer`, a resolution-time setting added in uv | |
| # 0.9.17), which is enabled with a 7-day window in the root pyproject.toml: | |
| # | |
| # [tool.uv] | |
| # exclude-newer = "7 days" | |
| # | |
| - name: Verify Environment Sync (Anti-Malware Gate) | |
| run: uv sync --frozen --all-groups |