Fix virtual package parsing to prevent invalid cache entries
Summary
Fixed the issue where APT virtual packages with no concrete providers caused invalid package names to be cached instead of failing with a clear error message.
Changes Made
- [x] Root Cause Analysis: Identified that virtual packages with no reverse provides (like
python) return "Reverse Provides:" which gets parsed as "Reverse=Provides:" package - [x] Core Fix: Enhanced
getNonVirtualPackagefunction insrc/internal/common/apt.goto detect and properly handle virtual packages with no providers - [x] Error Handling: Action now fails with clear error message:
"virtual package 'python' has no concrete package providers available" - [x] Consolidate Logic: Added
isVirtualPackagehelper function to centralize virtual package detection logic - [x] Fix Duplicate Messages: Removed redundant
errMsgs = append(errMsgs, strings.Join(errMsgs, "\n"))line that was causing error messages to be duplicated - [x] Test Coverage: Added comprehensive test case
TestNormalizedList_VirtualPackageWithNoProviders_StderrsErrorMessage - [x] Binary Updates: Rebuilt both x86 and ARM64
apt_querybinaries with the fix - [x] Verification: Confirmed end-to-end functionality:
- ✅ Invalid virtual packages (e.g.,
python) now fail with clear error (shown once, not duplicated) - ✅ Valid packages continue to work normally
- ✅ Virtual packages with providers (e.g.,
libz-dev→zlib1g-dev) resolve correctly
- ✅ Invalid virtual packages (e.g.,
Design Decisions
The code already automatically installs concrete packages when virtual packages have providers (preserving efficiency). When no providers exist, it fails with a clear error message to inform users they need to specify a valid package name. This approach:
- Maintains efficiency by auto-resolving when possible
- Prevents silent failures by explicitly reporting when resolution is not possible
- Gives users clear, actionable feedback (without message duplication)
Impact
Users will no longer experience silent failures where invalid packages get cached. Instead, they'll receive immediate, actionable error messages (shown once, clearly) when using virtual packages that have no concrete implementations.
Original prompt
This section details on the original issue you should resolve
<issue_title>APT no-installation candidates for package still saves to cache rather than failing with clear error message.</issue_title> <issue_description>I have a Github Action running daily on a private repo which tries to run some quick tests to verify an (extremely old) application is working. July 7th and prior ran fine before the latest update for the Google URL shortener removal, but July 8th and onward have failed (undetected by my checks, as my scripts were still reporting success even though the apt dependencies were not present. oops).
It seems to be failing because of the - Reverse=Provides: line is erroneously detecting as a package to install. E: Unable to locate package Reverse.
I have tried to update my Action to use Ubuntu v24.04 but unfortunately the application code I am running has not been touched since ~2019ish and thus there are build errors on newer Ubuntu versions that are a headache for another day. I am hoping there could be a quick fix for this so that I can continue caching my apt installs without having to touch ~30 year old C/C++ code 🙏.
Here is the relevant part of my ci.yml:
jobs:
build-and-test:
runs-on: ubuntu-22.04
steps:
- name: Checkout Repository
uses: actions/checkout@v4
with:
fetch-depth: 0
submodules: true
- name: Install Packages
uses: awalsh128/cache-apt-pkgs-action@latest
with:
packages: build-essential telnet expect git python bison \
autoconf automake autogen libevent-dev libjemalloc-dev \
default-libmysqlclient-dev libpcre3-dev libpq-dev libsqlite3-dev \
libssl-dev libz-dev libgtest-dev
version: 1.0
July 8th run
Run awalsh128/cache-apt-pkgs-action@latest
with:
packages: build-essential telnet expect git python bison \ autoconf automake autogen libevent-dev libjemalloc-dev \ default-libmysqlclient-dev libpcre3-dev libpq-dev libsqlite3-dev \ libssl-dev libz-dev libgtest-dev
version: 1
execute_install_scripts: false
debug: false
Run ${GITHUB_ACTION_PATH}/pre_cache_action.sh \
${GITHUB_ACTION_PATH}/pre_cache_action.sh \
~/cache-apt-pkgs \
"$VERSION" \
"$EXEC_INSTALL_SCRIPTS" \
"$DEBUG" \
"$PACKAGES"
echo "CACHE_KEY=$(cat ~/cache-apt-pkgs/cache_key.md5)" >> $GITHUB_ENV
shell: /usr/bin/bash --noprofile --norc -e -o pipefail {0}
env:
VERSION: 1
EXEC_INSTALL_SCRIPTS: false
DEBUG: false
PACKAGES: build-essential telnet expect git python bison \ autoconf automake autogen libevent-dev libjemalloc-dev \ default-libmysqlclient-dev libpcre3-dev libpq-dev libsqlite3-dev \ libssl-dev libz-dev libgtest-dev
Normalizing package list...
done
Validating action arguments (version='1', packages='Reverse=Provides: autoconf=2.71-2 autogen=1:5.18.16-4 automake=1:1.16.5-1.3 bison=2:3.8.2+dfsg-1build1 build-essential=12.9ubuntu3 default-libmysqlclient-dev=1.0.8 expect=5.45.4-2build1 git=1:2.49.0-2~ppa1~ubuntu22.04.1 libevent-dev=2.1.12-stable-1build3 libgtest-dev=1.11.0-3 libjemalloc-dev=5.2.1-4ubuntu1 libpcre3-dev=2:8.39-13ubuntu0.22.04.1 libpq-dev=17.5-1.pgdg22.04+1 libsqlite3-dev=3.37.2-2ubuntu0.4 libssl-dev=3.0.2-0ubuntu1.19 telnet=0.17-44build1')...
done
Creating cache key...
- Value to hash is 'Reverse=Provides: autoconf=2.71-2 autogen=1:5.18.16-4 automake=1:1.16.5-1.3 bison=2:3.8.2+dfsg-1build1 build-essential=12.9ubuntu3 default-libmysqlclient-dev=1.0.8 expect=5.45.4-2build1 git=1:2.49.0-2~ppa1~ubuntu22.04.1 libevent-dev=2.1.12-stable-1build3 libgtest-dev=1.11.0-3 libjemalloc-dev=5.2.1-4ubuntu1 libpcre3-dev=2:8.39-13ubuntu0.22.04.1 libpq-dev=17.5-1.pgdg22.04+1 libsqlite3-dev=3.37.2-2ubuntu0.4 libssl-dev=3.0.2-0ubuntu1.19 telnet=0.17-44build1 @ 1 3'.
- Value hashed as '68dff83ef6c4bb3671c78ab4e04a9cf1'.
done
Hash value written to /home/runner/cache-apt-pkgs/cache_key.md5
Run actions/cache/restore@v4
Cache not found for input keys: cache-apt-pkgs_68dff83ef6c4bb3671c78ab4e04a9cf1
Run ${GITHUB_ACTION_PATH}/post_cache_action.sh \
Updating APT package list...
done
Clean installing and caching 17 package(s).
Package list:
- Reverse=Provides:
- autoconf=2.71-2
- autogen=1:5.18.16-4
- automake=1:1.16.5-1.3
- bison=2:3.8.2+dfsg-1build1
- build-essential=12.9ubuntu3
- default-libmysqlclient-dev=1.0.8
- expect=5.45.4-2build1
- git=1:2.49.0-2~ppa1~ubuntu22.04.1
- libevent-dev=2.1.12-stable-1build3
- libgtest-dev=1.11.0-3
- libjemalloc-dev=5.2.1-4ubuntu1
- libpcre3-dev=2:8.39-13ubuntu0.22.04.1
- libpq-dev=17.5-1.pgdg22.04+1
- libsqlite3-dev=3.37.2-2ubuntu0.4
- libssl-dev=3.0.2-0ubuntu1.19
- telnet=0.17-44build1
Writing main packages manifest to /home/runner/cache-apt-pkgs/manifest_main.log...
done
Clean installing 17 packages...
E: Unable to locate package Reverse
[apt-fast 12:47:24]Package manager quit with exit code.
done
Installation log written to /home/runner/cache-apt-pkgs/install.log
Installed package list:
Caching 0...
</details>
Fixes awalsh128/cache-apt-pkgs-action#166
<!-- START COPILOT CODING AGENT TIPS -->
---
💬 Share your feedback on Copilot coding agent for the chance to win a $200 gift card! Click [here](https://survey3.medallia.com/?EAHeSx-AP01bZqG0Ld9QLQ) to start the survey.