refactor(routes): one supersession seam for REST and MCP; PUT/PATCH notes share a handler; shared mask/not-found/caller helpers (#2829, milestone 296 area 5)
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 9s
CI & Build / integration (push) Successful in 25s
CI & Build / TypeScript typecheck (push) Successful in 32s
CI & Build / Python tests (push) Failing after 37s
CI & Build / Build & push image (push) Skipped
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 9s
CI & Build / integration (push) Successful in 25s
CI & Build / TypeScript typecheck (push) Successful in 32s
CI & Build / Python tests (push) Failing after 37s
CI & Build / Build & push image (push) Skipped
Reading the 28 route modules against each other and against the MCP tools: - routes/notes.py carried a PUT and a PATCH handler that were the same function minus the supersedes contract on one of them — one handler now serves both verbs, so both carry it. - The two _attach_supersession copies (REST + MCP) become supersession_svc.attach_relations(uid, note_id, data, hint=) — the seam the two surfaces must agree through; only the agent surface adds the one-sentence reading hint. - Three local _uid() wrappers over g.user.id → scribe.auth.get_current_user_id like every other module; design_systems' private _not_found → routes.utils. not_found; the four "********" literals → settings_svc.SECRET_MASK with the read/write contract written once. - routes/plugin.py: the project_id/repo resolution block and the comma-separated id parse were copied into three endpoints — _project_scope() and _int_list() now. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -22,6 +22,7 @@ from scribe.services.email import SMTP_SETTING_KEYS, get_base_url, get_smtp_conf
|
||||
from scribe.services.logging import get_logs, get_log_stats, log_audit
|
||||
from scribe.services.notifications import send_invitation_email
|
||||
from scribe.services.settings import (
|
||||
SECRET_MASK,
|
||||
get_admin_setting,
|
||||
set_admin_setting,
|
||||
set_setting,
|
||||
@@ -116,7 +117,7 @@ async def get_smtp():
|
||||
config = await get_smtp_config()
|
||||
# Mask password
|
||||
if config.get("smtp_password"):
|
||||
config["smtp_password"] = "********"
|
||||
config["smtp_password"] = SECRET_MASK
|
||||
return jsonify(config)
|
||||
|
||||
|
||||
@@ -130,7 +131,7 @@ async def update_smtp():
|
||||
for key in SMTP_SETTING_KEYS:
|
||||
if key in data:
|
||||
# Skip password if it's the mask placeholder
|
||||
if key == "smtp_password" and data[key] == "********":
|
||||
if key == "smtp_password" and data[key] == SECRET_MASK:
|
||||
continue
|
||||
settings_to_save[key] = str(data[key])
|
||||
|
||||
@@ -157,9 +158,6 @@ async def test_smtp():
|
||||
return jsonify({"error": str(e)}), 500
|
||||
|
||||
|
||||
_TOKEN_MASK = "********"
|
||||
|
||||
|
||||
# The forge CONFIG moved to per-user keyring rows (#2778, Settings → Git
|
||||
# forges); what stays admin is the webhook secret, because the push endpoint
|
||||
# is one URL per instance and authenticates deliveries, not users.
|
||||
@@ -178,7 +176,7 @@ async def get_forge_webhook_settings():
|
||||
return jsonify({
|
||||
# Secrets never leave the server — the smtp_password convention:
|
||||
# masked when set, empty when not.
|
||||
"webhook_secret": _TOKEN_MASK if webhook_secret else "",
|
||||
"webhook_secret": SECRET_MASK if webhook_secret else "",
|
||||
})
|
||||
|
||||
|
||||
@@ -192,7 +190,7 @@ async def update_forge_webhook_settings():
|
||||
webhook_secret = data.get("webhook_secret")
|
||||
# The mask coming back means "unchanged" — the form round-trips what GET
|
||||
# showed it, and storing the mask would silently break the integration.
|
||||
if webhook_secret is not None and webhook_secret != _TOKEN_MASK:
|
||||
if webhook_secret is not None and webhook_secret != SECRET_MASK:
|
||||
await set_admin_setting(FORGE_WEBHOOK_SECRET_KEY, str(webhook_secret))
|
||||
# The secret is deliberately absent from the audit detail.
|
||||
await log_audit(
|
||||
|
||||
Reference in New Issue
Block a user