darcsweb - Log

fritjof@alokat.org
The gen/ directory is not tracked in darcs; it is produced by
`make -C verified extract`, which Setup.hs' preBuild hook already
runs during `stack build` using the pinned Rocq 9.0.0 installed in
the build stage.  COPY gen/ gen/ therefore failed on fresh hosts
(no directory in the build context) and risked shipping stale
host-side extractions when it did succeed.
M ./Dockerfile -1 +5
fritjof@alokat.org
A ./test/Properties/Config.hs
fritjof@alokat.org
Security:
- getRepoTree now rejects non-empty subpaths that fail isSafeSubPath,
  closing a path-disclosure that exposed _darcs/ via the tree UI.
- Tree/blob breadcrumbs HTML-escape labels and percent-encode hrefs
  so a directory name containing HTML or URL-structural characters
  can no longer inject markup or break out of the URL.
- serveClone enforces a strict two-segment allowlist
  (hashed_inventory, inventories/_, patches/_, pristine.hashed/_,
  optional packs/basic.tar.gz + packs/patches.tar.gz) instead of
  serving every file that passed isSafeSubPath.
- readRepoDescription and getRepoBlob use strict ByteString +
  explicit UTF-8 validation under try; a NUL-byte sniff keeps binary
  files from being escaped character by character.
- All request-time canonicalizePath calls go through a new
  safeCanonicalize helper that degrades IO errors to 404 instead of
  leaking framework 500s.
- parsePortPure rejects empty, whitespace, hex, and non-digit port
  strings, replacing the partial Text.Read.read on startup.

Performance:
- getRepoPatch hash-filters before rendering diffs; a missing hash no
  longer walks and renders the entire patch history.
- getRepoSummary replaces listRepos + getRepoPatches + getRepoTags
  with a single readPatches pass. Count and tag positions come from
  cheap PatchInfo; extractPatchListing only runs on rows actually
  displayed.
- Native Text implementation of esc replaces the HtmlPure.esc String
  bridge. Equivalence against the Coq-extracted spec is pinned by
  QuickCheck with a biased generator over escaped characters.
- Tree/blob breadcrumb build is now O(depth) (threaded Text prefix)
  instead of O(depth^2) (acc ++ [p]).

UX / mobile-first:
- renderPage emits semantic <header>/<main>/<footer> landmarks plus a
  favicon <link>. Empty breadcrumb <nav> is skipped on index and 404.
- Index page has a visible <h1> site title.
- repoNavBar is a <nav aria-label="Repository sections"> with
  aria-current="page" on the active tab.
- Full-log entries are <article class="log-entry">.
- Tree-icon cells carry aria-hidden="true".

Tests:
- New Properties.Config covers parsePortPure's accepted/rejected set.
- Properties.Clone pins the two-segment clone allowlist and rejects
  nested paths (patches/a/b, inventories/a/b, pristine.hashed/a/b).
- Properties.Html pins the native esc equivalence vs HtmlPure.esc
  with a biased generator, plus example-based tests for the
  breadcrumb escape + percent-encode contracts (including the empty
  blob-breadcrumb degenerate case).

