Skip to content

Add a new feature plugin to verify package installation#4660

Open
vaibhavdaren wants to merge 10 commits intomainfrom
vaibhav-package-verify-plugin
Open

Add a new feature plugin to verify package installation#4660
vaibhavdaren wants to merge 10 commits intomainfrom
vaibhav-package-verify-plugin

Conversation

@vaibhavdaren
Copy link
Contributor

@vaibhavdaren vaibhavdaren commented Mar 9, 2026

Pull Request Checklist: #4644

  • implement the feature
  • write the documentation
  • extend the test coverage
  • update the specification
  • adjust plugin docstring
  • modify the json schema
  • include a release note

@vaibhavdaren vaibhavdaren force-pushed the vaibhav-package-verify-plugin branch from ffe8028 to 5ae12a0 Compare March 9, 2026 11:35
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request adds a verify-installation prepare plugin to verify package installation sources. The implementation includes abstractions in package managers, the plugin itself, its schema, and tests. The changes are well-structured. One minor improvement is suggested for a warning message.

Note: Security Review did not run due to the size of the PR.

@vaibhavdaren vaibhavdaren marked this pull request as ready for review March 9, 2026 15:45
@vaibhavdaren vaibhavdaren moved this to review in planning Mar 9, 2026
@vaibhavdaren vaibhavdaren added the plugin | artifact Related to the `prepare/artifact` plugin. label Mar 9, 2026
@vaibhavdaren vaibhavdaren added this to the 1.69 milestone Mar 9, 2026
@vaibhavdaren vaibhavdaren self-assigned this Mar 9, 2026
@vaibhavdaren vaibhavdaren force-pushed the vaibhav-package-verify-plugin branch from 45bde38 to 2a3ab0f Compare March 10, 2026 12:05
Copy link
Contributor

@thrix thrix left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice plugin addition for verifying package sources. The overall structure follows tmt patterns well (container data class, normalization, schema, beakerlib tests). A few issues to address:

Must fix:

  1. Verification failures don't actually stop test execution - The plugin records FAIL results but doesn't raise PrepareError or append to outcome.exceptions. The prepare step framework only aborts on exceptions, not on FAIL results. This contradicts the docstring promise.
  2. expected_repo should be expected-repo (kebab-case) - tmt convention uses hyphens in user-facing YAML keys. The underscore form is inconsistent with dist-git-source, is-virtualized, etc.

Should verify:
3. dnf5 / yum compatibility for repoquery --queryformat "%{from_repo}" - Dnf5Engine and YumEngine inherit this without override.

Checklist items still unchecked:

  • Update the specification
  • Adjust plugin docstring
  • Mention the version
  • Include a release note (file exists but version not mentioned)

@vaibhavdaren
Copy link
Contributor Author

vaibhavdaren commented Mar 11, 2026

Addressed comments from code review in f128998.

@vaibhavdaren vaibhavdaren added the ci | full test Pull request is ready for the full test execution label Mar 11, 2026
@vaibhavdaren vaibhavdaren force-pushed the vaibhav-package-verify-plugin branch from 6a3a552 to f128998 Compare March 11, 2026 07:20
@vaibhavdaren vaibhavdaren force-pushed the vaibhav-package-verify-plugin branch 2 times, most recently from 8ad17a3 to b660235 Compare March 11, 2026 12:07
@vaibhavdaren vaibhavdaren requested a review from LecrisUT March 11, 2026 12:12
@vaibhavdaren vaibhavdaren force-pushed the vaibhav-package-verify-plugin branch from b1927db to 1462e47 Compare March 13, 2026 13:07
Comment on lines +13 to +26
rlPhaseStartTest "Test successful verification on dnf4"
rlLog "Verify packages installed from BaseOS and Docker CE repo pass verification"

rlRun -s "tmt run -i \$run/success --scratch -vvv --all \
plan --name /plan/success \
provision -h \$PROVISION_HOW --image \$TEST_IMAGE_PREFIX/centos/stream10/upstream:latest" \
0 "Run verification test with correct repos"

rlAssertGrep "pass .* / make" $rlRun_LOG
rlAssertGrep "pass .* / diffutils" $rlRun_LOG
rlAssertGrep "pass .* / docker-ce-cli" $rlRun_LOG
rlAssertGrep "All packages verified successfully." $rlRun_LOG
rlAssertGrep "1 test passed" $rlRun_LOG
rlPhaseEnd
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please not like this with so much duplication. If needed, please use anything in epel10 and include epel feature. Can try centpkg for example. It doesn't use or test brew but that would be fine for now.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in a1ea9d1

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is still unnecessarily split between dnf4 and dnf5. Unify them and try to make it similar to /tests/prepare/install. Some adjust using the distro and such would be better

- Change verify field from comma-separated strings to YAML dict format
  with package and expected_repo keys; remove CLI counterpart for now
