Documentation Index
Fetch the complete documentation index at: https://docs.pipefort.com/llms.txt
Use this file to discover all available pages before exploring further.
The big picture
Key architectural decisions
One scan engine, two callers
All detection lives in a single Go scanner package. The CLI reads from disk; the web API reads from the GitHub API. They both end up calling the sameScanBytes function:
Two independent auth concerns
Supabase Auth (GitHub provider)
Establishes who the user is. The SPA gets a JWT; the API verifies it (HS256) to extract the user ID for downstream queries.
GitHub App installation
Grants repo read access. The API mints installation tokens (RS256 app JWT) and links each installation to a user via
/api/github/callback.Read/write split around RLS
The React client reads Postgres directly through supabase-js. Every table has row-level security scoped toauth.uid() = user_id, so users can only see their own data even though they’re hitting Postgres with their JWT.
The Go API only handles privileged work — minting GitHub installation tokens, fetching/scanning, and writing scans + findings as the service role (which bypasses RLS). The findings table mirrors the scanner’s Finding struct 1:1.
Scan orchestration is client-driven
There is no server-side batch scan.POST /api/scan does one repo (fetch workflows → ScanBytes → persist). The SPA loops it across repos with bounded concurrency so each request stays within serverless time limits.
No git clone in the web app
The API pulls only the workflow YAML via the GitHub Git Trees/Blobs API and scans the bytes in memory, so each per-repo scan is sub-second and fits a serverless time budget. Org-wide scans are orchestrated client-side, one short request per repo, with live progress.
The CLI’s -g owner/repo mode does shallow-clone — it’s a one-shot local invocation, not a multi-tenant service.