Files
ja4sentinel/internal/capture/capture_test.go
Jacquin Antoine efd4481729 feat: implémentation complète du pipeline JA4 + Docker + tests
Nouveaux modules:
- cmd/ja4sentinel/main.go : point d'entrée avec pipeline capture→parse→fingerprint→output
- internal/config/loader.go : chargement YAML + env (JA4SENTINEL_*) + validation
- internal/tlsparse/parser.go : extraction ClientHello avec suivi d'état de flux (NEW/WAIT_CLIENT_HELLO/JA4_DONE)
- internal/fingerprint/engine.go : génération JA4/JA3 via psanford/tlsfingerprint
- internal/output/writers.go : StdoutWriter, FileWriter, UnixSocketWriter, MultiWriter

Infrastructure:
- Dockerfile (multi-stage), Dockerfile.dev, Dockerfile.test-server
- Makefile (build, test, lint, docker-build-*)
- docker-compose.test.yml pour tests d'intégration
- README.md (276 lignes) avec architecture, config, exemples

API (api/types.go):
- Ajout Close() aux interfaces Capture et Parser
- Ajout FlowTimeoutSec dans Config (défaut: 30s, env: JA4SENTINEL_FLOW_TIMEOUT)
- ServiceLog: +Timestamp, +TraceID, +ConnID
- LogRecord: champs flatten (ip_meta_*, tcp_meta_*, ja4*)
- Helper NewLogRecord() pour conversion TLSClientHello+Fingerprints→LogRecord

Architecture (architecture.yml):
- Documentation module logging + interfaces LoggerFactory/Logger
- Section service.systemd complète (unit, security, capabilities)
- Section logging.strategy (JSON lines, champs, règles)
- api.Config: +FlowTimeoutSec documenté

Fixes/cleanup:
- Suppression internal/api/types.go (consolidé dans api/types.go)
- Correction imports logging (ja4sentinel/api)
- .dockerignore / .gitignore
- config.yml.example

Tests:
- Tous les modules ont leurs tests (*_test.go)
- Tests unitaires : capture, config, fingerprint, output, tlsparse
- Tests d'intégration via docker-compose.test.yml

Build:
- Binaires dans dist/ (make build → dist/ja4sentinel)
- Docker runtime avec COPY --from=builder /app/dist/

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-02-25 20:02:52 +01:00

82 lines
1.6 KiB
Go

package capture
import (
"testing"
)
func TestBuildBPFForPorts(t *testing.T) {
tests := []struct {
name string
ports []uint16
want string
}{
{
name: "single port",
ports: []uint16{443},
want: "(tcp port 443)",
},
{
name: "multiple ports",
ports: []uint16{443, 8443},
want: "(tcp port 443) or (tcp port 8443)",
},
{
name: "no ports",
ports: []uint16{},
want: "tcp",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := buildBPFForPorts(tt.ports)
if got != tt.want {
t.Errorf("buildBPFForPorts() = %v, want %v", got, tt.want)
}
})
}
}
func TestJoinString(t *testing.T) {
tests := []struct {
name string
parts []string
sep string
want string
}{
{
name: "empty slices",
parts: []string{},
sep: ", ",
want: "",
},
{
name: "single element",
parts: []string{"hello"},
sep: ", ",
want: "hello",
},
{
name: "multiple elements",
parts: []string{"hello", "world", "test"},
sep: ", ",
want: "hello, world, test",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := joinString(tt.parts, tt.sep)
if got != tt.want {
t.Errorf("joinString() = %v, want %v", got, tt.want)
}
})
}
}
// Tests d'intégration nécessitant une interface valide seront à faire dans des environnements de test appropriés
// car la capture réseau nécessite des permissions élevées
func TestCaptureIntegration(t *testing.T) {
t.Skip("Skipping integration test requiring network access and elevated privileges")
}