Skip to content

Conversation

knqyf263
Copy link
Collaborator

@knqyf263 knqyf263 commented Jul 23, 2025

Description

This PR implements graceful shutdown for Trivy by adding signal handling for SIGINT and SIGTERM. When a signal is received, Trivy will attempt to complete ongoing operations before exiting. Users can send a second signal to force immediate termination.

Before

When pressing Ctrl+C, Trivy immediately terminates without cleanup:

$ trivy image alpine:latest
^C

After

Trivy now attempts graceful shutdown with user feedback:

$ trivy image alpine:latest
^C2024-07-23T10:00:00.000+0900	INFO	Received signal, attempting graceful shutdown...
2024-07-23T10:00:00.000+0900	INFO	Press Ctrl+C again to force exit

Server mode also supports graceful shutdown:

$ trivy server
^C2024-07-23T10:00:00.000+0900	INFO	Received signal, attempting graceful shutdown...
2024-07-23T10:00:00.000+0900	INFO	Press Ctrl+C again to force exit

Key Changes:

  1. Signal handling: Added commands.NotifyContext wrapper around signal.NotifyContext to handle SIGINT/SIGTERM
  2. Context-aware io.Copy: Implemented xio.Copy that respects context cancellation
  3. Server graceful shutdown: Modified server to shutdown gracefully with a 30-second timeout for active requests
  4. User feedback: Added logging to inform users about graceful shutdown progress

Implementation Note:

Currently, only the artifact download io.Copy is replaced with the context-aware version, as it's most likely to benefit from cancellation during vulnerability DB or Java DB downloads. Other io.Copy calls can be replaced as needed in the future.

Performance Analysis:

The xio.Copy implementation wraps the reader with a context check, which prevents the WriterTo optimization in io.Copy if the source implements it. However, testing shows:

  • Memory usage comparison shows negligible difference (<1%)
  • The layer.Compressed() reader used in artifact downloads doesn't implement WriterTo, so there's no performance regression in this use case
  • This is an acceptable trade-off for gaining context cancellation capability

Related issues

  • Related to temp file cleanup improvements

Checklist

  • I've read the guidelines for contributing to this repository.
  • I've followed the conventions in the PR title.
  • I've added tests that prove my fix is effective or that my feature works.
  • I've updated the documentation with the relevant information (if needed).
  • I've added usage information (if the PR introduces new options)
  • I've included a "before" and "after" example to the description (if the PR is a user interface change).

- Add signal handling (SIGINT/SIGTERM) with graceful shutdown
- Implement context-aware io.Copy in x/io package
- Update server to handle shutdown gracefully
- Log shutdown progress to inform users

Currently only artifact download io.Copy is replaced with context-aware
version as it's most likely to benefit from cancellation during
vulnerability DB or Java DB downloads. Other io.Copy calls can be
replaced as needed in the future.
@knqyf263 knqyf263 requested a review from Copilot July 23, 2025 10:55
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR implements graceful shutdown functionality for Trivy by adding signal handling for SIGINT and SIGTERM. When a signal is received, Trivy will attempt to complete ongoing operations before exiting, with users able to send a second signal for immediate termination.

  • Added signal handling wrapper that provides graceful shutdown with user feedback
  • Implemented context-aware I/O operations to respect cancellation during downloads
  • Modified server to shutdown gracefully with timeout for active requests

Reviewed Changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
pkg/commands/signal.go New signal handling wrapper with graceful shutdown logic and user feedback
pkg/x/io/io.go Context-aware Copy function that respects cancellation
pkg/x/io/io_test.go Test coverage for the new context-aware Copy function
pkg/oci/artifact.go Updated artifact download to use context-aware Copy
pkg/rpc/server/listen.go Modified server to support graceful shutdown with timeout
cmd/trivy/main.go Integration of signal handling into main application

@knqyf263 knqyf263 added the autoready Automatically mark PR as ready for review when all checks pass label Jul 23, 2025
@github-actions github-actions bot marked this pull request as ready for review July 23, 2025 11:15
@github-actions github-actions bot removed the autoready Automatically mark PR as ready for review when all checks pass label Jul 23, 2025
@knqyf263 knqyf263 requested a review from DmitriyLewen July 23, 2025 11:32
Copy link
Contributor

@DmitriyLewen DmitriyLewen left a comment

Choose a reason for hiding this comment

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

LGTM

left 1 comment

@@ -188,7 +189,7 @@ func (a *Artifact) download(ctx context.Context, layer v1.Layer, fileName, dir s
}()

// Download the layer content into a temporal file
if _, err = io.Copy(f, pr); err != nil {
if _, err = xio.Copy(ctx, f, pr); 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.

Do we want to overwrite xio.Copy for other cases?
e.g. we can copy big files to cache:

if _, err = io.Copy(f, o.reader); err != nil {
o.err = xerrors.Errorf("failed to copy: %w", err)
return
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes, possibly, as I mentioned in the PR description. Since xio.Copy has some trade-off, I would like to carefully replace other xio.Copy one by one.

@knqyf263 knqyf263 added this pull request to the merge queue Jul 24, 2025
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Jul 24, 2025
@DmitriyLewen DmitriyLewen added this pull request to the merge queue Jul 24, 2025
@knqyf263
Copy link
Collaborator Author

It doesn't seem relevant to my change.

=== RUN   TestScanner_Scan/with-remote-module
    scanner_test.go:67: 
        	Error Trace:	D:/a/trivy/trivy/pkg/iac/scanners/terraformplan/snapshot/scanner_test.go:67
        	Error:      	"[]" should have 1 item(s), but has 0
        	Test:       	TestScanner_Scan/with-remote-module
    scanner_test.go:74: 
        	Error Trace:	D:/a/trivy/trivy/pkg/iac/scanners/terraformplan/snapshot/scanner_test.go:74
        	Error:      	Not equal: 
        	            	expected: []string{"ID001"}
        	            	actual  : []string{}
        	            	
        	            	Diff:
        	            	--- Expected
        	            	+++ Actual
        	            	@@ -1,3 +1,2 @@
        	            	-([]string) (len=1) {
        	            	- (string) (len=5) "ID001"
        	            	+([]string) {
        	            	 }
        	Test:       	TestScanner_Scan/with-remote-module
--- FAIL: TestScanner_Scan (7.12s)
    --- PASS: TestScanner_Scan/just-resource (1.29s)
    --- PASS: TestScanner_Scan/with-local-module (0.41s)
    --- FAIL: TestScanner_Scan/with-remote-module (5.41s)

@DmitriyLewen
Copy link
Contributor

I assume that due to internet problems (or some kind of mistake) Trivy was unable to download the module.
it works for me locally.
So i re-added PR into merge queue.

@knqyf263
Copy link
Collaborator Author

Got it. Let's monitor the next try.

By the way, I don't think unit tests should include code that actually accesses external networks. We could mock the fetch process, or retrieve data from a locally hosted test server instead. In any case, we should eliminate any flaky elements from unit tests.

@DmitriyLewen
Copy link
Contributor

@nikpivkin @simar7 ^

Merged via the queue into aquasecurity:main with commit 2c05882 Jul 24, 2025
12 checks passed
@knqyf263 knqyf263 deleted the feat/signal-handling branch July 24, 2025 11:39
@nikpivkin
Copy link
Contributor

I'll look at the tests tomorrow.

alexlebens pushed a commit to alexlebens/infrastructure that referenced this pull request Jul 31, 2025
This PR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [mirror.gcr.io/aquasec/trivy](https://www.aquasec.com/products/trivy/) ([source](https://github.com/aquasecurity/trivy)) | minor | `0.64.1` -> `0.65.0` |

---

### Release Notes

<details>
<summary>aquasecurity/trivy (mirror.gcr.io/aquasec/trivy)</summary>

### [`v0.65.0`](https://github.com/aquasecurity/trivy/blob/HEAD/CHANGELOG.md#0650-2025-07-30)

[Compare Source](aquasecurity/trivy@v0.64.1...v0.65.0)

##### Features

- add graceful shutdown with signal handling ([#&#8203;9242](aquasecurity/trivy#9242)) ([2c05882](aquasecurity/trivy@2c05882))
- add HTTP request/response tracing support ([#&#8203;9125](aquasecurity/trivy#9125)) ([aa5b32a](aquasecurity/trivy@aa5b32a))
- **alma:** add AlmaLinux 10 support ([#&#8203;9207](aquasecurity/trivy#9207)) ([861d51e](aquasecurity/trivy@861d51e))
- **flag:** add schema validation for `--server` flag ([#&#8203;9270](aquasecurity/trivy#9270)) ([ed4640e](aquasecurity/trivy@ed4640e))
- **image:** add Docker context resolution ([#&#8203;9166](aquasecurity/trivy#9166)) ([99cd4e7](aquasecurity/trivy@99cd4e7))
- **license:** observe pkg types option in license scanner ([#&#8203;9091](aquasecurity/trivy#9091)) ([d44af8c](aquasecurity/trivy@d44af8c))
- **misconf:** add private ip google access attribute to subnetwork ([#&#8203;9199](aquasecurity/trivy#9199)) ([263845c](aquasecurity/trivy@263845c))
- **misconf:** added logging and versioning to the gcp storage bucket ([#&#8203;9226](aquasecurity/trivy#9226)) ([110f80e](aquasecurity/trivy@110f80e))
- **repo:** add git repository metadata to reports ([#&#8203;9252](aquasecurity/trivy#9252)) ([f4b2cf1](aquasecurity/trivy@f4b2cf1))
- **report:** add CVSS vectors in sarif report ([#&#8203;9157](aquasecurity/trivy#9157)) ([60723e6](aquasecurity/trivy@60723e6))
- **sbom:** add SHA-512 hash support for CycloneDX SBOM ([#&#8203;9126](aquasecurity/trivy#9126)) ([12d6706](aquasecurity/trivy@12d6706))

##### Bug Fixes

- **alma:** parse epochs from rpmqa file ([#&#8203;9101](aquasecurity/trivy#9101)) ([82db2fc](aquasecurity/trivy@82db2fc))
- also check `filepath` when removing duplicate packages ([#&#8203;9142](aquasecurity/trivy#9142)) ([4d10a81](aquasecurity/trivy@4d10a81))
- **aws:** update amazon linux 2 EOL date ([#&#8203;9176](aquasecurity/trivy#9176)) ([0ecfed6](aquasecurity/trivy@0ecfed6))
- **cli:** Add more non-sensitive flags to telemetry ([#&#8203;9110](aquasecurity/trivy#9110)) ([7041a39](aquasecurity/trivy@7041a39))
- **cli:** ensure correct command is picked by telemetry ([#&#8203;9260](aquasecurity/trivy#9260)) ([b4ad00f](aquasecurity/trivy@b4ad00f))
- **cli:** panic: attempt to get os.Args\[1] when len(os.Args) < 2 ([#&#8203;9206](aquasecurity/trivy#9206)) ([adfa879](aquasecurity/trivy@adfa879))
- **license:** add missed `GFDL-NIV-1.1` and `GFDL-NIV-1.2` into Trivy mapping ([#&#8203;9116](aquasecurity/trivy#9116)) ([a692f29](aquasecurity/trivy@a692f29))
- **license:** handle WITH operator for `LaxSplitLicenses` ([#&#8203;9232](aquasecurity/trivy#9232)) ([b4193d0](aquasecurity/trivy@b4193d0))
- migrate from `*.list` to `*.md5sums` files for `dpkg` ([#&#8203;9131](aquasecurity/trivy#9131)) ([f224de3](aquasecurity/trivy@f224de3))
- **misconf:** correctly adapt azure storage account ([#&#8203;9138](aquasecurity/trivy#9138)) ([51aa022](aquasecurity/trivy@51aa022))
- **misconf:** correctly parse empty port ranges in google\_compute\_firewall ([#&#8203;9237](aquasecurity/trivy#9237)) ([77bab7b](aquasecurity/trivy@77bab7b))
- **misconf:** fix log bucket in schema ([#&#8203;9235](aquasecurity/trivy#9235)) ([7ebc129](aquasecurity/trivy@7ebc129))
- **misconf:** skip rewriting expr if attr is nil ([#&#8203;9113](aquasecurity/trivy#9113)) ([42ccd3d](aquasecurity/trivy@42ccd3d))
- **nodejs:** don't use prerelease logic for compare npm constraints  ([#&#8203;9208](aquasecurity/trivy#9208)) ([fe96436](aquasecurity/trivy@fe96436))
- prevent graceful shutdown message on normal exit ([#&#8203;9244](aquasecurity/trivy#9244)) ([6095984](aquasecurity/trivy@6095984))
- **rootio:** check full version to detect `root.io` packages ([#&#8203;9117](aquasecurity/trivy#9117)) ([c2ddd44](aquasecurity/trivy@c2ddd44))
- **rootio:** fix severity selection ([#&#8203;9181](aquasecurity/trivy#9181)) ([6fafbeb](aquasecurity/trivy@6fafbeb))
- **sbom:** merge in-graph and out-of-graph OS packages in scan results ([#&#8203;9194](aquasecurity/trivy#9194)) ([aa944cc](aquasecurity/trivy@aa944cc))
- **sbom:** use correct field for licenses in CycloneDX reports ([#&#8203;9057](aquasecurity/trivy#9057)) ([143da88](aquasecurity/trivy@143da88))
- **secret:** add UTF-8 validation in secret scanner to prevent protobuf marshalling errors ([#&#8203;9253](aquasecurity/trivy#9253)) ([54832a7](aquasecurity/trivy@54832a7))
- **secret:** fix line numbers for multiple-line secrets ([#&#8203;9104](aquasecurity/trivy#9104)) ([e579746](aquasecurity/trivy@e579746))
- **server:** add HTTP transport setup to server mode ([#&#8203;9217](aquasecurity/trivy#9217)) ([1163b04](aquasecurity/trivy@1163b04))
- supporting .egg-info/METADATA in python.Packaging analyzer ([#&#8203;9151](aquasecurity/trivy#9151)) ([e306e2d](aquasecurity/trivy@e306e2d))
- **terraform:** `for_each` on a map returns a resource for every key ([#&#8203;9156](aquasecurity/trivy#9156)) ([153318f](aquasecurity/trivy@153318f))

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR is behind base branch, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MS4xLjMiLCJ1cGRhdGVkSW5WZXIiOiI0MS4xLjMiLCJ0YXJnZXRCcmFuY2giOiJtYWluIiwibGFiZWxzIjpbImltYWdlIl19-->

Reviewed-on: https://gitea.alexlebens.dev/alexlebens/infrastructure/pulls/1073
Co-authored-by: Renovate Bot <renovate-bot@alexlebens.net>
Co-committed-by: Renovate Bot <renovate-bot@alexlebens.net>
yutatokoi pushed a commit to yutatokoi/trivy that referenced this pull request Aug 12, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants