Repository navigation
Security
migrate,rule-pack init,coverage setupandci-template gitlab --vendorno longer write through a symlink that leaves the project. A cloned repository could commit a symlink at a path that one of these commands writes, and the link could point outside the project. The commands then wrote or overwrote the outside file. Now each command exits with code 2 when the target or a parent directory is a dangling symlink. The same applies to a symlink that resolves outside the project. A link that stays inside the project still works. When only the config file ofrule-pack initlinks outside the project, the command writes the pack and does not change the config. It prints therulePacksentry, and you add that entry by hand. Versions 3.41.0 and earlier are affected. Upgrade to 3.42.0. (#4410)- The analysis caches no longer write through a symlink that leaves the project. A cloned repository could commit
.fallow, a directory in it, or a cache file as a symlink to a path outside the project. An analysis run then created or overwrote the outside file, or wrote cache files into the outside directory. Now each cache writer skips its save when the path is a dangling symlink or a symlink that resolves outside the project, and the analysis continues.health --save-snapshotstops with an error in that case, andaudit-cache prunedoes not delete through such a link. A link that stays inside the project still works, and so does acache.dirorFALLOW_CACHE_DIRoutside the project. (#4422) - The MCP server requires
rmcp3.9 or later.rmcp3.8.0 has the advisory RUSTSEC-2026-0462 in its Streamable HTTP clients. The Fallow MCP server uses stdio and does not enable these clients, so it was not exposed. The update clears the dependency audit. (#4407, #4408) - The GitHub Action no longer writes its artifacts through a symlink, and it escapes a rejected dependency version in its installation diagnostics. (#4401)
Features
- The GitHub Action and the GitLab template can run
fallow mutation. Setmutation: true(GitLab:FALLOW_MUTATION: "true"). The default scope is the changed lines of the pull request, with a10mtime budget. The inputsmutation-scope,mutation-time-budget,mutation-max-mutantsandmutation-min-scorecontrol the run. A failedmutation-min-scorefails the job with exit code 1. A tool failure of the run fails the job with exit code 2. The step does not run in a job that can run fork code with the secrets of the base project. The step also removes the CI tokens from the test environment. (#4368) fallow reportrenders mutation results in CI. The new flags--mutation-report <PATH>and--mutation-not-run <REASON>work with the pr-comment, review,github-summary,github-annotationsandcodeclimateformats. Survived mutants on changed lines appear with the rulefallow/mutation-survivedin the new Tests category. The comment, the review summary and the job summary get a "Mutation testing" section. Afallow mutationrun with--min-scoreormutation.minScorewritesgate_outcomes["mutation-min-score"]into its report. The Action has the new outputmutation-report-rendered. (#4400)fallow mutation exportwrites a saved report in the openmutation-testing-report-schemaformat. Mutation dashboards and HTML report viewers read this format. The command runs no code, and it refuses a report whose mutated files changed after the run. (#4396)fallow mutationmakes more mutants with the existing operators. Anifor? :test that is a comparison or a logical expression becomestrueandfalse. A loop test of this kind becomesfalseonly. An&&operand that is a comparison or a!xbecomestrue. Such an||operand becomesfalse.regex-literalremoves a+,*or?quantifier, shortens{n,m}to{n}, and removes an anchor at the start or end of a group. Compound assignments, unary operators and template literals get new mutants. The operator names do not change, and an existing mutant keeps its id. (#4372)fallow mutationhas nine opt-in operators.block-statement,array-literal,object-literal,method-expression,switch-case,call-expression,throw-statement,regex-constructorandregex-assertionrun only when--operators,mutation.operatorsor the MCPoperatorsparameter names them. The default set does not change. (#4385)- New options to plan a mutation run.
--time-budgetnow runs the cheapest mutants first.--mutants-per-line <n>(mutation.mutantsPerLine) limits the mutants on each line, and the others arependingwith the reasonsampled-out.--function-scope(mutation.functionScope) widens each changed line to its whole function. The run also warns about skipped and todo tests in changed test files. (#4373, #4399) fallow mutation --typecheckadds an equivalence hint to an optional-chaining survivor. When the declared type ofaexcludesnullandundefined, the survivor ofa?.btoa.bgetsequivalence_hint: "type-non-nullish". The hint needsstrictNullChecksandnoUncheckedIndexedAccess. The hint can be wrong. The mutant stayssurvivedand stays in the score. (#4369)- New built-in plugins: gulp, n8n, unplugin-icons, vite-plugin-pages, SolidStart and dumi. The gulp, n8n, vite-plugin-pages, SolidStart and dumi plugins mark the files that their tool loads as entry points. These files and their imports are no longer unused files. The n8n plugin also credits the members that n8n reads from an
INodeTypeorICredentialTypeclass. With the unplugin-icons plugin, a~icons/...import is no longer an unlisted dependency. The import also credits the icon set packages. (#4393, #4394) fallow coverage upload-inventory --with-callersfinds the entry routes of Elysia and TanStack Router projects. Fallow does not upload a route whose path or prefix is not a string literal. (#4358)
Changed
- The warning for a config glob that matches fewer files since 3.34.0 names the files and gives two fixes. It names up to 3 lost files and tells you how to keep the one-level meaning, for example
{name1,name2}in place of*. ForentryanddynamicallyLoaded, a lost file that another entry source declares does not count. (#4345) fallow mutationis faster on Vitest projects. An endless loop through a mutant now stops at a CPU-time loop budget, without a restart of the test process. The Vitest adapter keeps one worker process for many mutant runs when the dry run shows that this gives the same results. On three public Vitest libraries, the CPU time of a full run decreased by a factor of 1.6 to 3.0, and no verdict changed. A mutant that only makes a test slow can now gettimeoutin place ofkilledorsurvived. (#4353, #4354, #4359, #4362)arithmetic-operatorskips*,/and%with a string or template operand, as it already did for+and-. (#4372)
Bug fixes
-
fallow dead-codecredits more class members. Fallow now credits a member in these cases:- on a method chain with arguments on a typed parameter;
- on the return value of an inherited method in a class that is not exported;
- on an element of an array that a function returns;
- on the result of an awaited async static factory;
- on an element of a typed array field;
- on a Playwright page object that a fixture reaches through a property.
-
fallow dead-codegives fewer false member credits. The element class of afor...ofloop variable applies only in the loop body. A nested function with its ownthisno longer credits members throughthis. (#4355) -
Plugin entry points apply again in a monorepo with 200 or more workspaces. Before, the plugin glob set did not compile at that size, and
fallow dead-codereported test files, pages and config files as unused. (#4387) -
An import into the unbuilt output folder of a workspace package resolves to the source file. This covers deep imports such as
lib/dist/utiland a packagemainin a customoutDir. (#4398) -
A wildcard
exportstarget in build output maps to its source files. With"./*": "./dist/*.js", the files undersrc/are no longer unused files. Workspace entry point paths also no longer keep a./segment. (#4388) -
A test runner or a bundler in the root
package.jsonactivates its plugin in a workspace when a script of that workspace calls its binary. (#4390) -
React Router route files that an imported module declares are entry points. The plugin follows spreads, imports and re-exports from
routes.ts, and it escapes brackets such as[workspaceSlug]in a route path. (#4392) -
fallow auditkeeps acss-duplicate-blockfinding inherited when only the lines of a later occurrence move. Thanks @Smrtnyk for the report. (#4348) -
fallow health --csskeeps a.scssor.lessfile with an absoluteurl()incss_analytics. Before, the//ofurl(//cdn.example.com/a.png)read as a line comment. Thanks @rezamuliawijaya for the fix. (#4340) -
Columns are correct with a byte order mark or non-ASCII text. The LSP, the duplication detector, extraction and
fallow mutation inspectnow handle a UTF-8 byte order mark the same way. The LSP now also shows diagnostics for an open file with a byte order mark. A Glimmer argument that only a<template>block reads now counts as used in such a file. Clonestart_colandend_colare now byte columns. A tool that reads them as character columns must change. (#4376, #4377, #4395, #4396) -
The LSP offers the remove-export quick fix for a name with a combining mark. (#4375)
-
SARIF region columns count UTF-16 code units. Before, on a line with non-ASCII text before a finding, a code scanning view showed the finding too far to the right. The fingerprints keep the byte column, so existing alerts keep their identity. JSON column fields do not change. (#4417)
-
The changed-code scope of
fallow mutationdetects renamed and copied files. When Git detects the source of a copy, only the edited lines of the copy get mutants. A diff that you supply keeps its literal meaning. (#4416) -
fallow mutationkeeps the scope of a diff that you supply. When the paths of an explicit patch do not match the project, the CLI now exits with code 2 before any test runs. Before, it used a generated Git diff in its place. (#4420) -
CodeClimate clone fingerprints no longer change with CRLF line endings. A project with CRLF files gets new fingerprints one time, and they then match an LF checkout. (#4381)
-
A warm run keeps its cache hits when the extraction cache is near its size limit. (#4389)
-
Crafted TOML, CSS, TypeScript, JSX and MDX files can no longer crash or hang fallow. Fallow now rejects or skips input past a nesting cap before it parses the file. Real code stays well below the caps. (#4360, #4361, #4365)
-
fallow mutationreports duplicate test IDs and selects more tests. It reports tests that share a test ID. It selects a test that asserts only on the output of a Node child process. It suggests--concurrency 1when a restarted test process fails in a parallel phase.return-valuenow mutates a concise arrow body that is a call. A branch or operand constant no longer gives an equivalent mutant through!. (#4350, #4356, #4385, #4404) -
fallow cloud loginstates the owner rule once when a member approves the code. The API keys links offallow cloud loginandfallow cloud logoutfollow the cloud that the login uses. (#4411)
Upgrade notes
- Clone
start_colandend_colin JSON output are now byte columns. (#4395) - A project with CRLF files gets new CodeClimate clone fingerprints one time. (#4381)
- A mutant at the start of an expression statement gets a new
replacementandmutant_id. Review a verdict for its old id again. (#4385) - A tool that reads
completion.reasonsof a mutation report must acceptsampled-out. (#4373)
Full Changelog: v3.41.0...v3.42.0