Skip to content
Notifications
Clear all

How do I exclude test directories in a monorepo?

4 Posts
4 Users
0 Reactions
2 Views
(@crm_hopper_2025)
Reputable Member
Joined: 2 months ago
Posts: 144
Topic starter   [#22384]

Alright folks, crm_hopper_2025 here. I'm deep in another one of my infamous platform migrations—this time it's our entire dev and marketing stack into a monorepo. You can imagine the fun. While I'm usually ranting about data mapping between Salesforce and HubSpot, today my headache is Semgrep. I've come to love it for catching the low-hanging fruit in our code, but my current setup is giving me grief.

We've got a typical monorepo structure: multiple packages and apps, each with their own `tests/`, `__tests__/`, `spec/`, and `*.test.*` files. When I run a broad Semgrep scan from the repo root, it's, understandably, lighting up like a Christmas tree in all those test directories. I don't want to ignore security findings in our actual source code, but I also don't want a thousand alerts about mocks, fixtures, and test-specific code that will never hit production.

I've been tinkering with the `.semgrepignore` file, and it *sorta* works, but paths in a monorepo feel tricky. If I just put `tests/`, it seems to only match at the very root. I need this to apply recursively for every package.

Could someone review my current approach and tell me the most efficient way to exclude all test directories, no matter how deep in the monorepo structure they are? Here's what I'm trying:

```
# .semgrepignore
**/tests/
**/__tests__/
**/*.test.js
**/*.spec.js
**/test_*.py
```

My questions:
* Is the double asterisk pattern the right way to go for a monorepo?
* Should I be combining this with the `--exclude` CLI flag for better control, or is the ignore file sufficient?
* Are there any gotchas with pattern matching, especially for different languages (we have JS/TS, Python, Go)?
* How do you all handle this in your CI pipelines? Do you run scans twice—once on `/src` and once on `/tests` with different rule sets?

I'm hoping to get this config solid so I can stop the alert fatigue and focus on the real issues. As always, I'm deep in the trenches of another "migration," this time just for our code scanning tooling 😅. Any war stories or proven patterns would be hugely appreciated.

Hopefully last migration.



   
Quote
(@charlie99)
Trusted Member
Joined: 2 weeks ago
Posts: 48
 

Oh, the monorepo path problem with tools like Semgrep is a classic! Been there with linters and other scanners.

Your hunch is right about `tests/` only matching at the root. The trick is using wildcards. In your `.semgrepignore`, you want patterns that account for directories at any depth. Try something like this:

```
**/tests/
**/__tests__/
**/spec/
**/*.test.*
**/*.spec.*
```

The double asterisk (`**`) is the key - it means "match in any subdirectory, recursively." This should catch `packages/some-lib/tests/` and `apps/webapp/__tests__/` alike.

One caveat though: if you *do* have any test files in your actual source code directories that you want scanned (unlikely, but possible), this will skip them too. But for standard test folder isolation, this pattern works great.

Let us know if that cuts down the noise!


Data nerd out


   
ReplyQuote
(@emilyk4)
Estimable Member
Joined: 2 weeks ago
Posts: 76
 

That's exactly the kind of path headache that makes me hesitate to set up tools at the monorepo level. Your example of the double asterisk pattern is super helpful for visualizing it.

I'm curious, though, does Semgrep also have a flag or setting to exclude these patterns from the command line? Sometimes I get nervous editing config files if I'm just testing something quickly.



   
ReplyQuote
(@ellej)
Trusted Member
Joined: 2 weeks ago
Posts: 59
 

Yeah, the `--exclude` CLI flag is what you're looking for. It takes the same patterns as the `.semgrepignore` file.

So for a quick test, you'd run something like:
`semgrep scan --exclude '**/tests/' --exclude '**/__tests__/' .`

But honestly, if you're doing this more than once, just commit the ignore file. The command gets unwieldy fast, and you'll forget a pattern. The config file is less scary once it's in version control.



   
ReplyQuote