Skip to content
Merged
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
36 changes: 21 additions & 15 deletions .claude/skills/pr-flow/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
---
name: pr-flow
description: Land current changes on main via the required PR workflow of this repository — feature branch, signed commits, required checks, CodeRabbit review handling, merge-commit merge. Use when asked to open a PR, ship/land changes, or merge work into main.
description: Land current changes on main via the required PR workflow of this repository — feature branch, signed commits, required checks, independent review, merge-commit merge. Use when asked to open a PR, ship/land changes, or merge work into main.
---

# PR flow for PyYoshi/go-clamav

`main` only accepts merge commits from PRs with green required checks and a
non-blocking CodeRabbit review. Follow the steps in order; never bypass a
step with `--no-verify`, force pushes or `gh pr merge --admin`.
`main` only accepts signed merge commits from PRs with green required
checks, and every PR gets an independent review before it is merged. Follow
the steps in order; never bypass a step with `--no-verify`, force pushes or
`gh pr merge --admin`.

## 1. Before committing

Expand Down Expand Up @@ -43,17 +44,22 @@ gh pr checks --watch
Required: `unit`, `lint`, `integration (1.4)`, `integration (1.5)`. Fix
failures and push; never merge around them.

## 5. Handle CodeRabbit

CodeRabbit reviews in Japanese with request-changes enabled; its
CHANGES_REQUESTED review blocks the merge (mergeStateStatus=BLOCKED).

- Address valid findings, push the fixes.
- For findings you reject, reply on the finding's thread with the concrete
reason (never resolve silently).
- When every finding is handled, comment on the PR:
`@coderabbitai resolve` — CodeRabbit re-checks and posts an approving
review; the merge state becomes CLEAN.
## 5. Independent review

No bot review gates the merge, so this step is where the PR gets reviewed.
Have the diff reviewed against the Review checklist in AGENTS.md by a
reviewer that is not the session that wrote it: the maintainer, or a
separate review run such as a fresh reviewer agent or Codex
`adversarial-review` (pass the checklist as its focus text).

- Address valid findings and push the fixes; the required checks rerun,
and the fixes go back to the reviewer — the review must cover the commit
that is merged.
- For findings you reject, reply in the PR with the concrete reason (never
drop one silently).
- Record the reviewed commit SHA in the PR. Merge only once every finding,
whatever its severity, is fixed or answered, then tick the review item
in the PR checklist.

## 6. Merge and clean up

Expand Down
115 changes: 0 additions & 115 deletions .coderabbit.yaml

This file was deleted.

1 change: 1 addition & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@
- [ ] `README.md` and `README.ja.md` updated together, or the change touches neither
- [ ] `CHANGELOG.md` updated under `[Unreleased]` for user-visible changes
- [ ] No new dependencies, no assembled EICAR string, no weakened guards; design changes reference an ADR
- [ ] Reviewed against the AGENTS.md Review checklist by someone other than the author, covering the merged commit (recorded in the PR); every finding fixed or answered
11 changes: 11 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
# Dependabot: weekly checks for the Go module (currently stdlib-only, but
# this also covers future additions), GitHub Actions pins, and the ClamAV
# image references in the compose file.
#
# Every ecosystem waits 7 days before proposing a newly published version,
# so a compromised release has time to be caught upstream before it lands
# here (zizmor's dependabot-cooldown audit). Cooldown applies to version
# updates only; security updates are not delayed.
version: 2
updates:
- package-ecosystem: gomod
directory: "/"
schedule:
interval: weekly
cooldown:
default-days: 7

- package-ecosystem: github-actions
directory: "/"
schedule:
interval: weekly
cooldown:
default-days: 7

# Note: the clamd image is referenced as ${CLAMAV_IMAGE:-clamav/clamav:1.4}.
# If Dependabot cannot parse the env-default form, remove this entry —
Expand All @@ -20,3 +29,5 @@ updates:
directory: "/docker"
schedule:
interval: weekly
cooldown:
default-days: 7
41 changes: 41 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ jobs:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
fetch-depth: 0 # full history: gitleaks scans every commit
- name: EICAR plaintext guard
run: bash ./scripts/check-eicar.sh tracked
- name: Zero-dependency policy (ADR-0003)
Expand All @@ -56,6 +57,46 @@ jobs:
run: |
go install golang.org/x/vuln/cmd/govulncheck@v1.7.0
govulncheck ./...
# Checks that previously ran only inside CodeRabbit. They are steps of
# this required job, so a finding blocks the merge.
- name: gitleaks (secrets in any commit)
# Scans the whole history, so a secret committed and later removed
# in the same PR is still caught; findings are printed redacted.
run: |
go install github.com/zricethezav/gitleaks/v8@v8.30.1
gitleaks git --redact --no-banner --verbose
- name: actionlint (workflow syntax, expressions, shellcheck)
run: |
go install github.com/rhysd/actionlint/cmd/actionlint@v1.7.12
actionlint
- name: zizmor (GitHub Actions security audit)
uses: zizmorcore/zizmor-action@cc914d7f3750a2d13d75c7f184a1060aa0e9d482 # v0.6.4
with:
version: 1.30.1
# This is the gating run: report in the job log and as PR
# annotations and fail the job on findings. The zizmor-sarif job
# uploads the same audit to code scanning, which cannot gate:
# with SARIF output zizmor exits 0 even when it finds something.
advanced-security: false
annotations: true

# Uploads the zizmor audit to code scanning (Security tab) for alert
# tracking. The only job with security-events: write, so the lint job
# stays read-only; merge gating is the zizmor step in lint.
zizmor-sarif:
runs-on: ubuntu-latest
permissions:
contents: read # check out the workflows to audit
security-events: write # upload the SARIF results to code scanning
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: zizmor (upload to code scanning)
uses: zizmorcore/zizmor-action@cc914d7f3750a2d13d75c7f184a1060aa0e9d482 # v0.6.4
with:
version: 1.30.1
advanced-security: true

# Required: pinned ClamAV versions. 1.4 is the LTS default (EOL
# 2027-08-15), 1.5 the current regular release. 1.0 was dropped at its
Expand Down
80 changes: 68 additions & 12 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ Changing any of these is a defect, not a refactor:
scanned data.

These invariants are enforced in layers: tests, CI, git hooks, Claude Code
hooks, CodeRabbit path instructions and GitHub rulesets. **Weakening a
guard layer (disabling a hook, deleting a check, softening an instruction)
is itself a critical defect.**
hooks, the independent review against the Review checklist below, and
GitHub rulesets. **Weakening a guard layer (disabling a hook, deleting a
check, softening an instruction) is itself a critical defect.**

## Definition of Done

Expand Down Expand Up @@ -72,33 +72,89 @@ Humans decide design; agents implement it. **Stop and ask the maintainer
Accepted designs are recorded as `docs/adr/NNNN-title.md`
(start from `docs/adr/template.md`).

## Review checklist

Every PR is reviewed against this list before it is merged, by a reviewer
other than its author: the maintainer, or a separate review run such as a
fresh reviewer agent or Codex `adversarial-review`. Valid findings are
fixed; a rejected finding is answered in the PR with the reason. No bot
review gates the merge, so this review is the only one a PR gets:

- it must cover the commit that is merged — fixes pushed after a review
go back to the reviewer, and the PR records the reviewed commit;
- a PR is merged only once every finding, whatever its severity, is fixed
or answered with a reason.

Critical — report these first:

- A path that returns a non-zero `ScanResult` together with `err != nil`
(invariant 1).
- A change that lets an unclassifiable clamd reply become `VerdictClean`,
or relaxes the reply classification in `internal/proto`: the
FOUND > ERROR > OK priority, the prefix-agnostic suffix matching of
FOUND and ERROR, the exact OK allowlist (ADR-0005), clean verdicts only
from a NUL-terminated reply (ADR-0007), or unknown replies mapping to
`OutcomeUnknown` (invariant 2).
- Relaxed or removed reply-read bounds, I/O deadlines or client-side size
limit (invariant 3).
- A change that could present a partial stream to clamd as complete: the
INSTREAM terminator handling, including any source error other than
`io.EOF` treated as end of input (invariant 4).
- A `require` in `go.mod` or any other non-stdlib dependency (invariant 5).
- The complete 68-byte EICAR string in the repository, or the
hex-assembled EICAR pattern in `scripts/` turned into a plaintext
constant (invariant 6).
- Scanned content in error messages or logs (invariant 7).
- A weakened guard: an invariant, the Definition of Done, the design gate
or the git rules in this file deleted or relaxed; a hook in `.claude/`
or `githooks/` disabled or relaxed (changed to exit 0, detection patterns
or block targets removed, wiring or the Stop hook removed, including the
`Co-Authored-By` and EICAR checks); a check in `scripts/` removed,
relaxed or made fail-open.

