Skip to main content

Runbook: dev tools and lint gates

Owner: DevOps. The technical writer owns docs/runbooks/, but DevOps maintains this file together with Taskfile.yml, lefthook.yml and scripts/.
This runbook lists the pinned tools, what each lint gate checks, and how to fix the usual failures. Setup is in dev-setup.md.

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 in scripts/scopecheck/main_test.go. The test runs first in lint: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.
Generated code, 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): raise GO_TOOLCHAIN in Taskfile.yml (or the toolchain line in backend/go.mod once it exists) to the fixed release.
  • A module: go get <module>@<fixed> in backend/, then go mod tidy. This is a go.mod change, so it goes through the backend owner.
Findings in modules the backend requires but doesn’t call are printed as a count and don’t fail the lint. govulncheck -show verbose ./... in backend/ lists them.

osv-scanner

The frontend lockfile has no ignores; fix a finding by upgrading the package (a package.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.toml that 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 runs npm ci from the lockfiles. Don’t use npm install except to add or upgrade a package, and commit the lockfile with it.
  • frontend/.npmrc sets ignore-scripts=true: no dependency runs install scripts. The native binaries (rolldown, Biome, lightningcss, Tailwind oxide) come as platform optionalDependencies and need no script. npm run <script> still works. npm reads the project .npmrc only from the package’s own folder, so a repo-root .npmrc would have no effect.
  • save-exact=true makes npm 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 dev runs the backend and Vite. Open http://localhost:5173: Vite listens on localhost only.
  • task dev:fake does the same with SESAME_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 dev but the Vite node process can keep running, and the next task dev fails with port 5173 in use. Stop it with Get-NetTCPConnection -LocalPort 5173 -State Listen | % { Stop-Process -Id $_.OwningProcess }. Ctrl+C in the terminal stops both.