Skip to content

fix(settings): stop a member's settings save writing to the whole org - #254

Merged
jlav merged 2 commits into
mainfrom
jl/scope-member-settings-broadcast
Aug 26, 2026
Merged

fix(settings): stop a member's settings save writing to the whole org#254
jlav merged 2 commits into
mainfrom
jl/scope-member-settings-broadcast

Conversation

@jlav

@jlav jlav commented Aug 26, 2026

Copy link
Copy Markdown
Member

HUMAN:

  • A human has tested these changes.

AGENT:


Why

One member switching their agent to codex broke new conversations for everyone else in the org. Every member without codex credentials got a 400 on every attempt:

{"detail":"Connect your Codex account or set an API key before starting a Codex conversation."}

This blocked all 17 members of the beta staging instance.

POST /api/v1/settings is the per-user settings save and any member can call it. It was writing the acting member's agent settings to org.agent_settings and to every other member's agent_settings_diff, so a personal harness choice became the org-wide default.

The same thing happened through a second column. Where an org keeps its LLM connection in a profile rather than in agent_settings, that profile is the only record of the org's model and base url, and a member's save was overwriting it with SDK defaults. I hit this on a second instance after fixing the first path.

Approach

store() writes the acting member's org_member row and nothing else. The managed litellm key is genuinely org-wide, so that one field still fans out to every member.

Org-wide defaults get their own way in: POST /orgs/{id}/app takes an agent_settings_diff, gated on EDIT_ORG_SETTINGS.

A member's save also no longer touches org-owned columns, and sync_active_profile_from_settings() skips a non-OpenHands agent, whose llm block is an unused placeholder rather than a real connection.

Issue Number

OHE-3138 - https://linear.app/all-hands-ai/issue/OHE-3138

How to Test

cd enterprise && poetry run pytest tests/unit/test_saas_settings_store.py tests/unit/test_agent_profiles.py tests/unit/storage/test_org_app_settings_store.py tests/unit/server/routes/test_org_defaults_settings.py

With two accounts in one org:

  1. As member A, switch to ACP + codex on /settings/agent and save.
  2. As member B, start a new conversation. It should launch normally.
  3. As a plain member, POST /orgs/{id}/app with an agent_settings_diff should 403. As admin or owner it should apply to org.agent_settings.

Video/Screenshots

Type

  • Bug fix
  • Feature
  • Refactor
  • Breaking change
  • Docs / chore

Notes

This is the minimum needed to stop one member reconfiguring the org. #241 carries the same two commits plus two follow-on fixes, which I split out so this one can go in on its own:

  • After switching back from a harness, a member keeps the SDK's placeholder model instead of the org's, so their first conversation fails until they pick one. Affects only the member who switched.
  • A member who has ever saved their agent settings stops tracking org-wide default changes. Real, but it changes how settings persist for every member on every save, so it wants its own review.

Rows already written by this bug aren't repaired here. That needs a separate cleanup.

I left MEMBER_PRIVATE_AGENT_KEYS alone on purpose. Adding the acp keys there looks like the one-line fix, but that set also gets stripped from the member's own row, so it'd silently discard everyone's harness choice. Only mcp_config survives it, via its own column.


Enterprise server image for this PR:

ghcr.io/openhands/enterprise-server:sha-174c586

@github-actions

Copy link
Copy Markdown

Coverage report

Click to see where and how coverage changed

FileStatementsMissingCoverageCoverage
(new stmts)
Lines missing
  enterprise/server/routes
  org_models.py 688-689, 699-702
  orgs.py 557-566
  enterprise/storage
  org_app_settings_store.py 215-225
  saas_settings_store.py 105, 201-207, 683-699, 717-723, 738, 751-765
  openhands/app_server/settings
  settings_models.py 803-811
Project Total  

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

@jlav
jlav marked this pull request as ready for review August 26, 2026 14:45
@jlav
jlav merged commit 92b10cc into main Aug 26, 2026
17 of 18 checks passed
@jlav
jlav deleted the jl/scope-member-settings-broadcast branch August 26, 2026 14:58
@openhands-release-bot

Copy link
Copy Markdown

🚀 Released in 1.56.0.

@openhands-release-bot openhands-release-bot Bot added the released: 1.56.0 Shipped in 1.56.0 label Aug 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants