feat(cli): background update check with pip-style notice#124
feat(cli): background update check with pip-style notice#124eFAILution merged 1 commit intofeat/argus-portabilityfrom
Conversation
A security tool that's months out of date is missing CVE-database
updates, new severity-classification rules, and bug fixes that affect
scan correctness. argus now polls PyPI once per day per machine,
caches the result for 24h, and prints a pip-style notice at the end
of long-running commands when a newer release exists.
Design constraints:
* Air-gap friendly. Every network failure (URLError, OSError, JSON
parse, missing field) is silenced — air-gapped CI runners and
offline machines never see a slowdown, error, or visible failure
because PyPI is unreachable.
* Privacy-respectful. One HTTP request per machine per 24h, cached
in ~/.cache/argus/update-check.json (or XDG_CACHE_HOME). The same
data PyPI already gets from pip install argus-security.
* Zero scan-latency cost. Runs in a daemon thread alongside the
scan; the result is consumed at end-of-command. Scans typically
take seconds to minutes; the update check completes in well under
500ms and runs in parallel.
* Override-friendly:
- ARGUS_NO_UPDATE_CHECK env var disables the check entirely
(set this in CI / air-gapped environments).
- --no-update-check flag for per-invocation control.
- --quiet auto-respects explicit silence.
- ARGUS_UPDATE_CHECK_URL points at TestPyPI or private mirrors
when the user knows their distribution channel differs from
public PyPI.
- Editable / dev / RC installs auto-skip — a contributor on
0.7.2.dev0+g123abc isn't told 0.7.2 is "available."
Notice shape matches pip's so it reads familiar:
[notice] A new release of argus-security is available: 0.7.2 → 0.8.1
[notice] To update, run: pip install --upgrade argus-security
Wired into _cmd_source_scan and _cmd_container_scan: start the
background check after argparse and manifest creation, consume right
before return exit_code so the notice never hides scan results
behind version chatter.
New module argus/update_check.py with 38 unit tests covering
suppression hooks, URL resolution, every error path returning None,
cache freshness, version comparison, notice formatting, and
background-thread exception swallowing.
End-to-end smoke test: argus scan with ARGUS_UPDATE_CHECK_URL set
to an unreachable host produced no [notice] block and exited
cleanly (air-gap contract).
CLI reference regenerated for the new flag.
Tests: 1628 passing (was 1590; +38).
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
🔒 Argus Container Security ScanBranch: 📊 Combined Findings Summary
Scanned: 4 containers | Build Failures: 0 📦 Container Breakdown
🔍 Detailed Findings by Container🚨 cli - 29 vulnerabilities (23 unique)Image: Combined (Deduplicated)
🔷 Trivy Scanner (29 findings, 23 unique)
⚓ Grype Scanner (0 findings, 0 unique)✅ No vulnerabilities detected by Grype 🟡 scanner-bandit - 2 vulnerabilities (2 unique)Image: Combined (Deduplicated)
🔷 Trivy Scanner (2 findings, 2 unique)
⚓ Grype Scanner (0 findings, 0 unique)✅ No vulnerabilities detected by Grype
|
| 🚨 Critical | 🟡 Medium | 🔵 Low | Total | Unique | |
|---|---|---|---|---|---|
| 0 | 7 | 44 | 63 | 114 | 50 |
🔷 Trivy Scanner (114 findings, 49 unique)
| CVE | Severity | Package | Version | Fixed |
|---|---|---|---|---|
| CVE-2026-4878 | libcap2 | 1:2.75-10+b8 | N/A | |
| CVE-2025-69720 | libncursesw6 | 6.5+20250216-2 | N/A | |
| CVE-2026-29111 | libsystemd0 | 257.9-1~deb13u1 | N/A | |
| CVE-2025-69720 | libtinfo6 | 6.5+20250216-2 | N/A | |
| CVE-2026-29111 | libudev1 | 257.9-1~deb13u1 | N/A | |
| CVE-2025-69720 | ncurses-base | 6.5+20250216-2 | N/A | |
| CVE-2025-69720 | ncurses-bin | 6.5+20250216-2 | N/A | |
| CVE-2026-27456 | 🟡 MEDIUM | bsdutils | 1:2.41-5 | N/A |
| CVE-2026-3184 | 🟡 MEDIUM | bsdutils | 1:2.41-5 | N/A |
| CVE-2026-27456 | 🟡 MEDIUM | libblkid1 | 2.41-5 | N/A |
| CVE-2026-3184 | 🟡 MEDIUM | libblkid1 | 2.41-5 | N/A |
| CVE-2026-4046 | 🟡 MEDIUM | libc-bin | 2.41-12+deb13u2 | N/A |
| CVE-2026-4437 | 🟡 MEDIUM | libc-bin | 2.41-12+deb13u2 | N/A |
| CVE-2026-4438 | 🟡 MEDIUM | libc-bin | 2.41-12+deb13u2 | N/A |
| CVE-2026-5435 | 🟡 MEDIUM | libc-bin | 2.41-12+deb13u2 | N/A |
| CVE-2026-5450 | 🟡 MEDIUM | libc-bin | 2.41-12+deb13u2 | N/A |
| CVE-2026-5928 | 🟡 MEDIUM | libc-bin | 2.41-12+deb13u2 | N/A |
| CVE-2026-6238 | 🟡 MEDIUM | libc-bin | 2.41-12+deb13u2 | N/A |
| CVE-2026-4046 | 🟡 MEDIUM | libc6 | 2.41-12+deb13u2 | N/A |
| CVE-2026-4437 | 🟡 MEDIUM | libc6 | 2.41-12+deb13u2 | N/A |
| CVE-2026-4438 | 🟡 MEDIUM | libc6 | 2.41-12+deb13u2 | N/A |
| CVE-2026-5435 | 🟡 MEDIUM | libc6 | 2.41-12+deb13u2 | N/A |
| CVE-2026-5450 | 🟡 MEDIUM | libc6 | 2.41-12+deb13u2 | N/A |
| CVE-2026-5928 | 🟡 MEDIUM | libc6 | 2.41-12+deb13u2 | N/A |
| CVE-2026-6238 | 🟡 MEDIUM | libc6 | 2.41-12+deb13u2 | N/A |
| CVE-2026-27456 | 🟡 MEDIUM | liblastlog2-2 | 2.41-5 | N/A |
| CVE-2026-3184 | 🟡 MEDIUM | liblastlog2-2 | 2.41-5 | N/A |
| CVE-2026-34743 | 🟡 MEDIUM | liblzma5 | 5.8.1-1 | N/A |
| CVE-2026-27456 | 🟡 MEDIUM | libmount1 | 2.41-5 | N/A |
| CVE-2026-3184 | 🟡 MEDIUM | libmount1 | 2.41-5 | N/A |
| CVE-2026-27456 | 🟡 MEDIUM | libsmartcols1 | 2.41-5 | N/A |
| CVE-2026-3184 | 🟡 MEDIUM | libsmartcols1 | 2.41-5 | N/A |
| CVE-2026-40225 | 🟡 MEDIUM | libsystemd0 | 257.9-1~deb13u1 | N/A |
| CVE-2026-40226 | 🟡 MEDIUM | libsystemd0 | 257.9-1~deb13u1 | N/A |
| CVE-2026-4105 | 🟡 MEDIUM | libsystemd0 | 257.9-1~deb13u1 | N/A |
| CVE-2026-40225 | 🟡 MEDIUM | libudev1 | 257.9-1~deb13u1 | N/A |
| CVE-2026-40226 | 🟡 MEDIUM | libudev1 | 257.9-1~deb13u1 | N/A |
| CVE-2026-4105 | 🟡 MEDIUM | libudev1 | 257.9-1~deb13u1 | N/A |
| CVE-2026-27456 | 🟡 MEDIUM | libuuid1 | 2.41-5 | N/A |
| CVE-2026-3184 | 🟡 MEDIUM | libuuid1 | 2.41-5 | N/A |
| CVE-2026-27456 | 🟡 MEDIUM | login | 1:4.16.0-2+really2.41-5 | N/A |
| CVE-2026-3184 | 🟡 MEDIUM | login | 1:4.16.0-2+really2.41-5 | N/A |
| CVE-2026-27456 | 🟡 MEDIUM | mount | 2.41-5 | N/A |
| CVE-2026-3184 | 🟡 MEDIUM | mount | 2.41-5 | N/A |
| CVE-2026-5958 | 🟡 MEDIUM | sed | 4.9-2 | N/A |
| CVE-2026-5704 | 🟡 MEDIUM | tar | 1.35+dfsg-3.1 | N/A |
| CVE-2026-27456 | 🟡 MEDIUM | util-linux | 2.41-5 | N/A |
| CVE-2026-3184 | 🟡 MEDIUM | util-linux | 2.41-5 | N/A |
| CVE-2026-27171 | 🟡 MEDIUM | zlib1g | 1:1.3.dfsg+really1.3.1-1+b1 | N/A |
| CVE-2026-3219 | 🟡 MEDIUM | pip | 26.0.1 | N/A |
...and 64 more
⚓ Grype Scanner (0 findings, 0 unique)
✅ No vulnerabilities detected by Grype
⚠️ scanner-supply-chain - 9 vulnerabilities (9 unique)
Image: ghcr.io/huntridge-labs/argus/scanner-supply-chain:9dcc7daeabd18dd3fa4bdf1aaa08b876aeed043c
Combined (Deduplicated)
| 🚨 Critical | 🟡 Medium | 🔵 Low | Total | Unique | |
|---|---|---|---|---|---|
| 0 | 4 | 5 | 0 | 9 | 9 |
🔷 Trivy Scanner (9 findings, 9 unique)
| CVE | Severity | Package | Version | Fixed |
|---|---|---|---|---|
| CVE-2026-32280 | stdlib | v1.26.1 | 1.25.9, 1.26.2 | |
| CVE-2026-32281 | stdlib | v1.26.1 | 1.25.9, 1.26.2 | |
| CVE-2026-32283 | stdlib | v1.26.1 | 1.25.9, 1.26.2 | |
| CVE-2026-33810 | stdlib | v1.26.1 | 1.26.2 | |
| CVE-2026-3219 | 🟡 MEDIUM | pip | 26.0.1 | N/A |
| CVE-2026-6357 | 🟡 MEDIUM | pip | 26.0.1 | 26.1 |
| CVE-2026-32282 | 🟡 MEDIUM | stdlib | v1.26.1 | 1.25.9, 1.26.2 |
| CVE-2026-32288 | 🟡 MEDIUM | stdlib | v1.26.1 | 1.25.9, 1.26.2 |
| CVE-2026-32289 | 🟡 MEDIUM | stdlib | v1.26.1 | 1.25.9, 1.26.2 |
⚓ Grype Scanner (0 findings, 0 unique)
✅ No vulnerabilities detected by Grype
Generated by Argus
Description
Surfaces a soft notice when a newer argus release is available on PyPI — a security tool that's months out of date is missing CVE-database updates, new severity-classification rules, and bug fixes that affect scan correctness. Mirrors the pattern users already know from
pip,gh,uv, etc.Changes Made
Details
New module:
argus/update_check.pyPolls PyPI (https://pypi.org/pypi/argus-security/json) once per day per machine, caches the result in
~/.cache/argus/update-check.json(XDG_CACHE_HOME aware), compares against the installed version, prints apip-style notice at end-of-command when a newer release exists.Five non-negotiable design constraints:
URLError/OSError/JSON-parse failure is silenced. No timeouts, no errors, no slowdown.pip install argus-security.0.7.2.dev0+g123abc,0.7.2rc1,0.7.2+dirtyall skip — contributors on bleeding-edge don't get told a release version is "available."Suppression hierarchy (most persistent first):
ARGUS_NO_UPDATE_CHECK=1env var (set once for CI / air-gap)--no-update-checkflag (per-invocation)--quietflag (auto-respects explicit silence)__version__contains.dev/+/rc)Custom registries:
Default is hardcoded to public PyPI because auto-detecting which index argus was installed from is unreliable in Python —
pipdoesn't preserve that metadata.CLI integration in
_cmd_source_scanand_cmd_container_scan:start_background_check(args)after argparse + manifest creationupdate_check.notice()consumed right beforereturn exit_codeso the notice never hides scan results behind version chatterTesting
Test Results
38 new unit tests in
argus/tests/test_update_check.pycovering:End-to-end smoke test:
ARGUS_UPDATE_CHECK_URL=https://invalid.example.test/foo.json argus scan ...produced no[notice]block and exited cleanly — air-gap contract holds.Full SDK suite: 1628 passing (was 1590; +38).
Security Considerations
Security Details
This is the security-tool-imperative completion. Outdated security tools miss CVE coverage, severity-rule updates, and bug fixes. The notice points users at the upgrade path so a security-conscious team isn't running an argus release that's silently 6 months behind.
The implementation itself is conservative: 24h cache, 2-second HTTP timeout, no telemetry beyond the version-fetch GET, no execution of fetched data. Air-gap support via env var plus silent network-failure handling.
AI Context Updates (.ai/)
Checklist
For New Scanners/Actions (if applicable)