Skip to content

feat(cost): GitHub as a cost source, read through the GitHub App installation - #2540

Open
Makisuo wants to merge 7 commits into
mainfrom
cost/github-source
Open

Makisuo wants to merge 7 commits into
mainfrom
cost/github-source

fix(cost): a GitHub usage date must be a real day or a real UTC times…

221ba3d
Select commit
Loading
Failed to load commit list.
Maple Review Bot / Maple / review succeeded Nov 13, 2026 in 3m 48s

Confidence 10/10 · No issues found

🟢 Confidence 10/10 · safe to merge. Changed page, lab and normalizer code hold up; removal by source id, the refusal link and first-sync copy all trace to code I read.
no findings · tests covered · risk high · 4/4 new units observable

Adds GitHub as a cost source read through the App installation: normalizer, a billing read on the provider port, internal routes, and the Cost page's installations step with add and remove. The changes since the last review hold up; the two listed webhook-enqueue errors are unrelated to this diff.

  • GitHub step lists installations with Add, and a GitHub source row gets Remove behind a confirm
  • fetchBillingUsage and installationSettingsUrl join the VCS provider port, implemented by GitHub
  • A usage date must be a real day or a real UTC timestamp, or the pull fails
  • Provider marks, removal copy and first-sync copy now name GitHub

Before merge

  • Manual · Add Administration: read to the GitHub App registration and accept it in one organization; until then adds are refused

Production impact

Open errors in the changed files (1)
Issue Service Occurrences File
@maple/api/routes/VcsWebhookEnqueueFailure (2 issues) maple-api 9 apps/api/src/runtime/http-graph.ts

After this merges, Maple checks whether they stop.

Production traffic of the changed files (last 7 days)
File Calls/day Busiest operations
packages/backend/src/services/integrations/vcs/vendor/github/GithubAppClient.ts 69 GithubAppClient.listInstallationRepositories 69/day, 0.0% err
Telemetry this change adds and removes (11)
  • ➕ span name HttpGithubCost.list · apps/api/src/routes/internal/github-cost.http.ts:33
  • ➕ span name HttpGithubCost.add · apps/api/src/routes/internal/github-cost.http.ts:47
  • ➕ span name HttpGithubCost.remove · apps/api/src/routes/internal/github-cost.http.ts:61
  • ➕ span name CostSyncService.reconcileGithub · packages/backend/src/services/cost/CostSyncService.ts:211
  • ➕ span name GithubCostSourceService.list · packages/backend/src/services/cost/GithubCostSourceService.ts:116
  • ➕ span name GithubCostSourceService.add · packages/backend/src/services/cost/GithubCostSourceService.ts:152
  • ➕ attribute maple.cost.error_reason · packages/backend/src/services/cost/GithubCostSourceService.ts:203
  • ➕ span name GithubCostSourceService.remove · packages/backend/src/services/cost/GithubCostSourceService.ts:234
  • ➕ span name GithubCostProvider.pull · packages/backend/src/services/cost/providers/github/GithubCostProvider.ts:34
  • ➕ attribute maple.cost.github.months · packages/backend/src/services/cost/providers/github/GithubCostProvider.ts:78
  • ➕ span name GithubAppClient.getOrganizationBillingUsage · packages/backend/src/services/integrations/vcs/vendor/github/GithubAppClient.ts:984
What was checked
  • Removal is keyed by source id (update.ts:251), so a GitHub and an OpenRouter source each clear only their own row
  • github_cost_permission_missing matches the API error code (github-cost.ts:103), so the settings link shows only on a permission refusal
  • First-sync copy matches planCostSync: monthStart(today,-1) first, then monthly backfill to monthStart(today,-3)
Observability coverage: 4 of 4 changes observable
Change Kind Observable Evidence
GET /internal/cost/github (installations to pick from) HTTP route yes Effect.withSpan("HttpGithubCost.list") at apps/api/src/routes/internal/github-cost.http.ts:33
PUT/DELETE /internal/cost/github/{installationId} HTTP route yes withSpan HttpGithubCost.add/.remove at github-cost.http.ts:47 and :61, audited on write
GitHub billing usage read (outbound) outbound call yes GithubAppClient.getOrganizationBillingUsage is an Effect.fn span; fetchBillingUsage wraps it on the provider port
Cost sync pull for a GitHub source background work yes GithubCostProvider.pull span annotates maple.cost.provider, maple.cost.start_day/end_day, maple.cost.rows and maple.cost.error_reason (GithubCostProvider.ts:34-83)

221ba3d · Reply "won't fix" to dismiss a finding, or mention @maple-review-bot to ask about one.