refactor(service-config): relocate forgejo_url into operator_oauth_tokens.base_url (PR C) #828

Merged
charles merged 1 commit from refactor/forge-url-relocation into main 2026-05-04 17:59:03 +00:00
Collaborator

Summary

PR C of the URL-consolidation series (specs/service-config-url-consolidation.md). Stacks on top of PR #827 (refactor/service-config-consolidation) — base branch is set accordingly so the diff only shows PR C's net changes once #827 lands.

Every URL now lives with its credentials. For Forgejo that means operator_oauth_tokens.base_url (forge_type='forgejo') — the URL the operator actually authenticated against — becomes the single source of truth. The pre-#823 home (service_config.forgejo_url) gets dropped.

What changes

Server

  • New migration 016-drop-service-config-forgejo-url.ts — logs a warning on divergence between the service-config value and the OAuth row's base_url, then ALTER TABLE service_config DROP COLUMN forgejo_url. Idempotent via PRAGMA table_info.
  • getForgejoUrl() switches source: operator_oauth_tokens.base_urlFORGEJO_URL env (bootstrap-only) → hardcoded default. Cheap base_url-only lookup avoids decrypting tokens. Fresh on every call (no in-memory cache).
  • WebhookConfig.forgejoUrl field deleted; every prior cfg.forgejoUrl reader switches to getForgejoUrl().
  • ServiceConfigRow / ServiceConfigRowRaw / SERVICE_CONFIG_DEFAULTS / PresetServiceOverrides / service-config HTTP handler all trim forgejo_url.

SPA

  • Forge tab removed from /settings/service. Tab bar collapses to Container · Watchdogs · Design. Page subtitle now points operators at /login (the OAuth dance). The proper editor surface returns in PR D once the sub-routes restructure (specs/settings-service-subroutes.md) lands.
  • ServiceConfigSettingsRow / ServiceConfigSettingsPatch types lose forgejo_url.

Tests

  • Every test that seeded service_config.forgejo_url switches to seeding operator_oauth_tokens (forgejo row).
  • webhook-config.test.ts SVC-2 block becomes a PR C block: covers (1) operator_oauth_tokens.base_url winning, (2) FORGEJO_URL env fallback, (3) hardcoded default fallback.

Bootstrap path

For fresh installs without an OAuth row yet, the loader falls back to the FORGEJO_URL env var (then the hardcoded default). PR D adds the inline editor that lets the operator change the URL post-OAuth.

Test plan

  • just qa — 3135/3135 server tests + web typecheck green
  • just restart — service running on the new helper; live DB's service_config no longer carries forgejo_url, operator_oauth_tokens.base_url is the single source
  • After #827 merges: rebase this onto main and verify the diff stays clean
  • After PR D: verify the inline editor in the restructured Forge sub-route writes through to operator_oauth_tokens.base_url

Follow-up

PR D — surface the per-forge OAuth client/secret editors in the Forge sub-route, with the URL editable inline alongside the credentials. Spec'd in specs/service-config-url-consolidation.md PR D section.

🤖 Generated with Claude Code

