oni.git

oni

~ A static Git browser written in Rust.
git clone https://github.com/debuman/oni.git

oni

A static Git browser for debuman's public repositories. The Rust generator, sqzer-stagit, produces the repository catalog, commit history, diffs, file views, branches, tags, rendered READMEs, and Atom feeds. It reimplements stagit's feature set without invoking the C stagit executable.

This project maintains its own HTML templates and CSS. Local build artifacts and repository snapshots are kept in .cache/.

The site is published at oni.sqzer.com through GitHub Pages. The source repository is debuman/oni.

All project documentation, code comments, and docstrings are written in English. Mirrored repository content and Unicode test fixtures retain their original text.

Running locally

For a fresh checkout, install the dependencies listed below and run these setup commands from the project directory in WSL Ubuntu:

cargo fetch --locked --manifest-path generator/Cargo.toml
python3 scripts/bootstrap_git.py

Then build the initial repository snapshot in Windows PowerShell:

.\build.ps1
python .\scripts\serve.py

Preview: http://127.0.0.1:4174/

For later rebuilds, use .\build.ps1 -Offline to reuse the local repository snapshot. Omit -Offline to refresh the public repository list and Git data from GitHub. The generator itself is always compiled offline from the locked local dependency cache.

These setup commands require network access. The Git bootstrap verifies the pinned upstream SHA-256 and installs under .cache/secure-git/; it does not replace system Git. Builds select that installation and require Git 2.56.1 or newer. Feed URLs use the local preview address by default. The build script accepts --base-url https://oni.sqzer.com when generating files for that hostname.

CI and deployment

CI and deploy runs on pull requests to main, pushes to main, and manual workflow dispatches.

  • Every run tests Rust, generator behavior, security boundaries, and deployment packaging, then builds all public repositories and checks the generated site.
  • A successful push to main deploys the verified artifact to GitHub Pages. Manual runs on main also deploy. Pull requests never deploy.
  • Repository snapshots are fetched fresh. Changes made only in other repositories appear on the next build; use Run workflow to refresh them without a source change in this repository.
  • The build job has read-only repository permissions. Only the separate deployment job can write to Pages and request an OIDC token. Action versions are pinned to commit hashes, and checkout does not persist credentials.
  • The CI runner uses Ubuntu 26.04, Python 3.14, Rust 1.99.1, and the checksum-pinned local Git build. Cargo dependencies and the patched Git installation are cached.

GitHub Pages is configured for GitHub Actions and the custom domain oni.sqzer.com, with HTTPS enforced. The DNS CNAME points oni.sqzer.com to debuman.github.io. Generated HTML and repository archives are deployment artifacts, not source commits. The packager preserves dot-prefixed repositories such as .github while rejecting actual Git metadata directories, symlinks, and special files.

The hosted site retains HTML sanitization, meta CSP, and referrer policy. GitHub Pages does not apply this project's custom HTTP response headers; see SECURITY.md for that hosting boundary.

Structure and dependencies

  • generator/: Rust generator with a locked Ammonia HTML5 sanitizer dependency.
  • generator/src/repo.rs: Repository access through the Git CLI. Repository code is not executed.
  • generator/src/html.rs: HTML documents, navigation, catalog, and shared layout.
  • generator/src/main.rs: File, commit, diff, reference, and feed generation.
  • generator/src/markdown.rs: Rust bindings to the system MD4C library's public API.
  • theme/style.css: Locally maintained CSS with no JavaScript, web fonts, or CDN dependencies.
  • scripts/build.py: GitHub API requests, bare repository synchronization, compilation, generation, and archives.
  • scripts/readme_assets.py: Relative README image and file link resolution.
  • scripts/benchmark.py: Scaling benchmarks and output equivalence checks.
  • scripts/package_site.py: Validated GitHub Pages artifact packaging.
  • .github/workflows/deploy.yml: CI checks and deployment to GitHub Pages.
  • security/csp.txt: Shared browser content policy for generated HTML and preview responses.
  • SECURITY.md: Trust boundaries, security review findings, limits, and deployment requirements.
  • public/: Generated site, including license notices under licenses/.
  • .cache/repos/: Local Git inputs with remote push URLs disabled.
  • .cache/cargo/: Compilation output.
  • .cache/previous-*/: Previous local previews.

Builds run in WSL Ubuntu and require Rust/Cargo, Git, Python 3, a system linker, libmd4c-dev, libmd4c-html0-dev, and prlimit from util-linux. The Git bootstrap also needs make, a C compiler, zlib/OpenSSL headers, and curl development headers (downloaded locally from Ubuntu when absent). Running the generator requires Git and libmd4c-html. The generated site contains static HTML, CSS, and images, so the hosting server does not need to run the generator.

MD4C handles Markdown parsing. Page generation and styles are maintained in Rust and CSS; no separate C page generator or libgit2 is used. Ammonia 4.2.4 sanitizes the resulting HTML with an HTML5 parser. It is the only direct Cargo dependency; Cargo.lock pins its transitive dependencies.

Behavior

  • The catalog is sorted by the latest commit date.
  • Log shows the latest 50 commits; detail pages cover all commits reachable from HEAD.
  • Rename and copy detection recognizes files with identical content. Diff graphs preserve insertion/deletion proportions.
  • Tags outside the default branch receive feed entries and commit detail pages.
  • The README navigation link opens the rendered README.html page.
  • README selection order is README, README.md, README.txt, readme, readme.txt, then README.markdown.
  • The Files view's file/README.md.html shows the original text with line numbers.
  • Raster images with expected file signatures are copied into raw/. Repository SVG images use commit-pinned URLs on GitHub's separate raw-content origin.
  • README HTML retains safe formatting, tables, details, tasks, and fenced code; executable content, inline styles, forms, and unsafe URL schemes are removed.
  • archive.tar.gz contains the default branch's HEAD source tree.
  • Diffs for deleted files remain readable and do not link to nonexistent current file pages.
  • Repositories made private or deleted are excluded from the next online build.
  • The generator also supports empty repositories.

Verification

From the project directory in WSL:

cargo test --offline --locked --manifest-path generator/Cargo.toml --target-dir .cache/cargo
cargo build --release --offline --locked --manifest-path generator/Cargo.toml --target-dir .cache/cargo
python3 scripts/test_generator.py
python3 scripts/test_security.py
python3 scripts/test_package_site.py
python3 scripts/audit_site.py

Tests create temporary local Git repositories to exercise Markdown, history limits, complete commit pages, Unicode paths, binary and deleted files, renames and copies, README selection, unmerged release tags, feed links, and empty repositories. They also cover empty, mode-only, and merge diffs, navigation, and README directory links. Stream tests cover marker-like filenames and source lines, binary payloads larger than a pipe buffer, empty blobs, and child process cleanup after success or failure. Security tests cover independent XSS payloads, unsafe assets, metadata and output symlinks, path traversal, size limits, preview host/origin checks, and HTTP headers. Run audit_site.py after building to check every page, local link, feed, and archive. The preview server requires Python 3.12 or newer.

Performance

Let F be the file count, C the generated commit count, and L the README link count. For fixed filename lengths and path depths, the following repeated scans have been removed. HTML output and Git's own diff computation costs are separate.

Operation Before Current
README, license, and submodule navigation selection O(F × (F + C)) O(F) setup, then O(1) per page
README directory link lookup O(F × L) O(F) setup, then average O(1) per link
Catalog input loading Full history and file tree per repository Latest commit only per repository

Commit numstat and patch data are calculated together, eliminating duplicate diff calculations. A persistent git diff-tree --stdin process handles all commits in each repository, reducing diff process launches from C to one. Diff computation still scales with the commits and their changes; replies are consumed one commit at a time. Tags already covered by HEAD do not require another history query.

Output directories are prepared once per distinct parent directory instead of checked for every page. README images share one lazy git cat-file --batch process instead of launching Git for each image. Source lines are HTML-escaped directly into the destination string, and patch rendering borrows its input buffer without shifting the patch bytes. The build script also avoids copying the log over an index page the generator has already written.

The benchmark script creates temporary repositories and checks that generated files and catalog HTML are byte-identical between versions. It warms each workload and reports the median of three runs by default. Compilation, network access, and archive generation are excluded. Git process counts are recorded separately from timing runs, and the optional asset comparison includes image extraction.

python3 scripts/benchmark.py --baseline /path/to/previous/sqzer-stagit \
  --baseline-assets /path/to/previous/readme_assets.py \
  --report .cache/performance-scaling.json

--baseline-assets is optional. Use --sizes, --history, --images, and --repeats to adjust file, commit, and image counts and repetitions. Compare binaries with the same site identity so the output equivalence check measures implementation changes. Security sanitization intentionally changes HTML; do not use a pre-sanitization binary as a byte-equivalence baseline.

Attribution and licenses

Project code is licensed under MIT; see LICENSE. Upstream stagit is a functional reference, and its notice is retained in third-party/stagit-LICENSE. MD4C's notice is retained in third-party/md4c-LICENSE. License files are copied into the generated site; no generator credit is displayed in the page footer. Cargo dependency license texts are retained in third-party/cargo-LICENSES.txt; regenerate them after lockfile changes with python3 scripts/license_notices.py.