-
Notifications
You must be signed in to change notification settings - Fork 3.8k
295 lines (249 loc) · 11.1 KB
/
Copy pathlicense-check.yaml
File metadata and controls
295 lines (249 loc) · 11.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
# Copyright (c) 2022-2026, The Isaac Lab Project Developers (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md).
# All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
name: Python Dependency Licenses Check
on:
pull_request:
types: [opened, synchronize, reopened]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
license-check:
# Fork PRs cannot access NGC_API_KEY, so they cannot resolve the immutable
# OVPhysX wheel required by the development extras.
if: github.event.pull_request.head.repo.full_name == github.repository
runs-on: ubuntu-24.04
env:
NGC_API_KEY: ${{ secrets.NGC_API_KEY }}
steps:
- name: Checkout code
uses: actions/checkout@v6
with:
filter: tree:0
- name: Load OVPhysX wheelhouse configuration
id: config
shell: bash
run: |
set -euo pipefail
resource=$(yq -r .ovphysx_wheelhouse_resource .github/workflows/config.yaml)
echo "wheelhouse_resource=${resource}" >> "$GITHUB_OUTPUT"
- name: Restore NGC CLI cache
uses: actions/cache@v4
with:
path: ${{ runner.temp }}/ngc-cli-cache/ngccli_linux.zip
key: ngc-cli-${{ runner.os }}-${{ runner.arch }}-4.20.0-5cf084c88998c58ad8abf7849d2d1b41d578423886eb03018df10194e341d35b
- name: Extract OVPhysX wheelhouse
id: extract-wheelhouse
shell: bash
env:
WHEELHOUSE_RESOURCE: ${{ steps.config.outputs.wheelhouse_resource }}
run: |
set -euo pipefail
if [ -z "${NGC_API_KEY:-}" ]; then
echo "::error::NGC_API_KEY is unavailable; cannot download the configured OVPhysX wheelhouse"
exit 1
fi
NGC_CLI_VERSION="4.20.0"
NGC_CLI_SHA256="5cf084c88998c58ad8abf7849d2d1b41d578423886eb03018df10194e341d35b"
NGC_CLI_URL="https://api.ngc.nvidia.com/v2/resources/nvidia/ngc-apps/ngc_cli/versions/${NGC_CLI_VERSION}/files/ngccli_linux.zip"
wheelhouse_root="$(mktemp -d "${RUNNER_TEMP:-/tmp}/ovphysx-wheelhouse.XXXXXX")"
download_root="$(mktemp -d "${RUNNER_TEMP:-/tmp}/ovphysx-wheelhouse-download.XXXXXX")"
ngc_home="$(mktemp -d "${RUNNER_TEMP:-/tmp}/ovphysx-ngc-home.XXXXXX")"
ngc_unpack_dir=""
preserve_wheelhouse_root=false
cleanup() {
if [ "$preserve_wheelhouse_root" != "true" ]; then
rm -rf "$wheelhouse_root"
fi
rm -rf "$download_root" "$ngc_home"
if [ -n "$ngc_unpack_dir" ]; then
rm -rf "$ngc_unpack_dir"
fi
}
trap cleanup EXIT
cache_dir="${RUNNER_TEMP:-/tmp}/ngc-cli-cache"
ngc_zip="${cache_dir}/ngccli_linux.zip"
mkdir -p "$cache_dir"
if [ ! -f "$ngc_zip" ]; then
echo "Downloading NGC CLI ${NGC_CLI_VERSION}"
curl -fsSL -o "$ngc_zip" "$NGC_CLI_URL"
fi
echo "${NGC_CLI_SHA256} ${ngc_zip}" | sha256sum -c -
ngc_unpack_dir="$(mktemp -d "${RUNNER_TEMP:-/tmp}/ngc-cli.XXXXXX")"
unzip -q "$ngc_zip" -d "$ngc_unpack_dir"
export PATH="${ngc_unpack_dir}/ngc-cli:${PATH}"
export NGC_CLI_API_KEY="$NGC_API_KEY"
export NGC_CLI_ORG=nvidian
export NGC_CLI_TEAM=no-team
export NGC_CLI_HOME="$ngc_home"
ngc --version
echo "Downloading wheelhouse resource: $WHEELHOUSE_RESOURCE"
ngc registry resource download-version "$WHEELHOUSE_RESOURCE" --dest "$download_root"
mapfile -t manifests < <(find "$download_root" -type f -name manifest.json)
if [ "${#manifests[@]}" -ne 1 ]; then
echo "::error::expected exactly one manifest.json in downloaded wheelhouse resource, found ${#manifests[@]}"
printf '%s\n' "${manifests[@]}"
exit 1
fi
payload_dir="$(dirname "${manifests[0]}")"
if [ ! -d "${payload_dir}/wheelhouse" ]; then
echo "::error::downloaded wheelhouse resource is missing wheelhouse/ next to manifest.json"
exit 1
fi
mkdir -p "$wheelhouse_root/wheelhouse"
cp "${payload_dir}/manifest.json" "$wheelhouse_root/manifest.json"
cp "${payload_dir}/wheelhouse/"*.whl "$wheelhouse_root/wheelhouse/"
python3 - <<'PY' "$wheelhouse_root/manifest.json" "$wheelhouse_root/wheelhouse"
import hashlib
import json
import pathlib
import sys
manifest_path = pathlib.Path(sys.argv[1])
wheelhouse_dir = pathlib.Path(sys.argv[2])
manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
expected = {
"artifact": "ovphysx-wheelhouse",
"platform": "manylinux_2_35_x86_64",
}
for key, value in expected.items():
actual = manifest.get(key)
if actual != value:
raise SystemExit(f"manifest {key!r} mismatch: expected {value!r}, got {actual!r}")
wheels = manifest.get("wheels")
if not isinstance(wheels, list) or not wheels:
raise SystemExit("manifest has no wheels list")
for wheel in wheels:
filename = wheel.get("file")
expected_sha = wheel.get("sha256")
if not filename or not expected_sha:
raise SystemExit(f"invalid wheel manifest entry: {wheel!r}")
wheel_path = wheelhouse_dir / filename
if not wheel_path.is_file():
raise SystemExit(f"manifest wheel is missing from wheelhouse: {filename}")
actual_sha = hashlib.sha256(wheel_path.read_bytes()).hexdigest()
if actual_sha != expected_sha:
raise SystemExit(f"sha256 mismatch for {filename}: expected {expected_sha}, got {actual_sha}")
print(f"Validated {len(wheels)} wheelhouse wheels from {manifest_path}")
PY
echo "wheelhouse_root=$wheelhouse_root" >> "$GITHUB_OUTPUT"
echo "wheelhouse_dir=$wheelhouse_root/wheelhouse" >> "$GITHUB_OUTPUT"
# - name: Install jq
# run: sudo apt-get update && sudo apt-get install -y jq
- name: Clean up disk space
run: |
# Remove pre-installed tools
rm -rf /opt/hostedtoolcache
rm -rf /usr/share/dotnet
rm -rf /opt/ghc
sudo rm -rf /usr/local/lib/android
rm -rf /usr/share/swift
rm -rf /usr/local/share/boost
sudo rm -rf /usr/local/.ghcup
sudo rm -rf /usr/local/lib/node_modules
sudo rm -rf /usr/local/share/chromium
sudo rm -rf /usr/local/share/powershell
# Clean apt cache
sudo apt-get clean
sudo rm -rf /var/lib/apt/lists/*
# Docker cleanup
docker container prune -f
docker image prune -af
docker volume prune -f
docker system prune -af
- name: Set up uv
uses: astral-sh/setup-uv@v6
with:
python-version: '3.12'
enable-cache: true
- name: Install dependencies with uv
env:
OMNI_KIT_ACCEPT_EULA: yes
ACCEPT_EULA: Y
ISAACSIM_ACCEPT_EULA: YES
UV_FIND_LINKS: ${{ steps.extract-wheelhouse.outputs.wheelhouse_dir }}
run: |
uv sync --extra all
# Isaac Sim conflicts with --extra all under uv, so install it imperatively
# after the sync. Read the pinned spec from pyproject (single source of truth).
ISAACSIM_SPEC=$(.venv/bin/python -c "import tomllib; print(tomllib.load(open('pyproject.toml','rb'))['project']['optional-dependencies']['isaacsim'][0])")
uv pip install "$ISAACSIM_SPEC"
uv pip install pip-licenses pipdeptree \
-r tools/template/requirements.txt \
-r docs/requirements.txt
# Put the venv on PATH for later steps.
echo "$PWD/.venv/bin" >> "$GITHUB_PATH"
# Optional: Print the license report for visibility
- name: Print License Report
run: pip-licenses --from=mixed --format=markdown
# Print pipdeptree
- name: Print pipdeptree
run: pipdeptree
- name: Check licenses against whitelist and exceptions
run: |
# Define the whitelist of allowed licenses
ALLOWED_LICENSES="MIT Apache BSD ISC zlib"
# Load the exceptions list from the exceptions.json file
EXCEPTIONS_FILE=".github/workflows/license-exceptions.json"
# Initialize counter for failed packages
FAILED_PACKAGES=0
# Get the list of installed packages and their licenses
pip-licenses --from=mixed --format=json > licenses.json
# Check the output of pip-licenses to ensure it is valid JSON
if ! jq empty licenses.json; then
echo "ERROR: Failed to parse pip-licenses output. Exiting..."
exit 1
fi
# Split ALLOWED_LICENSES into individual words
IFS=' ' read -r -a allowed_licenses <<< "$ALLOWED_LICENSES"
# Loop through the installed packages and their licenses
for pkg in $(jq -r '.[].Name' licenses.json); do
# Skip packages starting with nvidia (case-insensitive)
if [[ "${pkg,,}" == nvidia* ]]; then
continue
fi
LICENSE=$(jq -r --arg pkg "$pkg" '.[] | select(.Name == $pkg) | .License' licenses.json)
# Check if any of the allowed licenses are a substring of the package's license
match_found=false
for allowed_license in "${allowed_licenses[@]}"; do
if [[ "$LICENSE" == *"$allowed_license"* ]]; then
match_found=true
break
fi
done
if [ "$match_found" = false ]; then
# Check if the package is in the exceptions list
EXCEPTION=$(jq -r --arg pkg "$pkg" --arg license "$LICENSE" \
'.[] | select(.package == $pkg)' "$EXCEPTIONS_FILE")
# If the package is in the exceptions list
if [ -n "$EXCEPTION" ]; then
# If the license is provided in the exceptions list, check the license
EXCEPTION_LICENSE=$(echo "$EXCEPTION" | jq -r '.license')
# echo "Comparing licenses for $pkg:"
# echo " EXCEPTION_LICENSE='${EXCEPTION_LICENSE}' (len=${#EXCEPTION_LICENSE})"
# echo " LICENSE='${LICENSE}' (len=${#LICENSE})"
# If the exceptions list has a license and doesn't match the current license
if [ "$EXCEPTION_LICENSE" != "null" ] && [ "$EXCEPTION_LICENSE" != "$LICENSE" ]; then
echo "ERROR: $pkg has license: $LICENSE"
FAILED_PACKAGES=$((FAILED_PACKAGES + 1)) # Increment the counter
fi
else
# If the package is not in the exceptions list
echo "ERROR: $pkg has license: $LICENSE"
FAILED_PACKAGES=$((FAILED_PACKAGES + 1)) # Increment the counter
fi
fi
done
# After all packages are processed, check if there were any errors
if [ "$FAILED_PACKAGES" -gt 0 ]; then
echo "ERROR: $FAILED_PACKAGES packages were flagged."
exit 1 # Fail the build
else
echo "All packages were checked."
fi
- name: Clean up OVPhysX wheelhouse
if: always()
shell: bash
run: |
rm -rf "${{ steps.extract-wheelhouse.outputs.wheelhouse_root }}"