+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.ce.task.projectanalysis.step;
-
-import java.util.List;
-import java.util.Set;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.RegisterExtension;
-import org.sonar.api.utils.System2;
-import org.sonar.ce.task.projectanalysis.batch.BatchReportReaderRule;
-import org.sonar.ce.task.step.TestComputationStepContext;
-import org.sonar.core.util.UuidFactory;
-import org.sonar.core.util.UuidFactoryImpl;
-import org.sonar.db.DbClient;
-import org.sonar.db.DbSession;
-import org.sonar.db.DbTester;
-import org.sonar.db.dependency.CveCweDto;
-import org.sonar.db.dependency.CveDto;
-import org.sonar.scanner.protocol.output.ScannerReport.Cve;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.fail;
-
-class PersistCveStepIT {
-
- @RegisterExtension
- private final DbTester db = DbTester.create(System2.INSTANCE);
-
- @RegisterExtension
- private final BatchReportReaderRule batchReportReader = new BatchReportReaderRule();
-
- private final DbSession dbSession = db.getSession();
- private final DbClient dbClient = db.getDbClient();
- private final UuidFactory uuidFactory = UuidFactoryImpl.INSTANCE;
-
- private PersistCveStep persistCveStep;
-
- @BeforeEach
- void setUp() {
- persistCveStep = new PersistCveStep(batchReportReader, dbClient, uuidFactory, System2.INSTANCE);
- }
-
- @Test
- void getDescription_shouldReturnStepDescription() {
- assertThat(persistCveStep.getDescription()).isEqualTo("Persist CVEs");
- }
-
- @Test
- void execute_shouldInsertNewCVEs() {
- Cve cve1 = buildCve("1").build();
- Cve cve2 = buildCve("2").build();
- Cve cveAllOptionalEmpty = Cve.newBuilder().setCveId("CVE-empty").setDescription("Empty CVE").build();
- batchReportReader.putCves(List.of(cve1, cve2, cveAllOptionalEmpty));
-
- persistCveStep.execute(new TestComputationStepContext());
-
- assertCvePersistedInDatabase(cve1);
- assertCvePersistedInDatabase(cve2);
- assertCvePersistedInDatabase(cveAllOptionalEmpty);
- }
-
- private void assertCvePersistedInDatabase(Cve cve) {
- CveDto cveDto = dbClient.cveDao().selectById(dbSession, cve.getCveId())
- .orElseGet(() -> fail(String.format("CVE with id %s not found", cve.getCveId())));
- assertThat(cveDto.id()).isEqualTo(cve.getCveId());
- assertThat(cveDto.description()).isEqualTo(cve.getDescription());
- if (cve.hasCvssScore()) {
- assertThat(cveDto.cvssScore()).isEqualTo(cve.getCvssScore());
- } else {
- assertThat(cveDto.cvssScore()).isNull();
- }
- if (cve.hasEpssScore()) {
- assertThat(cveDto.epssScore()).isEqualTo(cve.getEpssScore());
- } else {
- assertThat(cveDto.epssScore()).isNull();
- }
- if (cve.hasEpssPercentile()) {
- assertThat(cveDto.epssPercentile()).isEqualTo(cve.getEpssPercentile());
- } else {
- assertThat(cveDto.epssPercentile()).isNull();
- }
- if (cve.hasPublishedDate()) {
- assertThat(cveDto.publishedAt()).isEqualTo(cve.getPublishedDate());
- } else {
- assertThat(cveDto.publishedAt()).isNull();
- }
- if (cve.hasLastModifiedDate()) {
- assertThat(cveDto.lastModifiedAt()).isEqualTo(cve.getLastModifiedDate());
- } else {
- assertThat(cveDto.lastModifiedAt()).isNull();
- }
- assertThat(cveDto.uuid()).isNotBlank();
- assertThat(cveDto.createdAt()).isNotNull();
- assertThat(cveDto.updatedAt()).isNotNull();
- }
-
- @Test
- void execute_shoudUpdateExistingCves() {
- dbClient.cveDao().insert(dbSession, new CveDto("cve-uuid-1", "CVE-1", "Old description 1", 10.0, 20.0, 30.0, 0L, 0L, 0L, 0L));
- dbClient.cveDao().insert(dbSession, new CveDto("cve-uuid-2", "CVE-2", "Old description 2", null, null, null, null, null, 0L, 0L));
- db.commit();
- Cve cve1 = buildCve("1").build();
- Cve cve2 = buildCve("2").build();
- batchReportReader.putCves(List.of(cve1, cve2));
-
- persistCveStep.execute(new TestComputationStepContext());
-
- assertThat(db.countRowsOfTable(dbSession, "cves")).isEqualTo(2);
- assertCvePersistedInDatabase(cve1);
- assertCvePersistedInDatabase(cve2);
- }
-
- @Test
- void execute_shouldInsertCwes_whenNewCVEs() {
- Cve cve1 = buildCve("1").addCwe("CWE-11").addCwe("CWE-12").build();
- Cve cve2 = buildCve("2").addCwe("CWE-11").build();
- batchReportReader.putCves(List.of(cve1, cve2));
-
- persistCveStep.execute(new TestComputationStepContext());
-
- assertCveHasExactlyCwes(cve1, "CWE-11", "CWE-12");
- assertCveHasExactlyCwes(cve2, "CWE-11");
- }
-
- @Test
- void execute_shouldUpdateExistingCwesAndInsertNewOnes_whenUpdatingCVEs() {
- dbClient.cveDao().insert(dbSession, new CveDto("cve-uuid-1", "CVE-1", "Old description 1", 0.0, 0.0, 0.0, 0L, 0L, 0L, 0L));
- dbClient.cveCweDao().insert(dbSession, new CveCweDto("cve-uuid-1", "CWE-1"));
- dbClient.cveCweDao().insert(dbSession, new CveCweDto("cve-uuid-1", "CWE-2"));
- db.commit();
- Cve cve = buildCve("1").addCwe("CWE-2").addCwe("CWE-3").build();
- batchReportReader.putCves(List.of(cve));
-
- persistCveStep.execute(new TestComputationStepContext());
-
- assertCveHasExactlyCwes(cve, "CWE-2", "CWE-3");
- }
-
- private void assertCveHasExactlyCwes(Cve cve, String... cwes) {
- Set<String> cweInDb = dbClient.cveCweDao().selectByCveUuid(dbSession, getCveUuid(cve.getCveId()));
- assertThat(cweInDb).containsExactlyInAnyOrder(cwes);
- }
-
- private String getCveUuid(String cveId) {
- return dbClient.cveDao().selectById(dbSession, cveId)
- .map(CveDto::uuid)
- .orElseGet(() -> fail("CVE not found"));
- }
-
- private static Cve.Builder buildCve(String suffix) {
- return Cve.newBuilder()
- .setCveId("CVE-"+suffix)
- .setCvssScore(7.5F)
- .setEpssScore(0.1F)
- .setEpssPercentile(0.4F)
- .setDescription("Some CVE description "+suffix)
- .setLastModifiedDate(5L)
- .setPublishedDate(4L);
- }
-}
CloseableIterator<ScannerReport.AnalysisWarning> readAnalysisWarnings();
- CloseableIterator<ScannerReport.Cve> readCves();
-
CloseableIterator<ScannerReport.TelemetryEntry> readTelemetryEntries();
CloseableIterator<ScannerReport.Dependency> readDependencies();
return delegate.readAnalysisWarnings();
}
- @Override
- public CloseableIterator<ScannerReport.Cve> readCves() {
- ensureInitialized();
- return delegate.readCves();
- }
-
@Override
public CloseableIterator<ScannerReport.TelemetryEntry> readTelemetryEntries() {
ensureInitialized();
}
issue.setIsFromExternalRuleEngine(true);
issue.setLocations(dbLocationsBuilder.build());
- if (reportExternalIssue.hasCveId()) {
- issue.setCveId(reportExternalIssue.getCveId());
- }
return issue;
}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.ce.task.projectanalysis.step;
-
-import java.util.HashSet;
-import java.util.Set;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.sonar.api.utils.System2;
-import org.sonar.ce.task.projectanalysis.batch.BatchReportReader;
-import org.sonar.ce.task.step.ComputationStep;
-import org.sonar.core.util.CloseableIterator;
-import org.sonar.core.util.UuidFactory;
-import org.sonar.db.DbClient;
-import org.sonar.db.DbSession;
-import org.sonar.db.dependency.CveCweDto;
-import org.sonar.db.dependency.CveDto;
-import org.sonar.scanner.protocol.output.ScannerReport;
-
-/**
- * Step that persists CVEs and their CWEs in the database.
- * CVEs are inserted or updated in the database based on the information from the scanner report.
- * If CWEs need to be updated, we simply remove all CWEs from the CVE and insert what is sent by the scanner.
- */
-public class PersistCveStep implements ComputationStep {
-
- private static final Logger LOG = LoggerFactory.getLogger(PersistCveStep.class);
-
- private final BatchReportReader batchReportReader;
- private final DbClient dbClient;
- private final UuidFactory uuidFactory;
- private final System2 system2;
-
- public PersistCveStep(BatchReportReader batchReportReader, DbClient dbClient, UuidFactory uuidFactory, System2 system2) {
- this.batchReportReader = batchReportReader;
- this.dbClient = dbClient;
- this.uuidFactory = uuidFactory;
- this.system2 = system2;
- }
-
- @Override
- public String getDescription() {
- return "Persist CVEs";
- }
-
- @Override
- public void execute(Context context) {
- int count = 0;
- try (DbSession dbSession = dbClient.openSession(false);
- CloseableIterator<ScannerReport.Cve> batchCves = batchReportReader.readCves()) {
- while (batchCves.hasNext()) {
- updateOrInsertCve(dbSession, batchCves.next());
- count++;
- }
- LOG.debug("{} CVEs were imported/updated", count);
- dbSession.commit();
- } catch (Exception exception) {
- throw new IllegalStateException(String.format("CVEs import failed after processing %d CVEs successfully", count), exception);
- }
- }
-
- private void updateOrInsertCve(DbSession dbSession, ScannerReport.Cve scannerCve) {
- dbClient.cveDao().selectById(dbSession, scannerCve.getCveId())
- .ifPresentOrElse(
- cveDto -> updateCve(dbSession, cveDto, scannerCve),
- () -> insertCve(dbSession, scannerCve));
- }
-
- private void updateCve(DbSession dbSession, CveDto cveInDb, ScannerReport.Cve scannerCve) {
- CveDto dtoForUpdate = toDtoForUpdate(scannerCve, cveInDb);
- dbClient.cveDao().update(dbSession, dtoForUpdate);
- String cveUuid = cveInDb.uuid();
- deleteThenInsertCwesIfUpdated(dbSession, scannerCve, cveUuid);
- }
-
- private CveDto toDtoForUpdate(ScannerReport.Cve cve, CveDto cveInDb) {
- return toDto(cve, cveInDb.uuid(), cveInDb.createdAt(), system2.now());
- }
-
- private void deleteThenInsertCwesIfUpdated(DbSession dbSession, ScannerReport.Cve scannerCve, String cveUuid) {
- Set<String> cweInDb = dbClient.cveCweDao().selectByCveUuid(dbSession, cveUuid);
- Set<String> cweFromReport = new HashSet<>(scannerCve.getCweList());
- if (!cweInDb.equals(cweFromReport)) {
- dbClient.cveCweDao().deleteByCveUuid(dbSession, cveUuid);
- cweFromReport.forEach(cwe -> dbClient.cveCweDao().insert(dbSession, new CveCweDto(cveUuid, cwe)));
- }
- }
-
- private void insertCve(DbSession dbSession, ScannerReport.Cve scannerCve) {
- CveDto dtoForInsert = toDtoForInsert(scannerCve);
- dbClient.cveDao().insert(dbSession, dtoForInsert);
- scannerCve.getCweList().forEach(cwe -> dbClient.cveCweDao().insert(dbSession, new CveCweDto(dtoForInsert.uuid(), cwe)));
- }
-
- private CveDto toDtoForInsert(ScannerReport.Cve cve) {
- long now = system2.now();
- return toDto(cve, uuidFactory.create(), now, now);
- }
-
- private static CveDto toDto(ScannerReport.Cve cve, String uuid, Long createdAt, Long updatedAt) {
- return new CveDto(
- uuid,
- cve.getCveId(),
- cve.getDescription(),
- cve.hasCvssScore() ? cve.getCvssScore() : null,
- cve.hasEpssScore() ? cve.getEpssScore() : null,
- cve.hasEpssPercentile() ? cve.getEpssPercentile() : null,
- cve.hasPublishedDate() ? cve.getPublishedDate() : null,
- cve.hasLastModifiedDate() ? cve.getLastModifiedDate() : null,
- createdAt,
- updatedAt);
- }
-
-}
PersistProjectMeasuresStep.class,
PersistMeasuresStep.class,
PersistAdHocRulesStep.class,
- PersistCveStep.class,
PersistIssuesStep.class,
CleanIssueChangesStep.class,
PersistProjectLinksStep.class,
import org.sonar.core.util.CloseableIterator;
import org.sonar.scanner.protocol.output.FileStructure;
import org.sonar.scanner.protocol.output.ScannerReport;
-import org.sonar.scanner.protocol.output.ScannerReport.Cve;
import org.sonar.scanner.protocol.output.ScannerReportWriter;
import static com.google.common.collect.ImmutableList.of;
assertThat(res).toIterable().containsExactlyElementsOf(warnings);
res.close();
}
-
- @Test
- public void readCves_shouldReturnCves() {
- Cve cve1 = builCve("1").build();
- writer.appendCve(cve1);
- Cve cve2 = builCve("2").build();
- writer.appendCve(cve2);
-
- CloseableIterator<Cve> cveCloseableIterator = underTest.readCves();
-
- assertThat(cveCloseableIterator).toIterable().containsExactlyInAnyOrder(cve1, cve2);
- }
-
- private Cve.Builder builCve(String suffix) {
- return Cve.newBuilder()
- .setCveId("CVE-" + suffix)
- .addCwe("CWE-" + suffix)
- .setDescription("Some CVE description " + suffix)
- .setCvssScore(7.5F)
- .setEpssScore(0.1F)
- .setEpssPercentile(0.1F)
- .setLastModifiedDate(1L)
- .setPublishedDate(2L);
- }
}
private Map<Integer, ScannerReport.ChangedLines> changedLines = new HashMap<>();
private List<ScannerReport.AnalysisWarning> analysisWarnings = Collections.emptyList();
private byte[] analysisCache;
- private List<ScannerReport.Cve> cves = new ArrayList<>();
private List<ScannerReport.TelemetryEntry> telemetryEntries = new ArrayList<>();
private List<ScannerReport.Dependency> dependencies = new ArrayList<>();
clear();
}
- @Override
- public CloseableIterator<ScannerReport.Cve> readCves() {
- return CloseableIterator.from(cves.iterator());
- }
-
@Override
public CloseableIterator<ScannerReport.TelemetryEntry> readTelemetryEntries() {
return CloseableIterator.from(telemetryEntries.iterator());
return this;
}
- public BatchReportReaderRule putCves(List<ScannerReport.Cve> cves) {
- this.cves = cves;
- return this;
- }
-
@Override
public CloseableIterator<ScannerReport.Dependency> readDependencies() {
return CloseableIterator.from(dependencies.iterator());
private RuleType type;
private String engineId;
private String ruleId;
- private String cveId;
private Map<SoftwareQuality, org.sonar.api.issue.impact.Severity> impacts = new EnumMap<>(SoftwareQuality.class);
private CleanCodeAttribute cleanCodeAttribute;
return ruleId;
}
- public String cveId() {
- return cveId;
- }
-
@Override
public Severity severity() {
return this.severity;
return this;
}
- public NewExternalIssue cveId(String cveId) {
- this.cveId = cveId;
- return this;
- }
-
@Override
public DefaultExternalIssue forRule(RuleKey ruleKey) {
this.engineId = ruleKey.repository();
import org.sonar.api.batch.sensor.issue.Issue.Flow;
import org.sonar.api.batch.sensor.issue.MessageFormatting;
import org.sonar.api.batch.sensor.issue.NewIssue.FlowType;
-import org.sonar.api.batch.sensor.issue.internal.DefaultExternalIssue;
import org.sonar.api.batch.sensor.issue.internal.DefaultIssueFlow;
import org.sonar.api.issue.impact.SoftwareQuality;
import org.sonar.api.rules.CleanCodeAttribute;
TextRange primaryTextRange = issue.primaryLocation().textRange();
// nullable fields
- var cveId = ((DefaultExternalIssue) issue).cveId();
- if (cveId != null) {
- builder.setCveId(cveId);
- }
CleanCodeAttribute cleanCodeAttribute = issue.cleanCodeAttribute();
if (cleanCodeAttribute != null) {
builder.setCleanCodeAttribute(cleanCodeAttribute.name());
return readFromReport(ScannerReportReader::readAdHocRules);
}
- public List<ScannerReport.Cve> cves() {
- return readFromReport(ScannerReportReader::readCves);
- }
-
public List<ScannerReport.Dependency> dependencies() {
return readFromReport(ScannerReportReader::readDependencies);
}
return new File(dir, "adhocrules.pb");
}
- public File cves() {
- return new File(dir, "cves.pb");
- }
-
public File fileFor(Domain domain, int componentRef) {
return new File(dir, domain.filePrefix + componentRef + domain.fileSuffix);
}
return Protobuf.readStream(file, ScannerReport.AdHocRule.parser());
}
- public CloseableIterator<ScannerReport.Cve> readCves() {
- File file = fileStructure.cves();
- if (!fileExists(file)) {
- return emptyCloseableIterator();
- }
- return Protobuf.readStream(file, ScannerReport.Cve.parser());
- }
-
public CloseableIterator<ScannerReport.Measure> readComponentMeasures(int componentRef) {
File file = fileStructure.fileFor(FileStructure.Domain.MEASURES, componentRef);
if (fileExists(file)) {
appendDelimitedTo(file, adHocRule, "ad hoc rule");
}
- public void appendCve(ScannerReport.Cve cve) {
- File file = fileStructure.cves();
- appendDelimitedTo(file, cve, "cve");
- }
-
public void appendComponentMeasure(int componentRef, ScannerReport.Measure measure) {
File file = fileStructure.fileFor(FileStructure.Domain.MEASURES, componentRef);
appendDelimitedTo(file, measure, "measure");
private JEditorPane activeRuleEditor;
private JScrollPane adHocRuleTab;
private JEditorPane adHocRuleEditor;
- private JScrollPane cveTab;
- private JEditorPane cveEditor;
private JScrollPane qualityProfileTab;
private JEditorPane qualityProfileEditor;
private JScrollPane pluginTab;
loadComponents();
updateActiveRules();
updateAdHocRules();
- updateCves();
updateQualityProfiles();
updatePlugins();
updateMetadata();
}
}
- private void updateCves() {
- cveEditor.setText("");
-
- StringBuilder builder = new StringBuilder();
- try (CloseableIterator<ScannerReport.Cve> cveCloseableIterator = reader.readCves()) {
- while (cveCloseableIterator.hasNext()) {
- builder.append(cveCloseableIterator.next().toString()).append("\n");
- }
- cveEditor.setText(builder.toString());
- }
- }
-
private void updateQualityProfiles() {
qualityProfileEditor.setText("");
adHocRuleEditor = new JEditorPane();
adHocRuleTab.setViewportView(adHocRuleEditor);
- cveTab = new JScrollPane();
- tabbedPane.addTab("CVEs", null, cveTab, null);
-
- cveEditor = new JEditorPane();
- cveTab.setViewportView(cveEditor);
-
qualityProfileTab = new JScrollPane();
tabbedPane.addTab("Quality Profiles", null, qualityProfileTab, null);
string rule_repository = 1;
string rule_key = 2;
Severity severity = 3;
- map<string,string> params_by_key = 4;
+ map<string, string> params_by_key = 4;
int64 createdAt = 5;
int64 updatedAt = 6;
string q_profile_key = 7;
enum ComponentType {
UNSET = 0;
PROJECT = 1;
- MODULE = 2 [deprecated=true];
- DIRECTORY = 3 [deprecated=true];
+ MODULE = 2 [deprecated = true];
+ DIRECTORY = 3 [deprecated = true];
FILE = 4;
}
repeated MessageFormatting msgFormatting = 9;
repeated Impact impacts = 10;
optional string cleanCodeAttribute = 11;
- optional string cve_id = 12;
}
message AdHocRule {
- string engine_id = 1;
- string rule_id = 2;
- string name = 3;
- string description = 4;
+ string engine_id = 1;
+ string rule_id = 2;
+ string name = 3;
+ string description = 4;
optional Severity severity = 5;
optional IssueType type = 6;
optional string cleanCodeAttribute = 7;
repeated Impact defaultImpacts = 8;
}
-message Cve {
- string cve_id = 1;
- string description = 2;
- optional double cvss_score = 3;
- optional double epss_score = 4;
- optional double epss_percentile = 5;
- optional int64 published_date = 6;
- optional int64 last_modified_date = 7;
- repeated string cwe = 8;
-}
-
enum IssueType {
UNSET = 0;
CODE_SMELL = 1;
import com.google.common.collect.Iterators;
import java.io.File;
-import java.time.Instant;
import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
}
}
- @Test
- void write_cve() {
- ScannerReport.Cve cve = ScannerReport.Cve.newBuilder()
- .setCveId("CVE-2023-20863")
- .setDescription("In spring framework versions prior to 5.2.24 release+ ,5.3.27+ and 6.0.8+ , it is possible for a user to provide a" +
- " specially crafted SpEL expression that may cause a denial-of-service (DoS) condition.")
- .setCvssScore(6.5f)
- .setEpssScore(0.00306f)
- .setEpssPercentile(0.70277f)
- .setPublishedDate(Instant.parse("2023-04-13T20:15:00Z").toEpochMilli())
- .setLastModifiedDate(Instant.parse("2024-02-04T02:22:24.474Z").toEpochMilli())
- .addCwe("CWE-400")
- .build();
- underTest.appendCve(cve);
-
- File file = underTest.getFileStructure().cves();
- assertThat(file).exists().isFile();
- try (CloseableIterator<ScannerReport.Cve> read = Protobuf.readStream(file, ScannerReport.Cve.parser())) {
- assertThat(Iterators.size(read)).isOne();
- }
- }
-
@Test
void write_changed_lines() {
assertThat(underTest.hasComponentData(FileStructure.Domain.CHANGED_LINES, 1)).isFalse();
underTest.writeTelemetry(input);
- try (CloseableIterator<ScannerReport.TelemetryEntry> telemetryIterator =
- Protobuf.readStream(underTest.getFileStructure().telemetryEntries(), ScannerReport.TelemetryEntry.parser())) {
+ try (CloseableIterator<ScannerReport.TelemetryEntry> telemetryIterator = Protobuf.readStream(underTest.getFileStructure().telemetryEntries(),
+ ScannerReport.TelemetryEntry.parser())) {
assertThat(telemetryIterator).toIterable()
.containsExactlyElementsOf(input)