From 90bf8e649cde4ef12c3b3d8fe67be476407f0921 Mon Sep 17 00:00:00 2001 From: Xianpeng Shen Date: Fri, 4 Sep 2026 04:33:54 +0000 Subject: [PATCH 1/3] docs: add a privacy page for the GitHub App A Marketplace listing needs a privacy policy URL, and the site had no page describing what the hosted App reads, keeps and never sees. This one does, in terms a reviewer can check against the App's permissions: four permissions, a sparse fetch of the commits and the config file, nothing stored, logs that carry ids and SHAs but no author identity. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_018xYa7m3qup5wyN5MaXFgf6 --- docs/privacy.md | 57 +++++++++++++++++++++++++++++++++++++++++++++++++ mkdocs.yml | 1 + 2 files changed, 58 insertions(+) create mode 100644 docs/privacy.md diff --git a/docs/privacy.md b/docs/privacy.md new file mode 100644 index 0000000..1c51b91 --- /dev/null +++ b/docs/privacy.md @@ -0,0 +1,57 @@ +# Privacy + +This page describes what the **Commit Check GitHub App** reads, what it +keeps, and what it never sees. The command-line tool, the pre-commit hooks +and the GitHub Action run entirely inside your own environment and send +nothing anywhere; this page is about the hosted App only. + +## What the App reads + +When you install the App, GitHub grants it these permissions and nothing +else: + +| Permission | Level | Used for | +|---|---|---| +| Metadata | read | Knowing which repositories it is installed on | +| Contents | read | Fetching the commits under test and the repository's `cchk.toml` / `commit-check.toml` | +| Checks | write | Posting the **Commit Check** result on each commit | +| Pull requests | read | Listing the commits of a pull request | + +On every push and pull request event the App performs a shallow, sparse +fetch of the commits under test into a temporary directory: the commit +objects themselves and the configuration file, if any. **No other file in +the repository is ever fetched.** The rules are evaluated, the result is +posted as a check run, and the temporary directory is deleted before the +event is considered handled. + +## What the App keeps + +Nothing. The App has no database and stores no repository content, commit +messages, author details or configuration. Each event is processed from the +webhook payload and discarded. + +The hosting platform retains **operational logs** for a short period. A log +line carries the webhook delivery id, the commit SHA being checked, the id +of the check run created and, when a check could not run, the error text +the tool produced — never an author name or email, and never file content. + +## What the App never sees + +- Your source code beyond the configuration file named above +- Repositories the App is not installed on +- Anything at all if the webhook signature does not verify — unsigned or + mis-signed deliveries are rejected before they are read + +## Where it runs + +The App runs on [Fly.io](https://fly.io) in the `ams` (Amsterdam) region. +Traffic between GitHub and the App is encrypted in transit; GitHub signs +every delivery and the App verifies the signature before doing anything +else. + +## Contact + +Questions about this page or the App's data handling: +[open an issue](https://github.com/commit-check/commit-check/issues). + +_Last updated: 2026-09-03._ diff --git a/mkdocs.yml b/mkdocs.yml index c8b610e..fa9e3a5 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -163,5 +163,6 @@ nav: - Rules: rules.md - Configuration: configuration.md - Changelog: changelog.md + - Privacy: privacy.md - Blog: - blog/index.md From 0c0ab203be673438c700b22f9f4b7dd6f2d84102 Mon Sep 17 00:00:00 2001 From: Xianpeng Shen Date: Fri, 4 Sep 2026 04:42:25 +0000 Subject: [PATCH 2/3] docs(privacy): say precisely when a bad signature is rejected MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The signature is an HMAC over the raw body, so the body is received before it can be verified. Rejection happens before parsing, not before receipt — the previous wording claimed more than the mechanism allows. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_018xYa7m3qup5wyN5MaXFgf6 --- docs/privacy.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/privacy.md b/docs/privacy.md index 1c51b91..5c129fb 100644 --- a/docs/privacy.md +++ b/docs/privacy.md @@ -39,8 +39,10 @@ the tool produced — never an author name or email, and never file content. - Your source code beyond the configuration file named above - Repositories the App is not installed on -- Anything at all if the webhook signature does not verify — unsigned or - mis-signed deliveries are rejected before they are read +- The contents of a delivery whose signature does not verify. GitHub signs + the raw request body, so the App has to receive that body to check the + signature; an unsigned or mis-signed delivery is rejected at that point, + before anything in it is parsed or acted on ## Where it runs From aaaab9c1be7f64144695239e5041564962e059e2 Mon Sep 17 00:00:00 2001 From: Xianpeng Shen Date: Fri, 4 Sep 2026 04:44:21 +0000 Subject: [PATCH 3/3] docs(privacy): state exactly what crosses the wire MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "No other file is ever fetched" was true of the working tree and false of the object store: a plain fetch downloads every blob the commits reach. commit-check-app#13 adds --filter=blob:none, after which the sentence is true on the wire too. Say what is transferred — commit metadata plus the one config file — and that other contents never reach the temporary object store either. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_018xYa7m3qup5wyN5MaXFgf6 --- docs/privacy.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/docs/privacy.md b/docs/privacy.md index 5c129fb..34fe284 100644 --- a/docs/privacy.md +++ b/docs/privacy.md @@ -17,12 +17,15 @@ else: | Checks | write | Posting the **Commit Check** result on each commit | | Pull requests | read | Listing the commits of a pull request | -On every push and pull request event the App performs a shallow, sparse -fetch of the commits under test into a temporary directory: the commit -objects themselves and the configuration file, if any. **No other file in -the repository is ever fetched.** The rules are evaluated, the result is -posted as a check run, and the temporary directory is deleted before the -event is considered handled. +On every push and pull request event the App fetches the commits under +test into a temporary directory. The fetch is shallow and filtered +(`--filter=blob:none`), so what comes across the wire is the commit +metadata — message, author, timestamps, the list of paths each commit +touches — plus the contents of exactly one file: the configuration file, +if the repository has one. **The contents of no other file are ever +downloaded**, not even into the temporary directory's object store. The +rules are evaluated, the result is posted as a check run, and the temporary +directory is deleted before the event is considered handled. ## What the App keeps