Reviews under reviews/ record the pre- and post-change findings from
three Codex + three Claude agents (first pass) and four Codex + four
Claude agents (post-change), plus the reconciliation document that
the user-visible fixes were derived from.
M ./app/Main.hs -69 +91
M ./darcsweb.cabal +1
A ./reviews/
A ./reviews/_post-prompt-bugs.md
A ./reviews/_post-prompt-efficiency.md
A ./reviews/_post-prompt-quality.md
A ./reviews/_post-prompt-webapp.md
A ./reviews/_prompt-readability.md
A ./reviews/_prompt-security.md
A ./reviews/_prompt-webperf.md
A ./reviews/claude-readability.md
A ./reviews/claude-security.md
A ./reviews/claude-webperf.md
A ./reviews/codex-readability.md
A ./reviews/codex-reconciliation.md
A ./reviews/codex-security.md
A ./reviews/codex-webperf.md
A ./reviews/post-claude-bugs.md
A ./reviews/post-claude-efficiency.md
A ./reviews/post-claude-quality.md
A ./reviews/post-claude-webapp.md
A ./reviews/post-codex-bugs.md
A ./reviews/post-codex-efficiency.md
A ./reviews/post-codex-quality.md
A ./reviews/post-codex-webapp.md
M ./src/DarcsWeb/Config.hs -2 +23
M ./src/DarcsWeb/Darcs.hs -54 +203
M ./src/DarcsWeb/Html.hs -163 +267
M ./test/Properties/Clone.hs -1 +77
M ./test/Properties/Html.hs -1 +73
M ./test/Spec.hs -1 +5
fritjof@alokat.org
M ./Caddyfile -8 +9
M ./README.md -32 +11
M ./docker-compose.yml -14 +8
R ./nginx.conf
M ./src/DarcsWeb/Html.hs -2 +4
M ./static/style.css -7 +50
fritjof@alokat.org
M ./app/Main.hs -3 +61
M ./darcsweb.cabal -1 +3
A ./src/DarcsWeb/Clone.hs
M ./src/DarcsWeb/Html.hs -2 +18
M ./static/style.css +35
A ./test/Properties/Clone.hs
M ./test/Spec.hs -1 +5
fritjof@alokat.org
M ./.dockerignore -5 +6
M ./Dockerfile -17 +64
M ./README.md +13
fritjof@alokat.org
M ./Dockerfile -8 +7
fritjof@alokat.org
A ./.dockerignore
A ./Caddyfile
A ./Dockerfile
M ./README.md +100
A ./Setup.hs
A ./app/
A ./app/Main.hs
M ./darcsweb.cabal +3
A ./docker-compose.yml
A ./nginx.conf
M ./src/DarcsWeb/Darcs.hs -4 +19
A ./static/darcs-logo.png
M ./static/style.css -174 +598
A ./test/
A ./test/Properties/
A ./test/Properties/Csp.hs
A ./test/Properties/Html.hs
A ./test/Spec.hs
A ./verified/
A ./verified/Makefile
A ./verified/csp_pure.v
A ./verified/csp_pure_proofs.v
A ./verified/html_pure.v
A ./verified/html_pure_proofs.v
A ./verified/path_pure.v
A ./verified/path_pure_proofs.v
fritjof@alokat.org
Security-critical pure functions (HTML escaping, path validation,
trailing slash normalization) are reimplemented in Gallina, formally
proven correct, and extracted to Haskell. Remaining pure functions
are covered by QuickCheck properties. Rocq extraction runs
automatically on stack build, proofs and QuickCheck on stack test.
R ./.claude/settings.local.json
R ./.claude/
M ./README.md +86
M ./darcsweb.cabal -9 +41
M ./src/DarcsWeb/Darcs.hs -18 +8
M ./src/DarcsWeb/Html.hs -9 +10
R ./src/Main.hs
Add diff highlighting. 2026-03-11 20:27:07
fritjof@alokat.org
M ./src/DarcsWeb/Html.hs -1 +12
M ./static/style.css +14
Hardening the path evalation. 2026-03-11 20:22:45
fritjof@alokat.org
So no one can access file, he is not allowed to.
M ./src/DarcsWeb/Darcs.hs -14 +70
M ./src/Main.hs -24 +20
fritjof@alokat.org
M ./darcsweb.cabal +1
M ./src/DarcsWeb/Darcs.hs -2 +45
M ./src/DarcsWeb/Html.hs -53 +177
M ./src/DarcsWeb/Types.hs +8
M ./src/Main.hs -7 +60
M ./static/style.css +57
Clean up the header. 2026-03-11 19:58:13
fritjof@alokat.org
M ./src/DarcsWeb/Html.hs -3 +2
M ./static/style.css +9
Initial commit of darcs web. 2026-03-11 19:41:54
fritjof@alokat.org
A ./.claude/
A ./.claude/settings.local.json
A ./LICENSE
A ./README.md
A ./darcsweb.cabal
A ./darcsweb.conf.example
A ./src/
A ./src/DarcsWeb/
A ./src/DarcsWeb/Config.hs
A ./src/DarcsWeb/Darcs.hs
A ./src/DarcsWeb/Html.hs
A ./src/DarcsWeb/Types.hs
A ./src/Main.hs
A ./stack.yaml
A ./stack.yaml.lock
A ./static/
A ./static/style.css