Runbook: dev tools and lint gates
Owner: DevOps. The technical writer ownsThis runbook lists the pinned tools, what each lint gate checks, and how to fix the usual failures. Setup is in dev-setup.md.docs/runbooks/, but DevOps maintains this file together withTaskfile.yml,lefthook.ymlandscripts/.
Tool versions
task tools installs these into go env GOPATH\bin. Rerun it after a version bump in
Taskfile.yml, which is the only place the versions are set.
Go toolchain. Task sets
GOTOOLCHAIN=go1.26.6+auto. On first use the go command
downloads Go 1.26.6 and verifies its checksum. Go 1.26.0 to 1.26.5 have standard-library
vulnerabilities that govulncheck reports as called by the backend. A GOTOOLCHAIN already
set in your shell takes precedence over the Taskfile value. Plain go build outside Task
uses your installed Go until backend/go.mod pins the toolchain.
Lint gates
task lint runs these in order, and MUST pass before a PR and before every merge.
lint:vuln and lint:osv query vuln.go.dev and osv.dev, so they need network access.
Other checks:
Enable the hooks once per clone with
lefthook install. lefthook run <hook> also
rewrites the installed hooks when lefthook.yml changed; add --no-auto-install to
avoid that.
Fixing common failures
Scope check
lint:scope prints path:line: fund-moving pattern "<regex>" (scope-patterns.txt:N).
The app holds trade-only credentials: it places and cancels orders and reads account data.
Deposits, withdrawals, bridge, transfers, approvals, permits and relayer operations
(redeem, split, merge) are out of scope, so the fix is to remove the code.
A false positive has two fixes:
- Tighten the pattern in
scripts/scope-patterns.txt, and add the line to the allowed list inscripts/scopecheck/main_test.go. The test runs first inlint:scope, so a pattern change that stops catching a known case fails the lint. - Mark the line with a
scope:allow <reason>comment, for example where the config loader refuses a relayer variable. A marker needs security review.
testdata/ and files with a Go Code generated ... DO NOT EDIT. header
are not scanned.
govulncheck
It fails only when the backend calls a vulnerable function. Each finding names the fixed version:- Standard library (
Found in: net/http@go1.26.x): raiseGO_TOOLCHAINinTaskfile.yml(or thetoolchainline inbackend/go.modonce it exists) to the fixed release. - A module:
go get <module>@<fixed>inbackend/, thengo mod tidy. This is ago.modchange, so it goes through the backend owner.
govulncheck -show verbose ./... in backend/ lists them.
osv-scanner
The frontend lockfile has no ignores; fix a finding by upgrading the package (apackage.json change goes through its owner). tools/vectors findings that can’t be
fixed are ignored in scripts/osv-scanner-vectors.toml, each with a reason and an
ignoreUntil date. When the date passes, the lint fails again: recheck the finding, then
fix it or extend the date with a new reason.
gitleaks
A pre-commit failure prints the file, line and rule, with the secret redacted:- A real secret: unstage it, move the value to
.env, and rotate it if it was ever committed or pushed. - A test value: add an allowlist to
.gitleaks.tomlthat names the exact value and the exact file, with a comment explaining why the value is harmless. The existing entries cover the Hardhat account #0 key and the fake L2 secrets in the golden signing vectors.
gitleaks: command not found means task tools has not been run.
npm
- Install dependencies with
task setup, which runsnpm cifrom the lockfiles. Don’t usenpm installexcept to add or upgrade a package, and commit the lockfile with it. frontend/.npmrcsetsignore-scripts=true: no dependency runs install scripts. The native binaries (rolldown, Biome, lightningcss, Tailwind oxide) come as platformoptionalDependenciesand need no script.npm run <script>still works. npm reads the project.npmrconly from the package’s own folder, so a repo-root.npmrcwould have no effect.save-exact=truemakesnpm install <pkg>record an exact version.- If a future dependency needs its install script, run it explicitly with
npm rebuild <pkg> --ignore-scripts=false, and note why in the PR.
Dev servers
task devruns the backend and Vite. Open http://localhost:5173: Vite listens on localhost only.task dev:fakedoes the same withSESAME_FAKE_VENUE=1. The backend then serves a fake venue, so the UI works without reaching Polymarket.- On Windows, if the backend exits by itself (for example on a config error), Task stops
npm run devbut the Vitenodeprocess can keep running, and the nexttask devfails with port 5173 in use. Stop it withGet-NetTCPConnection -LocalPort 5173 -State Listen | % { Stop-Process -Id $_.OwningProcess }. Ctrl+C in the terminal stops both.