Hosted: Security and data

Hosted

Security and data

What the hosted hub can and cannot see, how checks are isolated, and how to export or delete your data.

Design summary

  • The agent is outbound-only. It dials the hub over a WebSocket at /v1/agent/connect. There are no inbound ports to open and no SSH access for us.
  • Your source code never leaves your server. The agent clones the repository itself and sends the hub only results, annotations, and logs.
  • Each job runs as an unprivileged user with resource limits and, by default, a restricted network.
  • Anything you list in redact is scrubbed from logs before upload.

Outbound-only connection

The agent opens one connection to https://ci.webuno.io on port 443 and keeps it open. Jobs arrive over that connection. If the hub is unreachable, the agent retries and nothing on your side listens for traffic. Firewall rules need only allow outbound 443. See How it works.

Source code stays on your server

When a push or pull request arrives, the hub routes a job to your agent. The agent clones the repository using a short-lived GitHub installation token, runs the checks, and sends back:

  • job states and durations
  • annotations (file, line, message), at most 500 per job
  • logs, capped at 10 MiB per job

The hub does not receive file contents, diffs, or the working tree.

Isolation of checks

Every job runs as the unprivileged user hookci-run inside a transient systemd unit under hookci.slice, with CPU, memory, task, and time limits from checks.limits. Each job gets its own network namespace. Details and the --isolation none escape hatch are in Isolation and egress.

Egress allowlist

Job traffic goes through an egress proxy that allows only the hostnames you list in egress, on port 443. Everything else is refused. Add the registries your dependencies need, for example registry.npmjs.org.

Redaction

Values or variable names listed under redact in .hookci.yml are replaced in logs before they are uploaded.

redact: [MY_SECRET, DEPLOY_KEY]

Redaction is a safety net. Do not print secrets on purpose.

Fork pull requests

Untrusted code is the main risk of any CI. HookCI gates it:

  • checks.trust: collaborators runs pull requests from repo collaborators only.
  • checks.trust: approve waits for someone to click Approve run.
  • checks.forks: gated requires approval for fork PRs. never ignores them.
  • trust: all runs everything and is not recommended for public repositories.

See Trust and forks.

Token handling

  • Pair tokens (hc_pair_...) are single use and valid for 15 minutes.
  • The agent stores its credential in agent.json (mode 600) inside its state directory under /var/lib/hookci, which has mode 0700.
  • GitHub installation tokens given to the agent are short lived.
  • Revoking an agent in Slack App Home makes a running agent exit with code 3, and its unit does not restart.

The GitHub App asks for read access to contents, metadata, pull requests, and members, and write access to checks. It does not write commit statuses.

Data we store

Data Where
Run records, agent and repo metadata, workspace settings Cloudflare D1
Job logs Cloudflare R2
Slack and GitHub installation tokens Stored encrypted by the hub

Storage uses the EU jurisdiction where Cloudflare offers it. Retention depends on your plan: see pricing. Log uploads are capped at 10 MiB per job.

Logs are not public. Links posted to Slack or the hub open logs through signed URLs that expire after 15 minutes. Open the run again to get a fresh link.

Export and delete

In Slack:

/hookci export
/hookci delete-my-data

export returns the data held about you. delete-my-data removes it. Both are described in Slack.

Uninstall and purge

Uninstalling the GitHub App purges the installation’s data within 30 days. To fully leave, also revoke each agent in Slack App Home and remove the agent from your servers: see Upgrade and uninstall.

Contact and disclosure

If you prefer to keep everything under your control, self-host the hub.