chore: prepare release v0.4.0
This commit is contained in:
+146
-4
@@ -5,11 +5,152 @@ All notable changes to **volumen** are documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
> Versions ≤ 0.3.0 were implemented in Ruby. The current codebase is Python
|
||||
> (FastAPI). Earlier release notes are kept verbatim as historical record.
|
||||
|
||||
## [development]
|
||||
|
||||
## [0.4.0] — 2026-07-26
|
||||
|
||||
### Added
|
||||
|
||||
-
|
||||
- **`volumen init`** — a new `init` subcommand is the *operational*
|
||||
bootstrap (config, data dirs, admin password, optional systemd unit). Run
|
||||
as root for a system install (default `--systemd`); pass `--local` for a
|
||||
per-user install (`~/.config/volumen/`, `~/.local/share/volumen/`). The
|
||||
command renders the production-hardened config from the same commented
|
||||
TOML template (`host = "::1"`, `env = "production"`, `trust_proxy = true`,
|
||||
`cookie_secure = true`), prompts for an admin password (`getpass`), hashes
|
||||
it via the existing scrypt helper, generates a 64-byte hex session key,
|
||||
creates the system user (`useradd --system`) and the `/etc/volumen/` /
|
||||
`/var/lib/volumen/` layout, and (with `--systemd`) installs a hardened
|
||||
`/etc/systemd/system/volumen.service` and runs
|
||||
`systemctl daemon-reload && systemctl enable --now`.
|
||||
- **PyPI publish metadata** — `pyproject.toml` gains `readme`, `keywords`,
|
||||
a complete `classifiers` array (Development Status, Framework :: FastAPI,
|
||||
supported Python versions, OS, Topic, Typing), and a `[project.urls]`
|
||||
block (Homepage, Repository, Issues, Changelog, Documentation). PyPI now
|
||||
renders the README on the project page and links back to sourcedock.dev.
|
||||
- **`volumen status`** — read-only inspection of an installation. Prints
|
||||
human output by default or `--json` for tooling; reports `config_exists`,
|
||||
`data_dir_exists`, `users_file_exists`, `password_hash_set`,
|
||||
`session_key_ok`, `systemd_unit_installed`, `service_active`,
|
||||
`admin_user_present`, and any issues found. Exit code is `1` when any
|
||||
issue is reported.
|
||||
- **`volumen check-update`** — compares the installed version (read via
|
||||
`importlib.metadata`) with the latest release on PyPI. Uses only
|
||||
`urllib.request` (stdlib, 5 s timeout); exit code is `0` up-to-date,
|
||||
`1` update available (suggests `uv tool upgrade volumen`), `2` PyPI
|
||||
unreachable / offline / malformed response. `--json` returns the same
|
||||
fields plus `checked_at` for cron-friendly alerting.
|
||||
- **`src/volumen/installer.py`** — a new module exposing `system_install`,
|
||||
`user_install`, `inspect`, plus the private `_mutate_config_text` helper
|
||||
used to apply line-anchored substitutions to the rendered TOML template
|
||||
(preserves comment blocks byte-for-byte).
|
||||
- **Tests** — `tests/test_installer.py` adds 15 tests covering both install
|
||||
flows, the config-template mutator, the systemd-unit rendering,
|
||||
idempotency / backup behaviour, the `inspect` round-trip, and the
|
||||
`--systemd` + `--local` CLI guard.
|
||||
|
||||
### Changed
|
||||
|
||||
- **First-run setup is now `volumen init`** — replaces the legacy
|
||||
`install.sh`. The CLI subcommand renders config, creates data dirs,
|
||||
prompts for an admin password, generates a session key, and (with
|
||||
`--systemd`) installs and enables a hardened systemd unit. No bash
|
||||
required.
|
||||
- **Publishing now targets PyPI** — `release.yml` runs
|
||||
`uv publish --token "$PYPI_TOKEN"` after `python -m build` for `v*`
|
||||
tags. Wheel + sdist continue to be uploaded to sourcedock.dev Releases as a
|
||||
secondary mirror. End users get `uv tool install volumen` and
|
||||
`pipx install volumen` as the one-line install path; no checkout
|
||||
required.
|
||||
- **Distribution path is `uv tool install`** (or `pipx install`) — the
|
||||
CLI binary is installed globally; the operational bootstrap is delegated
|
||||
to `volumen init`. The legacy `uv sync` + project-local venv at
|
||||
`/opt/volumen/.venv` is gone.
|
||||
- **`Config.load` round-trips config-file `content_dir` / `users_file`** —
|
||||
the rendered template places these two keys after the `[server]` header,
|
||||
so TOML table folding puts them inside `[server]`. `Config.load` now
|
||||
hoists them to the root so files produced by `volumen init` (and any
|
||||
hand-edited config) round-trip through the canonical accessors without
|
||||
relying on CLI overrides.
|
||||
- **Migrated from Ruby to Python**: the runtime has been rewritten on top of
|
||||
FastAPI + Uvicorn, replacing Sinatra with FastAPI, kramdown with
|
||||
python-markdown + pymdown-extensions, Puma with Uvicorn, Bundler with uv,
|
||||
minitest with pytest, RuboCop with Ruff, and the TOML parser
|
||||
(`toml-rb`) with the standard library `tomllib` (plus `tomli-w` for
|
||||
round-tripping edits). The public API (`/api/volumen/*`) and the
|
||||
server-rendered admin (`/admin/*`) keep the same shape and HTTP semantics.
|
||||
- **Installer** — `install.sh` now bootstraps `uv` instead of Bundler, runs
|
||||
`uv sync --frozen` to provision `/opt/volumen/.venv`, and points the
|
||||
systemd `ExecStart` at the venv-resident `volumen` console script. The
|
||||
Python runtime is auto-installed on Fedora/openEuler; other distros get a
|
||||
heredoc with the equivalent `apt` / `pacman` / `zypper` / `apk` lines.
|
||||
- **CI** — Forgejo Actions moved to `setup-uv` + Ruff + pytest on a single
|
||||
Python 3.12 job (was: Ruby 3.3/3.4 matrix with Bundler, RuboCop, and
|
||||
`bundle exec rake test`). The release workflow builds wheel + sdist via
|
||||
`python -m build` and uploads them with the Forgejo Releases API.
|
||||
- **Migration guard** — new `.forgejo/workflows/migration-guard.yml` greps
|
||||
the tracked tree for Ruby-only terms (`bundle exec`, `RuboCop`, `Sinatra`,
|
||||
`Puma`, `kramdown`, `gem build`, `Volumen::`, `Rack::Session::Cookie`,
|
||||
`OpenSSL::KDF`, `lib/volumen/`) and fails the build if any of them leak
|
||||
back into production paths.
|
||||
- **Configuration** — `config.toml` gains six new keys surfaced in
|
||||
`config.toml.example`: `[server].env` (`"production"` enables strict
|
||||
startup), `[server].trust_proxy` (honour `X-Forwarded-Proto` from
|
||||
nginx), `[admin].min_password_length` (default `10`),
|
||||
`[admin].max_password_length` (default `1024`, caps scrypt work),
|
||||
`[admin].max_upload_bytes` (default `10485760`, 10 MB), and
|
||||
`[admin].cookie_secure` (default `false` in dev, set `true` behind
|
||||
HTTPS). See `docs/configuration.md` for the full schema.
|
||||
- **Default bind address** — the installer and `config.toml.example`
|
||||
default to `host = "::"` (IPv6 with automatic IPv4 fallback) so the
|
||||
service is reachable on both stacks out of the box. Bind to `"::1"`
|
||||
when running behind a reverse proxy.
|
||||
- **Test client now uses `httpx2`** — dev dependencies replace
|
||||
`httpx>=0.28` with `httpx2>=2.7` (the actively maintained fork by
|
||||
Pydantic). Starlette 1.3.x prefers `httpx2` in `TestClient` and emits
|
||||
`StarletteDeprecationWarning` when only legacy `httpx` is installed;
|
||||
shipping `httpx2` keeps the test suite warning-free. The legacy
|
||||
`httpx` package is still pulled in via `fastapi[standard]` for the
|
||||
`fastapi` CLI and remains API-compatible. The unused
|
||||
`ignore::DeprecationWarning:starlette.testclient` filter is removed
|
||||
from `[tool.pytest.ini_options]` (it targeted the wrong warning
|
||||
class and never matched).
|
||||
|
||||
### Removed
|
||||
|
||||
- `install.sh` — the bash installer is deleted. Use `uv tool install
|
||||
volumen` (or `pipx install volumen`) followed by `volumen init`.
|
||||
- `pkg/` build output and `volumen.gem` (Ruby gem packaging is gone; the
|
||||
project now ships as a wheel + sdist built with `python -m build`).
|
||||
- `Gemfile`, `volumen.gemspec`, `Rakefile`, `.rubocop.yml` and the
|
||||
Sinatra-era `lib/` tree.
|
||||
- `.editorconfig` — Ruff (`pyproject.toml`'s `[tool.ruff]`) is the single
|
||||
source of truth for Python formatting; modern editors default to UTF-8,
|
||||
LF, and a trailing newline. Markdown files in this repo use blank lines
|
||||
between paragraphs (no ` \n` line-break idiom), so trimming trailing
|
||||
whitespace is safe.
|
||||
|
||||
### Security
|
||||
|
||||
- **scrypt password hashing** now uses `hashlib.scrypt` and constant-time
|
||||
verification via `secrets.compare_digest` (was: Ruby's `OpenSSL::KDF`).
|
||||
- **Session cookies** are signed by Starlette's `SessionMiddleware`
|
||||
(`itsdangerous`) with `HttpOnly` and `SameSite=Strict`; `Secure` is added
|
||||
by `SecureCookieMiddleware` when the request was forwarded over HTTPS
|
||||
(only when `[server].trust_proxy = true`).
|
||||
- **CSRF tokens** are generated with `secrets.token_hex(32)` and verified
|
||||
with `secrets.compare_digest` on every state-changing admin POST.
|
||||
- **Markdown sanitisation policy** — the renderer still passes inline HTML
|
||||
through (authors are the trusted admin); document the trust model
|
||||
explicitly in `docs/security.md` so deployments that ingest untrusted
|
||||
content know to add a sanitiser.
|
||||
|
||||
> Note: refine the Security bullets above once the Python agent confirms the
|
||||
> final cryptographic controls (e.g. whether `image/*` upload signatures get
|
||||
> re-validated server-side and whether the CSRF token is rotated on login).
|
||||
|
||||
## [0.3.0] — 2026-07-12
|
||||
|
||||
@@ -240,6 +381,7 @@ admin — no database, no external services.
|
||||
- Configurable, stable `session_key` so sessions survive restarts.
|
||||
- Generic login error message to avoid username enumeration.
|
||||
|
||||
[0.1.0]: https://codeberg.org/petrbalvin/volumen/releases/tag/v0.1.0
|
||||
[0.2.0]: https://codeberg.org/petrbalvin/volumen/releases/tag/v0.2.0
|
||||
[0.3.0]: https://codeberg.org/petrbalvin/volumen/releases/tag/v0.3.0
|
||||
[0.1.0]: https://sourcedock.dev/petrbalvin/volumen/releases/tag/v0.1.0
|
||||
[0.2.0]: https://sourcedock.dev/petrbalvin/volumen/releases/tag/v0.2.0
|
||||
[0.3.0]: https://sourcedock.dev/petrbalvin/volumen/releases/tag/v0.3.0
|
||||
[0.4.0]: https://sourcedock.dev/petrbalvin/volumen/releases/tag/v0.4.0
|
||||
|
||||
Reference in New Issue
Block a user