Skip to content

Robustness batch: 13 fixes from the P2 audit (v0.120.0) - #146

Merged
gnacho merged 16 commits into
mainfrom
fix/v120-lote-p2
Aug 21, 2026
Merged

gnacho merged 16 commits into
mainfrom
fix/v120-lote-p2

Conversation

@gnacho

@gnacho gnacho commented Aug 21, 2026

Copy link
Copy Markdown
Owner

Second audit batch, this time the P2 candidates plus a live progress-race fix reported during validation. Each change lands as its own commit closing its issue.

Robustness:

Closes #133
Closes #134
Closes #135
Closes #136
Closes #137
Closes #138
Closes #139
Closes #140
Closes #141
Closes #142
Closes #143
Closes #144
Closes #145

gnacho added 16 commits August 21, 2026 17:11
configure compared only server/user/enabled, so after a re-authentication
the running worker kept the old password until a casual reconnect. The
password now participates in the change detection and triggers a
disconnect + fresh connect.

Closes #133
The overflow signal was a second try_send into the same full bounded
channel, so it could be dropped and the consumer would sync from a partial
event stream. The notify callback now sets an atomic flag that the consumer
polls on every event and rescans when set.

Closes #134
…size

Removing an account left its avatar file orphaned in the state directory
forever, and store_avatar persisted any byte length a server returned. The
cache now has delete_avatar wired into account removal and refuses bodies
larger than 4 MiB.

Closes #135
The fixed .tmp suffix let two instances share one staging file and mix
writes, and the rename was not made durable by an fsync of the directory.
Writes now stage on pid+counter tmp files and fsync the parent directory
after the rename.

Closes #136
…t as v1

A schema_version that is present but not a clean integer (string, decimal,
negative) silently fell to 0 or 1 and ran the v1 migrations over corrupt
data. Absent (or null) still means legacy v1; anything present must be a
valid integer.

Closes #137
…ports

An arbitrary string (e.g. 'banana') flowed straight into the theme
converter, which only understands system/light/dark. Validation now
restricts the value and falls back to the system default otherwise.

Closes #138
…pted UTF-8

from_utf8_lossy replaced invalid bytes with U+FFFD, so a non-UTF8 stored
secret read back as a different password and authentication failed opaquely.
The store now returns a Utf8 error for such bytes (CredentialError is an
enum wrapping secret_service::Error), which the engine maps to the
unavailable bucket.

Closes #139
The engine's sender survives across runs, so events still in the bounded
buffer after a run finishes were drained by the forwarder AFTER the
scheduler cleared the label, repainting it with a stale last event until
the next trigger or a view rebuild. A shared run-active flag now gates the
forwarder: the scheduler sets it on at prepare_sync and off (before
clearing progress) at run end, and the forwarder drops events drained
while it is off.

Closes #145
DriverContext and CommandSpec derived Debug and printed the password or
token verbatim, so any future dbg!/log debug of those structs would leak
the credential. Both now format with the secret values as [REDACTED].

Closes #140
…mpty

The first-run seed was detected with seen.is_empty(), so a first poll that
returned zero notifications left the set empty and the next poll with one
real notification re-entered the seed branch and swallowed it. A dedicated
seeded flag now marks the baseline after the first successful poll.

Closes #141
The committed catalog kept 18 msgids the po no longer had (conflict
actions, per-file progress labels, used-size summary), so regenerating
es.rs from the po dropped them. The po now carries those entries, es.rs is
re-regenerated from it (diff empty), and the CI workflow fails on any
future drift.

Closes #142
The project banished em dashes from user-facing strings; the tray title
'NextSync — {state}' used one. Now a regular hyphen.

Closes #143
parse_metered was only exercised by its own test; production reads metered
state through Gio's is_network_metered. Its loose any-field match could
also have misread a device literally named 'yes'.

Closes #144
The configure tests started the push consumer with glib::spawn_future_local
on the process-default context, which raced with other tests acquiring the
main context under parallel test threads (CI failure: 'already acquired by
another thread'). They now run inside glib::MainContext::new()
.with_thread_default like the other push facade tests, under TEST_LOCK.

Closes #133
@gnacho
gnacho merged commit 302d9f8 into main Aug 21, 2026
1 check passed
@gnacho
gnacho deleted the fix/v120-lote-p2 branch August 22, 2026 12:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment