security
What Fwozen can and cannot do.
Fwozen never reads or modifies source code, branches, workflows, or secrets. The only things it writes to GitHub are its own check runs, its own commit statuses on legacy branches, and, on an installation that has granted repository administration: write, the one ruleset that makes its own check required. It can edit no rule it did not create, and it deletes no rule at all. Every permission and every API call is listed on this page, along with where to read every ceiling. It is written so you can check it rather than trust it.
at a glance
writes
Five endpoints write to your repository: two check-run calls, the legacy commit status, and the create and repair of one ruleset. There is no DELETE.
the write rowsadministration
Repository scope only, granted per installation, bounded four ways. Organisation administration is never requested.
the administration askyour credentials
No GitHub token of yours is stored, in any form. The sign-in callback uses one inside a single function and drops it.
what the callback doesyour data
Repository metadata, plus the reasons and schedule names your team types. No diffs, no commit messages, no pull request titles or bodies, no committer email addresses.
what we storecompliance
Not SOC 2 certified, and no audit is in progress. The Type I starts when a paying customer’s procurement needs it.
where we stand todaypermissions
Permission by permission.
checkswrite
Create and update the fwozen check run that blocks the merge.
not allowedReading file contents, or writing anything except our own check runs.
statuseswrite
The legacy fwozen/status mode, for orgs still on classic branch protection.
not allowedReading code, or modifying another app’s statuses.
pull_requestsread
List open pull requests so we know which head SHAs to write to.
not allowedReading diffs. We do not request patch contents.
contentsread
GitHub requires it to deliver push events and to read the default branch ref.
not allowedWe never call the contents API for file data. This permission is the single most common misreading of a GitHub App’s scope. See the note below.
metadataread
Repository names and visibility. Mandatory for every GitHub App.
not allowed—
merge_queuesread
Receive merge_group events so a queued pull request cannot slip through a freeze.
not allowedModifying the queue.
Organization membersread
Verify that the person clicking Freeze is in your org.
not allowedReading profile data beyond membership, and no email address. The one email permission is an account permission, the row below this table.
administrationwriteon approval
A new installation grants this. An installation made before Fwozen asked for it keeps its old set until an organisation owner accepts the change. The install screen you will see asks for it, and an organisation owner approves it there. It buys one thing: writing the repository ruleset that makes the fwozen check required on a branch you enrolled, with the App’s own short-lived installation token. No GitHub credential of yours is stored or used.
not allowedAnything at organisation scope. Organisation administration is not requested in either direction. On a repository it cannot edit or delete a rule of yours, writes no classic branch-protection rule, and writes nothing to a repository marked as managed as code. It is not what freezes anything.
Fwozen asks for all eight of these rows. Every live installation grants at least seven of them today. The one marked on approval is repository administration, granted by every new installation, and by an older one when its owner accepts it. The install screen you will see asks for it, and an organisation owner approves it there. Until your own installation has granted it, enforcement setup stays a rule you save yourself.
The freeze is a check run, not a rule.
While a freeze is on, Fwozen’s own fwozen check reports failure, and that is what a merge meets. A ruleset only makes that check required. It is never the thing holding the freeze. So you can let one pull request through with a per-PR exception, without touching a rule. A repository whose rules live in your Terraform can be enforced with Fwozen writing nothing to it. And removing Fwozen leaves every rule you wrote where it is. None of that is available to a tool whose freeze is the rule change. One rule on your repository will not be yours. Fwozen writes the required-check ruleset itself where you ask it to, which is reachable only where an installation has granted repository administration. That ruleset stays behind when Fwozen goes, because nothing here deletes a ruleset, and while it is there it keeps requiring a check that has stopped reporting. Delete that one when you uninstall.
and one account permission, a different axis
Everything above is the repository and organisation axis: what a GitHub organisation grants when it installs Fwozen on its repositories, including the row marked on approval and the count note under the table. The App also requests one account permission, granted by the individual signing in rather than by the organisation. It is not part of an installation’s repository access, and it is listed here so what you read on this page is what GitHub’s consent screen shows you.
Email addressesread
Sign-in identity, and only that. Fwozen runs its own authorization server and identifies a person by their verified GitHub email. An account whose address is private returns no email at all from the sign-in callback, and that person cannot be identified.
not allowedAny access to a repository, an organisation, or anybody else’s address. The person signing in grants it, not the organisation installing the App, and it is not part of an installation’s repository access.
the administration ask
One permission needs its own section.
Repository administration: write buys exactly one thing. Fwozen writes the ruleset that makes the fwozen check required on a branch you enrolled, with the App’s own short-lived installation token, instead of walking you through saving that rule by hand. A freeze tool that works by toggling branch protection needs the same permission for as long as it is installed, and its freeze IS the rule change. Fwozen’s freeze is a check run, so this permission writes that one rule, and repairs it if it drifts. That is the whole of it.
where it stands
One-click setup is live. It runs on an installation that has granted the permission, which every new installation does, and an older installation keeps the guided path below until an owner approves.
The guided path costs one native GitHub rule, saved once by a person who already has that authority. Fwozen writes the current fwozen result to every branch tip, open pull request head, and live merge-group head first. Then it opens the exact GitHub Rules settings page with the values to enter, and verifies the ruleset when you come back. The save is yours. Everything on either side of it is ours.
That path is also what runs at organisation scope, and on any repository you have marked as managed as code.
the four bounds
It cannot edit or delete a rule of yours.
Repair can only name a ruleset id Fwozen’s own write ledger holds, and nothing but our own successful create puts an id there.
There is no delete verb.
No endpoint in the call list below deletes a ruleset. What Fwozen writes, only you can remove.
Organisation administration is never requested.
An organisation ruleset and your organisation’s own settings stay out of reach. The second entry in what we never ask for, below, states that at full width.
A repository managed as code is refused.
Mark a repository as managed as code, on its own page in Fwozen, and the writer refuses before a call is made.
None of these bounds is what freezes anything. The freeze is the check run claimed under the table above.
never requested
What we never ask for.
contents: write
Never, under any circumstance. Fwozen reads no file contents, no commits and no diffs, and nothing it writes to GitHub is a file: its own check runs, its own commit statuses, and the one ruleset that makes its check required.
organisation administration: read or write
Neither, in either direction. Fwozen cannot create, edit, or delete an organisation ruleset, and cannot read or change an organisation setting, so enforcement at organisation scope stays a rule you save yourself. Repository administration is a different permission, and Fwozen does ask for it. It is the eighth row above, and it has a section of its own on this page.
Slack user-token scopes
None. The Slack app is bot-only.
Slack message history
None. Fwozen reads its own slash commands and nothing else.
issues, workflows, deployments, secrets, packages, actions
None of them.
the contents scope
Why contents: read looks scarier than it is.
This is the single most common misreading of a GitHub App’s scope, so it gets its own section. GitHub bundles push event delivery behind contents: read. We need push events to know when a pull request’s head commit moved, because that is the commit we write the fwozen check to.
The permission would also allow reading file contents. We do not do that. You don’t have to take that on faith. The list below is every GitHub API call Fwozen makes, and nothing on it returns a byte of your code. If a future feature ever needed a content endpoint, it would appear there and in the changelog before it shipped.
api calls
Every GitHub API call we make.
The complete list, not a sample. Five rows write to your repository: two check-run calls, the legacy commit status, and the create and repair of the one ruleset that makes the fwozen check required, reachable only where an installation has granted repository administration. There is no DELETE on this list, nothing writes a branch protection rule, and nothing reads a line of your code. Everything else reads metadata.
writesPOST /repos/{owner}/{repo}/check-runs
Create the fwozen check run, and fwozen/deploy-gate where you enabled it.
App
writesPATCH /repos/{owner}/{repo}/check-runs/{check_run_id}
Update our own check run on thaw, exception, or a new head commit.
App
writesPOST /repos/{owner}/{repo}/statuses/{sha}
Legacy commit-status mode, only on branches where your org selected it.
App
POST /graphql — repository.pullRequests
One query per 100 open pull requests: number, head SHA, draft/approval/auto-merge state, and the ids of our own check runs. No titles, no bodies, no diffs.
App
GET /repos/{owner}/{repo}/rules/branches/{branch}
Read the effective branch rules, to verify a freeze would block a merge.
App
GET /repos/{owner}/{repo}/git/ref/{ref}
Resolve a watched branch’s current tip when we have seen no push since install, so guided setup can write the real policy result to it. Covered by Contents (read).
App
GET /repos/{owner}/{repo}/rulesets/{ruleset_id}
Two reads, one endpoint. The first is a best-effort detail read of a contributing ruleset, for bypass actors. GitHub rarely discloses a ruleset’s bypass list to the app reading it, and holding repository administration has not been measured to change that. So this call usually tells us nothing, and we report bypass assurance as unknown rather than as none. The eighth row of the table above says where that permission stands. The second read is the read-back after a one-click setup write. Fwozen reads that rule back from GitHub before the product or your audit log says it exists.
App
writesPOST /repos/{owner}/{repo}/rulesets
Reachable only on an installation that has granted repository administration: write. One-click enforcement setup: create the repository ruleset that makes the fwozen check required, with your default branch, our check pinned to our App id, and an empty bypass list. It writes with the App’s own short-lived installation token, and writes nothing to a repository you have marked as managed as code. The rule it writes is byte-identical to the gh api and Terraform snippets the setup page shows you, because the rule and both snippets come from one object.
App
writesPUT /repos/{owner}/{repo}/rulesets/{ruleset_id}
Reachable only on an installation that has granted repository administration: write. Repair a ruleset Fwozen created, by re-pinning our check or re-activating a rule left in evaluate mode. Only ids in our own write ledger are eligible, so a rule of yours is out of range. There is no endpoint here that deletes a ruleset at all.
App
GET /orgs/{org}/rulesets/{ruleset_id}
The same best-effort detail read when the rule requiring our check comes from an organisation ruleset rather than a repository one. Under this manifest it usually answers 403 or 404, which keeps bypass assurance at unknown. Nothing about the required-check verdict depends on it.
App
GET /repos/{owner}/{repo}/branches
Populate the branch picker when you add a watched branch.
App
GET /repos/{owner}/{repo}/collaborators/{username}/permission
Check that the person clicking Freeze is allowed to freeze this repository.
App
GET /user/{account_id}
Read the public login of one numeric GitHub user id, so the sign-in you already completed can be matched to the account the row above is checked against. We ask only while we do not already hold your login, through installations you have already granted, and an organisation with several installations may be asked through more than one. It reads the public profile of that one id and nothing else.
App
POST https://github.com/login/oauth/access_token
Exchange the authorization code you granted for a user-to-server token, when you link your GitHub identity. The token lives in that one function call. It is never written to a column, a queue, a log, or your browser, and we discard the refresh token unread.
Code exchange, no token yet
GET /user
Read the id and login of the person who just authorised, so each freeze can be attributed to a GitHub identity. Nothing else, and only during that callback.
Your OAuth, transient
GET /user/memberships/orgs
Org claim only. Confirm that you administer the GitHub organisation you are claiming. Reads membership, nothing else, in the same callback.
Your OAuth, transient
POST /app/installations/{installation_id}/access_tokens
GitHub’s own endpoint for minting a short-lived installation token.
App JWT
GET /app/installations/{installation_id}
Read back what your installation has actually granted: the permission list, the subscribed events, and whether it covers all repositories or a chosen few. Fwozen repairs its own copy of that list from this call when GitHub’s notification of a change is lost, so the product never claims access you did not grant, or hides access you did. It authenticates as the App itself rather than as your installation, which is why it reads no repository and can name no branch, file or pull request.
App JWT
“App” means a short-lived installation token scoped to the permissions in the table above. The two rows marked transient, and the code exchange above them, run only inside the callback that links your GitHub identity and proves your organisation claim. That callback uses the token inside one function and then drops it. The token never reaches a database column, a queue payload, a log line, or your browser, and we discard the refresh token unread. Fwozen holds no GitHub credential of yours between requests, and no part of enforcement or verification depends on one. No call here reads file contents, commit messages, pull request bodies, workflows, or secrets.
agent surfaces
What a program can reach, without a browser.
The table above is what Fwozen can do inside your GitHub organisation. This one runs the other way. It lists what an autonomous client can reach on our own hosts, what a stolen key would reach, and where the ceilings are. An autonomous client here is an LLM agent, a CI job, or an MCP client. The same test that keeps the GitHub-call list exhaustive checks every row here against the shipped code. The endpoint-by-endpoint walk-through is on the agent policy page.
Answered with no credential at all
GET /v1/plans
The Free/Team/Business ladder with prices, limits, capabilities and trial terms, so an agent can read what Fwozen costs before it has an account to authenticate with.
why that is safeA static catalogue compiled into the build. It performs no database read, so there is no tenant data for it to leak and nothing for an attacker to enumerate.
GET /v1/github/oauth/callback
GitHub returns your browser here after you authorise the identity link. A top-level navigation cannot carry an Authorization header, which is the whole reason this endpoint has none.
why that is safeIt authorises on the signed single-use state nonce it minted, and it grants nothing. It hands the browser a ticket that a signed-in session has to redeem separately. Whoever completes a GitHub round trip never gets to name the account it is written to.
GET /healthz
Liveness for the hosting platform. Says the process is up.
why that is safeNo database read, no tenant data, no detail beyond the build tag.
GET /readyz
Readiness. Reports whether this replica has the migrations it expects, so a replica whose pre-deploy step did not run never takes traffic.
why that is safeCounts applied migrations. It reads no tenant table.
GET /
The API root. A short JSON index of the documents below it, so a developer who types the API hostname into a browser gets the spec, the docs and the reference rather than a 404.
why that is safeA list of URLs built from this deployment’s own origins. It reads nothing, and every document it names is already public.
GET /openapi.json
The published OpenAPI document for the whole API.
why that is safeGenerated from the route manifest at build time. Publishing the shape of an API is not publishing its data. Every route in it still demands its own credential.
GET /v1/openapi.json
The same document under the versioned prefix, for clients that expect it there.
why that is safeByte-identical to the one above.
GET /llms.txt
The machine-readable map of Fwozen, for an LLM agent that has just arrived.
why that is safeStatic prose compiled from the same manifest. No per-request work, no tenant data.
GET /llms-full.txt
The same map plus the documentation corpus.
why that is safeStatic prose. No per-request work, no tenant data.
GET /auth.md
The agent-registration guide (auth.md convention): the user-claimed device flow, the statement that agent-verified/assertion-based registration is unsupported, and what credentials registration yields.
why that is safeStatic prose built from the same public constants as the other discovery documents. The device-flow client id is public by design, and nothing here authorises anything on its own.
GET /.well-known/fwozen-app
Discovery: the App slug, the install URL template, the auth scheme summary, and where the spec and the skills index live.
why that is safePublic configuration facts only. The device-flow client id it names is public by design. It identifies the application and authorises nothing on its own.
If an API key leaked, scope by scope
freeze:read
List freezes, freeze targets and freeze state, including the deploy-gate endpoint.
cannotStart, lift or extend anything.
freeze:write
Start a freeze, lift one, extend one, create a thaw override, retry targets.
cannotChange what a branch is protected by, or who may bypass it. No key scope reaches the ruleset writer: setting enforcement up is a signed-in action, a key is refused there outright, and there is no scope in this list that would grant it.
schedule:read
List schedules, occurrences and previews.
cannotCreate or change a schedule.
schedule:write
Create, edit, delete, skip and import schedules.
cannotRun one immediately. That stays a signed-in action.
exception:read
List per-PR exceptions and exception requests.
cannotGrant or revoke one.
exception:write
Grant, decide and revoke per-PR exceptions.
cannotWiden a freeze, or exempt anything larger than a single pull request.
repo:read
List repositories, watched branches and enforcement state; poll an installation you started.
cannotEnable a repository, or read a single line of code in one.
repo:write
Enable or disable repositories, change repository and watched-branch settings, re-sync the mirror. The one repository setting is “managed as code”, which stops Fwozen writing an enforcement rule there.
cannotEnable a repository implicitly, or UN-mark one as “managed as code”. Enrolment always names the repositories explicitly, because enrolling a private repository is what Fwozen bills on. Clearing the managed-as-code flag re-arms the rule writer against a repository somebody fenced off, so it takes a signed-in person. A key setting the flag only ever narrows what Fwozen may do.
audit:read
Read the audit log and stream the CSV export.
cannotModify or delete an audit row. The table refuses UPDATE and DELETE in Postgres itself, not by convention.
billing:read *
Read the billing summary, plan, trial state and resolved entitlements.
cannotSee a card, or an invoice. Fwozen never holds card details. Stripe does.
billing:write *
Start the 14-day no-card trial, and ask for a Stripe Checkout or Customer Portal link.
cannotPay for anything. Both of those endpoints return a URL for a human to open and accept no payment details, so a key holding this scope cannot complete a purchase, change a plan or cancel a subscription. The trial it can start collects no card and never converts to a charge.
Scopes marked * are the ones the key-creation form leaves unticked, so a key carries them only if somebody ticked them.
Keys declared as an agent’s
An agent key must carry an expiry, of at most 90 days.
A person can mint a deliberate never-expires key behind an explicit confirmation. An agent key is the credential most likely to be pasted into a config nobody revisits, and there is nobody to ask later. So the window is compulsory, and we refuse a request for a longer one rather than silently shortening it.
The kind is declared by whoever mints the key. It is never detected.
Nothing about a request distinguishes an autonomous agent from a shell script. Same token, same headers if it wants them. Recording what the creator said is the only honest option, and it is what makes the disclosure below possible.
Every action an agent key takes is marked as one, permanently.
The key id, its name and its kind go into the immutable actor label on the freeze, exception or audit row, so a Slack message, a CSV export and a years-old audit entry all show that an agent acted, distinct from the person who authorised it.
No key of any kind can mint another key.
Key management is signed-in only, always. Machine tokens that can issue machine tokens are the most common privilege-escalation bug in systems like this one, and the rule predates agents entirely.
What stops a machine doing it a thousand times
Creating organisations
Capped per person per day, and capped on how many you may hold at once with no GitHub App ever installed.
when it trips429 with Retry-After. The second limit is a live count rather than a counter, so installing on one of them clears it at once.
Writes per credential: freezes, repository enrolment, branch changes
A per-credential ceiling, by API key id or user id, in front of your organisation’s own, so one retry-happy client cannot spend the whole organisation’s budget. It applies to the MCP tools that adapt those routes exactly as it applies to the routes.
when it trips429 with Retry-After. Lifting a freeze is deliberately exempt from THIS bucket. Throttling the way OUT of a freeze would turn a fairness mechanism into an outage. It is not exempt from your organisation’s own ceiling, which the limiter charges first. A lift is an ordinary write there and can still answer 429, so honour Retry-After on a lift like any other write.
The 14-day no-card trial
One per organisation, and one per person.
when it trips409. Creating another organisation does not produce a second trial. The ledger keys on the person, not on the tenant.
Everything else
The per-tier read, write and deploy-gate ceilings, readable from GET /v1/entitlements.
when it trips429 with Retry-After. The limiter fails OPEN when its own storage is unavailable. A rate limit must never look like a freeze outage.
Reading a ceiling
Every /v1 response that carried a credential carries RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset, and a 429 carries Retry-After. The exceptions are the two credential-free routes listed above. GET /v1/plans and GET /v1/github/oauth/callback sit outside the organisation bucket, so they carry no rate headers and you cannot read a budget off them. We publish no figure on this page, because these are operational settings rather than promises. Size a retry budget from the headers, never from prose.
when it tripsNothing to trip. These are headers, on every credentialled answer, including the refusals.
Two structural rules hold across every row above, and they are the ones worth checking. A fwz_ key can never mint another credential. Key creation takes a session, so a leaked key cannot widen its own scopes or extend its own life. And nothing in this API completes a payment. The checkout and billing-portal routes hand back a URL for a person to open, so an agent cannot spend money on your behalf by accident.
outages
If Fwozen goes down.
Partly, and the precise answer matters more than the reassuring one.
A freeze writes an explicit failing fwozen check to every open pull request in scope. That result is stored on GitHub, not on us. If Fwozen goes down mid-freeze, those pull requests stay blocked. GitHub is enforcing a verdict we already wrote, and nothing about our being unreachable clears it.
What an outage costs you is new work. A pull request opened during the outage, or a new commit pushed to an existing one, needs a check written to a head commit we have never seen, and if we are down, nothing writes it. We tested whether a missing required check blocks a merge on its own. It did not reliably block, so we do not claim it does. Onboarding writes the real current verdict before the rule exists: a pass on an unfrozen branch, a failure on a frozen one. During an outage that written state is what governs. Those pull requests merge normally.
When we come back, the reconciler re-enumerates every open pull request in scope and re-asserts the freeze, so state converges without anyone doing anything.
That is the trade of writing explicit results instead of relying on absence: freezes already in force keep holding through an outage, and work that appears during one can get through until we recover. We chose it because the alternative turned out not to be true when we measured it.
A thaw is a write too. The Monday 09:00 lift on a scheduled freeze, and the expiry of a freeze you gave a time limit, are both jobs we run. If we are down when one is due, the branch stays frozen. The scheduled lift and the expiry sweep both catch up when the worker comes back, and neither needs anyone to do anything. We are not going to promise you a number of minutes for that, because we have not measured one.
You are not locked out while you wait. Any repository admin can disable or delete the fwozen ruleset, or take the fwozen check out of the required list, in GitHub’s own settings. Merges flow again immediately, and it is your rule to change with or without us. Fwozen does not write that rule back on its own: it is written again only when somebody in your organisation clicks Apply or calls the enforcement API.
The deploy gate is the opposite trade, on purpose. A deploy asks us a question, and a question we cannot answer is not a yes. A timeout, a non-2xx, or a missing header all count as frozen, so an unreachable Fwozen stops deploys rather than waving them through. The escape hatch is in your workflow rather than in our settings: the Action takes a fail-open input, and setting it true means an outage lets the deploy run.
leaving
Leaving Fwozen.
The order matters, and it is the opposite of the obvious one. Take the rule off the branch first, then remove the App.
first
Thaw, or let the freeze expire
Uninstalling ends every freeze Fwozen holds anyway, and the audit log keeps the row. Doing it deliberately means the last state your team sees is one somebody chose.
second
In GitHub, un-require the check
Disable or delete the fwozen ruleset, or take the fwozen context out of the required list on that branch. Do this while the App is still installed. Once it is gone, nothing can write that check again, and a required check that never reports is a branch nobody can merge to. This is the residue we would rather you read here than find on a blocked pull request.
third
Uninstall the App
Every freeze ends, every schedule is cancelled, and the organisation’s data is deleted 30 days later unless you reinstall inside that window. Audit history is retained until that deletion runs, and it is the only path that removes those rows.
and separately
Cancel the subscription
Uninstalling the App does not cancel a paid plan. Cancel it in billing settings, or write to us and we will. We would rather say that in advance than argue about it in a refund thread.
Nothing you configured lives only with us. The rule is yours, in your GitHub settings, written in values you can read; the freezes are check runs GitHub stores; the record exports as CSV or JSON on Business.
data
What we store, and what we don’t.
stored
- Repository ids, names, and visibility
- Branch names
- Pull request numbers and head commit SHAs
- GitHub logins of the people who act in Fwozen
- Freeze reasons, exception reasons, and schedule names, all user-authored text
- Slack workspace, channel, and user ids
Freeze and exception reasons are text your team writes, and Fwozen shows them on pull requests and in Slack. Don’t put secrets in them.
not stored
- Source code, in any form
- Diffs or patch contents
- Commit messages
- Pull request titles or bodies
- Committer email addresses
- Any token in plaintext
- Your GitHub access or refresh tokens, in any form. The identity callback uses one and drops it
This is a code path, not a promise. Fwozen projects each webhook payload the moment it arrives, reduces commits to SHAs, and drops titles, bodies, and email addresses before anything is persisted. A unit test over real GitHub push and pull_request fixtures asserts those keys are absent.
where
Railway, US region. Postgres 17, encrypted at rest; TLS in transit. No production data on laptops.
how much you can see
Visible audit history follows your plan: 7 days on Free, 90 on Team, unlimited on Business. This is a read filter, not a delete. Older records still exist and come back the moment you upgrade. Freeze history is not filtered on any plan.
deletion
Delete your organisation in the app and the data goes. After cancellation, we purge private data within 30 days. Sooner on request.
subprocessors
Subprocessors.
The same list appears in the privacy policy, rendered from the same source, so the two cannot drift.
Railway
Application hosting and Postgres, US region
seesEverything Fwozen stores
Stripe
Payments, invoices, tax
seesBilling contact, address, card token (Stripe holds the card, we never see it)
Slack
The Slack app and freeze notifications
seesWorkspace and channel ids, freeze reasons posted to your channel
GitHub
The product itself
seesRepository, branch, and pull request metadata; check run results
PostHog
Product analytics on explicit events, autocapture off
seesAnonymous usage events, org id, no repository names
compliance
Where we are on compliance.
We are not SOC 2 certified and no audit is in progress. We will start a Type I when a paying customer’s procurement requires it, and this line changes the day we sign an engagement.
If your procurement process requires a report today, we are the wrong choice today, and we would rather you found that out on this page than in week three of an evaluation.
Three things a questionnaire asks that are not answered above: a dated restore test, a dependency-scanning step in the build, and a written incident-notification window. None of the three is in place, so none of them is a tick here. Mail [email protected] and you get the state of each one as it is on the day you ask.
what we do have
- Encryption in transit and at rest
- Least-privilege GitHub scopes, itemised above
- An append-only audit log with a real actor on every row
- Tenant isolation with org-scoped queries, verified by a generated cross-tenant test suite
- Read-only, recorded support impersonation
- No production data on developer machines
operations
- Fwozen is one person. Production access is that person’s, and there is nobody else it could be granted to
- Postgres 17 on Railway, US region, encrypted at rest, TLS in transit
- No GitHub credential of yours is held in any form, so there is none here to take
- A leaked API key cannot mint another credential or widen its own scopes: key creation takes a browser session
disclosure
Reporting a vulnerability.
Mail [email protected]. We acknowledge within 72 hours, we will not threaten you with lawyers, and we will credit you unless you ask us not to.
We have not published a PGP key yet. Ask at [email protected] and we will send you one.