v0.99.13
Security
- Portable owner-only secret and private-directory floors now cover real
Windows NT DACLs (exclusive owner ACE, fail-closed world-readable
secrets) alongside the existing POSIX0600/0700mode floor. Key and
payload loaders assert the owner-only floor before reading secret bytes;
non-regular key paths (directories, unexpected types) are refused before
DACL/read. Advisory Windows CI exercises a focused NT security-floor pack
rather than the hang-prone full alphabetical suite; required Linuxci
remains the full-coverage merge gate.
Added
- The five-mode fleet communication workbench now follows the selected English,
Slovak, German, Spanish, or French cockpit locale across view controls,
filters, graph and table descriptions, selection details, evidence chains,
and operator-response controls. Exact identities, message bodies, sequence
numbers, delivery and response statuses, and server-authored outcome details
remain literal evidence. The former broad fleet component is split into
orchestration, communication projections, conversation detail, and temporal
projection modules, with focused component and production-browser coverage. - A complete offline French cockpit catalogue with typed key parity, URL,
saved-preference, and browser-language resolution. The HUD and in-product
guide exposeFR; built-browser coverage verifies the French guide and setup
assistant in narrow portrait and landscape layouts without accessibility
violations. Identities, wire outcomes, flags, paths, and setup placeholders
remain literal protocol evidence. - A complete offline Spanish cockpit catalogue with typed key parity, URL,
saved-preference, and browser-language resolution. The HUD and in-product
guide exposeES; built-browser coverage verifies the Spanish guide and setup
assistant in narrow portrait and landscape layouts without accessibility
violations. Identities, wire outcomes, flags, paths, and setup placeholders
remain literal protocol evidence. - A content-minimized local fleet-health summary in the cockpit risk rail. It
counts retained-log contention pairs, log-relative expired claims,
receipt-proven dead letters and recoveries, and escalation events from the
currently retained local event store. The projection includes retention
boundaries but omits identities, task ids, paths, messages, notes, and
payloads; it persists nothing and sends no telemetry. - Advisory
cross-osCI lane (.github/workflows/cross-os.yml) that runs the test
suite on macOS (POSIX) and Windows (NT) with Python 3.12, surfacing real
filesystem and socket semantics — path separators, permission/O_NOFOLLOW
behaviour, file locking, temp-dir layout, asyncio transport differences — that
the Linux-onlycimatrix cannot. The Linux-only backends (SQLCipher manylinux
wheels, TPM/PKCS#11 system libraries) are absent there, so those suites skip; the
lane is about OS filesystem/socket behaviour. Deliberately not a required check. - Scheduled advisory
soakCI lane (.github/workflows/soak.yml, weekly +
workflow_dispatch) that runs a bounded soak of the hub's waiter/liveness
bookkeeping under sustained connect churn (tests/test_waiter_liveness_soak.py),
asserting the per-identity live-socket and last-reaction maps return to baseline
rather than growing with the reconnect count. The cycle count scales via
SYNAPSE_SOAK_ITERATIONS; the ordinary suite runs a cheap default and the lane
amplifies it. It is deliberately not a required check. synapse hub --claim-peer HUB_ID=URI(repeatable, requires--namespace-owner,
with--claim-peer-token): the operator CLI route that configures cross-hub
claim forwarding. A remote-owned claim with a matching route is forwarded to
its owning hub and the verdict relayed; an owner with no route stays refused
with the owner named (opt-in, fail-closed). The forwarding library/serving
path already shipped — this closes the parity gap where the docs described
forwarding as configurable but no CLI flag populatedclaim_peers.- Normative coordination specification (
docs/coordination-spec.md): the
numbered invariants of the single-hub coordination core — mutual exclusion,
epoch fencing, lease liveness, journal-before-apply, restart replay,
crash/reconnect/partition semantics, per-verb delivery guarantees, the
hub/federation clock model (including the signed-frame skew budget), and an
explicit statement that two default hubs provide no cross-host mutual
exclusion — each mapped to the executable test that pins it, plus a
machine-checkableRuleBasedStateMachinemodel of the claim/lease/fencing
invariants (tests/test_coordination_spec_model.py) and a drift guard binding
the document to the implementation (tests/test_coordination_spec.py).
Changed
- The cockpit snapshot data layer is split by responsibility behind its stable
snapshotimport facade.snapshotParsernow owns defensive narrowing of
partial or malformed hub documents, whilesnapshotStoreowns authenticated
polling, listener delivery, freshness, timers, and abort lifecycle. Snapshot
defaults, status transitions, held-last-good behaviour, and consumer imports
are unchanged. - The cockpit communication library is split by responsibility while retaining
its stablecommunicationsimport facade.communicationEvidenceowns
retained chat and receipt normalisation,communicationModelowns the
metadata-only fleet projection,conversationDetailowns the selected
body-bearing pair timeline, andcommunicationLayoutowns deterministic web
and matrix bounds. Fleet views, filtering, semantic responses, and evidence
limits are unchanged. - The cockpit inspector is split by responsibility.
InspectorTabsnow owns
only accessible tab chrome;useInspectorNavigationowns roving focus and
task trace hops;InspectorPanelowns lazy panel routing and evidence-state
adapters. The public props, eight panel routes, deferred chunk boundaries,
trace prefill, and selection fallbacks are unchanged. - The cockpit activity spine is split by responsibility.
ActivitySpinenow
composes only the accessible canvas, lane labels, legend, and tooltip;
useActivitySpineowns live-source subscription, animation, theme/resize,
pointer, hover, and keyboard-brush lifecycle;activitySpineCanvasowns the
pure 75-second pixel projection. Public props, retained-event semantics,
reduced-motion behavior, brush controls, and selection evidence are
unchanged. - The cockpit signal log is split by responsibility.
SignalLogretains the
operator controls and composes the workspace;useSignalLogWorkspaceowns
live-view freezing, history scrubbing and comparison, and offline post-mortem
lifecycle;SignalLogRowsowns bounded flat/compact evidence rendering, raw
payload expansion, exact navigation, and browser-side Merkle verdicts. The
public component contract, evidence precedence, query semantics, render cap,
and fail-closed proof language are unchanged. - The cockpit feed lifecycle is split by responsibility.
useCockpitFeeds
retains the authenticated multiplexed transport and bounded polling fallback;
slower reliability, federation, metrics, sessions, waits, and anomaly stores
have an independent lifecycle owner. Pure frame projections now decode the
four live channels, and a separate headline projection owns KPI deltas and
the freshness stamp. Startup ordering, fallback timing, retained evidence,
credential-generation isolation, and the public hook contract are unchanged. - Non-default cockpit inspector panels now cross real production bundle
boundaries. Fleet, topology, metrics, audit, incident, and causality load only
when selected, with a localised accessible Suspense state; the default signal
log and attention queue remain in the entry path. The production entry falls
from 530.11 kB to 468.48 kB minified (151.60 kB to 137.26 kB gzip) without
raising the chunk warning limit, and the six deferred chunks remain bounded
between 4.27 kB and 29.19 kB minified. - The cockpit root now delegates replay reconstruction, persisted preferences,
transient overlays and command entry, live transition toasts, and live/replay
panel projections to dedicated hooks.App.tsxis limited to authenticated
feed/workspace composition and shell rendering. The split preserves the
existing access, URL, replay, focus, keyboard, toast, and panel contracts and
gives every extracted lifecycle its own full branch-tested surface. - Breaking (secure default flip toward 1.0): a hub that binds off loopback
with a connect token but over plaintextws://(no native TLS) is now
refused at startup instead of merely logging an advisory. The shared token
and every coordination frame would be readable on the network path, so the
off-loopback bind now requires native TLS (--tls-certfile/--tls-keyfile) or
awss://-terminating proxy. This joins the existing token-less and
metrics-token refusals under the same gate. Migration: front the hub with TLS
(or awss://proxy) when exposing it off loopback; on a trusted private
network where you accept plaintext, pass--insecure-off-loopbackto downgrade
the refusal to a warning (the same override that already covers the token-less
case). Loopback binds and TLS-terminated binds are unaffected;--paranoidand
--securealready required native WSS. - Breaking under
--require-acl(secure default flip toward 1.0): global chat
history and cursor-based resume (history_request/resume_request) are now
ACL-gated. A deny-by-default hub previously enforced the ACL on mutations but
still served its entire chat backlog to any authenticated agent — the read
counterpart to the channel-history membership gate was missing. They now require
the newrecallpermission on thehistory:globaltarget. Migration: on a
--require-aclhub, add arecallrule (target kindhistory, pattern
global) for every identity that legitimately pulls history — dashboards,
reconnecting workers doing catch-up. Hubs without--require-acl(open or
loopback) are unaffected: the recall reads stay open, matching the
proportionate-to-exposure posture. - Breaking (secure default flip toward 1.0): private-channel membership is now
invite-only. Previously any authenticated agent could self-join any private
channel by id; now the channel owner (its creator) is the sole party who may
invite, and an agent may join only a channel it was invited to. An invite grants
exactly one join and is consumed on join, so a member who leaves needs a fresh
invite to return. Newsynapse channel invite <id> --invitee <name>verb,
CHANNEL_INVITEwire message, andchannel_inviteclient method; the verb is
ACL-gated like the other channel verbs (messagepermission on the channel
target). Migration: the owner mustchannel inviteeach member before they can
channel join; self-join call sites now need an invite round-trip. Channel
creation, leave, list, and history are unchanged. - Breaking (secure default flip toward 1.0): a hub that binds off loopback
with a plaintext--dbevent store is now refused at startup. The durable
coordination log would otherwise sit unencrypted on a networked host's disk, so
a disk or backup compromise leaks the whole history. Proportionate to exposure,
mirroring the transport bind flip: a loopback / single-owner hub keeps a
plaintext store exactly as before, and an already-encrypted store (--db-key-file,
which selects the SQLCipher store) is unaffected. When the SQLCipher extra is
absent the refusal names the install step. Migration: on an exposed hub, encrypt
the store (synapse encrypt-key migrate-sqlcipher+--db-key-file, after
pip install 'synapse-channel[sqlcipher]'), or pass the new
--insecure-plaintext-at-restto accept the risk and bind anyway. The at-rest
override is independent of--insecure-off-loopback.
Fixed
- Governed cockpit writes now separate strict outcome/local-input validation
from authenticated POST transport and authority-preserving result mapping
behind the unchangedoperatorActionsfacade. Task, semantic-response, and
message payloads, URLs, validation text, HTTP status semantics, and unsafe
detail fallbacks remain unchanged. - The local incident workbench now separates fail-closed draft persistence,
typed evidence-cart mutation, and explicitly non-authoritative export
generation behind the unchangedincidentWorkspacefacade. Schema v1,
selection/replay validation, bounds, de-duplication, storage failure handling,
authority wording, and export filenames remain unchanged. - Durable receipt and governed-action feeds now separate strict document
validation from authenticated retained-cursor lifecycle behind the unchanged
auditFeedsfacade. HTTP polling and multiplexed live frames still share the
same fail-closed schemas, while absence reset, last-good retention, ordering,
de-duplication, and abort behavior remain unchanged. - The cockpit's durable event tail now has explicit trust, projection, and
lifecycle owners behind its unchanged import facade. Tolerant wire parsing,
exact hub sequence/timestamp projection, current and legacy history
bootstrap, absent/error provenance, and stop/abort behavior remain unchanged
while each contract can evolve and fail independently. - Overlapping dashboard live transports and snapshot reads now serialize the
short-lived hub fetch that shares the configured dashboard identity. Browser
access changes can no longer race two sockets under one name, trigger the
hub's4009 name conflict, or lose a snapshot cycle; the hub's single-owner
identity invariant and stable roster name remain unchanged. synapse demonow writes a genuinely self-contained static dashboard: its
styles and completed coordination evidence are embedded in the HTML, with no
missing CSS/JavaScript requests, live-feed dependency, or token prompt when
the generated file is opened directly.handoffnow enforces the same file-scope mutual exclusion as a direct claim:
a transfer whose scope collides with a live claim held by an agent other than
the recipient is refused, instead of silently leaving two different agents
holding the same files. Surfaced by the new coordination-spec state model.- Advisory cross-os process-group cleanup no longer treats Darwin
killpg(0)
PermissionErroras a hard failure: existence probes fall back to the group
leader's reaped state, and signal delivery can fall back to the leader when
group signalling is refused. Cockpit shell tests await deferred inspector
chunks after the lazy panel split. - Local setup receipt exceptions join the frozen error taxonomy; non-exception
setup refusal records no longer use an*Errorclass name that tripped the
AST drift gate. - Advisory
cross-osjob timeout raised from 30 to 90 minutes so the Windows
full-suite cell can finish instead of being cancelled mid-pytest. - Windows claim/timeout messages, shell path quoting (
Path.as_posix),
UTF-8 CLI e2e helpers, systemd notify shlex, and gitclaim runner encoding
no longer fail closed on NT path or console code-page differences that are
not security regressions. - Advisory Windows cross-os install uses the universal hash-locked
requirements-dev.txt(--require-hashes) plus editable--no-deps
install (same supply-chain pattern as requiredci), closing the Scorecard
Pinned-Dependencies finding on unhashedpip installof the dev extras. - Windows advisory lane runs a focused NT security-floor pytest pack (secure
path, secrets, at-rest keys, claims, CLI floors, path identity) so portable
owner-only floors stay proven without the mid-suite KeyboardInterrupt hang
class that still affects the full alphabetical Windows suite.
Artifact checksums (SHA-256)
0c0f7471f92412d257eefc645f554677fbe81dbc4958af8fa62b6c7c22fd494c synapse_channel-0.99.13-py3-none-any.whl
9872eaa955a81c2585215a0df251315da9fe4642056a731f79232249e25402f9 synapse_channel-0.99.13.tar.gz
e9d0557ee60de4e37b5578b0aec584bb7b602f52530fad49edf45a0b8292dc2c synapse-channel-v0.99.13-sbom.cdx.json