A browser-based tool for visualizing Calico and Kubernetes network policies. Import YAML, see an interactive graph, highlighted source, and plain-English explanation. Everything runs client-side.
Try it now — a live version is available at https://sbulav.github.io/calico-visualiser/
Cilium has the free Network Policy Editor for Kubernetes network policies. Calico does not. Its visualization tools are in the paid Cloud and Enterprise versions.
This project is a free alternative. Load your Calico or Kubernetes NetworkPolicy YAML. Get a graph of rules by traffic scope. See a text breakdown of what the policy allows or blocks.
- Three panels: YAML editor, graph visualization, explanation text. They sync on hover and selection.
- YAML editor: Editable CodeMirror editor with syntax highlighting. Edit the YAML directly and the graph and explanation update live (debounced at 400 ms). While the YAML is mid-edit and temporarily invalid, the last valid visualization stays on screen and an error banner shows the parse issue. Hover a rule in the graph to highlight the matching YAML lines and scroll to them.
- Graph: React Flow canvas. Central policy node connects to six rule categories (three for ingress, three for egress). Edges show action colors: green for Allow, red for Deny, amber for Log or mixed.
- Rule groups: Outside Cluster (CIDRs), In Namespace (pod selectors), In Cluster (cross-namespace). Each has rule cards with ports, selectors, services, and negation fields.
- Inferred access: Graph shows if Kubernetes DNS, any pod in namespace, or everything in cluster is allowed, denied, or uncertain. Defaults start as deny but catch-all rules override.
- Explanation: Bottom panel with policy details, flag descriptions (doNotTrack, preDNAT, applyOnForward), effective defaults, and per-rule text. Recognizes 20 well-known ports like Redis (6379), K8s API (6443), PostgreSQL (5432).
- Supported resources:
- Calico
projectcalico.org/v3:NetworkPolicy,GlobalNetworkPolicy(full existing support) - Kubernetes
networking.k8s.io/v1:NetworkPolicy(pod/namespace selectors,ipBlockwithexcept, named ports,endPort, policyTypes defaults)
- Calico
- Samples: Built-in examples for both Calico and Kubernetes NetworkPolicy.
- Privacy: No backend. No data sent anywhere.
docker run --rm -p 8080:8080 ghcr.io/sbulav/calico-policy-visualiser:latestOpen http://localhost:8080. The image serves the static SPA with Nginx and exposes a /health endpoint for container and Kubernetes probes.
To build locally:
docker build -t calico-policy-visualiser .The Dockerfile supports private base-image mirrors without changing the file:
docker build \
--build-arg NODE_IMAGE=your-registry/node:22-alpine \
--build-arg NGINX_IMAGE=your-registry/nginx:1.27-alpine \
-t calico-policy-visualiser .kubectl apply -f deploy/kubernetes/calico-policy-visualiser.yamlThe example creates a Deployment and ClusterIP Service on port 80. Copy deploy/kubernetes/ingress.example.yaml if you want to expose it through an ingress controller.
nix develop
make init # npm install
make dev # http://localhost:5173Node.js 22 or later.
npm install
npm run dev # http://localhost:5173Load a sample or import YAML. Hover rules in the graph. Read the explanation.
Click Import YAML in the toolbar and pick a .yaml or .yml file with:
- Calico
NetworkPolicy/GlobalNetworkPolicy(projectcalico.org/v3), or - Kubernetes
NetworkPolicy(networking.k8s.io/v1)
Or use one of the sample buttons to load a built-in example. You can also type or paste YAML directly into the editor — the visualization updates as you type.
In the graph:
- Drag nodes to rearrange.
- Zoom with mouse wheel or on-screen controls.
- Hover rule cards to highlight the corresponding YAML lines.
Resize panels by dragging the divider handles. Collapse the explanation panel with its toggle.
Example: load the NetworkPolicy sample. One ingress rule appears in the "In Cluster" group. The edge is green (Allow). The explanation panel shows "[ALLOW] incoming TCP to port 6379 (Redis)".
The app can auto-load a policy from the URL. This is useful for integrating with other tools (e.g., a Kubernetes policy viewer) so users can click a link and land here with the policy already loaded.
Supported parameters (query string or hash):
?url=— fetch YAML from a remote URL (recommended for real policies)?policy=— inline YAML (useful for short examples)?policy=lz:— inline LZ-String compressed YAML (recommended for longer inline policies)#policy=— same as?policy=, but in the hash fragment
Examples (GitHub Pages):
https://sbulav.github.io/calico-visualiser/?url=https%3A%2F%2Fexample.com%2Fpolicies%2Fdefault-deny.yaml
https://sbulav.github.io/calico-visualiser/?policy=apiVersion%3Aprojectcalico.org%2Fv3%0Akind%3ANetworkPolicy%0A...
https://sbulav.github.io/calico-visualiser/?policy=lz:N4Igzg9gTgpgBAHjAJgQwE4EsBOBLAOwA0IAnAsQG4C2ARhAHoB8c8A===
https://sbulav.github.io/calico-visualiser/#policy=apiVersion%3Aprojectcalico.org%2Fv3%0Akind%3ANetworkPolicy%0A...
https://sbulav.github.io/calico-visualiser/#policy=lz:N4Igzg9gTgpgBAHjAJgQwE4EsBOBLAOwA0IAnAsQG4C2ARhAHoB8c8A===
Notes:
?url=requires the remote server to allow cross-origin requests (CORS).- Inline
?policy=is limited by URL length. To avoid proxy and browser limits, treat ~2 KB total URL as a safe ceiling and prefer?url=for larger policies. ?policy=lz:is compressed and more space-efficient, but still subject to URL length limits.
Encoding example (JS):
import { compressToEncodedURIComponent } from 'lz-string';
const param = `lz:${compressToEncodedURIComponent(yaml)}`;
const url = `https://sbulav.github.io/calico-visualiser/?policy=${param}`;The GitHub Actions workflow in .github/workflows/container.yml validates the app with lint, test, and build, then publishes an OCI image to GitHub Container Registry on default-branch and v* tag pushes. Pull requests build the image but do not push it.
Published tags include branch names, sha-<shortsha>, semantic versions from tags like v0.9.2, and latest from the default branch.
Set repository variables NODE_IMAGE and NGINX_IMAGE if CI should build from private base-image mirrors.
| Command | What it does |
|---|---|
npm run dev |
Vite dev server with hot reload |
npm run build |
Type-check and production build to dist/ |
npm run test |
Run Vitest tests |
npm run test:watch |
Tests in watch mode |
npm run lint |
ESLint check |
npm run preview |
Serve built app locally |
npx tsc --noEmit |
Type-check only |
make targets mirror these (e.g., make test, make build, make lint). Run make help for the full list.
src/
main.tsx Entry point
App.tsx Root (PolicyProvider + layout)
index.css Tailwind v4, CSS variables, overrides
context/ React Context + useReducer state
hooks/ Reusable React hooks (debounce, etc.)
types/ Calico and graph type definitions
lib/
formatPort.ts Shared port formatting
ipUtils.ts IP/CIDR helpers
parser/ YAML parsing and validation
transform/ Policy to React Flow nodes and edges
explain/ Policy to human-readable text
matcher/ Selector parsing, rule matching, access testing
components/
Layout/ App shell, resizable panels
Editor/ CodeMirror YAML editor (editable, with live parsing)
Visualization/ React Flow canvas, custom nodes, edges
Explanation/ Bottom explanation panel
AccessTester/ Interactive access testing panel
samples/ Built-in YAML examples
- React 19, TypeScript 5.9, Vite 7
- React Flow (@xyflow/react) for the graph
- CodeMirror 6 (@uiw/react-codemirror) for YAML
- Tailwind CSS 4, dark theme with Slate palette
- js-yaml for parsing
- Vitest 4 for tests
- State: React Context + useReducer (no external state library)
Strict TypeScript with verbatimModuleSyntax, noUnusedLocals, noUnusedParameters, and strictNullChecks.
329 tests across nine files.
| File | Tests | Covers |
|---|---|---|
yamlParser.test.ts |
63 | Parsing, validation, Calico + Kubernetes fields |
yamlLineMapper.test.ts |
9 | Line ranges for editor highlighting |
policyToGraph.test.ts |
85 | Rule groups, edges, inferred statuses, defaults |
policyExplainer.test.ts |
47 | Text sections, port names, rule descriptions |
selectorParser.test.ts |
37 | Calico selector expression parsing and evaluation |
ruleMatcher.test.ts |
37 | Rule matching against traffic specifications |
accessTester.test.ts |
18 | End-to-end access verdict evaluation |
k8sSelector.test.ts |
10 | Kubernetes label selector normalization |
ipUtils.test.ts |
23 | CIDR containment, private range coverage, port/CIDR validation |
npm run test # all tests
npx vitest run src/lib/parser/yamlParser.test.ts # single fileMIT. See LICENSE. Author: Sergei Bulavintsev.