8000 Add ability to scan snaps (as a source) by wagoodman · Pull Request #3929 · anchore/syft · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Add ability to scan snaps (as a source) #3929

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 23 commits into from
Jun 25, 2025
Merged

Add ability to scan snaps (as a source) #3929

merged 23 commits into from
Jun 25, 2025

Conversation

wagoodman
Copy link
Contributor
@wagoodman wagoodman commented May 21, 2025

This adds support for cataloging single snap files, cataloging all contents. This can scan a local snap file:

syft /Users/wagoodman/OrbStack/ubuntu/home/wagoodman/snaps/etcd.snap

or grab the snap from snapcraft:

# assumes latest stable with amd64 arch
syft --from snap etcd

# specify a channel and arch
syft --from snap etcd@3.1/stable --platform i386
Screenshot 2025-05-23 at 3 20 15 PM Screenshot 2025-05-23 at 3 21 06 PM

Note: if --platform is given an OS then the source will error out and not continue (as this is not a valid form).

Type of change

  • New feature (non-breaking change which adds functionality)

Checklist

  • I have added unit tests that cover changed behavior
  • I have tested my code in common scenarios and confirmed there are no regressions
  • I have added comments to my code, particularly in hard-to-understand sections

TODO

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
wagoodman added 2 commits May 23, 2025 14:45
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
@popey
Copy link
Contributor
popey commented May 27, 2025

I'm seeing this a lot:

[0002] ERROR could not determine source: an error occurred attempting to resolve 'adguard-home': snap: unable to create snap file resolver: failed to walk squashfs file="/tmp/syft-snap-653810807/UXZIkJfJT2SPCGejjnSjOBqJ71yHk8bw_8117.snap": path="/" already exists but is NOT a regular file

Yet:

ls -l /tmp/syft-snap-653810807/UXZIkJfJT2SPCGejjnSjOBqJ71yHk8bw_8117.snap
-rw-rw-r-- 1 alan alan 9334784 May 27 15:31 /tmp/syft-snap-653810807/UXZIkJfJT2SPCGejjnSjOBqJ71yHk8bw_8117.snap
file /tmp/syft-snap-653810807/UXZIkJfJT2SPCGejjnSjOBqJ71yHk8bw_8117.snap
/tmp/syft-snap-653810807/UXZIkJfJT2SPCGejjnSjOBqJ71yHk8bw_8117.snap: Squashfs filesystem, little endian, version 4.0, xz compressed, 9332165 bytes, 8 inodes, blocksize: 131072 bytes, created: Tue May 27 12:20:03 2025

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
@wagoodman wagoodman added this to OSS May 29, 2025
@wagoodman wagoodman moved this to In Progress in OSS May 29, 2025
@wagoodman wagoodman self-assigned this May 29, 2025
wagoodman added 3 commits May 29, 2025 13:50
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
@wagoodman
Copy link
Contributor Author
wagoodman commented Jun 2, 2025

@popey pointed out that there are region locked snaps that fail with obtuse errors:

[0000] ERROR could not determine source: an error occurred attempting to resolve 'jp-ledger': snap: unable to open snap manifest file: failed to resolve request: failed to get download URL for snap "jp-ledger": API request failed with status code 404

We should probably use the search API to resolve an exact name match then extract the download link from there (search with q=NAME and only take results that locally match the given name exactly... or something similar). Then we could get an error message more like:

found snap 'jp-ledgrer' (id=jyDlMmifyQhSWGPM9fnKc1HSD7E6c47e) but it is unavailable for download

wagoodman added 3 commits June 3, 2025 09:38
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
@wagoodman wagoodman moved this from In Progress to In Review in OSS Jun 4, 2025
@wagoodman wagoodman marked this pull request as ready for review June 4, 2025 13:38
wagoodman added 2 commits June 4, 2025 11:07
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
wagoodman added 2 commits June 4, 2025 12:30
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
@wagoodman wagoodman requested a review from a team June 4, 2025 17:00
wagoodman added 2 commits June 4, 2025 14:17
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
r.mu.Lock()
defer r.mu.Unlock()

currentPos, err := r.Seek(0, io.SeekCurrent)
Copy link
Contributor

Choose a reason for hiding this comment

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

This should probably be tracked when the reader is created -- I don't think getting current position here will always be the right thing to do. I think this existing seekable reader behavior is close, albeit it's not ReaderAt but ReadSeeker:

func SeekableReader(reader io.Reader) (io.ReadSeeker, error) {

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is attempting to adapt the seeking ability (stateful) with a reader-at like experience (stateless), but doing so affects the pointer into the file, which would affect subsequent reads and seeks, so the first step is to keep the original position in order to restore it later in this call.

I think there is a problem in the sense that we are only locking for ReadAt, which in hindsight doesn't make sense because we're not locking for other operations.

Copy link
Contributor
E7F5

Choose a reason for hiding this comment

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

Let's say I have this reader, and I call .Read(bytes) and then I call .ReadAt(0,...), it will not have the correct starting position of the reader. I think, if we track the starting position when this custom reader is created, it should be reasonably assumed to be the "start of the stream". Happy to chat on this further, I was just pointing out it's a similar problem to the other reader I mentioned above

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The definition of ReaderAt is that the offset is absolute, not relative to any other read calls --we're only preserving the pointer state for other read/seek calls. That is, it could be that the file pointer is specifically there to subset a selection of the file, in which case the underlying reader should be wrapped with io.SectionReader or similar, where subsetting is explicit (and you can get the underlying non-section reader with .Outer()). However, us creating this wrapper around a io.ReadSeeker should not implicitly mean that we are intending to act like a io.SectionReader.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

tangent, I did update this to account for locking for other read/seek calls

}

func deriveID(path, name, version string) artifact.ID {
info := fmt.Sprintf("%s:%s@%s", digestOfFileContents(path), name, version)
Copy link
Contributor

Choose a reason for hiding this comment

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

seems like path.Base(path) might be a useful default here somewhere? and usually config aliases aren't set so name and version will be empty. e.g. <name | filename>@<version | hash> or something? this may not make a bit of difference, I didn't quite understand what the id is used for

Copy link
Contributor Author

Choose a reason for hiding this comment

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

the goal is to get a stable ID for the source when making relationships between other elements (packages / files) and the source.

Ideally this is content addressable -- regardless of the name of the file or any aliases used, we will get the same ID for the same file every time. However, we've found that for other kinds of sources that if there is a different logical name or version then we should have separate IDs.

This is mimicking the ID derivation from the file source.

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
@wagoodman wagoodman changed the title Add source that represents snaps Add ability to scan snaps (as a source) Jun 9, 2025
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
Copy link
Contributor
@kzantow kzantow left a comment

Choose a reason for hiding this comment

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

🎉

@wagoodman wagoodman merged commit 2bda086 into main Jun 25, 2025
12 checks passed
@wagoodman wagoodman deleted the add-snap-source branch June 25, 2025 20:53
@github-project-automation github-project-automation bot moved this from In Review to Done in OSS Jun 25, 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.

add native support for snap packages
3 participants
0