Releases: extremeshok/poll-ci
Release list
v1.5.0 — parallel checks, opt-in caching, self-update
Highlights
Parallel per-commit checks — on by default. A commit's checks (and the trivy scan) now run concurrently in a bounded pool instead of one at a time. CHECK_CONCURRENCY (default: host CPU count; 1 = serial = old behavior) caps how many run at once; checks share the host CPUs, with optional per-check cpus:/memory: hints. Measured ~2.4× faster on an 8-core host (24m → 10m for an 11-check repo).
Opt-in dependency caching (CACHE=true). A clean, monorepo-aware "golden" cache built by a prime step in an isolated container and copied into each check (never written back, so it can't be poisoned). Off by default — it only pays off for download-heavy checks; compute-bound checks (go test, bundler builds) see no gain, and the copy-in can cost at high concurrency.
Self-update timer — on by default. deploy/install.sh installs a systemd timer that pulls :latest daily and restarts poll-ci only when the image digest changed (--noautoupdate to skip). The systemd-native alternative to the compose watchtower profile.
Upgrading
Existing deployments get parallel checks automatically — no config change. To keep the old serial behavior, set CHECK_CONCURRENCY=1. See the README for the full configuration reference.
poll-ci v1.4.0
What's changed in v1.4.0
A reliability and hardening release, driven by an audit of poll-ci's production
status output on a busy watched repo plus a full code review.
Fixes
- Status posts retry on transient failures. A single dropped POST (network
blip, GitHub 5xx) left that contextpendingforever — observed in
production on a green, already-promoted commit. Posts now retry with backoff
and honorRetry-After; permanent failures (token permissions) still
surface immediately. - A still-running check can no longer be scored as passed.
docker start -areturning is no guarantee the container exited, and a running
container's inspect reports exit code 0. The outcome now comes from the
container state (plusdocker wait), so a broken attach stream can't
produce a false green that promotes untested code. - Crash/restart reconciliation. Runs persist an in-flight marker; on
startup, statuses strandedpendingby a mid-run kill (watchtower recreate,
reboot, OOM) are resolved asinterrupted by restartwhen the branch has
moved on. The startup sweep also removes containers and checkouts the dead
process orphaned (instance-scoped label; prune pre-v1.4 orphans once with
docker ps -aq -f label=poll-ci | xargs docker rm -f). - Short-circuit race fixed. A run that completed every step keeps its
results (and promotes) even if a newer tip's cancellation raced in at the
very end. - Force-push reverts re-run. Superseded SHAs are no longer marked
processed, so a branch force-pushed back to one re-tests it instead of
showing stalesuperseded bystatuses forever. - Heartbeat:
HEARTBEAT_MAX_LAGdefaults to0— with1, a failed
promotion affecting only the tip commit never alerted. The no-jq fallback
also extracted the wrong sha from the compare payload; fixed. Existing
installs keep their env file: setHEARTBEAT_MAX_LAG=0there to adopt the
new default. - Polish: invalid env values warn instead of being silently ignored,
scan.pathrejects.., and open-PR listing paginates past 100.
Security / hardening
- The git auth header is passed via environment (
GIT_CONFIG_*) instead of
argv, so it is no longer visible in process listings; log scrubbing also
redacts the base64 header form. Plain-binary deployments need git >= 2.31. - Optional resource limits for check/scan containers:
CHECK_MEMORY,
CHECK_CPUS,CHECK_PIDS. - Engine image base bumped to alpine:3.24 with
apk upgradeat build time.
Opt-in features (defaults preserve existing behavior)
MARK_SKIPPED=true— post a terminalcistatus (not tested — superseded by <sha>) on the intermediate commits a fast push skipped.CONCURRENCY=N— sweep multiple repos in parallel.IMAGE_REFRESH_HOURS=N— periodically re-pull present check images so
:latesttags don't freeze at first pull.- PR runs now short-circuit on force-push like branch runs do (under the
existingSHORT_CIRCUIT).
The state file migrates transparently from older versions, and is now pruned
after ~6 months (a branch's last result is always kept).
Install
docker pull ghcr.io/extremeshok/poll-ci:v1.4.0 # or :latest
go install github.com/extremeshok/poll-ci@v1.4.0Prebuilt binaries below (verify with poll-ci_v1.4.0_checksums.txt).
poll-ci v1.3.1
What's changed in v1.3.1
Patch release hardening the v1.3.0 short-circuit feature (found via an
adversarial review pass).
- No status is left
pendingon a superseded commit. When a run is
short-circuited by a newer commit, every status that hadn't finished —
the in-flight check, the not-yet-started checks, and theci/trivyscan if
it was unreached or mid-run — is now resolved tosuperseded by <sha>.
Checks that had already finished keep their real result. (v1.3.0 resolved
only thecirollup, leaving per-check and scan contexts stuckpending,
which could block branch protection on the dead commit.) ci/promoteno longer strands on shutdown. If the engine is stopped
mid-promotion, the commit is left unmarked so it re-runs (and re-promotes)
on restart instead of leavingci/promotepending forever.
No config changes. Upgrade is a straight image/binary swap.
Install
docker pull ghcr.io/extremeshok/poll-ci:v1.3.1 # or :latest
go install github.com/extremeshok/poll-ci@v1.3.1Prebuilt binaries below (verify with poll-ci_v1.3.1_checksums.txt).
poll-ci v1.3.0
What's new in v1.3.0
-
Short-circuit superseded runs. On a busy branch, commits can land faster
than CI finishes. poll-ci now watches the branch tip during a run and, the
moment a newer commit appears, aborts the stale run (killing the in-flight
check container), marks that commit'scistatussuperseded by <sha>, and
jumps straight to the newest commit — no more waiting on CI for a commit
that's already been replaced.On by default. The tip is re-checked every
POLL_INTERVAL, so only runs longer
than one interval get cut short. SetSHORT_CIRCUIT=falseto run every started
commit to completion. Applies to branch polling (not PRs or--once).
No config-file changes. Upgrade is a straight image/binary swap.
Install
docker pull ghcr.io/extremeshok/poll-ci:v1.3.0 # or :latest
go install github.com/extremeshok/poll-ci@v1.3.0Prebuilt binaries below (verify with poll-ci_v1.3.0_checksums.txt).
poll-ci v1.2.1
What's changed in v1.2.1
Patch release — polish for the scan: feature added in v1.2.0.
- Clearer
ci/trivyfailure status. A failing scan now reports
trivy found issues at HIGH,CRITICAL — see ci/trivy logsinstead of a stray
trivy log line. trivy writes its findings to stdout and INFO logs to stderr
(the opposite of a normal check), which the previous heuristic scraped; fixed,
and trivy now runs with--quiet(cleaner logs — the findings report still
streams). The status colour and promote-gating were already correct; this only
improves the red status text.
No config changes. Upgrade is a straight image/binary swap.
Install
docker pull ghcr.io/extremeshok/poll-ci:v1.2.1 # or :latest
go install github.com/extremeshok/poll-ci@v1.2.1Prebuilt binaries below (verify with poll-ci_v1.2.1_checksums.txt).
poll-ci v1.2.0
What's new in v1.2.0
-
Built-in trivy source scan (
scan:). Add ascan:block and poll-ci runs
a trivy filesystem scan of the checkout as a gate step,
reported as aci/trivycommit status. A finding fails the gate — so,
combined withpromote:, vulnerable deps, leaked secrets, or misconfigured
Dockerfiles/IaC never advance a deploy branch. Shift-left scanning of the
source, complementary to scanning built images. Needs no GitHub token; the
trivy DB is cached in a named volume so it isn't re-downloaded each run.checks: - { name: test, run: go test ./... } scan: {} # defaults: vuln,secret,misconfig · HIGH,CRITICAL promote: branch: release # only green + clean source promotes
-
Promotion-pipeline heartbeat (dead-man's-switch). Optional systemd
timer + monitor (deploy/heartbeat-monitor.sh) that alerts if the poller
stops advancing the deploy branch — so a silently-stuck pipeline is noticed.
Installed bydeploy/install.sh.
Install
# Docker
docker run -d --restart always \
-e GITHUB_TOKEN=github_pat_xxx -e REPO=you/repo -e BRANCH=main \
-v /var/run/docker.sock:/var/run/docker.sock \
-v poll-ci-state:/var/lib/poll-ci \
ghcr.io/extremeshok/poll-ci:v1.2.0
# Systemd service (one command)
git clone https://github.com/extremeshok/poll-ci && sudo poll-ci/deploy/install.sh
# Go
go install github.com/extremeshok/poll-ci@v1.2.0Prebuilt binaries below (verify with poll-ci_v1.2.0_checksums.txt).
Full docs: README.
poll-ci v1.1.0
What's new in v1.1.0
-
promote:— fast-forward a deploy branch on green. Optional per-repo
setting: when every check passes on a watched branch, poll-ci fast-forwards a
target branch (e.g.release) to that commit and reports aci/promote
status. Lets a deploy branch be gated behind green CI without GitHub Actions.
Opt-in, and only this needs the token's Contents: write.checks: - { name: test, run: go test ./... } promote: branch: release
-
One-command systemd installer.
deploy/install.sh
installs poll-ci as a boot-managed Docker service (systemd unit, pinned image,
0600 token env file). Gracefulsystemctl stop. -
Optional auto-update.
docker compose --profile autoupdate up -dkeeps
poll-ci on the latest image via watchtower (scoped to poll-ci only).
Install
# Docker
docker run -d --restart always \
-e GITHUB_TOKEN=github_pat_xxx -e REPO=you/repo -e BRANCH=main \
-v /var/run/docker.sock:/var/run/docker.sock \
-v poll-ci-state:/var/lib/poll-ci \
ghcr.io/extremeshok/poll-ci:v1.1.0
# Systemd service (one command)
git clone https://github.com/extremeshok/poll-ci && sudo poll-ci/deploy/install.sh
# Go
go install github.com/extremeshok/poll-ci@v1.1.0Or download a prebuilt binary below (verify with poll-ci_v1.1.0_checksums.txt).
Full docs in the README.
poll-ci v1.0.0
First release.
A dead-simple, single-container CI for GitHub: it watches repos by polling
(outbound only — no webhooks, no inbound ports), runs each repo's .poll-ci.yml
checks in Docker, and reports results as native GitHub commit statuses. One
process, one container, no database, no UI.
Install
Docker (recommended):
docker build -t poll-ci .
docker run -d --restart always \
-e GITHUB_TOKEN=github_pat_xxx -e REPO=you/repo -e BRANCH=main \
-v /var/run/docker.sock:/var/run/docker.sock \
-v poll-ci-state:/var/lib/poll-ci \
poll-ciGo:
go install github.com/extremeshok/poll-ci@v1.0.0Or download a prebuilt binary below (needs git and docker on the host).
Verify with poll-ci_v1.0.0_checksums.txt.
See the README for full usage,
configuration, security notes, and examples.