Skip to content
Open
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
3 changes: 2 additions & 1 deletion .github/workflows/ci.yml

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

5 changes: 3 additions & 2 deletions .github/workflows/merge-gate.yml

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

1 change: 0 additions & 1 deletion .github/workflows/periodic-validation.yml

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

12 changes: 12 additions & 0 deletions doc/api/custom_workflow_secrets.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
.. _custom_workflow_secrets:

CustomWorkflowSecrets
=====================

.. currentmodule:: exasol.toolbox.config

.. autoclass:: CustomWorkflowSecrets
:members:
:undoc-members:
:show-inheritance:
:member-order: bysource
1 change: 1 addition & 0 deletions doc/api/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@
:maxdepth: 2

base_config
custom_workflow_secrets
workflow_exceptions
workflow_patcher_config
1 change: 1 addition & 0 deletions doc/changes/unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ so ITDE-related test flows use the configured Exasol baseline and unit-test help
## Feature

* #878: Added Nox session `workflow:audit` which uses `zizmor` and added it in `checks.yml`
* #872: Added `custom_workflow_secrets` to `BaseConfig` so that tuples of secrets can be defined for custom workflows, like `slow-checks.yml`

## Refactoring

Expand Down
27 changes: 27 additions & 0 deletions doc/user_guide/features/github_workflows/workflow_variables.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,33 @@ standardized baseline that can be overridden in individual projects.
:start-at: github_template_dict
:end-before: @computed_field

Custom Workflow Secrets
^^^^^^^^^^^^^^^^^^^^^^^

If your project needs to pass secrets into project-controlled workflows, configure
the ``custom_workflow_secrets`` field on :class:`exasol.toolbox.config.BaseConfig`.
That field uses :class:`exasol.toolbox.config.CustomWorkflowSecrets` and lets you
define separate secret tuples for specific workflows. See the API reference for
:class:`exasol.toolbox.config.CustomWorkflowSecrets` for the exact structure.

Those custom secrets must be declared at the top of the reusable workflow file, under
``on.workflow_call`` and before ``jobs``. The generated workflows rely on that shape
when they call the reusable workflow with ``secrets:``.

For example, ``slow-checks.yml`` keeps its reusable workflow header at the top of the
file:

.. code-block:: yaml

name: Slow-Checks

on:
workflow_call:
secrets:
EXAMPLE_SECRET:
required: true



.. _workflow_matrix:

Expand Down
2 changes: 1 addition & 1 deletion doc/user_guide/troubleshooting/handle_zizmor_findings.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ A typical line-level ignore looks like this:

.. code-block:: yaml
secrets: inherit # zizmor: ignore[secrets-inherit] - PTB cannot customize inherited secrets here yet.
secrets: inherit # zizmor: ignore[github-env] - This shared action is used by many workflows, and downstream steps need `poetry` on PATH; we do not have a safer replacement 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
Expand Down
40 changes: 40 additions & 0 deletions exasol/toolbox/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,35 @@ def check_minimum_version(cls, v: str, info: ValidationInfo) -> str:
return v


class CustomWorkflowSecrets(BaseModel):
cd_extension: tuple[str, ...] = Field(
default=(),
description="""
This tuple defines the string names of secrets needed to pass to the
cd-extension.yml.
""",
)
merge_gate_extension: tuple[str, ...] = Field(
default=(),
description="""
This tuple defines the string names of secrets needed to pass to the
merge-gate-extension.yml.
""",
)
slow_checks: tuple[str, ...] = Field(
default=(),
description="""
This tuple defines the string names of secrets needed to pass to the
slow_checks.yml.
""",
)

def get_secrets_dict(self) -> dict[str, tuple[str, ...]]:
secrets = self.model_dump(exclude_computed_fields=True)
secrets["merge_gate"] = self.merge_gate_extension + self.slow_checks
return secrets


class BaseConfig(BaseModel):
"""
Basic configuration for projects using the PTB
Expand Down Expand Up @@ -207,6 +236,12 @@ class BaseConfig(BaseModel):
are supported.
""",
)
custom_workflow_secrets: CustomWorkflowSecrets = Field(
default=CustomWorkflowSecrets(),
description="""
This object is used to set the secret arrays for custom workflows.
""",
)

