Skip to content

Conversation

@amanycodes
Copy link
Contributor

@amanycodes amanycodes commented May 25, 2025

This PR checks and improves log consistency for "No Upgradable Packages" (NUP) across rpm, dpkg, and apk package managers. It also fixes a bug in the dpkg manager (later discussed).

I ran copa patch with a dummy report to simulate NUP. Dummy Report structure (dpkg example):

{
  "SchemaVersion": 2,
  "ArtifactName": "ubuntu:22.04",
  "ArtifactType": "container_image",
  "Metadata": {
    "OS": {
      "Family": "ubuntu",
      "Name": "22.04"
    },
    "Config": {
      "Arch": "amd64"
    }
  },
  "Results": [
    {
      "Target": "ubuntu:22.04 (ubuntu 22.04)",
      "Class": "os-pkgs",
      "Type": "debian",
      "Vulnerabilities": [
        {
          "VulnerabilityID": "CVE-DUMMY-UBUNTU-TAR",
          "PkgName": "tar",
          "InstalledVersion": "1.34+dfsg-1ubuntu0.1.22.04.2",
          "FixedVersion": "1.34+dfsg-1ubuntu0.1.22.04.2"
        }
      ]
    }
  ]
}

I checked consistency on two cases for each package manager:

  1. installedVersion == FixedVersion and expected a log like:
    INFO[...] Validated package <pkg> version <ver> meets requested version <ver>
  2. FixedVersion > InstalledVersion: The package manager attempts an upgrade but leaves the package at its original InstalledVersion because the higher FixedVersion is not found in its repositories and expected log like:
    ERRO[...] installed package <pkg> version <ver> is lower than required <ver> from report

I used a regular copa patch command: copa patch -i $IMAGE -r $REPORT --debug

For apk: I used alpine:latest and checked for busybox and scanelf and got:
image

For rpm: I used rockylinux:9-minimal and checked for coreutils-single and got:
image
image

For dpkg: I used ubuntu:22.04 and checked for tar and got:
image

and in dpkg I found the inconsistency. Upon checking the installUpdates() I found that checkUpgragdable was being unconditionally executed. copa was failing & terminating the patching early if image has no general updates even though report was specified. I have now fixed this and it's being conditionally executed(only running this check in "update all" mode like in apk.go).

This makes the logging for NUP consistent across all package managers.

partially closes: #1010

Signed-off-by: amanycodes <amanycodes@gmail.com>
@codecov
Copy link

codecov bot commented May 25, 2025

Codecov Report

❌ Patch coverage is 40.00000% with 15 lines in your changes missing coverage. Please review.
✅ Project coverage is 42.57%. Comparing base (4f133cf) to head (749f89e).
⚠️ Report is 55 commits behind head on main.

Files with missing lines Patch % Lines
pkg/pkgmgr/dpkg.go 16.66% 9 Missing and 1 partial ⚠️
pkg/pkgmgr/rpm.go 62.50% 2 Missing and 1 partial ⚠️
pkg/pkgmgr/apk.go 60.00% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1072      +/-   ##
==========================================
- Coverage   42.73%   42.57%   -0.17%     
==========================================
  Files          24       24              
  Lines        3938     3951      +13     
==========================================
- Hits         1683     1682       -1     
- Misses       2127     2138      +11     
- Partials      128      131       +3     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@amanycodes amanycodes changed the title fix: checkUpradable runs unconditionally in dpkg fix: checkUpgradable runs unconditionally in dpkg May 25, 2025
@ashnamehrotra
Copy link
Contributor

@amanycodes thanks for investigating! this should be expected behavior (if there are no upgradable packages with scan report or update all we should error out). It should be the case for dpkg, and rpm - can we change it for apk? In the issue I was referring to the logs such as "no patchable packages found" which we output for rpm but do not explicitly output in other cases. This way users will know patching is failing because there were not upgradable packages. Let me know if that makes sense!

@amanycodes
Copy link
Contributor Author

@amanycodes thanks for investigating! this should be expected behavior (if there are no upgradable packages with scan report or update all we should error out). It should be the case for dpkg, and rpm - can we change it for apk? In the issue I was referring to the logs such as "no patchable packages found" which we output for rpm but do not explicitly output in other cases. This way users will know patching is failing because there were not upgradable packages. Let me know if that makes sense!

