From 6a9dd568e88e35fe521ac9931ab41124fcc0a021 Mon Sep 17 00:00:00 2001 From: Ben van Breukelen Date: Sat, 10 Oct 2026 05:12:34 +0000 Subject: [PATCH 1/6] ci: apply the repository settings with the action itself Run action.yml against this repository on push to main, daily and on demand, using the SETTINGS_ACTION secret. The allowed-actions patterns now include lycheeverse/lychee-action and davidanson/markdownlint-cli2-action, which mcvs-general-action v0.7.x runs as nested actions; without them the general workflow in #61 fails. All other settings match the current repository state. Branch protection is left unmanaged. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/settings.yml | 49 ++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 .github/workflows/settings.yml diff --git a/.github/workflows/settings.yml b/.github/workflows/settings.yml new file mode 100644 index 0000000..732f05a --- /dev/null +++ b/.github/workflows/settings.yml @@ -0,0 +1,49 @@ +--- +name: settings +"on": + push: + branches: + - main + schedule: + - cron: "42 6 * * *" + workflow_dispatch: +permissions: + contents: read +jobs: + settings-action: + runs-on: ubuntu-24.04 + steps: + # yamllint disable rule:line-length + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + with: + python-version-file: pyproject.toml + - name: Install the dependencies of main.py + run: | + pip install . + - uses: ./ + env: + GH_TOKEN: ${{ secrets.SETTINGS_ACTION }} + with: + description: "Settings Action configures the settings of a GitHub repository." + project: ${{ github.repository }} + settings_actions_allowed_actions: selected + settings_actions_github_owned_allowed: true + settings_actions_verified_allowed: false + # mcvs-general-action v0.7.x runs lychee-action and + # markdownlint-cli2-action as nested actions. + settings_actions_patterns_allowed: "030/*,schubergphilis/*,zizmorcore/zizmor-action@*,lycheeverse/lychee-action@*,davidanson/markdownlint-cli2-action@*" + settings_actions_require_sha_pinning: true + settings_default_workflow_permissions: read + settings_delete_branch_on_merge: true + settings_discussions: false + settings_github_workflows_can_approve_pull_request_reviews: false + settings_merge_commit: false + settings_merge_rebase: false + settings_merge_squash: true + settings_projects: false + settings_protect_main_branch: false + settings_wiki: false + topics: github-settings,settings-as-code From 5bc83bfc43b1ee099463bc04456a82a47bf0201d Mon Sep 17 00:00:00 2001 From: Ben van Breukelen Date: Sat, 10 Oct 2026 05:18:21 +0000 Subject: [PATCH 2/6] fix: pin click and drop redundant quotes in the settings workflow The settings workflow installs the project in the step before the action runs with the admin SETTINGS_ACTION token, so click is now pinned to an exact version instead of taking whatever PyPI serves. Dependabot's pip-all group keeps the pin current. yamllint's quoted-strings rule flagged three redundantly quoted values; they parse to the same strings without quotes. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/settings.yml | 6 +++--- pyproject.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/settings.yml b/.github/workflows/settings.yml index 732f05a..4dab780 100644 --- a/.github/workflows/settings.yml +++ b/.github/workflows/settings.yml @@ -5,7 +5,7 @@ name: settings branches: - main schedule: - - cron: "42 6 * * *" + - cron: 42 6 * * * workflow_dispatch: permissions: contents: read @@ -27,14 +27,14 @@ jobs: env: GH_TOKEN: ${{ secrets.SETTINGS_ACTION }} with: - description: "Settings Action configures the settings of a GitHub repository." + description: Settings Action configures the settings of a GitHub repository. project: ${{ github.repository }} settings_actions_allowed_actions: selected settings_actions_github_owned_allowed: true settings_actions_verified_allowed: false # mcvs-general-action v0.7.x runs lychee-action and # markdownlint-cli2-action as nested actions. - settings_actions_patterns_allowed: "030/*,schubergphilis/*,zizmorcore/zizmor-action@*,lycheeverse/lychee-action@*,davidanson/markdownlint-cli2-action@*" + settings_actions_patterns_allowed: 030/*,schubergphilis/*,zizmorcore/zizmor-action@*,lycheeverse/lychee-action@*,davidanson/markdownlint-cli2-action@* settings_actions_require_sha_pinning: true settings_default_workflow_permissions: read settings_delete_branch_on_merge: true diff --git a/pyproject.toml b/pyproject.toml index ea50ce3..c81ad12 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,7 @@ requires-python = ">=3.11" name = "settings-action" readme = "README.md" license = { file = "LICENSE" } -dependencies = ["click"] +dependencies = ["click==8.5.0"] dynamic = ["version"] [project.optional-dependencies] From 8e09c46fadc80eb32a69bde3eee5d52f7d173bbd Mon Sep 17 00:00:00 2001 From: Ben van Breukelen Date: Sat, 10 Oct 2026 10:49:08 +0000 Subject: [PATCH 3/6] fix: install click from a hashed requirements file and move docs - Install main.py's only dependency with `pip install --require-hashes -r requirements.txt` instead of `pip install .`, so no unpinned build backend runs in the job that holds the admin token. - Bump coverage, mypy, types-requests and validate-pyproject. - Rename Usage to Quickstart and move the inputs table and testing notes to docs/. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/settings.yml | 2 +- README.md | 127 +++++++++++++-------------------- docs/inputs.md | 28 ++++++++ docs/testing.md | 7 ++ pyproject.toml | 8 +-- requirements.txt | 6 ++ 6 files changed, 95 insertions(+), 83 deletions(-) create mode 100644 docs/inputs.md create mode 100644 docs/testing.md create mode 100644 requirements.txt diff --git a/.github/workflows/settings.yml b/.github/workflows/settings.yml index 4dab780..2a09623 100644 --- a/.github/workflows/settings.yml +++ b/.github/workflows/settings.yml @@ -22,7 +22,7 @@ jobs: python-version-file: pyproject.toml - name: Install the dependencies of main.py run: | - pip install . + pip install --require-hashes -r requirements.txt - uses: ./ env: GH_TOKEN: ${{ secrets.SETTINGS_ACTION }} diff --git a/README.md b/README.md index 4a9bd31..e1977f9 100644 --- a/README.md +++ b/README.md @@ -7,81 +7,52 @@ Settings Action that will configure the settings of a GitHub repository. -## Usage - -Create a `~/.github/workflows/settings-guard.yml` file: - -```bash ---- -name: settings-guard -'on': - schedule: - - cron: '42 6 * * *' -permissions: {} -jobs: - settings-action: - runs-on: ubuntu-22.04 - steps: - - uses: 030/settings-action@v0.8.0 - env: - GH_TOKEN: ${{ secrets.SETTINGS_GUARD }} - with: - debug: false - description: "Settings Action configures the settings of a GitHub repository." - project: 030/settings-guard - settings_actions_allowed_actions: "selected" - settings_actions_github_owned_allowed: true - settings_actions_verified_allowed: false - settings_actions_patterns_allowed: "030/*" - settings_actions_require_sha_pinning: true - settings_default_workflow_permissions: "read" - settings_delete_branch_on_merge: true - settings_discussions: false - settings_github_workflows_can_approve_pull_request_reviews: true - settings_merge_commit: false - settings_merge_rebase: false - settings_merge_squash: true - settings_protect_main_branch: true - settings_protect_main_branch_enforce_admins: true - settings_protect_main_branch_required_approving_review_count: 1 - settings_projects: false - settings_wiki: false - topics: composite-action,github-project-setup,github-settings,settings-as-code -``` - -use the following variables: - -| Option | Description | -| ------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------- | -| debug | Enable debug logging | -| description | Change the description of a GitHub repository | -| project | The owner/repo | -| settings_actions_allowed_actions | Actions permissions: `all`, `local_only`, or `selected`. Use `selected` to allow OWNER + specific non-OWNER actions/reusable workflows | -| settings_actions_github_owned_allowed | When `settings_actions_allowed_actions` is `selected`, whether GitHub-owned actions (e.g. `actions/checkout`) are allowed | -| settings_actions_verified_allowed | When `settings_actions_allowed_actions` is `selected`, whether actions from verified creators are allowed | -| settings_actions_patterns_allowed | When `settings_actions_allowed_actions` is `selected`, comma-separated list of allowed actions/reusable workflows (e.g. `030/*`) | -| settings_actions_require_sha_pinning | Require actions to be pinned to a full-length commit SHA | -| settings_default_workflow_permissions | Set the default workflow permissions to read or write | -| settings_delete_branch_on_merge | Delete a branch on merge or not | -| settings_discussions | Enable the discussions tab or not | -| settings_github_workflows_can_approve_pull_request_reviews | Whether workflows can approve pull requests | -| settings_merge_commit | Enable merge commit | -| settings_merge_rebase | Enable merge request rebase | -| settings_merge_squash | Enable merge request squash | -| settings_protect_main_branch | Protect the main branch or not | -| settings_protect_main_branch_enforce_admins | Enforce branch protection for admins | -| settings_protect_main_branch_required_approving_review_count | The number of approvals that is required before a PR can be merged | -| settings_projects | Whether the project tab should be enabled | -| settings_wiki | Wiki enabled or not | -| topics | The topic(s) that will appear in the about menu of a project | - -and create a token with read and admin permissions and store it as a -`SETTINGS_GUARD` variable in the variables menu. - -## Testing - -- [Install](https://github.com/cli/cli?tab=readme-ov-file#installation) gh cli. -- Create a read only token. -- Login: `gh auth login` and `choose token` option. -- Check [these graphql samples](https://gist.github.com/duboisf/68fb6e22ac0a2165ca298074f0e3b553) - that can be useful while testing. +## Quickstart + +1. Create a `~/.github/workflows/settings-guard.yml` file: + + ```bash + --- + name: settings-guard + 'on': + schedule: + - cron: '42 6 * * *' + permissions: {} + jobs: + settings-action: + runs-on: ubuntu-22.04 + steps: + - uses: 030/settings-action@v0.8.0 + env: + GH_TOKEN: ${{ secrets.SETTINGS_GUARD }} + with: + debug: false + description: "Settings Action configures the settings of a GitHub repository." + project: 030/settings-guard + settings_actions_allowed_actions: "selected" + settings_actions_github_owned_allowed: true + settings_actions_verified_allowed: false + settings_actions_patterns_allowed: "030/*" + settings_actions_require_sha_pinning: true + settings_default_workflow_permissions: "read" + settings_delete_branch_on_merge: true + settings_discussions: false + settings_github_workflows_can_approve_pull_request_reviews: true + settings_merge_commit: false + settings_merge_rebase: false + settings_merge_squash: true + settings_protect_main_branch: true + settings_protect_main_branch_enforce_admins: true + settings_protect_main_branch_required_approving_review_count: 1 + settings_projects: false + settings_wiki: false + topics: composite-action,github-project-setup,github-settings,settings-as-code + ``` + +1. Create a token with read and admin permissions on the repository. +1. Store it as a `SETTINGS_GUARD` secret in the repository settings. + +## Documentation + +- [Inputs](docs/inputs.md): every option the action accepts. +- [Testing](docs/testing.md): testing the action locally. diff --git a/docs/inputs.md b/docs/inputs.md new file mode 100644 index 0000000..1f3bdc4 --- /dev/null +++ b/docs/inputs.md @@ -0,0 +1,28 @@ +# Inputs + +The inputs of the action, as used in the +[Quickstart](../README.md#quickstart) workflow: + +| Option | Description | +| ------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------- | +| debug | Enable debug logging | +| description | Change the description of a GitHub repository | +| project | The owner/repo | +| settings_actions_allowed_actions | Actions permissions: `all`, `local_only`, or `selected`. Use `selected` to allow OWNER + specific non-OWNER actions/reusable workflows | +| settings_actions_github_owned_allowed | When `settings_actions_allowed_actions` is `selected`, whether GitHub-owned actions (e.g. `actions/checkout`) are allowed | +| settings_actions_verified_allowed | When `settings_actions_allowed_actions` is `selected`, whether actions from verified creators are allowed | +| settings_actions_patterns_allowed | When `settings_actions_allowed_actions` is `selected`, comma-separated list of allowed actions/reusable workflows (e.g. `030/*`) | +| settings_actions_require_sha_pinning | Require actions to be pinned to a full-length commit SHA | +| settings_default_workflow_permissions | Set the default workflow permissions to read or write | +| settings_delete_branch_on_merge | Delete a branch on merge or not | +| settings_discussions | Enable the discussions tab or not | +| settings_github_workflows_can_approve_pull_request_reviews | Whether workflows can approve pull requests | +| settings_merge_commit | Enable merge commit | +| settings_merge_rebase | Enable merge request rebase | +| settings_merge_squash | Enable merge request squash | +| settings_protect_main_branch | Protect the main branch or not | +| settings_protect_main_branch_enforce_admins | Enforce branch protection for admins | +| settings_protect_main_branch_required_approving_review_count | The number of approvals that is required before a PR can be merged | +| settings_projects | Whether the project tab should be enabled | +| settings_wiki | Wiki enabled or not | +| topics | The topic(s) that will appear in the about menu of a project | diff --git a/docs/testing.md b/docs/testing.md new file mode 100644 index 0000000..4e5f426 --- /dev/null +++ b/docs/testing.md @@ -0,0 +1,7 @@ +# Testing + +- [Install](https://github.com/cli/cli?tab=readme-ov-file#installation) gh cli. +- Create a read only token. +- Login: `gh auth login` and `choose token` option. +- Check [these graphql samples](https://gist.github.com/duboisf/68fb6e22ac0a2165ca298074f0e3b553) + that can be useful while testing. diff --git a/pyproject.toml b/pyproject.toml index c81ad12..03c614e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,12 +12,12 @@ dynamic = ["version"] [project.optional-dependencies] dev = [ - "coverage==7.15.2", - "mypy==2.3.0", + "coverage==7.16.2", + "mypy==2.4.0", "mypy-extensions==1.1.0", "pytest-cov==7.1.0", - "types-requests==2.33.0.20260712", - "validate-pyproject==0.25", + "types-requests==2.33.0.20261006", + "validate-pyproject==0.26", "fastjsonschema<2.23", ] diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..f646cbc --- /dev/null +++ b/requirements.txt @@ -0,0 +1,6 @@ +# This file was autogenerated by uv via the following command: +# uv pip compile pyproject.toml --python-version 3.11 --generate-hashes -o requirements.txt +click==8.5.0 \ + --hash=sha256:255bc9599cf7748b4b1a446ccc735421bd08a2ae529a8b88597d3de5664ee360 \ + --hash=sha256:ba0d2089de75ea0310e2dde03160e6ca10009947fb95a182f9b54021bb272e34 + # via settings-action (pyproject.toml) From fec59034f9e1caba41220b903968c13c5738fd59 Mon Sep 17 00:00:00 2001 From: Ben van Breukelen Date: Sat, 10 Oct 2026 11:00:10 +0000 Subject: [PATCH 4/6] docs: tag the Quickstart example as yaml Co-Authored-By: Claude Opus 5.5 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e1977f9..5ece440 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Settings Action that will configure the settings of a GitHub repository. 1. Create a `~/.github/workflows/settings-guard.yml` file: - ```bash + ```yaml --- name: settings-guard 'on': From 9a856d487d07e7d0362c6f7ac77352b7bc469468 Mon Sep 17 00:00:00 2001 From: Ben van Breukelen Date: Sat, 10 Oct 2026 11:10:50 +0000 Subject: [PATCH 5/6] fix: drop the dev pin bumps and pin the Quickstart example by SHA The dev pin bumps are not needed for the CI fix and are not covered by a hashed file, so leave them to Dependabot. Co-Authored-By: Claude Opus 5.5 --- README.md | 2 +- pyproject.toml | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 5ece440..bb250fa 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ Settings Action that will configure the settings of a GitHub repository. settings-action: runs-on: ubuntu-22.04 steps: - - uses: 030/settings-action@v0.8.0 + - uses: 030/settings-action@a27696394dd22683f19303883d8ef275b7287e83 # v0.10.1 env: GH_TOKEN: ${{ secrets.SETTINGS_GUARD }} with: diff --git a/pyproject.toml b/pyproject.toml index 03c614e..c81ad12 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,12 +12,12 @@ dynamic = ["version"] [project.optional-dependencies] dev = [ - "coverage==7.16.2", - "mypy==2.4.0", + "coverage==7.15.2", + "mypy==2.3.0", "mypy-extensions==1.1.0", "pytest-cov==7.1.0", - "types-requests==2.33.0.20261006", - "validate-pyproject==0.26", + "types-requests==2.33.0.20260712", + "validate-pyproject==0.25", "fastjsonschema<2.23", ] From 46a59379859dd1a1184e717624657c2c481e209e Mon Sep 17 00:00:00 2001 From: Ben van Breukelen Date: Sat, 10 Oct 2026 11:32:02 +0000 Subject: [PATCH 6/6] fix: install click inside the action from the hashed requirements file main.py imports click, but the action never installed it, so a caller that copies the bare Quickstart step can hit ModuleNotFoundError. The action now creates a private venv in RUNNER_TEMP and installs requirements.txt with --require-hashes, so callers need no extra steps and their Python is left alone. The settings workflow no longer needs its own setup-python and install steps. requirements.txt is recompiled with --universal. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/settings.yml | 6 ------ action.yml | 15 +++++++++++++-- requirements.txt | 2 +- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/.github/workflows/settings.yml b/.github/workflows/settings.yml index 2a09623..fc6ad10 100644 --- a/.github/workflows/settings.yml +++ b/.github/workflows/settings.yml @@ -17,12 +17,6 @@ jobs: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false - - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 - with: - python-version-file: pyproject.toml - - name: Install the dependencies of main.py - run: | - pip install --require-hashes -r requirements.txt - uses: ./ env: GH_TOKEN: ${{ secrets.SETTINGS_ACTION }} diff --git a/action.yml b/action.yml index 3f9cb64..417cea0 100644 --- a/action.yml +++ b/action.yml @@ -119,6 +119,17 @@ runs: run: gh --version shell: bash + - name: install the dependencies of main.py + shell: bash + env: + ACTION_PATH: ${{ github.action_path }} + run: | + # A private venv, so the caller does not have to install click and + # the Python on the caller's PATH is left alone. + python3 -m venv "$RUNNER_TEMP/settings-action-venv" + "$RUNNER_TEMP/settings-action-venv/bin/pip" install --disable-pip-version-check \ + --require-hashes \ + -r "$ACTION_PATH/requirements.txt" - name: add a description for project ${{ inputs.project }} shell: bash env: @@ -184,7 +195,7 @@ runs: debug="--verbose" fi - python3 "$ACTION_PATH/main.py" actions-permissions \ + "$RUNNER_TEMP/settings-action-venv/bin/python" "$ACTION_PATH/main.py" actions-permissions \ --allowed-actions "$ALLOWED_ACTIONS" \ --github-owned-allowed "$GITHUB_OWNED_ALLOWED" \ --verified-allowed "$VERIFIED_ALLOWED" \ @@ -297,7 +308,7 @@ runs: fi update_branch_protection_rule() { - python3 "$ACTION_PATH/main.py" branch-protection-rules \ + "$RUNNER_TEMP/settings-action-venv/bin/python" "$ACTION_PATH/main.py" branch-protection-rules \ --enforce-admins "$ENFORCE_ADMINS" \ --required-approving-review-count "$REQUIRED_APPROVING_REVIEW_COUNT" diff --git a/requirements.txt b/requirements.txt index f646cbc..de511bf 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ # This file was autogenerated by uv via the following command: -# uv pip compile pyproject.toml --python-version 3.11 --generate-hashes -o requirements.txt +# uv pip compile pyproject.toml --universal --python-version 3.11 --generate-hashes -o requirements.txt click==8.5.0 \ --hash=sha256:255bc9599cf7748b4b1a446ccc735421bd08a2ae529a8b88597d3de5664ee360 \ --hash=sha256:ba0d2089de75ea0310e2dde03160e6ca10009947fb95a182f9b54021bb272e34