Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# πŸ›‘οΈ Divineo Bunker Security - Environment Template
# Duplicate this file to .env and replace with production values

# 🧠 AI Engine
GEMINI_API_KEY=your_gemini_api_key_here

# πŸ›‘οΈ Master Authentication Secret (abvetos.com)
LVT_SECRET_KEY=your_32_character_hex_secret_here

# πŸ‘— Shopify Integration (Optional for local testing)
# SHOPIFY_ACCESS_TOKEN=shpat_...
11 changes: 10 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,13 @@ coverage/
pids/
*.pid
*.seed
*.pid.lock
*.pid.lock

# Python cache
__pycache__/
*.pyc
*.pyo
*.pyd
.pytest_cache/
.venv/
venv/
8 changes: 8 additions & 0 deletions .jules/sentinel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Sentinel Journal

This journal tracks critical security learnings for the TryOnYou project.

## 2025-03-03 - Hardcoded Secrets and Insecure Error Handling
**Vulnerability:** Hardcoded `SECRET_KEY` in `backend/main.py` and `backend/DivineoBunker.py`. Inconsistent error handling when the AI engine failed.
**Learning:** Legacy development often leaves test credentials in code for simplicity, which can leak into production.
**Prevention:** Always load secrets from environment variables and implement centralized, generic error responses that don't leak internal states.
7 changes: 6 additions & 1 deletion backend/DivineoBunker.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,16 @@
import hashlib
import time
import json
import os
from dotenv import load_dotenv

# Load environment variables
load_dotenv()

class DivineoBunker:
def __init__(self):
# πŸ›‘οΈ ConfiguraciΓ³n Maestra (abvetos.com)
self.secret_key = "LVT_SECRET_PROD_091228222"
self.secret_key = os.getenv("LVT_SECRET_KEY", "DEVELOPMENT_SECRET_KEY_REPLACE_ME")
self.patent = "PCT/EP2025/067317"
self.algorithm_v = "V10_Divineo_Shopify_Final"

Expand Down
17 changes: 15 additions & 2 deletions backend/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
import hashlib
import time
import json
import os
from dotenv import load_dotenv
from fastapi import FastAPI, HTTPException
from fastapi.responses import JSONResponse
from fastapi.middleware.cors import CORSMiddleware
Expand All @@ -18,8 +20,11 @@
allow_headers=["*"],
)

# Load environment variables
load_dotenv()

# πŸ›‘οΈ ConfiguraciΓ³n Maestra (abvetos.com)
SECRET_KEY = "LVT_SECRET_PROD_091228222"
SECRET_KEY = os.getenv("LVT_SECRET_KEY", "DEVELOPMENT_SECRET_KEY_REPLACE_ME")
Comment on lines +24 to +27
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

While moving the secret to an environment variable is a great improvement, the configuration loading logic (calling load_dotenv() and getting the LVT_SECRET_KEY) is duplicated in backend/DivineoBunker.py. This violates the DRY (Don't Repeat Yourself) principle and could lead to maintenance issues if, for example, the environment variable name needs to change in the future. Consider centralizing your application's configuration into a single module (e.g., backend/config.py) that loads environment variables and defines configuration constants. Other modules could then import from this central config module.

PATENT = "PCT/EP2025/067317"

def verify_auth(user_id: str, token: str) -> bool:
Expand Down Expand Up @@ -68,7 +73,15 @@ async def recommend_garment(scan: UserScan, garment_id: str = "BALMAIN_SS26_SLIM
# Usamos Jules para el toque de estilo
styling_advice = get_jules_advice(scan, item)
except Exception as e:
styling_advice = f"Divineo confirmado con {item['name']}."
# πŸ›‘οΈ Security: Fail-secure and return structured error for the frontend/tests
return JSONResponse(
status_code=503,
content={
"status": "error",
"code": 503,
"message": "Jules AI Engine is currently recalibrating or unavailable. Please try again."
}
)
Comment on lines 75 to +84
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

This except block correctly provides a fail-secure response, but it completely hides the underlying error from the AI engine. Without logging the exception, debugging any issues with the get_jules_advice function will be impossible. The exception should be logged before returning the error response.

Suggested change
except Exception as e:
styling_advice = f"Divineo confirmado con {item['name']}."
# πŸ›‘οΈ Security: Fail-secure and return structured error for the frontend/tests
return JSONResponse(
status_code=503,
content={
"status": "error",
"code": 503,
"message": "Jules AI Engine is currently recalibrating or unavailable. Please try again."
}
)
except Exception:
import logging
logging.exception("Jules AI Engine failed")
# πŸ›‘οΈ Security: Fail-secure and return structured error for the frontend/tests
return JSONResponse(
status_code=503,
content={
"status": "error",
"code": 503,
"message": "Jules AI Engine is currently recalibrating or unavailable. Please try again."
}
)


if is_divineo and item['stock'] > 0:
return {
Expand Down
2 changes: 2 additions & 0 deletions backend/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ uvicorn
python-dotenv
pydantic
gunicorn
pytest
httpx
9 changes: 7 additions & 2 deletions backend/tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,18 @@ def test_recommend_garment_engine_failure(monkeypatch):
def mock_get_jules_advice(*args, **kwargs):
raise Exception("Simulated AI Engine Failure")

# Mock verify_auth to bypass security handshake for this test
monkeypatch.setattr("backend.main.verify_auth", lambda u, t: True)

# Use monkeypatch to replace the real function with our mock
monkeypatch.setattr("backend.main.get_jules_advice", mock_get_jules_advice)

# 2. Prepare the request payload
# Must match UserScan model in backend/models.py
payload = {
"height": 175.0,
"weight": 68.0,
"user_id": "TEST_USER",
"token": "0.TEST_TOKEN", # This will fail verify_auth due to timestamp, but get_jules_advice is called later
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The comment on this line is now incorrect and misleading. verify_auth is mocked on line 18 to always return True, so it will not fail as the comment suggests. This comment should be removed to avoid confusion for future developers maintaining this test.

Suggested change
"token": "0.TEST_TOKEN", # This will fail verify_auth due to timestamp, but get_jules_advice is called later
"token": "0.TEST_TOKEN",

"waist": 70.0,
"event_type": "Gala"
}

Expand Down