Plan 76 milestone A, drift/bug row 2 — scheduled as a fix, not a refactor,
because it is a behaviour difference shipping today.
rbac.get_current_user() is the only lookup that knows about both auth
mechanisms: it returns g.api_key_user for an X-API-Key request and falls back
to the JWT. 73 call sites answered "who is calling" with
`User.query.get(get_jwt_identity())` instead, behind 19 near-identical private
helpers (12 named get_current_user(), shadowing the real door).
The audit that scheduled this row predicted those return None for API-key
callers. Measured, it is worse: auth_required() deliberately skips
verify_jwt_in_request() once the key middleware has authenticated, so there is
no JWT context and get_jwt_identity() *raises*. Nine handlers reached through
an API-key-capable policy decorator therefore returned 500 to every API-key
caller:
bandwidth.get_app_bandwidth @viewer_required
servers.set_server_workspace @developer_required
servers.create_server @developer_required
sso.get_sso_config / update_provider_config / update_general_settings
source_connections.update_{github,gitlab,bitbucket}_admin_config
source_connections.complete_github_app_manifest
databases.execute_{mysql,pg,sqlite,docker}_query (see below)
Three service helpers had the same lookup inside a blanket `except Exception`,
which converted the raise into a silent user_id=None — the write landed and
the audit trail lost the actor (shared_resource_service, cf_ops_change_service,
secrets_webhooks).
The four databases.execute_*_query sites were a second admin check *inside* an
already-@admin_required route: dead code that always passed for JWT callers and
crashed for API-key ones. They now call require_admin_user() rather than
re-deriving the answer.
Also folds in a sixth _require_admin() found in the cloudflare-ops extension
source (29 gates, the same inverted contract as jobs.py), and fixes
serverkit-gui's blueprint at its sibling-repo source rather than in this repo's
live copy.
Ratchet (second-wave rule 1 — a migration without one regrows):
tests/identity_door_census.py counts both bypass shapes by AST, direct and the
two-line `uid = get_jwt_identity(); User.query.get(uid)` variant. The ceiling is
87, all of them on @jwt_required()-only routes where reading the JWT is correct
today; the ratchet's third assertion holds the API-key-capable population at
exactly zero, so migrating one of those routes to a policy decorator without
fixing its lookup now fails. Verified non-vacuous: an injected bypass fails both
assertions and passes again on revert.
The first wave's controller-boundary baseline is regenerated — this removes 74
persistence crossings (593 -> 519), a debt reduction with no new entries.
Gate: tests/test_api_key_identity.py (7, each red before the fix),
test_identity_door_ratchet.py (10), test_api_controller_boundaries.py (4), plus
the 65 test files covering every touched module: 1024 passed, 10 skipped.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Connecting GitHub required hand-registering an OAuth app and pasting a client
id + secret — friction, and an open-source panel can't ship a secret anyway.
Now an admin sets it up in one click.
- backend: build_github_app_manifest / complete_github_app_manifest — hand
GitHub an app manifest, convert the returned code into credentials stored
locally (client id/secret in settings; PEM + webhook secret encrypted). No
shared secret in the repo or build.
- connect flow: when an app slug exists, generate_github_authorize_url points at
the app's install screen (grants repos + authorizes in one hop); repositories
are listed per-installation since GitHub Apps don't use /user/repos.
- get_github_config surfaces provider_kind/app_slug/app_name/install_url.
- routes: GET/POST /source-connections/admin/github/app-manifest[/complete].
- frontend: Settings -> Connections leads with "Set up in one click" (auto-POSTs
the manifest form to github.com); a new /connections/github-app/callback page
finishes setup and chains into connect. Manual OAuth app moves under
"Advanced". 7 proving tests (manifest shape, conversion+storage, install-url
routing, app-mode repo listing); ratchet 2498->2505.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds source-connection support for browsing repositories on GitLab, Gitea, and
Bitbucket (new *RepoPicker components) plus a PathSelector, wired through
RepoConnectForm / GitProviders / ConnectionsHub / providerCatalog and the
sourceConnections + files APIs, backed by additions to the source_connections
API and service.
Bundled from in-progress work in a concurrent session at the user's request.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Introduce a broad Connections expansion: add RegistrarConnection model, RegistrarService and /api/v1/registrars endpoints to surface domain portfolios and expiry. Add EmailRelayService and API routes plus Postfix relay wiring to configure/test/disable outbound SMTP. Extend DNSProviderService with DigitalOcean and GoDaddy implementations and helpers. Add GitLab support to source connection service and routes. Frontend: expand Connections hub, provider catalog, modal bodies, provider icons, RegistrarPortfolio component, API client methods and styles. Add docs/CONNECTIONS_ROADMAP.md describing roadmap and intent.
Introduce RepositoryManifestService to detect deployment manifests (ServerKit, Render, Railway, Compose, app.json, Dockerfile, Nixpacks) and recommend app/build settings. Add backend integration: analyze repo during import (apps.create_app_from_repository), new GitHub manifest API route, and SourceConnectionService helpers to list root files and fetch file contents from GitHub. Pass resolved dockerfile_path/custom build/start commands into build configuration. Add unit tests for the manifest service. Frontend: add template support and manifest UI in NewService.jsx, new API call inspectGithubRepositoryManifest, and related SCSS styles for templates/manifest display. Misc: updated imports and minor UX messaging changes.
Introduce source provider connections to allow OAuth-backed GitHub repository selection and authenticated cloning. Backend: add SourceConnection model, SettingsService keys for GitHub OAuth, and a SourceConnectionService that handles OAuth flow, token storage (encrypted), repo/branch listing, and authenticated clone URL generation. Expose new API blueprint under /api/v1/source-connections with endpoints for status, authorize, callback, repos, branches, disconnect, and admin config. Update app creation flow to accept source_connection_id and repository_full_name, use authenticated clone URLs for cloning/deploy, and sanitize clone errors to show public repo URLs. Frontend: add SourceConnectionsTab UI, source connection callback route/component, extend App routes, and revamp New Service page to support connecting GitHub, picking repositories/branches, or using a manual git remote; update API client and styles accordingly. Note: database migration will be required to create the source_connections table and admins must configure GitHub client ID/secret.