feat: scoped threshold-config merge for non-admin saves
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NfPpSpccTWBfZg1FTveyaU
This commit is contained in:
@@ -139,3 +139,30 @@ def merge_hosts_scoped(existing: Any, payload: Any, username: str,
|
||||
raise ScopedMergeError(f"host {name!r}: only the owner may delete a host")
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def merge_threshold_configs_scoped(existing: Any, payload: Any,
|
||||
username: str) -> Dict[str, Any]:
|
||||
"""Return a new threshold_configs section with the user's own configs
|
||||
replaced by *payload*.
|
||||
|
||||
Global and foreign-owned configs are preserved and may not appear in the
|
||||
payload ('default' included). Own configs missing from the payload are
|
||||
deleted. Every payload entry gets its owner forced to *username*.
|
||||
"""
|
||||
existing = existing or {}
|
||||
payload = payload or {}
|
||||
result: Dict[str, Any] = {
|
||||
n: c for n, c in existing.items()
|
||||
if not (isinstance(c, dict) and c.get("owner") == username)
|
||||
}
|
||||
for name, entry in payload.items():
|
||||
if name == "default":
|
||||
raise ScopedMergeError("threshold config 'default' is global and admin-managed")
|
||||
old = existing.get(name)
|
||||
if old is not None and (not isinstance(old, dict) or old.get("owner") != username):
|
||||
raise ScopedMergeError(f"threshold config {name!r}: not owned by you")
|
||||
new_cfg = dict(entry) if isinstance(entry, dict) else {}
|
||||
new_cfg["owner"] = username
|
||||
result[name] = new_cfg
|
||||
return result
|
||||
|
||||
Reference in New Issue
Block a user