Add slug validation and test (#1891)

Fixes #1890 

Adds validation for org slugs, ensuring that they contain only ASCII
alphanumeric characters and dashes (`-`). If an invalid slug is
provided, an HTTPException is returned with status code 400 and detail
`invalid_slug`.
This commit is contained in:
Tessa Walsh 2024-06-26 15:04:54 -04:00 committed by GitHub
parent 6df10d5fb0
commit b7631d1b91
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 30 additions and 3 deletions

View File

@ -41,7 +41,7 @@ from .models import (
PaginatedResponse,
)
from .pagination import DEFAULT_PAGE_SIZE, paginated_format
from .utils import slug_from_name
from .utils import slug_from_name, validate_slug
if TYPE_CHECKING:
from .invites import InviteOps
@ -775,8 +775,10 @@ def init_orgs_api(app, mdb, user_manager, invites, user_dep):
id_ = uuid4()
slug = new_org.slug
if not slug:
if new_org.slug:
validate_slug(new_org.slug)
slug = new_org.slug
else:
slug = slug_from_name(new_org.name)
org = Organization(
@ -803,6 +805,7 @@ def init_orgs_api(app, mdb, user_manager, invites, user_dep):
):
org.name = rename.name
if rename.slug:
validate_slug(rename.slug)
org.slug = rename.slug
else:
org.slug = slug_from_name(rename.name)

View File

@ -8,6 +8,7 @@ import json
import signal
import os
import sys
import re
from datetime import datetime
from typing import Optional, Dict, Union, List
@ -123,6 +124,15 @@ def slug_from_name(name: str) -> str:
return slugify(name.replace("'", ""))
def validate_slug(slug: str) -> None:
"""Validate org slug, raise HTTPException if invalid
Slugs must contain alphanumeric characters and dashes (-) only.
"""
if re.match(r"^[\w-]+$", slug) is None:
raise HTTPException(status_code=400, detail="invalid_slug")
def stream_dict_list_as_csv(data: List[Dict[str, Union[str, int]]], filename: str):
"""Stream list of dictionaries as CSV with attachment filename header"""
if not data:

View File

@ -72,6 +72,20 @@ def test_rename_org(admin_auth_headers, default_org_id):
assert data["slug"] == UPDATED_SLUG
def test_rename_org_invalid_slug(admin_auth_headers, default_org_id):
UPDATED_NAME = "updated org name"
UPDATED_SLUG = "not a valid slug"
rename_data = {"name": UPDATED_NAME, "slug": UPDATED_SLUG}
r = requests.post(
f"{API_PREFIX}/orgs/{default_org_id}/rename",
headers=admin_auth_headers,
json=rename_data,
)
assert r.status_code == 400
assert r.json()["detail"] == "invalid_slug"
def test_create_org(admin_auth_headers):
NEW_ORG_NAME = "New Org"
r = requests.post(