Skip to content

Commit

Permalink
Merge pull request #10 from yunojuno/issues/upgrade-pydantic-to-v2
Browse files Browse the repository at this point in the history
Update Pydantic to version 2.4.2
  • Loading branch information
paulopaixaoamaral authored Nov 7, 2023
2 parents 4e3f309 + 13d70c4 commit e2d3215
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 27 deletions.
11 changes: 9 additions & 2 deletions .github/workflows/tox.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,15 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python: ["3.10"]
django: [32,40,41,main]
python: ["3.10", "3.11", "3.12"]
django: [32,42,50,main]
exclude:
- python: "3.11"
django: "32"
- python: "3.12"
django: "32"
- python: "3.12"
django: "42"

env:
TOXENV: py${{ matrix.python }}-django${{ matrix.django }}
Expand Down
5 changes: 5 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

All notable changes to this project will be documented in this file.

## [3.0.0] - 2023-02-17

- Drop support for Python < 3.10
- Drop support for Pydantic < 2

## [0.10.0] - 2023-02-17

- Improve admin list view to include date filters and value search [#8]
Expand Down
38 changes: 18 additions & 20 deletions csp/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,19 @@

import logging
from collections import defaultdict
from typing import Any, TypeAlias
from typing import Any

from django.db import models
from django.db.models import F
from django.db.utils import IntegrityError
from django.utils.timezone import now as tz_now
from pydantic import BaseModel, Field, root_validator, validator
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator

from .settings import PolicyType
from .utils import strip_query

logger = logging.getLogger(__name__)

PydanticValues: TypeAlias = dict[str, str | None]


class ReportData(BaseModel):
# browser support for CSP reports turns out to be patchy at best -
Expand All @@ -28,17 +26,18 @@ class ReportData(BaseModel):
# min_length ensures we don't have an empty string
blocked_uri: str = Field(alias="blocked-uri", min_length=1)
# we must have one of these - validate_directives enforces this
effective_directive: str | None = Field(alias="effective-directive")
violated_directive: str | None = Field(alias="violated-directive")
effective_directive: str | None = Field(None, alias="effective-directive")
violated_directive: str | None = Field(None, alias="violated-directive")
# optional
disposition: str | None = Field("", alias="disposition")
document_uri: str | None = Field("", alias="document-uri")
original_policy: str | None = Field(alias="original-policy")
referrer: str | None = Field(alias="referrer")
script_sample: str | None = Field(alias="script-sample")
original_policy: str | None = Field(None, alias="original-policy")
referrer: str | None = Field(None, alias="referrer")
script_sample: str | None = Field(None, alias="script-sample")
status_code: str | None = Field(0, alias="status-code")

@validator("document_uri", "blocked_uri")
@field_validator("document_uri", "blocked_uri")
@classmethod
def strip_uri(cls, uri: str) -> str:
"""
Strip querystring and truncate to fit model length.
Expand All @@ -49,25 +48,24 @@ def strip_uri(cls, uri: str) -> str:
"""
return strip_query(uri)[:200] if uri else ""

@root_validator
def validate_directives(cls, values: PydanticValues) -> PydanticValues:
@model_validator(mode="after")
def validate_directives(self) -> ReportData:
"""Ensure that we have either effective_directive or violated_directive."""
if values.get("effective_directive", ""):
return values
if self.effective_directive:
return self
# if effective_directive is empty, but violated_directive is not,
# then udpate the former with the latter.
if violated_directive := values.get("violated_directive", ""):
# then update the former with the latter.
if self.violated_directive:
logger.debug(
"'effective_directive' missing - using 'violated_directive' attr."
)
values["effective_directive"] = violated_directive
return values
self.effective_directive = self.violated_directive
return self
raise ValueError(
"Either 'effective_directive' or 'violated_directive' must be present."
)

class Config:
allow_population_by_field_name = True
model_config = ConfigDict(populate_by_name=True, coerce_numbers_to_str=True)


class DispositionChoices(models.TextChoices):
Expand Down
6 changes: 2 additions & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "django-csp-plus"
version = "0.10.0"
version = "3.0.0"
description = "CSP tracking and violation report endpoint."
license = "MIT"
authors = ["YunoJuno <[email protected]>"]
Expand All @@ -19,8 +19,6 @@ classifiers = [
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
]
Expand All @@ -29,7 +27,7 @@ packages = [{ include = "csp" }]
[tool.poetry.dependencies]
python = "^3.8"
django = "^3.2 || ^4.0"
pydantic = "^1"
pydantic = "*"

[tool.poetry.dev-dependencies]
black = "*"
Expand Down
6 changes: 5 additions & 1 deletion tox.ini
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
[tox]
isolated_build = True
envlist = fmt, lint, mypy, checks, py{3.8,3.9,3.10,3.11}-django{32,41,42,main}
envlist =
fmt, lint, mypy, checks,
py{3.10}-django{32,42,50,main}
py{3.11}-django{42,50,main}
py{3.12}-django{50,main}

[testenv]
deps =
Expand Down

0 comments on commit e2d3215

Please sign in to comment.