Skip to content

Release v1.3.0 - #35

Merged
locainin merged 275 commits into
masterfrom
dev
Aug 13, 2026
Merged

Release v1.3.0#35
locainin merged 275 commits into
masterfrom
dev

Conversation

@locainin

Copy link
Copy Markdown
Owner

Summary

This PR promotes the current dev baseline to master.

The release updates UnixNotis across configuration, notification lifecycle handling, application attribution, theming, preset management, service-manager integration, diagnostics, media/artwork handling, and installer/reset behavior.

The largest compatibility change is the move to configuration schema 5. Current builds require an explicit config_version = 5; older, newer, and unversioned configurations are rejected rather than silently migrated.

Highlights

Notification lifecycle and control

  • Separate popup visibility from active-notification lifetime
  • Correct timeout handling for resident and critical notifications
  • Positive timeouts close non-critical active notifications even when resident is set
  • Critical notifications may hide their popup while remaining active
  • Resolve notification deadlines when a generation is committed rather than changing existing deadlines after config reloads
  • Keep actions and inline replies generation-aware to prevent stale controls from acting on replacement notifications
  • Expand notification diagnostics through noticenterctl explain-notification <id>
  • Add explicit popup admission/delivery state and notification attribution diagnostics

Trusted application attribution

  • Distinguish daemon-resolved application identity from sender-provided claims
  • Make app rules operate on trusted daemon-resolved identity and fail closed when attribution is unresolved, conflicting, or relayed
  • Add claimed_app for explicitly matching the untrusted freedesktop app_name
  • Preserve claimed_desktop_id only as bounded presentation/decorative metadata rather than trusted identity
  • Separate authorization policy for default activation, actions, and inline replies
  • Keep sender-provided visuals separate from the trusted application badge

Notification images and artwork

  • Add explicit roles for conversation avatars, application-provided visuals, and content images
  • Add independent panel control for notification avatars
  • Pass sanitized pixel data to UI processes instead of exposing sender-provided filesystem paths
  • Add the bounded unixnotis-svg-renderer helper for local SVG rasterization
  • Reject SVGs outside the supported size/resource policy or those requiring external/secondary image loading
  • Harden native/browser media artwork admission and browser-player deduplication

Sound hardening

  • Disable sender-provided sound-file hints by default
  • Add sound.allow_file_hints
  • Add sound.allowed_file_hint_dirs
  • Require sender-provided sound files to resolve inside an explicitly allowed directory
  • Restrict accepted sender files to local regular uncompressed PCM WAV files within the size limit
  • Reject remote, symlinked, out-of-policy, or unsupported sound-file hints and fall back to sound-name/configured defaults
  • Advertise the D-Bus sound capability only when the required sound configuration and playback support are actually available

D-Bus and DND behavior

  • Remove the unsupported body-markup capability advertisement
  • Expand the private UnixNotis control API and expose its version through GetApiVersion()
  • Add richer notification attribution, image, diagnostics, popup-decision, inhibitor, and UI-health data
  • Enforce sender ownership for replacement and close operations
  • Keep generation-aware action/reply methods
  • Tighten timed DND validation
  • SetDndUntil accepts a bounded future timestamp; clearing DND is done through SetDnd(false) rather than using a zero deadline
  • Clarify inhibitor scopes and the distinction between no_popups and drop_all

Configuration

  • Move the current configuration baseline to config_version = 5
  • Remove implicit migration of unversioned/older configurations
  • Reject unsupported schema versions instead of guessing compatibility
  • Add notification-avatar configuration
  • Add the sound-file allowlist settings
  • Remove automatic migration of legacy standalone style.css
  • Keep unknown-key logging and runtime bounds/sanitization

Theming

  • Raise the supported GTK baseline to GTK 4.18+
  • Standardize on the five runtime CSS layers: base.css, panel.css, popup.css, widgets.css, and media.css
  • Load runtime CSS directly from configured [theme] paths
  • Treat theme.toml as compatibility metadata rather than a runtime requirement or normal preset-export input
  • Support GTK custom properties and supported var(...)/calc(...) expressions as part of the normal theme contract
  • Fall back per-layer to embedded CSS when an active stylesheet is missing, unsafe, invalid, oversized, or unreadable
  • Refuse unsafe symlink/non-regular stylesheet paths
  • Preserve existing regular theme files during install/repair
  • Replace obsolete notification selectors with the current grouped-row and stack-layer hooks
  • Keep CSS hot reload isolated from Rust widget hierarchy changes

Presets and reset workflow

  • Re-export bundled presets against schema 5 and the current CSS hooks
  • Keep normal preset exports dependency-based rather than treating theme.toml as a required payload
  • Retain archive/path/content validation for preset inspection and import
  • Add noticenterctl preset reset-config
  • Add noticenterctl preset reset-config --yes
  • Add noticenterctl theme export-stock
  • Make reset transactional: create a recovery snapshot, replace only the fixed stock targets, and leave unrelated/custom files untouched

Reset targets are:

  • config.toml
  • base.css
  • panel.css
  • popup.css
  • widgets.css
  • media.css
  • the four bundled unixnotis-blue-light-* helper scripts

Backups use timestamped names with collision suffixes when necessary:

  • Backup-YYYY-MM-DD-HHMMSS
  • Backup-YYYY-MM-DD-HHMMSS-001
  • Backup-YYYY-MM-DD-HHMMSS-002
  • ...

CLI and diagnostics

Expand the locally usable command families and add operational tooling including:

  • noticenterctl explain-notification <id>
  • noticenterctl refresh-applications
  • noticenterctl sync-session-environment
  • noticenterctl preset reset-config
  • noticenterctl theme export-stock

doctor --verbose now covers configuration/CSS, D-Bus ownership, private-control authorization, compositor environment, service-manager state, and available service logs.

Service-manager and session integration

UnixNotis continues to use systemd --user as the default service-manager path and supports user-service backends for:

  • systemd
  • dinit
  • runit
  • s6-rc

Add sync-session-environment to validate and propagate the compositor/session environment after login, compositor restart, or service-manager migration.

Relevant session state includes Wayland, runtime-directory, desktop/session, PATH, display, and D-Bus environment values.

Installer and release packaging

  • Require GTK 4.18 or newer before installation proceeds
  • Include and verify unixnotis-svg-renderer in release archives
  • Harden CSS provisioning and repair around configured paths
  • Preserve existing regular files
  • Do not create missing external stylesheet targets
  • Reject unsafe/symlinked targets
  • Synchronize the graphical session environment before service startup
  • Expand reset/restore validation and restore executable helper scripts with the expected mode

Breaking changes / migration notes

This release is not configuration-compatible with older schemas.

Before upgrading:

  • Back up the existing UnixNotis configuration
  • Update config.toml to schema 5
  • Review fields whose defaults or semantics changed rather than only changing the version number
  • Update custom CSS using obsolete grouped-notification/stack selectors
  • Re-export old presets with the current CLI
  • Review rules that previously treated sender-provided application names as trusted identity
  • Explicitly configure the allowlist if sender-provided sound-file hints are required
  • Confirm GTK 4.18+ is installed
  • Run session-environment synchronization if the daemon is managed outside the compositor process

locainin added 30 commits July 20, 2026 17:04
Summary: use typed service commands.

Scope: installer.
Summary: separate builtin readers and detection.

Scope: stats.
Summary: separate grid, card, and worker ownership.

Scope: stats.
Summary: bound normalization and truncation work.

Scope: text.
Summary: preserve OS-native playback paths.

Scope: sound.
Summary: reduce queue and collection churn.

Scope: repository.
Summary: isolate builtin reader dispatch.

Scope: stats.
Summary: cover optimized boundary behavior.

Scope: repository.
Summary: classify shell wrappers and timeouts consistently.

Scope: commands.
Summary: isolate refresh state and coverage.

Scope: stats.
Summary: identify inline shell command strings precisely.

Scope: core.
Summary: expose panel modules by responsibility.

Scope: center.
Summary: reduce hover and overlay scroll work.

