djcheckup 0.2.0__tar.gz → 0.2.2__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.
- {djcheckup-0.2.0 → djcheckup-0.2.2}/PKG-INFO +1 -1
- {djcheckup-0.2.0 → djcheckup-0.2.2}/pyproject.toml +11 -1
- {djcheckup-0.2.0 → djcheckup-0.2.2}/src/djcheckup/checks.py +66 -22
- {djcheckup-0.2.0 → djcheckup-0.2.2}/src/djcheckup/run.py +2 -2
- {djcheckup-0.2.0 → djcheckup-0.2.2}/LICENSE +0 -0
- {djcheckup-0.2.0 → djcheckup-0.2.2}/README.md +0 -0
- {djcheckup-0.2.0 → djcheckup-0.2.2}/src/djcheckup/__init__.py +0 -0
- {djcheckup-0.2.0 → djcheckup-0.2.2}/src/djcheckup/check_defs.py +0 -0
- {djcheckup-0.2.0 → djcheckup-0.2.2}/src/djcheckup/cli.py +0 -0
- {djcheckup-0.2.0 → djcheckup-0.2.2}/src/djcheckup/outputs.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "djcheckup"
|
|
3
|
-
version = "0.2.
|
|
3
|
+
version = "0.2.2"
|
|
4
4
|
description = "DJ Checkup is a security scanner for Django sites."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [{ name = "Stuart Maxwell", email = "stuart@amanzi.nz" }]
|
|
@@ -26,5 +26,15 @@ target-version = "py313"
|
|
|
26
26
|
[tool.ruff.lint]
|
|
27
27
|
select = ["ALL"]
|
|
28
28
|
|
|
29
|
+
[tool.ruff.lint.extend-per-file-ignores]
|
|
30
|
+
"tests/**" = ["S101", "ANN201", "ANN001", "ARG001"]
|
|
31
|
+
|
|
29
32
|
[tool.ruff.lint.pydocstyle]
|
|
30
33
|
convention = "google" # Accepts: "google", "numpy", or "pep257".
|
|
34
|
+
|
|
35
|
+
[dependency-groups]
|
|
36
|
+
dev = ["pytest>=8.4.2"]
|
|
37
|
+
|
|
38
|
+
[tool.pytest.ini_options]
|
|
39
|
+
pythonpath = "."
|
|
40
|
+
python_files = "test_*.py"
|
|
@@ -4,7 +4,7 @@ from abc import ABC, abstractmethod
|
|
|
4
4
|
from dataclasses import dataclass
|
|
5
5
|
from enum import Enum
|
|
6
6
|
from http.cookiejar import CookieJar
|
|
7
|
-
from typing import Literal
|
|
7
|
+
from typing import Literal, Self
|
|
8
8
|
|
|
9
9
|
import httpx
|
|
10
10
|
|
|
@@ -286,23 +286,76 @@ class SchemeCheck(_BaseCheck):
|
|
|
286
286
|
return response.url.scheme == self.end_scheme
|
|
287
287
|
|
|
288
288
|
|
|
289
|
+
def create_context(url: httpx.URL, client: httpx.Client, response: httpx.Response) -> SiteCheckContext:
|
|
290
|
+
"""Create a SiteCheckContext context object.
|
|
291
|
+
|
|
292
|
+
Args:
|
|
293
|
+
url: The URL to check.
|
|
294
|
+
client: The HTTPX client to use for requests.
|
|
295
|
+
response: The HTTPX response object from the initial request.
|
|
296
|
+
|
|
297
|
+
Returns:
|
|
298
|
+
A SiteCheckContext object containing the provided parameters.
|
|
299
|
+
"""
|
|
300
|
+
return SiteCheckContext(
|
|
301
|
+
url=url,
|
|
302
|
+
client=client,
|
|
303
|
+
headers=response.headers,
|
|
304
|
+
cookies=response.cookies.jar,
|
|
305
|
+
content=response.text,
|
|
306
|
+
response_url=response.url,
|
|
307
|
+
)
|
|
308
|
+
|
|
309
|
+
|
|
289
310
|
class SiteChecker:
|
|
290
311
|
"""Run all the checks for a given site."""
|
|
291
312
|
|
|
292
|
-
def __init__(
|
|
293
|
-
|
|
313
|
+
def __init__(
|
|
314
|
+
self,
|
|
315
|
+
url: str,
|
|
316
|
+
*,
|
|
317
|
+
client: httpx.Client | None = None,
|
|
318
|
+
user_agent: str = "DJCheckupBot/1.0 (+https://pypi.org/project/djcheckup/)",
|
|
319
|
+
timeout: float = 10.0,
|
|
320
|
+
follow_redirects: bool = True,
|
|
321
|
+
) -> None:
|
|
322
|
+
"""Initialize the SiteChecker with a URL and optional HTTPX client.
|
|
323
|
+
|
|
324
|
+
Args:
|
|
325
|
+
url: The URL to check.
|
|
326
|
+
client: An optional HTTPX client to use for requests.
|
|
327
|
+
user_agent: The User-Agent string to use for requests.
|
|
328
|
+
timeout: The timeout for requests in seconds.
|
|
329
|
+
follow_redirects: Whether to follow redirects.
|
|
330
|
+
"""
|
|
294
331
|
self.url: httpx.URL = httpx.URL(url)
|
|
295
|
-
self.
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
332
|
+
self._client_provided = client is not None
|
|
333
|
+
|
|
334
|
+
if client is not None:
|
|
335
|
+
self.client = client
|
|
336
|
+
else:
|
|
337
|
+
self.client = httpx.Client(
|
|
338
|
+
headers={"User-Agent": user_agent},
|
|
339
|
+
timeout=timeout,
|
|
340
|
+
follow_redirects=follow_redirects,
|
|
341
|
+
)
|
|
302
342
|
|
|
303
343
|
def close(self) -> None:
|
|
304
|
-
"""Close the HTTP client and release resources.
|
|
305
|
-
|
|
344
|
+
"""Close the HTTP client and release resources.
|
|
345
|
+
|
|
346
|
+
Only close the client if it was created by this instance.
|
|
347
|
+
"""
|
|
348
|
+
if not self._client_provided:
|
|
349
|
+
self.client.close()
|
|
350
|
+
|
|
351
|
+
# Context manager support for automatic cleanup
|
|
352
|
+
def __enter__(self) -> Self:
|
|
353
|
+
"""Context manager entry."""
|
|
354
|
+
return self
|
|
355
|
+
|
|
356
|
+
def __exit__(self, exc_type, exc_val, exc_tb) -> None: # noqa: ANN001
|
|
357
|
+
"""Context manager exit."""
|
|
358
|
+
self.close()
|
|
306
359
|
|
|
307
360
|
def run_first_check(self) -> CheckResponse:
|
|
308
361
|
"""Run the first check.
|
|
@@ -327,14 +380,7 @@ class SiteChecker:
|
|
|
327
380
|
message=error_message,
|
|
328
381
|
)
|
|
329
382
|
|
|
330
|
-
self.context =
|
|
331
|
-
url=self.url,
|
|
332
|
-
client=self.client,
|
|
333
|
-
headers=response.headers,
|
|
334
|
-
cookies=response.cookies.jar,
|
|
335
|
-
content=response.text,
|
|
336
|
-
response_url=response.url,
|
|
337
|
-
)
|
|
383
|
+
self.context = create_context(self.url, self.client, response)
|
|
338
384
|
|
|
339
385
|
return CheckResponse(
|
|
340
386
|
name=check_name,
|
|
@@ -360,6 +406,4 @@ class SiteChecker:
|
|
|
360
406
|
site_check_results.check_results.append(result)
|
|
361
407
|
previous_results[check.check_id] = result
|
|
362
408
|
|
|
363
|
-
# Close the HTTP client
|
|
364
|
-
self.client.close()
|
|
365
409
|
return site_check_results
|
|
@@ -15,8 +15,8 @@ def run_checks(url: str, output_format: Literal["json"]) -> str: ...
|
|
|
15
15
|
|
|
16
16
|
def run_checks(url: str, output_format: Literal["object", "json"] = "object") -> str | SiteCheckResult:
|
|
17
17
|
"""Run the DJ Checkup tool against a specific URL and returns a JSON string."""
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
with SiteChecker(url) as checker:
|
|
19
|
+
results = checker.run_checks(all_checks)
|
|
20
20
|
|
|
21
21
|
if output_format not in {"object", "json"}:
|
|
22
22
|
msg = f"Invalid output_format: {output_format!r}. Must be 'object' or 'json'."
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|