|
25 | 25 |
|
26 | 26 | import re |
27 | 27 | from enum import StrEnum, auto |
| 28 | +from typing import Annotated |
| 29 | + |
| 30 | +from pydantic import Field |
28 | 31 |
|
29 | 32 | X_PFX = "x_" |
30 | 33 | """The prefix for extension namespaces. Extension namespaces must start with this prefix.""" |
31 | 34 |
|
| 35 | +MIN_NS_LENGTH = 3 |
| 36 | +MAX_NS_LENGTH = 1000 |
| 37 | +NS_LENGTH_INTERVAL = MAX_NS_LENGTH - MIN_NS_LENGTH |
| 38 | + |
| 39 | +LENGTH_CHECK_PATTERN = rf"(?=.{{{MIN_NS_LENGTH},{MAX_NS_LENGTH}}}$)" |
| 40 | +"""Ensures the string is between MIN_NS_LENGTH and MAX_NS_LENGTH characters long.""" |
| 41 | + |
| 42 | +PREFIX_CHECK_PATTERN = rf"(x_)?[a-z0-9]{{{MIN_NS_LENGTH}}}" |
| 43 | +"""Ensures the string starts with an optional prefix followed by at least 3 alphanumeric characters.""" |
| 44 | + |
| 45 | +REMAINDER_CHECK_PATTERN = rf"([/.-]?[a-z0-9]+){{0,{NS_LENGTH_INTERVAL}}}$" |
| 46 | +"""Ensures that the string contains only lowercase alphanumeric characters and limited punctuation characters (`/`, `.`, `-`),""" |
| 47 | + |
| 48 | + |
32 | 49 | # pattern to match |
33 | | -# `(?=.{3,100}$)`: 3-25 characters long |
34 | | -# `^(x_)`: `x_` prefix is optional |
35 | | -# `[a-z0-9]{3,4}`: must start with 3-4 alphanumeric characters |
36 | | -# `[/.-]?`: only one punctuation character is allowed between alphanumeric characters |
37 | | -# `[a-z0-9]+`: at least one alphanumeric character is required after the punctuation character |
38 | | -# `([/.-]?[a-z0-9]+){0,22}`: zero to 22 occurrences of the punctuation character followed by at least one alphanumeric character |
39 | | -# (note that the total limit will kick in at or before this point) |
40 | | -# `$`: end of the string |
41 | | -NS_PATTERN = re.compile(r"^(?=.{3,100}$)(x_)?[a-z0-9]{3}([/.-]?[a-z0-9]+){0,97}$") |
42 | | -"""The regular expression pattern for validating namespaces. |
43 | | -
|
44 | | -Note: |
| 50 | +# NOTE: be careful with this regex. We're using f-strings to insert the min and max lengths, so we need to ensure that |
| 51 | +# literal { and } characters are escaped properly (doubled up) so they appear in as single braces in the final regex. |
| 52 | +NS_PATTERN = re.compile( |
| 53 | + rf"^{LENGTH_CHECK_PATTERN}{PREFIX_CHECK_PATTERN}{REMAINDER_CHECK_PATTERN}$" |
| 54 | +) |
| 55 | +f"""The regular expression pattern for validating namespaces. |
| 56 | +
|
| 57 | +!!! note "Namespace Validation Rules" |
| 58 | +
|
45 | 59 | Namespace values must |
46 | 60 | |
47 | | - - be 3-25 characters long |
| 61 | + - be {MIN_NS_LENGTH}-{MAX_NS_LENGTH} characters long |
48 | 62 | - contain only lowercase alphanumeric characters and limited punctuation characters (`/`,`.` and `-`) |
49 | 63 | - have only one punctuation character in a row |
50 | | - - start with 3-4 alphanumeric characters after the optional extension prefix |
| 64 | + - start with 3 alphanumeric characters after the optional extension prefix |
51 | 65 | - end with an alphanumeric character |
52 | 66 | |
53 | | - See examples in the `NameSpace` enum. |
54 | 67 | """ |
55 | 68 |
|
| 69 | +NamespaceString = Annotated[ |
| 70 | + str, |
| 71 | + Field( |
| 72 | + description="The namespace of the SSVC object.", |
| 73 | + examples=["ssvc", "cisa", "x_private-test", "ssvc/de-DE/reference-arch-1"], |
| 74 | + pattern=NS_PATTERN, |
| 75 | + min_length=MIN_NS_LENGTH, |
| 76 | + max_length=MAX_NS_LENGTH, |
| 77 | + ), |
| 78 | +] |
| 79 | +"""A string datatype for namespace values, for use in Pydantic models.""" |
| 80 | + |
56 | 81 |
|
57 | 82 | class NameSpace(StrEnum): |
58 | | - """ |
| 83 | + f""" |
59 | 84 | Defines the official namespaces for SSVC. |
60 | 85 |
|
61 | 86 | The namespace value must be one of the members of this enum or start with the prefix specified in X_PFX. |
62 | | - Namespaces must be 3-25 lowercase characters long and must start with 3-4 alphanumeric characters after the optional prefix. |
| 87 | + Namespaces must be {MIN_NS_LENGTH}-{MAX_NS_LENGTH} lowercase characters long and must start with 3-4 |
| 88 | + alphanumeric characters after the optional prefix. |
63 | 89 | Limited punctuation characters (/.-) are allowed between alphanumeric characters, but only one at a time. |
64 | 90 |
|
65 | 91 | Example: |
|
0 commit comments