diff --git a/agents/patchmon-agent.sh b/agents/patchmon-agent.sh index 7749d85..364dda2 100755 --- a/agents/patchmon-agent.sh +++ b/agents/patchmon-agent.sh @@ -821,7 +821,7 @@ EOF success "Update sent successfully" echo "$response" | grep -o '"packagesProcessed":[0-9]*' | cut -d':' -f2 | xargs -I {} info "Processed {} packages" - # Check for auto-update instructions (look specifically in autoUpdate section) + # Check for PatchMon agent update instructions (this updates the agent script, not system packages) if echo "$response" | grep -q '"autoUpdate":{'; then local auto_update_section=$(echo "$response" | grep -o '"autoUpdate":{[^}]*}') local should_update=$(echo "$auto_update_section" | grep -o '"shouldUpdate":true' | cut -d':' -f2) @@ -830,15 +830,15 @@ EOF local current_version=$(echo "$auto_update_section" | grep -o '"currentVersion":"[^"]*' | cut -d'"' -f4) local update_message=$(echo "$auto_update_section" | grep -o '"message":"[^"]*' | cut -d'"' -f4) - info "Auto-update detected: $update_message" + info "PatchMon agent update detected: $update_message" info "Current version: $current_version, Latest version: $latest_version" - # Automatically run update-agent command - info "Automatically updating agent to latest version..." + # Automatically run update-agent command to update the PatchMon agent script + info "Automatically updating PatchMon agent to latest version..." if "$0" update-agent; then - success "Agent auto-update completed successfully" + success "PatchMon agent update completed successfully" else - warning "Agent auto-update failed, but data was sent successfully" + warning "PatchMon agent update failed, but data was sent successfully" fi fi fi diff --git a/agents/patchmon_install.sh b/agents/patchmon_install.sh index 7a5feac..7c30d6a 100644 --- a/agents/patchmon_install.sh +++ b/agents/patchmon_install.sh @@ -158,8 +158,8 @@ else warning "Initial package data failed, but agent is configured. You can run 'patchmon-agent.sh update' manually." fi -# Setup crontab for automatic updates -info "⏰ Setting up automatic updates every $UPDATE_INTERVAL minutes..." +# Setup crontab for automatic package status updates +info "⏰ Setting up automatic package status update every $UPDATE_INTERVAL minutes..." if [[ $UPDATE_INTERVAL -eq 60 ]]; then # Hourly updates echo "0 * * * * /usr/local/bin/patchmon-agent.sh update >/dev/null 2>&1" | crontab - @@ -179,7 +179,7 @@ if [[ "$EXPECTED_VERSION" != "Unknown" ]]; then fi echo " • Config directory: /etc/patchmon/" echo " • Credentials file: /etc/patchmon/credentials" -echo " • Automatic updates: Every $UPDATE_INTERVAL minutes via crontab" +echo " • Status updates: Every $UPDATE_INTERVAL minutes via crontab" echo " • View logs: tail -f /var/log/patchmon-agent.log" echo "" echo "🔧 Manual commands:" diff --git a/backend/src/routes/authRoutes.js b/backend/src/routes/authRoutes.js index d61934b..bcffc02 100644 --- a/backend/src/routes/authRoutes.js +++ b/backend/src/routes/authRoutes.js @@ -118,9 +118,21 @@ router.post( // Create default dashboard preferences for the new admin user await createDefaultDashboardPreferences(user.id, "admin"); + // Generate token for immediate login + const token = generateToken(user.id); + res.status(201).json({ message: "Admin user created successfully", - user: user, + token, + user: { + id: user.id, + username: user.username, + email: user.email, + role: user.role, + first_name: user.first_name, + last_name: user.last_name, + is_active: user.is_active, + }, }); } catch (error) { console.error("Error creating admin user:", error); diff --git a/backend/src/routes/hostRoutes.js b/backend/src/routes/hostRoutes.js index 444e3ef..0317e88 100644 --- a/backend/src/routes/hostRoutes.js +++ b/backend/src/routes/hostRoutes.js @@ -375,14 +375,21 @@ router.post( updateData.status = "active"; } - await prisma.hosts.update({ - where: { id: host.id }, - data: updateData, - }); + // Calculate package counts before transaction + const securityCount = packages.filter( + (pkg) => pkg.isSecurityUpdate, + ).length; + const updatesCount = packages.filter((pkg) => pkg.needsUpdate).length; - // Process packages in transaction + // Process everything in a single transaction to avoid race conditions await prisma.$transaction(async (tx) => { - // Clear existing host packages + // Update host data + await tx.hosts.update({ + where: { id: host.id }, + data: updateData, + }); + + // Clear existing host packages to avoid duplicates await tx.host_packages.deleteMany({ where: { host_id: host.id }, }); @@ -423,8 +430,22 @@ router.post( } // Create host package relationship - await tx.host_packages.create({ - data: { + // Use upsert to handle potential duplicates gracefully + await tx.host_packages.upsert({ + where: { + host_id_package_id: { + host_id: host.id, + package_id: pkg.id, + }, + }, + update: { + current_version: packageData.currentVersion, + available_version: packageData.availableVersion || null, + needs_update: packageData.needsUpdate, + is_security_update: packageData.isSecurityUpdate || false, + last_checked: new Date(), + }, + create: { id: uuidv4(), host_id: host.id, package_id: pkg.id, @@ -493,29 +514,24 @@ router.post( }); } } + + // Create update history record + await tx.update_history.create({ + data: { + id: uuidv4(), + host_id: host.id, + packages_count: updatesCount, + security_count: securityCount, + status: "success", + }, + }); }); - // Create update history record - const securityCount = packages.filter( - (pkg) => pkg.isSecurityUpdate, - ).length; - const updatesCount = packages.filter((pkg) => pkg.needsUpdate).length; - - await prisma.update_history.create({ - data: { - id: uuidv4(), - host_id: host.id, - packages_count: updatesCount, - security_count: securityCount, - status: "success", - }, - }); - - // Check if auto-update is enabled and if there's a newer agent version available + // Check if agent auto-update is enabled and if there's a newer version available let autoUpdateResponse = null; try { const settings = await prisma.settings.findFirst(); - // Check both global auto-update setting AND host-specific auto-update setting + // Check both global agent auto-update setting AND host-specific agent auto-update setting if (settings?.auto_update && host.auto_update) { // Get current agent version from the request const currentAgentVersion = req.body.agentVersion; @@ -544,8 +560,8 @@ router.post( } } } catch (error) { - console.error("Auto-update check error:", error); - // Don't fail the update if auto-update check fails + console.error("Agent auto-update check error:", error); + // Don't fail the update if agent auto-update check fails } const response = { @@ -555,7 +571,7 @@ router.post( securityUpdates: securityCount, }; - // Add auto-update response if available + // Add agent auto-update response if available if (autoUpdateResponse) { response.autoUpdate = autoUpdateResponse; } @@ -1044,7 +1060,7 @@ router.delete( }, ); -// Toggle host auto-update setting +// Toggle agent auto-update setting router.patch( "/:hostId/auto-update", authenticateToken, @@ -1052,7 +1068,7 @@ router.patch( [ body("auto_update") .isBoolean() - .withMessage("Auto-update must be a boolean"), + .withMessage("Agent auto-update setting must be a boolean"), ], async (req, res) => { try { @@ -1073,7 +1089,7 @@ router.patch( }); res.json({ - message: `Host auto-update ${auto_update ? "enabled" : "disabled"} successfully`, + message: `Agent auto-update ${auto_update ? "enabled" : "disabled"} successfully`, host: { id: host.id, friendlyName: host.friendly_name, @@ -1081,8 +1097,8 @@ router.patch( }, }); } catch (error) { - console.error("Host auto-update toggle error:", error); - res.status(500).json({ error: "Failed to toggle host auto-update" }); + console.error("Agent auto-update toggle error:", error); + res.status(500).json({ error: "Failed to toggle agent auto-update" }); } }, ); diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 4f015f6..e6a3efd 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -2,6 +2,7 @@ import { Route, Routes } from "react-router-dom"; import FirstTimeAdminSetup from "./components/FirstTimeAdminSetup"; import Layout from "./components/Layout"; import ProtectedRoute from "./components/ProtectedRoute"; +import { isAuthPhase } from "./constants/authPhases"; import { AuthProvider, useAuth } from "./contexts/AuthContext"; import { ThemeProvider } from "./contexts/ThemeContext"; import { UpdateNotificationProvider } from "./contexts/UpdateNotificationContext"; @@ -20,11 +21,14 @@ import Settings from "./pages/Settings"; import Users from "./pages/Users"; function AppRoutes() { - const { needsFirstTimeSetup, checkingSetup, isAuthenticated } = useAuth(); + const { needsFirstTimeSetup, authPhase, isAuthenticated } = useAuth(); const isAuth = isAuthenticated(); // Call the function to get boolean value - // Show loading while checking if setup is needed - if (checkingSetup) { + // Show loading while checking setup or initialising + if ( + isAuthPhase.initialising(authPhase) || + isAuthPhase.checkingSetup(authPhase) + ) { return (
- Your admin account has been successfully created. You will be - automatically logged in shortly. + Your admin account has been successfully created and you are now + logged in. Redirecting to the dashboard...
+
Friendly Name
+
System Hostname
@@ -384,7 +379,7 @@ const HostDetail = () => { )}
+
Host Group
{host.host_groups ? ( @@ -402,7 +397,7 @@ const HostDetail = () => {+
Operating System
- Agent Version -
-- {host.agent_version} -
-+ Agent Version +
++ {host.agent_version || "Unknown"} +
++ Auto-update +
+ +