Skip to content

core+net: stamp session onto register/attach/assign/deregister envelopes; fix control-byte JSON escaping in 3 writers - #75

Merged
Yaraslaut merged 6 commits into
masterfrom
issue-cluster-f-session-auth
Aug 12, 2026
Merged

core+net: stamp session onto register/attach/assign/deregister envelopes; fix control-byte JSON escaping in 3 writers#75
Yaraslaut merged 6 commits into
masterfrom
issue-cluster-f-session-auth

Conversation

@Yaraslaut

Copy link
Copy Markdown
Member

Summary

Closes #63, closes #62.

Review

Ran contour-workflows:cpp-review against the branch diff (real skill invocation). No findings — lock discipline for the new _sessionMtx verified leaf-only (no lock-order inversion), the three new escaping structs are deliberate duplicates (avoiding a new core/ dependency in headers meant to stay independently includable under MORPH_CLIENT_ONLY).

Caveat

The SocketBackend fix (include/morph/net/socket_backend.hpp) could not be compile-tested — morph::net is POSIX-only and ignored on this Windows build machine. It mirrors the verified SimulatedRemoteBackend fix exactly but is unverified by a build here; worth a CI check on Linux before merging.

Test plan

Full suite: 854/854 passing (excluding the two known pre-existing unrelated environment issues).

🤖 Generated with Claude Code

@Yaraslaut
Yaraslaut force-pushed the issue-cluster-f-session-auth branch from aeb721f to 922f7d7 Compare August 12, 2026 06:19
@codecov

codecov Bot commented Aug 12, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 97.50000% with 1 line in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
include/morph/session/session_auth.hpp 75.00% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@Yaraslaut
Yaraslaut force-pushed the issue-cluster-f-session-auth branch 2 times, most recently from 482a491 to ef139b2 Compare August 12, 2026 13:37
Yaraslau Tamashevich and others added 4 commits August 12, 2026 19:06
…ster envelopes

Add IBackend::setSession(session::Context), mirroring the
setReconnectHandler/setConnectHandler/setDisconnectHandler no-op-default
pattern. Bridge pushes the current default session to the active backend
from its constructor, from setDefaultSession(), and to the incoming backend
in switchBackend() (before phase 1's re-registration loop runs, so
re-registered handlers' control envelopes carry it too).

SimulatedRemoteBackend, SocketBackend, and QtWebSocketBackend override
setSession to store the session and stamp it onto every register,
registerShared, attach, assign, and deregister envelope they build.
LocalBackend needs no change -- the local path never serialises a Context
onto a wire envelope.

Previously these control envelopes always carried a default-constructed,
unauthenticated session::Context regardless of Bridge::setDefaultSession(),
so RemoteServer::authorizeRegister could never see a caller's identity and
the owner principal recorded at register time was always empty --
degrading authorizeInstance's ownership check to allow-all for every
Bridge-registered instance.

Updated docs/spec/core/backend.md, docs/spec/core/bridge.md, and
docs/spec/session/session.md to document the new hook and its call sites.

Note: SocketBackend's fix (include/morph/net/socket_backend.hpp) could not
be compile-tested on this Windows machine -- morph::net is POSIX-only and
MORPH_BUILD_NET is ignored on Windows -- but mirrors the verified
SimulatedRemoteBackend fix exactly. Same for QtWebSocketBackend, fixed for
consistency though not explicitly required by the issue's hint.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ters

Apply the same control-byte escaping option morph::wire::encode already
uses (morph::wire::detail::EscapingWriteOpts) to the three writers on
caller-supplied strings that never got the fix:
  - morph::journal::toJson(LogEntry)                (journal/action_log.hpp)
  - morph::offline::detail::toJson(FileQueueRecord)  (offline/file_offline_queue.hpp)
  - morph::session::TokenIssuer::issue(SessionToken) (session/session_auth.hpp)

glaze 7.4 leaves ASCII control bytes (0x00-0x1F) unescaped by default:
RFC 8259 requires them escaped, so a raw control byte in any of these
writers' string fields produced JSON the sibling reader either failed to
decode outright, or -- when the same string also held an escaped `\`/`"`
-- silently corrupted via glaze's chunked writer path before the payload
ever reached disk or was signed.

Each file gets its own local EscapingWriteOpts (duplicated, not shared,
to avoid a new core/ dependency from journal/offline/session -- these stay
independently includable, e.g. under MORPH_CLIENT_ONLY).

Also routes TokenIssuer::issue's previously-discarded
(void)glz::write_json(...) through a new throwOnGlazeError-style helper
(mirroring the other two writers already had), adding a TokenIssuanceError
type. Not realistically reachable for SessionToken's flat shape, but keeps
the writer consistent with its siblings instead of silently serialising a
claims blob that could later fail to verify.

Updated docs/spec/journal/journal.md, docs/spec/offline/offline.md, and
docs/spec/security.md to document the escaping and the new error type.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ol_characters members

Doxygen's WARN_AS_ERROR=FAIL_ON_WARNINGS gate flagged the two of these
three duplicated structs it happened to reach as undocumented (journal
and session; the offline-queue copy has the identical gap, fixed here
too for consistency). Matches the @brief already present on the
original in core/wire.hpp that these three deliberately mirror.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…Entry literals

Both structs gained fields (roles on SessionToken; outcome, error,
principal, timestampMs, idempotencyKey on LogEntry) at various points
in their history, and this branch's new test files built designated
initializers against the earlier, shorter field lists. MSVC doesn't
warn on this; Linux clang-debug's strict -Werror,
-Wmissing-designated-field-initializers does. List every field
explicitly at each call site.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@Yaraslaut
Yaraslaut force-pushed the issue-cluster-f-session-auth branch from ef139b2 to 1e5dd5a Compare August 12, 2026 16:11
Yaraslau Tamashevich and others added 2 commits August 12, 2026 21:25
Comments should describe the present implementation and its rationale,
not narrate what a fix changed — once merged, that framing has no
context to anchor to.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…not history

docs/spec/core/backend.md, docs/spec/session/session.md,
include/morph/core/backend.hpp, and two test file headers/comments
narrated the pre-fix state ('before IBackend::setSession existed',
'was always empty', 'reproduces and verifies the fix for #63') instead
of describing the current design. Rewritten to state only present-tense
facts and their rationale — once merged, 'before the fix' framing has
no context to anchor to.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@Yaraslaut
Yaraslaut merged commit 7b38831 into master Aug 12, 2026
23 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant