diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d9a53b8..ad78537 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,6 +16,8 @@ jobs: runs-on: ubuntu-24.04 steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 with: @@ -49,3 +51,19 @@ jobs: run: | test -f "$(zepp-devkit path)/preview/zeus_preview.sh" zepp-devkit path + + # The one check the main ruleset requires: passes only when every check job above did, so + # jobs can be added or renamed without touching the ruleset. + ci: + name: CI passed + if: always() + needs: [test] + runs-on: ubuntu-24.04 + permissions: {} + steps: + - name: Every check job passed + env: + RESULTS: ${{ toJSON(needs.*.result) }} + run: | + echo "$RESULTS" + if echo "$RESULTS" | grep -qE '"(failure|cancelled)"'; then exit 1; fi diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4a54590..85d0f2b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -20,6 +20,7 @@ jobs: steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: + persist-credentials: false fetch-depth: 0 - uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0 diff --git a/CHANGELOG.md b/CHANGELOG.md index 4415085..ca99ac8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ All notable changes to the Zepp devkit. The format is based on ## [Unreleased] +### Internal + +- CI hardening: a single `CI passed` check gates releases, and no job keeps the workflow token on disk unless it pushes with git (`persist-credentials: false`). + ## [0.1.0] - 2026-11-01 ### Added diff --git a/CLAUDE.md b/CLAUDE.md index 4037c71..4e17141 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -2,10 +2,10 @@ Shared tooling for the owner's Zepp OS projects (raetha/zepp-kestrel, raetha/zepp-watch-faces, more later): GitHub Actions and scripts for building, test builds, Zepp previews, releases and the emulator. Read `README.md` and `docs/plan.md` first. -- **Branches:** work on `dev`; never push to `main`. A release is one squash-merged pull request from `dev` into `main`, opened when the owner asks: it sets `pyproject.toml`'s and `zepp_devkit/__init__.py`'s version and dates the changelog section. After the merge, CI tags `main` as `vX.Y.Z`, publishes the GitHub release and resets `dev` to `main` (`release.yml`). Projects pin a commit with the version in a comment, and Dependabot proposes updates there. -- **Repository settings:** a ruleset protects `main` (pull requests, squash only); merged branches are deleted automatically; a classic rule keeps `dev` from being deleted and allows force pushes: after a release squash merge, CI resets `dev` onto `main` (`sync-dev` in `release.yml`) when nothing new landed on `dev` meanwhile; otherwise reset it by hand once that work is released (`git checkout dev && git reset --hard origin/main && git push --force-with-lease`). +- **Branches:** Claude runs `dev`: small, settled changes go straight to it, anything else through a `try/` branch and pull request that Claude squash-merges once CI is green; `dev` must stay releasable. Never push to `main`. A release is one squash-merged pull request from `dev` into `main`, opened when the owner asks: it sets `pyproject.toml`'s and `zepp_devkit/__init__.py`'s version and dates the changelog section. After the merge, CI tags `main` as `vX.Y.Z`, publishes the GitHub release and resets `dev` to `main` (`release.yml`). Projects pin a commit with the version in a comment, and Dependabot proposes updates there. +- **Repository settings:** a ruleset protects `main` (pull requests, squash only, the `CI passed` check from `ci.yml`'s gate job, CodeQL code scanning results); merged branches are deleted automatically; a classic rule keeps `dev` from being deleted and allows force pushes: after a release squash merge, CI resets `dev` onto `main` (`sync-dev` in `release.yml`) when nothing new landed on `dev` meanwhile; otherwise reset it by hand once that work is released (`git checkout dev && git reset --hard origin/main && git push --force-with-lease`). - Record each change under `## [Unreleased]` in `CHANGELOG.md`, written for the projects using it. Never bump a version or date the changelog without being asked. - **Behaviour changes reach every project.** Keep inputs backwards compatible within a major version; a breaking change is a new major version, with the migration in the changelog. Test with the fake Zeus (`test/`), and then in a project's CI before releasing. -- **Security:** the Zepp login is in each project's secrets, never here. Never print it, the Zepp app's log, or `zeus bridge` output. Actions pinned to commits; `contents: read` unless a job needs more. +- **Security:** the Zepp login is in each project's secrets, never here. Never print it, the Zepp app's log, or `zeus bridge` output. Actions pinned to commits; `contents: read` unless a job needs more; `persist-credentials: false` on every checkout except in jobs that `git push`. - Project-specific things (page layouts and wording, app IDs, which watches, the HA component) stay in each project, passed in as inputs. - Licence: MIT.