Also check:

- Credentials or tokens in the diff (gitleaks also scans the whole
history in the `lint` job).
- Blocking I/O that ignores the context, and goroutine leaks.
- Tests that are timing-dependent or race under `-race`.
- godoc and comments in English; a `CHANGELOG.md` `[Unreleased]` entry for
user-visible behavior changes; `README.md` and `README.ja.md` changed
together.
- Changes to this file kept consistent with `CLAUDE.md` (which imports
it) and `CONTRIBUTING.md`.
- `.github/`: actions pinned to commit SHAs and minimal `permissions`
(actionlint and zizmor also check workflows in the `lint` job); a
renamed CI job (`unit`, `lint`, `integration (1.4)`,
`integration (1.5)`) renamed in the branch ruleset's required checks
too.
- `docker/`: clamd.conf limits such as `StreamMaxLength` consistent with
the expectations in `integration_test.go`.

## Git rules

- **Never** add `Co-Authored-By` or other attribution trailers to commits.
- Every commit must be signed. Signing is automatic via repo config;
verify with `git log --format='%h %G?'` (expect `G`).
- Never push to `main`. Work on a feature branch, open a PR, wait for the
four required checks (`unit`, `lint`, `integration (1.4)`,
`integration (1.5)`) and CodeRabbit, then merge with a merge commit
(`gh pr merge --merge --delete-branch`). Squash and rebase merges are
disabled to preserve signatures.
`integration (1.5)`) and the independent review (see Review checklist),
then merge with a merge commit (`gh pr merge --merge --delete-branch`).
Squash and rebase merges are disabled to preserve signatures.
- Never use `--no-verify`, `--no-gpg-sign`, force pushes,
`gh pr merge --admin`, or `core.hooksPath` overrides.
- Run `make setup` once per clone to enable the repository git hooks.

See CONTRIBUTING.md for the full pull-request and CodeRabbit workflow.
See CONTRIBUTING.md for the full pull-request and review workflow.

## Language policy

- Everything that becomes part of the repository or its history is written
in **English**: code, comments, godoc, documentation, ADRs, CHANGELOG
entries, commit messages, and pull-request titles and descriptions.
- Exceptions: `README.ja.md` (the Japanese mirror of `README.md`) and the
Japanese instruction text in `.coderabbit.yaml` (review output is
deliberately ja-JP).
- Exception: `README.ja.md` (the Japanese mirror of `README.md`).
- Interaction language is not fixed: conversations with AI assistants and
review-thread discussions follow the participants' preference (e.g.
CodeRabbit reviews and replies to it are typically in Japanese).
review discussions follow the participants' preference.

## Commands

Expand Down
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,16 @@ project adheres to [Semantic Versioning](https://semver.org/).
govulncheck is pinned to a release version in CI and the Makefile
instead of `@latest` (the vulnerability database is still fetched live
at scan time).
- CodeRabbit is retired. Its review contract now lives in the Review
checklist in AGENTS.md, and every PR gets an independent review against
it before merging. The workflow checks CodeRabbit used to run now run in
the required `lint` job: gitleaks over the whole git history,
actionlint (both also in `make lint`) and zizmor. A separate
`zizmor-sarif` job, the only one with `security-events: write`, also
uploads the zizmor audit to code scanning; it does not gate, since
zizmor exits 0 with SARIF output. YAML and Markdown style linting is
dropped. Dependabot now waits 7 days before proposing a new version
(security updates are not delayed).
- Reply classification is stricter: a clean verdict is now produced only
by the exact reply lines `stream: OK` or `OK` (ADR-0005). Previously
any `<prefix>: OK` whose prefix contained "stream"
Expand Down
Loading
Loading