Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ jobs:

- name: Test
run: cargo test
# 19 of the player tests need a real audio device and are #[ignore]d, so
# 20 of the player tests need a real audio device and are #[ignore]d, so
# this proves the suite compiles and the rest passes -- not that audio
# works on a runner with no sound card.

Expand Down
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ and because releases are signed, Colony verifies the signature before installing

Grab the asset for your platform from the
[latest release](https://github.com/Project-Colony/Grape/releases/latest). Each
one ships with a matching `.sig` file.
one ships with a matching `.sig`, `.meta` and `.meta.sig`.

| Platform | Asset |
|---|---|
Expand All @@ -165,8 +165,9 @@ There is no installer: download the asset and run it.

#### Running the binaries

The `.sig` files are Colony's own ed25519 signatures. The binaries are not
signed by Apple or Microsoft, so macOS and Windows warn on first launch.
The `.sig` and `.meta.sig` files are Colony's own ed25519 signatures. The
binaries are not signed by Apple or Microsoft, so macOS and Windows warn on
first launch.

- **Linux:** `chmod +x grape-linux && ./grape-linux`
- **macOS:** make it executable and clear the download quarantine flag, then
Expand Down
25 changes: 10 additions & 15 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,16 @@
# Security Policy

## Supported Versions
## Supported versions

Use this section to tell people about which versions of your project are
currently being supported with security updates.
Only the **latest release** receives security fixes. Grape ships as a single
binary, through Colony and the release page, so the fix for a vulnerability is
the next release, not a patch to an older one.

| Version | Supported |
| ------- | ------------------ |
| 5.1.x | :white_check_mark: |
| 5.0.x | :x: |
| 4.0.x | :white_check_mark: |
| < 4.0 | :x: |
## Reporting a vulnerability

## Reporting a Vulnerability
Please report vulnerabilities **privately** via
[GitHub Security Advisories](https://github.com/Project-Colony/Grape/security/advisories/new)
("Report a vulnerability"). Do not open a public issue for exploitable bugs.

Use this section to tell people how to report a vulnerability.

Tell them where to go, how often they can expect to get an update on a
reported vulnerability, what to expect if the vulnerability is accepted or
declined, etc.
Include the version (`grape --version`), the platform, and the steps or file
that reproduce it. The report stays private until a fixed release is out.
3 changes: 2 additions & 1 deletion docs/guide/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ refuses an asset that does not match.

## Direct binary download

Every release ships exactly four assets, each with a detached `.sig` beside it:
Every release ships exactly four binaries, each with a detached `.sig` beside
it and a signed `.meta` (plus its `.meta.sig`) binding it to the version:

| Platform | Asset | Target triple |
|---|---|---|
Expand Down
4 changes: 2 additions & 2 deletions docs/internals/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ kept alive at all.
## Tests

`tests/cache_tests.rs` (20), `tests/metadata_online_tests.rs` (20) and
`tests/player_tests.rs` (23, of which 19 are `#[ignore]` because they need a
real audio device), plus 50 `#[test]` functions inside `src/`. What that
`tests/player_tests.rs` (25, of which 20 are `#[ignore]` because they need a
real audio device), plus 65 `#[test]` functions inside `src/`. What that
coverage does and does not prove is in
[contributing.md](contributing.md#what-the-tests-do-not-cover).
36 changes: 19 additions & 17 deletions docs/internals/contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ allows. A new warning anywhere fails the build, which is deliberate.

## Checks before committing

There is no CI that runs them, so the hooks are how they get run.
CI builds and tests every pull request (see below), but it does not run
rustfmt or clippy yet, so the hooks are how those two get run.

```bash
./scripts/setup-hooks.sh # rustfmt + clippy + cargo test on every commit
Expand All @@ -51,27 +52,30 @@ Formatting is `rustfmt.toml`; lints are the `.cargo/config.toml` block above.

| | |
|---|---|
| `src/**` | 50 `#[test]` functions — settings normalization and clamping, the theme migration, album-artist inference, cache-path validation, EQ clamping, the migration marker |
| `src/**` | 65 `#[test]` functions, 2 of them `#[ignore]` (one needs an audio device, one a private D-Bus session): settings normalization and clamping, the theme migration, album-artist inference, cache-path validation, EQ clamping, the migration marker, the native media-session state |
| `tests/cache_tests.rs` | 20 tests over the `.grape_cache/` round trip and signature invalidation |
| `tests/metadata_online_tests.rs` | 20 tests over Last.fm response parsing, the TTL, and the backoff |
| `tests/player_tests.rs` | 23 tests, **19 of them `#[ignore]`** |
| `tests/player_tests.rs` | 25 tests, **20 of them `#[ignore]`** |

### What the tests do not cover

Say this plainly, because it is the part that surprises people.

- **The audio path is barely tested.** Nineteen of the twenty-three player
tests need a real output device and are marked `#[ignore]`, so a default
`cargo test` runs four of them. Playback, seeking, gapless and the EQ are
- **The audio path is barely tested.** Twenty of the twenty-five player tests
need a real output device and are marked `#[ignore]`, so a default
`cargo test` runs five of them. Playback, seeking, gapless and the EQ are
verified by hand.
- **Nothing runs the tests automatically.** `.github/workflows/` contains
`release.yml` and nothing else — no test, clippy or fmt job. CI compiles four
targets when a release is cut, and never runs a test. The git hooks in
`scripts/` are the entire safety net, and they are opt-in.
- **Windows and macOS are compile-verified only.** The release matrix builds
both, so those paths typecheck every release, but the LaunchAgent, the HKCU
autostart, the `tray-icon` backend and the global hotkeys have no automated
exercise on either OS. Linux is the platform actually run.
- **CI does not gate rustfmt or clippy.** `.github/workflows/ci.yml` runs on
every pull request and every push to `main`: `cargo build --all-targets` and
`cargo test` on Linux, Windows and macOS, a build at the declared minimum
Rust (1.90), and a check of `colony.json` against the published schema. The
header of `ci.yml` says why rustfmt and clippy are not gated yet; until they
are, the opt-in git hooks in `scripts/` are the only thing running them.
- **Windows and macOS are built and tested, not run.** CI compiles and runs the
suite on both, and a release starts the Windows and Apple Silicon binaries
with `--version`, but the LaunchAgent, the HKCU autostart, the `tray-icon`
backend and the global hotkeys have no automated exercise on either OS. Linux
is the platform actually run.
- **Last.fm is never contacted by a test.** The online tests cover parsing,
caching, the TTL and the backoff against fixtures. The live API is not in the
loop, and the code path needs a user-supplied key to do anything at all.
Expand All @@ -88,8 +92,6 @@ cargo test --test player_tests -- --ignored
commit messages, and these documents. French is a shipped *UI locale*, which
is a different thing: it lives in `src/ui/i18n.rs` as `STRINGS_FR` and stays
there.
through the binary: the startup failure message in `src/main.rs` is still
French.
- **Commits are Conventional Commits.** release-please parses them to decide
the next version and to write `CHANGELOG.md`; a `fix:` is a patch, a `feat:`
a minor. `CHANGELOG.md` is never edited by hand.
Expand Down Expand Up @@ -117,7 +119,7 @@ Enough of them exist that the shape is settled:
```
assets/ logos, application icons, the bundled JetBrains Mono Nerd Font
docs/ these pages
scripts/ the git hooks
scripts/ the git hooks, and sign-release.sh (the manual signing fallback)
src/ the program — see architecture.md
tests/ integration tests
```
11 changes: 9 additions & 2 deletions docs/internals/packaging.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,9 @@ job sees a key. The Windows job also checks that `grape-windows.exe` carries
the version resource `build.rs` writes: ProductName `Grape` and the release
version as ProductVersion, which SignPath requires before it signs.

That build is also the only automated check Windows and macOS ever get: those
targets typecheck at release time and are never tested. See
A release build is not the first time Windows and macOS compile: `ci.yml`
builds and tests on both for every pull request. Neither workflow exercises the
tray, autostart or hotkeys there; see
[contributing.md](contributing.md#what-the-tests-do-not-cover).

## 3. Everything is signed, then published
Expand All @@ -70,6 +71,12 @@ If a run fails after the tag exists, finish the draft from the tag:
gh workflow run release.yml -R Project-Colony/Grape --ref vX.Y.Z -f tag=vX.Y.Z
```

`scripts/sign-release.sh` writes the same three files by hand. No workflow
uses it: it is the manual fallback for when the shared workflow cannot run, and
it needs the release private key, which is not in the repository. It only
signs and checks its own signatures; it does no Authenticode, and uploading the
files and publishing the draft are left to whoever runs it.

## 4. Colony picks it up

`colony.json` is the launcher manifest:
Expand Down
18 changes: 12 additions & 6 deletions docs/project/roadmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,13 @@ here as complete but are not have been moved down to *Started and unfinished*.
itself when the platform says no.
- Linux tray on `ksni` / StatusNotifierItem, after `tray-icon`'s GTK 3 backend
turned out to abort the process.
- Signed releases: four targets, ed25519 signatures verified at sign time, and
a release that fails rather than shipping unsigned.
- Signed releases: four targets built and checked, then the shared
Project-Colony sign-and-publish workflow writes ed25519 `.sig`, `.meta` and
`.meta.sig`, verifies them on the release, and only then publishes it. A
failed run leaves a draft rather than shipping unsigned. Windows Authenticode
through SignPath is wired and waits for SignPath to accept the project.
- CI on every pull request: build and `cargo test` on Linux, Windows and
macOS, a build at the minimum supported Rust, and a `colony.json` check.

## Started and unfinished

Expand Down Expand Up @@ -95,10 +100,11 @@ Either finish it or remove the control; leaving it is the worst of the three.
`preferences.json`.
- **Expose sorting.** `SortOption` implements alphabetical, by album, by year
and by duration, and no control emits it — the order is permanently by album.
- **Run the tests in CI.** `.github/workflows/` has only `release.yml`. The
hooks under `scripts/` are opt-in and the only thing running clippy, rustfmt
or `cargo test` today.
- **Cover the audio path.** Nineteen of the twenty-three player tests are
- **Gate rustfmt and clippy in CI.** `ci.yml` runs neither: `rustfmt.toml`
asks for nightly-only options and edition 2024 on an edition 2021 crate, and
clippy has a pedantic/nursery backlog. The opt-in hooks under `scripts/` are
the only thing running them today. Fix both, then add the gate.
- **Cover the audio path.** Twenty of the twenty-five player tests are
`#[ignore]` for want of an output device.
- **Report real scan progress.** The scan already runs on the tokio executor
(`ui/app/playback.rs`), but the banner's bar is a 120 ms cosmetic loop that
Expand Down
2 changes: 1 addition & 1 deletion scripts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ cargo fmt --all -- --check
# Run clippy
cargo clippy --all-targets --all-features

# Strict mode (as in CI)
# Strict mode (as the git hooks run it; CI does not run clippy yet)
cargo clippy --all-targets --all-features -- -D warnings
```

Expand Down
14 changes: 8 additions & 6 deletions scripts/sign-release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
# "<asset>.sig" that the launcher verifies before applying a self-update.
#
# The signature is the raw 64-byte ed25519 signature over the asset bytes, as
# produced by `openssl pkeyutl -sign -rawin` — the same format src/signing.rs
# verifies against the embedded public key. openssl is the only dependency.
# produced by `openssl pkeyutl -sign -rawin` - the same format Colony's
# src/signing.rs verifies against its embedded public key. openssl is the only
# dependency.
#
# A signature over raw bytes proves only "these bytes came from the org" — not
# WHICH artefact or WHICH version they are. So each asset also gets a signed
Expand All @@ -28,10 +29,11 @@
# COLONY_SIGNING_KEY=/path/to/colony-release.pem \
# COLONY_RELEASE_VERSION=v1.2.3 ./scripts/sign-release.sh <asset> [<asset> ...]
#
# In CI, provide the private key via a secret (e.g. write it to a temp file from
# a GitHub Actions secret) and set COLONY_SIGNING_KEY to its path. Upload every
# generated "<asset>.sig", "<asset>.meta" and "<asset>.meta.sig" as release
# assets alongside their binary.
# Releases do not use this script. CI signs in the shared sign-and-publish
# workflow of Project-Colony-Resources, which writes the same three files (see
# docs/internals/packaging.md). This is the manual fallback for when that
# workflow cannot run: upload every generated "<asset>.sig", "<asset>.meta" and
# "<asset>.meta.sig" to the draft release alongside their binary, by hand.
set -euo pipefail

KEY="${COLONY_SIGNING_KEY:-$HOME/.config/colony/release-signing/colony-release.pem}"
Expand Down
Loading