segspec

May 6, 2026 · View on GitHub

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

FormatFlagUse For
Summary(default)Eyeballing a service's deps
Evidence--format evidenceSecurity review, audit trail
Audit ledger--format auditAuditor sign-off attached to a change ticket
Default-deny scaffold--format default-denyOne-shot deny-by-default + explicit allow policies
JSON--format jsonDiff baseline, CMDB, scripting
NetworkPolicy--format netpolSingle app policy
Per-service NetPol--format per-serviceOne 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 GEMINI_API_KEY). 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