1616package junit
1717
1818import (
19+ "archive/tar"
1920 "archive/zip"
2021 "bufio"
22+ "compress/gzip"
2123 "errors"
2224 "fmt"
2325 "io"
2426 "io/fs"
2527 "net/http"
2628 "os"
27- "path/filepath"
2829 "strings"
2930
3031 "github.com/joshdk/go-junit"
@@ -51,9 +52,14 @@ func Ingest(filePath string) ([]junit.Suite, error) {
5152 mime := http .DetectContentType (buf )
5253 switch strings .Split (mime , ";" )[0 ] {
5354 case "application/zip" :
54- suites , err = ingestArchive (filePath )
55+ suites , err = ingestZipArchive (filePath )
5556 if err != nil {
56- return nil , fmt .Errorf ("could not ingest JUnit XML: %w" , err )
57+ return nil , fmt .Errorf ("could not ingest Zip archive : %w" , err )
58+ }
59+ case "application/x-gzip" :
60+ suites , err = ingestGzipArchive (filePath )
61+ if err != nil {
62+ return nil , fmt .Errorf ("could not ingest GZip archive: %w" , err )
5763 }
5864 case "text/xml" , "application/xml" :
5965 suites , err = junit .IngestFile (filePath )
@@ -70,52 +76,74 @@ func Ingest(filePath string) ([]junit.Suite, error) {
7076 return suites , nil
7177}
7278
73- func ingestArchive (filename string ) ([]junit.Suite , error ) {
74- archive , err := zip .OpenReader (filename )
79+ func ingestGzipArchive (filename string ) ([]junit.Suite , error ) {
80+ result := make ([]junit.Suite , 0 )
81+
82+ f , err := os .Open (filename )
7583 if err != nil {
76- return nil , fmt .Errorf ("could not open zip archive : %w" , err )
84+ return nil , fmt .Errorf ("can't open the file : %w" , err )
7785 }
78- defer archive .Close ()
79- dir , err := os .MkdirTemp ("" , "junit" )
86+ defer f .Close ()
87+
88+ // Decompress the file if possible
89+ uncompressedStream , err := gzip .NewReader (f )
8090 if err != nil {
81- return nil , fmt .Errorf ("could not create temporary directory : %w" , err )
91+ return nil , fmt .Errorf ("can't uncompress file, unexpected material type : %w" , err )
8292 }
83- for _ , zf := range archive .File {
84- if zf .FileInfo ().IsDir () {
85- continue
86- }
87- // extract file to dir
88- // nolint: gosec
89- path := filepath .Join (dir , zf .Name )
9093
91- // Check for ZipSlip (Directory traversal)
92- if ! strings .HasPrefix (path , filepath .Clean (dir )+ string (os .PathSeparator )) {
93- return nil , fmt .Errorf ("illegal file path: %s" , path )
94+ // Create a tar reader
95+ tarReader := tar .NewReader (uncompressedStream )
96+ for {
97+ header , err := tarReader .Next ()
98+ if err != nil {
99+ if errors .Is (err , io .EOF ) {
100+ // Reached the end of tar archive
101+ break
102+ }
103+ return nil , fmt .Errorf ("can't read tar header: %w" , err )
104+ }
105+ // Check if the file is a regular file
106+ if header .Typeflag != tar .TypeReg || ! strings .HasSuffix (header .Name , ".xml" ) {
107+ continue // Skip if it's not a regular file
94108 }
95109
96- f , err := os . Create ( path )
110+ suites , err := junit . IngestReader ( tarReader )
97111 if err != nil {
98- return nil , fmt .Errorf ("could not open file %s: %w" , path , err )
112+ return nil , fmt .Errorf ("can't ingest JUnit XML file %q: %w" , header .Name , err )
113+ }
114+ result = append (result , suites ... )
115+ }
116+
117+ return result , nil
118+ }
119+
120+ func ingestZipArchive (filename string ) ([]junit.Suite , error ) {
121+ result := make ([]junit.Suite , 0 )
122+
123+ archive , err := zip .OpenReader (filename )
124+ if err != nil {
125+ return nil , fmt .Errorf ("could not open zip archive: %w" , err )
126+ }
127+ defer archive .Close ()
128+
129+ for _ , zf := range archive .File {
130+ if zf .FileInfo ().IsDir () || ! strings .HasSuffix (zf .Name , ".xml" ) {
131+ continue
99132 }
100133
101134 rc , err := zf .Open ()
102135 if err != nil {
103- return nil , fmt .Errorf ("could not open file %s : %w" , path , err )
136+ return nil , fmt .Errorf ("could not open file %q : %w" , zf . Name , err )
104137 }
105138
106- _ , err = f . ReadFrom (rc )
139+ suites , err := junit . IngestReader (rc )
107140 if err != nil {
108- return nil , fmt .Errorf ("could not read file %s : %w" , path , err )
141+ return nil , fmt .Errorf ("could not ingest JUnit XML file %q : %w" , zf . Name , err )
109142 }
110143
111- rc . Close ( )
112- f .Close ()
144+ result = append ( result , suites ... )
145+ _ = rc .Close ()
113146 }
114147
115- suites , err := junit .IngestDir (dir )
116- if err != nil {
117- return nil , fmt .Errorf ("could not ingest JUnit XML: %w" , err )
118- }
119-
120- return suites , nil
148+ return result , nil
121149}
0 commit comments