Scope: panel.
Summary: add a reduced-motion policy.

Scope: panel.
Summary: reject privileged execution early.

Scope: installer.
Summary: apply reduced motion immediately.

Scope: ui.
Summary: preserve modes in atomic user-file writes.

Scope: filesystem.
Summary: harden service and config publication.

Scope: installer.
…riptors

Summary: publish binaries and backups through stable descriptors.

Scope: installer.
Summary: remove artifacts through stable anchors.

Scope: installer.
Summary: manage directories through stable descriptors.

Scope: installer.
Summary: publish links through stable anchors.

Scope: installer.
Summary: move and read files beneath stable descriptors.

Scope: filesystem.
Summary: harden legacy theme migration.

Scope: config.
Summary: cover reduced-motion and media lifecycle.

Scope: ui.
Summary: cover config and installer filesystem lifecycle.

Scope: repository.
Summary: colocate module coverage and reject orphans.

Scope: repository.
Summary: reconcile brightness slider writes.

Scope: center.
Summary: add guarded ownership transactions.

Scope: filesystem.
Summary: harden reference scanning.

Scope: css.
locainin added 29 commits August 6, 2026 20:02
Build trusted control executable fingerprints while constructing DaemonState, before D-Bus names and control objects are published. Read only the immutable startup map during authorization and remove lazy first-caller trust initialization. Update authorization tests for startup snapshots and missing trusted binaries.
Resolve Cargo, rustc, and rustdoc from the effective account and execute canonical validated paths. Rebuild PATH from trusted toolchain and system directories, pin Rustup state, and remove inherited compiler and linker override variables. Cover poisoned HOME, PATH, and build-environment inputs with installer tests.
Resolve an issue where certain notification images could fail to appear.

Incoming notification images were being subjected to the smaller retained
model limit before they could be downsampled. This caused otherwise valid
large sender and content images to be discarded.

Separate transient wire-image validation from persistent image storage,
validate and downsample images before applying retained-model limits, and
keep the existing wire and storage security bounds unchanged.

Also fix file-backed visuals so source images can be safely decoded before
being reduced to their requested display size.

Add regression coverage for large, non-square, padded RGB, oversized, and
invalid image inputs.
Make config v5 a clean schema break and reject older schemas instead of silently migrating changed semantics.

Match app= rules against daemon-resolved application identity and add claimed_app= for explicit matching of sender-provided app_name metadata. Use an explicit positive assurance allowlist so future assurance states fail closed.

Keep forced urgency and retained urgency hints synchronized, and update config consumers and tests for the v5 schema.
Bound PropertiesChanged messages before dynamic deserialization and propagate timeouts across the complete property snapshot.

Replace pass-count fairness with monotonic admission leases and scheduled wakeups so full player inventories cannot starve newcomers indefinitely.

Construct replacement players before evicting incumbents, preserve incumbents when candidate construction fails, and add coverage for quiet full-capacity rotation, property limits, timeout handling, and selection behavior.
Harden notification ownership, callback routing, quotas, protocol validation, and lifecycle handling around stable Linux process identity.

Prevent D-Bus name churn from resetting per-sender quotas, preserve callback delivery across reconnects, restrict replacement to active notifications, and make failed CloseNotification requests indistinguishable.

Preserve absolute popup deadlines across renderer downtime, correct resident and critical expiration behavior, and give DropAll notifications a content-free lifecycle with reply-before-close ordering.

Validate raw image channel and row layout, advertise only implemented capabilities, canonicalize stored urgency, and consume sound cooldown only after a sound request is actually accepted.

Add integration coverage for D-Bus lifecycle ordering, ownership, reconnects, quota principals, images, sounds, expiration, and popup replay.
Treat session-only systemd masks as recoverable during explicit installs while preserving persistent masks and checking for package-owned artifacts.

Clear runtime masks immediately before service activation, surface the config v5 clean-break requirement without exposing parser details, and derive test home layouts without hardcoded account paths.
Harden notification mutation and interaction boundaries against same-ID replacement races and unfair quota consumption.

