Skip to content

updated slug validation regex to make it url safe#3603

Open
praffq wants to merge 2 commits intodevelopfrom
prafful/make-slug-url-safe
Open

updated slug validation regex to make it url safe#3603
praffq wants to merge 2 commits intodevelopfrom
prafful/make-slug-url-safe

Conversation

@praffq
Copy link
Copy Markdown
Contributor

@praffq praffq commented Mar 27, 2026

Proposed Changes

Regex used - ^[a-zA-Z0-9][a-zA-Z0-9_-]*[a-zA-Z0-9]$

  • ^ — start of string
  • [a-zA-Z0-9] — first character must be a letter (upper or lower) or digit
  • [a-zA-Z0-9_-]* — middle characters (zero or more) can be letters, digits, hyphens, or underscores
  • [a-zA-Z0-9] — last character must be a letter (upper or lower) or digit
  • $ — end of string

Only PR's with test cases included and passing lint and test pipelines will be reviewed

@ohcnetwork/care-backend-maintainers @ohcnetwork/care-backend-admins

Summary by CodeRabbit

  • Bug Fixes

    • Slug validation tightened: slugs must start and end with an ASCII alphanumeric character; hyphens and underscores are allowed only in the middle. Validation message updated accordingly.
  • Tests

    • Questionnaire and slug-related tests updated to align with the new slug validation rules.

@praffq praffq requested a review from a team as a code owner March 27, 2026 14:03
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 27, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: f4e4697c-8c7a-4cd0-82b4-6fdd7fb64814

📥 Commits

Reviewing files that changed from the base of the PR and between 6dc5a07 and 9c5cad6.

📒 Files selected for processing (2)
  • care/emr/tests/test_slug_type.py
  • care/emr/utils/slug_type.py
✅ Files skipped from review due to trivial changes (1)
  • care/emr/utils/slug_type.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • care/emr/tests/test_slug_type.py

📝 Walkthrough

Walkthrough

Validator regex tightened to require slugs to start and end with ASCII alphanumerics and allow only ASCII letters/digits, hyphen or underscore in the middle; questionnaire test fixtures were adjusted to lowercase slugs; a slug test was simplified to accept uppercase input (validator now allows uppercase boundaries).

Changes

Cohort / File(s) Summary
Slug Validation Logic
care/emr/utils/slug_type.py
Replaced loose ^[-\w]+$ with ^[a-zA-Z0-9][a-zA-Z0-9_-]*[a-zA-Z0-9]$ in slug_validator and extended_slug_validator; dropped explicit re.ASCII flag and updated validation message to remove "lowercase" wording.
Slug Validation Tests
care/emr/tests/test_slug_type.py
test_uppercase_slug_handling simplified: now constructs TestModel(slug="UPPERCASE") unconditionally and asserts the slug is preserved (uppercase input is accepted).
Questionnaire Test Fixtures
care/emr/tests/test_questionnaire_api.py
Two questionnaire fixture slugs changed to lowercase: "Appointment""appointment", "Appointment-any""appointment-any".

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~18 minutes

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 28.57% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The description explains the proposed regex pattern with clear component breakdown, but lacks required sections like issue links, architecture changes explanation, and merge checklist items. Add the 'Associated Issue' section with relevant GitHub issue link, clarify if architecture changes exist, and complete the merge checklist with test/lint status updates.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately reflects the main change: updating slug validation regex to enforce URL-safe formatting with alphanumeric start/end characters.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch prafful/make-slug-url-safe

Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps
Copy link
Copy Markdown

greptile-apps bot commented Mar 27, 2026

Greptile Summary

This PR tightens the slug validation regex from the permissive ^[-\w]+$ (which allowed uppercase letters and hyphens/underscores at the start or end) to ^[a-z0-9][a-z0-9_-]*[a-z0-9]$, enforcing strictly URL-safe, lowercase slugs with alphanumeric boundaries. The re.ASCII flag is correctly dropped since the new character class already constrains the match to ASCII. Two hardcoded test slugs in the questionnaire API tests are updated to lowercase to comply with the new rule, and the flimsy test_uppercase_slug_handling test (which previously accepted either success or failure) is correctly tightened to always assert a ValidationError.

