From 47154c28d235b6cd7d06e34fcbc5f748b415671f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 6 Feb 2026 21:51:49 +0000 Subject: [PATCH 1/4] Initial plan From 9ea40bec61ca55a9c5e92fd573bc76349a0513f2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 6 Feb 2026 21:59:19 +0000 Subject: [PATCH 2/4] Add security fixes and comprehensive documentation Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com> --- .env.example | 118 ++++ .github/ISSUE_TEMPLATE/bug_report.yml | 139 +++++ .github/ISSUE_TEMPLATE/feature_request.yml | 114 ++++ .github/ISSUE_TEMPLATE/security.yml | 59 ++ .github/PULL_REQUEST_TEMPLATE.md | 150 ++++- AGENTS.md | 429 ++++++++++++++- ROADMAP.md | 608 +++++++++++++++++++++ SECURITY.md | 323 +++++++++++ musicround/config.py | 8 +- requirements.txt | 9 +- tests/conftest.py | 91 +++ tests/test_security.py | 240 ++++++++ 12 files changed, 2254 insertions(+), 34 deletions(-) create mode 100644 .env.example create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml create mode 100644 .github/ISSUE_TEMPLATE/feature_request.yml create mode 100644 .github/ISSUE_TEMPLATE/security.yml create mode 100644 ROADMAP.md create mode 100644 SECURITY.md create mode 100644 tests/conftest.py create mode 100644 tests/test_security.py diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..0eaafd4 --- /dev/null +++ b/.env.example @@ -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= diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000..346cd29 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -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 diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 0000000..b6aa9a8 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -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 diff --git a/.github/ISSUE_TEMPLATE/security.yml b/.github/ISSUE_TEMPLATE/security.yml new file mode 100644 index 0000000..c5a274f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/security.yml @@ -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 diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 7d10ffc..eae07fb 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -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) + ## Type of Change + + - [ ] 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 + + +Fixes # +Relates to # + +## Changes Made + + + +- +- +- + +## Testing + + + +### 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 + + + +- [ ] Added new tests for new functionality +- [ ] Updated existing tests +- [ ] No tests needed (documentation/config only) + +## Security Checklist + + + +- [ ] 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 + + + +- [ ] 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. + -## Additional Context +### Before -Add any other context or information about the pull request here. \ No newline at end of file + +### After + + +## Deployment Notes + + + +- [ ] Database migrations required +- [ ] Environment variables added/changed +- [ ] Configuration changes needed +- [ ] Dependencies updated (requirements.txt) +- [ ] No deployment steps required + +### Migration Steps + + + +1. +2. + +## Performance Impact + + + +- [ ] No performance impact +- [ ] Performance improved +- [ ] Performance impact (explain below) + +## Breaking Changes + + + + + +## Checklist + + + +- [ ] 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 + + + + +--- + +## For Reviewers + +### Review Focus Areas + +- [ ] Security implications +- [ ] Performance impact +- [ ] Code quality and maintainability +- [ ] Test coverage +- [ ] Documentation completeness \ No newline at end of file diff --git a/AGENTS.md b/AGENTS.md index 8839c9d..7f95210 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -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'' +``` + +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. +``` +(): + + + +