Emoji markers, markdown bold inside code comments, and em-dashes are gone from source comments, string literals, scripts, Gradle files and the markdown docs. Counted before and after: emoji markers 2680 -> 1 (the emoji picker's own list, which is the feature) em-dashes 2490 -> 9 (table placeholders and fenced code) Two warning glyphs in user-facing strings in ChatScreens.kt are removed as well; the sentences say the same thing without them. Two backtick test names carried an em-dash and now carry a comma. Nothing else changed. 1208 tests pass, counted from the result XML. The three obfs4 interop tests are opted out with OBFS4_INTEROP_OPTOUT=1 for this run, as their own message instructs when no bridge is set up. CONTRIBUTING gets a four-line rule so it does not grow back. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
92 lines
4.0 KiB
Bash
Executable File
92 lines
4.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Run the Kotlin obfs4 port against real lyrebird, in both directions.
|
|
#
|
|
# The only check that proves interoperability. Everything else in `:obfs4`
|
|
# compares against recorded vectors or against itself, and two identically-wrong
|
|
# ends agree perfectly.
|
|
#
|
|
# A wire-format bug shows up as SILENCE, not an error: obfs4 bridges do not
|
|
# answer handshakes they cannot verify. The Kotlin side uses read timeouts and
|
|
# reports them as "the bridge refused to answer".
|
|
#
|
|
# The Go counterparty lives in the flamenet-elligator2 checkout, which also
|
|
# holds the Swift port. Both clients are pinned to the SAME reference rather
|
|
# than to each other, two independent implementations agreeing with lyrebird is
|
|
# a real statement; agreeing with each other is not.
|
|
set -euo pipefail
|
|
cd "$(dirname "$0")/.."
|
|
|
|
REFERENCE="${FN_OBFS4_REFERENCE:-../flamenet-elligator2/Reference}"
|
|
if [[ ! -d "$REFERENCE" ]]; then
|
|
echo "Cannot find the Go reference at $REFERENCE."
|
|
echo "Clone flamenet-elligator2 beside this repo, or set FN_OBFS4_REFERENCE."
|
|
exit 1
|
|
fi
|
|
|
|
WORK="$(mktemp -d)"
|
|
PARAMS="$WORK/params.json"
|
|
SERVER_LOG="$WORK/server.log"
|
|
|
|
cleanup() {
|
|
if [[ -n "${SERVER_PID:-}" ]] && kill -0 "$SERVER_PID" 2>/dev/null; then
|
|
kill "$SERVER_PID" 2>/dev/null || true
|
|
wait "$SERVER_PID" 2>/dev/null || true
|
|
fi
|
|
# The bridge log is the other half of every diagnosis: it says whether the
|
|
# handshake was accepted or refused, which the silent client cannot.
|
|
if [[ -s "$SERVER_LOG" ]]; then echo "--- bridge log ---"; cat "$SERVER_LOG"; fi
|
|
rm -rf "$WORK"
|
|
}
|
|
trap cleanup EXIT
|
|
|
|
echo "building the lyrebird bridge and client..."
|
|
(cd "$REFERENCE" && go build -o "$WORK/interopserver" ./interopserver)
|
|
(cd "$REFERENCE" && go build -o "$WORK/interopclient" ./interopclient)
|
|
|
|
"$WORK/interopserver" -params "$PARAMS" -addr 127.0.0.1:0 >/dev/null 2>"$SERVER_LOG" &
|
|
SERVER_PID=$!
|
|
|
|
# Poll for the params file rather than sleeping. A fixed sleep is either
|
|
# flaky or slow, and on a loaded machine it is both.
|
|
for _ in $(seq 1 100); do
|
|
[[ -f "$PARAMS" ]] && break
|
|
kill -0 "$SERVER_PID" 2>/dev/null || { echo "the bridge died on startup"; exit 1; }
|
|
sleep 0.1
|
|
done
|
|
[[ -f "$PARAMS" ]] || { echo "the bridge never published its parameters"; exit 1; }
|
|
|
|
# sed, not python3 or jq: the CI images for this repo cannot be assumed to
|
|
# have either, and that assumption has cost red pipelines before.
|
|
ADDRESS="$(sed -n 's/.*"address"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$PARAMS")"
|
|
[[ -n "$ADDRESS" ]] || { echo "could not read the bridge address from $PARAMS"; exit 1; }
|
|
echo "bridge up at $ADDRESS"
|
|
|
|
# `--rerun-tasks`, because Gradle's up-to-date check does not know the
|
|
# counterparty changed. Without it a second run skips the task entirely and
|
|
# prints nothing, the tests do not fail, they simply never happen. Caught by
|
|
# the name check below, which is the second time that check has earned its keep
|
|
# in ten minutes.
|
|
OBFS4_INTEROP_PARAMS="$PARAMS" OBFS4_INTEROP_CLIENT="$WORK/interopclient" \
|
|
./gradlew :obfs4:test --tests '*InteropTest*' --rerun-tasks --console=plain 2>&1 \
|
|
| tee "$WORK/test.log"
|
|
|
|
# A Gradle filter that matches nothing still exits 0, which would make "no
|
|
# interop coverage at all" look exactly like success.
|
|
for name in "a handshake and an echo against a real lyrebird bridge" \
|
|
"a bridge ignores a handshake it cannot verify" \
|
|
"a real lyrebird client accepts the kotlin bridge"; do
|
|
# Gradle prints `name() PASSED`, with parentheses. Matching on
|
|
# "$name PASSED" silently matches nothing, which this check caught on
|
|
# itself, reporting failure while all three tests had passed.
|
|
grep -qF "$name() PASSED" "$WORK/test.log" || {
|
|
echo
|
|
echo "FAILED: '$name' did not pass. A filter that matches nothing exits 0,"
|
|
echo "so each test is checked by name rather than trusting the exit code."
|
|
exit 1
|
|
}
|
|
done
|
|
|
|
echo
|
|
echo "ANDROID INTEROP OK: both directions -- a real lyrebird bridge accepted the"
|
|
echo "Kotlin client, and a real lyrebird client accepted the Kotlin bridge."
|