Key observations:

  • The core regex change in both slug_validator and extended_slug_validator is correct and well-motivated.
  • The test_uppercase_slug_handling fix is a clear improvement — the old try/except pattern made the test pass even when no exception was raised.
  • ExtendedSlugType (via extended_slug_validator) received the same regex update but has no dedicated test coverage in this PR.
  • test_invalid_slugs is missing explicit cases for slugs starting or ending with - / _, which are the most notable new constraints introduced by this regex change.

Confidence Score: 5/5

Safe to merge — the logic change is correct and the test suite is improved; remaining findings are minor coverage gaps.

All findings are P2 (style/coverage suggestions). The regex itself is correct, the boundary conditions are properly enforced, and the existing tests are strengthened. No runtime errors, data-loss risk, or broken validation paths were identified.

No files require special attention, though care/emr/utils/slug_type.py and care/emr/tests/test_slug_type.py would benefit from ExtendedSlugType test coverage.

Important Files Changed

Filename Overview
care/emr/utils/slug_type.py Both validators updated from the permissive ^[-\w]+$ (ASCII) to the stricter ^[a-z0-9][a-z0-9_-]*[a-z0-9]$; re.ASCII flag removed as no longer needed. Logic is correct; no test coverage for extended_slug_validator changes.
care/emr/tests/test_slug_type.py test_uppercase_slug_handling correctly tightened to always assert ValidationError; missing explicit test cases for slugs starting/ending with - or _.
care/emr/tests/test_questionnaire_api.py Two hardcoded test slugs updated from uppercase-starting values ("Appointment", "Appointment-any") to lowercase equivalents to comply with the new validator.

Comments Outside Diff (2)

  1. care/emr/tests/test_slug_type.py, line 27-40 (link)

    P2 Missing edge-case tests for boundary characters

    The new regex explicitly requires the first and last characters to be alphanumeric ([a-z0-9]), rejecting slugs that begin or end with - or _. The test_invalid_slugs list doesn't cover these now-rejected patterns, so the stricter start/end constraint is untested here.

    Consider adding entries like "-leading-hyphen", "trailing-hyphen-", "_leading_under", and "trailing_under_" to invalid_slugs to directly document and verify the new boundary rule:

  2. care/emr/utils/slug_type.py, line 25-43 (link)

    P2 ExtendedSlugType regex change has no test coverage

    extended_slug_validator was updated with the same new regex, but the test file (test_slug_type.py) only exercises SlugType. The ExtendedSlugType behavior — including the new boundary enforcement ([a-z0-9] start/end) combined with the "f-" / "i-" prefix check — is not tested at all. A dedicated TestExtendedSlugTypeValidation class similar to TestSlugTypeValidation would prevent regressions here.

Reviews (1): Last reviewed commit: "updated slug validation regex to make it..." | Re-trigger Greptile

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
care/emr/utils/slug_type.py (2)

33-34: Please centralize the slug regex to avoid validator drift.

Line [33] duplicates the same pattern from Line [15]. A shared constant keeps both validators aligned and easier to maintain.

♻️ Proposed refactor
 import re
 from typing import Annotated

 from pydantic import AfterValidator, Field

+SLUG_PATTERN = r"^[a-z0-9][a-z0-9_-]*[a-z0-9]$"


 def slug_validator(value: str) -> str:
