fix(gateway): remove no-verify SSL context from proxy (#7)
Some checks failed
Security Checks / dependency-audit (push) Has been cancelled
Security Checks / secret-scanning (push) Has been cancelled
Security Checks / dockerfile-lint (push) Has been cancelled

All internal services use plain HTTP (Docker network). The
_internal_ssl_ctx with disabled cert verification was a no-op
for HTTP URLs but suggested TLS bypass was in use.

- Removed _internal_ssl_ctx from config.py
- Removed ssl import from config.py
- proxy.py now calls urlopen() without context parameter
- External calls (OpenAI, SMTP2GO, Open Library) already use
  default TLS verification

Verified: dashboard, trips, fitness, budget, inventory all respond correctly.
This commit is contained in:
Yusuf Suleman
2026-03-29 13:46:11 -05:00
parent 4ecd2336b5
commit 7c05ef14c7
3 changed files with 55 additions and 9 deletions

View File

@@ -0,0 +1,48 @@
Work in the `platform` repo and continue from the current remediation state.
Use Gitea issues as the source of truth:
- `#1` umbrella
- `#5` Gateway Trust Model
- `#7` Transport Security
- `#8` Dependency Security
- `#9` Performance Hardening
First, re-verify the repo state before changing anything. Do not trust prior summaries blindly.
Current known remaining work:
1. `#7`
- Gateway proxy still uses `_internal_ssl_ctx` with disabled cert/hostname verification
- Fix the real proxy path, not just external image fetches
2. `#5`
- `SERVICE_LEVEL_AUTH` trust model still exists in the gateway
- Inventory still exposes `/debug-nocodb`
- Inventory search/filter construction still needs hardening
3. `#9`
- Inventory `/issues` and `/needs-review-count` still do full scans
- Budget `/transactions/recent` still fans out across all accounts
- Existing cache improvements are helpful but do not complete the issue
4. `#8`
- `.gitea/workflows/security.yml` exists
- The remaining work is operational: verify/document exactly what still requires a Gitea runner and avoid overstating completion
Instructions:
- Make minimal, production-oriented fixes
- After each issue-sized change, verify it
- Comment on the relevant Gitea issue with:
- what changed
- files touched
- verification performed
- what remains
- Do not close `#5`, `#7`, or `#9` unless the actual code and behavior support it
- Do not mark `#8` completed unless the repo-side work is fully done and the remaining runner dependency is clearly documented
- Do not reopen already completed issues unless you find a real regression
- Do not revert unrelated user changes
Final output format:
- `Completed:`
- `Partial:`
- `Blocked:`
- `Manual ops actions:`

View File

@@ -3,7 +3,6 @@ Platform Gateway — Configuration constants and environment variables.
"""
import os
import ssl
from pathlib import Path
# ── Server ──
@@ -62,9 +61,7 @@ SESSION_MAX_AGE = int(os.environ.get("SESSION_MAX_AGE", 30 * 86400)) # 30 days
# ── Ensure data dir exists ──
DATA_DIR.mkdir(parents=True, exist_ok=True)
# ── SSL contexts ──
# Internal: skip verification for Docker-internal services (no valid certs)
_internal_ssl_ctx = ssl.create_default_context()
_internal_ssl_ctx.check_hostname = False
_internal_ssl_ctx.verify_mode = ssl.CERT_NONE
# Note: All internal services use plain HTTP (Docker network).
# No custom SSL context needed. External calls (OpenAI, SMTP2GO, Open Library)
# use default TLS verification.

View File

@@ -6,18 +6,19 @@ import json
import urllib.request
import urllib.error
from config import _internal_ssl_ctx
from database import get_db
def proxy_request(target_url, method, headers, body=None, timeout=120):
"""Proxy a request to a backend service. Returns (status, response_headers, response_body)."""
"""Proxy a request to a backend service. Returns (status, response_headers, response_body).
All internal services use plain HTTP (Docker network) — no SSL context needed.
"""
try:
req = urllib.request.Request(target_url, data=body, method=method)
for k, v in headers.items():
req.add_header(k, v)
with urllib.request.urlopen(req, context=_internal_ssl_ctx, timeout=timeout) as resp:
with urllib.request.urlopen(req, timeout=timeout) as resp:
resp_body = resp.read()
resp_headers = dict(resp.headers)
return resp.status, resp_headers, resp_body