clawbot 8d639aa258
All checks were successful
check / check (push) Successful in 9s
Add a Cloudflare Pages _headers file with baseline security headers (closes #14)
Hugo copies static/ verbatim into public/, so static/_headers lands at
the deploy output root, which is where Pages reads it from. This is the
first root-level static/ in the repo; Hugo unions it with the theme's
static/ per path rather than shadowing it, and the built tree confirms
that: public/css/style.css and public/index.html are byte-identical to
the previous build and the static file count goes from 1 to 2.

The live "before" was measured rather than assumed. Cloudflare already
sends X-Content-Type-Options and Referrer-Policy by default, so those
two lines are restatements; the substance is Strict-Transport-Security,
Content-Security-Policy, X-Frame-Options and Permissions-Policy, none of
which the site sends today.

Every value is checked against the built page, which loads nothing: no
script, img, link, iframe, form or media element, no style= and no on*=
attribute. It has exactly one inline <style> block, filled by readFile
in baseof.html. So default-src 'none' with style-src 'unsafe-inline' is
both achievable and tight, and 'unsafe-inline' is required by, and only
by, that deliberate inlining. There is no script-src allowance because
there are no scripts. X-Frame-Options: DENY and frame-ancestors 'none'
agree.

HSTS carries neither preload nor includeSubDomains. www.lora.vegas is
the only other name in DNS and it is served by this same Pages project,
so this file sets HSTS on its responses directly; includeSubDomains
would instead bind every future subdomain for a year, with no way to
walk it back inside the max-age window without also dropping the apex
protection.

Verified in a headless Chrome against a local server that parses the
committed _headers and applies it as real response headers: zero CSP
violations, the inlined stylesheet parses to 17 rules with the computed
body padding, tagline colour and link colour all coming from the theme
CSS, framing from another origin refused by frame-ancestors, and all
five named outbound links still navigating with status 200.

Whether Pages actually parses the file cannot be verified from here.
Pages silently ignores a malformed _headers, so the green build proves
nothing about it; that check belongs after the next deploy and must be
made on Strict-Transport-Security or Content-Security-Policy, since
X-Content-Type-Options would pass either way.
2026-08-09 16:50:27 +00:00

lora.vegas

lora.vegas is the website of the Las Vegas Meshtastic and LoRa community: a single-page static site, built with Hugo, by @sneak.

It publishes what the local mesh needs in one linkable place:

  • Mesh channel configurations
  • Community coordination links (Discord, Signal)
  • Meetup information
  • Local resources

Getting Started

From a fresh clone, make setup installs every build dependency (git, make, go, the pinned Hugo, node/npm) and the git pre-commit hook, and make serve starts the Hugo development server:

git clone git@git.eeqj.de:sneak/lora.vegas.git
cd lora.vegas
make setup
make serve

Then open http://localhost:1313 to preview the site.

To produce the production build, which writes the rendered site to public/:

make test

Before committing, run the full check suite — the production build, the lint build, and the formatting check:

make check

make fmt rewrites the repo's markdown and CSS to the project's prettier settings; run it if make check fails on formatting.

To contribute to this site, contact sneak@sneak.berlin for git repository access.

Entrypoints

This repository adheres to the Scripts to Rule Them All standard: normalized scripts in script/ are the entrypoints for the development workflow, and the Makefile targets are thin shims that call them. We provide:

  • script/bootstrap — install all build dependencies (git, make, go, hugo, node/npm) idempotently. Hugo is pinned to an exact version and installed with go install, which verifies it against sum.golang.org; the version is the HUGO_VERSION constant at the top of the script
  • script/setup — prepare a fresh clone: run script/bootstrap and install the git pre-commit hook
  • script/test — the correctness check: a clean hugo --minify production build
  • script/lint — a clean build that surfaces broken links and path collisions
  • script/fmt — format every markdown and CSS file in the repo with prettier; the exclusions live in .prettierignore with the reason for each
  • script/fmt-check — check that formatting (read-only)
  • script/check — run script/test, script/lint, then script/fmt-check; modifies no tracked files
  • script/docker — build the Docker image tagged with the project name
  • script/cibuild — the CI build; the Dockerfile runs make check
  • script/install-precommit — install the git pre-commit hook that runs script/check

Build the image through script/cibuild or script/docker only. Both pass a per-invocation CHECK_EPOCH build argument that the Dockerfile requires, so the make check layer can never be served from cache — without it Docker returns a green it did not earn. A bare docker build . fails closed on the Dockerfile's CHECK_EPOCH guard rather than caching its way to a false success.

A convenience make serve target runs hugo server for local preview.

Rationale

The Las Vegas Meshtastic and LoRa community needs one durable, linkable place for its channel configurations and group links. Those details otherwise live inside a Discord or Signal thread, where they scroll away, cannot be linked to from outside, are invisible to anyone who has not already joined, and quietly go stale. A static site at a stable domain is the opposite of that: one URL to hand to a newcomer, and one place to correct when a channel changes.

Design

The site is a single page. All of its content is one Hugo content file, content/_index.md, rendered by a minimal theme vendored in-repo at themes/loravega/ — there is no upstream theme dependency and no submodule.

The theme's layouts/_default/baseof.html inlines themes/loravega/static/css/style.css into a <style> block with Hugo's readFile, so the whole site ships as a single HTML document with no external CSS request and no second round trip.

hugo --minify builds the site into public/. Deployment is automatic: on push to main, the Gitea Actions workflow .gitea/workflows/deploy.yml builds the site and publishes public/ to Cloudflare Pages.

TODO

The live task list is in TODO.md.

License

Content is provided as-is for community use.

Author

@sneak

Description
No description provided
https://lora.vegas
Readme MIT 320 KiB
Languages
Shell 72.9%
Dockerfile 13.4%
CSS 8.1%
HTML 3.7%
Makefile 1.9%