mirror of
https://github.com/syntrex-lab/gomcp.git
synced 2026-04-25 04:16:22 +02:00
chore: add copyright headers, CI tests, and sanitize gitignore
This commit is contained in:
parent
5cbb3d89d3
commit
d1f844235e
325 changed files with 2267 additions and 902 deletions
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package contextengine
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package contextengine
|
||||
|
||||
import (
|
||||
|
|
@ -5,9 +9,9 @@ import (
|
|||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
ctxdomain "github.com/syntrex-lab/gomcp/internal/domain/context"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
ctxdomain "github.com/syntrex-lab/gomcp/internal/domain/context"
|
||||
)
|
||||
|
||||
func TestLoadConfig_FileNotExists(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
// Package contextengine implements the Proactive Context Engine.
|
||||
// It automatically injects relevant memory facts into every MCP tool response
|
||||
// via ToolHandlerMiddleware, so the LLM always has context without asking.
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package contextengine
|
||||
|
||||
import (
|
||||
|
|
@ -10,9 +14,9 @@ import (
|
|||
"github.com/mark3labs/mcp-go/mcp"
|
||||
"github.com/syntrex-lab/gomcp/internal/domain/memory"
|
||||
|
||||
ctxdomain "github.com/syntrex-lab/gomcp/internal/domain/context"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
ctxdomain "github.com/syntrex-lab/gomcp/internal/domain/context"
|
||||
)
|
||||
|
||||
// --- Mock FactProvider ---
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
// Package contextengine — processor.go
|
||||
// Processes unprocessed interaction log entries into session summary facts.
|
||||
// This closes the memory loop: tool calls → interaction log → summary facts → boot instructions.
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package contextengine
|
||||
|
||||
import (
|
||||
|
|
@ -5,10 +9,10 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/syntrex-lab/gomcp/internal/domain/memory"
|
||||
"github.com/syntrex-lab/gomcp/internal/infrastructure/sqlite"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/syntrex-lab/gomcp/internal/domain/memory"
|
||||
"github.com/syntrex-lab/gomcp/internal/infrastructure/sqlite"
|
||||
)
|
||||
|
||||
// --- mock FactStore for processor tests ---
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package contextengine
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package contextengine
|
||||
|
||||
import (
|
||||
|
|
@ -6,9 +10,9 @@ import (
|
|||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/syntrex-lab/gomcp/internal/domain/memory"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/syntrex-lab/gomcp/internal/domain/memory"
|
||||
)
|
||||
|
||||
// --- Mock FactStore for provider tests ---
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
// Package lifecycle manages graceful shutdown with auto-save of session state,
|
||||
// cache flush, and database closure.
|
||||
package lifecycle
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package lifecycle
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package lifecycle
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package lifecycle
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package orchestrator
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package orchestrator
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
// Package orchestrator implements the DIP Heartbeat Orchestrator.
|
||||
//
|
||||
// The orchestrator runs a background loop with 4 modules:
|
||||
|
|
@ -439,7 +443,7 @@ func (o *Orchestrator) stabilityCheck(ctx context.Context, result *HeartbeatResu
|
|||
if err := o.store.Add(ctx, recoveryMarker); err == nil {
|
||||
o.mu.Lock()
|
||||
o.lastApoptosisWritten = time.Now()
|
||||
o.mu.Unlock()
|
||||
o.mu.Unlock()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package orchestrator
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package resilience
|
||||
|
||||
import (
|
||||
|
|
@ -10,24 +14,24 @@ import (
|
|||
|
||||
// BehaviorProfile captures the runtime behavior of a component.
|
||||
type BehaviorProfile struct {
|
||||
Goroutines int `json:"goroutines"`
|
||||
HeapAllocMB float64 `json:"heap_alloc_mb"`
|
||||
HeapObjectsK float64 `json:"heap_objects_k"`
|
||||
GCPauseMs float64 `json:"gc_pause_ms"`
|
||||
NumGC uint32 `json:"num_gc"`
|
||||
FileDescriptors int `json:"file_descriptors,omitempty"`
|
||||
CustomMetrics map[string]float64 `json:"custom_metrics,omitempty"`
|
||||
Goroutines int `json:"goroutines"`
|
||||
HeapAllocMB float64 `json:"heap_alloc_mb"`
|
||||
HeapObjectsK float64 `json:"heap_objects_k"`
|
||||
GCPauseMs float64 `json:"gc_pause_ms"`
|
||||
NumGC uint32 `json:"num_gc"`
|
||||
FileDescriptors int `json:"file_descriptors,omitempty"`
|
||||
CustomMetrics map[string]float64 `json:"custom_metrics,omitempty"`
|
||||
}
|
||||
|
||||
// BehavioralAlert is emitted when a behavioral anomaly is detected.
|
||||
type BehavioralAlert struct {
|
||||
Component string `json:"component"`
|
||||
AnomalyType string `json:"anomaly_type"` // goroutine_leak, memory_leak, gc_pressure, etc.
|
||||
Metric string `json:"metric"`
|
||||
Current float64 `json:"current"`
|
||||
Baseline float64 `json:"baseline"`
|
||||
ZScore float64 `json:"z_score"`
|
||||
Severity string `json:"severity"`
|
||||
Component string `json:"component"`
|
||||
AnomalyType string `json:"anomaly_type"` // goroutine_leak, memory_leak, gc_pressure, etc.
|
||||
Metric string `json:"metric"`
|
||||
Current float64 `json:"current"`
|
||||
Baseline float64 `json:"baseline"`
|
||||
ZScore float64 `json:"z_score"`
|
||||
Severity string `json:"severity"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
}
|
||||
|
||||
|
|
@ -35,12 +39,12 @@ type BehavioralAlert struct {
|
|||
// It profiles the current process and compares against learned baselines.
|
||||
// On Linux, eBPF hooks (immune/resilience_hooks.c) extend this to kernel level.
|
||||
type BehavioralAnalyzer struct {
|
||||
mu sync.RWMutex
|
||||
metricsDB *MetricsDB
|
||||
alertBus chan BehavioralAlert
|
||||
interval time.Duration
|
||||
component string // self component name
|
||||
logger *slog.Logger
|
||||
mu sync.RWMutex
|
||||
metricsDB *MetricsDB
|
||||
alertBus chan BehavioralAlert
|
||||
interval time.Duration
|
||||
component string // self component name
|
||||
logger *slog.Logger
|
||||
}
|
||||
|
||||
// NewBehavioralAnalyzer creates a new behavioral analyzer.
|
||||
|
|
@ -112,10 +116,10 @@ func (ba *BehavioralAnalyzer) storeMetrics(p BehaviorProfile) {
|
|||
// detectAnomalies checks each metric against its baseline via Z-score.
|
||||
func (ba *BehavioralAnalyzer) detectAnomalies(p BehaviorProfile) {
|
||||
checks := []struct {
|
||||
metric string
|
||||
value float64
|
||||
metric string
|
||||
value float64
|
||||
anomalyType string
|
||||
severity string
|
||||
severity string
|
||||
}{
|
||||
{"goroutines", float64(p.Goroutines), "goroutine_leak", "WARNING"},
|
||||
{"heap_alloc_mb", p.HeapAllocMB, "memory_leak", "CRITICAL"},
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package resilience
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package resilience
|
||||
|
||||
import (
|
||||
|
|
@ -66,10 +70,10 @@ type Action struct {
|
|||
|
||||
// TriggerCondition defines when a healing strategy activates.
|
||||
type TriggerCondition struct {
|
||||
Metrics []string `json:"metrics,omitempty"`
|
||||
Metrics []string `json:"metrics,omitempty"`
|
||||
Statuses []ComponentStatus `json:"statuses,omitempty"`
|
||||
ConsecutiveFailures int `json:"consecutive_failures"`
|
||||
WithinWindow time.Duration `json:"within_window"`
|
||||
ConsecutiveFailures int `json:"consecutive_failures"`
|
||||
WithinWindow time.Duration `json:"within_window"`
|
||||
}
|
||||
|
||||
// RollbackPlan defines what happens if healing fails.
|
||||
|
|
@ -91,11 +95,11 @@ type HealingStrategy struct {
|
|||
|
||||
// Diagnosis is the result of root cause analysis.
|
||||
type Diagnosis struct {
|
||||
Component string `json:"component"`
|
||||
Metric string `json:"metric"`
|
||||
RootCause string `json:"root_cause"`
|
||||
Confidence float64 `json:"confidence"`
|
||||
SuggestedFix string `json:"suggested_fix"`
|
||||
Component string `json:"component"`
|
||||
Metric string `json:"metric"`
|
||||
RootCause string `json:"root_cause"`
|
||||
Confidence float64 `json:"confidence"`
|
||||
SuggestedFix string `json:"suggested_fix"`
|
||||
RelatedAlerts []HealthAlert `json:"related_alerts,omitempty"`
|
||||
}
|
||||
|
||||
|
|
@ -117,7 +121,7 @@ type HealingOperation struct {
|
|||
// ActionLog records the execution of a single action.
|
||||
type ActionLog struct {
|
||||
Action ActionType `json:"action"`
|
||||
StartedAt time.Time `json:"started_at"`
|
||||
StartedAt time.Time `json:"started_at"`
|
||||
Duration time.Duration `json:"duration"`
|
||||
Success bool `json:"success"`
|
||||
Error string `json:"error,omitempty"`
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package resilience
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package resilience
|
||||
|
||||
import "time"
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package resilience
|
||||
|
||||
import (
|
||||
|
|
@ -63,12 +67,12 @@ type ComponentConfig struct {
|
|||
|
||||
// ComponentHealth tracks the health state of a single component.
|
||||
type ComponentHealth struct {
|
||||
Name string `json:"name"`
|
||||
Status ComponentStatus `json:"status"`
|
||||
Name string `json:"name"`
|
||||
Status ComponentStatus `json:"status"`
|
||||
Metrics map[string]float64 `json:"metrics"`
|
||||
LastCheck time.Time `json:"last_check"`
|
||||
Consecutive int `json:"consecutive_failures"`
|
||||
Config ComponentConfig `json:"-"`
|
||||
LastCheck time.Time `json:"last_check"`
|
||||
Consecutive int `json:"consecutive_failures"`
|
||||
Config ComponentConfig `json:"-"`
|
||||
}
|
||||
|
||||
// HealthAlert represents a detected health anomaly.
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package resilience
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package resilience
|
||||
|
||||
import (
|
||||
|
|
@ -23,11 +27,11 @@ const (
|
|||
|
||||
// IntegrityReport is the full result of an integrity verification.
|
||||
type IntegrityReport struct {
|
||||
Overall IntegrityStatus `json:"overall"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
Binaries map[string]BinaryStatus `json:"binaries,omitempty"`
|
||||
Chain *ChainStatus `json:"chain,omitempty"`
|
||||
Configs map[string]ConfigStatus `json:"configs,omitempty"`
|
||||
Overall IntegrityStatus `json:"overall"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
Binaries map[string]BinaryStatus `json:"binaries,omitempty"`
|
||||
Chain *ChainStatus `json:"chain,omitempty"`
|
||||
Configs map[string]ConfigStatus `json:"configs,omitempty"`
|
||||
}
|
||||
|
||||
// BinaryStatus is the integrity status of a single binary.
|
||||
|
|
@ -56,13 +60,13 @@ type ConfigStatus struct {
|
|||
// IntegrityVerifier performs periodic integrity checks on binaries,
|
||||
// decision chain, and config files.
|
||||
type IntegrityVerifier struct {
|
||||
mu sync.RWMutex
|
||||
binaryHashes map[string]string // path → expected SHA-256
|
||||
configPaths []string // config files to verify
|
||||
hmacKey []byte // key for config HMAC-SHA256
|
||||
chainPath string // path to decision chain log
|
||||
logger *slog.Logger
|
||||
lastReport *IntegrityReport
|
||||
mu sync.RWMutex
|
||||
binaryHashes map[string]string // path → expected SHA-256
|
||||
configPaths []string // config files to verify
|
||||
hmacKey []byte // key for config HMAC-SHA256
|
||||
chainPath string // path to decision chain log
|
||||
logger *slog.Logger
|
||||
lastReport *IntegrityReport
|
||||
}
|
||||
|
||||
// NewIntegrityVerifier creates a new integrity verifier.
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
// Package resilience implements the Sentinel Autonomous Resilience Layer (SARL).
|
||||
//
|
||||
// Five levels of autonomous self-recovery:
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package resilience
|
||||
|
||||
import (
|
||||
|
|
@ -43,13 +47,13 @@ type ModeActionFunc func(mode EmergencyMode, action string, params map[string]in
|
|||
|
||||
// PreservationEngine manages emergency modes (safe/lockdown/apoptosis).
|
||||
type PreservationEngine struct {
|
||||
mu sync.RWMutex
|
||||
currentMode EmergencyMode
|
||||
activation *ModeActivation
|
||||
history []PreservationEvent
|
||||
actionFn ModeActionFunc
|
||||
integrityFn func() IntegrityReport // pluggable integrity check
|
||||
logger *slog.Logger
|
||||
mu sync.RWMutex
|
||||
currentMode EmergencyMode
|
||||
activation *ModeActivation
|
||||
history []PreservationEvent
|
||||
actionFn ModeActionFunc
|
||||
integrityFn func() IntegrityReport // pluggable integrity check
|
||||
logger *slog.Logger
|
||||
}
|
||||
|
||||
// NewPreservationEngine creates a new preservation engine.
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package resilience
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package resilience
|
||||
|
||||
import (
|
||||
|
|
@ -12,58 +16,58 @@ import (
|
|||
type PlaybookStatus string
|
||||
|
||||
const (
|
||||
PlaybookPending PlaybookStatus = "PENDING"
|
||||
PlaybookRunning PlaybookStatus = "RUNNING"
|
||||
PlaybookSucceeded PlaybookStatus = "SUCCEEDED"
|
||||
PlaybookFailed PlaybookStatus = "FAILED"
|
||||
PlaybookPending PlaybookStatus = "PENDING"
|
||||
PlaybookRunning PlaybookStatus = "RUNNING"
|
||||
PlaybookSucceeded PlaybookStatus = "SUCCEEDED"
|
||||
PlaybookFailed PlaybookStatus = "FAILED"
|
||||
PlaybookRolledBack PlaybookStatus = "ROLLED_BACK"
|
||||
)
|
||||
|
||||
// PlaybookStep is a single step in a recovery playbook.
|
||||
type PlaybookStep struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"` // shell, api, consensus, crypto, systemd, http, prometheus
|
||||
Timeout time.Duration `json:"timeout"`
|
||||
Retries int `json:"retries"`
|
||||
Params map[string]interface{} `json:"params,omitempty"`
|
||||
OnError string `json:"on_error"` // abort, continue, rollback
|
||||
Condition string `json:"condition,omitempty"` // prerequisite condition
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"` // shell, api, consensus, crypto, systemd, http, prometheus
|
||||
Timeout time.Duration `json:"timeout"`
|
||||
Retries int `json:"retries"`
|
||||
Params map[string]interface{} `json:"params,omitempty"`
|
||||
OnError string `json:"on_error"` // abort, continue, rollback
|
||||
Condition string `json:"condition,omitempty"` // prerequisite condition
|
||||
}
|
||||
|
||||
// Playbook defines a complete recovery procedure.
|
||||
type Playbook struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version"`
|
||||
TriggerMetric string `json:"trigger_metric"`
|
||||
TriggerSeverity string `json:"trigger_severity"`
|
||||
DiagnosisChecks []PlaybookStep `json:"diagnosis_checks"`
|
||||
Actions []PlaybookStep `json:"actions"`
|
||||
RollbackActions []PlaybookStep `json:"rollback_actions"`
|
||||
SuccessCriteria []string `json:"success_criteria"`
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version"`
|
||||
TriggerMetric string `json:"trigger_metric"`
|
||||
TriggerSeverity string `json:"trigger_severity"`
|
||||
DiagnosisChecks []PlaybookStep `json:"diagnosis_checks"`
|
||||
Actions []PlaybookStep `json:"actions"`
|
||||
RollbackActions []PlaybookStep `json:"rollback_actions"`
|
||||
SuccessCriteria []string `json:"success_criteria"`
|
||||
}
|
||||
|
||||
// PlaybookExecution tracks a single playbook run.
|
||||
type PlaybookExecution struct {
|
||||
ID string `json:"id"`
|
||||
PlaybookID string `json:"playbook_id"`
|
||||
Component string `json:"component"`
|
||||
Status PlaybookStatus `json:"status"`
|
||||
StartedAt time.Time `json:"started_at"`
|
||||
CompletedAt time.Time `json:"completed_at,omitempty"`
|
||||
StepsRun []StepResult `json:"steps_run"`
|
||||
Error string `json:"error,omitempty"`
|
||||
ID string `json:"id"`
|
||||
PlaybookID string `json:"playbook_id"`
|
||||
Component string `json:"component"`
|
||||
Status PlaybookStatus `json:"status"`
|
||||
StartedAt time.Time `json:"started_at"`
|
||||
CompletedAt time.Time `json:"completed_at,omitempty"`
|
||||
StepsRun []StepResult `json:"steps_run"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// StepResult records the execution of a single playbook step.
|
||||
type StepResult struct {
|
||||
StepID string `json:"step_id"`
|
||||
StepName string `json:"step_name"`
|
||||
Success bool `json:"success"`
|
||||
Duration time.Duration `json:"duration"`
|
||||
Output string `json:"output,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
StepID string `json:"step_id"`
|
||||
StepName string `json:"step_name"`
|
||||
Success bool `json:"success"`
|
||||
Duration time.Duration `json:"duration"`
|
||||
Output string `json:"output,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// PlaybookExecutorFunc runs a single playbook step.
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package resilience
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
// Package resources provides MCP resource implementations.
|
||||
package resources
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package resources
|
||||
|
||||
import (
|
||||
|
|
@ -5,11 +9,11 @@ import (
|
|||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/syntrex-lab/gomcp/internal/domain/memory"
|
||||
"github.com/syntrex-lab/gomcp/internal/domain/session"
|
||||
"github.com/syntrex-lab/gomcp/internal/infrastructure/sqlite"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func newTestProvider(t *testing.T) (*Provider, *sqlite.DB, *sqlite.DB) {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package shadow_ai
|
||||
|
||||
import (
|
||||
|
|
@ -14,10 +18,10 @@ import (
|
|||
type ApprovalStatus string
|
||||
|
||||
const (
|
||||
ApprovalPending ApprovalStatus = "pending"
|
||||
ApprovalApproved ApprovalStatus = "approved"
|
||||
ApprovalDenied ApprovalStatus = "denied"
|
||||
ApprovalExpired ApprovalStatus = "expired"
|
||||
ApprovalPending ApprovalStatus = "pending"
|
||||
ApprovalApproved ApprovalStatus = "approved"
|
||||
ApprovalDenied ApprovalStatus = "denied"
|
||||
ApprovalExpired ApprovalStatus = "expired"
|
||||
ApprovalAutoApproved ApprovalStatus = "auto_approved"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package shadow_ai
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package shadow_ai
|
||||
|
||||
import (
|
||||
|
|
@ -14,11 +18,11 @@ import (
|
|||
|
||||
// AISignatureDB contains known AI service signatures for detection.
|
||||
type AISignatureDB struct {
|
||||
mu sync.RWMutex
|
||||
services []AIServiceInfo
|
||||
domainPatterns []*domainPattern
|
||||
apiKeyPatterns []*APIKeyPattern
|
||||
httpSignatures []string
|
||||
mu sync.RWMutex
|
||||
services []AIServiceInfo
|
||||
domainPatterns []*domainPattern
|
||||
apiKeyPatterns []*APIKeyPattern
|
||||
httpSignatures []string
|
||||
}
|
||||
|
||||
type domainPattern struct {
|
||||
|
|
@ -62,14 +66,14 @@ func (db *AISignatureDB) loadDefaults() {
|
|||
|
||||
// HTTP header signatures.
|
||||
db.httpSignatures = []string{
|
||||
"authorization: bearer sk-", // OpenAI
|
||||
"authorization: bearer ant-", // Anthropic
|
||||
"x-api-key: sk-ant-", // Anthropic v2
|
||||
"x-goog-api-key:", // Google AI
|
||||
"authorization: bearer gsk_", // Groq
|
||||
"authorization: bearer hf_", // HuggingFace
|
||||
"api-key:", // Azure OpenAI (x-ms header)
|
||||
"x-api-key: xai-", // xAI Grok API
|
||||
"authorization: bearer sk-", // OpenAI
|
||||
"authorization: bearer ant-", // Anthropic
|
||||
"x-api-key: sk-ant-", // Anthropic v2
|
||||
"x-goog-api-key:", // Google AI
|
||||
"authorization: bearer gsk_", // Groq
|
||||
"authorization: bearer hf_", // HuggingFace
|
||||
"api-key:", // Azure OpenAI (x-ms header)
|
||||
"x-api-key: xai-", // xAI Grok API
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -246,7 +250,7 @@ func (nd *NetworkDetector) SignatureDB() *AISignatureDB {
|
|||
// UserBehaviorProfile tracks a user's AI access behavior for anomaly detection.
|
||||
type UserBehaviorProfile struct {
|
||||
UserID string `json:"user_id"`
|
||||
AccessFrequency float64 `json:"access_frequency"` // Requests per hour
|
||||
AccessFrequency float64 `json:"access_frequency"` // Requests per hour
|
||||
DataVolumePerHour float64 `json:"data_volume_per_hour"` // Bytes per hour
|
||||
KnownDestinations []string `json:"known_destinations"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package shadow_ai
|
||||
|
||||
import (
|
||||
|
|
@ -17,62 +21,62 @@ import (
|
|||
type DocReviewStatus string
|
||||
|
||||
const (
|
||||
DocReviewPending DocReviewStatus = "pending"
|
||||
DocReviewScanning DocReviewStatus = "scanning"
|
||||
DocReviewClean DocReviewStatus = "clean"
|
||||
DocReviewRedacted DocReviewStatus = "redacted"
|
||||
DocReviewBlocked DocReviewStatus = "blocked"
|
||||
DocReviewApproved DocReviewStatus = "approved"
|
||||
DocReviewPending DocReviewStatus = "pending"
|
||||
DocReviewScanning DocReviewStatus = "scanning"
|
||||
DocReviewClean DocReviewStatus = "clean"
|
||||
DocReviewRedacted DocReviewStatus = "redacted"
|
||||
DocReviewBlocked DocReviewStatus = "blocked"
|
||||
DocReviewApproved DocReviewStatus = "approved"
|
||||
)
|
||||
|
||||
// ScanResult contains the results of scanning a document.
|
||||
type ScanResult struct {
|
||||
DocumentID string `json:"document_id"`
|
||||
Status DocReviewStatus `json:"status"`
|
||||
PIIFound []PIIMatch `json:"pii_found,omitempty"`
|
||||
SecretsFound []SecretMatch `json:"secrets_found,omitempty"`
|
||||
DataClass DataClassification `json:"data_classification"`
|
||||
ContentHash string `json:"content_hash"`
|
||||
ScannedAt time.Time `json:"scanned_at"`
|
||||
SizeBytes int `json:"size_bytes"`
|
||||
DocumentID string `json:"document_id"`
|
||||
Status DocReviewStatus `json:"status"`
|
||||
PIIFound []PIIMatch `json:"pii_found,omitempty"`
|
||||
SecretsFound []SecretMatch `json:"secrets_found,omitempty"`
|
||||
DataClass DataClassification `json:"data_classification"`
|
||||
ContentHash string `json:"content_hash"`
|
||||
ScannedAt time.Time `json:"scanned_at"`
|
||||
SizeBytes int `json:"size_bytes"`
|
||||
}
|
||||
|
||||
// PIIMatch represents a detected PII pattern in content.
|
||||
type PIIMatch struct {
|
||||
Type string `json:"type"` // "email", "phone", "ssn", "credit_card", "passport"
|
||||
Location int `json:"location"` // Character offset
|
||||
Type string `json:"type"` // "email", "phone", "ssn", "credit_card", "passport"
|
||||
Location int `json:"location"` // Character offset
|
||||
Length int `json:"length"`
|
||||
Masked string `json:"masked"` // Redacted value, e.g., "j***@example.com"
|
||||
Masked string `json:"masked"` // Redacted value, e.g., "j***@example.com"
|
||||
}
|
||||
|
||||
// SecretMatch represents a detected secret/API key in content.
|
||||
type SecretMatch struct {
|
||||
Type string `json:"type"` // "api_key", "password", "token", "private_key"
|
||||
Type string `json:"type"` // "api_key", "password", "token", "private_key"
|
||||
Location int `json:"location"`
|
||||
Length int `json:"length"`
|
||||
Provider string `json:"provider"` // "OpenAI", "AWS", "GitHub", etc.
|
||||
Provider string `json:"provider"` // "OpenAI", "AWS", "GitHub", etc.
|
||||
}
|
||||
|
||||
// DocBridge manages document scanning, redaction, and review workflow.
|
||||
type DocBridge struct {
|
||||
mu sync.RWMutex
|
||||
reviews map[string]*ScanResult
|
||||
piiPatterns []*piiPattern
|
||||
secretPats []secretPattern // Cached compiled patterns
|
||||
signatures *AISignatureDB // Reused across scans
|
||||
maxDocSize int // bytes
|
||||
mu sync.RWMutex
|
||||
reviews map[string]*ScanResult
|
||||
piiPatterns []*piiPattern
|
||||
secretPats []secretPattern // Cached compiled patterns
|
||||
signatures *AISignatureDB // Reused across scans
|
||||
maxDocSize int // bytes
|
||||
}
|
||||
|
||||
type piiPattern struct {
|
||||
name string
|
||||
regex *regexp.Regexp
|
||||
maskFn func(string) string
|
||||
name string
|
||||
regex *regexp.Regexp
|
||||
maskFn func(string) string
|
||||
}
|
||||
|
||||
// NewDocBridge creates a new Document Review Bridge.
|
||||
func NewDocBridge() *DocBridge {
|
||||
return &DocBridge{
|
||||
reviews: make(map[string]*ScanResult),
|
||||
reviews: make(map[string]*ScanResult),
|
||||
piiPatterns: defaultPIIPatterns(),
|
||||
secretPats: secretPatterns(),
|
||||
signatures: NewAISignatureDB(),
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package shadow_ai
|
||||
|
||||
import (
|
||||
|
|
@ -134,7 +138,7 @@ func (fm *FallbackManager) logDetectOnly(target, reason string) {
|
|||
DetectionMethod: DetectNetwork,
|
||||
Action: "detect_only",
|
||||
Metadata: map[string]string{
|
||||
"reason": reason,
|
||||
"reason": reason,
|
||||
"fallback_strategy": fm.strategy,
|
||||
},
|
||||
Timestamp: time.Now(),
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package shadow_ai
|
||||
|
||||
import (
|
||||
|
|
@ -19,13 +23,13 @@ const (
|
|||
|
||||
// PluginHealth tracks the health state of a single plugin.
|
||||
type PluginHealth struct {
|
||||
Vendor string `json:"vendor"`
|
||||
Type PluginType `json:"type"`
|
||||
Status PluginStatus `json:"status"`
|
||||
LastCheck time.Time `json:"last_check"`
|
||||
Consecutive int `json:"consecutive_failures"`
|
||||
Vendor string `json:"vendor"`
|
||||
Type PluginType `json:"type"`
|
||||
Status PluginStatus `json:"status"`
|
||||
LastCheck time.Time `json:"last_check"`
|
||||
Consecutive int `json:"consecutive_failures"`
|
||||
Latency time.Duration `json:"latency"`
|
||||
LastError string `json:"last_error,omitempty"`
|
||||
LastError string `json:"last_error,omitempty"`
|
||||
}
|
||||
|
||||
// MaxConsecutivePluginFailures before marking offline.
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
// Package shadow_ai implements the Sentinel Shadow AI Control Module.
|
||||
//
|
||||
// Five levels of shadow AI management:
|
||||
|
|
@ -107,7 +111,7 @@ type PluginConfig struct {
|
|||
// IntegrationConfig is the top-level Shadow AI configuration.
|
||||
type IntegrationConfig struct {
|
||||
Plugins []PluginConfig `yaml:"plugins" json:"plugins"`
|
||||
FallbackStrategy string `yaml:"fallback_strategy" json:"fallback_strategy"` // "detect_only" | "alert_only"
|
||||
FallbackStrategy string `yaml:"fallback_strategy" json:"fallback_strategy"` // "detect_only" | "alert_only"
|
||||
HealthCheckInterval time.Duration `yaml:"health_check_interval" json:"health_check_interval"` // default: 30s
|
||||
}
|
||||
|
||||
|
|
@ -117,13 +121,13 @@ type IntegrationConfig struct {
|
|||
type DetectionMethod string
|
||||
|
||||
const (
|
||||
DetectNetwork DetectionMethod = "network" // Domain/IP match
|
||||
DetectHTTP DetectionMethod = "http" // HTTP header signature
|
||||
DetectTLS DetectionMethod = "tls" // TLS/JA3 fingerprint
|
||||
DetectProcess DetectionMethod = "process" // AI tool process execution
|
||||
DetectAPIKey DetectionMethod = "api_key" // AI API key in payload
|
||||
DetectBehavioral DetectionMethod = "behavioral" // Anomalous AI access pattern
|
||||
DetectClipboard DetectionMethod = "clipboard" // Large clipboard → AI browser pattern
|
||||
DetectNetwork DetectionMethod = "network" // Domain/IP match
|
||||
DetectHTTP DetectionMethod = "http" // HTTP header signature
|
||||
DetectTLS DetectionMethod = "tls" // TLS/JA3 fingerprint
|
||||
DetectProcess DetectionMethod = "process" // AI tool process execution
|
||||
DetectAPIKey DetectionMethod = "api_key" // AI API key in payload
|
||||
DetectBehavioral DetectionMethod = "behavioral" // Anomalous AI access pattern
|
||||
DetectClipboard DetectionMethod = "clipboard" // Large clipboard → AI browser pattern
|
||||
)
|
||||
|
||||
// DataClassification determines the approval tier required.
|
||||
|
|
@ -141,22 +145,22 @@ type ShadowAIEvent struct {
|
|||
ID string `json:"id"`
|
||||
UserID string `json:"user_id"`
|
||||
Hostname string `json:"hostname"`
|
||||
Destination string `json:"destination"` // Target AI service domain/IP
|
||||
AIService string `json:"ai_service"` // "chatgpt", "claude", "gemini", etc.
|
||||
Destination string `json:"destination"` // Target AI service domain/IP
|
||||
AIService string `json:"ai_service"` // "chatgpt", "claude", "gemini", etc.
|
||||
DetectionMethod DetectionMethod `json:"detection_method"`
|
||||
Action string `json:"action"` // "blocked", "allowed", "pending"
|
||||
EnforcedBy string `json:"enforced_by"` // Plugin vendor that enforced
|
||||
DataSize int64 `json:"data_size"` // Bytes sent to AI
|
||||
Action string `json:"action"` // "blocked", "allowed", "pending"
|
||||
EnforcedBy string `json:"enforced_by"` // Plugin vendor that enforced
|
||||
DataSize int64 `json:"data_size"` // Bytes sent to AI
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
Metadata map[string]string `json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
// AIServiceInfo describes a known AI service for signature matching.
|
||||
type AIServiceInfo struct {
|
||||
Name string `json:"name"` // "ChatGPT", "Claude", "Gemini"
|
||||
Vendor string `json:"vendor"` // "OpenAI", "Anthropic", "Google"
|
||||
Domains []string `json:"domains"` // ["*.openai.com", "chat.openai.com"]
|
||||
Category string `json:"category"` // "llm", "image_gen", "code_assist"
|
||||
Name string `json:"name"` // "ChatGPT", "Claude", "Gemini"
|
||||
Vendor string `json:"vendor"` // "OpenAI", "Anthropic", "Google"
|
||||
Domains []string `json:"domains"` // ["*.openai.com", "chat.openai.com"]
|
||||
Category string `json:"category"` // "llm", "image_gen", "code_assist"
|
||||
}
|
||||
|
||||
// BlockRequest is an API request to manually block a target.
|
||||
|
|
@ -188,27 +192,27 @@ type Violator struct {
|
|||
|
||||
// ApprovalTier defines the approval requirements for a data classification level.
|
||||
type ApprovalTier struct {
|
||||
Name string `yaml:"name" json:"name"`
|
||||
Name string `yaml:"name" json:"name"`
|
||||
DataClass DataClassification `yaml:"data_class" json:"data_class"`
|
||||
ApprovalNeeded []string `yaml:"approval_needed" json:"approval_needed"` // ["manager"], ["manager", "soc"], ["ciso"]
|
||||
SLA time.Duration `yaml:"sla" json:"sla"`
|
||||
AutoApprove bool `yaml:"auto_approve" json:"auto_approve"`
|
||||
ApprovalNeeded []string `yaml:"approval_needed" json:"approval_needed"` // ["manager"], ["manager", "soc"], ["ciso"]
|
||||
SLA time.Duration `yaml:"sla" json:"sla"`
|
||||
AutoApprove bool `yaml:"auto_approve" json:"auto_approve"`
|
||||
}
|
||||
|
||||
// ApprovalRequest tracks a pending approval for AI access.
|
||||
type ApprovalRequest struct {
|
||||
ID string `json:"id"`
|
||||
DocID string `json:"doc_id"`
|
||||
UserID string `json:"user_id"`
|
||||
Tier string `json:"tier"`
|
||||
DataClass DataClassification `json:"data_class"`
|
||||
Status string `json:"status"` // "pending", "approved", "denied", "expired"
|
||||
ApprovedBy string `json:"approved_by,omitempty"`
|
||||
DeniedBy string `json:"denied_by,omitempty"`
|
||||
Reason string `json:"reason,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
ExpiresAt time.Time `json:"expires_at"`
|
||||
ResolvedAt time.Time `json:"resolved_at,omitempty"`
|
||||
ID string `json:"id"`
|
||||
DocID string `json:"doc_id"`
|
||||
UserID string `json:"user_id"`
|
||||
Tier string `json:"tier"`
|
||||
DataClass DataClassification `json:"data_class"`
|
||||
Status string `json:"status"` // "pending", "approved", "denied", "expired"
|
||||
ApprovedBy string `json:"approved_by,omitempty"`
|
||||
DeniedBy string `json:"denied_by,omitempty"`
|
||||
Reason string `json:"reason,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
ExpiresAt time.Time `json:"expires_at"`
|
||||
ResolvedAt time.Time `json:"resolved_at,omitempty"`
|
||||
}
|
||||
|
||||
// ComplianceReport is the Shadow AI compliance report for GDPR/SOC2/EU AI Act.
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package shadow_ai
|
||||
|
||||
import (
|
||||
|
|
@ -14,9 +18,9 @@ import (
|
|||
|
||||
// CheckPointEnforcer is a stub implementation for Check Point firewalls.
|
||||
type CheckPointEnforcer struct {
|
||||
apiURL string
|
||||
apiKey string
|
||||
logger *slog.Logger
|
||||
apiURL string
|
||||
apiKey string
|
||||
logger *slog.Logger
|
||||
}
|
||||
|
||||
func NewCheckPointEnforcer() *CheckPointEnforcer {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package shadow_ai
|
||||
|
||||
import (
|
||||
|
|
@ -13,10 +17,10 @@ type PluginFactory func() interface{}
|
|||
// Thread-safe via sync.RWMutex.
|
||||
type PluginRegistry struct {
|
||||
mu sync.RWMutex
|
||||
plugins map[string]interface{} // vendor → plugin instance
|
||||
factories map[string]PluginFactory // "type_vendor" → factory
|
||||
configs map[string]*PluginConfig // vendor → config
|
||||
health map[string]*PluginHealth // vendor → health status
|
||||
plugins map[string]interface{} // vendor → plugin instance
|
||||
factories map[string]PluginFactory // "type_vendor" → factory
|
||||
configs map[string]*PluginConfig // vendor → config
|
||||
health map[string]*PluginHealth // vendor → health status
|
||||
logger *slog.Logger
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package shadow_ai
|
||||
|
||||
import (
|
||||
|
|
@ -36,7 +40,7 @@ func (m *mockFirewall) BlockDomain(_ context.Context, domain string, _ string) e
|
|||
return nil
|
||||
}
|
||||
|
||||
func (m *mockFirewall) UnblockIP(_ context.Context, _ string) error { return nil }
|
||||
func (m *mockFirewall) UnblockIP(_ context.Context, _ string) error { return nil }
|
||||
func (m *mockFirewall) UnblockDomain(_ context.Context, _ string) error { return nil }
|
||||
|
||||
func (m *mockFirewall) HealthCheck(_ context.Context) error {
|
||||
|
|
@ -61,8 +65,8 @@ func (m *mockEDR) IsolateHost(_ context.Context, hostname string) error {
|
|||
m.isolated = append(m.isolated, hostname)
|
||||
return nil
|
||||
}
|
||||
func (m *mockEDR) ReleaseHost(_ context.Context, _ string) error { return nil }
|
||||
func (m *mockEDR) KillProcess(_ context.Context, _ string, _ int) error { return nil }
|
||||
func (m *mockEDR) ReleaseHost(_ context.Context, _ string) error { return nil }
|
||||
func (m *mockEDR) KillProcess(_ context.Context, _ string, _ int) error { return nil }
|
||||
func (m *mockEDR) QuarantineFile(_ context.Context, _ string, _ string) error { return nil }
|
||||
|
||||
func (m *mockEDR) HealthCheck(_ context.Context) error {
|
||||
|
|
@ -87,8 +91,8 @@ func (m *mockGateway) BlockURL(_ context.Context, url string, _ string) error {
|
|||
m.blockedURLs = append(m.blockedURLs, url)
|
||||
return nil
|
||||
}
|
||||
func (m *mockGateway) UnblockURL(_ context.Context, _ string) error { return nil }
|
||||
func (m *mockGateway) BlockCategory(_ context.Context, _ string) error { return nil }
|
||||
func (m *mockGateway) UnblockURL(_ context.Context, _ string) error { return nil }
|
||||
func (m *mockGateway) BlockCategory(_ context.Context, _ string) error { return nil }
|
||||
|
||||
func (m *mockGateway) HealthCheck(_ context.Context) error {
|
||||
if !m.healthy {
|
||||
|
|
@ -1075,8 +1079,8 @@ func TestApproval_ExpireOverdue(t *testing.T) {
|
|||
|
||||
func TestApproval_Stats(t *testing.T) {
|
||||
ae := NewApprovalEngine()
|
||||
ae.SubmitRequest("u1", "d1", DataPublic) // auto
|
||||
ae.SubmitRequest("u2", "d2", DataInternal) // pending
|
||||
ae.SubmitRequest("u1", "d1", DataPublic) // auto
|
||||
ae.SubmitRequest("u2", "d2", DataInternal) // pending
|
||||
req := ae.SubmitRequest("u3", "d3", DataConfidential) // pending
|
||||
_ = ae.Deny(req.ID, "ciso", "no")
|
||||
|
||||
|
|
@ -1222,4 +1226,3 @@ func TestController_ReviewDocument_WithSecrets(t *testing.T) {
|
|||
t.Fatal("blocked docs should not create approval")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package shadow_ai
|
||||
|
||||
import (
|
||||
|
|
@ -19,7 +23,7 @@ type ShadowAIController struct {
|
|||
behavioral *BehavioralDetector
|
||||
docBridge *DocBridge
|
||||
approval *ApprovalEngine
|
||||
events []ShadowAIEvent // In-memory event store (bounded)
|
||||
events []ShadowAIEvent // In-memory event store (bounded)
|
||||
maxEvents int
|
||||
socEventFn func(source, severity, category, description string, meta map[string]string) // Bridge to SOC event bus
|
||||
logger *slog.Logger
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package sidecar
|
||||
|
||||
import (
|
||||
|
|
@ -42,15 +46,15 @@ func NewBusClient(baseURL, sensorID, apiKey string) *BusClient {
|
|||
// ingestPayload matches the SOC ingest API expected JSON.
|
||||
type ingestPayload struct {
|
||||
Source string `json:"source"`
|
||||
SensorID string `json:"sensor_id"`
|
||||
SensorKey string `json:"sensor_key,omitempty"`
|
||||
Severity string `json:"severity"`
|
||||
Category string `json:"category"`
|
||||
Subcategory string `json:"subcategory,omitempty"`
|
||||
Confidence float64 `json:"confidence"`
|
||||
Description string `json:"description"`
|
||||
SessionID string `json:"session_id,omitempty"`
|
||||
Metadata map[string]string `json:"metadata,omitempty"`
|
||||
SensorID string `json:"sensor_id"`
|
||||
SensorKey string `json:"sensor_key,omitempty"`
|
||||
Severity string `json:"severity"`
|
||||
Category string `json:"category"`
|
||||
Subcategory string `json:"subcategory,omitempty"`
|
||||
Confidence float64 `json:"confidence"`
|
||||
Description string `json:"description"`
|
||||
SessionID string `json:"session_id,omitempty"`
|
||||
Metadata map[string]string `json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
// SendEvent posts a SOCEvent to the Event Bus.
|
||||
|
|
@ -58,15 +62,15 @@ type ingestPayload struct {
|
|||
func (c *BusClient) SendEvent(ctx context.Context, evt *domsoc.SOCEvent) error {
|
||||
payload := ingestPayload{
|
||||
Source: string(evt.Source),
|
||||
SensorID: c.sensorID,
|
||||
SensorKey: c.apiKey,
|
||||
Severity: string(evt.Severity),
|
||||
Category: evt.Category,
|
||||
SensorID: c.sensorID,
|
||||
SensorKey: c.apiKey,
|
||||
Severity: string(evt.Severity),
|
||||
Category: evt.Category,
|
||||
Subcategory: evt.Subcategory,
|
||||
Confidence: evt.Confidence,
|
||||
Confidence: evt.Confidence,
|
||||
Description: evt.Description,
|
||||
SessionID: evt.SessionID,
|
||||
Metadata: evt.Metadata,
|
||||
SessionID: evt.SessionID,
|
||||
Metadata: evt.Metadata,
|
||||
}
|
||||
|
||||
body, err := json.Marshal(payload)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
// Package sidecar implements the Universal Sidecar (§5.5) — a zero-dependency
|
||||
// Go binary that runs alongside SENTINEL sensors, tails their STDOUT/logs,
|
||||
// and pushes parsed security events to the SOC Event Bus.
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package sidecar
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package sidecar
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package sidecar
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
// Package soc provides SOC analytics: event trends, severity distribution,
|
||||
// top sources, MITRE ATT&CK coverage, and time-series aggregation.
|
||||
package soc
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package soc
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package soc
|
||||
|
||||
import (
|
||||
|
|
@ -524,4 +528,3 @@ func TestE2E_CrescendoEscalation(t *testing.T) {
|
|||
assert.Equal(t, domsoc.SeverityCritical, lastInc.Severity)
|
||||
assert.Contains(t, lastInc.MITREMapping, "T1059")
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package soc
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package soc
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
// Package soc provides application services for the SENTINEL AI SOC subsystem.
|
||||
package soc
|
||||
|
||||
|
|
@ -29,14 +33,14 @@ const (
|
|||
// Service orchestrates the SOC event pipeline:
|
||||
// Step 0: Secret Scanner (INVARIANT) → DIP → Decision Logger → Persist → Correlation.
|
||||
type Service struct {
|
||||
mu sync.RWMutex
|
||||
repo domsoc.SOCRepository
|
||||
logger *audit.DecisionLogger
|
||||
rules []domsoc.SOCCorrelationRule
|
||||
mu sync.RWMutex
|
||||
repo domsoc.SOCRepository
|
||||
logger *audit.DecisionLogger
|
||||
rules []domsoc.SOCCorrelationRule
|
||||
playbookEngine *domsoc.PlaybookEngine
|
||||
executorRegistry *domsoc.ExecutorRegistry
|
||||
sensors map[string]*domsoc.Sensor
|
||||
draining bool // §15.7: graceful shutdown mode — rejects new events
|
||||
sensors map[string]*domsoc.Sensor
|
||||
draining bool // §15.7: graceful shutdown mode — rejects new events
|
||||
|
||||
// Alert Clustering engine (§7.6): groups related alerts.
|
||||
clusterEngine *domsoc.ClusterEngine
|
||||
|
|
@ -45,8 +49,8 @@ type Service struct {
|
|||
eventBus *domsoc.EventBus
|
||||
|
||||
// Rate limiting per sensor (§17.3): sensorID → timestamps of recent events.
|
||||
sensorRates map[string][]time.Time
|
||||
rateLimitDisabled bool
|
||||
sensorRates map[string][]time.Time
|
||||
rateLimitDisabled bool
|
||||
|
||||
// Sensor authentication (§17.3 T-01): sensorID → pre-shared key.
|
||||
sensorKeys map[string]string
|
||||
|
|
@ -85,9 +89,9 @@ func NewService(repo domsoc.SOCRepository, logger *audit.DecisionLogger) *Servic
|
|||
// Build executor registry with all SOAR action handlers
|
||||
reg := domsoc.NewExecutorRegistry()
|
||||
reg.Register(&domsoc.BlockIPExecutor{})
|
||||
reg.Register(domsoc.NewNotifyExecutor("")) // URL configured via SetNotifyURL()
|
||||
reg.Register(domsoc.NewNotifyExecutor("")) // URL configured via SetNotifyURL()
|
||||
reg.Register(domsoc.NewQuarantineExecutor())
|
||||
reg.Register(domsoc.NewEscalateExecutor("")) // URL configured via SetEscalateURL()
|
||||
reg.Register(domsoc.NewEscalateExecutor("")) // URL configured via SetEscalateURL()
|
||||
// Webhook executor configured separately via SetWebhookConfig()
|
||||
|
||||
// Create playbook engine with live executor handler (not just logging)
|
||||
|
|
@ -100,21 +104,21 @@ func NewService(repo domsoc.SOCRepository, logger *audit.DecisionLogger) *Servic
|
|||
)
|
||||
|
||||
return &Service{
|
||||
repo: repo,
|
||||
logger: logger,
|
||||
rules: domsoc.DefaultSOCCorrelationRules(),
|
||||
playbookEngine: pe,
|
||||
executorRegistry: reg,
|
||||
sensors: make(map[string]*domsoc.Sensor),
|
||||
clusterEngine: domsoc.NewClusterEngine(domsoc.DefaultClusterConfig()),
|
||||
eventBus: domsoc.NewEventBus(256),
|
||||
sensorRates: make(map[string][]time.Time),
|
||||
zeroG: domsoc.NewZeroGMode(),
|
||||
p2pSync: domsoc.NewP2PSyncService(),
|
||||
anomaly: domsoc.NewAnomalyDetector(),
|
||||
repo: repo,
|
||||
logger: logger,
|
||||
rules: domsoc.DefaultSOCCorrelationRules(),
|
||||
playbookEngine: pe,
|
||||
executorRegistry: reg,
|
||||
sensors: make(map[string]*domsoc.Sensor),
|
||||
clusterEngine: domsoc.NewClusterEngine(domsoc.DefaultClusterConfig()),
|
||||
eventBus: domsoc.NewEventBus(256),
|
||||
sensorRates: make(map[string][]time.Time),
|
||||
zeroG: domsoc.NewZeroGMode(),
|
||||
p2pSync: domsoc.NewP2PSyncService(),
|
||||
anomaly: domsoc.NewAnomalyDetector(),
|
||||
threatIntelEngine: domsoc.NewThreatIntelEngine(),
|
||||
retention: domsoc.NewDataRetentionPolicy(),
|
||||
scanSemaphore: make(chan struct{}, 8), // §20.1: max 8 concurrent scans
|
||||
retention: domsoc.NewDataRetentionPolicy(),
|
||||
scanSemaphore: make(chan struct{}, 8), // §20.1: max 8 concurrent scans
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -213,7 +217,6 @@ func (s *Service) TestWebhook() []WebhookResult {
|
|||
return wh.NotifyIncident("webhook_test", testIncident)
|
||||
}
|
||||
|
||||
|
||||
// Drain puts the service into drain mode (§15.7 Stage 1).
|
||||
// New events are rejected with ErrDraining; existing processing continues.
|
||||
func (s *Service) Drain() {
|
||||
|
|
@ -301,6 +304,7 @@ func (s *Service) runRetentionPurge() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// IngestEvent processes an incoming security event through the SOC pipeline.
|
||||
// Returns the event ID and any incident created by correlation.
|
||||
//
|
||||
|
|
@ -523,7 +527,7 @@ func (s *Service) isRateLimited(sensorID string) bool {
|
|||
pruned = append(pruned, ts)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
rateLimited := len(pruned) >= MaxEventsPerSecondPerSensor
|
||||
if !rateLimited {
|
||||
pruned = append(pruned, now)
|
||||
|
|
@ -768,9 +772,9 @@ func (s *Service) GetRecentDecisions(limit int) []map[string]any {
|
|||
return []map[string]any{
|
||||
{
|
||||
"total_decisions": s.logger.Count(),
|
||||
"hash_chain": s.logger.PrevHash(),
|
||||
"log_path": s.logger.Path(),
|
||||
"status": "operational",
|
||||
"hash_chain": s.logger.PrevHash(),
|
||||
"log_path": s.logger.Path(),
|
||||
"status": "operational",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -979,10 +983,10 @@ func (s *Service) ListIncidentsAdvanced(f IncidentFilter) (*IncidentFilterResult
|
|||
|
||||
// BulkAction defines a batch operation on incidents.
|
||||
type BulkAction struct {
|
||||
Action string `json:"action"` // assign, status, close, delete
|
||||
Action string `json:"action"` // assign, status, close, delete
|
||||
IncidentIDs []string `json:"incident_ids"`
|
||||
Value string `json:"value"` // analyst email, new status
|
||||
Actor string `json:"actor"` // who initiated
|
||||
Value string `json:"value"` // analyst email, new status
|
||||
Actor string `json:"actor"` // who initiated
|
||||
}
|
||||
|
||||
// BulkActionResult is the result of a batch operation.
|
||||
|
|
@ -1030,12 +1034,12 @@ type SLAThreshold struct {
|
|||
|
||||
// SLAStatus represents an incident's SLA compliance state.
|
||||
type SLAStatus struct {
|
||||
ResponseBreached bool `json:"response_breached"`
|
||||
ResolutionBreached bool `json:"resolution_breached"`
|
||||
ResponseRemaining float64 `json:"response_remaining_min"` // minutes remaining (negative = breached)
|
||||
ResponseBreached bool `json:"response_breached"`
|
||||
ResolutionBreached bool `json:"resolution_breached"`
|
||||
ResponseRemaining float64 `json:"response_remaining_min"` // minutes remaining (negative = breached)
|
||||
ResolutionRemaining float64 `json:"resolution_remaining_min"`
|
||||
ResponseTarget float64 `json:"response_target_min"`
|
||||
ResolutionTarget float64 `json:"resolution_target_min"`
|
||||
ResponseTarget float64 `json:"response_target_min"`
|
||||
ResolutionTarget float64 `json:"resolution_target_min"`
|
||||
}
|
||||
|
||||
// DefaultSLAThresholds returns SLA targets per severity.
|
||||
|
|
@ -1161,7 +1165,7 @@ func (s *Service) Dashboard(tenantID string) (*DashboardData, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
lastHourEvents, err := s.repo.CountEventsSince(tenantID, time.Now().Add(-1 * time.Hour))
|
||||
lastHourEvents, err := s.repo.CountEventsSince(tenantID, time.Now().Add(-1*time.Hour))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package soc
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package soc
|
||||
|
||||
import (
|
||||
|
|
@ -17,7 +21,7 @@ type STIXBundle struct {
|
|||
|
||||
// STIXObject represents a generic STIX 2.1 object.
|
||||
type STIXObject struct {
|
||||
Type string `json:"type"` // indicator, malware, attack-pattern, etc.
|
||||
Type string `json:"type"` // indicator, malware, attack-pattern, etc.
|
||||
ID string `json:"id"`
|
||||
Created time.Time `json:"created"`
|
||||
Modified time.Time `json:"modified"`
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package soc
|
||||
|
||||
import (
|
||||
|
|
@ -111,8 +115,8 @@ func TestProcessBundle_FiltersNonIndicators(t *testing.T) {
|
|||
Objects: []STIXObject{
|
||||
{Type: "indicator", Pattern: "[ipv4-addr:value = '10.0.0.1']", Modified: time.Now()},
|
||||
{Type: "malware", Name: "BadMalware"}, // should be skipped
|
||||
{Type: "indicator", Pattern: ""}, // empty pattern → skipped
|
||||
{Type: "attack-pattern", Name: "Phish"}, // should be skipped
|
||||
{Type: "indicator", Pattern: ""}, // empty pattern → skipped
|
||||
{Type: "attack-pattern", Name: "Phish"}, // should be skipped
|
||||
{Type: "indicator", Pattern: "[domain-name:value = 'bad.com']", Modified: time.Now()},
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
// Package soc provides a threat intelligence feed integration
|
||||
// for enriching SOC events and correlation rules.
|
||||
//
|
||||
|
|
@ -36,9 +40,9 @@ const (
|
|||
type IOC struct {
|
||||
Type IOCType `json:"type"`
|
||||
Value string `json:"value"`
|
||||
Source string `json:"source"` // Feed name
|
||||
Severity string `json:"severity"` // critical/high/medium/low
|
||||
Tags []string `json:"tags"` // MITRE ATT&CK, campaign, etc.
|
||||
Source string `json:"source"` // Feed name
|
||||
Severity string `json:"severity"` // critical/high/medium/low
|
||||
Tags []string `json:"tags"` // MITRE ATT&CK, campaign, etc.
|
||||
FirstSeen time.Time `json:"first_seen"`
|
||||
LastSeen time.Time `json:"last_seen"`
|
||||
Confidence float64 `json:"confidence"` // 0.0-1.0
|
||||
|
|
@ -46,31 +50,31 @@ type IOC struct {
|
|||
|
||||
// ThreatFeed represents a configured threat intelligence source.
|
||||
type ThreatFeed struct {
|
||||
Name string `json:"name"`
|
||||
URL string `json:"url"`
|
||||
Type string `json:"type"` // stix, csv, json
|
||||
Enabled bool `json:"enabled"`
|
||||
Interval time.Duration `json:"interval"`
|
||||
APIKey string `json:"api_key,omitempty"`
|
||||
LastFetch time.Time `json:"last_fetch"`
|
||||
IOCCount int `json:"ioc_count"`
|
||||
LastError string `json:"last_error,omitempty"`
|
||||
Name string `json:"name"`
|
||||
URL string `json:"url"`
|
||||
Type string `json:"type"` // stix, csv, json
|
||||
Enabled bool `json:"enabled"`
|
||||
Interval time.Duration `json:"interval"`
|
||||
APIKey string `json:"api_key,omitempty"`
|
||||
LastFetch time.Time `json:"last_fetch"`
|
||||
IOCCount int `json:"ioc_count"`
|
||||
LastError string `json:"last_error,omitempty"`
|
||||
}
|
||||
|
||||
// ─── Threat Intel Store ─────────────────────────────────
|
||||
|
||||
// ThreatIntelStore manages IOCs from multiple feeds.
|
||||
type ThreatIntelStore struct {
|
||||
mu sync.RWMutex
|
||||
iocs map[string]*IOC // key: type:value
|
||||
feeds []ThreatFeed
|
||||
mu sync.RWMutex
|
||||
iocs map[string]*IOC // key: type:value
|
||||
feeds []ThreatFeed
|
||||
client *http.Client
|
||||
|
||||
// Stats
|
||||
TotalIOCs int `json:"total_iocs"`
|
||||
TotalFeeds int `json:"total_feeds"`
|
||||
TotalIOCs int `json:"total_iocs"`
|
||||
TotalFeeds int `json:"total_feeds"`
|
||||
LastRefresh time.Time `json:"last_refresh"`
|
||||
MatchesFound int64 `json:"matches_found"`
|
||||
MatchesFound int64 `json:"matches_found"`
|
||||
}
|
||||
|
||||
// NewThreatIntelStore creates an empty threat intel store.
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package soc
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
// Package webhook provides outbound SOAR webhook notifications
|
||||
// for the SOC pipeline. Fires HTTP POST on incident creation/update.
|
||||
package soc
|
||||
|
|
@ -38,8 +42,8 @@ type WebhookConfig struct {
|
|||
type WebhookPayload struct {
|
||||
EventType string `json:"event_type"` // incident_created, incident_updated, sensor_offline
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
Source string `json:"source"`
|
||||
Data json.RawMessage `json:"data"`
|
||||
Source string `json:"source"`
|
||||
Data json.RawMessage `json:"data"`
|
||||
}
|
||||
|
||||
// WebhookResult tracks delivery status per endpoint.
|
||||
|
|
@ -80,8 +84,6 @@ func NewWebhookNotifier(config WebhookConfig) *WebhookNotifier {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// NotifyIncident sends an incident webhook to all configured endpoints.
|
||||
// Non-blocking: fires goroutines for each endpoint.
|
||||
func (w *WebhookNotifier) NotifyIncident(eventType string, incident *domsoc.Incident) []WebhookResult {
|
||||
|
|
@ -105,7 +107,7 @@ func (w *WebhookNotifier) NotifyIncident(eventType string, incident *domsoc.Inci
|
|||
EventType: eventType,
|
||||
Timestamp: time.Now().UTC(),
|
||||
Source: "sentinel-soc",
|
||||
Data: data,
|
||||
Data: data,
|
||||
}
|
||||
|
||||
body, err := json.Marshal(payload)
|
||||
|
|
@ -151,7 +153,7 @@ func (w *WebhookNotifier) NotifySensorOffline(sensor domsoc.Sensor) []WebhookRes
|
|||
EventType: "sensor_offline",
|
||||
Timestamp: time.Now().UTC(),
|
||||
Source: "sentinel-soc",
|
||||
Data: data,
|
||||
Data: data,
|
||||
}
|
||||
|
||||
body, _ := json.Marshal(payload)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
// Package tools — Apathy Detection and Apoptosis Recovery (DIP H1.4).
|
||||
//
|
||||
// This file implements:
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package tools
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package tools
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -1,12 +1,16 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package tools
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/syntrex-lab/gomcp/internal/infrastructure/sqlite"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/syntrex-lab/gomcp/internal/infrastructure/sqlite"
|
||||
)
|
||||
|
||||
func newTestCausalService(t *testing.T) *CausalService {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package tools
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -1,12 +1,16 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package tools
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/syntrex-lab/gomcp/internal/infrastructure/sqlite"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/syntrex-lab/gomcp/internal/infrastructure/sqlite"
|
||||
)
|
||||
|
||||
func newTestCrystalService(t *testing.T) *CrystalService {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package tools
|
||||
|
||||
// DecisionRecorder is the interface for recording tamper-evident decisions (v3.7).
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package tools
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
// Package tools provides application-level tool services that bridge
|
||||
// domain logic with MCP tool handlers.
|
||||
package tools
|
||||
|
|
|
|||
|
|
@ -1,13 +1,17 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package tools
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/syntrex-lab/gomcp/internal/domain/memory"
|
||||
"github.com/syntrex-lab/gomcp/internal/infrastructure/sqlite"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/syntrex-lab/gomcp/internal/domain/memory"
|
||||
"github.com/syntrex-lab/gomcp/internal/infrastructure/sqlite"
|
||||
)
|
||||
|
||||
func newTestFactService(t *testing.T) *FactService {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
// Package tools provides application-level tool services.
|
||||
// This file adds the Intent Distiller MCP tool integration (DIP H0.2).
|
||||
package tools
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package tools
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package tools
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -1,13 +1,17 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package tools
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/syntrex-lab/gomcp/internal/domain/session"
|
||||
"github.com/syntrex-lab/gomcp/internal/infrastructure/sqlite"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/syntrex-lab/gomcp/internal/domain/session"
|
||||
"github.com/syntrex-lab/gomcp/internal/infrastructure/sqlite"
|
||||
)
|
||||
|
||||
func newTestSessionService(t *testing.T) *SessionService {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package tools
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package tools
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -1,12 +1,16 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package tools
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/syntrex-lab/gomcp/internal/infrastructure/sqlite"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/syntrex-lab/gomcp/internal/infrastructure/sqlite"
|
||||
)
|
||||
|
||||
func newTestSystemService(t *testing.T) *SystemService {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package config
|
||||
|
||||
import (
|
||||
|
|
@ -10,34 +14,34 @@ import (
|
|||
|
||||
// Config is the root configuration loaded from syntrex.yaml (§19.3, §21).
|
||||
type Config struct {
|
||||
Server ServerConfig `yaml:"server"`
|
||||
SOC SOCConfig `yaml:"soc"`
|
||||
RBAC RBACConfig `yaml:"rbac"`
|
||||
Webhooks []WebhookConfig `yaml:"webhooks"`
|
||||
Server ServerConfig `yaml:"server"`
|
||||
SOC SOCConfig `yaml:"soc"`
|
||||
RBAC RBACConfig `yaml:"rbac"`
|
||||
Webhooks []WebhookConfig `yaml:"webhooks"`
|
||||
ThreatIntel ThreatIntelConfig `yaml:"threat_intel"`
|
||||
Sovereign SovereignConfig `yaml:"sovereign"`
|
||||
P2P P2PConfig `yaml:"p2p"`
|
||||
Logging LoggingConfig `yaml:"logging"`
|
||||
Sovereign SovereignConfig `yaml:"sovereign"`
|
||||
P2P P2PConfig `yaml:"p2p"`
|
||||
Logging LoggingConfig `yaml:"logging"`
|
||||
}
|
||||
|
||||
// ServerConfig defines HTTP server settings.
|
||||
type ServerConfig struct {
|
||||
Port int `yaml:"port"`
|
||||
ReadTimeout time.Duration `yaml:"read_timeout"`
|
||||
WriteTimeout time.Duration `yaml:"write_timeout"`
|
||||
RateLimitPerMin int `yaml:"rate_limit_per_min"`
|
||||
CORSAllowOrigins []string `yaml:"cors_allow_origins"`
|
||||
Port int `yaml:"port"`
|
||||
ReadTimeout time.Duration `yaml:"read_timeout"`
|
||||
WriteTimeout time.Duration `yaml:"write_timeout"`
|
||||
RateLimitPerMin int `yaml:"rate_limit_per_min"`
|
||||
CORSAllowOrigins []string `yaml:"cors_allow_origins"`
|
||||
}
|
||||
|
||||
// SOCConfig defines SOC pipeline settings (§7).
|
||||
type SOCConfig struct {
|
||||
DataDir string `yaml:"data_dir"`
|
||||
MaxEventsPerHour int `yaml:"max_events_per_hour"`
|
||||
ClusterEnabled bool `yaml:"cluster_enabled"`
|
||||
DataDir string `yaml:"data_dir"`
|
||||
MaxEventsPerHour int `yaml:"max_events_per_hour"`
|
||||
ClusterEnabled bool `yaml:"cluster_enabled"`
|
||||
ClusterEps float64 `yaml:"cluster_eps"`
|
||||
ClusterMinPts int `yaml:"cluster_min_pts"`
|
||||
KillChainEnabled bool `yaml:"kill_chain_enabled"`
|
||||
SSEBufferSize int `yaml:"sse_buffer_size"`
|
||||
ClusterMinPts int `yaml:"cluster_min_pts"`
|
||||
KillChainEnabled bool `yaml:"kill_chain_enabled"`
|
||||
SSEBufferSize int `yaml:"sse_buffer_size"`
|
||||
}
|
||||
|
||||
// RBACConfig defines API key authentication (§17).
|
||||
|
|
@ -65,9 +69,9 @@ type WebhookConfig struct {
|
|||
|
||||
// ThreatIntelConfig defines IOC feed sources (§6).
|
||||
type ThreatIntelConfig struct {
|
||||
Enabled bool `yaml:"enabled"`
|
||||
Enabled bool `yaml:"enabled"`
|
||||
RefreshInterval time.Duration `yaml:"refresh_interval"`
|
||||
Feeds []FeedConfig `yaml:"feeds"`
|
||||
Feeds []FeedConfig `yaml:"feeds"`
|
||||
}
|
||||
|
||||
// FeedConfig is a single threat intel feed.
|
||||
|
|
@ -80,8 +84,8 @@ type FeedConfig struct {
|
|||
|
||||
// SovereignConfig implements §21 — air-gapped deployment mode.
|
||||
type SovereignConfig struct {
|
||||
Enabled bool `yaml:"enabled"`
|
||||
Mode string `yaml:"mode"` // airgap, restricted, open
|
||||
Enabled bool `yaml:"enabled"`
|
||||
Mode string `yaml:"mode"` // airgap, restricted, open
|
||||
DisableExternalAPI bool `yaml:"disable_external_api"`
|
||||
DisableTelemetry bool `yaml:"disable_telemetry"`
|
||||
LocalModelsOnly bool `yaml:"local_models_only"`
|
||||
|
|
@ -108,7 +112,7 @@ type PeerConfig struct {
|
|||
|
||||
// LoggingConfig defines structured logging settings.
|
||||
type LoggingConfig struct {
|
||||
Level string `yaml:"level"` // debug, info, warn, error
|
||||
Level string `yaml:"level"` // debug, info, warn, error
|
||||
Format string `yaml:"format"` // json, text
|
||||
AccessLog bool `yaml:"access_log"`
|
||||
AuditLog bool `yaml:"audit_log"`
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package config
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
// Package alert defines the Alert domain entity and severity levels
|
||||
// for the DIP-Watcher proactive monitoring system.
|
||||
package alert
|
||||
|
|
|
|||
|
|
@ -1,12 +1,16 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package alert_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/syntrex-lab/gomcp/internal/domain/alert"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/syntrex-lab/gomcp/internal/domain/alert"
|
||||
)
|
||||
|
||||
func TestAlert_New(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package alert
|
||||
|
||||
import "sync"
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
// Package causal defines domain entities for causal reasoning chains.
|
||||
package causal
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package causal
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
// Package circuitbreaker implements a state machine that controls
|
||||
// the health of recursive pipelines (DIP H1.1).
|
||||
//
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package circuitbreaker
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
// Package context defines domain entities for the Proactive Context Engine.
|
||||
// The engine automatically injects relevant memory facts into every tool response,
|
||||
// ensuring the LLM always has context without explicitly requesting it.
|
||||
|
|
|
|||
|
|
@ -1,12 +1,16 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package context
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/syntrex-lab/gomcp/internal/domain/memory"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/syntrex-lab/gomcp/internal/domain/memory"
|
||||
)
|
||||
|
||||
// --- ScoredFact tests ---
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package context
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package context
|
||||
|
||||
import (
|
||||
|
|
@ -5,9 +9,9 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/syntrex-lab/gomcp/internal/domain/memory"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/syntrex-lab/gomcp/internal/domain/memory"
|
||||
)
|
||||
|
||||
// --- RelevanceScorer tests ---
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
// Package crystal defines domain entities for code crystal indexing (C³).
|
||||
package crystal
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package crystal
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package engines
|
||||
|
||||
import (
|
||||
|
|
@ -9,9 +13,9 @@ import (
|
|||
type EngineStatus string
|
||||
|
||||
const (
|
||||
EngineHealthy EngineStatus = "HEALTHY"
|
||||
EngineDegraded EngineStatus = "DEGRADED"
|
||||
EngineOffline EngineStatus = "OFFLINE"
|
||||
EngineHealthy EngineStatus = "HEALTHY"
|
||||
EngineDegraded EngineStatus = "DEGRADED"
|
||||
EngineOffline EngineStatus = "OFFLINE"
|
||||
EngineInitializing EngineStatus = "INITIALIZING"
|
||||
)
|
||||
|
||||
|
|
@ -84,10 +88,10 @@ type BlockedIP struct {
|
|||
// StubSentinelCore is a no-op sentinel-core when Rust engine is not deployed.
|
||||
type StubSentinelCore struct{}
|
||||
|
||||
func NewStubSentinelCore() *StubSentinelCore { return &StubSentinelCore{} }
|
||||
func (s *StubSentinelCore) Name() string { return "sentinel-core-stub" }
|
||||
func NewStubSentinelCore() *StubSentinelCore { return &StubSentinelCore{} }
|
||||
func (s *StubSentinelCore) Name() string { return "sentinel-core-stub" }
|
||||
func (s *StubSentinelCore) Status() EngineStatus { return EngineOffline }
|
||||
func (s *StubSentinelCore) Version() string { return "stub-1.0" }
|
||||
func (s *StubSentinelCore) Version() string { return "stub-1.0" }
|
||||
|
||||
func (s *StubSentinelCore) ScanPrompt(_ context.Context, _ string) (*ScanResult, error) {
|
||||
return &ScanResult{
|
||||
|
|
@ -114,10 +118,10 @@ func (s *StubSentinelCore) ScanResponse(_ context.Context, _ string) (*ScanResul
|
|||
// StubShield is a no-op shield when C++ engine is not deployed.
|
||||
type StubShield struct{}
|
||||
|
||||
func NewStubShield() *StubShield { return &StubShield{} }
|
||||
func (s *StubShield) Name() string { return "shield-stub" }
|
||||
func NewStubShield() *StubShield { return &StubShield{} }
|
||||
func (s *StubShield) Name() string { return "shield-stub" }
|
||||
func (s *StubShield) Status() EngineStatus { return EngineOffline }
|
||||
func (s *StubShield) Version() string { return "stub-1.0" }
|
||||
func (s *StubShield) Version() string { return "stub-1.0" }
|
||||
|
||||
func (s *StubShield) InspectTraffic(_ context.Context, _ []byte, _ map[string]string) (*ScanResult, error) {
|
||||
return &ScanResult{
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package engines
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
//go:build sentinel_native
|
||||
|
||||
package engines
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
//go:build !sentinel_native
|
||||
|
||||
package engines
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
//go:build shield_native
|
||||
|
||||
package engines
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
//go:build !shield_native
|
||||
|
||||
package engines
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
// Package entropy implements the Entropy Gate — a DIP H0.3 component
|
||||
// that measures Shannon entropy of text signals and blocks anomalous patterns.
|
||||
//
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package entropy
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2026 Syntrex Lab. All rights reserved.
|
||||
// Use of this source code is governed by an Apache-2.0 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
// Package eval implements the CLASP Evaluation Framework (SDD-005).
|
||||
//
|
||||
// Provides structured capability scoring for SOC agents across 6 dimensions
|
||||
|
|
@ -52,23 +56,23 @@ type Score struct {
|
|||
|
||||
// EvalScenario defines a test scenario for agent evaluation.
|
||||
type EvalScenario struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Stage Stage `json:"stage"`
|
||||
Description string `json:"description"`
|
||||
Inputs []string `json:"inputs"`
|
||||
Expected string `json:"expected"`
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Stage Stage `json:"stage"`
|
||||
Description string `json:"description"`
|
||||
Inputs []string `json:"inputs"`
|
||||
Expected string `json:"expected"`
|
||||
Dimensions []Dimension `json:"dimensions"` // Which dimensions this tests
|
||||
}
|
||||
|
||||
// EvalResult represents the outcome of evaluating an agent on a scenario.
|
||||
type EvalResult struct {
|
||||
AgentID string `json:"agent_id"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
ScenarioID string `json:"scenario_id"`
|
||||
Scores map[Dimension]Score `json:"scores"`
|
||||
OverallL int `json:"overall_l"` // 1-5 aggregate
|
||||
JudgeModel string `json:"judge_model,omitempty"`
|
||||
AgentID string `json:"agent_id"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
ScenarioID string `json:"scenario_id"`
|
||||
Scores map[Dimension]Score `json:"scores"`
|
||||
OverallL int `json:"overall_l"` // 1-5 aggregate
|
||||
JudgeModel string `json:"judge_model,omitempty"`
|
||||
}
|
||||
|
||||
// ComputeOverall calculates the aggregate maturity level (average, rounded down).
|
||||
|
|
@ -86,12 +90,12 @@ func (r *EvalResult) ComputeOverall() int {
|
|||
|
||||
// AgentProfile aggregates multiple EvalResults into a capability profile.
|
||||
type AgentProfile struct {
|
||||
AgentID string `json:"agent_id"`
|
||||
Results []EvalResult `json:"results"`
|
||||
AgentID string `json:"agent_id"`
|
||||
Results []EvalResult `json:"results"`
|
||||
Averages map[Dimension]float64 `json:"averages"`
|
||||
OverallL int `json:"overall_l"`
|
||||
EvalCount int `json:"eval_count"`
|
||||
LastEvalAt time.Time `json:"last_eval_at"`
|
||||
OverallL int `json:"overall_l"`
|
||||
EvalCount int `json:"eval_count"`
|
||||
LastEvalAt time.Time `json:"last_eval_at"`
|
||||
}
|
||||
|
||||
// ComputeAverages calculates per-dimension average scores across all results.
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue