Skip to content

3-tier architecture, security hardening, parser fixes, and upstream backports#64

Closed
xMinhx wants to merge 41 commits into
accso:mainfrom
xMinhx:pr/upstream-clean
Closed

3-tier architecture, security hardening, parser fixes, and upstream backports#64
xMinhx wants to merge 41 commits into
accso:mainfrom
xMinhx:pr/upstream-clean

Conversation

@xMinhx

@xMinhx xMinhx commented Jun 27, 2026

Copy link
Copy Markdown
Collaborator

Summary

Rebased fork branch containing 41 commits across several independent concerns, curated from xMinhx/SecureCheckNext.

Changes

3-tier architecture (7 commits)

Separates the Django monolith into a 3-tier stack: React SPA frontend (Webpack 5, served as Django static files) + Django REST API backend + PostgreSQL. Adds Docker Compose preview deployment with frontend nginx container.

Security hardening (9 commits)

  • C1: Constant-time API key comparison via hmac.compare_digest
  • C2: LDAP injection prevention via username escaping
  • C3: Guard dev auth behind IS_DEV flag
  • H1: Permission check on DeleteProjectAPI
  • H2: CVE ID format validation + request timeouts
  • H3/H4/M2/M3: Rate limiting, dev credentials, CORS, HTTPS settings
  • H5: Template whitelist in HtmlView
  • L1/L2/L3: Docker security (non-root user, healthcheck)
  • M4: Remove duplicate api_404_view function

Parser fixes + tests (6 commits)

  • Fix CycloneDX parser for dict-type input
  • Deduplicate CVEs by (name, version) in Trivy parser
  • Unit tests for both parsers
  • E2E tests for Trivy and CycloneDX report uploads
  • Test fixtures for both report formats

CI improvements (4 commits)

  • Add e2e_test job to CI pipeline
  • Mock NVD API calls, add nvd_integration test marker
  • Fix requirements-dev.txt reference
  • Add pytest-django, .nvmrc, requirements.lock

Upstream backports (8 commits)

Incorporates changes originally authored by @NikAcc and @kreinern from open PRs:

Documentation (2 commits)

  • Update docs to match 3-tier architecture
  • Rewrite QUICK_START and API_TEST_GUIDE in clean English

Notes

Schubert, Stefan and others added 30 commits June 27, 2026 14:51
Sponsored docker compose preview version.
Agentic Coding Fixed to dockerize the frontend container.
Startet dokumentation change (not finished yet)
- Add api/ prefix to all route constants in constants.tsx
- Remove /api/ from ApiClientProvider baseURL (routes now carry it)
- Add CSRF pre-fetch (GET /api/login) before login POST
- Wrap LoginBox in <form> with handleSubmit, make onConfirm async
- Remove email-only validation (accept usernames)
- Fix eye icon z-index and add alt text
- Add @ensure_csrf_cookie to Login view, add GET handler for CSRF cookie
- Remove email validation from backend login view
- Add JSON 404 handler, make SPA catch-all dev-only in urls.py
- Profile.tsx: remove onClick from Menu that broke MenuItem handlers
- CORS_ALLOW_CREDENTIALS for cross-origin cookie auth
- Remove STATICFILES_DIRS (Nginx serves frontend assets)
- Fix HTTPS detection (startswith instead of substring check)
- Add build script to package.json
- Output webpack to ./dist with HtmlWebpackPlugin + DefinePlugin
- Add REACT_APP_API_URL DefinePlugin for API endpoint config
- Uncomment gunicorn CMD with LOG_LEVEL env var
- set -e in entrypoint, collectstatic comment, seed_preview_data for dev
- Add frontend staticfiles/dist to .gitignore
- Fix EOF newlines in UserSettingsContent

Co-authored-by: Stefan Schubert <stefan@bluewhale.de>
- docker-compose-preview.yml: preview/development compose config
- frontend/Dockerfile: Nginx container serving built SPA
- frontend/.dockerignore, frontend/nginx.conf: nginx config
- frontend/src/index.html, login.html: standalone HTML templates for HtmlWebpackPlugin
- frontend/src/queries/apiClient.ts: axios instance with CSRF config
- backend/analyzer/management/: seed_preview_data management command
- backend/assets/.gitkeep: ensure assets directory exists

Co-authored-by: Stefan Schubert <stefan@bluewhale.de>
- update quick-start API/static expectations for 3-tier preview

- document REACT_APP_API_URL same-origin proxy behavior

- clarify makemigrations is a manual dev workflow, not container startup

- point dev installation guide to docker-compose-preview.yml

- ignore generated backend/staticfiles artifacts
- remove invalid frontend image COPY of /staticfiles paths that are outside frontend build context

- proxy /static/ via frontend nginx to backend in preview mode

- stop running makemigrations at container startup; keep migrate only for deterministic schema

- add RUNNER_UID/GID defaults in preview compose to improve first-run reliability

- run gunicorn in Dockerfile prod stage with LOG_LEVEL default expansion

- switch docker-compose.ci.yml build target to prod so CI validates production-like runtime

Reasoning:

These changes remove non-deterministic startup behavior and fix a concrete preview build failure, while making CI exercise the same runtime model used for production deployment.
- conftest.py patches requests.get + time.sleep in cve_fetcher module
- Skips mock for tests marked @pytest.mark.nvd_integration
- Moves test_cve_fetcher.py module-level code into fixtures
- pytest.ini excludes nvd_integration by default

66 tests now run in ~1s vs timing out at >120s
- Remove debug console statements that logged passwords (LoginBox.tsx)
- Translate German comments to English (LoginBox.tsx)
- Add GET method with @ensure_csrf_cookie to Login view; remove validate_email from username check
- Restore deleted backend/assets/icons/ and backend/assets/images/ (eye.svg, logos, flags, etc.)
- Add set -e to entrypoint.sh
- Fix FQDN https check to use startswith("https://") instead of substring match
- Switch frontend Dockerfile from yarn to npm ci + npm run build
- Add frontend/.dockerignore
5 tests covering the full upload→parse→DB flow using
pre-baked OWASP fixtures (no live NVD calls):

- test_large_report_parses_correctly (54 deps, 33 CVEs)
- test_small_report_parses_correctly (19 deps, 1 CVE)
- test_cve_ids_valid_format (CVE-YYYY-NNNNN pattern)
- test_cve_severity_not_null
- test_threshold_rejects_when_exceeded (406 on LOW)

Marked @pytest.mark.e2e, excluded from default pytest run.
Runs E2E report analysis tests on bare Ubuntu runner with
PostgreSQL 16, Python 3.12, and pre-baked fixtures. No
Docker-in-Docker needed. Uses pytest -m e2e marker.
The e2e_test job referenced backend/requirements-dev.txt which does
not exist. Remove the line since all dependencies (including pytest
and pytest-django) are already in backend/requirements.txt.
Use hmac.compare_digest for constant-time string comparison
to prevent timing side-channel attacks that could allow
an attacker to recover API keys character by character.

Fixes C1 from security audit.
Use ldap3.utils.conv.escape_filter_chars to escape special
characters in LDAP search filters before interpolation.
Prevents authentication bypass and data exfiltration via
crafted username values.

Fixes C2 from security audit.
Only allow hardcoded dev credentials when IS_DEV=True to
prevent accidental exposure in production. Use
hmac.compare_digest for constant-time password comparison
to prevent timing attacks on credential validation.

Fixes C3 from security audit.
Add IsAuthenticated and analyzer.delete_project permission
requirements to DeleteProjectAPI to prevent IDOR.
Any authenticated user could previously delete any project.

Fixes H1 from security audit.
Add regex validation for CVE ID format to prevent SSRF via
crafted CVE IDs. Add 30-second timeout to NVD and EPSS API
requests to prevent slow-loris DoS attacks.

Fixes H2 from security audit.
Add ALLOWED_TEMPLATES frozenset to HtmlView to prevent
template injection. Non-whitelisted template names are
logged and the login page is rendered instead. This
mitigates information disclosure via path traversal.

Fixes H5 from security audit.
The api_404_view function was defined twice in urls.py.
The second definition silently shadowed the first.
Remove the duplicate to ensure consistent behavior.

Fixes M4 from security audit.
L1: Use specific UID (1000) for baseuser to avoid permission
    issues with volume mounts.
L2: Add HEALTHCHECK instruction using Python urllib to verify
    the application is responding.
L3: Make gunicorn workers and threads configurable via
    GUNICORN_WORKERS and GUNICORN_THREADS env vars.

