utils/scripts/check_no_crdt_sync_override.sh
Krzysztof kuhy Rudnicki 5f64a8959b
Some checks failed
crdt-sync pre-commit / pre-commit (push) Has been cancelled
crdt-sync tests / test (3.10) (push) Has been cancelled
crdt-sync tests / test (3.11) (push) Has been cancelled
crdt-sync tests / test (3.12) (push) Has been cancelled
Sign in with Google, and stop trusting a revoked session
Two changes to the shared sync credential path, both driven by devices
that reported "Connected" while every sync failed.

Google sign-in (signInWithGoogle, both languages) replaces typing the
sync account's password on a fresh install. The account is linked once
from the PC with tool/link_google.py, which asserts the pinned uid --
without that assertion an unlinked identity is *signed up* rather than
refused, and the new uid is then denied every read and write by the
security rules.

The second change is the one with teeth. hasSession() is a presence
check, so a refresh token the server had revoked still read as a live
session: the desktop todo build showed "Connected" and then failed every
sync with `HTTP 400 (TOKEN_EXPIRED)`. A refresh that fails for a terminal
reason now clears the stored session, so hasSession() answers honestly.

Deliberately narrow: only TOKEN_EXPIRED, USER_DISABLED, USER_NOT_FOUND,
INVALID_REFRESH_TOKEN, INVALID_GRANT_TYPE and MISSING_REFRESH_TOKEN
clear it. A network error or a 5xx must not -- a device that signs
itself out whenever the wifi drops needs a manual sign-in on every
device to recover, which is worse than the stale banner this fixes.
Verified against the live endpoint, not just mocks: has_session flips
True -> False on a real rejection.

crdt_sync_dart 0.9.0 -> 0.10.0; the five apps pin the matching tag.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0192EkoAyFBEWTvAN5vVgmSy
2026-08-11 23:58:02 +02:00

89 lines
3.2 KiB
Bash
Executable File

#!/bin/bash
# ============================================================================
# Fail if a pubspec still overrides crdt_sync with a local path.
#
# The apps depend on crdt_sync as a *git dependency pinned to a tag*, so what
# CI builds is whatever that tag points at. A `dependency_overrides:` entry
# pointing at ~/utils/crdt_sync_dart is invaluable while developing an unreleased
# library change -- and catastrophic if it survives the commit: local tests go
# green against code CI has never seen, and the failure is silent in both
# directions.
#
# A comment in the pubspec asking someone to remember is deployment hygiene,
# not a fix. This is the gate.
#
# Usage: check_no_crdt_sync_override.sh [pubspec.yaml ...]
# With no arguments, checks ./pubspec.yaml.
# ============================================================================
set -euo pipefail
SCRIPT_NAME="$(basename "$0")"
readonly SCRIPT_NAME
usage() {
echo "Usage: $SCRIPT_NAME [pubspec.yaml ...]"
echo " Fails when a pubspec overrides crdt_sync with a local path."
exit 0
}
# Returns 0 (found) when the file has a crdt_sync entry under
# dependency_overrides. Deliberately a small state machine rather than a grep:
# `path:` appears under plenty of other keys, and a false positive here blocks
# a legitimate commit.
has_override() {
local file="$1"
awk '
# Track indent depth explicitly. An earlier version used an awk
# interval expression ({1,4}) to spot a sibling key, which plain awk
# does not enable by default -- so the check silently never fired and
# reported every file clean. A safety check that fails open is worse
# than none, so this version is written to be obvious instead of terse.
function indent(line, n) {
n = match(line, /[^ ]/)
return (n == 0) ? 0 : n - 1
}
/^[[:space:]]*#/ { next } # comments
/^[[:space:]]*$/ { next } # blank lines
/^dependency_overrides:[[:space:]]*$/ { in_overrides = 1; next }
/^[^[:space:]]/ { in_overrides = 0; in_crdt = 0; next }
in_overrides {
if ($0 ~ /^[[:space:]]+crdt_sync:[[:space:]]*$/) {
in_crdt = 1
crdt_indent = indent($0)
next
}
# Any key at or above crdt_sync{s} own indent ends its block.
if (in_crdt && indent($0) <= crdt_indent) { in_crdt = 0 }
if (in_crdt && $0 ~ /^[[:space:]]+path:/) { found = 1 }
}
END { exit(found ? 0 : 1) }
' "$file"
}
main() {
local -a files=("$@")
if [[ ${#files[@]} -eq 0 ]]; then
files=("pubspec.yaml")
fi
local failed=0
for file in "${files[@]}"; do
[[ -f "$file" ]] || continue
if has_override "$file"; then
echo "Error: $file still has a local crdt_sync dependency_override." >&2
echo " Remove it and bump the git 'ref:' to the released tag" >&2
echo " before committing, or CI will build different code." >&2
failed=1
fi
done
return "$failed"
}
if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
usage
fi
main "$@"