@computed_field # type: ignore[misc]
@property
Expand Down Expand Up @@ -324,11 +359,16 @@ def github_template_dict(self) -> dict[str, Any]:
self.github_workflow_directory / "merge-gate-extension.yml"
)

secrets = self.custom_workflow_secrets.get_secrets_dict()
# merge-gate.yml also calls report.yml and needs Sonar token
secrets["merge_gate"] += (self.sonar_token_name,)

return {
"dependency_manager_version": self.dependency_manager.version,
"minimum_python_version": self.minimum_python_version,
"os_version": self.os_version,
"python_versions": self.python_versions,
"secrets": secrets,
"sonar_token_name": self.sonar_token_name,
"workflow_header": f"{WORKFLOW_HEADER_PREFIX}{__version__}.",
"workflow_extension": {
Expand Down
7 changes: 6 additions & 1 deletion exasol/toolbox/templates/github/workflows/cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,12 @@ jobs:
uses: ./.github/workflows/cd-extension.yml
needs:
- check-release-tag
secrets: inherit # zizmor: ignore[secrets-inherit] - PTB cannot customize inherited secrets here yet; tracked in https://github.com/exasol/python-toolbox/issues/872.
(% if secrets.cd_extension %)
secrets:
(% for secret_name in secrets.cd_extension %)
(( secret_name )): ${{ secrets.(( secret_name )) }}
(% endfor %)
(% endif %)
permissions:
contents: write
(% endif %)
Expand Down
7 changes: 6 additions & 1 deletion exasol/toolbox/templates/github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@ jobs:
merge-gate:
name: Merge Gate
uses: ./.github/workflows/merge-gate.yml
secrets: inherit # zizmor: ignore[secrets-inherit] - PTB cannot customize inherited secrets here yet; tracked in https://github.com/exasol/python-toolbox/issues/872.
(% if secrets.merge_gate %)
secrets:
(% for secret_name in secrets.merge_gate %)
(( secret_name )): ${{ secrets.(( secret_name )) }}
(% endfor %)
(% endif %)
permissions:
contents: read

Expand Down
25 changes: 21 additions & 4 deletions exasol/toolbox/templates/github/workflows/merge-gate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@ name: Merge-Gate

on:
workflow_call:
(% if secrets.merge_gate %)
secrets:
(% for secret_name in secrets.merge_gate %)
(( secret_name )):
required: true
(% endfor %)
(% endif %)

jobs:
run-fast-checks:
Expand Down Expand Up @@ -46,14 +53,24 @@ jobs:
needs:
- approve-run-slow-tests
uses: ./.github/workflows/slow-checks.yml
secrets: inherit # zizmor: ignore[secrets-inherit] - PTB cannot customize inherited secrets here yet; tracked in https://github.com/exasol/python-toolbox/issues/872.
(% if secrets.slow_checks %)
secrets:
(% for secret_name in secrets.slow_checks %)
(( secret_name )): ${{ secrets.(( secret_name )) }}
(% endfor %)
(% endif %)
permissions:
contents: read

(% if workflow_extension.merge_gate %)
merge-gate-extension:
uses: ./.github/workflows/merge-gate-extension.yml
secrets: inherit # zizmor: ignore[secrets-inherit] - PTB cannot customize inherited secrets here yet; tracked in https://github.com/exasol/python-toolbox/issues/872.
(% if secrets.merge_gate_extension %)
secrets:
(% for secret_name in secrets.merge_gate_extension %)
(( secret_name )): ${{ secrets.(( secret_name )) }}
(% endfor %)
(% endif %)
permissions:
contents: read
(% endif %)
Expand All @@ -70,9 +87,9 @@ jobs:
- run-fast-checks
- run-fast-tests
- run-slow-checks
(% if workflow_extension.merge_gate %)
(% if workflow_extension.merge_gate %)
- merge-gate-extension
(% endif %)
(% endif %)
# To prevent accidentally merges, this step is required. For more details
# see: https://github.com/exasol/python-toolbox/issues/563
steps:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,12 @@ jobs:
uses: ./.github/workflows/slow-checks.yml
needs:
- restrict-to-default-branch
secrets: inherit # zizmor: ignore[secrets-inherit] - PTB cannot customize inherited secrets here yet; tracked in https://github.com/exasol/python-toolbox/issues/872.
(% if secrets.slow_checks %)
secrets:
(% for secret_name in secrets.slow_checks %)
(( secret_name )): ${{ secrets.(( secret_name )) }}
(% endfor %)
(% endif %)
permissions:
contents: read

Expand Down
2 changes: 0 additions & 2 deletions exasol/toolbox/templates/github/workflows/slow-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ jobs:
runs-on: "(( os_version ))"
permissions:
contents: read
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.build-matrix.outputs.matrix) }}
Expand Down
66 changes: 66 additions & 0 deletions test/unit/config_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from exasol.toolbox.config import (
DEFAULT_EXCLUDED_PATHS,
BaseConfig,
CustomWorkflowSecrets,
DependencyManager,
minimum_declared_version,
valid_version_string,
Expand Down Expand Up @@ -42,6 +43,11 @@ def test_works_as_defined(tmp_path, test_project_config_factory):
assert config_dump == {
"add_to_excluded_python_paths": (),
"create_major_version_tags": False,
"custom_workflow_secrets": {
"cd_extension": (),
"merge_gate_extension": (),
"slow_checks": (),
},
"dependency_manager": {"name": "poetry", "version": "2.3.0"},
"documentation_path": root_path / "doc",
"exasol_versions": ("8.29.13", "2025.1.8"),
Expand All @@ -60,6 +66,12 @@ def test_works_as_defined(tmp_path, test_project_config_factory):
"3.13",
"3.14",
),
"secrets": {
"cd_extension": (),
"merge_gate": ("SONAR_TOKEN",),
"merge_gate_extension": (),
"slow_checks": (),
},
"workflow_extension": {
"cd": False,
"fast_tests": False,
Expand Down Expand Up @@ -132,6 +144,60 @@ def sonar_token_name(self) -> str:
return "SONAR_ANOTHER_TOKEN"


class TestCustomWorkflowSecrets:
@staticmethod
def test_get_secrets_dict_defaults():
custom_workflow_secrets = CustomWorkflowSecrets()
secrets = custom_workflow_secrets.get_secrets_dict()

assert secrets == {
"cd_extension": (),
"merge_gate": (),
"merge_gate_extension": (),
"slow_checks": (),
}

@staticmethod
def test_get_secrets_dict_with_cd_extension_override():
cd_ext_secret = "CD_SECRET"

custom_workflow_secrets = CustomWorkflowSecrets(
cd_extension=(cd_ext_secret,),
)
secrets = custom_workflow_secrets.get_secrets_dict()

assert secrets == {
"cd_extension": (cd_ext_secret,),
"merge_gate": (),
"merge_gate_extension": (),
"slow_checks": (),
}

@staticmethod
def test_get_secrets_dict_merges_merge_gate_extension_and_slow_checks():
cd_ext_secret = "CD_SECRET"
merge_gate_ext_secret = "MERGE_GATE_SECRET"
slow_checks_secret = "SLOW_CHECKS_SECRET"

custom_workflow_secrets = CustomWorkflowSecrets(
cd_extension=(cd_ext_secret,),
merge_gate_extension=(merge_gate_ext_secret, merge_gate_ext_secret),
slow_checks=(slow_checks_secret,),
)
secrets = custom_workflow_secrets.get_secrets_dict()

assert secrets == {
"cd_extension": (cd_ext_secret,),
"merge_gate": (
merge_gate_ext_secret,
merge_gate_ext_secret,
slow_checks_secret,
),
"merge_gate_extension": (merge_gate_ext_secret, merge_gate_ext_secret),
"slow_checks": (slow_checks_secret,),
}


def test_expansion_validation_fails_for_invalid_version():
with pytest.raises(ValueError):
BaseConfigExpansion(python_versions=("1.f.0",))
Expand Down
Loading