Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions .github/workflows/checks.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 1 addition & 19 deletions .github/workflows/fast-tests-extension.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,4 @@ jobs:

- name: Lint Imports
id: lint-imports
run: poetry run -- nox -s lint:import

# This will be moved to a standard check in the checks.yml in:
# https://github.com/exasol/python-toolbox/issues/811
lint-github-actions:
name: Lint GitHub Actions
runs-on: ubuntu-24.04
steps:
- name: Check out Repository
id: check-out-repository
uses: actions/checkout@v6
with:
persist-credentials: false

- name: Lint GitHub actions with Zizmor
id: lint-github-actions
uses: zizmorcore/zizmor-action@b1d7e1fb5de872772f31590499237e7cce841e8e # v0.5.3
with:
advanced-security: false
run: poetry run -- nox -s lint:import
File renamed without changes.
5 changes: 5 additions & 0 deletions doc/changes/unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,14 @@ so ITDE-related test flows use the configured Exasol baseline and unit-test help

* #744: Updated nox DB-version handling to use `BaseConfig.minimum_exasol_version` instead hardcoded `7.1.9`

## Feature

* #878: Added Nox session `workflow:audit` which uses `zizmor` and added it in `checks.yml`

## Refactoring

* #744: Extracted shared minimum-version selection logic into `minimum_declared_version()`

## Security

* #867: Fixed zizmor linting results
1 change: 1 addition & 0 deletions doc/user_guide/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ features:

features/metrics/sonar
Formatting <features/formatting_code/configuration>
Zizmor <features/managing_dependencies/zizmor_configuration>
features/github_workflows/github_project_configuration
2 changes: 1 addition & 1 deletion doc/user_guide/features/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Features
github_workflows/index
documentation/index
creating_a_release
managing_dependencies
managing_dependencies/index
git_hooks/index
metrics/collecting_metrics

Expand Down
17 changes: 0 additions & 17 deletions doc/user_guide/features/managing_dependencies.rst

This file was deleted.

31 changes: 31 additions & 0 deletions doc/user_guide/features/managing_dependencies/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
.. _managing_dependencies:

Managing Dependencies and Vulnerabilities
=========================================

.. toctree::
:maxdepth: 1

zizmor_configuration

.. list-table::
:widths: 25 20 55
:header-rows: 1

* - Nox session
- CI Usage
- Action
* - ``dependency:licenses``
- ``report.yml``
- Uses ``pip-licenses`` to return packages with their licenses.
* - ``dependency:audit``
- ``dependency-update.yml``
- Uses ``pip-audit`` to report active vulnerabilities in our dependencies.
* - ``vulnerabilities:resolved``
- No
- Uses ``pip-audit`` to report known vulnerabilities in dependencies that
have been resolved in comparison to the last release.
* - ``workflow:audit``
- ``checks.yml``
- Uses ``zizmor`` to audit GitHub actions and workflows for security issues
and accepts extra zizmor arguments. See :ref:`zizmor_configuration`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
.. _zizmor_configuration:

Configuring Zizmor
==================

``workflow:audit`` uses `zizmor <https://docs.zizmor.sh/>`__ to audit GitHub
Actions and workflows. Zizmor reads its project configuration from a file named
``.zizmor.yml`` in the repository root.

As a starting point, copy the template shipped with the PTB:

.. literalinclude:: ../../../../exasol/toolbox/templates/github/zizmor.yml
:language: yaml

For troubleshooting help, see :ref:`handle_zizmor_findings`.
39 changes: 39 additions & 0 deletions doc/user_guide/troubleshooting/handle_zizmor_findings.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
.. _handle_zizmor_findings:

Handling Zizmor Findings
========================

Fixing the Issues
-----------------

`zizmor <https://docs.zizmor.sh/>`__ can automatically fix some findings. The
``--fix`` flag accepts three modes:

* ``--fix=safe`` applies only safe fixes. This is the default.
* ``--fix=unsafe-only`` applies only unsafe fixes, meaning fixes that may be
correct but require human review because they can affect semantics.
* ``--fix=all`` applies both safe and unsafe fixes.

If a finding does not have a known auto-fix, check the relevant audit
documentation in the `zizmor documentation <https://docs.zizmor.sh/>`__.
That usually makes it clearer whether the issue needs a code change, a
configuration change, or an accepted exception.

Ignoring Accepted Issues
------------------------

When you are first enabling ``workflow:audit``, it can be practical to start with
a broader ``.zizmor.yml`` configuration and then tighten it over time.
However, once a finding is understood, prefer ignoring the specific line that
triggers it instead of adding a broader suppressing rule to ``.zizmor.yml``.
That keeps the exception local and visible during review.

A typical line-level ignore looks like this:

