Add security fixes and comprehensive documentation

Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2026-02-06 21:59:19 +00:00
parent 47154c28d2
commit 9ea40bec61
12 changed files with 2254 additions and 34 deletions
+118
View File
@@ -0,0 +1,118 @@
# Quizzical Beats - Environment Variables Example
# Copy this file to .env and replace with your actual values
# SECURITY NOTE: Never commit .env file to version control!
# ============================================================================
# CRITICAL SECURITY SETTINGS - MUST BE SET
# ============================================================================
# Secret key for Flask session management (REQUIRED)
# Generate with: python -c 'import secrets; print(secrets.token_hex(32))'
SECRET_KEY=
# Automation token for API endpoints (REQUIRED)
# Generate with: python -c 'import secrets; print(secrets.token_urlsafe(32))'
AUTOMATION_TOKEN=
# ============================================================================
# DEBUG SETTINGS
# ============================================================================
# WARNING: Set DEBUG=False in production environments!
DEBUG=False
DEBUG2=False
# ============================================================================
# DATABASE CONFIGURATION
# ============================================================================
SQLALCHEMY_DATABASE_URI=sqlite:///data/song_data.db
SQLALCHEMY_TRACK_MODIFICATIONS=False
# ============================================================================
# HTTPS CONFIGURATION
# ============================================================================
# Set to True when running behind a reverse proxy with HTTPS (e.g., Traefik, nginx)
USE_HTTPS=False
# PREFERRED_URL_SCHEME=https
# ============================================================================
# SPOTIFY API CONFIGURATION (REQUIRED)
# ============================================================================
# Get credentials from: https://developer.spotify.com/dashboard/applications
SPOTIFY_CLIENT_ID=
SPOTIFY_CLIENT_SECRET=
SPOTIFY_REDIRECT_URI=http://localhost:5000/auth/spotify/callback
# ============================================================================
# MUSIC METADATA APIs
# ============================================================================
# Last.fm API for genre enrichment (REQUIRED)
# Get from: https://www.last.fm/api/account/create
LASTFM_API_KEY=
# ============================================================================
# DEEZER API CONFIGURATION (OPTIONAL)
# ============================================================================
# Get credentials from: https://developers.deezer.com/myapps
DEEZER_APP_ID=
DEEZER_APP_SECRET=
DEEZER_REDIRECT_URI=http://localhost:5000/deezer-callback
# ============================================================================
# OAUTH PROVIDERS (OPTIONAL)
# ============================================================================
# Google OAuth
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
# Authentik OAuth (self-hosted SSO)
AUTHENTIK_CLIENT_ID=
AUTHENTIK_CLIENT_SECRET=
AUTHENTIK_METADATA_URL=
# Dropbox OAuth (for cloud export)
DROPBOX_APP_KEY=
DROPBOX_APP_SECRET=
DROPBOX_REDIRECT_URI=http://localhost:5000/users/dropbox/callback
# ============================================================================
# AI SERVICES (OPTIONAL)
# ============================================================================
# OpenAI API for quiz generation features
OPENAI_API_KEY=
OPENAI_URL=https://api.openai.com/v1
OPENAI_MODEL=gpt-4o-mini
OPENAI_SEARCH_MODEL=gpt-4o-mini-search-preview
# ElevenLabs API for voice generation
ELEVENLABS_API_KEY=
# Translation services (optional)
DEEPL_API_KEY=
MEANINGCLOUD_API_KEY=
# ACRCloud for audio fingerprinting (optional)
ACRCLOUD_TOKEN=
# ============================================================================
# EMAIL CONFIGURATION (OPTIONAL)
# ============================================================================
MAIL_HOST=smtp.example.com
MAIL_PORT=587
MAIL_USE_TLS=True
MAIL_USE_SSL=False
MAIL_USERNAME=
MAIL_PASSWORD=
MAIL_SENDER=quizzical-beats@example.com
MAIL_RECIPIENT=admin@example.com
# ============================================================================
# ADVANCED CONFIGURATION (OPTIONAL)
# ============================================================================
# Static OAuth URLs for production (when behind complex reverse proxies)
# STATIC_OAUTH_URLS=False
# OAUTH_SPOTIFY_AUTH_URL=
# OAUTH_SPOTIFY_LINK_URL=
# OAUTH_GOOGLE_URL=
# OAUTH_AUTHENTIK_URL=
# OAUTH_DROPBOX_URL=
+139
View File
@@ -0,0 +1,139 @@
name: Bug Report
description: Report a bug or unexpected behavior
title: "[Bug]: "
labels: ["bug", "needs-triage"]
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to report a bug! Please fill out the form below to help us investigate.
- type: textarea
id: description
attributes:
label: Bug Description
description: A clear and concise description of what the bug is.
placeholder: What happened?
validations:
required: true
- type: textarea
id: steps
attributes:
label: Steps to Reproduce
description: Steps to reproduce the behavior
placeholder: |
1. Go to '...'
2. Click on '...'
3. Scroll down to '...'
4. See error
validations:
required: true
- type: textarea
id: expected
attributes:
label: Expected Behavior
description: What did you expect to happen?
placeholder: I expected...
validations:
required: true
- type: textarea
id: actual
attributes:
label: Actual Behavior
description: What actually happened?
placeholder: Instead...
validations:
required: true
- type: dropdown
id: version
attributes:
label: Version
description: What version of Quizzical Beats are you running?
options:
- Latest (main branch)
- v1.9 (Security Hardening)
- v1.8 (Documentation Dynamo)
- v1.7 (Dropbox Dispatch)
- v1.6 (Bulletproof Backups)
- Other (please specify in additional context)
validations:
required: true
- type: dropdown
id: deployment
attributes:
label: Deployment Method
description: How are you running Quizzical Beats?
options:
- Docker Compose (recommended)
- Docker (custom)
- Manual installation (pip)
- Other (please specify)
validations:
required: true
- type: textarea
id: environment
attributes:
label: Environment Details
description: |
Provide relevant environment information:
- OS (e.g., Ubuntu 22.04, macOS 13, Windows 11)
- Python version (e.g., 3.11)
- Browser (if web UI issue)
- Database (SQLite, PostgreSQL, MySQL)
placeholder: |
- OS: Ubuntu 22.04
- Python: 3.11.5
- Browser: Chrome 120
- Database: SQLite
validations:
required: false
- type: textarea
id: logs
attributes:
label: Relevant Logs
description: |
Please copy and paste any relevant log output. This will be automatically formatted into code.
**Security Note**: Remove any API keys, tokens, or personal information!
render: shell
placeholder: |
Paste logs here...
validations:
required: false
- type: textarea
id: screenshots
attributes:
label: Screenshots
description: If applicable, add screenshots to help explain your problem.
placeholder: Drag and drop images here or paste URLs
validations:
required: false
- type: textarea
id: context
attributes:
label: Additional Context
description: Add any other context about the problem here.
placeholder: Any additional information that might be helpful...
validations:
required: false
- type: checkboxes
id: checklist
attributes:
label: Pre-submission Checklist
description: Please confirm the following before submitting
options:
- label: I have searched existing issues to ensure this is not a duplicate
required: true
- label: I have removed any sensitive information (API keys, passwords, etc.) from logs and screenshots
required: true
- label: I am using a supported version of Quizzical Beats
required: true
+114
View File
@@ -0,0 +1,114 @@
name: Feature Request
description: Suggest a new feature or enhancement
title: "[Feature]: "
labels: ["enhancement", "needs-triage"]
body:
- type: markdown
attributes:
value: |
Thanks for suggesting a feature! Please provide as much detail as possible.
- type: textarea
id: problem
attributes:
label: Problem Statement
description: Is your feature request related to a problem? Please describe.
placeholder: I'm always frustrated when...
validations:
required: true
- type: textarea
id: solution
attributes:
label: Proposed Solution
description: Describe the solution you'd like to see
placeholder: I would like...
validations:
required: true
- type: textarea
id: alternatives
attributes:
label: Alternatives Considered
description: Describe any alternative solutions or features you've considered
placeholder: I also thought about...
validations:
required: false
- type: dropdown
id: priority
attributes:
label: Priority
description: How important is this feature to you?
options:
- Critical (blocking my use)
- High (would significantly improve experience)
- Medium (nice to have)
- Low (minor enhancement)
validations:
required: true
- type: dropdown
id: category
attributes:
label: Feature Category
description: Which area does this feature relate to?
options:
- Import/Export
- Round Generation
- User Interface
- Authentication
- API Integration
- Performance
- Security
- Documentation
- Other
validations:
required: true
- type: textarea
id: use-case
attributes:
label: Use Case
description: Describe how you would use this feature
placeholder: I would use this feature to...
validations:
required: false
- type: textarea
id: mockups
attributes:
label: Mockups or Examples
description: If applicable, add mockups, wireframes, or links to similar features in other apps
placeholder: Drag and drop images here or paste URLs
validations:
required: false
- type: textarea
id: context
attributes:
label: Additional Context
description: Add any other context about the feature request here
placeholder: Any additional information...
validations:
required: false
- type: checkboxes
id: contribution
attributes:
label: Contribution
description: Would you be willing to contribute to this feature?
options:
- label: I would like to implement this feature myself
- label: I can help test this feature
- label: I can help write documentation for this feature
- type: checkboxes
id: checklist
attributes:
label: Pre-submission Checklist
options:
- label: I have searched existing issues and feature requests
required: true
- label: I have checked the roadmap to see if this is already planned
required: true
+59
View File
@@ -0,0 +1,59 @@
name: Security Vulnerability
description: Report a security vulnerability (private disclosure)
title: "[Security]: "
labels: ["security"]
body:
- type: markdown
attributes:
value: |
## ⚠️ SECURITY NOTICE
**DO NOT** report security vulnerabilities in public issues!
Please report security issues privately via email to:
**christian@kaufdeinquiz.com**
See [SECURITY.md](https://github.com/christianlouis/QuizzicalBeats/blob/main/SECURITY.md) for our full security policy.
---
This issue template is for non-critical security improvements or discussions only.
- type: textarea
id: description
attributes:
label: Security Concern Description
description: Describe the security improvement or concern (not a vulnerability)
placeholder: I noticed that...
validations:
required: true
- type: dropdown
id: severity
attributes:
label: Severity
description: How severe is this concern?
options:
- Low (security improvement suggestion)
- Medium (potential security issue)
- High (security vulnerability - REPORT VIA EMAIL!)
validations:
required: true
- type: textarea
id: impact
attributes:
label: Potential Impact
description: What could happen if this is not addressed?
placeholder: This could lead to...
validations:
required: false
- type: textarea
id: recommendation
attributes:
label: Recommendation
description: What steps should be taken to address this?
placeholder: I recommend...
validations:
required: false
+135 -15
View File
@@ -1,32 +1,152 @@
# Pull Request Template
# Pull Request
## Description
Provide a brief description of the changes made in this pull request. Include the motivation and context for the change.
Fixes # (issue)
<!-- Provide a brief description of your changes -->
## Type of Change
<!-- Mark the relevant option with an 'x' -->
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] Documentation update
- [ ] Performance improvement
- [ ] Code refactoring
- [ ] Security fix
- [ ] Dependency update
## Checklist
## Related Issues
- [ ] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [ ] I have added tests that prove my fix is effective or that my feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream modules
<!-- Link to related issues using #issue_number -->
Fixes #
Relates to #
## Changes Made
<!-- List the specific changes you made -->
-
-
-
## Testing
<!-- Describe the testing you performed -->
### Test Environment
- OS:
- Python Version:
- Database:
- Browser (if applicable):
### Tests Performed
- [ ] Unit tests pass
- [ ] Integration tests pass
- [ ] Manual testing completed
- [ ] Browser compatibility tested (if UI changes)
### Test Coverage
<!-- If you added new code, describe the test coverage -->
- [ ] Added new tests for new functionality
- [ ] Updated existing tests
- [ ] No tests needed (documentation/config only)
## Security Checklist
<!-- Confirm security considerations -->
- [ ] No sensitive data (API keys, passwords, tokens) included in code
- [ ] All user inputs are validated and sanitized
- [ ] No SQL injection vulnerabilities
- [ ] No XSS vulnerabilities
- [ ] Dependencies checked for known vulnerabilities
- [ ] Security implications documented (if applicable)
## Documentation
<!-- Documentation updates -->
- [ ] Code comments added/updated
- [ ] README.md updated (if needed)
- [ ] Documentation updated (if needed)
- [ ] CHANGELOG.md updated
- [ ] API documentation updated (if applicable)
## Screenshots (if applicable)
Add screenshots to help explain your changes if applicable.
<!-- If applicable, add screenshots to demonstrate UI changes -->
## Additional Context
### Before
Add any other context or information about the pull request here.
### After
## Deployment Notes
<!-- Any special deployment considerations -->
- [ ] Database migrations required
- [ ] Environment variables added/changed
- [ ] Configuration changes needed
- [ ] Dependencies updated (requirements.txt)
- [ ] No deployment steps required
### Migration Steps
<!-- If migrations are required, list the steps -->
1.
2.
## Performance Impact
<!-- Describe any performance implications -->
- [ ] No performance impact
- [ ] Performance improved
- [ ] Performance impact (explain below)
## Breaking Changes
<!-- If this is a breaking change, describe what breaks and migration path -->
## Checklist
<!-- Final checklist before submitting -->
- [ ] My code follows the project's coding standards (PEP 8)
- [ ] I have performed a self-review of my code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published
- [ ] I have checked my code for security vulnerabilities
## Additional Notes
<!-- Any additional information that reviewers should know -->
---
## For Reviewers
### Review Focus Areas
- [ ] Security implications
- [ ] Performance impact
- [ ] Code quality and maintainability
- [ ] Test coverage
- [ ] Documentation completeness
+414 -15
View File
@@ -1,22 +1,421 @@
# AGENTS Instructions for Quizzical Beats
# AI Agent Instructions for Quizzical Beats
These instructions apply to the entire repository.
This document provides guidelines for AI coding agents working on the Quizzical Beats repository.
## Development Guidelines
- Follow **PEP 8** with a maximum line length of **100 characters**.
- Use **4 spaces** for indentation. Tabs are not allowed.
- Provide docstrings for all functions and classes using Google's style guide.
- Keep Flask routes organized using blueprints and prefer class-based views for complex endpoints.
## Project Overview
**Quizzical Beats** is a Flask-based web application for creating music quiz rounds for pub quizzes. It integrates with multiple music APIs (Spotify, Deezer, Last.fm) and provides PDF/MP3 export capabilities.
## Technology Stack
- **Backend**: Python 3.11+, Flask 3.x
- **Database**: SQLAlchemy ORM (SQLite dev, PostgreSQL/MySQL production)
- **Frontend**: Jinja2 templates, vanilla JavaScript
- **APIs**: Spotify, Deezer, Last.fm, OpenAI, Dropbox
- **Authentication**: Flask-Login, Authlib (OAuth)
- **Deployment**: Docker, Docker Compose
## Repository Structure
```
musicround/ # Main application package
├── __init__.py # Application factory
├── config.py # Configuration management
├── models.py # Database models (SQLAlchemy)
├── helpers/ # Utility modules
├── routes/ # Flask blueprints (auth, api, core, generate, etc.)
├── static/ # CSS, JavaScript, images
└── templates/ # Jinja2 HTML templates
tests/ # Test suite
docs/ # MkDocs documentation
migrations/ # Database migration scripts
```
## Code Style Guidelines
### Python Style
- Follow **PEP 8** with maximum line length of **100 characters**
- Use **4 spaces** for indentation (no tabs)
- Provide docstrings for all functions and classes (Google style)
- Use type hints where beneficial
```python
def process_playlist(playlist_id: str, user_id: int) -> dict:
"""Process a Spotify playlist and import songs.
Args:
playlist_id: The Spotify playlist ID
user_id: The user's database ID
Returns:
Dictionary containing import results with keys:
- success: Boolean indicating success
- songs_imported: Number of songs imported
- errors: List of error messages (if any)
"""
pass
```
### Flask Best Practices
- Organize routes using blueprints
- Prefer class-based views for complex endpoints
- Use Flask-WTF for form handling
- Always validate and sanitize user inputs
- Use SQLAlchemy ORM (never raw SQL without parameterization)
### Security Requirements
- **NEVER** commit API keys, secrets, or passwords
- **ALWAYS** use environment variables for sensitive data
- Validate all user inputs
- Use parameterized queries (SQLAlchemy ORM does this)
- Escape all template outputs (Jinja2 auto-escaping)
- Check [SECURITY.md](SECURITY.md) before making security-related changes
## Development Workflow
### Before Making Changes
1. **Understand the codebase**:
- Read related code in `musicround/routes/` and `musicround/helpers/`
- Check existing tests in `tests/`
- Review documentation in `docs/`
2. **Check existing issues and roadmap**:
- Review [TODO.md](TODO.md) for planned features
- Check [ROADMAP.md](ROADMAP.md) for strategic direction
- Search GitHub issues for related discussions
3. **Set up development environment**:
```bash
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
pip install -r requirements.txt
```
### Making Changes
1. **Create minimal, focused changes**:
- Make the smallest change that solves the problem
- Don't refactor unrelated code
- Don't fix unrelated bugs or style issues
2. **Write tests**:
- Add tests for new functionality in `tests/`
- Update existing tests if behavior changes
- Run tests: `pytest tests/ -v`
3. **Update documentation**:
- Update docstrings for modified functions
- Update `docs/` if user-facing changes
- Update `README.md` if installation/setup changes
### Testing
```bash
# Run all tests
pytest tests/ -v
# Run specific test file
pytest tests/test_metadata.py -v
# Run with coverage
pytest --cov=musicround tests/
```
### Linting and Code Quality
```bash
# Format code (if black is installed)
black musicround/ --line-length 100
# Check code style
flake8 musicround/ --max-line-length=100
# Type checking (if mypy is installed)
mypy musicround/
```
## Common Tasks
### Adding a New Route
```python
# In musicround/routes/new_feature.py
from flask import Blueprint, render_template, request
from flask_login import login_required, current_user
new_feature_bp = Blueprint('new_feature', __name__)
@new_feature_bp.route('/new-feature')
@login_required
def index():
"""Display the new feature page."""
return render_template('new_feature/index.html')
```
Then register in `musicround/__init__.py`:
```python
from musicround.routes.new_feature import new_feature_bp
app.register_blueprint(new_feature_bp)
```
### Adding a Database Model
```python
# In musicround/models.py
class NewModel(db.Model):
"""Description of what this model represents."""
__tablename__ = 'new_model'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100), nullable=False)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
def __repr__(self):
return f'<NewModel {self.name}>'
```
Then create a migration:
```bash
flask db migrate -m "Add NewModel"
flask db upgrade
```
### Adding a Configuration Variable
```python
# In musicround/config.py
class Config:
NEW_SETTING = os.getenv("NEW_SETTING", "default_value")
```
Add to `.env.example`:
```env
# Description of what this does
NEW_SETTING=default_value
```
## Database Migrations
- Migration files are in `migrations/`
- Use `run_migration.py` to run migrations
- Always test migrations on a backup database first
- Document schema changes in migration message
```bash
# Create a new migration
python run_migration.py
# Or manually
flask db migrate -m "Description of change"
flask db upgrade
```
## API Integration Guidelines
### Spotify API
- Token management in `musicround/helpers/spotify_helper.py`
- Use existing client manager: `SpotifyClientManager`
- Handle rate limits gracefully (retry with backoff)
- Always refresh expired tokens
### OAuth Integration
- OAuth routes in `musicround/routes/auth.py`
- Store tokens encrypted in database (User model)
- Implement token refresh before expiration
- Follow existing patterns for new OAuth providers
## Error Handling
```python
# Use Flask error handlers
from musicround.errors import APIError
@app.errorhandler(APIError)
def handle_api_error(error):
return render_template('error.html', error=error), error.status_code
# In your code
if not valid:
raise APIError("Invalid input", status_code=400)
```
## Logging
```python
import logging
logger = logging.getLogger(__name__)
# Use appropriate log levels
logger.debug("Detailed debugging information")
logger.info("Informational messages")
logger.warning("Warning messages")
logger.error("Error messages")
logger.critical("Critical errors")
```
## Commit Messages
- Write clear, concise commit messages in English.
- Reference related issues when applicable.
## Testing
- Run `pytest` before committing changes. If tests fail due to missing
dependencies or external services, mention this in the PR.
Follow conventional commit format:
## Pull Request
- Summarize major changes and reference relevant documentation updates.
- Include test results in the PR description.
```
<type>(<scope>): <subject>
<body>
<footer>
```
Types:
- `feat`: New feature
- `fix`: Bug fix
- `docs`: Documentation changes
- `style`: Code style changes (formatting)
- `refactor`: Code refactoring
- `test`: Adding or updating tests
- `chore`: Maintenance tasks
- `security`: Security fixes
Examples:
```
feat(import): Add support for Deezer playlist import
Implemented Deezer API client and playlist parsing.
Supports public and user playlists.
Fixes #123
---
fix(auth): Refresh Spotify tokens before expiration
Previously tokens would expire during long operations.
Now checks expiration 5 minutes in advance.
---
security: Upgrade authlib to 1.6.5
Fixes CVE-2024-XXXXX (JWT validation bypass)
```
## Pull Request Guidelines
1. Fill out the PR template completely
2. Reference related issues with `Fixes #123` or `Relates to #456`
3. Include before/after screenshots for UI changes
4. List any database migrations required
5. Note any breaking changes
6. Ensure all tests pass
7. Check security implications
## Testing Strategy
### What to Test
- Business logic in helpers and models
- API integration error handling
- Authentication and authorization
- Database operations
- Input validation
### What Not to Test
- Third-party library internals
- Database engine specifics
- Flask framework itself
### Test Structure
```python
# tests/test_feature.py
import pytest
from musicround import create_app, db
from musicround.models import User
@pytest.fixture
def app():
"""Create application for testing."""
app = create_app('testing')
with app.app_context():
db.create_all()
yield app
db.session.remove()
db.drop_all()
def test_feature(app):
"""Test description."""
# Arrange
user = User(username='test', email='test@example.com')
# Act
result = some_function(user)
# Assert
assert result == expected_value
```
## Documentation
- User documentation in `docs/user-guide/`
- Admin documentation in `docs/admin-guide/`
- Developer documentation in `docs/developer-guide/`
- API documentation in `docs/developer-guide/api-reference.md`
- Use MkDocs markdown format
## Common Pitfalls to Avoid
1. **Don't use default SECRET_KEY**: Must be set via environment variable
2. **Don't commit .env files**: Use .env.example as template
3. **Don't store credentials in code**: Use environment variables
4. **Don't make breaking changes without migration path**: Document upgrade steps
5. **Don't skip input validation**: All user input is untrusted
6. **Don't use raw SQL**: Use SQLAlchemy ORM for safety
7. **Don't forget CSRF protection**: Use Flask-WTF forms
8. **Don't expose sensitive data in logs**: Sanitize before logging
## Useful Commands
```bash
# Development server
python run.py
# Run migrations
python run_migration.py
# Run tests
pytest tests/ -v
# Check dependencies for vulnerabilities
pip install safety
safety check
# Docker commands
docker-compose up -d
docker-compose logs -f
docker-compose down
# Database backup
# (Use built-in backup functionality in web UI or /backup endpoint)
```
## Getting Help
- Check [documentation](https://quizzicalbeats.readthedocs.io/)
- Review [FAQ](https://quizzicalbeats.readthedocs.io/faq.html)
- Search [GitHub issues](https://github.com/christianlouis/QuizzicalBeats/issues)
- Read [CONTRIBUTING.md](CONTRIBUTING.md)
- Contact: christian@kaufdeinquiz.com
## References
- [Flask Documentation](https://flask.palletsprojects.com/)
- [SQLAlchemy Documentation](https://docs.sqlalchemy.org/)
- [Spotify Web API](https://developer.spotify.com/documentation/web-api/)
- [PEP 8 Style Guide](https://peps.python.org/pep-0008/)
- [Google Python Style Guide](https://google.github.io/styleguide/pyguide.html)
---
*Last updated: February 2026*
+608
View File
@@ -0,0 +1,608 @@
# Quizzical Beats - Project Roadmap
**Version**: 2026.Q1
**Last Updated**: February 2026
## Vision Statement
Quizzical Beats aims to be the premier platform for creating, managing, and delivering engaging music quiz experiences. Our roadmap focuses on reliability, scalability, user experience, and AI-powered innovation.
## Current Status
**Latest Release**: v1.9 - "Documentation Dynamo"
**Active Development**: v2.0 - Scaling & Performance
**Repository Health**: ✅ Production-Ready
---
## 🎯 Strategic Priorities (2026)
### Q1 2026: Foundation & Security
**Focus**: Security hardening, stability, and production readiness
### Q2 2026: Scale & Performance
**Focus**: Concurrent operations, infrastructure, queue systems
### Q3 2026: Intelligence & Automation
**Focus**: AI features, scraping, advanced search
### Q4 2026: Collaboration & Cloud
**Focus**: Multi-user features, cloud storage, sharing
---
## 📋 Release Schedule
### ✅ Completed Releases
#### v1.0 - "Spotify Integration Fix"
*Released: Q4 2024*
- ✅ Spotify playlist import with pagination
- ✅ API rate limit handling
- ✅ Refactored Spotify client
- ✅ Comprehensive logging
#### v1.1 - "Authentication Foundation"
*Released: Q4 2024*
- ✅ User database schema
- ✅ Local authentication system
- ✅ User management interfaces
- ✅ Role-based access control
- ✅ Secure password handling
#### v1.2 - "Spotify OAuth Integration"
*Released: Q1 2025*
- ✅ User-specific Spotify tokens
- ✅ OAuth login option
- ✅ Service account fallback
- ✅ Playlist-user linking
#### v1.3 - "Enhanced User Experience"
*Released: Q1 2025*
- ✅ Custom intro/outro/replay MP3s
- ✅ User-specific email settings
- ✅ User preferences system
#### v1.4 - "Multi-Provider OAuth"
*Released: Q2 2025*
- ✅ Google OAuth integration
- ✅ Authentik OAuth integration
- ✅ Unified authentication experience
#### v1.5 - "Advanced Features"
*Released: Q2 2025*
- ✅ Comprehensive logging
- ✅ System monitoring
#### v1.6 - "Bulletproof Backups"
*Released: Q3 2025*
- ✅ Full system backup/restore
- ✅ Scheduled backups (Ofelia)
- ✅ Admin backup management UI
- ✅ Backup versioning
- ✅ Retention policies
- ✅ CLI backup tools
#### v1.7 - "Dropbox Dispatch"
*Released: Q4 2025*
- ✅ Dropbox OAuth per-user
- ✅ Round export to Dropbox
- ✅ ZIP and PDF export
- ✅ Token refresh handling
#### v1.8 - "Documentation Dynamo"
*Released: Q4 2025*
- ✅ User guide with screenshots
- ✅ FAQ section
- ✅ API documentation
- ✅ Architecture documentation
- ✅ Deployment guides
- ✅ MkDocs portal
- ✅ ReadTheDocs integration
#### v1.9 - "Security Hardening"
*Released: Q1 2026*
- ✅ Upgraded authlib to 1.6.5+ (CVE fixes)
- ✅ Required secure SECRET_KEY
- ✅ Required secure AUTOMATION_TOKEN
- ✅ Comprehensive SECURITY.md
- ✅ .env.example template
- ✅ Security documentation
---
### 🚀 Upcoming Releases
#### v2.0 - "Import Infrastructure" *(Q1 2026 - HIGH PRIORITY)*
**Status**: 🔴 Not Started
**Priority**: Critical
**Effort**: 2-3 weeks
**Goals**: Background processing for large imports
**Features**:
- [ ] Import queue system (Celery/RQ)
- [ ] Background worker processes
- [ ] Concurrent import job support
- [ ] Priority queue handling
- [ ] Job retry logic
- [ ] Dead letter queue for failures
**Success Metrics**:
- Import 1000+ song playlists without timeout
- Support 5+ concurrent imports
- 99% job completion rate
**Dependencies**:
- Redis or RabbitMQ
- Worker orchestration (Docker Compose)
---
#### v2.1 - "Progress Pulse" *(Q1 2026 - HIGH PRIORITY)*
**Status**: 🔴 Not Started
**Priority**: High
**Effort**: 1-2 weeks
**Goals**: Real-time import status tracking
**Features**:
- [ ] WebSocket/SSE progress updates
- [ ] Progress bars for active imports
- [ ] Detailed error reporting
- [ ] Recovery options for failed imports
- [ ] Email notifications on completion
- [ ] Import history dashboard
**Success Metrics**:
- Real-time progress updates (<1s latency)
- Clear error messages for 90%+ failures
- User satisfaction with transparency
**Dependencies**:
- v2.0 (Import Infrastructure)
- Flask-SocketIO or SSE
---
#### v2.2 - "Server Stability" *(Q1 2026 - HIGH PRIORITY)*
**Status**: 🔴 Not Started
**Priority**: Critical
**Effort**: 1 week
**Goals**: Production-grade web server
**Features**:
- [ ] Replace Flask dev server with Gunicorn
- [ ] Configure worker processes (4-8 workers)
- [ ] Graceful shutdown/restart
- [ ] Nginx reverse proxy configuration
- [ ] SSL termination
- [ ] Static file optimization
- [ ] Response compression
- [ ] Security headers
**Success Metrics**:
- Handle 100+ concurrent users
- <500ms median response time
- 99.9% uptime
- Zero downtime deployments
**Dependencies**:
- Docker configuration updates
- nginx configuration
---
#### v2.3 - "Database Durability" *(Q2 2026 - HIGH PRIORITY)*
**Status**: 🔴 Not Started
**Priority**: High
**Effort**: 1-2 weeks
**Goals**: Production database configuration
**Features**:
- [ ] Connection pooling (SQLAlchemy pool)
- [ ] Database query optimization
- [ ] Index creation for common queries
- [ ] Concurrent write handling
- [ ] Database performance monitoring
- [ ] Read replica support (optional)
- [ ] Zero-downtime migrations
**Success Metrics**:
- Support 50+ concurrent connections
- <100ms query execution (95th percentile)
- No deadlocks or transaction conflicts
**Dependencies**:
- PostgreSQL or MySQL recommended
- Monitoring tools (Prometheus/Grafana)
---
#### v2.4 - "Search Supercharge" *(Q2 2026 - MEDIUM PRIORITY)*
**Status**: 🔴 Not Started
**Priority**: Medium
**Effort**: 2 weeks
**Goals**: Advanced search capabilities
**Features**:
- [ ] Full-text search (PostgreSQL FTS or Elasticsearch)
- [ ] Relevance scoring improvements
- [ ] Advanced filters (year, genre, artist, BPM)
- [ ] Search result caching
- [ ] Faceted search
- [ ] Search suggestions/autocomplete
- [ ] Search analytics
**Success Metrics**:
- Search results <200ms
- 80%+ user satisfaction with relevance
- Support 10,000+ song database efficiently
**Dependencies**:
- v2.3 (Database Durability)
- Optional: Elasticsearch
---
#### v2.5 - "Performance Pulse" *(Q2 2026 - MEDIUM PRIORITY)*
**Status**: 🔴 Not Started
**Priority**: Medium
**Effort**: 1-2 weeks
**Goals**: Application performance optimization
**Features**:
- [ ] Database index optimization
- [ ] Lazy loading for lists
- [ ] Pagination for all large datasets
- [ ] MP3 preview streaming
- [ ] Redis caching layer
- [ ] Query result caching
- [ ] CDN for static assets
- [ ] Load testing suite
**Success Metrics**:
- Page load <1s (90th percentile)
- Support 10,000+ songs in library
- <100MB memory per worker
**Dependencies**:
- v2.2 (Server Stability)
- Redis for caching
---
#### v2.6 - "Textual Transport" *(Q2 2026 - MEDIUM PRIORITY)*
**Status**: 🔴 Not Started
**Priority**: Medium
**Effort**: 2 weeks
**Goals**: Text-based playlist import
**Features**:
- [ ] Plain text playlist parsing
- [ ] CSV format support
- [ ] Artist/song detection algorithms
- [ ] Confidence scoring for matches
- [ ] Manual review interface
- [ ] Bulk import workflow
- [ ] Format templates
**Success Metrics**:
- 90%+ accurate matching for clean input
- Support 500+ songs per import
- Clear review workflow for low-confidence matches
---
#### v3.0 - "Rhythm Roundsmith" *(Q3 2026 - HIGH PRIORITY)*
**Status**: 🔴 Not Started
**Priority**: High
**Effort**: 3-4 weeks
**Goals**: AI-powered quiz generation
**Features**:
- [ ] AI quiz round generation
- [ ] Multiple quiz formats (MCQ, clips, open-ended)
- [ ] Theme-based generation
- [ ] Metadata-driven questions
- [ ] User review/edit interface
- [ ] Prompt optimization
- [ ] AI provider abstraction (OpenAI, Anthropic, local)
- [ ] Cost tracking
**Success Metrics**:
- Generate engaging rounds in <30s
- 80%+ user satisfaction with AI questions
- <$0.10 cost per round generation
**Dependencies**:
- OpenAI API or compatible
- Prompt engineering
---
#### v3.1 - "Curated Collector" *(Q3 2026 - MEDIUM PRIORITY)*
**Status**: 🔴 Not Started
**Priority**: Medium
**Effort**: 2-3 weeks
**Goals**: Web scraping for playlists
**Features**:
- [ ] Spotify web scraper
- [ ] HTML/JSON extraction
- [ ] Rate limiting and rotation
- [ ] User-agent rotation
- [ ] Proxy support
- [ ] Scraper detection avoidance
- [ ] Compliance with ToS
**Success Metrics**:
- Successfully scrape 95%+ playlists
- Avoid detection/blocking
- Extract complete metadata
**Legal Note**: ⚠️ Scraping must comply with platform ToS
---
#### v3.2 - "Scraper Symphony" *(Q3 2026 - LOW PRIORITY)*
**Status**: 🔴 Not Started
**Priority**: Low
**Effort**: 3 weeks
**Goals**: External music chart data
**Features**:
- [ ] Billboard chart scraper
- [ ] Official Charts scraper
- [ ] 2-3 additional sources
- [ ] Data normalization
- [ ] Spotify record linking
- [ ] Admin review interface
- [ ] Scheduled scraper runs
- [ ] Error logging
**Success Metrics**:
- Weekly chart updates
- 95%+ successful Spotify matching
- Comprehensive historical data
---
#### v3.3 - "Alert Amplifier" *(Q3 2026 - MEDIUM PRIORITY)*
**Status**: 🔴 Not Started
**Priority**: Medium
**Effort**: 1-2 weeks
**Goals**: Comprehensive notification system
**Features**:
- [ ] Email verification
- [ ] Round completion notifications
- [ ] OAuth token expiration warnings
- [ ] Admin usage summaries
- [ ] Push notifications (browser/Telegram)
- [ ] Notification preferences
- [ ] Digest emails
**Success Metrics**:
- <5s notification delivery
- 90%+ email deliverability
- User-controlled notification settings
---
#### v4.0 - "Storage Sanctuary" *(Q4 2026 - HIGH PRIORITY)*
**Status**: 🔴 Not Started
**Priority**: High
**Effort**: 3-4 weeks
**Goals**: Cloud storage integration
**Features**:
- [ ] Storage backend abstraction
- [ ] AWS S3 support
- [ ] S3-compatible storage (MinIO, Wasabi)
- [ ] Dropbox storage backend
- [ ] Unified management UI
- [ ] Cloud backup storage
- [ ] MP3 cloud storage
- [ ] Differential uploads
- [ ] Background synchronization
**Success Metrics**:
- Support 100GB+ storage
- <$10/month storage costs
- Automatic failover between providers
**Dependencies**:
- boto3 (AWS SDK)
- Storage abstraction layer
---
#### v4.1 - "Collaboration Core" *(Q4 2026 - MEDIUM PRIORITY)*
**Status**: 🔴 Not Started
**Priority**: Medium
**Effort**: 3 weeks
**Goals**: Multi-user collaboration
**Features**:
- [ ] Shared round editing
- [ ] Collaboration roles (view/comment/edit)
- [ ] User invitations via email/username
- [ ] Presence indicators
- [ ] Revision history
- [ ] Public sharing links
- [ ] Access audit logs
- [ ] Comment threads
**Success Metrics**:
- Real-time collaboration (<2s sync)
- Support 10+ simultaneous editors
- Full audit trail for compliance
---
#### v4.2 - "Profile Personalizer" *(Q4 2026 - LOW PRIORITY)*
**Status**: 🟡 Partially Complete
**Priority**: Low
**Effort**: 1 week
**Features**:
- [x] Custom user MP3 fallbacks
- [x] Persistent user settings
- [ ] Default round format preferences
- [ ] Personal tag system
- [ ] Tag filtering and sorting
- [ ] Dark mode toggle
- [ ] UI customization
---
#### v4.3 - "Deployment Dynamo" *(Q4 2026 - HIGH PRIORITY)*
**Status**: 🔴 Not Started
**Priority**: High
**Effort**: 2 weeks
**Goals**: CI/CD and automation
**Features**:
- [ ] GitHub Actions CI/CD pipeline
- [ ] Automated testing
- [ ] Automated builds
- [ ] Nightly backup jobs
- [ ] Sentry error tracking
- [ ] Auto-updater script
- [ ] Health check endpoint (/healthz)
- [ ] Uptime monitoring integration
**Success Metrics**:
- <10min build and deploy time
- Automated security scanning
- Zero-downtime deployments
---
## 🔮 Future Considerations (2027+)
### Ideas Under Evaluation
#### "Blind Test" Mode
- Hide title/artist metadata during play
- Reveal answers on command
- Scoring system
#### Team Scoreboard
- Live projection mode
- Real-time score tracking
- Leaderboard display
#### Public Round Library
- Community-shared rounds
- Clone and customize
- Rating and reviews
- Trending rounds
#### REST API
- Third-party integrations
- Trivia bot support
- Mobile app backend
- Webhook support
#### Audio Fingerprinting
- Validate user uploads
- Detect duplicates
- Copyright compliance
#### Round Analytics
- Usage frequency
- Popularity metrics
- User ratings
- A/B testing
#### Video Tutorials
- Complex workflow guides
- YouTube integration
- Interactive help
#### Keyboard Shortcuts
- Power user features
- Accessibility improvements
- Documentation
---
## 📊 Metrics & KPIs
### User Metrics
- Monthly Active Users (MAU)
- Round Creation Rate
- Export Success Rate
- User Retention (30/60/90 day)
### Performance Metrics
- Page Load Time (p50, p95, p99)
- API Response Time
- Error Rate (<0.1% target)
- Uptime (99.9% target)
### Technical Metrics
- Test Coverage (>80% target)
- Code Quality Score
- Security Vulnerabilities (0 high/critical)
- Dependency Freshness
---
## 🎯 Success Criteria
### By Q2 2026
- [ ] 100+ active users
- [ ] 99.5% uptime
- [ ] <1s median page load
- [ ] Support 10,000+ songs per user
- [ ] All critical security issues resolved
### By Q4 2026
- [ ] 500+ active users
- [ ] 99.9% uptime
- [ ] AI-generated rounds feature
- [ ] Cloud storage integration
- [ ] Collaboration features
- [ ] Full CI/CD pipeline
---
## 📞 Feedback & Contributions
We welcome community feedback on this roadmap!
- **GitHub Discussions**: Share ideas and vote on features
- **GitHub Issues**: Report bugs and request features
- **Email**: christian@kaufdeinquiz.com
See [CONTRIBUTING.md](CONTRIBUTING.md) for contribution guidelines.
---
## 📝 Changelog
| Date | Change |
|------|--------|
| 2026-02 | Added v1.9 Security Hardening release |
| 2026-02 | Initial comprehensive roadmap created |
| 2025-12 | v1.8 Documentation Dynamo completed |
| 2025-10 | v1.7 Dropbox Dispatch completed |
---
*This roadmap is subject to change based on user feedback, technical constraints, and strategic priorities.*
+323
View File
@@ -0,0 +1,323 @@
# Security Policy
## Supported Versions
We take security seriously and actively maintain the latest version of Quizzical Beats.
| Version | Supported |
| ------- | ------------------ |
| Latest | :white_check_mark: |
| < Latest| :x: |
## Reporting a Vulnerability
If you discover a security vulnerability in Quizzical Beats, please report it responsibly:
1. **DO NOT** open a public GitHub issue
2. Email security details to: christian@kaufdeinquiz.com
3. Include:
- Description of the vulnerability
- Steps to reproduce
- Potential impact
- Suggested fix (if available)
We will respond within 48 hours and work with you to understand and address the issue.
## Security Best Practices
### Deployment Security
#### 1. Environment Variables
**CRITICAL**: Never use default values in production!
```bash
# Generate secure secrets
python -c 'import secrets; print(secrets.token_hex(32))' # For SECRET_KEY
python -c 'import secrets; print(secrets.token_urlsafe(32))' # For AUTOMATION_TOKEN
```
**Required secure variables:**
- `SECRET_KEY`: Flask session encryption (32+ bytes hex)
- `AUTOMATION_TOKEN`: API authentication (32+ bytes URL-safe)
#### 2. HTTPS Configuration
**REQUIRED for production:**
```env
USE_HTTPS=True
PREFERRED_URL_SCHEME=https
DEBUG=False
```
Use a reverse proxy (nginx, Traefik, Caddy) for SSL termination.
#### 3. Database Security
- Use PostgreSQL or MySQL in production (not SQLite)
- Enable database encryption at rest
- Use strong database passwords
- Restrict database network access
- Regular backups with encryption
#### 4. OAuth Configuration
**Redirect URI Security:**
- Use HTTPS redirect URIs in production
- Never use wildcards in redirect URIs
- Validate all OAuth state parameters
**Token Storage:**
- OAuth tokens are encrypted in the database
- Use secure session storage (Redis recommended)
- Set appropriate token expiration times
#### 5. API Keys Protection
**Storage:**
- Store API keys in `.env` file only
- Never commit `.env` to version control
- Use secret management services (e.g., AWS Secrets Manager, HashiCorp Vault)
**Rotation:**
- Rotate Spotify/Deezer API credentials regularly
- Update OAuth client secrets periodically
- Monitor API key usage for anomalies
### Application Security
#### 1. Authentication
- Use strong passwords (12+ characters, mixed case, numbers, symbols)
- Enable multi-factor authentication via OAuth providers
- Implement account lockout after failed login attempts
- Use secure password hashing (werkzeug PBKDF2-SHA256)
#### 2. Session Management
- Sessions expire after inactivity
- Use secure, httponly cookies
- CSRF protection enabled (Flask-WTF)
- Session data encrypted with SECRET_KEY
#### 3. Input Validation
- All user inputs are validated
- SQL injection protected via SQLAlchemy ORM
- XSS protection via template auto-escaping
- File upload validation (type, size limits)
#### 4. Rate Limiting
**Recommendations:**
```python
# Add to production deployment
- Login endpoints: 5 attempts per minute
- API endpoints: 100 requests per minute
- File uploads: 10 per hour
```
#### 5. Dependency Management
**Current Known Issues:**
- ~~authlib < 1.6.5~~ (FIXED: upgraded to 1.6.5+)
**Maintenance:**
```bash
# Check for vulnerabilities
pip install safety
safety check
# Update dependencies
pip list --outdated
pip install --upgrade <package>
```
### Infrastructure Security
#### 1. Docker Security
**Best practices:**
```dockerfile
# Use non-root user
USER musicround
# Minimize attack surface
FROM python:3.11-slim
# Security updates
RUN apt-get update && apt-get upgrade -y
```
#### 2. Network Security
- Use firewall rules (only expose ports 80, 443)
- Implement DDoS protection (Cloudflare, AWS Shield)
- Use VPN for administrative access
- Enable audit logging
#### 3. File System Security
```bash
# Secure file permissions
chmod 600 .env
chmod 700 data/
chmod 755 musicround/
# Restrict write access
chown -R musicround:musicround /app
```
#### 4. Backup Security
- Encrypt backups at rest and in transit
- Store backups in separate location/region
- Test backup restoration regularly
- Implement retention policies (30-90 days)
### Monitoring and Logging
#### 1. Security Logging
**Log these events:**
- Failed login attempts
- Password changes
- OAuth token creation/refresh
- API key usage
- Admin actions
- File uploads/downloads
#### 2. Alerting
**Configure alerts for:**
- Multiple failed logins
- Unusual API traffic patterns
- Database errors
- Backup failures
- Certificate expiration
#### 3. Audit Trail
```python
# Enable comprehensive logging
import logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
```
## Security Checklist for Production
- [ ] Generated secure SECRET_KEY (32+ bytes)
- [ ] Generated secure AUTOMATION_TOKEN (32+ bytes)
- [ ] Set DEBUG=False
- [ ] Enabled HTTPS (USE_HTTPS=True)
- [ ] Using production database (PostgreSQL/MySQL)
- [ ] Database credentials are strong and unique
- [ ] All OAuth redirect URIs use HTTPS
- [ ] API keys rotated from defaults
- [ ] Reverse proxy configured (nginx/Traefik)
- [ ] Firewall rules enabled
- [ ] SSL certificate valid and auto-renewing
- [ ] Automated backups configured
- [ ] Backup encryption enabled
- [ ] Security monitoring enabled
- [ ] Logs reviewed regularly
- [ ] Dependencies up to date
- [ ] File permissions restricted
- [ ] Running as non-root user
- [ ] Rate limiting implemented
- [ ] CSRF protection enabled
## Security Updates
We recommend:
1. Subscribe to security advisories for Python, Flask, and dependencies
2. Review [GitHub Security Advisories](https://github.com/christianlouis/QuizzicalBeats/security/advisories)
3. Monitor the [CHANGELOG](https://quizzicalbeats.readthedocs.io/changelog.html) for security updates
4. Join our security mailing list (coming soon)
## Compliance
### Data Protection
- User data stored securely with encryption
- OAuth tokens encrypted at rest
- Personal information minimization
- Data retention policies implemented
### GDPR Considerations
- User data export available
- Account deletion supported
- Privacy policy available
- Cookie consent implemented
## Security Tools
### Recommended Tools
```bash
# Static analysis
pip install bandit
bandit -r musicround/
# Dependency scanning
pip install safety
safety check
# Secret detection
git-secrets --scan
# Container scanning
docker scan quizzicalbeats:latest
```
### CI/CD Security
**GitHub Actions recommended checks:**
- Dependency vulnerability scanning
- Static code analysis (CodeQL)
- Secret scanning
- Container image scanning
- License compliance
## Known Security Considerations
### Current Limitations
1. **SQLite in Development**: Not suitable for concurrent production use
2. **File System Storage**: MP3 files stored locally (consider S3 for scale)
3. **Session Storage**: In-memory sessions don't scale (use Redis)
4. **Rate Limiting**: Not implemented (add nginx/Cloudflare)
### Future Improvements
- [ ] Add two-factor authentication (TOTP)
- [ ] Implement rate limiting middleware
- [ ] Add security headers middleware
- [ ] Content Security Policy (CSP)
- [ ] Subresource Integrity (SRI)
- [ ] Add honeypot fields to forms
- [ ] Implement IP reputation checking
- [ ] Add user session management dashboard
## Resources
- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
- [Flask Security Guide](https://flask.palletsprojects.com/en/latest/security/)
- [Python Security Best Practices](https://python.readthedocs.io/en/latest/library/security_warnings.html)
- [Docker Security Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Docker_Security_Cheat_Sheet.html)
## Contact
For security concerns, contact:
- Email: christian@kaufdeinquiz.com
- Maintainer: Christian Krakau-Louis
- Response Time: Within 48 hours
---
*Last updated: February 2026*
+6 -2
View File
@@ -17,7 +17,9 @@ class Config:
# Debug settings
DEBUG = os.getenv("DEBUG", "True") == "True"
DEBUG2 = os.getenv("DEBUG2", "False") == "True"
SECRET_KEY = os.getenv('SECRET_KEY', 'dev-key-please-change')
SECRET_KEY = os.getenv('SECRET_KEY')
if not SECRET_KEY:
raise ValueError("SECRET_KEY environment variable must be set. Generate a secure key with: python -c 'import secrets; print(secrets.token_hex(32))'")
# API Keys
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
@@ -69,7 +71,9 @@ class Config:
MAIL_RECIPIENT = os.getenv("MAIL_RECIPIENT", "admin@example.com")
# Automation settings
AUTOMATION_TOKEN = os.getenv("AUTOMATION_TOKEN", "change-this-token-in-production") # Reverse proxy settings
AUTOMATION_TOKEN = os.getenv("AUTOMATION_TOKEN")
if not AUTOMATION_TOKEN:
raise ValueError("AUTOMATION_TOKEN environment variable must be set. Generate a secure token with: python -c 'import secrets; print(secrets.token_urlsafe(32))'") # Reverse proxy settings
USE_HTTPS = os.getenv("USE_HTTPS", "False") == "True" # Force HTTPS URL generation
PREFERRED_URL_SCHEME = os.getenv("PREFERRED_URL_SCHEME", 'https' if USE_HTTPS else 'http')
+6 -1
View File
@@ -15,6 +15,11 @@ flask-admin
Flask-Login
Flask-Mail
Flask-Session
authlib
authlib>=1.6.5
Flask-Caching
psutil
# Testing dependencies
pytest>=7.4.0
pytest-cov>=4.1.0
pytest-flask>=1.2.0
+91
View File
@@ -0,0 +1,91 @@
"""Pytest configuration and fixtures for Quizzical Beats tests."""
import os
import sys
import pytest
from unittest.mock import MagicMock
# Add project root to path
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
@pytest.fixture
def app():
"""Create a test Flask application instance."""
from musicround import create_app, db
# Create app in testing mode
test_config = {
'TESTING': True,
'SQLALCHEMY_DATABASE_URI': 'sqlite:///:memory:',
'SQLALCHEMY_TRACK_MODIFICATIONS': False,
'SECRET_KEY': 'test-secret-key-for-testing-only',
'AUTOMATION_TOKEN': 'test-automation-token-for-testing',
'WTF_CSRF_ENABLED': False, # Disable CSRF for testing
}
app = create_app()
app.config.update(test_config)
with app.app_context():
db.create_all()
yield app
db.session.remove()
db.drop_all()
@pytest.fixture
def client(app):
"""Create a test client for the app."""
return app.test_client()
@pytest.fixture
def runner(app):
"""Create a test CLI runner."""
return app.test_cli_runner()
@pytest.fixture
def mock_app():
"""Create a mock Flask app for unit testing."""
app = MagicMock()
app.logger = MagicMock()
app.config = {
'SECRET_KEY': 'test-key',
'AUTOMATION_TOKEN': 'test-token',
}
return app
@pytest.fixture
def mock_spotify_client():
"""Create a mock Spotify client."""
client = MagicMock()
client.search.return_value = {
'tracks': {
'items': []
}
}
return client
@pytest.fixture
def sample_user_data():
"""Sample user data for testing."""
return {
'username': 'testuser',
'email': 'test@example.com',
'password': 'SecurePassword123!',
}
@pytest.fixture
def sample_song_data():
"""Sample song data for testing."""
return {
'title': 'Highway to Hell',
'artist_name': 'AC/DC',
'year': '1979',
'genre': 'Hard Rock',
'isrc': 'AUAP07900028',
}
+240
View File
@@ -0,0 +1,240 @@
"""Security tests for Quizzical Beats."""
import pytest
import os
import re
class TestSecurityConfiguration:
"""Test security configuration and settings."""
def test_secret_key_required(self):
"""Test that SECRET_KEY must be set."""
# Remove SECRET_KEY from environment
secret_key = os.environ.get('SECRET_KEY')
if secret_key:
del os.environ['SECRET_KEY']
# Import should fail if SECRET_KEY not set
with pytest.raises(ValueError, match="SECRET_KEY environment variable must be set"):
from musicround.config import Config
_ = Config.SECRET_KEY
# Restore environment
if secret_key:
os.environ['SECRET_KEY'] = secret_key
def test_automation_token_required(self):
"""Test that AUTOMATION_TOKEN must be set."""
# Remove AUTOMATION_TOKEN from environment
token = os.environ.get('AUTOMATION_TOKEN')
if token:
del os.environ['AUTOMATION_TOKEN']
# Import should fail if AUTOMATION_TOKEN not set
with pytest.raises(ValueError, match="AUTOMATION_TOKEN environment variable must be set"):
from musicround.config import Config
_ = Config.AUTOMATION_TOKEN
# Restore environment
if token:
os.environ['AUTOMATION_TOKEN'] = token
def test_no_credentials_in_code(self):
"""Test that no credentials are hardcoded in Python files."""
project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
musicround_dir = os.path.join(project_root, 'musicround')
# Patterns that indicate potential credentials
dangerous_patterns = [
r'password\s*=\s*["\'][^"\']{8,}["\']', # password = "something"
r'token\s*=\s*["\'][A-Za-z0-9]{20,}["\']', # token = "longstring"
r'api[_-]?key\s*=\s*["\'][A-Za-z0-9]{20,}["\']', # api_key = "key"
r'secret\s*=\s*["\'][A-Za-z0-9]{20,}["\']', # secret = "value"
]
issues = []
for root, dirs, files in os.walk(musicround_dir):
# Skip __pycache__ and test files
dirs[:] = [d for d in dirs if d != '__pycache__']
for file in files:
if not file.endswith('.py'):
continue
filepath = os.path.join(root, file)
with open(filepath, 'r', encoding='utf-8', errors='ignore') as f:
content = f.read()
for pattern in dangerous_patterns:
matches = re.finditer(pattern, content, re.IGNORECASE)
for match in matches:
# Exclude common test/example patterns
matched_text = match.group(0)
if any(safe in matched_text.lower() for safe in [
'test', 'example', 'placeholder', 'changeme',
'your-', 'secret-key-here', 'getenvi'
]):
continue
issues.append({
'file': filepath,
'line': content[:match.start()].count('\n') + 1,
'match': matched_text
})
if issues:
message = "Found potential hardcoded credentials:\n"
for issue in issues[:5]: # Show first 5
message += f" {issue['file']}:{issue['line']}: {issue['match']}\n"
pytest.fail(message)
def test_env_example_exists(self):
"""Test that .env.example file exists."""
project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
env_example = os.path.join(project_root, '.env.example')
assert os.path.exists(env_example), ".env.example file should exist"
def test_security_md_exists(self):
"""Test that SECURITY.md file exists."""
project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
security_md = os.path.join(project_root, 'SECURITY.md')
assert os.path.exists(security_md), "SECURITY.md file should exist"
class TestDependencySecurity:
"""Test dependency security."""
def test_authlib_version(self):
"""Test that authlib is at least version 1.6.5."""
requirements_path = os.path.join(
os.path.dirname(__file__), '..', 'requirements.txt'
)
with open(requirements_path, 'r') as f:
content = f.read()
# Check for authlib with version constraint
assert 'authlib>=1.6.5' in content, \
"authlib should be pinned to >= 1.6.5 to fix known vulnerabilities"
class TestInputValidation:
"""Test that user input is properly validated."""
def test_sql_injection_prevention(self):
"""Test that SQLAlchemy ORM is used (not raw SQL)."""
project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
musicround_dir = os.path.join(project_root, 'musicround')
# Look for dangerous SQL patterns
dangerous_patterns = [
r'\.execute\(["\'].*%s.*["\']', # .execute("... %s ...")
r'\.execute\(["\'].*\+.*["\']', # .execute("... " + var)
r'\.execute\(f["\']', # .execute(f"...")
]
issues = []
for root, dirs, files in os.walk(musicround_dir):
dirs[:] = [d for d in dirs if d != '__pycache__']
for file in files:
if not file.endswith('.py'):
continue
filepath = os.path.join(root, file)
with open(filepath, 'r', encoding='utf-8', errors='ignore') as f:
content = f.read()
for pattern in dangerous_patterns:
matches = re.finditer(pattern, content)
for match in matches:
issues.append({
'file': filepath,
'line': content[:match.start()].count('\n') + 1,
'match': match.group(0)
})
# migrations are allowed to use raw SQL
issues = [i for i in issues if '/migrations/' not in i['file']]
if issues:
message = "Found potential SQL injection risks:\n"
for issue in issues[:5]:
message += f" {issue['file']}:{issue['line']}: {issue['match']}\n"
pytest.fail(message)
class TestSecureDefaults:
"""Test that secure defaults are in place."""
def test_debug_disabled_by_default(self):
"""Test that DEBUG is disabled by default in config."""
# Check .env.example
env_example_path = os.path.join(os.path.dirname(__file__), '..', '.env.example')
with open(env_example_path, 'r') as f:
content = f.read()
# Should have DEBUG=False
assert 'DEBUG=False' in content, ".env.example should have DEBUG=False"
def test_https_recommended(self):
"""Test that HTTPS is documented as recommended."""
security_md_path = os.path.join(os.path.dirname(__file__), '..', 'SECURITY.md')
with open(security_md_path, 'r') as f:
content = f.read()
assert 'HTTPS' in content or 'https' in content, \
"SECURITY.md should mention HTTPS"
assert 'USE_HTTPS' in content, \
"SECURITY.md should document USE_HTTPS setting"
class TestSecretManagement:
"""Test secret management practices."""
def test_gitignore_includes_env(self):
"""Test that .env is in .gitignore."""
gitignore_path = os.path.join(os.path.dirname(__file__), '..', '.gitignore')
with open(gitignore_path, 'r') as f:
content = f.read()
assert '.env' in content, ".env should be in .gitignore"
def test_no_env_files_committed(self):
"""Test that actual .env files are not in git."""
project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
# .env.example is OK, but .env should not exist in repo
# (it will exist locally but should be gitignored)
# We're checking if demo files have placeholder values
demo_files = ['.env.demo', '.env.oauth', '.env.oauth.production']
for demo_file in demo_files:
demo_path = os.path.join(project_root, demo_file)
if os.path.exists(demo_path):
with open(demo_path, 'r') as f:
content = f.read()
# Check that these don't contain real-looking credentials
# Real API keys are usually 32+ characters of alphanumeric
patterns = [
r'[A-Za-z0-9]{40,}', # Very long alphanumeric strings
]
for pattern in patterns:
matches = re.findall(pattern, content)
for match in matches:
# Skip if it's obviously a placeholder
if any(x in match.lower() for x in [
'your-', 'example', 'changeme', 'placeholder'
]):
continue
# This might be a real credential
if len(match) > 40:
pytest.fail(
f"Found potential real credential in {demo_file}: "
f"{match[:20]}... (redacted)"
)