## Summary PR C of the URL-consolidation series (`specs/service-config-url-consolidation.md`). Stacks on top of PR #827 (`refactor/service-config-consolidation`) — base branch is set accordingly so the diff only shows PR C's net changes once #827 lands. Every URL now lives with its credentials. For Forgejo that means `operator_oauth_tokens.base_url` (forge_type='forgejo') — the URL the operator actually authenticated against — becomes the single source of truth. The pre-#823 home (`service_config.forgejo_url`) gets dropped. ## What changes **Server** - New migration `016-drop-service-config-forgejo-url.ts` — logs a warning on divergence between the service-config value and the OAuth row's `base_url`, then `ALTER TABLE service_config DROP COLUMN forgejo_url`. Idempotent via PRAGMA table_info. - `getForgejoUrl()` switches source: `operator_oauth_tokens.base_url` → `FORGEJO_URL` env (bootstrap-only) → hardcoded default. Cheap base_url-only lookup avoids decrypting tokens. Fresh on every call (no in-memory cache). - `WebhookConfig.forgejoUrl` field deleted; every prior `cfg.forgejoUrl` reader switches to `getForgejoUrl()`. - `ServiceConfigRow` / `ServiceConfigRowRaw` / `SERVICE_CONFIG_DEFAULTS` / `PresetServiceOverrides` / service-config HTTP handler all trim `forgejo_url`. **SPA** - Forge tab removed from `/settings/service`. Tab bar collapses to **Container · Watchdogs · Design**. Page subtitle now points operators at `/login` (the OAuth dance). The proper editor surface returns in PR D once the sub-routes restructure (`specs/settings-service-subroutes.md`) lands. - `ServiceConfigSettingsRow` / `ServiceConfigSettingsPatch` types lose `forgejo_url`. **Tests** - Every test that seeded `service_config.forgejo_url` switches to seeding `operator_oauth_tokens` (forgejo row). - `webhook-config.test.ts` SVC-2 block becomes a PR C block: covers (1) operator_oauth_tokens.base_url winning, (2) `FORGEJO_URL` env fallback, (3) hardcoded default fallback. ## Bootstrap path For fresh installs without an OAuth row yet, the loader falls back to the `FORGEJO_URL` env var (then the hardcoded default). PR D adds the inline editor that lets the operator change the URL post-OAuth. ## Test plan - [x] `just qa` — 3135/3135 server tests + web typecheck green - [x] `just restart` — service running on the new helper; live DB's `service_config` no longer carries `forgejo_url`, `operator_oauth_tokens.base_url` is the single source - [ ] After #827 merges: rebase this onto `main` and verify the diff stays clean - [ ] After PR D: verify the inline editor in the restructured Forge sub-route writes through to `operator_oauth_tokens.base_url` ## Follow-up PR D — surface the per-forge OAuth client/secret editors in the Forge sub-route, with the URL editable inline alongside the credentials. Spec'd in `specs/service-config-url-consolidation.md` PR D section. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Picks up where PR B (#827, refactor/service-config-consolidation) leaves off.
Every URL now lives with its credentials — for Forgejo that means the
`base_url` column on `operator_oauth_tokens` (forge_type='forgejo'),
which the OAuth dance already populates from the URL the operator
authenticated against. The pre-#823 home (`service_config.forgejo_url`)
is now redundant and gets dropped.

Server changes:

- Migration `016-drop-service-config-forgejo-url.ts` — logs a warning
  when `service_config.forgejo_url` diverges from
  `operator_oauth_tokens.base_url` (OAuth value wins after the migration),
  then `ALTER TABLE service_config DROP COLUMN forgejo_url`. Idempotent
  via PRAGMA table_info.
- `getForgejoUrl()` switches source: `operator_oauth_tokens.base_url` →
  `FORGEJO_URL` env var → hardcoded default. Cheap base_url-only lookup
  avoids decrypting the access/refresh tokens on every call. Fresh on
  every call — no in-memory cache.
- `WebhookConfig.forgejoUrl` field deleted; every prior `cfg.forgejoUrl`
  / `webhookConfig.forgejoUrl` reader switches to `getForgejoUrl()`
  (main.ts, board.ts, pipeline.ts, forgejo-api.ts, forgejo-oauth.ts,
  architect-agent-dispatch.ts).
- `service_config_settings` HTTP handler drops the field from the PUT
  body validator + INSERT statement; ServiceConfigRow / ServiceConfigRowRaw
  / ServiceConfigSettingsRow / SERVICE_CONFIG_DEFAULTS / PresetServiceOverrides
  all trim `forgejo_url`. The setup-wizard preset writer no longer needs
  to set it (operators set the URL via the OAuth dance).

SPA changes:

- Forge tab removed from `/settings/service`. Tab bar collapses to
  **Container · Watchdogs · Design**. Page subtitle now points operators
  at `/login` (the OAuth dance) for the forge URL. Confirm-dialog's
  destructive-field guard drops `forgejo_url`.
- `ServiceConfigSettingsRow` / `ServiceConfigSettingsPatch` types in
  `apps/web/src/lib/api.ts` lose `forgejo_url`.

Tests:

