diff --git a/backend/app/version.py b/backend/app/version.py index ceb6b6c..20c8587 100644 --- a/backend/app/version.py +++ b/backend/app/version.py @@ -1,5 +1,5 @@ """Единый источник версии SAC (API, health, логи, OpenAPI).""" APP_NAME = "Security Alert Center" -APP_VERSION = "0.5.12" +APP_VERSION = "0.5.13" APP_VERSION_LABEL = f"{APP_NAME} v.{APP_VERSION}" diff --git a/frontend/src/components/HostActionLogModal.vue b/frontend/src/components/HostActionLogModal.vue index e0e1dcb..4d2cd8b 100644 --- a/frontend/src/components/HostActionLogModal.vue +++ b/frontend/src/components/HostActionLogModal.vue @@ -67,8 +67,6 @@ import { fetchHostRemoteJob, type HostRemoteActionJobStatus } from "../api"; const LOG_POLL_MS = 1500; const AUTO_CLOSE_MS = 30_000; -const PLACEHOLDER = - "Ожидание лога с хоста…\n(обновление /var/log/update_script.log)"; const props = defineProps<{ hostId: number; @@ -78,6 +76,7 @@ const props = defineProps<{ ok: boolean | null; message: string; output: string; + logPlaceholder: string; logVisible: boolean; sessionStartedAt: string; }>(); @@ -135,7 +134,7 @@ const displayMessage = computed(() => { const displayOutput = computed(() => { const text = (polledOutput.value || props.output).trim(); - return text || PLACEHOLDER; + return text || props.logPlaceholder; }); function stopPoll() { diff --git a/frontend/src/components/HostActionLogStack.vue b/frontend/src/components/HostActionLogStack.vue index 218aca7..b58abba 100644 --- a/frontend/src/components/HostActionLogStack.vue +++ b/frontend/src/components/HostActionLogStack.vue @@ -10,6 +10,7 @@ :ok="entry.ok" :message="entry.message" :output="entry.output" + :log-placeholder="entry.logPlaceholder" :log-visible="entry.logVisible" :session-started-at="entry.sessionStartedAt" @close="closeHostRemoteActionLog(entry.id)" diff --git a/frontend/src/composables/useHostRemoteAction.ts b/frontend/src/composables/useHostRemoteAction.ts index 921bd5d..f4fc1e4 100644 --- a/frontend/src/composables/useHostRemoteAction.ts +++ b/frontend/src/composables/useHostRemoteAction.ts @@ -22,6 +22,8 @@ export type HostRemoteActionLogEntry = { title: string; message: string; output: string; + /** Текст в окне лога, пока output с сервера ещё пустой */ + logPlaceholder: string; /** ISO-время открытия окна — отсекаем stale success от прошлого job */ sessionStartedAt: string; }; @@ -189,6 +191,7 @@ async function executeRemoteAction( export async function pollHostRemoteAction( hostId: number, title: string, + logPlaceholder?: string, ): Promise { const existingPromise = hostRunningPromises.get(hostId); if (existingPromise) { @@ -209,6 +212,7 @@ export async function pollHostRemoteAction( title, message: "Выполняется на удалённом хосте…", output: "", + logPlaceholder: logPlaceholder || "Ожидание лога с хоста…", sessionStartedAt: new Date().toISOString(), }; hostRemoteActionLogs.push(entry); @@ -240,6 +244,7 @@ export async function runHostRemoteAction( hostId: number, title: string, kind: HostRemoteActionKind, + logPlaceholder?: string, ): Promise { const existingPromise = hostRunningPromises.get(hostId); if (existingPromise) { @@ -260,6 +265,7 @@ export async function runHostRemoteAction( title, message: "Запуск на сервере SAC…", output: "", + logPlaceholder: logPlaceholder || "Ожидание лога с хоста…", sessionStartedAt: new Date().toISOString(), }; hostRemoteActionLogs.push(entry); diff --git a/frontend/src/utils/hostAgentUpgrade.ts b/frontend/src/utils/hostAgentUpgrade.ts index dbee7f3..4a73f22 100644 --- a/frontend/src/utils/hostAgentUpgrade.ts +++ b/frontend/src/utils/hostAgentUpgrade.ts @@ -58,3 +58,37 @@ export function remoteActionTitleForHost(host: HostSummary): string { } return `Обновление ssh-monitor (SSH): ${label}`; } + +const LOG_PLACEHOLDER_SSH_UPDATE = + "Ожидание лога с хоста…\n(обновление /var/log/update_script.log)"; + +const LOG_PLACEHOLDER_WINRM = + "Ожидание вывода с хоста…\n(WinRM: Deploy-LoginMonitor.ps1)"; + +const LOG_PLACEHOLDER_GENERIC = "Ожидание лога с хоста…"; + +export function remoteActionLogPlaceholder( + host: Pick | null | undefined, + kind: HostRemoteActionKind | null, +): string { + if (kind === "ssh-update") { + return LOG_PLACEHOLDER_SSH_UPDATE; + } + if (host && isWindowsAgentHost(host)) { + return LOG_PLACEHOLDER_WINRM; + } + if (kind === "fallback") { + return LOG_PLACEHOLDER_SSH_UPDATE; + } + return LOG_PLACEHOLDER_GENERIC; +} + +export function remoteActionLogPlaceholderFromTitle(title: string): string { + if (/winrm/i.test(title)) { + return LOG_PLACEHOLDER_WINRM; + } + if (/ssh-monitor|\/var\/log\/update_script/i.test(title)) { + return LOG_PLACEHOLDER_SSH_UPDATE; + } + return LOG_PLACEHOLDER_GENERIC; +} diff --git a/frontend/src/version.ts b/frontend/src/version.ts index 5439fac..e2ce694 100644 --- a/frontend/src/version.ts +++ b/frontend/src/version.ts @@ -1,4 +1,4 @@ /** Fallback до загрузки /health; при релизе держите в sync с backend/app/version.py */ export const APP_NAME = "Security Alert Center"; -export const APP_VERSION = "0.5.12"; +export const APP_VERSION = "0.5.13"; export const APP_VERSION_LABEL = `${APP_NAME} v.${APP_VERSION}`; diff --git a/frontend/src/views/HostDetailView.vue b/frontend/src/views/HostDetailView.vue index 04c3111..829156f 100644 --- a/frontend/src/views/HostDetailView.vue +++ b/frontend/src/views/HostDetailView.vue @@ -315,6 +315,7 @@ import { import { isLinuxAgentHost, remoteActionKindForHost, + remoteActionLogPlaceholder, remoteActionTitleForHost, type AgentGitVersions, } from "../utils/hostAgentUpgrade"; @@ -638,7 +639,7 @@ async function runRequestAgentUpdate() { async function runAgentFallback() { agentControlMessage.value = ""; const title = isWindowsHost.value ? "Обновление через WinRM" : "Fallback SSH (ssh-monitor)"; - const job = await runHostRemoteAction(hostId.value, title, "fallback"); + const job = await runHostRemoteAction(hostId.value, title, "fallback", remoteActionLogPlaceholder(host.value, "fallback")); if (job) { agentControlOk.value = job.ok ?? false; if (job.ok) { @@ -706,6 +707,7 @@ async function runAgentUpdate() { hostId.value, "Обновление ssh-monitor (SSH)", "ssh-update", + remoteActionLogPlaceholder(host.value, "ssh-update"), ); if (job?.ok) { const detail = await fetchHost(hostId.value); @@ -728,6 +730,7 @@ async function runAgentUpgradeFromCell() { hostId.value, remoteActionTitleForHost(host.value), kind, + remoteActionLogPlaceholder(host.value, kind), ); if (job?.ok) { const detail = await fetchHost(hostId.value); diff --git a/frontend/src/views/HostsView.vue b/frontend/src/views/HostsView.vue index c8f9011..64fe2bc 100644 --- a/frontend/src/views/HostsView.vue +++ b/frontend/src/views/HostsView.vue @@ -135,6 +135,8 @@ import { isAgentVersionOutdated } from "../utils/agentVersion"; import { isGitAgentUpgradeAvailable, remoteActionKindForHost, + remoteActionLogPlaceholder, + remoteActionLogPlaceholderFromTitle, remoteActionTitleForHost, } from "../utils/hostAgentUpgrade"; import { @@ -289,7 +291,12 @@ async function startAgentUpgrade(h: HostSummary) { } const kind = remoteActionKindForHost(h); if (!kind) return; - void runHostRemoteAction(h.id, remoteActionTitleForHost(h), kind); + void runHostRemoteAction( + h.id, + remoteActionTitleForHost(h), + kind, + remoteActionLogPlaceholder(h, kind), + ); } function openHost(id: number) { @@ -450,7 +457,11 @@ interface HostDeleteResponse { async function onManualAddStarted(payload: { hostId: number; title: string }) { await loadHosts(); - void pollHostRemoteAction(payload.hostId, payload.title); + void pollHostRemoteAction( + payload.hostId, + payload.title, + remoteActionLogPlaceholderFromTitle(payload.title), + ); } async function confirmDelete(h: HostSummary) {