{"id":48533585,"url":"https://github.com/sebdeveloper6952/mtls-sandbox","last_synced_at":"2026-04-08T01:01:09.714Z","repository":{"id":346576210,"uuid":"1188904036","full_name":"sebdeveloper6952/mtls-sandbox","owner":"sebdeveloper6952","description":"Sandbox to test your mTLS integrations.","archived":false,"fork":false,"pushed_at":"2026-03-31T23:35:17.000Z","size":155,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-04-04T07:48:31.806Z","etag":null,"topics":["devtool","mtls","mtls-authentication","mtls-request","sandbox","testing"],"latest_commit_sha":null,"homepage":"https://mtls.apps.sebdev.io","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sebdeveloper6952.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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-03-22T18:32:00.000Z","updated_at":"2026-03-31T23:34:59.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/sebdeveloper6952/mtls-sandbox","commit_stats":null,"previous_names":["sebdeveloper6952/mtls-sandbox"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/sebdeveloper6952/mtls-sandbox","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sebdeveloper6952%2Fmtls-sandbox","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sebdeveloper6952%2Fmtls-sandbox/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sebdeveloper6952%2Fmtls-sandbox/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sebdeveloper6952%2Fmtls-sandbox/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sebdeveloper6952","download_url":"https://codeload.github.com/sebdeveloper6952/mtls-sandbox/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sebdeveloper6952%2Fmtls-sandbox/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31535203,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-07T16:28:08.000Z","status":"ssl_error","status_checked_at":"2026-04-07T16:28:06.951Z","response_time":105,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["devtool","mtls","mtls-authentication","mtls-request","sandbox","testing"],"created_at":"2026-04-08T01:00:37.071Z","updated_at":"2026-04-08T01:01:09.708Z","avatar_url":"https://github.com/sebdeveloper6952.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# mTLS Sandbox\n\nA zero-config Go server that enforces mutual TLS, designed for developers who need to validate their mTLS stack before connecting to a real third party (banks, payment processors, partner APIs). It auto-generates a full PKI (CA, server cert, client cert), starts an HTTPS server requiring client certificates, and gives structured diagnostic feedback on every connection attempt — telling you *why* the handshake failed, not just *that* it failed.\n\n## Why\n\nSetting up mTLS is hard to debug. When your TLS handshake fails against a production endpoint, you get a cryptic error and no way to inspect what went wrong. mTLS Sandbox gives you a local server that behaves like a strict third party but returns structured `InspectionReport`s with failure codes and actionable hints for every connection.\n\n## Public Testing Service\n\n**[mtls.apps.sebdev.io](https://mtls.apps.sebdev.io)** is a hosted instance of mTLS Sandbox. Use it to validate that your server correctly enforces inbound mutual TLS — no installation required.\n\nThe flow: you get a session with a unique client certificate issued by the sandbox CA. You configure your server to trust that CA and require client certificates. The sandbox calls your server and tells you whether the handshake succeeded or failed, and why.\n\n### How it works\n\n```\n  Your server                    mtls.apps.sebdev.io\n      │                                  │\n      │  1. Trust sandbox CA             │\n      │◄────────────────────────────────►│  POST /api/sessions\n      │                                  │  ← session ID + CA cert\n      │  2. Require client certs         │\n      │     from that CA                 │\n      │                                  │\n      │  3. Set your callback URL        │\n      │ ────────────────────────────────►│  PATCH /api/sessions/{id}\n      │                                  │\n      │  4. Sandbox calls you            │\n      │ ◄────────────────────────────────│  POST /api/sessions/{id}/test\n      │     presents session client cert │\n      │                                  │\n      │  5. View result                  │\n      │◄────────────────────────────────►│  GET /api/sessions/{id}/calls\n```\n\n### Step-by-step\n\n**1. Create a session**\n\nOpen [mtls.apps.sebdev.io](https://mtls.apps.sebdev.io) in your browser and click **New Session**, or via curl:\n\n```bash\nSESSION=$(curl -s -X POST https://mtls.apps.sebdev.io/api/sessions)\nSESSION_ID=$(echo \"$SESSION\" | jq -r '.id')\necho \"$SESSION\" | jq -r '.ca_cert_pem' \u003e sandbox-ca.crt\n```\n\nEach session gets a unique client certificate (`cert_cn: session-\u003cid\u003e`) valid for 24 hours.\n\n**2. Configure your server to trust the sandbox CA**\n\nYour server needs to trust `sandbox-ca.crt` for incoming client certificates and require client authentication.\n\nnginx:\n```nginx\nssl_client_certificate /etc/nginx/sandbox-ca.crt;\nssl_verify_client on;\n```\n\nGo:\n```go\ncaPool := x509.NewCertPool()\ncaPool.AppendCertsFromPEM(sandboxCAPEM)\ntlsCfg := \u0026tls.Config{\n    ClientCAs:  caPool,\n    ClientAuth: tls.RequireAndVerifyClientCert,\n}\n```\n\n**3. Set your callback URL**\n\n```bash\ncurl -s -X PATCH https://mtls.apps.sebdev.io/api/sessions/$SESSION_ID \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"callback_url\": \"https://your-server.example.com\"}'\n```\n\nThe callback URL must be `https` and publicly reachable. Private/internal IPs are blocked.\n\n**4. Trigger a test**\n\n```bash\ncurl -s -X POST https://mtls.apps.sebdev.io/api/sessions/$SESSION_ID/test | jq .\n```\n\nThe sandbox makes an outbound HTTPS request to your server using the session's client certificate and returns a full inspection report:\n\n```json\n{\n  \"call_id\": 1,\n  \"test_mode\": \"normal\",\n  \"status_code\": 200,\n  \"duration_ms\": 143,\n  \"inspection\": {\n    \"handshake_ok\": true,\n    \"presented\": { \"cert_chain\": [{\"cn\": \"session-abc123\"}], \"tls_version\": \"TLS 1.3\" }\n  }\n}\n```\n\n**5. Run negative tests**\n\nVerify your server correctly *rejects* connections it shouldn't accept:\n\n```bash\n# No client cert — server should return a TLS handshake error\ncurl -s -X POST https://mtls.apps.sebdev.io/api/sessions/$SESSION_ID/test \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"test_mode\": \"no_cert\"}'\n\n# Client cert from a different, untrusted CA — server should reject\ncurl -s -X POST https://mtls.apps.sebdev.io/api/sessions/$SESSION_ID/test \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"test_mode\": \"wrong_ca\"}'\n```\n\n| `test_mode` | What the sandbox sends | Expected result |\n|---|---|---|\n| `normal` | Session client cert (trusted CA) | Server accepts — HTTP 2xx |\n| `no_cert` | No client certificate | Server rejects — TLS handshake error |\n| `wrong_ca` | Client cert from a different CA | Server rejects — TLS handshake error |\n\n**6. View call history**\n\n```bash\ncurl -s \"https://mtls.apps.sebdev.io/api/sessions/$SESSION_ID/calls\" | jq .\n```\n\nOr open the session page in the dashboard: `https://mtls.apps.sebdev.io/session/\u003cid\u003e`\n\n### Limits\n\n- Sessions expire after **24 hours**\n- Test calls are rate-limited to **10 per 60 seconds** per session\n- Callback URL must be `https` and must not resolve to a private/internal IP\n- No authentication — keep your session ID private\n\n---\n\n## Self-Hosting\n\n### Docker\n\n```bash\ndocker run -d \\\n  -p 8443:8443 \\\n  -p 8080:8080 \\\n  -v $(pwd)/data:/data \\\n  -e MTLS_TLS_PERSIST_PATH=/data/certs \\\n  -e MTLS_SESSION_DB_PATH=/data/sessions.db \\\n  -e MTLS_HOSTNAMES=your-domain.example.com \\\n  ghcr.io/sebdeveloper6952/mtls-sandbox:latest\n```\n\nOn first boot, the CA and server certificates are generated and written to `/data/certs`. They reload automatically on subsequent starts.\n\n### Docker Compose\n\n```bash\ngit clone https://github.com/sebdeveloper6952/mtls-sandbox.git\ncd mtls-sandbox\ndocker compose up\n```\n\nTo use a custom domain, update `MTLS_HOSTNAMES` in `docker-compose.yml`:\n\n```yaml\nenvironment:\n  - MTLS_HOSTNAMES=your-domain.example.com,localhost\n  - MTLS_TLS_PERSIST_PATH=/data/certs\n  - MTLS_SESSION_DB_PATH=/data/sessions.db\n```\n\n### Kubernetes\n\nFor Kubernetes deployments you need:\n- A `Deployment` with `strategy: Recreate` (SQLite doesn't support concurrent writers)\n- A `ReadWriteOnce` PVC mounted at `/data` for certs and the session database\n- Two ingress routes on the same domain: TLS termination on port 443 for the dashboard, and TLS passthrough on port 8443 for the mTLS endpoint (the app manages its own CA)\n\nSet the data paths via env vars:\n\n```yaml\nenv:\n  - name: MTLS_TLS_PERSIST_PATH\n    value: /data/certs\n  - name: MTLS_SESSION_DB_PATH\n    value: /data/sessions.db\n  - name: MTLS_HOSTNAMES\n    value: your-domain.example.com\n```\n\n### Session service configuration\n\n| Variable | Description | Default |\n|---|---|---|\n| `MTLS_SESSION_ENABLED` | Enable the session testing API | `true` |\n| `MTLS_SESSION_DB_PATH` | SQLite database file path | `sessions.db` |\n| `MTLS_SESSION_MAX_AGE` | Session TTL (e.g. `24h`) | `24h` |\n| `MTLS_SESSION_RATE_LIMIT` | Max test calls per window per session | `10` |\n| `MTLS_SESSION_RATE_WINDOW` | Rate limit window (e.g. `60s`) | `60s` |\n\nTo run as a pure mTLS sandbox without the public session API:\n\n```bash\nMTLS_SESSION_ENABLED=false mtls-sandbox\n```\n\n---\n\n## Quick Start\n\n### From source\n\n```bash\ngo install github.com/sebdeveloper6952/mtls-sandbox/cmd/mtls-sandbox@latest\nmtls-sandbox\n```\n\n### Build and run locally\n\n```bash\ngit clone https://github.com/sebdeveloper6952/mtls-sandbox.git\ncd mtls-sandbox\ngo run ./cmd/mtls-sandbox\n```\n\nOn first boot, the server will:\n\n1. Generate a self-signed root CA (ECDSA P-256)\n2. Issue a server certificate (SANs: `localhost`, `127.0.0.1`)\n3. Issue a client certificate for you to use\n4. Write all certs to `./certs/`\n5. Print the full certificate bundle to stdout\n6. Start the mTLS server on `:8443` and a health endpoint on `:8080`\n\n### Test it with curl\n\n```bash\n# This will be rejected — returns 401 with diagnostic report\ncurl -sk https://localhost:8443/ | jq .\n# {\n#   \"handshake_ok\": false,\n#   \"failure_code\": \"no_client_cert\",\n#   \"failure_reason\": \"client certificate not presented\",\n#   \"expected\": { \"client_auth\": \"strict\", \"trusted_ca\": \"mtls-sandbox-ca\" },\n#   \"presented\": { \"cert_chain\": [], \"tls_version\": \"TLS 1.3\", ... },\n#   \"hints\": [\n#     \"Your client did not present a certificate during the TLS handshake.\",\n#     \"If using curl, add: --cert client.crt --key client.key --cacert ca.crt\",\n#     ...\n#   ]\n# }\n\n# This will succeed (using the generated client cert)\ncurl -s \\\n  --cert ./certs/client.crt \\\n  --key ./certs/client.key \\\n  --cacert ./certs/ca.crt \\\n  https://localhost:8443/ | jq .\n# {\"client\":{\"cn\":\"mtls-sandbox-client\",\"expires\":\"...\",\"issuer\":\"mtls-sandbox-ca\"},\"message\":\"mTLS handshake successful\",\"status\":\"ok\"}\n\n# Health check (plain HTTP, always accessible)\ncurl http://localhost:8080/health\n# {\"status\":\"ok\"}\n```\n\n## Server Modes\n\nThe server supports three modes that control how it handles client certificate validation. Set the mode via config file, environment variable, or flag.\n\n### `strict` (default)\n\nBehaves like a real production mTLS endpoint. Connections without a valid client certificate receive an HTTP 401 response with a structured `InspectionReport` containing failure details and actionable hints.\n\n```bash\n# Rejected with diagnostic feedback\ncurl -sk https://localhost:8443/\n# HTTP 401 — InspectionReport with failure_code, failure_reason, and hints\n\n# Accepted\ncurl --cert ./certs/client.crt --key ./certs/client.key --cacert ./certs/ca.crt https://localhost:8443/\n# {\"status\":\"ok\",\"message\":\"mTLS handshake successful\",\"client\":{\"cn\":\"mtls-sandbox-client\",...}}\n```\n\n### `lenient`\n\nAccepts connections with or without a client certificate. Always returns HTTP 200 with an inspection report. When no cert is presented, the response includes a warning header.\n\n```bash\nMTLS_MODE=lenient mtls-sandbox\n```\n\n```bash\n# Accepted with warning\ncurl -sk https://localhost:8443/\n# HTTP 200\n# Header: X-MTLS-Warning: client certificate not presented\n# Body: {\"status\":\"ok\",\"inspection\":{\"handshake_ok\":false,\"failure_code\":\"no_client_cert\",...}}\n\n# Accepted with full success\ncurl --cert ./certs/client.crt --key ./certs/client.key --cacert ./certs/ca.crt https://localhost:8443/\n# {\"status\":\"ok\",\"inspection\":{\"handshake_ok\":true,...}}\n```\n\n### `inspect`\n\nAccepts all connections and returns the full `InspectionReport` as the response body. Use this to debug your TLS configuration.\n\n```bash\nMTLS_MODE=inspect mtls-sandbox\n```\n\n```bash\ncurl -sk https://localhost:8443/ | jq .\n# {\n#   \"handshake_ok\": false,\n#   \"failure_code\": \"no_client_cert\",\n#   \"failure_reason\": \"client certificate not presented\",\n#   \"expected\": { \"client_auth\": \"inspect\", \"trusted_ca\": \"mtls-sandbox-ca\" },\n#   \"presented\": { \"cert_chain\": [], \"tls_version\": \"TLS 1.3\", \"cipher_suite\": \"TLS_AES_128_GCM_SHA256\", \"server_name\": \"localhost\" },\n#   \"hints\": [\"Your client did not present a certificate...\", \"If using curl...\"],\n#   \"timestamp\": \"2026-03-18T20:27:40-06:00\"\n# }\n```\n\nWhen a client certificate is provided, the response includes full cert details (subject, issuer, serial, validity period, SANs, key type and strength).\n\n## Inspection Report\n\nEvery connection to the mTLS server is analyzed by the inspector and produces a structured `InspectionReport`. The report identifies the specific failure and provides actionable hints to fix it.\n\n### Failure Codes\n\n| Failure Code | Meaning | Example Hint |\n|---|---|---|\n| `no_client_cert` | Client did not present a certificate | \"If using curl, add: --cert client.crt --key client.key --cacert ca.crt\" |\n| `wrong_ca` | Certificate was signed by an untrusted CA | \"Your cert was signed by 'Other CA', but this server trusts only 'mtls-sandbox-ca'\" |\n| `cert_expired` | Certificate has expired | \"Your certificate expired on 2025-01-15T00:00:00Z\" |\n| `cert_not_yet_valid` | Certificate's NotBefore is in the future | \"Your certificate is not valid until 2027-01-01. Check your system clock.\" |\n| `weak_key` | RSA key is less than 2048 bits | \"Your certificate uses a RSA 1024-bit key, which is below the minimum accepted strength.\" |\n| `no_client_auth_eku` | Certificate lacks ClientAuth extended key usage | \"Your certificate does not include the ClientAuth EKU. This usually means a server certificate is being used as a client certificate.\" |\n\n### `/debug` Endpoint\n\nThe `/debug` endpoint always returns the full `InspectionReport` regardless of server mode. Use it when you want diagnostics without changing the server mode.\n\n```bash\ncurl -sk https://localhost:8443/debug | jq .\n```\n\n## Configuration\n\n### Config file (YAML)\n\n```yaml\nmode: strict              # strict | lenient | inspect\nport: 8443\nhealth_port: 8080\ntls:\n  ca_cert: \"\"             # path to CA cert PEM (empty = auto-generate)\n  ca_key: \"\"              # path to CA key PEM\n  server_cert: \"\"         # path to server cert PEM\n  server_key: \"\"          # path to server key PEM\n  client_cert: \"\"         # path to client cert PEM\n  client_key: \"\"          # path to client key PEM\n  persist_path: \"./certs\" # where to write generated certs\nhostnames:\n  - localhost\n  - 127.0.0.1\nlog:\n  level: info             # debug | info | warn | error\n  format: json            # json | text\n  file: \"\"                # log file path (empty = stdout)\n```\n\nPass the config file path with `-config`:\n\n```bash\nmtls-sandbox -config config.yaml\n```\n\n### Environment variables\n\nEvery config field can be overridden with an environment variable. Environment variables take precedence over the config file.\n\n| Variable | Description | Default |\n|---|---|---|\n| `MTLS_MODE` | Server mode (`strict`, `lenient`, `inspect`) | `strict` |\n| `MTLS_PORT` | mTLS server port | `8443` |\n| `MTLS_HEALTH_PORT` | Health endpoint port | `8080` |\n| `MTLS_TLS_CA_CERT` | Path to CA certificate PEM | (auto-generate) |\n| `MTLS_TLS_CA_KEY` | Path to CA key PEM | (auto-generate) |\n| `MTLS_TLS_SERVER_CERT` | Path to server certificate PEM | (auto-generate) |\n| `MTLS_TLS_SERVER_KEY` | Path to server key PEM | (auto-generate) |\n| `MTLS_TLS_CLIENT_CERT` | Path to client certificate PEM | (auto-generate) |\n| `MTLS_TLS_CLIENT_KEY` | Path to client key PEM | (auto-generate) |\n| `MTLS_TLS_PERSIST_PATH` | Directory for generated certs | `./certs` |\n| `MTLS_HOSTNAMES` | Comma-separated SANs for server cert | `localhost,127.0.0.1` |\n| `MTLS_LOG_LEVEL` | Log level | `info` |\n| `MTLS_LOG_FORMAT` | Log format (`json`, `text`) | `json` |\n| `MTLS_LOG_FILE` | Log file path (empty = stdout) | (stdout) |\n\n### CLI flags\n\n```\nmtls-sandbox [flags]\n\n  -config string\n        Path to config YAML file\n  -ephemeral\n        Do not persist generated certificates to disk\n```\n\n## Certificate Management\n\n### Auto-generation (default)\n\nOn first boot with no existing certs, the server generates:\n\n| File | Description |\n|---|---|\n| `certs/ca.crt` | Root CA certificate (ECDSA P-256, valid 10 years) |\n| `certs/ca.key` | Root CA private key |\n| `certs/server.crt` | Server certificate (valid 1 year, SANs from config) |\n| `certs/server.key` | Server private key |\n| `certs/client.crt` | Client certificate (valid 1 year) |\n| `certs/client.key` | Client private key |\n\nOn subsequent boots, existing certs at `persist_path` are reloaded automatically.\n\n### Ephemeral mode\n\nGenerate fresh certs on every boot without writing to disk. Useful for CI and testing:\n\n```bash\nmtls-sandbox -ephemeral\n```\n\n### Bring your own CA\n\nSupply your own CA to match a specific third party's PKI structure:\n\n```bash\nMTLS_TLS_CA_CERT=/path/to/ca.crt MTLS_TLS_CA_KEY=/path/to/ca.key mtls-sandbox\n```\n\nThe server will use your CA to issue server and client certificates.\n\n## Request Logging\n\nEvery request to the mTLS server is logged as structured JSON with the following fields:\n\n```json\n{\n  \"time\": \"2026-03-18T20:27:40.006037-06:00\",\n  \"level\": \"INFO\",\n  \"msg\": \"request\",\n  \"client_ip\": \"[::1]:50098\",\n  \"method\": \"GET\",\n  \"path\": \"/\",\n  \"status\": 200,\n  \"latency\": 26916,\n  \"tls_version\": \"TLS 1.3\",\n  \"cert_cn\": \"mtls-sandbox-client\",\n  \"cert_sans\": [\"localhost\"],\n  \"cert_expiry\": \"2027-03-19T02:27:38Z\"\n}\n```\n\nSwitch to human-readable text logging with:\n\n```bash\nMTLS_LOG_FORMAT=text mtls-sandbox\n```\n\n## Observability\n\nThe server is instrumented with [OpenTelemetry](https://opentelemetry.io/). Tracing and metrics are always-on in the code but export to a no-op backend by default, so there is zero overhead unless you configure an OTLP endpoint.\n\nTo enable, set the standard `OTEL_*` environment variables:\n\n```bash\nOTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 mtls-sandbox\n```\n\n| Variable | Description | Default |\n|---|---|---|\n| `OTEL_EXPORTER_OTLP_ENDPOINT` | OTLP HTTP endpoint (enables telemetry when set) | (unset — no-op) |\n| `MTLS_ENVIRONMENT` | Value for `deployment.environment.name` resource attribute | `development` |\n\n### Traces\n\nAutomatic HTTP spans via `otelhttp` on both the mTLS (`:8443`) and API (`:8080`) servers, plus manual spans:\n\n- `session.create` — session creation with `session.id` attribute\n- `session.test` — outbound test call with `session.id` and `test.mode`\n- `outbound.probe` — the actual HTTP call to the callback URL\n- `tls.inspect` — TLS inspection with `handshake.ok` and `failure_code`\n\n### Metrics\n\n| Metric | Type | Description |\n|---|---|---|\n| `mtls.inbound.requests` | Counter | Total inbound mTLS requests (by status, handshake result) |\n| `mtls.outbound.probes` | Counter | Total outbound session test probes (by test mode, status) |\n| `mtls.sessions.created` | Counter | Total sessions created |\n| `mtls.handshake.results` | Counter | TLS handshake pass/fail counts |\n| `mtls.inbound.latency_ms` | Histogram | Inbound request latency |\n| `mtls.outbound.latency_ms` | Histogram | Outbound probe latency |\n| `mtls.sessions.active` | UpDownCounter | Number of active sessions |\n\n## Architecture\n\n```\nmtls-sandbox/\n├── cmd/mtls-sandbox/\n│   └── main.go              # Entry point, subcommand dispatch (serve/ping/probe)\n├── config/\n│   └── config.go            # Config struct, YAML loading, env overrides\n├── internal/\n│   ├── ca/\n│   │   └── ca.go            # CA generation, cert issuance, persistence\n│   ├── client/\n│   │   └── client.go        # Outbound mTLS client (ping/probe)\n│   ├── inspector/\n│   │   ├── inspector.go     # InspectionReport, TLS analysis, failure detection\n│   │   └── hints.go         # Actionable hint generation per failure code\n│   ├── mock/\n│   │   ├── router.go        # Path matching, template expansion, delay simulation\n│   │   ├── loader.go        # YAML mock route loading\n│   │   └── mock.go          # Types: Route, Response, compiledRoute\n│   ├── ratelimit/\n│   │   └── limiter.go       # Fixed-window rate limiter (per session)\n│   ├── safedial/\n│   │   └── safedial.go      # SSRF-safe dialer (blocks private IPs)\n│   ├── server/\n│   │   ├── server.go        # mTLS server + health/API server + session handlers\n│   │   └── middleware.go    # Mode handlers, recording middleware, request logging\n│   ├── session/\n│   │   ├── store.go         # SQLite session store + call history\n│   │   └── migrations/      # sql-migrate SQL migration files\n│   ├── store/\n│   │   └── store.go         # In-memory ring buffer for inbound request log\n│   ├── telemetry/\n│   │   ├── telemetry.go     # OTel bootstrap (trace + metric providers)\n│   │   └── metrics.go       # Custom metric instruments\n│   └── ui/\n│       ├── dashboard.go     # go:embed SPA handler with client-side routing fallback\n│       └── static/          # SvelteKit build output (generated — do not edit)\n├── web/                     # SvelteKit 2 + Tailwind CSS 4 + DaisyUI 5 dashboard\n│   ├── src/\n│   │   ├── routes/          # SPA pages: landing, session, monitor\n│   │   └── lib/             # API client, types, components (PemBlock, CurlCommand, etc.)\n│   ├── svelte.config.js\n│   └── vite.config.ts\n├── Dockerfile               # Multi-stage: Node.js → SvelteKit, Go → embed, distroless runtime\n├── Makefile                 # build-web, build, clean targets\n├── go.mod\n└── go.sum\n```\n\nThe mTLS server and health server run on separate ports. The health endpoint is always plain HTTP so it remains accessible even when your TLS configuration is broken.\n\nAll three server modes use `tls.RequestClientCert` at the TLS layer, which means the HTTP handler always runs. Certificate verification is performed in the handler by the inspector package, allowing every connection to receive structured diagnostic feedback.\n\nThe dashboard is a SvelteKit SPA built with `adapter-static` and embedded into the Go binary via `go:embed`. The Go server includes a fallback handler that serves `index.html` for any unknown path, enabling client-side routing.\n\n## Development\n\n### Prerequisites\n\n- Go 1.26+\n- Node.js 22+ and pnpm (for the dashboard)\n\n### Run from source\n\n```bash\n# Go server only (uses previously built/embedded UI, or no UI if not built yet)\ngo run ./cmd/mtls-sandbox\n\n# Dashboard dev server (hot reload, proxies /api to Go backend)\ncd web \u0026\u0026 pnpm install \u0026\u0026 pnpm dev\n```\n\n### Run tests\n\n```bash\ngo test ./...\n```\n\nTests cover:\n- Config loading, defaults, YAML parsing, env overrides, and validation\n- CA generation (ECDSA P-256 and RSA 4096), cert issuance, chain verification, persistence round-trip\n- Inspector: all failure modes (no cert, wrong CA, expired, not yet valid, weak key, missing EKU), hint generation, cert info extraction\n- All three server modes with and without client certificates, wrong-CA rejection, `/debug` endpoint, health endpoint, and graceful shutdown\n\n### Build\n\n```bash\n# Full build: SvelteKit UI + Go binary\nmake build\n\n# Or step by step:\nmake build-web              # Build SvelteKit → internal/ui/static/\ngo build -o mtls-sandbox ./cmd/mtls-sandbox\n```\n\nThe `make build-web` step compiles the SvelteKit app with `adapter-static` and copies the output into `internal/ui/static/`, which is then embedded into the Go binary at compile time via `go:embed`.\n\n## License\n\nApache 2.0\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsebdeveloper6952%2Fmtls-sandbox","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsebdeveloper6952%2Fmtls-sandbox","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsebdeveloper6952%2Fmtls-sandbox/lists"}