fix: breadcrumbs audit batch (CRUMB-25, 28, 32, 35, 36, 37, 44) #46
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "fix/crumb-audit-batch"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Batch of breadcrumbs audit findings. Each card is one commit on this branch with a test that covers it.
CRUMB-25: detect --apply --json emitted more than one JSON object
detect --apply --json, which printed the apply result and the detection result as separate JSON objects, so a consumer parsing one object failed.f66fca8, src/app.rs).CRUMB-28: connect did not propagate hidden=false to the saved profile
802-11-wireless.hidden=truein the NetworkManager profile, because the rewrite only ran for credential changes or hidden=true.profile_needs_updatecompares the saved hidden flag in both directions, and treats a missing key as false (d4e313a, src/nm.rs).unhiding_a_network_triggers_a_profile_update_and_clears_the_flagandhidden_flag_matching_the_saved_profile_does_not_force_a_rewritein src/nm.rs.CRUMB-32: DNS pin left DHCP DNS on IPv6 when the profile had no ipv6 section
apply_dns. The pin created the ipv4 section but only touched ipv6 if it already existed, so a profile without one kept auto DNS around the pin.method. Unpin still only touches existing sections (4b5f017, src/nm.rs).apply_dns_pin_creates_ipv6_section_when_profile_has_none(fails before the fix),apply_dns_pin_v4_only_still_clears_ipv6_auto_dns_on_created_section(fails before the fix),apply_dns_unpin_does_not_invent_ipv6_section,apply_dns_unpin_without_ipv6_section_leaves_no_ipv6_when_pinned_before.CRUMB-35: a blank password answer could wipe a network created concurrently
cmd_add.existingwas computed from the config loaded at startup, before the interactive prompt. The lockedConfig::updateclosure reloads the config, so a network created in the meantime was treated as new and got its password set to none.password_to_write. The prompt stays outside the lock (c3889ea, src/app.rs).blank_prompt_keeps_password_when_network_exists_in_fresh_config,blank_prompt_sets_no_password_for_a_new_network,non_blank_prompt_sets_password_for_existing_and_new_networks,explicit_password_always_replaces_even_when_empty.CRUMB-36: a non-204 HTTP answer with a blocked ping was not treated as a portal
a2e3e2c, src/status.rs).CRUMB-44: a configured profile key with surrounding spaces could not be selected from the bus
set_profilebus command. The payload was trimmed before the config lookup, so a configured key such as" home "could never match. A whitespace-only payload also reportedmissing string "profile", which was misleading.319e473, src/bread_events.rs).exact_profile_key_with_spaces_resolves_to_itself,padded_payload_falls_back_to_trimmed_key,exact_key_wins_over_trimmed_key_when_both_exist,whitespace_only_payload_reports_empty_profile_not_missing_field,absent_or_non_string_payload_reports_missing_field). The integration testset_profile_command_trims_name_before_applyingis renamed toset_profile_command_falls_back_to_trimmed_name_when_applyingand now asserts the new contract. The tests use config fixtures only and do not touch the bus.CRUMB-37: two release workflows published the same tag
.github/workflows/release.ymland.forgejo/workflows/release.ymlboth ran onv*tag pushes, and both wrote/srv/breadway-dl/breadcrumbs/<version>and rangh release upload --clobber. Forgejo is authoritative, since GitHub auto-mirrors from origin.workflow_dispatchonly (e44b642). The Forgejo release path is unchanged.tests/release_workflows.rs, which asserts the GitHub workflow does not trigger on tag pushes and the Forgejo one still triggers onv*.CLAUDE.mdis not tracked in this repo (removed in7a58d4aand listed in.gitignoreas local-only), so there is no tracked file to rewrite. This card's CLAUDE.md part is therefore not applicable here.Verified locally:
cargo fmt --all -- --check,cargo clippy --all-targets -- -D warnings,cargo test --release.Refs CRUMB-25 CRUMB-28 CRUMB-32 CRUMB-35 CRUMB-36 CRUMB-37 CRUMB-44
Review of PR #46 at head
e44b642c3d(base main939d9edc). Head re-read from Forgejo before and after review: unchanged.PR VERDICT: CHANGES REQUESTED (blocking: CRUMB-32; test gap: CRUMB-36). Five cards pass.
Checks on this head: Forgejo "check / check (push)" = success. Independently in a clean worktree: cargo fmt --check rc 0, cargo clippy --all-targets -D warnings rc 0, cargo test rc 0 (113 lib, 54, 56, 2 release_workflows, 0 failures). Existing reviews: none. Branch protection is not readable anonymously, so required-check configuration is unverified.
PER CARD
939d9edc; removed in7a58d4a; listed in .gitignore), so that half is correctly not applicable. Non-blocking hazard: the GitHub workflow still derives VERSION from GITHUB_REF_NAME, so a manual dispatch from a branch writes /srv/breadway-dl/breadcrumbs/ and repoints the "latest" symlink at it. Consider deleting that workflow or guarding the job with if: startsWith(github.ref, 'refs/tags/v').CRUMB-32 (blocking)
Change: apply_dns (src/nm.rs:857-858) now creates an ipv6 section containing only ignore-auto-dns and dns, with no method key. Tests assert the absence of method on purpose (nm.rs:1226 and :1237).
Evidence that this is invalid to NetworkManager:
Consequence: if the hypothetical profile ever does occur, enforce_dns's Update2 fails, the error is only logged ("dns: could not apply DNS setting"), and the v4 pin that worked before this change is lost too. That is a regression in the one case the change targets.
The fake does not catch it: tests/common/fake_nm.rs validate_settings (line 206) checks dns wire types but not that ip sections carry a method, so the tests mirror the code.
Requested: when creating a missing ipv6 section, also set method=auto (as the create path at nm.rs:697-699 does); flip the two assertions to expect method == "auto"; teach validate_settings to reject ipv4/ipv6 sections without method, so a regression fails in the fake.
Does pinning stop v6 auto DNS? With method=auto, per nm-settings docs ipv6.ignore-auto-dns=TRUE ignores RA/DHCPv6 name servers and search domains, and only dns/dns-search are used; so yes for this profile's own DNS. Not covered: dns-priority is never set, so other active connections (VPN, second NIC) can still contribute DNS; the card does not claim that. Separate pre-existing issue, not for this PR: with ipv6.method ignore, disabled or link-local, libnm rejects a non-empty ipv6.dns, so a pin with a v6 server on such a profile fails the same way (reproduced in-process).
Confidence: high that methodless ipv6 is rejected (source plus libnm 1.46.0 run); medium-high that the no-ipv6-section case rarely occurs live. Only provable on a live system: the running daemon's behavior (same libnm code, but I did not run NetworkManager), real RA/RDNSS and DHCPv6 DNS being dropped after Reapply, resulting resolv.conf or systemd-resolved state, and interaction with Tailscale DNS. None of that was touched.
Scope: seven files, all attributable to the seven cards; no scope creep. Added lines and commit messages contain no em or en dashes and no attribution.
Not merged. Cards not moved.
NetworkManager rejects an ipv4 or ipv6 section that has no method ("ipv6.method: property is missing"), so the DNS pin's created sections made verify and Update2 fail and the pin never took effect. Created sections now carry method = auto, the default NM applies to a profile with no section at all. Existing sections keep their method. The fake NM now rejects a present ipv4/ipv6 section without a method, so a client that builds an invalid shape fails in tests the way it would against real NetworkManager.Rework for the independent review (comment 5672), on the same branch.
d4db5b8fix(nm): give a created ipv4/ipv6 section method auto (CRUMB-32). The DNS pin now creates a missing ipv6 section withmethod = auto. The same missing-method path existed for ipv4, so that is fixed too. Existing sections keep their method. The assertions at the two previously flagged spots now expectauto. The fake NM'svalidate_settingsrejects a present ipv4/ipv6 section with nomethod, with unit tests for reject and accept.2dff10btest(status): cover the non-204 HTTP answer with a blocked ping (CRUMB-36). Tests ofconnectivity()through FakeRunner: 403/404 with ping blocked gives Portal, 000/500 with ping blocked gives NoNet, 403 with ping working gives Online. Breaking the portal branch toelse if false && answeredfails the 403/404 test; restored afterwards.Checks on
2dff10b: cargo fmt --check, cargo clippy --all-targets -- -D warnings, cargo test --release all pass.View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.Merge
Merge the changes and update on Forgejo.Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.