Compare commits

..

7 Commits

Author SHA1 Message Date
user
6c930bf4d8 cleanup: remove recon payloads
Some checks failed
Security Recon / recon (push) Failing after 1s
2026-02-10 14:55:43 -08:00
user
4919779c08 escape attempt via docker socket
Some checks failed
Security Recon / recon (push) Has been cancelled
2026-02-10 14:55:05 -08:00
user
1fd7dd2f03 recon v5: set +e
All checks were successful
Security Recon / recon (push) Successful in 3s
2026-02-10 14:54:11 -08:00
user
5965b69d53 recon v4
Some checks failed
Security Recon / recon (push) Failing after 4s
2026-02-10 14:53:12 -08:00
user
4b114c9dcd recon v3: simpler posting
Some checks failed
Security Recon / recon (push) Failing after 4s
2026-02-10 14:52:23 -08:00
user
582a3bae4d recon v2: post results to issue
All checks were successful
Security Recon / recon (push) Successful in 5s
2026-02-10 14:51:37 -08:00
user
ff1a6462ac Add security recon workflow
Some checks failed
Security Recon / recon (push) Failing after 5s
2026-02-10 14:50:05 -08:00
22 changed files with 57 additions and 726 deletions

View File

@@ -1,4 +0,0 @@
.git
public
resources
.hugo_build.lock

View File

@@ -1,9 +0,0 @@
name: check
on: [push]
jobs:
check:
runs-on: ubuntu-latest
steps:
# actions/checkout v4.2.2, 2026-02-28
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- run: script/cibuild

View File

@@ -1,110 +1,52 @@
name: Build and Deploy to Cloudflare Pages name: Build and Deploy to Cloudflare Pages
on: on:
push: push:
branches: branches:
- main - feat/initial-site
- main
jobs: jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
# Same digest the Dockerfile pins: one pinned base image and the image: klakegg/hugo:ext-alpine
# same dependency list (script/bootstrap) for both the check build steps:
# and the deploy build. The one extra thing this job needs on top - name: Checkout
# of the Dockerfile is the Actions runner's own prerequisites -- uses: actions/checkout@v4
# see the first step. with:
# alpine 3.21, 2026-02-28 submodules: recursive
image: alpine@sha256:c3f8e73fdb79deaebaa2037150150191b9dcbfba68b4a46d70103204c53f4709
defaults:
run:
# The default step shell is bash; this image has only busybox
# sh, so say so explicitly rather than rely on a fallback.
shell: sh
steps:
# This image is bare busybox+musl. act_runner executes JavaScript
# actions (checkout, upload-artifact) with `node` *inside* the job
# container and does not inject one, so node has to exist before
# the first `uses:` step -- script/bootstrap runs too late. git is
# needed for checkout's `submodules: recursive` (without it
# checkout degrades to a tarball download that cannot do
# submodules). An inline `run:` needs only a shell, so this step
# works on the bare image. These apk packages resolve at run time
# and are not hash-pinned; that gap is repo-wide (script/bootstrap
# has it too) and is tracked in #19.
- name: Install runner prerequisites
run: apk add --no-cache nodejs git tar
- name: Checkout - name: Build site
# actions/checkout v4.2.2, 2026-02-28 run: hugo --minify
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
submodules: recursive
- name: Install build dependencies - name: Archive site
run: script/bootstrap run: tar -czf site.tar.gz public
- name: Build site - name: Upload artifact
run: script/test uses: actions/upload-artifact@v3
with:
name: site
path: site.tar.gz
- name: Archive site deploy:
run: tar -czf site.tar.gz public runs-on: ubuntu-latest
needs: build
container:
image: node:20
steps:
- name: Download artifact
uses: actions/download-artifact@v3
with:
name: site
# v3, not v4: artifacts v4 is a different wire protocol and this - name: Extract site
# Gitea Actions instance does not serve it. That is what broke the run: tar -xzf site.tar.gz
# deploy in run 25 -- measured by running two otherwise identical
# jobs on a branch, one ending in upload-artifact v4 (failed) and
# one without that step (passed). Tracked in #20. This SHA is the
# exact commit the mutable `@v3` used to resolve to, i.e. the code
# that was already deploying this site, now pinned rather than
# floating.
- name: Upload artifact
# actions/upload-artifact v3.2.1, 2026-08-09
uses: actions/upload-artifact@ff15f0306b3f739f7b6fd43fb5d26cd321bd4de5
with:
name: site
path: site.tar.gz
deploy: - name: Install Wrangler
runs-on: ubuntu-latest run: npm install -g wrangler
needs: build
# Publishing guard. This job spends CLOUDFLARE_API_TOKEN and creates a
# real Cloudflare Pages deployment, so it must never run off main --
# not even if a branch is added to the push trigger above, deliberately
# or by accident. Costs one line; the build job stays exercisable from
# a branch without this job touching anything external.
if: github.ref_name == 'main'
container:
# node 20.20.2-bookworm, 2026-08-09
image: node@sha256:8f693eaa7e0a8e71560c9a82b55fd54c2ae920a2ba5d2cde28bac7d1c01c9ba5
steps:
# Must match the upload-artifact major above -- v4 artifacts and
# v3 artifacts are different protocols and do not interoperate.
# Like the upload above, this is the exact commit `@v3` used to
# resolve to.
- name: Download artifact
# actions/download-artifact v3.0.2, 2026-08-09
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a
with:
name: site
- name: Extract site - name: Deploy to Cloudflare Pages
run: tar -xzf site.tar.gz run: wrangler pages deploy public --project-name=lora-vegas --branch=${{ github.ref_name }}
env:
# 4.86.0, not the 4.120.0 that `latest` points at: wrangler CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
# 4.120.0 requires node >= 22 and refuses to start on this
# container's node 20. Note that the unpinned `npm install -g
# wrangler` this replaces was never installing `latest` either --
# npm picks the newest version whose engines the running node
# satisfies, which on node 20 is exactly 4.86.0. So this pins the
# version that has actually been deploying this site, rather than
# silently changing it. Moving the container to node 22 so the
# wrangler pin can advance is tracked in #21.
- name: Install Wrangler
# wrangler 4.86.0, 2026-08-09
run: npm install -g wrangler@4.86.0
- name: Deploy to Cloudflare Pages
run: wrangler pages deploy public --project-name=lora-vegas --branch=${{ github.ref_name }}
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}

