Skip to content

1.157.2 - #63

Open
tulir wants to merge 43 commits into
upstream-1.157.2from
beeper-1.157.2
Open

1.157.2#63
tulir wants to merge 43 commits into
upstream-1.157.2from
beeper-1.157.2

Conversation

@tulir

@tulir tulir commented Jul 30, 2026

Copy link
Copy Markdown
Member

No description provided.

@indent-zero

indent-zero Bot commented Jul 30, 2026

Copy link
Copy Markdown
PR Summary

Rebases the Beeper fork onto upstream synapse-1.157.2. Most fork commits carry over unchanged; a handful (log formatter, inbox endpoints, notification counts, receipts) required conflict resolution against upstream picking up MSC4446 and refactoring the pusher payload. The fork's own Support MSC4446 commit is dropped since upstream now provides msc4446_enabled, and one new commit adds a com.beeper.hs.order stream-ordering hint to the client-serialized unsigned dict. Force-pushes a78c1334 and e6254cd5 addressed test breakages surfaced by the rebase.

  • Rebased all Beeper fork commits (JWT UI auth, extra receipt content, inbox endpoints/previews/notification counts, high-priority push, purge/shutdown histograms, task scheduler throttling, generic-worker admin puppet & OpenIdStore, IP tracking opt-out, empty identity server in well-known, etc.) on top of upstream 1.157.2.
  • Dropped the fork's Support MSC4446: Move fully read markers backwards commit — now provided by upstream.
  • New commit Include stream ordering in the unsigned event dict adds com.beeper.hs.order in Rust serialize_event_value (client serializer only — federation uses get_pdu_json and is unaffected).
  • Bumps beeper-ci to actions/checkout@v7, actions/setup-python@v7, Python 3.13, sytest bookworm image, and refreshed sytest/complement pins.
  • Rebase-conflict resolutions in synapse/logging/_terse_json.py, synapse/rest/client/{account_data.py,read_marker.py,receipts.py}, synapse/config/experimental.py, and synapse/push/httppusher.py to accommodate upstream's neighbouring changes.
  • Test fixes: migrated tests/push/test_push_rule_evaluator.py from the removed FrozenEvent to make_test_event, switched test_stream_ordering_is_included to pass unsigned via positional event_dict, and replaced the hardcoded ts = 500/ts = 400 in the beeper inbox account-data tests with a before_ts/after_ts window captured around the PUT.

Issues

7 potential issues found:

  • HTTP pusher no longer sends counts.com.beeper.server_type when disable_badge_count=True. Before the refactor in Update CI/fix types for recent synapse changes, the initial content dict included that field and was only overwritten in the badge-enabled branch; now counts is set exclusively inside if not self.disable_badge_count:, so pushers with badges disabled silently lose the server-type marker. Trigger: any pusher registered with disable_badge_count=True. → Autofix
  • JwtAuthChecker.check_auth re-implements the JWT decoding, claim validation, and audience enforcement that already exist in JwtHandler.validate_login; the two functions are nearly byte-for-byte identical except for what they return. Any future change to JWT semantics (leeway, claim options, audience handling) must be made in both places. → Autofix
  • SetBeeperDone log line reads at_order from the wrong place, so it always logs at_order=None. The follow-up fix (Look for done.at_order in the correct place) moved reads to body["done"]["at_order"], but the logger.info(...) line was left reading body.get('at_order'). This defeats the observability the fix was meant to preserve. → Autofix
  • Bot-filter regexes in account_data.py are too loose: HUNGRYSERV_BOT_PATTERN uses an unescaped . in beeper.local (matches beeperzlocal), and both patterns rely on re.match with no $ anchor and a trailing \:* (zero-or-more colons), so @_foo_bot_notreally:example.com still matches. The failure mode is silently removing "ignored user" entries the user tried to add. → Autofix
  • The only new test for the com.beeper.hs.order insertion covers the overwrite path (unsigned already has the field). Missing: (1) plain positive case where unsigned doesn't include it, (2) the stream_ordering is None path asserting the field is absent / pre-existing value untouched. Regressions that skip the insertion or clobber a caller-provided value under None would go undetected. → Autofix
  • priority = "high" is now assigned unconditionally at the top of HttpPusher._build_notification_dict, making the following if event.type == EventTypes.Encrypted or tweaks.get("highlight") or tweaks.get("sound"): block dead code (it only re-assigns "high" to "high"). The stale comment ("send our push as high priority only if...") also misleads future readers about pusher priority behavior. → Autofix
  • BeeperInboxBatchArchiveServlet.on_POST accesses body["room_ids"] and iterates it with no validation of presence, type, or room-ID shape. A missing key raises KeyError (500 to the client), a string body would iterate characters, and unlike the sibling RoomBeeperInboxStateServlet the room IDs are not validated with RoomID.is_valid. → Autofix

CI Checks

test-trial and lint-types now pass after the two force-pushes. Only test-complement remains red, and only because of TestThreadsEndpoint: the /threads endpoint returns one thread root when two are expected. This lines up with the fork's Disable bundled aggregations change (get_bundled_aggregations returns {}), which shares logic with the threads listing / relation aggregation surface. The earlier TestCannotSendNonJoinViaSendJoinV1 flake did not recur.

Failing test-complement
  • TestThreadsEndpoint fails at room_threads_test.go:89: HaveInOrder: index 0 got $Cw...|, want $Cw...|$wl... — the /threads endpoint returns only one thread root when the test expects two. Most likely a regression from the fork's Disable bundled aggregations commit (synapse/handlers/relations.py:get_bundled_aggregations short-circuits to {}), since /threads pagination depends on the same relation-aggregation code path. No other Complement tests fail in this run.

⚡ Autofix All Issues

@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1b195b1e-dab3-4a40-a5e5-9dc364f9b5db

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

@tulir tulir changed the title Beeper 1.157.2 1.157.2 Jul 30, 2026
"com.beeper.user_id": self.user_id,
"prio": priority,
}
if not self.disable_badge_count:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Latent regression: com.beeper.server_type dropped when disable_badge_count=True.

Before commit b72880c4c, the initial content dict carried counts = {"unread": badge, "com.beeper.server_type": "synapse"} and was only overwritten to {"unread": badge} in the not disable_badge_count branch. Net effect: when disable_badge_count=True, com.beeper.server_type was sent (kept as part of the default), and when disable_badge_count=False, it was (buggily) stripped.

After the refactor, content no longer has a default counts, so when disable_badge_count=True the entire counts dict is absent and com.beeper.server_type is lost. Any downstream consumer (Sygnal, custom relays) keying off counts.com.beeper.server_type to identify Synapse-originated pushes won't see it for pushers configured with badges disabled.

Since this field is server-identity metadata rather than a count, it likely belongs on content directly. Suggested fix — hoist it out of counts and set it unconditionally:

content["com.beeper.server_type"] = "synapse"
if not self.disable_badge_count:
    content["counts"] = {"unread": badge}

Apply the same in the full-content branch (~line 515) and _send_badge (~line 551), and add a disable_badge_count=True case to tests/push/test_http.py.

user_id, room_id, "com.beeper.inbox.done", done
)
logger.info(
f"SetBeeperDone done_delta_ms={delta_ms} at_order={body.get('at_order')}"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This log line still reads body.get('at_order') at the top level, but commit 1b1872e2 moved the field to body["done"]["at_order"]. Result: this log always prints at_order=None, even when the client sent the value. Should match the read on line 356.

Suggested change
f"SetBeeperDone done_delta_ms={delta_ms} at_order={body.get('at_order')}"
f"SetBeeperDone done_delta_ms={delta_ms} at_order={body['done'].get('at_order')}"

body = parse_json_object_from_request(request)

done = {"updated_ts": ts, "at_ts": ts}
for room_id in body["room_ids"]:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

body["room_ids"] is not validated. If a client omits the key, this raises KeyError and Synapse returns 500 instead of a 400. If it's a string, iterating will loop over characters and attempt to write account data for each. The sibling RoomBeeperInboxStateServlet.on_PUT already validates RoomID.is_valid(room_id) — do the same here (plus a presence + list-of-strings check).

logger = logging.getLogger(__name__)

# Regex pattern for detecting a bridge bot (cached here for performance)
SYNAPSE_BOT_PATTERN = re.compile(r"^@_.*_bot\:*")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two loose-anchor problems here:

  1. HUNGRYSERV_BOT_PATTERN doesn't escape the . in beeper.local, so it also matches things like @fooxbotxbeeperzlocal.
  2. Neither pattern anchors at the end ($), and the trailing \:* accepts zero-or-more colons, so @_foo_bot_notreally:example.com matches SYNAPSE_BOT_PATTERN.

Suggested tightening:

SYNAPSE_BOT_PATTERN = re.compile(r"^@_.*_bot:[^:]+$")
HUNGRYSERV_BOT_PATTERN = re.compile(r"^@[a-z]+bot:beeper\.local$")

Silent filtering of user IDs the user tried to add is surprising — worth over-filtering as little as possible.

"""
priority = "low"
priority = "high" # Beep: always use high priority
if (

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This whole block is dead code after priority = "high" was set unconditionally on the previous line — both branches assign the same "high" value. The comment ("send our push as high priority only if...") is also stale. Consider removing the if entirely so future readers aren't confused about when high-priority is used.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

5 participants