tigrcorn-static 0.3.18.dev2__tar.gz → 0.3.18.dev3__tar.gz
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.
- {tigrcorn_static-0.3.18.dev2 → tigrcorn_static-0.3.18.dev3}/PKG-INFO +5 -5
- {tigrcorn_static-0.3.18.dev2 → tigrcorn_static-0.3.18.dev3}/README.md +1 -1
- {tigrcorn_static-0.3.18.dev2 → tigrcorn_static-0.3.18.dev3}/pyproject.toml +4 -4
- {tigrcorn_static-0.3.18.dev2 → tigrcorn_static-0.3.18.dev3}/src/tigrcorn_static/static/__init__.py +8 -0
- {tigrcorn_static-0.3.18.dev2 → tigrcorn_static-0.3.18.dev3}/src/tigrcorn_static/static/security.py +109 -0
- {tigrcorn_static-0.3.18.dev2 → tigrcorn_static-0.3.18.dev3}/src/tigrcorn_static.egg-info/PKG-INFO +5 -5
- tigrcorn_static-0.3.18.dev3/src/tigrcorn_static.egg-info/requires.txt +3 -0
- tigrcorn_static-0.3.18.dev2/src/tigrcorn_static.egg-info/requires.txt +0 -3
- {tigrcorn_static-0.3.18.dev2 → tigrcorn_static-0.3.18.dev3}/LICENSE +0 -0
- {tigrcorn_static-0.3.18.dev2 → tigrcorn_static-0.3.18.dev3}/setup.cfg +0 -0
- {tigrcorn_static-0.3.18.dev2 → tigrcorn_static-0.3.18.dev3}/src/tigrcorn_static/__init__.py +0 -0
- {tigrcorn_static-0.3.18.dev2 → tigrcorn_static-0.3.18.dev3}/src/tigrcorn_static/py.typed +0 -0
- {tigrcorn_static-0.3.18.dev2 → tigrcorn_static-0.3.18.dev3}/src/tigrcorn_static/static/app.py +0 -0
- {tigrcorn_static-0.3.18.dev2 → tigrcorn_static-0.3.18.dev3}/src/tigrcorn_static/static/models.py +0 -0
- {tigrcorn_static-0.3.18.dev2 → tigrcorn_static-0.3.18.dev3}/src/tigrcorn_static/static/mounting.py +0 -0
- {tigrcorn_static-0.3.18.dev2 → tigrcorn_static-0.3.18.dev3}/src/tigrcorn_static/static/representations.py +0 -0
- {tigrcorn_static-0.3.18.dev2 → tigrcorn_static-0.3.18.dev3}/src/tigrcorn_static/static/responses.py +0 -0
- {tigrcorn_static-0.3.18.dev2 → tigrcorn_static-0.3.18.dev3}/src/tigrcorn_static.egg-info/SOURCES.txt +0 -0
- {tigrcorn_static-0.3.18.dev2 → tigrcorn_static-0.3.18.dev3}/src/tigrcorn_static.egg-info/dependency_links.txt +0 -0
- {tigrcorn_static-0.3.18.dev2 → tigrcorn_static-0.3.18.dev3}/src/tigrcorn_static.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tigrcorn-static
|
|
3
|
-
Version: 0.3.18.
|
|
3
|
+
Version: 0.3.18.dev3
|
|
4
4
|
Summary: Static file origin, file-send, validators, ranges, and cache-aware HTTP responses for the Tigrcorn ASGI server.
|
|
5
5
|
Author-email: Jacob Stewart <jacob@swarmauri.com>
|
|
6
6
|
License: Apache License
|
|
@@ -186,9 +186,9 @@ Classifier: Typing :: Typed
|
|
|
186
186
|
Requires-Python: <3.15,>=3.10
|
|
187
187
|
Description-Content-Type: text/markdown
|
|
188
188
|
License-File: LICENSE
|
|
189
|
-
Requires-Dist: tigrcorn-core==0.3.18.
|
|
190
|
-
Requires-Dist: tigrcorn-asgi==0.3.18.
|
|
191
|
-
Requires-Dist: tigrcorn-http==0.3.18.
|
|
189
|
+
Requires-Dist: tigrcorn-core==0.3.18.dev3
|
|
190
|
+
Requires-Dist: tigrcorn-asgi==0.3.18.dev3
|
|
191
|
+
Requires-Dist: tigrcorn-http==0.3.18.dev3
|
|
192
192
|
Dynamic: license-file
|
|
193
193
|
|
|
194
194
|
<div align="center">
|
|
@@ -279,7 +279,7 @@ The package exposes its supported public surface through the <code>tigrcorn_stat
|
|
|
279
279
|
|
|
280
280
|
## Package Graph
|
|
281
281
|
|
|
282
|
-
[tigrcorn-core](https://pypi.org/project/tigrcorn-core/) | [tigrcorn-config](https://pypi.org/project/tigrcorn-config/) | [tigrcorn-http](https://pypi.org/project/tigrcorn-http/) | [tigrcorn-asgi](https://pypi.org/project/tigrcorn-asgi/) | [tigrcorn-contract](https://pypi.org/project/tigrcorn-contract/) | [tigrcorn-transports](https://pypi.org/project/tigrcorn-transports/) | [tigrcorn-security](https://pypi.org/project/tigrcorn-security/) | [tigrcorn-protocols](https://pypi.org/project/tigrcorn-protocols/) | [tigrcorn-static](https://pypi.org/project/tigrcorn-static/) | [tigrcorn-observability](https://pypi.org/project/tigrcorn-observability/) | [tigrcorn-runtime](https://pypi.org/project/tigrcorn-runtime/) | [tigrcorn-compat](https://pypi.org/project/tigrcorn-compat/) | [tigrcorn-certification](https://pypi.org/project/tigrcorn-certification/)
|
|
282
|
+
[tigrcorn-core](https://pypi.org/project/tigrcorn-core/) | [tigrcorn-quic-cc](https://pypi.org/project/tigrcorn-quic-cc/) | [tigrcorn-quic-cc-reno](https://pypi.org/project/tigrcorn-quic-cc-reno/) | [tigrcorn-config](https://pypi.org/project/tigrcorn-config/) | [tigrcorn-http](https://pypi.org/project/tigrcorn-http/) | [tigrcorn-asgi](https://pypi.org/project/tigrcorn-asgi/) | [tigrcorn-contract](https://pypi.org/project/tigrcorn-contract/) | [tigrcorn-transports](https://pypi.org/project/tigrcorn-transports/) | [tigrcorn-security](https://pypi.org/project/tigrcorn-security/) | [tigrcorn-protocols](https://pypi.org/project/tigrcorn-protocols/) | [tigrcorn-static](https://pypi.org/project/tigrcorn-static/) | [tigrcorn-observability](https://pypi.org/project/tigrcorn-observability/) | [tigrcorn-runtime](https://pypi.org/project/tigrcorn-runtime/) | [tigrcorn-compat](https://pypi.org/project/tigrcorn-compat/) | [tigrcorn-certification](https://pypi.org/project/tigrcorn-certification/)
|
|
283
283
|
|
|
284
284
|
## Best Practices
|
|
285
285
|
|
|
@@ -86,7 +86,7 @@ The package exposes its supported public surface through the <code>tigrcorn_stat
|
|
|
86
86
|
|
|
87
87
|
## Package Graph
|
|
88
88
|
|
|
89
|
-
[tigrcorn-core](https://pypi.org/project/tigrcorn-core/) | [tigrcorn-config](https://pypi.org/project/tigrcorn-config/) | [tigrcorn-http](https://pypi.org/project/tigrcorn-http/) | [tigrcorn-asgi](https://pypi.org/project/tigrcorn-asgi/) | [tigrcorn-contract](https://pypi.org/project/tigrcorn-contract/) | [tigrcorn-transports](https://pypi.org/project/tigrcorn-transports/) | [tigrcorn-security](https://pypi.org/project/tigrcorn-security/) | [tigrcorn-protocols](https://pypi.org/project/tigrcorn-protocols/) | [tigrcorn-static](https://pypi.org/project/tigrcorn-static/) | [tigrcorn-observability](https://pypi.org/project/tigrcorn-observability/) | [tigrcorn-runtime](https://pypi.org/project/tigrcorn-runtime/) | [tigrcorn-compat](https://pypi.org/project/tigrcorn-compat/) | [tigrcorn-certification](https://pypi.org/project/tigrcorn-certification/)
|
|
89
|
+
[tigrcorn-core](https://pypi.org/project/tigrcorn-core/) | [tigrcorn-quic-cc](https://pypi.org/project/tigrcorn-quic-cc/) | [tigrcorn-quic-cc-reno](https://pypi.org/project/tigrcorn-quic-cc-reno/) | [tigrcorn-config](https://pypi.org/project/tigrcorn-config/) | [tigrcorn-http](https://pypi.org/project/tigrcorn-http/) | [tigrcorn-asgi](https://pypi.org/project/tigrcorn-asgi/) | [tigrcorn-contract](https://pypi.org/project/tigrcorn-contract/) | [tigrcorn-transports](https://pypi.org/project/tigrcorn-transports/) | [tigrcorn-security](https://pypi.org/project/tigrcorn-security/) | [tigrcorn-protocols](https://pypi.org/project/tigrcorn-protocols/) | [tigrcorn-static](https://pypi.org/project/tigrcorn-static/) | [tigrcorn-observability](https://pypi.org/project/tigrcorn-observability/) | [tigrcorn-runtime](https://pypi.org/project/tigrcorn-runtime/) | [tigrcorn-compat](https://pypi.org/project/tigrcorn-compat/) | [tigrcorn-certification](https://pypi.org/project/tigrcorn-certification/)
|
|
90
90
|
|
|
91
91
|
## Best Practices
|
|
92
92
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "tigrcorn-static"
|
|
7
|
-
version = "0.3.18.
|
|
7
|
+
version = "0.3.18.dev3"
|
|
8
8
|
description = "Static file origin, file-send, validators, ranges, and cache-aware HTTP responses for the Tigrcorn ASGI server."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10,<3.15"
|
|
@@ -29,9 +29,9 @@ classifiers = [
|
|
|
29
29
|
"Typing :: Typed",
|
|
30
30
|
]
|
|
31
31
|
dependencies = [
|
|
32
|
-
"tigrcorn-core==0.3.18.
|
|
33
|
-
"tigrcorn-asgi==0.3.18.
|
|
34
|
-
"tigrcorn-http==0.3.18.
|
|
32
|
+
"tigrcorn-core==0.3.18.dev3",
|
|
33
|
+
"tigrcorn-asgi==0.3.18.dev3",
|
|
34
|
+
"tigrcorn-http==0.3.18.dev3",
|
|
35
35
|
]
|
|
36
36
|
|
|
37
37
|
[tool.setuptools]
|
{tigrcorn_static-0.3.18.dev2 → tigrcorn_static-0.3.18.dev3}/src/tigrcorn_static/static/__init__.py
RENAMED
|
@@ -5,21 +5,26 @@ from .mounting import mount_static_app, normalize_static_route
|
|
|
5
5
|
from .security import (
|
|
6
6
|
StaticSecurityCertificationError,
|
|
7
7
|
StaticSecurityPolicy,
|
|
8
|
+
build_static_certification_evidence,
|
|
8
9
|
certify_static_delivery_security,
|
|
9
10
|
static_alt_svc_headers,
|
|
10
11
|
static_cache_headers,
|
|
11
12
|
static_delivery_certification_artifact,
|
|
12
13
|
static_security_policy,
|
|
13
14
|
validate_static_early_hints,
|
|
15
|
+
validate_static_content_length,
|
|
14
16
|
validate_static_path,
|
|
15
17
|
validate_static_range_request,
|
|
18
|
+
validate_static_range_amplification,
|
|
16
19
|
validate_static_resolved_path,
|
|
20
|
+
validate_static_sidecar_pair,
|
|
17
21
|
)
|
|
18
22
|
|
|
19
23
|
__all__ = [
|
|
20
24
|
"StaticFilesApp",
|
|
21
25
|
"StaticSecurityCertificationError",
|
|
22
26
|
"StaticSecurityPolicy",
|
|
27
|
+
"build_static_certification_evidence",
|
|
23
28
|
"certify_static_delivery_security",
|
|
24
29
|
"mount_static_app",
|
|
25
30
|
"normalize_static_route",
|
|
@@ -28,7 +33,10 @@ __all__ = [
|
|
|
28
33
|
"static_delivery_certification_artifact",
|
|
29
34
|
"static_security_policy",
|
|
30
35
|
"validate_static_early_hints",
|
|
36
|
+
"validate_static_content_length",
|
|
31
37
|
"validate_static_path",
|
|
32
38
|
"validate_static_range_request",
|
|
39
|
+
"validate_static_range_amplification",
|
|
33
40
|
"validate_static_resolved_path",
|
|
41
|
+
"validate_static_sidecar_pair",
|
|
34
42
|
]
|
{tigrcorn_static-0.3.18.dev2 → tigrcorn_static-0.3.18.dev3}/src/tigrcorn_static/static/security.py
RENAMED
|
@@ -76,6 +76,34 @@ def static_delivery_certification_artifact() -> dict[str, Any]:
|
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
|
|
79
|
+
def build_static_certification_evidence(root: str | Path, *, profile: str = "default") -> dict[str, Any]:
|
|
80
|
+
root_path = Path(root)
|
|
81
|
+
negative_corpus = {
|
|
82
|
+
"dotdot_traversal": _raises_static_error(lambda: validate_static_path(root_path, "/../secret.txt")),
|
|
83
|
+
"encoded_traversal": _raises_static_error(lambda: validate_static_path(root_path, "/%2e%2e/secret.txt")),
|
|
84
|
+
"unicode_traversal": _raises_static_error(lambda: validate_static_path(root_path, "/\uff0e\uff0e/secret.txt")),
|
|
85
|
+
"symlink_escape": _raises_static_error(lambda: validate_static_resolved_path(root_path, root_path.parent / "__tigrcorn_escape_probe__")),
|
|
86
|
+
}
|
|
87
|
+
alt_svc_headers = static_alt_svc_headers(
|
|
88
|
+
profile=profile,
|
|
89
|
+
static_enabled=True,
|
|
90
|
+
requested_headers=[b'h3=":443"; ma=3600', b'h2=":443"'],
|
|
91
|
+
)
|
|
92
|
+
early_hints = validate_static_early_hints([(b"link", b"</assets/app.css>; rel=preload")])
|
|
93
|
+
return {
|
|
94
|
+
"checks": {
|
|
95
|
+
"alt_svc": _json_header_list(alt_svc_headers),
|
|
96
|
+
"early_hints": _json_header_list(early_hints),
|
|
97
|
+
"range_amplification": validate_static_range_amplification(b"bytes=0-0", resource_length=1),
|
|
98
|
+
},
|
|
99
|
+
"mount_name": root_path.name,
|
|
100
|
+
"negative_corpus": negative_corpus,
|
|
101
|
+
"policy": static_security_policy()["policy"],
|
|
102
|
+
"profile": profile,
|
|
103
|
+
"schema_version": 1,
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
|
|
79
107
|
def validate_static_path(root: str | Path, request_path: str) -> dict[str, Any]:
|
|
80
108
|
root_path = Path(root).resolve()
|
|
81
109
|
decoded = _decode_static_path(request_path)
|
|
@@ -182,6 +210,71 @@ def validate_static_range_request(
|
|
|
182
210
|
}
|
|
183
211
|
|
|
184
212
|
|
|
213
|
+
def validate_static_sidecar_pair(
|
|
214
|
+
origin: str | Path,
|
|
215
|
+
sidecar: str | Path,
|
|
216
|
+
*,
|
|
217
|
+
coding: str,
|
|
218
|
+
) -> dict[str, Any]:
|
|
219
|
+
origin_path = Path(origin)
|
|
220
|
+
sidecar_path = Path(sidecar)
|
|
221
|
+
expected_suffix = _sidecar_suffix_map().get(coding)
|
|
222
|
+
if expected_suffix is None:
|
|
223
|
+
raise StaticSecurityCertificationError(f"unsupported static sidecar coding: {coding}")
|
|
224
|
+
if sidecar_path.name != origin_path.name + expected_suffix:
|
|
225
|
+
raise StaticSecurityCertificationError("static sidecar name does not match origin")
|
|
226
|
+
if not origin_path.exists() or not sidecar_path.exists():
|
|
227
|
+
raise StaticSecurityCertificationError("static sidecar pair is incomplete")
|
|
228
|
+
return {
|
|
229
|
+
"accepted": True,
|
|
230
|
+
"coding": coding,
|
|
231
|
+
"origin": os.fspath(origin_path),
|
|
232
|
+
"sidecar": os.fspath(sidecar_path),
|
|
233
|
+
"sidecar_size": sidecar_path.stat().st_size,
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def validate_static_content_length(
|
|
238
|
+
headers: Iterable[tuple[bytes | str, bytes | str]],
|
|
239
|
+
*,
|
|
240
|
+
expected_length: int,
|
|
241
|
+
) -> dict[str, Any]:
|
|
242
|
+
normalized = [
|
|
243
|
+
(
|
|
244
|
+
name if isinstance(name, bytes) else str(name).encode("latin1"),
|
|
245
|
+
value if isinstance(value, bytes) else str(value).encode("latin1"),
|
|
246
|
+
)
|
|
247
|
+
for name, value in headers
|
|
248
|
+
]
|
|
249
|
+
value = get_header([(name.lower(), header_value) for name, header_value in normalized], b"content-length")
|
|
250
|
+
if value is None:
|
|
251
|
+
return {"accepted": True, "content_length": None}
|
|
252
|
+
try:
|
|
253
|
+
parsed = int(value.decode("ascii"))
|
|
254
|
+
except ValueError as exc:
|
|
255
|
+
raise StaticSecurityCertificationError("invalid static content-length") from exc
|
|
256
|
+
if parsed != expected_length:
|
|
257
|
+
raise StaticSecurityCertificationError("static content-length mismatch")
|
|
258
|
+
return {"accepted": True, "content_length": parsed}
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def validate_static_range_amplification(
|
|
262
|
+
range_header: bytes | str,
|
|
263
|
+
*,
|
|
264
|
+
resource_length: int,
|
|
265
|
+
max_parts: int = 16,
|
|
266
|
+
) -> dict[str, Any]:
|
|
267
|
+
value = range_header if isinstance(range_header, bytes) else str(range_header).encode("latin1")
|
|
268
|
+
if not value.lower().startswith(b"bytes="):
|
|
269
|
+
raise StaticSecurityCertificationError("unsupported static range unit")
|
|
270
|
+
parts = [part.strip() for part in value[6:].split(b",") if part.strip()]
|
|
271
|
+
if len(parts) > max_parts:
|
|
272
|
+
raise StaticSecurityCertificationError("static range amplification limit exceeded")
|
|
273
|
+
if resource_length < 0:
|
|
274
|
+
raise StaticSecurityCertificationError("invalid static resource length")
|
|
275
|
+
return {"accepted": True, "parts": len(parts), "resource_length": resource_length}
|
|
276
|
+
|
|
277
|
+
|
|
185
278
|
def certify_static_delivery_security(evidence: Mapping[str, Any]) -> dict[str, Any]:
|
|
186
279
|
corpus = evidence.get("negative_corpus") or {}
|
|
187
280
|
required = ("dotdot_traversal", "encoded_traversal", "unicode_traversal", "symlink_escape")
|
|
@@ -226,3 +319,19 @@ def _validate_static_path_parts(path: str) -> StaticPathDecision:
|
|
|
226
319
|
def _without_header(headers: HeaderList, name: bytes) -> HeaderList:
|
|
227
320
|
lowered = name.lower()
|
|
228
321
|
return [(header_name, value) for header_name, value in headers if header_name.lower() != lowered]
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
def _raises_static_error(callback) -> bool:
|
|
325
|
+
try:
|
|
326
|
+
callback()
|
|
327
|
+
except StaticSecurityCertificationError:
|
|
328
|
+
return True
|
|
329
|
+
return False
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
def _sidecar_suffix_map() -> dict[str, str]:
|
|
333
|
+
return {"br": ".br", "gzip": ".gz"}
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
def _json_header_list(headers: Iterable[tuple[bytes, bytes]]) -> list[list[str]]:
|
|
337
|
+
return [[name.decode("latin1"), value.decode("latin1")] for name, value in headers]
|
{tigrcorn_static-0.3.18.dev2 → tigrcorn_static-0.3.18.dev3}/src/tigrcorn_static.egg-info/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tigrcorn-static
|
|
3
|
-
Version: 0.3.18.
|
|
3
|
+
Version: 0.3.18.dev3
|
|
4
4
|
Summary: Static file origin, file-send, validators, ranges, and cache-aware HTTP responses for the Tigrcorn ASGI server.
|
|
5
5
|
Author-email: Jacob Stewart <jacob@swarmauri.com>
|
|
6
6
|
License: Apache License
|
|
@@ -186,9 +186,9 @@ Classifier: Typing :: Typed
|
|
|
186
186
|
Requires-Python: <3.15,>=3.10
|
|
187
187
|
Description-Content-Type: text/markdown
|
|
188
188
|
License-File: LICENSE
|
|
189
|
-
Requires-Dist: tigrcorn-core==0.3.18.
|
|
190
|
-
Requires-Dist: tigrcorn-asgi==0.3.18.
|
|
191
|
-
Requires-Dist: tigrcorn-http==0.3.18.
|
|
189
|
+
Requires-Dist: tigrcorn-core==0.3.18.dev3
|
|
190
|
+
Requires-Dist: tigrcorn-asgi==0.3.18.dev3
|
|
191
|
+
Requires-Dist: tigrcorn-http==0.3.18.dev3
|
|
192
192
|
Dynamic: license-file
|
|
193
193
|
|
|
194
194
|
<div align="center">
|
|
@@ -279,7 +279,7 @@ The package exposes its supported public surface through the <code>tigrcorn_stat
|
|
|
279
279
|
|
|
280
280
|
## Package Graph
|
|
281
281
|
|
|
282
|
-
[tigrcorn-core](https://pypi.org/project/tigrcorn-core/) | [tigrcorn-config](https://pypi.org/project/tigrcorn-config/) | [tigrcorn-http](https://pypi.org/project/tigrcorn-http/) | [tigrcorn-asgi](https://pypi.org/project/tigrcorn-asgi/) | [tigrcorn-contract](https://pypi.org/project/tigrcorn-contract/) | [tigrcorn-transports](https://pypi.org/project/tigrcorn-transports/) | [tigrcorn-security](https://pypi.org/project/tigrcorn-security/) | [tigrcorn-protocols](https://pypi.org/project/tigrcorn-protocols/) | [tigrcorn-static](https://pypi.org/project/tigrcorn-static/) | [tigrcorn-observability](https://pypi.org/project/tigrcorn-observability/) | [tigrcorn-runtime](https://pypi.org/project/tigrcorn-runtime/) | [tigrcorn-compat](https://pypi.org/project/tigrcorn-compat/) | [tigrcorn-certification](https://pypi.org/project/tigrcorn-certification/)
|
|
282
|
+
[tigrcorn-core](https://pypi.org/project/tigrcorn-core/) | [tigrcorn-quic-cc](https://pypi.org/project/tigrcorn-quic-cc/) | [tigrcorn-quic-cc-reno](https://pypi.org/project/tigrcorn-quic-cc-reno/) | [tigrcorn-config](https://pypi.org/project/tigrcorn-config/) | [tigrcorn-http](https://pypi.org/project/tigrcorn-http/) | [tigrcorn-asgi](https://pypi.org/project/tigrcorn-asgi/) | [tigrcorn-contract](https://pypi.org/project/tigrcorn-contract/) | [tigrcorn-transports](https://pypi.org/project/tigrcorn-transports/) | [tigrcorn-security](https://pypi.org/project/tigrcorn-security/) | [tigrcorn-protocols](https://pypi.org/project/tigrcorn-protocols/) | [tigrcorn-static](https://pypi.org/project/tigrcorn-static/) | [tigrcorn-observability](https://pypi.org/project/tigrcorn-observability/) | [tigrcorn-runtime](https://pypi.org/project/tigrcorn-runtime/) | [tigrcorn-compat](https://pypi.org/project/tigrcorn-compat/) | [tigrcorn-certification](https://pypi.org/project/tigrcorn-certification/)
|
|
283
283
|
|
|
284
284
|
## Best Practices
|
|
285
285
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tigrcorn_static-0.3.18.dev2 → tigrcorn_static-0.3.18.dev3}/src/tigrcorn_static/static/app.py
RENAMED
|
File without changes
|
{tigrcorn_static-0.3.18.dev2 → tigrcorn_static-0.3.18.dev3}/src/tigrcorn_static/static/models.py
RENAMED
|
File without changes
|
{tigrcorn_static-0.3.18.dev2 → tigrcorn_static-0.3.18.dev3}/src/tigrcorn_static/static/mounting.py
RENAMED
|
File without changes
|
|
File without changes
|
{tigrcorn_static-0.3.18.dev2 → tigrcorn_static-0.3.18.dev3}/src/tigrcorn_static/static/responses.py
RENAMED
|
File without changes
|
{tigrcorn_static-0.3.18.dev2 → tigrcorn_static-0.3.18.dev3}/src/tigrcorn_static.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|