Whatβs the Blast Radius? Automating Impact Analysis in Multi-Repo CI/CD
One of the hardest problems in a large, multi-repository environment isnβt necessarily deploying software. Itβs understanding what else might break when you change something shared.
Imagine an organization with dozens of repositories, shared npm packages, internally maintained Docker images, reusable Terraform modules, and independent CI/CD pipelines managed by multiple engineering teams.
A developer changes a shared Terraform module. The pull request passes all tests. The repository builds successfully. The PR looks entirely safe.
But three other repositories consume that module. One is pinned to an older version. Another expects a slightly different source reference. A third repository isnβt even owned by the same team.
The real question becomes: What is the blast radius of this change?
To explore and solve this problem, I built two open-source GitHub Actions: blast-radius-indexer and blast-radius-check. Together, they build a dependency graph and use it to perform automated impact analysis directly during pull requests.
The Problem with Repository-Local CI
Most CI pipelines are excellent at answering one specific question: "Is this repository healthy?"
They reliably run unit tests, security scans, Terraform validations, and linting checks. But repository-local CI doesnβt necessarily answer a much more critical question for distributed systems:
"Which other repositories depend on what I just changed?"
This distinction becomes increasingly important as organizations move toward loosely coupled, multi-repository architectures. A shared package or infrastructure module effectively becomes an API between repositories. Changing the producer can therefore break consumers that are entirely invisible to the producerβs CI pipeline.
The Solution: A Two-Part Architecture
To solve this efficiently, the solution is intentionally split into two distinct components: an Indexer for organization-wide discovery, and a Checker for lightweight PR-time analysis.
βββββββββββββββββββββββββββββ
β Organization Repos β
βββββββββββββββ¬ββββββββββββββ
β
βΌ
βββββββββββββββββββββββ
β Blast Radius β
β Indexer β
ββββββββββββ¬βββββββββββ
β
βΌ
dependency
graph.json
β
βΌ
βββββββββββββββββββββββ
β Blast Radius Check β
β GitHub Action β
ββββββββββββ¬βββββββββββ
β
Pull Request
β
βΌ
βββββββββββββββββββββββ
β Impact Analysis β
β PR Comment / Gate β
βββββββββββββββββββββββ
This separation is deliberate. Organization-wide indexing can require hundreds of API operations. Doing that on every single PR would be unnecessarily expensive and slow. Instead, the index is refreshed periodically (e.g., nightly) and reused by fast, lightweight pull-request checks.
Component 1: Blast Radius Indexer
The first component, the Blast Radius Indexer, is the dependency discovery engine. It scans your repositories and builds a cross-repository dependency graph, mapping out publishers, artifacts, consumers, and version requirements.
Currently, it understands three artifact types:
π¦ npm packages
It identifies packages published by repositories and maps consumers by parsing package.json files (checking dependencies, devDependencies, peerDependencies, etc.). Private packages are explicitly separated from published packages to prevent false publisher relationships.
π³ Docker images
It maps dependencies discovered from Dockerfiles (e.g., FROM acme/platform-base:2.4). The indexer smartly normalizes equivalent Docker references while keeping different registries distinct (e.g., it knows docker.io/acme/platform and acme/platform are the same, but ghcr.io and quay.io are different).
ποΈ Terraform modules
It connects Terraform dependencies discovered from module blocks:
module "network" {
source = "github.com/acme/network"
}
The indexer normalizes common Git-based Terraform source formats, allowing different representations of the same repository to be properly connected.
The Output: graph.json
The result is a reusable dependency intelligence layer output as a JSON file:
{
"artifacts": {
"npm:@acme/core-ui": {
"type": "npm",
"name": "@acme/core-ui",
"publisherRepo": "acme/core-ui-lib",
"consumers": [
{
"repo": "acme/user-portal",
"sourceFile": "package.json",
"versionRequirement": "^2.0.0"
}
]
}
}
}
Component 2: Blast Radius Check
The second component, the Blast Radius Check, consumes that graph. It runs directly against a pull request with a deliberately narrow job: Compare the files modified by the PR with the shared artifacts declared in the dependency graph.
The analysis follows four simple steps:
- Identify files modified by the PR.
- Find shared artifacts declared by those files.
- Query the graph for repositories consuming those artifacts.
- Render the downstream impact.
If a PR modifies a library, the Action immediately generates an impact matrix right in the pull request:
| Downstream repository | Artifact | Consumer file | Version |
|---|---|---|---|
auth-service |
@acme/core-ui |
package.json |
~2.1.0 |
user-portal |
@acme/core-ui |
package.json |
^2.0.0 |
Turning Impact Analysis into a Merge Gate
Visibility is useful, but automation is better. Because the checker exposes actionable outputs (has-impact, affected-repo-count, etc.), you can build powerful workflows around it.
- uses: mchittineni/blast-radius-check@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
graph-path: .graph/graph.json
fail-on-impact: 'true'
A team can make this check a required status gate, or even use the output to automatically trigger downstream integration tests in the consuming repositories. This turns dependency discovery from static documentation into an active, protective part of your CI/CD pipeline.
Design Philosophy
Building this required establishing some deliberate boundaries:
- Zero-SaaS Architecture: There is no external dependency database or hosted SaaS platform required. The graph can be committed to a repository (even a private one) and consumed entirely within GitHub Actions.
-
Declaration-Level Analysis: The checker reacts to changes in files that declare shared artifacts (like
package.jsonor root-level Terraform files). It doesn't attempt to guess if a deep source code change is semantically breakingβit leaves semantic compatibility decisions to the engineering workflow. - Stale over Speculative: The graph represents the last indexing run. Dependencies generated dynamically by build systems are hard to track, so the indexer favors explicit, explainable relationships rather than speculative guesses.
Why This Matters for Platform Engineering
This project sits at an interesting intersection of Platform Engineering, DevOps, CI/CD, and Developer Experience.
One of the primary goals of platform engineering is giving development teams safer paths to production without adding unnecessary bureaucratic process. Instead of asking developers to manually search dozens of repositories before modifying a shared component, the platform surfaces the likely downstream impact automatically.
The ideal workflow:
Developer opens PR β Platform detects shared artifact change β Graph identifies consumers β PR displays impact matrix β Team makes an informed decision to proceed, update consumers, or run downstream validation.
The long-term idea is bigger than just a GitHub Action. Itβs about creating a lightweight dependency intelligence layer for multi-repository engineering environments.
Try it out
Both projects are open source and MIT licensed. I'd love for you to try them out:
π₯ Blast Radius Indexer: github.com/mchittineni/blast-radius-indexer
π Blast Radius Check: github.com/mchittineni/blast-radius-check
If youβre working with multiple repositories, shared infrastructure modules, internal packages, or platform components, Iβd be interested in hearing how you currently handle cross-repository impact analysis.
Does your CI already know the blast radius of a change? Let me know in the comments!
#devops #platformengineering #githubactions #devsecops #terraform #docker #npm #cicd #softwareengineering #sre #opensource
Top comments (0)