fix: agent acknowledgment recursion and subsystem UI improvements
- Fix recursive call in reportLogWithAck that caused infinite loop - Add machine binding and security API endpoints - Enhance AgentScanners component with security status display - Update scheduler and timeout service reliability - Remove deprecated install.sh script - Add subsystem configuration and logging improvements
This commit is contained in:
@@ -23,14 +23,19 @@ func (q *AgentQueries) CreateAgent(agent *models.Agent) error {
|
||||
query := `
|
||||
INSERT INTO agents (
|
||||
id, hostname, os_type, os_version, os_architecture,
|
||||
agent_version, last_seen, status, metadata
|
||||
agent_version, current_version, machine_id, public_key_fingerprint,
|
||||
last_seen, status, metadata
|
||||
) VALUES (
|
||||
:id, :hostname, :os_type, :os_version, :os_architecture,
|
||||
:agent_version, :last_seen, :status, :metadata
|
||||
:agent_version, :current_version, :machine_id, :public_key_fingerprint,
|
||||
:last_seen, :status, :metadata
|
||||
)
|
||||
`
|
||||
_, err := q.db.NamedExec(query, agent)
|
||||
return err
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create agent %s (version %s): %w", agent.Hostname, agent.CurrentVersion, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetAgentByID retrieves an agent by ID
|
||||
|
||||
@@ -2,6 +2,7 @@ package queries
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Fimeg/RedFlag/aggregator-server/internal/models"
|
||||
@@ -31,13 +32,14 @@ func (q *CommandQueries) CreateCommand(cmd *models.AgentCommand) error {
|
||||
}
|
||||
|
||||
// GetPendingCommands retrieves pending commands for an agent
|
||||
// Only returns 'pending' status - 'sent' commands are handled by timeout service
|
||||
func (q *CommandQueries) GetPendingCommands(agentID uuid.UUID) ([]models.AgentCommand, error) {
|
||||
var commands []models.AgentCommand
|
||||
query := `
|
||||
SELECT * FROM agent_commands
|
||||
WHERE agent_id = $1 AND status = 'pending'
|
||||
ORDER BY created_at ASC
|
||||
LIMIT 10
|
||||
LIMIT 100
|
||||
`
|
||||
err := q.db.Select(&commands, query, agentID)
|
||||
return commands, err
|
||||
@@ -338,6 +340,23 @@ func (q *CommandQueries) ClearAllFailedCommands(days int) (int64, error) {
|
||||
return result.RowsAffected()
|
||||
}
|
||||
|
||||
// ClearAllFailedCommandsRegardlessOfAge archives ALL failed/timed_out commands regardless of age
|
||||
// This is used when all_failed=true is passed to truly clear all failed commands
|
||||
func (q *CommandQueries) ClearAllFailedCommandsRegardlessOfAge() (int64, error) {
|
||||
query := `
|
||||
UPDATE agent_commands
|
||||
SET status = 'archived_failed'
|
||||
WHERE status IN ('failed', 'timed_out')
|
||||
`
|
||||
|
||||
result, err := q.db.Exec(query)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to archive all failed commands regardless of age: %w", err)
|
||||
}
|
||||
|
||||
return result.RowsAffected()
|
||||
}
|
||||
|
||||
// CountPendingCommandsForAgent returns the number of pending commands for a specific agent
|
||||
// Used by scheduler for backpressure detection
|
||||
func (q *CommandQueries) CountPendingCommandsForAgent(agentID uuid.UUID) (int, error) {
|
||||
@@ -373,16 +392,30 @@ func (q *CommandQueries) VerifyCommandsCompleted(commandIDs []string) ([]string,
|
||||
return []string{}, nil
|
||||
}
|
||||
|
||||
// Convert UUIDs back to strings for SQL query
|
||||
uuidStrs := make([]string, len(uuidIDs))
|
||||
for i, id := range uuidIDs {
|
||||
uuidStrs[i] = id.String()
|
||||
}
|
||||
|
||||
// Query for commands that are completed or failed
|
||||
query := `
|
||||
// Use ANY with proper array literal for PostgreSQL
|
||||
placeholders := make([]string, len(uuidStrs))
|
||||
args := make([]interface{}, len(uuidStrs))
|
||||
for i, id := range uuidStrs {
|
||||
placeholders[i] = fmt.Sprintf("$%d", i+1)
|
||||
args[i] = id
|
||||
}
|
||||
|
||||
query := fmt.Sprintf(`
|
||||
SELECT id
|
||||
FROM agent_commands
|
||||
WHERE id = ANY($1)
|
||||
AND status IN ('completed', 'failed')
|
||||
`
|
||||
WHERE id::text = ANY(%s)
|
||||
AND status IN ('completed', 'failed', 'timed_out')
|
||||
`, fmt.Sprintf("ARRAY[%s]", strings.Join(placeholders, ",")))
|
||||
|
||||
var completedUUIDs []uuid.UUID
|
||||
err := q.db.Select(&completedUUIDs, query, uuidIDs)
|
||||
err := q.db.Select(&completedUUIDs, query, args...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to verify command completion: %w", err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user