feat(P9.6): block story/feature and maintenance/release task creation via general create endpoints

This commit is contained in:
zhi
2026-03-17 13:02:46 +00:00
parent 7542f2d7c1
commit c18b8f3850
2 changed files with 22 additions and 2 deletions

View File

@@ -52,7 +52,17 @@ TASK_SUBTYPE_MAP = {
ALLOWED_TASK_TYPES = set(TASK_SUBTYPE_MAP.keys())
def _validate_task_type_subtype(task_type: str | None, task_subtype: str | None):
"""P9.6 — type+subtype combos that may NOT be created via general create endpoints.
feature story → must come from propose accept
release maintenance → must come from controlled milestone/release flow
"""
RESTRICTED_TYPE_SUBTYPES = {
("story", "feature"),
("maintenance", "release"),
}
def _validate_task_type_subtype(task_type: str | None, task_subtype: str | None, *, allow_restricted: bool = False):
if task_type is None:
return
if task_type not in ALLOWED_TASK_TYPES:
@@ -60,6 +70,13 @@ def _validate_task_type_subtype(task_type: str | None, task_subtype: str | None)
allowed = TASK_SUBTYPE_MAP.get(task_type, set())
if task_subtype and task_subtype not in allowed:
raise HTTPException(status_code=400, detail=f'Invalid task_subtype for {task_type}: {task_subtype}')
# P9.6: block restricted combos unless explicitly allowed (e.g. propose accept, internal create)
if not allow_restricted and (task_type, task_subtype) in RESTRICTED_TYPE_SUBTYPES:
raise HTTPException(
status_code=400,
detail=f"Cannot create {task_type}/{task_subtype} task via general create. "
f"Use the appropriate workflow (propose accept / milestone release setup)."
)
def _notify_user(db, user_id, ntype, title, message=None, entity_type=None, entity_id=None):