Skip to content

v0.98.3

Choose a tag to compare

@github-actions github-actions released this 06 Jul 10:39
· 1022 commits to main since this release

Added

  • The armed auto-action policy is now durable, so the terminal and a live orchestration loop share
    one source of truth. synapse auto-action arm compact,log and disarm log add or remove
    actions in a JSON policy file in the coordination home ($SYN_HOME or ~/synapse, overridable
    with --store PATH), clear disarms everything, and show renders the persisted posture; the
    bare command still previews the static model and touches no files. New participants.auto_action_store
    (load_policy, save_policy) is the seam an orchestration harness loads to build its dispatch,
    so what the operator arms is what the loop would fire. Persisting a policy still fires nothing —
    an armed action fires only when its signal is raised at runtime and a handler was supplied.

Security

  • The cross-hub operator relay can now require two-person approval: a hub started with
    require_two_person_relay records an authorised relay pending instead of applying it, and
    carries it out only when a second, different operator relays the same action, namespace, and
    task. The same operator repeating the request cannot approve their own relay (it stays pending),
    and both the pending request and the approval are audited, so a governed cross-hub force-release
    under this policy names two distinct operators in the log. The RelayActionResult gains a
    pending field and synapse federation relay a new exit code 3 for a recorded-pending
    verdict; both default off, so a single-operator hub and an older initiator read exactly as
    before. The quorum lives in the new core.operator_relay_approval ledger (bounded, in-memory),
    completing the operator-relay policy rituals begun with reason-required receipts and break-glass
    tagging; break-glass does not bypass the quorum.
  • The cross-hub operator relay now carries a reason and a break_glass tag, recorded in the
    operator_relay audit on both the originating and the owning hub, so a governed force-release
    across hubs leaves an auditable why and an emergency override stands apart from routine
    governance in the log. synapse federation relay gains --reason and --break-glass, and a
    hub started with require_relay_reason refuses a relay that carries no reason (reason-required
    receipts) — deny-by-default, checked in authorise_relay after the peer and action gates. Both
    wire fields default empty for backward compatibility. (Two-person approval of a relay is a
    larger stateful workflow, tracked as a follow-up.)
  • The AES-GCM per-key message limit can now be enforced across restarts, not just within one
    process. AtRestCipher takes an optional counter, and the new core.at_rest_counter
    provides a crash-safe PersistentMessageCounter that persists the count to a sidecar file by
    reserving a batch ahead of use — so a long-lived encrypted store resumes a key's cumulative
    lifetime count after a restart or crash (over-counting by less than a batch and rekeying early,
    never under-counting and risking a fresh nonce colliding with an old one). The default remains
    the per-process InMemoryMessageCounter, byte-identical to before. AtRestCipher.from_key_file
    and from_wrapped_key_file accept the counter so a store can opt in.
  • The WebAssembly sandbox now canonicalises a filesystem grant's host path before it
    preopens it, and refuses the run fail-closed if the path resolves through a symlink or
    is not an existing directory. A host path is resolved on disk at run time, so a symlink
    swapped into a granted path between manifest authoring and execution could have
    redirected a preopen to a directory the operator never granted; the sandbox now preopens
    the resolved real directory and records it in the run receipt's new preopened_paths
    field, so the run reaches exactly the directory the receipt shows and no moving target.
    New core.sandbox_paths (resolve_preopen_host, harden_preopens).
  • SECURITY.md no longer describes at-rest encryption as unimplemented. The at-rest
    encryption runtime (envelope encryption of SQLite stores, WAL/SHM sidecars, relay
    logs, A2A state, archives, and backups; scrypt/PKCS#11/TPM2 key-encryption backends;
    migration/rekey) has shipped, so the security posture doc now states it accurately,
    with the transparent live-database (SQLCipher-class) boundary kept honest as the
    remaining gap. Private channels are likewise no longer listed as future work.
  • Dashboard operator writes now require Content-Type: application/json, closing a
    local cross-site-request-forgery hole. A cross-origin web page can POST a body to
    the loopback dashboard without a CORS preflight only with a "simple" content type
    (text/plain, form-encoded, multipart); the operator write path parsed JSON from any
    content type, so a malicious page a local operator visited could drive /message,
    /task, and /task/update in synapse dashboard --operator without reading the
    response. Requiring application/json forces a preflight the surface never answers
    with cross-origin allow headers, so the browser blocks the write; a non-JSON operator
    write is refused 415. The read-only dashboard and the same-origin cockpit (which
    already sends application/json) are unaffected. The misleading docstring that claimed
    loopback writes require the bearer token is corrected.