jentic-openapi-datamodels 1.0.0a12__py3-none-any.whl → 1.0.0a13__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- jentic/apitools/openapi/datamodels/low/context.py +21 -0
- jentic/apitools/openapi/datamodels/low/extractors.py +126 -0
- jentic/apitools/openapi/datamodels/low/fields.py +45 -0
- jentic/apitools/openapi/datamodels/low/model_builder.py +113 -0
- jentic/apitools/openapi/datamodels/low/py.typed +0 -0
- jentic/apitools/openapi/datamodels/low/sources.py +89 -0
- jentic/apitools/openapi/datamodels/low/v30/__init__.py +0 -28
- jentic/apitools/openapi/datamodels/low/v30/discriminator.py +53 -78
- jentic/apitools/openapi/datamodels/low/v30/external_documentation.py +47 -61
- jentic/apitools/openapi/datamodels/low/v30/oauth_flow.py +54 -123
- jentic/apitools/openapi/datamodels/low/v30/oauth_flows.py +102 -151
- jentic/apitools/openapi/datamodels/low/v30/reference.py +43 -44
- jentic/apitools/openapi/datamodels/low/v30/schema.py +316 -607
- jentic/apitools/openapi/datamodels/low/v30/security_requirement.py +82 -72
- jentic/apitools/openapi/datamodels/low/v30/security_scheme.py +94 -286
- jentic/apitools/openapi/datamodels/low/v30/tag.py +88 -119
- jentic/apitools/openapi/datamodels/low/v30/xml.py +46 -120
- jentic_openapi_datamodels-1.0.0a13.dist-info/METADATA +211 -0
- jentic_openapi_datamodels-1.0.0a13.dist-info/RECORD +23 -0
- jentic/apitools/openapi/datamodels/low/v30/specification_object.py +0 -217
- jentic_openapi_datamodels-1.0.0a12.dist-info/METADATA +0 -52
- jentic_openapi_datamodels-1.0.0a12.dist-info/RECORD +0 -18
- /jentic/apitools/openapi/datamodels/low/{v30/py.typed → __init__.py} +0 -0
- {jentic_openapi_datamodels-1.0.0a12.dist-info → jentic_openapi_datamodels-1.0.0a13.dist-info}/WHEEL +0 -0
- {jentic_openapi_datamodels-1.0.0a12.dist-info → jentic_openapi_datamodels-1.0.0a13.dist-info}/licenses/LICENSE +0 -0
- {jentic_openapi_datamodels-1.0.0a12.dist-info → jentic_openapi_datamodels-1.0.0a13.dist-info}/licenses/NOTICE +0 -0
|
@@ -1,91 +1,101 @@
|
|
|
1
|
-
|
|
2
|
-
OpenAPI 3.0.4 Security Requirement Object model.
|
|
1
|
+
from dataclasses import dataclass
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
required for execution (for OAuth2/OIDC) or an empty list (for other schemes).
|
|
7
|
-
"""
|
|
3
|
+
from ruamel import yaml
|
|
4
|
+
from ruamel.yaml import MappingNode, SequenceNode
|
|
8
5
|
|
|
9
|
-
from jentic.apitools.openapi.datamodels.low.
|
|
6
|
+
from jentic.apitools.openapi.datamodels.low.context import Context
|
|
7
|
+
from jentic.apitools.openapi.datamodels.low.fields import patterned_field
|
|
8
|
+
from jentic.apitools.openapi.datamodels.low.sources import KeySource, ValueSource
|
|
10
9
|
|
|
11
10
|
|
|
12
|
-
__all__ = ["SecurityRequirement"]
|
|
11
|
+
__all__ = ["SecurityRequirement", "build"]
|
|
13
12
|
|
|
14
13
|
|
|
15
|
-
|
|
14
|
+
@dataclass(frozen=True, slots=True)
|
|
15
|
+
class SecurityRequirement:
|
|
16
16
|
"""
|
|
17
|
-
|
|
17
|
+
Security Requirement Object representation for OpenAPI 3.0.
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
Lists the required security schemes to execute an operation. Each named security scheme
|
|
20
|
+
must correspond to a security scheme declared in the Security Schemes under the Components Object.
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
Objects are defined, only ONE needs to be satisfied to authorize the request.
|
|
22
|
+
When multiple Security Requirement Objects are specified, only ONE needs to be satisfied
|
|
23
|
+
to authorize a request. Within a single Security Requirement Object, ALL schemes must be satisfied.
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
Note: An empty Security Requirement object ({}) makes security optional for the operation.
|
|
26
|
+
Note: Specification extensions (x-* fields) are NOT supported for Security Requirement objects.
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
>>> # OAuth2 requirement with scopes
|
|
35
|
-
>>> req = SecurityRequirement({"petstore_auth": ["write:pets", "read:pets"]})
|
|
36
|
-
>>> req["petstore_auth"]
|
|
37
|
-
['write:pets', 'read:pets']
|
|
38
|
-
|
|
39
|
-
>>> # Empty requirement (makes security optional)
|
|
40
|
-
>>> req = SecurityRequirement({})
|
|
41
|
-
|
|
42
|
-
>>> # Security scheme named "x-custom" (NOT an extension)
|
|
43
|
-
>>> req = SecurityRequirement({"x-custom": []})
|
|
44
|
-
>>> "x-custom" in req
|
|
45
|
-
True
|
|
28
|
+
Attributes:
|
|
29
|
+
root_node: The top-level node representing the entire Security Requirement object in the original source file
|
|
30
|
+
requirements: Dictionary mapping security scheme names to arrays of scope strings.
|
|
31
|
+
For OAuth2 schemes, the array contains required scopes.
|
|
32
|
+
For other schemes (API key, HTTP), the array is empty.
|
|
46
33
|
"""
|
|
47
34
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
return super().__getitem__(key) # type: ignore
|
|
53
|
-
|
|
54
|
-
def __getattr__(self, name: str) -> list[str]:
|
|
55
|
-
"""Get scopes for a security scheme (attribute-style access)."""
|
|
56
|
-
return super().__getattr__(name) # type: ignore
|
|
57
|
-
|
|
58
|
-
def get_schemes(self) -> list[str]:
|
|
59
|
-
"""
|
|
60
|
-
Get the list of security scheme names referenced.
|
|
61
|
-
|
|
62
|
-
Returns:
|
|
63
|
-
List of security scheme names
|
|
64
|
-
"""
|
|
65
|
-
return list(self.keys())
|
|
35
|
+
root_node: yaml.Node
|
|
36
|
+
requirements: ValueSource[dict[KeySource[str], ValueSource[list[ValueSource[str]]]]] | None = (
|
|
37
|
+
patterned_field()
|
|
38
|
+
)
|
|
66
39
|
|
|
67
|
-
def get_scopes(self, scheme_name: str) -> list[str]:
|
|
68
|
-
"""
|
|
69
|
-
Get the scopes required for a specific security scheme.
|
|
70
40
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
Returns:
|
|
75
|
-
List of scope names (empty for non-OAuth2/OIDC schemes)
|
|
41
|
+
def build(root: yaml.Node, context: Context | None = None) -> SecurityRequirement | None:
|
|
42
|
+
"""
|
|
43
|
+
Build a SecurityRequirement object from a YAML node.
|
|
76
44
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
"""
|
|
80
|
-
return self[scheme_name]
|
|
45
|
+
Preserves all source data as-is, regardless of type. This is a low-level/plumbing
|
|
46
|
+
model that provides complete source fidelity for inspection and validation.
|
|
81
47
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
48
|
+
Args:
|
|
49
|
+
root: The YAML node to parse (should be a MappingNode)
|
|
50
|
+
context: Optional parsing context. If None, a default context will be created.
|
|
85
51
|
|
|
86
|
-
|
|
52
|
+
Returns:
|
|
53
|
+
A SecurityRequirement object if the node is valid, None otherwise
|
|
87
54
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
55
|
+
Example:
|
|
56
|
+
from ruamel.yaml import YAML
|
|
57
|
+
yaml = YAML()
|
|
58
|
+
root = yaml.compose("api_key: []")
|
|
59
|
+
security_req = build(root)
|
|
60
|
+
assert security_req.requirements is not None
|
|
61
|
+
"""
|
|
62
|
+
if not isinstance(root, MappingNode):
|
|
63
|
+
return None
|
|
64
|
+
|
|
65
|
+
if context is None:
|
|
66
|
+
context = Context()
|
|
67
|
+
|
|
68
|
+
requirements_dict: dict[KeySource[str], ValueSource[list[ValueSource[str]]]] = {}
|
|
69
|
+
|
|
70
|
+
for key_node, value_node in root.value:
|
|
71
|
+
key = context.yaml_constructor.construct_yaml_str(key_node)
|
|
72
|
+
|
|
73
|
+
# Skip non-string keys
|
|
74
|
+
if not isinstance(key, str):
|
|
75
|
+
continue
|
|
76
|
+
|
|
77
|
+
# Security scheme requirement field
|
|
78
|
+
# For requirements, we need to wrap each scope string in ValueSource
|
|
79
|
+
if isinstance(value_node, SequenceNode):
|
|
80
|
+
# Wrap each scope string in the array with its source node
|
|
81
|
+
scope_list: list[ValueSource[str]] = []
|
|
82
|
+
for item_node in value_node.value:
|
|
83
|
+
item_value = context.yaml_constructor.construct_object(item_node, deep=True)
|
|
84
|
+
scope_list.append(ValueSource(value=item_value, value_node=item_node))
|
|
85
|
+
|
|
86
|
+
requirements_dict[KeySource(value=key, key_node=key_node)] = ValueSource(
|
|
87
|
+
value=scope_list, value_node=value_node
|
|
88
|
+
)
|
|
89
|
+
else:
|
|
90
|
+
# Not a sequence - preserve as-is for validation to catch
|
|
91
|
+
value = context.yaml_constructor.construct_object(value_node, deep=True)
|
|
92
|
+
requirements_dict[KeySource(value=key, key_node=key_node)] = ValueSource(
|
|
93
|
+
value=value, value_node=value_node
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
return SecurityRequirement(
|
|
97
|
+
root_node=root,
|
|
98
|
+
requirements=(
|
|
99
|
+
ValueSource(value=requirements_dict, value_node=root) if requirements_dict else None
|
|
100
|
+
),
|
|
101
|
+
)
|
|
@@ -1,301 +1,109 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
from
|
|
8
|
-
from
|
|
9
|
-
|
|
1
|
+
from dataclasses import dataclass, field, replace
|
|
2
|
+
|
|
3
|
+
from ruamel import yaml
|
|
4
|
+
|
|
5
|
+
from jentic.apitools.openapi.datamodels.low.context import Context
|
|
6
|
+
from jentic.apitools.openapi.datamodels.low.fields import fixed_field
|
|
7
|
+
from jentic.apitools.openapi.datamodels.low.model_builder import build_model
|
|
8
|
+
from jentic.apitools.openapi.datamodels.low.sources import (
|
|
9
|
+
FieldSource,
|
|
10
|
+
KeySource,
|
|
11
|
+
ValueSource,
|
|
12
|
+
YAMLInvalidValue,
|
|
13
|
+
YAMLValue,
|
|
14
|
+
)
|
|
10
15
|
from jentic.apitools.openapi.datamodels.low.v30.oauth_flows import OAuthFlows
|
|
11
|
-
from jentic.apitools.openapi.datamodels.low.v30.
|
|
16
|
+
from jentic.apitools.openapi.datamodels.low.v30.oauth_flows import build as build_oauth_flows
|
|
12
17
|
|
|
13
18
|
|
|
14
|
-
__all__ = ["SecurityScheme"]
|
|
19
|
+
__all__ = ["SecurityScheme", "build"]
|
|
15
20
|
|
|
16
21
|
|
|
17
|
-
|
|
22
|
+
@dataclass(frozen=True, slots=True)
|
|
23
|
+
class SecurityScheme:
|
|
18
24
|
"""
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
Defines a security scheme that can be used by
|
|
22
|
-
scheme
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
>>> scheme.in_
|
|
36
|
-
'header'
|
|
37
|
-
|
|
38
|
-
>>> # HTTP Bearer scheme
|
|
39
|
-
>>> scheme = SecurityScheme({
|
|
40
|
-
... "type": "http",
|
|
41
|
-
... "scheme": "bearer",
|
|
42
|
-
... "bearerFormat": "JWT"
|
|
43
|
-
... })
|
|
44
|
-
>>> scheme.is_http()
|
|
45
|
-
True
|
|
46
|
-
>>> scheme.bearer_format
|
|
47
|
-
'JWT'
|
|
48
|
-
|
|
49
|
-
>>> # OAuth2 scheme with flows
|
|
50
|
-
>>> scheme = SecurityScheme({
|
|
51
|
-
... "type": "oauth2",
|
|
52
|
-
... "flows": {
|
|
53
|
-
... "implicit": {
|
|
54
|
-
... "authorizationUrl": "https://example.com/oauth/authorize",
|
|
55
|
-
... "scopes": {"read": "Read access"}
|
|
56
|
-
... }
|
|
57
|
-
... }
|
|
58
|
-
... })
|
|
59
|
-
>>> scheme.is_oauth2()
|
|
60
|
-
True
|
|
61
|
-
>>> scheme.flows.implicit.authorization_url
|
|
62
|
-
'https://example.com/oauth/authorize'
|
|
63
|
-
|
|
64
|
-
>>> # OpenID Connect scheme
|
|
65
|
-
>>> scheme = SecurityScheme({
|
|
66
|
-
... "type": "openIdConnect",
|
|
67
|
-
... "openIdConnectUrl": "https://example.com/.well-known/openid-configuration"
|
|
68
|
-
... })
|
|
69
|
-
>>> scheme.is_openid_connect()
|
|
70
|
-
True
|
|
25
|
+
Security Scheme Object representation for OpenAPI 3.0.
|
|
26
|
+
|
|
27
|
+
Defines a security scheme that can be used by operations.
|
|
28
|
+
The security scheme type determines which additional fields are required.
|
|
29
|
+
|
|
30
|
+
Attributes:
|
|
31
|
+
root_node: The top-level node representing the entire Security Scheme object in the original source file
|
|
32
|
+
type: REQUIRED. The type of the security scheme. Valid values: "apiKey", "http", "oauth2", "openIdConnect"
|
|
33
|
+
description: A short description for the security scheme. CommonMark syntax MAY be used for rich text representation
|
|
34
|
+
name: REQUIRED for apiKey. The name of the header, query or cookie parameter to be used
|
|
35
|
+
in_: REQUIRED for apiKey. The location of the API key. Valid values: "query", "header", "cookie"
|
|
36
|
+
scheme: REQUIRED for http. The name of the HTTP Authorization scheme (e.g., "basic", "bearer")
|
|
37
|
+
bearer_format: A hint to the client to identify how the bearer token is formatted (e.g., "JWT")
|
|
38
|
+
flows: REQUIRED for oauth2. An object containing configuration information for the flow types supported
|
|
39
|
+
openid_connect_url: REQUIRED for openIdConnect. OpenId Connect URL to discover OAuth2 configuration values
|
|
40
|
+
extensions: Specification extensions (x-* fields)
|
|
71
41
|
"""
|
|
72
42
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
43
|
+
root_node: yaml.Node
|
|
44
|
+
type: FieldSource[str] | None = fixed_field()
|
|
45
|
+
description: FieldSource[str] | None = fixed_field()
|
|
46
|
+
name: FieldSource[str] | None = fixed_field()
|
|
47
|
+
in_: FieldSource[str] | None = fixed_field(metadata={"yaml_name": "in"})
|
|
48
|
+
scheme: FieldSource[str] | None = fixed_field()
|
|
49
|
+
bearer_format: FieldSource[str] | None = fixed_field(metadata={"yaml_name": "bearerFormat"})
|
|
50
|
+
flows: FieldSource[OAuthFlows] | None = fixed_field()
|
|
51
|
+
openid_connect_url: FieldSource[str] | None = fixed_field(
|
|
52
|
+
metadata={"yaml_name": "openIdConnectUrl"}
|
|
76
53
|
)
|
|
54
|
+
extensions: dict[KeySource[str], ValueSource[YAMLValue]] = field(default_factory=dict)
|
|
77
55
|
|
|
78
|
-
def __init__(self, data: Mapping[str, Any] | None = None):
|
|
79
|
-
"""
|
|
80
|
-
Initialize a SecurityScheme object.
|
|
81
|
-
|
|
82
|
-
Automatically marshals nested flows data (Mapping) into OAuthFlows instance.
|
|
83
|
-
|
|
84
|
-
Args:
|
|
85
|
-
data: Optional mapping to initialize the object with
|
|
86
|
-
"""
|
|
87
|
-
super().__init__()
|
|
88
|
-
if data:
|
|
89
|
-
for key, value in data.items():
|
|
90
|
-
# Marshal flows field specifically if it's a raw Mapping (not already OAuthFlows)
|
|
91
|
-
if (
|
|
92
|
-
key == "flows"
|
|
93
|
-
and isinstance(value, Mapping)
|
|
94
|
-
and not isinstance(value, OAuthFlows)
|
|
95
|
-
):
|
|
96
|
-
self[key] = OAuthFlows(value)
|
|
97
|
-
else:
|
|
98
|
-
# Store as-is (already OAuthFlows, extension, or other)
|
|
99
|
-
self[key] = self._copy_value(value)
|
|
100
|
-
|
|
101
|
-
@property
|
|
102
|
-
def type(self) -> str | None:
|
|
103
|
-
"""
|
|
104
|
-
The type of the security scheme.
|
|
105
|
-
|
|
106
|
-
Valid values: "apiKey", "http", "oauth2", "openIdConnect", "mutualTLS"
|
|
107
|
-
|
|
108
|
-
REQUIRED field.
|
|
109
|
-
|
|
110
|
-
Returns:
|
|
111
|
-
Security scheme type or None if not present
|
|
112
|
-
"""
|
|
113
|
-
return self.get("type")
|
|
114
|
-
|
|
115
|
-
@type.setter
|
|
116
|
-
def type(self, value: str | None) -> None:
|
|
117
|
-
"""Set the security scheme type."""
|
|
118
|
-
if value is None:
|
|
119
|
-
self.pop("type", None)
|
|
120
|
-
else:
|
|
121
|
-
self["type"] = value
|
|
122
|
-
|
|
123
|
-
@property
|
|
124
|
-
def description(self) -> str | None:
|
|
125
|
-
"""
|
|
126
|
-
A description for security scheme.
|
|
127
|
-
|
|
128
|
-
Returns:
|
|
129
|
-
Description or None if not present
|
|
130
|
-
"""
|
|
131
|
-
return self.get("description")
|
|
132
|
-
|
|
133
|
-
@description.setter
|
|
134
|
-
def description(self, value: str | None) -> None:
|
|
135
|
-
"""Set the description."""
|
|
136
|
-
if value is None:
|
|
137
|
-
self.pop("description", None)
|
|
138
|
-
else:
|
|
139
|
-
self["description"] = value
|
|
140
|
-
|
|
141
|
-
@property
|
|
142
|
-
def name(self) -> str | None:
|
|
143
|
-
"""
|
|
144
|
-
The name of the header, query or cookie parameter.
|
|
145
|
-
|
|
146
|
-
REQUIRED for apiKey type.
|
|
147
|
-
|
|
148
|
-
Returns:
|
|
149
|
-
Parameter name or None if not present
|
|
150
|
-
"""
|
|
151
|
-
return self.get("name")
|
|
152
|
-
|
|
153
|
-
@name.setter
|
|
154
|
-
def name(self, value: str | None) -> None:
|
|
155
|
-
"""Set the parameter name."""
|
|
156
|
-
if value is None:
|
|
157
|
-
self.pop("name", None)
|
|
158
|
-
else:
|
|
159
|
-
self["name"] = value
|
|
160
|
-
|
|
161
|
-
@property
|
|
162
|
-
def in_(self) -> str | None:
|
|
163
|
-
"""
|
|
164
|
-
The location of the API key.
|
|
165
|
-
|
|
166
|
-
Valid values: "query", "header", "cookie"
|
|
167
|
-
|
|
168
|
-
REQUIRED for apiKey type.
|
|
169
56
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
return self.get("in")
|
|
176
|
-
|
|
177
|
-
@in_.setter
|
|
178
|
-
def in_(self, value: str | None) -> None:
|
|
179
|
-
"""Set the API key location."""
|
|
180
|
-
if value is None:
|
|
181
|
-
self.pop("in", None)
|
|
182
|
-
else:
|
|
183
|
-
self["in"] = value
|
|
184
|
-
|
|
185
|
-
@property
|
|
186
|
-
def scheme(self) -> str | None:
|
|
187
|
-
"""
|
|
188
|
-
The name of the HTTP Authorization scheme.
|
|
189
|
-
|
|
190
|
-
Examples: "bearer", "basic", "digest"
|
|
191
|
-
|
|
192
|
-
REQUIRED for http type.
|
|
193
|
-
|
|
194
|
-
Returns:
|
|
195
|
-
Scheme name or None if not present
|
|
196
|
-
"""
|
|
197
|
-
return self.get("scheme")
|
|
198
|
-
|
|
199
|
-
@scheme.setter
|
|
200
|
-
def scheme(self, value: str | None) -> None:
|
|
201
|
-
"""Set the HTTP scheme."""
|
|
202
|
-
if value is None:
|
|
203
|
-
self.pop("scheme", None)
|
|
204
|
-
else:
|
|
205
|
-
self["scheme"] = value
|
|
206
|
-
|
|
207
|
-
@property
|
|
208
|
-
def bearer_format(self) -> str | None:
|
|
209
|
-
"""
|
|
210
|
-
A hint to the client to identify how the bearer token is formatted.
|
|
211
|
-
|
|
212
|
-
Examples: "JWT", "opaque"
|
|
213
|
-
|
|
214
|
-
Returns:
|
|
215
|
-
Bearer format or None if not present
|
|
216
|
-
"""
|
|
217
|
-
return self.get("bearerFormat")
|
|
218
|
-
|
|
219
|
-
@bearer_format.setter
|
|
220
|
-
def bearer_format(self, value: str | None) -> None:
|
|
221
|
-
"""Set the bearer format."""
|
|
222
|
-
if value is None:
|
|
223
|
-
self.pop("bearerFormat", None)
|
|
224
|
-
else:
|
|
225
|
-
self["bearerFormat"] = value
|
|
226
|
-
|
|
227
|
-
@property
|
|
228
|
-
def flows(self) -> OAuthFlows | None:
|
|
229
|
-
"""
|
|
230
|
-
Configuration information for the OAuth flows.
|
|
231
|
-
|
|
232
|
-
REQUIRED for oauth2 type.
|
|
233
|
-
|
|
234
|
-
Returns:
|
|
235
|
-
OAuthFlows instance or None if not present
|
|
236
|
-
"""
|
|
237
|
-
return self.get("flows")
|
|
238
|
-
|
|
239
|
-
@flows.setter
|
|
240
|
-
def flows(self, value: OAuthFlows | None) -> None:
|
|
241
|
-
"""Set the OAuth flows configuration."""
|
|
242
|
-
if value is None:
|
|
243
|
-
self.pop("flows", None)
|
|
244
|
-
else:
|
|
245
|
-
self["flows"] = value
|
|
246
|
-
|
|
247
|
-
@property
|
|
248
|
-
def open_id_connect_url(self) -> str | None:
|
|
249
|
-
"""
|
|
250
|
-
OpenID Connect URL to discover OAuth2 configuration values.
|
|
251
|
-
|
|
252
|
-
REQUIRED for openIdConnect type.
|
|
253
|
-
|
|
254
|
-
Returns:
|
|
255
|
-
OpenID Connect URL or None if not present
|
|
256
|
-
"""
|
|
257
|
-
return self.get("openIdConnectUrl")
|
|
258
|
-
|
|
259
|
-
@open_id_connect_url.setter
|
|
260
|
-
def open_id_connect_url(self, value: str | None) -> None:
|
|
261
|
-
"""Set the OpenID Connect URL."""
|
|
262
|
-
if value is None:
|
|
263
|
-
self.pop("openIdConnectUrl", None)
|
|
264
|
-
else:
|
|
265
|
-
self["openIdConnectUrl"] = value
|
|
266
|
-
|
|
267
|
-
def is_api_key(self) -> bool:
|
|
268
|
-
"""
|
|
269
|
-
Check if this is an API Key security scheme.
|
|
270
|
-
|
|
271
|
-
Returns:
|
|
272
|
-
True if type is "apiKey"
|
|
273
|
-
"""
|
|
274
|
-
return self.type == "apiKey"
|
|
275
|
-
|
|
276
|
-
def is_http(self) -> bool:
|
|
277
|
-
"""
|
|
278
|
-
Check if this is an HTTP security scheme.
|
|
279
|
-
|
|
280
|
-
Returns:
|
|
281
|
-
True if type is "http"
|
|
282
|
-
"""
|
|
283
|
-
return self.type == "http"
|
|
57
|
+
def build(
|
|
58
|
+
root: yaml.Node, context: Context | None = None
|
|
59
|
+
) -> SecurityScheme | ValueSource[YAMLInvalidValue]:
|
|
60
|
+
"""
|
|
61
|
+
Build a SecurityScheme object from a YAML node.
|
|
284
62
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
Check if this is an OAuth2 security scheme.
|
|
63
|
+
Preserves all source data as-is, regardless of type. This is a low-level/plumbing
|
|
64
|
+
model that provides complete source fidelity for inspection and validation.
|
|
288
65
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
return self.type == "oauth2"
|
|
66
|
+
Args:
|
|
67
|
+
root: The YAML node to parse (should be a MappingNode)
|
|
68
|
+
context: Optional parsing context. If None, a default context will be created.
|
|
293
69
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
70
|
+
Returns:
|
|
71
|
+
A SecurityScheme object if the node is valid, or a ValueSource containing
|
|
72
|
+
the invalid data if the root is not a MappingNode (preserving the invalid data
|
|
73
|
+
and its source location for validation).
|
|
297
74
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
75
|
+
Example:
|
|
76
|
+
from ruamel.yaml import YAML
|
|
77
|
+
yaml = YAML()
|
|
78
|
+
root = yaml.compose("type: apiKey\\nname: api_key\\nin: header")
|
|
79
|
+
security_scheme = build(root)
|
|
80
|
+
assert security_scheme.type.value == 'apiKey'
|
|
81
|
+
"""
|
|
82
|
+
# Initialize context once at the beginning
|
|
83
|
+
if context is None:
|
|
84
|
+
context = Context()
|
|
85
|
+
|
|
86
|
+
if not isinstance(root, yaml.MappingNode):
|
|
87
|
+
# Preserve invalid root data instead of returning None
|
|
88
|
+
value = context.yaml_constructor.construct_object(root, deep=True)
|
|
89
|
+
return ValueSource(value=value, value_node=root)
|
|
90
|
+
|
|
91
|
+
# Use build_model to handle most fields
|
|
92
|
+
security_scheme = build_model(root, SecurityScheme, context=context)
|
|
93
|
+
|
|
94
|
+
# Manually handle special fields that build_model can't process (nested objects)
|
|
95
|
+
for key_node, value_node in root.value:
|
|
96
|
+
key = context.yaml_constructor.construct_yaml_str(key_node)
|
|
97
|
+
|
|
98
|
+
if key == "flows":
|
|
99
|
+
# Handle nested OAuthFlows object - child builder handles invalid nodes
|
|
100
|
+
# FieldSource will auto-unwrap ValueSource if child returns it for invalid data
|
|
101
|
+
flows = FieldSource(
|
|
102
|
+
value=build_oauth_flows(value_node, context=context),
|
|
103
|
+
key_node=key_node,
|
|
104
|
+
value_node=value_node,
|
|
105
|
+
)
|
|
106
|
+
security_scheme = replace(security_scheme, flows=flows)
|
|
107
|
+
break
|
|
108
|
+
|
|
109
|
+
return security_scheme
|