Skip to content

fix: protect personal organization billing credits - #167

Merged
tofarr merged 10 commits into
mainfrom
fix/personal-org-billing-credits
Aug 20, 2026
Merged

fix: protect personal organization billing credits#167
tofarr merged 10 commits into
mainfrom
fix/personal-org-billing-credits

Conversation

@saurya

@saurya saurya commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Summary

  • preserve explicit unlimited LiteLLM budgets while treating absent or partial financial data as unavailable
  • prevent personal organizations and passively disabled settings from governance-budget maintenance
  • preserve intentional shared-team cap removal only for explicit enabled-to-disabled governance transitions
  • make purchases retryable when budget state is unavailable and add credits above current spend for unlimited or overspent accounts
  • render the localized no-budget-limit state without $NaN, and expose organization credit availability separately from balance

Validation

  • 336 passed across affected enterprise billing, LiteLLM, organization, organization-route, and governance-budget unit modules
  • 33 passed, 1 todo across the payment-form and manage-organization frontend suites
  • frontend typecheck, source ESLint, and Prettier passed
  • enterprise all-files pre-commit suite passed, including Ruff and mypy
  • GitHub Actions: 20 successful, 1 skipped, 0 failing

Notes

  • Migration 144 removes personal-organization governance rows so they cannot cause future LiteLLM budget mutations.
  • This PR does not guess historical caps for accounts that may already have been affected: the database does not retain an authoritative pre-wipe LiteLLM cap, and current spend or checkout totals cannot safely reconstruct initial grants, refunds, adjustments, or post-wipe spend. Historical reconciliation should use authoritative billing and audit data.
  • Existing Stripe callback tests still emit an unrelated warning for an unawaited AsyncSession.merge.

This pull request was updated by an AI agent (OpenHands) on behalf of Saurya Velagapudi.


Enterprise server image for this PR:

ghcr.io/openhands/enterprise-server:sha-0d4cc45

Co-authored-by: openhands <openhands@all-hands.dev>
@saurya saurya changed the title Fix personal organization billing credit limits fix: protect personal organization billing credits Aug 12, 2026
@github-actions

Copy link
Copy Markdown

⚠️ This PR contains migrations. Please synchronize before merging to prevent conflicts.

@github-actions github-actions Bot added the type: fix A bug fix label Aug 12, 2026
Co-authored-by: openhands <openhands@all-hands.dev>
@github-actions

github-actions Bot commented Aug 12, 2026

Copy link
Copy Markdown

Coverage report

Click to see where and how coverage changed

FileStatementsMissingCoverageCoverage
(new stmts)
Lines missing
  enterprise
  run_budget_maintenance.py 23, 27, 36-37, 56-60
  enterprise/server/routes
  billing.py 83-87, 96-116, 292-309
  org_models.py 102, 241-248
  enterprise/server/services
  org_budget_service.py 100-101, 104-105, 108-109, 122-125, 149-160, 194-197, 235-246, 274-275, 284, 287-290, 601-607
  enterprise/storage
  lite_llm_manager.py 101-117, 1260-1267
  org_service.py 606, 611-626, 637-643, 861-872
Project Total  

This report was generated by python-coverage-comment-action

@saurya
saurya requested a review from hieptl August 12, 2026 15:14
@saurya
saurya marked this pull request as ready for review August 12, 2026 15:14
Comment thread enterprise/server/services/org_budget_service.py
Comment thread enterprise/run_budget_maintenance.py
Comment thread enterprise/storage/lite_llm_manager.py Outdated
Comment thread enterprise/server/routes/billing.py Outdated
Comment thread enterprise/server/routes/billing.py
Comment thread frontend/src/components/features/payment/payment-form.tsx
Comment thread frontend/src/components/features/payment/payment-form.tsx
saurya and others added 3 commits August 12, 2026 10:04
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: openhands <openhands@all-hands.dev>
@saurya

saurya commented Aug 17, 2026

Copy link
Copy Markdown
Contributor Author

E2E follow-up: OpenHands-Cloud #1103 adds release-level coverage for this PR.

I reviewed the existing open budget drafts (#1064, #1070, #1071, #1072, #1074, #1077, #1078, and #1080); they cover shared/team governance but not the personal-workspace and nullable/unlimited billing behavior here. The new draft extends the real Stripe flow to verify:

  • fresh personal organizations reject governance-budget access;
  • /api/billing/credits and /api/organizations agree on finite versus explicit unlimited credit state;
  • the UI renders localized No budget limit and never $NaN;
  • a $10 Stripe test purchase preserves finite balances and converts an unlimited balance into $10 of purchased credits.

Validation completed: locked dependency install, full TypeScript/ESLint/Prettier checks, Playwright test discovery, and the Cloud PR validate check all pass. Live release execution is still pending because this agent environment has no non-production BASE_URL, GitHub/Keycloak E2E credentials or mounted auth state, or Stripe-enabled deployment using ghcr.io/openhands/enterprise-server:pr-167. The draft documents that exact execution contract rather than substituting request mocks.

AI disclosure: This comment was generated by an AI agent (OpenHands) on behalf of the user.

@saurya

saurya commented Aug 17, 2026

Copy link
Copy Markdown
Contributor Author

Hey @hieptl - please take another look and offer any advice on how we can better test this code before merging. Since it's a sensitive piece of the product, I'd love to get more assurance.

@hieptl hieptl left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you! 🙏

saurya and others added 2 commits August 19, 2026 09:39
Renumber the personal organization budget cleanup migration to follow the current revision 147 head and update its regression-test import.

Co-authored-by: openhands <openhands@all-hands.dev>
@tofarr
tofarr enabled auto-merge (squash) August 20, 2026 13:20
@tofarr
tofarr merged commit ac920c6 into main Aug 20, 2026
21 checks passed
@tofarr
tofarr deleted the fix/personal-org-billing-credits branch August 20, 2026 13:30
tofarr pushed a commit that referenced this pull request Aug 20, 2026
Resolve merge conflict in enterprise/tests/unit/test_org_budget_service.py
by combining both branches' new tests:
- main's test_sync_litellm_budgets_skips_passive_disabled_team_org (from #167)
- this PR's test_sync_litellm_budgets_keeps_member_cap_stable_across_sessions

Co-authored-by: openhands <openhands@all-hands.dev>
@openhands-release-bot

Copy link
Copy Markdown

🚀 Released in 1.55.0.

hieptl added a commit that referenced this pull request Aug 26, 2026
…hell

Resolve conflicts with main (#167 null balance, #176 dropdown search term,
#199 quota nav item) and align the merged result with the neo settings shell:

- credits/payment: keep main's null balance -> "no budget limit" semantics
- settings nav: add the Quota entry (subline + icon) and tokenize the quota
  page with the shared form-control helpers
- settings loader: fall back to the backend's current org after a hard load
  so /settings/credits stays reachable
- integrations: style the Jira member-guidance row like the other rows
- tests: move the no-limit credits test with the credits UI; drop the
  legacy-sidebar avatar E2E spec (the sidebar no longer renders)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

released: 1.55.0 Shipped in 1.55.0 type: fix A bug fix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants