Public Faktorial website plus the hosted GitHub App installation endpoint.
GET /serves the public Faktorial page.GET /bokabraserves the BokaBra case page;GET /bokabra.htmlredirects there.GET /asynkron-jsengineandGET /jsengineserve the Asynkron.JsEngine case page; the.htmlaliases redirect there.GET /comparisonserves the product comparison sheet;GET /product-sheetis an alias, and the.htmlaliases redirect there.GET /healthzreturns200 OK.GET /login?callback=http://127.0.0.1:<port>/callbackstarts CLI GitHub login.GET /api/mereturns the logged-in GitHub user for a Faktorial bearer token.POST /api/github/tokenexchanges a Faktorial bearer token and{ "repo": "owner/name" }for a short-lived GitHub installation token.GET /setup?installation_id=...&setup_action=installverifies the GitHub App installation and stores it in Supabase/Postgres.GET /github/setup?installation_id=...&setup_action=installis kept as a compatibility alias.GET /callbackcompletes GitHub OAuth login and redirects back to the CLI callback.
For the hosted SaaS app:
- Set Where can this GitHub App be installed? to
Any account. - Set Setup URL to
https://<your-domain>/setup. - Leave Request user authorization (OAuth) during installation off unless the SaaS needs to link the installing GitHub user.
- Leave Callback URL empty unless OAuth is enabled.
Required:
GITHUB_APP_ID=123456
GITHUB_APP_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----..."
GITHUB_OAUTH_CLIENT_ID=Ov23li...
GITHUB_OAUTH_CLIENT_SECRET=...
DATABASE_URL="postgresql://postgres:...@...supabase.co:5432/postgres"Optional:
PORT=8080
PUBLIC_BASE_URL=https://faktorial.aiGITHUB_APP_PRIVATE_KEY can contain literal newlines or escaped \n sequences.
The GitHub App callback URL must include https://faktorial.ai/callback for
CLI login to work.
Apply the versioned files in supabase/migrations before deploying. schema.sql
is retained for the original GitHub App installation table bootstrap.
go run .docker build -t faktorial-public .
docker run --rm -p 8080:8080 --env-file .env faktorial-publicTo publish the production image:
./build.sh
./build.sh 2026-04-26The script publishes rogeralsing/faktorialpublic:<tag>. When the tag is not
latest, it also updates rogeralsing/faktorialpublic:latest.
Authorized callers may send { "repo": "owner/name", "access": "contents-read" }
to the existing /api/github/token endpoint. The broker requests exactly that
repository and contents: read, then checks GitHub's returned permissions before
returning the token. Only implicit metadata: read is also accepted. The response
includes access, permissions, token and expires_at and is marked no-store.
An omitted access field preserves the existing CLI token permission behavior.
Unknown access modes fail instead of falling back to broader permissions.
Before contacting GitHub, the broker requires an exact
faktorial_repository_grants row for the authenticated GitHub user, repository,
and requested access mode. An omitted access field maps to the explicit legacy
grant. Missing grants fail closed with 403 Forbidden. Project pods must not
receive the Faktorial session or the app private key. Tokens still expire and
callers must renew before using them for a subsequent fetch. This change does not
implement Kubernetes rotation.
POST /api/github/token also accepts access: "worker-build". It requires an
explicit faktorial_repository_grants row for that exact access mode, GitHub user
and repository. Contents-read and legacy grants do not authorize this mode.
Apply migration 20260909214500_worker_build_repository_grants.sql before enrolling
worker-build grants; the migration itself grants nothing.
The token request names one repository and exactly contents: read,
pull_requests: write and issues: write. The broker verifies those permissions
in GitHub's response, allowing only the implicit metadata: read addition. This
mode supports reading worker commits and writing PRs/comments. It does not grant
code-write or repository administration access. Existing empty-access and
contents-read requests retain their behavior.
Validation: the Go race suite tests single-repository requests, exact permission confirmation, rejection of extra/missing rights and denial before any GitHub call when the session lacks a worker-build grant. The constraint migration was tested in a rolled-back local PostgreSQL transaction, preserving prior modes and rejecting an unknown mode. Production migration, grants and broker deployment are separate rollout steps and were not performed with this change.
A worker can turn its existing Faktorial session into one renewable, project-bound source credential without sending that session to the project:
POST /api/github/project-sourcewith the Faktorial session bearer and{ "repo": "owner/name", "project": "https://app.faktorial.ai/projects/<id>" }returns{ "repo", "project", "token" }. The response token is opaque; only its hash is stored. It is bound to that exact repository, Cloud project andworker-buildaccess mode.POST /api/github/project-source/tokenwith that opaque bearer and the same JSON returns{ "repo", "project", "access": "worker-build", "token", "expires_at", "permissions" }. It rechecks the exact repository grant on every renewal and mints one short-lived installation token for one repository.
Project URLs must be canonical https://app.faktorial.ai/projects/<id> values.
A token for another project or repository is rejected. The service never returns
Faktorial login sessions or the GitHub App private key.
When an agent needs a missing worker-build grant, it starts the existing GitHub
App user-login flow with repo=owner/name&access=worker-build. The OAuth token is
used only during that callback to verify GitHub reports exact repository push
access, then discarded. A successful check records the exact grant; ordinary
login requests do not create grants. The broker does not request broad repo
OAuth scope or infer access from repository visibility. If GitHub cannot prove
push access, the user must complete the explicit repository login after granting
the Faktorial GitHub App access.
Worker-build tokens request and verify only contents: write, pull_requests: write, issues: write, checks: read and statuses: read (plus GitHub's
implicit metadata permission). Apply
20260913153000_project_source_credentials.sql before enabling these routes.