- serialize action, reply, close, and replacement commits by notification ID
- revalidate exact notification generations before protocol signals and cleanup
- make notify admission atomic across global and per-principal buckets
- separate unauthorized close attempts from authorized close-commit budget
- bound fresh-principal churn
- enforce per-principal active notification limits
- prevent one sender from monopolizing the global active set
- add regression coverage for replacement races and quota accounting
Keep application identity, conversation identity, and message content as separate presentation concepts.

- retain bounded conversation-avatar pixels without treating them as app trust
- require positive attribution before materializing local application artwork
- keep application-provided visuals out of the message-thumbnail lane
- restore conversation avatars to the popup identity column
- preserve avatars across collapsed and expanded notification-center rows
- retain authenticated app-icon fallback and trust presentation
- clamp configured popup timeouts and handle deadline overflow defensively
- preserve fail-closed trial-mode owner inspection
- harden SVG renderer test coverage for timeout and output bounds
Make backup restoration durable, validated, and recoverable.

- validate restore input before publishing live configuration
- stage restore contents before mutation
- journal previous file state before replacing live files
- reject unsafe paths, duplicate entries, invalid schemas, and oversized files
- restore original files after interrupted or failed transactions
- commit successful restores by removing transaction state
- add recovery, validation, and exact-size boundary tests
Replace raw exit-status interpretation with bounded semantic service-manager probes.

- add explicit Available, Unavailable, and Indeterminate manager states
- bound subprocess runtime and captured output
- interpret systemd and dinit manager state using backend-specific semantics
- use native service probes for runit and s6 where no manager-wide query exists
- fail closed on ambiguous active-state and manager-availability results
- classify partial, unsafe, active, and indeterminate alternate-manager installs
- make compatibility checks consume the same semantic availability API
- add backend regressions for reachable, absent, inactive, and ambiguous states
Represent installed binaries as immutable verified release generations.

- generate manifests for complete binary sets
- record package version, file size, mode, and SHA-256 digests
- stage complete generations before publication
- verify staged and existing generations before trusting them
- inspect installed entrypoints against the current verified generation
- reject corrupt, mixed, malformed, or unmanaged binary layouts
- retain generation health metadata for install-state reporting
- add manifest, health, corruption, and generation-consistency tests
Make binary publication atomic and recoverable across interrupted installs.

- create a durable pending-release journal before live entrypoint mutation
- move legacy entrypoints into generation-scoped rollback storage
- publish managed entrypoints without following unsafe links
- atomically switch the current generation
- recover interrupted release transactions before new mutation
- revalidate the previous generation before rollback
- retain rollback authority until service readiness commits the release
- prune superseded generations only after successful activation
- add journal, entrypoint, rollback, recovery, and transaction regressions
Distinguish healthy installs from missing and damaged installations.

- replace binary existence checks with verified generation health
- require all managed binaries to belong to one verified generation
- include service artifact and manager inspection health in installed state
- introduce NotInstalled, InstalledHealthy, and RepairRequired dispositions
- expose verified installed version from generation metadata
- label healthy installs as Reinstall and damaged installs as Repair
- avoid presenting incomplete installations as clean fresh installs
- add install-state and UI disposition regressions
Fail closed when existing installation ownership cannot be established.

- canonicalize systemd fragment and executable identity before classifying channels
- reject mixed, package-owned, partial, and unrecognized installations
- treat systemctl inspection failures as errors rather than absence
- preserve persistent user masks and recover supported runtime masks safely
- validate installed service artifacts by expected object shape
- serialize mutating installer sessions with an owned runtime-directory lock
- refuse symlink-redirection and foreign lock-file ownership
- add channel-classification, path-identity, and installer-lock regressions
Close the reinstall activation race across daemon shutdown, binary publication, and service preparation.

- stop the selected daemon and wait for actual runtime quiescence
- distinguish transient shutdown convergence from strict mutation checks
- reserve both org.freedesktop.Notifications and com.unixnotis.Control
- make the activation reservation a non-forgeable production capability
- require the reservation for binary and service-artifact publication
- retain the guard through manager refresh and pre-start preparation
- recheck selected service state around destructive transaction boundaries
- release activation exclusion only immediately before controlled startup
- verify service readiness before committing the pending release
- retain strict checks for direct service-manager starts
- add reservation, quiescence, handoff, and reinstall-race tests
Keep daemon activation inhibited when failed installation recovery cannot prove a safe runtime and disk state.

- distinguish ordinary recovered failures from ActivationInhibited failures
- retain the dual-name reservation when pending-journal inspection fails
- retain activation exclusion when guarded rollback itself fails
- treat contradictory in-memory and on-disk release state as catastrophic
- keep the worker and installer lock alive while activation remains inhibited
- expose a dedicated Manual recovery required progress state
- prevent returning to the installer menu while the recovery guard is held
- preserve concise status errors and complete anyhow chains in logs
- test guard lifetime across install steps and catastrophic recovery branches
Allow an advertised default notification action only when the callback owner is bound to a concrete sender process lifetime.

Keep application identity independent from callback ownership. Arbitrary action buttons and inline reply remain denied for owner-bound unresolved senders.

Require stable sender name, PID, process start time, and UID evidence. Credential failures, incomplete evidence, conflicts, and relay fallback paths continue to fail closed.

Add resolver, sender-evidence, and action-target regression coverage.
Preserve bounded desktop-entry metadata as presentation-only application branding without treating caller claims as identity evidence.

Separate wire conversation visuals, application-provided visuals, and content media so choosing a presentation slot cannot grant filesystem or interaction authority.

Keep local visual paths gated on positive attribution while allowing bounded wire avatar pixels to retain communication semantics.

Normalize desktop identifiers used for local presentation lookup and keep conflict and relay trust states authoritative over decorative branding.

Clarify unresolved presentation as "App identity could not be verified" and add shared generic visual and trust regression coverage.
Restore compact application identity in the popup header and keep conversation avatars beside message content.

Prevent fixed application and avatar slots from inheriting horizontal expansion so short messages retain correct spacing.

Resolve presentation-only application branding without allowing it to override conflict or relay trust states.

Include claimed desktop branding and trust-dependent candidate order in icon cache identity so attribution transitions cannot reuse stale icons.

Keep content thumbnails independent from sender avatars and application branding.

Add generic popup visual-matrix, layout, cache, trust, malformed-image, and short-message regression coverage.
Restore application branding and conversation-avatar presentation in notification and group rows while keeping trust state visually separate.

Invalidate asynchronous icon ownership whenever rows are cleared, rebound, grouped, or unbound so late decode completion cannot resurrect stale branding.

Include every branding and trust input in row icon signatures and clear recycled conflict, relay, recognized, unresolved, tooltip, and warning state when a group loses its sample notification.

Keep semantic conflict and relay badges authoritative over presentation branding.

Add generic row-recycling, group-lifecycle, icon-cache, trust-transition, thumbnail, and visual-matrix regression coverage.
Treat human-readable CLI diagnostics as terminal trust boundaries.

Sanitize and bound every free-form attribution field rendered by explain-notification so notification metadata cannot inject lines, terminal controls, bidi controls, or unbounded output.

Apply the existing doctor text sanitizer to every free-form field in human-readable doctor reports while preserving the structured JSON schema unchanged.

Keep empty sanitized diagnostic values rendered as "none" and add deterministic terminal-injection regression coverage.
Remove ~/.local/bin as an independent executable trust root in trial mode.

Require privileged UnixNotis control and renderer processes to resolve to
the known trial build/install tree, including the expected debug/release
siblings, instead of trusting a same-UID executable by writable launcher
pathname alone.

Preserve temporary ~/.local/bin/noticenterctl symlinks when they resolve
to the genuine trial binary, while rejecting copied or renamed
noticenterctl, center, popup, and daemon executables.

Keep Linux process-handle and executable fingerprint verification intact
and add regression coverage for forged local-bin component names and
trial-shim compatibility.
@locainin
locainin merged commit f09e405 into master Aug 13, 2026
7 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

Development

Successfully merging this pull request may close these issues.

1 participant