Compare commits
80 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 | ||
|
|
cce88443a7 | ||
|
|
04c269efdc | ||
|
|
f22fd11c6a | ||
|
|
e5e5bb4943 | ||
|
|
e75f4e6b21 | ||
|
|
6b7dc40731 | ||
|
|
39d1d0727f | ||
|
|
ad890dc94a | ||
|
|
252231c091 | ||
|
|
d88c6e2ef7 | ||
|
|
6bfc6a0ebf | ||
|
|
a354d479d8 | ||
|
|
82a7566979 | ||
|
|
4aa57b6d51 | ||
|
|
a84a2d863a | ||
|
|
71fea02bf0 |
+64
@@ -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
|
||||
Vendored
+11
@@ -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
@@ -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:
|
||||
Vendored
+12
@@ -0,0 +1,12 @@
|
||||
---
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
groups:
|
||||
actions:
|
||||
patterns:
|
||||
- "*"
|
||||
...
|
||||
Vendored
+7
-3
@@ -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.10"
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
|
||||
with:
|
||||
python-version: "3.x"
|
||||
- name: lint
|
||||
run: make lint
|
||||
|
||||
Vendored
+150
-3
@@ -7,16 +7,163 @@ on:
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
selftest:
|
||||
runs-on: ubuntu-latest
|
||||
selftest-requirements:
|
||||
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:
|
||||
inputs: ./test/vulnerable.txt
|
||||
no-deps: 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
|
||||
shell: bash
|
||||
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}")
|
||||
|
||||
selftest-environment:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- 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
|
||||
- uses: ./
|
||||
id: pip-audit
|
||||
with:
|
||||
# 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}")
|
||||
|
||||
selftest-virtualenv:
|
||||
strategy:
|
||||
matrix:
|
||||
local: [true, false]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: make a virtual environment vulnerable
|
||||
run: |
|
||||
python -m venv env
|
||||
./env/bin/python -m pip install --upgrade pip wheel
|
||||
./env/bin/python -m pip install --no-deps --requirement ./test/vulnerable.txt
|
||||
- uses: ./
|
||||
id: pip-audit
|
||||
with:
|
||||
virtual-environment: env/
|
||||
local: ${{ matrix.local }}
|
||||
# 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}")
|
||||
|
||||
selftest-pyproject:
|
||||
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/pyproject/pyproject.toml
|
||||
inputs: test/pyproject/
|
||||
# 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}")
|
||||
|
||||
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) }}
|
||||
|
||||
Vendored
+28
@@ -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
|
||||
Vendored
+38
@@ -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
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
FROM python:3.10-alpine
|
||||
|
||||
LABEL org.opencontainers.image.authors="William Woodruff <william@trailofbits.com>"
|
||||
|
||||
ADD requirements.txt /requirements.txt
|
||||
ADD action.py /action.py
|
||||
|
||||
RUN apk add python3 && \
|
||||
pip install -r requirements.txt
|
||||
|
||||
ENTRYPOINT ["/action.py"]
|
||||
@@ -0,0 +1,177 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
@@ -12,6 +12,6 @@ dev: env/pyvenv.cfg
|
||||
|
||||
.PHONY: lint
|
||||
lint: env/pyvenv.cfg action.py
|
||||
./env/bin/python -m black action.py
|
||||
./env/bin/python -m isort action.py
|
||||
./env/bin/python -m flake8 --max-line-length 100 action.py
|
||||
./env/bin/python -m black action.py
|
||||
|
||||
@@ -1,28 +1,59 @@
|
||||
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: pip install .
|
||||
- uses: trailofbits/gh-action-pip-audit@v0.0.1
|
||||
run: python -m pip install .
|
||||
- uses: pypa/gh-action-pip-audit@v1.1.0
|
||||
```
|
||||
|
||||
By default, `pip-audit` will run in "pip source" mode, meaning that it'll
|
||||
Or, with a virtual environment:
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
selftest:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: install
|
||||
run: |
|
||||
python -m venv env/
|
||||
source env/bin/activate
|
||||
python -m pip install .
|
||||
- uses: pypa/gh-action-pip-audit@v1.1.0
|
||||
with:
|
||||
virtual-environment: env/
|
||||
```
|
||||
|
||||
By default, `pip-audit` will run in "`pip list` source" mode, meaning that it'll
|
||||
attempt to collect dependencies from the local environment. See
|
||||
the [configuration](#configuration) documentation below for more input
|
||||
and behavioral options.
|
||||
@@ -34,14 +65,14 @@ optional.
|
||||
|
||||
### `inputs`
|
||||
|
||||
**Default**: Empty, indicating "pip source" mode
|
||||
**Default**: Empty, indicating "`pip list` source" mode
|
||||
|
||||
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@v0.0.1
|
||||
- uses: pypa/gh-action-pip-audit@v1.1.0
|
||||
with:
|
||||
inputs: requirements.txt dev-requirements.txt
|
||||
```
|
||||
@@ -49,12 +80,59 @@ 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@v0.0.1
|
||||
- uses: pypa/gh-action-pip-audit@v1.1.0
|
||||
with:
|
||||
# NOTE: this can be `.`, for the current directory
|
||||
inputs: path/to/project/
|
||||
```
|
||||
|
||||
### `virtual-environment`
|
||||
|
||||
**Default**: Empty, indicating no virtual environment
|
||||
|
||||
The `virtual-environment` setting controls the
|
||||
[virtual environment](https://docs.python.org/3/tutorial/venv.html) that this
|
||||
action loads to, if specified. The value is the top-level directory for the
|
||||
virtual environment, which is conventionally named `env` or `venv`.
|
||||
|
||||
Depending on your CI and project configuration, you may or may not need this
|
||||
setting. Specifically, you only need it if you satisfy *all* of the following
|
||||
conditions:
|
||||
|
||||
1. You are auditing an *environment* (**not** a requirements file or other
|
||||
project metadata)
|
||||
2. Your environment is not already "active", i.e. `python -m pip` points to a
|
||||
different `pip` than the one that your environment uses
|
||||
|
||||
Example: use the virtual environment specified at `env/`, relative to the
|
||||
current directory:
|
||||
|
||||
```yaml
|
||||
- uses: pypa/gh-action-pip-audit@v1.1.0
|
||||
with:
|
||||
virtual-environment: env/
|
||||
# Note the absence of `input:`, since we're auditing the environment.
|
||||
```
|
||||
|
||||
### `local`
|
||||
|
||||
**Default**: `false`
|
||||
|
||||
The `local` setting corresponds to `pip-audit`'s `--local` flag, which controls
|
||||
whether non-local dependencies are included when auditing in "`pip list` source"
|
||||
mode.
|
||||
|
||||
By default all dependencies are included; with `local: true`, only dependencies
|
||||
installed directly into the current environment are included.
|
||||
|
||||
Example:
|
||||
|
||||
```yaml
|
||||
- uses: pypa/gh-action-pip-audit@v1.1.0
|
||||
with:
|
||||
local: true
|
||||
```
|
||||
|
||||
### `vulnerability-service`
|
||||
|
||||
**Default**: `PyPI`
|
||||
@@ -67,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@v0.0.1
|
||||
- uses: pypa/gh-action-pip-audit@v1.1.0
|
||||
with:
|
||||
vulnerability-service: osv
|
||||
```
|
||||
@@ -82,7 +160,7 @@ It's directly equivalent to `pip-audit --require-hashes ...`.
|
||||
Example:
|
||||
|
||||
```yaml
|
||||
- uses: trailofbits/gh-action-pip-audit@v0.0.1
|
||||
- uses: pypa/gh-action-pip-audit@v1.1.0
|
||||
with:
|
||||
# NOTE: only works with requirements-style inputs
|
||||
inputs: requirements.txt
|
||||
@@ -99,7 +177,7 @@ It's directly equivalent to `pip-audit --no-deps ...`.
|
||||
Example:
|
||||
|
||||
```yaml
|
||||
- uses: trailofbits/gh-action-pip-audit@v0.0.1
|
||||
- uses: pypa/gh-action-pip-audit@v1.1.0
|
||||
with:
|
||||
# NOTE: only works with requirements-style inputs
|
||||
inputs: requirements.txt
|
||||
@@ -117,18 +195,103 @@ is rendered at the end of the action.
|
||||
Example:
|
||||
|
||||
```yaml
|
||||
- uses: trailofbits/gh-action-pip-audit@v0.0.1
|
||||
- uses: pypa/gh-action-pip-audit@v1.1.0
|
||||
with:
|
||||
summary: false
|
||||
```
|
||||
|
||||
### `index-url`
|
||||
|
||||
**Default**: Empty, indicating [PyPI](https://pypi.org)
|
||||
|
||||
The `index-url` setting specifies a base URL for an alternative PEP 503-compatible
|
||||
package index.
|
||||
|
||||
**This is probably not want you want.** If your goal is to add *complementary*
|
||||
indices to search (such as a corporate index with private packages), see
|
||||
[`extra-index-urls`](#extra-index-urls).
|
||||
|
||||
Example:
|
||||
|
||||
```yaml
|
||||
- uses: pypa/gh-action-pip-audit@v1.1.0
|
||||
with:
|
||||
index-url: https://example.corporate.local/simple
|
||||
```
|
||||
|
||||
### `extra-index-urls`
|
||||
|
||||
**Default**: Empty (no extra indexes are searched by default)
|
||||
|
||||
The `extra-index-urls` setting specifies one or more *extra* PEP 503-compatible packages
|
||||
indexes to search when resolving dependencies. Each URL is whitespace-separated.
|
||||
|
||||
Example:
|
||||
|
||||
```yaml
|
||||
- uses: pypa/gh-action-pip-audit@v1.1.0
|
||||
with:
|
||||
extra-index-urls: |
|
||||
https://example.corporate.local/simple
|
||||
https://prod.corporate.local/simple
|
||||
```
|
||||
|
||||
### `ignore-vulns`
|
||||
|
||||
**Default**: Empty (no vulnerabilities are ignored)
|
||||
|
||||
The `ignore-vulns` setting specifies one or more vulnerability IDs to
|
||||
ignore (i.e., exclude from the results) if present. Each ID is whitespace-separated.
|
||||
|
||||
Example
|
||||
|
||||
```yaml
|
||||
- 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>
|
||||
|
||||
Everything below is considered "internal," which means that it
|
||||
isn't part of the stable public settings and may be removed or changed at
|
||||
any points. **You probably do not need these settings.**
|
||||
any point. **You probably do not need these settings.**
|
||||
|
||||
All internal options are prefixed with `internal-be-careful-`.
|
||||
|
||||
@@ -145,8 +308,123 @@ Example:
|
||||
Example:
|
||||
|
||||
```yaml
|
||||
- uses: trailofbits/gh-action-pip-audit@v0.0.1
|
||||
- uses: pypa/gh-action-pip-audit@v1.1.0
|
||||
with:
|
||||
internal-be-careful-allow-failure: true
|
||||
```
|
||||
|
||||
#### `internal-be-careful-extra-flags`
|
||||
**Default**: `""`
|
||||
|
||||
The `internal-be-careful-extra-flags` setting passes the specified flags
|
||||
to `pip-audit`.
|
||||
|
||||
Example:
|
||||
|
||||
```yaml
|
||||
- uses: pypa/gh-action-pip-audit@v1.1.0
|
||||
with:
|
||||
internal-be-careful-extra-flags: --not-a-real-pip-audit-flag
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
This section is still a work in progress. Please help us improve it!
|
||||
|
||||
### The action takes longer than I expect!
|
||||
|
||||
If you're auditing a requirements file, consider setting `no-deps: true` or
|
||||
`require-hashes: true`:
|
||||
|
||||
```yaml
|
||||
- uses: pypa/gh-action-pip-audit@v1.1.0
|
||||
with:
|
||||
inputs: requirements.txt
|
||||
require-hashes: true
|
||||
```
|
||||
|
||||
or:
|
||||
|
||||
```yaml
|
||||
- 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/pypa/pip-audit#pip-audit-takes-longer-than-i-expect)
|
||||
troubleshooting for more details.
|
||||
|
||||
### The action shows dependencies that aren't in my environment!
|
||||
|
||||
In the default ("`pip list` source") configuration, `pip-audit` collects all
|
||||
dependencies that are visible in the current environment.
|
||||
|
||||
Depending on the project or CI's configuration, this can include packages installed
|
||||
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: pypa/gh-action-pip-audit@v1.1.0
|
||||
with:
|
||||
# must be populated earlier in the CI
|
||||
virtual-environment: env/
|
||||
```
|
||||
|
||||
and, more aggressively, specify that only dependencies marked as "local"
|
||||
in the virtual environment should be included:
|
||||
|
||||
```yaml
|
||||
- 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.
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
Everyone interacting with this project is expected to follow the
|
||||
[PSF Code of Conduct](https://github.com/pypa/.github/blob/main/CODE_OF_CONDUCT.md).
|
||||
|
||||
@@ -6,26 +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"
|
||||
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"::debug::{msg}")
|
||||
|
||||
|
||||
def _log(msg):
|
||||
for output in _OUTPUTS:
|
||||
print(msg, file=output)
|
||||
print(msg, file=sys.stderr)
|
||||
|
||||
|
||||
def _pip_audit(*args):
|
||||
@@ -33,18 +49,18 @@ def _pip_audit(*args):
|
||||
|
||||
|
||||
def _fatal_help(msg):
|
||||
print(f"❌ {msg}", file=sys.stderr)
|
||||
subprocess.run(_pip_audit("--help"))
|
||||
print(f"::error::❌ {msg}")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
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 = [
|
||||
# The spinner is useless in the CI.
|
||||
"--progress-spinner=off",
|
||||
# We intend to emit a Markdown-formatted table.
|
||||
"--format=markdown",
|
||||
# `pip cache dir` doesn't work in this container for some reason, and I
|
||||
# haven't debugged it yet.
|
||||
"--cache-dir=/tmp/pip-audit-cache",
|
||||
@@ -52,7 +68,10 @@ 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")
|
||||
|
||||
if os.getenv("GHA_PIP_AUDIT_NO_DEPS", "false") != "false":
|
||||
pip_audit_args.append("--no-deps")
|
||||
@@ -60,12 +79,38 @@ if os.getenv("GHA_PIP_AUDIT_NO_DEPS", "false") != "false":
|
||||
if os.getenv("GHA_PIP_AUDIT_REQUIRE_HASHES", "false") != "false":
|
||||
pip_audit_args.append("--require-hashes")
|
||||
|
||||
if (
|
||||
service := os.getenv("GHA_PIP_AUDIT_VULNERABILITY_SERVICE", "pypi").lower()
|
||||
) != "pypi":
|
||||
pip_audit_args.extend(["--vulnerability-service", service])
|
||||
if os.getenv("GHA_PIP_AUDIT_LOCAL", "false") != "false":
|
||||
pip_audit_args.append("--local")
|
||||
|
||||
# If inputs is empty, we let `pip-audit` run in "pip source" mode by not
|
||||
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])
|
||||
|
||||
|
||||
extra_index_urls = os.getenv("GHA_PIP_AUDIT_EXTRA_INDEX_URLS", "").split()
|
||||
for url in extra_index_urls:
|
||||
pip_audit_args.extend(["--extra-index-url", url])
|
||||
|
||||
|
||||
ignored_vuln_ids = os.getenv("GHA_PIP_AUDIT_IGNORE_VULNS", "").split()
|
||||
for vuln_id in ignored_vuln_ids:
|
||||
pip_audit_args.extend(["--ignore-vuln", vuln_id])
|
||||
|
||||
pip_audit_args.extend(
|
||||
[
|
||||
"--vulnerability-service",
|
||||
os.getenv("GHA_PIP_AUDIT_VULNERABILITY_SERVICE", "pypi").lower(),
|
||||
]
|
||||
)
|
||||
|
||||
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)
|
||||
# or one or more requirements-style inputs (all files).
|
||||
@@ -82,45 +127,44 @@ 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]}")
|
||||
|
||||
status = subprocess.run(
|
||||
_pip_audit(*pip_audit_args),
|
||||
text=True,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
env=os.environ | {"PIP_NO_CACHE_DIR": "1"},
|
||||
env={**os.environ, "PIP_NO_CACHE_DIR": "1"},
|
||||
)
|
||||
|
||||
_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:
|
||||
# NOTE: `pip-audit`'s table format isn't quite Markdown-style.
|
||||
# See: https://github.com/trailofbits/pip-audit/issues/296
|
||||
_summary("```")
|
||||
_log(io.read())
|
||||
_summary("```")
|
||||
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.
|
||||
print(f"output={b64encode(output.encode()).decode()}", file=_GITHUB_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.
|
||||
|
||||
+70
-11
@@ -19,21 +19,80 @@ inputs:
|
||||
required: false
|
||||
default: "PyPI"
|
||||
inputs:
|
||||
description: "the inputs to audit, space separated (defaults to current path)"
|
||||
description: "the inputs to audit, whitespace separated (defaults to current path)"
|
||||
required: false
|
||||
default: ""
|
||||
virtual-environment:
|
||||
description: "the virtual environment to audit within (default none)"
|
||||
required: false
|
||||
default: ""
|
||||
local:
|
||||
description: "for environmental audits, consider only packages marked local (default false)"
|
||||
required: false
|
||||
default: false
|
||||
index-url:
|
||||
description: "the base URL for the PEP 503-compatible package index to use"
|
||||
required: false
|
||||
default: ""
|
||||
extra-index-urls:
|
||||
description: "extra PEP 503-compatible indexes to use, whitespace separated"
|
||||
required: false
|
||||
default: ""
|
||||
ignore-vulns:
|
||||
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-extra-flags:
|
||||
description: "extra flags to be passed in to pip-audit"
|
||||
required: false
|
||||
default: ""
|
||||
outputs:
|
||||
internal-be-careful-output:
|
||||
description: "the column-formatted output from pip-audit, wrapped as base64"
|
||||
value: "${{ steps.pip-audit.outputs.output }}"
|
||||
runs:
|
||||
using: 'docker'
|
||||
image: 'Dockerfile'
|
||||
env:
|
||||
GHA_PIP_AUDIT_SUMMARY: "${{ inputs.summary }}"
|
||||
GHA_PIP_AUDIT_NO_DEPS: "${{ inputs.no-deps }}"
|
||||
GHA_PIP_AUDIT_REQUIRE_HASHES: "${{ inputs.require-hashes }}"
|
||||
GHA_PIP_AUDIT_VULNERABILITY_SERVICE: "${{ inputs.vulnerability-service }}"
|
||||
GHA_PIP_AUDIT_INTERNAL_BE_CAREFUL_ALLOW_FAILURE: "${{ inputs.internal-be-careful-allow-failure }}"
|
||||
args:
|
||||
- "${{ inputs.inputs }}"
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Set up pip-audit
|
||||
run: |
|
||||
# NOTE: Sourced, not executed as a script.
|
||||
source "${{ github.action_path }}/setup/setup.bash"
|
||||
env:
|
||||
GHA_PIP_AUDIT_VIRTUAL_ENVIRONMENT: "${{ inputs.virtual-environment }}"
|
||||
shell: bash
|
||||
|
||||
- name: Run pip-audit
|
||||
id: pip-audit
|
||||
run: |
|
||||
# NOTE: Sourced, not executed as a script.
|
||||
source "${{ github.action_path }}/setup/venv.bash"
|
||||
|
||||
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 }}"
|
||||
GHA_PIP_AUDIT_VULNERABILITY_SERVICE: "${{ inputs.vulnerability-service }}"
|
||||
GHA_PIP_AUDIT_VIRTUAL_ENVIRONMENT: "${{ inputs.virtual-environment }}"
|
||||
GHA_PIP_AUDIT_LOCAL: "${{ inputs.local }}"
|
||||
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_EXTRA_FLAGS: "${{ inputs.internal-be-careful-extra-flags }}"
|
||||
shell: bash
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
pip-audit==2.3.2
|
||||
pip-audit ~= 2.0, >= 2.5.6
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eo pipefail
|
||||
|
||||
die() {
|
||||
echo "::error::${1}"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# NOTE: This file is meant to be sourced, not executed as a script.
|
||||
if [[ "${0}" == "${BASH_SOURCE[0]}" ]]; then
|
||||
die "Internal error: setup harness was executed instead of being sourced?"
|
||||
fi
|
||||
|
||||
# Load the virtual environment, if there is one.
|
||||
source "${GITHUB_ACTION_PATH}/setup/venv.bash"
|
||||
|
||||
# Check the Python version, making sure it's new enough (3.7+)
|
||||
# The installation step immediately below will technically catch this,
|
||||
# but doing it explicitly gives us the opportunity to produce a better
|
||||
# error message.
|
||||
vers=$(python -V | cut -d ' ' -f2)
|
||||
maj_vers=$(cut -d '.' -f1 <<< "${vers}")
|
||||
min_vers=$(cut -d '.' -f2 <<< "${vers}")
|
||||
|
||||
[[ "${maj_vers}" == "3" && "${min_vers}" -ge 7 ]] || die "Bad Python version: ${vers}"
|
||||
|
||||
python -m pip install --requirement "${GITHUB_ACTION_PATH}/requirements.txt"
|
||||
@@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eo pipefail
|
||||
|
||||
die() {
|
||||
echo "::error::${1}"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# NOTE: This file is meant to be sourced, not executed as a script.
|
||||
if [[ "${0}" == "${BASH_SOURCE[0]}" ]]; then
|
||||
die "Internal error: setup harness was executed instead of being sourced?"
|
||||
fi
|
||||
|
||||
# If the user has explicitly specified a virtual environment, then we install
|
||||
# `pip-audit` into it rather than into whatever environment the default
|
||||
# `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
|
||||
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
|
||||
fi
|
||||
@@ -0,0 +1,11 @@
|
||||
<details>
|
||||
|
||||
<summary>
|
||||
Raw <code>pip-audit</code> output
|
||||
</summary>
|
||||
|
||||
```
|
||||
$output
|
||||
```
|
||||
|
||||
</details>
|
||||
@@ -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"
|
||||
@@ -0,0 +1,6 @@
|
||||
# this is not a real pyproject.toml; only enough to run the selftests in CI.
|
||||
|
||||
[project]
|
||||
dependencies = [
|
||||
"pyyaml==5.1"
|
||||
]
|
||||
Reference in New Issue
Block a user