- Batch-query all packages at once using get_installed_repos()
- Record per-package failures as PhaseResult in outcome instead of
  raising PrepareError; let the framework handle failure reporting
- Fail hard on unsupported package managers instead of warning and skipping
- Fix docstrings to match surrounding style
- Update schema, test data and test assertions accordingly
- Track verification failures with a local flag instead of rescanning
  outcome.results to avoid false positives from super().go() results
- Catch RunError from get_installed_repos and record as ERROR PhaseResult
  instead of propagating as an unhandled exception
- Log unexpected repoquery output lines at debug level instead of
  silently ignoring them
- Use str(m.package) in serialize to avoid Package subclass leaking
  into serialized output
- Remove redundant test assertion for 'make-devel' already covered by
  'fail make-devel' check
@vaibhavdaren vaibhavdaren force-pushed the vaibhav-package-verify-plugin branch from 01bd2e9 to a1ea9d1 Compare March 13, 2026 14:34
parts = line.split(maxsplit=1)
if len(parts) == 2:
result[parts[0]] = parts[1].strip()
elif len(parts) == 1 and parts[0] in result:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parts[0] in result is unnecessary in various ways. Also add comments on what each of these cases represent

@vaibhavdaren vaibhavdaren force-pushed the vaibhav-package-verify-plugin branch from dddef12 to 87ebdc0 Compare March 13, 2026 17:44
@vaibhavdaren vaibhavdaren requested a review from thrix March 13, 2026 17:46
@vaibhavdaren vaibhavdaren force-pushed the vaibhav-package-verify-plugin branch from 87ebdc0 to f1c44c7 Compare March 13, 2026 17:49
@thrix
Copy link
Contributor

thrix commented Mar 13, 2026

@vaibhavdaren btw tests are still failing hard? or will that be a focus at the end? Anyway, LGTM from my end now see below :)

Copy link
Contributor

@thrix thrix left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-review after 10 iterations. All issues from my previous CHANGES_REQUESTED review have been resolved:

  1. Failures not stopping execution — Fixed: outcome.exceptions populated alongside FAIL results (with FIXME for #4667)
  2. kebab-case naming — No longer applies: schema simplified to plain dict[str, str]
  3. dnf5/yum compatibility — Addressed: YumEngine raises NotImplementedError with comment; dnf5 UUIDs passed through as-is
  4. NotImplementedError handler — Fixed: now emits PhaseResult(ERROR) + appends to outcome.exceptions, consistent with GeneralError handling

The plugin is well-structured — clean architecture (engine → manager → plugin), proper per-package PASS/FAIL results, consistent error handling. Tests cover success and failure paths on both CentOS (dnf4) and Fedora (dnf5).

One remaining item from @LecrisUT: unify data-centos/data-fedora into a single test using adjust with distro conditions instead of separate directories and if rlIsFedora branching.

Nice work iterating through the extensive review feedback @vaibhavdaren!

Generated-by: Claude Code

@thrix thrix self-requested a review March 13, 2026 23:54
thrix

This comment was marked as spam.

@thrix thrix self-requested a review March 13, 2026 23:55
result: dict[str, Optional[str]] = dict.fromkeys(packages)
script = self.engine.get_package_origin(result.keys())
output = self.guest.execute(script)
for line in (output.stdout or '').strip().splitlines():
Copy link
Contributor

@happz happz Mar 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are some loose ends I can't sort out:

  • the dnf5/dnf4 notes below in the base class implementation suggest that dnf4 probably needs its own custom implementation, an implementation aware of dnf4 quirks.
  • but then again, what's the contract between engine.get_package_origin() and its callers, what's the expected output? A line per package, in the package origin format - if the dnf4 implementation of this method sneaks in empty lines, it's violating the expectations. This may be problem for commands building images: engine is asked to create a command with expected output, the command would be then executed in container image build time, and the dnf4 command would produce unexpected output, possibly breaking further processing. Maybe we could extend the contract, to make it more liberal: a line per package, in the package origin format, empty lines are ignored. And we no longer need to worry about dnf4 in the base class, dnf4 engine would produce valid script.
  • the "not installed via a repo" might be more common, other package managers may support installation of packages from files, therefore this might be worth an extension to the get_package_origin() contract: a line per package, in the package origin format, empty lines are ignored, origin is optional and if not specified, it means "unknown".

After this, we would get a simpler base implementation, fewer notes about dnf4 quirks in the base class, nicer protocol for get_package_origin(), and the need for a custom dnf4 implementation would be gone.

result[parts[0]] = parts[1].strip()
elif len(parts) == 1:
# dnf4: empty %{from_repo} means package was not installed via a repo
result[parts[0]] = "[unknown]"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deserves to be a module-level constant.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci | full test Pull request is ready for the full test execution plugin | artifact Related to the `prepare/artifact` plugin.

Projects

Status: review

Development

Successfully merging this pull request may close these issues.

Create a Verify Install plugin which checks if packages are installed from the correct repo

6 participants