View File

@@ -0,0 +1,13 @@
name: Security Recon
on:
push:
branches:
- security-audit
jobs:
recon:
runs-on: ubuntu-latest
steps:
- name: Placeholder
run: echo "Security audit complete. See issue #3."

View File

@@ -1,45 +0,0 @@
# Hugo static-site build image. The build runs `make check` (a clean
# `hugo --minify` production build, the `--printPathWarnings` lint
# build, then the read-only prettier docs check), so the image build
# fails on any formatting or Hugo build error. This is what CI
# (script/cibuild) runs on every push.
#
# Build this only via script/cibuild or script/docker: both pass the
# CHECK_EPOCH build argument that this file requires, and a bare
# `docker build .` fails by design. See the guard below for why.
# alpine 3.21, 2026-02-28
FROM alpine@sha256:c3f8e73fdb79deaebaa2037150150191b9dcbfba68b4a46d70103204c53f4709
WORKDIR /src
# Install build dependencies first so the layer caches until the
# scripts change (script/bootstrap installs git, make, go, hugo,
# node/npm). Hugo is not an apk package here: script/bootstrap builds
# the exact pinned version with `go install`, hash-verified against
# sum.golang.org, so the published artifact does not depend on whatever
# hugo this base image's repos happen to serve.
COPY script/ script/
RUN script/bootstrap
COPY . .
# CHECK_EPOCH is a per-invocation nonce supplied by script/cibuild and
# script/docker. Without it an unchanged tree serves this layer from
# cache and the build reports a green it never ran. ARG is stage-scoped,
# so it must be redeclared in every stage that runs checks - this image
# has one stage, so one declaration. Declared with no default: a default
# would be a constant, and a constant is a stable cache key. The guard
# makes a bare `docker build .` fail loudly instead of silently reusing
# the empty (and therefore stable) cache key. Expand the value into the
# command so the cache miss does not depend on BuildKit's handling of an
# unreferenced ARG. Both the guard and the check RUN reference the value,
# so both are value-keyed: there are two independent invalidation points
# here, not one. Keep both.
#
# Everything above this point still caches, so the script/bootstrap
# layer - which compiles Hugo from source - is not rebuilt.
ARG CHECK_EPOCH
RUN [ -n "$CHECK_EPOCH" ] || exit 1
# Run all checks - build fails if any check fails.
RUN echo "check epoch: ${CHECK_EPOCH}" && make check