Yeah, makes sense! will update the dpkg and apk to show the error of "no patchable packages found". I misunderstood this with existing packages not being further upgradable. Thanks for clarification! Also is that unconditional execution in dpkg.go intentional? If so i would like to know why in that specefic case? 🤔. Will add the error logs for apk in this case.

@amanycodes
Copy link
Contributor Author

I'm still confused about the check we're doing in apk.go and not in dpkg.go before executing the checkUpgradable 🤔

@ashnamehrotra
Copy link
Contributor

@amanycodes for all package managers we want to error out if there are no upgradable packages - thats why we check for that in debian, and want to do it similarly for apk - it looks like right now its within the update all case

@sozercan
Copy link
Member

@ashnamehrotra @robert-cronin @amanycodes do we want this to be in v0.11 release?

).Root()

checkUpgradable := `sh -c "apt-get -s upgrade 2>/dev/null | grep -q "^Inst" || exit 1"`
checkUpgradable := `sh -c "apt-get -s upgrade 2>/dev/null | grep -q "^Inst" > /upgradable.txt || exit 1"`
Copy link
Contributor

Choose a reason for hiding this comment

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

can we do the same thing in the case of distroless images (unpackAndMergeUpdates func)

Copy link
Contributor

Choose a reason for hiding this comment

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

and then same thing for rpm distroless just to keep the errors consistent

amanycodes and others added 2 commits June 27, 2025 03:15
@ashnamehrotra
Copy link
Contributor

ashnamehrotra commented Jun 27, 2025

@amanycodes looks like tests are failing for debian patching with no scan report

@leodewang leodewang moved this from 🆕 New to 👀 In review in Copacetic Workboard Jun 27, 2025
@amanycodes
Copy link
Contributor Author

@amanycodes looks like tests are failing for debian patching with no scan report

the image we are testing doesn't have any upgradable packages and we are returning the required error "no patchable packages found". I think the right now the workflow intends to patch successfully that's why it's failing.
https://github.com/project-copacetic/copacetic/actions/runs/15914354643/job/44888974517?pr=1072#step:12:682

Should I update the test to allow "no patchable packages found" as a valid error in this case?

@ashnamehrotra
Copy link
Contributor

@amanycodes the images have outdated packages, you can run the images to check or scan with trivy to test

amanycodes and others added 3 commits June 30, 2025 22:11
Signed-off-by: amanycodes <amanycodes@gmail.com>
Signed-off-by: amanycodes <amanycodes@gmail.com>
Signed-off-by: amanycodes <amanycodes@gmail.com>
@amanycodes
Copy link
Contributor Author

@ashnamehrotra I tried but actually I am having trouble finding the exact location of checking the upgradable package among the distroless command shenanigans, I tried multiple approaches but they aren't working. please let me know where am i going wrong

checkUpgradable := `sh -c "apt-get -s upgrade 2>/dev/null | grep -q \"^Inst\" > /upgradable.txt || exit 1"`
updatedCheck := updated.Run(llb.Shlex(checkUpgradable)).Root()
_, err = buildkit.ExtractFileFromState(ctx, dm.config.Client, &updatedCheck, "/upgradable.txt")
if err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think the problem is here, you are just checking if this file exists, and it will always be created even if it is empty.

Copy link
Contributor

Choose a reason for hiding this comment

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

@amanycodes I guess you could instead use the file bytes returned in the first arg to check if the file is empty?

@leodewang leodewang moved this from 👀 In review to 🏗 In progress in Copacetic Workboard Jul 2, 2025
@ashnamehrotra
Copy link
Contributor

@amanycodes are you still working on this? should we resolve via #1274 ?

@ashnamehrotra
Copy link
Contributor

ashnamehrotra commented Oct 1, 2025

closing this for #1274, @amanycodes to reopen that one

@github-project-automation github-project-automation bot moved this from 🏗 In progress to ✅ Done in Copacetic Workboard Oct 1, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

[REQ] Improve error logs

4 participants