feat: add config sync endpoint and security UI updates

- Add GET /api/v1/agents/:id/config endpoint for server configuration
- Agent fetches config during check-in and applies updates
- Add version tracking to prevent unnecessary config applications
- Clean separation: config sync independent of commands
- Fix agent UI subsystem settings to actually control agent behavior
- Update Security Health UI with frosted glass styling and tooltips
This commit is contained in:
Fimeg
2025-11-03 22:36:26 -05:00
parent eccc38d7c9
commit 38894f64d3
18 changed files with 944 additions and 87 deletions

View File

@@ -19,16 +19,18 @@ type AgentHandler struct {
commandQueries *queries.CommandQueries
refreshTokenQueries *queries.RefreshTokenQueries
registrationTokenQueries *queries.RegistrationTokenQueries
subsystemQueries *queries.SubsystemQueries
checkInInterval int
latestAgentVersion string
}
func NewAgentHandler(aq *queries.AgentQueries, cq *queries.CommandQueries, rtq *queries.RefreshTokenQueries, regTokenQueries *queries.RegistrationTokenQueries, checkInInterval int, latestAgentVersion string) *AgentHandler {
func NewAgentHandler(aq *queries.AgentQueries, cq *queries.CommandQueries, rtq *queries.RefreshTokenQueries, regTokenQueries *queries.RegistrationTokenQueries, sq *queries.SubsystemQueries, checkInInterval int, latestAgentVersion string) *AgentHandler {
return &AgentHandler{
agentQueries: aq,
commandQueries: cq,
refreshTokenQueries: rtq,
registrationTokenQueries: regTokenQueries,
subsystemQueries: sq,
checkInInterval: checkInInterval,
latestAgentVersion: latestAgentVersion,
}
@@ -1136,3 +1138,44 @@ func (h *AgentHandler) TriggerReboot(c *gin.Context) {
"hostname": agent.Hostname,
})
}
// GetAgentConfig returns current subsystem configuration for an agent
// GET /api/v1/agents/:id/config
func (h *AgentHandler) GetAgentConfig(c *gin.Context) {
idStr := c.Param("id")
agentID, err := uuid.Parse(idStr)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid agent ID"})
return
}
// Verify agent exists
agent, err := h.agentQueries.GetAgentByID(agentID)
if err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "agent not found"})
return
}
// Get subsystem configuration from database
subsystems, err := h.subsystemQueries.GetSubsystems(agentID)
if err != nil {
log.Printf("Failed to get subsystems for agent %s: %v", agentID, err)
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to get subsystem configuration"})
return
}
// Convert to simple format for agent
config := make(map[string]interface{})
for _, subsystem := range subsystems {
config[subsystem.Subsystem] = map[string]interface{}{
"enabled": subsystem.Enabled,
"interval_minutes": subsystem.IntervalMinutes,
"auto_run": subsystem.AutoRun,
}
}
c.JSON(http.StatusOK, gin.H{
"subsystems": config,
"version": time.Now().Unix(), // Simple version timestamp
})
}