Skip to content

Commit 61f8ac4

Browse files
authored
Adds http url validation to all weblinks (Netflix#4340)
1 parent 8ae79af commit 61f8ac4

File tree

8 files changed

+957
-113
lines changed

8 files changed

+957
-113
lines changed

data/dispatch-sample-data.dump

+936-98
Large diffs are not rendered by default.

src/dispatch/case/type/models.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from typing import List, Optional
22

3-
from pydantic import Field, validator
3+
from pydantic import Field, validator, HttpUrl
44
from sqlalchemy import JSON, Boolean, Column, ForeignKey, Integer, String
55
from sqlalchemy.event import listen
66
from sqlalchemy.ext.hybrid import hybrid_method
@@ -60,7 +60,7 @@ class Document(DispatchBase):
6060
name: NameStr
6161
resource_id: Optional[str] = Field(None, nullable=True)
6262
resource_type: Optional[str] = Field(None, nullable=True)
63-
weblink: str
63+
weblink: Optional[HttpUrl] = Field(None, nullable=True)
6464

6565

6666
class IncidentType(DispatchBase):

src/dispatch/data/source/models.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from typing import Optional, List
22
from datetime import datetime
3-
from pydantic import Field
3+
from pydantic import Field, HttpUrl
44

55
from sqlalchemy import (
66
JSON,
@@ -122,7 +122,7 @@ class SourceBase(DispatchBase):
122122
size: Optional[int] = Field(None, nullable=True)
123123
external_id: Optional[str] = Field(None, nullable=True)
124124
aggregated: Optional[bool] = Field(False, nullable=True)
125-
links: Optional[List] = []
125+
links: Optional[List[HttpUrl]] = []
126126
tags: Optional[List[TagRead]] = []
127127
incidents: Optional[List[IncidentRead]] = []
128128
queries: Optional[List[QueryReadMinimal]] = []

src/dispatch/incident/models.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from datetime import datetime
33
from typing import ForwardRef, List, Optional
44

5-
from pydantic import validator, Field
5+
from pydantic import validator, Field, HttpUrl
66

77
from sqlalchemy import Column, DateTime, ForeignKey, Integer, PrimaryKeyConstraint, String, Table
88
from sqlalchemy.ext.hybrid import hybrid_property
@@ -263,7 +263,7 @@ class TaskRead(DispatchBase):
263263
created_at: Optional[datetime]
264264
description: Optional[str] = Field(None, nullable=True)
265265
status: TaskStatus = TaskStatus.open
266-
weblink: Optional[str]
266+
weblink: Optional[HttpUrl] = Field(None, nullable=True)
267267

268268

269269
class TaskReadMinimal(DispatchBase):

src/dispatch/incident/type/models.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from typing import List, Optional
2-
from pydantic import validator, Field
2+
from pydantic import validator, Field, HttpUrl
33
from dispatch.models import NameStr, PrimaryKey
44

55
from sqlalchemy import Column, Boolean, ForeignKey, Integer, String, JSON
@@ -76,7 +76,7 @@ class Document(DispatchBase):
7676
resource_type: Optional[str] = Field(None, nullable=True)
7777
resource_id: Optional[str] = Field(None, nullable=True)
7878
description: Optional[str] = Field(None, nullable=True)
79-
weblink: str
79+
weblink: Optional[HttpUrl] = Field(None, nullable=True)
8080

8181

8282
# Pydantic models...

src/dispatch/individual/models.py

+9-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from datetime import datetime
2-
from typing import List, Optional
3-
from pydantic import Field
2+
from typing import List, Optional, Union
3+
from pydantic import Field, HttpUrl, validator
44

55
from sqlalchemy import Column, ForeignKey, Integer, PrimaryKeyConstraint, String, Table
66
from sqlalchemy.sql.schema import UniqueConstraint
@@ -63,12 +63,18 @@ class IndividualContact(Base, ContactMixin, ProjectMixin):
6363

6464

6565
class IndividualContactBase(ContactBase):
66-
weblink: Optional[str] = Field(None, nullable=True)
66+
weblink: Union[HttpUrl, None, str] = Field(None, nullable=True)
6767
mobile_phone: Optional[str] = Field(None, nullable=True)
6868
office_phone: Optional[str] = Field(None, nullable=True)
6969
title: Optional[str] = Field(None, nullable=True)
7070
external_id: Optional[str] = Field(None, nullable=True)
7171

72+
@validator("weblink")
73+
def weblink_validator(cls, v):
74+
if v is None or isinstance(v, HttpUrl) or v == "":
75+
return v
76+
raise ValueError("weblink is not an empty string or a valid weblink")
77+
7278

7379
class IndividualContactCreate(IndividualContactBase):
7480
filters: Optional[List[SearchFilterRead]]

src/dispatch/models.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from datetime import datetime, timedelta
33

44
from pydantic.fields import Field
5-
from pydantic.networks import EmailStr
5+
from pydantic.networks import EmailStr, HttpUrl
66
from pydantic import BaseModel
77
from pydantic.types import conint, constr, SecretStr
88

@@ -136,7 +136,7 @@ class EvergreenBase(DispatchBase):
136136
class ResourceBase(DispatchBase):
137137
resource_type: Optional[str] = Field(None, nullable=True)
138138
resource_id: Optional[str] = Field(None, nullable=True)
139-
weblink: Optional[str] = Field(None, nullable=True)
139+
weblink: Optional[HttpUrl] = Field(None, nullable=True)
140140

141141

142142
class ContactBase(DispatchBase):

src/dispatch/plugins/dispatch_slack/models.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from typing import Optional, NewType
22

3-
from pydantic import BaseModel
3+
from pydantic import BaseModel, Field, HttpUrl
44

55
from dispatch.enums import DispatchEnum
66

@@ -27,7 +27,7 @@ class TaskMetadata(SubjectMetadata):
2727

2828

2929
class MonitorMetadata(SubjectMetadata):
30-
weblink: str
30+
weblink: Optional[HttpUrl] = Field(None, nullable=True)
3131
plugin_instance_id: int
3232

3333

0 commit comments

Comments
 (0)