.. code-block:: yaml

secrets: inherit # zizmor: ignore[secrets-inherit] - PTB cannot customize inherited secrets here yet.

Use configuration rules in ``.zizmor.yml`` only when the finding is genuinely
project-wide. If you add a temporary rule while working through a batch of
findings, remove it again once the repository is clean.
1 change: 1 addition & 0 deletions doc/user_guide/troubleshooting/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ proposed mitigations, some potentially specific to the related tool.
format_check_reports_unmodified_files
formatting_disable
"F401 unused import" (reported by Ruff) <ignore_ruff_findings>
Handling Zizmor Findings <handle_zizmor_findings>
../features/metrics/ignore_findings
debug_github_workflows

Expand Down
8 changes: 8 additions & 0 deletions exasol/toolbox/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -351,3 +351,11 @@ def github_workflow_patcher_yaml(self) -> Path | None:
if workflow_patcher_yaml.is_file():
return workflow_patcher_yaml
return None

@computed_field # type: ignore[misc]
@property
def zizmor_config_path(self) -> Path:
"""
Path where the zizmor configuration file for the project is stored.
"""
return self.root_path / ".zizmor.yml"
20 changes: 20 additions & 0 deletions exasol/toolbox/nox/_workflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,23 @@ def generate_workflow(session: Session) -> None:
workflow_choice=args.workflow_choice,
config=PROJECT_CONFIG,
).generate_workflows()


@nox.session(name="workflow:audit", python=False)
def audit_workflows(session: Session) -> None:
"""
Audit GitHub actions & workflows with zizmor.
This Nox session passes through additional arguments that zizmor supports.
In some cases, zizmor findings can be automatically fixed with `--fix=safe`.
"""
config_path = PROJECT_CONFIG.zizmor_config_path
if not config_path.is_file():
raise FileNotFoundError(f"{config_path} must exist.")

session.run(
"zizmor",
"--config",
config_path,
*session.posargs,
PROJECT_CONFIG.root_path,
)
23 changes: 23 additions & 0 deletions exasol/toolbox/templates/github/workflows/checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -226,3 +226,26 @@ jobs:
- name: Check Workflows
id: check-workflows
run: poetry run -- nox -s workflow:check -- all

audit-workflows:
name: Audit Workflows
runs-on: "(( os_version ))"
permissions:
contents: read
steps:
- name: Check out Repository
id: check-out-repository
uses: actions/checkout@v6
with:
persist-credentials: false

- name: Set up Python & Poetry Environment
id: set-up-python-and-poetry-environment
uses: exasol/python-toolbox/.github/actions/python-environment@v9
with:
python-version: "(( minimum_python_version ))"
poetry-version: "(( dependency_manager_version ))"

- name: Audit Workflows
id: audit-workflows
run: poetry run -- nox -s workflow:audit
1 change: 1 addition & 0 deletions test/unit/config_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ def test_works_as_defined(tmp_path, test_project_config_factory):
"root_path": root_path,
"sonar_code_path": Path("exasol/test"),
"source_code_path": root_path / "exasol" / "test",
"zizmor_config_path": root_path / ".zizmor.yml",
}

@staticmethod
Expand Down
38 changes: 37 additions & 1 deletion test/unit/nox/_workflow_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

from exasol.toolbox.config import BaseConfig
from exasol.toolbox.nox._workflow import (
audit_workflows,
check_workflow,
generate_workflow,
)
Expand All @@ -32,7 +33,8 @@ def github_workflow_patcher_yaml(self) -> None:

@pytest.fixture
def nox_session_runner_posargs(request):
return [request.param]
value = request.param
return list(value) if isinstance(value, (list, tuple)) else [value]


class TestGenerateWorkflow:
Expand Down Expand Up @@ -144,3 +146,37 @@ def test_raises_session_quit_when_workflows_are_out_of_date(
"- report\n"
"- slow-checks"
)


class TestAuditWorkflows:
@staticmethod
@pytest.mark.parametrize(
"nox_session_runner_posargs",
[["--version"]],
indirect=["nox_session_runner_posargs"],
)
def test_passes_through_extra_arguments(
nox_session,
project_config_without_patcher,
nox_session_runner_posargs,
):
config_path = project_config_without_patcher.root_path / ".zizmor.yml"
config_path.parent.mkdir(parents=True, exist_ok=True)
config_path.write_text("rules: []\n")

with (
patch(
"exasol.toolbox.nox._workflow.PROJECT_CONFIG",
new=project_config_without_patcher,
),
patch("nox.sessions.Session.run") as run_mock,
):
audit_workflows(nox_session)

run_mock.assert_called_once_with(
"zizmor",
"--config",
config_path,
"--version",
project_config_without_patcher.root_path,
)