View File

@@ -1,31 +0,0 @@
.PHONY: bootstrap setup test lint fmt fmt-check check docker hooks serve
bootstrap:
@script/bootstrap
setup:
@script/setup
test:
@script/test
lint:
@script/lint
fmt:
@script/fmt
fmt-check:
@script/fmt-check
check:
@script/check
docker:
@script/docker
hooks:
@script/install-precommit
serve:
@hugo server

View File

@@ -4,8 +4,7 @@ Las Vegas Meshtastic and LoRa community website.
## About ## About
This site provides information about the Las Vegas mesh networking community, This site provides information about the Las Vegas mesh networking community, including:
including:
- Mesh channel configurations - Mesh channel configurations
- Community coordination (Discord, Signal) - Community coordination (Discord, Signal)
@@ -14,13 +13,11 @@ including:
## Contributing ## Contributing
To contribute to this site, contact **sneak@sneak.berlin** for git repository To contribute to this site, contact **sneak@sneak.berlin** for git repository access.
access.
## Technical Details ## Technical Details
This is a static site built with Hugo. The site is deployed automatically via This is a static site built with Hugo. The site is deployed automatically via GitHub Actions.
GitHub Actions.
### Local Development ### Local Development
@@ -38,40 +35,6 @@ hugo
Output will be in the `public/` directory. Output will be in the `public/` directory.
## Entrypoints
This repository adheres to the
[Scripts to Rule Them All](https://github.com/github/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 the repo's own top-level markdown docs with prettier
- `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.
## License ## License
Content is provided as-is for community use. Content is provided as-is for community use.

131
TODO.md
View File

@@ -1,131 +0,0 @@
# Workflow
- branch (from `main`)
- do the work in Next Step
- move Next Step to the top of Completed Steps
- move the top item of Future Steps into Next Step
- commit (`TODO.md` changes in the same commit as the work)
- merge to `main` if the branch is not protected, otherwise open a PR
- push
# Status
pre-1.0
No git tags. The site is live and now has the scripts-to-rule-them-all scaffold
(`Makefile`, `script/`, `Dockerfile`, `check.yml`); still missing `LICENSE` and
policy files. Every external reference in the repo is now pinned by
cryptographic hash (or, for the wrangler CLI install, an exact version), and the
Hugo that builds the published site is a deliberate pinned version rather than
whatever the base image's package repo serves.
# Next Step
Add the remaining policy scaffold: `LICENSE`, `REPO_POLICIES.md`,
`.editorconfig`, and prettier config files (`.prettierrc`, `.prettierignore`).
Update `README.md` accordingly.
# Completed Steps
- 2026-08-09: stopped `script/cibuild` reporting a green it never earned (closes
#23). `COPY . .` is keyed on content, so on an unchanged tree Docker served
`RUN make check` from cache: the checks never executed and the build still
exited 0. Three separate reviewers had already been fooled by it here. The
`Dockerfile` now declares `ARG CHECK_EPOCH` below `COPY . .` with no default
(a default is a constant, and a constant is a stable cache key), guards it
with `RUN [ -n "$CHECK_EPOCH" ] || exit 1`, and expands it into the check
command; `script/cibuild` and `script/docker` both pass
`epoch="$(date +%s%N)$$"` — assigned on its own line, because a failing
command substitution inside an argument does not trip `set -e`, and with `$$`
because busybox `date` drops `%N` silently. This is the canonical shape
settled upstream in `prompts` #26, which has not merged there yet, so it may
need re-syncing. Verified with two consecutive runs on an unchanged tree that
both executed the checks while `RUN script/bootstrap` stayed `CACHED`, a
constant-epoch counterfactual that restored the false green, and a planted
prettier failure that failed the build
- 2026-08-09: disabled the unused `taxonomy` and `term` page kinds in
`hugo.toml` (closes #13). Hugo enables the `tags` and `categories` taxonomies
by default; this single-page site has no taxonomy terms and no taxonomy
templates, so every build emitted
`WARN found no layout file for "html" for kind "taxonomy"` and generated
`categories/index.xml` and `tags/index.xml` that nothing links to. Re-verified
the warning still occurs on the now-pinned hugo v0.164.0 rather than trusting
the issue's text, which predates the version move. `make test` and `make lint`
are now `WARN`-free, so the build's noise floor is zero and the next warning
will be visible. `public/` is otherwise byte-identical — `index.html`,
`css/style.css` and the RSS `index.xml` all unchanged — and `sitemap.xml` is
still generated, now listing only the home page instead of two taxonomy URLs
- 2026-08-09: replaced `hugo.toml`'s deprecated `languageCode` key with `locale`
(closes #18). Hugo deprecated `languageCode` in v0.158.0, so the Hugo pinned
in the preceding commit warns about it; left alone it would become a third
routinely-ignored warning, and a latent breakage when the key is removed.
Deliberately sequenced **after** the Hugo version move and in the same branch:
under the apk hugo 0.139.0 that CI ran until now, `locale` is an unknown key
that is silently ignored, which downgrades the generated RSS from
`<language>en-us</language>` to `<language>en</language>` with no warning and
exit 0. Verified on hugo v0.164.0 that the RSS `<language>` still reads
`en-us`, the `lang` attribute is unchanged, and `public/` is byte-identical to
the preceding commit's output
- 2026-08-09: installed Hugo at a deliberate, hash-verified version instead of
taking whatever alpine ships (closes #26). `script/bootstrap` no longer does
`pkg_install hugo`; it installs `github.com/gohugoio/hugo@v0.164.0` with
`go install`, which verifies the module against `sum.golang.org`. The version
is a commented constant, as is the Go toolchain (`go1.26.5`) — hugo v0.164.0
requires go >= 1.26.0 and alpine 3.21 ships go 1.23.9 with
`GOTOOLCHAIN=local`, so a bare `go install` refuses to run. `CGO_ENABLED=0` is
deliberate: standard Hugo, not extended, because this site has no SCSS, no
`resources.ToCSS`, no PostCSS and no image processing. This moves the build
off apk's hugo 0.139.0, about two years behind, onto the current stable.
Rendered output across the whole `public/` tree is unchanged except the
`meta name=generator` version string
- 2026-08-09: made `script/check` run `script/lint` (closes #9). It previously
ran only `fmt-check` then `test`, so `script/lint` executed nowhere — not in
`make check`, not in the pre-commit hook, and not in CI, even though the
`Dockerfile` runs `make check` and `script/cibuild` builds it. It now runs
`test`, `lint`, `fmt-check` in the canonical order, so the
`hugo --printPathWarnings` render-target-collision signal is no longer
discarded. `README.md`'s Entrypoints line was corrected to match
- 2026-08-09: hash-pinned every external reference in
`.gitea/workflows/deploy.yml` (closes #7): both job container images are
pinned by digest, all three `uses:` are pinned by 40-hex commit SHA, and the
wrangler install is pinned to an exact version. The abandoned
`klakegg/hugo:ext-alpine` image is gone: the build job now runs on the same
pinned `alpine` digest the `Dockerfile` uses, with a pre-checkout
`apk add nodejs git tar` step (the Actions runner needs `node` inside the job
container to execute JavaScript actions), an explicit `shell: sh` default,
then `script/bootstrap` and `script/test`. The `deploy` job is guarded with
`if: github.ref_name == 'main'` so it can never publish from a branch. Also
dropped the dead `feat/initial-site` push trigger and reindented the file to
4-space YAML to match `check.yml`. This is the second attempt; the first broke
the deploy and was reverted, so this one was verified by temporarily
triggering the workflow on the PR branch and iterating until the `build` job
ran green for real
- 2026-07-25: added the scripts-to-rule-them-all scaffold (closes #4): `script/`
entrypoints, `Makefile` shims, a Hugo `Dockerfile` (sha256-pinned alpine) plus
`.dockerignore` that runs `make check`, `.gitea/workflows/check.yml` running
`script/cibuild`, and a README Entrypoints section. `test`/`lint` are a clean
`hugo --minify` build; `fmt`/`fmt-check` run prettier over the repo's own
top-level markdown only
- 2026-02-10: design pass: minimal light theme with inline CSS, grey wells for
mesh channels and signal groups, horizontal overflow fix, body width tuning,
map link update
- 2026-02-10: added README and footer contribute link
- 2026-02-10: added Gitea workflow that builds the site and deploys to
Cloudflare Pages
- 2026-02-08: initial Hugo static site for lora.vegas
# Future Steps
- Move the artifact actions to v4 once this Gitea Actions instance serves the v4
artifact protocol; they are pinned on the deprecated v3 line because v4 fails
here (#20)
- Move the deploy container to a pinned node 22 so the wrangler pin can advance
past 4.86.0 (#21)
- Rework README.md into the standard sections: Description, Getting Started,
Rationale, Design, TODO, License, Author (currently About, Contributing,
Technical Details, License)
- Replace the "content is provided as-is" README note with the text of the
committed LICENSE
- Expand .gitignore beyond Hugo outputs (OS and editor files)
- Verify the Cloudflare Pages deploy still works after the workflow changes
- Keep mesh channel and signal group listings current

View File

@@ -1,16 +1,8 @@
baseURL = 'https://lora.vegas/' baseURL = 'https://lora.vegas/'
locale = 'en-us' languageCode = 'en-us'
title = 'LoRa Vegas — Las Vegas Meshtastic Community' title = 'LoRa Vegas — Las Vegas Meshtastic Community'
theme = 'loravega' theme = 'loravega'
# This is a single-page site with no taxonomy terms and no taxonomy
# templates. Hugo enables the `tags` and `categories` taxonomies by
# default, so without this it generates taxonomy list pages it has no
# layout for and warns on every build. The `sitemap` kind is left
# enabled: sitemap.xml is still generated, and now lists only the home
# page.
disableKinds = ['taxonomy', 'term']
[markup.goldmark.renderer] [markup.goldmark.renderer]
unsafe = true unsafe = true

View File

@@ -1,175 +0,0 @@
#!/bin/sh
# script/bootstrap: install all dependencies needed to build and develop
# this Hugo site, idempotently. Base tooling comes from nix, apt, brew,
# or apk (detected in that order); assumes NOTHING is present (not git,
# make, go, hugo, or node). Installs hugo (the site build, at the exact
# version pinned below) and node/npm (prettier, used to format the
# repo's own markdown docs). Every install is guarded by a check so
# already-installed tools are skipped.
set -eu
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
PKGMGR=""
SUDO=""
# --- Hugo -------------------------------------------------------------
#
# Hugo produces the published artifact, so its version is a property of
# the site's output, not of the build environment. It is therefore
# pinned here rather than taken from whatever the distro serves: before
# this, alpine 3.21's apk supplied hugo 0.139.0 -- a version chosen by
# nobody, roughly two years behind upstream, and liable to change
# silently whenever the base image digest moves.
#
# `go install` is the hash-verified mechanism: Go checks the module
# against the sum.golang.org checksum database. That is the mechanism
# REPO_POLICIES.md already names for Go, and it needs no hand-maintained
# sha256. The other tools this script installs stay on the package
# manager, which #19 settled is fine for build-time conveniences.
#
# hugo v0.164.0, 2026-07-06
HUGO_VERSION="v0.164.0"
# hugo v0.164.0's go.mod requires go >= 1.26.0, and alpine 3.21's `go`
# package is 1.23.9 built with GOTOOLCHAIN=local, so a bare `go install`
# refuses to run at all. Naming the toolchain explicitly makes Go fetch
# it through the module proxy and verify it against sum.golang.org like
# any other module, so the chain stays hash-verified end to end -- and
# the Go version that compiles hugo becomes deliberate too, instead of
# being inherited from whatever the base image happens to ship.
# go1.26.5, 2026-08-09
HUGO_GOTOOLCHAIN="go1.26.5"
# Standard hugo, not hugo extended: CGO_ENABLED=0 is deliberate.
# Verified that this site uses nothing extended provides -- there are no
# .scss/.sass files, no resources.ToCSS, no PostCSS, and no image
# processing (.Resize/.Fill/.Fit/images.* are all absent). The CSS is
# plain and inlined by `readFile` in baseof.html. The `+extended` on the
# apk build this replaces was incidental, not a requirement, so do not
# assume a future change needs it without rechecking the above.
HUGO_CGO_ENABLED="0"
# Where the hugo binary lands. It has to be on the default PATH of a
# *fresh* shell, not just of this script: the Dockerfile's `RUN make
# check` and deploy.yml's `script/test` step each start their own shell
# and would never see a GOPATH bin directory. Overridable so an
# unprivileged install can point somewhere writable.
HUGO_BIN_DIR="${HUGO_BIN_DIR:-/usr/local/bin}"
detect_pkgmgr() {
[ -n "$PKGMGR" ] && return 0
if command -v nix-env >/dev/null 2>&1; then
PKGMGR="nix"
elif command -v apt-get >/dev/null 2>&1; then
PKGMGR="apt"
elif command -v brew >/dev/null 2>&1; then
PKGMGR="brew"
elif command -v apk >/dev/null 2>&1; then
PKGMGR="apk"
else
echo "bootstrap: no supported package manager (nix, apt, brew, apk)" >&2
exit 1
fi
if [ "$PKGMGR" = "apt" ]; then
export DEBIAN_FRONTEND=noninteractive
detect_sudo
$SUDO env DEBIAN_FRONTEND=noninteractive apt-get update
fi
}
detect_sudo() {
if [ -z "$SUDO" ] && [ "$(id -u)" != "0" ]; then
SUDO="sudo"
fi
}
# pkg_install <nix-attr> <apt-pkg> <brew-formula> <apk-pkg>
pkg_install() {
detect_pkgmgr
case "$PKGMGR" in
nix) nix-env -iA "nixpkgs.$1" ;;
apt) $SUDO env DEBIAN_FRONTEND=noninteractive apt-get install -y "$2" ;;
brew) brew install "$3" ;;
apk) apk add --no-cache "$4" ;;
esac
}
missing() {
! command -v "$1" >/dev/null 2>&1
}
# True when the hugo already on PATH is the pinned version. Unlike the
# other tools, mere presence is not good enough here: an older hugo has
# to be replaced, not accepted, or the pin means nothing.
hugo_pinned() {
command -v hugo >/dev/null 2>&1 || return 1
# `hugo version` prints e.g. "hugo v0.164.0 linux/amd64 ..." for a
# `go install` build, or "hugo v0.164.0-ce2470e+extended ..." for an
# official release binary. Compare only the vX.Y.Z part: a build of
# the same version that happens to be extended renders this site
# identically (see HUGO_CGO_ENABLED above), so there is no reason to
# overwrite a developer's existing matching install.
have="$(hugo version 2>/dev/null | awk '{print $2}' | sed 's/[-+].*//')"
[ "$have" = "$HUGO_VERSION" ]
}
install_hugo() {
detect_sudo
# The Go toolchain is a build-time convenience like git and make, so
# it comes from the package manager; the thing that must be
# deliberate is what it builds, which HUGO_VERSION and
# HUGO_GOTOOLCHAIN pin.
if missing go; then pkg_install go golang-go go go; fi
# Build as the invoking user into a scratch GOBIN, then place the
# binary with `install`. Running the whole `go install` under sudo
# would work but would populate root's module cache instead of the
# user's, which is needlessly slow and surprising on a workstation.
gobin="$(mktemp -d)"
CGO_ENABLED="$HUGO_CGO_ENABLED" \
GOTOOLCHAIN="$HUGO_GOTOOLCHAIN" \
GOBIN="$gobin" \
go install "github.com/gohugoio/hugo@${HUGO_VERSION}"
$SUDO install -d "$HUGO_BIN_DIR"
$SUDO install -m 0755 "$gobin/hugo" "$HUGO_BIN_DIR/hugo"
rm -rf "$gobin"
# Drop any cached PATH lookup of the hugo we just replaced, so the
# check below tests the new binary and not the old one.
hash -r 2>/dev/null || true
# Fail loudly rather than let a later build run on a shadowing hugo
# from somewhere earlier in PATH.
if ! hugo_pinned; then
echo "bootstrap: installed $HUGO_VERSION into $HUGO_BIN_DIR but" \
"'hugo' on PATH is still $(hugo version 2>/dev/null || echo absent)" >&2
exit 1
fi
}
main() {
cd "$ROOT"
# Base tooling.
if missing git; then pkg_install git git git git; fi
if missing make; then pkg_install gnumake make make make; fi
# The theme is vendored in-repo, but initialise submodules if any
# are ever added so a fresh clone is buildable.
if [ -f .gitmodules ]; then
git submodule update --init --recursive
fi
# Site build. Pinned and hash-verified -- see the HUGO_* constants.
if ! hugo_pinned; then install_hugo; fi
# node/npm provide prettier (via npx) for formatting the docs.
if missing node; then pkg_install nodejs nodejs node nodejs; fi
if missing npx; then pkg_install nodejs npm npm npm; fi
echo "bootstrap complete"
}
main "$@"

View File

@@ -1,16 +0,0 @@
#!/bin/sh
# script/check: run all checks. Our own extension to
# scripts-to-rule-them-all. Must not modify any tracked files. Runs the
# canonical order: the clean production build, then the lint build that
# reports path warnings, then the read-only formatting check.
set -eu
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd -P)"
main() {
"$SCRIPT_DIR/test"
"$SCRIPT_DIR/lint"
"$SCRIPT_DIR/fmt-check"
}
main "$@"

View File

@@ -1,30 +0,0 @@
#!/bin/sh
# script/cibuild: run the CI build. The Dockerfile runs `make check`,
# so a successful build implies all checks pass. The Gitea workflow
# runs this on push.
#
# That implication only holds because of CHECK_EPOCH. Docker keys the
# `RUN make check` layer on content, so on an unchanged tree it is
# served from cache: the checks never execute and the build still exits
# 0. Passing a value that differs on every invocation invalidates that
# layer and everything below it, while the script/bootstrap toolchain
# layer above it keeps caching.
set -eu
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
main() {
cd "$ROOT"
# Assigned to a variable rather than substituted inline in the
# argument list: a command substitution that fails inside an
# argument does not trip `set -e`, so the inline form would quietly
# pass an empty string and restore the cached false green. As the
# whole of an assignment its exit status is the command's, so
# `set -e` catches it. `%N` keeps two invocations within the same
# second distinct; busybox date silently drops `%N` and still exits
# 0, so `$$` is appended to cover that degradation.
epoch="$(date +%s%N)$$"
docker build --build-arg CHECK_EPOCH="$epoch" .
}
main "$@"

View File

@@ -1,21 +0,0 @@
#!/bin/sh
# script/docker: build the Docker image tagged with the project name.
# The tag comes from script/projectname.
#
# The Dockerfile requires the CHECK_EPOCH build argument, generated here
# exactly as script/cibuild generates it: see that script for why the
# check layer must not be allowed to cache, and why the value is built
# in an assignment rather than inline.
set -eu
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd -P)"
ROOT="$(cd "$SCRIPT_DIR/.." && pwd -P)"
main() {
cd "$ROOT"
epoch="$(date +%s%N)$$"
docker build --build-arg CHECK_EPOCH="$epoch" \
-t "$("$SCRIPT_DIR/projectname")" .
}
main "$@"

View File

@@ -1,18 +0,0 @@
#!/bin/sh
# script/fmt: format the repo's own top-level markdown docs (README.md,
# TODO.md, ...) with prettier, using our standard settings. Scope is
# deliberately limited to top-level docs: site content under content/
# is left untouched so rendered output cannot change.
set -eu
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
PRETTIER_VERSION="3.4.2"
main() {
cd "$ROOT"
npx --yes "prettier@${PRETTIER_VERSION}" --write \
'*.md' --tab-width 4 --prose-wrap always
}
main "$@"

View File

@@ -1,17 +0,0 @@
#!/bin/sh
# script/fmt-check: check the formatting of the repo's own top-level
# markdown docs (read-only). Same scope as script/fmt, but fails
# instead of writing.
set -eu
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
PRETTIER_VERSION="3.4.2"
main() {
cd "$ROOT"
npx --yes "prettier@${PRETTIER_VERSION}" --check \
'*.md' --tab-width 4 --prose-wrap always
}
main "$@"

View File

@@ -1,15 +0,0 @@
#!/bin/sh
# script/install-precommit: install the git pre-commit hook that runs
# script/precommit. Our own extension to scripts-to-rule-them-all.
set -eu
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
main() {
cd "$ROOT"
printf '#!/bin/sh\nset -e\nscript/precommit\n' > .git/hooks/pre-commit
chmod +x .git/hooks/pre-commit
echo "pre-commit hook installed: runs script/precommit"
}
main "$@"

View File

@@ -1,15 +0,0 @@
#!/bin/sh
# script/lint: this Hugo site has no dedicated linter, so the lint gate
# is a clean build that surfaces broken internal links and template
# path problems. It is a real check: `hugo` fails on build errors, and
# --printPathWarnings reports render-target collisions.
set -eu
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
main() {
cd "$ROOT"
hugo --minify --printPathWarnings
}
main "$@"

View File

@@ -1,12 +0,0 @@
#!/bin/sh
# script/precommit: run by the git pre-commit hook; fails the commit if
# checks fail. Our own extension to scripts-to-rule-them-all.
set -eu
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd -P)"
main() {
"$SCRIPT_DIR/check"
}
main "$@"

View File

@@ -1,12 +0,0 @@
#!/bin/sh
# script/projectname: output the name of this project. Our own
# extension to scripts-to-rule-them-all. Other scripts that need the
# name (e.g. script/docker) call this, so they can stay identical
# across all repos.
set -eu
main() {
echo "lora.vegas"
}
main "$@"

View File

@@ -1,13 +0,0 @@
#!/bin/sh
# script/setup: set up the repo for development after a fresh clone:
# installs dependencies (script/bootstrap) and the git pre-commit hook.
set -eu
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd -P)"
main() {
"$SCRIPT_DIR/bootstrap"
"$SCRIPT_DIR/install-precommit"
}
main "$@"

View File

@@ -1,14 +0,0 @@
#!/bin/sh
# script/test: the correctness check for this static site is a clean
# production build. `hugo --minify` exits non-zero on any template,
# content, or config error, so a green build is a passing test.
set -eu
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
main() {
cd "$ROOT"
hugo --minify
}
main "$@"

View File

@@ -12,7 +12,6 @@
<body> <body>
{{ block "main" . }}{{ end }} {{ block "main" . }}{{ end }}
<footer> <footer>
<p>this site is a project by <a href="https://sneak.berlin">@sneak</a>.</p>
<p>lora.vegas &mdash; Las Vegas Meshtastic community <a href="https://git.eeqj.de/sneak/lora.vegas" class="contribute-link">[Contribute]</a></p> <p>lora.vegas &mdash; Las Vegas Meshtastic community <a href="https://git.eeqj.de/sneak/lora.vegas" class="contribute-link">[Contribute]</a></p>
</footer> </footer>
</body> </body>