Add SECURITY.md, issue templates, update CONTRIBUTING
This commit is contained in:
@@ -0,0 +1,87 @@
|
|||||||
|
name: Bug report
|
||||||
|
description: Something isn't working as expected
|
||||||
|
labels: [bug]
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
Thanks for taking the time to report a bug. The more detail you provide, the faster it gets fixed.
|
||||||
|
|
||||||
|
- type: dropdown
|
||||||
|
id: area
|
||||||
|
attributes:
|
||||||
|
label: Area
|
||||||
|
options:
|
||||||
|
- Falling notes / visualization
|
||||||
|
- Sheet music rendering
|
||||||
|
- Piano keyboard
|
||||||
|
- Audio / playback
|
||||||
|
- MIDI input (hardware keyboard)
|
||||||
|
- File import (MIDI)
|
||||||
|
- File import (MusicXML / MXL)
|
||||||
|
- File import (PDF)
|
||||||
|
- Practice tools (loop, speed trainer, wait mode, metronome)
|
||||||
|
- Settings / UI
|
||||||
|
- Other
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: description
|
||||||
|
attributes:
|
||||||
|
label: What happened?
|
||||||
|
description: A clear description of the bug.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: reproduction
|
||||||
|
attributes:
|
||||||
|
label: Steps to reproduce
|
||||||
|
placeholder: |
|
||||||
|
1. Import a MIDI file
|
||||||
|
2. Enable wait mode
|
||||||
|
3. ...
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: expected
|
||||||
|
attributes:
|
||||||
|
label: What did you expect?
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: dropdown
|
||||||
|
id: how
|
||||||
|
attributes:
|
||||||
|
label: How are you running the app?
|
||||||
|
options:
|
||||||
|
- pnpm dev (local)
|
||||||
|
- Docker
|
||||||
|
- Other
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: input
|
||||||
|
id: browser
|
||||||
|
attributes:
|
||||||
|
label: Browser + version
|
||||||
|
placeholder: "Chrome 124, Edge 123, ..."
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: input
|
||||||
|
id: os
|
||||||
|
attributes:
|
||||||
|
label: OS
|
||||||
|
placeholder: "macOS 14, Windows 11, ..."
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: logs
|
||||||
|
attributes:
|
||||||
|
label: Console errors (if any)
|
||||||
|
description: Open DevTools → Console and paste anything relevant.
|
||||||
|
render: shell
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
blank_issues_enabled: false
|
||||||
|
contact_links:
|
||||||
|
- name: Security vulnerability
|
||||||
|
url: https://github.com/gigliof/bach-to-basics/security/advisories/new
|
||||||
|
about: Please report security issues privately via GitHub's vulnerability reporting.
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
name: Feature request
|
||||||
|
description: Suggest an idea or improvement
|
||||||
|
labels: [enhancement]
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
Got an idea? Check the [roadmap](https://github.com/gigliof/bach-to-basics#roadmap) first — some features are already planned.
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: problem
|
||||||
|
attributes:
|
||||||
|
label: What problem does this solve?
|
||||||
|
description: Describe the use case or frustration behind the request.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: solution
|
||||||
|
attributes:
|
||||||
|
label: Proposed solution
|
||||||
|
description: What would you like to see? Sketches, examples, or references to similar tools are welcome.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: alternatives
|
||||||
|
attributes:
|
||||||
|
label: Alternatives you've considered
|
||||||
|
description: Any workarounds you're currently using?
|
||||||
|
|
||||||
|
- type: dropdown
|
||||||
|
id: area
|
||||||
|
attributes:
|
||||||
|
label: Area
|
||||||
|
options:
|
||||||
|
- Falling notes / visualization
|
||||||
|
- Sheet music rendering
|
||||||
|
- Piano keyboard
|
||||||
|
- Audio / playback
|
||||||
|
- MIDI input
|
||||||
|
- File import / export
|
||||||
|
- Practice tools
|
||||||
|
- Settings / UI
|
||||||
|
- Performance
|
||||||
|
- Other
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
+9
-5
@@ -31,14 +31,18 @@ pnpm dev # starts frontend (5173) + backend (8000) concurrently
|
|||||||
|
|
||||||
## Before opening a PR
|
## Before opening a PR
|
||||||
|
|
||||||
1. `pnpm --filter frontend exec tsc --noEmit`: type check
|
1. `pnpm lint`: ESLint (must pass with zero warnings)
|
||||||
2. `pnpm test`: frontend unit tests
|
2. `pnpm --filter frontend exec tsc --noEmit`: type check
|
||||||
3. If you touched the backend: `cd backend && python -m py_compile $(find . -name "*.py" -not -path "./.venv/*")`
|
3. `pnpm test`: frontend unit tests
|
||||||
4. Verify the dev server still boots cleanly (`pnpm dev`)
|
4. If you touched the backend: `cd backend && python -m py_compile $(find . -name "*.py" -not -path "./.venv/*")`
|
||||||
|
5. Verify the dev server still boots cleanly (`pnpm dev`)
|
||||||
|
|
||||||
|
The pre-commit hook runs ESLint + Prettier automatically on staged files, so formatting is handled for you.
|
||||||
|
|
||||||
## Reporting bugs
|
## Reporting bugs
|
||||||
|
|
||||||
Include:
|
Include:
|
||||||
|
|
||||||
- Browser + OS version
|
- Browser + OS version
|
||||||
- Whether you're running via `pnpm dev` or Docker
|
- Whether you're running via `pnpm dev` or Docker
|
||||||
- Steps to reproduce
|
- Steps to reproduce
|
||||||
@@ -46,4 +50,4 @@ Include:
|
|||||||
|
|
||||||
## Security
|
## Security
|
||||||
|
|
||||||
Found a vulnerability? Please don't open a public issue. Reach out via the contact info on the repo owner's GitHub profile.
|
Found a vulnerability? Please don't open a public issue. See [SECURITY.md](SECURITY.md) for how to report it privately.
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ A browser-based piano practice tool. Drop in a **MIDI file**, a **MusicXML score
|
|||||||

|

|
||||||
|
|
||||||
| Sheet music | All views | Settings |
|
| Sheet music | All views | Settings |
|
||||||
|---|---|---|
|
| ----------------------------------------- | ------------------------------------- | ----------------------------------------- |
|
||||||
| [](docs/screenshot-sheet.png) | [](docs/screenshot-all.png) | [](docs/screenshot-settings.png) |
|
|  |  |  |
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
@@ -31,6 +31,7 @@ A browser-based piano practice tool. Drop in a **MIDI file**, a **MusicXML score
|
|||||||
Drag-and-drop anywhere on the window, or use the import button.
|
Drag-and-drop anywhere on the window, or use the import button.
|
||||||
|
|
||||||
> ⚠️ **A note on import accuracy.** Both PDF-to-MIDI (optical music recognition) and MIDI-to-sheet-music (notation reconstruction) are inherently lossy conversions. Expect some inconsistencies:
|
> ⚠️ **A note on import accuracy.** Both PDF-to-MIDI (optical music recognition) and MIDI-to-sheet-music (notation reconstruction) are inherently lossy conversions. Expect some inconsistencies:
|
||||||
|
>
|
||||||
> - **PDF imports** can mis-read notes, dynamics, ornaments, articulation, and voicing, especially with low-resolution scans, handwritten scores, or complex layouts. Audiveris is the best open-source OMR engine available, but no engine matches a careful human transcription.
|
> - **PDF imports** can mis-read notes, dynamics, ornaments, articulation, and voicing, especially with low-resolution scans, handwritten scores, or complex layouts. Audiveris is the best open-source OMR engine available, but no engine matches a careful human transcription.
|
||||||
> - **MIDI imports** produce sheet music by re-deriving notation from raw note timings. MIDI doesn't encode key signatures, beaming, voicing, articulation, or enharmonic spelling, so the rendered sheet is an interpretation, not a faithful reproduction of the composer's original score.
|
> - **MIDI imports** produce sheet music by re-deriving notation from raw note timings. MIDI doesn't encode key signatures, beaming, voicing, articulation, or enharmonic spelling, so the rendered sheet is an interpretation, not a faithful reproduction of the composer's original score.
|
||||||
>
|
>
|
||||||
@@ -68,7 +69,7 @@ Drag-and-drop anywhere on the window, or use the import button.
|
|||||||
## Tech stack
|
## Tech stack
|
||||||
|
|
||||||
| Layer | Technology |
|
| Layer | Technology |
|
||||||
|-------|-----------|
|
| ---------------- | ---------------------------------------------------------------- |
|
||||||
| Frontend | React 19, TypeScript, Vite, Tailwind CSS |
|
| Frontend | React 19, TypeScript, Vite, Tailwind CSS |
|
||||||
| Rendering | PixiJS 8 (falling notes + piano), AlphaTab (sheet music) |
|
| Rendering | PixiJS 8 (falling notes + piano), AlphaTab (sheet music) |
|
||||||
| Audio | Tone.js (scheduling), smplr (sampled instruments), Web Audio API |
|
| Audio | Tone.js (scheduling), smplr (sampled instruments), Web Audio API |
|
||||||
@@ -130,13 +131,13 @@ Without the JAR, MIDI / MusicXML import still works, only PDF import is unavaila
|
|||||||
All backend settings come from environment variables. Copy `.env.example` to `.env` and edit.
|
All backend settings come from environment variables. Copy `.env.example` to `.env` and edit.
|
||||||
|
|
||||||
| Variable | Default | Description |
|
| Variable | Default | Description |
|
||||||
|----------|---------|-------------|
|
| -------------------------- | ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| `ALLOWED_ORIGINS` | `http://localhost:5173` | Comma-separated list of allowed CORS origins |
|
| `ALLOWED_ORIGINS` | `http://localhost:5173` | Comma-separated list of allowed CORS origins |
|
||||||
| `BACKEND_API_KEY` | *(unset = open)* | When set, all requests must include `X-API-Key: <value>` |
|
| `BACKEND_API_KEY` | _(unset = open)_ | When set, all requests must include `X-API-Key: <value>` |
|
||||||
| `REQUIRE_AUTH` | *(unset)* | Set to `1` to make the server refuse to start if `BACKEND_API_KEY` is not configured — useful for preventing accidental open deployments |
|
| `REQUIRE_AUTH` | _(unset)_ | Set to `1` to make the server refuse to start if `BACKEND_API_KEY` is not configured — useful for preventing accidental open deployments |
|
||||||
| `RATE_LIMIT_PER_MIN` | `60` | Max requests per IP per minute. `0` disables it |
|
| `RATE_LIMIT_PER_MIN` | `60` | Max requests per IP per minute. `0` disables it |
|
||||||
| `HEAVY_RATE_LIMIT_PER_MIN` | `10` | Stricter limit applied to expensive endpoints (`/omr/`, `/youtube/`) |
|
| `HEAVY_RATE_LIMIT_PER_MIN` | `10` | Stricter limit applied to expensive endpoints (`/omr/`, `/youtube/`) |
|
||||||
| `TRUSTED_PROXY_IPS` | *(unset)* | Comma-separated IPs of trusted reverse proxies. When set, the real client IP is read from `X-Forwarded-For` instead of the connection address |
|
| `TRUSTED_PROXY_IPS` | _(unset)_ | Comma-separated IPs of trusted reverse proxies. When set, the real client IP is read from `X-Forwarded-For` instead of the connection address |
|
||||||
| `MUSIC21_TIMEOUT_S` | `60` | Hard timeout (seconds) for music21 conversions (MIDI-to-MusicXML, MusicXML-to-MIDI). Raise for very dense scores |
|
| `MUSIC21_TIMEOUT_S` | `60` | Hard timeout (seconds) for music21 conversions (MIDI-to-MusicXML, MusicXML-to-MIDI). Raise for very dense scores |
|
||||||
| `AUDIVERIS_TIMEOUT_S` | `120` | Hard timeout (seconds) for Audiveris OMR. Raise for large or multi-page PDFs |
|
| `AUDIVERIS_TIMEOUT_S` | `120` | Hard timeout (seconds) for Audiveris OMR. Raise for large or multi-page PDFs |
|
||||||
|
|
||||||
@@ -188,30 +189,35 @@ These will become user-facing in upcoming releases. PRs welcome.
|
|||||||
<summary><strong>Sheet music doesn't render after loading a MIDI file</strong></summary>
|
<summary><strong>Sheet music doesn't render after loading a MIDI file</strong></summary>
|
||||||
|
|
||||||
The MIDI-to-MusicXML conversion runs on the backend. Check that the backend is up (`curl http://localhost:8000/health` should return OK) and look at the backend terminal for `music21` errors. Very dense scores can hit the `MUSIC21_TIMEOUT_S` (default 60s); raise it if needed.
|
The MIDI-to-MusicXML conversion runs on the backend. Check that the backend is up (`curl http://localhost:8000/health` should return OK) and look at the backend terminal for `music21` errors. Very dense scores can hit the `MUSIC21_TIMEOUT_S` (default 60s); raise it if needed.
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary><strong>No sound from the on-screen piano</strong></summary>
|
<summary><strong>No sound from the on-screen piano</strong></summary>
|
||||||
|
|
||||||
The first interaction (any click) wakes the audio context. If you still hear nothing, open DevTools > Console and look for errors related to `AudioContext` or sample fetches from `danigb.github.io` / `gleitz.github.io`. Some corporate networks block these CDNs.
|
The first interaction (any click) wakes the audio context. If you still hear nothing, open DevTools > Console and look for errors related to `AudioContext` or sample fetches from `danigb.github.io` / `gleitz.github.io`. Some corporate networks block these CDNs.
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary><strong>"WebMIDI not supported" on Firefox or Safari</strong></summary>
|
<summary><strong>"WebMIDI not supported" on Firefox or Safari</strong></summary>
|
||||||
|
|
||||||
Use Chrome, Edge, Brave, or Arc. Firefox and Safari haven't implemented Web MIDI.
|
Use Chrome, Edge, Brave, or Arc. Firefox and Safari haven't implemented Web MIDI.
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary><strong>PDF import says "OMR engine not available"</strong></summary>
|
<summary><strong>PDF import says "OMR engine not available"</strong></summary>
|
||||||
|
|
||||||
Either Audiveris isn't installed, or `audiveris.jar` isn't at `backend/bin/audiveris.jar`, or Java 17+ isn't on the PATH. See the PDF import section above. MIDI and MusicXML import are unaffected.
|
Either Audiveris isn't installed, or `audiveris.jar` isn't at `backend/bin/audiveris.jar`, or Java 17+ isn't on the PATH. See the PDF import section above. MIDI and MusicXML import are unaffected.
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary><strong>Docker build fails on the frontend</strong></summary>
|
<summary><strong>Docker build fails on the frontend</strong></summary>
|
||||||
|
|
||||||
The frontend Dockerfile uses the repo root as build context to read `pnpm-workspace.yaml` and `shared/`. If you've moved or renamed those, update `docker-compose.yml`'s `build.context` accordingly.
|
The frontend Dockerfile uses the repo root as build context to read `pnpm-workspace.yaml` and `shared/`. If you've moved or renamed those, update `docker-compose.yml`'s `build.context` accordingly.
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
@@ -225,4 +231,4 @@ See [CONTRIBUTING.md](CONTRIBUTING.md). Bug reports and PRs welcome.
|
|||||||
Third-party components (AlphaTab, music21, etc.) keep their own licenses, see [NOTICE](NOTICE) for the rundown. Notably:
|
Third-party components (AlphaTab, music21, etc.) keep their own licenses, see [NOTICE](NOTICE) for the rundown. Notably:
|
||||||
|
|
||||||
- **AlphaTab** is MPL-2.0 (per-file copyleft), fine for both open source and commercial use as long as you don't modify AlphaTab's own files.
|
- **AlphaTab** is MPL-2.0 (per-file copyleft), fine for both open source and commercial use as long as you don't modify AlphaTab's own files.
|
||||||
- **Audiveris** is AGPL-3.0 and is *not* bundled, users download it separately, so this repo doesn't inherit AGPL obligations.
|
- **Audiveris** is AGPL-3.0 and is _not_ bundled, users download it separately, so this repo doesn't inherit AGPL obligations.
|
||||||
|
|||||||
+28
@@ -0,0 +1,28 @@
|
|||||||
|
# Security Policy
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
Bach to Basics handles no user accounts, no personal data, and no financial information. It is a local music practice tool — the main attack surface is **file processing** (MIDI, MusicXML, PDF uploads) and the **FastAPI backend** when self-hosted.
|
||||||
|
|
||||||
|
## What to report
|
||||||
|
|
||||||
|
Worth reporting privately:
|
||||||
|
|
||||||
|
- Remote code execution or sandbox escape via a crafted MIDI, MusicXML, or PDF file
|
||||||
|
- Server-side vulnerabilities in the FastAPI backend (path traversal, SSRF, etc.)
|
||||||
|
- Dependency vulnerabilities with a realistic exploit path
|
||||||
|
|
||||||
|
Probably not a security issue (open a regular bug instead):
|
||||||
|
|
||||||
|
- Unexpected UI behaviour caused by a malformed music file
|
||||||
|
- The app crashing or producing wrong output from bad input
|
||||||
|
|
||||||
|
## Reporting
|
||||||
|
|
||||||
|
Use **GitHub's private vulnerability reporting**:
|
||||||
|
|
||||||
|
1. Go to the [Security tab](https://github.com/gigliof/bach-to-basics/security) of this repo
|
||||||
|
2. Click **"Report a vulnerability"**
|
||||||
|
3. Fill in the details — steps to reproduce, impact, any suggested fix
|
||||||
|
|
||||||
|
You'll get a response within a few days. There's no formal embargo policy given the nature of this project, but please give a reasonable heads-up before going public.
|
||||||
Reference in New Issue
Block a user