django-octo-security 0.1.0__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.
@@ -0,0 +1,3 @@
1
+ import logging
2
+
3
+ logging.getLogger("django_octo_security").addHandler(logging.NullHandler())
@@ -0,0 +1,131 @@
1
+ from django.contrib import admin, messages
2
+ from django.http import HttpResponseRedirect
3
+ from django.urls import path, reverse
4
+ from django.utils.html import format_html, format_html_join
5
+ from .models import CveAuditScan
6
+ from .scanner import run_full_cve_audit
7
+
8
+
9
+ @admin.register(CveAuditScan)
10
+ class CveAuditScanAdmin(admin.ModelAdmin):
11
+ list_display = (
12
+ "id",
13
+ "executed_at",
14
+ "total_packages",
15
+ "vulnerabilities_found",
16
+ "status_badge",
17
+ )
18
+ readonly_fields = (
19
+ "executed_at",
20
+ "total_packages",
21
+ "vulnerabilities_found",
22
+ "status",
23
+ "error_message",
24
+ "rendered_report",
25
+ )
26
+ exclude = ("report_data",)
27
+ actions = ["execute_cve_scan_action"]
28
+ change_list_template = "admin/django_octo_security/cveauditscan/change_list.html"
29
+
30
+ def get_urls(self):
31
+ urls = super().get_urls()
32
+ custom_urls = [
33
+ path(
34
+ "run-scan/",
35
+ self.admin_site.admin_view(self.run_scan_view),
36
+ name="django_octo_security_run_scan",
37
+ ),
38
+ ]
39
+ return custom_urls + urls
40
+
41
+ def run_scan_view(self, request):
42
+ result = run_full_cve_audit()
43
+ scan = CveAuditScan.objects.create(
44
+ total_packages=result["total_packages"],
45
+ vulnerabilities_found=len(result["vulnerabilities"]),
46
+ status=result["status"],
47
+ error_message=result["error"],
48
+ report_data=result["vulnerabilities"],
49
+ )
50
+
51
+ if scan.status == "ERROR":
52
+ self.message_user(
53
+ request,
54
+ f"Audit #{scan.id} failed: {scan.error_message}",
55
+ level=messages.ERROR,
56
+ )
57
+ else:
58
+ msg = f"Audit #{scan.id} completed: {scan.total_packages} packages checked, {scan.vulnerabilities_found} vulnerabilities detected."
59
+ self.message_user(
60
+ request,
61
+ msg,
62
+ level=messages.WARNING
63
+ if scan.vulnerabilities_found
64
+ else messages.SUCCESS,
65
+ )
66
+
67
+ changelist_url = reverse("admin:django_octo_security_cveauditscan_changelist")
68
+ return HttpResponseRedirect(changelist_url)
69
+
70
+ @admin.display(description="Status")
71
+ def status_badge(self, obj):
72
+ palette = {
73
+ "CLEAN": ("#065f46", "#d1fae5", "CLEAN"),
74
+ "VULNERABLE": ("#991b1b", "#fee2e2", "VULNERABLE"),
75
+ "ERROR": ("#92400e", "#fef3c7", "API ERROR"),
76
+ }
77
+ fg, bg, text = palette.get(obj.status, ("#374151", "#f3f4f6", obj.status))
78
+ return format_html(
79
+ '<span style="color:{}; background:{}; padding:4px 10px; border-radius:4px; font-weight:700; font-size:11px;">{}</span>',
80
+ fg,
81
+ bg,
82
+ text,
83
+ )
84
+
85
+ @admin.display(description="Detailed CVE & Source Diagnostics")
86
+ def rendered_report(self, obj):
87
+ if obj.status == "ERROR":
88
+ return format_html(
89
+ '<p style="color:#b91c1c;"><strong>Query failure:</strong> {}</p>',
90
+ obj.error_message,
91
+ )
92
+ if not obj.report_data:
93
+ return format_html(
94
+ '<p style="color:#059669;"><strong>Clean environment:</strong> No known vulnerabilities found across {} packages.</p>',
95
+ obj.total_packages,
96
+ )
97
+
98
+ cards = []
99
+ for item in obj.report_data:
100
+ aliases = ", ".join(item.get("aliases", [])) or "No CVE alias"
101
+ fixed = ", ".join(item.get("fixed_versions", [])) or "Check references"
102
+ refs_html = format_html_join(
103
+ "",
104
+ '<li><a href="{}" target="_blank" rel="noopener">{}</a></li>',
105
+ ((url, url) for url in item.get("references", [])),
106
+ )
107
+ cards.append(
108
+ format_html(
109
+ '<div style="border:1px solid #e5e7eb; border-left:4px solid #dc2626; padding:12px; margin-bottom:12px; border-radius:4px; background:#fafafa;">'
110
+ '<h4 style="margin:0 0 6px 0; color:#111827;">{} (installed: <code>{}</code>) — <span style="color:#dc2626;">{}</span> <small>({})</small></h4>'
111
+ '<p style="margin:4px 0;"><strong>Summary:</strong> {}</p>'
112
+ '<p style="margin:4px 0;"><strong>Fixed Version:</strong> <code style="background:#dcfce7; color:#166534; padding:2px 6px;">{}</code></p>'
113
+ '<p style="margin:6px 0 2px 0;"><strong>Official References:</strong></p><ul style="margin:0; padding-left:18px;">{}</ul>'
114
+ "</div>",
115
+ item.get("package"),
116
+ item.get("installed_version"),
117
+ item.get("id"),
118
+ aliases,
119
+ item.get("summary"),
120
+ fixed,
121
+ refs_html,
122
+ )
123
+ )
124
+ return format_html("{}", format_html_join("", "{}", ((c,) for c in cards)))
125
+
126
+ @admin.action(description="Run new CVE environment audit")
127
+ def execute_cve_scan_action(self, request, queryset):
128
+ return self.run_scan_view(request)
129
+
130
+ def has_add_permission(self, request):
131
+ return False
@@ -0,0 +1,7 @@
1
+ from django.apps import AppConfig
2
+
3
+
4
+ class DjangoOctoSecurityConfig(AppConfig):
5
+ default_auto_field = "django.db.models.BigAutoField"
6
+ name = "django_octo_security"
7
+ verbose_name = "Security"
@@ -0,0 +1,70 @@
1
+ # Generated by Django 6.1.2 on 2026-11-14 13:01
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+ initial = True
8
+
9
+ dependencies = []
10
+
11
+ operations = [
12
+ migrations.CreateModel(
13
+ name="CveAuditScan",
14
+ fields=[
15
+ (
16
+ "id",
17
+ models.BigAutoField(
18
+ auto_created=True,
19
+ primary_key=True,
20
+ serialize=False,
21
+ verbose_name="ID",
22
+ ),
23
+ ),
24
+ (
25
+ "executed_at",
26
+ models.DateTimeField(auto_now_add=True, verbose_name="Executed At"),
27
+ ),
28
+ (
29
+ "total_packages",
30
+ models.PositiveIntegerField(
31
+ default=0, verbose_name="Packages Checked"
32
+ ),
33
+ ),
34
+ (
35
+ "vulnerabilities_found",
36
+ models.PositiveIntegerField(
37
+ default=0, verbose_name="Vulnerabilities Found"
38
+ ),
39
+ ),
40
+ (
41
+ "status",
42
+ models.CharField(
43
+ choices=[
44
+ ("CLEAN", "Clean"),
45
+ ("VULNERABLE", "Vulnerable"),
46
+ ("ERROR", "Network Error"),
47
+ ],
48
+ default="CLEAN",
49
+ max_length=20,
50
+ verbose_name="Status",
51
+ ),
52
+ ),
53
+ (
54
+ "error_message",
55
+ models.TextField(blank=True, default="", verbose_name="Error Log"),
56
+ ),
57
+ (
58
+ "report_data",
59
+ models.JSONField(
60
+ blank=True, default=list, verbose_name="Technical Report (JSON)"
61
+ ),
62
+ ),
63
+ ],
64
+ options={
65
+ "verbose_name": "CVE Checker",
66
+ "verbose_name_plural": "CVE Checker",
67
+ "ordering": ["-executed_at"],
68
+ },
69
+ ),
70
+ ]
File without changes
@@ -0,0 +1,34 @@
1
+ from django.db import models
2
+
3
+
4
+ class CveAuditScan(models.Model):
5
+ executed_at = models.DateTimeField(auto_now_add=True, verbose_name="Executed At")
6
+ total_packages = models.PositiveIntegerField(
7
+ default=0, verbose_name="Packages Checked"
8
+ )
9
+ vulnerabilities_found = models.PositiveIntegerField(
10
+ default=0, verbose_name="Vulnerabilities Found"
11
+ )
12
+ status = models.CharField(
13
+ max_length=20,
14
+ choices=[
15
+ ("CLEAN", "Clean"),
16
+ ("VULNERABLE", "Vulnerable"),
17
+ ("ERROR", "Network Error"),
18
+ ],
19
+ default="CLEAN",
20
+ verbose_name="Status",
21
+ )
22
+ error_message = models.TextField(blank=True, default="", verbose_name="Error Log")
23
+ report_data = models.JSONField(
24
+ default=list, blank=True, verbose_name="Technical Report (JSON)"
25
+ )
26
+
27
+ class Meta:
28
+ app_label = "django_octo_security"
29
+ verbose_name = "CVE Checker"
30
+ verbose_name_plural = "CVE Checker"
31
+ ordering = ["-executed_at"]
32
+
33
+ def __str__(self):
34
+ return f"Audit #{self.id} — {self.get_status_display()} ({self.vulnerabilities_found} CVEs)"
@@ -0,0 +1,139 @@
1
+ import importlib.metadata
2
+ import json
3
+ import ssl
4
+ import urllib.error
5
+ import urllib.request
6
+
7
+
8
+ OSV_API_HOST = "api.osv.dev"
9
+ OSV_BATCH_PATH = "/v1/querybatch"
10
+ OSV_VULN_PATH = "/v1/vulns/"
11
+
12
+
13
+ def _get_ssl_context():
14
+ try:
15
+ import certifi
16
+
17
+ return ssl.create_default_context(cafile=certifi.where())
18
+ except ImportError:
19
+ return ssl.create_default_context()
20
+
21
+
22
+ DEFAULT_HEADERS = {
23
+ "Content-Type": "application/json",
24
+ "Accept": "application/json",
25
+ "User-Agent": "django-octo-security/0.1.0",
26
+ }
27
+
28
+
29
+ def get_installed_packages() -> list[dict]:
30
+ packages = []
31
+ for dist in importlib.metadata.distributions():
32
+ name = dist.metadata.get("Name")
33
+ version = dist.version
34
+ if name and version:
35
+ packages.append(
36
+ {"package": {"name": name, "ecosystem": "PyPI"}, "version": version}
37
+ )
38
+ return packages
39
+
40
+
41
+ def fetch_vuln_full_details(vuln_id: str) -> dict:
42
+ url = f"https://{OSV_API_HOST}{OSV_VULN_PATH}{vuln_id}"
43
+ req = urllib.request.Request(
44
+ url,
45
+ headers={
46
+ "Accept": "application/json",
47
+ "User-Agent": "django-octo-security/0.1.0",
48
+ },
49
+ )
50
+ try:
51
+ with urllib.request.urlopen(
52
+ req, timeout=8, context=_get_ssl_context()
53
+ ) as response:
54
+ data = json.loads(response.read().decode("utf-8"))
55
+ import_source = data.get("database_specific", {}).get("import_source", "")
56
+ references = [
57
+ ref.get("url") for ref in data.get("references", []) if ref.get("url")
58
+ ]
59
+ aliases = data.get("aliases", [])
60
+ fixed_versions = []
61
+ for affected in data.get("affected", []):
62
+ for rng in affected.get("ranges", []):
63
+ for event in rng.get("events", []):
64
+ if "fixed" in event:
65
+ fixed_versions.append(event["fixed"])
66
+ return {
67
+ "id": data.get("id", vuln_id),
68
+ "aliases": aliases,
69
+ "summary": data.get("summary") or "No summary available.",
70
+ "import_source": import_source,
71
+ "references": references[:5],
72
+ "fixed_versions": list(set(fixed_versions)),
73
+ }
74
+ except Exception as exc:
75
+ return {
76
+ "id": vuln_id,
77
+ "aliases": [],
78
+ "summary": f"Failed to retrieve details: {exc}",
79
+ "import_source": "",
80
+ "references": [],
81
+ "fixed_versions": [],
82
+ }
83
+
84
+
85
+ def run_full_cve_audit() -> dict:
86
+ packages = get_installed_packages()
87
+ if not packages:
88
+ return {
89
+ "total_packages": 0,
90
+ "vulnerabilities": [],
91
+ "status": "CLEAN",
92
+ "error": "",
93
+ }
94
+
95
+ batch_url = f"https://{OSV_API_HOST}{OSV_BATCH_PATH}"
96
+ payload = json.dumps({"queries": packages}).encode("utf-8")
97
+ req = urllib.request.Request(
98
+ batch_url,
99
+ data=payload,
100
+ headers=DEFAULT_HEADERS,
101
+ method="POST",
102
+ )
103
+
104
+ enriched_findings = []
105
+ try:
106
+ with urllib.request.urlopen(
107
+ req, timeout=15, context=_get_ssl_context()
108
+ ) as response:
109
+ batch_data = json.loads(response.read().decode("utf-8"))
110
+ results = batch_data.get("results", [])
111
+ for pkg_info, res in zip(packages, results):
112
+ for v in res.get("vulns", []):
113
+ vuln_id = v.get("id")
114
+ if vuln_id:
115
+ details = fetch_vuln_full_details(vuln_id)
116
+ details["package"] = pkg_info["package"]["name"]
117
+ details["installed_version"] = pkg_info["version"]
118
+ enriched_findings.append(details)
119
+
120
+ return {
121
+ "total_packages": len(packages),
122
+ "vulnerabilities": enriched_findings,
123
+ "status": "VULNERABLE" if enriched_findings else "CLEAN",
124
+ "error": "",
125
+ }
126
+ except urllib.error.HTTPError as exc:
127
+ return {
128
+ "total_packages": len(packages),
129
+ "vulnerabilities": [],
130
+ "status": "ERROR",
131
+ "error": f"OSV API HTTP {exc.code} ({exc.reason})",
132
+ }
133
+ except Exception as exc:
134
+ return {
135
+ "total_packages": len(packages),
136
+ "vulnerabilities": [],
137
+ "status": "ERROR",
138
+ "error": str(exc),
139
+ }
@@ -0,0 +1,11 @@
1
+ {% extends "admin/change_list.html" %}
2
+ {% load i18n admin_urls %}
3
+
4
+ {% block object-tools-items %}
5
+ <li>
6
+ <a href="{% url 'admin:django_octo_security_run_scan' %}" class="addlink" style="background: #0284c7; color: #ffffff; font-weight: 600;">
7
+ Run CVE Environment Audit
8
+ </a>
9
+ </li>
10
+ {{ block.super }}
11
+ {% endblock %}
@@ -0,0 +1,58 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Django-Octo Security — Runtime & CVE Audit</title>
7
+ <style>
8
+ body { font-family: system-ui, -apple-system, sans-serif; background: #0f172a; color: #f8fafc; margin: 0; padding: 2rem; }
9
+ .container { max-width: 820px; margin: 0 auto; }
10
+ .card { background: #1e293b; border: 1px solid #334155; border-radius: 8px; padding: 1.5rem; margin-bottom: 1.5rem; }
11
+ h1 { font-size: 1.5rem; margin-top: 0; color: #38bdf8; }
12
+ h2 { font-size: 1.1rem; color: #94a3b8; border-bottom: 1px solid #334155; padding-bottom: 0.5rem; }
13
+ .badge { display: inline-block; padding: 0.25rem 0.6rem; border-radius: 4px; font-weight: 700; font-size: 0.8rem; }
14
+ .clean { background: #065f46; color: #6ee7b7; }
15
+ .vuln { background: #7f1d1d; color: #fca5a5; }
16
+ .pending { background: #334155; color: #cbd5e1; }
17
+ table { width: 100%; border-collapse: collapse; margin-top: 1rem; font-size: 0.9rem; }
18
+ td, th { text-align: left; padding: 0.6rem; border-bottom: 1px solid #334155; }
19
+ code { background: #0f172a; padding: 0.2rem 0.4rem; border-radius: 4px; color: #38bdf8; }
20
+ </style>
21
+ </head>
22
+ <body>
23
+ <div class="container">
24
+ <div class="card">
25
+ <h1>Django-Octo Security Engine</h1>
26
+ <p>Decoupled runtime hardening and environment CVE audit module.</p>
27
+ {% if latest_scan %}
28
+ <p>
29
+ <strong>Latest Audit (#{{ latest_scan.id }}):</strong>
30
+ {% if latest_scan.status == "CLEAN" %}
31
+ <span class="badge clean">CLEAN ({{ latest_scan.total_packages }} packages)</span>
32
+ {% elif latest_scan.status == "VULNERABLE" %}
33
+ <span class="badge vuln">VULNERABLE ({{ latest_scan.vulnerabilities_found }} CVEs)</span>
34
+ {% else %}
35
+ <span class="badge pending">{{ latest_scan.get_status_display }}</span>
36
+ {% endif %}
37
+ </p>
38
+ {% else %}
39
+ <p><span class="badge pending">No audit executed yet — access /admin/ to run a scan</span></p>
40
+ {% endif %}
41
+ </div>
42
+
43
+ <div class="card">
44
+ <h2>Active Security Headers</h2>
45
+ <table>
46
+ <thead>
47
+ <tr><th>HTTP Header</th><th>Enforced Policy</th></tr>
48
+ </thead>
49
+ <tbody>
50
+ {% for header, value in security_headers.items %}
51
+ <tr><td><code>{{ header }}</code></td><td><code>{{ value }}</code></td></tr>
52
+ {% endfor %}
53
+ </tbody>
54
+ </table>
55
+ </div>
56
+ </div>
57
+ </body>
58
+ </html>
@@ -0,0 +1 @@
1
+ # Create your tests here.
@@ -0,0 +1,8 @@
1
+ from django.urls import path
2
+ from .views import security_audit_view
3
+
4
+ app_name = "django_octo_security"
5
+
6
+ urlpatterns = [
7
+ path("security-audit/", security_audit_view, name="audit"),
8
+ ]
@@ -0,0 +1,15 @@
1
+ from django.shortcuts import render
2
+ from .models import CveAuditScan
3
+
4
+
5
+ def security_audit_view(request):
6
+ latest_scan = CveAuditScan.objects.first()
7
+ context = {
8
+ "latest_scan": latest_scan,
9
+ "security_headers": {
10
+ "X-Frame-Options": "DENY",
11
+ "X-Content-Type-Options": "nosniff",
12
+ "Referrer-Policy": "strict-origin-when-cross-origin",
13
+ },
14
+ }
15
+ return render(request, "security_audit.html", context)
@@ -0,0 +1,129 @@
1
+ Metadata-Version: 2.3
2
+ Name: django-octo-security
3
+ Version: 0.1.0
4
+ Summary: Enterprise-ready Django runtime security and zero-dependency environment CVE audit module under the Django-Octo architecture.
5
+ Project-URL: Homepage, https://github.com/jeanpmodev/django_octo_security
6
+ Project-URL: Repository, https://github.com/jeanpmodev/django_octo_security
7
+ Author-email: jeanpmodev <jeanpmodev@gmail.com>
8
+ License: MIT
9
+ License-File: LICENSE
10
+ Keywords: audit,cve,django,hardening,osv,security,vulnerability-scanner
11
+ Classifier: Framework :: Django
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Topic :: Security
16
+ Requires-Python: >=3.12
17
+ Requires-Dist: django>=6.1.2
18
+ Requires-Dist: python-dotenv
19
+ Description-Content-Type: text/markdown
20
+
21
+ # django_octo_security
22
+
23
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow)](LICENSE)
24
+ [![Python](https://img.shields.io/badge/Python-3.11+-blue)](https://python.org)
25
+ [![Framework: Django](https://img.shields.io/badge/Framework-Django-darkgreen)](https://djangoproject.com)
26
+ [![Package Manager: Rye](https://img.shields.io/badge/Package_Manager-Rye-orange)](https://astral.sh)
27
+ ![PyPI Version](https://img.shields.io/pypi/v/django-octo-security)
28
+ [![Latest on Django Packages](https://img.shields.io/badge/Django_Packages-django__octo__security-8c3c26.svg)](https://djangopackages.org/packages/p/django_octo_security/)
29
+ [![Tests: pytest](https://img.shields.io/badge/Tests-pytest%20passed-2ea44f.svg)](https://github.com/jeanpmodev/django_octo_security/blob/main/TESTING.md)
30
+ [![BDD: Behave](https://img.shields.io/badge/BDD-Behave%20verified-009688.svg)](https://github.com/jeanpmodev/django_octo_security/blob/main/TESTING.md)
31
+ [![Load Test: Locust](https://img.shields.io/badge/Load_Test-11ms_median_%7C_0%25_fails-blueviolet.svg)](https://github.com/jeanpmodev/django_octo_security/blob/main/performance/locust_load_report.pdf)
32
+ [![CI](https://img.shields.io/github/actions/workflow/status/jeanpmodev/django_octo_security/ci.yml?branch=main&label=CI)](https://github.com/jeanpmodev/django_octo_security/actions/workflows/ci.yml)
33
+ [![Code Style: PEP 8](https://img.shields.io/badge/code%20style-PEP%208-blue)](https://peps.python.org/pep-0008/)
34
+ [![PyPI Provenance](https://img.shields.io/badge/PyPI-With%20Provenance-blue?logo=pypi&logoColor=white)](https://pypi.org/project/django-octo-security/#provenance)
35
+
36
+ **Enterprise-ready, non-intrusive Django runtime security posture and zero-dependency environment CVE audit module under the Django-Octo architecture.**
37
+
38
+ ---
39
+
40
+ ## Core Philosophy: Non-Intrusive Dual Access
41
+
42
+ `django-octo-security` is engineered to plug into any existing Django application **without altering your host project's native logic, templates, or root routes**:
43
+
44
+ 1. **Public/Internal Posture Endpoint (`/security-audit/`):** Single-query database lookup (`CveAuditScan.objects.first()`) rendering enforced HTTP security headers and the latest environment vulnerability audit status.
45
+ 2. **Native Django Admin Integration (`Security > CVE Checker`):** Automatically registers a dedicated administrative module in the left sidebar of `/admin/` with one-click environment scanning (`Run CVE Environment Audit`), querying the official **OSV.dev** vulnerability database via Python standard library (`importlib.metadata` + `urllib.request`) with **zero external runtime dependencies**.
46
+
47
+ ---
48
+
49
+ ## Security & Audit Architecture
50
+
51
+ | Layer | Mechanism / Target | Engineering Purpose |
52
+ | :--- | :--- | :--- |
53
+ | **01** | **Clickjacking Shield** | Enforces `X-Frame-Options: DENY` to prevent unauthorized iframe embedding. |
54
+ | **02** | **MIME Sniffing Guard** | Enforces `X-Content-Type-Options: nosniff` against content-type confusion attacks. |
55
+ | **03** | **Referrer Isolation** | Applies `Referrer-Policy: strict-origin-when-cross-origin` to prevent token leakage. |
56
+ | **04** | **Single-Query Posture View** | Renders `/security-audit/` in a single ORM query for high-throughput scalability. |
57
+ | **05** | **Runtime Introspection** | Reads active virtual environment packages via native `importlib.metadata`. |
58
+ | **06** | **Batch OSV Vulnerability Query** | Cross-references all installed PyPI packages against `api.osv.dev/v1/querybatch`. |
59
+ | **07** | **Advisory Enrichment & Fixes** | Resolves CVE aliases, patched versions, and official references per vulnerability. |
60
+ | **08** | **Immutable Audit Persistence** | Stores historical snapshots (`CveAuditScan`) directly in the host database. |
61
+
62
+ ---
63
+
64
+ ## Plug-and-Play Installation
65
+
66
+ Install the official package directly into any modern Django (`>=6.1.2`) and Python (`>=3.12`) infrastructure using **pip** or **Rye**:
67
+
68
+ ### 1. Clone & Synchronize Environment
69
+ Clone the repository and trigger the Rust-backed Rye environment compiler to lock and synchronize dependencies:
70
+ ```bash
71
+ git clone https://github.com/jeanpmodev/django_octo_security.git
72
+ cd django_octo_security
73
+ rye sync
74
+ ```
75
+
76
+
77
+ ### 2. Register in `settings.py`
78
+ Add `"django_octo_security"` to your `INSTALLED_APPS`:
79
+ ```python
80
+ INSTALLED_APPS = [
81
+ # ... your existing apps
82
+ "django_octo_security",
83
+ ]
84
+ ```
85
+
86
+ ### 3. Include the Audit Route in `urls.py`
87
+ Including the module at the root preserves your host application's homepage (`/`) and mounts the posture report at `/security-audit/`:
88
+ ```python
89
+ from django.contrib import admin
90
+ from django.urls import include, path
91
+
92
+ urlpatterns = [
93
+ path("admin/", admin.site.urls),
94
+ path("", include("django_octo_security.urls")),
95
+ ]
96
+ ```
97
+
98
+ ### 4. Apply Migrations
99
+ ```bash
100
+ python3 manage.py migrate
101
+ ```
102
+
103
+
104
+ ### 5. Initialize Runtime Service
105
+ Fire up the local development engine instance:
106
+ ```bash
107
+ python3 manage.py runserver
108
+ ```
109
+ Navigate to `127.0.0.1:8000/security-audit/` to inspect live.
110
+
111
+ ---
112
+
113
+ ## Usage
114
+
115
+ * **Security Posture Screen:** Navigate to `http://127.0.0.1:8000/security-audit/` to inspect active HTTP security policies and the latest environment CVE audit badge.
116
+ * **Admin CVE Checker:** Log in to `http://127.0.0.1:8000/admin/`, open **Security > CVE Checker** in the left navigation bar, and click **Run CVE Environment Audit** at the top right to scan all installed Python packages in real time.
117
+
118
+ ---
119
+
120
+
121
+ ## Quality Assurance & Testing
122
+
123
+ This module is backed by a dedicated QA suite covering **Unit & Query-Count Tests (`pytest`)**, **BDD Specifications (`behave`)**, and **Load Testing (`locust`)**. To keep the core package minimal, test dependencies are installed on demand—see [TESTING.md](TESTING.md) for instructions and benchmark reports.
124
+
125
+
126
+ ## đŸ“„ License & Ecosystem Blueprint
127
+
128
+ Distributed under the permissive terms of the **MIT License**.
129
+
@@ -0,0 +1,16 @@
1
+ django_octo_security/__init__.py,sha256=6IDSSveaGiOUyL_8cXbuMVsaSgzvhKp7WGIviatml0s,92
2
+ django_octo_security/admin.py,sha256=WhExEN-C_tiAOFTzyI3N6XTyd0v08oQCVqCU1w5ZZfk,5214
3
+ django_octo_security/apps.py,sha256=fbPYVJPmpiEvWKe14t750MONDsoxafebiHa0nD7ulmQ,200
4
+ django_octo_security/models.py,sha256=UIjsUkcwN1LKbtdjZL4cWfgCOzdVAy7turI6N2ZUswQ,1142
5
+ django_octo_security/scanner.py,sha256=8HFqH5XU5hOe0-b516em6qN4YGLu6k2Uz7rErpslWbg,4447
6
+ django_octo_security/tests.py,sha256=qWDvA9ZhVCQ1rPbkoFify7o_fDirXMUdYMxF12q3WIM,26
7
+ django_octo_security/urls.py,sha256=g3WO6ybXdTxVx2edDkinZAiW8D-xIuIfegUWHE3JMk8,186
8
+ django_octo_security/views.py,sha256=0-eO6rnyxbM-XxT4oYjxz_SNt9Msv-hqs1wOY3VENGA,464
9
+ django_octo_security/migrations/0001_initial.py,sha256=JmROQkumAZdJUXSRLcLlA7-Sx0kN-8BR_G15T0v7qF0,2254
10
+ django_octo_security/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
+ django_octo_security/templates/security_audit.html,sha256=AkoX-MR1NP8uhbjYjAgWXFxkqnWk1sZPjebMgRjL3sY,2848
12
+ django_octo_security/templates/admin/django_octo_security/cveauditscan/change_list.html,sha256=ZwbpE4oVEEnXFWzNhYTBZtcKe3qEIJhtw06T8g_r3r8,351
13
+ django_octo_security-0.1.0.dist-info/METADATA,sha256=reWRMU09m1Bkm-ibE0TEliAyiYeaGLCbykjtBxgs2Z8,6657
14
+ django_octo_security-0.1.0.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
15
+ django_octo_security-0.1.0.dist-info/licenses/LICENSE,sha256=E7iyIHGFXOmOjqnNkyF1f846sz1z1VLj9qeCC_EeDTQ,1067
16
+ django_octo_security-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.25.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 jeanpmodev
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.