Generated from cat-harness/skills/sdlc/sdlc-core/deployment-auth.md — do not edit here.

✎ Edit this page’s source

Deployment & Auth Skill

Role

Handles questions and tasks related to the folio deployment infrastructure, OAuth authentication, role-based access control, and server management.

Architecture Overview

Internet → Caddy (:443, auto TLS)
         → auth-gateway (:4180, Bun) — dual OAuth + role sessions
         → folio-mcp (:8080) — content API + MCP
         → static viewer/assistant files

Dual OAuth + Role System

Providers

ProviderRoleWhitelist fileCapabilities
Googleviewerdeploy/google-viewers.txtRead papers, submit feedback (with username)
GitHubcollaboratordeploy/github-collaborators.txtEdit/WYSIWYG, delete todos, manage branches
GitHub (owner match)ownerSame file, auto-detectedAll above + commit to main

Auth flow

  1. User visits folio → redirected to /login chooser page
  2. User picks Google or GitHub → OAuth flow with respective provider
  3. Auth-gateway checks whitelist → rejects if not listed
  4. Auth-gateway issues HMAC-signed session cookie with {email, name, provider, role}
  5. All subsequent requests carry cookie → auth-gateway injects X-User-Role headers
  6. API server reads headers and enforces permissions

Bearer token bypass

CLI/API clients can skip OAuth entirely:

curl -H 'Authorization: Bearer <FOLIO_API_TOKEN>' https://<folio-domain>/mcp

The API decides with ODRL (issues #1180, #1207)

Half built, 2026-09-23 (#1207). The API server no longer compares a viewer < collaborator < owner ladder. src/core/rbac.ts treats the gateway’s tier as a declared actor (viewer, collaborator, owner in cat-harness/scenarios/actors/), each route names the ODRL action it performs, and policies/http-gateway.jsonld says which tier holds which action. It reproduces what the ladder allowed. An explicit X-User-Actor header, once the gateway sends one, takes precedence over the tier. What is still to build is steps 1 and 4 below: the gateway mapping a login to a finer-grained actor, and a relationship engine. The same policies govern BPMN task execution (task-authorization).

The target, per the owner’s 2026-09-23 decisions:

  1. The data store authenticates (the auth-gateway here) and maps the login to an actor id. That mapping lives in the data store only; no actor file and no policy carries a login.
  2. It authorizes with the instance’s ODRL policies in policies/, by calling permits() (schemas/odrl.ts) with the actor, the action and the scope. unknown is a refusal, never a pass.
  3. An unauthenticated request is cat-harness:anyone, which the policies allow to visualize and render, and nothing else.
  4. A relationship engine (OpenFGA) is later, and the policies do not change when it arrives: the data store would compile them.

Until then the whitelists stay authoritative, and the table below still describes the running gateway.

Asking GitHub directly: auth_whoami

Without the gateway, the auth_whoami MCP tool (Tool node user-auth) asks GitHub for the caller’s login and repository role, and maps the role onto the same three gateway actors: admin → owner; maintain and write → collaborator; triage and read → viewer. A GitHub role covers the whole repository, never a sub-graph, node or query path. The trade-off is argued in task-authorization §”GitHub as the auth layer”.

CRITICAL: Whitelist Protection

NEVER modify these files:

  • deploy/google-viewers.txt
  • deploy/github-collaborators.txt

Only the repo owner can edit them manually. If asked to add/remove users, instruct the owner to edit the files directly and push to main. The self-updater will pick up changes within 60 seconds.

API Permission Matrix

EndpointMethodODRL action (held by)Notes
/api/paper, /api/folioGET— (anyone)Read-only
/api/feedbackGET— (anyone)Read feedback
/api/feedbackPOST— (anyone)Create feedback (author attached)
/api/feedbackDELETEreview-comments (collaborator, owner)Delete feedback items
/api/block/save, revert, upload, glossary curationPOSTcontent-authoring (collaborator, owner)Edit content
relevance adjudicationPOSTadjudication (collaborator, owner)Adjudicate a verdict
/mcpPOSTviewer (OAuth) or bearer tokenMCP protocol

Who holds what is policies/http-gateway.jsonld; change it there, not in a route.

Unified Docker Image

The folio deployment uses the same Docker image as all CI/CD workflows: the paper-assistant image.

Built by .github/workflows/build-folio-mcp.yml from adapters/mcp-server/Dockerfile, it includes everything needed to run the MCP server, build outputs, run the content pipeline, and execute CI scripts — all offline once pulled.

Image build triggers

TriggerFrequency
Push to main (content, MCP, CI scripts)On change
Weekly scheduleSunday 06:00 UTC
Manual dispatchbuild-folio-mcp.yml

Auto-deployment

The deploy/self-update-folio.sh cron script (runs every 60s on the server) polls the registry for new image digests and auto-deploys. Typical latency from merge to live: ~2-3 minutes.

LLM provider config

The llm section in folio-mcp.config.json configures which LLM backend the MCP server uses:

"llm": {
  "provider": "<provider>",
  "providers": {
    "<provider-a>": { "model": "<model>", "api_base": "https://..." },
    "<provider-b>": { "model": "<model>", "api_base": "https://..." },
    "local":        { "model": "<model>", "api_base": "http://localhost:11434/v1" }
  }
}

Switch provider by changing "provider". For local LLMs, start the local server before the MCP server.

Key Files

FilePurpose
folio-mcp.config.jsonCentral config (auth, LLM, image, domain)
adapters/mcp-server/DockerfileUnified Docker image (MCP + CI + build)
.github/workflows/build-folio-mcp.ymlImage build workflow
deploy/auth-gateway/server.tsAuth gateway service (Bun)
deploy/docker-compose.folio.ymlService orchestration (Caddy + auth-gateway + folio-mcp)
deploy/Caddyfile.folio.templateReverse proxy config template
deploy/generate-config.shGenerate .env + Caddyfile from config
deploy/self-update-folio.shAuto-update cron script
.github/workflows/deploy-folio.ymlCI: provision/update/destroy server
deploy/google-viewers.txtGoogle viewer whitelist (PROTECTED)
deploy/github-collaborators.txtGitHub collaborator whitelist (PROTECTED)

CI/CD Secrets Required

SecretPurpose
CLOUD_API_TOKENCloud infrastructure provisioning
GOOGLE_CLIENT_IDGoogle OAuth (viewers)
GOOGLE_CLIENT_SECRETGoogle OAuth (viewers)
GITHUB_OAUTH_CLIENT_IDGitHub OAuth (collaborators)
GITHUB_OAUTH_CLIENT_SECRETGitHub OAuth (collaborators)

Common Tasks

Add a new viewer

Instruct the repo owner to add their Google email to deploy/google-viewers.txt and push.

Add a new collaborator

Instruct the repo owner to add their GitHub username to deploy/github-collaborators.txt and push.

Rotate OAuth credentials

Run the “update” action in the Deploy Folio workflow after updating CI/CD secrets.

Debug auth issues

  1. Check /health endpoint (no auth)
  2. Check auth-gateway logs: docker logs auth-gateway
  3. Verify whitelist files are mounted: docker exec auth-gateway cat /etc/auth-gateway/google-viewers.txt
  4. Check cookie in browser DevTools → Application → Cookies

folio-assistant — code under the Apache License 2.0, documentation under CC BY 3.0. Generated schema and API references are rebuilt from source on every push to main.

deployed dev