[FIX] Uge session of debugging and code coverage.
This commit is contained in:
@@ -20,7 +20,52 @@ site is archived in `legacy/` and must not be modified.
|
||||
- Node.js 26 / npm 11
|
||||
- Svelte 5, SvelteKit 2, `@sveltejs/adapter-static`, Vite 5, Tailwind 3
|
||||
- PHP 8.5 (CLI built-in server in development)
|
||||
- Dependencies: `axios`, `pdfjs-dist`, `lucide-svelte` (front); `setasign/fpdi`, `setasign/fpdf`, `tecnickcom/tcpdf` (back)
|
||||
|
||||
## Dependencies
|
||||
|
||||
### Frontend (`partitions/package.json`)
|
||||
|
||||
Runtime:
|
||||
|
||||
| Package | Version |
|
||||
|---|---|
|
||||
| `axios` | ^1.6.0 |
|
||||
| `pdfjs-dist` | ^4.0.379 |
|
||||
|
||||
Dev:
|
||||
|
||||
| Package | Version |
|
||||
|---|---|
|
||||
| `svelte` | ^5.0.0 |
|
||||
| `@sveltejs/kit` | ^2.0.0 |
|
||||
| `@sveltejs/adapter-static` | ^3.0.0 |
|
||||
| `@sveltejs/vite-plugin-svelte` | ^4.0.0 |
|
||||
| `vite` | ^5.0.0 |
|
||||
| `typescript` | ^5.0.0 |
|
||||
| `svelte-check` | ^4.0.0 |
|
||||
| `tailwindcss` | ^3.4.0 |
|
||||
| `autoprefixer` | ^10.4.16 |
|
||||
| `postcss` | ^8.4.32 |
|
||||
|
||||
Install: `cd partitions && npm install`.
|
||||
|
||||
### Backend (`api/composer.json`)
|
||||
|
||||
| Package | Version |
|
||||
|---|---|
|
||||
| `setasign/fpdi` | ^2.6 (import de pages PDF) |
|
||||
| `setasign/fpdf` | ^1.8 (base PDF) |
|
||||
| `tecnickcom/tcpdf` | ^6.10 |
|
||||
|
||||
Install: `cd api && php composer.phar install` (le dossier `vendor/` est déjà présent).
|
||||
|
||||
PHP extensions requises (via `composer.lock`) : `gd`, `zlib`, `curl`. Déjà fournies
|
||||
ou activées avec les paquets Arch `php` + `php-gd`.
|
||||
|
||||
### Tooling de développement
|
||||
|
||||
- `xdebug` (paquet Arch `extra/xdebug`) — optionnel, utilisé pour mesurer la
|
||||
couverture de code du backend (`xdebug.mode=coverage`).
|
||||
|
||||
> PHP 8.5 note: nullable parameters MUST use explicit `?type` syntax
|
||||
> (e.g. `?string $x = null`). Implicit nullable is deprecated and pollutes API output.
|
||||
@@ -46,12 +91,14 @@ cd partitions
|
||||
npm install
|
||||
npm run dev # http://localhost:5173
|
||||
npm run build # outputs to partitions/build
|
||||
npm run check # svelte-check (0 errors / 0 warnings expected)
|
||||
npm run preview
|
||||
```
|
||||
|
||||
- `frontend` is a symlink to `partitions/build` (the deployed static site).
|
||||
- `VITE_API_URL` (build/dev env) selects the API base URL; falls back to
|
||||
`localhost:8000` (dev) or the production URL.
|
||||
- No ESLint / test framework is configured for the frontend.
|
||||
- `VITE_API_URL` is defined but currently unused (base URL is chosen from `import.meta.env.DEV`).
|
||||
|
||||
### Deploy
|
||||
|
||||
@@ -65,6 +112,17 @@ npm run preview
|
||||
|
||||
## Testing
|
||||
|
||||
### Run everything (single command)
|
||||
|
||||
```bash
|
||||
./test.sh
|
||||
```
|
||||
|
||||
Runs, in order: backend tests (`api/tests.php`), backend code coverage (Xdebug,
|
||||
if available), frontend `npm run check` (svelte-check), and the frontend E2E smoke
|
||||
test. It starts the API and dev servers if needed and stops them afterwards.
|
||||
"Test the project" means running `./test.sh`.
|
||||
|
||||
### PHP API tests
|
||||
|
||||
```bash
|
||||
@@ -80,6 +138,49 @@ php tests.php
|
||||
validation, INI injection, security headers.
|
||||
- `tests.php` is kept for development only and MUST NOT be shipped in the deploy zip.
|
||||
|
||||
### Code coverage (optional, requires Xdebug)
|
||||
|
||||
The test suite covers ~96% of `api/` non-vendor code (`Auth.php` and `router.php`
|
||||
at 100%, `ScoreScanner.php` +99%). The remaining uncovered lines are defensive
|
||||
I/O-failure branches (rate-limiter `flock`/`fopen` failures, missing
|
||||
`SCORES_PATH`, `OOM`/partial PHP upload errors, `createScore` rollback) that
|
||||
need OS-level fault injection to trigger.
|
||||
|
||||
```bash
|
||||
cd api
|
||||
rm -rf /tmp/ohmj_cov
|
||||
# Terminal 1: instrumented dev server
|
||||
php -d zend_extension=xdebug -d xdebug.mode=coverage \
|
||||
-d auto_prepend_file="$PWD/coverage-prepend.php" \
|
||||
-c php-upload.ini -S localhost:8000 router.php
|
||||
# Terminal 2: run tests through the instrumented server
|
||||
php -d zend_extension=xdebug -d xdebug.mode=coverage \
|
||||
-d auto_prepend_file="$PWD/coverage-prepend.php" tests.php
|
||||
# Then, from the repo root:
|
||||
SHOW_MISSING=1 php api/coverage-report.php \
|
||||
api/index.php api/router.php api/lib/Auth.php api/lib/ScoreScanner.php
|
||||
```
|
||||
|
||||
`coverage-prepend.php` / `coverage-report.php` are dev-only and excluded from the
|
||||
deploy archive.
|
||||
|
||||
### Frontend E2E smoke test (CDP, no dependency)
|
||||
|
||||
Requires the API (`:8000`) and the frontend dev server (`:5173`) to be running.
|
||||
|
||||
```bash
|
||||
cd partitions
|
||||
npm run test:e2e
|
||||
```
|
||||
|
||||
`tests/e2e-smoke.mjs` drives the system `chromium` through the DevTools Protocol:
|
||||
it logs in via the API, injects the session, then visits `/scores`, a score
|
||||
detail, the PDF viewer and `/admin`. It asserts that every API call returns
|
||||
`< 400`, that the SPA stays on each route, and that the PDF is fetched with an
|
||||
`Authorization` header (no token in the URL).
|
||||
|
||||
Env overrides: `API_URL`, `FRONT_URL`, `CHROME_PATH`, `LOGIN_USER`, `LOGIN_PASS`.
|
||||
|
||||
## Authentication
|
||||
|
||||
- Login: `POST /login` with `{"username":"admin","password":"password"}` (development).
|
||||
@@ -137,6 +238,9 @@ Admin only (`role === 'admin'`):
|
||||
|
||||
## Data Model (files)
|
||||
|
||||
> Full filename/directory convention: see [`NAMING.md`](NAMING.md). It is
|
||||
> normalized and MUST NOT be changed casually (backend + frontend depend on it).
|
||||
|
||||
```
|
||||
legacy/Scores/<NUM>/<PIECE>/<INSTRUMENT>/<VERSION>/<PARTIE>.pdf
|
||||
legacy/Scores/<NUM>/score.ini
|
||||
@@ -218,11 +322,20 @@ curl -s -I http://localhost:8000/login -X POST \
|
||||
-d '{"username":"admin","password":"password"}'
|
||||
```
|
||||
|
||||
> Known security findings from the latest review (not yet fixed): static file
|
||||
> passthrough in `api/router.php` exposes `.env`/`users.json`; `deleteScoreFile`
|
||||
> lacks path containment; `api/.env` is tracked by git; JWT is standard base64
|
||||
> (not base64url) and expiry is optional; stored XSS via the `ressource` link.
|
||||
> See the project issue tracker / recent review notes.
|
||||
> Security fixes applied recently: `api/router.php` no longer serves files
|
||||
> statically (`.env`/`config/users.json` are not reachable); `deleteScoreFile`
|
||||
> enforces `realpath()` containment and only deletes `.pdf`; `api/.env` and
|
||||
> `partitions/.env` are untracked/gitignored (rotate the secret since it remains
|
||||
> in git history); JWT uses base64url, requires `exp` and validates `alg`;
|
||||
> credentials errors are generic; the `ressource` link rejects non-http(s) URLs.
|
||||
>
|
||||
> Known findings still open: default `admin`/`password` credentials; login rate
|
||||
> limiter is race-prone (no `flock`) and `/api/login` bypasses it; CORS falls
|
||||
> back to `*` for unknown origins; `GET /admin/scores/:id` passes extra
|
||||
> arguments dropped by `ScoreScanner::updateScore` (so `ressource` is not
|
||||
> persisted); watermarking only keeps page 1 of multi-page PDFs; `createScore`
|
||||
> and `uploadPdf` do not validate path segments; `updateScore`/`updatePieces`
|
||||
> do not sanitize INI values.
|
||||
|
||||
## Temporary Files
|
||||
|
||||
|
||||
Reference in New Issue
Block a user