Skip to content

Commit 552f32f

Browse files
committed
jar: support unconventional jar names
Signed-off-by: RTann <[email protected]>
1 parent 79e0035 commit 552f32f

File tree

6 files changed

+80
-32
lines changed

6 files changed

+80
-32
lines changed

java/jar/errors.go

+2-21
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,8 @@ type localError struct {
1111
msg string
1212
}
1313

14-
// These are sentinel errors that can be used with errors.Is.
15-
var (
16-
ErrUnidentified = errors.New("unidentified jar")
17-
ErrNotAJar = errors.New("does not seem to be a jar")
18-
)
14+
// ErrNotAJar is a sentinel error that can be used with errors.Is.
15+
var ErrNotAJar = errors.New("does not seem to be a jar")
1916

2017
func (e *localError) Error() string {
2118
switch {
@@ -45,22 +42,6 @@ func archiveErr(m srcPath, err error) *localError {
4542
}
4643
}
4744

48-
type errUnidentified struct {
49-
name string
50-
}
51-
52-
func unidentified(n string) *errUnidentified {
53-
return &errUnidentified{n}
54-
}
55-
56-
func (e *errUnidentified) Is(target error) bool {
57-
return target == ErrUnidentified || target == e
58-
}
59-
60-
func (e *errUnidentified) Error() string {
61-
return fmt.Sprintf("unidentified jar: %s", e.name)
62-
}
63-
6445
type errNotAJar struct {
6546
inner error
6647
name string

java/jar/jar.go

+6-5
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ func parse(ctx context.Context, name srcPath, z *zip.Reader) ([]Info, error) {
136136
default:
137137
return nil, archiveErr(name, err)
138138
}
139-
// As a last resort, just look at the name of the jar.
139+
// Try to learn something from the name of the jar if that fails.
140140
i, err = checkName(ctx, name.Cur())
141141
switch {
142142
case errors.Is(err, nil):
@@ -148,9 +148,11 @@ func parse(ctx context.Context, name srcPath, z *zip.Reader) ([]Info, error) {
148148
default:
149149
return nil, archiveErr(name, err)
150150
}
151-
// If we haven't jumped past this point, this is almost certainly not a jar,
152-
// so return an error.
153-
return nil, mkErr("", unidentified(base))
151+
152+
// At this point, we have yet to find anything other than the file
153+
// extension which can help confirm this is, in fact, a JAR.
154+
// We accept this, and continue to search through the non-standard JAR
155+
// in case we may find any valid inner JARs.
154156

155157
Finish:
156158
// Now, we need to examine any jars bundled in this jar.
@@ -308,7 +310,6 @@ func extractInner(ctx context.Context, p srcPath, z *zip.Reader) ([]Info, error)
308310
switch {
309311
case errors.Is(err, nil):
310312
case errors.Is(err, ErrNotAJar) ||
311-
errors.Is(err, ErrUnidentified) ||
312313
errors.Is(err, errInsaneManifest):
313314
zlog.Debug(ctx).
314315
Str("member", name).

java/jar/jar_test.go

+50-4
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,6 @@ func TestParse(t *testing.T) {
7070
switch {
7171
case errors.Is(err, nil):
7272
t.Log(ps)
73-
case errors.Is(err, ErrUnidentified):
74-
t.Log(err)
7573
case filepath.Base(h.Name) == "javax.inject-1.jar" && errors.Is(err, ErrNotAJar):
7674
// This is an odd one, it has no metadata.
7775
t.Log(err)
@@ -111,8 +109,6 @@ func TestWAR(t *testing.T) {
111109
for _, p := range ps {
112110
t.Log(p.String())
113111
}
114-
case errors.Is(err, ErrUnidentified):
115-
t.Error(err)
116112
default:
117113
t.Errorf("unexpected: %v", err)
118114
}
@@ -475,3 +471,53 @@ func TestManifestSectionReader(t *testing.T) {
475471
})
476472
}
477473
}
474+
475+
func TestInnerJar(t *testing.T) {
476+
name := filepath.Join("testdata", "inner", "inner.jar")
477+
rc, err := zip.OpenReader(name)
478+
if err != nil {
479+
t.Fatal(err)
480+
}
481+
t.Cleanup(func() {
482+
if err := rc.Close(); err != nil {
483+
t.Fatal(err)
484+
}
485+
})
486+
487+
ctx := zlog.Test(context.Background(), t)
488+
got, err := Parse(ctx, name, &rc.Reader)
489+
if err != nil {
490+
t.Fatal(err)
491+
}
492+
493+
if len(got) != 3 {
494+
t.Errorf("got %d entries, expected 3", len(got))
495+
}
496+
497+
// Ignore the SHA.
498+
for i := range got {
499+
got[i].SHA = nil
500+
}
501+
502+
want := []Info{
503+
{
504+
Name: "jackson-annotations",
505+
Version: "2.13.0",
506+
Source: ".",
507+
},
508+
{
509+
Name: "log4j-api",
510+
Version: "2.14",
511+
Source: ".",
512+
},
513+
{
514+
Name: "log4j",
515+
Version: "2.14.0",
516+
Source: ".",
517+
},
518+
}
519+
520+
if !cmp.Equal(got, want) {
521+
t.Error(cmp.Diff(got, want))
522+
}
523+
}

java/jar/testdata/inner/README.md

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
inner.jar looks as such:
2+
3+
inner.jar
4+
META-INF/
5+
MANIFEST.MF
6+
BOOT-INF/
7+
lib/
8+
jackson-annotations-2.13.0.jar
9+
META-INF/
10+
MANIFEST.MF
11+
log4j-api-2.14.jar
12+
META-INF/
13+
MANIFEST.MF
14+
inner-jar/
15+
something-invalid.jar
16+
META-INF/
17+
MANIFEST.MF
18+
log4j-2.14.0.jar
19+
META-INF/
20+
MANIFEST.MF

java/jar/testdata/inner/inner.jar

1.67 KB
Binary file not shown.

java/packagescanner.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ type Scanner struct {
7171
func (*Scanner) Name() string { return "java" }
7272

7373
// Version implements scanner.VersionedScanner.
74-
func (*Scanner) Version() string { return "6" }
74+
func (*Scanner) Version() string { return "7" }
7575

7676
// Kind implements scanner.VersionedScanner.
7777
func (*Scanner) Kind() string { return "package" }
@@ -185,7 +185,7 @@ func (s *Scanner) Scan(ctx context.Context, layer *claircore.Layer) ([]*claircor
185185
infos, err := jar.Parse(ctx, n, z)
186186
switch {
187187
case err == nil:
188-
case errors.Is(err, jar.ErrUnidentified) || errors.Is(err, jar.ErrNotAJar):
188+
case errors.Is(err, jar.ErrNotAJar):
189189
// If there's an error that's one of the "known" reasons (e.g. not a
190190
// read error or a malformed file), just log it and continue on.
191191
zlog.Info(ctx).

0 commit comments

Comments
 (0)