dormstern
segspec
Go

Static analysis from configs → Kubernetes NetworkPolicies in seconds

Last updated May 6, 2026
15
Stars
0
Forks
0
Issues
0
Stars/day
Attention Score
24
Language breakdown
No language data available.
Files click to expand
README

segspec

Catch unauthorized network changes in PR review, before they hit prod. Static analysis of app configs -- no agents, no runtime, no observation period.

Go License: MIT Build Status


A service quietly grows a new dependency. Memcached gets added, RabbitMQ gets removed, an env var points somewhere it shouldn't. None of it shows up cleanly in a 500-line YAML PR review. By the time it's in prod, the NetworkPolicy is already wrong.

segspec reads the configs you've already written -- Spring, Docker Compose, Kubernetes, Helm, .env, Maven/Gradle -- extracts every network dependency, and traces each one to the exact config line that declared it. Run it on a baseline JSON in CI with --exit-code and your pipeline fails the moment a service's network surface changes. Reviewers see intent, not noise.

Gate PRs on Network Changes

Diff demo

segspec diff baseline.json ./your-app
Network Dependency Changes
==========================

ADDED (2): + your-app → memcached:11211/TCP [medium] Evidence: MEMCACHED_HOST=memcached:11211 + memcached → memcached:11211/TCP [high] Evidence: ports: 11211:11211

REMOVED (1): - your-app → rabbitmq:5672/TCP [high] Was in: src/main/resources/application.yml

UNCHANGED: 13 dependencies

In CI, add --exit-code and the job fails on any change. The output names exactly what moved and the config line that caused it.

Why This Exists

Every other tool in this lane wants to deploy an agent, watch your traffic for thirty days, and ship the inferred policy off to a control plane. That's a fine answer if you have the budget for a $40k+ runtime platform and the appetite for an observation period. Most teams don't.

segspec takes the opposite stance. It reads what you've already declared in source. It doesn't ask for an agent. It doesn't demand an observation window. It doesn't send your config off-box. It runs as a single static Go binary on a developer laptop or a CI runner, fully offline, and every dependency it reports is anchored to a specific file:line in your repo. If it's not in source, segspec doesn't claim it.

That makes it compatible with air-gapped clusters, regulated environments, and CI gates -- places runtime tooling can't go.

What's Underneath: The Analyze Output

segspec analyze https://github.com/getsentry/self-hosted --format evidence

411 dependencies from Sentry's 70+ services in 11ms. Each one linked to the config line that created it.

Evidence demo

The diff above is just analyze run twice, structurally compared. The evidence trail is what makes the diff trustworthy.

Output Formats

| Format | Flag | Use For | |--------|------|---------| | Summary | (default) | Eyeballing a service's deps | | Evidence | --format evidence | Security review, audit trail | | Audit ledger | --format audit | Auditor sign-off attached to a change ticket | | Default-deny scaffold | --format default-deny | One-shot deny-by-default + explicit allow policies | | JSON | --format json | Diff baseline, CMDB, scripting | | NetworkPolicy | --format netpol | Single app policy | | Per-service NetPol | --format per-service | One policy per service, ingress + egress (recommended) |

Default-deny scaffold

--format default-deny emits a namespace-scoped default-deny NetworkPolicy (podSelector: {} with empty Ingress and Egress rules) followed by every per-service allow policy needed to override it for declared dependencies — in one multi-document YAML, deterministically ordered (default-deny first, then services alphabetical). This satisfies the auditor demand documented in cilium/cilium#43502 ("cluster auditors want every component to have a targeted NetworkPolicy") in a single command. If a namespace can be inferred from FQDNs in the input, the default-deny policy carries it; otherwise the cluster admin fills it on apply. Free tier.

segspec analyze ./services/orders --format default-deny > netpol.yaml

Audit ledger

--format audit emits a Markdown document scoped to the way cluster auditors actually review network changes. Each workload gets its own section with separated Ingress and Egress tables, every row is anchored to a file:line (secrets redacted), and confidence levels are re-labelled as approve / review / investigate so a reviewer can sweep the document top-to-bottom and tick boxes. A short SHA-256 fingerprint over the dependency keys lets two ledgers be compared at a glance without diffing the whole file. The output ends with a sign-off checklist (one NetworkPolicy per workload, low-confidence rows confirmed, no rogue external egress) suitable for pasting into a change-management ticket.

segspec analyze ./services/orders --format audit > orders-audit.md

JSON example:

{
  "service": "your-app",
  "dependencies": [
    {
      "source": "your-app",
      "target": "postgres-primary",
      "port": 5432,
      "protocol": "TCP",
      "confidence": "high",
      "source_file": "src/main/resources/application.yml",
      "evidence_line": "spring.datasource.url: jdbc:postgresql://postgres-primary:5432/myapp"
    }
  ]
}

Example: per-service NetworkPolicy YAML

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: frontend-netpol
  labels:
    generated-by: segspec
spec:
  podSelector:
    matchLabels:
      app: frontend
  policyTypes:
    - Ingress
    - Egress
  egress:
    - to:
        - podSelector:
            matchLabels:
              app: cartservice
      ports:
        - port: 8080
          protocol: TCP
    - to:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: kube-system
      ports:
        - port: 53
          protocol: UDP
        - port: 53
          protocol: TCP

apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: cartservice-netpol labels: generated-by: segspec spec: podSelector: matchLabels: app: cartservice policyTypes: - Ingress - Egress ingress: - from: - podSelector: matchLabels: app: frontend ports: - port: 8080 protocol: TCP egress: - to: - podSelector: matchLabels: app: redis ports: - port: 6379 protocol: TCP

kubectl apply -f policies.yaml

Or commit to your GitOps repo and let ArgoCD/Flux handle it.

Install

go install github.com/dormstern/segspec@latest

Or grab the binary:

curl -fsSL https://github.com/dormstern/segspec/releases/latest/download/segspec-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m) -o /usr/local/bin/segspec
chmod +x /usr/local/bin/segspec

Try it now

No repo to point it at? Two demo corpora ship inside the binary:

segspec analyze --demo sentry-mini

--demo list shows every available fixture. The corpora are license-clean and fit in ~15 KB total — they exist so you can see segspec's output on a realistic dependency graph without cloning anything.

Usage

# Scan a local directory or GitHub URL
segspec analyze ./your-app
segspec analyze https://github.com/org/repo

Show evidence -- the exact config line behind each dependency

segspec analyze ./your-app --format evidence

Generate per-service NetworkPolicies (ingress + egress)

segspec analyze ./your-app --format per-service

JSON output for scripting or as a diff baseline

segspec analyze ./your-app --format json -o baseline.json

Diff against a baseline -- use --exit-code in CI to block on changes

segspec diff baseline.json ./your-app --exit-code

CI Integration

Gate PRs on network changes

# .github/workflows/netpol-diff.yml
name: Network Policy Drift
on: [pull_request]

jobs: check: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Check for network dependency changes run: | curl -fsSL https://github.com/dormstern/segspec/releases/latest/download/segspec-linux-amd64 -o segspec chmod +x segspec ./segspec diff deps-baseline.json . --exit-code

Exit code 1 means something changed. The diff output shows exactly what and the config line that caused it.

Auto-generate policies on merge

# .github/workflows/netpol.yml
name: Network Policies
on:
  push:
    branches: [main]

jobs: generate: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Generate Network Policies run: | curl -fsSL https://github.com/dormstern/segspec/releases/latest/download/segspec-linux-amd64 -o segspec chmod +x segspec ./segspec analyze . --format per-service > k8s/network-policies.yaml - name: Commit policy run: | git add k8s/network-policies.yaml git diff --cached --quiet || git commit -m "update network policies [segspec]"

Interactive Mode

Review every dependency before committing to a policy:

segspec analyze ./your-app --interactive --format per-service
segspec: 34 dependencies found (34 selected)

> [x] frontend -> cartservice:8080/TCP [high] K8s Service [x] frontend -> productcatalog:3550/TCP [high] K8s Service [ ] frontend -> adservice:9555/TCP [med] AI [x] cartservice -> redis-cart:6379/TCP [high] Spring ...

up/down navigate SPACE toggle a all n none ENTER generate q quit

Toggle with space, press Enter to generate from only what you've approved.

Supported Config Families

Spring Boot (application.yml/.properties), Docker Compose, Kubernetes (Deployments/Services/ConfigMaps), Helm charts (auto-rendered via helm template), .env files, and Maven/Gradle build files. Each parser extracts declared hosts, ports, protocols, and env-var references and links them back to source.

Helm is auto-detected. Pass --helm-values values-prod.yaml for custom values. If the helm CLI isn't available, segspec skips charts with a warning and continues.

AI-Enhanced Analysis (Optional)

segspec analyze ./your-app --ai             # auto-detect (tries local first)
segspec analyze ./your-app --ai local       # fully offline via Ollama + NuExtract
segspec analyze ./your-app --ai cloud       # via Gemini Flash (free tier)

Local runs NuExtract (3.8B, MIT license) via Ollama. Nothing leaves your machine. Cloud uses Gemini Flash (1,000 free requests/day, set GEMINIAPIKEY). AI-discovered dependencies are marked medium confidence so you know to verify them.

CLI Reference

segspec analyze <path> [flags]

<path> Local directory or GitHub URL

-f, --format string summary, netpol, per-service, all, evidence, json (default "summary") -o, --output string Write output to file -i, --interactive Review dependencies before generating --ai [string] AI: local (Ollama), cloud (Gemini), or auto-detect --helm-values string Helm values file

segspec diff <baseline.json> <path> [flags]

<baseline.json> JSON from segspec analyze --format json <path> Directory or GitHub URL to compare against

--exit-code Exit 1 if changes detected (for CI)

Roadmap

  • GitHub Action -- uses: dormstern/segspec-action@v1
  • AWS Security Groups, Cilium, Calico output formats
  • Terraform security group generation

Author

Built by Dor Morgenstern — ex-product lead at Orchid Security and Torq, building and shipping network and security products for over a decade.

Contributing

Contributions welcome. Open an issue first for anything non-trivial. PRs should include tests.

License

MIT

🔗 More in this category

© 2026 GitRepoTrend · dormstern/segspec · Updated daily from GitHub