Legal — Privacy

Privacy Policy

Effective as posted. Contact: legal@corund.dev

Scope, and how to read this page

This policy covers the Corund GitHub App at app.corund.dev, the marketing site at corund.dev and its waitlist, and what Corund posts back to GitHub. Corund is operated by Grade Inc., a Delaware corporation, 131 Continental Drive, Suite 305, Newark, New Castle County, DE 19713.

Every sentence on this page that says what Corund does with data was written against the code that does it, at a named commit, and the repository's test suite holds the page and that record to the same set of statements. A sentence carrying a mark describes something the code does not yet settle; it is a draft, not a fact. A small number of sentences instead state a business or legal fact that is the owner's or counsel's alone to set, which no amount of code review ever resolves; those are tracked as a distinct status in the repository's own evidence and carry no bracket here either. None currently apply: every business or legal fact on this page today is either verified against the code or confirmed against a primary source such as a certificate of incorporation, cited in the repository's evidence.

The open-source Corund Action runs inside your own CI and publishes its results as a GitHub check run; the App reads those results from GitHub, so the Action has no reason to call Corund's servers, and its code does not: the Action's only outbound HTTP client talks to GitHub's own API.

1. When you install the App

Installation record. When the App is installed, GitHub sends Corund a signed webhook and Corund stores the installation's id, the account's numeric id, login and type (user or organisation), the time, and — if GitHub later suspends the installation — the suspension time.

Repository record. For each repository you grant, Corund stores GitHub's repository id, its full name, whether it is private, and its default branch; for a private repository it also mints a random badge token so that only someone holding the token can load its README badge.

Settings you enter. Corund stores what you type into a repository's settings: the loud-skip allowlist, the required-path map, which of the four checks are enabled, and which rules may block. On plans with org auto-enable, a newly added repository inherits the installation's most recent settings.

Membership. The person who installs the App becomes its owner; roles are owner, admin and member, one per person per installation, with a record of who granted each.

Webhook ledger. Corund verifies GitHub's signature over the raw body before it parses anything, then records each delivery once: its delivery id, event, action, installation id, the time, and a SHA-256 hash of the payload. The payload itself is never stored.

What the App may read on GitHub. The App is registered with the permissions checks: write, pull_requests: read, contents: read and metadata: read. It has no write access to your code.

2. When you sign in

Sign-in is GitHub OAuth with the read:user scope. Corund keys your account on GitHub's immutable numeric user id and caches your login and display name for the screen only; neither is used to decide what you may see. Corund does not store your email address.

Audit log. Sign-ins, membership changes and internal failures are appended to an audit log: the time, the acting account's internal id, the installation, the action name, a target, and a short detail (for example the reason a webhook handler crashed).

3. When a pull request is opened or updated

Run record. Each pull-request event creates a run row: the PR number, the PR author's numeric id, account type and login (login for display only), whether the repository was private at run time, head and base commit SHAs and the base branch name, the triggering event, the run's state, the ids of the check runs Corund created on GitHub, a snapshot of the branch's required status checks (for C3), whether the receipt comment could be posted, any error text, the receipt's content hash, the Corund build that produced it, and timestamps.

What Corund reads during a run. Using a short-lived installation token, the App reads from GitHub: the repository's metadata; the pull request; the pull request's diff (C2); its reviews — reviewer id, state and the commit each approval was given for (C4); the check runs on the head commit, to find the red-on-revert results the Corund Action published (C1); branch rulesets or classic branch protection and the workflow files under .github/workflows at base and head (C3); the policy file .github/corund.yml at the base branch; and the pull request's existing comments, to update Corund's own comment in place.

Transient means this. Those inputs live in the process's memory for the length of that one run, are handed to the check core, and are discarded when the run ends. The diff, the workflow files, the per-test pass/fail maps and the policy text are not written to Corund's database or to any file store; Corund has no object storage. What persists from a run is the run record above and the receipt rows below.

Corund's servers never execute your tests. The red-on-revert results C1 needs are produced by the Corund Action inside your own CI and read back from its check-run output on GitHub; if the Action has not run for a commit, C1 reports NOT_RUN and says why.

Receipt rows. For each of the four checks, Corund stores the check id, its verdict, the UNPROVEN reason where one applies, the base, head and approval SHAs, the time, and a free-text detail: the evidence lines the check produced, or the text of the exception if it crashed. Those lines can name file paths, test identifiers and skip sites. The check core truncates what it quotes: at most 140 characters of a matched source line for a skip-audit finding, and at most 160 characters of an assertion or exception message for a red-on-revert witness. There is no field for a file's full contents, and none of the four checks ever writes one to a receipt.

Receipt integrity. When a run finishes, Corund stamps it with a SHA-256 over the receipt's canonical rows, the Corund build id and a fingerprint of the code that produced it, so a reader can later check that a receipt has not been altered.

