# P1-001: Agent Install ID Parsing Issue **Priority:** P1 (Major) **Source Reference:** From needsfixingbeforepush.md line 3 **Date Identified:** 2025-11-12 ## Problem Description The `generateInstallScript` function in downloads.go is not properly extracting the `agent_id` query parameter, causing the install script to always generate new agent IDs instead of using existing registered agent IDs for upgrades. ## Current Behavior Install script downloads always generate new UUIDs instead of preserving existing agent IDs: ```bash # BEFORE (broken) curl -sfL "http://localhost:8080/api/v1/install/linux?agent_id=6fdba4c92c4d4d33a4010e98db0df72d8bbe3d62c6b7e0a33cef3325e29bdd6d" # Result: AGENT_ID="cf865204-125a-491d-976f-5829b6c081e6" (NEW UUID generated) ``` ## Expected Behavior For upgrade scenarios, the install script should preserve the existing agent ID passed via query parameter: ```bash # AFTER (fixed) curl -sfL "http://localhost:8080/api/v1/install/linux?agent_id=6fdba4c92c4d4d33a4010e98db0df72d8bbe3d62c6b7e0a33cef3325e29bdd6d" # Result: AGENT_ID="6fdba4c92c4d4d33a4010e98db0df72d8bbe3d62c6b7e0a33cef3325e29bdd6d" (PASSED UUID) ``` ## Root Cause Analysis The `generateInstallScript` function only looks at query parameters but doesn't properly validate/extract the UUID format from the `agent_id` parameter. The function likely ignores or fails to parse the existing agent ID, falling back to generating a new UUID each time. ## Proposed Solution Implement proper agent ID parsing with security validation following this priority order: 1. **Header:** `X-Agent-ID` (most secure, not exposed in URLs/logs) 2. **Path:** `/api/v1/install/:platform/:agent_id` (legacy support) 3. **Query:** `?agent_id=uuid` (fallback for current usage) All paths must: - Validate UUID format before using - Enforce rate limiting on agent ID reuse - Apply signature validation for security ## Implementation Details ```go // Example fix in downloads.go func generateInstallScript(c *gin.Context) (string, error) { var agentID string // Priority 1: Check header (most secure) if agentID = c.GetHeader("X-Agent-ID"); agentID != "" { if isValidUUID(agentID) { // Use header agent ID } } // Priority 2: Check path parameter if agentID == "" { if agentID = c.Param("agent_id"); agentID != "" { if isValidUUID(agentID) { // Use path agent ID } } } // Priority 3: Check query parameter (current broken behavior) if agentID == "" { if agentID = c.Query("agent_id"); agentID != "" { if isValidUUID(agentID) { // Use query agent ID } } } // Fallback: Generate new UUID if no valid agent ID provided if agentID == "" { agentID = generateNewUUID() } // Generate install script with the determined agent ID return generateScriptTemplate(agentID), nil } ``` ## Definition of Done - [ ] Install script preserves existing agent ID when provided via query parameter - [ ] Agent ID format validation (UUID v4) prevents malformed IDs - [ ] New UUID generated only when no valid agent ID is provided - [ ] Security validation prevents agent ID spoofing - [ ] Rate limiting prevents abuse of agent ID reuse - [ ] Backward compatibility maintained for existing install methods ## Test Plan 1. **Query Parameter Test:** ```bash # Test with valid UUID in query parameter TEST_UUID="6fdba4c92c4d4d33a4010e98db0df72d8bbe3d62c6b7e0a33cef3325e29bdd6d" curl -sfL "http://localhost:8080/api/v1/install/linux?agent_id=$TEST_UUID" | grep "AGENT_ID=" # Expected: AGENT_ID="$TEST_UUID" (same UUID) # Not: AGENT_ID="" ``` 2. **Invalid UUID Test:** ```bash # Test with malformed UUID curl -sfL "http://localhost:8080/api/v1/install/linux?agent_id=invalid-uuid" | grep "AGENT_ID=" # Expected: AGENT_ID="" (rejects invalid, generates new) ``` 3. **Empty Parameter Test:** ```bash # Test with empty agent_id parameter curl -sfL "http://localhost:8080/api/v1/install/linux?agent_id=" | grep "AGENT_ID=" # Expected: AGENT_ID="" (empty treated as not provided) ``` 4. **No Parameter Test:** ```bash # Test without agent_id parameter (current behavior) curl -sfL "http://localhost:8080/api/v1/install/linux" | grep "AGENT_ID=" # Expected: AGENT_ID="" (maintain backward compatibility) ``` 5. **Security Validation Test:** ```bash # Test with UUID validation edge cases curl -sfL "http://localhost:8080/api/v1/install/linux?agent_id=00000000-0000-0000-0000-000000000000" | grep "AGENT_ID=" # Should handle edge cases appropriately ``` ## Files to Modify - `aggregator-server/internal/api/handlers/downloads.go` (main fix location) - Add UUID validation utility functions - Potentially update rate limiting logic for agent ID reuse - Add tests for install script generation ## Impact - **Agent Upgrades:** Prevents agent identity loss during upgrades/reinstallation - **Agent Management:** Maintains consistent agent identity across system lifecycle - **Audit Trail:** Preserves agent history and command continuity - **User Experience:** Allows seamless agent reinstallation without re-registration ## Security Considerations - **Agent ID Spoofing:** Must validate that agent ID belongs to legitimate agent - **Rate Limiting:** Prevent abuse of agent ID reuse for malicious purposes - **Signature Validation:** Ensure agent ID requests are authenticated - **Audit Logging:** Log agent ID reuse attempts for security monitoring ## Upgrade Scenario Use Case ```bash # Agent needs upgrade/reinstallation on same machine # Admin provides existing agent ID to preserve history EXISTING_AGENT_ID="6fdba4c92c4d4d33a4010e98db0df72d8bbe3d62c6b7e0a33cef3325e29bdd6d" # Install script preserves agent identity curl -sfL "http://redflag-server:8080/api/v1/install/linux?agent_id=$EXISTING_AGENT_ID" | sudo bash # Result: Agent reinstalls with same ID, preserving: # - Command history # - Configuration settings # - Agent registration record # - Audit trail continuity ``` ## Verification Commands After fix implementation: ```bash # Verify query parameter preservation UUID="6fdba4c92c4d4d33a4010e98db0df72d8bbe3d62c6b7e0a33cef3325e29bdd6d" SCRIPT=$(curl -sfL "http://localhost:8080/api/v1/install/linux?agent_id=$UUID") echo "$SCRIPT" | grep "AGENT_ID=" # Should output: AGENT_ID="6fdba4c92c4d4d33a4010e98db0df72d8bbe3d62c6b7e0a33cef3325e29bdd6d" # Test invalid UUID rejection INVALID_SCRIPT=$(curl -sfL "http://localhost:8080/api/v1/install/linux?agent_id=invalid") echo "$INVALID_SCRIPT" | grep "AGENT_ID=" # Should output different UUID (generated new) ```