Conversation
#1593 asked whether podup should ship a postinst writing /etc/apt/apt.conf.d/20auto-upgrades, the file that actually switches unattended upgrades on. It should not. That file turns on automatic upgrades for every package on the machine rather than for Glyndor's, and podup only answers for Glyndor's. Whether a whole server updates itself is the operator's decision, or a fleet manager's, not the container runtime's. Choosing to leave the gap is what made the README wrong, which is the substance here. It said an apt-installed podup "updates through apt and nothing else", reading as a promise that it stays current. The dependency guarantees the package is installed, not that it runs: on a Debian where somebody registered the archive by hand and ran `apt install podup`, the package and the Glyndor allowlist are both present and the daemon is off. The README now names that row and gives `systemctl status unattended-upgrades` as the way to tell which one you are on. debian/control already recorded this in a comment and nothing enforced it. tests/no_system_wide_apt_policy.rs does: no file podup packages writes the switch, a first maintainer script trips a tripwire asking you to re-read the decision rather than passing as routine, and the README keeps the sentence. Two things came out of building it. The first matcher reported debian/control as a breach, because the paragraph explaining that podup does not write the switch names the switch; comment lines are now stripped, and a heredoc emitting the file is still a line, checked by adding a postinst that does exactly that. And the README needle spanned a line break, which cannot match on the CRLF Windows checkout — reproduced locally by converting the file rather than inferred from the error — so the assertion now collapses whitespace and compares words, which also survives a reflow. Closes #1593. Signed-off-by: Jaro-c <75870284+Jaro-c@users.noreply.github.com>
…1605) `line-limit` reads the whole tree, not the diff, so a file that has crept to within a few lines of the 500-line hard limit fails whichever pull request next touches it. The pull request that breaks is not the one that made the file long. internal/engine/lifecycle/tests.rs 487 -> 212, plus teardown_tests.rs 285 internal/quadlet/tests/fields.rs 481 -> 365, plus fields_resources.rs 119 Both are test files with no inline module, and that distinction decides the cost. cargo llvm-cov does not report on sibling test files -- measured: both are absent from the coverage data, while quadlet/warnings.rs appears at 95.0% because its 271 lines of inline tests count as covered lines of the file. So these two cannot move the number, and the run confirms it: 81.88% to 81.91%. Splitting the other eleven by moving their inline tests out would, against a threshold of 79 with about three points of headroom. That is a decision about the coverage gate rather than a refactor, so it is not made here. Both cuts are by subject and both follow a precedent in the same directory: scale_tests.rs and drop_recheck_tests.rs were already split off the lifecycle suite, and fields_logging.rs off fields.rs for this exact reason (#1354). 1731 unit tests pass, the same count as before, so nothing was dropped in the move. Signed-off-by: Jaro-c <75870284+Jaro-c@users.noreply.github.com>
…ation (#1604) Cargo.toml excludes fuzz and bench/timeit from the workspace, so each resolves its own dependencies into its own Cargo.lock. Dependabot's cargo entry names a directory, and the one for / reaches neither. Both have been unwatched for as long as they existed, and audit.yml runs cargo audit against the workspace lock rather than these two. The fuzz harness is the sharper of the pair: it exists to be fed hostile input. Both new entries group every update type, majors included, unlike the entry for the crate itself, because nothing here is shipped. Their limit is 5 rather than 10: once an ecosystem's limit is full Dependabot stops proposing anything for it, security bumps included. tests/dependabot_covers_every_lockfile.rs is the gate. It derives the directories from [workspace] exclude rather than from the tree, which matters twice over: the first version shelled out to git ls-files and the Debian build container has no git binary, and the second took the file's first exclude -- the [package] one that Cargo.toml warns about two lines above -- so the derived list came back as just / and the test passed comparing an empty set. It now carries a floor that fails on that. Signed-off-by: Jaro-c <75870284+Jaro-c@users.noreply.github.com>
podup was published to crates.io for helmly-agent, and helmly-agent does not use it. Measured: zero `use podup::` in its source, zero entries for podup in its Cargo.lock, and its own manifest records that the dep is gone. When the dependency did exist it was a git dep, so crates.io was never what carried it. crates.io reports zero reverse dependencies. What it cost: a semver promise on seventeen pub items with nobody to make it to, two of the thirteen required status checks, and 219 lines of workflow and test that existed only to keep the promise. Removed crates-publish.yml, the cargo publish steps at the end of release.yml -- which is the one worth finding, since deleting only the workflow would have left the release pipeline publishing on the next tag -- and the two API-surface tests. package-check and semver-check are false in ci.yml, and both were taken out of protect-main and protect-develop FIRST: a job with a job-level if: does not emit its check, so flipping the input while the ruleset still required the name would have blocked this very pull request. Kept: the [lib] target, because the integration tests build against it; rust / Doc warnings, because cargo doc with warnings denied catches broken intra-doc links whether or not anyone downloads the crate, so only two of the three checks were publish-only; and 5.4.0 on crates.io, which cannot be deleted, only yanked, and reserves the name. publish = false is the part cargo enforces. tests/podup_is_not_published.rs is the part it does not. The claim that helmly-agent consumed the library had gone false in four places, not one: README.md, CONTRIBUTING.md verbatim, Cargo.toml's documentation pointing at docs.rs which would freeze at 5.4.0 while reading as current, and docs/debian-packaging.md. Prose does not have one home, so a third test now scans README, CONTRIBUTING and every docs/*.md. Signed-off-by: Jaro-c <75870284+Jaro-c@users.noreply.github.com>
unattended-upgrades has been a hard dependency since 5.4.0, and on its own it guarantees an engine with nothing aimed at Glyndor. glyndor-archive-keyring is what aims it: it ships /etc/apt/sources.list.d/glyndor.sources and /etc/apt/apt.conf.d/51glyndor-unattended-upgrades and nothing else. Without them the daemon runs against Debian's own security suite, the logs look healthy, and podup is never upgraded -- the exact outcome the unattended-upgrades dependency was added to prevent. Two paths reached it: dpkg -i of a release .deb, and adding the repository by hand. No bootstrap problem, measured rather than reasoned: apt-cache policy resolves the keyring from apt.glyndor.net, so a machine that already reaches the archive installs it like any other dependency, and a standalone dpkg -i with no repository fails on the unmet dependency, which is the intended answer. The one-line installer was never affected -- it dpkg -i's the keyring before apt-get install. The field stays on one line: a continuation is valid and dpkg reads it, but tests/podman_floor.rs finds it with starts_with, so a wrapped field would have been invisible to the checks that exist to read it. the_package_requires_the_archive_keyring is the gate, driven red by demoting to Recommends and by removing it. Also corrected: debian/control claimed 'Ubuntu server ships both'; measured on 26.04 the switch is present and enabled but no package owns the file, so that was right about the outcome and wrong about the mechanism. And docs/debian-packaging.md now records that a fork publishing its own archive must declare Provides: glyndor-archive-keyring. Scope is podup alone, by the owner's decision: epistle declares neither dependency, so two products of the same archive answer this differently, knowingly. Closes #1602. Signed-off-by: Jaro-c <75870284+Jaro-c@users.noreply.github.com>
podup update replaces the running executable in place and refuses when a package manager owns it, because doing so desyncs that manager's record of the file. It only ever recognised one. pkg.rs said so plainly -- 'Only dpkg/apt is detected, on Linux' -- and off Linux it did not look at all. So a Homebrew or Scoop install running podup update had its binary rewritten underneath a manifest that still claimed to know the contents. apt is still asked, because dpkg-query -S is an authoritative database lookup. The other two are read off the path, deliberately: brew costs a process spawn on every update to learn a prefix the path already shows, and Scoop is a PowerShell function rather than an executable, so there is nothing to spawn. Homebrew installs under <prefix>/Cellar/<name>/<version>/ and links into <prefix>/bin, so the existing canonicalize resolves into the Cellar either way. The prefix moves -- /opt/homebrew, /usr/local, /home/linuxbrew/.linuxbrew, anywhere custom -- and the Cellar component does not, which is why that is what is matched. Scoop puts apps under <root>/apps with shims in <root>/shims, with SCOOP consulted first for a relocated root. Both path checks can be wrong in one direction only, and it is the safe one: a layout that merely looks like theirs refuses an update that would have worked, which is visible and recoverable, rather than missing one and rewriting a file whose manager still believes it knows the contents. scoop_owns delegates to scoop_owns_under, which takes the root as an argument, because setting an environment variable in a parallel test binary is a race rather than a fixture -- and that branch is the one the fallback provably cannot see. Six tests, all driven red. The Windows fixtures use / on purpose: Path::components splits on backslash too when it runs on Windows, while a backslash fixture would not parse into components on Linux and the test would pass by asserting nothing. The error message hardcoded 'apt upgrade podup', correct while apt was the only manager detected and a wrong instruction the moment it is not. Each manager now gets its own command, asserted. docs/self-update.md carried the same stale claim and now carries the table. Signed-off-by: Jaro-c <75870284+Jaro-c@users.noreply.github.com>
…ns (#1611) Seven rust/cleartext-logging alerts are open on main, all the same shape: an assertion in the integration suite formatting a Result that CodeQL traced back to create_project_secrets. The source is the function's NAME. SensitiveDataCall matches on HeuristicNames::nameIndicatesSensitiveData, so create_project_secrets is a taint source because it contains 'secret', not because of anything its Result<()> can carry -- and #1599 already made it impossible for a payload to reach one of those errors. The fix that corrects the model rather than the sinks needs a barrier model, which needs a configuration this repository owns, which the organization's Glyndor baseline pins away. That was #1603 and it is closed. Removing the formatted value removes the sink, and that is certain rather than hoped: resources_health.rs:209 already asserts on the same tainted result with a plain message and is not flagged, and eighteen .unwrap() calls on the same values are not flagged either. Only assert! interpolating the value is a sink. Seven changed, eleven left alone. There are eighteen occurrences and CodeQL flagged seven; the rest are on paths the query does not reach. Nothing syntactic separates them, so each of the three files gains a note saying the inconsistency is deliberate -- without it the next reader tidies it up and the alerts come back. The matches! assertion lost the most, so it is split rather than flattened: expect_err first, which prints the Ok value -- here () -- then the variant check. That keeps the difference between 'the run succeeded' and 'it failed with the wrong variant'. The cost, stated rather than discovered: these seven no longer say which error they got, and nothing prevents an eighth, because a syntactic gate cannot tell the seven from the eleven. Signed-off-by: Jaro-c <75870284+Jaro-c@users.noreply.github.com>
…odup (#1612) A machine with podup installed and glyndor-archive-keyring absent is never upgraded automatically, and never learns it. The rule permitting the Glyndor origin is shipped by that package, so unattended-upgrades does not look at podup, the version carrying the fix never arrives, and the Depends added in #1607 is never seen. Circular, and silent -- nobody reports it because the affected machine does not find out. podup update already refuses on an apt-owned binary and sends the operator to apt upgrade podup. That instruction is correct and, on such a machine, half the story. The refusal now appends the reason and the remedy when nothing will act. Where it runs is the design. Not a cron, which would have the same silence one level down. Not a stored timestamp, which needs new state on disk and reintroduces the same problem when the file goes missing. Not every command, which is how a warning becomes noise. Only on the refusal, where the operator has just asked to update and is being told to use something else: one process spawn, on the one path that has earned it. Three checks, because there are three ways to be stuck and the first draft knew one. Allowed-Origins is what our keyring writes; Origins-Pattern is documented by the package's own README as an alternative, so an operator using it is covered and a check that knew only the first would have raised exactly the false alarm this exists to avoid; and Package-Blacklist vetoes by name, so an allowed origin is not sufficient. No rule of either kind means Unknown and silence. The origin match is loose on purpose -- any rule mentioning Glyndor rather than Glyndor:stable exactly. An operator who allowed a different suite has thought about this; the machine worth warning is the one whose configuration has never heard of Glyndor. glyndor_auto_update takes the dump text rather than fetching it, so the configurations that matter can be fed to it. Five fixtures, one of them this machine's real apt-config dump verbatim -- that one alone would have been the trap, because a check only ever seen to agree with the configuration we write ourselves has not been tested against the ones it meets in the field. All three checks driven red. Not verified end to end on a machine in this state, because there is not one here. Refs #1602. Signed-off-by: Jaro-c <75870284+Jaro-c@users.noreply.github.com>
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.
Summary
Promotes
developtomainwith no version bump and no tag. Both branches stay at 5.4.0, andrelease.ymlfires only on av*tag or a manual dispatch, so nothing is published.What it carries
Eight pull requests. Three of them landed after this was opened, which is why the checks ran more than once.
Update path
podup update's refusal on an apt-owned binary now says when apt will never do it either. The rule permitting the Glyndor origin ships inglyndor-archive-keyring, so a machine without it is never upgraded and never learns it; the refusal reads apt's merged configuration at that moment and appends the reason and the remedy.glyndor-archive-keyringbecomes a hardDepends.unattended-upgradesis the engine; the keyring is what points it at Glyndor.Security
Resultthey assert on. Whether the sevenrust/cleartext-loggingalerts clear is only visible once this reachesmain, which is the other thing this promotion measures.Housekeeping
fuzzandbench/timeit, excluded from the workspace, get their own Dependabot entries; both lockfiles had been unwatched for as long as they existed.unattended-upgradesdoes not buy.What this promotion measured, before it merged
The
code_scanningrule does not block on pre-existing alerts. It was added toprotect-mainearlier today with the configurationGlyndor/aptuses. Sevenrust/cleartext-loggingalerts were open onmain, and the first green run of this pull request came backmergeState=CLEAN. GitHub's documented behaviour — that the rule blocks on alerts introduced by the pull request rather than pre-existing ones — is now confirmed rather than read. The rule stays.What it does not do
Code scanning still runs on the default branch only, so none of the eight was scanned on its own pull request. That is why alerts from a promotion are attributed to the promotion rather than to the change that caused them. #1603 would have fixed it and is closed: the organization's
Glyndor baselineconfiguration pins CodeQL to default setup across fifteen repositories.Test plan
developbefore thismainanddevelopare both at 5.4.0 inCargo.tomlanddebian/changelog, so no changelog entry is owedrelease.ymltriggers re-read:push: tags: v*andworkflow_dispatchonlycargo publishsteps, andtests/podup_is_not_published.rsfails if any workflow gains one backWhat changes for a user
Two things, both shipping with the next release rather than with this promotion: podup requires
glyndor-archive-keyring, andpodup updaterefuses on Homebrew and Scoop installs rather than overwriting them.Signed-off-by: Jaro-c 75870284+Jaro-c@users.noreply.github.com