Repository navigation
Sightread CI
Review every update before it's merged. On a pull request that moves a lockfile, Sightread reviews every version the change adds or moves, writes the result to the job summary and one pull request comment, keeps the reports as an artifact and fails the job at the level you set. This page covers init ci, the GitHub Action and its inputs, Dependabot and Renovate, code scanning and running changes in any other CI.
rhythm sightread init ci # fail on high, keep one PR comment
rhythm sightread init ci --fail-on critical --sarif # fail on critical, upload to code scanning
rhythm sightread init ci --comment=false # no PR commentRun it at the repository root:
$ rhythm sightread init ci
Wrote .github/workflows/sightread.yml: reviews lockfile changes on pull requests and everything each Monday, fails on high or worse.
Next steps:
1. Review the file, then commit and push it:
git add .github/workflows/sightread.yml
git commit -m "ci: review updates with sightread"
2. Protect .sightread/allowed.yaml with CODEOWNERS, so a pull request can't approve its own update:
/.sightread/allowed.yaml @your-org/reviewers
3. Dependabot and Renovate pull requests get a read-only token: the gate and the job summary still
work while the comment and the SARIF upload are skipped with a notice.
More: https://github.com/RhythmShahriar/rhythm/wiki/Sightread-CI
The workflow it wrote:
name: Sightread
on:
pull_request:
paths: ["**/composer.lock", "**/package-lock.json", "**/npm-shrinkwrap.json", "**/pnpm-lock.yaml", "**/yarn.lock", "**/bun.lock"]
schedule:
- cron: "17 3 * * 1"
permissions:
contents: read
pull-requests: write
jobs:
sightread:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with: {fetch-depth: 0}
- uses: RhythmShahriar/sightread@4e49be6985e64cb0e668ea99a7192f612d424626 # v1.0.0
with:
version: 1.0.0
fail-on: high
comment: trueBoth actions are pinned by commit. A commit doesn't name a release, so init ci also sets version; without it the Action installs the latest release and warns. fetch-depth: 0 gives changes the base branch to compare with. On pull requests the job reviews the lockfile changes; each Monday it reviews every available update in the repository. init ci never replaces an existing workflow without --force: it exits 2 and says to add it.
A build from source (rhythm-sightread version says dev) has no release commit to pin. Its init ci prints a warning first, writes uses: RhythmShahriar/sightread@v1 # pin this to a commit SHA and set version below and leaves the input as a comment under with:, # version: 1.2.3. Pin the commit of the release you want and set version to it, or write the workflow with a released binary.
- uses: RhythmShahriar/sightread@v1
with:
fail-on: high
comment: trueThe Action installs the Sightread release that matches its tag, checks it with cosign before anything runs (it never builds from source), restores a per-day cache of data and archives, runs the review and then:
- writes the Markdown review to the job summary;
- uploads the JSON and HTML reports as a workflow artifact;
- with
comment: true, posts one pull request comment and updates that same comment on later runs; - with
sarif: true, uploads findings to code scanning under the categorysightread; - fails the job when the review exits non-zero:
Sightread found updates with findings at or above high. See the job summary and the report artifact.
It runs on Linux and macOS runners, not Windows. On pull_request it runs changes against the pull request's base branch; on any other event it runs all.
| Input | Default | Meaning |
|---|---|---|
mode |
changes on pull_request, else all
|
changes, all or package
|
package |
for mode package, one eco:name@version per line, e.g. npm:left-pad@1.4.0
|
|
path |
. |
the site or project folder, relative to working-directory
|
working-directory |
. |
folder every step runs in, e.g. apps/web in a monorepo |
base |
the pull request's base branch | for mode changes, the branch to compare with; allow entries count only from it |
fail-on |
high |
fail the job at none, info, low, medium, high or critical
|
min-confidence |
the config's, else likely
|
confirmed or likely
|
allow-partial |
false |
let fail-on pass a run with packages not checked, fetch failures or timeouts |
allow-unverified |
false |
review packages whose integrity couldn't be checked and let fail-on pass them |
baseline |
a saved JSON report whose findings are hidden | |
trust-pr-allow |
false |
count the allow entries, config and baseline the pull request itself edits |
transitive |
false |
review transitive Composer and npm dependencies too; on pull requests changes always does |
sarif |
false |
write sightread.sarif and upload it to code scanning; needs security-events: write
|
comment |
false |
one pull request comment, updated on later runs; needs pull-requests: write
|
summary |
true |
the Markdown review in the job summary |
upload |
true |
the JSON and HTML reports as a workflow artifact |
attest |
false |
sign the JSON report with actions/attest under the workflow's identity; needs id-token: write and attestations: write
|
args |
extra flags, e.g. --only npm:* --jobs 2, split on spaces with no glob expansion |
|
version |
the release that matches the action's tag | e.g. 1.0.0 or latest; at a commit or @v1 it installs the latest release and warns |
verify-signature |
true |
check with cosign that checksums.txt was signed by Sightread's release workflow; false checks only the checksum and warns |
github-token |
${{ github.token }} |
for the comment, the SARIF upload and the GitHub API rate of Composer packages and tag checks |
download-url |
a folder holding the release files instead of the GitHub release, for mirrors; needs version
|
| Output | Meaning |
|---|---|
exit-code |
Sightread's exit code |
verdict |
the worst verdict of the run: hold, review, unverified, allowed or routine, or none
|
updates |
how many updates were reviewed |
findings |
how many findings count, at every severity |
report |
path of the JSON report |
html |
path of the HTML report |
sarif-file |
path of the SARIF file, when sarif is true |
summary |
path of the Markdown review |
comment-id |
ID of the pull request comment, when one was posted or updated |
version |
the Sightread version that ran |
- uses: RhythmShahriar/sightread@v1
id: sightread
with: {fail-on: none}
- if: steps.sightread.outputs.verdict == 'hold'
run: echo "A dependency update is on HOLD; read ${{ steps.sightread.outputs.html }}"changes compares each lockfile at the base with the working tree. In a repository where a Renovate branch moved fetchkit from 1.2.0 to 1.2.1 and its lockfile entry to a tarball off the registry:
$ rhythm sightread changes --base main --fail-on high
reviewing 1 of 1: fetchkit 1.2.0 → 1.2.1
♪ rhythm sightread 1.0.0 npm fetchkit 1.2.0 → 1.2.1
────────────────────────────────────────────────────────────────────────
Read-only. Sightread changes nothing on your site and never runs the
code it downloads.
▸ Installed 1.2.0 in node_modules/fetchkit
▸ Candidate 1.2.1 · released 2026-10-28
▸ Integrity both versions: SHA-512 matches dist.integrity and the
registry signature verifies with a pinned npm key (this
proves the registry published it, not that the content
is harmless) ✓
▸ Publisher unchanged (goodmaintainer)
▸ Diff 2 files changed · +2 −1 lines · 56 B → 209 B
▸ Changelog none for this version
HIGH 1 ────────────────────────────────────────────────────────────────
▌ HIGH Lockfile entry moved off the registry package-lock.json:8
▌ the lock entry moved from the registry to a tarball URL:
▌ https://evil-mirror.example/fetchkit-1.2.1.tgz
▌ → Find out who moved this entry off the registry before
▌ merging.
...
╭──────────────────────────────────────────────────────────────────────╮
│ VERDICT REVIEW │
│ ■ 1 high ■ 2 medium │
│ Sightread reports what changed. It does not judge intent. │
╰──────────────────────────────────────────────────────────────────────╯
It exits 1. The job summary and the comment get the Markdown form (--md), shown here as GitHub renders it from this run:
Verdict Update From To Findings ⚠️ REVIEWfetchkit (npm) 1.2.0 1.2.1 1 high, 2 medium Integrity (both versions): SHA-512 matches dist.integrity and the registry signature verifies with a pinned npm key (this proves the registry published it, not that the content is harmless). Publisher: goodmaintainer. Changelog: none for this version.
Severity Signal Where Evidence high Lockfile entry moved off the registry package-lock.json:8the lock entry moved from the registry to a tarball URL: hxxps://evil-mirror[.]example/fetchkit-1.2.1.tgzmedium Released very recently n/a published 3 hours ago (2026-10-28 11:11 UTC); the minimum age is 72hmedium Changelog does not mention what the code adds index.js:2no changelog entry for 1.2.1; the update adds network sends (index.js:2), file writes outside the package (index.js:2)Record your review:
rhythm sightread allow npm:fetchkit@1.2.1 --reason "..."Static diff of official releases; Sightread never ran this code. Not proof an update is safe.
The comment also holds the flagged hunks in a collapsed diff. Fetched URLs and hosts are defanged and package text is escaped, so a package can't ping anyone, link anywhere or inject HTML into the comment. Rows of routine updates fold into one <details> above 10. The comment stays under GitHub's size limit by trimming hunks first.
A pull request can't approve its own update. changes reads .sightread/allowed.yaml, the config and a committed baseline at the base branch. An entry the pull request adds shows as allowed in this change, not counted (--trust-pr-allow counts it). Anything else it relaxes (an ignore entry, osv: false, a new mirror, a lower fail_on) gets the note relaxed in this change, not counted (--trust-pr-allow counts it). To accept an update:
- Read the comment or the HTML report from the artifact.
- In a separate pull request (or on the base branch), record the review:
rhythm sightread allow npm:fetchkit@1.2.1 --reason "...". It's bound to that archive's sha256. - Merge it; the next run of the dependency pull request shows the update as ALLOWED.
Protect the allow file with CODEOWNERS so only reviewers can merge it. trust-pr-allow: true turns the rule off, for repositories where every pull request is already reviewed by the same people.
Their pull requests get a read-only token. The gate and the job summary still work; the comment and the SARIF upload are skipped with a notice that says which permission was missing. To run the job only on their pull requests:
jobs:
sightread:
if: github.actor == 'dependabot[bot]' || github.actor == 'renovate[bot]'Don't use pull_request_target with a checkout of the pull request's head: that hands a write token to code from the pull request.
permissions:
contents: read
security-events: write
steps:
- uses: actions/checkout@<sha> # v7.0.1
with: {fetch-depth: 0}
- uses: RhythmShahriar/sightread@v1
with:
sarif: trueEach finding becomes a result located where the version is pinned: the lockfile line, or the plugin's main file when the WordPress site is in the repository, since code scanning ignores files that aren't committed. The path inside the package is in the message and in properties.package_path. Fingerprints are stable across runs, so an alert closes when the update is allowed or gone. See Output and reports.
changes is a plain command; any CI that has the repository's history can run it. Install with rhythm install sightread (or the installer, see CI setup) and run:
rhythm sightread changes --base origin/main --fail-on high --md -o sightread.md -o sightread.jsonCI set turns on --redact-paths, so reports hold paths relative to the repository. Set GITHUB_TOKEN when the project has Composer packages on GitHub; api.github.com allows 60 requests an hour without one. Exit codes are in the CLI reference: 1 for findings at --fail-on, 3 for packages that couldn't be fetched or verified unless --allow-partial or --allow-unverified.
For a whole site on a schedule, outside a repository, see Watch.
← Watch · Home · Configuration →
rhythm · Useful ideas. Working systems. · Check only sites you own or have permission to test. Keep staging sealed (responsible use) · This wiki is published from wiki/ in the rhythm repository; suggest changes there with a pull request.
Get started
rhythm in depth
Tuner
- Overview
- Your first scan
- Reading results
- Choosing checks
- Requests and politeness
- Output and reports
- Batch scans
- Local scans
- Integrity and malware
- Changes and notifications
Tuner in depth
- Known vulnerabilities
- PHP advisories
- CI and code scanning
- GitHub Action
- Config file
- Watch and serve
- Writing checks
- Check packs
- Finding reference
- CLI reference
- Coming from Wordfence CLI or WPScan
- FAQ and troubleshooting
Soundcheck
- Overview
- Your first check
- Reading results
- Review and accept
- Discovery
- Page health
- Visual changes
- Interactions
- Forms and flows
- Cache
- Speed
- Accessibility and SEO
- EAA mode
- Keyboard walkthrough
- Accessibility statement
Soundcheck in depth
- CI
- CI baselines and PR comments
- Configuration
- Error rules and exec
- WordPress updates
- Fleet and client reports
- History
- Import from BackstopJS and Lost Pixel
- Firefox and WebKit
- CLI reference
- FAQ and troubleshooting
- Benchmark
Echo
- Overview
- Your first run
- Connectors
- Sealing staging
- Echo Inbox
- Messages and checks
- Checks and rules
- Attachments
- Actions and compare
- With Soundcheck
- Replay
- Deliverability
Echo cookie consent
Echo in depth
- Docker and DDEV
- Agency hub and reports
- Schedule
- MCP server
- Conformance kit
- CI
- Configuration
- API
- CLI reference
- FAQ and troubleshooting
- Benchmark
Roadie
- Overview
- Getting started
- Copy and prepare
- Sources and targets
- Profiles
- Pseudonymisation
- Live keys
- Kill switch
- Verify and reports
Roadie in depth
- Laravel
- Generic SQL and Postgres
- Multisite
- CI and the GitHub Action
- Configuration
- Security and limits
- CLI reference
- Troubleshooting
- FAQ and honest limits
- Benchmark
Sightread
- Overview
- Your first review
- Signal reference
- Allow and baseline
- Sources and integrity
- With Soundcheck and Roadie
- Watch
Sightread in depth
- CI and the GitHub Action
- Configuration
- Output and reports
- Security model
- CLI reference
- FAQ and honest limits
- Benchmark
Project