Repository navigation
fix(ci): replace markdownlint-cli2 with markdownlint-cli, drop the shim - #471
Conversation
549bc62 to
3565c52
Compare
3565c52 to
a3ac8fe
Compare
wz-gsa
left a comment
There was a problem hiding this comment.
Independently verified in an isolated worktree, not just trusting the PR description:
Security fix confirmed real:
npm audit --audit-level=moderate: 6 vulnerabilities (1 moderate, 5 high, including the unpatchedCVE-2026-93687inbraces) → 0 vulnerabilities, via a freshnpm cion the PR branch.
File-selection parity confirmed exact (with a correction on my own part worth recording):
- I initially suspected the hand-rolled walker in
run-markdownlint.mjsdouble-counted theskills/→.agents/skills/symlinked directory, based on a 193 vs 153 file-count mismatch against my ownglobbyreimplementation of the old tool's selection. - Before applying a fix, I re-verified against the real
markdownlint-cli2 v0.23.3binary's own direct output rather than my reimplementation. It reports exactly 190 files — matching this PR's unmodified walker exactly (193 total, minus 3 of my own leftover test fixtures from manual testing = 190). My own comparison had usedglobby's non-defaultdot:falseoption, which was the actual error. - My proposed
lstatSync-based "fix" to skip symlinked directories would have been a regression, silently dropping 36 real skill files (the entireskills//.agents/skills/tree) from lint coverage. I discarded it before applying anything to the PR. - Net: the walker in this PR is correct as submitted. No changes needed.
Also confirmed:
- Rule-violation detection still works: injected real
MD018/MD012violations into a test file, both caught correctly, exit code 1. - Frontmatter-skip behavior preserved: injected malformed YAML frontmatter, correctly left unlinted per the
frontMatterregex config. - The hand-rolled glob matcher only supports
**/*.mdand**/*SUFFIXforms, not arbitrary globs — checked.markdownlint-cli2.yamlonmain, which only uses the single**/*.mdform, so this is not a practical gap for this repo's current config.
Not independently verified: the mkdtempSync + spawnSync-with-generated-JSON-config pattern for injection/race risk. Low-risk given this is an unprivileged CI step with no untrusted input reaching the generated path, but flagging that I didn't do a dedicated check on it.
This correctly unblocks the shared CI failure affecting the whole repo (confirmed independently — this was failing on main itself, not just this PR, before this fix). Approving.
[email protected] pulls a vulnerable braces path through micromatch/globby (CVE-2026-93687, no patched release available), which was failing `npm audit --audit-level=moderate` in CI for every PR and on main itself. A prior approach (now superseded) kept markdownlint-cli2 as the command surface via a local bin-shim package plus a hand-rolled recursive file walker reimplementing globby's glob matching. That walker was verified correct for this repo's current **/*.md glob, but reimplementing glob matching by hand is exactly the kind of code most likely to drift from the real tool's behavior on edge cases (symlinked directories, nested wildcards, etc.) without anyone noticing until something silently stops being linted. This replaces markdownlint-cli2 entirely with [email protected], which has zero vulnerable transitive dependencies (confirmed via a fresh `npm ci && npm audit`) and takes globs/ignores directly as CLI arguments, resolved by its own tinyglobby glob engine rather than any custom code of ours. Changes: - .github/linters/package.json: markdownlint-cli2 -> markdownlint-cli, with a js-yaml override to clear markdownlint-cli's own single moderate transitive CVE (GHSA-r3ph-w7gj-g6xm). - .markdownlint-cli2.yaml -> .markdownlint.yaml: markdownlint-cli auto-discovers this filename directly, no --config flag needed. Only the rule-config block and frontMatter regex carry over; globs/ignores are not a markdownlint-cli config concept. - .github/linters/run-markdownlint.mjs: a ~50-line script holding the glob/ignore list once, shared by CI and the pre-commit hook (same single-source-of-truth guarantee the old globs: key gave us). Supports --fix passthrough and --count-only (prints the matched file count via the same tinyglobby engine, for CI's "did this actually lint anything" guard, replacing the old `Linting: N file(s)` stdout scrape). - ci.yml / .pre-commit-config.yaml: both now call `node .github/linters/run-markdownlint.mjs` instead of `npx markdownlint-cli2`. Verification: - npm ci && npm audit --audit-level=moderate: 0 vulnerabilities. - node .github/linters/run-markdownlint.mjs --count-only: 190, an exact match to the real [email protected] binary's own reported count on the pre-existing **/*.md glob (verified directly against the real tool, not a reimplementation, before trusting this number). - node .github/linters/run-markdownlint.mjs: clean exit 0 against the current repo content, matching main's current passing state. - pre-commit run markdownlint --hook-stage manual (fix) and markdownlint-check --hook-stage manual --all-files (check-only): both pass. - make validate: all validators pass. Supersedes the markdownlint-cli2 shim approach on this same branch. Co-authored-by: OpenCode Agent <[email protected]>
a3ac8fe to
6aa576e
Compare
|
This will likely get closed; @wz-gsa has a separate PR brewing with a preferable solution. |
Scratch that, it looks like Will is commandeering this PR! |
|
Blocker-only adversarial review of current head Blockers: none. Scope reviewed:
Blocker criteria used: only issues that should stop an ASAP merge, such as CI still broken, npm audit still failing, markdown lint silently disabled for meaningful repo content, or a concrete security problem. Evidence:
No merge-blocking findings from this review. |
…toml) (#478) ## Summary Two new advisories landed and were GitHub-reviewed **today**, both reachable through `[email protected]`'s dependency tree (the version adopted in #471/#548's `markdownlint-cli2` → `markdownlint-cli` migration): - `katex` 0.11.0–0.18.1: `CVE-2026-103923` / `GHSA-238p-pmpm-9mq7`, a prototype-pollution bypass of trust restrictions (low severity). Reached via `markdownlint` → `micromark-extension-math` → `katex`. - `smol-toml` ≤1.8.0: `GHSA-r4xh-jqrq-34v2`, a quadratic-time `parse()` DoS on ordinary valid TOML input (moderate severity). Reached via `markdownlint-cli` → `smol-toml` directly. Both have patched releases (`[email protected]`, `[email protected]`) — unlike the `braces` CVE that prompted the `markdownlint-cli2` → `markdownlint-cli` migration in the first place (that one had no patched release at all). This is a straightforward override bump. ## Not caused by this PR, not caused by #471/#548 either Confirmed independently: this reproduces on current `main`, unmodified, before making any change: ```text $ npm ci && npm audit --audit-level=moderate # on main, as-is 5 vulnerabilities (3 low, 2 moderate) ``` Same "advisory lands, previously-green gate goes red with zero local changes" pattern as the `braces` CVE #471 fixed — these two were just GitHub-reviewed hours after #471/#548 merged. ## Fix Two `overrides` entries added to `.github/linters/package.json`. `markdownlint-cli` itself stays pinned at `0.49.1`; only its own transitive `katex` and `smol-toml` resolutions move. ```json "overrides": { "js-yaml": "4.3.2", "katex": "0.18.2", "smol-toml": "1.9.0" } ``` ## Verification ```text $ npm ci && npm audit --audit-level=moderate found 0 vulnerabilities $ node .github/linters/run-markdownlint.mjs --count-only 190 $ node .github/linters/run-markdownlint.mjs (exit 0, clean) ``` 190 matches the exact file-count parity established in #471. ## Safety Checklist - [x] No secrets, tokens, credentials, or private keys - [x] No PII, CUI, customer data, or sensitive info - [x] No internal URLs or system details - [x] Examples use placeholders where applicable ## Security Impact Clears a moderate-severity DoS advisory and a low-severity prototype-pollution advisory in dev-only, CI-only tooling (markdown linting). No application runtime impact. ## AI Disclosure This PR was prepared with OpenCode AI assistance. Human review is required before merge. Co-authored-by: OpenCode Agent <[email protected]>
Summary
Fix the shared Markdown Lint CI failure (
npm audit --audit-level=moderatefailing on an unpatchedbracesCVE pulled in transitively bymarkdownlint-cli2) by replacingmarkdownlint-cli2entirely withmarkdownlint-cli, rather than keepingmarkdownlint-cli2as the command surface via a shim.This supersedes an earlier approach on this same branch (a local
markdownlint-cli2bin-shim package + a hand-rolled recursive file walker reimplementingglobby's glob matching). That walker was verified correct for this repo's current**/*.mdglob after a close call where I almost "fixed" a symlink-handling difference that was actually correct behavior — which is exactly the risk of reimplementing glob matching by hand instead of using a real glob engine. Simplifying tomarkdownlint-cliremoves that whole class of risk.Changes
.github/linters/package.json:markdownlint-cli2→[email protected], with ajs-yamloverride to clearmarkdownlint-cli's own single moderate transitive CVE (GHSA-r3ph-w7gj-g6xm). Zero vulnerable dependencies in its tree otherwise..markdownlint-cli2.yaml→.markdownlint.yaml:markdownlint-cliauto-discovers this filename directly, no--configflag needed. Only the rule-config block andfrontMatterregex carry over —globs/ignoresaren't amarkdownlint-cliconfig-file concept..github/linters/run-markdownlint.mjs: a ~50-line script holding the glob/ignore list once, shared by CI and the pre-commit hook (same single-source-of-truth guarantee the oldglobs:key gave us). Supports--fixpassthrough and--count-only(prints the matched file count via the sametinyglobbyenginemarkdownlint-cliuses internally, replacing the oldLinting: N file(s)stdout-scrape).ci.yml/.pre-commit-config.yaml: both now callnode .github/linters/run-markdownlint.mjsinstead ofnpx markdownlint-cli2.Verification
190 is an exact match to the real
[email protected]binary's own reported file count on the pre-existing**/*.mdglob — verified directly against the real tool's own output, not a reimplementation, before trusting this number.Safety Checklist
Security Impact
Removes
markdownlint-cli2's entire vulnerable dependency chain (globby→fast-glob→micromatch→braces, plusmarkdown-it) rather than working around it, and removes a hand-rolled file-selection reimplementation in favor of the glob engine a widely-used, actively maintained CLI already ships and tests.AI Disclosure
This PR was prepared with OpenCode AI assistance. Human review is required before merge.