Compare commits
64 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
66a6ee35b1 | ||
|
|
7fa452fb4b | ||
|
|
9970334372 | ||
|
|
98cf6988a1 | ||
|
|
8e7c7748a9 | ||
|
|
2ffb2343b3 | ||
|
|
f0318e8b9e | ||
|
|
d10ebbb9e0 | ||
|
|
34ad292862 | ||
|
|
e93921ea5a | ||
|
|
f1c3022531 | ||
|
|
de8855bb5b | ||
|
|
bfbcd5f00a | ||
|
|
41edf6f055 | ||
|
|
b3978f6f12 | ||
|
|
da98638f18 | ||
|
|
e2eb0a2b6b | ||
|
|
02a0ac8d1d | ||
|
|
648d9a1458 | ||
|
|
cbfb60b762 | ||
|
|
834dac3117 | ||
|
|
b0e7c507ca | ||
|
|
31eb18f0de | ||
|
|
7714fcb0ce | ||
|
|
52b2e35e0c | ||
|
|
6833440696 | ||
|
|
96dc0a401e | ||
|
|
68a61d77e9 | ||
|
|
0b37897812 | ||
|
|
82ecb5449d | ||
|
|
ca6166b637 | ||
|
|
fee84f2320 | ||
|
|
49949764d3 | ||
|
|
63a52c0a3a | ||
|
|
218578ea1c | ||
|
|
db23b68152 | ||
|
|
1220774d90 | ||
|
|
8c34e8a682 | ||
|
|
530374b67a | ||
|
|
d499194be7 | ||
|
|
cf52d21d83 | ||
|
|
3ac8fed01c | ||
|
|
f7e969538f | ||
|
|
28aa5e1be6 | ||
|
|
1abec09c8d | ||
|
|
75edeacda5 | ||
|
|
666b1b8831 | ||
|
|
9075e938de | ||
|
|
0007f08635 | ||
|
|
c5b051c6b3 | ||
|
|
e187a7bf0b | ||
|
|
b0690898d5 | ||
|
|
454d956b51 | ||
|
|
e02369acd1 | ||
|
|
1d4b225904 | ||
|
|
d634a13a33 | ||
|
|
5e29e47492 | ||
|
|
5ed8d3149c | ||
|
|
2e332741f5 | ||
|
|
fc80c9a7d2 | ||
|
|
ac6a629be3 | ||
|
|
2d48142e41 | ||
|
|
6257a8afdd | ||
|
|
4a89a38104 |
64
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
64
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
name: Bug report
|
||||
description: Report a bug with pip-audit's GitHub Action
|
||||
labels: bug
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: >-
|
||||
Thank you for reporting a potential bug in `gh-action-pip-audit`! Please
|
||||
read the following carefully:
|
||||
|
||||
|
||||
**IMPORTANT:** This issue tracker is for `pip-audit`'s
|
||||
**GitHub Action**, the scaffolding that integrates `pip-audit` with your
|
||||
CI. If the buggy behavior you are experiencing appears to be in
|
||||
`pip-audit`, please file an issue
|
||||
[against the `pip-audit` repo](https://github.com/pypa/pip-audit/issues/new/choose).
|
||||
|
||||
|
||||
**IMPORTANT:** Please fill out every section below. Bug reports with
|
||||
missing information will be given a lower priority or closed outright.
|
||||
|
||||
|
||||
Before filing an issue, check out our
|
||||
[troubleshooting guide](https://github.com/pypa/gh-action-pip-audit#troubleshooting) :)
|
||||
- type: textarea
|
||||
id: current-behavior
|
||||
attributes:
|
||||
label: Current behavior
|
||||
description: >-
|
||||
What issue are you having with the action? What were you trying to do
|
||||
when the issue occurred?
|
||||
placeholder: The action run succeeds when I ...
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: expected-behavior
|
||||
attributes:
|
||||
label: Expected behavior
|
||||
description: What should've happened instead?
|
||||
placeholder: I expected the action run to fail.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: repro
|
||||
attributes:
|
||||
label: Steps to reproduce
|
||||
description: What are the detailed steps we can follow to trigger this issue?
|
||||
placeholder: |-
|
||||
1. ...
|
||||
2. ...
|
||||
3. ...
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: context
|
||||
attributes:
|
||||
label: Relevant context
|
||||
description: >-
|
||||
Please include a link to an action run, as well as any logs that you think might
|
||||
be helpful! You can
|
||||
[follow these instructions](https://docs.github.com/en/actions/managing-workflow-runs/re-running-workflows-and-jobs#re-running-all-the-jobs-in-a-workflow)
|
||||
to re-run the action with debug logging.
|
||||
validations:
|
||||
required: true
|
||||
11
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
11
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: pip-audit's issue tracker
|
||||
url: https://github.com/pypa/pip-audit/issues/new/choose
|
||||
about: >-
|
||||
You may want to file a report on pip-audit instead if your issue is not
|
||||
directly related to this GitHub Action
|
||||
- name: Troubleshooting guide
|
||||
url: https://github.com/pypa/gh-action-pip-audit#troubleshooting
|
||||
about: >-
|
||||
Learn how to fix some common issues or enable debug logging here
|
||||
50
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
50
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
name: Feature request
|
||||
description: Suggest an idea for pip-audit's GitHub Action
|
||||
labels: enhancement
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: >-
|
||||
Thank you for filing a feature request for `gh-action-pip-audit`! Please
|
||||
read the following carefully:
|
||||
|
||||
|
||||
**IMPORTANT:** This form is for `pip-audit`'s **GitHub Action**, the
|
||||
scaffolding that integrates `pip-audit` with your CI. If you would like
|
||||
a new feature in `pip-audit` itself, please go to
|
||||
[the `pip-audit` repo](https://github.com/pypa/pip-audit/issues/new/choose).
|
||||
|
||||
|
||||
**IMPORTANT:** Please fill out every required section below to the best
|
||||
of your ability. Feature requests with missing information may be given
|
||||
a lower priority or closed outright.
|
||||
- type: textarea
|
||||
id: problem
|
||||
attributes:
|
||||
label: Is your feature request related to a problem?
|
||||
description: Describe how the current solution is deficient.
|
||||
placeholder: I am frustrated when ...
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: solution
|
||||
attributes:
|
||||
label: Describe the solution you'd like
|
||||
description:
|
||||
placeholder: I think gh-action-pip-audit would benefit from ...
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: alternatives-considered
|
||||
attributes:
|
||||
label: Alternative solutions or features you've considered
|
||||
description:
|
||||
placeholder:
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: context
|
||||
attributes:
|
||||
label: Additional context
|
||||
description: Add any context or screenshots related to the feature request.
|
||||
placeholder:
|
||||
12
.github/dependabot.yml
vendored
Normal file
12
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
---
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
groups:
|
||||
actions:
|
||||
patterns:
|
||||
- "*"
|
||||
...
|
||||
10
.github/workflows/ci.yml
vendored
10
.github/workflows/ci.yml
vendored
@@ -6,13 +6,17 @@ on:
|
||||
- main
|
||||
pull_request:
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-python@v4
|
||||
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||
with:
|
||||
python-version: "3.7"
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
|
||||
with:
|
||||
python-version: "3.x"
|
||||
- name: lint
|
||||
run: make lint
|
||||
|
||||
89
.github/workflows/selftest.yml
vendored
89
.github/workflows/selftest.yml
vendored
@@ -7,11 +7,22 @@ on:
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
selftest-requirements:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: ./
|
||||
id: pip-audit
|
||||
with:
|
||||
@@ -21,6 +32,7 @@ jobs:
|
||||
# explicitly uses a vulnerable requirements file.
|
||||
internal-be-careful-allow-failure: true
|
||||
- name: assert expected output
|
||||
shell: bash
|
||||
env:
|
||||
PIP_AUDIT_OUTPUT: "${{ steps.pip-audit.outputs.internal-be-careful-output }}"
|
||||
run: |
|
||||
@@ -29,7 +41,9 @@ jobs:
|
||||
selftest-environment:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: make the environment vulnerable
|
||||
run: |
|
||||
python -m pip install --no-deps --requirement ./test/vulnerable.txt
|
||||
@@ -51,7 +65,9 @@ jobs:
|
||||
local: [true, false]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: make a virtual environment vulnerable
|
||||
run: |
|
||||
python -m venv env
|
||||
@@ -74,7 +90,9 @@ jobs:
|
||||
selftest-pyproject:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: ./
|
||||
id: pip-audit
|
||||
with:
|
||||
@@ -88,3 +106,64 @@ jobs:
|
||||
PIP_AUDIT_OUTPUT: "${{ steps.pip-audit.outputs.internal-be-careful-output }}"
|
||||
run: |
|
||||
grep -E 'pyyaml\s+\|\s+5.1' <<< $(base64 -d <<< "${PIP_AUDIT_OUTPUT}")
|
||||
|
||||
selftest-pipaudit-fail:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: ./
|
||||
id: pip-audit
|
||||
with:
|
||||
# we do not care about pip-audit's actual output in this test, we just need a file to pass
|
||||
# in so as to not exercise `pip list` mode.
|
||||
inputs: ./test/empty.txt
|
||||
# pass in a fake flag here to reliably trigger the failure we're looking for.
|
||||
internal-be-careful-extra-flags: --not-a-real-pip-audit-flag
|
||||
internal-be-careful-allow-failure: true
|
||||
- name: assert expected output
|
||||
env:
|
||||
PIP_AUDIT_OUTPUT: "${{ steps.pip-audit.outputs.internal-be-careful-output }}"
|
||||
run: |
|
||||
grep 'pip-audit did not return any output' <<< $(base64 -d <<< "${PIP_AUDIT_OUTPUT}")
|
||||
|
||||
selftest-locked:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: ./
|
||||
id: pip-audit
|
||||
with:
|
||||
# should attempt to discover test/pylock/pylock.toml
|
||||
inputs: test/pylock/
|
||||
locked: true
|
||||
# NOTE: We intentionally allow failure here, since the self-test
|
||||
# explicitly uses a vulnerable requirements file.
|
||||
internal-be-careful-allow-failure: true
|
||||
- name: assert expected output
|
||||
env:
|
||||
PIP_AUDIT_OUTPUT: "${{ steps.pip-audit.outputs.internal-be-careful-output }}"
|
||||
run: |
|
||||
grep -E 'pyyaml\s+\|\s+5.1' <<< $(base64 -d <<< "${PIP_AUDIT_OUTPUT}")
|
||||
|
||||
all-selftests-pass:
|
||||
if: always()
|
||||
|
||||
needs:
|
||||
- selftest-requirements
|
||||
- selftest-environment
|
||||
- selftest-virtualenv
|
||||
- selftest-pyproject
|
||||
- selftest-pipaudit-fail
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: check test jobs
|
||||
if: (github.event_name != 'pull_request') || !github.event.pull_request.head.repo.fork
|
||||
uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe # v1.2.2
|
||||
with:
|
||||
jobs: ${{ toJSON(needs) }}
|
||||
|
||||
28
.github/workflows/semgrep.yml
vendored
Normal file
28
.github/workflows/semgrep.yml
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
name: Semgrep
|
||||
|
||||
on:
|
||||
pull_request: {}
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- master
|
||||
paths:
|
||||
- .github/workflows/semgrep.yml
|
||||
schedule:
|
||||
- cron: '0 0 * * 0'
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
semgrep:
|
||||
name: Scan
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }}
|
||||
container:
|
||||
image: semgrep/semgrep
|
||||
steps:
|
||||
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- run: semgrep ci
|
||||
38
.github/workflows/zizmor.yml
vendored
Normal file
38
.github/workflows/zizmor.yml
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
name: GitHub Actions Security Analysis with zizmor 🌈
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["main"]
|
||||
pull_request:
|
||||
branches: ["**"]
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
zizmor:
|
||||
name: zizmor latest via PyPI
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
security-events: write
|
||||
# required for workflows in private repositories
|
||||
contents: read
|
||||
actions: read
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Install the latest version of uv
|
||||
uses: astral-sh/setup-uv@681c641aba71e4a1c380be3ab5e12ad51f415867 # v7.1.6
|
||||
|
||||
- name: Run zizmor 🌈
|
||||
run: uvx zizmor --format sarif . > results.sarif
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Upload SARIF file
|
||||
uses: github/codeql-action/upload-sarif@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # v4.31.9
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
category: zizmor
|
||||
145
README.md
145
README.md
@@ -1,34 +1,38 @@
|
||||
gh-action-pip-audit
|
||||
===================
|
||||
|
||||
[](https://github.com/trailofbits/gh-action-pip-audit/actions/workflows/ci.yml)
|
||||
[](https://github.com/trailofbits/gh-action-pip-audit/actions/workflows/selftest.yml)
|
||||
[](https://github.com/pypa/gh-action-pip-audit/actions/workflows/ci.yml)
|
||||
[](https://github.com/pypa/gh-action-pip-audit/actions/workflows/selftest.yml)
|
||||
|
||||
A GitHub Action that uses [`pip-audit`](https://github.com/trailofbits/pip-audit)
|
||||
A GitHub Action that uses [`pip-audit`](https://github.com/pypa/pip-audit)
|
||||
to scan Python dependencies for known vulnerabilities.
|
||||
|
||||
This project is maintained in part by [Trail of Bits](https://www.trailofbits.com/)
|
||||
with support from Google. This is not an official Google or Trail of Bits product.
|
||||
|
||||
## Index
|
||||
|
||||
* [Usage](#usage)
|
||||
* [Configuration](#configuration)
|
||||
* [⚠️ Internal options ⚠️](#internal-options)
|
||||
* [Troubleshooting](#troubleshooting)
|
||||
* [Tips and Tricks](#tips-and-tricks)
|
||||
* [Licensing](#licensing)
|
||||
* [Code of Conduct](#code-of-conduct)
|
||||
|
||||
## Usage
|
||||
|
||||
Simply add `trailofbits/gh-action-pip-audit` to one of your workflows:
|
||||
Simply add `pypa/gh-action-pip-audit` to one of your workflows:
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
selftest:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: install
|
||||
run: python -m pip install .
|
||||
- uses: trailofbits/gh-action-pip-audit@v1.0.0
|
||||
- uses: pypa/gh-action-pip-audit@v1.1.0
|
||||
```
|
||||
|
||||
Or, with a virtual environment:
|
||||
@@ -38,13 +42,13 @@ jobs:
|
||||
selftest:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: install
|
||||
run: |
|
||||
python -m venv env/
|
||||
source env/bin/activate
|
||||
python -m pip install .
|
||||
- uses: trailofbits/gh-action-pip-audit@v1.0.0
|
||||
- uses: pypa/gh-action-pip-audit@v1.1.0
|
||||
with:
|
||||
virtual-environment: env/
|
||||
```
|
||||
@@ -68,7 +72,7 @@ The `inputs` setting controls what sources `pip-audit` runs on.
|
||||
To audit one or more requirements-style inputs:
|
||||
|
||||
```yaml
|
||||
- uses: trailofbits/gh-action-pip-audit@v1.0.0
|
||||
- uses: pypa/gh-action-pip-audit@v1.1.0
|
||||
with:
|
||||
inputs: requirements.txt dev-requirements.txt
|
||||
```
|
||||
@@ -76,7 +80,7 @@ To audit one or more requirements-style inputs:
|
||||
To audit a project that uses `pyproject.toml` for its dependencies:
|
||||
|
||||
```yaml
|
||||
- uses: trailofbits/gh-action-pip-audit@v1.0.0
|
||||
- uses: pypa/gh-action-pip-audit@v1.1.0
|
||||
with:
|
||||
# NOTE: this can be `.`, for the current directory
|
||||
inputs: path/to/project/
|
||||
@@ -104,7 +108,7 @@ Example: use the virtual environment specified at `env/`, relative to the
|
||||
current directory:
|
||||
|
||||
```yaml
|
||||
- uses: trailofbits/gh-action-pip-audit@v1.0.0
|
||||
- uses: pypa/gh-action-pip-audit@v1.1.0
|
||||
with:
|
||||
virtual-environment: env/
|
||||
# Note the absence of `input:`, since we're auditing the environment.
|
||||
@@ -124,7 +128,7 @@ installed directly into the current environment are included.
|
||||
Example:
|
||||
|
||||
```yaml
|
||||
- uses: trailofbits/gh-action-pip-audit@v1.0.0
|
||||
- uses: pypa/gh-action-pip-audit@v1.1.0
|
||||
with:
|
||||
local: true
|
||||
```
|
||||
@@ -141,7 +145,7 @@ It's directly equivalent to `pip-audit --vulnerability-service=...`.
|
||||
To audit with OSV instead of PyPI:
|
||||
|
||||
```yaml
|
||||
- uses: trailofbits/gh-action-pip-audit@v1.0.0
|
||||
- uses: pypa/gh-action-pip-audit@v1.1.0
|
||||
with:
|
||||
vulnerability-service: osv
|
||||
```
|
||||
@@ -156,7 +160,7 @@ It's directly equivalent to `pip-audit --require-hashes ...`.
|
||||
Example:
|
||||
|
||||
```yaml
|
||||
- uses: trailofbits/gh-action-pip-audit@v1.0.0
|
||||
- uses: pypa/gh-action-pip-audit@v1.1.0
|
||||
with:
|
||||
# NOTE: only works with requirements-style inputs
|
||||
inputs: requirements.txt
|
||||
@@ -173,7 +177,7 @@ It's directly equivalent to `pip-audit --no-deps ...`.
|
||||
Example:
|
||||
|
||||
```yaml
|
||||
- uses: trailofbits/gh-action-pip-audit@v1.0.0
|
||||
- uses: pypa/gh-action-pip-audit@v1.1.0
|
||||
with:
|
||||
# NOTE: only works with requirements-style inputs
|
||||
inputs: requirements.txt
|
||||
@@ -191,7 +195,7 @@ is rendered at the end of the action.
|
||||
Example:
|
||||
|
||||
```yaml
|
||||
- uses: trailofbits/gh-action-pip-audit@v1.0.0
|
||||
- uses: pypa/gh-action-pip-audit@v1.1.0
|
||||
with:
|
||||
summary: false
|
||||
```
|
||||
@@ -210,7 +214,7 @@ indices to search (such as a corporate index with private packages), see
|
||||
Example:
|
||||
|
||||
```yaml
|
||||
- uses: trailofbits/gh-action-pip-audit@v1.0.0
|
||||
- uses: pypa/gh-action-pip-audit@v1.1.0
|
||||
with:
|
||||
index-url: https://example.corporate.local/simple
|
||||
```
|
||||
@@ -225,7 +229,7 @@ indexes to search when resolving dependencies. Each URL is whitespace-separated.
|
||||
Example:
|
||||
|
||||
```yaml
|
||||
- uses: trailofbits/gh-action-pip-audit@v1.0.0
|
||||
- uses: pypa/gh-action-pip-audit@v1.1.0
|
||||
with:
|
||||
extra-index-urls: |
|
||||
https://example.corporate.local/simple
|
||||
@@ -242,13 +246,45 @@ ignore (i.e., exclude from the results) if present. Each ID is whitespace-separa
|
||||
Example
|
||||
|
||||
```yaml
|
||||
- uses: trailofbits/gh-action-pip-audit@v1.0.0
|
||||
- uses: pypa/gh-action-pip-audit@v1.1.0
|
||||
with:
|
||||
ignore-vulns: |
|
||||
GHSA-XXXX-YYYYYY
|
||||
PYSEC-AAAA-BBBBB
|
||||
```
|
||||
|
||||
### `disable-pip`
|
||||
|
||||
**Default**: `false`
|
||||
|
||||
The `disable-pip` setting disable the use of `pip` for dependency resolution. This can only be used with
|
||||
hashed requirements files or if the `no-deps` setting has been provided.
|
||||
|
||||
Example
|
||||
|
||||
```yaml
|
||||
- uses: pypa/gh-action-pip-audit@v1.1.0
|
||||
with:
|
||||
inputs: requirements.lock
|
||||
disable-pip: true
|
||||
no-deps: true
|
||||
```
|
||||
|
||||
### `locked`
|
||||
|
||||
**Default**: `false`
|
||||
|
||||
The `locked` setting enables audits of lock files (`pylock.*.toml`) from the local Python project.
|
||||
|
||||
Example
|
||||
|
||||
```yaml
|
||||
- uses: pypa/gh-action-pip-audit@v1.1.0
|
||||
with:
|
||||
inputs: path/to/project/
|
||||
locked: true
|
||||
```
|
||||
|
||||
### Internal options
|
||||
<details>
|
||||
<summary>⚠️ Internal options ⚠️</summary>
|
||||
@@ -272,29 +308,24 @@ Example
|
||||
Example:
|
||||
|
||||
```yaml
|
||||
- uses: trailofbits/gh-action-pip-audit@v1.0.0
|
||||
- uses: pypa/gh-action-pip-audit@v1.1.0
|
||||
with:
|
||||
internal-be-careful-allow-failure: true
|
||||
```
|
||||
|
||||
#### `internal-be-careful-debug`
|
||||
#### `internal-be-careful-extra-flags`
|
||||
**Default**: `""`
|
||||
|
||||
**Default**: `false`
|
||||
The `internal-be-careful-extra-flags` setting passes the specified flags
|
||||
to `pip-audit`.
|
||||
|
||||
The `internal-be-careful-debug` setting enables additional debug logs,
|
||||
both within `pip-audit` itself and the action's harness code. You can
|
||||
use it to debug troublesome configurations.
|
||||
Example:
|
||||
|
||||
Be mindful that `pip-audit`'s own debug logs contain HTTP requests,
|
||||
which may or may not be sensitive in your use case.
|
||||
|
||||
Example:
|
||||
|
||||
```yaml
|
||||
- uses: trailofbits/gh-action-pip-audit@v1.0.0
|
||||
with:
|
||||
internal-be-careful-debug: true
|
||||
```
|
||||
```yaml
|
||||
- uses: pypa/gh-action-pip-audit@v1.1.0
|
||||
with:
|
||||
internal-be-careful-extra-flags: --not-a-real-pip-audit-flag
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
@@ -308,7 +339,7 @@ If you're auditing a requirements file, consider setting `no-deps: true` or
|
||||
`require-hashes: true`:
|
||||
|
||||
```yaml
|
||||
- uses: trailofbits/gh-action-pip-audit@v1.0.0
|
||||
- uses: pypa/gh-action-pip-audit@v1.1.0
|
||||
with:
|
||||
inputs: requirements.txt
|
||||
require-hashes: true
|
||||
@@ -317,14 +348,14 @@ If you're auditing a requirements file, consider setting `no-deps: true` or
|
||||
or:
|
||||
|
||||
```yaml
|
||||
- uses: trailofbits/gh-action-pip-audit@v1.0.0
|
||||
- uses: pypa/gh-action-pip-audit@v1.1.0
|
||||
with:
|
||||
inputs: requirements.txt
|
||||
no-deps: true
|
||||
```
|
||||
|
||||
See the
|
||||
["`pip-audit` takes longer than I expect!"](https://github.com/trailofbits/pip-audit#pip-audit-takes-longer-than-i-expect)
|
||||
["`pip-audit` takes longer than I expect!"](https://github.com/pypa/pip-audit#pip-audit-takes-longer-than-i-expect)
|
||||
troubleshooting for more details.
|
||||
|
||||
### The action shows dependencies that aren't in my environment!
|
||||
@@ -338,7 +369,7 @@ by the host system itself, or other Python projects that happen to be installed.
|
||||
To minimize external dependencies, you can opt into a virtual environment:
|
||||
|
||||
```yaml
|
||||
- uses: trailofbits/gh-action-pip-audit@v1.0.0
|
||||
- uses: pypa/gh-action-pip-audit@v1.1.0
|
||||
with:
|
||||
# must be populated earlier in the CI
|
||||
virtual-environment: env/
|
||||
@@ -348,13 +379,47 @@ and, more aggressively, specify that only dependencies marked as "local"
|
||||
in the virtual environment should be included:
|
||||
|
||||
```yaml
|
||||
- uses: trailofbits/gh-action-pip-audit@v1.0.0
|
||||
- uses: pypa/gh-action-pip-audit@v1.1.0
|
||||
with:
|
||||
# must be populated earlier in the CI
|
||||
virtual-environment: env/
|
||||
local: true
|
||||
```
|
||||
|
||||
### There's an issue with the action and I want to enable debug logging!
|
||||
|
||||
The action prints debug information when the `ACTIONS_STEP_DEBUG` secret is set
|
||||
to `true``. You should be able to enable this behavior by
|
||||
[following these instructions](https://docs.github.com/en/actions/managing-workflow-runs/re-running-workflows-and-jobs#re-running-all-the-jobs-in-a-workflow).
|
||||
|
||||
## Tips and Tricks
|
||||
|
||||
### Running against a pipenv project
|
||||
|
||||
If you are adding `pip-audit` to a pipenv based project, you'll first need
|
||||
to convert the `Pipfile[.lock]` to a `requirements.txt` file that `pip-audit`
|
||||
can ingest. Use a Python tool, such as
|
||||
[`pipfile-requirements`](https://github.com/frostming/pipfile-requirements), to
|
||||
convert your `Pipfile[.lock]` to a `requirements.txt` file and then run
|
||||
`pip-audit` GitHub Action against the generated requirements file.
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
pip-audit:
|
||||
steps:
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: 3.9 # change to your required version of Python
|
||||
|
||||
- name: 'Generate requirements.txt'
|
||||
run: |
|
||||
pipx run pipfile-requirements Pipfile.lock > requirements.txt
|
||||
|
||||
- uses: pypa/gh-action-pip-audit@v1.1.0
|
||||
with:
|
||||
inputs: requirements.txt
|
||||
```
|
||||
|
||||
## Licensing
|
||||
|
||||
`gh-action-pip-audit` is licensed under the Apache 2.0 License.
|
||||
|
||||
80
action.py
80
action.py
@@ -6,33 +6,42 @@
|
||||
# is a whitespace-separated list of inputs
|
||||
|
||||
import os
|
||||
import string
|
||||
import subprocess
|
||||
import sys
|
||||
from base64 import b64encode
|
||||
from pathlib import Path
|
||||
|
||||
_OUTPUTS = [sys.stderr]
|
||||
_SUMMARY = Path(os.getenv("GITHUB_STEP_SUMMARY")).open("a")
|
||||
_RENDER_SUMMARY = os.getenv("GHA_PIP_AUDIT_SUMMARY", "true") == "true"
|
||||
_DEBUG = os.getenv("GHA_PIP_AUDIT_INTERNAL_BE_CAREFUL_DEBUG", "false") != "false"
|
||||
sys.stdout.reconfigure(encoding="utf-8")
|
||||
|
||||
if _RENDER_SUMMARY:
|
||||
_OUTPUTS.append(_SUMMARY)
|
||||
_HERE = Path(__file__).parent.resolve()
|
||||
_TEMPLATES = _HERE / "templates"
|
||||
|
||||
_GITHUB_STEP_SUMMARY = Path(os.getenv("GITHUB_STEP_SUMMARY")).open(
|
||||
"a", encoding="utf-8"
|
||||
)
|
||||
_GITHUB_OUTPUT = Path(os.getenv("GITHUB_OUTPUT")).open("a", encoding="utf-8")
|
||||
_RENDER_SUMMARY = os.getenv("GHA_PIP_AUDIT_SUMMARY", "true") == "true"
|
||||
_DEBUG = os.getenv("RUNNER_DEBUG") is not None
|
||||
|
||||
|
||||
def _template(name):
|
||||
path = _TEMPLATES / f"{name}.md"
|
||||
return string.Template(path.read_text())
|
||||
|
||||
|
||||
def _summary(msg):
|
||||
if _RENDER_SUMMARY:
|
||||
print(msg, file=_SUMMARY)
|
||||
print(msg, file=_GITHUB_STEP_SUMMARY)
|
||||
|
||||
|
||||
def _debug(msg):
|
||||
if _DEBUG:
|
||||
print(f"\033[93mDEBUG: {msg}\033[0m", file=sys.stderr)
|
||||
print(f"::debug::{msg}")
|
||||
|
||||
|
||||
def _log(msg):
|
||||
for output in _OUTPUTS:
|
||||
print(msg, file=output)
|
||||
print(msg, file=sys.stderr)
|
||||
|
||||
|
||||
def _pip_audit(*args):
|
||||
@@ -45,7 +54,6 @@ def _fatal_help(msg):
|
||||
|
||||
|
||||
inputs = [Path(p).resolve() for p in sys.argv[1].split()]
|
||||
summary = Path(os.getenv("GITHUB_STEP_SUMMARY")).open("a")
|
||||
|
||||
# The arguments we pass into `pip-audit` get built up in this list.
|
||||
pip_audit_args = [
|
||||
@@ -60,7 +68,7 @@ pip_audit_args = [
|
||||
"--desc",
|
||||
# Write the output to this logfile, which we'll turn into the step summary (if configured).
|
||||
"--output=/tmp/pip-audit-output.txt",
|
||||
]
|
||||
] + os.getenv("GHA_PIP_AUDIT_INTERNAL_BE_CAREFUL_EXTRA_FLAGS").split()
|
||||
|
||||
if _DEBUG:
|
||||
pip_audit_args.append("--verbose")
|
||||
@@ -74,6 +82,9 @@ if os.getenv("GHA_PIP_AUDIT_REQUIRE_HASHES", "false") != "false":
|
||||
if os.getenv("GHA_PIP_AUDIT_LOCAL", "false") != "false":
|
||||
pip_audit_args.append("--local")
|
||||
|
||||
if os.getenv("GHA_PIP_DISABLE_PIP", "false") != "false":
|
||||
pip_audit_args.append("--disable-pip")
|
||||
|
||||
index_url = os.getenv("GHA_PIP_AUDIT_INDEX_URL")
|
||||
if index_url != "":
|
||||
pip_audit_args.extend(["--index-url", index_url])
|
||||
@@ -95,6 +106,10 @@ pip_audit_args.extend(
|
||||
]
|
||||
)
|
||||
|
||||
locked = os.getenv("GHA_PIP_AUDIT_LOCKED", "false") != "false"
|
||||
if locked:
|
||||
pip_audit_args.append("--locked")
|
||||
|
||||
# If inputs is empty, we let `pip-audit` run in "`pip list` source" mode by not
|
||||
# adding any explicit input argument(s).
|
||||
# Otherwise, we handle either exactly one project path (a directory)
|
||||
@@ -112,6 +127,8 @@ for input_ in inputs:
|
||||
else:
|
||||
if not input_.is_file():
|
||||
_fatal_help(f"input {input_} does not look like a file")
|
||||
if locked:
|
||||
_fatal_help("locked only applies to audits of project paths")
|
||||
pip_audit_args.extend(["--requirement", input_])
|
||||
|
||||
_debug(f"running: pip-audit {[str(a) for a in pip_audit_args]}")
|
||||
@@ -127,38 +144,27 @@ status = subprocess.run(
|
||||
_debug(status.stdout)
|
||||
|
||||
if status.returncode == 0:
|
||||
_log("🎉 pip-audit exited successfully")
|
||||
_summary("🎉 pip-audit exited successfully")
|
||||
else:
|
||||
_log("❌ pip-audit found one or more problems")
|
||||
_summary("❌ pip-audit found one or more problems")
|
||||
|
||||
with open("/tmp/pip-audit-output.txt", "r") as io:
|
||||
output = io.read()
|
||||
output = "⚠️ pip-audit did not return any output"
|
||||
try:
|
||||
with open("/tmp/pip-audit-output.txt", "r") as io:
|
||||
output = io.read()
|
||||
except OSError as ex:
|
||||
_log(ex)
|
||||
|
||||
# This is really nasty: our output contains multiple lines,
|
||||
# so we can't naively stuff it into an output (since this is all done
|
||||
# in-channel as a special command on stdout).
|
||||
print(f"::set-output name=output::{b64encode(output.encode()).decode()}")
|
||||
# This is really nasty: our output contains multiple lines,
|
||||
# so we can't naively stuff it into an output.
|
||||
print(f"output={b64encode(output.encode()).decode()}", file=_GITHUB_OUTPUT)
|
||||
|
||||
_log(output)
|
||||
_log(output)
|
||||
_summary(output)
|
||||
|
||||
|
||||
_summary(
|
||||
"""
|
||||
<details>
|
||||
<summary>
|
||||
Raw `pip-audit` output
|
||||
</summary>
|
||||
|
||||
```
|
||||
"""
|
||||
)
|
||||
_log(status.stdout)
|
||||
_summary(
|
||||
"""
|
||||
```
|
||||
</details>
|
||||
"""
|
||||
)
|
||||
_summary(_template("pip-audit").substitute(output=status.stdout))
|
||||
|
||||
# Normally, we exit with the same code as `pip-audit`, but the user can
|
||||
# explicitly configure the CI to always pass.
|
||||
|
||||
21
action.yml
21
action.yml
@@ -42,14 +42,22 @@ inputs:
|
||||
description: "vulnerabilities to explicitly exclude, if present (whitespace separated)"
|
||||
required: false
|
||||
default: ""
|
||||
disable-pip:
|
||||
description: "disable pip"
|
||||
required: false
|
||||
default: false
|
||||
locked:
|
||||
description: "audit lock files from the local Python project"
|
||||
required: false
|
||||
default: false
|
||||
internal-be-careful-allow-failure:
|
||||
description: "don't fail the job if the audit fails (default false)"
|
||||
required: false
|
||||
default: false
|
||||
internal-be-careful-debug:
|
||||
description: "run with debug logs (default false)"
|
||||
internal-be-careful-extra-flags:
|
||||
description: "extra flags to be passed in to pip-audit"
|
||||
required: false
|
||||
default: false
|
||||
default: ""
|
||||
outputs:
|
||||
internal-be-careful-output:
|
||||
description: "the column-formatted output from pip-audit, wrapped as base64"
|
||||
@@ -71,8 +79,9 @@ runs:
|
||||
# NOTE: Sourced, not executed as a script.
|
||||
source "${{ github.action_path }}/setup/venv.bash"
|
||||
|
||||
${{ github.action_path }}/action.py "${{ inputs.inputs }}"
|
||||
python "${{ github.action_path }}/action.py" "$GHA_PIP_AUDIT_INPUTS"
|
||||
env:
|
||||
GHA_PIP_AUDIT_INPUTS: "${{ inputs.inputs }}"
|
||||
GHA_PIP_AUDIT_SUMMARY: "${{ inputs.summary }}"
|
||||
GHA_PIP_AUDIT_NO_DEPS: "${{ inputs.no-deps }}"
|
||||
GHA_PIP_AUDIT_REQUIRE_HASHES: "${{ inputs.require-hashes }}"
|
||||
@@ -82,6 +91,8 @@ runs:
|
||||
GHA_PIP_AUDIT_INDEX_URL: "${{ inputs.index-url }}"
|
||||
GHA_PIP_AUDIT_EXTRA_INDEX_URLS: "${{ inputs.extra-index-urls }}"
|
||||
GHA_PIP_AUDIT_IGNORE_VULNS: "${{ inputs.ignore-vulns }}"
|
||||
GHA_PIP_DISABLE_PIP: "${{ inputs.disable-pip }}"
|
||||
GHA_PIP_AUDIT_LOCKED: "${{ inputs.locked }}"
|
||||
GHA_PIP_AUDIT_INTERNAL_BE_CAREFUL_ALLOW_FAILURE: "${{ inputs.internal-be-careful-allow-failure }}"
|
||||
GHA_PIP_AUDIT_INTERNAL_BE_CAREFUL_DEBUG: "${{ inputs.internal-be-careful-debug }}"
|
||||
GHA_PIP_AUDIT_INTERNAL_BE_CAREFUL_EXTRA_FLAGS: "${{ inputs.internal-be-careful-extra-flags }}"
|
||||
shell: bash
|
||||
|
||||
@@ -1 +1 @@
|
||||
pip-audit==2.4.3
|
||||
pip-audit ~= 2.0, >= 2.5.6
|
||||
|
||||
@@ -17,7 +17,12 @@ fi
|
||||
# `python -m pip install ...` invocation might happen to choose.
|
||||
if [[ -n "${GHA_PIP_AUDIT_VIRTUAL_ENVIRONMENT}" ]] ; then
|
||||
if [[ -d "${GHA_PIP_AUDIT_VIRTUAL_ENVIRONMENT}" ]]; then
|
||||
source "${GHA_PIP_AUDIT_VIRTUAL_ENVIRONMENT}/bin/activate"
|
||||
if [[ "$(uname)" == MSYS_NT* || "$(uname)" == MINGW* ]]; then
|
||||
# execute in windows
|
||||
source "${GHA_PIP_AUDIT_VIRTUAL_ENVIRONMENT}/scripts/activate"
|
||||
else
|
||||
source "${GHA_PIP_AUDIT_VIRTUAL_ENVIRONMENT}/bin/activate"
|
||||
fi
|
||||
else
|
||||
die "Fatal: virtual environment is not a directory"
|
||||
fi
|
||||
|
||||
11
templates/pip-audit.md
Normal file
11
templates/pip-audit.md
Normal file
@@ -0,0 +1,11 @@
|
||||
<details>
|
||||
|
||||
<summary>
|
||||
Raw <code>pip-audit</code> output
|
||||
</summary>
|
||||
|
||||
```
|
||||
$output
|
||||
```
|
||||
|
||||
</details>
|
||||
0
test/empty.txt
Normal file
0
test/empty.txt
Normal file
13
test/pylock/pylock.toml
Normal file
13
test/pylock/pylock.toml
Normal file
@@ -0,0 +1,13 @@
|
||||
lock-version = "1.0"
|
||||
created-by = "pip"
|
||||
|
||||
[[packages]]
|
||||
name = "pyyaml"
|
||||
version = "5.1"
|
||||
|
||||
[packages.sdist]
|
||||
name = "PyYAML-5.1.tar.gz"
|
||||
url = "https://files.pythonhosted.org/packages/9f/2c/9417b5c774792634834e730932745bc09a7d36754ca00acf1ccd1ac2594d/PyYAML-5.1.tar.gz"
|
||||
|
||||
[packages.sdist.hashes]
|
||||
sha256 = "436bc774ecf7c103814098159fbb84c2715d25980175292c648f2da143909f95"
|
||||
Reference in New Issue
Block a user