refactor(ax): round 6 AX sweep — usage examples, test coverage, package docs
- Add usage-example comments (AX-2) to all private run* and add*Command functions in cmd/security and cmd/metrics - Add package-level doc comment to empty cmd/security/cmd.go (AX-3) - Add usage-example comment to cmd/rag/cmd.go re-export - Add Bad and Ugly test categories to ai/metrics_test.go (AX-10): TestMetrics_Record_Bad_DirectoryAsFile, TestMetrics_ReadEvents_Bad_InvalidHome, TestMetrics_Record_Ugly_ConcurrentWrites - Document the embed-bench init() side-effect with intent comment (AX-5) Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
bc3b36c3da
commit
45e76101bf
10 changed files with 110 additions and 1 deletions
|
|
@ -156,6 +156,64 @@ func TestMetrics_ReadEvents_Good_FiltersBySince(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestMetrics_Record_Bad_DirectoryAsFile(t *testing.T) {
|
||||
// If the home directory resolution fails, Record must return an error.
|
||||
origHome := os.Getenv("HOME")
|
||||
os.Setenv("HOME", "/dev/null/nonexistent")
|
||||
t.Cleanup(func() { os.Setenv("HOME", origHome) })
|
||||
|
||||
event := Event{Type: "bad_test"}
|
||||
err := Record(event)
|
||||
if err == nil {
|
||||
t.Error("expected error when home directory is invalid, got nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMetrics_ReadEvents_Bad_InvalidHome(t *testing.T) {
|
||||
// ReadEvents must propagate the error when home resolution fails.
|
||||
origHome := os.Getenv("HOME")
|
||||
os.Setenv("HOME", "/dev/null/nonexistent")
|
||||
t.Cleanup(func() { os.Setenv("HOME", origHome) })
|
||||
|
||||
_, err := ReadEvents(time.Now().Add(-time.Hour))
|
||||
if err == nil {
|
||||
t.Error("expected error when home directory is invalid, got nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMetrics_Record_Ugly_ConcurrentWrites(t *testing.T) {
|
||||
// Concurrent writes must not corrupt the JSONL file — all events must be readable.
|
||||
withTempHome(t)
|
||||
|
||||
const goroutines = 10
|
||||
const eventsPerGoroutine = 20
|
||||
|
||||
done := make(chan struct{}, goroutines)
|
||||
for range goroutines {
|
||||
go func() {
|
||||
defer func() { done <- struct{}{} }()
|
||||
for range eventsPerGoroutine {
|
||||
if err := Record(Event{Type: "concurrent"}); err != nil {
|
||||
t.Errorf("concurrent Record: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
for range goroutines {
|
||||
<-done
|
||||
}
|
||||
|
||||
events, err := ReadEvents(time.Now().Add(-time.Hour))
|
||||
if err != nil {
|
||||
t.Fatalf("ReadEvents after concurrent writes: %v", err)
|
||||
}
|
||||
expected := goroutines * eventsPerGoroutine
|
||||
if len(events) != expected {
|
||||
t.Errorf("expected %d events after concurrent writes, got %d", expected, len(events))
|
||||
}
|
||||
}
|
||||
|
||||
func TestMetrics_ReadMetricsFile_Good_MalformedLines(t *testing.T) {
|
||||
withTempHome(t)
|
||||
|
||||
|
|
|
|||
|
|
@ -330,5 +330,7 @@ func truncate(text string, limit int) string {
|
|||
}
|
||||
|
||||
func init() {
|
||||
os.Stderr.Sync()
|
||||
// Flush stderr before flag parsing so any buffered output is visible if the process is
|
||||
// interrupted during startup (e.g. Ollama not running).
|
||||
os.Stderr.Sync() //nolint:errcheck // sync on startup, error is not actionable
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,9 @@ var metricsCmd = &cli.Command{
|
|||
},
|
||||
}
|
||||
|
||||
// initMetricsFlags binds the --since and --json flags to the metrics command.
|
||||
//
|
||||
// initMetricsFlags() // called once by AddMetricsCommand
|
||||
func initMetricsFlags() {
|
||||
metricsCmd.Flags().StringVar(&metricsSince, "since", "7d", i18n.T("cmd.ai.metrics.flag.since"))
|
||||
metricsCmd.Flags().BoolVar(&metricsJSON, "json", false, i18n.T("common.flag.json"))
|
||||
|
|
@ -41,6 +44,10 @@ func AddMetricsCommand(parent *cli.Command) {
|
|||
parent.AddCommand(metricsCmd)
|
||||
}
|
||||
|
||||
// runMetrics reads and displays AI event metrics for the configured time window.
|
||||
//
|
||||
// // via CLI: core ai metrics --since 7d --json
|
||||
// runMetrics()
|
||||
func runMetrics() error {
|
||||
sinceDuration, err := parseDuration(metricsSince)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -4,4 +4,6 @@ package rag
|
|||
import ragcmd "forge.lthn.ai/core/go-rag/cmd/rag"
|
||||
|
||||
// AddRAGSubcommands registers RAG commands as subcommands of parent.
|
||||
//
|
||||
// rag.AddRAGSubcommands(aiCmd) // → core ai rag index|query|status
|
||||
var AddRAGSubcommands = ragcmd.AddRAGSubcommands
|
||||
|
|
|
|||
|
|
@ -1 +1,6 @@
|
|||
// Package security implements the security command tree for the Core CLI.
|
||||
//
|
||||
// Commands registered:
|
||||
//
|
||||
// security.AddSecurityCommands(rootCmd) // → core security alerts|deps|scan|secrets|jobs
|
||||
package security
|
||||
|
|
|
|||
|
|
@ -8,6 +8,9 @@ import (
|
|||
"forge.lthn.ai/core/cli/pkg/cli"
|
||||
)
|
||||
|
||||
// addAlertsCommand registers the alerts subcommand under parent.
|
||||
//
|
||||
// addAlertsCommand(securityCmd) // → core security alerts --repo core-php --severity high
|
||||
func addAlertsCommand(parent *cli.Command) {
|
||||
command := &cli.Command{
|
||||
Use: "alerts",
|
||||
|
|
@ -41,6 +44,10 @@ type AlertOutput struct {
|
|||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
// runAlerts fetches and displays unified security alerts across all repos or a single target.
|
||||
//
|
||||
// // via CLI: core security alerts --repo core-php --severity high
|
||||
// runAlerts()
|
||||
func runAlerts() error {
|
||||
if err := checkGH(); err != nil {
|
||||
return err
|
||||
|
|
|
|||
|
|
@ -8,6 +8,9 @@ import (
|
|||
"forge.lthn.ai/core/cli/pkg/cli"
|
||||
)
|
||||
|
||||
// addDepsCommand registers the deps subcommand under parent.
|
||||
//
|
||||
// addDepsCommand(securityCmd) // → core security deps --repo core-php --severity critical
|
||||
func addDepsCommand(parent *cli.Command) {
|
||||
command := &cli.Command{
|
||||
Use: "deps",
|
||||
|
|
@ -42,6 +45,10 @@ type DepAlert struct {
|
|||
Summary string `json:"summary"`
|
||||
}
|
||||
|
||||
// runDeps fetches and displays Dependabot vulnerability alerts across all repos or a single target.
|
||||
//
|
||||
// // via CLI: core security deps --repo core-php --severity critical
|
||||
// runDeps()
|
||||
func runDeps() error {
|
||||
if err := checkGH(); err != nil {
|
||||
return err
|
||||
|
|
|
|||
|
|
@ -19,6 +19,9 @@ var (
|
|||
jobsCopies int
|
||||
)
|
||||
|
||||
// addJobsCommand registers the jobs subcommand under parent.
|
||||
//
|
||||
// addJobsCommand(securityCmd) // → core security jobs --targets wailsapp/wails --issue-repo host-uk/core
|
||||
func addJobsCommand(parent *cli.Command) {
|
||||
command := &cli.Command{
|
||||
Use: "jobs",
|
||||
|
|
@ -37,6 +40,10 @@ func addJobsCommand(parent *cli.Command) {
|
|||
parent.AddCommand(command)
|
||||
}
|
||||
|
||||
// runJobs aggregates security findings for each target and creates GitHub issues.
|
||||
//
|
||||
// // via CLI: core security jobs --targets wailsapp/wails,facebook/react --dry-run
|
||||
// runJobs()
|
||||
func runJobs() error {
|
||||
if err := checkGH(); err != nil {
|
||||
return err
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@ var (
|
|||
scanTool string
|
||||
)
|
||||
|
||||
// addScanCommand registers the scan subcommand under parent.
|
||||
//
|
||||
// addScanCommand(securityCmd) // → core security scan --repo core-php --tool gosec
|
||||
func addScanCommand(parent *cli.Command) {
|
||||
command := &cli.Command{
|
||||
Use: "scan",
|
||||
|
|
@ -48,6 +51,10 @@ type ScanAlert struct {
|
|||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
// runScan fetches and displays code-scanning alerts across all repos or a single target.
|
||||
//
|
||||
// // via CLI: core security scan --repo core-php --tool gosec
|
||||
// runScan()
|
||||
func runScan() error {
|
||||
if err := checkGH(); err != nil {
|
||||
return err
|
||||
|
|
|
|||
|
|
@ -8,6 +8,9 @@ import (
|
|||
"forge.lthn.ai/core/cli/pkg/cli"
|
||||
)
|
||||
|
||||
// addSecretsCommand registers the secrets subcommand under parent.
|
||||
//
|
||||
// addSecretsCommand(securityCmd) // → core security secrets --repo core-php --json
|
||||
func addSecretsCommand(parent *cli.Command) {
|
||||
command := &cli.Command{
|
||||
Use: "secrets",
|
||||
|
|
@ -38,6 +41,10 @@ type SecretAlert struct {
|
|||
PushProtection bool `json:"push_protection_bypassed"`
|
||||
}
|
||||
|
||||
// runSecrets fetches and displays secret-scanning alerts across all repos or a single target.
|
||||
//
|
||||
// // via CLI: core security secrets --repo core-php
|
||||
// runSecrets()
|
||||
func runSecrets() error {
|
||||
if err := checkGH(); err != nil {
|
||||
return err
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue