Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
c9679de
Add ruff
moshekaplan Nov 9, 2025
3cd3ac9
Add dependabot config
moshekaplan Nov 9, 2025
b635216
Add dependabot config
moshekaplan Nov 9, 2025
fe31067
Add dependabot config
moshekaplan Nov 9, 2025
2d3ac6c
Merge pull request #1 from moshekaplan/add_dependabot
moshekaplan Nov 9, 2025
cea0b15
Bump actions/setup-python from 5 to 6 in /.github/workflows
dependabot[bot] Nov 9, 2025
42ca78f
Bump actions/checkout from 4 to 5 in /.github/workflows
dependabot[bot] Nov 9, 2025
a1f831a
Bump cryptography from 45.0.6 to 46.0.3
dependabot[bot] Nov 9, 2025
207f217
Bump pytest from 8.4.1 to 9.0.0
dependabot[bot] Nov 9, 2025
207d09c
Bump cffi from 1.17.1 to 2.0.0
dependabot[bot] Nov 9, 2025
a66e7cf
Add pytest
moshekaplan Nov 9, 2025
abe01c4
Add pytest
moshekaplan Nov 9, 2025
c34fb36
Merge pull request #7 from moshekaplan/add_pytest
moshekaplan Nov 9, 2025
e5313ad
Merge pull request #6 from moshekaplan/dependabot/uv/cffi-2.0.0
moshekaplan Nov 9, 2025
ab0636b
Merge pull request #2 from moshekaplan/dependabot/github_actions/dot-…
moshekaplan Nov 9, 2025
6ea3611
Merge pull request #3 from moshekaplan/dependabot/github_actions/dot-…
moshekaplan Nov 9, 2025
5bf83ea
Merge pull request #4 from moshekaplan/dependabot/uv/cryptography-46.0.3
moshekaplan Nov 9, 2025
2c5b7ce
Merge pull request #5 from moshekaplan/dependabot/uv/pytest-9.0.0
moshekaplan Nov 9, 2025
805c52b
Add typing job (with failure)
moshekaplan Nov 9, 2025
507aa8d
Pytest: Enable more
moshekaplan Nov 9, 2025
a8122fc
Merge pull request #8 from moshekaplan/add_typing
moshekaplan Nov 9, 2025
4cebdc7
Clean arg parsing
moshekaplan Nov 9, 2025
0f902ad
Merge pull request #9 from moshekaplan/clean_args
moshekaplan Nov 9, 2025
e14f86a
Update README.md
moshekaplan Nov 9, 2025
0a998c4
Remove engine_last var
moshekaplan Nov 9, 2025
50ec507
args.limit_timestamps
moshekaplan Nov 9, 2025
386eb13
Merge pull request #10 from moshekaplan/clean_argparsing_further
moshekaplan Nov 9, 2025
2adaa19
Merge pull request #11 from moshekaplan/remove_engine_last
moshekaplan Nov 9, 2025
646a9c1
demonstrate enumerate
moshekaplan Nov 9, 2025
4e4f7eb
Merge pull request #12 from moshekaplan/clean_loop
moshekaplan Nov 9, 2025
e77deea
Improve logging
moshekaplan Nov 9, 2025
0366f2c
Add missing )
moshekaplan Nov 9, 2025
1c14f30
Merge pull request #13 from moshekaplan/improve_logging
moshekaplan Nov 9, 2025
c26c857
Update typing.yml
moshekaplan Nov 9, 2025
b8f495a
Move file validation to separate function
moshekaplan Nov 9, 2025
91d7a50
Update typing.yml
moshekaplan Nov 9, 2025
77f45f1
Update typing.yml
moshekaplan Nov 9, 2025
bee0999
Update typing.yml
moshekaplan Nov 9, 2025
91f5e09
Merge pull request #15 from moshekaplan/moshekaplan-patch-1
moshekaplan Nov 9, 2025
8c8c48a
Merge pull request #14 from moshekaplan/move_isvalidfile
moshekaplan Nov 9, 2025
8f11aa3
Prevent XSS on pagination
moshekaplan Nov 10, 2025
a73f457
Try to remove XSS form fileset
moshekaplan Nov 10, 2025
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
32 changes: 32 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
version: 2

# Security sensitive updates (ie: upgrades which fix vulnerabilities)
# aren't affected by any filtering we define below so this is
# purely to do with keeping dependencies compatible and supported.
updates:

# These entries are for our development dependencies
# which we want to keep up to date but only really
# care about major versions for supportability.
- package-ecosystem: "github-actions"
directory: "/.github/workflows"
schedule:
interval: "daily"
ignore:
- dependency-name: "*"
update-types:
- "version-update:semver-minor"
- "version-update:semver-patch"

- package-ecosystem: "uv"
directory: "/"
schedule:
interval: "daily"
allow:
- dependency-type: "direct"
- dependency-type: "indirect"
ignore:
- dependency-name: "*"
update-types:
- "version-update:semver-minor"
- "version-update:semver-patch"
28 changes: 28 additions & 0 deletions .github/workflows/pytest.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Run Pytest

on:
push:
pull_request:
workflow_dispatch:

jobs:
test:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v3

- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.x'

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install pytest

- name: "Run tests"
run: |
pytest tests/
18 changes: 18 additions & 0 deletions .github/workflows/ruff.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: CI
on: push
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Install Python
uses: actions/setup-python@v6
with:
python-version: "3.11"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install ruff
# Update output format to enable automatic inline annotations.
- name: Run Ruff
run: ruff check --output-format=github .
27 changes: 27 additions & 0 deletions .github/workflows/typing.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: Validate Python Typing (Experimental)

on:
workflow_dispatch:

jobs:
type-check:
runs-on: ubuntu-latest
continue-on-error: true # Allow graceful failure

Choose a reason for hiding this comment

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

the commit message says "with failure" but this line seems to specifically not fail in case of error, which I guess is the opposite; do I misunderstand the commit message?


steps:
- name: Checkout code
uses: actions/checkout@v3

- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.x'

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install mypy types-PyMySQL types-requests types-Authlib
- name: Run mypy type checks
run: mypy .

4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ GITHUB_CLIENT_SECRET=github_client_secret_from_oauth_app
FLASK_SECRET_KEY=any_random_key
```

### 10. Local Development instance:
`uv run -m src.app.fileset`

## Deployment Guide
The Flask application is deployed using `mod_wsgi`, an Apache module for hosting WSGI applications.
Assuming Apache and mod_wsgi are already installed:
Expand Down Expand Up @@ -183,3 +186,4 @@ http://localhost:5000/validate
```
with the request body in JSON format as shown in `sample_json_request.json` present in the root directory.


41 changes: 30 additions & 11 deletions src/app/fileset.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
from collections import defaultdict
from datetime import timedelta
import html as html_lib
import json
import os
import re
import urllib.parse

import difflib

from flask import (
Flask,
request,
Expand All @@ -10,20 +20,14 @@
session,
)


import requests
from datetime import timedelta
import json
import html as html_lib
import os

from src.app.pagination import create_page
import difflib

import src.app.env_loader # noqa
from src.scripts.db_functions import (
insert_game,
get_all_related_filesets,
convert_log_text_to_links,

Choose a reason for hiding this comment

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

It's a fine change, but moving the convert_log_text_to_links function is not described by commit message "Try to remove XSS from fileset"; should this be a separate commit?

Copy link
Author

Choose a reason for hiding this comment

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

Probably. I had moved it as part of doing the XSS sanitization.

user_integrity_check,
create_log,
delete_original_fileset,
Expand All @@ -32,7 +36,6 @@
insert_filechecksum,
)
from src.utils.db_config import db_connect, db_connect_root
from collections import defaultdict
from src.scripts.schema import init_database
from src.app.validate_user_payload import validate_user_payload
from src.utils.cookie import get_filesets_per_page, get_logs_per_page
Expand Down Expand Up @@ -126,6 +129,21 @@ def clear_database():
return redirect("/")


def convert_log_text_to_links(log_text):
log_text = re.sub(
r"Fileset:(\d+)", r'<a href="/fileset?id=\1">Fileset:\1</a>', log_text
)
log_text = re.sub(
r"user:(\w+)", r'<a href="/log?search=user:\1">user:\1</a>', log_text
)
log_text = re.sub(
r"Transaction:(\d+)",
r'<a href="/transaction?id=\1">Transaction:\1</a>',
log_text,
)
return log_text


@app.route("/fileset", methods=["GET", "POST"])
@role_required("Admin", "Moderator", "Read Only")
def fileset():
Expand Down Expand Up @@ -511,7 +529,8 @@ def fileset():
for column in sortable_columns:
if column not in ["id"]:
vars = "&".join(
[f"{k}={v}" for k, v in request.args.items() if k != "sort"]
f"{urllib.parse.quote_plus(str(k))}={urllib.parse.quote_plus(str(v))}"
for k, v in request.args.items() if k != "sort"
)
sort_link = f"{column}"
if sort == column:
Expand Down Expand Up @@ -599,7 +618,7 @@ def fileset():
)
log_text = cursor.fetchone()["text"]
log_text = convert_log_text_to_links(log_text)
html += f"<td><a href='logs?id={h['log']}'>Log {h['log']}</a>: {log_text}</td>\n"
html += f"<td><a href='logs?id={html_lib.escape(h['log'])}'>Log {html_lib.escape(h['log'])}</a>: {html_lib.escape(log_text)}</td>\n"
else:
html += "<td>No log available</td>\n"
html += "</tr>\n"
Expand All @@ -614,7 +633,7 @@ def fileset():
cursor.execute("SELECT `text` FROM log WHERE id = %s", (h["log"],))
log_text = cursor.fetchone()["text"]
log_text = convert_log_text_to_links(log_text)
html += f"<td><a href='logs?id={h['log']}'>Log {h['log']}</a>: {log_text}</td>\n"
html += f"<td><a href='logs?id={html_lib.escape(h['log'])}'>Log {html_lib.escape(h['log'])}</a>: {html_lib.escape(log_text)}</td>\n"
else:
html += "<td>No log available</td>\n"
html += "</tr>\n"
Expand Down
Loading