Repository navigation
Conversation
…efin#617) The repo_security_option_errors gate attested proxy, sslverify, gpgcheck, pkg_gpgcheck, and repo_gpgcheck on allowlisted repository sections but left `gpgkey=` entirely unchecked. An override drop-in setting `gpgkey=https://attacker.example.com/key` on an allowlisted id passed: the gate had no record of which key the section was supposed to serve. Add `[repositories.gpgkeys]` to the overlay manifest, mapping repo_id to the URLs/file paths the section is approved to use. Mirror the `[repositories.baseurls]` shape: a `gpgkey=` value in any allowlisted section must match a pinned entry, an entry for a repo not in `[repositories.allowed]` is rejected as approving nothing, and a non-list value in the manifest fails loudly. utah-packages needs no entry because its bind-mounted OCI repo authenticates RPMs by image provenance rather than an RPM GPG key. Wire the new table through check_repo_sections and verify_repository_policy so both the `--check` path and the runtime reposdir scan gate gpgkey=. The shipped manifest pins the keys hummingbird.repo (file path and Hummingbird-published URL) and nvidia-container.repo (NVIDIA Open Source Projects gpgkey) declare. Hive-Run: projectbluefin#617 Hive-Plan: issue-617-gpgkey-pin-check Hive-Spec: package-contract#repo-policy Signed-off-by: dtg01100 <dtg01100@users.noreply.github.com>
There was a problem hiding this comment.
style
scripts/verify-rpm-contract.py:717-718— in the enabled branch,repo_gpgkey_pin_errorsruns for every section, not just allowlisted ones (unlikerepo_pin_errorsat L715, which is underelif section_name in allowed_repos). A non-allowlisted section withgpgkey=therefore emits a second, false diagnostic:Allowlisted repository 'evil' is enabled in f.repo with gpgkey=…; the manifest declares no pinned key…alongside the correctUnapproved repository 'evil'error (reproduced at head). Fails closed, so not a gate hole, but the message states the opposite of the truth. Gate L717 onsection_name in allowed_repos(the disabled branch at L689-697 already does).scripts/verify-rpm-contract.py:97-109and:548-556— docstrings contain garbled prose ("whitespace-trimmed, trailing-whitespace sensitive only where libdnf5 would be…"; "(https://, issue #617)"). Worth a tidy since these explain the pin semantics.tests/test_verify_rpm_contract.py— test nametest_repo_gpgkey_pin_errors_passes_when_every_sever_keys_is_pinnedtypo (sever).
No findings from: correctness, security, intent-alignment, docs-currency.
Confidence: 3/5 (needs attention) — 1 perspective requested changes
— hive: agent=reviewer backend=copilot model=claude-fable-5.1 copilot=1.0.88
Only run repo_gpgkey_pin_errors for allowlisted sections, matching the disabled-section branch, so unapproved repos get a single accurate diagnostic. Clean up normalize_gpgkey/repo_gpgkey_pin_errors docstrings and fix a test name typo. Hive-Fix-Attempt: 1/6 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: scanner <scanner@hive.kubestellar.io>
There was a problem hiding this comment.
Reviewed at head 7c23810. Ran tests/test_verify_rpm_contract.py (175 passed) and verify-rpm-contract.py --check packages/bluefin.toml packages/utah.toml (valid).
intent-alignment
- (low)
packages/utah.toml:585pinshttps://packages.redhat.com/api/pulp-content/public-hummingbird/x86_64/RPM-GPG-KEY-redhat-release-2as a second approved key forpublic-hummingbird-x86_64-rpms. The PR body sayspackages/hummingbird.repodeclares "the file path and the Hummingbird-published URL", butpackages/hummingbird.repo:17declares onlygpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release-2, no other file in the tree references that URL, and it returns HTTP 404 today. The entry approves a key location nothing uses and nothing serves; suggest dropping it (and the "both spellings are pinned" comment atpackages/utah.toml:579-581) so the pin set stays exactly what the shipped.repofiles declare.
docs-currency
- (low)
docs/skills/package-contract.md:141-143saysutah-packages"is exempt" from the gpgkey pin. Code has no exemption:scripts/verify-rpm-contract.py:552-563rejects anygpgkey=on an allowlisted id without a[repositories.gpgkeys]entry, so a drop-in addinggpgkey=toutah-packagesfails (correctly). Reword to "has no entry because its.repodeclares nogpgkey=; anygpgkey=added to it is rejected", matching the accurate wording atpackages/utah.toml:575-577.
No findings from: correctness, security, style.
Confidence: 3/5 (needs attention) — 1 perspective requested changes
— hive: agent=reviewer backend=copilot model=claude-fable-5.1 copilot=1.0.88
Reword package-contract.md: utah-packages has no [repositories.gpgkeys] entry because it declares no gpgkey=, not because it is exempt; an added gpgkey= is rejected. Drop the packages.redhat.com key URL pin, which no shipped .repo references, so the pin set matches hummingbird.repo. Hive-Fix-Attempt: 2/6 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: scanner <scanner@hive.kubestellar.io>
There was a problem hiding this comment.
Read at head 930ff97.
docs-currency
docs/skills/package-contract.md:168-169— "the shipped[repositories.gpgkeys]pins the key URL each publishes" refers to the two signature-check exceptions (utah-packages,nvidia-container-toolkit), bututah-packageshas no pin (as the same paragraph says at L145 andpackages/utah.toml:572-574). Only NVIDIA's URL is pinned; the sentence contradicts itself.
intent-alignment
- PR body says the Hummingbird pin covers "file path and the Hummingbird-published URL";
packages/utah.toml:583pins onlyfile:///etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release-2. The diff is tighter than the description (good) — body should be corrected so the record matches.
style
scripts/verify-rpm-contract.py:528-534split_gpgkeysis byte-identical tosplit_baseurls(L524-525); alias or reuse rather than duplicate.
No findings from: correctness, security.
Confidence: 3/5 (needs attention) — 1 perspective requested changes
— hive: agent=reviewer backend=copilot model=claude-fable-5.1 copilot=1.0.88
Hive-Fix-Attempt: 3/6 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: scanner <scanner@hive.kubestellar.io>
There was a problem hiding this comment.
docs-currency
docs/skills/package-contract.md:168-170says "Onlynvidia-container-toolkithas a[repositories.gpgkeys]pin", but the manifest this PR ships pins two repos:packages/utah.toml:583(public-hummingbird-x86_64-rpms→file:///etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release-2) and:586(nvidia-container-toolkit). The PR body gets it right; the prose contradicts the manifest it describes. Drop the "Only …" sentence or list both pins.
correctness (low, non-blocking)
scripts/verify-rpm-contract.py:97-115normalize_gpgkeyis documented as mirroringnormalize_baseurl, but omits the${var}→$varfold at:516. Agpgkey=…/$basearch/keypin spelled${basearch}in a.repofile would be reported as unpinned. No shipped.repouses variables ingpgkey=, so the gate holds today; worth aligning since the two helpers are meant to share semantics.
Verified at 9fc319c: python3 scripts/verify-rpm-contract.py --check packages/bluefin.toml passes; pytest tests/test_verify_rpm_contract.py → 175 passed.
No findings from: security, intent-alignment, style.
Confidence: 3/5 (needs attention) — 1 medium finding; 1 perspective requested changes
— hive: agent=reviewer backend=copilot model=claude-fable-5.1 copilot=1.0.88
…n docs
normalize_gpgkey now applies the same ${var} -> $var fold as
normalize_baseurl, so braced and bare variable spellings compare equal.
package-contract.md now names both [repositories.gpgkeys] pins
(public-hummingbird-x86_64-rpms and nvidia-container-toolkit).
Hive-Fix-Attempt: 4/6
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: scanner <scanner@hive.kubestellar.io>
Stack on the validated static-gate fixes and preserve exact key URL paths. Check partial, disabled, and wildcard overrides before early returns, and pass key pins to every runtime scan. Assisted-by: GPT-6 via GitHub Copilot Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Read scripts/verify-rpm-contract.py at ae0fdd3 end to end, plus the four packages/*.repo files. The gate change looks correct to me and matches #617.
Verified
[repositories.gpgkeys]inpackages/utah.tomlpins exactly what the shipped sections declare:packages/hummingbird.repo:17→file:///etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release-2,packages/nvidia-container.repo:27→https://nvidia.github.io/libnvidia-container/gpgkey.packages/utah-packages.repohas nogpgkey=, so its absence from the table is right and a drop-in adding one is rejected.fedora-44.repois builder-only and not allowlisted, so its key is out of scope as intended.check_repo_sections(:770-774) runs the key check before everycontinue, so a partial orenabled=0named override that carriesgpgkey=is still rejected, and a wildcard override withgpgkey=is refused outright beforeglob_override_errors. That matches the "checked before their early returns" note in the new reference doc.expected_gpgkeysreaches all threeverify_repository_policycall sites (:1240source check,:1312on-image repos.d,:1341override dirs) and the onecheck_repo_sectionscall (:891). Nothing is left unpinned.normalize_gpgkeylowercases only scheme and host and keeps the path exact, including trailing slashes — appropriate for file identities;${basearch}→$basearchfolding matches how dnf5 expands either spelling.- Manifest validation rejects a
[repositories.gpgkeys]id outside[repositories.allowed](:1136-1143), mirroring[repositories.security].
One low-severity wording issue (repo_gpgkey_pin_errors, :584-589): for override scans the check runs on every section (is_override or section_name in allowed_repos), so a non-allowlisted override section with an unpinned gpgkey= is reported as "Allowlisted repository '…' is enabled … the manifest declares no pinned key". The rejection itself is correct; the message just mislabels the id as allowlisted (and as enabled, even when enabled=0). Worth a small tweak so the operator isn't sent to the allowlist for a repo that isn't on it.
Stacked on #623 (fix/validation-gates); retarget to main after it lands.
Confidence: 5/5 (safe)
— hive: agent=reviewer backend=copilot model=claude-fable-5.1 copilot=1.0.88
Report a drop-in override whose id is not allowlisted as a repository override rather than an allowlisted repository when it sets an unpinned gpgkey=, split the gpgkey branch in check_repo_sections for readability, describe override key pinning declaratively in the authenticity reference, and correct a test docstring that contradicted its assertion. Hive-Fix-Attempt: 5/6 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: scanner <scanner@hive.kubestellar.io>
There was a problem hiding this comment.
docs-currency
- (low)
docs/skills/package-contract.md:176-189— the on-image override bullets still give the exhaustive rule for partial and wildcard drop-ins ("passes for any id unless it sets aproxy=or disablessslverify=or an unapproved signature check"; "a wildcard override passes only when it … sets noproxy=, and disables neithersslverify=nor any signature check"). Afterscripts/verify-rpm-contract.py:776-790a partial/disabled override withgpgkey=is pinned and any wildcard override settinggpgkey=is rejected, but only the new reference (references/repository-authenticity.md:60-64) says so. Addgpgkey=to both bullets so the summary doc does not promise a pass the gate no longer gives.
No findings from: correctness, security, intent-alignment, style.
Confidence: 3/5 (needs attention) — 1 perspective requested changes
— hive: agent=reviewer backend=copilot model=claude-fable-5.1 copilot=1.0.88
|
Installed KVM evidence at b32c2b3: baseline RPM contract and all four malicious GPG-key overrides were checked in the booted system, including disabled and wildcard sections and the trailing-slash key resource. All were rejected, then the restored baseline passed. Run 37574083892 retained review-checks.json. The broader gate stopped later on a Flatpak ref formatter issue, so full VM success remains pending. |
Hive-Fix-Attempt: 6/6 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: scanner <scanner@hive.kubestellar.io>
|
Hive filed out-of-scope review findings as backlog issues so they do not block this PR:
Cap: 3 backlog issue(s) per PR. |
Closes #617.
Pin declared RPM GPG keys to
[repositories.gpgkeys]. Reject unpinned keys in ordinary repositories and named partial or disabled DNF overrides. Reject wildcard key replacement before override shortcuts and propagate pins to both runtime override directories. Key URL paths remain exact, including trailing slashes.Stacked on #623 for the static/pre-commit fixes; retarget to main after #623 merges. #527 is already merged. Detailed authenticity policy is preserved in a linked skill reference.
Validation: full
just checkand pre-commit passed on ae0fdd3. Regression tests cover partial, disabled and wildcard key substitutions. Installed-guest checks are in the pending isolated VM run: https://github.com/projectbluefin/utah/actions/runs/37568822950 .