What Corund posts to GitHub. The receipt goes back to GitHub as four check runs (each with a title, summary and the check's detail text) and as one pull-request comment that later runs update in place. Every posting carries a link to the receipt's permalink.

Receipt permalinks. A receipt at /r/<id> is public, with no sign-in, when the repository was public at run time; a private repository's receipt is visible only to signed-in members of that installation. Any other request gets the same not-found answer, so ids cannot be probed.

When something breaks. If a run crashes, the exception's text is stored on the run and on a CRASHED receipt for each check that has none, and one structured failure line is logged. Corund never turns a crash into a passing result.

4. Replay

On install, and whenever an owner or admin asks, Corund replays a repository's most recent merged pull requests (50 by default) through the four checks, read-only, building the same inputs as a live run and posting nothing to GitHub. It stores one row per pull request and check: the PR number, merge SHA, check id, verdict, reason, whether a block rule would have fired, the evidence lines with the SHAs, and any true- or false-positive mark an operator sets, with that operator's account id and the time. The replay export you can download is built from those stored rows only.

5. The README badge

A badge request returns one word derived from the latest finished run on the default branch. Each time a badge is served Corund records an event with the word, the installation and the repository; nothing about the viewer is recorded. A private repository's badge needs its token.

6. Product events and metrics

Corund keeps an append-only events ledger — install, uninstall, run started, run finished, fake green caught, badge served, replay started and finished, and operator overrides — with the installation id, repository id, time and a small payload of kinds, states and numeric ids. The writer refuses any payload key that looks like a login, name, email, token or secret. Corund's own metrics page is derived from this ledger and is visible only to Corund's administrators, identified by numeric GitHub id.

Seat counts and the product-qualified-lead signal are derived from the same records: the distinct people who authored pull requests on the installation's private repositories in the trailing 90 days, counted by numeric id, with bot accounts excluded and a 48-hour grace period for a newly seen author. Reaching the lead threshold is recorded once per installation.

Corund also keeps a global list of citations — URLs of articles, repositories and posts that link to Corund, entered by an administrator or imported from a CSV. It names no customer and holds no customer data.

7. Cookies and sessions

The App sets two cookies and no others: corund_session (HttpOnly; Secure when served over HTTPS; SameSite=Lax; path /; expires after 30 days) carrying a random session token, and corund_gh_oauth_state (same flags; path /auth/github; expires after 10 minutes) carrying the sign-in flow's anti-forgery state. The marketing site at corund.dev sets no cookies at all. There are no advertising or analytics cookies anywhere, which is why there is no cookie banner.

Only a SHA-256 hash of the session token is stored, never the token. A session ends after 30 days at most, sooner when idle — 12 hours for an owner, 24 hours for an admin, 7 days for a member — the moment any of your roles changes, or when you sign out.

8. Logs

Each request is logged with its method, path, status and duration and an 8-character prefix of a salted SHA-256 hash of the client IP address (the salt is a server secret); never the raw IP address, headers, cookies, request bodies or query strings. A failure is logged as one structured line with a request id, the method, the matched route pattern, the path, the status, the installation id if the route named one, and the exception's class name; the logger refuses fields whose names look like a token, secret, cookie, password, header or body. Every response carries an X-Request-ID header so you can quote a request to us.

Application logs are held by our hosting provider.

9. The marketing site and the waitlist

The pages at corund.dev are static files, served by Cloudflare Pages, which sees the requests for them.

The waitlist endpoint on the Railway web host (POST /api/waitlist) stores the email address you submit (normalised to lower case), a short source tag, the salted IP hash described above, up to 256 characters of your browser's User-Agent string, and the time. A duplicate address is silently ignored; a submission that fills the hidden honeypot field is answered but stores nothing; the endpoint is rate-limited per IP address in memory.

On the published marketing site the waitlist button is a mail link to hello@corund.dev. Mail sent there is handled by whichever mail provider the owner points that address at — outside Corund's own code, the same as for any address.

Today, both the marketing pages and the App's pages load their typefaces from Google Fonts, so your browser requests fonts.googleapis.com and fonts.gstatic.com directly and Google receives those requests, including your IP address. If those hosts are unreachable the pages fall back to system fonts.

10. Billing

Paid plans are billed through Stripe. Checkout happens on Stripe's hosted page. To start it, Corund creates a Stripe customer named after the installation's GitHub account login, tagged with the installation id and the GitHub account id, and opens a checkout session that carries the installation id, the plan's prices and seat quantity, and the return addresses. Corund sends Stripe no email address and never sees, asks for or stores a card number; whatever you type on Stripe's page goes to Stripe.

What Corund keeps from Stripe. The Stripe customer id; for each subscription its id, item id, price id, plan, billing interval, seat quantity, Stripe's own status word, current period start and end, whether it is set to cancel at period end, when it entered past-due, any add-ons, and the status and time of the last invoice; a billing-events ledger of checkout completed, subscription created or cancelled, seats added or removed, and lead reached, each with the ids, plan, quantity and status involved; and a trial record with its start and end dates.

Stripe's webhooks. Corund verifies Stripe's signature over the raw body before parsing, processes each event once, and records only the event's id, type, the installation it resolved to, a SHA-256 hash of the payload, and the outcome. The payload itself is never stored.

Seats are measured at billing time from the private-repository authorship described in section 6; Corund never lowers a subscription's quantity on its own, and by default reports rather than changes it.

Stripe's handling of your payment details is governed by Stripe's own privacy policy at stripe.com/privacy and its data processing agreement at stripe.com/legal/dpa.

11. No training on your code

Corund does not use your code, diffs, test results or receipts to train, fine-tune or evaluate any machine-learning model, its own or anyone else's, and nothing in the App sends customer content to a model provider. No model takes part in a verdict: each of the four checks is a deterministic comparison, and a check that could not run says so.

12. Subprocessors and other third parties

Three companies process data on Corund's behalf. Each is wired into the code or the deployment configuration named below, and the repository's tests refuse a change that adds one to this list without the other, or to the other without this list.

ProviderWhat it does for CorundWhat it receivesWhere it is wiredIts terms
RailwayHosts the App and the web host and provides their Postgres databaseEverything this policy says Corund stores or logsOur hosting and deploy configurationrailway.com/legal/privacy, railway.com/legal/dpa
StripePayments, subscriptions, the customer portalWhat section 10 lists; the payment details you enter on Stripe's pageOur billing integrationstripe.com/privacy, stripe.com/legal/dpa
GitHubThe platform Corund runs on: installation and pull-request webhooks, the API reads in section 3, OAuth sign-in, and the check runs and comments Corund postsThe receipt (check runs and one PR comment) and the API requests the App makes with its installation tokenOur webhook handler and GitHub API clientGitHub privacy statement

Your browser also contacts two hosts on its own when it loads a Corund page: Google Fonts (section 9) and, for the marketing site, Cloudflare Pages (section 9). Neither receives customer content from Corund.

13. Retention and deletion

Corund keeps the records above for the life of the account. We commit to purging them within 30 days of account deletion; the automated purge is being built, and until it runs the deletion is performed by hand on request. Removing the installation from GitHub, or using the delete control in Settings, starts that clock. One exception, stated here rather than left to be discovered: an expired or revoked session is refused immediately, but its row is removed on that same schedule rather than at once.

Deletion. Only one action deletes an installation's data: an installation owner pressing delete in the App's settings. That self-serve delete removes the installation's data in one pass and in this order: billing events, billing webhook ledger, subscriptions, trials and billing customer; check receipts; jobs; replay items and replay runs; runs; repository settings; repositories; the webhook ledger; audit rows carrying the installation id; memberships; and finally the installation record itself. Uninstalling the App on GitHub is a separate action and does not trigger this — see the next paragraph.

Uninstalling the App on GitHub deletes nothing. It flags the installation as uninstalled and keeps every row exactly as it was; a re-install of the same installation clears the flag and resumes runs. If a paid subscription is active, Corund also sets it to cancel at the end of the current billing period in Stripe — the subscription, trial and billing-event rows are not touched. Nothing here is deleted until, and unless, the installation owner separately chooses the self-serve delete described above.

What survives the self-serve delete. Rows in the events ledger are anonymised rather than deleted — the installation id, repository id and payload are set to null and only the event kind and time remain, so install counts never shrink because a tenant left. Your own account record (GitHub numeric id, login, display name) and your sessions survive, because they may belong to other installations; audit rows that name no installation, such as sign-ins, survive too. Stripe keeps its own records under its own retention.

An expired or revoked session is refused but its row is not purged.

14. Security

GitHub and Stripe webhooks are authenticated over the raw body before anything is parsed. Session tokens are stored hashed. A request for an installation you do not belong to gets the same not-found answer as one that does not exist. The App holds the least GitHub permission its checks need. Every response carries strict transport security, a content-security policy with no third-party script hosts, and frame denial. Report a suspected vulnerability privately to security@corund.dev; the repository's SECURITY.md has the details.

15. Your choices

Write to the contact address above to access, correct or delete information Corund holds about you, or with any privacy question. Corund serves business customers; where regional privacy rights apply to you, they are honoured as the law requires. Today that request is handled by hand, as section 13 describes; there is no self-serve export or erasure screen yet.

Corund is not directed at children and does not knowingly collect information from them.

16. Changes

Changes to this policy take effect when posted here; the version served is the one in force.