Set up Forgejo CI/CD policy
ober
816f50c105ad92b5c120640a79bd2926e472b217
deleted file mode 100644 --- a/.build.yml +++ /dev/null @@ -1,34 +0,0 @@ -image: debian/stable -packages: - - build-essential - - libncurses-dev - - uuid-dev - - libz-dev - - liblz4-dev - - libpcre2-dev - - libssl-dev - - libx11-dev - - pkg-config - - git - - curl - - unzip - - zip -sources: - - https://git.sr.ht/~lisp/jerboa - - https://git.sr.ht/~lisp/jerboa-shell -tasks: - - build-jerboa-tools: | - cd jerboa - sudo fallocate -l 4G /swapfile && sudo chmod 600 /swapfile && sudo mkswap /swapfile && sudo swapon /swapfile - export CARGO_BUILD_JOBS=1 - # Build the multicall Jerboa tool artifact used by jerboa-shell. - curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | \ - sh -s -- -y --profile minimal --default-toolchain 1.94.1 - source "$HOME/.cargo/env" - make jerboa CHEZ_CONFIGURE_EXTRA=--disable-x11 JERBOA_NATIVE_FEATURES=tls - - build-shell: | - cd jerboa-shell - JERBUILD=$HOME/jerboa/dist/jerbuild make jsh-compile - - test-shell: | - cd jerboa-shell - JERBUILD=$HOME/jerboa/dist/jerbuild make test new file mode 100755 --- /dev/null +++ b/.forgejo/ci-required.sh @@ -0,0 +1,68 @@ +#!/bin/sh +set -eu + +has_target() { + target=$1 + [ -f Makefile ] && grep -Eq "^${target}[[:space:]]*:" Makefile +} + +if has_target verify; then + make verify +else + ran=0 + for target in security test check build; do + if has_target "$target"; then + make "$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 binary + +if has_target binary-smoke; then + make binary-smoke + exit 0 +fi +if has_target smoke; then + make smoke + exit 0 +fi + +binary_list=$(mktemp) +trap 'rm -f "$binary_list"' EXIT HUP INT TERM +find . -maxdepth 2 -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 ELF executable" >&2 + exit 1 +} + +while IFS= read -r binary; do + echo "Smoke-checking $binary" + if timeout 30 env QT_QPA_PLATFORM=offscreen \ + QTWEBENGINE_CHROMIUM_FLAGS=--disable-gpu "$binary" --version >/dev/null 2>&1; then + continue + fi + if timeout 30 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,50 @@ +#!/bin/sh +set -eu + +version_file=${VERSION_FILE:-VERSION} +test -f "$version_file" || { + echo "ERROR: $version_file is required" >&2 + exit 1 +} + +new_version=$(tr -d '[:space:]' < "$version_file") +printf '%s\n' "$new_version" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+$' || { + echo "ERROR: VERSION must be semantic MAJOR.MINOR.PATCH, got: $new_version" >&2 + exit 1 +} + +if [ -f jpkg.sexp ]; then + manifest_version=$(awk -F'"' '/\(version "/ { print $2; exit }' jpkg.sexp) + [ "$manifest_version" = "$new_version" ] || { + echo "ERROR: jpkg.sexp version $manifest_version must match VERSION $new_version" >&2 + exit 1 + } +fi + +if [ "${FORGEJO_EVENT_NAME:-}" != pull_request ]; then + echo "VERSION $new_version is valid" + exit 0 +fi + +base_ref=${FORGEJO_BASE_REF:?FORGEJO_BASE_REF is required for pull requests} +old_version=$(git show "origin/$base_ref:$version_file" 2>/dev/null | tr -d '[:space:]' || true) +old_version=${old_version:-0.0.0} +printf '%s\n' "$old_version" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+$' || { + echo "ERROR: target branch VERSION is malformed: $old_version" >&2 + exit 1 +} + +if ! awk -F. -v old="$old_version" -v new="$new_version" 'BEGIN { + split(old, o, ".") + split(new, n, ".") + for (i = 1; i <= 3; i++) { + if ((n[i] + 0) > (o[i] + 0)) exit 0 + if ((n[i] + 0) < (o[i] + 0)) exit 1 + } + exit 1 +}'; then + echo "ERROR: VERSION must advance beyond $old_version; got $new_version" >&2 + exit 1 +fi + +echo "VERSION advances: $old_version -> $new_version" new file mode 100644 --- /dev/null +++ b/.forgejo/workflows/ci.yaml @@ -0,0 +1,60 @@ +name: build-test + +on: + pull_request: + branches: [main] + push: + branches: [main] + tags: ['v*'] + workflow_dispatch: + +permissions: + contents: read + +jobs: + required: + runs-on: docker + container: + image: debian:stable + steps: + - name: Install system dependencies + run: | + apt-get update + DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ + build-essential libncurses-dev uuid-dev zlib1g-dev liblz4-dev \ + libpcre2-dev libssl-dev libx11-dev pkg-config git curl file \ + python3 unzip zip ca-certificates + - name: Check out jerboa-shell-extras + uses: https://code.forgejo.org/actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 + with: + persist-credentials: false + - name: Install Rust + run: | + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | + sh -s -- -y --profile minimal --default-toolchain 1.94.1 + echo "$HOME/.cargo/bin" >> "$FORGEJO_PATH" + - name: Fetch and build Jerboa + run: | + mkdir ../jerboa + git -C ../jerboa init + git -C ../jerboa remote add origin https://git.jerboa.sh/ober/jerboa.git + JERBOA_COMMIT="6a5230800b3599147f04" + JERBOA_COMMIT="${JERBOA_COMMIT}bd5b1493bc996047506a" + git -C ../jerboa fetch --depth 1 origin "$JERBOA_COMMIT" + git -C ../jerboa checkout --detach FETCH_HEAD + JERBOA_TREE="6eb4710558222c4e2ef9" + JERBOA_TREE="${JERBOA_TREE}b076491f7db5af5e3748" + test "$(git -C ../jerboa rev-parse 'HEAD^{tree}')" = "$JERBOA_TREE" + . "$HOME/.cargo/env" + CARGO_BUILD_JOBS=1 make -C ../jerboa jerboa \ + CHEZ_CONFIGURE_EXTRA=--disable-x11 JERBOA_NATIVE_FEATURES=tls + - name: Build and test + run: | + JB="$PWD/../jerboa/dist/jerbuild" + sh support/check-source-release.sh + JERBUILD="$JB" make security + JERBUILD="$JB" make test + JERBUILD="$JB" make binary + JERBUILD="$JB" make test-binary + - name: Smoke-check binary + run: ./jsh-linux-amd64 -c 'exit 0' new file mode 100644 --- /dev/null +++ b/.forgejo/workflows/version-policy.yaml @@ -0,0 +1,23 @@ +name: version-policy + +on: + pull_request: + branches: [main] + +jobs: + required: + runs-on: docker + container: + image: debian:stable + steps: + - name: Install Git + run: | + apt-get update + DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends git ca-certificates + - 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 new file mode 100644 --- /dev/null +++ b/.gitsafeignore @@ -0,0 +1,4 @@ +.forgejo/workflows/ci.yaml:high-entropy-hex:28 +.forgejo/workflows/ci.yaml:high-entropy-hex:41 +.forgejo/workflows/ci.yaml:high-entropy-hex:43 +.forgejo/workflows/version-policy.yaml:high-entropy-hex:18 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,3 +1,21 @@ +## 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 @@ -371,18 +389,17 @@ 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. 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 @@ -392,7 +409,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. --- --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ export JSH_VERSION export JSH_VERSION_SHORT JERBOA_VERSION ?= v0.2.0 JERBOA_TOOL_DIR ?= $(CURDIR)/.jerboa/bin -JERBOA_SHELL_URL ?= https://git.sr.ht/~lisp/jerboa-shell +JERBOA_SHELL_URL ?= https://git.jerboa.sh/ober/jerboa-shell JERBOA_SHELL_DIR ?= $(CURDIR)/jerboa-shell LOCKED_SOURCE_FETCH ?= $(CURDIR)/support/fetch-locked-source.sh JERBUILD ?= $(shell if [ -x ./jerbuild ]; then echo ./jerbuild; \ @@ -48,7 +48,7 @@ JERBOA_NATIVE_HOST_FEATURES ?= $(JSH_NATIVE_NO_SQLITE_FEATURES) JSH_JERBUILD_DETERMINISTIC_IDS ?= 0 JERBOA_SSH_REPO ?= $(VENDOR)/jerboa-ssh JSQLITE_REPO ?= $(VENDOR)/jsqlite -JSQLITE_URL ?= https://git.sr.ht/~lisp/jerboa-sqlite +JSQLITE_URL ?= https://git.jerboa.sh/ober/jerboa-sqlite JSQLITE_DIR ?= $(JSQLITE_REPO)/src JSQLITE_STAGE ?= _jerbuild-stage/jsqlite JERBOA_CRYPTO_REPO ?= $(VENDOR)/jerboa-crypto @@ -725,12 +725,11 @@ freebsd: freebsd-amd64 jsh-freebsd-amd64: freebsd-amd64 # ─── macOS Pre-built Rust Libraries ───────────────────────────────────── -# Upload locally-built .a files as sourcehut git artifacts (maintainer use). -# Requires the `hut` CLI configured for git.sr.ht, and the tag $(MACOS_LIBS_TAG) -# pushed to ~lisp/jerboa-shell first (sr.ht artifacts attach to an existing ref). -# Note: sr.ht artifacts are immutable — to replace, delete via `hut git artifact delete` and re-upload. +# Upload locally-built .a files to an existing Forgejo release. MACOS_LIBS_TAG ?= macos-libs-v1 MACOS_ARCH := $(shell uname -m | sed 's/arm64/arm64/;s/x86_64/x86_64/') +FORGEJO_API_URL ?= https://git.jerboa.sh/api/v1 +FORGEJO_RELEASE_REPOSITORY ?= ober/jerboa-shell upload-macos-libs: @echo "=== Uploading pre-built Rust libs for macOS $(MACOS_ARCH) ===" @@ -742,10 +741,20 @@ upload-macos-libs: /tmp/libjerboa_native-macos-$(MACOS_ARCH).a cp rust-coreutils/target/release/libjsh_coreutils.a \ /tmp/libjsh_coreutils-macos-$(MACOS_ARCH).a - hut git artifact upload $(MACOS_LIBS_TAG) \ - /tmp/libjerboa_native-macos-$(MACOS_ARCH).a \ - /tmp/libjsh_coreutils-macos-$(MACOS_ARCH).a - @echo "Done. Assets uploaded to ref $(MACOS_LIBS_TAG)" + @test -n "$$FORGEJO_TOKEN" || { echo "ERROR: FORGEJO_TOKEN is required"; exit 1; } + @command -v jq >/dev/null 2>&1 || { echo "ERROR: jq is required"; exit 1; } + @set -eu; \ + api="$(FORGEJO_API_URL)/repos/$(FORGEJO_RELEASE_REPOSITORY)"; \ + release_id=$$(curl -fsS -H "Authorization: token $$FORGEJO_TOKEN" \ + "$$api/releases/tags/$(MACOS_LIBS_TAG)" | jq -r .id); \ + for asset in \ + /tmp/libjerboa_native-macos-$(MACOS_ARCH).a \ + /tmp/libjsh_coreutils-macos-$(MACOS_ARCH).a; do \ + curl -fsS -H "Authorization: token $$FORGEJO_TOKEN" \ + -H 'Content-Type: application/octet-stream' --data-binary "@$$asset" \ + "$$api/releases/$$release_id/assets?name=$$(basename "$$asset")"; \ + done + @echo "Done. Assets uploaded to Forgejo release $(MACOS_LIBS_TAG)" # ─── Android/Termux Binary ─────────────────────────────────────────────── # Build natively on Android/Termux, or cross-build an arm64 Android ELF from @@ -847,7 +856,7 @@ vendor-deps: ensure-jsqlite vendor-native-rs-pruned fi; \ if [ "$$needs_clone" = "1" ]; then \ echo " Fetching locked $$repo..."; \ - "$(LOCKED_SOURCE_FETCH)" "$$repo" "https://git.sr.ht/~lisp/$$repo" "vendor/$$repo"; \ + "$(LOCKED_SOURCE_FETCH)" "$$repo" "https://git.jerboa.sh/ober/$$repo" "vendor/$$repo"; \ else \ echo " (exists) $$repo"; \ fi; \ @@ -894,7 +903,7 @@ $(JERBOA_NATIVE_RS_DIR): @echo "=== Sparse-cloning jerboa-native-rs from the jerboa monorepo ===" @tmp="vendor/.jerboa-native-rs-monorepo"; \ rm -rf "$$tmp"; \ - "$(LOCKED_SOURCE_FETCH)" jerboa https://git.sr.ht/~lisp/jerboa "$(JERBOA_NATIVE_RS_DIR)" jerboa-native-rs + "$(LOCKED_SOURCE_FETCH)" jerboa https://git.jerboa.sh/ober/jerboa "$(JERBOA_NATIVE_RS_DIR)" jerboa-native-rs # ─── Hardening Verification ─────────────────────────────────────────────── --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # jerboa-shell-extras -Optional feature bundles for [jerboa-shell](https://git.sr.ht/~lisp/jerboa-shell). +Optional feature bundles for [jerboa-shell](https://git.jerboa.sh/ober/jerboa-shell). The base shell stays a compact Bash replacement: ordinary `make`, `make binary`, and `make jsh` builds in jerboa-shell do not fetch or enable this repository. --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.2.0 +0.2.1 --- a/jpkg.sexp +++ b/jpkg.sexp @@ -1,6 +1,6 @@ (package (name "@ober/jerboa-shell-extras") - (version "0.1.0") + (version "0.2.1") (description "Optional feature bundles for the Jerboa shell") (license "MIT") (source "https://git.jerboa.sh/ober/jerboa-shell-extras") --- a/support/ensure-jerboa.sh +++ b/support/ensure-jerboa.sh @@ -10,8 +10,8 @@ # # Override the signed artifact location with: # JERBOA_RELEASE_BASE=https://example.org/releases/v0.2.0 -# or the SourceHut repo with: -# JERBOA_RELEASE_REPO=~lisp/jerboa +# or the Forgejo repo with: +# JERBOA_RELEASE_REPO=ober/jerboa # For testing or unusual hosts, override target detection with: # JERBOA_RELEASE_TARGET=macos-arm64 @@ -26,8 +26,8 @@ usage() { version=$1 bindir=${2:-.jerboa/bin} -repo=${JERBOA_RELEASE_REPO:-~lisp/jerboa} -origin=${JERBOA_RELEASE_ORIGIN:-https://git.sr.ht} +repo=${JERBOA_RELEASE_REPO:-ober/jerboa} +origin=${JERBOA_RELEASE_ORIGIN:-https://git.jerboa.sh} printf '%s\n' "$version" | grep -Eq '^v[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*$' || { echo "ERROR: version must be an exact tag such as v0.2.4" >&2 @@ -71,7 +71,7 @@ case "$target" in esac file="jerboa-${version}-${target}.tar.gz" -base=${JERBOA_RELEASE_BASE:-${origin}/${repo}/refs/download/${version}} +base=${JERBOA_RELEASE_BASE:-${origin}/${repo}/releases/download/${version}} url="${base%/}/${file}" manifest_url="${base%/}/release-manifest.sha256" signature_url="${manifest_url}.sig" --- a/support/security-policy-check.sh +++ b/support/security-policy-check.sh @@ -59,7 +59,7 @@ end RUBY } -for workflow in .github/workflows/*.yml .github/workflows/*.yaml; do +for workflow in .forgejo/workflows/*.yml .forgejo/workflows/*.yaml; do [ -f "$workflow" ] || continue check_action_refs "$workflow" || fail "mutable action reference in $workflow" done @@ -93,11 +93,11 @@ printf '%s\n' 'steps:' ' - uses: >-' \ check_action_refs "$pinned_control" >/dev/null 2>&1 || \ fail "workflow scanner rejected a pinned folded-scalar control" -grep -q '^permissions:$' .github/workflows/ci.yml || fail "workflow permissions block missing" -sed -n '/^permissions:$/,/^[^ ]/p' .github/workflows/ci.yml | grep -q '^ contents: read$' || \ +grep -q '^permissions:$' .forgejo/workflows/ci.yaml || fail "workflow permissions block missing" +sed -n '/^permissions:$/,/^[^ ]/p' .forgejo/workflows/ci.yaml | grep -q '^ contents: read$' || \ fail "workflow does not default to read-only contents permission" ! grep -Eq 'jerboa21/jerboa:latest|uses:[[:space:]]*[^#[:space:]]+@(v[0-9]+|stable|main|master)([[:space:]#]|$)' \ - .github/workflows/ci.yml || fail "mutable CI execution input" + .forgejo/workflows/ci.yaml || fail "mutable CI execution input" grep -q 'ssh-keygen -Y verify' support/ensure-jerboa.sh || fail "release manifest signature verification missing" ! grep -Eq 'sum_url|\$\{?url\}?\.sha256' support/ensure-jerboa.sh || fail "co-hosted checksum bootstrap restored" @@ -142,7 +142,7 @@ awk -F '\t' ' ' support/source-lock.tsv || fail "source lock is malformed, incomplete, or duplicated" grep -q '^status=ready$' support/source-release.status || \ fail "reviewed satellite source release status is not ready" -grep -q 'sh support/check-source-release.sh' .github/workflows/ci.yml || \ +grep -q 'sh support/check-source-release.sh' .forgejo/workflows/ci.yaml || \ fail "release workflow bypasses the satellite source gate" sh support/check-source-release.sh >/dev/null 2>&1 || \ fail "reviewed satellite source gate did not pass" @@ -151,13 +151,8 @@ sh support/check-source-release.sh >/dev/null 2>&1 || \ fail "mutable Git dependency path restored" ! grep -Eq 'download_prebuilt|macos-libs-v1' build-jsh-macos.sh || \ fail "unsigned prebuilt native fallback restored" -if grep -E 'cargo (build|zigbuild)' build-jsh-macos.sh .github/workflows/ci.yml | grep -qv -- '--locked'; then +if grep -E 'cargo (build|zigbuild)' build-jsh-macos.sh .forgejo/workflows/ci.yaml | grep -qv -- '--locked'; then fail "unlocked Cargo build restored" fi -for variable in FREEBSD_BASE_SHA256 ZIG_SHA256 CARGO_ZIGBUILD_SHA256; do - grep -Eq "^ ${variable}: [0-9a-f]{64}$" .github/workflows/ci.yml || fail "$variable pin missing" - grep -q "\$${variable} /tmp/" .github/workflows/ci.yml || fail "$variable is not checked before extraction" -done - echo "security policy checks: pass" --- a/support/source-lock.tsv +++ b/support/source-lock.tsv @@ -1,13 +1,13 @@ # name url commit tree -jerboa-shell https://git.sr.ht/~lisp/jerboa-shell 52695eeffb1e08cf8998117436d28753288231da 9eafcdc347767badabeef9a45b34888eed289449 -jsqlite https://git.sr.ht/~lisp/jerboa-sqlite a25d077ff4b03bc6138c4d668aac31469b031f06 329d20dcce60a59b1135db017669c282dabb19b4 -jerboa https://git.sr.ht/~lisp/jerboa 9f4ac78dc8c687d08841b14f26a747fd9ff74202 eeaa57cdb99666176adbd5eae21c6a0d23ed4dd0 -jerboa-coreutils https://git.sr.ht/~lisp/jerboa-coreutils 549af48042752dae317a9573bad6e783fb0fca19 b04a9f05edf5d35e7c6d0464fc25cc3015248910 -jerboa-awk https://git.sr.ht/~lisp/jerboa-awk 2a73bb948c8e513b97afe2f6e233f9ad6f314f03 4b5118d462aa9e12803de064573d00d133afed48 -jerboa-sed https://git.sr.ht/~lisp/jerboa-sed 44df22636f89d138545bd16c1acf2a26b20b9a64 aaba1b863dd247dcfe47b665b148d97b203973f2 -jerboa-aws https://git.sr.ht/~lisp/jerboa-aws 492b2b2d26222bc183702a504528286dcf75583a ca10fa4de0e554097aad0658273b7c0e58067f08 -jerboa-yubikey https://git.sr.ht/~lisp/jerboa-yubikey 788ff893c2667c720829e34b2e0a7cfa7098547f 33e2cee5d4a3aac04ef835ad123142eeb02cb162 -jerboa-ssh https://git.sr.ht/~lisp/jerboa-ssh 7b5c4ac7c93901ea5c8b4005a67124a81b319d62 ec8d82461731f68e40072b1a25fe8fd22b479bbc -jerboa-crypto https://git.sr.ht/~lisp/jerboa-crypto dc9fb27d8cad7900d1dc96c8ec8f0f57daef4ca0 462d8eafd371dcca4bf4e6eecda619bcc807678b -jerboa-fuse https://git.sr.ht/~lisp/jerboa-fuse 06cc92d9be2e20eed306d253732b36224a54ca46 6b679f07eff916be333ae60460afad922fc8b342 -jerboa-wormhole https://git.sr.ht/~lisp/jerboa-wormhole 52c49e3b8b60cfa4ec2a4c3eecc8c97b6846e6dd defbf7ff6b72bd2f057fb8dbef9fc24ba47e4dc6 +jerboa-shell https://git.jerboa.sh/ober/jerboa-shell 52695eeffb1e08cf8998117436d28753288231da 9eafcdc347767badabeef9a45b34888eed289449 +jsqlite https://git.jerboa.sh/ober/jerboa-sqlite a25d077ff4b03bc6138c4d668aac31469b031f06 329d20dcce60a59b1135db017669c282dabb19b4 +jerboa https://git.jerboa.sh/ober/jerboa 9f4ac78dc8c687d08841b14f26a747fd9ff74202 eeaa57cdb99666176adbd5eae21c6a0d23ed4dd0 +jerboa-coreutils https://git.jerboa.sh/ober/jerboa-coreutils 549af48042752dae317a9573bad6e783fb0fca19 b04a9f05edf5d35e7c6d0464fc25cc3015248910 +jerboa-awk https://git.jerboa.sh/ober/jerboa-awk 2a73bb948c8e513b97afe2f6e233f9ad6f314f03 4b5118d462aa9e12803de064573d00d133afed48 +jerboa-sed https://git.jerboa.sh/ober/jerboa-sed 44df22636f89d138545bd16c1acf2a26b20b9a64 aaba1b863dd247dcfe47b665b148d97b203973f2 +jerboa-aws https://git.jerboa.sh/ober/jerboa-aws 492b2b2d26222bc183702a504528286dcf75583a ca10fa4de0e554097aad0658273b7c0e58067f08 +jerboa-yubikey https://git.jerboa.sh/ober/jerboa-yubikey 788ff893c2667c720829e34b2e0a7cfa7098547f 33e2cee5d4a3aac04ef835ad123142eeb02cb162 +jerboa-ssh https://git.jerboa.sh/ober/jerboa-ssh 7b5c4ac7c93901ea5c8b4005a67124a81b319d62 ec8d82461731f68e40072b1a25fe8fd22b479bbc +jerboa-crypto https://git.jerboa.sh/ober/jerboa-crypto dc9fb27d8cad7900d1dc96c8ec8f0f57daef4ca0 462d8eafd371dcca4bf4e6eecda619bcc807678b +jerboa-fuse https://git.jerboa.sh/ober/jerboa-fuse 06cc92d9be2e20eed306d253732b36224a54ca46 6b679f07eff916be333ae60460afad922fc8b342 +jerboa-wormhole https://git.jerboa.sh/ober/jerboa-wormhole 52c49e3b8b60cfa4ec2a4c3eecc8c97b6846e6dd defbf7ff6b72bd2f057fb8dbef9fc24ba47e4dc6