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:
@@ -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
|
||||
})
|
||||
}
|
||||
|
||||
@@ -68,13 +68,13 @@ func (h *DockerReportsHandler) ReportDockerImages(c *gin.Context) {
|
||||
event := models.StoredDockerImage{
|
||||
ID: uuid.New(),
|
||||
AgentID: agentID,
|
||||
PackageType: item.PackageType,
|
||||
PackageName: item.PackageName,
|
||||
CurrentVersion: item.CurrentVersion,
|
||||
AvailableVersion: item.AvailableVersion,
|
||||
PackageType: "docker_image",
|
||||
PackageName: item.ImageName + ":" + item.ImageTag,
|
||||
CurrentVersion: item.ImageID,
|
||||
AvailableVersion: item.LatestImageID,
|
||||
Severity: item.Severity,
|
||||
RepositorySource: item.RepositorySource,
|
||||
Metadata: models.JSONB(item.Metadata),
|
||||
Metadata: convertToJSONB(item.Metadata),
|
||||
EventType: "discovered",
|
||||
CreatedAt: req.Timestamp,
|
||||
}
|
||||
@@ -123,6 +123,8 @@ func (h *DockerReportsHandler) GetAgentDockerImages(c *gin.Context) {
|
||||
pageSize = 50
|
||||
}
|
||||
|
||||
offset := (page - 1) * pageSize
|
||||
|
||||
imageName := c.Query("image_name")
|
||||
registry := c.Query("registry")
|
||||
severity := c.Query("severity")
|
||||
@@ -136,7 +138,7 @@ func (h *DockerReportsHandler) GetAgentDockerImages(c *gin.Context) {
|
||||
Severity: nil,
|
||||
HasUpdates: nil,
|
||||
Limit: &pageSize,
|
||||
Offset: &((page - 1) * pageSize),
|
||||
Offset: &(offset),
|
||||
}
|
||||
|
||||
if imageName != "" {
|
||||
@@ -274,4 +276,13 @@ func countUpdates(images []models.DockerImageInfo) int {
|
||||
}
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
// Helper function to convert map[string]interface{} to models.JSONB
|
||||
func convertToJSONB(data map[string]interface{}) models.JSONB {
|
||||
result := make(map[string]interface{})
|
||||
for k, v := range data {
|
||||
result[k] = v
|
||||
}
|
||||
return models.JSONB(result)
|
||||
}
|
||||
Reference in New Issue
Block a user