MINDER BLOG SERIES ( PART - 1)

Why I Chose Minder Over Everything Else
While exploring different aspects of the LFX ecosystem, I came across OpenSSF and honestly, it caught my attention.
I found it interesting that OpenSSF isn't just a single project, but an umbrella with several projects focused on improving the security of the open-source ecosystem. Even more interesting was the fact that many of these projects are closely connected to real-world software security and supply chain problems.
That immediately made me curious.
I have been building a few personal projects around security over the past few months, so somewhere along the way, I had already come across the name Minder. I couldn't remember exactly where I had heard about it, but when I started exploring OpenSSF projects more seriously, I decided to finally understand what Minder actually does.
And that's when it clicked.
Minder helps development teams and open-source communities build more secure software and provide evidence that the software they've built follows security best practices.
That idea was particularly interesting to me.
Why did Minder stand out?
For me, it wasn't just about security.
What made Minder interesting was the combination of security + backend engineering + DevSecOps.
The project has a Go codebase, and since I already have an interest in backend engineering and working with Go-based systems, contributing to Minder would give me an opportunity to work on a real production oriented codebase.
Instead of only learning security concepts theoretically, I could actually see how those concepts are implemented in software.
Things like:
How security policies are represented
How evaluations are performed
How APIs and backend services are structured
How integrations work
How security findings move through the system
How all of this fits into a larger software supply chain workflow
That was much more interesting to me than simply building another project from scratch.
And it also naturally takes me in the direction I want to explore more deeply: DevSecOps.
Building my own projects vs. contributing to Minder
For the past few months, I had mostly been learning by building my own personal projects.
That has taught me a lot.
When you're building something yourself, you control everything the architecture, the technologies, the abstractions, and even the problems you're trying to solve.
But there's another kind of learning that happens when you enter an existing production codebase.
You don't get to design everything from scratch.
You have to understand why things are already designed the way they are.
You have to read code written by people you've never met, understand existing abstractions, follow execution paths, understand tests, work with conventions, and eventually make changes without breaking what already exists.
For me, that felt like a much more valuable next step.
I wanted to move from:
“I can build my own system.”
to:
“I can understand, navigate, and contribute to someone else's production system.”
And that's a very different skill.
But there was one more question
Finding an interesting project isn't enough.
I wanted to know whether I would actually enjoy contributing to it.
So I discussed Minder with one of my friends and asked him whether he thought it would be a good project for me to pursue.
He gave me two very simple questions to answer.
1. Are the people in the community helpful?
I started exploring the community and its Slack discussions.
And the answer was yes.
I found people actively helping each other, answering questions, discussing implementation details, and being approachable specially the maintainers.
That mattered to me because when you're entering an unfamiliar codebase, the community is almost as important as the code itself.
You can read documentation for hours, but sometimes one good answer from someone who already understands the system can save you an entire day.
More importantly, interacting with maintainers and contributors is itself part of learning open source.
2. Do you actually enjoy the architecture?
This question was even more important.
My friend basically told me:
If you don't enjoy understanding how the project works, you're probably not going to enjoy contributing to it for a long time.
So I started reading the official documentation.
I went through the architecture, the different components, the concepts behind Minder, and how the pieces fit together.
And I genuinely enjoyed it.
I wasn't reading it just because I wanted to find an issue to solve.
I actually wanted to understand how the system worked.
That was probably the biggest signal for me.
The community was helpful.
The architecture was interesting.
The technology stack aligned with what I wanted to learn.
And the problem space was directly connected to security and DevSecOps.
So my friend's conclusion was pretty simple:
If both answers are yes, then go with it.
And I decided to.
From reading to actually contributing
At that point, I didn't want to keep exploring Minder only from the outside.
I wanted to see the real thing.
So I set up Minder locally and started going through the codebase.
This was the point where the journey became much more interesting.
I wanted to use the project as an opportunity to take the things I already knew especially Go, backend development, Git, and DevOps and apply them to a real production codebase while filling the gaps along the way.
That became my approach:
Don't wait until you know everything. Understand enough to make a meaningful change, then learn from the codebase, the tests, the reviews, and the people around you.
My First Serious Contribution
I didn't immediately look for the biggest or most impressive issue.I started looking for something that would force me to understand an actual part of the system.
That's how I ended up looking at the REST datasource handler.
While going through the code, I found something interesting:
// TODO: Handle fallback here.
There were already fallback and expected_status fields defined in the protobuf/API definition, but the REST datasource handler wasn't actually using them.
That immediately gave me a concrete question:
If the API already supports configuring fallbacks, what is supposed to happen when the upstream REST service returns an unexpected status code?
I traced the existing request flow before writing any code.
The important part of the flow looked roughly like:
REST DataSource Definition
↓
Handler creation
↓
HTTP request
↓
Upstream response
↓
Check status code
↓
┌──────┴────────┐
│ │
Expected Unexpected
status status
│ │
↓ ↓
Parse body Check fallback
│
┌─────┴─────┐
│ │
Match No match
│ │
↓ ↓
Return fallback Existing
behavior
The more I understood the existing behavior, the more important one constraint became:
Don't break existing datasources.
If a datasource doesn't configure a fallback, the implementation shouldn't suddenly change how it behaves.
So instead of redesigning the response handling, I tried to make the smallest change that wired the existing configuration into the handler.
What I Actually Changed
The implementation had three main pieces.
1. Wire the existing configuration into the handler
The restHandler previously didn't retain the fallback or expected-status configuration.
I added those fields and populated them when constructing the handler:
fallback []*minderv1.RestDataSource_Def_Fallback
expectedStatus []int32
and then:
fallback: def.GetFallback(),
expectedStatus: def.GetExpectedStatus(),
This sounds small, but it was an important part of understanding how configuration flows through Minder.
The values already existed at the API/protobuf level. The missing piece was carrying them into the runtime handler where they could actually affect behavior.
2. Determine whether the response status is expected
I added a small helper:
func (h *restHandler) isExpectedStatus(statusCode int) bool
The behavior is intentionally simple:
If
expected_statusisn't configured,200 OKis treated as the expected status.If it is configured, the response is considered expected when its status code appears in that list.
That means a datasource can explicitly say that statuses such as 200 and 202 are valid responses.
3. Match an unexpected response against a fallback
If the upstream response has an unexpected status code, the handler checks whether a fallback has been configured for that exact status.
For example:
Upstream → 404
↓
Is 404 expected?
↓
No
↓
Is 404 configured
as a fallback?
↙ ↘
Yes No
↓ ↓
Return fallback Keep existing
response behavior
If a matching fallback exists, Minder returns the configured fallback body and status instead of the real upstream response.
If there isn't a matching fallback, the existing behavior remains unchanged.
That last part was important to me.
I wasn't trying to introduce a new error handling model into the REST datasource. I was implementing the missing fallback behavior while preserving the behavior that existing users already depended on.
Testing the Change
I didn't want to stop at testing the helper functions.
The behavior happens as part of an HTTP request, so I wanted to test it through the actual Call() path as well.
I added table-driven tests covering cases such as:
expected_statusnot configured →200is acceptedexpected_statusnot configured → non200is unexpectedExplicit
expected_statuslist matchesExplicit list rejects an unlisted status
Matching fallback is returned
No fallback is configured
Unexpected status with no matching fallback keeps the existing behavior
Expected status bypasses fallback handling
For the end-to-end-ish handler tests, I used Go's httptest.NewServer to simulate the upstream REST service.
That gave me a setup like:
httptest.Server
↓
mock HTTP response
↓
restHandler.Call()
↓
fallback handling
↓
assertion
I also ran the relevant existing REST datasource tests to make sure the change didn't introduce regressions.
The implementation was formatted with gofmt, and the relevant golangci lint checks passed as well.
What This Contribution Taught Me
The actual code change wasn't enormous.
But the learning was much bigger than the diff.
This was my first experience of taking a partially implemented feature in an unfamiliar production codebase and figuring out:
Where the configuration originates.
How it gets propagated into the runtime.
Where the actual behavior needs to change.
What the existing behavior is.
What behavior must remain unchanged.
How to test both the isolated logic and the real execution path.
How to communicate the design decision during review.
And then came the part that I think is one of the most important differences between personal projects and open source:
Code review.
I didn't just write the code and move on.
A maintainer reviewed the PR and questioned an important behavioral decision: what should happen when an unexpected status has no matching fallback?
That forced me to go back to the related issue and confirm the intended behavior rather than simply assuming my interpretation was correct.
That was a valuable lesson.
In a personal project, I can decide what the behavior should be.
In an established open source project, the code has to fit the project's existing contract and design decisions.
And that's exactly the kind of engineering experience I was hoping to get from contributing to Minder.
