chore: org hardening — SHA-pinned actions, governance docs, Scorecard, issue forms - #501
Merged
Merged
Conversation
…s, add zizmor Every third-party action in ci.yml and drivers.yml now references the commit SHA the current tag resolves to (with the version as a trailing comment so dependabot's github-actions ecosystem keeps it current): actions/checkout v7.0.1, actions/setup-go v7.0.0, golangci/golangci-lint-action v9.3.0. A floating major tag can be moved by anyone with push access to the action repository; a SHA cannot. actions/checkout gets `persist-credentials: false` in every job — none of them pushes or uses the token after checkout, so the job token no longer sits in .git/config where any later step (or a compromised dependency) could read it. Tool installs are pinned too: mage v1.17.2 and actionlint v1.7.12 instead of @latest, so a new upstream release cannot turn main red on its own. govulncheck stays @latest on purpose — its vulnerability database is fetched at runtime, the binary version is not the freshness that matters. A zizmor step runs next to actionlint (pipx, exact version 1.30.0). actionlint checks workflow syntax; zizmor checks security posture — unpinned actions, persisted credentials, template injection, excessive permissions. It only needs the ephemeral read-only job token for its online audits, no repository secrets. Workflow semantics are otherwise unchanged. org hardening review 2026-09-06
Same SHA pins as ci.yml (checkout v7.0.1, setup-go v7.0.0).
The workflow granted `contents: write` to every job; only tag-submodules
pushes tags. The top level is now `contents: read` and the write grant
moves onto that single job, so a compromise of the proxy-notify or
validate steps cannot push to the repository.
`${{ github.event.release.tag_name }}` was spliced directly into six
`run:` scripts. It is now passed through step `env:` and read as a plain
shell variable — identical behaviour for every valid tag, but a crafted
tag name can no longer become shell code (zizmor template-injection).
notify-proxy's setup-go gets `cache: false`: the job only runs
`go list -m` against the proxy and needs no module cache, and a cache
restored into a release-triggered job is a poisoning vector.
notify-proxy's checkout gets `persist-credentials: false`; tag-submodules
keeps the default because it pushes (explicit zizmor ignore with the
reason on the step). The reusable-workflow call keeps the `./` form
because actionlint 1.7.12 does not yet accept GitHub's `$/` syntax.
org hardening review 2026-09-06
Runs ossf/scorecard-action (v2.4.4, SHA-pinned) on push to main, weekly, and whenever branch protection changes; publishes results to the Scorecard API and uploads SARIF to code scanning via github/codeql-action/upload-sarif (v4.37.9, SHA-pinned). Top-level permissions are read-all; the single job adds only security-events: write (SARIF upload) and id-token: write (OIDC for publish_results). Checkout does not persist credentials. Scorecard gives a continuous, public measurement of the supply-chain posture the rest of this review hardens (pinned dependencies, token permissions, branch protection, dangerous workflow patterns). org hardening review 2026-09-06
Write down how the project is actually run so contributors do not have to infer it: Contributor (fork PRs) -> member of the org team `contributors` (write on celeris only; may approve; may merge own PRs only after a code-owner approval and green required checks; ~3 merged non-trivial PRs + sustained engagement) -> Maintainer (admin, cuts releases, owns CODEOWNERS; currently FumingPower3925). The merge rule is stated once: required checks green + approval from a code owner; the author with write access or the approving maintainer (auto-merge) merges; nobody merges their own PR without a code-owner approval; the admin bypass is for release/infra emergencies and is visible in the audit log. Decisions are the single maintainer's today, lazy consensus (72 h) once there is more than one. Releases are tagged after the probatorium nightly and weekend soak pass; release notes come from PR labels; GitHub Releases is the changelog (no CHANGELOG.md). CODEOWNERS routes every PR to @FumingPower3925 and shows how to delegate an area (commented example). MAINTAINERS.md lists the maintainer and the `contributors` team (WdnLiu) and links to the criteria. org hardening review 2026-09-06
… sign-off Mirror the governance merge rule in the place contributors actually read; tell them which label to put on a PR (bug / enhancement / performance / security / breaking / dependencies) now that release notes are generated from labels and there is no CHANGELOG.md; recommend `git commit -s` (DCO) without making it mandatory yet; point the security paragraph at private vulnerability reporting; link GOVERNANCE.md and MAINTAINERS.md. Everything else is unchanged. org hardening review 2026-09-06
…dgement Private vulnerability reporting is enabled on the repository, so the Security tab -> "Report a vulnerability" flow becomes the preferred channel (report, advisory, CVE and credit all in one place, visible only to maintainers); security@goceleris.dev stays as the alternative. The acknowledgement window is stated as 72 hours, which is what a single-maintainer project can actually promise. Supported-versions table and per-release notes are kept as they were. org hardening review 2026-09-06
…onfig Replace the markdown issue templates with issue forms. The bug form requires engine (std / epoll / io_uring / adaptive), architecture (amd64 / arm64 / other), celeris version and a Go reproduction, and asks for OS/kernel and expected-vs-actual — the fields that decide whether an engine bug can be reproduced at all. Both forms apply `needs-triage`. config.yml disables blank issues and routes security reports to the private advisory form instead of a public issue. The PR template gains "Closes #", an engine x architecture "Tested on" line, a breaking-change checkbox and a "labeled for release notes" checkbox, matching the label-driven release notes. .github/release.yml defines the generated release-notes sections (Breaking changes / Security / Fixes / Performance / Features / Other) and excludes dependabot's `dependencies` and `github_actions` labels. GitHub Releases is the changelog; there is no CHANGELOG.md. org hardening review 2026-09-06
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
File-based part of the org hardening review 2026-09-06 for
goceleris/celeris. GitHub settings/rulesets and the bench cluster are handled separately; this PR only touches files. Workflow semantics are unchanged except where listed.Changes and rationale
Supply chain / workflows
ci.yml,drivers.yml,release.yml(+ the newscorecard.yml):actions/checkout@3d3c42e5… # v7.0.1,actions/setup-go@b7ad1dad… # v7.0.0,golangci/golangci-lint-action@ba0d7d2e… # v9.3.0,ossf/scorecard-action@2d114668… # v2.4.4,github/codeql-action/upload-sarif@cdf488f5… # v4.37.9. SHAs resolved from the current tags via the GitHub API (annotated tags dereferenced to the commit).github-actionsecosystem (already configured) keep the SHAs current.persist-credentials: falseon everyactions/checkoutstep in jobs that never push (all ofci.yml,drivers.yml, andnotify-proxyinrelease.yml).tag-submoduleskeeps the default because it pushes tags (explicitzizmor: ignore[artipacked]with the reason)..git/configfor every later step and any compromised dependency to read.mage@v1.17.2,actionlint@v1.7.12(were@latest).govulncheckstays@latest.mainred by itself. govulncheck's DB is fetched at runtime, so its binary version is not the freshness that matters.pipx run --spec zizmor==1.30.0 zizmor .github/workflowswithGH_TOKEN: ${{ github.token }}(ephemeral read-only job token, no repository secrets).release.ymlleast privilege: top-levelcontents: read;contents: writeonly ontag-submodules.ci.yml(contents: read).release.ymltemplate injection:${{ github.event.release.tag_name }}moved from sixrun:bodies into stepenv:and read as$TAG/$VERSION.release.ymlnotify-proxysetup-gocache: false.go list -magainst the proxy; a module cache restored into a release-triggered job is a cache-poisoning vector.scorecard.yml(OpenSSF Scorecard): triggersbranch_protection_rule, weekly schedule, push tomain;permissions: read-allat top, jobsecurity-events: write+id-token: write; checkout without credentials;publish_results: true; SARIF upload via SHA-pinnedcodeql-action/upload-sarif.Note: the reusable-workflow call stays
uses: ./.github/workflows/ci.yml— actionlint 1.7.12 does not yet accept GitHub's newer$/self-repository form, so it carries a commentedzizmor: ignore[self-repository].Governance and process
GOVERNANCE.md(one page): roles Contributor →contributorsteam member (write on celeris only; may approve; may merge own PRs only after a code-owner approval and green required checks; ~3 merged non-trivial PRs + sustained engagement) → Maintainer (admin; cuts releases; owns CODEOWNERS; currently @FumingPower3925). Merge rule: required checks green + code-owner approval; author with write or approving maintainer (auto-merge) merges; nobody merges their own PR without a code-owner approval; admin bypass reserved for release/infra emergencies and visible in the audit log. Decisions: single maintainer today; lazy consensus (72 h) once there is more than one. Releases: tagged after the probatorium nightly + weekend soak pass; notes from PR labels + hand-written highlights; GitHub Releases is the changelog (noCHANGELOG.md).MAINTAINERS.md: maintainer table (@FumingPower3925, areas: all) and thecontributorsteam (@WdnLiu), with how to become one (links GOVERNANCE.md)..github/CODEOWNERS: header,* @FumingPower3925, commented area-delegation example (# /middleware/ @FumingPower3925 @WdnLiu).CONTRIBUTING.md: new "How changes get merged", "Labels and release notes" (bug / enhancement / performance / security / breaking / dependencies; no CHANGELOG.md), "Commit sign-off" (git commit -s, DCO recommended, not mandatory yet); links GOVERNANCE.md and MAINTAINERS.md; security paragraph points at private reporting. Everything else kept.SECURITY.md: private vulnerability reporting (Security tab → "Report a vulnerability",https://github.com/goceleris/celeris/security/advisories/new) is now the preferred channel, abovesecurity@goceleris.dev; acknowledgement within 72 hours. Supported-versions table and release notes kept..github/release.yml:changelog.excludelabelsdependencies,github_actions; categories Breaking changes [breaking], Security [security], Fixes [bug], Performance [performance], Features [enhancement], Other [*].bug_report.yml(Engine dropdown std/epoll/io_uring/adaptive required, Architecture dropdown amd64/arm64/other required, celeris version required, OS/kernel, Minimal reproductionrender: gorequired, Expected vs actual; labelsbug,needs-triage),feature_request.yml(problem / proposal / alternatives; labelsenhancement,needs-triage),config.yml(blank_issues_enabled: false, contact link "Security vulnerability" → private advisory form).bug_report.mdandfeature_request.mddeleted.Closes #,Tested on: [ ] std [ ] epoll [ ] io_uring — [ ] amd64 [ ] arm64,[ ] Breaking change? (label breaking),[ ] Labeled for release notes.Verification
actionlint(v1.7.12, local): clean on all four workflows.zizmor 1.30.0with online audits (GH_TOKENset, as CI will run it): No findings (2 ignored with reasons, 16 suppressed).python3 -c 'import yaml'parse of every.github/**/*.yml: OK (workflows, issue forms,release.yml,dependabot.yml).grep -rnE 'uses: [^./][^@]*@v' .github/→ nothing (no unpinned third-party references remain; the only non-SHAuses:is the in-repo./.github/workflows/ci.yml).go build/go vetwas needed.Not in this PR
Rulesets / branch protection, required checks, the
contributorsteam scope, private-vulnerability-reporting toggle and the bench cluster are configured separately as part of the same review. Labels referenced by.github/release.ymland the issue forms (performance,security,breaking,needs-triage) must exist in the repository for the sections/forms to apply them.