@@
-    pattern = r"^[a-z0-9][a-z0-9_-]*[a-z0-9]$"
-    if not re.match(pattern, value):
+    if not re.match(SLUG_PATTERN, value):
         raise ValueError(
@@
 def extended_slug_validator(value: str) -> str:
@@
-    pattern = r"^[a-z0-9][a-z0-9_-]*[a-z0-9]$"
-    if not re.match(pattern, value):
+    if not re.match(SLUG_PATTERN, value):
         raise ValueError(

As per coding guidelines, "**/*.py: Prioritize readability and maintainability; follow Django's coding style guide (PEP 8 compliance)."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@care/emr/utils/slug_type.py` around lines 33 - 34, Duplicate regex pattern in
slug_type.py should be centralized: define a single module-level constant (e.g.,
SLUG_PATTERN or SLUG_REGEX) near the top of the file and replace both
occurrences of the inline pattern (the local variable pattern used at the call
to re.match in the validator) with that constant; update the validator(s) that
reference pattern to use SLUG_REGEX and ensure imports (re) remain, keeping name
uppercase and a brief docstring comment so both validators (the one around line
15 and the one around line 33) use the same source of truth.

15-16: Extract the repeated regex pattern into a module-level constant.

The pattern r"^[a-z0-9][a-z0-9_-]*[a-z0-9]$" is defined identically in both slug_validator (line 16) and extended_slug_validator (line 34). Duplicating regex patterns violates DRY and creates a maintainability risk if the pattern needs updating later. Define it once at module level and reference it in both validators.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@care/emr/utils/slug_type.py` around lines 15 - 16, The regex pattern
r"^[a-z0-9][a-z0-9_-]*[a-z0-9]$" is duplicated in slug_validator and
extended_slug_validator; extract it into a module-level constant (e.g.,
SLUG_PATTERN) and update both functions to reference that constant instead of
hardcoding the pattern so future changes are centralized and DRY is preserved.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@care/emr/tests/test_slug_type.py`:
- Around line 43-44: Add explicit boundary-case assertions to the existing test
that currently checks uppercase rejection: after the TestModel(slug="UPPERCASE")
assertion, add additional with self.assertRaises(ValidationError) checks
constructing TestModel with slugs "-start", "_start", "end-", and "end_" to
ensure the model enforces “must start/end alphanumeric” behavior; reference the
TestModel constructor and ValidationError in care/emr/tests/test_slug_type.py
when adding these cases.

---

Nitpick comments:
In `@care/emr/utils/slug_type.py`:
- Around line 33-34: Duplicate regex pattern in slug_type.py should be
centralized: define a single module-level constant (e.g., SLUG_PATTERN or
SLUG_REGEX) near the top of the file and replace both occurrences of the inline
pattern (the local variable pattern used at the call to re.match in the
validator) with that constant; update the validator(s) that reference pattern to
use SLUG_REGEX and ensure imports (re) remain, keeping name uppercase and a
brief docstring comment so both validators (the one around line 15 and the one
around line 33) use the same source of truth.
- Around line 15-16: The regex pattern r"^[a-z0-9][a-z0-9_-]*[a-z0-9]$" is
duplicated in slug_validator and extended_slug_validator; extract it into a
module-level constant (e.g., SLUG_PATTERN) and update both functions to
reference that constant instead of hardcoding the pattern so future changes are
centralized and DRY is preserved.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 7aeb0aa7-92c7-42b5-9cf3-b449bdaccb98

📥 Commits

Reviewing files that changed from the base of the PR and between c691750 and 6dc5a07.

📒 Files selected for processing (3)
  • care/emr/tests/test_questionnaire_api.py
  • care/emr/tests/test_slug_type.py
  • care/emr/utils/slug_type.py

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 27, 2026

Codecov Report

❌ Patch coverage is 75.00000% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 77.19%. Comparing base (c691750) to head (9c5cad6).

Files with missing lines Patch % Lines
care/emr/utils/slug_type.py 75.00% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #3603      +/-   ##
===========================================
- Coverage    77.20%   77.19%   -0.01%     
===========================================
  Files          474      474              
  Lines        22421    22421              
  Branches      2348     2348              
===========================================
- Hits         17310    17308       -2     
- Misses        4531     4532       +1     
- Partials       580      581       +1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant