Skip to content

chore(plugins): update linter versions (security + simple bumps) - #2847

Merged
marschattha merged 5 commits into
mainfrom
ma/update-linter-versions-2026-08-26
Aug 28, 2026
Merged

chore(plugins): update linter versions (security + simple bumps)#2847
marschattha merged 5 commits into
mainfrom
ma/update-linter-versions-2026-08-26

Conversation

@marschattha

@marschattha marschattha commented Aug 26, 2026

Copy link
Copy Markdown
Member

Summary

Update linter plugin versions with stability and security vetting. Covers the
gaps the weekly updateLinterVersions.ts script leaves behind.

After this PR, knip is the only linter with latest_version ahead of
known_good_version
(blocked on #2826), and every script-unreachable linter
is either current or has a filed reason below.

Updates

Linter Previous New Published Age Notes
redocly 2.32.2 2.41.0 2026-07-27 30d ⚠️ security — see below
shfmt 3.8.0 3.13.1 2026-04-06 142d ⚠️ also fixes a silent-pass bug — see below
checkstyle 13.5.0 13.9.0 2026-07-27 30d
pmd 7.25.0 7.26.0 2026-06-29 58d
trufflehog 3.95.5 3.96.0 2026-07-24 33d security-sensitive linter
swiftformat 0.61.1 0.62.1 2026-07-07 50d custom-download
swiftlint 0.63.3 0.65.0 2026-06-27 60d custom-download
terraform 1.15.6 1.15.8 2026-07-08 49d custom-download
eslint 10.5.0 10.8.0 2026-07-24 33d within the major from #2825
oxc (oxlint) 1.70.0 1.76.0 2026-07-27 30d within the major from #2825
prisma 7.8.0 7.9.1 2026-07-27 30d within the major from #2825

Security

redocly 2.32.2 was vulnerable. The pinned version falls inside the range of
two advisories published 2026-07-27:

  • CVE-2026-63325 (high) — arbitrary code execution via Arazzo $faker
    expression using respect; patched in 2.33.0.
  • CVE-2026-63225 (medium) — path traversal in the split command; patched
    in 2.33.2.

2.41.0 clears both.

All other candidates were checked against /repos/{owner}/{repo}/security-advisories
and the GitHub Advisory Database, filtering withdrawn advisories. The only hits
were against versions far older than both current and target (checkstyle < 8.29,
pmd <= 7.21.0, trufflehog < 3.81.9, terraform < 0.12.17, prisma < 2.20.0).

trufflehog is a security-sensitive linter (secret detection, elevated
trust). Beyond the advisory check, its 3.96.0 release assets were verified for
expected content types and its release notes reviewed — nothing suspicious.

shfmt was reporting unparseable files as clean

The version bump surfaced a live correctness bug, fixed here.

The format driver declared success_codes = [0, 1], but with -w shfmt exits
0 whether or not it rewrites the file — exit 1 means only a parse or I/O
error
. Accepting 1 as success meant any shell file shfmt could not parse
produced no rewrite, no error, and zero issues. Verified across both versions:

input shfmt 3.8.0 shfmt 3.13.1
unterminated quote 1 1
unfinished case 1 1
unclosed { 1 1
if true; then / fi (empty body) 0 1
valid but misformatted 0 0

The exit-code contract is identical across versions, so this is not
version-gated — 3.8.0 silently passes an unterminated quote today, and gating
would preserve that for anyone pinning an old shfmt. shfmt 3.9 only made the
parser stricter (an if with an empty body is now correctly rejected), which is
what exposed the bug: the old fixture was invalid shell, so 3.13.1 refused it,
the rewrite never ran, and the test went green with zero findings.

The fixture now has a body, so old and new shfmt both parse it and both still
find it misformatted. Its snapshot is unchanged — output = "rewrite" records
only a generic formatting issue, not file contents. An invalid fixture cannot be
kept as coverage once exit 1 is honored, since the harness asserts
success: true per fixture.

Behavior change: shell files that cannot be parsed now surface a plugin
error instead of silently reporting clean.

Worth a follow-up audit: biome, ktlint, markdownlint, rubocop, ruby-stree, and
standardrb also declare [0, 1] on rewrite-mode drivers. For several of them
exit 1 legitimately means "issues found" and the config is correct — but each
should be checked against its tool's actual contract.

Coverage of script-unreachable linters

The script can only update a linter that declares releases or a runtime in
{java, php, ruby, python, node}; anything else hits its Unknown runtime throw.
Because it also cannot write their latest_version, these linters never appear
in the usual "latest != known_good" gap scan either. Full enumeration:

Linter Why unreachable Disposition
kube-linter no releases, no runtime already latest (0.8.3)
stringslint no releases, no runtime already latest (0.1.10)
swiftformat, swiftlint, terraform no releases, no runtime updated here
shfmt runtime go updated here
clippy, rustfmt runtime rust see below
gofmt runtime go see below
hadolint skip-list too new (2.15.1 is 26d)
tsc skip-list no version fields (hidden = true)

clippy, rustfmt, and gofmt are runtime-coupled, not ordinary plugins.
gofmt 1.22.0 is the managed Go pin (tool_builder.rs:148), and
clippy/rustfmt track the Rust toolchain (pinned 1.77.2). Upstream is far ahead
— Rust 1.98.0, Go 1.27.0 — but bumping them means moving the managed runtimes,
the same class of work as the node 21→22 bump in #2814/#2825, with much wider
blast radius. Deliberately out of scope here; worth its own issue.

Stability policy

Every version here has been published for at least 30 days, no overrides.
Newer releases rejected by the gate, to pick up next run: redocly 2.48.0,
checkstyle 14.0.0, eslint 10.9.1, oxlint 1.80.0, prisma 7.10.0,
swiftlint 0.65.1, terraform 1.15.9, hadolint 2.15.1 (26d).

Node linters were pre-checked with npm view {pkg}@{ver} engines against the
managed runtime (22.23.1) — all satisfied.

Also noticed

Test results

All 11 updated linters pass in plain mode, which runs every fixture at every
historical snapshot version — what CI effectively exercises. Each target was
additionally run in compare-latest-snapshot mode. Apart from shfmt, output was
byte-identical everywhere, so no snapshot changes were needed. Snapshots were
inspected for non-zero findings to rule out vacuous passes (this is what caught
shfmt).

Two fixtures fail in compare mode only — eslint basic_8 (eslintrc, ESLint 8
only) and prisma basic (prisma 5 schema). Compare mode forces the target
version onto every fixture regardless of what it supports. Both were confirmed
to fail identically at the current promoted versions (10.5.0 / 7.8.0), so
this is pre-existing harness behaviour, not a regression.

Custom-download URL templates were HEAD-checked at the target version across
every platform variant (all 200) — no asset-name drift this round.

Test plan

  • All linter tests pass in CI
  • Download URLs verified for custom-download linters (all platforms, 200)
  • No security advisories affect updated versions
  • Node engines checked against the managed runtime
  • Every script-unreachable linter enumerated and dispositioned
  • Watch the windows-2022 job specifically — local runs only cover macOS

marschattha and others added 3 commits August 26, 2026 20:40
The pinned 2.32.2 falls inside the vulnerable range of two advisories
published 2026-07-27: CVE-2026-63325 (high, arbitrary code execution via
Arazzo `$faker` expression, < 2.33.0) and CVE-2026-63225 (medium, path
traversal in `split`, < 2.33.2).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Version-only bumps, each published at least 30 days ago and checked
against GitHub Security Advisories:

- checkstyle 13.5.0 -> 13.9.0
- pmd 7.25.0 -> 7.26.0
- swiftformat 0.61.1 -> 0.62.1
- swiftlint 0.63.3 -> 0.65.0
- terraform 1.15.6 -> 1.15.8
- trufflehog 3.95.5 -> 3.96.0

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Routine bumps within the majors landed by #2825, each published at least
30 days ago with no advisories:

- eslint 10.5.0 -> 10.8.0
- oxlint 1.70.0 -> 1.76.0
- prisma 7.8.0 -> 7.9.1

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@qltysh

qltysh Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Qlty


Coverage Impact - ubuntu-latest

This PR will not change total coverage.

🚦 See full report on Qlty Cloud »

🛟 Help
  • Diff Coverage: Coverage for added or modified lines of code (excludes deleted files). Learn more.

  • Total Coverage: Coverage for the whole repository, calculated as the sum of all File Coverage. Learn more.

  • File Coverage: Covered Lines divided by Covered Lines plus Missed Lines. (Excludes non-executable lines including blank lines and comments.)

    • Indirect Changes: Changes to File Coverage for files that were not modified in this PR. Learn more.

@qltysh

qltysh Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Qlty


Coverage Impact - macos-15

This PR will not change total coverage.

🚦 See full report on Qlty Cloud »

🛟 Help
  • Diff Coverage: Coverage for added or modified lines of code (excludes deleted files). Learn more.

  • Total Coverage: Coverage for the whole repository, calculated as the sum of all File Coverage. Learn more.

  • File Coverage: Covered Lines divided by Covered Lines plus Missed Lines. (Excludes non-executable lines including blank lines and comments.)

    • Indirect Changes: Changes to File Coverage for files that were not modified in this PR. Learn more.

marschattha and others added 2 commits August 26, 2026 21:23
shfmt >=3.9 rejects the basic fixture with "`then` must be followed by a
statement list" and exits 1. Because the driver declares
success_codes = [0, 1], qlty treated that parse failure as success, the
rewrite never happened, and the linter silently reported zero issues.

The fixture was invalid shell — an `if` with an empty body. Give it a
body so both old and new shfmt parse it and still find it misformatted.
The snapshot is unchanged: `output = "rewrite"` records only a generic
formatting issue, not the file contents.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The shfmt format driver declared success_codes = [0, 1], but with `-w`
shfmt exits 0 whether or not it rewrites the file — exit 1 means only a
parse or I/O error. Accepting 1 as success meant any shell file shfmt
could not parse produced no rewrite, no error, and zero issues.

The exit-code contract is the same across versions, so this is not
version-gated: shfmt 3.8.0 also exits 1 on an unterminated quote,
unfinished `case`, or unclosed `{`. shfmt 3.9 only made the parser
stricter (an `if` with an empty body is now correctly rejected), which
is what surfaced this.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@marschattha
marschattha marked this pull request as ready for review August 27, 2026 20:22

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

Claude Code Review is paused for this repository. To reconnect it, an admin of this repository's GitHub organization (or the account owner, for personal repositories) who can also manage your Claude organization's Code Review settings needs to re-link GitHub in Code Review settings. This is a one-time step.

Tip: disable this comment in your organization's Code Review settings.

@marschattha
marschattha merged commit ff9278f into main Aug 28, 2026
18 checks passed
@marschattha
marschattha deleted the ma/update-linter-versions-2026-08-26 branch August 28, 2026 19:43
@qlty-releases qlty-releases Bot mentioned this pull request Aug 28, 2026
marschattha pushed a commit that referenced this pull request Aug 28, 2026
Automated PR for release 0.644.0.

Review (and edit, if needed) the changelog entry below, then
merge this pull request to publish the release.

## Draft release notes


### Fixed

- Bump redocly from 2.32.2 to 2.41.0, which patches CVE-2026-63325
(arbitrary code execution via Arazzo `$faker` expressions) and
CVE-2026-63225 (path traversal in the `split` command) (#2847)
- Fix shfmt reporting unparseable shell files as clean; files it cannot
parse now surface a plugin error instead of silently passing with zero
findings (#2847)

Co-authored-by: qlty-releases[bot] <181762136+qlty-releases[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant