First release of open core

This commit is contained in:
t
2026-04-02 10:57:36 -04:00
parent 1c94f12d1c
commit 084c1321fc
101 changed files with 8812 additions and 17 deletions

16
pkg/domain/adapter.go Normal file
View File

@@ -0,0 +1,16 @@
package domain
// Adapter represents a saved mapping profile for a specific scanner
type Adapter struct {
ID int `json:"id"`
Name string `json:"name"`
SourceName string `json:"source_name"`
FindingsPath string `json:"findings_path"`
MappingTitle string `json:"mapping_title"`
MappingAsset string `json:"mapping_asset"`
MappingSeverity string `json:"mapping_severity"`
MappingDescription string `json:"mapping_description"`
MappingRemediation string `json:"mapping_remediation"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
}

74
pkg/domain/analytics.go Normal file
View File

@@ -0,0 +1,74 @@
package domain
type ResolutionMetrics struct {
Total int
Patched int
RiskAccepted int
FalsePositive int
PatchedPct int
RiskAccPct int
FalsePosPct int
}
type SheriffAnalytics struct {
ActiveKEVs int
GlobalMTTRDays int
OpenCriticals int
TotalOverdue int
SourceHealth []SourceMetrics
Resolution ResolutionMetrics
Severity SeverityMetrics
TopAssets []AssetMetric
}
type SourceMetrics struct {
Source string
TotalOpen int
Criticals int
CisaKEVs int
Untriaged int
PatchOverdue int
PendingRisk int
TotalClosed int
Patched int
RiskAccepted int
FalsePositive int
TopAssignee string
StrategicNote string
}
type FeedItem struct {
Actor string
ActivityType string
NewValue string
TimeAgo string
}
type SeverityMetrics struct {
Critical int
High int
Medium int
Low int
Info int
Total int
CritPct int
HighPct int
MedPct int
LowPct int
InfoPct int
}
type AssetMetric struct {
Asset string
Count int
Percentage int
}
type SyncLog struct {
ID int `json:"id"`
Source string `json:"source"`
Status string `json:"status"`
RecordsProcessed int `json:"records_processed"`
ErrorMessage string `json:"error_message"`
CreatedAt string `json:"created_at"`
}

18
pkg/domain/auth.go Normal file
View File

@@ -0,0 +1,18 @@
package domain
import "time"
type User struct {
ID int `json:"id"`
Email string `json:"email"`
FullName string `json:"full_name"`
PasswordHash string `json:"-"`
GlobalRole string `json:"global_role"`
IsActive bool `json:"is_active"`
CreatedAt time.Time `json:"created_at"`
}
type Session struct {
Token string `json:"token"`
UserID int `json:"user_id"`
ExpiresAt time.Time `json:"expires_at"`
}

15
pkg/domain/config.go Normal file
View File

@@ -0,0 +1,15 @@
package domain
type AppConfig struct {
Timezone string `json:"timezone"`
BusinessStart int `json:"business_start"`
BusinessEnd int `json:"business_end"`
DefaultExtensionDays int `json:"default_extension_days"`
Backup BackupPolicy `json:"backup"`
}
type BackupPolicy struct {
Enabled bool `json:"enabled"`
IntervalHours int `json:"interval_hours"`
RetentionDays int `json:"retention_days"`
}

16
pkg/domain/connector.go Normal file
View File

@@ -0,0 +1,16 @@
package domain
// ConnectorTemplate defines how to translate third-party JSON into ticket format
type ConnectorTemplate struct {
ID string `json:"id"`
Name string `json:"name"`
SourceDefault string `json:"source_default"`
FindingsArrayPath string `json:"findings_array_path"`
FieldMappings struct {
Title string `json:"title"`
AssetIdentifier string `json:"asset_identifier"`
Severity string `json:"severity"`
Description string `json:"description"`
RecommendedRemediation string `json:"recommended_remediation"`
} `json:"field_mappings"`
}

11
pkg/domain/drafts.go Normal file
View File

@@ -0,0 +1,11 @@
package domain
type DraftTicket struct {
ID int `json:"id"`
ReportID string `json:"report_id"`
Title string `json:"title"`
Description string `json:"description"`
Severity string `json:"severity"`
AssetIdentifier string `json:"asset_identifier"`
RecommendedRemediation string `json:"recommended_remediation"`
}

11
pkg/domain/export.go Normal file
View File

@@ -0,0 +1,11 @@
package domain
type ExportState struct {
AppConfig AppConfig `json:"app_config"`
SLAPolicies []SLAPolicy `json:"sla_policies"`
Users []User `json:"users"`
Adapters []Adapter `json:"adapters"`
Tickets []Ticket `json:"tickets"`
Version string `json:"export_version"`
ExportedAt string `json:"exported_at"`
}

95
pkg/domain/store.go Normal file
View File

@@ -0,0 +1,95 @@
package domain
import (
"context"
"net/http"
"time"
)
// Store embeds all sub interfaces for Core
type Store interface {
TicketStore
IdentityStore
IngestStore
ConfigStore
AnalyticsStore
DraftStore
}
// TicketStore: Core CRUD and Workflow
type TicketStore interface {
GetTickets(ctx context.Context) ([]Ticket, error)
GetDashboardTickets(ctx context.Context, tabStatus, filter, assetFilter, userEmail, userRole string, limit, offset int) ([]Ticket, int, map[string]int, error)
CreateTicket(ctx context.Context, t *Ticket) error
GetTicketByID(ctx context.Context, id int) (Ticket, error)
UpdateTicketInline(ctx context.Context, ticketID int, severity, description, remediation, comment, actor, status, assignee string) error
}
// IdentityStore: Users, Sessions, and Dispatching
type IdentityStore interface {
CreateUser(ctx context.Context, email, fullName, passwordHash, globalRole string) (*User, error)
GetUserByEmail(ctx context.Context, email string) (*User, error)
GetUserByID(ctx context.Context, id int) (*User, error)
GetAllUsers(ctx context.Context) ([]*User, error)
GetUserCount(ctx context.Context) (int, error)
UpdateUserPassword(ctx context.Context, id int, newPasswordHash string) error
UpdateUserRole(ctx context.Context, id int, newRole string) error
DeactivateUserAndReassign(ctx context.Context, userID int) error
CreateSession(ctx context.Context, token string, userID int, expiresAt time.Time) error
GetSession(ctx context.Context, token string) (*Session, error)
DeleteSession(ctx context.Context, token string) error
GetWranglers(ctx context.Context) ([]User, error)
}
// IngestStore: Scanners, Adapters, and Sync History
type IngestStore interface {
IngestTickets(ctx context.Context, tickets []Ticket) error
ProcessIngestionBatch(ctx context.Context, source string, assetIdentifier string, incoming []Ticket) error
GetAdapters(ctx context.Context) ([]Adapter, error)
GetAdapterByID(ctx context.Context, id int) (Adapter, error)
GetAdapterByName(ctx context.Context, name string) (Adapter, error)
SaveAdapter(ctx context.Context, adapter Adapter) error
DeleteAdapter(ctx context.Context, id int) error
LogSync(ctx context.Context, source, status string, records int, errMsg string) error
GetRecentSyncLogs(ctx context.Context, limit int) ([]SyncLog, error)
}
// ConfigStore: Global System Settings
type ConfigStore interface {
GetAppConfig(ctx context.Context) (AppConfig, error)
UpdateAppConfig(ctx context.Context, config AppConfig) error
GetSLAPolicies(ctx context.Context) ([]SLAPolicy, error)
UpdateSLAPolicies(ctx context.Context, slas []SLAPolicy) error
UpdateBackupPolicy(ctx context.Context, policy BackupPolicy) error
ExportSystemState(ctx context.Context) (ExportState, error)
}
// AnalyticsStore: Audit Logs and KPI Metrics
type AnalyticsStore interface {
GetSheriffAnalytics(ctx context.Context) (SheriffAnalytics, error)
GetAnalyticsSummary(ctx context.Context) (map[string]int, error)
GetGlobalActivityFeed(ctx context.Context, limit int) ([]FeedItem, error)
GetPaginatedActivityFeed(ctx context.Context, filter string, limit int, offset int) ([]FeedItem, int, error)
}
// DraftStore: The Pentest Desk OSS, word docx
type DraftStore interface {
SaveDraft(ctx context.Context, draft DraftTicket) error
GetDraftsByReport(ctx context.Context, reportID string) ([]DraftTicket, error)
DeleteDraft(ctx context.Context, draftID string) error
UpdateDraft(ctx context.Context, draftID int, payload Ticket) error
PromotePentestDrafts(ctx context.Context, reportID string, analystEmail string, tickets []Ticket) error
}
type Authenticator interface {
Middleware(next http.Handler) http.Handler
}
type SLACalculator interface {
CalculateDueDate(severity string) *time.Time
CalculateTrueSLAHours(ctx context.Context, ticketID int, store Store) (float64, error)
}

61
pkg/domain/ticket.go Normal file
View File

@@ -0,0 +1,61 @@
package domain
import (
"time"
)
// SLAPolicy represents the global SLA configuration per severity
type SLAPolicy struct {
Domain string `json:"domain"`
Severity string `json:"severity"`
DaysToRemediate int `json:"days_to_remediate"`
MaxExtensions int `json:"max_extensions"`
DaysToTriage int `json:"days_to_triage"`
}
// AssetRiskSummary holds the rolled-up vulnerability counts for a single asset
type AssetRiskSummary struct {
AssetIdentifier string
TotalActive int
Critical int
High int
Medium int
Low int
Info int
}
type Ticket struct {
ID int `json:"id"`
Domain string `json:"domain"`
IsOverdue bool `json:"is_overdue"`
DaysToResolve *int `json:"days_to_resolve"`
Source string `json:"source"`
AssetIdentifier string `json:"asset_identifier"`
Title string `json:"title"`
Description string `json:"description"`
RecommendedRemediation string `json:"recommended_remediation"`
Severity string `json:"severity"`
Status string `json:"status"`
DedupeHash string `json:"dedupe_hash"`
PatchEvidence *string `json:"patch_evidence"`
OwnerViewedAt *time.Time `json:"owner_viewed_at"`
TriageDueDate time.Time `json:"triage_due_date"`
RemediationDueDate time.Time `json:"remediation_due_date"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
PatchedAt *time.Time `json:"patched_at"`
SLAString string `json:"sla_string"`
Assignee string `json:"assignee"`
LatestComment string `json:"latest_comment"`
}
// TicketAssignment represents the many-to-many relationship
type TicketAssignment struct {
TicketID int `json:"ticket_id"`
Assignee string `json:"assignee"`
Role string `json:"role"`
}