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
29 changes: 29 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,35 @@

## Unreleased

## v0.2.1 - 2026-07-27

A six-dimension audit of v0.2.0 (architecture, code quality, security, frontend, tests, docs) produced 31 findings. The fixes landed after the v0.2.0 release was cut, so **v0.2.0 does not contain them** — upgrade if you run DreamLoop anywhere but loopback.

### Security

- Binding a non-loopback host (`--host 0.0.0.0`, the Docker demo) now enables token authentication, prints the access URL at startup, and accepts the token via cookie, header, or query. Previously the app had no authentication at all and relied on a spoofable `Host` header, so a published Docker port exposed every dream to the local network and let anyone repoint the AI provider.
- Refuse header-less writes from non-loopback clients unless they authenticate. `--no-auth` / `DREAMLOOP_NO_AUTH=1` keeps them open, because that mode has no token to offer a scripted client.
- Hand `?token=` to a cookie and redirect it out of page URLs, and redact it from uvicorn's access log, which records full query strings.
- Compare tokens as bytes: `compare_digest` raises `TypeError` on non-ASCII input, which turned a bad token into a 500.
- Return JSON rather than HTML for 401s on `/api/` paths.

### Data safety

- `migrate_analysis_table` dropped the renamed old table unconditionally, so an analysis table missing a required column lost every stored analysis silently. Unmigratable rows are now preserved in a backup table, and the migration paths have test coverage.
- Recover from a corrupt `config.json` instead of returning 500 from every page, including the settings page needed to fix it. Both config writers now replace the file atomically.
- Wrap invalid model JSON as `AnalysisIncomplete`; a truncated or fenced response from a local model surfaced as a 500.

### Fixes

- `POST /drafts/analyze` stores the draft and redirects, so a refresh no longer re-runs a slow LLM call and the URL survives navigation.
- Log the three swallowed exceptions in `web.py` (the project had no logging at all), stop reporting a missing dream as a provider error, and surface image-generation failures to the user.
- Map import errors to 400/404 instead of 500.
- `init()` is idempotent; every `DreamLoop` method re-ran the full migration.
- `feedback_summary` uses one join instead of a query per feedback row.
- Clamp dream text in cards, fix heat-cell contrast to WCAG AA, add a skip link, reset loading buttons on bfcache restore, and preload the bundled fonts.
- Add `SECURITY.md`, issue and PR templates, and document that `.dreamloop/` is created relative to the working directory.
- 212 tests pass; coverage 87% -> 91%.

## v0.2.0 - 2026-07-25

- Upgrade all six web pages with a shared local design system, page-specific atmospheric art, progressive reveal and count-up effects, native dream-card transitions, responsive navigation, and refreshed English/Chinese screenshots.
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "hatchling.build"

[project]
name = "dreamloop"
version = "0.2.0"
version = "0.2.1"
description = "A local-first AI dream journal for people who want to notice patterns in their dreams."
readme = "README.md"
requires-python = ">=3.11"
Expand Down
2 changes: 1 addition & 1 deletion src/dreamloop/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
"""DreamLoop local-first dream journal."""

__version__ = "0.2.0"
__version__ = "0.2.1"
3 changes: 2 additions & 1 deletion src/dreamloop/web.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates

from . import __version__
from .analysis import (
AnalysisIncomplete,
AnalysisLanguageMismatch,
Expand Down Expand Up @@ -707,7 +708,7 @@ def create_app(
auth_token: str | None = None,
allow_unauthenticated_writes: bool = False,
) -> FastAPI:
app = FastAPI(title="DreamLoop", version="0.2.0")
app = FastAPI(title="DreamLoop", version=__version__)
if auth_token is None:
# The Host allowlist is DNS-rebinding protection for the
# unauthenticated loopback mode. With token auth the token is the
Expand Down
2 changes: 1 addition & 1 deletion tests/test_packaging_release.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def test_project_version_is_consistent_across_package_and_web_app():
pyproject = tomllib.loads((ROOT / "pyproject.toml").read_text(encoding="utf-8"))
app = create_app(ROOT)

assert pyproject["project"]["version"] == "0.2.0"
assert pyproject["project"]["version"] == "0.2.1"
assert __version__ == pyproject["project"]["version"]
assert app.version == pyproject["project"]["version"]

Expand Down
4 changes: 2 additions & 2 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading