Merge main and reconcile repository policies
ober
c9e0097d8e72fd2c78fba03787e92db08c240286
new file mode 100755 --- /dev/null +++ b/.forgejo/ci-required.sh @@ -0,0 +1,76 @@ +#!/bin/sh +set -eu + +if [ -n "${MAKE:-}" ]; then + MAKE_CMD=$MAKE +elif command -v gmake >/dev/null 2>&1; then + MAKE_CMD=gmake +else + MAKE_CMD=make +fi + +has_target() { + target=$1 + [ -f Makefile ] && grep -Eq "^${target}[[:space:]]*:" Makefile +} + +if has_target verify; then + "$MAKE_CMD" verify +else + ran=0 + for target in security test check build; do + if has_target "$target"; then + "$MAKE_CMD" "$target" + ran=1 + fi + done + [ "$ran" = 1 ] || { + echo "ERROR: no verify, test, check, or build target is available" >&2 + exit 1 + } +fi + +if ! has_target binary; then + echo "No standalone binary target; full repository verification passed." + exit 0 +fi + +"$MAKE_CMD" binary + +if has_target binary-smoke; then + "$MAKE_CMD" binary-smoke + exit 0 +fi +if has_target smoke; then + "$MAKE_CMD" smoke + exit 0 +fi + +binary_list=$(mktemp) +trap 'rm -f "$binary_list"' EXIT HUP INT TERM +find . -maxdepth 3 -type f -perm -111 ! -path './.git/*' ! -path './.jerboa/*' ! -path './vendor/*' ! -path './test/*' ! -path './tests/*' -exec file {} \; | + awk -F: '/(ELF .*executable|Mach-O .*executable)/ { print $1 }' > "$binary_list" + +[ -s "$binary_list" ] || { + echo "ERROR: make binary succeeded but produced no runnable executable" >&2 + exit 1 +} + +while IFS= read -r binary; do + echo "Smoke-checking $binary" + if command -v timeout >/dev/null 2>&1; then + run_with_timeout() { timeout 30 "$@"; } + else + run_with_timeout() { "$@"; } + fi + if run_with_timeout env QT_QPA_PLATFORM=offscreen QTWEBENGINE_CHROMIUM_FLAGS=--disable-gpu "$binary" --version >/dev/null 2>&1; then + continue + fi + if run_with_timeout env QT_QPA_PLATFORM=offscreen QTWEBENGINE_CHROMIUM_FLAGS=--disable-gpu "$binary" --help >/dev/null 2>&1; then + continue + fi + echo "ERROR: $binary failed both --version and --help runtime smoke checks" >&2 + exit 1 +done < "$binary_list" + +echo "Full verification, binary build, and runtime smoke checks passed." new file mode 100755 --- /dev/null +++ b/.forgejo/require-version-bump.sh @@ -0,0 +1,38 @@ +#!/bin/sh +set -eu +base_ref=${1:-origin/${GITHUB_BASE_REF:-${FORGEJO_BASE_REF:-master}}} +head_ref=${2:-HEAD} + +current_version() { + if [ -f VERSION ]; then + tr -d '[:space:]' < VERSION + elif [ -f Cargo.toml ]; then + sed -n '0,/^version[[:space:]]*=/s/^version[[:space:]]*=[[:space:]]*"\([^"]*\)".*//p' Cargo.toml | head -1 + elif [ -f package.json ]; then + sed -n 's/.*"version"[[:space:]]*:[[:space:]]*"\([^"]*\)".*//p' package.json | head -1 + else + echo "0.0.0" + fi +} + +old=$(git show "$base_ref:VERSION" 2>/dev/null | tr -d '[:space:]' || echo 0.0.0) +new=$(current_version) +case "$new" in + [0-9]*.[0-9]*.[0-9]*) ;; + *) echo "ERROR: VERSION must be semantic version MAJOR.MINOR.PATCH, got '$new'" >&2; exit 1 ;; +esac +if [ "$old" = "$new" ]; then + echo "ERROR: version did not advance: $old" >&2 + exit 1 +fi +python3 - "$old" "$new" <<'PY2' +import sys +old=sys.argv[1]; new=sys.argv[2] +def parse(v): + try: return tuple(int(x) for x in v.split('.')[:3]) + except Exception: return (0,0,0) +if parse(new) <= parse(old): + print(f"ERROR: version must increase: {old} -> {new}", file=sys.stderr) + sys.exit(1) +print(f"VERSION {new} is valid") +PY2 new file mode 100644 --- /dev/null +++ b/.forgejo/workflows/ci.yaml @@ -0,0 +1,25 @@ +name: required-ci + +on: + pull_request: + branches: [main] + push: + branches: [main] + tags: ['v*'] + workflow_dispatch: + +jobs: + required: + runs-on: freebsd-amd64 + steps: + - name: Check runner tools + run: | + for tool in sh git gmake file; do + command -v "$tool" + done + - name: Check out repository + uses: https://code.forgejo.org/actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 + with: + persist-credentials: false + - name: Build, test, and smoke-check + run: sh .forgejo/ci-required.sh new file mode 100644 --- /dev/null +++ b/.forgejo/workflows/version-policy.yaml @@ -0,0 +1,19 @@ +name: version-policy + +on: + pull_request: + branches: [main] + +jobs: + required: + runs-on: freebsd-amd64 + steps: + - name: Check runner tools + run: command -v git + - name: Check out full history + uses: https://code.forgejo.org/actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 + with: + fetch-depth: 0 + persist-credentials: false + - name: Require semantic version advancement + run: sh .forgejo/require-version-bump.sh origin/main HEAD new file mode 100644 --- /dev/null +++ b/.gitsafeignore @@ -0,0 +1,5 @@ +.forgejo/workflows/ci.yaml:high-entropy-hex:24 +.forgejo/workflows/ci.yaml:high-entropy-hex:37 +.forgejo/workflows/ci.yaml:high-entropy-hex:39 +.forgejo/workflows/ci.yaml:high-entropy-hex:63 +.forgejo/workflows/version-policy.yaml:high-entropy-hex:18 --- a/AGENTS.md +++ b/AGENTS.md @@ -4,6 +4,24 @@ Always commit development changes only in the matching `/Users/user/mine/jerboa- Before starting work that compares against or uses a vendor checkout, update that vendor checkout to the latest revision and verify it matches exactly with the corresponding `/Users/user/mine/jerboa-*` repository state. If they differ, stop and sync from `/Users/user/mine/jerboa-*` before making or committing changes. The `/Users/user/mine/jerboa-*` worktree must always represent the latest authoritative version. +## STOP: Forgejo Pull Requests Are Mandatory + +Every change to this repository must use the Forgejo pull-request workflow. + +1. Start from the current remote default branch and create a dedicated feature, fix, or chore branch **before editing**. +2. Make only the scoped changes on that branch. +3. Run every repository-required test and build. If the repository produces binaries, build them and run a meaningful smoke check (such as the documented startup, `--help`, or `--version`). Do not commit while any required check fails. +4. Commit the verified changes on the feature branch and push that branch to `origin`. +5. Open a pull request on `git.jerboa.sh` targeting the default branch. A human must review, approve, and merge it. + +Absolute bans: never commit or push directly to `main` or `master`; never self-approve or self-merge; never bypass branch protection; and never leave completed changes only in a local branch. Release work and urgent fixes follow the same branch-and-PR process. + +### Every PR Must Advance the Version + +`VERSION` is the authoritative repository version. Every pull request must change it to a strictly greater semantic version (`MAJOR.MINOR.PATCH`). Use a patch increment for fixes and maintenance, a minor increment for backward-compatible features, and a major increment for breaking changes. Keep package manifests, generated version constants, release artifact names, and user-visible version output synchronized with `VERSION`. + +Forgejo CI compares the proposed `VERSION` with the target branch and rejects an unchanged, malformed, or lower version. + ## STOP: Editing `.ss`/`.sls` Files — Mandatory Rules These rules exist because local-model sessions have lost **hours** fighting @@ -376,30 +394,26 @@ improved versions of the above. When working in a Jerboa project, **ONLY modify files in the current repo** unless the user explicitly names another path. -### Release Distribution: git.jerboa.sh Only +### Git Hosting & Release Distribution: git.jerboa.sh Only -**Never use SourceHut or GitHub Releases, release URLs, mirrors, or fallbacks -for Jerboa artifacts.** The canonical human-facing repository URL is -`https://git.jerboa.sh/ober/jerboa`. Publish release files on the matching -versioned release at `git.jerboa.sh`; consumers download them from +**Never use SourceHut or GitHub** for remotes, dependency fetches, release +artifacts, mirrors, or fallbacks. All Jerboa repositories and versioned release +assets live on `git.jerboa.sh`. Publish through Forgejo releases and download +artifacts from `https://git.jerboa.sh/ober/jerboa/releases/download/<tag>/<artifact>`. -If delivery needs work, repair or configure the `git.jerboa.sh` release path. -Do not reintroduce SourceHut or add a GitHub mirror. - Common sibling repos that exist but must NOT be touched without explicit instruction: -- `~/mine/jerboa-mcp` — Legacy node MCP, superseded. The active MCP server now lives in THIS repo at `mcp/` + `data/`. Don't modify the legacy repo unless told. -- `~/mine/jerboa-shell` — Only modify when user explicitly says to work there. -- `~/mine/gerbil-mcp` — **NEVER touch**. Deprecated. -- `~/mine/gerbil-orig` — Read-only reference for upstream Gerbil. Never modify. +- the legacy Jerboa MCP sibling checkout — Legacy node MCP, superseded. The active MCP server now lives in THIS repo at `mcp/` + `data/`. Don't modify the legacy repo unless told. +- the Jerboa shell sibling checkout — Only modify when user explicitly says to work there. +- the deprecated Gerbil MCP sibling checkout — **NEVER touch**. Deprecated. +- the upstream Gerbil reference checkout — Read-only reference for upstream Gerbil. Never modify. If a user instruction mentions a file path, use EXACTLY that path. Do not substitute a similar-looking path from another repo. ### Never Reference Sibling Checkouts in Build Files Build files (Makefile, shell scripts, CI config) must **never** resolve a -dependency via a relative sibling path (`../jerboa-foo`) or an absolute -`~/mine/jerboa-foo` path. That layout is specific to this one machine — +dependency via a relative sibling path (`..`-relative) or an absolute machine-specific sibling path. That layout is specific to this one machine — other users and CI do not have it. Always vendor instead: fetch/clone the dependency into `vendor/` (or this repo's equivalent) at build time, or use a pinned-release fetch script, so the build is reproducible without @@ -409,7 +423,7 @@ A sibling-path fallback is not just a portability bug: it can silently substitute a full alternate source tree (build config, embedded data, secrets) for the vendored one, with no equivalent safety default, changing what actually gets built without any indication. If you find one -(`grep -rn '\.\./jerboa\|~/mine/jerboa'` over Makefiles/scripts), remove it +(for example, any sibling-checkout reference in Makefiles or scripts), remove it and vendor properly instead. --- new file mode 100644 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +0.1.3 --- a/jpkg.sexp +++ b/jpkg.sexp @@ -1,6 +1,6 @@ (package (name "@ober/gitsite") - (version "0.1.0") + (version "0.1.2") (description "Minimal self-hosted git forge in Jerboa") (license "MIT") (source "https://git.jerboa.sh/ober/jerboa-gitsite")