Skip to content

fix(gateway): exempt system events from the busy-path auth gate - #35

Merged
cwest merged 1 commit into
cwest/integrationfrom
topic/wake-auth-gate-exempt
Jul 2, 2026
Merged

fix(gateway): exempt system events from the busy-path auth gate#35
cwest merged 1 commit into
cwest/integrationfrom
topic/wake-auth-gate-exempt

Conversation

@cwest

@cwest cwest commented Jul 2, 2026

Copy link
Copy Markdown
Owner

The final swallow

With origin routing (#26), busy-precedence (#29), busy-handler exemption (#32),
stale-suppression exemption (#33), and owning-adapter dispatch (#34) all in place
and verified live, an origin-routed wake reaching the busy origin session was
STILL silently dropped. Live log:

WARNING gateway.run: Dropping message from unauthorized user in active session:
  user=None (None), platform=discord, session=agent:main:discord:thread:...

The busy handler's user-authorization gate (NousResearch#17775) runs first. A transition
wake carries a user-less SessionSource (the webhook builds no user_id for a
shared thread) and is HMAC-authenticated at the webhook route — but the auth gate
sees user=None, deems it unauthorized, and returns True (dropped) before
the wake exemption further down ever runs.

The fix

Exempt system-internal events (transition wakes + events flagged internal) from
the busy-path user-authorization gate. They are not user messages and are already
authenticated upstream; they remain exempted from interrupt/steer/fold below, so
this only lets them reach the queue-as-distinct-turn path. Ordinary unauthorized
user messages are still dropped — the NousResearch#17775 protection is intact.

Verification

  • New tests in tests/gateway/test_busy_session_auth_bypass.py:
    • test_transition_wake_not_dropped_by_auth_gatewitnessed RED against the
      pre-fix gate (the wake was dropped: "user= ()"), GREEN with the fix (falls
      through, running agent not interrupted).
    • test_ordinary_userless_message_still_dropped — control: an unauthorized
      non-system message is still dropped.
  • Full test_busy_session_auth_bypass.py: 6 passed.

After merge

Requires a gateway restart (sys.modules-cached run.py) before it goes live.
This is expected to be the LAST fix in the autonomous-wake chain — the wake now
survives every gate to the drain.

An origin-routed kanban-transition wake carries a user-less SessionSource (the
webhook builds no user_id for a shared thread) and is HMAC-authenticated at the
webhook route. When the origin session was busy, the busy handler's
user-authorization gate (NousResearch#17775) ran first, saw user=None, deemed the wake
'unauthorized', and silently dropped it (return True) BEFORE the wake exemption
further down — the final swallow that kept an origin-routed wake from ever
becoming a turn while the session was busy.

Exempt system-internal events (transition wakes and events flagged internal)
from the user-authorization gate: they are not user messages and are already
authenticated upstream. They remain exempted from interrupt/steer/fold below, so
this only lets them reach the queue-as-distinct-turn path. Ordinary
unauthorized user messages are still dropped (the NousResearch#17775 protection is intact).

Adds a regression test (witnessed-RED against the pre-fix gate) plus a control
proving an unauthorized non-system message is still dropped.
@cwest
cwest marked this pull request as ready for review July 2, 2026 00:45

@cwest cwest left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

No changes needed.

The gate placement is the crux and it's right: the exemption is computed as internal-flag OR transition-wake, and it only skips the user-authorization drop. A system event still flows through the two dedicated exemptions below (internal at run.py:5027, wake at run.py:5041), both of which return False so the event falls through to the base adapter's wake-precedence enqueue rather than interrupting the running turn. So the change opens exactly one path — reaching the queue-as-distinct-turn logic — and nothing more.

The exemption isn't forgeable from the wire. internal is a server-set field on MessageEvent, and kanban_transition_wake is stamped in one place only: webhook.py:800, which runs after HMAC validation at webhook.py:487-507 (401 on a bad signature, 403 on a missing secret). An inbound platform message can set neither. The control test confirms an unauthorized non-system message is still dropped, so the NousResearch#17775 protection stays intact.

Verified the regression test is real, not a tautology: reverting just the guard on run.py:4894 fails test_transition_wake_not_dropped_by_auth_gate with the exact live drop (user= (), "Dropping message from unauthorized user"), while the control keeps passing. Full suite is green on this head SHA (all 8 test slices plus e2e).

@cwest
cwest merged commit 6f196eb into cwest/integration Jul 2, 2026
31 checks passed
@cwest
cwest deleted the topic/wake-auth-gate-exempt branch July 2, 2026 00:46
cwest added a commit that referenced this pull request Jul 26, 2026
An origin-routed kanban-transition wake carries a user-less SessionSource (the
webhook builds no user_id for a shared thread) and is HMAC-authenticated at the
webhook route. When the origin session was busy, the busy handler's
user-authorization gate (NousResearch#17775) ran first, saw user=None, deemed the wake
'unauthorized', and silently dropped it (return True) BEFORE the wake exemption
further down — the final swallow that kept an origin-routed wake from ever
becoming a turn while the session was busy.

Exempt system-internal events (transition wakes and events flagged internal)
from the user-authorization gate: they are not user messages and are already
authenticated upstream. They remain exempted from interrupt/steer/fold below, so
this only lets them reach the queue-as-distinct-turn path. Ordinary
unauthorized user messages are still dropped (the NousResearch#17775 protection is intact).

Adds a regression test (witnessed-RED against the pre-fix gate) plus a control
proving an unauthorized non-system message is still dropped.

(cherry picked from commit 6f196eb)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant