-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add grant summary generator action (#2)
This adds a GitHub Action that generates a license compliance report (from a SBOM file) using [`grant`]. It can output in two ways: - HTML: for pull request comments (e.g., when adding a new dependency, or when dependabot bumps versions) - TTY: for terminal/CLI users [`grant`]: https://github.com/anchore/grant
- Loading branch information
1 parent
fb9c0a1
commit 2e7957e
Showing
34 changed files
with
2,142 additions
and
0 deletions.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# Generated SBOM files for test fixtures. | ||
sample-*.json linguist-generated | ||
|
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
name: Run tests against grant-license-checker | ||
on: | ||
pull_request: | ||
types: | ||
- opened | ||
- synchronize | ||
paths: | ||
- .github/workflows/test-grant-license-checker.yaml | ||
- ./grant-license-checker/** | ||
push: | ||
branches: [ main ] | ||
paths: | ||
- .github/workflows/test-grant-license-checker.yaml | ||
- ./grant-license-checker/** | ||
|
||
jobs: | ||
main: | ||
runs-on: ubuntu-22.04 | ||
defaults: | ||
run: | ||
working-directory: ./grant-license-checker | ||
steps: | ||
- name: Checkout Code | ||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 | ||
with: | ||
sparse-checkout: ./grant-license-checker | ||
|
||
- name: Setup Python | ||
uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0 | ||
with: | ||
# Note: make sure to update `poetry env use pythonX.Y` below. | ||
python-version: '3.12' | ||
|
||
- name: Install Python Dependencies | ||
shell: bash | ||
run: | | ||
pip install poetry~=1.8.0 | ||
poetry env use python3.12 | ||
poetry install --with=dev | ||
echo "$(poetry env info -p)"/bin >> "$GITHUB_PATH" | ||
- name: pytest | ||
run: | | ||
pytest ./ |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# Files that may be accidentally pushed by developers | ||
# when testing locally. | ||
.grant/ | ||
bom.json | ||
sbom.json |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
# Contributing | ||
|
||
## GitHub Workflows: Best Practices | ||
|
||
- Prefer creating script files (`.sh`, `.py`), it makes local testing easier; | ||
- If the shell code cannot be ran locally (e.g., deeply depends on GitHub Workflows), it's acceptable to not put the script outside the workflow. |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,210 @@ | ||
# grant-license-checker | ||
|
||
An action that generates a report of licenses used by main and transient dependencies, | ||
and checks for compliance issues using [grant](https://github.com/anchore/grant). | ||
|
||
## Example Output | ||
|
||
<table> | ||
<tr> | ||
<th width='200px'>License Name</th> | ||
<th>Package Count</th> | ||
<th>Packages</th> </tr> | ||
<tr> | ||
<td>PSF-2.0</td> | ||
<td>1</td> | ||
<td> | ||
<details> | ||
<summary>Packages</summary> | ||
<ul> | ||
<li>typing-extensions</li> | ||
</ul> | ||
</details> | ||
</td> | ||
</tr> | ||
<tr> | ||
<td>0BSD</td> | ||
<td>4</td> | ||
<td> | ||
<details> | ||
<summary>Packages</summary> | ||
<ul> | ||
<li>colorama</li> | ||
<li>Jinja2</li> | ||
<li>MarkupSafe</li> | ||
<li>packaging</li> | ||
</ul> | ||
</details> | ||
</td> | ||
</tr> | ||
<tr> | ||
<td>MIT</td> | ||
<td>6</td> | ||
<td> | ||
<details> | ||
<summary>Packages</summary> | ||
<ul> | ||
<li>annotated-types</li> | ||
<li>iniconfig</li> | ||
<li>pluggy</li> | ||
<li>pydantic</li> | ||
<li>pydantic-core</li> | ||
<li>pytest</li> | ||
</ul> | ||
</details> | ||
</td> | ||
</tr> | ||
</table> | ||
|
||
## Usage | ||
|
||
### GitHub Action | ||
|
||
```yaml | ||
on: | ||
pull_request: | ||
types: | ||
- opened | ||
- synchronize | ||
paths: | ||
# Python Ecosystem | ||
- "**/pyproject.toml" | ||
- "**/setup.py" | ||
- "**/requirements*.txt" | ||
- "**/Pipfile.lock" | ||
- "**/poetry.lock" | ||
# JS/TS Ecosystem | ||
- "**/package.json" | ||
- "**/pnpm-lock.yaml" | ||
- "**/package-lock.json" | ||
|
||
permissions: | ||
contents: read | ||
|
||
jobs: | ||
check: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Checkout | ||
uses: actions/checkout@v4 | ||
|
||
- name: Analyze Licenses | ||
uses: saleor/saleor-internal-actions/grant-license-checker@v0 | ||
with: | ||
# Needs to be a SBOM that contains license information (SPDX, CycloneDX, | ||
# and Syft formats are supported). | ||
# You can use 'saleor/saleor-internal-actions/sbom-generator' to generate such SBOMs. | ||
sbom_path: ./sbom.json | ||
# See https://cyclonedx.github.io/cdxgen/#/PROJECT_TYPES for the supported | ||
# ecosystems ("Project Types" column). | ||
ecosystems: | | ||
python | ||
javascript | ||
# YAML rules for grant. | ||
rules: | | ||
- pattern: "BSD-*" | ||
name: "allow-bsd" | ||
mode: "allow" | ||
- pattern: "*" | ||
name: "default-deny-all" | ||
mode: "deny" | ||
reason: "All licenses need to be explicitly approved (allow-list)" | ||
``` | ||
### Reusable GitHub Workflow | ||
```yaml | ||
name: Check Licenses | ||
on: | ||
pull_request: | ||
types: | ||
- opened | ||
- synchronize | ||
paths: | ||
# Python Ecosystem | ||
- "**/pyproject.toml" | ||
- "**/setup.py" | ||
- "**/requirements*.txt" | ||
- "**/Pipfile.lock" | ||
- "**/poetry.lock" | ||
# JS/TS Ecosystem | ||
- "**/package.json" | ||
- "**/pnpm-lock.yaml" | ||
- "**/package-lock.json" | ||
|
||
jobs: | ||
default: | ||
permissions: | ||
contents: read | ||
pull-requests: write | ||
uses: saleor/saleor-internal-actions/.github/workflows/run-license-check.yaml@v0 | ||
``` | ||
### CLI | ||
Usage: | ||
``` | ||
usage: grant-summarize [-h] -i INPUT [-l] [-m MAX_PACKAGES] [-f {html,tty}] [-o OUTPUT] [-v VERBOSE | -D DEBUG] | ||
|
||
This command summarizes a grant JSON output with human friendly formats. Such as: - HTML table (GitHub Markdown-compatible), - TTY plaintext. | ||
|
||
options: | ||
-h, --help show this help message and exit | ||
-v VERBOSE, --verbose VERBOSE | ||
Enable verbose logging | ||
-D DEBUG, --debug DEBUG | ||
Enable debug logging | ||
|
||
Input Preferences: | ||
-i INPUT, --input INPUT | ||
The grant JSON output file | ||
|
||
Output Preferences: | ||
-l, --list-packages Whether to include the package list in the output. | ||
-m MAX_PACKAGES, --max-packages MAX_PACKAGES | ||
The maximum number of packages to include in the output per license. A value too large can potentially not fit inside GitHub comments. | ||
-f {html,tty}, --format {html,tty} | ||
The output format, one of: 'text' (logs friendly), 'html' (markdown friendly) | ||
-o OUTPUT, --output OUTPUT | ||
The path to the output the result. Defaults to stdout. | ||
``` | ||
|
||
End to end example: | ||
|
||
1. `cd <path to project>` | ||
2. Generate the SBOM: | ||
``` | ||
docker run \ | ||
--rm \ | ||
-v "$(pwd):/app:rw" \ | ||
--env FETCH_LICENSE=true \ | ||
-t ghcr.io/cyclonedx/cdxgen:v10.9.5 \ | ||
-r /app -o /app/bom.json --profile license-compliance -t npm -t python | ||
``` | ||
3. Generate the `grant` report: | ||
``` | ||
grant check ./bom.json -o json > ./grant.json | ||
``` | ||
4. Generate the summary: | ||
``` | ||
grant-summarize -i grant.json | ||
``` | ||
|
||
## Development | ||
|
||
This project takes a `grant check` JSON report as input and renders it. | ||
|
||
### Project Structure | ||
|
||
- `cmd/` | ||
- Module where commands should be defined at; | ||
- When adding a new command, add it in `pyproject.toml` to ensure it is installed into the `PATH` (`PATH` is updated on `poetry install`). | ||
- `renderers/` | ||
- Module containing rendering templates and logics; | ||
- When adding a new renderer, register it inside `__init__.py`, it will be automatically available for use via `--format=<name>`. | ||
- `tests/fixtures/` | ||
- Contains test data that can also be used during the project's development; | ||
- `sample-sbom-v1.5.json` - a basic CycloneDX SBOM file (https://cyclonedx.org/docs/1.5/json/). | ||
Can be used against `grant`, e.g `grant check ./bom.json -o table --show-packages`; | ||
- `sample-grant-report.json` - a basic JSON report generated by `grant check`. |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
name: grant-license-checker | ||
description: >- | ||
Generates a report of licenses used by main and transient dependencies, | ||
and checks for compliance issues. | ||
inputs: | ||
sbom_path: | ||
required: true | ||
description: >- | ||
The path of the SBOM to analyze. | ||
Supported formats: SPDX, CycloneDX, Syft. | ||
rules: | ||
description: >- | ||
A list of grant YAML rules (default: deny all GPL licenses). | ||
More details at: https://github.com/anchore/grant/blob/v0.2.1/README.md#usage. | ||
default: | | ||
- pattern: "*gpl*" | ||
name: "default-deny-gpl" | ||
mode: "deny" | ||
reason: "GPL licenses are not compatible with BSD-3-Clause." | ||
outputs: | ||
results_dir_path: | ||
description: "Where all the results files are stored (JSON, and HTML)" | ||
value: ${{ steps.results-paths.outputs.results_dir }} | ||
grant_json_path: | ||
description: "Where the JSON results of grant are stored" | ||
value: ${{ steps.results-paths.outputs.grant_json_path }} | ||
grant_html_path: | ||
description: "Where the HTML results of grant are stored" | ||
value: ${{ steps.results-paths.outputs.grant_html_path }} | ||
runs: | ||
using: composite | ||
steps: | ||
- name: Setup Python | ||
uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0 | ||
with: | ||
# Note: make sure to update `poetry env use pythonX.Y` below. | ||
python-version: '3.12' | ||
|
||
- name: Install Python Dependencies | ||
shell: bash | ||
working-directory: ${{ github.action_path }} | ||
run: | | ||
pip install poetry~=1.8.0 | ||
poetry env use python3.12 | ||
poetry install --only=main | ||
echo "$(poetry env info -p)"/bin >> "$GITHUB_PATH" | ||
- name: Install Grant | ||
shell: bash | ||
run: | | ||
"${GITHUB_ACTION_PATH}/scripts/download-grant.sh" | ||
- name: Set-up Results Path | ||
id: results-paths | ||
shell: bash | ||
run: | | ||
results_dir=.grant/results | ||
mkdir -p "$results_dir" | ||
{ | ||
echo "results_dir=$results_dir" | ||
echo "grant_json_path=$results_dir/grant.json" | ||
echo "grant_html_path=$results_dir/grant.html" | ||
} >> "$GITHUB_OUTPUT" | ||
- name: Configure Grant | ||
id: grant-cfg | ||
shell: bash | ||
env: | ||
RULES_YAML_ARRAY: ${{ inputs.rules }} | ||
run: | | ||
cfg_path=./.grant.yaml | ||
echo "cfg_path=$cfg_path" >> "$GITHUB_OUTPUT" | ||
# Construct grant config YAML with the contents: `rules: [<user-input>]` | ||
printf '%s' "$RULES_YAML_ARRAY" | yq '{"rules": .}' - > "$cfg_path" | ||
- name: Check Dependencies | ||
shell: bash | ||
id: grant-check | ||
env: | ||
SBOM_PATH: ${{ inputs.sbom_path }} | ||
RESULTS_PATH: ${{ steps.results-paths.outputs.grant_json_path }} | ||
GRANT_CONFIG_PATH: ${{ steps.grant-cfg.outputs.cfg_path }} | ||
run: | | ||
cmd_args=() | ||
# Enable trace and debug logging if the runner has debug mode enabled | ||
test -z "${RUNNER_DEBUG+x}" || cmd_args+=( "-vvv" ) | ||
./.grant/grant check "$SBOM_PATH" \ | ||
-o json \ | ||
--show-packages \ | ||
"--config=$GRANT_CONFIG_PATH" \ | ||
"${cmd_args[@]}" > "$RESULTS_PATH" | ||
- name: Generate Report | ||
# Always generate the report, even if there are license violations | ||
if: ${{ success() || ( failure() && steps.grant-check.conclusion == 'failure' ) }} | ||
shell: bash | ||
env: | ||
RESULTS_JSON_PATH: ${{ steps.results-paths.outputs.grant_json_path }} | ||
RESULTS_HTML_PATH: ${{ steps.results-paths.outputs.grant_html_path }} | ||
run: | | ||
grant-summarize \ | ||
-i "$RESULTS_JSON_PATH" \ | ||
-f html \ | ||
-o "$RESULTS_HTML_PATH" \ | ||
--list-packages |
Empty file.
Empty file.
Oops, something went wrong.