chore: apply ruff formatting and fix whitespace issues

Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2026-02-13 09:12:11 +00:00
parent 43bc58770d
commit b03ebab747
96 changed files with 991 additions and 993 deletions
+4 -4
View File
@@ -71,16 +71,16 @@ def make_api_request(url, max_retries=3):
"""Make API request with rate limit handling."""
for attempt in range(max_retries):
response = requests.get(url)
if response.status_code == 429:
# Rate limit exceeded
retry_after = int(response.headers.get('Retry-After', 60))
print(f"Rate limit exceeded. Retrying after {retry_after} seconds...")
time.sleep(retry_after)
continue
return response
raise Exception("Max retries exceeded")
```
@@ -203,7 +203,7 @@ The DocuElevate browser extension uses this endpoint to send files directly from
Upload one or more files from your computer for processing.
**Request**:
**Request**:
- Multipart form data with file(s)
**Response**:
+1 -1
View File
@@ -79,7 +79,7 @@ For larger deployments or when you need more advanced authentication features, O
### 1. Create an Application in Authentik
1. Log in to your Authentik admin interface
2. Navigate to "Applications" > "Applications"
2. Navigate to "Applications" > "Applications"
3. Click "Create"
4. Fill in the following details:
- **Name**: DocuElevate
+2 -2
View File
@@ -243,7 +243,7 @@ docker build -t docuelevate .
**Cause:** Building outside of a Git repository
**Solution:**
**Solution:**
- Clone the repository properly with `.git` directory
- Or set `GIT_COMMIT_SHA` environment variable
@@ -261,7 +261,7 @@ docker build --no-cache -t docuelevate .
**Cause:** Files listed in `.dockerignore`
**Solution:**
**Solution:**
- Check `.dockerignore` doesn't block `BUILD_DATE`, `GIT_SHA`, or `RUNTIME_INFO`
- The `VERSION` file should always be committed to git
+1 -1
View File
@@ -352,7 +352,7 @@ PAPERLESS_CUSTOM_FIELDS_MAPPING='{"absender": "Sender", "empfaenger": "Recipient
### Dropbox
| **Variable** | **Description** |
| **Variable** | **Description** |
|-------------------------|--------------------------------------------------|
| `DROPBOX_APP_KEY` | Dropbox API app key. |
| `DROPBOX_APP_SECRET` | Dropbox API app secret. |
+1 -1
View File
@@ -1,4 +1,4 @@
# DocuElevate Configuration
# DocuElevate Configuration
This section contains detailed documentation about configuring DocuElevate for your environment.
+4 -4
View File
@@ -106,17 +106,17 @@ Add security headers to your Nginx configuration:
server {
listen 443 ssl http2;
server_name docuelevate.example.com;
# SSL configuration
ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/key.pem;
# Security headers
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:;" always;
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
location / {
proxy_pass http://localhost:8000;
proxy_set_header Host $host;
@@ -185,7 +185,7 @@ For production use, we recommend setting up a reverse proxy (like Nginx or Traef
server {
listen 80;
server_name docuelevate.example.com;
location / {
proxy_pass http://localhost:8000;
proxy_set_header Host $host;
+5 -5
View File
@@ -4,7 +4,7 @@ This guide explains how to set up the Dropbox integration for DocuElevate.
## Required Configuration Parameters
| **Variable** | **Description** |
| **Variable** | **Description** |
|-------------------------|--------------------------------------------------|
| `DROPBOX_APP_KEY` | Dropbox API app key |
| `DROPBOX_APP_SECRET` | Dropbox API app secret |
@@ -64,11 +64,11 @@ The wizard handles all the token exchange steps and provides you with the exact
1. Go to the "OAuth 2" tab in your app settings
2. Add a redirect URI: `http://localhost` (this is for the authorization flow)
3. Generate an authorization URL with these instructions:
```
https://www.dropbox.com/oauth2/authorize?client_id=YOUR_APP_KEY&response_type=code&token_access_type=offline
```
4. Replace `YOUR_APP_KEY` with your app key
5. Open this URL in your browser
6. Authorize the app when prompted
@@ -78,7 +78,7 @@ The wizard handles all the token exchange steps and provides you with the exact
### 5. Exchange the Code for a Refresh Token
1. Use this curl command to exchange the code for tokens:
```bash
curl -X POST https://api.dropboxapi.com/oauth2/token \
-d code=YOUR_AUTH_CODE \
@@ -87,7 +87,7 @@ The wizard handles all the token exchange steps and provides you with the exact
-d client_secret=YOUR_APP_SECRET \
-d redirect_uri=http://localhost
```
2. From the response, copy the `refresh_token` value
### 6. Configure DocuElevate
-1
View File
@@ -108,4 +108,3 @@ Text extraction logs to check for `extracted_text`:
- `process_with_azure_document_intelligence` - Azure OCR processing
Both may contain extracted text in the `detail` field when `status = 'success'`.
+3 -3
View File
@@ -215,9 +215,9 @@ for step in ["hash_file", "create_file_record", "check_text", ...]:
# Start
update_step_status(db, file.id, step, "in_progress", started_at=now())
log_event(db, file.id, step, "in_progress", "Starting...")
# Do work...
# Complete
update_step_status(db, file.id, step, "success", completed_at=now())
log_event(db, file.id, step, "success", "Completed successfully")
@@ -349,6 +349,6 @@ For deploying to existing system:
- [ ] Run migration utility: `migrate_all_files(db, dry_run=True)` to test
- [ ] Run actual migration: `migrate_all_files(db, dry_run=False)`
- [ ] Verify: Check a few files with `verify_migration()`
- [ ] Update workers to call `update_step_status()`
- [ ] Update workers to call `update_step_status()`
- [ ] Update file creation to call `initialize_file_steps()`
- [ ] Monitor dashboard for correct status display
+35 -35
View File
@@ -16,19 +16,19 @@ on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install dependencies
run: |
pip install -r requirements-dev.txt
- name: Run OAuth tests (mock)
run: |
pytest tests/test_oauth_integration_flows.py -v
@@ -48,19 +48,19 @@ jobs:
runs-on: ubuntu-latest
# Only run if secrets are available (not on external PRs)
if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install dependencies
run: |
pip install -r requirements-dev.txt
- name: Run OAuth tests (real)
env:
AUTHENTIK_CLIENT_ID: ${{ secrets.AUTHENTIK_CLIENT_ID }}
@@ -84,43 +84,43 @@ jobs:
test-mock-oauth:
name: OAuth Tests (Mock)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install dependencies
run: |
pip install -r requirements-dev.txt
- name: Run mock OAuth tests
run: |
pytest tests/test_oauth_integration_flows.py \
-v \
-m "not requires_external"
test-real-oauth:
name: OAuth Tests (Real - Internal Only)
runs-on: ubuntu-latest
# Only run on internal commits where secrets are available
if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install dependencies
run: |
pip install -r requirements-dev.txt
- name: Run real OAuth tests
env:
AUTHENTIK_CLIENT_ID: ${{ secrets.AUTHENTIK_CLIENT_ID }}
@@ -157,7 +157,7 @@ on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
services:
mock-oauth:
image: ghcr.io/navikt/mock-oauth2-server:2.1.1
@@ -168,24 +168,24 @@ jobs:
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install dependencies
run: |
pip install -r requirements-dev.txt
- name: Configure OAuth to use service
run: |
export OAUTH_MOCK_URL=http://localhost:8080
export USE_MOCK_OAUTH=true
- name: Run tests
run: |
pytest tests/test_oauth_integration_flows.py -v
@@ -255,7 +255,7 @@ Add this step to debug mock OAuth server issues:
**Cause**: Real OAuth credentials not configured or not accessible.
**Solution**:
**Solution**:
- For local dev: Use mock mode (default)
- For CI: Add secrets to GitHub repository settings
- Check secret availability: `if github.event_name == 'push'`
@@ -291,20 +291,20 @@ on: [push, pull_request]
jobs:
# Fast mock OAuth tests (always run)
mock-oauth-tests:
name: OAuth Tests (Mock)
name: OAuth Tests (Mock)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install dependencies
run: pip install -r requirements-dev.txt
- name: Run mock OAuth tests
run: |
pytest tests/test_oauth_integration_flows.py \
@@ -312,7 +312,7 @@ jobs:
-m "not requires_external" \
--cov=app.auth \
--cov-report=term-missing
- name: Upload coverage
uses: codecov/codecov-action@v3
with:
@@ -324,18 +324,18 @@ jobs:
name: OAuth Tests (Real - Internal)
runs-on: ubuntu-latest
if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install dependencies
run: pip install -r requirements-dev.txt
- name: Run real OAuth tests
env:
AUTHENTIK_CLIENT_ID: ${{ secrets.AUTHENTIK_CLIENT_ID }}
@@ -345,7 +345,7 @@ jobs:
pytest tests/test_oauth_integration_flows.py \
-v \
-m requires_external
- name: Upload coverage
uses: codecov/codecov-action@v3
with:
+5 -5
View File
@@ -138,7 +138,7 @@ If you're using a work/school account provided by your organization:
### 2. Configuration based on use case
**Option A: Access your own OneDrive (Interactive Login)**
This option requires a refresh token:
1. Use the auth wizard with your tenant ID, or
2. Follow the same manual steps as for personal accounts, but use your work email to sign in
@@ -146,7 +146,7 @@ This option requires a refresh token:
4. Set the refresh token you receive as `ONEDRIVE_REFRESH_TOKEN`
**Option B: Access OneDrive as a system service (App-only access)**
This option is for service accounts or automated systems with no user interaction:
1. In API permissions, add "Application permissions" instead of "Delegated permissions"
2. Add `Files.ReadWrite.All` permission under "Application permissions"
@@ -158,15 +158,15 @@ This option is for service accounts or automated systems with no user interactio
If you encounter errors during authentication:
1. **Check account permissions**:
1. **Check account permissions**:
- Ensure your Microsoft account has the necessary permissions to grant access
- For corporate accounts, check if your admin has restricted third-party app access
2. **Permission errors**:
2. **Permission errors**:
- Verify the app registration has the correct API permissions
- For corporate accounts, ensure an admin has consented to the permissions
3. **Refresh token expired**:
3. **Refresh token expired**:
- If uploads stop working, you can generate a new refresh token using the auth wizard
- Click on "Refresh Token" in the OneDrive setup page
+1 -1
View File
@@ -271,7 +271,7 @@ from locust import HttpUser, task, between
class APIUser(HttpUser):
wait_time = between(0.1, 0.5)
@task
def get_files(self):
self.client.get("/api/files")
+3 -3
View File
@@ -93,7 +93,7 @@ The current value displayed is **always** the effective value after applying pre
6. Successfully saved settings will show a 🟢 DB badge
7. If any changed setting requires a restart, you'll be notified
**Important**:
**Important**:
- You don't need to fill all fields - only change what you want to override
- Saving a setting to the database makes it override environment variables
- Empty fields are ignored (won't clear existing values)
@@ -196,7 +196,7 @@ Settings are stored in the `application_settings` table with:
### Can't Access Settings Page
- **Check authentication**: Make sure you're logged in
- **Check admin status**:
- **Check admin status**:
- Local auth: Verify `ADMIN_USERNAME` and `ADMIN_PASSWORD` are correct
- OAuth: Verify your user is in the admin group (configurable via `ADMIN_GROUP_NAME`)
- **Check logs**: Look for "Non-admin user attempted to access settings page" messages
@@ -243,5 +243,5 @@ python3 test_integration.py
## Related Documentation
- [Configuration Guide](./ConfigurationGuide.md) - Environment variable reference
- [Deployment Guide](./DeploymentGuide.md) - Production deployment
- [Deployment Guide](./DeploymentGuide.md) - Production deployment
- [API Documentation](./API.md) - Full API reference
+1 -1
View File
@@ -223,7 +223,7 @@ curl -X POST "http://localhost:8000/api/files/123/reprocess-with-cloud-ocr" \
```python
class FileRecord(Base):
__tablename__ = "files"
id = Column(Integer, primary_key=True)
filehash = Column(String, unique=True, nullable=False)
original_filename = Column(String) # User's original name
+4 -4
View File
@@ -1,7 +1,7 @@
# Repository Analysis & Improvement Summary
**Date:** 2026-02-06
**Repository:** christianlouis/DocuElevate
**Date:** 2026-02-06
**Repository:** christianlouis/DocuElevate
**Current Version:** v0.5.0
## Executive Summary
@@ -343,6 +343,6 @@ httpx>=0.26.0
---
**Prepared by:** GitHub Copilot Agent
**Review Status:** Ready for maintainer review
**Prepared by:** GitHub Copilot Agent
**Review Status:** Ready for maintainer review
**Recommended Action:** Merge and continue with TODO.md priorities
+1 -1
View File
@@ -61,7 +61,7 @@ Created comprehensive unit tests to verify:
1. **Test 1**: Original filename is preserved when parameter is provided
- Uploads a file with UUID-based path but provides original filename "Apostille Sverige.pdf"
- Verifies the database stores the original filename, not the UUID-based path
2. **Test 2**: Backward compatibility is maintained
- Calls `process_document` without the optional parameter
- Verifies it falls back to extracting filename from path
+1 -1
View File
@@ -170,7 +170,7 @@ Phase 1 (Current - MVP):
Settings: DB + ENV + DEFAULT
Encryption: Fernet (app-level)
UI: Custom settings page
Phase 2 (Production - Optional):
Settings: DB + ENV + DEFAULT (keep)
Secrets: HashiCorp Vault (add)
+1 -1
View File
@@ -155,7 +155,7 @@
**Status: 100% COMPLETE (Code Implementation)**
✅ Core settings functionality: 100% complete
✅ Encryption implementation: 100% complete
✅ Encryption implementation: 100% complete
✅ Setup wizard: 100% complete
⚠️ Testing: Manual testing recommended
⚠️ Documentation: Enhancement recommended
+1 -1
View File
@@ -121,7 +121,7 @@ Created comprehensive `docs/SettingsManagement.md` covering:
# Non-admin users
/settings @require_login @require_admin_access Redirect to /
# Admin users
# Admin users
/settings @require_login @require_admin_access Settings page renders
```
@@ -10,11 +10,11 @@ A comprehensive security audit was conducted on all file path operations in Docu
### 1. Critical: Path Traversal via GPT Metadata Filename
**Severity:** CRITICAL
**Location:** `app/tasks/embed_metadata_into_pdf.py` (line 144)
**Severity:** CRITICAL
**Location:** `app/tasks/embed_metadata_into_pdf.py` (line 144)
**Status:** ✅ FIXED
**Description:**
**Description:**
The `metadata["filename"]` field extracted by GPT was used directly in file path construction without sanitization. A malicious document could be crafted to make GPT return metadata containing path traversal sequences (e.g., `../../etc/passwd`), allowing file writes outside the intended directory.
**Attack Scenario:**
@@ -39,11 +39,11 @@ final_path = os.path.join(processed_dir, suggested_filename) # Safe
### 2. Medium: Insecure String-Based Path Validation
**Severity:** MEDIUM
**Location:** `app/tasks/embed_metadata_into_pdf.py` (line 188)
**Severity:** MEDIUM
**Location:** `app/tasks/embed_metadata_into_pdf.py` (line 188)
**Status:** ✅ FIXED
**Description:**
**Description:**
Used insecure string-based `startswith()` check to validate file paths before deletion. This approach is vulnerable to:
- Partial directory name matches
- Symlink attacks (symlinks not resolved)
@@ -78,11 +78,11 @@ if original_file_path.is_relative_to(workdir_tmp_resolved):
### 3. Medium: Insufficient GPT Filename Validation
**Severity:** MEDIUM
**Location:** `app/tasks/extract_metadata_with_gpt.py`
**Severity:** MEDIUM
**Location:** `app/tasks/extract_metadata_with_gpt.py`
**Status:** ✅ FIXED
**Description:**
**Description:**
While the GPT prompt requested specific filename format, there was no enforcement. GPT could return filenames with path separators or traversal patterns.
**Fix Applied:**
@@ -221,7 +221,7 @@ All identified path traversal vulnerabilities have been successfully remediated
---
**Audit Date:** February 10, 2026
**Auditor:** GitHub Copilot Agent
**Scope:** All Python file path operations
**Audit Date:** February 10, 2026
**Auditor:** GitHub Copilot Agent
**Scope:** All Python file path operations
**Next Review:** Recommended within 6 months or after significant file handling changes