{"id":32109094,"url":"https://github.com/fetch-kit/chaos-proxy-go","last_synced_at":"2026-05-29T03:04:45.862Z","repository":{"id":345387631,"uuid":"1072583598","full_name":"fetch-kit/chaos-proxy-go","owner":"fetch-kit","description":"Golang port of chaos-proxy","archived":false,"fork":false,"pushed_at":"2026-03-19T02:15:26.000Z","size":44,"stargazers_count":21,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-19T10:56:29.941Z","etag":null,"topics":["chaos-testing","go","golang","reliability","testing"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fetch-kit.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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":"2025-10-08T23:43:25.000Z","updated_at":"2026-03-19T02:14:54.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/fetch-kit/chaos-proxy-go","commit_stats":null,"previous_names":["fetch-kit/chaos-proxy-go"],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/fetch-kit/chaos-proxy-go","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fetch-kit%2Fchaos-proxy-go","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fetch-kit%2Fchaos-proxy-go/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fetch-kit%2Fchaos-proxy-go/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fetch-kit%2Fchaos-proxy-go/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fetch-kit","download_url":"https://codeload.github.com/fetch-kit/chaos-proxy-go/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fetch-kit%2Fchaos-proxy-go/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33634615,"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-05-29T02:00:06.066Z","response_time":107,"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":["chaos-testing","go","golang","reliability","testing"],"created_at":"2025-10-20T12:01:29.332Z","updated_at":"2026-05-29T03:04:45.857Z","avatar_url":"https://github.com/fetch-kit.png","language":"Go","funding_links":[],"categories":["Go"],"sub_categories":[],"readme":"[![Build](https://github.com/fetch-kit/chaos-proxy-go/actions/workflows/ci.yml/badge.svg)](https://github.com/fetch-kit/chaos-proxy-go/actions)\n[![GitHub stars](https://img.shields.io/github/stars/fetch-kit/chaos-proxy-go?style=social)](https://github.com/fetch-kit/chaos-proxy-go)\n\n# chaos-proxy-go\n\n**chaos-proxy-go** is a Go port of [fetch-kit/chaos-proxy](https://github.com/fetch-kit/chaos-proxy): a proxy server for injecting configurable network chaos (latency, failures, connection drops, rate-limiting, etc.) into any HTTP or HTTPS traffic. Use it via CLI or programmatically to apply ordered middleware (global and per-route) and forward requests to your target server, preserving method, path, headers, query, and body.\n\n---\n\n## Quick Start\n\n1. Download from [GitHub Releases](https://github.com/fetch-kit/chaos-proxy-go/releases) or build from source:\n\n   ```sh\n   go build -o chaos-proxy-go .\n   ```\n\n2. Create a minimal `chaos.yaml`:\n\n   ```yaml\n   target: \"http://localhost:4000\"\n   port: 5000\n   global:\n     - failRandomly:\n         rate: 0.1\n         status: 503\n   ```\n\n3. Run the proxy:\n\n   ```sh\n   ./chaos-proxy-go --config chaos.yaml --verbose\n   ```\n\nAll traffic to `http://localhost:5000` is now forwarded to `http://localhost:4000` with 10% random 503 failures injected.\n\n---\n\n## Documentation\n\n- [Middleware reference](docs/middlewares.md) — all 11 built-in primitives with config tables\n- [Observability](docs/observability.md) — OpenTelemetry tracing, span attributes, connecting to a collector\n- [Hot reload](docs/hot-reload.md) — runtime config reload, endpoint spec, edge cases\n\n---\n\n## Presets\n\nReady-made scenarios in the [`presets/`](presets/) folder:\n\n| Preset | Simulates |\n|--------|-----------|\n| [`flaky-backend.yaml`](presets/flaky-backend.yaml) | Unstable upstream: latency jitter, 5% 503s, 2% connection drops |\n| [`mobile-3g.yaml`](presets/mobile-3g.yaml) | Mobile 3G: 100–300ms latency, 50 KB/s bandwidth, 1% drops |\n| [`burst-errors.yaml`](presets/burst-errors.yaml) | Error bursts: every 5th fails with 500, plus 10% random 503s |\n| [`timeout-storm.yaml`](presets/timeout-storm.yaml) | Timeout storm: 1–8s delays, 10% drops, 15% instant 504s |\n\nRun a preset directly:\n\n```sh\n./chaos-proxy-go --config presets/flaky-backend.yaml\n```\n\n---\n\n## Features\n\n- Simple configuration via a single `chaos.yaml` file\n- Programmatic API and CLI usage\n- Built-in middleware primitives: latency, latencyRange, fail, failRandomly, failNth, dropConnection, rateLimit, cors, throttle, headerTransform, bodyTransformJSON\n- Extensible registry for custom middleware\n- Supports both request and response interception/modification\n- Method+path route support (e.g., `GET /api/users`)\n- Robust short-circuiting: middlewares halt further processing when sending a response or dropping a connection\n- Runtime config reload via `POST /reload` without process restart\n\n---\n\n## Installation\n\nDownload the latest release from [GitHub Releases](https://github.com/fetch-kit/chaos-proxy-go/releases) or build from source:\n\n```sh\ngo build -o chaos-proxy-go .\n```\n\nRequires Go 1.21 or later.\n\n---\n\n## Usage\n\n### CLI\n\n```sh\n./chaos-proxy-go --config chaos.yaml [--verbose]\n```\n- `--config \u003cpath\u003e`: YAML config file (default `./chaos.yaml`)\n- `--verbose`: print loaded config, middleware setup, and per-request logs\n\n### Programmatic API\n\n```go\nimport (\n\t\"log\"\n\n\t\"chaos-proxy-go/internal/config\"\n\t\"chaos-proxy-go/internal/proxy\"\n)\n\ncfg, err := config.Load(\"chaos.yaml\")\nif err != nil {\n\tlog.Fatalf(\"failed to load config: %v\", err)\n}\nserver, err := proxy.New(cfg, false)\nif err != nil {\n\tlog.Fatalf(\"failed to create server: %v\", err)\n}\nif err := server.Start(); err != nil {\n\tlog.Fatalf(\"server error: %v\", err)\n}\n```\n\n---\n\n## Runtime Config Reload\n\nChaos Proxy supports full runtime reloads without process restart.\n\n- Endpoint: `POST /reload`\n- Content-Type: `application/json`\n- Payload: full config snapshot (same shape as `chaos.yaml`, but JSON)\n- Behavior: build-then-swap — all-or-nothing, the active state is never partially updated\n- Body size limit: 1 MB\n\n### Request Example\n\n```sh\ncurl -X POST http://localhost:5000/reload \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"target\": \"http://localhost:4000\",\n    \"port\": 5000,\n    \"global\": [\n      { \"latency\": { \"ms\": 120 } },\n      { \"failRandomly\": { \"rate\": 0.05, \"status\": 503 } }\n    ],\n    \"routes\": {\n      \"GET /users/:id\": [\n        { \"failNth\": { \"n\": 3, \"status\": 500 } }\n      ]\n    }\n  }'\n```\n\n### Success Response\n\n```json\n{\n  \"ok\": true,\n  \"version\": 2,\n  \"reload_ms\": 3\n}\n```\n\n### Failure Responses\n\n| Status | Reason |\n|--------|--------|\n| `400` | Invalid or unparseable config (active state is unchanged) |\n| `409` | Reload already in progress |\n| `415` | Wrong `Content-Type` (must be `application/json`) |\n\n```json\n{\n  \"ok\": false,\n  \"error\": \"target is required\",\n  \"version\": 1,\n  \"reload_ms\": 0\n}\n```\n\n### Programmatic Reload\n\n`proxy.New(...)` returns a `*Server` with a `ReloadConfig` method:\n\n```go\nresult := server.ReloadConfig(newCfg)\nif !result.OK {\n    log.Printf(\"reload failed: %s\", result.Error)\n} else {\n    log.Printf(\"reloaded to version %d in %dms\", result.Version, result.ReloadMs)\n}\n```\n\n### Edge-Case Semantics\n\n- **In-flight requests** are deterministic: they run on the snapshot captured at the moment the request arrived, immune to concurrent reloads.\n- **New requests** after a successful swap immediately use the new snapshot.\n- **All-or-nothing**: if parse, validate, or middleware-build fails, the active state is unchanged.\n- **Middleware state resets** on reload (e.g., rate-limit and failNth counters start fresh).\n- **Concurrent reloads** are rejected with `409`; the second caller must retry.\n\n---\n\n## Configuration (`chaos.yaml`)\n\n```yaml\ntarget: \"http://localhost:4000\"  # required\nport: 5000                       # default: 5000\n\n# Optional: OpenTelemetry tracing\notel:\n  serviceName: \"my-service\"      # required if otel is set\n  endpoint: \"http://localhost:4318\" # required if otel is set\n  flushIntervalMs: 5000          # default\n  maxBatchSize: 100              # default\n  maxQueueSize: 1000             # default\n  headers:                       # optional OTLP request headers\n    x-api-key: \"secret\"\n\n# Global middleware — applied to every proxied request\nglobal:\n  - latencyRange:\n      minMs: 20\n      maxMs: 100\n  - failRandomly:\n      rate: 0.05\n      status: 503\n\n# Route-specific middleware — \"METHOD /path\" format\nroutes:\n  GET /api/users:\n    - latency:\n        ms: 500\n  POST /api/orders:\n    - failNth:\n        n: 3\n        status: 500\n```\n\nSee [docs/middlewares.md](docs/middlewares.md) for the full middleware reference and [docs/observability.md](docs/observability.md) for `otel` options.\n\n---\n\n## Middleware Primitives\n\n- `latency(ms)` — delay every request\n- `latencyRange(minMs, maxMs, seed?)` — random delay (deterministic when `seed` is set)\n- `fail({ status, body })` — always fail\n- `failRandomly({ rate, status, body, seed? })` — fail with probability (deterministic when `seed` is set)\n- `failNth({ n, status, body })` — fail every nth request\n- `dropConnection({ prob, seed? })` — randomly drop connection (`prob` defaults to `1.0` if omitted; deterministic when `seed` is set)\n- `rateLimit({ limit, windowMs, key })` — rate limiting (by header key if configured, otherwise by client remote address in ip:port format)\n- `cors({ origin, methods, headers })` — enable and configure CORS headers\n- `throttle({ rate, chunkSize, burst })` — throttles bandwidth per request (`rate` is bytes/second)\n- `headerTransform({ request: { set, delete }, response: { set, delete } })` — mutate request/response headers\n- `bodyTransformJSON({ request: { set, delete }, response: { set, delete } })` — mutate JSON request/response bodies\n\n---\n\n## Extensibility\n\nRegister custom middleware in Go. See the `internal/middleware` package for examples.\n\n---\n\n## Security \u0026 Limitations\n\n- Proxy forwards all headers; be careful with sensitive tokens.\n- Intended for local/dev/test only.\n- HTTPS pass-through requires TLS termination; not supported out-of-the-box.\n- Not intended for stress testing; connection limits apply.\n- Middleware execution order is nondeterministic when multiple middlewares are in the same YAML map element. For example:\n  ```yaml\n  global:\n    - latency: { ms: 100 }\n      fail: { status: 500 }      # Order vs latency is not guaranteed\n  ```\n  For deterministic order, use separate map elements:\n  ```yaml\n  global:\n    - latency: { ms: 100 }\n    - fail: { status: 500 }      # Always runs after latency\n  ```\n\n---\n\n## License\n\nMIT\n\n---\n\nGo port of [fetch-kit/chaos-proxy](https://github.com/fetch-kit/chaos-proxy).\n\n---\n\n\u003e This is a Go port of [fetch-kit/chaos-proxy](https://github.com/fetch-kit/chaos-proxy).","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffetch-kit%2Fchaos-proxy-go","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffetch-kit%2Fchaos-proxy-go","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffetch-kit%2Fchaos-proxy-go/lists"}