Commit Graph

4 Commits

Author SHA1 Message Date
8798105aa1 Grade against 3.14 too, not just run on it
The pre-commit workflow already installs `python-version: "3.x"`, but ruff was
still grading the archive against py310 -- so it kept withholding the pyupgrade
and type-checking fixes that only become safe at the newer target.
`pin_ci_python.py` rewrites the knob.

The 17 findings that appeared are what the stale target was hiding:
`datetime.timezone.utc` where `datetime.UTC` is now correct (UP017), and 14
imports used only in annotations that belong under `TYPE_CHECKING` (TC002,
TC003) -- safe here precisely because 3.14's PEP 649 defers annotation
evaluation, which is the same reason ruff would not offer them at py310.

`ruff check` and `ruff format --check` are clean again, so the zero-findings
state this repo reached earlier today holds at the new target.

Still contradictory and deliberately untouched: the four
`Programming/ERSMS-project/*/Dockerfile` files say `FROM python:3.10-slim`.
They build an archived coursework service against its own era's pinned
dependencies, and nothing in this repo runs them; bumping the base image would
be a rewrite of that project, not a lint-target change.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SfnJmxxsZ534AKk16rC2Gr
2026-08-29 11:55:43 +02:00
f58f55f68b ERSMS-project: zero findings, and the SQL is parameterised now
Some checks are pending
md-naming / markdown naming convention (push) Waiting to run
pre-commit / pre-commit (push) Waiting to run
runnability / runnability (push) Waiting to run
156 ruff findings to 0. That takes the whole archive to 0, from 9,281.

Six of those findings were SQL injection, and they were the real ones. The
connector interpolated a username and an OAuth id straight out of the URL into
f-string SQL. With psycopg2 installed, the difference is not theoretical:

  username = "x'; DROP TABLE users; --"
  old:  select * from users where username='x'; DROP TABLE users; --';
  new:  select * from users where username='x''; DROP TABLE users; --';

The old form is two statements and the second one runs. The new one is a
parameter, so the whole thing stays a string literal. Every query in that file
is parameterised now.

`get_recommendations` also called
`cursor.execute("... oauth_ID='{}'", oauth_ID)`, which is wrong twice over:
psycopg2 wants %s rather than {}, and its second argument must be a sequence,
not a bare string. That route could never have worked.

Ten blind `except Exception` handlers turned every programming error into a
500 with the message hidden. They are now the exceptions each block can
actually raise -- verified against the installed libraries, where
InvalidIdTokenError and ExpiredIdTokenError really are FirebaseError
subclasses -- and the handlers log a traceback instead of printing the
exception's str().

Three services bound `host="localhost"`. Each of them runs in a container with
a published port, on a compose bridge network, so binding loopback makes them
unreachable from both the host and their siblings. All four now read
ERSMS_HOST, which docker-compose sets to 0.0.0.0, and default to loopback when
run outside Docker. Flask's debug console executes arbitrary code, so that is
opt-in via FLASK_DEBUG too.

`movie_recommender.py` fitted the model at import: reading two CSVs and
building a 4803x4803 similarity matrix as a side effect of `import`. It failed
outright here, since the datasets are not committed. It is in `main()` now, and
the module imports cleanly. `error_decorator` was dead code that swallowed its
wrapped function's return value; it is gone.

Verified: all four modules import (the backend still needs its Firebase
credential JSON, which is not committed, exactly as before), the recommender's
helpers still pick the director out of a crew list, trim cast to three, fold
"Tom Hanks" to "tomhanks" and join a soup in the same order, and every route
parameter rename was matched by the URL rule it comes from.

Three of the four services are clean under mypy --strict. The backend keeps
four errors: flask-sqlalchemy builds `db.Model` dynamically, so `--strict`
refuses to subclass it. Migrating to a typed DeclarativeBase would rewrite both
models in an app that cannot be run here, so those four are reported in
TODO-refactor-remaining.md rather than hidden.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-29 08:30:01 +02:00
bd24dd57ea Hold the coursework to the same lint bar as the tooling
kuhy overruled the "do not fix coursework to be better than it was submitted"
rule: git history is the archive, so the working tree can be clean. This lands
the config and the mechanical half of the cleanup -- 9,281 ruff findings under
the fleet config down to 3,686, with no per-file-ignores anywhere.

What is in here:

- pyproject.toml, the first one in this repo. select = ["ALL"], mypy strict,
  and the vendored list mirrored into ruff exclude and coverage omit. Five
  rules are off and each says why; CPY001 is the only judgement call, because
  stamping a copyright header onto 137 university assignments would assert a
  licence that was never claimed. No hook is wired up yet -- a gate lands only
  once its subject is clean.

- ruff format + the safe fixes, then a second pass over the docstring rules
  ruff marks unsafe (they only edit docstring text). 108 files.

- TRAK/sightpy is vendored, not coursework: it is rafael-fuente/Python-Raytracer
  (BSD 3-Clause). Verified against a fresh upstream clone with line endings
  normalised -- 30 of 32 files byte-identical, ray.py and scene.py carrying a
  12- and 13-line local patch that counts rays for the report. 35 files that
  should never have been linted, now excluded and restored.

- WDWR, SPD, MOM and ECRYPT are fully clean, by hand and verified by running
  them: WDWR's three plot scripts print the same statistics as before, MOM's
  PuLP model solves to the same cost. WDWR's graph.py had a 342-character CSV
  header embedded as a string literal, which cannot be wrapped -- the data
  moved to data/pareto_front.csv. Two 0-byte .py stubs are deleted; an empty
  file is not a deliverable and git still has it.

Three harness bugs found by actually running things:

- `run` now forces MPLBACKEND=Agg. TRAK finished its ray trace in 37 seconds
  and then sat for 45 minutes: plt.show() had opened an image viewer and was
  waiting for someone to close the window.
- TRAK's main.py only pops that viewer with --show now, and its runner writes
  to a gitignored build/ via the new --entry-args. The default output path is
  outputs/output.png, which is TRACKED -- a plain run overwrote a submitted
  deliverable.
- course_lib.sh was 357 lines, over this repo's own cap. Split into
  course_probe.sh and course_run.sh.

Verified: ECOTE 26 tests pass, ECRYPT_PROJECT 99 pass, TRAK renders
cornell_box in 37s and exits 0, every module compiles, and every import ruff
removed was checked to be genuinely unused.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0172dj34FDpao6wsix8ZuCzE
2026-08-28 19:53:04 +02:00
838184c85b Add 'Programming/ERSMS-project/' from commit 'd060e8285ad6f3dddde51a842f2c8498138afb0b'
git-subtree-dir: Programming/ERSMS-project
git-subtree-mainline: 7861d69ae9
git-subtree-split: d060e8285a
2026-02-06 22:14:41 +01:00