Restructure solution layout by module
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using StellaOps.Scanner.Analyzers.OS;
|
||||
using StellaOps.Scanner.Analyzers.OS.Abstractions;
|
||||
using StellaOps.Scanner.Analyzers.OS.Analyzers;
|
||||
using StellaOps.Scanner.Analyzers.OS.Helpers;
|
||||
|
||||
namespace StellaOps.Scanner.Analyzers.OS.Apk;
|
||||
|
||||
internal sealed class ApkPackageAnalyzer : OsPackageAnalyzerBase
|
||||
{
|
||||
private static readonly IReadOnlyList<OSPackageRecord> EmptyPackages =
|
||||
new ReadOnlyCollection<OSPackageRecord>(System.Array.Empty<OSPackageRecord>());
|
||||
|
||||
private readonly ApkDatabaseParser _parser = new();
|
||||
|
||||
public ApkPackageAnalyzer(ILogger<ApkPackageAnalyzer> logger)
|
||||
: base(logger)
|
||||
{
|
||||
}
|
||||
|
||||
public override string AnalyzerId => "apk";
|
||||
|
||||
protected override ValueTask<IReadOnlyList<OSPackageRecord>> ExecuteCoreAsync(OSPackageAnalyzerContext context, CancellationToken cancellationToken)
|
||||
{
|
||||
var installedPath = Path.Combine(context.RootPath, "lib", "apk", "db", "installed");
|
||||
if (!File.Exists(installedPath))
|
||||
{
|
||||
Logger.LogInformation("Apk installed database not found at {Path}; skipping analyzer.", installedPath);
|
||||
return ValueTask.FromResult<IReadOnlyList<OSPackageRecord>>(EmptyPackages);
|
||||
}
|
||||
|
||||
using var stream = File.OpenRead(installedPath);
|
||||
var entries = _parser.Parse(stream, cancellationToken);
|
||||
|
||||
var records = new List<OSPackageRecord>(entries.Count);
|
||||
foreach (var entry in entries)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(entry.Name) ||
|
||||
string.IsNullOrWhiteSpace(entry.Version) ||
|
||||
string.IsNullOrWhiteSpace(entry.Architecture))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var versionParts = PackageVersionParser.ParseApkVersion(entry.Version);
|
||||
var purl = PackageUrlBuilder.BuildAlpine(entry.Name, entry.Version, entry.Architecture);
|
||||
|
||||
var vendorMetadata = new Dictionary<string, string?>(StringComparer.Ordinal)
|
||||
{
|
||||
["origin"] = entry.Origin,
|
||||
["description"] = entry.Description,
|
||||
["homepage"] = entry.Url,
|
||||
["maintainer"] = entry.Maintainer,
|
||||
["checksum"] = entry.Checksum,
|
||||
["buildTime"] = entry.BuildTime,
|
||||
};
|
||||
|
||||
foreach (var pair in entry.Metadata)
|
||||
{
|
||||
vendorMetadata[$"apk:{pair.Key}"] = pair.Value;
|
||||
}
|
||||
|
||||
var files = new List<OSPackageFileEvidence>(entry.Files.Count);
|
||||
foreach (var file in entry.Files)
|
||||
{
|
||||
files.Add(new OSPackageFileEvidence(
|
||||
file.Path,
|
||||
layerDigest: null,
|
||||
sha256: file.Digest,
|
||||
sizeBytes: null,
|
||||
isConfigFile: file.IsConfig));
|
||||
}
|
||||
|
||||
var cveHints = CveHintExtractor.Extract(
|
||||
string.Join(' ', entry.Depends),
|
||||
string.Join(' ', entry.Provides));
|
||||
|
||||
var record = new OSPackageRecord(
|
||||
AnalyzerId,
|
||||
purl,
|
||||
entry.Name,
|
||||
versionParts.BaseVersion,
|
||||
entry.Architecture,
|
||||
PackageEvidenceSource.ApkDatabase,
|
||||
epoch: null,
|
||||
release: versionParts.Release,
|
||||
sourcePackage: entry.Origin,
|
||||
license: entry.License,
|
||||
cveHints: cveHints,
|
||||
provides: entry.Provides,
|
||||
depends: entry.Depends,
|
||||
files: files,
|
||||
vendorMetadata: vendorMetadata);
|
||||
|
||||
records.Add(record);
|
||||
}
|
||||
|
||||
records.Sort();
|
||||
return ValueTask.FromResult<IReadOnlyList<OSPackageRecord>>(records);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user