From 805e48135041b9b8c0030260b72f44c2be970e2a Mon Sep 17 00:00:00 2001 From: BREW <81044362+b-re-w@users.noreply.github.com> Date: Sat, 3 Oct 2026 20:09:47 +0900 Subject: [PATCH] Chore: Protect main by repository settings alone, and drop the source guard The maintainer's decision (2026-10-03, option B): main is protected by its branch settings only -- a pull request is required with no approving review, direct push, force-push and deletion are blocked, the branch is not locked, and only administrators may merge. The maintainer merges the release PR after checking its source branch, so no workflow has to. - main-source-guard.yml is deleted. - release-sync.yml no longer posts the guard's commit status: the step and its statuses: write permission are gone. - protect-main.sh applies the B settings, as python-multiplatform's PR #122 does (no required check, restrictions with empty lists so only admins merge, lock_branch false). Applying it stays the maintainer's step. - The release README and PROJECT.md describe the new arrangement. deleted: .github/workflows/main-source-guard.yml. documentation corrected: .github/scripts/release/README.md, PROJECT.md. Release test: 49 passed, 0 failed. The pytest suite does not touch these. Refs #64 --- .github/scripts/release/README.md | 16 +++++++--------- .github/scripts/release/protect-main.sh | 13 +++++++------ .github/workflows/main-source-guard.yml | 24 ------------------------ .github/workflows/release-sync.yml | 15 --------------- PROJECT.md | 6 +++--- 5 files changed, 17 insertions(+), 57 deletions(-) delete mode 100644 .github/workflows/main-source-guard.yml diff --git a/.github/scripts/release/README.md b/.github/scripts/release/README.md index 17ca366..9288dc3 100644 --- a/.github/scripts/release/README.md +++ b/.github/scripts/release/README.md @@ -14,13 +14,10 @@ ignored and overwritten. The push uses `--force-with-lease` pinned to the remote sha the run observed. 2. The workflow opens (or updates) a pull request `release` -> `main` with the default `GITHUB_TOKEN`. This needs the repository setting *Actions -> General -> Allow GitHub - Actions to create and approve pull requests*. A PR opened with `GITHUB_TOKEN` - triggers no workflows, so `main-source-guard` would never run on it; the workflow - therefore sets the `only-release-into-main` commit status on the release commit - itself, which satisfies the required check. No PAT is needed; an optional + Actions to create and approve pull requests*. No PAT is needed; an optional `RELEASE_PR_TOKEN` secret is used for the PR step when present. -3. Merging that PR is the only way to change `main`. `main-source-guard.yml` fails - any PR into `main` whose head is not `release`. +3. Merging that PR is the only way to change `main`. The maintainer merges it after checking + that its source branch is `release`; repository settings alone protect `main` (below). 4. On push to `main`, `pages.yml` deploys `docs/guide/` to GitHub Pages. ## What is dropped on release @@ -46,6 +43,7 @@ It refuses to run while `release` is checked out. .github/scripts/release/protect-main.sh # print what would be applied .github/scripts/release/protect-main.sh --apply # apply via gh api (needs admin) -This requires a pull request, blocks force-push and deletion. Classic protection cannot -restrict a PR's source branch, so add the check `only-release-into-main` as required -(the script does; the workflow must have run once first). +The settings (the maintainer's decision, 2026-10-03): a pull request is required with no +approving review, direct push, force-push and deletion are blocked, the branch is not locked, and +only administrators may merge. No workflow checks the source branch; the maintainer does, when +merging the release PR. diff --git a/.github/scripts/release/protect-main.sh b/.github/scripts/release/protect-main.sh index 5d3588f..4bc6514 100755 --- a/.github/scripts/release/protect-main.sh +++ b/.github/scripts/release/protect-main.sh @@ -14,12 +14,13 @@ done [ -n "$REPO" ] || REPO="{owner}/{repo}" # gh expands these placeholders from the current repo BODY='{ - "required_status_checks": {"strict": true, "contexts": ["only-release-into-main"]}, - "enforce_admins": true, + "required_status_checks": null, + "enforce_admins": false, "required_pull_request_reviews": {"required_approving_review_count": 0}, - "restrictions": null, + "restrictions": {"users": [], "teams": [], "apps": []}, "allow_force_pushes": false, - "allow_deletions": false + "allow_deletions": false, + "lock_branch": false }' CMD="gh api --method PUT repos/$REPO/branches/$BRANCH/protection --input -" @@ -29,6 +30,6 @@ if [ "$APPLY" -eq 1 ]; then else echo "[dry run] would run: $CMD" echo "$BODY" - echo "Re-run with --apply to apply. The check 'only-release-into-main' comes from .github/workflows/main-source-guard.yml;" - echo "it must have run once before GitHub accepts it as a required check." + echo "Re-run with --apply to apply (needs admin). 'restrictions' with empty lists means only" + echo "administrators may merge; it is accepted for organisation repositories only." fi diff --git a/.github/workflows/main-source-guard.yml b/.github/workflows/main-source-guard.yml deleted file mode 100644 index 4eb5d20..0000000 --- a/.github/workflows/main-source-guard.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: Main source guard - -# Make the job "only-release-into-main" a required status check on main. -on: - pull_request: - branches: [main] - types: [opened, reopened, synchronize, edited] - -permissions: - contents: read - -jobs: - only-release-into-main: - runs-on: ubuntu-latest - steps: - - name: Require head branch "release" - env: - HEAD_REF: ${{ github.head_ref }} - HEAD_REPO: ${{ github.event.pull_request.head.repo.full_name }} - run: | - if [ "$HEAD_REF" != "release" ] || [ "$HEAD_REPO" != "${{ github.repository }}" ]; then - echo "::error::PRs into main must come from the release branch of this repository (got '$HEAD_REPO:$HEAD_REF')." - exit 1 - fi diff --git a/.github/workflows/release-sync.yml b/.github/workflows/release-sync.yml index cf35f65..8914610 100644 --- a/.github/workflows/release-sync.yml +++ b/.github/workflows/release-sync.yml @@ -10,7 +10,6 @@ on: permissions: contents: write pull-requests: write - statuses: write concurrency: group: release-sync @@ -51,17 +50,3 @@ jobs: else gh pr create --head release --base main --title "$title" --body "$body" fi - - # A PR opened with GITHUB_TOKEN triggers no workflows, so main-source-guard - # never runs on it. Report the guard's verdict for the release commit here: - # this job just generated it from develop, which is exactly what the guard - # requires. A status set with GITHUB_TOKEN satisfies a required check. - - name: Mark release as passing the main source guard - env: - GH_TOKEN: ${{ github.token }} - run: | - set -eu - if ! git rev-parse -q --verify refs/heads/release >/dev/null; then exit 0; fi - gh api "repos/${GITHUB_REPOSITORY}/statuses/$(git rev-parse release)" \ - -f state=success -f context=only-release-into-main \ - -f description="generated from develop ${GITHUB_SHA::7} by release-sync" diff --git a/PROJECT.md b/PROJECT.md index cec7da9..8abdcb3 100644 --- a/PROJECT.md +++ b/PROJECT.md @@ -109,9 +109,9 @@ python3 .github/scripts/check_guide.py # 가이드: HTML 파싱, 링 1. **코루틴 스코프** — 노트북이 import 하는 `DefaultCoroutineScope`·`MainCoroutineScope`. 2. **`pythonx-map.toml` 의 이중 표기** — `pythonx.compose.layout` 과 `pythonx.compose.foundation.layout` 를 둘 다 유지할지. -3. **릴리스·Pages 활성화** — `.github/scripts/release/` 와 `.github/workflows/`(release-sync, main-source-guard, - pages)는 들어와 있다. 실제로 돌려면 원격 푸시, `RELEASE_PR_TOKEN` 시크릿, main 보호 적용이 - 필요하고, 셋 다 메인테이너 승인 사항이다. +3. **릴리스·Pages 활성화** — `.github/scripts/release/` 와 `.github/workflows/`(release-sync, pages)는 + 들어와 있다. main 보호는 저장소 설정만으로 한다(PR 필수, 승인 0, 직접 push·force-push·삭제 + 금지, 머지는 관리자만; #64). 설정 적용과 release→main PR 머지는 메인테이너가 한다. ### 결정됨 (2026-10-03, #60)