Fixes L1, L2, L3 from security audit.
H3: Add AnonRateThrottle and UserRateThrottle. Tighten login
    rate to 5/min to prevent brute-force attacks.
H4: Use secrets.token_urlsafe() to generate random dev
    credentials when not explicitly set. Log warning.
M2: Replace CORS_ALLOW_ALL_ORIGINS with explicit origins
    whitelist (already correct, but add dev origins).
M3: Add HTTPS enforcement settings (HSTS, SSL redirect,
    X-Frame-Options, content type nosniff) for production.

Fixes H3, H4, M2, M3 from security audit.
The ParserManager passes request.data as a dict, but cyclonedx_parser
called json.loads() directly, which crashes on dict input. Add an
isinstance check to handle both string and dict input, matching the
trivy parser's behavior.
Trivy reports can list multiple CVEs for the same (pkg, version) pair.
The parser used dependency_name as the dict key, which caused later
entries to overwrite earlier ones for the same dep. Switch the key to
f"{name}:{version}" and skip duplicate CVE IDs so all vulnerabilities
for a dependency are preserved.

Discovered via E2E test: requests@2.32.3 was silently losing CVEs.
Cover the happy path (string + dict input) and the ParserManager
dispatch. CycloneDX tests include a regression case for the
dict-input crash that was fixed in the previous commit.
Verify the full upload pipeline for both tools:
- Trivy: 17 deps, 56 Reports, 55 unique CVEObjects stored
- CycloneDX: 14 components stored, 0 CVEs (clean SBOM)

These tests also cover the dedup behavior: trivy's 58 raw vulnerability
entries collapse to 56 (dep, cve) pairs because 3 CVEs are shared
between deps and 2 are duplicated within the same dep.
xMinhx and others added 11 commits June 27, 2026 14:51
Generated by scanning this project with trivy 0.71.2 and
cyclonedx-bom 7.3.0 to provide realistic test data for the
previously untested parsers.

- trivy-report-securechecknext.json (312K, 17 deps, 58 vuln entries)
- cyclonedx-report-securechecknext.json (12K, 14 components)
…t parsers

- README.md: CycloneDX and Trivy are now supported (not 'future features');
  add 'Supported Report Formats' section
- API.md: toolName now lists owasp, trivy, cyclonedx; add example fixtures
- ARCHITECTURE.md: reflect Nginx frontend container, Gunicorn backend,
  and 3-tier deployment (not Django-serves-SPA)
- QUICK_START.md, PROJEKTUEBERSICHT_3TIER.md: docker-compose (v1)
  -> docker compose (v2)
- README-DEV-INSTALLATION.md: docker-compose is bundled with Docker
  Engine 20.10+, no separate install
Fixes accso#22

The solution was generated using github copilot workspace.

---

For more details, open the [Copilot Workspace session](https://copilot-workspace.githubnext.com/accso/SecureCheckPlus/issues/22?shareId=XXXX-XXXX-XXXX-XXXX).
…stream accso#22)

- Swap adventurer-neutral API URL for local @dicebear/core v9 + bottts-neutral
- Add avatar.ts utility wrapping createAvatar() -> toDataUri()
- Update UserSettingsContent.tsx and Profile.tsx to use getAvatarDataUri()
- Remove dicebear.com URL from constants.tsx
- Remove django-csp app, middleware, and all CSP config (no external images left)
- Shell -> exec form CMD in Dockerfile for proper signal handling
- as -> AS in Dockerfile per convention
- Exclude .opencode/ from git tracking

Co-authored-by: Niklas Büchel <NikAcc@users.noreply.github.com>
)

Co-authored-by: Niklas Büchel <NikAcc@users.noreply.github.com>
…stream accso#38)

Co-authored-by: Nils Kreiner <kreinern@users.noreply.github.com>
The original versions were heavily German with emoji slop
("🚀", "✅", "❌", etc.). Rewrite both files in plain English
following the project's existing style (API.md, ARCHITECTURE.md).

Changes:
- QUICK_START.md: complete rewrite, 268 -> 215 lines, no German
- API_TEST_GUIDE.md: complete rewrite, 88 -> 137 lines, English only
  with practical curl examples and URL structure reference
- README.md: fix broken link to renamed README-INSTALLATION.md
@xMinhx xMinhx closed this Jun 27, 2026
@xMinhx xMinhx deleted the pr/upstream-clean branch June 27, 2026 19:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants