auditDependencies function
List<SbomIssue>
auditDependencies({
- required List<
DependencyEntry> entries, - required Map<
String, LicenseCategory> licenseByPackage, - required int nowMs,
- List<
VulnerabilityAdvisory> advisories = const [], - List<
SbomSuppression> suppressions = const [], - Set<
String> unpinnedPackages = const {},
Cross-checks entries against license classifications, an optional
advisories list, and pinnedOnly policy, returning every issue not
covered by an unexpired SbomSuppression.
licenseByPackage maps a hosted package's name to its
classifyLicenseText result — a package this map has no entry for
(e.g. its LICENSE file couldn't be read) is treated as
LicenseCategory.unknown, same as an empty/unparseable one.
Implementation
List<SbomIssue> auditDependencies({
required List<DependencyEntry> entries,
required Map<String, LicenseCategory> licenseByPackage,
required int nowMs,
List<VulnerabilityAdvisory> advisories = const [],
List<SbomSuppression> suppressions = const [],
Set<String> unpinnedPackages = const {},
}) {
bool suppressed(String package, SbomIssueKind kind) => suppressions.any(
(s) => s.package == package && s.kind == kind && s.expiresAtMs > nowMs,
);
final issues = <SbomIssue>[];
for (final entry in entries) {
if (entry.source != DependencySource.hosted) continue;
final category = licenseByPackage[entry.name] ?? LicenseCategory.unknown;
if (category == LicenseCategory.copyleft &&
!suppressed(entry.name, SbomIssueKind.copyleftLicense)) {
issues.add(
SbomIssue(
package: entry.name,
kind: SbomIssueKind.copyleftLicense,
severity: AdvisorySeverity.high,
detail:
'license copyleft (GPL/LGPL/AGPL họ) — cần review pháp lý trước khi publish',
),
);
} else if (category == LicenseCategory.unknown &&
!suppressed(entry.name, SbomIssueKind.unknownLicense)) {
issues.add(
SbomIssue(
package: entry.name,
kind: SbomIssueKind.unknownLicense,
severity: AdvisorySeverity.low,
detail:
'không xác định được license (thiếu LICENSE file hoặc không khớp header đã biết)',
),
);
}
}
for (final advisory in advisories) {
final match = entries.any(
(e) => e.name == advisory.package && e.version == advisory.version,
);
if (match && !suppressed(advisory.package, SbomIssueKind.vulnerability)) {
issues.add(
SbomIssue(
package: advisory.package,
kind: SbomIssueKind.vulnerability,
severity: advisory.severity,
detail: advisory.description,
),
);
}
}
for (final package in unpinnedPackages) {
if (!suppressed(package, SbomIssueKind.unpinnedConstraint)) {
issues.add(
SbomIssue(
package: package,
kind: SbomIssueKind.unpinnedConstraint,
severity: AdvisorySeverity.medium,
detail:
'pubspec.yaml không giới hạn version (any) — có thể resolve bất kỳ bản nào kể cả bản hỏng/độc hại',
),
);
}
}
return issues;
}