{"id":50933155,"url":"https://github.com/frozenprocess/telepathy","last_synced_at":"2026-06-17T06:30:37.527Z","repository":{"id":363211680,"uuid":"1262359759","full_name":"frozenprocess/telepathy","owner":"frozenprocess","description":"A Network policy simulator.","archived":false,"fork":false,"pushed_at":"2026-06-07T22:44:05.000Z","size":304,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-08T00:17:53.185Z","etag":null,"topics":["kubernetes","kubernetes-security","networkpolicy","simulator"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/frozenprocess.png","metadata":{"files":{"readme":"README.MD","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-07T22:43:31.000Z","updated_at":"2026-06-07T22:54:02.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/frozenprocess/telepathy","commit_stats":null,"previous_names":["frozenprocess/telepathy"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/frozenprocess/telepathy","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/frozenprocess%2Ftelepathy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/frozenprocess%2Ftelepathy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/frozenprocess%2Ftelepathy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/frozenprocess%2Ftelepathy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/frozenprocess","download_url":"https://codeload.github.com/frozenprocess/telepathy/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/frozenprocess%2Ftelepathy/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34437448,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-17T02:00:05.408Z","response_time":127,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["kubernetes","kubernetes-security","networkpolicy","simulator"],"created_at":"2026-06-17T06:30:36.481Z","updated_at":"2026-06-17T06:30:37.517Z","avatar_url":"https://github.com/frozenprocess.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cimg src=\"assets/telepathy.jpg\" align=\"right\" width=\"300\"\u003e\n\n# Telepathy\n\n**Know what a NetworkPolicy does before you merge it — no cluster required.**\n\nTelepathy evaluates Kubernetes \u0026 Calico NetworkPolicies by running [Calico](https://github.com/projectcalico)'s **own policy engine** against a topology. In milliseconds, with no Kubernetes, no CNI, and no nodes, it tells you which pod can talk to which.\n\nBecause it reuses Felix's (Brain of Calico) real code instead of re-implementing policy semantics, the verdict matches what your cluster would actually enforce, Telepathy can even show you the **iptables/nftables chains, eBPF programs, and Windows HNS ACLs** Felix would program for the same policy.\n\n\u003e You changed a NetworkPolicy. Did you just lock yourself out of the database? Did you just open the attacker pod's path to it? Find out in CI, on the PR — not at 2am.\n\n---\n\n## What it's for\n\n- **Test your policies** like code — assert `frontend → backend = allow`, `attacker → backend = deny`, and fail the build when an assertion breaks.\n- **See the blast radius of a PR** — a base-vs-PR connectivity diff, posted as a comment, showing every flow the change *opened* or *closed*.\n- **Inspect the dataplane** — render the actual iptables/nftables/eBPF/HNS rules a policy compiles to, without a cluster.\n\n## Quick start\n\n```bash\nmake build          # clones the pinned Calico tree, builds bin/telepathy\nmake test           # evaluate the sample topology + policy -\u003e connectivity matrix\nmake verify         # run the sample assertions (the CI gate)\nmake diff-demo      # diff a base policy vs a PR that loosens it\n```\n\nThe engine is a stdin → stdout filter: a topology Request goes in, a JSON connectivity matrix comes out.\n\n```bash\n./bin/telepathy -policy testdata/sample-policy.yaml \u003c testdata/sample-topology.yaml\n```\n```json\n{ \"matrix\": {\n    \"demo/frontend-\u003edemo/backend\": \"allow\",\n    \"demo/attacker-\u003edemo/backend\": \"deny\"\n} }\n```\n\n## The three modes\n\n### 1. `evaluate` (default) — the connectivity matrix\nProbe every ordered pod pair at a port/protocol. A pair is `allow` only if it clears **both** the source's egress and the destination's ingress — exactly how a real packet has to pass.\n\n### 2. `test` — assertions as a CI gate\nWrite expectations next to your policies and let Telepathy enforce them. Exit code is non-zero when any assertion fails.\n\n```yaml\n# telepathy.tests.yaml\nassertions:\n  - name: frontend may reach backend\n    from: demo/frontend\n    to:   demo/backend\n    expect: allow\n  - name: attacker must not reach backend\n    from: demo/attacker\n    to:   demo/backend\n    expect: deny      # port/protocol optional — inherit the probe\n```\n```bash\ntelepathy test -assert telepathy.tests.yaml -policy ./policies \u003c topology.yaml\n# PASS  frontend may reach backend  (demo/frontend -\u003e demo/backend)  expect=allow got=allow\n# PASS  attacker must not reach backend  (demo/attacker -\u003e demo/backend)  expect=deny got=deny\n# 2 passed, 0 failed\n```\n\n### 3. `diff` — what did this change open or close?\nEvaluate the matrix on two revisions (one per git checkout) and report only what moved:\n\n```bash\ntelepathy -policy ./policies \u003c topology.yaml \u003e base.json   # on the base branch\ntelepathy -policy ./policies \u003c topology.yaml \u003e head.json   # on the PR branch\ntelepathy diff -format markdown base.json head.json\n```\n\nrenders the PR comment:\n\n\u003e ## 🔮 Telepathy — NetworkPolicy impact\n\u003e **1 flow(s) changed** — 🟠 1 opened\n\u003e\n\u003e | Change | Flow | Before | After |\n\u003e |---|---|---|---|\n\u003e | 🟠 opened | `demo/attacker` → `demo/backend` | deny | **allow** |\n\n`opened` (deny→allow) is a new exposure; `closed` (allow→deny) is a possible outage. Use `-format json` for machine output, or `-exit-code` to fail on any change.\n\n## Use it in CI/CD\n\nA GitHub Action wraps both gates. On every PR it runs your assertions **and** posts the base-vs-PR connectivity diff as a sticky comment:\n\n```yaml\n# .github/workflows/networkpolicy.yml\non: pull_request\npermissions:\n  contents: read\n  pull-requests: write\njobs:\n  telepathy:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n        with: { fetch-depth: 0 }   # the diff needs git history\n      - uses: frozenprocess/telepathy@v1\n        with:\n          topology: path/to/topology.yaml\n          policy: path/to/policies/         # file or directory\n          assertions: path/to/telepathy.tests.yaml\n```\n\nSee [`examples/github-actions.yml`](examples/github-actions.yml) for all inputs. The engine is a single static binary in a `scratch` image, so any CI that runs a container (GitLab, Tekton, Argo, Jenkins) can call it the same way:\n\n```bash\ndocker run --rm -i ghcr.io/frozenprocess/telepathy:latest \\\n  test -assert /w/telepathy.tests.yaml -policy /w/policies \u003c /w/topology.yaml\n```\n\n## Inspect the dataplane\n\nThe same Request renders the rules Felix would actually program — a unique window into what your policy *compiles to*:\n\n```bash\ntelepathy iptables -policy p.yaml \u003c topology.yaml   # iptables / nftables chains\ntelepathy bpf      -policy p.yaml \u003c topology.yaml   # annotated eBPF policy program\ntelepathy hns      -policy p.yaml \u003c topology.yaml   # Windows HNS ACL rules\n```\n\n## Input format\n\nA Request is a topology (`endpoints`, `namespaces`) plus a probe (`port`, `protocol`); policies are layered in from stdin or via `-policy` (a file or a directory of manifests). Kubernetes `networking.k8s.io/v1` NetworkPolicies and Calico `projectcalico.org/v3` (Global)NetworkPolicy, Tier, NetworkSet, HostEndpoint, Service/ServiceAccount selectors, and more are supported. See [`testdata/`](testdata/) for a minimal end-to-end example.\n\n```yaml\nnamespaces:\n  - { name: demo, labels: { kubernetes.io/metadata.name: demo } }\nendpoints:\n  - { id: demo/frontend, namespace: demo, name: frontend, ip: 10.0.0.1, labels: { app: frontend } }\n  - { id: demo/backend,  namespace: demo, name: backend,  ip: 10.0.0.2, labels: { app: backend } }\n  - { id: demo/attacker, namespace: demo, name: attacker, ip: 10.0.0.3, labels: { app: attacker } }\nport: 8080\nprotocol: tcp\n```\n\n## How it works\n\nTelepathy is pluggable across CNIs. The vendor-neutral request/response schema lives in the small [`api`](api/) module, and each CNI's policy engine sits behind the `Provider` interface in [`provider`](provider/), selected at runtime with `-provider` (default `calico`; `telepathy version` lists the registered providers). Both drive the CNI's own code offline — no cluster.\n\nCrucially, **each CNI engine builds as its own binary from its own Go module**, so their dependency graphs never have to reconcile (Calico and Antrea pin incompatible versions of `network-policy-api`, `controller-runtime`, etc. — linking them into one binary is impossible without version hacks). The neutral `api` JSON contract is the boundary between them:\n\n- **`calico`** ([`provider/calico`](provider/calico/)) is linked into the main `telepathy` binary (built over `third_party/calico`): it builds a Felix `CalculationGraph` from your topology + policies, walks each ordered pair through `app-policy/checker.Evaluate` for both egress and ingress, and can render the iptables/nftables/eBPF/HNS dataplane Felix would program.\n- **`antrea`** is a separate binary, `telepathy-engine-antrea` ([`engines/antrea`](engines/antrea/), built over `third_party/antrea` with Antrea's native dependency versions). The shell dispatches `-provider antrea` to it over the JSON contract (Request on stdin → Response on stdout). It drives Antrea's real `grouping.GroupEntityIndex` to resolve pod/namespace selectors, then applies Kubernetes NetworkPolicy semantics over the resolved members. A cross-process test asserts it agrees with the Calico engine flow-for-flow.\n\n`make build` produces both binaries side by side; the shell finds the engine next to itself (override with `TELEPATHY_ANTREA_ENGINE`).\n\n### Legal Notice\n\nThe Telepathy card image used above is unofficial Fan Content permitted under the Fan Content Policy. It is not approved or endorsed by Wizards of the Coast. Portions of the materials used are the property of Wizards of the Coast. ©Wizards of the Coast LLC.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffrozenprocess%2Ftelepathy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffrozenprocess%2Ftelepathy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffrozenprocess%2Ftelepathy/lists"}