Updates to scanner with CVE saving and auto update
This commit is contained in:
+75
-62
@@ -168,68 +168,6 @@ struct ContentView: View {
|
||||
Text("Docker assessment: \(result.dockerAuditStatus)").foregroundStyle(.secondary)
|
||||
dataSection("Docker coverage (PHP CLI not detected)", result.dockerCoverage)
|
||||
dataSection("Security triage — follow-up actions", result.securityTriage)
|
||||
VStack(alignment: .leading, spacing: 10) {
|
||||
Text("CVE assessment").font(.title2.bold())
|
||||
Text(result.cveAssessmentStatus).foregroundStyle(.secondary)
|
||||
Text("NVD identifies upstream candidates. Ubuntu advisory status is checked separately. A published fix does not prove that the installed package is patched.")
|
||||
.font(.caption).foregroundStyle(.secondary)
|
||||
if result.cveAssessments.isEmpty {
|
||||
Text("No upstream PHP CVE candidates recorded. This is not a clean security bill.")
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
ForEach(result.cveAssessments) { item in
|
||||
VStack(alignment: .leading, spacing: 5) {
|
||||
HStack {
|
||||
Link(item.cveID, destination: URL(string: item.referenceURL)!)
|
||||
.font(.headline)
|
||||
Text(item.severity).font(.caption.bold())
|
||||
Spacer()
|
||||
Text(item.status).foregroundStyle(.orange)
|
||||
}
|
||||
Text(item.runtime + " — " + item.summary).lineLimit(3)
|
||||
Text(item.evidence)
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
|
||||
if let vendorStatus = item.vendorStatus {
|
||||
|
||||
HStack(spacing: 8) {
|
||||
|
||||
Image(
|
||||
systemName:
|
||||
vendorStatus == "Not affected" ||
|
||||
vendorStatus == "Patched"
|
||||
? "checkmark.shield.fill"
|
||||
: vendorStatus == "Vulnerable"
|
||||
? "exclamationmark.shield.fill"
|
||||
: "shield.lefthalf.filled"
|
||||
)
|
||||
|
||||
Text("Vendor: " + vendorStatus)
|
||||
.font(.subheadline.bold())
|
||||
}
|
||||
.foregroundStyle(
|
||||
vendorStatus == "Not affected" ||
|
||||
vendorStatus == "Patched"
|
||||
? Color.green
|
||||
: vendorStatus == "Vulnerable"
|
||||
? Color.red
|
||||
: Color.orange
|
||||
)
|
||||
.padding(.top, 5)
|
||||
}
|
||||
|
||||
if let vendorEvidence = item.vendorEvidence {
|
||||
|
||||
Text(vendorEvidence)
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
.textSelection(.enabled)
|
||||
}
|
||||
}.padding(10)
|
||||
.background(.quaternary.opacity(0.22), in: RoundedRectangle(cornerRadius: 10))
|
||||
}
|
||||
}
|
||||
// Repository matching and binary verification are
|
||||
// separate from vendor CVE verification.
|
||||
VStack(alignment: .leading, spacing: 10) {
|
||||
@@ -305,6 +243,81 @@ struct ContentView: View {
|
||||
in: RoundedRectangle(cornerRadius: 10)
|
||||
)
|
||||
|
||||
VStack(alignment: .leading, spacing: 10) {
|
||||
Text("CVE assessment").font(.title2.bold())
|
||||
Text(result.cveAssessmentStatus).foregroundStyle(.secondary)
|
||||
Text("NVD identifies upstream candidates. Ubuntu advisory status is checked separately. A published fix does not prove that the installed package is patched.")
|
||||
.font(.caption).foregroundStyle(.secondary)
|
||||
if result.cveAssessments.isEmpty {
|
||||
Text("No upstream PHP CVE candidates recorded. This is not a clean security bill.")
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
ForEach(result.cveAssessments) { item in
|
||||
VStack(alignment: .leading, spacing: 5) {
|
||||
HStack {
|
||||
Link(item.cveID, destination: URL(string: item.referenceURL)!)
|
||||
.font(.headline)
|
||||
Text(item.severity).font(.caption.bold())
|
||||
Spacer()
|
||||
Text(item.status).foregroundStyle(.orange)
|
||||
}
|
||||
Text(item.runtime + " — " + item.summary)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
Text(item.evidence)
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
|
||||
if let vendorStatus = item.vendorStatus {
|
||||
|
||||
HStack(spacing: 8) {
|
||||
|
||||
Image(
|
||||
systemName:
|
||||
vendorStatus == "Not affected" ||
|
||||
vendorStatus == "Patched"
|
||||
? "checkmark.shield.fill"
|
||||
: vendorStatus == "Vulnerable"
|
||||
? "exclamationmark.shield.fill"
|
||||
: "shield.lefthalf.filled"
|
||||
)
|
||||
|
||||
Text("Vendor: " + vendorStatus)
|
||||
.font(.subheadline.bold())
|
||||
}
|
||||
.foregroundStyle(
|
||||
vendorStatus == "Not affected" ||
|
||||
vendorStatus == "Patched"
|
||||
? Color.green
|
||||
: vendorStatus == "Vulnerable"
|
||||
? Color.red
|
||||
: Color.orange
|
||||
)
|
||||
.padding(.top, 5)
|
||||
}
|
||||
|
||||
if let vendorEvidence = item.vendorEvidence,
|
||||
!vendorEvidence.hasPrefix(
|
||||
"Installed PHP package versions match official Ubuntu repository entries."
|
||||
) {
|
||||
|
||||
Text(vendorEvidence)
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.textSelection(.enabled)
|
||||
}
|
||||
}
|
||||
.padding(10)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.background(
|
||||
.quaternary.opacity(0.22),
|
||||
in: RoundedRectangle(cornerRadius: 10)
|
||||
)
|
||||
}
|
||||
}
|
||||
HStack {
|
||||
Text("Security findings").font(.title2.bold())
|
||||
Spacer()
|
||||
|
||||
@@ -393,35 +393,10 @@ extension VulnerabilityService {
|
||||
// may unlock vendor conclusions. Repository listings alone never qualify.
|
||||
line == "VERIFIED_INSTALLED_ORIGIN|ubuntu|" + report.ubuntuCodename
|
||||
}
|
||||
guard hasUbuntuOrigin else {
|
||||
return assessments.map { original in
|
||||
var item = original
|
||||
item.vendorStatus = "Unverified"
|
||||
let ubuntuMatches = report.packageOrigins.filter {
|
||||
$0.hasPrefix("UBUNTU_REPOSITORY_MATCH|")
|
||||
}
|
||||
|
||||
let otherMatches = report.packageOrigins.filter {
|
||||
$0.hasPrefix("OTHER_REPOSITORY_MATCH|")
|
||||
}
|
||||
|
||||
if !ubuntuMatches.isEmpty && otherMatches.isEmpty {
|
||||
item.vendorEvidence =
|
||||
"Installed PHP package versions match official Ubuntu repository entries. " +
|
||||
"Installed binary provenance has not been independently verified; " +
|
||||
"vendor CVE status remains Unverified."
|
||||
} else if !otherMatches.isEmpty {
|
||||
item.vendorEvidence =
|
||||
"One or more PHP package versions match third-party repositories. " +
|
||||
"Ubuntu vendor CVE status remains Unverified."
|
||||
} else {
|
||||
item.vendorEvidence =
|
||||
"Ubuntu archive provenance not established for installed PHP packages. " +
|
||||
"No confirmed Ubuntu repository matches were collected."
|
||||
}
|
||||
return item
|
||||
}
|
||||
}
|
||||
// Repository matching is sufficient to investigate Ubuntu
|
||||
// advisories, but not to certify installed binary integrity.
|
||||
// Advisory results remain Unverified unless independently
|
||||
// verified installed-package provenance is available.
|
||||
|
||||
let installed = installedPackages(report.packageSources)
|
||||
|
||||
@@ -496,6 +471,11 @@ extension VulnerabilityService {
|
||||
forHTTPHeaderField: "Accept"
|
||||
)
|
||||
|
||||
NSLog(
|
||||
"PHPGuard Ubuntu advisory: fetching %@",
|
||||
original.cveID
|
||||
)
|
||||
|
||||
let (data, response) =
|
||||
try await URLSession.shared.data(for: request)
|
||||
|
||||
@@ -714,6 +694,21 @@ extension VulnerabilityService {
|
||||
error.localizedDescription
|
||||
}
|
||||
|
||||
if !hasUbuntuOrigin {
|
||||
let advisoryStatus = item.vendorStatus ?? "Unverified"
|
||||
let advisoryEvidence = item.vendorEvidence ?? ""
|
||||
|
||||
item.vendorStatus = "Unverified"
|
||||
|
||||
item.vendorEvidence =
|
||||
"Ubuntu advisory assessment: " +
|
||||
advisoryStatus +
|
||||
". " +
|
||||
advisoryEvidence +
|
||||
"\\nInstalled binary provenance has not been independently verified; " +
|
||||
"this advisory result is not a confirmed host security verdict."
|
||||
}
|
||||
|
||||
output.append(item)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user