- Every `INSERT INTO service_config (..., forgejo_url, ...)` in the test
  fixtures swaps to `INSERT INTO operator_oauth_tokens (...)` for the
  forgejo row; tests that exercise the bootstrap path use
  `process.env.FORGEJO_URL`. Affected: tail-pr-rebase-watchdog
  integration, forgejo-api, pipeline, gitlab-fm4-smoke, forgejo-oauth,
  onboarding-apply.
- `webhook-config.test.ts` `loadWebhookConfig — split config` block:
  rewrites the legacy `cfg.forgejoUrl` assertions as `getForgejoUrl()`
  reads against the new source. SVC-2 describe block becomes the PR C
  describe — covers (1) operator_oauth_tokens.base_url winning, (2)
  FORGEJO_URL env fallback, (3) hardcoded default fallback.
- `resolver.test.ts` getServiceConfig DOB-1 defaults block trims
  `forgejo_url` from every assertion + INSERT.

`just qa` green (3135/3135 server tests + web typecheck). Service
restarted; live DB's `service_config` no longer carries `forgejo_url`,
`operator_oauth_tokens.base_url` is the single source.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Collaborator

CI still pending at review time (no run found for sha 402056fe). Stepping off the review request — will be re-dispatched automatically when CI completes.

CI still pending at review time (no run found for sha `402056fe`). Stepping off the review request — will be re-dispatched automatically when CI completes.
reviewer approved these changes 2026-05-04 17:45:53 +00:00
Dismissed
reviewer left a comment

Migration, fallback chain, WebhookConfig field removal, SPA tab removal, test coverage — all correct.

nit: main.ts:2379 comment says "static config forgejoUrl" but that field no longer exists on WebhookConfig. Update to "getForgejoUrl()" or drop the comment.

Migration, fallback chain, WebhookConfig field removal, SPA tab removal, test coverage — all correct. nit: `main.ts:2379` comment says "static config forgejoUrl" but that field no longer exists on WebhookConfig. Update to "getForgejoUrl()" or drop the comment.
reviewer approved these changes 2026-05-04 17:49:13 +00:00
reviewer left a comment

Migration 016 is idempotent (PRAGMA check), logs divergence warnings correctly, and drops the column cleanly.

getForgejoUrl() 3-tier fallback (oauth row → FORGEJO_URL env → hardcoded default) is correct; bootstrap/first-sign-in path works because forgejoBaseUrl() in the OAuth handler uses the same helper to build the authorize URL and then stores that URL as base_url — no circularity.

All tests updated to seed operator_oauth_tokens instead of service_config.forgejo_url; env-var fallback test added. SPA Forge tab removal is clean.

CI does not run for stacked PRs targeting non-main — expected; author reports 3135/3135 green locally. Will run after rebase onto main.

Migration 016 is idempotent (PRAGMA check), logs divergence warnings correctly, and drops the column cleanly. `getForgejoUrl()` 3-tier fallback (oauth row → `FORGEJO_URL` env → hardcoded default) is correct; bootstrap/first-sign-in path works because `forgejoBaseUrl()` in the OAuth handler uses the same helper to build the authorize URL and then stores that URL as `base_url` — no circularity. All tests updated to seed `operator_oauth_tokens` instead of `service_config.forgejo_url`; env-var fallback test added. SPA Forge tab removal is clean. CI does not run for stacked PRs targeting non-main — expected; author reports 3135/3135 green locally. Will run after rebase onto main.
charles changed target branch from refactor/service-config-consolidation to main 2026-05-04 17:51:01 +00:00
charles changed target branch from main to refactor/service-config-consolidation 2026-05-04 17:51:17 +00:00
claude-desktop changed target branch from refactor/service-config-consolidation to main 2026-05-04 17:51:54 +00:00
charles force-pushed refactor/forge-url-relocation from 402056fe36 to a6b5b70f2a
All checks were successful
qa / dockerfile (pull_request) Successful in 17s
qa / qa-1 (pull_request) Successful in 3m2s
qa / qa (pull_request) Successful in 0s
2026-05-04 17:53:46 +00:00
Compare
charles deleted branch refactor/forge-url-relocation 2026-05-04 17:59:03 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
3 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
charles/claude-hooks!828
No description provided.