feat: machine binding and version enforcement

migration 017 adds machine_id to agents table
middleware validates X-Machine-ID header on authed routes
agent client sends machine ID with requests
MIN_AGENT_VERSION config defaults 0.1.22
version utils added for comparison

blocks config copying attacks via hardware fingerprint
old agents get 426 upgrade required
breaking: <0.1.22 agents rejected
This commit is contained in:
Fimeg
2025-11-02 09:30:04 -05:00
parent 99480f3fe3
commit ec3ba88459
48 changed files with 3811 additions and 122 deletions

View File

@@ -4,6 +4,7 @@ import {
Search,
Package,
Download,
Upload,
CheckCircle,
RefreshCw,
Terminal,
@@ -18,6 +19,7 @@ import { updateApi, agentApi } from '@/lib/api';
import toast from 'react-hot-toast';
import { cn } from '@/lib/utils';
import type { UpdatePackage } from '@/types';
import { AgentUpdatesModal } from './AgentUpdatesModal';
interface AgentUpdatesEnhancedProps {
agentId: string;
@@ -52,7 +54,7 @@ export function AgentUpdatesEnhanced({ agentId }: AgentUpdatesEnhancedProps) {
const [selectedSeverity, setSelectedSeverity] = useState('all');
const [showLogsModal, setShowLogsModal] = useState(false);
const [logsData, setLogsData] = useState<LogResponse | null>(null);
const [isLoadingLogs, setIsLoadingLogs] = useState(false);
const [showUpdateModal, setShowUpdateModal] = useState(false);
const [expandedUpdates, setExpandedUpdates] = useState<Set<string>>(new Set());
const [selectedUpdates, setSelectedUpdates] = useState<string[]>([]);
@@ -300,6 +302,15 @@ export function AgentUpdatesEnhanced({ agentId }: AgentUpdatesEnhancedProps) {
)}
</button>
)}
{/* Update Agent Button */}
<button
onClick={() => setShowUpdateModal(true)}
className="text-sm text-primary-600 hover:text-primary-800 flex items-center space-x-1 border border-primary-300 px-2 py-1 rounded"
>
<Upload className="h-4 w-4" />
<span>Update Agent</span>
</button>
</div>
{/* Search and Filters */}
@@ -531,6 +542,17 @@ export function AgentUpdatesEnhanced({ agentId }: AgentUpdatesEnhancedProps) {
</div>
</div>
)}
{/* Agent Update Modal */}
<AgentUpdatesModal
isOpen={showUpdateModal}
onClose={() => setShowUpdateModal(false)}
selectedAgentIds={[agentId]}
onAgentsUpdated={() => {
setShowUpdateModal(false);
queryClient.invalidateQueries({ queryKey: ['agents'] });
}}
/>
</div>
);
}