Security
Fukura sits in the middle of your developer loop. Stderr of failed commands is famously leaky data — tokens, bearer headers, internal hostnames. We take the position that the safest place for that data to live is on the developer’s own machine, and that the hub should only ever see what has already been redacted. This page spells out how.
Redaction happens on the producer
Every captured invocation passes through Redactor (src/domain/redaction.rs) before anything is written to disk. The default pattern set catches AWS access / secret keys, GitHub / GitLab tokens, bearer tokens, JWTs, API-key query parameters, Postgres / MySQL / MongoDB connection strings, RSA / EC private-key headers, email addresses, and IPv4 literals. Matches are replaced with *** in place — the shape of the output is preserved, the sensitive substring is gone.
Adapters can extend the pattern set for their environment (internal hostname regex, ticket-ID format, build-system scheme). The contract (EKP §7) is that nothing leaves the producer unredacted — the hub accepts already-scrubbed documents and never sees the raw form.
Privacy tiers on the wire
Every note carries one of three tiers (EKP §4):
- private — client-local only. MUST NOT be transmitted. The hub MUST reject uploads at this tier with
422. Our CLI also blocks it before the request leaves the process. - org — visible only to members of the uploader’s organisation. Default tier for team use.
- public — visible to every authenticated reader of the hub, and (if the operator enables anonymous reads) to the world.
The CLI enforces (1) on the client side (Hub API §10.2); the hub enforces it on the server side (ADR 0005). Both sides refuse, so a non-conforming tool cannot accidentally leak a private row.
Deployment options
- Fully local. Free tier. The CLI runs against a
.fukura/directory on the engineer’s machine. Nothing ever leaves. - Self-host the hub. Run the same image we run in any environment you own — data plane, VPC, on-prem. See the deploy guide.
- Managed hub. Hosted by us for teams that don’t want to run the infra. Data plane is isolated per customer; production goals include SOC 2 Type I within the first year of GA.
The open-source CLI is identical across all three — switching between them is a config change, not a migration.
Authentication and scoping
Bearer tokens over Authorization: Bearer. The hub uses short-lived JWTs signed with its own secret; a token carries the user ID and an optional org_id claim indicating the current context (ADR 0004). Context switches reissue the token via POST /api/auth/switch-context; server-side handlers scope queries automatically, so a bug in a handler cannot leak across orgs — the DB query simply returns nothing.
Write endpoints always require auth. Read endpoints for public notes MAY be exposed unauthenticated if the operator opts in.
Rate limits and abuse
The hub enforces a per-user rate limit (default 600 req/min) via an in-process token bucket. Exceeded requests return 429 with Retry-After. The CLI automatically honours Retry-After and adds exponential backoff on top (base 2s, cap 60s, max 4 attempts).
Data retention and deletion
Free tier: 30 days. Team: 1 year. Enterprise: configurable. Soft deletes (notes.deleted_at) surface as 410 Gone rather than 404 Not Found on subsequent reads, so a client can tell “deleted” from “never existed” and stop retrying idempotent uploads. Hard purges are a single SQL operation available to org admins.
Vendor-lock-in posture
The capture path (CLI), the protocol (EKP), and the MCP server are Apache-2.0 forever. The hub server is source-available commercial. This means: if we vanish, your team can self-host forever. If we raise prices unreasonably, any EKP-conformant server works with the same CLI — the wire contract (Hub API v1) is public. We publish a contract test suite so a third-party implementation can prove conformance on its own CI.
Reporting a vulnerability
Email security@fukura.dev. We acknowledge within one business day and ship a fix or mitigation within 30 days for remote-exploitable issues, 90 days for local-only. We do not take public issues for undisclosed vulnerabilities.