Skip to content

Commit df9dfcb

Browse files
authored
ni/python-actions: Enable static analysis with zizmor (#77)
* ni/python-actions: Enable static analysis with zizmor * tests: Use env vars to pass inputs to test_setup_python
1 parent 396817b commit df9dfcb

11 files changed

Lines changed: 212 additions & 108 deletions

File tree

.github/workflows/CI.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,14 @@ on:
88
workflow_call:
99
workflow_dispatch:
1010

11+
permissions: {}
12+
1113
jobs:
14+
check_actions:
15+
name: Check actions
16+
uses: ./.github/workflows/check_actions.yml
17+
permissions:
18+
security-events: write
1219
test_actions:
1320
name: Test actions
1421
uses: ./.github/workflows/test_actions.yml

.github/workflows/PR.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,15 @@ on:
88
workflow_call:
99
workflow_dispatch:
1010

11+
permissions: {}
12+
1113
concurrency:
1214
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
1315
cancel-in-progress: true
1416

1517
jobs:
1618
run_ci:
1719
name: Run CI
18-
uses: ./.github/workflows/CI.yml
20+
uses: ./.github/workflows/CI.yml
21+
permissions:
22+
security-events: write
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
name: Check actions
2+
3+
on:
4+
workflow_call:
5+
workflow_dispatch:
6+
7+
permissions: {}
8+
9+
jobs:
10+
zizmor:
11+
name: Run zizmor
12+
runs-on: ubuntu-latest
13+
permissions:
14+
security-events: write
15+
steps:
16+
- name: Check out repo
17+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
18+
with:
19+
persist-credentials: false
20+
- name: Run zizmor
21+
uses: zizmorcore/zizmor-action@b1d7e1fb5de872772f31590499237e7cce841e8e # v0.5.3

.github/workflows/sync_github_issues_to_azdo.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ on:
88
issue_comment:
99
types: [created, edited, deleted]
1010

11+
permissions: {}
12+
1113
jobs:
1214
alert:
1315
if: ${{ !github.event.issue.pull_request && github.event.issue.title != 'Dependency Dashboard' }}

.github/workflows/test_actions.yml

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ on:
44
workflow_call:
55
workflow_dispatch:
66

7+
permissions: {}
8+
79
jobs:
810
test_setup_python:
911
name: Test setup-python
@@ -16,6 +18,8 @@ jobs:
1618
steps:
1719
- name: Check out repo
1820
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
21+
with:
22+
persist-credentials: false
1923
- name: Set up Python
2024
id: setup-python
2125
uses: ./setup-python
@@ -25,8 +29,8 @@ jobs:
2529
run: |
2630
import sys, sysconfig, re, os
2731
28-
matrix_python_version = "${{ matrix.python-version }}"
29-
output_python_version = "${{ steps.setup-python.outputs.python-version }}"
32+
matrix_python_version = os.environ["MATRIX_PYTHON_VERSION"]
33+
output_python_version = os.environ["OUTPUT_PYTHON_VERSION"]
3034
3135
match = re.search(r"(\d+)\.(\d+)(?:\.(\d+))?", matrix_python_version)
3236
expected_version = tuple(int(g) for g in match.groups() if g is not None)
@@ -63,6 +67,9 @@ jobs:
6367
print(f"::error title=Test Failure::env.pythonVersion does not match outputs.python-version. Got {env_python_version}, expected {output_python_version}.")
6468
sys.exit(1)
6569
shell: python
70+
env:
71+
MATRIX_PYTHON_VERSION: ${{ matrix.python-version }}
72+
OUTPUT_PYTHON_VERSION: ${{ steps.setup-python.outputs.python-version }}
6673

6774
test_setup_poetry:
6875
name: Test setup-poetry
@@ -74,6 +81,8 @@ jobs:
7481
steps:
7582
- name: Check out repo
7683
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
84+
with:
85+
persist-credentials: false
7786
- name: Set up Python
7887
uses: ./setup-python
7988
with:
@@ -101,6 +110,8 @@ jobs:
101110
steps:
102111
- name: Check out repo
103112
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
113+
with:
114+
persist-credentials: false
104115
- name: Set up Python
105116
uses: ./setup-python
106117
with:
@@ -133,6 +144,8 @@ jobs:
133144
steps:
134145
- name: Check out repo
135146
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
147+
with:
148+
persist-credentials: false
136149
- name: Set up Python
137150
uses: ./setup-python
138151
with:
@@ -162,6 +175,8 @@ jobs:
162175
steps:
163176
- name: Check out repo
164177
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
178+
with:
179+
persist-credentials: false
165180
- name: Set up Python
166181
uses: ./setup-python
167182
- name: Set up Poetry
@@ -196,6 +211,8 @@ jobs:
196211
steps:
197212
- name: Check out repo
198213
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
214+
with:
215+
persist-credentials: false
199216
- name: Set up Python
200217
uses: ./setup-python
201218
- name: Set up Poetry
@@ -248,6 +265,8 @@ jobs:
248265
steps:
249266
- name: Check out repo
250267
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
268+
with:
269+
persist-credentials: false
251270
- name: Set up Python
252271
uses: ./setup-python
253272
with:
@@ -347,6 +366,8 @@ jobs:
347366
steps:
348367
- name: Check out repo
349368
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
369+
with:
370+
persist-credentials: false
350371
- name: Set up Python
351372
uses: ./setup-python
352373
with:
@@ -405,6 +426,8 @@ jobs:
405426
steps:
406427
- name: Check out repo
407428
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
429+
with:
430+
persist-credentials: false
408431
- name: Set up Python
409432
uses: ./setup-python
410433
with:

analyze-project/README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,9 @@ If there are extra command-line arguments you need to install from your
4242
pyproject.toml, specify them with this input. You can specify any arguments that
4343
work with `poetry install` including `--extras` and `--with`. These
4444
`install-args` will be appended to the basic command line which is `poetry
45-
install -v`. For example,
45+
install -v`. Do not pass untrusted user input.
46+
47+
For example,
4648

4749
```yaml
4850
- uses: ni/python-actions/analyze-project@v0

analyze-project/action.yml

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: Analyze project
22
description: >
3-
This workflow analyzes the code quality of a Python project using various
3+
This action analyzes the code quality of a Python project using various
44
linters and type checkers including ni-python-styleguide,
55
mypy (if the 'mypy' package is installed), and pyright (if the 'pyright'
66
package is installed).
@@ -11,14 +11,22 @@ inputs:
1111
default: ${{ github.workspace }}
1212
install-args:
1313
# E.g. "--extras 'drivers addons' --with examples,docs"
14-
description: 'Extra arguments. Install command will be "poetry install <install-args>".'
14+
description: >
15+
Extra arguments. Install command will be "poetry install -v <install-args>".
16+
Do not pass untrusted user input.
1517
default: ''
1618
required: false
1719
type: string
1820

1921
runs:
2022
using: composite
2123
steps:
24+
- name: Validate event type
25+
if: ${{ github.event_name == 'pull_request_target' || github.event_name == 'workflow_run' }}
26+
run: |
27+
echo "::error title=Analyze Project Error::Unsupported event '$GITHUB_EVENT_NAME'"
28+
exit 1
29+
shell: bash
2230
- name: Get project info
2331
id: get_project_info
2432
run: |
@@ -36,25 +44,30 @@ runs:
3644
shell: bash
3745
working-directory: ${{ inputs.project-directory }}
3846
- name: Check for lock changes
39-
run: poetry check --lock -C "${{ inputs.project-directory }}"
47+
run: poetry check --lock
4048
shell: bash
49+
working-directory: ${{ inputs.project-directory }}
4150
- name: Generate install args hash
4251
id: install_args_hash
4352
run: |
44-
install_args_hash=$(echo "${{ inputs.install-args }}" | sha256sum | cut -d ' ' -f1)
53+
install_args_hash=$(echo "$INSTALL_ARGS" | sha256sum | cut -d ' ' -f1)
4554
echo "hash=$install_args_hash" >> "$GITHUB_OUTPUT"
4655
shell: bash
56+
env:
57+
INSTALL_ARGS: ${{ inputs.install-args }}
4758
- name: Cache virtualenv
4859
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
4960
with:
5061
path: ${{ steps.get_project_info.outputs.venv-path }}
5162
key: ${{ steps.get_project_info.outputs.name }}-${{ runner.os }}-py${{ env.pythonVersion }}-${{ hashFiles(format('{0}/poetry.lock', inputs.project-directory)) }}-${{ steps.install_args_hash.outputs.hash }}
5263
- name: Install ${{ steps.get_project_info.outputs.name }}
5364
run: |
54-
install_cmd="poetry install -v ${{ inputs.install-args }}"
65+
install_cmd="poetry install -v $INSTALL_ARGS"
5566
eval $install_cmd
5667
working-directory: ${{ inputs.project-directory }}
5768
shell: bash
69+
env:
70+
INSTALL_ARGS: ${{ inputs.install-args }}
5871
- name: Lint
5972
run: poetry run ni-python-styleguide lint
6073
working-directory: ${{ inputs.project-directory }}
@@ -79,9 +92,12 @@ runs:
7992
shell: poetry run python {0}
8093
- name: Echo check_tools outputs
8194
run: |
82-
echo "mypy installed: ${{ steps.check_tools.outputs.mypy }}"
83-
echo "pyright installed: ${{ steps.check_tools.outputs.pyright }}"
95+
echo "mypy installed: $MYPY_INSTALLED"
96+
echo "pyright installed: $PYRIGHT_INSTALLED"
8497
shell: bash
98+
env:
99+
MYPY_INSTALLED: ${{ steps.check_tools.outputs.mypy }}
100+
PYRIGHT_INSTALLED: ${{ steps.check_tools.outputs.pyright }}
85101
- name: Mypy static analysis
86102
if: steps.check_tools.outputs.mypy == 'true'
87103
run: poetry run mypy
@@ -90,7 +106,7 @@ runs:
90106
- name: Add virtualenv to the path for pyright-action
91107
if: steps.check_tools.outputs.pyright == 'true'
92108
shell: bash
93-
run: |
109+
run: | # zizmor: ignore[github-env] # intentionally add project venv to the path
94110
echo "$(dirname $(poetry env info --executable))" >> $GITHUB_PATH
95111
working-directory: ${{ inputs.project-directory }}
96112
- name: Pyright static analysis

check-project-version/action.yml

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -13,33 +13,35 @@ inputs:
1313
runs:
1414
using: composite
1515
steps:
16-
- name: Check project version
17-
run: |
18-
project_version="$(poetry version --short)"
19-
expected_version="${{ inputs.expected-version }}"
20-
# Strip the leading 'v', in case this is a GitHub release tag.
21-
expected_version="${expected_version#v}"
16+
- name: Check project version
17+
run: |
18+
project_version="$(poetry version --short)"
19+
expected_version="$EXPECTED_VERSION"
20+
# Strip the leading 'v', in case this is a GitHub release tag.
21+
expected_version="${expected_version#v}"
2222
23-
error_message="$(cat <<EOF
24-
The project version in pyproject.toml does not match the expected version.
25-
26-
If this workflow was triggered by a GitHub release, verify that the
27-
release was tagged with the correct version. If they don't match, you
28-
should either update pyproject.toml or delete and re-create the release
29-
with the correct tag.
23+
error_message="$(cat <<EOF
24+
The project version in pyproject.toml does not match the expected version.
25+
26+
If this workflow was triggered by a GitHub release, verify that the
27+
release was tagged with the correct version. If they don't match, you
28+
should either update pyproject.toml or delete and re-create the release
29+
with the correct tag.
3030
31-
Project version: $project_version
32-
Expected version: $expected_version
33-
EOF
34-
)"
31+
Project version: $project_version
32+
Expected version: $expected_version
33+
EOF
34+
)"
3535
36-
# Convert newline to %0A so that GitHub includes the entire error message
37-
# in the annotation.
38-
error_message="$(echo "$error_message" | sed -z 's/\n/%0A/g;s/%0A$/\n/')"
36+
# Convert newline to %0A so that GitHub includes the entire error message
37+
# in the annotation.
38+
error_message="$(echo "$error_message" | sed -z 's/\n/%0A/g;s/%0A$/\n/')"
3939
40-
if [ x"$project_version" != x"$expected_version" ]; then
41-
echo "::error title=Project Version Error::$error_message"
42-
exit 1
43-
fi
44-
shell: bash
45-
working-directory: ${{ inputs.project-directory }}
40+
if [ x"$project_version" != x"$expected_version" ]; then
41+
echo "::error title=Project Version Error::$error_message"
42+
exit 1
43+
fi
44+
shell: bash
45+
working-directory: ${{ inputs.project-directory }}
46+
env:
47+
EXPECTED_VERSION: ${{ inputs.expected-version }}

setup-poetry/action.yml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ runs:
2525
fi
2626
shell: bash
2727
- name: Set paths
28-
run: |
28+
run: | # zizmor: ignore[github-env] # paths are based on RUNNER_TEMP, not user input
2929
poetry_root="$RUNNER_TEMP/poetry"
3030
poetry_home="$poetry_root/home"
3131
poetry_bin="$poetry_root/bin"
@@ -62,11 +62,17 @@ runs:
6262
- name: Install Poetry
6363
if: steps.cache-poetry.outputs.cache-hit != 'true'
6464
run: |
65+
if [[ ! "$POETRY_VERSION" =~ ^([0-9]+)\.([0-9]+)(\.([0-9]+))?((a|b|rc)[0-9]+)?(\.post[0-9]+)?$ ]]; then
66+
echo "::error title=Setup Poetry Error::Invalid version number: '$POETRY_VERSION'"
67+
exit 1
68+
fi
6569
python -m venv "$POETRY_HOME"
66-
"$POETRY_HOME_BIN/python" -m pip install poetry==${{ inputs.poetry-version }}
70+
"$POETRY_HOME_BIN/python" -m pip install "poetry==$POETRY_VERSION"
6771
mkdir -p "$POETRY_BIN_DIR"
6872
ln -s "$POETRY_HOME_BIN/poetry"* "$POETRY_BIN_DIR/"
6973
shell: bash
74+
env:
75+
POETRY_VERSION: ${{ inputs.poetry-version }}
7076
- name: Print Poetry version
7177
run: poetry --version
7278
shell: bash

setup-python/action.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,8 @@ runs:
1717
with:
1818
python-version: ${{ inputs.python-version }}
1919
- name: Add pythonVersion environment variable
20-
run: echo "pythonVersion=${{ steps.setup-python.outputs.python-version }}" >> "$GITHUB_ENV"
20+
run: | # zizmor: ignore[github-env] # value is queried from the installed Python interpreter, not user input
21+
echo "pythonVersion=$PYTHON_VERSION" >> "$GITHUB_ENV"
2122
shell: bash
23+
env:
24+
PYTHON_VERSION: ${{ steps.setup-python.outputs.python-version }}

0 commit comments

Comments
 (0)