mirror of
https://github.com/shankar0123/certctl.git
synced 2026-06-09 13:48:52 +00:00
feat: add network certificate discovery (M21) and Prometheus metrics (M22)
M21 adds server-side active TLS scanning of CIDR ranges with concurrent probing, sentinel agent pattern for pipeline reuse, and full CRUD API for scan targets. M22 adds Prometheus exposition format endpoint alongside existing JSON metrics. Comprehensive documentation audit updates all docs to reflect 91 endpoints, 19 tables, 6 scheduler loops, and 900+ tests. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
package domain
|
||||
|
||||
import "time"
|
||||
|
||||
// NetworkScanTarget defines a network range to scan for TLS certificates.
|
||||
type NetworkScanTarget struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
CIDRs []string `json:"cidrs"`
|
||||
Ports []int `json:"ports"`
|
||||
Enabled bool `json:"enabled"`
|
||||
ScanIntervalHours int `json:"scan_interval_hours"`
|
||||
TimeoutMs int `json:"timeout_ms"`
|
||||
LastScanAt *time.Time `json:"last_scan_at,omitempty"`
|
||||
LastScanDurationMs *int `json:"last_scan_duration_ms,omitempty"`
|
||||
LastScanCertsFound *int `json:"last_scan_certs_found,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// NetworkScanResult holds the outcome of scanning a single endpoint.
|
||||
type NetworkScanResult struct {
|
||||
Address string // "ip:port"
|
||||
Certs []DiscoveredCertEntry
|
||||
Error string
|
||||
LatencyMs int
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package domain
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestNetworkScanTarget_Defaults(t *testing.T) {
|
||||
target := NetworkScanTarget{
|
||||
ID: "nst-test",
|
||||
Name: "Test Target",
|
||||
CIDRs: []string{"10.0.0.0/24"},
|
||||
Ports: []int{443},
|
||||
Enabled: true,
|
||||
ScanIntervalHours: 6,
|
||||
TimeoutMs: 5000,
|
||||
}
|
||||
|
||||
if target.ID != "nst-test" {
|
||||
t.Errorf("expected ID nst-test, got %s", target.ID)
|
||||
}
|
||||
if len(target.CIDRs) != 1 || target.CIDRs[0] != "10.0.0.0/24" {
|
||||
t.Errorf("unexpected CIDRs: %v", target.CIDRs)
|
||||
}
|
||||
if target.LastScanAt != nil {
|
||||
t.Error("expected nil LastScanAt for new target")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNetworkScanTarget_WithScanResults(t *testing.T) {
|
||||
now := time.Now()
|
||||
duration := 1500
|
||||
found := 12
|
||||
target := NetworkScanTarget{
|
||||
ID: "nst-prod",
|
||||
Name: "Production Network",
|
||||
CIDRs: []string{"192.168.1.0/24", "10.0.0.0/16"},
|
||||
Ports: []int{443, 8443, 636},
|
||||
Enabled: true,
|
||||
ScanIntervalHours: 1,
|
||||
TimeoutMs: 3000,
|
||||
LastScanAt: &now,
|
||||
LastScanDurationMs: &duration,
|
||||
LastScanCertsFound: &found,
|
||||
}
|
||||
|
||||
if len(target.Ports) != 3 {
|
||||
t.Errorf("expected 3 ports, got %d", len(target.Ports))
|
||||
}
|
||||
if *target.LastScanCertsFound != 12 {
|
||||
t.Errorf("expected 12 certs found, got %d", *target.LastScanCertsFound)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNetworkScanResult_Fields(t *testing.T) {
|
||||
result := NetworkScanResult{
|
||||
Address: "192.168.1.1:443",
|
||||
Error: "",
|
||||
LatencyMs: 45,
|
||||
}
|
||||
if result.Address != "192.168.1.1:443" {
|
||||
t.Errorf("expected address 192.168.1.1:443, got %s", result.Address)
|
||||
}
|
||||
if result.LatencyMs != 45 {
|
||||
t.Errorf("expected latency 45ms, got %d", result.LatencyMs)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user