{"id":51319276,"url":"https://github.com/tuist/kura","last_synced_at":"2026-07-01T11:02:32.774Z","repository":{"id":353071324,"uuid":"1213402381","full_name":"tuist/kura","owner":"tuist","description":"Leaderless distributed cache for productive software teams","archived":false,"fork":false,"pushed_at":"2026-06-24T00:04:56.000Z","size":623,"stargazers_count":1,"open_issues_count":23,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-24T02:06:38.169Z","etag":null,"topics":["bazel","cache","gradle","xcode"],"latest_commit_sha":null,"homepage":"","language":"Rust","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/tuist.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-04-17T10:44:11.000Z","updated_at":"2026-06-04T07:10:14.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/tuist/kura","commit_stats":null,"previous_names":["tuist/kura"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/tuist/kura","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tuist%2Fkura","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tuist%2Fkura/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tuist%2Fkura/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tuist%2Fkura/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tuist","download_url":"https://codeload.github.com/tuist/kura/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tuist%2Fkura/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35003464,"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-07-01T02:00:05.325Z","response_time":130,"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":["bazel","cache","gradle","xcode"],"created_at":"2026-07-01T11:02:31.636Z","updated_at":"2026-07-01T11:02:32.768Z","avatar_url":"https://github.com/tuist.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\".github/assets/kura-logo.png\" alt=\"Kura logo\" width=\"420\" /\u003e\n\u003c/p\u003e\n\n# Kura\n\n`Kura` is a Rust server for building low-latency cache meshes for tenants, handling distributed cache traffic for binary artifacts and metadata.\n\n\u003e [!NOTE]\n\u003e `Kura` comes from the Japanese word `蔵` (`kura`), which refers to a storehouse or warehouse. The name fits the system's role: keeping build artifacts and cache metadata stored durably and close at hand so they can be served with low latency.\n\n## Summary ✨\n\n- ⚡ Hot reads come from local disk\n- 🪨 Local metadata, multipart state, and the replication outbox live in RocksDB\n- 🔁 Blobs and cache metadata replicate to peer nodes with eventual consistency\n- 🔎 Nodes can discover peers through DNS and bootstrap themselves from already-running nodes\n- 📦 The HTTP API covers key value entries, Xcode CAS artifacts, Gradle artifacts, multipart module uploads, Nx self-hosted cache artifacts, Metro cache artifacts, and namespace clean\n- 🧰 The gRPC API exposes the Bazel Remote Execution cache services used by Bazel and Buck2\n- 📊 The local stack includes Grafana, Prometheus, Loki, Promtail, and Tempo traces\n\n## Local stack 🧪\n\nRun:\n\n```bash\ndocker compose up --build -d\n```\n\nUseful endpoints:\n\n- `http://localhost:4101/up`\n- `http://localhost:4102/up`\n- `http://localhost:4103/up`\n- `grpc://localhost:5101` for Bazel/Buck2 REAPI against `kura-us`\n- `grpc://localhost:5102` for Bazel/Buck2 REAPI against `kura-eu`\n- `grpc://localhost:5103` for Bazel/Buck2 REAPI against `kura-ap`\n- `http://localhost:3000` for Grafana with `admin` / `admin`\n- `http://localhost:9090` for Prometheus\n- `http://localhost:3100` for Loki\n- `http://localhost:3200` for Tempo\n\nSupported cache protocols:\n\n- `Bazel` and `Buck2`: Bazel Remote Execution API v2 over gRPC on `KURA_GRPC_PORT`\n- `Nx`: self-hosted remote cache API on `GET/PUT /v1/cache/{hash}`\n- `React Native Metro`: `HttpStore` / `HttpGetStore` on `GET/PUT /api/metro/cache/{cache_key}`\n\n## Toolchain 🛠️\n\nInstall Rust from `mise.toml`:\n\n```bash\nmise trust mise.toml\nmise install\n```\n\nRun tests:\n\n```bash\nmise x rust@1.94.1 -- cargo test\nmise x shellspec@0.28.1 -- shellspec\n```\n\nRuntime configuration is summarized in the table under [Runtime Model And Limits](#-runtime-model-and-limits). Kura now derives sensible defaults for the main FD, memory, and metadata-store budgets at startup when you do not set them explicitly.\n\n## 🗺️ Project Areas\n\nKura is easier to read by subsystem than by tutorial step. The sections below group the project by the main areas you operate or extend.\n\n- 🔌 [Protocol surfaces](#-protocol-surfaces)\n- 🗄️ [Storage and replication](#-storage-and-replication)\n- ⚙️ [Runtime model and limits](#-runtime-model-and-limits)\n- 📊 [Observability](#-observability)\n- 📣 [Runtime analytics](#-runtime-analytics)\n- ☸️ [Deployment options](#-deployment-options)\n- 🧩 [Extensions and policy](#-extensions-and-policy)\n\n## 🔌 Protocol Surfaces\n\nKura exposes multiple cache protocols behind one service:\n\nThe following HTTP surfaces are Tuist-specific client protocols. They exist so Tuist clients can talk to Kura without changing their cache behavior:\n\n- 🍎 `Xcode CAS`: `POST/GET /api/cache/cas/{id}?tenant_id=...\u0026namespace_id=...`\n- 🗂️ `Keyvalue / action-cache style entries`: `PUT /api/cache/keyvalue?tenant_id=...\u0026namespace_id=...`\n- 🐘 `Gradle`: `PUT/GET /api/cache/gradle/{cache_key}?tenant_id=...\u0026namespace_id=...`\n- 📦 `Multipart module cache uploads`: `POST /api/cache/module/start?...`, `POST /api/cache/module/part?...`, `POST /api/cache/module/complete?...`, `HEAD/GET /api/cache/module/{id}?...`\n\nKura also exposes broader ecosystem protocols that are not specific to Tuist:\n\n- 🧱 `Nx`: `PUT/GET /v1/cache/{hash}`\n- 📱 `Metro`: `PUT/GET /api/metro/cache/{cache_key}`\n- 🛠️ `Bazel` and `Buck2`: REAPI over gRPC on `KURA_GRPC_PORT`\n\nThe local compose stack is still the quickest way to exercise all of those surfaces together:\n\n```bash\ndocker compose up --build -d\n```\n\nExample Xcode artifact round trip:\n\n```bash\ncurl -X POST \\\n  \"http://localhost:4101/api/cache/cas/artifact-1?tenant_id=acme\u0026namespace_id=ios\" \\\n  -H \"content-type: application/octet-stream\" \\\n  --data-binary \"xcode-binary\"\n\ncurl \\\n  \"http://localhost:4102/api/cache/cas/artifact-1?tenant_id=acme\u0026namespace_id=ios\"\n```\n\nExample keyvalue entry round trip:\n\n```bash\ncurl -X PUT \\\n  \"http://localhost:4101/api/cache/keyvalue?tenant_id=acme\u0026namespace_id=ios\" \\\n  -H \"content-type: application/json\" \\\n  -d '{\"cas_id\":\"cas-1\",\"entries\":[{\"value\":\"hello\"},{\"value\":\"world\"}]}'\n\ncurl \\\n  \"http://localhost:4103/api/cache/keyvalue/cas-1?tenant_id=acme\u0026namespace_id=ios\"\n```\n\n## 🗄️ Storage And Replication\n\nKura splits storage into two planes:\n\n- 🪨 RocksDB stores metadata, keyvalue payloads, multipart state, tombstones, segment lifecycle state, and the replication outbox.\n- 📦 Segment files store large immutable binary artifacts for the hot path.\n\nReplication is leaderless and eventually consistent:\n\n- 🔁 local writes become durable together with their outbox work\n- 🌍 peers bootstrap by pulling manifests, tombstones, and artifact bodies\n- 🔎 DNS discovery can expand the peer set automatically\n- 🧠 the outbox is processed incrementally so queue depth does not blow up heap usage during backlog\n\nPeer-to-peer mTLS is available for the internal plane:\n\n- `KURA_INTERNAL_PORT`\n- `KURA_INTERNAL_TLS_CA_CERT_PATH`\n- `KURA_INTERNAL_TLS_CERT_PATH`\n- `KURA_INTERNAL_TLS_KEY_PATH`\n\nWhen peer mTLS is enabled:\n\n- 🔒 `KURA_NODE_URL` and every value in `KURA_PEERS` must use `https://...:\u003cKURA_INTERNAL_PORT\u003e`\n- 🌍 the public API still stays on `KURA_PORT`\n- 🧱 `/_internal/*` is only served on the internal mTLS listener\n- 🪪 the certificate configured through `KURA_INTERNAL_TLS_CERT_PATH` should be valid for both server and client auth\n- 🏷️ the certificate SANs must cover the hostname used in `KURA_NODE_URL`\n\n## ⚙️ Runtime Model And Limits\n\nKura is designed around explicit resource budgets instead of relying on ambient process limits.\n\nWhen `Optional` is `Yes`, the `Default` column shows what Kura uses today. `auto` means Kura derives the value at startup from detected file-descriptor limits, memory limits, or CPU count.\n\n| Name | Description | Optional | Default |\n| --- | --- | --- | --- |\n| `KURA_PORT` | Public HTTP port. | No | `—` |\n| `KURA_GRPC_PORT` | gRPC port for REAPI. | No | `—` |\n| `KURA_TENANT_ID` | Default tenant identifier for the node. | No | `—` |\n| `KURA_REGION` | Region label advertised in metrics and replication state. | No | `—` |\n| `KURA_TMP_DIR` | Temporary directory for staged request bodies and multipart assembly. | No | `—` |\n| `KURA_DATA_DIR` | Persistent directory for metadata state and segment files. | No | `—` |\n| `KURA_NODE_URL` | Canonical URL other peers use to reach this node. | No | `—` |\n| `KURA_PEERS` | Seed peer list used before discovery converges. | Yes | `KURA_NODE_URL` |\n| `KURA_DISCOVERY_DNS_NAME` | DNS name to probe for automatic peer discovery. | Yes | disabled |\n| `KURA_FILE_DESCRIPTOR_POOL_SIZE` | App-managed file-descriptor budget for request and background I/O. | Yes | auto |\n| `KURA_FILE_DESCRIPTOR_ACQUIRE_TIMEOUT_MS` | How long a request waits before FD backpressure fails the checkout. | Yes | `5000` |\n| `KURA_SEGMENT_HANDLE_CACHE_SIZE` | Maximum number of pinned segment read handles; must stay below the FD pool size. | Yes | auto |\n| `KURA_MEMORY_SOFT_LIMIT_BYTES` | Soft watermark where Kura starts shedding optional memory use. | Yes | auto |\n| `KURA_MEMORY_HARD_LIMIT_BYTES` | Hard watermark where Kura pauses replication work and trims hot caches aggressively. | Yes | auto |\n| `KURA_MANIFEST_CACHE_MAX_BYTES` | Maximum size of the in-memory manifest hot cache. | Yes | auto |\n| `KURA_MAX_KEYVALUE_BYTES` | Maximum per-request keyvalue payload size on public and replication APIs. | Yes | `1048576` |\n| `KURA_METADATA_STORE_MAX_OPEN_FILES` | Descriptor budget reserved for the metadata store itself. | Yes | auto |\n| `KURA_METADATA_STORE_MAX_BACKGROUND_JOBS` | Background flush and compaction concurrency for the metadata store. | Yes | auto |\n| `KURA_METADATA_STORE_READ_CACHE_BYTES` | Capacity of the metadata-store read cache. | Yes | auto |\n| `KURA_METADATA_STORE_WRITE_BUFFER_POOL_BYTES` | Total memory budget reserved for metadata write buffering. | Yes | auto |\n| `KURA_METADATA_STORE_WRITE_BUFFER_BYTES` | Size of each metadata write buffer before flush. | Yes | auto |\n| `KURA_METADATA_STORE_MAX_WRITE_BUFFERS` | Maximum number of metadata write buffers kept in memory. | Yes | auto |\n\nAuto-derived defaults currently follow these rules:\n\n- `file_descriptor_limit` comes from `RLIMIT_NOFILE` when available, otherwise Kura falls back to a conservative host default.\n- `memory_limit_bytes` comes from the cgroup memory limit when available, otherwise Kura falls back to physical host memory.\n- `cpu_count` comes from detected parallelism via the runtime.\n- `KURA_FILE_DESCRIPTOR_POOL_SIZE` is `usable_fds / 8`, clamped to `[64, 256]`, where `usable_fds` is the detected FD limit minus reserved headroom.\n- `KURA_SEGMENT_HANDLE_CACHE_SIZE` is `KURA_FILE_DESCRIPTOR_POOL_SIZE / 4`, clamped to `[16, 64]`, and then capped below the FD pool so transient work keeps headroom.\n- `KURA_MEMORY_SOFT_LIMIT_BYTES` is `70%` of detected memory, rounded down to MiB boundaries, with a minimum of `128 MiB`.\n- `KURA_MEMORY_HARD_LIMIT_BYTES` is `85%` of detected memory, rounded down to MiB boundaries, and always at least `64 MiB` above the soft limit.\n- `KURA_MANIFEST_CACHE_MAX_BYTES` is `KURA_MEMORY_SOFT_LIMIT_BYTES / 16`, rounded down to MiB boundaries and clamped to `[8 MiB, 64 MiB]`.\n- `KURA_METADATA_STORE_MAX_OPEN_FILES` is `usable_fds / 2`, clamped to `[128, 1024]`.\n- `KURA_METADATA_STORE_MAX_BACKGROUND_JOBS` is `cpu_count`, clamped to `[1, 8]`.\n- `KURA_METADATA_STORE_READ_CACHE_BYTES` is `memory_limit_bytes / 32`, rounded down to MiB boundaries and clamped to `[16 MiB, 128 MiB]`.\n- `KURA_METADATA_STORE_WRITE_BUFFER_POOL_BYTES` follows the same `memory_limit_bytes / 32` rule as the metadata-store read cache.\n- `KURA_METADATA_STORE_WRITE_BUFFER_BYTES` is `KURA_METADATA_STORE_WRITE_BUFFER_POOL_BYTES / 4`, rounded down to MiB boundaries and clamped to `[4 MiB, 32 MiB]`.\n- `KURA_METADATA_STORE_MAX_WRITE_BUFFERS` is `KURA_METADATA_STORE_WRITE_BUFFER_POOL_BYTES / KURA_METADATA_STORE_WRITE_BUFFER_BYTES`, clamped to `[2, 8]`.\n- `KURA_MAX_KEYVALUE_BYTES` defaults to `1048576`, and `KURA_FILE_DESCRIPTOR_ACQUIRE_TIMEOUT_MS` defaults to `5000`.\n\nA minimal direct-binary deployment still looks like:\n\n```bash\nKURA_PORT=4000 \\\nKURA_GRPC_PORT=50051 \\\nKURA_TENANT_ID=default \\\nKURA_REGION=eu-central \\\nKURA_TMP_DIR=/tmp/kura \\\nKURA_DATA_DIR=/var/cache/kura \\\nKURA_NODE_URL=http://cache-1.internal:4000 \\\nKURA_OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://otel-collector:4318/v1/traces \\\nKURA_OTEL_SERVICE_NAME=kura-eu-central \\\nKURA_OTEL_DEPLOYMENT_ENVIRONMENT=production \\\n./target/release/kura\n```\n\n## 📊 Observability\n\nKura ships with a fairly complete local observability story:\n\n- 📈 Prometheus metrics\n- 📉 Grafana dashboards\n- 🪵 Loki and Promtail logs\n- 🧭 Tempo traces\n\nPrometheus exposes live metadata-store memory gauges:\n\n- `kura_rocksdb_block_cache_usage_bytes`\n- `kura_rocksdb_block_cache_pinned_usage_bytes`\n- `kura_rocksdb_block_cache_capacity_bytes`\n- `kura_rocksdb_write_buffer_usage_bytes`\n- `kura_rocksdb_write_buffer_capacity_bytes`\n\nKura also exports:\n\n- 📦 artifact read and write counters by `kind`, `client`, `artifact_class`, and `result`\n- 🔁 replication latency and result metrics\n- 💾 file descriptor pool pressure metrics\n- 🧠 manifest cache occupancy and admission metrics\n\n## 📣 Runtime Analytics\n\nAnalytics webhooks are a separate optional subsystem that mirrors the older Tuist cache contract for Xcode and Gradle traffic.\n\nWhen enabled:\n\n- 🍎 Xcode upload and download events are sent to `/webhooks/cache`\n- 🐘 Gradle upload and download events are sent to `/webhooks/gradle-cache`\n- ✍️ requests are signed with `x-cache-signature`\n- 🧭 requests also include `x-cache-endpoint`\n- 🪶 delivery stays in-memory and best-effort, so analytics never block the hot path\n- 🧯 a per-pipeline circuit breaker opens after repeated delivery failures so Kura sheds analytics instead of backing up under a misbehaving upstream\n\nConfigure it with:\n\n- `KURA_ANALYTICS_SERVER_URL`\n- `KURA_ANALYTICS_SIGNING_KEY`\n- optional `KURA_ANALYTICS_BATCH_SIZE` default `100`\n- optional `KURA_ANALYTICS_BATCH_TIMEOUT_MS` default `5000`\n- optional `KURA_ANALYTICS_QUEUE_CAPACITY` default `1000`\n- optional `KURA_ANALYTICS_REQUEST_TIMEOUT_MS` default `5000`\n- optional `KURA_ANALYTICS_CIRCUIT_BREAKER_FAILURE_THRESHOLD` default `5`\n- optional `KURA_ANALYTICS_CIRCUIT_BREAKER_OPEN_MS` default `30000`\n\nIt also exposes analytics-specific runtime metrics for:\n\n- 📣 queue depth and drops\n- 📦 batch sizes and flush outcomes\n- 🧯 circuit-breaker state and open events\n\n## ☸️ Deployment Options\n\n### Helm And Kubernetes\n\nThe repository includes a Helm chart at `ops/helm/kura` that deploys Kura as a `StatefulSet` with:\n\n- 💾 one PVC per pod for metadata-state and segment storage\n- 🧭 a headless service for stable pod DNS and peer discovery\n- 🌐 a regular service exposing both HTTP and gRPC\n- 🚪 optional ingress for the HTTP API\n- 🧩 optional inline extension script mounting through a `ConfigMap`\n- 🔐 optional peer mTLS for `/_internal/*` traffic via a mounted Kubernetes `Secret`\n\nLint and render the chart:\n\n```bash\nhelm lint ops/helm/kura\nhelm template kura ops/helm/kura --namespace kura\n```\n\nInstall it on a generic cluster:\n\n```bash\nhelm upgrade --install kura ./ops/helm/kura \\\n  --namespace kura \\\n  --create-namespace \\\n  --set image.repository=ghcr.io/tuist/kura \\\n  --set image.tag=latest \\\n  --set config.region=fr-par \\\n  --set config.telemetry.otlpTracesEndpoint=http://otel-collector.monitoring.svc.cluster.local:4318/v1/traces\n```\n\nFor a local kind smoke test, the repo includes:\n\n```bash\n./test/e2e/kura_helm_kind.sh\n```\n\nTo enable peer mTLS in Kubernetes, set:\n\n- `peerTls.enabled=true`\n- `peerTls.internalPort=\u003cport\u003e`\n- `peerTls.secretName=\u003csecret-with-ca-cert-and-key-material\u003e`\n\nThe referenced secret should contain the files configured by:\n\n- `peerTls.caCertFileName`\n- `peerTls.certFileName`\n- `peerTls.keyFileName`\n\nWhen enabled, the chart advertises peer URLs over `https` on the internal port and mounts the secret into `/etc/kura/peer-tls`.\n\n### Scaleway Kapsule\n\nFor Scaleway, start from the bundled overrides in `ops/helm/kura/values-scaleway.yaml`:\n\n```bash\nhelm upgrade --install kura ./ops/helm/kura \\\n  --namespace kura \\\n  --create-namespace \\\n  -f ./ops/helm/kura/values-scaleway.yaml \\\n  --set image.repository=ghcr.io/tuist/kura \\\n  --set image.tag=latest \\\n  --set config.region=fr-par \\\n  --set config.telemetry.otlpTracesEndpoint=http://otel-collector.monitoring.svc.cluster.local:4318/v1/traces\n```\n\nThat values file does two important things:\n\n- 🚪 uses a `LoadBalancer` service, which is the simplest way to expose Kura on Kapsule\n- 💾 pins persistence to `scw-bssd`, which Scaleway documents as the default block storage class for Kapsule multi-AZ clusters\n\n## 🧩 Extensions And Policy\n\nKura can load one operator-provided extension script at startup to customize authentication, authorization, and response headers without recompiling the binary.\n\nCore env vars:\n\n- `KURA_EXTENSION_ENABLED=true`\n- `KURA_EXTENSION_SCRIPT_PATH=/etc/kura/extensions/hooks.lua`\n- `KURA_EXTENSION_HOOK_TIMEOUT_MS=25`\n- `KURA_EXTENSION_AUTH_CACHE_ALLOW_TTL_SECONDS=600`\n- `KURA_EXTENSION_AUTH_CACHE_DENY_TTL_SECONDS=3`\n- `KURA_EXTENSION_FAIL_CLOSED_AUTHENTICATE=true`\n- `KURA_EXTENSION_FAIL_CLOSED_AUTHORIZE=true`\n- `KURA_EXTENSION_FAIL_OPEN_RESPONSE_HEADERS=true`\n\nGeneric host resources are also env-driven:\n\n- ✍️ signers:\n  - `KURA_EXTENSION_SIGNER_\u003cID\u003e_ALGORITHM`\n  - `KURA_EXTENSION_SIGNER_\u003cID\u003e_SECRET`\n- 🪪 JWT verifiers:\n  - `KURA_EXTENSION_JWT_VERIFIER_\u003cID\u003e_ALGORITHM`\n  - `KURA_EXTENSION_JWT_VERIFIER_\u003cID\u003e_SECRET`\n  - `KURA_EXTENSION_JWT_VERIFIER_\u003cID\u003e_ISSUER`\n  - `KURA_EXTENSION_JWT_VERIFIER_\u003cID\u003e_AUDIENCES`\n- 🌐 HTTP clients:\n  - `KURA_EXTENSION_HTTP_CLIENT_\u003cID\u003e_BASE_URL`\n  - `KURA_EXTENSION_HTTP_CLIENT_\u003cID\u003e_CONNECT_TIMEOUT_MS`\n  - `KURA_EXTENSION_HTTP_CLIENT_\u003cID\u003e_REQUEST_TIMEOUT_MS`\n\nThe script may define these hooks:\n\n- `authenticate(ctx)`\n- `authorize(ctx, principal)`\n- `response_headers(ctx, principal)`\n\nThe runtime keeps decision caching, metrics, timeouts, and cryptographic primitives in Rust, while the script supplies policy.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftuist%2Fkura","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftuist%2Fkura","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftuist%2Fkura/lists"}