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

@@ -2,6 +2,7 @@ import axios, { AxiosResponse } from 'axios';
import {
Agent,
UpdatePackage,
AgentUpdatePackage,
DashboardStats,
AgentListResponse,
UpdateListResponse,
@@ -160,6 +161,27 @@ export const agentApi = {
const response = await api.post(`/agents/${agentId}/subsystems/${subsystem}/interval`, { interval_minutes: intervalMinutes });
return response.data;
},
// Update single agent
updateAgent: async (agentId: string, updateData: {
version: string;
platform: string;
scheduled?: string;
}): Promise<{ message: string; update_id: string; download_url: string; signature: string; checksum: string; file_size: number; estimated_time: number }> => {
const response = await api.post(`/agents/${agentId}/update`, updateData);
return response.data;
},
// Update multiple agents (bulk)
updateMultipleAgents: async (updateData: {
agent_ids: string[];
version: string;
platform: string;
scheduled?: string;
}): Promise<{ message: string; updated: Array<{ agent_id: string; hostname: string; update_id: string; status: string }>; failed: string[]; total_agents: number; package_info: any }> => {
const response = await api.post('/agents/bulk-update', updateData);
return response.data;
},
};
export const updateApi = {
@@ -185,6 +207,11 @@ export const updateApi = {
await api.post(`/updates/${id}/approve`, { scheduled_at: scheduledAt });
},
// Approve multiple updates
approveMultiple: async (updateIds: string[]): Promise<void> => {
await api.post('/updates/approve', { update_ids: updateIds });
},
// Reject/cancel update
rejectUpdate: async (id: string): Promise<void> => {
await api.post(`/updates/${id}/reject`);
@@ -250,6 +277,28 @@ export const updateApi = {
const response = await api.delete(`/commands/failed${params.toString() ? '?' + params.toString() : ''}`);
return response.data;
},
// Get available update packages
getPackages: async (params?: {
version?: string;
platform?: string;
limit?: number;
offset?: number;
}): Promise<{ packages: AgentUpdatePackage[]; total: number; limit: number; offset: number }> => {
const response = await api.get('/updates/packages', { params });
return response.data;
},
// Sign new update package
signPackage: async (packageData: {
version: string;
platform: string;
architecture: string;
binary_path: string;
}): Promise<{ message: string; package: UpdatePackage }> => {
const response = await api.post('/updates/packages/sign', packageData);
return response.data;
},
};
export const statsApi = {