Repository navigation
OmaBlock 1.5.0: full-stack fixes, tests and release notes - #1
Merged
Merged
Conversation
…kaging - hosts-sync: replace the nft table atomically instead of appending rules on every apply, clear it when kernel enforcement is off, keep user entries after an unterminated marker block, preserve non-UTF-8 bytes, fsync before/after the atomic replace, always remove browser DoH policies on --clear, fstat the opened rules file, accept inner underscores like the engine does - engine: blackout uses oifname (loopback DNS stub stays reachable) in its own table, resolve the nft binary path, pure pause-expiry helper so tests no longer write real config or run the privileged sync, normalise trailing dots on removal, non-zero exit on invalid domain/category and failed update, declare rust-version 1.88 - QML: queue engine actions (Quickshell ignored overlapping commands), re-run a status refresh requested while one was in flight, real update/test toasts, parsed test result and pause countdown in MainWindow, hoverEnabled on hover buttons, declare textEdited() and stop Tab insertion in BoundedTextInput - packaging: install BoundedTextInput.qml, pre_remove hook clears hosts/nft/ policies, nftables optdepend, dashboard finds the plugin's qml dir, command -v instead of which - build.sh runs ownership checks before compiling; uninstall.sh disables the shield first and keeps the manifest when files were preserved - extension 1.0.4: whitelisting a site adds a DNR allowAllRequests rule, popup uses the same suffix match as content.js, version badge from the manifest, observer only on the two first-party sites and rAF-throttled, permission docs match the manifest - tests: sandbox the helper tests so they never touch /etc or run nft/resolvectl, skip the mode-000 case as root, add regression tests Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QkEeVbVXsojuz4Jb4j693q
- Kernel enforcement and panic blackout status was always false because the unprivileged engine ran `nft` without CAP_NET_ADMIN. The helper now owns every nft change (new --blackout-on/--blackout-off), feeds scripts on stdin and publishes /run/omablock/kernel_state.json, which the engine reads for --json. Blackout/resume go through sudo -n then pkexec like hosts sync. - One run_privileged_helper() replaces the duplicated sudo/pkexec code, with deadlines long enough for a large apply and a password prompt, so a slow but authorised sudo run is no longer re-run through pkexec. - Mutating commands take an flock on engine.lock; --update reloads the config under the lock before its final save, so concurrent panel actions are not lost (12 parallel --whitelist-add: 1 survived before, 12 now). Status polls stay lock-free and only lock when they have to expire a pause. - pre_remove also clears the blackout table. - CI workflow: clippy -D warnings, cargo test, Python tests, shell syntax, rules.json and version consistency. CodeQL now also scans python and rust. - Installer lifecycle test finds a rustup cargo under its temp HOME. - Fix the two existing clippy warnings. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QkEeVbVXsojuz4Jb4j693q
…nfig and DGA - main.rs uses the library crate instead of compiling a second copy of every module and of validate_domain - active_rules reports the sinkhole entries actually in /etc/hosts - an invalid config.json is moved to config.json.corrupt-<ts> instead of being overwritten; an unreadable one is left untouched - home directory comes from $HOME or the passwd entry, no hard-coded fallback - blocklist downloads are capped with curl --max-filesize - DGA classifier: punycode decoding, plain IDNs (muenchen.de, yandex.rf) are no longer phishing, whole-script and mixed-script look-alikes still are; brand first-party domains (githubusercontent.com, googleapis.com, ...) and compound suffixes (co.uk) no longer produce false positives Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QkEeVbVXsojuz4Jb4j693q
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QkEeVbVXsojuz4Jb4j693q
… zip script - badge shows ON/OFF per tab (OFF on whitelisted sites) and refreshes when the whitelist changes - cosmetic CSS is injected before the async storage read and removed for whitelisted sites, so ads no longer flash in at document_start - content script shares the whitelist matcher; dead omablock_disabled removed - 'tabs' permission dropped: <all_urls> already exposes tab URLs - extensions/build-chrome-zip.sh builds the versioned store package without store images and the 'key' field; the stale 1.0.0 zip is removed - extension 1.0.5 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QkEeVbVXsojuz4Jb4j693q
…, CI copy check Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QkEeVbVXsojuz4Jb4j693q
Addresses the CodeQL cleartext-logging alert on the new load_config branch. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QkEeVbVXsojuz4Jb4j693q
…hared QML client, i18n - Ultimate respects category and DoH toggles; leaving Ultimate resets DoH/kernel - doh_prevention defaults to false and skips whitelisted DoH resolvers - AI protection warns before whitelisting look-alike domains - verify-integrity compares against the install manifest (OK/MISMATCH/UNKNOWN) - pause expiry runs from a systemd user timer (--expire-pause) - --restore-hosts restores the pre-OmaBlock /etc/hosts backup - failed privileged sync exits 1, rejected input exits 2; UIs report it - qml/EngineClient.qml shares status polling and the action queue - drop the duplicate root BoundedTextInput.qml - rule parsing moved to the lib (rules.rs) and validates every domain; removes reserved names (local, *.omablock.local, localhost.localdomain) from the builtin list - Chrome popup localized (en, tr) - USB armor documented as experimental; README claims corrected Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QkEeVbVXsojuz4Jb4j693q
… restore - The IDN radar only stays on while the flagged look-alike domain is still whitelisted, and --whitelist-remove clears the flag for that domain. Before, one warning lit the alert permanently. - --restore-hosts turns protection off afterwards, so the next action does not silently re-apply the block and the status matches /etc/hosts. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QkEeVbVXsojuz4Jb4j693q
…e tests - BoundedTextInput no longer declares textEdited(): TextEdit has it from Qt 6.9, where the declaration is an invalid override. It is emitted only where it exists. - When omablock-hosts-sync is not installed, the engine skips sudo/pkexec (no pointless password prompt), saves the change and exits 4. Panel and MainWindow say the system helper is needed instead of "Action failed". - tests/test_qml_runtime.py loads EngineClient and MainWindow under PySide6 with Quickshell stand-ins (tests/qml/quickshell_stub.py): action order, exit codes, refresh coalescing and status mapping. CI installs the Qt runtime for it; the test skips where PySide6 is missing. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QkEeVbVXsojuz4Jb4j693q
The stub runs with HOME set to a temp dir, which hid the `pip --user` install of PySide6 from the child interpreter on the CI runner. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QkEeVbVXsojuz4Jb4j693q
tests/e2e_privileged.sh re-execs itself in private mount and network namespaces, bind-mounts a copy of /etc and drives the real engine through sudo and omablock-hosts-sync: enable, whitelist, Ultimate (kernel table, DoH), panic blackout on/off, back to Standard, pause/resume and hosts restore, checking /etc/hosts, nft tables and the status JSON each time. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QkEeVbVXsojuz4Jb4j693q
A user-level CARGO_TARGET_DIR or build.target/target-dir in ~/.cargo/config.toml moved the binary away from target/release, so package() failed with 'cannot stat target/release/omablock-engine'. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QkEeVbVXsojuz4Jb4j693q
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QkEeVbVXsojuz4Jb4j693q
ozdil
marked this pull request as ready for review
October 16, 2026 13:20
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
- Refuse to save or apply defaults when config.json exists but is unreadable, so the whitelist and blacklist are never overwritten. - --startup reloads and applies the config under engine.lock; --startup and --update take the lock for the pause-expiry save. - uninstall.sh lifts an active panic blackout before removing the engine. - Count managed hosts entries on raw bytes so non-UTF-8 lines do not hide them. - Derive the IDN alert from the whitelist so it covers every flagged domain. - Chrome 1.0.6: the service worker owns the allow rules (serialised, resynced on change and on startup); the popup waits for it before reloading. - Pin CI actions to commit hashes. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QkEeVbVXsojuz4Jb4j693q
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QkEeVbVXsojuz4Jb4j693q
There was a problem hiding this comment.
ozdil has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.
There was a problem hiding this comment.
ozdil has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Requested by ozan · project thread
Description
Fixes from a full-stack review. The bugs that were visible to users:
nftitself.BoundedTextInput.qmlwas missing.cargo testand the Python tests could touch the real/etcand config files.local,localhost.localdomain).Privileged nft and locking
--blackout-onand--blackout-off./run/omablock/kernel_state.json, which the engine reads for status.run_privileged_helper()is used. sudo gets 30 s and pkexec 90 s, so a slow but authorised run is not repeated with a second password prompt.engine.lockwithflock.--updatereloads the config under that lock before its final save. With 12 parallel adds, 1 entry survived before and all 12 survive now.flock, and/etc/hostskeeps its mode and owner.Hosts helper (
omablock-hosts-sync)--with-kernelis absent.fsyncruns around the atomic replace.--clearalways removes the browser DoH policies.fstaton the opened fd..localdomain,.testand.invalidare rejected.--restore-backuprestores/etc/hosts.omablock.bakand keeps the current file as/etc/hosts.omablock.pre-restore.Engine
validate_domain.active_rulesreports the entries actually present in/etc/hosts.config.jsonis moved toconfig.json.corrupt-<ts>rather than overwritten. An unreadable one is left untouched.$HOMEor the passwd entry; there is no/home/ozdilfallback.curl --max-filesize.oifname, so the loopback DNS stub stays reachable.omablock_blackouttable.1when a change was saved but the privileged sync failed,2for an invalid domain, category or option,4when the system helper is not installed. Without the helper the engine no longer runs pkexec, so there is no password prompt that can only fail.Level semantics and new commands
doh_preventiondefaults to false, and a whitelisted DoH resolver stays reachable.verify-integritycompares the binary with the hash in the install manifest: OK (0), MISMATCH (1), UNKNOWN (3).--pauseschedules asystemd-run --usertimer that runs--expire-pause. The status-time expiry stays as a fallback.--restore-hostsruns the helper's restore, then turns protection off so the next action does not re-apply the block.src/rules.rsand validates every domain, so a tampered cache cannot inject hosts syntax.QML
qml/EngineClient.qmlholds status polling and the action queue for both Panel and MainWindow, and reports exit codes.hoverEnabledis set on 7 buttons.BoundedTextInput(a single copy inqml/, which Panel now imports):textEdited()only where TextEdit provides it (Qt 6.9+), since declaring it there is an invalid override;Packaging and scripts
pre_removehook (--clear,--blackout-off);nftablesoptdepend;prepare()that runscargo fetch, sobuild()uses--frozen.qml/directory.build.shchecks ownership before compiling.uninstall.shdisables the shield first and keeps the manifest when it preserved files.Chrome extension 1.0.5
allowAllRequestsrule. The popup and content script share one matcher.tabspermission is dropped._locales/en,_locales/tr).extensions/build-chrome-zip.shbuilds the store package without the store images and without thekeyfield. The stale 1.0.0 zip is removed.Docs
auth_admin_keep), output caps are 16 to 32 KiB, and the zeroize claim is removed. New commands and exit codes are documented.CI
ci.ymlruns:-D warnings;cargo test;tests/test_qml_runtime.py, which loads EngineClient and MainWindow under PySide6 with Quickshell stand-ins (tests/qml/quickshell_stub.py);rules.jsonand version consistency checks.pythonandrust.Type of Change
Verification Checklist
Tests run
cargo testandcargo clippy --all-targets -D warnings: clean. The simulation tests now use the real rule parser, and a new test checks that every builtin rule is a valid domain.verify-integrityOK and MISMATCH, and exit codes 2 and 4.ERR_BLOCKED_BY_CLIENT;allowAllRequestsrule;Not tested: Panel.qml, which needs Omarchy's
qs.*modules; the real Quickshell runtime; the sudo/polkit flow and the systemd pause timer on Omarchy.🤖 Generated with Claude Code
https://claude.ai/code/session_01QkEeVbVXsojuz4Jb4j693q
Fix startup locking, unreadable configuration recovery, and blackout cleanup before merging.
Fix with agent prompt
Summary
This release moves privileged changes into the helper and adds shared QML action queues, browser whitelist rules, safer hosts writes, and broader tests.
Diagram
%%{init: {'theme': 'neutral'}}%% flowchart LR UI["Panel / MainWindow"] --> Queue["EngineClient action queue"] Queue --> Engine["Rust engine"] Timer["Pause timer"] --> Engine Engine --> Config["User configuration"] Engine --> Auth["sudo / pkexec"] Auth --> Helper["Privileged helper"] Helper --> Hosts["Hosts file and browser policies"] Helper --> NFT["Enforcement and blackout tables"] Helper --> State["Published kernel state"] State --> EngineReviews (1) · Last reviewed commit: "Release 1.5.0: changelog and what's new ..." · Reviewed by Greptile