I could not make sense of this work without research. After three years at CERN, back in Bilbao I decided to work on my own and keep researching and learning. I believe entrepreneurship is the ultimate professional challenge — and, at the same time, an expression of creativity and a claim to freedom.
Zetesis comes from the Greek ζήτησις, inquiry: find the cause before proposing the solution.
A full environment for every pull request — deleted automatically
LabGitOpsKubernetesDevOps
Reviewing a pull request by reading the diff works for the logic and not much else. If the change touches a migration, a Helm template or the behavior of a screen, approving it is an act of faith.
The alternative is for every pull request to spin up its own complete environment, and for it to be deleted automatically when it's closed.
What exactly gets spun up
In the homelab, when a PR carries the preview label, ArgoCD's Pull Request Generator detects it in under a minute and creates the entire environment.
Resource
What the PR gets
Namespace
Its own, with the PR number
Database
Its own PostgreSQL, via CNPG
Search
Its own Typesense instance
Secrets
Its own, from Infisical
Domain
Its own subdomain
Everything with its own name: nothing is shared with staging.
The list isn't what matters — what matters is that it shares nothing with staging. A destructive migration in a preview breaks that preview and nothing else.
The two halves meet at the SHA
The setup is two pieces that never talk to each other: GitHub Actions builds the images and ArgoCD deploys the manifests. Nobody calls anybody. What keeps them aligned is that both use the pull request's commit as the identifier.
On the GitHub side
The workflow listens for PR events —opened, updated, reopened, labeled and closed— and only acts if it carries the preview label. It builds the four services in parallel and tags each image with the PR number and the SHA of its head:
The matrix runs without canceling its siblings when one fails. That's not an oversight: the public registry's storage returns intermittent certificate errors, and with cancellation enabled a transient failure in one service would take down the build of the other three.
On the ArgoCD side
Here there is no webhook. A pull request generator asks GitHub every sixty seconds for PRs carrying that label:
Manifest and image come from the same commit without either side knowing the other. Pushing another commit to the PR changes the SHA, and with it both the tag the workflow builds and the revision ArgoCD deploys change at once.
Lifecycle management and activation
When the pull request closes, teardown happens on both sides: ArgoCD deletes the applications —and with them the entire namespace, with its database and its secrets— because the generator stops seeing it, and a final workflow job deletes that PR's images from Harbor. No orphaned environments and no registry growing with images nobody will ever download again.
An ephemeral environment that doesn't clean itself up stops being ephemeral and becomes a cluster full of garbage. Cleanup is automatic when the PR closes, and the portal also has a twenty-four-hour cap.
The label matters too: a preview only spins up if the PR carries it. Without that, every documentation change would drag a database along with it.
When it's not worth it
The cost isn't CPU: it's that you need the platform underneath. Without GitOps, without external secrets and without a database that knows how to provision itself, building per-PR previews means building those three things first.
If you already have them, it's one of the cheapest things you can add. If you don't, the correct order is the reverse.