Files
keyhunter/cmd/schedule.go
salvacybersec 0319d288db feat(phase-17): Telegram bot + scheduler + serve/schedule CLI commands
pkg/bot: Bot struct with telego long-polling, command handlers (/scan, /verify,
/recon, /status, /stats, /providers, /help, /key), /subscribe + /unsubscribe,
notification dispatcher.

pkg/scheduler: gocron v2 wrapper with SQLite-backed job persistence,
Start/Stop/AddJob/RemoveJob lifecycle.

cmd/serve.go: keyhunter serve [--telegram] [--port=8080]
cmd/schedule.go: keyhunter schedule add/list/remove
2026-04-06 17:50:43 +03:00

105 lines
2.5 KiB
Go

package cmd
import (
"fmt"
"github.com/salvacybersec/keyhunter/pkg/storage"
"github.com/spf13/cobra"
)
var scheduleCmd = &cobra.Command{
Use: "schedule",
Short: "Manage scheduled recurring scans",
}
var scheduleAddCmd = &cobra.Command{
Use: "add",
Short: "Add a scheduled scan job",
RunE: func(cmd *cobra.Command, args []string) error {
name, _ := cmd.Flags().GetString("name")
cron, _ := cmd.Flags().GetString("cron")
scan, _ := cmd.Flags().GetString("scan")
if name == "" || cron == "" || scan == "" {
return fmt.Errorf("--name, --cron, and --scan are required")
}
db, _, err := openDBWithKey()
if err != nil {
return err
}
defer db.Close()
job := storage.ScheduledJob{
Name: name,
CronExpr: cron,
ScanPath: scan,
Enabled: true,
}
id, err := db.SaveScheduledJob(job)
if err != nil {
return fmt.Errorf("adding job: %w", err)
}
fmt.Printf("Scheduled job %q (ID %d) added: %s -> %s\n", name, id, cron, scan)
return nil
},
}
var scheduleListCmd = &cobra.Command{
Use: "list",
Short: "List scheduled scan jobs",
RunE: func(cmd *cobra.Command, args []string) error {
db, _, err := openDBWithKey()
if err != nil {
return err
}
defer db.Close()
jobs, err := db.ListScheduledJobs()
if err != nil {
return err
}
if len(jobs) == 0 {
fmt.Println("No scheduled jobs.")
return nil
}
fmt.Printf("%-5s %-20s %-20s %-30s %-8s\n", "ID", "NAME", "CRON", "SCAN", "ENABLED")
for _, j := range jobs {
fmt.Printf("%-5d %-20s %-20s %-30s %-8v\n", j.ID, j.Name, j.CronExpr, j.ScanPath, j.Enabled)
}
return nil
},
}
var scheduleRemoveCmd = &cobra.Command{
Use: "remove <id>",
Short: "Remove a scheduled scan job by ID",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
db, _, err := openDBWithKey()
if err != nil {
return err
}
defer db.Close()
var id int64
if _, err := fmt.Sscanf(args[0], "%d", &id); err != nil {
return fmt.Errorf("invalid job ID: %s", args[0])
}
if _, err := db.DeleteScheduledJob(id); err != nil {
return fmt.Errorf("removing job: %w", err)
}
fmt.Printf("Removed scheduled job #%d\n", id)
return nil
},
}
func init() {
scheduleAddCmd.Flags().String("name", "", "job name")
scheduleAddCmd.Flags().String("cron", "", "cron expression")
scheduleAddCmd.Flags().String("scan", "", "scan path/command")
scheduleCmd.AddCommand(scheduleAddCmd)
scheduleCmd.AddCommand(scheduleListCmd)
scheduleCmd.AddCommand(scheduleRemoveCmd)
}