WitNote / internal /cli /report /security_test.go
AUXteam's picture
Upload folder using huggingface_hub
6a7089a verified
package report
import (
"os"
"path/filepath"
"testing"
"github.com/pinchtab/pinchtab/internal/config"
)
func TestAssessSecurityWarnings(t *testing.T) {
t.Run("safe local defaults stay quiet", func(t *testing.T) {
cfg := &config.RuntimeConfig{
Bind: "127.0.0.1",
Token: "secret",
AttachAllowHosts: []string{"127.0.0.1", "localhost", "::1"},
AttachAllowSchemes: []string{"ws", "wss"},
IDPI: config.IDPIConfig{
Enabled: true,
AllowedDomains: []string{"127.0.0.1", "localhost", "::1"},
StrictMode: true,
ScanContent: true,
WrapContent: true,
},
}
warnings := assessSecurityWarnings(cfg)
if len(warnings) != 0 {
t.Fatalf("expected no warnings, got %+v", warnings)
}
})
t.Run("website whitelist missing and other security gaps are flagged", func(t *testing.T) {
cfg := &config.RuntimeConfig{
Bind: "0.0.0.0",
Token: "",
AllowEvaluate: true,
AllowDownload: true,
AttachEnabled: true,
AttachAllowHosts: []string{"localhost", "chrome.internal"},
IDPI: config.IDPIConfig{
Enabled: true,
},
}
warnings := assessSecurityWarnings(cfg)
ids := make(map[string]bool, len(warnings))
for _, warning := range warnings {
ids[warning.ID] = true
}
for _, expected := range []string{
"sensitive_endpoints_enabled",
"api_auth_disabled",
"sensitive_endpoints_without_auth",
"non_loopback_bind",
"idpi_whitelist_not_set",
"idpi_warn_mode",
"idpi_content_protection_disabled",
"attach_external_hosts",
} {
if !ids[expected] {
t.Fatalf("expected warning %q, got %+v", expected, warnings)
}
}
})
t.Run("wildcard whitelist is warned", func(t *testing.T) {
cfg := &config.RuntimeConfig{
Bind: "127.0.0.1",
Token: "secret",
IDPI: config.IDPIConfig{
Enabled: true,
AllowedDomains: []string{"*"},
StrictMode: true,
ScanContent: true,
},
}
warnings := assessSecurityWarnings(cfg)
ids := make(map[string]bool, len(warnings))
for _, warning := range warnings {
ids[warning.ID] = true
}
if !ids["idpi_whitelist_allows_all"] {
t.Fatalf("expected wildcard whitelist warning, got %+v", warnings)
}
})
t.Run("disabled IDPI is warned", func(t *testing.T) {
cfg := &config.RuntimeConfig{
Bind: "127.0.0.1",
Token: "secret",
AttachAllowHosts: []string{"127.0.0.1", "localhost", "::1"},
AttachAllowSchemes: []string{"ws", "wss"},
}
warnings := assessSecurityWarnings(cfg)
ids := make(map[string]bool, len(warnings))
for _, warning := range warnings {
ids[warning.ID] = true
}
if !ids["idpi_disabled"] {
t.Fatalf("expected idpi_disabled warning, got %+v", warnings)
}
})
}
func TestAssessSecurityPosture(t *testing.T) {
t.Run("fully locked local config scores all defaults", func(t *testing.T) {
cfg := &config.RuntimeConfig{
Bind: "127.0.0.1",
Token: "secret",
AttachAllowHosts: []string{"127.0.0.1", "localhost", "::1"},
AttachAllowSchemes: []string{"ws", "wss"},
IDPI: config.IDPIConfig{
Enabled: true,
AllowedDomains: []string{"127.0.0.1", "localhost", "::1"},
StrictMode: true,
ScanContent: true,
WrapContent: true,
},
}
posture := assessSecurityPosture(cfg)
if posture.Passed != posture.Total {
t.Fatalf("expected all checks to pass, got %d/%d", posture.Passed, posture.Total)
}
if posture.Level != "LOCKED" {
t.Fatalf("expected LOCKED posture, got %q", posture.Level)
}
})
t.Run("exposed config drops posture score", func(t *testing.T) {
cfg := &config.RuntimeConfig{
Bind: "0.0.0.0",
AllowEvaluate: true,
AllowDownload: true,
AttachEnabled: true,
AttachAllowHosts: []string{"chrome.internal"},
IDPI: config.IDPIConfig{
Enabled: true,
},
}
posture := assessSecurityPosture(cfg)
if posture.Passed >= 3 {
t.Fatalf("expected exposed posture below 3 passed checks, got %d/%d", posture.Passed, posture.Total)
}
if posture.Level != "EXPOSED" {
t.Fatalf("expected EXPOSED posture, got %q", posture.Level)
}
})
}
func TestApplyRecommendedSecurityDefaults(t *testing.T) {
allowEvaluate := true
attachEnabled := true
fc := &config.FileConfig{
Server: config.ServerConfig{
Port: "9999",
Bind: "0.0.0.0",
Token: "secret",
},
Security: config.SecurityConfig{
AllowEvaluate: &allowEvaluate,
Attach: config.AttachConfig{
Enabled: &attachEnabled,
AllowHosts: []string{"chrome.internal"},
},
IDPI: config.IDPIConfig{
Enabled: false,
},
},
}
applyRecommendedSecurityDefaults(fc)
if fc.Server.Port != "9999" {
t.Fatalf("expected port to be preserved, got %q", fc.Server.Port)
}
if fc.Server.Token != "secret" {
t.Fatalf("expected token to be preserved, got %q", fc.Server.Token)
}
if fc.Server.Bind != "127.0.0.1" {
t.Fatalf("expected bind to reset to loopback, got %q", fc.Server.Bind)
}
if fc.Security.AllowEvaluate == nil || *fc.Security.AllowEvaluate {
t.Fatalf("expected allowEvaluate to reset to false, got %+v", fc.Security.AllowEvaluate)
}
if !fc.Security.IDPI.Enabled {
t.Fatalf("expected idpi to be enabled")
}
}
func TestApplyRecommendedSecurityDefaults_GeneratesTokenWhenMissing(t *testing.T) {
fc := &config.FileConfig{}
applyRecommendedSecurityDefaults(fc)
if fc.Server.Token == "" {
t.Fatalf("expected generated token, got empty")
}
}
func TestRestoreSecurityDefaults(t *testing.T) {
tmpDir := t.TempDir()
configPath := filepath.Join(tmpDir, "config.json")
t.Setenv("PINCHTAB_CONFIG", configPath)
allowEvaluate := true
attachEnabled := true
fc := &config.FileConfig{
Server: config.ServerConfig{
Port: "9999",
Bind: "0.0.0.0",
Token: "secret",
},
Security: config.SecurityConfig{
AllowEvaluate: &allowEvaluate,
Attach: config.AttachConfig{
Enabled: &attachEnabled,
AllowHosts: []string{"chrome.internal"},
},
IDPI: config.IDPIConfig{
Enabled: false,
},
},
}
if err := config.SaveFileConfig(fc, configPath); err != nil {
t.Fatalf("SaveFileConfig() error = %v", err)
}
gotPath, changed, err := restoreSecurityDefaults()
if err != nil {
t.Fatalf("restoreSecurityDefaults() error = %v", err)
}
if gotPath != configPath {
t.Fatalf("restoreSecurityDefaults() path = %q, want %q", gotPath, configPath)
}
if !changed {
t.Fatalf("restoreSecurityDefaults() changed = false, want true")
}
saved, err := os.ReadFile(configPath)
if err != nil {
t.Fatalf("ReadFile() error = %v", err)
}
loaded := &config.FileConfig{}
if err := config.PatchConfigJSON(loaded, string(saved)); err != nil {
t.Fatalf("PatchConfigJSON() error = %v", err)
}
if loaded.Server.Port != "9999" {
t.Fatalf("expected port to be preserved, got %q", loaded.Server.Port)
}
if loaded.Server.Token != "secret" {
t.Fatalf("expected token to be preserved, got %q", loaded.Server.Token)
}
if loaded.Server.Bind != "127.0.0.1" {
t.Fatalf("expected bind to be restored, got %q", loaded.Server.Bind)
}
if !loaded.Security.IDPI.Enabled {
t.Fatalf("expected idpi to be enabled after restore")
}
}
func TestRestoreSecurityDefaults_TokenOnlyChangeIsSaved(t *testing.T) {
tmpDir := t.TempDir()
configPath := filepath.Join(tmpDir, "config.json")
t.Setenv("PINCHTAB_CONFIG", configPath)
fc := config.DefaultFileConfig()
fc.Server.Token = ""
if err := config.SaveFileConfig(&fc, configPath); err != nil {
t.Fatalf("SaveFileConfig() error = %v", err)
}
_, changed, err := restoreSecurityDefaults()
if err != nil {
t.Fatalf("restoreSecurityDefaults() error = %v", err)
}
if !changed {
t.Fatalf("restoreSecurityDefaults() changed = false, want true")
}
loaded, _, err := config.LoadFileConfig()
if err != nil {
t.Fatalf("LoadFileConfig() error = %v", err)
}
if loaded.Server.Token == "" {
t.Fatalf("expected generated token to be persisted")
}
}