cloudflare-native port of the tangled knot server
22

Configure Feed

Select the types of activity you want to include in your feed.

ci: add L0 lint gates

Add AC11 SSH-path preservation, AC12 lexicon namespace/parity, and AC14/AC15
literal-block byte-identity lints with self-tests.

Wire make lint into CI and leave build out until the L1 modernc.org/sqlite
swap makes CGO_ENABLED=0 builds pass.

Patch category: aerie-distribution

Jer Miller (May 24, 2026, 8:33 PM -0600) 4d2b0224 9c4e439c

+475 -3
+13 -3
Makefile
··· 10 10 # install fetch Go module dependencies 11 11 # build build the knot binary as a pure-Go static executable 12 12 # test run the full upstream test suite 13 - # ci install + test + build (the green-CI gate every lode must satisfy) 13 + # lint run L0 repo-governance lint gates and their self-tests 14 + # ci install + lint + test (build returns to CI in Lode 1) 14 15 # clean remove build artifacts 15 16 16 17 GO ?= go ··· 18 19 BUILD_FLAGS ?= 19 20 KNOT_BIN ?= bin/knot 20 21 21 - .PHONY: install build test ci clean 22 + .PHONY: install build test lint ci clean 22 23 23 24 install: 24 25 $(GO) mod download ··· 30 31 test: 31 32 $(GO) test ./... 32 33 33 - ci: install test build 34 + lint: 35 + bash scripts/lint-ssh-dormant.sh 36 + bash scripts/lint-ssh-dormant.sh --self-test 37 + bash scripts/lint-lexicon-namespace.sh 38 + bash scripts/lint-lexicon-namespace.sh --self-test 39 + bash scripts/check-literal-blocks.sh 40 + bash scripts/check-literal-blocks.sh --self-test 41 + 42 + # TODO(L1): re-add `build` to this chain once modernc.org/sqlite is in place 43 + ci: install lint test 34 44 35 45 clean: 36 46 rm -rf bin
+136
scripts/check-literal-blocks.sh
··· 1 + #!/usr/bin/env bash 2 + # SPDX-License-Identifier: MIT 3 + # AC14 and AC15 require byte-identical owner-facing literal paragraphs. This 4 + # check keeps future edits from paraphrasing the README lineage paragraph or the 5 + # COMMUNITY.md lexicon-namespace commitment. 6 + 7 + set -uo pipefail 8 + 9 + README_PATH="${AERIE_LITERAL_README_PATH:-readme.md}" 10 + COMMUNITY_PATH="${AERIE_LITERAL_COMMUNITY_PATH:-COMMUNITY.md}" 11 + 12 + README_LITERAL="$(cat <<'LITERAL' 13 + aerie is a Cloudflare-native community implementation of the [Tangled](https://tangled.sh) knot server, building on Tangled Labs Oy's MIT-licensed upstream. Fork blessed by Anirudh Oppiliappan (Tangled co-founder & CEO) on 2026-04-28. aerie publishes the same `sh.tangled.*` lexicons unchanged, so aerie-hosted repositories render natively on tangled.org's appview. 14 + LITERAL 15 + )" 16 + 17 + COMMUNITY_LITERAL="$(cat <<'LITERAL' 18 + aerie is a community implementation of the Tangled knot. Any new record types aerie defines are published under sol pbc's own namespace (`org.solpbc.aerie.*`); aerie does not define new records under `sh.tangled.*`, which remains Tangled Labs Oy's namespace to evolve. 19 + LITERAL 20 + )" 21 + 22 + error() { 23 + printf '%s\n' "$*" >&2 24 + } 25 + 26 + script_path() { 27 + local source="${BASH_SOURCE[0]}" 28 + local dir 29 + dir="$(cd "$(dirname "$source")" && pwd)" 30 + printf '%s/%s\n' "$dir" "$(basename "$source")" 31 + } 32 + 33 + emit_diff() { 34 + local expected="$1" 35 + local path="$2" 36 + local needle="$3" 37 + local expected_file actual_file 38 + 39 + expected_file="$(mktemp)" 40 + actual_file="$(mktemp)" 41 + 42 + printf '%s\n' "$expected" > "$expected_file" 43 + if [[ -f "$path" ]]; then 44 + if ! grep -F -m1 -- "$needle" "$path" > "$actual_file"; then 45 + head -n 5 "$path" > "$actual_file" 46 + fi 47 + else 48 + : > "$actual_file" 49 + fi 50 + 51 + diff -u "$expected_file" "$actual_file" >&2 || true 52 + rm -f "$expected_file" "$actual_file" 53 + } 54 + 55 + check_literal() { 56 + local ac="$1" 57 + local path="$2" 58 + local expected="$3" 59 + local enforce_top="$4" 60 + local line 61 + 62 + if [[ ! -f "$path" ]]; then 63 + error "error: $ac literal target missing: $path" 64 + emit_diff "$expected" "$path" "aerie is" 65 + return 1 66 + fi 67 + 68 + line="$(grep -nFx -- "$expected" "$path" | head -n 1 | cut -d: -f1 || true)" 69 + if [[ -z "$line" ]]; then 70 + error "error: $ac literal mismatch: $path missing exact literal block" 71 + emit_diff "$expected" "$path" "aerie is" 72 + return 1 73 + fi 74 + 75 + if [[ "$enforce_top" == "yes" && "$line" -gt 3 ]]; then 76 + error "error: $ac literal placement: $path literal starts at line $line, expected line 1, 2, or 3" 77 + return 1 78 + fi 79 + 80 + return 0 81 + } 82 + 83 + run_lint() { 84 + local failures=0 85 + 86 + check_literal "AC14" "$README_PATH" "$README_LITERAL" "yes" || failures=1 87 + check_literal "AC15" "$COMMUNITY_PATH" "$COMMUNITY_LITERAL" "no" || failures=1 88 + 89 + return "$failures" 90 + } 91 + 92 + self_test() { 93 + local script tmp out rc 94 + script="$(script_path)" 95 + tmp="$(mktemp -d /tmp/aerie-l0-literal-selftest-XXXXXX)" 96 + trap "rm -rf -- '$tmp'" EXIT 97 + 98 + cat > "$tmp/readme.md" <<'README' 99 + # aerie 100 + 101 + aerie is a Cloudflare-native implementation of the Tangled knot server, with similar lexicons. 102 + README 103 + 104 + printf '%s\n' "$COMMUNITY_LITERAL" > "$tmp/COMMUNITY.md" 105 + 106 + out="$tmp/out.txt" 107 + (AERIE_LITERAL_README_PATH="$tmp/readme.md" AERIE_LITERAL_COMMUNITY_PATH="$tmp/COMMUNITY.md" bash "$script") >"$out" 2>&1 108 + rc=$? 109 + 110 + if [[ "$rc" -ne 1 ]]; then 111 + cat "$out" >&2 112 + error "error: literal self-test: expected lint to exit 1 for paraphrased README literal, got $rc" 113 + return 1 114 + fi 115 + 116 + if ! grep -q "AC14" "$out"; then 117 + cat "$out" >&2 118 + error "error: literal self-test: expected error output to mention AC14" 119 + return 1 120 + fi 121 + 122 + return 0 123 + } 124 + 125 + case "${1:-}" in 126 + "") 127 + run_lint 128 + ;; 129 + --self-test) 130 + self_test 131 + ;; 132 + *) 133 + error "error: check-literal-blocks.sh: unknown argument: $1" 134 + exit 1 135 + ;; 136 + esac
+199
scripts/lint-lexicon-namespace.sh
··· 1 + #!/usr/bin/env bash 2 + # SPDX-License-Identifier: MIT 3 + # AC12 preserves upstream lexicon parity. aerie may add future lexicons under 4 + # org.solpbc.aerie.*, but it must not invent new sh.tangled.* records, remove 5 + # upstream sh.tangled.* records, or modify inherited sh.tangled.* lexicon files. 6 + 7 + set -uo pipefail 8 + 9 + error() { 10 + printf '%s\n' "$*" >&2 11 + } 12 + 13 + script_path() { 14 + local source="${BASH_SOURCE[0]}" 15 + local dir 16 + dir="$(cd "$(dirname "$source")" && pwd)" 17 + printf '%s/%s\n' "$dir" "$(basename "$source")" 18 + } 19 + 20 + run_git() { 21 + if [[ -n "${AERIE_LINT_GIT_ROOT:-}" ]]; then 22 + git -C "$AERIE_LINT_GIT_ROOT" "$@" 23 + else 24 + git "$@" 25 + fi 26 + } 27 + 28 + read_upstream_sha() { 29 + if [[ ! -f UPSTREAM.md ]]; then 30 + error "error: AC12 config: missing UPSTREAM.md with UPSTREAM_BASE_SHA" 31 + return 1 32 + fi 33 + 34 + awk -F': ' '/^UPSTREAM_BASE_SHA:/ {print $2; exit}' UPSTREAM.md 35 + } 36 + 37 + json_id_from_file() { 38 + local path="$1" 39 + jq -er '.id // empty' "$path" 2>/dev/null 40 + } 41 + 42 + json_id_from_git() { 43 + local sha="$1" 44 + local path="$2" 45 + run_git show "$sha:$path" | jq -er '.id // empty' 46 + } 47 + 48 + sha256_from_git() { 49 + local sha="$1" 50 + local path="$2" 51 + run_git show "$sha:$path" | sha256sum | awk '{print $1}' 52 + } 53 + 54 + run_lint() { 55 + local upstream_sha 56 + upstream_sha="$(read_upstream_sha)" || return 1 57 + 58 + if [[ -z "$upstream_sha" ]]; then 59 + error "error: AC12 config: UPSTREAM_BASE_SHA is empty in UPSTREAM.md" 60 + return 1 61 + fi 62 + 63 + if ! run_git rev-parse --verify -q "${upstream_sha}^{commit}" >/dev/null; then 64 + error "error: AC12 config: upstream base SHA does not resolve: $upstream_sha" 65 + return 1 66 + fi 67 + 68 + if [[ ! -d lexicons ]]; then 69 + error "error: AC12 config: missing lexicons/ directory" 70 + return 1 71 + fi 72 + 73 + local upstream_files current_files 74 + upstream_files="$(run_git ls-tree -r --name-only "$upstream_sha" -- lexicons | grep '\.json$' || true)" 75 + current_files="$(find lexicons -type f -name '*.json' | sort || true)" 76 + 77 + if [[ -z "$upstream_files" ]]; then 78 + error "error: AC12 config: no upstream lexicon JSON files found at $upstream_sha" 79 + return 1 80 + fi 81 + 82 + if [[ -z "$current_files" ]]; then 83 + error "error: AC12 config: no current lexicon JSON files found under lexicons/" 84 + return 1 85 + fi 86 + 87 + declare -A upstream_ids=() 88 + declare -A upstream_paths=() 89 + declare -A current_ids=() 90 + declare -A current_paths=() 91 + 92 + local path id failures 93 + failures=0 94 + 95 + while IFS= read -r path; do 96 + [[ -n "$path" ]] || continue 97 + if ! id="$(json_id_from_git "$upstream_sha" "$path")"; then 98 + error "error: AC12 violation: upstream-invalid-id: $path: missing or invalid .id at $upstream_sha" 99 + failures=1 100 + continue 101 + fi 102 + upstream_ids["$id"]="$path" 103 + upstream_paths["$path"]="$id" 104 + done <<< "$upstream_files" 105 + 106 + while IFS= read -r path; do 107 + [[ -n "$path" ]] || continue 108 + if ! id="$(json_id_from_file "$path")"; then 109 + error "error: AC12 violation: current-invalid-id: $path: missing or invalid .id" 110 + failures=1 111 + continue 112 + fi 113 + if [[ -n "${current_ids[$id]+x}" ]]; then 114 + error "error: AC12 violation: duplicate-current-id: $id: ${current_ids[$id]} and $path" 115 + failures=1 116 + continue 117 + fi 118 + current_ids["$id"]="$path" 119 + current_paths["$path"]="$id" 120 + done <<< "$current_files" 121 + 122 + for id in "${!current_ids[@]}"; do 123 + if [[ -z "${upstream_ids[$id]+x}" && ! "$id" =~ ^org\.solpbc\.aerie\. ]]; then 124 + error "error: AC12 violation: new-id: $id: not present at upstream base and not under org.solpbc.aerie.*" 125 + failures=1 126 + fi 127 + done 128 + 129 + for id in "${!upstream_ids[@]}"; do 130 + if [[ "$id" == sh.tangled.* && -z "${current_ids[$id]+x}" ]]; then 131 + error "error: AC12 violation: missing-upstream-id: $id: inherited sh.tangled.* ID removed from aerie tree" 132 + failures=1 133 + fi 134 + done 135 + 136 + local upstream_hash current_hash 137 + for path in "${!upstream_paths[@]}"; do 138 + id="${upstream_paths[$path]}" 139 + [[ "$id" == sh.tangled.* ]] || continue 140 + 141 + if [[ ! -f "$path" ]]; then 142 + error "error: AC12 violation: missing-upstream-path: $path: inherited sh.tangled.* file removed from aerie tree" 143 + failures=1 144 + continue 145 + fi 146 + 147 + upstream_hash="$(sha256_from_git "$upstream_sha" "$path")" 148 + current_hash="$(sha256sum "$path" | awk '{print $1}')" 149 + if [[ "$upstream_hash" != "$current_hash" ]]; then 150 + error "error: AC12 violation: content-drift: $path: inherited sh.tangled.* lexicon differs from upstream base" 151 + failures=1 152 + fi 153 + done 154 + 155 + return "$failures" 156 + } 157 + 158 + self_test() { 159 + local script repo_root tmp out rc 160 + script="$(script_path)" 161 + repo_root="$(git rev-parse --show-toplevel)" || return 1 162 + tmp="$(mktemp -d /tmp/aerie-l0-ac12-selftest-XXXXXX)" 163 + trap "rm -rf -- '$tmp'" EXIT 164 + 165 + cp -R lexicons "$tmp/lexicons" 166 + cp UPSTREAM.md "$tmp/UPSTREAM.md" 167 + printf '%s\n' '{"id":"sh.tangled.invented"}' > "$tmp/lexicons/aerie-invented.json" 168 + 169 + out="$tmp/out.txt" 170 + (cd "$tmp" && AERIE_LINT_GIT_ROOT="$repo_root" bash "$script") >"$out" 2>&1 171 + rc=$? 172 + 173 + if [[ "$rc" -ne 1 ]]; then 174 + cat "$out" >&2 175 + error "error: AC12 self-test: expected lint to exit 1 for sh.tangled.invented, got $rc" 176 + return 1 177 + fi 178 + 179 + if ! grep -q "sh.tangled.invented" "$out"; then 180 + cat "$out" >&2 181 + error "error: AC12 self-test: expected error output to mention sh.tangled.invented" 182 + return 1 183 + fi 184 + 185 + return 0 186 + } 187 + 188 + case "${1:-}" in 189 + "") 190 + run_lint 191 + ;; 192 + --self-test) 193 + self_test 194 + ;; 195 + *) 196 + error "error: lint-lexicon-namespace.sh: unknown argument: $1" 197 + exit 1 198 + ;; 199 + esac
+127
scripts/lint-ssh-dormant.sh
··· 1 + #!/usr/bin/env bash 2 + # SPDX-License-Identifier: MIT 3 + # AC11 keeps the upstream SSH push path present in source while Cloudflare 4 + # deployments leave it dormant. This lint checks the concrete files and command 5 + # registrations that make the path available for later scopes without trying to 6 + # exercise SSH runtime behavior. 7 + 8 + set -uo pipefail 9 + 10 + UPSTREAM_SHORT_SHA="c2f17d5e" 11 + MAIN_FILE="cmd/knot/main.go" 12 + 13 + script_path() { 14 + local source="${BASH_SOURCE[0]}" 15 + local dir 16 + dir="$(cd "$(dirname "$source")" && pwd)" 17 + printf '%s/%s\n' "$dir" "$(basename "$source")" 18 + } 19 + 20 + error() { 21 + printf '%s\n' "$*" >&2 22 + } 23 + 24 + require_file() { 25 + local path="$1" 26 + if [[ ! -f "$path" ]]; then 27 + error "error: AC11 guarded path missing: $path (verified present at upstream SHA $UPSTREAM_SHORT_SHA)" 28 + return 1 29 + fi 30 + return 0 31 + } 32 + 33 + require_nonempty_dir() { 34 + local path="$1" 35 + if [[ ! -d "$path" ]]; then 36 + error "error: AC11 guarded path missing: $path (verified present at upstream SHA $UPSTREAM_SHORT_SHA)" 37 + return 1 38 + fi 39 + if ! find "$path" -mindepth 1 -print -quit | grep -q .; then 40 + error "error: AC11 guarded path empty: $path (verified present at upstream SHA $UPSTREAM_SHORT_SHA)" 41 + return 1 42 + fi 43 + return 0 44 + } 45 + 46 + require_main_contains() { 47 + local kind="$1" 48 + local needle="$2" 49 + if [[ ! -f "$MAIN_FILE" ]]; then 50 + error "error: AC11 guarded path missing: $MAIN_FILE (verified present at upstream SHA $UPSTREAM_SHORT_SHA)" 51 + return 1 52 + fi 53 + if ! grep -Fq "$needle" "$MAIN_FILE"; then 54 + error "error: AC11 $kind missing: $needle in $MAIN_FILE (verified present at upstream SHA $UPSTREAM_SHORT_SHA)" 55 + return 1 56 + fi 57 + return 0 58 + } 59 + 60 + run_lint() { 61 + local failures=0 62 + 63 + require_file "$MAIN_FILE" || failures=1 64 + 65 + require_main_contains "import" '"tangled.org/core/guard"' || failures=1 66 + require_main_contains "import" '"tangled.org/core/keyfetch"' || failures=1 67 + require_main_contains "import" '"tangled.org/core/hook"' || failures=1 68 + 69 + require_main_contains "command registration" "guard.Command()" || failures=1 70 + require_main_contains "command registration" "keyfetch.Command()" || failures=1 71 + require_main_contains "command registration" "hook.Command()" || failures=1 72 + 73 + require_nonempty_dir "guard" || failures=1 74 + require_nonempty_dir "keyfetch" || failures=1 75 + require_nonempty_dir "hook" || failures=1 76 + 77 + require_file "knotserver/db/pubkeys.go" || failures=1 78 + require_file "knotserver/xrpc/list_keys.go" || failures=1 79 + 80 + return "$failures" 81 + } 82 + 83 + self_test() { 84 + local script tmp out rc 85 + script="$(script_path)" 86 + tmp="$(mktemp -d /tmp/aerie-l0-ac11-selftest-XXXXXX)" 87 + trap "rm -rf -- '$tmp'" EXIT 88 + 89 + mkdir -p "$tmp/cmd/knot" "$tmp/knotserver/db" "$tmp/knotserver/xrpc" 90 + cp "$MAIN_FILE" "$tmp/cmd/knot/main.go" 91 + cp -R guard keyfetch hook "$tmp/" 92 + cp knotserver/db/pubkeys.go "$tmp/knotserver/db/pubkeys.go" 93 + cp knotserver/xrpc/list_keys.go "$tmp/knotserver/xrpc/list_keys.go" 94 + 95 + rm -rf "$tmp/guard" 96 + out="$tmp/out.txt" 97 + 98 + (cd "$tmp" && bash "$script") >"$out" 2>&1 99 + rc=$? 100 + 101 + if [[ "$rc" -ne 1 ]]; then 102 + cat "$out" >&2 103 + error "error: AC11 self-test: expected lint to exit 1 after removing guard/, got $rc" 104 + return 1 105 + fi 106 + 107 + if ! grep -q "guard" "$out"; then 108 + cat "$out" >&2 109 + error "error: AC11 self-test: expected error output to mention guard" 110 + return 1 111 + fi 112 + 113 + return 0 114 + } 115 + 116 + case "${1:-}" in 117 + "") 118 + run_lint 119 + ;; 120 + --self-test) 121 + self_test 122 + ;; 123 + *) 124 + error "error: lint-ssh-dormant.sh: unknown argument: $1" 125 + exit 1 126 + ;; 127 + esac