Updates to scanner

This commit is contained in:
Mark Gregory
2026-10-22 12:44:24 +01:00
parent f2f0ee10e2
commit 9970beadaf
7 changed files with 124 additions and 14 deletions
+16
View File
@@ -6,6 +6,10 @@ import SwiftUI
@Published var results: [AuditResult] = [] { didSet { saveResults() } }
@Published var scanning: Set<UUID> = []
@Published var lastError: String?
@Published var discoveredCVEs: [CVERecord] = []
@Published var cveLastChecked: Date?
@Published var cveError: String?
@Published var fetchingCVEs = false
private var folder: URL {
let base = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)[0]
@@ -43,6 +47,18 @@ import SwiftUI
}
}
func scanAll() { servers.forEach { scan($0) } }
func refreshCVEs() {
guard !fetchingCVEs else { return }
fetchingCVEs = true
cveError = nil
Task {
defer { fetchingCVEs = false }
do {
discoveredCVEs = try await VulnerabilityService.discover()
cveLastChecked = Date()
} catch { cveError = error.localizedDescription }
}
}
func export(_ result: AuditResult) {
let panel = NSSavePanel()
panel.allowedContentTypes = [.json]
+30 -1
View File
@@ -31,6 +31,7 @@ struct ContentView: View {
}
}
Section("Navigation") {
Label("CVE research", systemImage: "shield.lefthalf.filled").tag(UUID(uuidString: "00000000-0000-0000-0000-000000000002")!)
Label("Scan history", systemImage: "clock.arrow.circlepath").tag(UUID(uuidString: "00000000-0000-0000-0000-000000000001")!)
}
}
@@ -39,7 +40,9 @@ struct ContentView: View {
Button { editing = nil; showingEditor = true } label: { Image(systemName: "plus") }.help("Add server")
}
} detail: {
if selection == UUID(uuidString: "00000000-0000-0000-0000-000000000001") {
if selection == UUID(uuidString: "00000000-0000-0000-0000-000000000002") {
cveView
} else if selection == UUID(uuidString: "00000000-0000-0000-0000-000000000001") {
historyView
} else if let server = store.servers.first(where: { $0.id == selection }) {
serverView(server)
@@ -125,6 +128,32 @@ struct ContentView: View {
else { ForEach(values, id: \.self) { Text($0).font(.system(.body, design: .monospaced)).textSelection(.enabled) } }
}
}
private var cveView: some View {
VStack(alignment: .leading, spacing: 14) {
HStack {
Text("PHP CVE research").font(.largeTitle.bold())
Spacer()
if store.fetchingCVEs { ProgressView() }
Button("Refresh from NVD") { store.refreshCVEs() }.disabled(store.fetchingCVEs)
}
Text("Research candidates from the NVD keyword index. These records are NOT matched to installed PHP versions, Ubuntu backports or Docker images. Do not interpret them as confirmed server vulnerabilities.")
.foregroundStyle(.secondary)
if let date = store.cveLastChecked { Text("Last fetched: \(date.formatted())").foregroundStyle(.secondary) }
if let error = store.cveError { Text(error).foregroundStyle(.red) }
List(store.discoveredCVEs) { cve in
VStack(alignment: .leading, spacing: 6) {
HStack {
Link(cve.id, destination: URL(string: cve.referenceURL)!)
.font(.headline)
Spacer()
Text(cve.severity + (cve.score.map { " (\($0))" } ?? ""))
Text(String(cve.published.prefix(10))).foregroundStyle(.secondary)
}
Text(cve.description).lineLimit(4).textSelection(.enabled)
}.padding(.vertical, 5)
}
}.padding(24)
}
private var historyView: some View {
List(store.results) { result in
HStack {
+10
View File
@@ -35,3 +35,13 @@ struct AuditResult: Codable, Identifiable {
var rawOutput = ""
var error: String? = nil
}
struct CVERecord: Codable, Identifiable {
var id: String
var description: String
var published: String
var severity: String
var score: Double?
var referenceURL: String { "https://nvd.nist.gov/vuln/detail/" + id }
}
+26 -13
View File
@@ -1,18 +1,31 @@
# PHPGuard — Phase 2
# PHPGuard 1.2 — Phase 3
Native SwiftUI macOS application for **read-only** SSH inventory of PHP installations on Linux servers.
Native macOS SwiftUI PHP inventory and CVE research tool.
## New in Phase 2
- APT PHP package upgrade inventory (no automatic updates)
- PHP version discovery inside accessible running Docker containers
- Per-server findings and status of package/Docker checks
- Existing SSH inventory, scan history, and JSON export retained
## Included
- Phase 2 SSH inventory, APT update listing, Docker PHP inventory, JSON reports.
- Phase 3 **CVE research** screen using the public NVD 2.0 API, with published dates, descriptions, and CVSS metadata.
- NVD records are keyword-search **candidates only**, NOT confirmed vulnerabilities on your servers.
- No Ubuntu package revision/backport matching is performed; no server is marked secure.
- `Scripts/build.sh` for unsigned local Debug builds and optional launch.
- `Scripts/release.sh` for Release build, Developer ID signing, DMG, notarization and stapling.
## Security interpretation
**This is not a CVE scanner yet.** Available upgrades are not necessarily security updates; the absence of upgrades is not evidence of safety. Vendor backports and security advisories must be checked before labelling an installation vulnerable or patched. Docker inspection only checks running containers with a `php` executable accessible on PATH. No compromise detection is performed.
## Build
```bash
./Scripts/build.sh
LAUNCH_AFTER_BUILD=0 CONFIGURATION=Release ./Scripts/build.sh
```
## Open in Xcode
Unzip the archive, open `PHPGuard/PHPGuard.xcodeproj`, select My Mac, and build. macOS 15+; the build has not been verified in Xcode in this environment.
## Release
Configure a notarytool keychain profile on your Mac, then run:
```bash
NOTARY_PROFILE=your-profile ./Scripts/release.sh
```
The script auto-detects a Developer ID Application identity, or use `SIGNING_IDENTITY`.
Release artifacts go to `dist/`. No automatic upload or publication.
## SSH
The app invokes `/usr/bin/ssh` with BatchMode and StrictHostKeyChecking. Configure working key-based SSH access in Terminal first. Remote scripts are read-only; APT's upgrade listing may refresh no metadata and uses currently cached package lists. Docker access depends on remote user permissions.
## Security
SSH requires existing known_hosts entries and key-based authentication. Scans are read-only. NVD results are for research, not a substitute for vendor-specific package advisories.
## Known limitations
Not built/tested with Xcode in this environment. CVE discovery is broad keyword search and may include unrelated products or omit relevant vulnerabilities. NVD may rate-limit requests. Automatic backport assessment is a future phase.
+11
View File
@@ -0,0 +1,11 @@
#!/bin/zsh
set -euo pipefail
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
CONFIG="${CONFIGURATION:-Debug}"
DERIVED="${DERIVED_DATA_PATH:-$ROOT/.build}"
command -v xcodebuild >/dev/null || { echo "Xcode command line tools required" >&2; exit 1; }
xcodebuild -project "$ROOT/PHPGuard.xcodeproj" -scheme PHPGuard -configuration "$CONFIG" -derivedDataPath "$DERIVED" CODE_SIGNING_ALLOWED=NO build
APP="$DERIVED/Build/Products/$CONFIG/PHPGuard.app"
[[ -d "$APP" ]] || { echo "Built application not found: $APP" >&2; exit 1; }
echo "Built: $APP"
if [[ "${LAUNCH_AFTER_BUILD:-1}" == "1" ]]; then open "$APP"; fi
+31
View File
@@ -0,0 +1,31 @@
#!/bin/zsh
set -euo pipefail
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
cd "$ROOT"
command -v xcodebuild >/dev/null || { echo "Xcode is required" >&2; exit 1; }
command -v hdiutil >/dev/null || { echo "hdiutil missing" >&2; exit 1; }
IDENTITY="${SIGNING_IDENTITY:-$(security find-identity -v -p codesigning | sed -nE 's/.*"(Developer ID Application: [^"]+)".*/\1/p' | head -1)}"
[[ -n "$IDENTITY" ]] || { echo "Developer ID Application signing identity required. Set SIGNING_IDENTITY." >&2; exit 1; }
PROFILE="${NOTARY_PROFILE:-}"
[[ -n "$PROFILE" ]] || { echo "Set NOTARY_PROFILE to an existing notarytool keychain profile." >&2; exit 1; }
VERSION="$(/usr/libexec/PlistBuddy -c 'Print :CFBundleShortVersionString' "$ROOT/.build/Build/Products/Release/PHPGuard.app/Contents/Info.plist" 2>/dev/null || true)"
DERIVED="$ROOT/.build"
xcodebuild -project "$ROOT/PHPGuard.xcodeproj" -scheme PHPGuard -configuration Release -derivedDataPath "$DERIVED" CODE_SIGNING_ALLOWED=NO build
APP="$DERIVED/Build/Products/Release/PHPGuard.app"
[[ -d "$APP" ]] || { echo "Missing Release app" >&2; exit 1; }
VERSION="$(/usr/libexec/PlistBuddy -c 'Print :CFBundleShortVersionString' "$APP/Contents/Info.plist")"
mkdir -p "$ROOT/dist"
STAGING="$(mktemp -d)"
trap 'rm -rf "$STAGING"' EXIT
cp -R "$APP" "$STAGING/PHPGuard.app"
# No --deep signing: sign embedded executables individually if added in future.
codesign --force --options runtime --timestamp --sign "$IDENTITY" "$STAGING/PHPGuard.app"
codesign --verify --strict --verbose=2 "$STAGING/PHPGuard.app"
DMG="$ROOT/dist/PHPGuard-$VERSION.dmg"
rm -f "$DMG"
ln -s /Applications "$STAGING/Applications"
hdiutil create -volname "PHPGuard $VERSION" -srcfolder "$STAGING" -ov -format UDZO "$DMG"
xcrun notarytool submit "$DMG" --keychain-profile "$PROFILE" --wait
xcrun stapler staple "$DMG"
xcrun stapler validate "$DMG"
echo "Release ready: $DMG"