mirror of
https://github.com/anchore/syft.git
synced 2026-10-11 21:57:22 +02:00
Fix hang when scanning a Java resource adapter (.rar) file (#5348)
* fix: scan a Java resource adapter (.rar) given as a file source The file source picks an extractor for the scan target from its file name alone. A Java resource adapter archive (JCA) uses the .rar extension but is a zip file, so it was handed to the RAR extractor. With rardecode v2.2.0 the RAR extractor does not return on non-RAR input (an infinite loop in its signature search), so `syft scan --from file adapter.rar` never finished. The same bytes named .jar scan in under a second. When the name says RAR but the content is a zip archive, leave the file unextracted, the same way .jar, .war and .ear scan targets are handled. The java cataloger already reads .rar files (anchore/syft#4136) and now finds the resource adapter and its nested jars. Real RAR archives are still extracted. Signed-off-by: Ismael Donmez <ismael.donmez@chainguard.dev> Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * chore(deps): bump github.com/nwaples/rardecode/v2 from 2.2.0 to 2.4.1 rardecode v2.2.0 loops forever in its RAR signature search when the input does not start with a RAR signature (fixed upstream in nwaples/rardecode f501ac8, "fix infinite loop in findSig", released in v2.2.2). syft reaches that search for any file source whose name contains ".rar", so a scan of a self-extracting RAR, or of any other file with such a name, never finished. With v2.4.1 a self-extracting RAR is extracted, and a file that is not a RAR archive fails fast with "rardecode: RAR signature not found", the same way a file named .zip that is not a zip archive fails today. github.com/mholt/archives v0.1.5 (the latest release) still requires v2.2.0, so the newer version is selected here. Signed-off-by: Ismael Donmez <ismael.donmez@chainguard.dev> Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: clarify the .rar zip log line and cover self-extracting RAR sources - the debug line no longer calls every `.rar`-named zip a resource adapter - a self-extracting RAR (stub before the signature) given as a file source is still extracted Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> --------- Signed-off-by: Ismael Donmez <ismael.donmez@chainguard.dev> Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Co-authored-by: Alex Goodman <wagoodman@users.noreply.github.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
Alex Goodman
parent
f21e439a63
commit
0bbcff1ae3
@@ -2,6 +2,8 @@ package cli
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
@@ -31,6 +33,25 @@ func TestArchiveScan(t *testing.T) {
|
||||
assertPackageCount(1),
|
||||
},
|
||||
},
|
||||
{
|
||||
// a Java resource adapter archive is a zip file with a .rar extension
|
||||
name: "scan a java resource adapter archive",
|
||||
args: []string{
|
||||
"scan",
|
||||
"-o",
|
||||
"json",
|
||||
"--from",
|
||||
"file",
|
||||
createResourceAdapterArchive(t, t.TempDir()),
|
||||
},
|
||||
assertions: []traitAssertion{
|
||||
assertSuccessfulReturnCode,
|
||||
assertJsonReport,
|
||||
assertInOutput("pkg:maven/org.example/example-ra@1.0.0"),
|
||||
assertInOutput("pkg:maven/org.example/example-lib@1.0.0"),
|
||||
assertPackageCount(2),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
@@ -58,3 +79,37 @@ func createArchive(t *testing.T, path string, destDir string) string {
|
||||
|
||||
return archivePath
|
||||
}
|
||||
|
||||
// createResourceAdapterArchive writes a minimal Java resource adapter archive (a zip file with a .rar extension that
|
||||
// holds a deployment descriptor and a nested jar) into destDir and returns its path.
|
||||
func createResourceAdapterArchive(t *testing.T, destDir string) string {
|
||||
lib := zipBytes(t, [][2]string{
|
||||
{"META-INF/MANIFEST.MF", "Manifest-Version: 1.0\n"},
|
||||
{"META-INF/maven/org.example/example-lib/pom.properties", "groupId=org.example\nartifactId=example-lib\nversion=1.0.0\n"},
|
||||
})
|
||||
|
||||
ra := zipBytes(t, [][2]string{
|
||||
{"META-INF/MANIFEST.MF", "Manifest-Version: 1.0\n"},
|
||||
{"META-INF/ra.xml", "<connector/>\n"},
|
||||
{"example-lib-1.0.0.jar", string(lib)},
|
||||
{"META-INF/maven/org.example/example-ra/pom.properties", "groupId=org.example\nartifactId=example-ra\nversion=1.0.0\n"},
|
||||
})
|
||||
|
||||
archivePath := filepath.Join(destDir, "example-ra-1.0.0.rar")
|
||||
require.NoError(t, os.WriteFile(archivePath, ra, 0o600))
|
||||
return archivePath
|
||||
}
|
||||
|
||||
// zipBytes returns a zip archive holding the given (name, contents) entries, in order.
|
||||
func zipBytes(t *testing.T, entries [][2]string) []byte {
|
||||
var buf bytes.Buffer
|
||||
w := zip.NewWriter(&buf)
|
||||
for _, e := range entries {
|
||||
f, err := w.Create(e[0])
|
||||
require.NoError(t, err)
|
||||
_, err = f.Write([]byte(e[1]))
|
||||
require.NoError(t, err)
|
||||
}
|
||||
require.NoError(t, w.Close())
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user