Reject thread creation on nonexistent namespaces

POST /api/v1/threads now returns 404 if the namespace doesn't already
exist, instead of auto-creating it. Prevents phantom namespaces from
accumulating when callers mistype the namespace name.

get_or_create_namespace is still used for read-only endpoints (GET)
where lazy creation is acceptable.
This commit is contained in:
timehexon 2026-02-02 18:04:53 +00:00
parent 66964f736a
commit df3f3d231e
2 changed files with 22 additions and 2 deletions

View file

@ -17,7 +17,11 @@ from remarkbox.models.user import (
is_user_name_valid,
is_user_name_available,
)
from remarkbox.models.namespace import get_or_create_namespace, get_topsecret_namespaces
from remarkbox.models.namespace import (
get_namespace_by_name,
get_or_create_namespace,
get_topsecret_namespaces,
)
from remarkbox.models.node import Node
from remarkbox.lib.mail import send_verification_digits_to_email
from remarkbox.lib.notify import schedule_notifications
@ -464,7 +468,10 @@ def api_create_thread(request):
)
}
namespace = get_or_create_namespace(request.dbsession, namespace_name)
namespace = get_namespace_by_name(request.dbsession, namespace_name)
if namespace is None:
request.response.status_code = 404
return {"error": "namespace '{}' does not exist".format(namespace_name)}
denied = check_namespace_api_access(request, namespace)
if denied:

View file

@ -119,6 +119,19 @@ class TestAPIAnonymousPosting(APIFunctionalTests):
self.assertEqual(res.status_int, 400)
self.assertIn("namespace", res.json["error"])
def test_create_thread_nonexistent_namespace(self):
res = self.testapp.post_json(
"/api/v1/threads",
{
"namespace": "does-not-exist.example.com",
"title": "Test",
"data": "Should fail",
},
expect_errors=True,
)
self.assertEqual(res.status_int, 404)
self.assertIn("does not exist", res.json["error"])
def test_create_thread_missing_title(self):
res = self.testapp.post_json(
"/api/v1/threads",