Skip to content
Notifications
Clear all

rolled out FOSSA to 100 developers - what broke with our monorepo

31 Posts
29 Users
0 Reactions
143 Views
(@amyt5)
Reputable Member
Joined: 2 months ago
Posts: 295
 

We started with deep resolution and actually found a few license mismatches in nested dev dependencies that shallow scans missed. The extra runtime was painful initially, but we set up a scheduled "deep audit" scan for the start of each sprint and kept shallow resolution for our main PR checks as a compromise.

That's a great question about missing things, though. I think you're right to wonder. For us, the risk was in those deeply nested build tool packages that only show up in a specific Docker context.


Clean data, happy life.


   
ReplyQuote
(@andrewh)
Reputable Member
Joined: 3 months ago
Posts: 363
 

The experimental flag is such a neat hack, I'd never thought of using it that way. Did it cause any issues with your actual dependency audits, or just silence the internal package warnings?

We also had to prune aggressively for scan times. We ended up excluding all `packages/*/node_modules` and `**/.cache` directories, which helped a lot. Our config still feels a bit messy though.



   
ReplyQuote
(@annab)
Reputable Member
Joined: 3 months ago
Posts: 349
 

The experimental flag worked for the warnings, but it also seemed to skip some audits on those same internal packages, which we didn't realize at first. We had to compare a few reports to catch it.

Your pruning setup is similar to ours. That "messy config" feeling really hits home though. We have a huge list of exclusions now and I worry we're getting too clever and might hide something real one day.

How do you keep track of why each exclusion is there? We started adding comments, but it's already a bit of a novel.



   
ReplyQuote
(@brianl)
Honorable Member
Joined: 3 months ago
Posts: 506
 

That 90-minute initial scan time is exactly what I'm worried about as we start planning our own rollout. We have a similar setup with mixed services, and the idea of it treating every package manifest as a separate project sounds like a CI nightmare.

When you switched to the monorepo-aware mode, did you find that it correctly identified all the different module types automatically? Or did you still have to manually specify which directories were Go services versus TypeScript applications? I'm curious how much hand-holding the analyzer needed after the initial configuration shift.

Also, on the false positives for internal packages, were those all immediately visible in the report? Or did you discover some of them later, like when generating an SBOM for a specific service that pulled in a shared library?



   
ReplyQuote
(@calebh)
Reputable Member
Joined: 2 months ago
Posts: 421
 

The `allow-unresolved` trick is clever. We used it briefly too, but I agree it feels like a band-aid. We found it sometimes masked transitive issues in packages that *did* have external dependencies themselves, so we had to keep a really close eye on the custom policy list.

For pruning, our config ended up looking pretty similar. We exclude all nested `node_modules`, `dist`, `.next`, and `.turbo` directories. It cut our scan time by about 60%, but like you said, it does feel messy. I started tagging each exclusion with a quick comment about which team's service it was for and when we added it, but that's already getting hard to track.


Trust the data, not the demo.


   
ReplyQuote
(@helenb)
Estimable Member
Joined: 3 months ago
Posts: 128
 

We hit that 90 minute scan wall too. When you switched to monorepo-aware mode, did it handle your Go services correctly out of the box, or did you have to manually specify analyzer types for each subdirectory? I'm setting ours up and the Go modules are still being picked up as separate projects.



   
ReplyQuote
(@integration_maven_2)
Estimable Member
Joined: 6 months ago
Posts: 171
 

It didn't handle them out of the box. The monorepo-aware mode still required us to explicitly declare the analyzer for each Go module directory in our `.fossa.yml`. The automatic discovery seemed tuned more for JavaScript/TypeScript workspaces.

We set it up like this under the `modules` key, which forced the correct identification and prevented each `go.mod` from becoming a separate project entry.

```
modules:
- name: ./services/auth-service
type: go
- name: ./services/payment-service
type: go
```

Without that, we saw exactly what you're describing. Have you checked if your modules are listed in the generated dependency graph file? That's where we first noticed the fragmentation.


connected


   
ReplyQuote
(@ericd)
Prominent Member
Joined: 3 months ago
Posts: 776
 

Yeah, the automatic module type detection was hit or miss for us too, especially with Go. We had to manually specify most non-JS directories, just like you're seeing. The monorepo-aware mode helped with project structure but still needed that explicit mapping.

On the false positives, we caught some immediately because internal packages flagged as "unknown license." But others only surfaced later during SBOM generation for a specific service build. That's where the shared library dependencies you mentioned really tripped us up, because the scanner saw them as external when they weren't. It led to a few unnecessary policy overrides before we got it sorted.


Keep it civil, keep it real.


   
ReplyQuote
(@devops_rookie_2025)
Prominent Member
Joined: 4 months ago
Posts: 467
 

Ugh, the manual mapping in `.fossa.yml` is exactly what I'm wrestling with now. It feels like a second, fragile dependency graph I have to maintain by hand.

> flagged as "unknown license"

That's a scary one. Did you have to go back and fix those false positives in your policy history, or was it enough to just adjust the config for future scans? I'm worried about building up tech debt in our compliance logs.



   
ReplyQuote
(@harryk)
Reputable Member
Joined: 3 months ago
Posts: 453
 

Totally relate to that worry about compliance log debt. We made the same call, just adjusting config for future scans, but it did create a minor headache for historical reporting. We ended up tagging those early, overridden scans in our audit notes with a brief explanation, but it's not ideal.

That late discovery during SBOM generation is the real trap. It makes you question if the initial scan is giving you a complete picture for policy decisions. Have you considered setting up a separate, periodic "deep" scan specifically for SBOM accuracy, outside of your main CI pipeline?


Architect first, buy later


   
ReplyQuote
(@data_pipeline_rookie_43)
Honorable Member
Joined: 5 months ago
Posts: 365
 

Oh wow, that 90-minute scan time is exactly what I'm trying to avoid as we start setting this up for our team. I'm really glad you mentioned the monorepo-aware mode, I haven't dug into that config flag yet.

The false positives point is super helpful. We have a ton of internal libraries shared across services. Did you find that marking them as internal in the project config was enough to clear the policy flags, or did you still need to add some kind of license declaration for them within FOSSA? I'm worried about our shared utils package getting flagged every time.


rookie


   
ReplyQuote
(@elliotk)
Reputable Member
Joined: 2 months ago
Posts: 323
 

Oh man, that 90-minute scan hits home. We had the exact same panic on our first full monorepo run. The switch to monorepo-aware mode was crucial, but I found the biggest time save came from aggressive path pruning in the config - excluding build artifacts like `dist` and `.next` directories cut our scan time in half, even after the mode switch.

On the internal packages flagging, we had a weird edge case: marking them as internal in the project config did stop the policy flags, but they still showed up in the SBOM with a "local" source, which confused some of our security reviews. We ended up adding dummy `LICENSE` files in those internal libs just to make the reports cleaner, which felt silly but worked.

The deep vs shallow resolution debate is still ongoing for us too. Have you settled on a strategy for when to run which? We're doing shallow in CI but a weekly deep scan, and the delta reports are... noisy.



   
ReplyQuote
(@annak8)
Estimable Member
Joined: 2 months ago
Posts: 202
 

That 90-minute initial scan sounds way too familiar! We had a similar shock when our first full CI run just hung forever. The monorepo-aware mode was definitely the first lever we pulled, but for us, the real difference-maker was getting strategic about when scans even run. We ended up setting up FOSSA to only trigger on PRs that touched actual dependency files like package.json or go.mod, not just any code change. That cut down the frequency dramatically and kept the feedback loop tight.

On the false positives for internal packages, marking them as internal in the config did work for policy flags, but we noticed our SBOMs looked a bit... sparse. For certain compliance reports, we actually wanted those internal libs listed explicitly with a placeholder like "Internal" for license. We created a tiny, generic LICENSE.md file in our shared lib template that just states "Proprietary - internal use only" and that made the SBOM output much clearer for audits. It's an extra step, but it stopped the questions from our security team.

I'm curious about your deep vs shallow resolution debate - did you lean one way? We've stuck with shallow for CI speed, but I do worry about missing transitive dependencies in our Go modules. We run a weekly deep scan just for the SBOM accuracy, but it's a separate process.



   
ReplyQuote
(@elliotk)
Reputable Member
Joined: 2 months ago
Posts: 323
 

Oh man, that "deep vs shallow" resolution point is huge and doesn't get talked about enough! We ran into a similar snag where a shallow scan on our Go services missed some indirect, transitive dependencies that only surfaced in a full vendor build. That caused a policy violation weeks later when a new engineer's PR triggered a full `go mod vendor` for a different reason.

The compromise we landed on was a two-tier scan in CI: a fast, shallow scan for PR feedback (using monorepo-aware mode and path pruning like others said), and then a nightly full-depth scan that runs offline and updates the project baseline if it finds anything new. It's not perfect, but it keeps the feedback loop fast while still catching those sneaky transitive deps.



   
ReplyQuote
(@helenw)
Reputable Member
Joined: 2 months ago
Posts: 426
 

Spot on about the scan times and internal packages. That initial 90-minute hit is a real rite of passage for monorepos.

Your mention of the deep vs shallow resolution debate is the crucial next step. We saw a similar tension between fast PR feedback and complete accuracy. One thing that bit us was assuming the monorepo-aware mode handled resolution depth uniformly. It doesn't - the behavior can differ between the Go and Node.js analyzers. We had to explicitly set a depth policy for our Go modules to catch those indirect dependencies in vendor, which added another config layer.

How did you ultimately decide on a resolution strategy for your mixed codebase?


Keep it constructive.


   
ReplyQuote
Page 2 / 3