diff --git a/internal/analyse/analyse.go b/internal/analyse/analyse.go index fee0d3f..75a6ced 100644 --- a/internal/analyse/analyse.go +++ b/internal/analyse/analyse.go @@ -16,8 +16,10 @@ import ( type NoteLevel string const ( - NoteLevelWarn NoteLevel = "warn" - NoteLevelError NoteLevel = "error" + NoteLevelWarn NoteLevel = "warn" + NoteLevelError NoteLevel = "error" + fingerprintHeader = "SHA-256 Fingerprint" + commentsHeader = "Comments" ) type Note struct { @@ -53,20 +55,46 @@ func downloadMozillaRemovedCACertsList() ([]removedCertificate, error) { return nil, err } csvReader := csv.NewReader(resp.Body) - csvLines, err := csvReader.ReadAll() + // Read the header first + headers, err := csvReader.Read() if err != nil { return nil, err } - removedCerts := make([]removedCertificate, len(csvLines)) - for i, csvLine := range csvLines { - removedCerts[i] = removedCertificate{ - // From the CSV format that Mozilla publishes, the 8th column (id 7) is the fingerprint and the 23rd column - // (id 22) is the comment. - Fingerprint: csvLine[7], - Comments: csvLine[22], + // Find column indices by their names from the header + fingerprint := -1 + comments := -1 + for idx, header := range headers { + switch header { + case fingerprintHeader: + fingerprint = idx + case commentsHeader: + comments = idx } } + + if fingerprint == -1 { + return nil, fmt.Errorf("required column 'SHA-256 Fingerprint' not found in CSV header") + } + if comments == -1 { + return nil, fmt.Errorf("required column 'Comments' not found in CSV header") + } + + // Now process each line individually instead of loading everything into memory + var removedCerts []removedCertificate + for { + record, err := csvReader.Read() + if err != nil { + break // End of file or other error + } + + removedCerts = append(removedCerts, removedCertificate{ + Fingerprint: record[fingerprint], + Comments: record[comments], + }) + } + + // All CSV processing is done in the loop above, we already have the removedCerts slice return removedCerts, nil }