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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
*.egg
*.egg-info/
dist/
build/

# Virtual Environment
venv/
env/
ENV/

# Testing
.pytest_cache/
.coverage
htmlcov/

# Flask
instance/
.webassets-cache
flask.log

# Progress data
progress.json

# IDE
.vscode/
.idea/
*.swp
*.swo
*~

# OS
.DS_Store
Thumbs.db
87 changes: 87 additions & 0 deletions main.py
Original file line number Diff line number Diff line change
@@ -1,0 +1,87 @@
from flask import Flask, jsonify, request
import json
import os
import threading

app = Flask(__name__)

# In-memory storage for progress data
progress_data = []

# Thread lock for synchronization
progress_lock = threading.Lock()

# File path for persistence
PROGRESS_FILE = 'progress.json'

# Load progress from file if it exists
def load_progress():
global progress_data
if os.path.exists(PROGRESS_FILE):
try:
with open(PROGRESS_FILE, 'r', encoding='utf-8') as f:
progress_data = json.load(f)
except Exception as e:
print(f"Error loading progress: {e}")
progress_data = []

# Save progress to file
def save_progress():
try:
with open(PROGRESS_FILE, 'w', encoding='utf-8') as f:
json.dump(progress_data, f, ensure_ascii=False, indent=2)
except Exception as e:
print(f"Error saving progress: {e}")

# Load progress on startup
load_progress()

@app.route('/')
def index():
"""Top page route"""
return jsonify({
"message": "Welcome to the Progress API",
"endpoints": {
"/": "This page",
"/api/progress": "GET - Retrieve progress data, POST - Save progress data"
}
})

@app.route('/api/progress', methods=['GET'])
def get_progress():
"""Get progress data"""
with progress_lock:
return jsonify({
"success": True,
"data": progress_data.copy()
})

@app.route('/api/progress', methods=['POST'])
def post_progress():
"""Save progress data"""
try:
data = request.get_json()

if not data:
return jsonify({
"success": False,
"error": "No data provided"
}), 400

with progress_lock:
progress_data.append(data)
save_progress()

return jsonify({
"success": True,
"message": "Progress saved successfully",
"data": data
}), 201
except Exception as e:
return jsonify({
"success": False,
"error": str(e)
}), 500
Comment thread Fixed
Comment on lines +81 to +84

Check warning

Code scanning / CodeQL

Information exposure through an exception Medium

Stack trace information
flows to this location and may be exposed to an external user.

Copilot Autofix

AI 9 months ago

To fix the issue, we should avoid returning the actual exception message str(e) to the user in the JSON response. Instead, we should:

  • Return a generic error message such as "An internal error occurred!" or similar in the API response. This prevents leakage of exception details.
  • Optionally, to help with debugging, log the exception (including stack trace) on the server side using Python's logging module or print(traceback.format_exc()).
  • The change is to the except block in the post_progress route, i.e., lines 81–83 of file main.py.
  • Additionally, import the traceback module (if logging a stack trace was chosen) and/or the logging module.
  • If a logging solution is not already set up, use print(traceback.format_exc()) for simplicity.

Suggested changeset 1
main.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/main.py b/main.py
--- a/main.py
+++ b/main.py
@@ -2,7 +2,7 @@
 import json
 import os
 import threading
-
+import traceback
 app = Flask(__name__)
 
 # In-memory storage for progress data
@@ -78,9 +78,10 @@
             "data": data
         }), 201
     except Exception as e:
+        print(traceback.format_exc())
         return jsonify({
             "success": False,
-            "error": str(e)
+            "error": "An internal error has occurred."
         }), 500
 
 if __name__ == '__main__':
EOF
@@ -2,7 +2,7 @@
import json
import os
import threading

import traceback
app = Flask(__name__)

# In-memory storage for progress data
@@ -78,9 +78,10 @@
"data": data
}), 201
except Exception as e:
print(traceback.format_exc())
return jsonify({
"success": False,
"error": str(e)
"error": "An internal error has occurred."
}), 500

if __name__ == '__main__':
Copilot is powered by AI and may make mistakes. Always verify output.

if __name__ == '__main__':
app.run(debug=False, host='0.0.0.0', port=5000)
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Flask==3.0.0
pytest==7.4.3
134 changes: 134 additions & 0 deletions test_main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import pytest
import json
import os
from main import app, progress_data, PROGRESS_FILE

@pytest.fixture
def client():
"""Create a test client for the Flask app"""
app.config['TESTING'] = True
with app.test_client() as client:
yield client

@pytest.fixture(autouse=True)
def cleanup():
"""Clean up progress data before and after each test"""
# Clear in-memory data
progress_data.clear()

# Remove progress file if it exists
if os.path.exists(PROGRESS_FILE):
os.remove(PROGRESS_FILE)

yield

# Clean up after test
progress_data.clear()
if os.path.exists(PROGRESS_FILE):
os.remove(PROGRESS_FILE)

def test_index_route(client):
"""Test the index (/) route"""
response = client.get('/')
assert response.status_code == 200
data = json.loads(response.data)
assert 'message' in data
assert 'endpoints' in data
assert data['message'] == "Welcome to the Progress API"

def test_get_progress_empty(client):
"""Test GET /api/progress with no data"""
response = client.get('/api/progress')
assert response.status_code == 200
data = json.loads(response.data)
assert data['success'] is True
assert data['data'] == []

def test_post_progress_valid(client):
"""Test POST /api/progress with valid data"""
test_data = {
"task": "Implement Flask API",
"status": "completed",
"percentage": 100
}

response = client.post('/api/progress',
data=json.dumps(test_data),
content_type='application/json')

assert response.status_code == 201
data = json.loads(response.data)
assert data['success'] is True
assert data['message'] == "Progress saved successfully"
assert data['data'] == test_data

def test_post_progress_no_data(client):
"""Test POST /api/progress with no data"""
response = client.post('/api/progress',
data=json.dumps(None),
content_type='application/json')

assert response.status_code == 400
data = json.loads(response.data)
assert data['success'] is False
assert 'error' in data

def test_get_progress_after_post(client):
"""Test GET /api/progress after posting data"""
test_data = {
"task": "Write tests",
"status": "in progress",
"percentage": 50
}

# Post data
client.post('/api/progress',
data=json.dumps(test_data),
content_type='application/json')

# Get data
response = client.get('/api/progress')
assert response.status_code == 200
data = json.loads(response.data)
assert data['success'] is True
assert len(data['data']) == 1
assert data['data'][0] == test_data

def test_multiple_progress_entries(client):
"""Test posting multiple progress entries"""
entries = [
{"task": "Task 1", "status": "completed"},
{"task": "Task 2", "status": "in progress"},
{"task": "Task 3", "status": "pending"}
]

for entry in entries:
response = client.post('/api/progress',
data=json.dumps(entry),
content_type='application/json')
assert response.status_code == 201

# Verify all entries are stored
response = client.get('/api/progress')
data = json.loads(response.data)
assert len(data['data']) == 3
assert data['data'] == entries

def test_progress_persistence(client):
"""Test that progress data persists to file"""
test_data = {"task": "Test persistence", "status": "saved"}

# Post data
client.post('/api/progress',
data=json.dumps(test_data),
content_type='application/json')

# Check that file was created
assert os.path.exists(PROGRESS_FILE)

# Read file and verify content
with open(PROGRESS_FILE, 'r', encoding='utf-8') as f:
file_data = json.load(f)

assert len(file_data) == 1
assert file_data[0] == test_data