diff --git a/frontend/src/features/integrations/components/IntegrationDrawer.tsx b/frontend/src/features/integrations/components/IntegrationDrawer.tsx
index 9bf269c02..661d5f493 100644
--- a/frontend/src/features/integrations/components/IntegrationDrawer.tsx
+++ b/frontend/src/features/integrations/components/IntegrationDrawer.tsx
@@ -18,6 +18,7 @@ import { CrowdStrikeGuide } from '@/features/integrations/components/setup/cloud
import { M365Guide, O365_GRAPH_FIELDS } from '@/features/integrations/components/setup/collector/collectors/M365Guide'
import { SophosGuide } from '@/features/integrations/components/setup/collector/collectors/SophosGuide'
import { CustomSetup } from '@/features/integrations/components/setup/CustomSetup'
+import { Section } from '@/features/integrations/components/ui/Section'
import { getIntegrationDashboardSearch } from '@/features/dashboard/utils/integration-dashboard-routing'
import type { Integration } from '@/features/integrations/types'
@@ -195,7 +196,17 @@ export function IntegrationDrawer({ integration: i, onClose }: IntegrationDrawer
<>
{isCustom(i) &&
}
- {!isCustom(i) && isAgent(i) &&
}
+ {!isCustom(i) && isAgent(i) && i.guideChannel &&
}
+ {!isCustom(i) && isAgent(i) && !i.guideChannel && (
+ <>
+
+ {i.guideSetting && (
+
+ )}
+ >
+ )}
{!isCustom(i) && i.kind === 'cloud' && isAWS(i.name) &&
}
{!isCustom(i) && i.kind === 'cloud' && isAzure(i.name) &&
}
{!isCustom(i) && i.kind === 'cloud' && isGCP(i) &&
}
diff --git a/frontend/src/features/integrations/components/setup/ChannelGuide.tsx b/frontend/src/features/integrations/components/setup/ChannelGuide.tsx
index 0f3ca4e01..70daac203 100644
--- a/frontend/src/features/integrations/components/setup/ChannelGuide.tsx
+++ b/frontend/src/features/integrations/components/setup/ChannelGuide.tsx
@@ -5,7 +5,9 @@ import type { ReactNode } from 'react'
import { Section } from '@/features/integrations/components/ui/Section'
import { CodeBlock } from '@/features/integrations/components/ui/CodeBlock'
import { AgentSetup } from '@/features/integrations/components/setup/AgentSetup'
-import { forwarderHost } from '@/features/integrations/components/setup/collector/ForwarderGuide'
+import { ForwarderGuide } from '@/features/integrations/components/setup/collector/ForwarderGuide'
+import type { RemoteEnableSelection } from '@/features/integrations/components/setup/collector/RemoteEnablePanel'
+import { defaultPortFor } from '@/features/integrations/components/setup/collector/protoCatalog'
import type { Integration, IntegrationGuideChannel } from '@/features/integrations/types'
export function ChannelGuide({ integration }: { integration: Integration }) {
@@ -41,74 +43,79 @@ function GuideLayout({
function SyslogDeviceGuide({ integration }: { integration: Integration }) {
const { t } = useTranslation()
- const [protocol, setProtocol] = useState<'tcp' | 'udp'>('tcp')
- const host = forwarderHost()
+ const sourceType = integration.forwarderDataType || 'syslog'
+ const port = defaultPortFor(sourceType, 'tcp') || '7014'
+ const [selection, setSelection] = useState
({ proto: 'tcp', port })
+ const host = selection.collector?.ip || ''
return (
-
-
- Configure the device to send syslog to the UTMStack Collector. TCP is recommended for chatty
- devices; the UDP receiver uses a 2,048-byte message buffer and truncates longer messages.
-
-
-
+
+
+ Configure the device to send syslog to the selected UTMStack Collector. TCP is recommended
+ for chatty devices; the UDP receiver uses a 2,048-byte message buffer and truncates longer
+ messages.
+
+
-
- For a device that only supports port 514, change the Collector's syslog UDP port with:
-
-
-
- Only do this on a Collector that is not running Cisco integrations; they may already use UDP
- 514. The command refuses a port that is busy. Changing a built-in port is not done with
- enable-integration.
-
-
- {t('datasources.drawer.viewLogs')} will open Log Explorer for this integration's data type.
-
- {integration.guideSetting && (
- {integration.guideSetting}
- )}
-
+ />
+
+ {t('datasources.drawer.viewLogs')} will open Log Explorer for this integration's data type.
+
+ {integration.guideSetting && (
+ {integration.guideSetting}
+ )}
+
+
)
}
function NetflowExporterGuide({ integration }: { integration: Integration }) {
- const host = forwarderHost()
+ const sourceType = integration.forwarderDataType || 'netflow'
+ const port = defaultPortFor(sourceType, 'udp') || '2055'
+ const [selection, setSelection] = useState({ proto: 'udp', port })
+ const host = selection.collector?.ip || ''
+
return (
-
-
- Configure the exporter to send NetFlow over UDP to the UTMStack Collector:
-
-
+
+
+ Configure the exporter to send NetFlow over UDP to the selected UTMStack Collector:
+
+
-
- Select the export version supported by the device and configure its source interface. Verify
- that flows arrive in Log Explorer using the View logs button.
-
- {integration.guideSetting && (
- {integration.guideSetting}
- )}
-
+ />
+
+ Select the export version supported by the device and configure its source interface. Verify
+ that flows arrive in Log Explorer using the View logs button.
+
+ {integration.guideSetting && (
+ {integration.guideSetting}
+ )}
+
+
)
}
diff --git a/frontend/src/features/integrations/components/setup/CustomSetup.tsx b/frontend/src/features/integrations/components/setup/CustomSetup.tsx
index 962e5cc98..dd9b4a53a 100644
--- a/frontend/src/features/integrations/components/setup/CustomSetup.tsx
+++ b/frontend/src/features/integrations/components/setup/CustomSetup.tsx
@@ -1,6 +1,6 @@
import { useState } from 'react'
import { useTranslation, Trans } from 'react-i18next'
-import { Forward, Server, ShieldCheck } from 'lucide-react'
+import { Forward, Server, ShieldCheck } from 'lucide-react'
import { Section } from '@/features/integrations/components/ui/Section'
import { CodeBlock } from '@/features/integrations/components/ui/CodeBlock'
import {
@@ -9,7 +9,7 @@ import {
FlowEdge,
} from '@/features/integrations/components/setup/collector/ForwarderGuide'
import type { Integration } from '@/features/integrations/types'
-import { type RemoteEnableSelection } from './collector/RemoteEnablePanel'
+import type { RemoteEnableSelection } from './collector/RemoteEnablePanel'
const ROOT = 'integrations.setup.custom'
// A custom data type has no ProtoPorts/HTTPPorts catalog entry, so every
@@ -18,7 +18,8 @@ const ROOT = 'integrations.setup.custom'
export function CustomSetup({ integration }: { integration: Integration }) {
const { t } = useTranslation()
- const name = integration.dataType || integration.moduleName?.toLowerCase() || 'my-integration'
+ const dataType = integration.dataType
+ const name = dataType || integration.moduleName?.toLowerCase() || 'my-integration'
const [selection, setSelection] = useState({ proto: 'udp', port: '7100' })
const { proto, port } = selection
@@ -28,43 +29,55 @@ export function CustomSetup({ integration }: { integration: Integration }) {
// to the Forwarder host.
const endpoint = `${proto}://127.0.0.1:${port}/logs`
- return (
-
-
- {t(`${ROOT}.intro.body`)}
-
- }
- title={t(`${ROOT}.diagram.source`)}
- sub={t(`${ROOT}.diagram.sourceSub`)}
- tone="neutral"
- />
-
- }
- title={t(`${ROOT}.diagram.forwarder`)}
- sub={`:${selection.port}`}
- tone="accent"
- />
-
- }
- title="UTMStack"
- sub={t(`${ROOT}.diagram.utmstackSub`)}
- tone="brand"
- />
-
-
- {t(`${ROOT}.intro.note`)}
+ if (!dataType) {
+ return (
+
+
+ {t('integrations.setup.collector.guideUnavailableBody', { name: integration.name })}
- )}
- >
+ )
+ }
+
+ return (
+
+
+ {t(`${ROOT}.intro.body`)}
+
+ }
+ title={t(`${ROOT}.diagram.source`)}
+ sub={t(`${ROOT}.diagram.sourceSub`)}
+ tone="neutral"
+ />
+
+ }
+ title={t(`${ROOT}.diagram.forwarder`)}
+ sub={`:${selection.port}`}
+ tone="accent"
+ />
+
+ }
+ title="UTMStack"
+ sub={t(`${ROOT}.diagram.utmstackSub`)}
+ tone="brand"
+ />
+
+
+ {t(`${ROOT}.intro.note`)}
+
+
+ )}
+ >
{isHttp ? (
@@ -90,7 +103,11 @@ export function CustomSetup({ integration }: { integration: Integration }) {
',
+ port: selection.port,
+ proto: selection.proto.toUpperCase(),
+ }}
components={{ hl: }}
/>
@@ -102,9 +119,7 @@ export function CustomSetup({ integration }: { integration: Integration }) {
{t(`${ROOT}.parserBody`, { dataType: name })}
-
-
+
)
}
-
diff --git a/frontend/src/features/integrations/components/setup/collector/ForwarderGuide.tsx b/frontend/src/features/integrations/components/setup/collector/ForwarderGuide.tsx
index a0beb172b..a7921c94b 100644
--- a/frontend/src/features/integrations/components/setup/collector/ForwarderGuide.tsx
+++ b/frontend/src/features/integrations/components/setup/collector/ForwarderGuide.tsx
@@ -157,10 +157,14 @@ interface ForwarderGuideProps {
source: string
/** Forwarder port for this data type, e.g. "7016" (illustrative default shown in the diagram). */
port: string
+ /** Stable initial port fallback when the data type has no catalog entry. */
+ defaultPort?: string
/** The dataType shown in the connection details, e.g. "ibm-aix". */
sourceType: string
/** Initial protocol, when the device needs something other than the catalog's first entry (e.g. ESXi/SentinelOne are TCP-only in practice). */
defaultProto?: Proto
+ /** Explicit protocol choices when this integration has a narrower catalog than its data type. */
+ availableProtos?: Proto[]
/** Vendor-specific device-side config (how to point the device at the Forwarder). */
header?: ReactNode
onSetSelection?:(selection:RemoteEnableSelection)=>void
@@ -170,18 +174,24 @@ interface ForwarderGuideProps {
export function ForwarderGuide({
source,
port,
+ defaultPort,
sourceType,
defaultProto,
+ availableProtos: configuredProtos,
header,
onSetSelection,
children
}: ForwarderGuideProps) {
const { t } = useTranslation()
- const availableProtos = useMemo(() => availableProtosFor(sourceType), [sourceType])
+ const availableProtos = useMemo(
+ () => configuredProtos ?? availableProtosFor(sourceType),
+ [sourceType, configuredProtos],
+ )
const initialProto = defaultProto ?? availableProtos[0]
+ const fallbackPort = defaultPortFor(sourceType, initialProto) || defaultPort || port
const [selection, setSelection] = useState(() => ({
proto: initialProto,
- port: defaultPortFor(sourceType, initialProto) || port,
+ port: fallbackPort,
apiKey: null,
}))
@@ -215,6 +225,7 @@ export function ForwarderGuide({
dataType={sourceType}
availableProtos={availableProtos}
defaultProto={defaultProto}
+ defaultPort={fallbackPort}
step={1}
onSelectionChange={setSelection}
onRequestAddCollector={handleAddCollector}
diff --git a/frontend/src/features/integrations/components/setup/collector/GenericCollectorGuide.tsx b/frontend/src/features/integrations/components/setup/collector/GenericCollectorGuide.tsx
index d8147fbdb..8e12850ab 100644
--- a/frontend/src/features/integrations/components/setup/collector/GenericCollectorGuide.tsx
+++ b/frontend/src/features/integrations/components/setup/collector/GenericCollectorGuide.tsx
@@ -1,10 +1,85 @@
+import { useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { Section } from '@/features/integrations/components/ui/Section'
+import { CodeBlock } from '@/features/integrations/components/ui/CodeBlock'
import { ChannelGuide } from '@/features/integrations/components/setup/ChannelGuide'
+import { ForwarderGuide } from '@/features/integrations/components/setup/collector/ForwarderGuide'
+import type { RemoteEnableSelection } from './RemoteEnablePanel'
+import { availableProtosFor, defaultPortFor, type Proto } from './protoCatalog'
import type { Integration } from '@/features/integrations/types'
-interface GenericCollectorGuideProps {
- integration: Integration
+const ROOT = 'integrations.setup.collector'
+
+function getDefaultEndpoint(integration: Integration): { proto: Proto; port: string; protos: Proto[] } | null {
+ const dataType = integration.forwarderDataType || integration.dataType
+ if (!dataType) return null
+
+ const availableProtos = availableProtosFor(dataType)
+ const configuredDefault = integration.defaultPort?.match(/^(\d+)(?:\/(udp|tcp|tls|http|https))?$/i)
+ const configuredProto = configuredDefault?.[2]?.toLowerCase() as Proto | undefined
+ const configuredPort = Number(configuredDefault?.[1])
+ const validConfiguredPort = configuredPort > 0 && configuredPort <= 65535
+ const catalogProtos = availableProtos.filter((proto) => !!defaultPortFor(dataType, proto))
+
+ if (catalogProtos.length > 0) {
+ const proto = configuredProto && catalogProtos.includes(configuredProto)
+ ? configuredProto
+ : catalogProtos[0]
+ const port = defaultPortFor(dataType, proto) || (validConfiguredPort ? String(configuredPort) : '')
+ return port ? { proto, port, protos: catalogProtos } : null
+ }
+
+ if (!configuredProto || !validConfiguredPort) return null
+ return { proto: configuredProto, port: String(configuredPort), protos: [configuredProto] }
}
-export function GenericCollectorGuide({ integration: i }: GenericCollectorGuideProps) {
- return
+export function GenericCollectorGuide({ integration }: { integration: Integration }) {
+ const { t } = useTranslation()
+ const endpoint = getDefaultEndpoint(integration)
+ const [selection, setSelection] = useState(() => ({
+ proto: endpoint?.proto ?? 'udp',
+ port: endpoint?.port ?? '',
+ }))
+
+ if (integration.guideChannel) {
+ return
+ }
+
+ const forwarderDataType = integration.forwarderDataType || integration.dataType
+
+ if (integration.ingestType?.toLowerCase() === 'forwarder' && endpoint && forwarderDataType) {
+ const host = selection.collector?.ip || ''
+
+ return (
+
+
+
+ {t(`${ROOT}.genericSourceBody`, { name: integration.name })}
+
+
+
+
+ )
+ }
+
+ return (
+
+
+ {t(`${ROOT}.guideUnavailableBody`, { name: integration.name })}
+
+
+ )
}
diff --git a/frontend/src/features/integrations/components/setup/collector/RemoteEnablePanel.tsx b/frontend/src/features/integrations/components/setup/collector/RemoteEnablePanel.tsx
index 2a4893280..90c9643a1 100644
--- a/frontend/src/features/integrations/components/setup/collector/RemoteEnablePanel.tsx
+++ b/frontend/src/features/integrations/components/setup/collector/RemoteEnablePanel.tsx
@@ -24,6 +24,7 @@ interface RemoteEnablePanelProps {
dataType: string
availableProtos: Proto[]
defaultProto?: Proto
+ defaultPort?: string
step?: number
onSelectionChange?: (selection: RemoteEnableSelection) => void
onRequestAddCollector?: () => void
@@ -133,6 +134,7 @@ export function RemoteEnablePanel({
dataType,
availableProtos,
defaultProto,
+ defaultPort = '',
step,
onSelectionChange,
onRequestAddCollector,
@@ -148,7 +150,7 @@ export function RemoteEnablePanel({
const initialProto = defaultProto ?? availableProtos[0]
const [collectorId, setCollectorId] = useState(null)
const [proto, setProto] = useState(initialProto)
- const [port, setPort] = useState(() => defaultPortFor(dataType, initialProto))
+ const [port, setPort] = useState(() => defaultPortFor(dataType, initialProto) || defaultPort)
const httpDefaults = httpDefaultsFor(dataType)
const [auth, setAuth] = useState(httpDefaults?.auth ?? '')
const [path, setPath] = useState(httpDefaults?.path ?? '')
@@ -215,7 +217,7 @@ export function RemoteEnablePanel({
if (data.configured) {
const nextProto = (data.proto as Proto) || initialProto
setProto(nextProto)
- setPort(data.port || defaultPortFor(dataType, nextProto))
+ setPort(data.port || defaultPortFor(dataType, nextProto) || defaultPort)
setAuth((data.auth as HttpAuth) ?? '')
setPath(data.path ?? '')
setSignatureHeader(data.signatureHeader ?? '')
@@ -223,11 +225,11 @@ export function RemoteEnablePanel({
}
setProto(initialProto)
- setPort(defaultPortFor(dataType, initialProto))
+ setPort(defaultPortFor(dataType, initialProto) || defaultPort)
setAuth(httpDefaults?.auth ?? '')
setPath(httpDefaults?.path ?? '')
setSignatureHeader(httpDefaults?.signatureHeader ?? '')
- }, [collectorId, currentConfig.isSuccess, currentConfig.data])
+ }, [collectorId, currentConfig.isSuccess, currentConfig.data, defaultPort])
if (!canManage) {
return (
@@ -351,7 +353,7 @@ export function RemoteEnablePanel({
onChange={(e) => {
const next = e.target.value as Proto
setProto(next)
- setPort(defaultPortFor(dataType, next))
+ setPort(defaultPortFor(dataType, next) || defaultPort)
setGeneratedSecret(null)
}}
disabled={availableProtos.length <= 1 || isConfigLocked}
diff --git a/frontend/src/features/integrations/constants/injectedModules.test.ts b/frontend/src/features/integrations/constants/injectedModules.test.ts
index c3514ebd2..1ad792f58 100644
--- a/frontend/src/features/integrations/constants/injectedModules.test.ts
+++ b/frontend/src/features/integrations/constants/injectedModules.test.ts
@@ -1,5 +1,5 @@
import { describe, expect, it } from 'vitest'
-import { INJECTED_MODULES } from './injectedModules'
+import { applyInjectedGuideMetadata, INJECTED_MODULES, mergeInjectedIntegrations } from './injectedModules'
describe('frontend-injected integration guides', () => {
it('keeps guide-only catalog entries available with unique stable ids', () => {
@@ -9,15 +9,85 @@ describe('frontend-injected integration guides', () => {
})
it('provides a demonstrative integration for every supported guide channel', () => {
- const channels = new Set(INJECTED_MODULES.map((integration) => integration.guideChannel))
+ const channels = new Set(
+ INJECTED_MODULES
+ .map((integration) => integration.guideChannel)
+ .filter((channel) => channel !== undefined),
+ )
expect(channels).toEqual(new Set(['syslog', 'netflow', 'windows-agent', 'linux-agent']))
})
+ it('assigns every injected integration an explicit ingest type', () => {
+ expect(INJECTED_MODULES.every((integration) => integration.ingestType)).toBe(true)
+ expect(INJECTED_MODULES.find((integration) => integration.moduleName === 'NGINX')?.ingestType).toBe('agent')
+ expect(INJECTED_MODULES.find((integration) => integration.moduleName === 'IIS')?.ingestType).toBe('agent')
+ expect(INJECTED_MODULES.find((integration) => integration.moduleName === 'SYSLOG')?.ingestType).toBe('forwarder')
+ expect(INJECTED_MODULES.find((integration) => integration.moduleName === 'NGINX')?.kind).toBe('agents & syslog')
+ })
+
it('uses the supported Syslog and NetFlow endpoints', () => {
const syslog = INJECTED_MODULES.find((integration) => integration.moduleName === 'SYSLOG')
const netflow = INJECTED_MODULES.find((integration) => integration.moduleName === 'NETFLOW')
- expect(syslog).toMatchObject({ dataType: 'syslog', defaultPort: '7014/tcp', logFilterField: 'dataSource' })
- expect(netflow).toMatchObject({ dataType: 'netflow', defaultPort: '2055/udp', logFilterField: 'log.exporter' })
+ expect(syslog).toMatchObject({
+ dataType: 'syslog',
+ forwarderDataType: 'syslog',
+ defaultPort: '7014/tcp',
+ logFilterField: 'dataSource',
+ })
+ expect(netflow).toMatchObject({
+ dataType: 'netflow',
+ forwarderDataType: 'netflow',
+ defaultPort: '2055/udp',
+ logFilterField: 'log.exporter',
+ })
+ })
+
+ it('adds guide metadata to backend rows without replacing backend-owned fields', () => {
+ const syslog = INJECTED_MODULES.find((integration) => integration.moduleName === 'SYSLOG')!
+ const backendIntegration = {
+ ...syslog,
+ id: 'backend-syslog-id',
+ dataType: 'backend-syslog-type',
+ ingestType: 'collector',
+ forwarderDataType: undefined,
+ defaultPort: '6514/tcp',
+ guideChannel: undefined,
+ }
+
+ expect(applyInjectedGuideMetadata(backendIntegration)).toMatchObject({
+ id: 'backend-syslog-id',
+ dataType: 'backend-syslog-type',
+ ingestType: 'collector',
+ forwarderDataType: 'syslog',
+ defaultPort: '6514/tcp',
+ guideChannel: 'syslog',
+ guideOnly: true,
+ })
+ })
+
+ it('leaves integrations without matching guide metadata unchanged', () => {
+ const integration = { ...INJECTED_MODULES[0], moduleName: 'UNMAPPED_INTEGRATION' }
+ expect(applyInjectedGuideMetadata(integration)).toBe(integration)
+ })
+
+ it('deduplicates backend and injected rows case-insensitively while keeping backend identity', () => {
+ const injectedSyslog = INJECTED_MODULES.find((integration) => integration.moduleName === 'SYSLOG')!
+ const backendSyslog = {
+ ...injectedSyslog,
+ id: 'backend-syslog-id',
+ moduleName: 'syslog',
+ dataType: 'backend-syslog-type',
+ }
+
+ const merged = mergeInjectedIntegrations([backendSyslog])
+ const syslogEntries = merged.filter((integration) => integration.moduleName?.toUpperCase() === 'SYSLOG')
+
+ expect(syslogEntries).toHaveLength(1)
+ expect(syslogEntries[0]).toMatchObject({
+ id: 'backend-syslog-id',
+ dataType: 'backend-syslog-type',
+ forwarderDataType: 'syslog',
+ })
})
it('filters nested Windows and Linux product fields with is-one-of', () => {
diff --git a/frontend/src/features/integrations/constants/injectedModules.ts b/frontend/src/features/integrations/constants/injectedModules.ts
index 0ed2d7c01..a481d290a 100644
--- a/frontend/src/features/integrations/constants/injectedModules.ts
+++ b/frontend/src/features/integrations/constants/injectedModules.ts
@@ -1,6 +1,7 @@
import type {
Integration,
DeployKind,
+ IngestType,
IntegrationGuideChannel,
IntegrationLogFilter,
} from '@/features/integrations/types'
@@ -54,38 +55,75 @@ const SEEDS: InjectedSeed[] = [
]
interface GuideMetadata {
- channel: IntegrationGuideChannel
+ channel?: IntegrationGuideChannel
+ ingestType: IngestType
dataType?: string
+ forwarderDataType?: string
defaultPort?: string
filters?: IntegrationLogFilter[]
filterField?: 'dataSource' | 'log.exporter'
setting?: string
}
+const SYSLOG_FORWARDER: GuideMetadata = {
+ channel: 'syslog',
+ ingestType: 'forwarder',
+ dataType: 'syslog',
+ forwarderDataType: 'syslog',
+ defaultPort: '7014/tcp',
+ filterField: 'dataSource',
+}
+
const GUIDE_METADATA: Record = {
- DEFAULT: {
- channel: 'syslog',
- dataType: 'syslog',
- defaultPort: '7014/tcp',
- filterField: 'dataSource',
- },
+ APACHE: SYSLOG_FORWARDER,
+ APACHE2: SYSLOG_FORWARDER,
+ ELASTICSEARCH: SYSLOG_FORWARDER,
+ HAPROXY: SYSLOG_FORWARDER,
+ KAFKA: SYSLOG_FORWARDER,
+ KIBANA: SYSLOG_FORWARDER,
+ LOGSTASH: SYSLOG_FORWARDER,
+ MONGODB: SYSLOG_FORWARDER,
+ MYSQL: SYSLOG_FORWARDER,
+ NATS: SYSLOG_FORWARDER,
NGINX: {
channel: 'linux-agent',
+ ingestType: 'agent',
dataType: 'linux',
filters: [{ field: 'log.syslogIdentifier', operator: 'IS_ONE_OF_TERMS', value: ['nginx'] }],
setting: 'Configure Nginx access and error logs to be forwarded to the Linux journal or syslog.',
},
- SYSLOG: { channel: 'syslog', defaultPort: '7014/tcp', filterField: 'dataSource' },
- NETFLOW: { channel: 'netflow', defaultPort: '2055/udp', filterField: 'log.exporter' },
+ OSQUERY: {
+ ingestType: 'agent',
+ setting: 'Install the UTMStack agent on the host and configure it to collect the osquery results.',
+ },
+ POSTGRESQL: SYSLOG_FORWARDER,
+ REDIS: SYSLOG_FORWARDER,
+ SYSLOG: SYSLOG_FORWARDER,
+ TRAEFIK: SYSLOG_FORWARDER,
+ NETFLOW: {
+ channel: 'netflow',
+ ingestType: 'forwarder',
+ dataType: 'netflow',
+ forwarderDataType: 'netflow',
+ defaultPort: '2055/udp',
+ filterField: 'log.exporter',
+ },
JSON: {
channel: 'syslog',
+ ingestType: 'forwarder',
dataType: 'syslog',
+ forwarderDataType: 'syslog',
defaultPort: '7014/tcp',
filterField: 'dataSource',
setting: 'The legacy JSON HTTP endpoint is not published in v12. This demo entry uses the supported syslog channel; send JSON text as a syslog message.',
},
+ IIS: {
+ ingestType: 'agent',
+ setting: 'Install the Windows UTMStack agent on the IIS host and configure it to collect IIS log files.',
+ },
WINDOWS_SQL_SERVER: {
channel: 'windows-agent',
+ ingestType: 'agent',
filters: [
{ field: 'log.providerName', operator: 'IS_ONE_OF_TERMS', value: ['MSSQLSERVER'] },
{ field: 'log.channel', operator: 'IS_ONE_OF_TERMS', value: ['Application'] },
@@ -94,6 +132,7 @@ const GUIDE_METADATA: Record = {
},
WINDOWS_FILE_AUDITING: {
channel: 'windows-agent',
+ ingestType: 'agent',
filters: [
{ field: 'log.providerName', operator: 'IS_ONE_OF_TERMS', value: ['Microsoft-Windows-Security-Auditing'] },
{ field: 'log.channel', operator: 'IS_ONE_OF_TERMS', value: ['Security'] },
@@ -103,14 +142,18 @@ const GUIDE_METADATA: Record = {
}
export const INJECTED_MODULES: Integration[] = SEEDS.map((s) => {
- const guide = GUIDE_METADATA[s.moduleName] ?? GUIDE_METADATA.DEFAULT
+ const guide = GUIDE_METADATA[s.moduleName]
+ if (!guide) {
+ throw new Error(`Missing guide metadata for injected integration "${s.moduleName}"`)
+ }
+
return {
id: s.id,
name: s.name,
moduleName: s.moduleName,
dataType: guide.dataType ?? s.dataType,
- ingestType: 'forwarder',
- kind: s.kind,
+ ingestType: guide.ingestType,
+ kind: guide.ingestType === 'agent' ? 'agents & syslog' : s.kind,
status: 'available',
description: guide.setting ?? '',
category: s.category,
@@ -119,11 +162,46 @@ export const INJECTED_MODULES: Integration[] = SEEDS.map((s) => {
guideOnly: true,
defaultPort: guide.defaultPort ?? s.defaultPort,
guideChannel: guide.channel,
+ forwarderDataType: guide.forwarderDataType,
logFilters: guide.filters,
logFilterField: guide.filterField,
- guideSetting: guide.setting ?? `Configure ${s.name} to send its logs through the supported syslog channel.`,
+ guideSetting: guide.setting,
events24h: undefined,
rate: undefined,
darkInvert: false,
}
})
+
+export function applyInjectedGuideMetadata(integration: Integration): Integration {
+ const moduleName = integration.moduleName?.toUpperCase()
+ const guide = moduleName ? GUIDE_METADATA[moduleName] : undefined
+ if (!guide) return integration
+
+ return {
+ ...integration,
+ ...(integration.dataType || !guide.dataType ? {} : { dataType: guide.dataType }),
+ ...(integration.ingestType ? {} : { ingestType: guide.ingestType }),
+ ...(guide.channel ? { guideChannel: guide.channel } : {}),
+ ...(guide.forwarderDataType ? { forwarderDataType: guide.forwarderDataType } : {}),
+ ...(integration.defaultPort || !guide.defaultPort ? {} : { defaultPort: guide.defaultPort }),
+ ...(guide.filters ? { logFilters: guide.filters } : {}),
+ ...(guide.filterField ? { logFilterField: guide.filterField } : {}),
+ ...(guide.setting ? { guideSetting: guide.setting } : {}),
+ guideOnly: true,
+ }
+}
+
+export function mergeInjectedIntegrations(
+ backendIntegrations: Integration[],
+ injectedIntegrations: Integration[] = INJECTED_MODULES,
+): Integration[] {
+ const backendModuleNames = new Set(
+ backendIntegrations.map((integration) => integration.moduleName?.toUpperCase()).filter(Boolean),
+ )
+ const normalizedBackend = backendIntegrations.map(applyInjectedGuideMetadata)
+ const missingInjected = injectedIntegrations.filter(
+ (integration) => !backendModuleNames.has(integration.moduleName?.toUpperCase()),
+ )
+
+ return [...normalizedBackend, ...missingInjected]
+}
diff --git a/frontend/src/features/integrations/pages/IntegrationsPage.tsx b/frontend/src/features/integrations/pages/IntegrationsPage.tsx
index f0749326d..846e332e7 100644
--- a/frontend/src/features/integrations/pages/IntegrationsPage.tsx
+++ b/frontend/src/features/integrations/pages/IntegrationsPage.tsx
@@ -13,7 +13,7 @@ import { AddCustomIntegrationCard } from '@/features/integrations/components/Add
import { CreateIntegrationDrawer } from '@/features/integrations/components/CreateIntegrationDrawer'
import { KIND_META, categoryLabel } from '@/features/integrations/constants'
import { SYSTEM_MODULES } from '@/features/integrations/constants/systemModules'
-import { INJECTED_MODULES } from '@/features/integrations/constants/injectedModules'
+import { INJECTED_MODULES, mergeInjectedIntegrations } from '@/features/integrations/constants/injectedModules'
import type {
Integration,
DeployKind,
@@ -32,7 +32,7 @@ const LOGO = (slug: string) => {
}
const INJECTED_BY_MODULE_NAME = new Map(
- INJECTED_MODULES.map((integration) => [integration.moduleName ?? '', integration]),
+ INJECTED_MODULES.map((integration) => [(integration.moduleName ?? '').toUpperCase(), integration]),
)
function mapModuleToIntegration(module: IntegrationResponse, t: TFunction): Integration {
@@ -40,13 +40,15 @@ function mapModuleToIntegration(module: IntegrationResponse, t: TFunction): Inte
// System integrations: icon, description and category are owned by the frontend
// (per-theme icons + i18n). Custom ones keep using the catalog row's own icon
// and description, and group under 'custom'.
- const injectedMeta = INJECTED_BY_MODULE_NAME.get(module.name)
+ const injectedMeta = INJECTED_BY_MODULE_NAME.get(module.name.toUpperCase())
const meta = isSystem ? SYSTEM_MODULES[module.name] : undefined
const category = meta?.category ?? injectedMeta?.category ?? 'custom'
// Map the category to a known DeployKind; anything unknown falls back to
// 'other' (Collector group) so a new integration never breaks the grid.
- const kind: DeployKind = (category in KIND_META ? category : 'other') as DeployKind
+ const kind: DeployKind = module.ingestType?.toLowerCase() === 'agent'
+ ? 'agents & syslog'
+ : (category in KIND_META ? category : 'other') as DeployKind
const description = isSystem
? t(`integrations.modules.${module.name}.description`, { defaultValue: module.description || '' })
@@ -86,8 +88,6 @@ function mapModuleToIntegration(module: IntegrationResponse, t: TFunction): Inte
logo,
logoDark,
darkInvert: false,
- ...(module.name.toUpperCase() === 'NETFLOW' ? { guideChannel: 'netflow' as const } : {}),
- ...(module.name.toUpperCase() === 'NETFLOW' ? { logFilterField: 'log.exporter' as const } : {}),
events24h: undefined,
rate: undefined,
}
@@ -181,33 +181,23 @@ export function IntegrationsPage() {
const modules = integrations.integrations.data || []
const displayList = useMemo(() => {
- const injectedByName = new Map(INJECTED_MODULES.map((entry) => [entry.moduleName, entry]))
- const catalog = modules.map((m) => {
- const mapped = mapModuleToIntegration(m, t)
- const guideMetadata = injectedByName.get(m.name)
- return guideMetadata
- ? {
- ...mapped,
- guideChannel: guideMetadata.guideChannel,
- guideOnly: true,
- logFilters: guideMetadata.logFilters,
- logFilterField: guideMetadata.logFilterField,
- guideSetting: guideMetadata.guideSetting,
- }
- : mapped
+ const backend = modules.map((module) => mapModuleToIntegration(module, t))
+ const merged = mergeInjectedIntegrations(backend, INJECTED_MODULES)
+ const backendModuleNames = new Set(modules.map((module) => module.name.toUpperCase()))
+
+ return merged.map((integration) => {
+ if (backendModuleNames.has((integration.moduleName ?? '').toUpperCase())) {
+ return integration
+ }
+
+ return {
+ ...integration,
+ name: t(`integrations.modules.${integration.moduleName}.name`, { defaultValue: integration.name }),
+ description: t(`integrations.modules.${integration.moduleName}.description`, {
+ defaultValue: integration.description,
+ }),
+ }
})
- // Injected catalog cards are frontend-owned; dedupe against the backend
- // list by moduleName so a future backend row for the same module never
- // shows up twice (backend row wins — it carries the real id + dataType).
- const backendModuleNames = new Set(modules.map((m) => m.name))
- const injected = INJECTED_MODULES
- .filter((i) => !backendModuleNames.has(i.moduleName ?? ''))
- .map((i) => ({
- ...i,
- name: t(`integrations.modules.${i.moduleName}.name`, { defaultValue: i.name }),
- description: t(`integrations.modules.${i.moduleName}.description`, { defaultValue: i.description }),
- }))
- return [...catalog, ...injected]
}, [modules, t])
// The raw catalog row for the module being edited (for its actual stored icon).
diff --git a/frontend/src/features/integrations/types/index.ts b/frontend/src/features/integrations/types/index.ts
index 1ae0d0af1..4e1f0ac6e 100644
--- a/frontend/src/features/integrations/types/index.ts
+++ b/frontend/src/features/integrations/types/index.ts
@@ -62,6 +62,8 @@ export interface Integration {
defaultPort?: string;
/** Frontend-only guide route for injected and channel-based integrations. */
guideChannel?: IntegrationGuideChannel;
+ /** Forwarder configuration data type when it differs from the integration's log data type. */
+ forwarderDataType?: string;
/** This entry is a presentation/demo fallback and has no catalog row of its own. */
guideOnly?: boolean;
/** Technology-specific filters passed to Log Explorer. */
diff --git a/frontend/src/shared/i18n/locales/en.json b/frontend/src/shared/i18n/locales/en.json
index 1d2f67194..ff8db5d1a 100644
--- a/frontend/src/shared/i18n/locales/en.json
+++ b/frontend/src/shared/i18n/locales/en.json
@@ -4349,6 +4349,4514 @@
"30d": "Last 30 days"
}
},
+ "lookup": {
+ "title": "Lookup any indicator",
+ "placeholder": "Paste an IP, domain, hash, URL, or CVE — we'll check feeds and your environment",
+ "button": "Lookup",
+ "busy": "Searching…"
+ },
+ "tabs": {
+ "iocs": "IOCs",
+ "actors": "Threat actors",
+ "feeds": "Feeds",
+ "analyst": "AI Analyst"
+ },
+ "toolbar": {
+ "searchPlaceholders": {
+ "iocs": "Search IOC value, tag, source…",
+ "actors": "Search actors, aliases, techniques…",
+ "feeds": "Search feeds…"
+ },
+ "last24h": "Last 24 hours",
+ "filters": "Filters",
+ "refresh": "Refresh"
+ },
+ "iocs": {
+ "table": {
+ "type": "Type",
+ "indicator": "Indicator",
+ "reputation": "Reputation",
+ "tags": "Tags",
+ "lastSeen": "Last seen"
+ },
+ "empty": "No IOCs match.",
+ "loadingMore": "Loading more…",
+ "loadedProgress": "Loaded {{loaded}} of {{total}}. Scroll for more.",
+ "endOfResults": "End of results ({{loaded}} of {{total}})."
+ },
+ "drawer": {
+ "loading": "Loading…",
+ "accuracy": "Accuracy:",
+ "actions": {
+ "block": "Block at perimeter",
+ "viewEvents": "View matched events",
+ "externalLookup": "External lookup",
+ "trackCampaign": "Track campaign",
+ "viewIocs": "View matched IOCs",
+ "mitre": "MITRE ATT&CK"
+ },
+ "sections": {
+ "timeline": "Timeline",
+ "networkOrigin": "Network / origin",
+ "associationsWithCount": "Associations ({{count}})",
+ "geolocationsWithCount": "Geolocations ({{count}})",
+ "about": "About",
+ "activity": "Activity"
+ },
+ "fields": {
+ "firstSeen": "First seen",
+ "lastSeen": "Last seen",
+ "country": "Country",
+ "city": "City",
+ "aso": "ASO",
+ "asn": "ASN",
+ "reputation": "Reputation",
+ "accuracy": "Accuracy",
+ "current": "Current",
+ "best": "Best",
+ "worst": "Worst"
+ },
+ "aiBrief": "AI brief",
+ "noDescription": "No description available for this indicator.",
+ "lastObserved": "Last observed {{when}}."
+ },
+ "actors": {
+ "empty": "No actors found."
+ },
+ "feeds": {
+ "empty": "No feeds configured.",
+ "table": {
+ "name": "Feed",
+ "type": "Type",
+ "accuracy": "Accuracy",
+ "header": "Feeds",
+ "format": "Format"
+ },
+ "download": "Download feed",
+ "checksum": "Checksum"
+ },
+ "entityTypes": {
+ "ip": "IP",
+ "hostname": "Host",
+ "domain": "Domain",
+ "url": "URL",
+ "hash": "Hash",
+ "cve": "CVE",
+ "threat": "Threat",
+ "entity": "Entity"
+ },
+ "reputation": {
+ "alarming": "Alarming",
+ "suspicious": "Suspicious",
+ "indefinable": "Indefinable",
+ "fair": "Fair",
+ "trustworthy": "Trustworthy"
+ },
+ "feedAccuracy": {
+ "level1": "Level 1",
+ "level2": "Level 2",
+ "level3": "Level 3"
+ },
+ "triage": {
+ "title": "Triage",
+ "subtitle": "Paste indicators, get verdicts",
+ "input": "Indicators",
+ "placeholder": "Paste IPs, domains, URLs or hashes — one per line, or comma separated.\nDefanged values (1.2.3[.]4, hxxp://) are accepted.",
+ "run": "Triage",
+ "stop": "Stop",
+ "reset": "Clear",
+ "parsed": "{{count}} unique indicators",
+ "capped": "Capped at {{max}} per run.",
+ "progress": "{{done}} of {{total}}",
+ "empty": "Paste indicators above to begin.",
+ "indicator": "Indicator",
+ "type": "Type",
+ "verdict": "Verdict",
+ "reputation": "Rep",
+ "accuracy": "Acc",
+ "tags": "Tags",
+ "lastSeen": "Last seen",
+ "exportCsv": "Export CSV",
+ "exportStix": "Export STIX",
+ "stixNote": "STIX export includes malicious and suspicious rows only.",
+ "open": "Open",
+ "notConfigured": "Threat intelligence is not configured — triage needs an upstream ThreatWinds instance.",
+ "v.malicious": "Malicious",
+ "v.suspicious": "Suspicious",
+ "v.benign": "Benign",
+ "v.unknown": "Unknown",
+ "v.notFound": "Not found",
+ "v.invalid": "Unrecognised",
+ "summary": "Summary"
+ },
+ "report": {
+ "title": "Report",
+ "subtitle": "Publish an indicator to the ThreatWinds graph",
+ "submit": "Report indicator",
+ "submitting": "Reporting…",
+ "error": {
+ "generic": "Could not submit the indicator. Try again."
+ },
+ "value": {
+ "label": "Indicator",
+ "placeholder": "IP, domain, URL, hash or email address"
+ },
+ "type": {
+ "label": "Type",
+ "placeholder": "Inferred from the value",
+ "inferred": "Inferred: {{type}}",
+ "inferenceFailed": "No type could be inferred from this value. Choose one from the list, or type it.",
+ "unknown": "“{{type}}” is not an entity type. Choose one from the list."
+ },
+ "tags": {
+ "label": "Tags",
+ "placeholder": "phishing, credential-theft"
+ },
+ "description": {
+ "label": "Notes"
+ },
+ "reputation": {
+ "legend": "Reputation",
+ "hint": "Leave unset if you have not reached a verdict.",
+ "alarming": "Alarming",
+ "worrying": "Worrying",
+ "concerning": "Concerning",
+ "indefinable": "Indefinable",
+ "adequate": "Adequate",
+ "good": "Good",
+ "exceptional": "Exceptional"
+ },
+ "associations": {
+ "legend": "Related indicators",
+ "add": "Add related indicator",
+ "remove": "Remove",
+ "valuePlaceholder": "Related value",
+ "typePlaceholder": "Type (optional)",
+ "modeLabel": "Relationship",
+ "mode": {
+ "association": "Related to",
+ "aggregation": "Part of"
+ },
+ "visibilityConflict": "This shares no visibility group with the indicator above. The whole submission would be rejected."
+ },
+ "attributes": {
+ "legend": "Details",
+ "hint": "Optional. Anything left blank is not submitted.",
+ "invalidHex": "Expected {{length}} hexadecimal characters.",
+ "invalidHexAny": "Expected hexadecimal characters only.",
+ "invalidNumber": "Expected a number."
+ },
+ "correlate": {
+ "legend": "Correlate",
+ "hint": "Each ticked attribute is published as its own entity, linked to this one.",
+ "count_one": "Creates {{count}} linked entity.",
+ "count_other": "Creates {{count}} linked entities."
+ },
+ "scan": {
+ "notice": "Reporting this also queues a scan of the target."
+ },
+ "receipt": {
+ "title": "Submitted",
+ "noVerdict": "No verdict stated",
+ "skipped": "Not submitted, no type could be inferred",
+ "pending": "Waiting for the indicator to appear in the corpus…",
+ "live": "Live in the corpus — view entity",
+ "processing": "Still being processed. It will appear once ingestion catches up.",
+ "another": "Report another"
+ },
+ "visibility": {
+ "legend": "Visible to"
+ },
+ "example": "Try example"
+ }
+ },
+ "notifications": {
+ "title": "Notifications",
+ "markAllRead": "Mark all read",
+ "empty": "You have no notifications.",
+ "viewAll": "View all",
+ "markRead": "Mark as read",
+ "markUnread": "Mark as unread",
+ "delete": "Delete",
+ "subtitle": "{{total}} total · {{unread}} unread",
+ "allCaughtUp": "All caught up.",
+ "loadFailed": "Could not load notifications."
+ },
+ "pagination": {
+ "perPage": "Per page",
+ "pageOf": "Page {{page}} of {{total}}",
+ "previous": "Previous",
+ "next": "Next"
+ },
+ "license": {
+ "title": "License",
+ "subtitle": "Your edition, capabilities, and license file.",
+ "loading": "Loading license…",
+ "loadError": "Could not load license information.",
+ "statusLabel": "Status",
+ "status": {
+ "community": "Community",
+ "active": "Active",
+ "expiring": "Expiring soon",
+ "expired": "Expired"
+ },
+ "edition": "Edition",
+ "enterprise": "Enterprise",
+ "community": "Community",
+ "editionLine": "{{edition}} edition",
+ "datasourceLimit": "Datasource limit",
+ "unlimited": "Unlimited",
+ "mssp": "MSSP / multi-tenant",
+ "enabled": "Enabled",
+ "licenseType": "License type",
+ "instanceId": "Instance ID",
+ "enterpriseUnlocked": "Enterprise features unlocked",
+ "validUntil": "Valid until",
+ "noExpiry": "No expiry",
+ "timeRemaining": "Time remaining",
+ "expiredAgo": "Expired {{days}}d ago",
+ "daysShort": "{{days}}d",
+ "msspShort": "MSSP",
+ "communityEdition": "Community edition",
+ "communityBlurb": "Free and open-source. Upload an Enterprise license below to unlock multi-tenancy, SSO, higher datasource limits, and advanced compliance.",
+ "upgrade": "Upgrade to Enterprise",
+ "uploadTitle": "Upload a license",
+ "uploadBlurb": "Install or replace the signed LICENSE file. The server validates the signature and expiry before applying it. Admin only.",
+ "installLicense": "Install license",
+ "chooseFile": "Choose file",
+ "noFileSelected": "No file selected",
+ "toast": {
+ "installed": "License installed — {{edition}} edition.",
+ "adminRequired": "Administrator privileges are required to upload a license.",
+ "invalid": "Invalid or expired license file.",
+ "installFailed": "Could not install the license."
+ },
+ "ingestLimit": "Ingest volume",
+ "notMetered": "Not metered",
+ "gbPerMonth": "{{gb}} GB/month"
+ },
+ "audit": {
+ "title": "Audit log",
+ "subtitle": "Record of every security-relevant action.",
+ "totalEntries": "{{total}} total entries.",
+ "loadError": "Could not load audit log",
+ "stats": {
+ "totalEntries": "Total entries",
+ "acrossAllTime": "Across all time",
+ "successRate": "Success rate",
+ "failuresOnPage_one": "{{count}} failure on this page",
+ "failuresOnPage_other": "{{count}} failures on this page",
+ "topAction": "Top action",
+ "onPage": "{{count}} on this page",
+ "uniqueActors": "Unique actors",
+ "includingSystem": "Including system"
+ },
+ "filters": {
+ "title": "Filters",
+ "clear": "Clear",
+ "last24h": "Last 24h",
+ "failuresOnly": "Failures only",
+ "authEvents": "Auth events",
+ "actionPrefix": "Action prefix",
+ "actionPlaceholder": "e.g. auth., user.update",
+ "status": "Status",
+ "any": "Any",
+ "resourceType": "Resource type",
+ "resourceTypePlaceholder": "user, alert…",
+ "resourceId": "Resource id",
+ "user": "User",
+ "userPlaceholder": "login…"
+ },
+ "statusValue": {
+ "success": "Success",
+ "failure": "Failure"
+ },
+ "table": {
+ "timestamp": "Timestamp",
+ "actor": "Actor",
+ "action": "Action",
+ "resource": "Resource",
+ "status": "Status",
+ "ip": "IP",
+ "loading": "Loading…",
+ "emptyTitle": "No audit entries match these filters.",
+ "emptyHint": "Try clearing filters or widening the date range.",
+ "system": "system",
+ "view": "View"
+ },
+ "drawer": {
+ "entry": "entry #{{id}}",
+ "overview": "Overview",
+ "raw": "Raw JSON",
+ "error": "Error",
+ "actor": "Actor",
+ "resource": "Resource",
+ "ip": "IP",
+ "userAgent": "User agent",
+ "session": "Session",
+ "metadata": "Metadata",
+ "copy": "Copy",
+ "copied": "Copied",
+ "copyJson": "Copy JSON"
+ }
+ },
+ "team": {
+ "title": "Team",
+ "subtitle": "Manage users and their roles.",
+ "tabs": {
+ "members": "Members",
+ "roles": "Roles & permissions"
+ },
+ "toast": {
+ "rolesLoadFailed": "Could not load roles",
+ "userLoadFailed": "Could not load user",
+ "rolesUpdated": "Roles updated",
+ "userReactivated": "User reactivated",
+ "userDeactivated": "User deactivated",
+ "tfaReset": "Two-factor authentication reset",
+ "invitationSent": "Invitation sent",
+ "loginOrEmailInUse": "That login or email is already in use",
+ "invalidRequest": "Invalid request",
+ "noPermission": "You do not have permission to do that",
+ "userNotFound": "User not found",
+ "operationFailed": "Operation failed",
+ "emailInUse": "That email is already in use",
+ "roleCreated": "Role created",
+ "roleUpdated": "Role updated",
+ "roleDeleted": "Role deleted",
+ "roleNameInUse": "A role with that identifier already exists",
+ "roleImmutable": "System roles cannot be modified",
+ "permissionsLoadFailed": "Could not load permissions",
+ "localUserCreated": "Local user created"
+ },
+ "members": {
+ "searchPlaceholder": "Search by name or email…",
+ "invite": "Invite user",
+ "colUser": "User",
+ "colRoles": "Roles",
+ "col2fa": "2FA",
+ "colStatus": "Status",
+ "loading": "Loading users…",
+ "loadFailed": "Could not load users.",
+ "retry": "Retry",
+ "noSearchMatch": "No users match your search.",
+ "none": "No users yet.",
+ "noRole": "none",
+ "on": "On",
+ "off": "Off",
+ "countLabel_one": "{{count}} user · page {{page}} of {{pages}}",
+ "countLabel_other": "{{count}} users · page {{page}} of {{pages}}",
+ "federated": "SSO"
+ },
+ "status": {
+ "inactive": "Inactive",
+ "pendingPassword": "Pending password",
+ "active": "Active",
+ "pending": "Pending invite",
+ "suspended": "Suspended"
+ },
+ "drawer": {
+ "createdBy": "created by {{actor}}",
+ "loading": "Loading…",
+ "profileTitle": "Profile",
+ "profileSubtitle": "Only the user can edit these — from their own profile.",
+ "name": "Name",
+ "username": "Username",
+ "email": "Email",
+ "language": "Language",
+ "accountTitle": "Account",
+ "status": "Status",
+ "statusActive": "Active",
+ "statusInactive": "Inactive",
+ "tfa": "2FA",
+ "tfaEnabled": "Enabled",
+ "tfaNotConfigured": "Not configured",
+ "resetTfa": "Reset",
+ "resetTfaHint": "Disable this user's 2FA so they can re-enroll at next login",
+ "resetTfaConfirmTitle": "Reset two-factor authentication?",
+ "resetTfaConfirmBody": "This disables 2FA for {{name}}. They'll sign in with just their password and can set it up again from their profile.",
+ "resetTfaConfirm": "Reset 2FA",
+ "pendingPasswordNote": "Still using the temporary password (invite not completed).",
+ "lastModified": "Last modified {{time}}",
+ "rolesTitle": "Roles",
+ "rolesSubtitle": "Roles grant module permissions. A user can hold more than one.",
+ "noRoleWarning": "No role assigned — the user will have no module access.",
+ "deactivate": "Deactivate",
+ "reactivate": "Reactivate",
+ "waitingInvite": "Waiting for the user to accept the invitation.",
+ "cancel": "Cancel",
+ "saving": "Saving…",
+ "saveRoles": "Save roles",
+ "created": "created {{time}}",
+ "pendingNote": "Invitation not accepted yet.",
+ "federatedNote": "Signs in through an identity provider."
+ },
+ "invite": {
+ "title": "Invite user",
+ "description": "The account is created inactive. The user receives an email to set their password and activate it.",
+ "username": "Username",
+ "usernameHint": "At least 3 characters.",
+ "email": "Email",
+ "firstName": "First name",
+ "lastName": "Last name",
+ "roles": "Roles",
+ "cancel": "Cancel",
+ "sending": "Sending…",
+ "send": "Send invite",
+ "name": "Name",
+ "emailHint": "This is the address they sign in with.",
+ "localDescription": "The account is created with a password and activated immediately. No email is sent.",
+ "modeInvite": "Invite user",
+ "modeLocal": "Create local user",
+ "passwordLabel": "Password",
+ "passwordPlaceholder": "Set a strong password",
+ "localUserNote": "This user will not receive an email and will be automatically activated.",
+ "createLocal": "Create user",
+ "passwordRules": {
+ "length": "At least 8 characters",
+ "case": "At least one uppercase and one lowercase letter",
+ "special": "At least one special character"
+ },
+ "emailInvalid": "Please enter a valid email address"
+ },
+ "rolePicker": {
+ "none": "No roles available."
+ },
+ "roles": {
+ "loading": "Loading roles…",
+ "loadFailed": "Could not load role permissions.",
+ "readonlyNote": "Roles and their permissions are defined by the system and are read-only. Assign them to users from the Members tab.",
+ "permissionsCount_one": "{{count}} permission",
+ "permissionsCount_other": "{{count}} permissions",
+ "modulesCount_one": "{{count}} module",
+ "modulesCount_other": "{{count}} modules",
+ "matrixTitle": "Permission matrix",
+ "matrixSubtitle": "What each role can do, by module.",
+ "permission": "Permission",
+ "systemNote": "System roles ship with the platform and cannot be edited. Roles you create belong to this tenant.",
+ "newRole": "New role",
+ "edit": "Edit",
+ "delete": "Delete",
+ "systemBadge": "System",
+ "createTitle": "New role",
+ "editTitle": "Edit role",
+ "editorSubtitle": "Pick what this role may do. A user can hold more than one role.",
+ "nameLabel": "Identifier",
+ "nameHint": "Used in code and in the API. ROLE_AUDITOR, for example.",
+ "displayNameLabel": "Display name",
+ "descriptionLabel": "Description",
+ "permissionsLabel": "Permissions",
+ "selectedCount": "{{count}} selected",
+ "toggleAll": "all",
+ "loadingPermissions": "Loading permissions…",
+ "save": "Save role",
+ "deleteConfirmTitle": "Delete this role?",
+ "deleteConfirmBody": "{{name}} will be removed. Users who hold only this role will be left without module access."
+ },
+ "langDefault": "System default",
+ "relative": {
+ "justNow": "just now",
+ "minutesAgo": "{{count}}m ago",
+ "hoursAgo": "{{count}}h ago",
+ "daysAgo": "{{count}}d ago"
+ },
+ "roleNames": {
+ "ROLE_ADMIN": "Administrator",
+ "ROLE_USER": "User"
+ },
+ "roleDescriptions": {
+ "ROLE_ADMIN": "Full access to all resources",
+ "ROLE_USER": "Standard user with module-level read access"
+ },
+ "actions": {
+ "read": "Read",
+ "write": "Write",
+ "delete": "Delete"
+ },
+ "resources": {
+ "adaudit": "AD Audit",
+ "alerts": "Alerts",
+ "audit": "Audit log",
+ "compliance": "Compliance",
+ "config": "Configuration",
+ "dashboards": "Dashboards",
+ "datasources": "Datasources",
+ "eventprocessing": "Event processing",
+ "idp": "Identity providers",
+ "incidents": "Incidents",
+ "integrations": "Integrations",
+ "loganalyzer": "Log analyzer",
+ "opensearch": "OpenSearch",
+ "roles": "Roles",
+ "soar": "SOAR",
+ "users": "Users",
+ "notifications": "Notifications",
+ "socai": "SOC AI",
+ "tenant": "Tenants",
+ "threatintel": "Threat intelligence"
+ }
+ },
+ "apiKeys": {
+ "title": "API keys",
+ "subtitle": "Programmatic access tokens for the UTMStack API.",
+ "new": "New API key",
+ "searchPlaceholder": "Search by name or allowed IP…",
+ "refresh": "Refresh",
+ "loading": "Loading API keys…",
+ "loadFailed": "Could not load API keys.",
+ "retry": "Retry",
+ "noSearchMatch": "No API keys match your search.",
+ "empty": "No API keys yet. Create one to get started.",
+ "anyIp": "Any IP",
+ "never": "Never",
+ "count_one": "{{count}} key · page {{page}} of {{pages}}",
+ "count_other": "{{count}} keys · page {{page}} of {{pages}}",
+ "enterprise": {
+ "title": "API keys are an Enterprise feature",
+ "body": "Issue, scope and rotate API keys for programmatic access to the UTMStack API. This capability is available on the Enterprise edition.",
+ "upgrade": "Upgrade to Enterprise",
+ "manageLicense": "Manage your license"
+ },
+ "col": {
+ "name": "Name",
+ "allowedIps": "Allowed IPs",
+ "created": "Created",
+ "lastRotated": "Last rotated",
+ "expires": "Expires",
+ "status": "Status",
+ "actions": "Actions"
+ },
+ "status": {
+ "active": "Active",
+ "expiring": "Expiring",
+ "expired": "Expired"
+ },
+ "action": {
+ "rotate": "Rotate",
+ "edit": "Edit",
+ "delete": "Delete"
+ },
+ "dialog": {
+ "editTitle": "Edit API key",
+ "newTitle": "New API key",
+ "name": "Name",
+ "namePlaceholder": "ci-pipeline",
+ "allowedIps": "Allowed IPs",
+ "allowedIpsHint": "Comma-separated. Leave empty to allow any IP.",
+ "expires": "Expires",
+ "expiresHint": "Leave empty for a key that never expires.",
+ "secretNote": "The secret token is shown once, right after creation. Copy it then — it can’t be retrieved later (only rotated).",
+ "cancel": "Cancel",
+ "saving": "Saving…",
+ "saveChanges": "Save changes",
+ "createKey": "Create key"
+ },
+ "confirm": {
+ "deleteTitle": "Delete API key",
+ "rotateTitle": "Rotate API key",
+ "deleteBody": "Delete {{name}}? Any client using it will immediately lose access. This cannot be undone.",
+ "rotateBody": "Rotate {{name}}? A new secret is issued and the current one stops working immediately. The new token is shown once.",
+ "cancel": "Cancel",
+ "working": "Working…",
+ "delete": "Delete",
+ "rotate": "Rotate"
+ },
+ "reveal": {
+ "title": "API key created",
+ "note": "Copy this secret now — for {{name}}. It won’t be shown again. If you lose it, rotate the key.",
+ "copied": "Copied",
+ "copy": "Copy",
+ "done": "Done"
+ },
+ "toast": {
+ "updated": "API key updated",
+ "secretIssueFailed": "Key created, but the secret could not be issued. Use Rotate to get one.",
+ "deleted": "API key deleted"
+ },
+ "error": {
+ "nameTaken": "An API key with that name already exists",
+ "enterpriseRequired": "API keys require the Enterprise edition",
+ "notFound": "API key not found",
+ "invalidRequest": "Invalid request",
+ "failed": "Operation failed"
+ }
+ },
+ "idp": {
+ "title": "Identity Providers",
+ "subtitle": "SAML 2.0 single sign-on for your organization.",
+ "add": "Add provider",
+ "enterprise": {
+ "title": "SSO is an Enterprise feature",
+ "body": "Connect a SAML 2.0 identity provider (Entra ID, Okta, Google Workspace…) so your team signs in with your IdP. Single sign-on is available on the Enterprise edition.",
+ "upgrade": "Upgrade to Enterprise"
+ },
+ "loading": "Loading identity providers…",
+ "loadFailed": "Could not load identity providers.",
+ "retry": "Retry",
+ "empty": {
+ "title": "No identity providers configured",
+ "body": "Add a SAML 2.0 provider to let your team sign in with your corporate IdP."
+ },
+ "card": {
+ "enable": "Enable",
+ "disable": "Disable",
+ "active": "Active",
+ "disabled": "Disabled",
+ "metadataUrl": "Metadata URL",
+ "spEntityId": "SP Entity ID",
+ "spAcsUrl": "SP ACS URL",
+ "loginUrl": "Login URL",
+ "copy": "Copy",
+ "edit": "Edit",
+ "delete": "Delete",
+ "jit": "Provisioning",
+ "jitOn": "creates accounts on first sign-in",
+ "sync": "Roles",
+ "syncOn": "re-applied on every sign-in"
+ },
+ "form": {
+ "addTitle": "Add identity provider",
+ "editTitle": "Edit identity provider",
+ "name": "Name",
+ "nameHint": "Unique. Used in the SSO URL.",
+ "providerType": "Provider type",
+ "providerTypeHint": "A label, e.g. azure, okta, google.",
+ "metadataUrl": "IdP metadata URL",
+ "spEntityId": "SP Entity ID",
+ "spAcsUrl": "SP ACS URL",
+ "certificate": "SP certificate (PEM)",
+ "privateKey": "SP private key (PEM)",
+ "privateKeyHintEdit": "Leave empty to keep the stored key.",
+ "privateKeyHintCreate": "Required. Stored encrypted; never shown again.",
+ "privateKeyUnchanged": "•••••••• (unchanged)",
+ "active": "Active (show on the login page)",
+ "cancel": "Cancel",
+ "saving": "Saving…",
+ "save": "Save changes",
+ "create": "Create provider",
+ "issuer": "Issuer URL",
+ "issuerHint": "Discovery runs against this; the provider must serve /.well-known/openid-configuration under it.",
+ "clientId": "Client ID",
+ "redirectUrl": "Redirect URL",
+ "redirectUrlHint": "Register this exact URL with the provider.",
+ "host": "Host",
+ "port": "Port",
+ "startTls": "TLS",
+ "startTlsOn": "Use StartTLS",
+ "bindDn": "Bind DN",
+ "bindDnHint": "A service account that may search the directory.",
+ "baseDn": "Base DN",
+ "userFilter": "User filter",
+ "userFilterHint": "Must contain %s, where the address typed at login is placed.",
+ "emailAttribute": "Email attribute",
+ "nameAttribute": "Name attribute",
+ "groupAttribute": "Group attribute",
+ "provisioning": "Accounts and roles",
+ "provisioningHint": "What happens when someone the directory vouches for signs in.",
+ "jit": "Create the account on first sign-in",
+ "defaultRole": "Default role",
+ "defaultRoleHint": "Given when no group matches. Without one, an unmatched sign-in is refused.",
+ "noDefaultRole": "None",
+ "groupsAttribute": "Groups attribute",
+ "groupsAttributeHint": "Where the provider puts group membership.",
+ "syncRoles": "Re-apply roles on every sign-in",
+ "syncRolesHint": "Roles not in the mapping are removed, so a change in the directory reaches here. Without this, a demotion never arrives.",
+ "mappings": "Group to role",
+ "mappingsHint": "A directory group on the left, the role it grants on the right.",
+ "addMapping": "Add",
+ "noMappings": "No mappings. Everyone gets the default role.",
+ "groupPlaceholder": "SOC Analysts",
+ "pickRole": "Pick a role",
+ "secret.saml": "SP private key",
+ "secret.oidc": "Client secret",
+ "secret.ldap": "Bind password",
+ "secretHintCreate": "Stored encrypted and never shown again.",
+ "secretHintEdit": "Leave blank to keep the stored one.",
+ "secretUnchanged": "unchanged",
+ "errors": {
+ "required": "This field is required.",
+ "url": "Must be a valid http(s) URL.",
+ "httpsUrl": "Must be a valid https URL.",
+ "hostname": "Enter a host or IP without a scheme (e.g. ldap.example.com).",
+ "port": "Port must be a whole number between 0 and 65535.",
+ "pemCertificate": "Does not look like a PEM certificate (missing -----BEGIN/END CERTIFICATE-----).",
+ "pemKey": "Does not look like a PEM private key (missing -----BEGIN/END PRIVATE KEY-----).",
+ "userFilterPlaceholder": "The filter must contain %s, where the login address is placed.",
+ "userFilterUnbalanced": "Parentheses are unbalanced — the search will return nothing.",
+ "nameFormat": "Use letters, digits, dots, dashes or underscores (max 64). It appears in the SSO URL, so no spaces.",
+ "redirectUrl": "Must be a valid https URL, or an http loopback URL (localhost / 127.0.0.1 / [::1]).",
+ "entityId": "Must be a valid URI, e.g. https://utmstack.example.com/sp."
+ }
+ },
+ "delete": {
+ "title": "Delete identity provider",
+ "body": "Delete {{name}}? Users will no longer be able to sign in through it. This cannot be undone.",
+ "cancel": "Cancel",
+ "deleting": "Deleting…",
+ "confirm": "Delete"
+ },
+ "toast": {
+ "enabled": "Provider enabled",
+ "disabled": "Provider disabled",
+ "created": "Identity provider created",
+ "updated": "Identity provider updated",
+ "deleted": "Identity provider deleted",
+ "paidPlan": "SAML SSO requires a paid plan",
+ "enterpriseRequired": "SSO requires the Enterprise edition",
+ "notFound": "Identity provider not found",
+ "invalid": "Invalid configuration",
+ "failed": "Operation failed"
+ },
+ "providerType": {
+ "saml": "SAML 2.0",
+ "oidc": "OpenID Connect",
+ "ldap": "LDAP / Active Directory",
+ "comingSoon": "not available yet"
+ }
+ },
+ "userAuditor": {
+ "title": "User auditor",
+ "subtitle": "Active Directory accounts observed in your Windows security logs — discovered from create, logon and delete events.",
+ "export": "Export",
+ "accountsChip": "{{count}} accounts",
+ "overview": {
+ "title": "Account inventory",
+ "active": "active",
+ "disabled": "disabled",
+ "deleted": "deleted",
+ "seen24h": "{{count}} seen in the last 24 hours",
+ "byDomain": "By domain"
+ },
+ "views": {
+ "all": "All accounts",
+ "windows": "Windows",
+ "linux": "Linux",
+ "active": "Active",
+ "disabled": "Disabled",
+ "deleted": "Deleted",
+ "service": "Service accounts",
+ "stale": "Stale (30d+)"
+ },
+ "searchPlaceholder": "Search by account name or SID…",
+ "allTenants": "All tenants",
+ "filters": {
+ "add": "Add filter",
+ "clearAll": "Clear all",
+ "filterValues": "Filter values…",
+ "loadingValues": "Loading values…",
+ "noValues": "No values found.",
+ "pickValue": "Pick a value to add the filter.",
+ "empty": "(empty)",
+ "cancel": "Cancel",
+ "addBtn": "Add"
+ },
+ "filterFields": {
+ "status": "Lifecycle status"
+ },
+ "ops": {
+ "is": "is"
+ },
+ "refresh": "Refresh",
+ "layout": {
+ "list": "List",
+ "cards": "Cards"
+ },
+ "list": {
+ "account": "Account",
+ "identity": "Identity",
+ "sid": "SID",
+ "status": "Status",
+ "lastLogon": "Last logon",
+ "lastSeen": "Last seen",
+ "tenant": "Tenant"
+ },
+ "status": {
+ "active": "Active",
+ "disabled": "Disabled",
+ "deleted": "Deleted"
+ },
+ "badge": {
+ "service": "service",
+ "stale": "stale"
+ },
+ "empty": "No accounts match this view.",
+ "loadError": "Could not load AD accounts.",
+ "retry": "Retry",
+ "card": {
+ "lastLogon": "Last logon"
+ },
+ "pageInfo": "{{from}}–{{to}} of {{count}}",
+ "drawer": {
+ "tenantInline": "tenant {{id}}",
+ "serviceAccount": "service account",
+ "stale": "stale 30d+",
+ "viewInLogs": "View events in Log Explorer",
+ "copySid": "Copy SID",
+ "copyUid": "Copy identity",
+ "copied": "Copied",
+ "identity": "Identity",
+ "accountName": "Account name",
+ "domain": "Domain",
+ "hostname": "Hostname",
+ "sid": "SID",
+ "uidNumber": "UID",
+ "machineId": "Machine ID",
+ "tenant": "Tenant",
+ "adStatus": "AD status",
+ "enabled": "Enabled",
+ "disabled": "Disabled",
+ "lifecycle": "Lifecycle",
+ "created": "Account created",
+ "lastLogon": "Last logon",
+ "lastSeen": "Last seen in logs",
+ "deleted": "Account deleted",
+ "noLifecycle": "No lifecycle events recorded."
+ },
+ "relative": {
+ "justNow": "just now",
+ "minutesAgo": "{{count}}m ago",
+ "hoursAgo": "{{count}}h ago",
+ "daysAgo": "{{count}}d ago"
+ },
+ "none": "—"
+ },
+ "connectionKey": {
+ "title": "Connection key",
+ "subtitle1": "The key agents present when they register with this instance.",
+ "subtitleEmphasis": "It is only used for agent installation",
+ "subtitle2": "— not for collectors, integrations, or the API. It is managed by the agent-manager.",
+ "status": {
+ "label": "Status",
+ "loading": "Loading…",
+ "unavailable": "Agent-manager unavailable",
+ "active": "Active",
+ "unavailableHint": "Could not reach the agent-manager to read the key.",
+ "activeHint": "Agents can register using this key."
+ },
+ "token": {
+ "title": "Connection key",
+ "subtitle": "Treat this value as a credential. Rotating it issues a new key for future agent installations — agents already registered keep working.",
+ "loadFailedTitle": "Couldn’t load the connection key",
+ "unavailableTitle": "Connection key unavailable",
+ "loadFailedHint": "The key is managed by the agent-manager, which didn’t respond. Try again in a moment.",
+ "retry": "Retry",
+ "show": "Show key",
+ "hide": "Hide key",
+ "copy": "Copy",
+ "copied": "Copied",
+ "regenerate": "Regenerate connection key",
+ "confirmTitle": "Regenerate the key?",
+ "confirmBody": "New agent installations will need the new key. Agents already registered keep working. There's no undo.",
+ "regenerating": "Regenerating…",
+ "confirmYes": "Yes, regenerate",
+ "cancel": "Cancel"
+ },
+ "security": {
+ "title": "Security recommendations",
+ "subtitle": "Best practices for protecting this credential.",
+ "rotateTitle": "Rotate every 90 days",
+ "rotateBody": "Schedule a recurring rotation. UTMStack can email you a reminder when the key is older than 90 days.",
+ "rotateAction": "Set up reminder",
+ "secretTitle": "Store as a secret",
+ "secretBody": "Don't commit the key to source control. Use your secret manager (Vault, AWS SM, etc.) and inject it at install time.",
+ "auditTitle": "Audit who fetched it",
+ "auditBody": "Every fetch and rotation is recorded in the application audit log.",
+ "auditAction": "View audit log"
+ },
+ "toast": {
+ "loadFailed": "Could not load connection key",
+ "rotated": "Connection key rotated",
+ "rotateFailed": "Could not rotate connection key",
+ "copyFailed": "Could not copy"
+ }
+ },
+ "dataRetention": {
+ "title": "Data retention",
+ "subtitle": "How long each dataset is kept, and when its records stop costing local disk.",
+ "loading": "Loading…",
+ "loadFailed": "Could not read the store.",
+ "retry": "Retry",
+ "datasets": {
+ "logs": "Logs",
+ "alerts": "Alerts",
+ "statistics": "Ingestion statistics"
+ },
+ "holding": "{{documents}} records · {{size}}",
+ "since": "since {{date}}",
+ "diskUsed": "Disk {{pct}}% used",
+ "keep": "Delete after",
+ "keepHint": "A record is deleted this many days after it happened, wherever it is stored by then.",
+ "cold": "Move to cold storage after",
+ "coldHint": "Older records move to object storage and stay queryable. 0 keeps everything on local disk.",
+ "coldUnavailable": "Set up cold storage below to move older records off local disk.",
+ "coldBeforeDelete": "Records have to move before they are deleted: use fewer days than the lifetime, or 0.",
+ "tieredNote": "This dataset moves records to cold storage. Going back to local-only needs the table rebuilt, so it cannot be turned off here.",
+ "days": "days",
+ "save": "Save",
+ "saving": "Saving…",
+ "toast": {
+ "saved": "Retention saved",
+ "noPermission": "You do not have permission to change retention",
+ "saveFailed": "Could not save the retention"
+ },
+ "coldStorage": {
+ "title": "Cold storage",
+ "hint": "An object store the event store treats as a second, slower disk. Older records move there and are still queried from the same place — it is not an archive and nothing has to be restored.",
+ "active": "In use",
+ "inactive": "Not set up",
+ "writtenNotReady": "The bucket is configured but the store has not picked it up. Check that the deployment shares the store's configuration directory.",
+ "endpoint": "Bucket URL",
+ "accessKey": "Access key",
+ "secretKey": "Secret key",
+ "bucketLocked": "The credentials can be changed at any time. The bucket cannot, once records live in it: the parts already moved carry it.",
+ "enable": "Enable cold storage",
+ "update": "Update credentials",
+ "toast": {
+ "saved": "Cold storage configured",
+ "failed": "Could not configure cold storage"
+ },
+ "kind": "Type",
+ "kind_s3": "S3-compatible object store",
+ "kind_local": "Local folder or NFS",
+ "kind_azure": "Azure Blob Storage",
+ "accountUrl": "Storage account URL",
+ "container": "Container",
+ "accountName": "Account name",
+ "accountKey": "Account key",
+ "useRole": "Use the server's IAM role instead of keys",
+ "s3Hint": "Works with AWS S3 and any S3-compatible store: MinIO, Ceph, Wasabi, Cloudflare R2, or Google Cloud Storage (endpoint https://storage.googleapis.com// with HMAC keys).",
+ "localHint": "Records move to the folder mounted at /mnt/utmstack-cold inside the event store: a plain directory in the data folder, or an NFS share mounted over /clickhouse/cold on the host before the stack starts. No credentials needed.",
+ "changeWarning": "Records already moved to the current destination are not migrated. They stay there and stop being readable from here until the old destination is copied across by hand."
+ },
+ "forbidden": {
+ "title": "This page belongs to the platform",
+ "body": "Retention applies to the tables every tenant shares, so only a platform administrator can read or change it. Ask one, or sign in with a platform account."
+ }
+ },
+ "languageSettings": {
+ "title": "Platform language",
+ "subtitle": "Default UI language for pre-login screens, system emails and new users. Each user can still pick their own in their profile.",
+ "label": "Default language",
+ "hint": "Used when a user hasn't chosen their own language.",
+ "save": "Save",
+ "saving": "Saving…",
+ "saved": "Platform language updated",
+ "loadError": "Could not load the language setting",
+ "saveError": "Could not save the language setting"
+ },
+ "branding": {
+ "title": "Branding",
+ "subtitle": "White-label UTMStack with your organization’s identity — applied everywhere: the login screen, sidebar, emails and reports.",
+ "enterpriseRequired": "White-labeling is an Enterprise feature.",
+ "manageLicense": "Manage license",
+ "enable": {
+ "title": "White-label",
+ "description": "Replace the UTMStack brand with your own across the platform.",
+ "label": "Enable white-labeling"
+ },
+ "identity": {
+ "title": "Identity",
+ "productName": "Product name",
+ "productNameHint": "Shown in the title bar, sidebar and emails.",
+ "accent": "Accent color",
+ "accentHint": "Primary color for buttons, links and active states.",
+ "custom": "Custom color"
+ },
+ "logos": {
+ "title": "Logos",
+ "hint": "PNG, SVG, WEBP, JPG or ICO. Up to 5 MB.",
+ "logo": "Logo (light)",
+ "logoDark": "Logo (dark)",
+ "favicon": "Favicon"
+ },
+ "reports": {
+ "title": "Report assets",
+ "hint": "Embedded in generated PDF reports.",
+ "reportLogo": "Report logo",
+ "reportCover": "Report cover"
+ },
+ "asset": {
+ "upload": "Upload",
+ "replace": "Replace"
+ },
+ "save": "Save changes",
+ "saving": "Saving…",
+ "saved": "Branding updated",
+ "saveError": "Could not save branding",
+ "uploaded": "Image uploaded",
+ "uploadError": "Could not upload image",
+ "loadError": "Could not load branding",
+ "enterprise": {
+ "title": "White-labelling is an Enterprise feature",
+ "body": "Replace the product name, logo and report cover with your own, so the panel and everything it generates carry your brand instead of UTMStack's.",
+ "upgrade": "Upgrade to Enterprise"
+ },
+ "restore": "Restore UTMStack defaults",
+ "restored": "Branding restored to the UTMStack defaults"
+ },
+ "emailConfig": {
+ "title": "Email configuration",
+ "subtitle": "SMTP server used to send alert notifications, reports and account emails.",
+ "server": {
+ "title": "SMTP server",
+ "host": "Host",
+ "hostHint": "Hostname of your SMTP server.",
+ "port": "Port",
+ "encryption": "Encryption",
+ "username": "Username",
+ "password": "Password",
+ "passwordSetHint": "A password is saved. Leave blank to keep it, or type a new one to change it."
+ },
+ "encryptionOpt": {
+ "TLS": "TLS",
+ "SSL": "SSL",
+ "NONE": "None"
+ },
+ "sender": {
+ "title": "Sender",
+ "from": "From address",
+ "fromHint": "Address emails are sent from.",
+ "organization": "Organization name",
+ "organizationHint": "Shown in alert and incident notification emails.",
+ "baseUrl": "Base URL",
+ "baseUrlHint": "Public URL of this instance, used for links in emails."
+ },
+ "test": {
+ "button": "Send test",
+ "sending": "Sending…",
+ "sentTo": "A test email will be sent to {{email}}.",
+ "success": "Test email sent to {{email}}",
+ "fail": "Could not send the test email",
+ "fromRequired": "Set a From address before testing"
+ },
+ "save": "Save changes",
+ "saving": "Saving…",
+ "saved": "Email configuration saved",
+ "saveError": "Could not save the configuration",
+ "loadError": "Could not load the configuration",
+ "recipients": {
+ "alertsTitle": "Alert recipients",
+ "incidentsTitle": "Incident recipients",
+ "to": "To",
+ "cc": "CC",
+ "alertsHelper": "Addresses notified when new alerts are raised. Leave empty and alerts are not emailed.",
+ "incidentsHelper": "Addresses notified when an incident is created. Leave empty and incidents are not emailed.",
+ "add": "Add"
+ }
+ },
+ "dateFormat": {
+ "title": "Date & time",
+ "subtitle": "How timestamps are displayed across the platform. Logs are always stored in UTC.",
+ "timezone": {
+ "title": "Time zone",
+ "hint": "Timestamps are shown in this time zone. Stored data stays in UTC.",
+ "system": "Browser default",
+ "now": "Now: {{value}}"
+ },
+ "format": {
+ "title": "Date format",
+ "hint": "Style used for dates and times."
+ },
+ "styles": {
+ "short": "Short",
+ "medium": "Medium",
+ "long": "Long",
+ "full": "Full"
+ },
+ "save": "Save changes",
+ "saving": "Saving…",
+ "saved": "Date settings saved",
+ "saveError": "Could not save the settings",
+ "loadError": "Could not load the settings"
+ },
+ "about": {
+ "title": "About this instance",
+ "subtitle": "Version, license, and system health for this UTMStack deployment.",
+ "loading": "Loading instance information…",
+ "edition": {
+ "enterprise": "Enterprise",
+ "community": "Community"
+ },
+ "fields": {
+ "hostname": "Server",
+ "instanceId": "Instance ID",
+ "noInstanceMeta": "No instance metadata available."
+ },
+ "license": {
+ "title": "License",
+ "enterpriseMssp": "Enterprise · MSSP",
+ "datasources": "Datasources",
+ "communityLimited": "Community limit",
+ "unlimited": "Unlimited",
+ "expires": "Expires",
+ "managedNote": "Edition, datasource limits and license upload are managed on the License page.",
+ "view": "View license",
+ "ingest": "Ingest volume",
+ "notMetered": "Not metered",
+ "gbPerMonth": "{{gb}} GB/month"
+ },
+ "services": {
+ "backend": {
+ "name": "Backend API",
+ "desc": "REST gateway, auth and module orchestration."
+ },
+ "opensearch": {
+ "name": "OpenSearch",
+ "desc": "Log and event storage backend.",
+ "detail": "{{nodes}} nodes · {{shards}} shards"
+ },
+ "unreachable": "Unreachable"
+ },
+ "status": {
+ "up": "Healthy",
+ "degraded": "Degraded",
+ "down": "Down",
+ "unknown": "Unknown"
+ },
+ "health": {
+ "title": "System health",
+ "allHealthy": "All services healthy. Refresh to recheck.",
+ "issues_one": "{{count}} service needs attention.",
+ "issues_other": "{{count}} services need attention.",
+ "refresh": "Refresh"
+ },
+ "usage": {
+ "title": "Data sources",
+ "subtitle": "Data sources configured in this deployment.",
+ "ofUnlimited": "of unlimited",
+ "ofLimit": "of {{limit}}",
+ "overLimit": "Over the licensed limit — data beyond the cap is at risk.",
+ "configured": "configured"
+ },
+ "support": {
+ "title": "Support",
+ "docs": "Documentation",
+ "repo": "GitHub repository",
+ "issues": "Report an issue",
+ "website": "utmstack.com"
+ },
+ "legal": {
+ "title": "Legal",
+ "license": "License",
+ "security": "Security disclosure",
+ "copyright": "© {{year}} UTMStack. All rights reserved."
+ }
+ },
+ "logExplorer": {
+ "title": "Log explorer",
+ "eventsIn": "events in",
+ "searching": "Searching…",
+ "query": {
+ "allDataTypes": "All data types",
+ "dataTypes": "Data types",
+ "exportCsv": "Export CSV",
+ "filterDataTypes": "Filter data types…",
+ "noDataTypes": "No data types",
+ "noDataTypesMatch": "No matching data types",
+ "noTextSearch": "This data source has no full-text field — filter by field instead",
+ "refresh": "Refresh",
+ "run": "Run",
+ "search": "Search",
+ "searchPlaceholder": "Search across all fields…"
+ },
+ "time": {
+ "15m": "Last 15 minutes",
+ "1h": "Last 1 hour",
+ "6h": "Last 6 hours",
+ "24h": "Last 24 hours",
+ "7d": "Last 7 days",
+ "30d": "Last 30 days"
+ },
+ "ops": {
+ "is": "is",
+ "isNot": "is not",
+ "contains": "contains",
+ "exists": "exists",
+ "between": "between",
+ "search": "search",
+ "isOneOf": "is one of",
+ "isNotOneOf": "is not one of",
+ "doesNotContain": "does not contain",
+ "startsWith": "starts with",
+ "doesNotStartWith": "does not start with",
+ "endsWith": "ends with",
+ "doesNotEndWith": "does not end with",
+ "doesNotExist": "does not exist",
+ "notBetween": "not between",
+ "greaterThan": "is greater than",
+ "greaterThanOrEquals": "is greater than or equal to",
+ "lessThan": "is less than",
+ "lessThanOrEquals": "is less than or equal to"
+ },
+ "filters": {
+ "label": "Filters",
+ "clearAll": "Clear all"
+ },
+ "fields": {
+ "title": "Fields",
+ "filterPlaceholder": "Filter fields…",
+ "none": "No fields",
+ "selected": "Selected fields",
+ "available": "Available fields",
+ "topValues_one": "Top {{count}} value",
+ "topValues_other": "Top {{count}} values",
+ "loading": "Loading…",
+ "noValues": "No values",
+ "addColumn": "Add as column",
+ "removeColumn": "Remove column from table",
+ "filterFor": "Filter for value",
+ "filterOut": "Filter out value",
+ "empty": "(empty)"
+ },
+ "results": {
+ "dataTypesFailed": "Could not load data types.",
+ "endOfResults": "All {{count}} events loaded",
+ "loadingMore": "Loading more…",
+ "message": "Message",
+ "none": "No logs match this query.",
+ "removeColumn": "Remove {{field}}",
+ "retry": "Retry",
+ "searchFailed": "Search failed.",
+ "searching": "Searching…",
+ "source": "Source",
+ "time": "Time",
+ "scope": "Searched {{dataset}} · {{dataType}}.",
+ "searchAllDataTypes": "Search every data type"
+ },
+ "detail": {
+ "fieldsCount_one": "{{count}} field",
+ "fieldsCount_other": "{{count}} fields",
+ "copyJson": "Copy JSON",
+ "copied": "Document copied",
+ "parsedFields": "Parsed fields",
+ "json": "JSON",
+ "filterFor": "Filter for",
+ "filterOut": "Filter out",
+ "surrounding": "Surrounding events",
+ "surroundingHint": "Show events ±15 min around this one, from the same source"
+ },
+ "view": {
+ "table": "Table",
+ "chart": "Chart"
+ },
+ "chart": {
+ "aggregateOn": "Aggregate on",
+ "per": "per",
+ "topValues": "— top 20 values",
+ "building": "Building chart…",
+ "failed": "Could not build the chart for this field.",
+ "noData": "No data to chart."
+ },
+ "intervals": {
+ "minute": "Minute",
+ "hour": "Hour",
+ "day": "Day",
+ "week": "Week",
+ "month": "Month",
+ "quarter": "Quarter",
+ "year": "Year"
+ },
+ "toast": {
+ "exportFailed": "Export failed"
+ },
+ "builder": {
+ "add": "Add filter",
+ "filterValues": "Filter values…",
+ "loadingValues": "Loading values…",
+ "noValues": "No values found.",
+ "pickValue": "Pick a value to add the filter.",
+ "cancel": "Cancel",
+ "confirm": "Add"
+ },
+ "related": {
+ "nLogs_one": "{{count}} log",
+ "nLogs_other": "{{count}} logs",
+ "truncated": "Showing the first {{count}} related logs (the full set is larger)."
+ },
+ "saved": {
+ "title": "Saved",
+ "empty": "No saved searches yet",
+ "saveCurrent": "Save current search",
+ "save": "Save",
+ "namePlaceholder": "Search name",
+ "delete": "Delete",
+ "saved": "Saved “{{name}}”",
+ "loading": "Loading…",
+ "loadFailed": "Could not load saved searches",
+ "saveFailed": "Could not save the search",
+ "deleteFailed": "Could not delete the search",
+ "unreadable": "That saved search could not be read"
+ }
+ },
+ "integrations": {
+ "title": "Integrations",
+ "searchPlaceholder": "Search integrations…",
+ "noMatch": "No integrations match.",
+ "browseMarketplace": "Browse marketplace",
+ "loading": "Loading integrations…",
+ "addCustom": {
+ "title": "Add custom integration",
+ "description": "Create a new custom source",
+ "cta": "Create"
+ },
+ "tabs": {
+ "all": "All",
+ "agents": "Agents",
+ "collectors": "Collectors",
+ "cloud": "Cloud",
+ "custom": "Custom"
+ },
+ "kind": {
+ "agents & syslog": "Agent",
+ "device": "Collector",
+ "antivirus": "Collector",
+ "other": "Collector",
+ "custom": "Custom",
+ "cloud": "Cloud",
+ "utmstack modules": "Collector"
+ },
+ "status": {
+ "configured": "Configured",
+ "available": "Available"
+ },
+ "card": {
+ "manage": "Manage →",
+ "setup": "Set up →",
+ "eventsPerSec": "{{rate}} e/s",
+ "enabled": "Enabled",
+ "setupShort": "Set up"
+ },
+ "drawer": {
+ "manage": "Manage",
+ "openDashboard": "Open dashboard",
+ "viewEvents": "View events",
+ "documentation": "Documentation",
+ "getInstallCmd": "Get install command",
+ "setupCollector": "Set up collector",
+ "connect": "Connect",
+ "configureCustom": "Configure custom source",
+ "eventsRate": "{{rate}} events/sec · {{count}} in 24h",
+ "manageRules": "Rules",
+ "manageFilters": "Filters"
+ },
+ "setup": {
+ "agent": {
+ "howItWorksTitle": "How it works",
+ "howItWorksBody": "The {{name}} agent is a small daemon that runs on the host and forwards local events to UTMStack over an authenticated TLS connection. It auto-updates and reports its health.",
+ "installTitle": "Install on {{name}}",
+ "installHint": "Run this command on every {{name}} host you want to monitor. The token already encodes your current workspace.",
+ "afterTitle": "What you'll see after install",
+ "after1": "The host appears under Data Sources within ~60 seconds of agent start.",
+ "after2": "Telemetry begins flowing into Log Explorer, scoped to your workspace.",
+ "after3": "The agent self-reports CPU / memory / disk health back to UTMStack.",
+ "actionLabel": "Action",
+ "platformLabel": "Platform",
+ "optionsLabel": "Options",
+ "skipCertValidation": "Skip TLS certificate validation (self-signed server)",
+ "noRemoteControl": "Disable remote command execution on this host",
+ "loadingToken": "Loading token…",
+ "actions": {
+ "install": "Install",
+ "uninstall": "Uninstall"
+ },
+ "prereqTitle": "Pre-installation requirements",
+ "prereqBody": "The UTMStack agent communicates with the server over the following ports. Make sure they are open between the host and UTMStack before installing:",
+ "sensitiveWarning": "The command below contains a sensitive enrollment token — do not share it.",
+ "uninstall": {
+ "title": "Uninstall the agent",
+ "body": "Run this on the host to stop and remove the UTMStack agent and its services. It uses the platform selected above."
+ },
+ "macCompat": "Requires macOS 11 (Big Sur) or later on Apple Silicon (M1/M2/M3 or newer). Intel-based Macs are not supported."
+ },
+ "collector": {
+ "guideUnavailableTitle": "Setup guide unavailable",
+ "guideUnavailableBody": "A setup guide for {{name}} has not been configured yet. Contact your administrator before enabling this integration.",
+ "genericSourceTitle": "Configure {{name}}",
+ "genericSourceBody": "Configure the source to send events to the selected UTMStack Collector using these connection details.",
+ "howItWorksTitle": "How it works",
+ "howItWorksBody": "{{name}} doesn't run a UTMStack agent. Instead, you install the UTMStack collector somewhere on the network that both your {{name}} device and UTMStack can reach. {{name}} sends syslog to the collector, the collector parses, normalizes, and forwards events into UTMStack.",
+ "step1Title": "1 · Install the UTMStack collector",
+ "step1Hint": "Run on a Linux host with network access from the {{name}} device.",
+ "step2Title": "2 · Configure {{name}} to send syslog",
+ "step2Hint": "On the {{name}} device, point syslog forwarding to the collector's address on {{port}}.",
+ "vendorDocs": "See vendor-specific instructions",
+ "step3Title": "3 · Verify",
+ "step3Body": "Within a few minutes you should see {{name}} events under source: {{source}} in Log Explorer, and a new entry in Data Sources.",
+ "endpoint": {
+ "title": "Connection details",
+ "hint": "Configure {{name}} to forward its logs to the Collector using the host and port below."
+ },
+ "syslog": {
+ "sections": {
+ "sendLogs": {
+ "title": "Send logs to UTMStack",
+ "body": "Configure your device to send syslog messages over UDP (514) or TCP (514) to the UTMStack agent."
+ },
+ "enableCollector": {
+ "title": "Enable the syslog collector",
+ "body": "Enable the log collector and the syslog integration in the configuration file where your UTMStack agent is installed."
+ },
+ "activate": {
+ "title": "Activate",
+ "body": "Activate the UTMStack module so events start flowing into Log Explorer."
+ }
+ }
+ },
+ "netflow": {
+ "source": "Network device",
+ "step1": {
+ "title": "Enable the NetFlow listener on the Collector",
+ "body": "On the host where the Collector is installed, run this command to open the NetFlow collector on port 2055:",
+ "note": "NetFlow uses UDP only — TCP and TLS are not supported for this protocol."
+ },
+ "step2": {
+ "title": "Configure your device to export NetFlow",
+ "body": "Point NetFlow export on your router or firewall at the Collector host on port {{port}} UDP. The example below is for Cisco IOS — consult your vendor's documentation for other platforms:",
+ "note": "Replace with the interface name where traffic should be monitored (e.g. GigabitEthernet0/0). Apply ingress/egress on each relevant interface."
+ }
+ },
+ "cisco": {
+ "source": "Cisco ASA",
+ "step1": {
+ "title": "Enable the Cisco ASA listener on the Collector",
+ "body": "On the host where the Collector is installed, run this command to open the Cisco ASA log listener:",
+ "note": "To use TCP instead of UDP, replace udp with tcp in the command above."
+ },
+ "step2": {
+ "title": "Configure Cisco ASA to forward logs",
+ "body": "On your Cisco ASA, enable syslog and point it at the Collector host on port {{port}}. Run these commands in privileged EXEC mode (replace with your inside or management interface name):"
+ }
+ },
+ "ciscoSwitch": {
+ "source": "Cisco Switch",
+ "step1": {
+ "title": "Enable the Cisco Switch listener on the Collector",
+ "body": "On the host where the Collector is installed, run this command to open the Cisco Switch log listener:",
+ "note": "To use TCP instead of UDP, replace udp with tcp in the command above."
+ },
+ "step2": {
+ "title": "Configure the switch to forward logs",
+ "body": "In privileged EXEC mode on your Cisco switch, enable syslog and point it at the Collector host on port {{port}}:"
+ }
+ },
+ "ciscoMeraki": {
+ "source": "Cisco Meraki",
+ "step1": {
+ "title": "Enable the Cisco Meraki listener on the Collector",
+ "body": "On the host where the Collector is installed, run this command to open the Cisco Meraki log listener:",
+ "note": "To use TCP instead of UDP, replace udp with tcp in the command above."
+ },
+ "step2": {
+ "title": "Configure Meraki to forward logs",
+ "body": "In the Meraki Dashboard, go to Network-wide → Configure → General, scroll to the Reporting section and add a syslog server with the Collector IP and port {{port}}. Select all roles you want to forward."
+ }
+ },
+ "ciscoFirepower": {
+ "source": "Cisco Firepower",
+ "step1": {
+ "title": "Enable the Cisco Firepower listener on the Collector",
+ "body": "On the host where the Collector is installed, run this command to open the Cisco Firepower log listener:",
+ "note": "To use TCP instead of UDP, replace udp with tcp in the command above."
+ },
+ "step2": {
+ "title": "Configure Firepower to forward logs",
+ "body": "In Firepower Management Center (FMC), go to Devices → Platform Settings, edit or create a policy and navigate to Syslog → Syslog Servers. Add the Collector IP with port {{port}} (UDP), then assign the policy to your devices and deploy."
+ }
+ },
+ "vmware": {
+ "source": "VMware ESXi",
+ "step1": {
+ "title": "Enable the VMware listener on the Collector",
+ "body": "On the host where the Collector is installed, run this command to open the VMware ESXi syslog listener. ESXi streams over TCP:",
+ "note": "For an encrypted channel use tls instead of tcp (load certificates on the Collector first)."
+ },
+ "step2": {
+ "title": "Point ESXi syslog at the Collector",
+ "body": "Open an SSH/ESXi Shell session on the host (or use the vSphere Client: Host → Configure → Advanced System Settings → Syslog.global.logHost). Set the remote loghost to {{host}}:{{port}} and reload the configuration:",
+ "note": "On vSphere you can instead set Syslog.global.logHost to the same tcp://host:port value rather than running esxcli."
+ },
+ "step3": {
+ "title": "Open the ESXi firewall for syslog",
+ "body": "Allow outbound syslog through the ESXi firewall so the host can reach the Collector:"
+ }
+ },
+ "as400": {
+ "intro": {
+ "title": "How it works",
+ "body": "The AS/400 Collector is a Linux service that connects directly to your AS/400 (IBM i) systems and pulls security journal entries, then streams them securely to UTMStack for correlation and alerting.",
+ "note": "Nothing is installed on the AS/400 itself — the Collector runs on a Linux host that has network access to your AS/400 systems.",
+ "diagram": {
+ "source": "your journals",
+ "edge1": "journals",
+ "collector": "AS/400 Collector",
+ "collectorSub": "pulls from AS/400",
+ "edge2": "secure",
+ "utmstackSub": "alerts & correlation"
+ }
+ },
+ "install": {
+ "title": "Install the AS/400 Collector",
+ "body": "Run this command on a Linux host that can reach both UTMStack and your AS/400 systems over the network.",
+ "reuse": "Already have the AS/400 Collector installed? Skip this step — just add your servers to the configuration file in the next step."
+ },
+ "configure": {
+ "title": "Add your AS/400 servers",
+ "body": "Edit as400-config.yaml in the collector's installation directory and add each AS/400 system you want to monitor:",
+ "note": "You can list multiple servers. The collector watches this file and reloads automatically on save — no restart needed."
+ },
+ "journal": {
+ "title": "Enable audit journaling on AS/400",
+ "body": "On each AS/400 system, make sure the QAUDJRN security audit journal is active. Refer to IBM's documentation for the exact steps — the procedure varies between IBM i versions."
+ },
+ "uninstall": {
+ "title": "Optional — Uninstall the Collector",
+ "body": "Run this command on the host where the AS/400 Collector is installed to stop the service and remove all files."
+ }
+ },
+ "bitdefender": {
+ "intro": {
+ "title": "How it works",
+ "body": "UTMStack connects to Bitdefender GravityZone using your API key to configure the Event Push Service. GravityZone then sends security events directly to UTMStack for correlation and alerting.",
+ "diagram": {
+ "source": "endpoint events",
+ "edge": "Event Push Service",
+ "utmstackSub": "alerts & correlation"
+ },
+ "note": "No agent is installed on GravityZone — UTMStack registers itself as the push destination using read-only API credentials."
+ },
+ "whitelist": {
+ "title": "Whitelist Bitdefender IPs",
+ "body": "The following Bitdefender GravityZone IP addresses must be allowed through your firewall on port 8000 so that the Event Push Service can reach UTMStack:",
+ "note": "Add these IPs to your firewall or security group before completing the setup."
+ },
+ "apiSection": "Get API credentials",
+ "api": {
+ "myAccount": {
+ "title": "Open My Account",
+ "body": "In the Bitdefender GravityZone console, click on My Account."
+ },
+ "accessUrl": {
+ "title": "Note the Access URL",
+ "body": "Scroll down to the Control Center API section and save the Access URL — you will enter it in the credentials form below. Then open the API key section and click Add at the top of the table."
+ },
+ "createKey": {
+ "title": "Create an API key",
+ "body": "Write a description for the API key, select the Event Push Service API option, and click Save. Copy the generated key."
+ }
+ },
+ "companySection": "Get Company IDs",
+ "company": {
+ "myCompany": {
+ "title": "Open My Company",
+ "body": "In the GravityZone console, click on My Company."
+ },
+ "licensing": {
+ "title": "Note the Company IDs",
+ "body": "Open the Licensing section and save the Company IDs you want to monitor — enter them comma-separated in the credentials form below."
+ }
+ },
+ "credentials": {
+ "title": "Enter credentials",
+ "body": "Fill in the Access URL, API key, your UTMStack public IP (where GravityZone will push events), and the Company IDs to monitor. UTMStack verifies the credentials before saving."
+ },
+ "fields": {
+ "accessUrl": {
+ "label": "GravityZone Access URL"
+ },
+ "connectionKey": {
+ "label": "API key"
+ },
+ "utmPublicIP": {
+ "label": "UTMStack public IP"
+ },
+ "companyIds": {
+ "label": "Company IDs (comma-separated)"
+ }
+ }
+ },
+ "eset": {
+ "source": "ESET Protect",
+ "step1": {
+ "title": "Enable the ESET listener on the Collector",
+ "body": "On the host where the Collector is installed, run this command to open the ESET syslog listener:",
+ "note": "To use TCP instead of UDP, replace udp with tcp in the command above."
+ },
+ "console": {
+ "moreMenu": {
+ "title": "Open the More menu",
+ "body": "In the ESET Protect console sidebar, click the More menu."
+ },
+ "serverConfig": {
+ "title": "Open Server settings",
+ "body": "Under More, open the Server settings (Server configuration) section."
+ },
+ "advanced": {
+ "title": "Expand Advanced settings",
+ "body": "Click Advanced settings to expand the full list of configuration options."
+ },
+ "syslog": {
+ "title": "Configure the Syslog server",
+ "body": "Scroll to Syslog server, enable Export logs to Syslog, and set the destination to the Collector host on port {{port}} (UDP). ESET sends LEEF/syslog, which the Collector ingests as the antivirus-esmc-eset data type."
+ }
+ }
+ },
+ "kaspersky": {
+ "source": "Kaspersky Security",
+ "step1": {
+ "title": "Enable the Kaspersky listener on the Collector",
+ "body": "On the host where the Collector is installed, run this command to open the Kaspersky syslog listener:",
+ "note": "To use TCP instead of UDP, replace udp with tcp in the command above."
+ },
+ "console": {
+ "consoleSettings": {
+ "title": "Open Console settings → Integration",
+ "body": "In the Kaspersky Security Center sidebar, open Console settings and click the Integration submenu."
+ },
+ "siem": {
+ "title": "Open the SIEM integration settings",
+ "body": "Under Integration, select SIEM and click the Settings link to open the export configuration."
+ },
+ "configure": {
+ "title": "Configure the SIEM export",
+ "body": "Enable export and set Kaspersky to send events in Splunk (CEF) format to the Collector host on port {{port}} (UDP). The Collector ingests them as the antivirus-kaspersky data type."
+ }
+ }
+ },
+ "sophos": {
+ "intro": {
+ "title": "Sophos Central — API Plugin",
+ "body": "Sophos Central provides secure APIs to retrieve event and alert data. UTMStack connects to those APIs to centralize monitoring and enhance your security visibility — no agent or collector required.",
+ "diagram": {
+ "source": "Sophos Central API",
+ "edge": "HTTPS API",
+ "utmstackSub": "Ingests & correlates"
+ },
+ "note": "UTMStack polls the Sophos Central API on a schedule. Ensure the API credentials you create below have read access to events and alerts."
+ },
+ "apiSection": "Generate API Credentials in Sophos Central",
+ "steps": {
+ "apiCredentials": {
+ "title": "Open API Credentials Management",
+ "body": "In Sophos Central Admin, navigate to Global Settings → API Credentials Management."
+ },
+ "addCredential": {
+ "title": "Create a new credential",
+ "body": "Click Add Credential. Provide a Name and Description, select the appropriate Role, then click Add."
+ },
+ "copyIds": {
+ "title": "Copy Client ID and Client Secret",
+ "body": "Copy the Client ID and Client Secret and store them securely.",
+ "secretNote": "The Client Secret is shown only once. Save it somewhere safe before closing this dialog."
+ }
+ },
+ "credentialsSection": "Connect to UTMStack",
+ "credentials": {
+ "title": "Add Sophos Central credentials",
+ "body": "Enter the credentials you just created. You can add more than one Sophos account by clicking Add config group."
+ },
+ "fields": {
+ "clientId": {
+ "label": "Client ID"
+ },
+ "apiKey": {
+ "label": "Client Secret / API Key"
+ }
+ }
+ },
+ "webroot": {
+ "sections": {
+ "login": {
+ "title": "1 · Log in to the management console",
+ "body": "Log in to the Webroot management console. It opens on the Sites tab."
+ },
+ "openSettings": {
+ "title": "2 · Open Settings",
+ "body": "Click on the Settings tab."
+ },
+ "apiAccess": {
+ "title": "3 · Open API Access",
+ "body": "From the Subscriptions tab, click on the API Access tab."
+ },
+ "createCredential": {
+ "title": "4 · Create a client credential",
+ "body": "Click New and fill in the Name and Description. Read the SecureAnywhere Business Solution and Unity API agreement, then click Create."
+ },
+ "noteClientSecret": {
+ "title": "5 · Copy the client ID and secret",
+ "body": "Save the Client ID from the list and the Client Secret that's shown only once. Click \"I have made note of the client secret\" to confirm."
+ },
+ "fillForm": {
+ "title": "6 · Fill the form",
+ "body": "Provide the client ID and client secret to UTMStack. You can add more than one Webroot config group if needed."
+ },
+ "activate": {
+ "title": "7 · Activate",
+ "body": "Activate the UTMStack module so Webroot events start flowing."
+ }
+ }
+ },
+ "sentinelOne": {
+ "source": "SentinelOne",
+ "step1": {
+ "title": "Enable the SentinelOne listener on the Collector",
+ "body": "On the host where the Collector is installed, run this command to open the SentinelOne syslog listener. SentinelOne streams CEF over TCP:",
+ "note": "For an encrypted channel use tls instead of tcp (load certificates on the Collector first)."
+ },
+ "console": {
+ "settings": {
+ "title": "Open the SentinelOne Settings",
+ "body": "In the SentinelOne management console sidebar, click the Settings menu."
+ },
+ "syslog": {
+ "title": "Configure the Syslog integration",
+ "body": "Go to Integrations → Syslog and enable it. Set the host to {{host}} and port to {{port}}, keep the format as CEF, click Test to verify the connection, then Save."
+ }
+ }
+ },
+ "office365": {
+ "intro": {
+ "title": "How it works",
+ "body": "UTMStack connects to Microsoft 365 using a registered Azure AD app and polls the Office 365 Management Activity API for audit and security events. No agent is installed in your tenant.",
+ "diagram": {
+ "source": "audit & security events",
+ "edge": "Management API",
+ "utmstackSub": "correlation & alerts"
+ },
+ "note": "UTMStack requires read-only API access — no write permissions are requested."
+ },
+ "appSection": "Azure App Registration",
+ "steps": {
+ "azurePortal": {
+ "title": "Open Microsoft Entra ID",
+ "body": "Open the Azure Portal (portal.azure.com) and click on Microsoft Entra ID."
+ },
+ "appRegistrations": {
+ "title": "Go to App registrations",
+ "body": "In the left menu, click App registrations."
+ },
+ "registerApp": {
+ "title": "Register a new app",
+ "body": "Click New registration. Name it UTMStack O365 Agent, select Accounts in this organizational directory only (Single-tenant), and click Register."
+ },
+ "clientSecret": {
+ "title": "Create a client secret",
+ "body": "Go to Certificates & Secrets → New client secret. Add a description, set expiry to 730 days (24 months), and click Add.",
+ "copyNote": "Copy the secret Value immediately — it is only shown once and cannot be retrieved later."
+ },
+ "apiPermissions": {
+ "title": "Add Office 365 Management API permissions",
+ "body": "Go to API Permissions → Add a permission and search for Office 365 Management APIs."
+ },
+ "activityFeed": {
+ "title": "Grant ActivityFeed permissions",
+ "body": "Select Application Permissions and add ActivityFeed.Read and ActivityFeed.ReadDlp. Click Grant admin consent and confirm."
+ },
+ "graphPermissions": {
+ "title": "Add Microsoft Graph permissions",
+ "body": "Back in Add a permission, click Microsoft Graph."
+ },
+ "delegatedPermissions": {
+ "title": "Add delegated SecurityAlert permissions",
+ "body": "Select Delegated Permissions and add SecurityAlert.Read.All and SecurityAlert.ReadWrite.All. Click Grant admin consent and confirm."
+ },
+ "appPermissions": {
+ "title": "Add application SecurityAlert permissions",
+ "body": "Select Application Permissions and add SecurityAlert.Read.All and SecurityAlert.ReadWrite.All. Click Grant admin consent and confirm."
+ },
+ "noteIds": {
+ "title": "Copy the app IDs",
+ "body": "Go to the app Overview and copy the Application (client) ID and Directory (tenant) ID. You also need the secret value copied in step 4."
+ }
+ },
+ "credentialsSection": "Credentials",
+ "credentials": {
+ "title": "Connect your Microsoft 365 tenant",
+ "body": "Enter the details from the steps above. UTMStack verifies the credentials before saving. You can add multiple config groups."
+ },
+ "fields": {
+ "tenantId": {
+ "label": "Tenant ID (Directory ID)"
+ },
+ "clientId": {
+ "label": "Client ID (Application ID)"
+ },
+ "clientSecret": {
+ "label": "Client Secret"
+ },
+ "cloudEnv": {
+ "label": "Cloud Environment (optional)",
+ "hint": "Commercial (default), GCC, GCCHigh, or DoD"
+ }
+ }
+ },
+ "github": {
+ "source": "GitHub",
+ "step1": {
+ "title": "Enable the GitHub webhook listener on the Collector",
+ "body": "On the host where the Collector is installed, run this command to open the HTTPS webhook listener for GitHub:",
+ "tokenNote": "The terminal will print a secret token — copy it immediately. It will not be shown again."
+ },
+ "certWarning": {
+ "title": "GitHub requires a CA-signed TLS certificate",
+ "body": "GitHub only delivers webhooks to HTTPS endpoints with a certificate issued by a public CA (self-signed certificates are rejected). Make sure the Collector host has a valid domain certificate before registering the webhook."
+ },
+ "step2": {
+ "title": "Register the webhook in GitHub",
+ "body": "In your repository or organization, go to Settings → Webhooks → Add webhook and fill in the form:",
+ "payloadUrl": "Payload URL",
+ "contentType": "Content type",
+ "secret": "Secret",
+ "secretHint": "Paste the token shown when the integration was enabled above.",
+ "events": "Which events",
+ "eventsHint": "Send me everything — or select specific event types."
+ }
+ },
+ "salesforce": {
+ "sections": {
+ "openSetup": {
+ "title": "1 · Open Setup",
+ "body": "Go to Setup and select \"Setup for the current app\" at the top right of the screen."
+ },
+ "appManager": {
+ "title": "2 · Open App Manager",
+ "body": "Type \"App Manager\" in the quick search box and select App Manager."
+ },
+ "newConnectedApp": {
+ "title": "3 · Create a new Connected App",
+ "body": "On the Lightning Experience App Manager screen, click \"New Connected App\" and fill in the fields."
+ },
+ "oauthSettings": {
+ "title": "4 · Enable OAuth Settings",
+ "body": "In the \"API (Enable OAuth Settings)\" section, check \"Enable OAuth Settings\" and use https://login.salesforce.com/services/oauth2/success as the Callback URL."
+ },
+ "oauthScopes": {
+ "title": "5 · Add OAuth scopes",
+ "body": "Select \"Access Connect REST API resources (chatter_api)\" under Selected OAuth Scopes."
+ },
+ "save": {
+ "title": "6 · Save",
+ "body": "Save your changes and select Continue on the next screen."
+ },
+ "manageConsumer": {
+ "title": "7 · Open Manage Consumer Details",
+ "body": "Inside your Connected App, go to \"API (Enable OAuth Settings)\" and click \"Manage Consumer Details\" next to Consumer Key and Secret."
+ },
+ "copyCredentials": {
+ "title": "8 · Copy the consumer key and secret",
+ "body": "Verify your identity. The Consumer Key and Consumer Secret appear under \"Consumer Details\". Copy both with the Copy button."
+ },
+ "fillForm": {
+ "title": "9 · Fill the form",
+ "body": "Provide the Consumer Key, Consumer Secret, Salesforce username and password to UTMStack."
+ },
+ "activate": {
+ "title": "10 · Activate",
+ "body": "Activate the UTMStack module so Salesforce events start flowing."
+ }
+ }
+ },
+ "iis": {
+ "sections": {
+ "enableModule": {
+ "title": "1 · Enable the IIS Filebeat module",
+ "body": "On the UTMStack agent host, run:\ncd \"C:\\Program Files\\UTMStack\\UTMStack Agent\\beats\\filebeat\\\" && filebeat modules enable iis"
+ },
+ "configureModule": {
+ "title": "2 · Configure the IIS module",
+ "body": "Edit C:\\Program Files\\UTMStack\\UTMStack Agent\\beats\\filebeat\\modules.d\\iis.yml as shown below to point at the IIS log directories you want to ship."
+ },
+ "activate": {
+ "title": "3 · Activate",
+ "body": "Activate the UTMStack module so IIS events start flowing."
+ }
+ }
+ },
+ "filebeat": {
+ "sections": {
+ "installRsyslog": {
+ "title": "1 · Install rsyslog",
+ "body": "Ensure rsyslog is installed on the host. Use your distribution's package manager (apt, dnf, yum)."
+ },
+ "configureRsyslog": {
+ "title": "2 · Configure rsyslog to forward to UTMStack",
+ "body": "Edit /etc/rsyslog.conf (or a file under /etc/rsyslog.d/) and add a forwarding rule that targets the UTMStack agent over UDP or TCP on port 514."
+ },
+ "restartRsyslog": {
+ "title": "3 · Restart rsyslog",
+ "body": "Restart the rsyslog service: sudo systemctl restart rsyslog"
+ },
+ "enableCollector": {
+ "title": "4 · Enable the Linux logs collector",
+ "body": "Enable the log collector and the Linux Logs integration in the configuration file where your UTMStack agent is installed."
+ }
+ }
+ },
+ "json": {
+ "sections": {
+ "overview": {
+ "title": "Use the HTTP/JSON ingestion endpoint",
+ "body": "UTMStack accepts arbitrary JSON events over HTTPS. Send a POST request with a list of events; UTMStack parses them and routes through your configured parser."
+ },
+ "auth": {
+ "title": "Authenticate with a federation token",
+ "body": "Get a federation token from Settings → Connection Key and send it as a Bearer token in the Authorization header."
+ }
+ },
+ "endpoint": {
+ "title": "JSON ingestion endpoint",
+ "hint": "Use this request shape from your application or a cron job. The token is the federation key from Settings → Connection Key."
+ }
+ },
+ "ldap": {
+ "sections": {
+ "openServerManager": {
+ "title": "1 · Open Server Manager",
+ "body": "On the AD domain controller, open Server Manager."
+ },
+ "addRoles": {
+ "title": "2 · Add Roles and Features",
+ "body": "Choose \"Add roles and features\" from the Manage menu."
+ },
+ "selectCertServices": {
+ "title": "3 · Select Active Directory Certificate Services",
+ "body": "On the Server Roles step, select Active Directory Certificate Services."
+ },
+ "installServices": {
+ "title": "4 · Install the Certificate Authority role service",
+ "body": "On the Role Services step, select Certificate Authority and finish the wizard."
+ },
+ "configureAdCs": {
+ "title": "5 · Configure AD CS",
+ "body": "After install, click the notification to configure AD CS and choose Certificate Authority as the role service to configure."
+ },
+ "pickCaType": {
+ "title": "6 · Pick the CA type",
+ "body": "Choose Enterprise CA → Root CA → Create a new private key."
+ },
+ "setValidity": {
+ "title": "7 · Set the certificate validity period",
+ "body": "Set a validity period that fits your organization (5 years is typical)."
+ },
+ "confirm": {
+ "title": "8 · Confirm and install",
+ "body": "Review the settings and click Configure to finish."
+ },
+ "restart": {
+ "title": "9 · Restart the domain controller",
+ "body": "Restart the domain controller so LDAPS becomes available on TCP 636."
+ },
+ "activate": {
+ "title": "10 · Activate",
+ "body": "Activate the UTMStack module so AD audit events start flowing."
+ }
+ }
+ },
+ "oracle": {
+ "source": "Oracle DB server",
+ "step1": {
+ "title": "Enable the Oracle integration on the Collector",
+ "body": "On the server where the Collector is installed, run the following command to start listening for Oracle logs:",
+ "note": "The Collector will begin receiving syslog events from Oracle on port 7021."
+ },
+ "step2": {
+ "title": "Configure rsyslog on the Oracle server",
+ "body": "Create the rsyslog configuration file:",
+ "editBody": "Open the file with your preferred editor and add the following configuration. Replace BASEDIR with your Oracle installation path (e.g., /u01/app/oracle) and with the Collector's IP address or hostname:",
+ "note": "Use @@:7021 instead of @ if you prefer TCP delivery."
+ },
+ "step3": {
+ "title": "Restart rsyslog",
+ "body": "Apply the new configuration by restarting the rsyslog service:"
+ },
+ "step4": {
+ "title": "Validate the configuration",
+ "body": "Send test log messages to verify that UTMStack is receiving events from all three Oracle log sources:",
+ "note": "Open Log Explorer and search for the test message text above to confirm they arrived."
+ }
+ },
+ "vulnerabilities": {
+ "sections": {
+ "overview": {
+ "title": "1 · About the vulnerabilities scanner",
+ "body": "The UTMStack vulnerabilities module scans assets discovered through the Asset Management module and matches their fingerprint against the CVE database."
+ },
+ "scope": {
+ "title": "2 · Define scan scope",
+ "body": "Use the Asset Management module to register the hosts you want scanned. The vulnerabilities scanner will run periodically against them."
+ },
+ "activate": {
+ "title": "3 · Activate",
+ "body": "Activate the UTMStack module to start scanning."
+ }
+ }
+ },
+ "assetScanner": {
+ "sections": {
+ "overview": {
+ "title": "1 · About Asset Management",
+ "body": "The Asset Management module discovers and inventories hosts, software, and services across your network."
+ },
+ "agentRequirement": {
+ "title": "2 · Agent requirement",
+ "body": "Asset discovery uses UTMStack agents running on Linux, Windows, or macOS hosts. Install the agent on the systems you want inventoried."
+ },
+ "activate": {
+ "title": "3 · Activate",
+ "body": "Activate the UTMStack module to start asset discovery."
+ }
+ }
+ },
+ "fileIntegrity": {
+ "sections": {
+ "enableAuditPolicy": {
+ "title": "1 · Enable Audit Object Access",
+ "body": "On the Windows host, open Group Policy → Computer Configuration → Windows Settings → Security Settings → Advanced Audit Policy Configuration → Object Access and enable \"Audit File System\"."
+ },
+ "configureFolderAuditing": {
+ "title": "2 · Configure folder auditing",
+ "body": "On each folder you want monitored, open Properties → Security → Advanced → Auditing and add an auditing entry for the principals and access types you care about."
+ },
+ "verifyEvents": {
+ "title": "3 · Verify events appear in Security log",
+ "body": "Open Event Viewer and confirm 4663/4670 events are being generated when the audited objects are accessed."
+ },
+ "activate": {
+ "title": "4 · Activate",
+ "body": "Activate the UTMStack module so file integrity events start flowing."
+ }
+ }
+ },
+ "socAi": {
+ "sections": {
+ "overview": {
+ "title": "1 · About SOC AI",
+ "body": "SOC AI augments UTMStack with an LLM-backed analyst that summarizes alerts and suggests next steps. It runs against the provider you configure."
+ },
+ "chooseProvider": {
+ "title": "2 · Choose a provider",
+ "body": "Pick a provider — OpenAI, Anthropic, Azure OpenAI, Google Gemini, Ollama, Mistral, DeepSeek, Groq, or a custom OpenAI-compatible endpoint."
+ },
+ "configureCredentials": {
+ "title": "3 · Configure credentials",
+ "body": "Provide the API key and (where applicable) the model name and endpoint URL."
+ },
+ "activate": {
+ "title": "4 · Activate",
+ "body": "Activate the UTMStack module so SOC AI starts working on alerts."
+ }
+ }
+ },
+ "utmstack": {
+ "intro": {
+ "title": "How it works",
+ "body": "This integration self-monitors your UTMStack deployment. A lightweight collector installed on the UTMStack host tails the platform's own Docker container logs and ships them back into UTMStack for correlation and alerting.",
+ "diagram": {
+ "source": "Docker logs",
+ "sourceSub": "UTMStack containers",
+ "edge1": "tail",
+ "collector": "Collector",
+ "collectorSub": "on the host",
+ "edge2": "ingest",
+ "utmstackSub": "Correlates & alerts"
+ }
+ },
+ "requirements": {
+ "title": "Runs on the UTMStack host only",
+ "body": "This integration can only be installed on a UTMStack instance running Ubuntu or a Red Hat-family distribution. Install the collector directly on the UTMStack server."
+ },
+ "install": {
+ "title": "Install the collector",
+ "body": "On the UTMStack host, pick your operating system and run the command below to download and install the self-monitoring collector:",
+ "sensitiveWarning": "This command contains a sensitive connection token. Treat it like a password and don't share it."
+ },
+ "after": {
+ "title": "What you'll see after installing",
+ "item1": "The collector registers itself and appears under Data sources.",
+ "item2": "UTMStack container logs start flowing within a minute.",
+ "item3": "Events become searchable in Log Explorer under the utmstack data type."
+ },
+ "uninstall": {
+ "title": "Uninstall the collector",
+ "body": "To remove the self-monitoring collector from the UTMStack host, run:"
+ }
+ },
+ "windowsFaa": {
+ "sections": {
+ "enableAuditPolicy": {
+ "title": "1 · Enable Audit Object Access",
+ "body": "On the Windows host, open Group Policy → Computer Configuration → Windows Settings → Security Settings → Advanced Audit Policy Configuration → Object Access and enable \"Audit File System\"."
+ },
+ "configureFolderAuditing": {
+ "title": "2 · Configure folder auditing",
+ "body": "On each folder you want monitored, open Properties → Security → Advanced → Auditing and add an auditing entry for the principals and access types you care about."
+ },
+ "activate": {
+ "title": "3 · Activate",
+ "body": "Activate the UTMStack module so file activity events start flowing."
+ }
+ }
+ },
+ "awsBeanstalk": {
+ "sections": {
+ "openConsole": {
+ "title": "1 · Open the Elastic Beanstalk console",
+ "body": "In the AWS Console, open Elastic Beanstalk."
+ },
+ "environment": {
+ "title": "2 · Open the environment management page",
+ "body": "Navigate to the management page for the environment you want to monitor."
+ },
+ "configuration": {
+ "title": "3 · Open Configuration",
+ "body": "Choose Configuration."
+ },
+ "software": {
+ "title": "4 · Modify the Software configuration",
+ "body": "In the Software configuration category, choose Modify."
+ },
+ "s3LogStorage": {
+ "title": "5 · Enable S3 log storage",
+ "body": "Under S3 log storage, choose Rotate logs to upload rotated logs to Amazon S3."
+ },
+ "cloudwatchStreaming": {
+ "title": "6 · Enable CloudWatch Logs streaming",
+ "body": "Under Instance log streaming to CloudWatch Logs, enable streaming, set the retention period, and pick whether to upload existing logs."
+ },
+ "activate": {
+ "title": "7 · Activate",
+ "body": "Activate the UTMStack module so Beanstalk events start flowing."
+ }
+ }
+ },
+ "awsFargate": {
+ "sections": {
+ "taskDefinition": {
+ "title": "1 · Update your task definition",
+ "body": "In the task definition for the Fargate task, set the logDriver to \"awslogs\" and define the log group name."
+ },
+ "cloudwatchLogs": {
+ "title": "2 · Confirm CloudWatch Logs is receiving logs",
+ "body": "Open the CloudWatch Logs console and confirm the log group is being populated when tasks run."
+ },
+ "iamPrerequisite": {
+ "title": "3 · IAM user prerequisite",
+ "body": "This integration shares credentials with the AWS IAM User module — make sure it's configured with CloudWatchLogsReadOnlyAccess."
+ },
+ "activate": {
+ "title": "4 · Activate",
+ "body": "Activate the UTMStack module so Fargate events start flowing."
+ }
+ }
+ },
+ "awsIamUser": {
+ "sections": {
+ "iamConsole": {
+ "title": "1 · Open the IAM console",
+ "body": "In the AWS console, go to IAM → Users → Add users."
+ },
+ "createUser": {
+ "title": "2 · Create the user",
+ "body": "Pick a username (e.g. utmstack-ingest). Choose programmatic access."
+ },
+ "programmaticAccess": {
+ "title": "3 · Set credential type",
+ "body": "Select \"Access key — Programmatic access\"."
+ },
+ "attachPolicy": {
+ "title": "4 · Attach the CloudWatch read policy",
+ "body": "Attach the AWS-managed policy CloudWatchLogsReadOnlyAccess."
+ },
+ "review": {
+ "title": "5 · Review the user",
+ "body": "Review the user details and click Create user."
+ },
+ "copyKeys": {
+ "title": "6 · Copy the access key ID and secret",
+ "body": "Copy the Access key ID and the Secret access key — the secret is shown only once."
+ },
+ "createLogGroup": {
+ "title": "7 · Create a CloudWatch log group",
+ "body": "In CloudWatch → Log groups, create a log group named \"utmstack\" — other AWS integrations will deliver to it."
+ },
+ "fillForm": {
+ "title": "8 · Fill the form",
+ "body": "Provide the access key, secret, default region, and the log group name (e.g. \"utmstack\") to UTMStack."
+ },
+ "activate": {
+ "title": "9 · Activate",
+ "body": "Activate the UTMStack module so AWS events start flowing."
+ }
+ }
+ },
+ "awsLambda": {
+ "sections": {
+ "iamPrerequisite": {
+ "title": "1 · IAM user prerequisite",
+ "body": "Lambda relies on the AWS IAM User module — make sure that integration is configured first with CloudWatchLogsReadOnlyAccess."
+ },
+ "cloudwatchStream": {
+ "title": "2 · Lambda already streams to CloudWatch Logs",
+ "body": "AWS Lambda automatically publishes execution logs to CloudWatch Logs under /aws/lambda/. UTMStack ingests from the log group you configured in the IAM user setup."
+ },
+ "activate": {
+ "title": "3 · Activate",
+ "body": "Activate the UTMStack module so Lambda events start flowing."
+ }
+ }
+ },
+ "awsSqlServer": {
+ "sections": {
+ "openRds": {
+ "title": "1 · Open the Amazon RDS console",
+ "body": "Open https://console.aws.amazon.com/rds/."
+ },
+ "pickDb": {
+ "title": "2 · Pick the DB instance",
+ "body": "In the navigation pane, choose Databases and select the DB instance you want to monitor."
+ },
+ "modify": {
+ "title": "3 · Modify the instance",
+ "body": "Choose Modify."
+ },
+ "logExports": {
+ "title": "4 · Enable Log Exports",
+ "body": "In the Log exports section, choose Error log and Agent log to publish to CloudWatch Logs."
+ },
+ "apply": {
+ "title": "5 · Apply changes",
+ "body": "Choose Continue, then Modify DB Instance on the summary page."
+ },
+ "activate": {
+ "title": "6 · Activate",
+ "body": "Activate the UTMStack module so SQL Server events start flowing."
+ }
+ }
+ },
+ "awsPostgresql": {
+ "sections": {
+ "openRds": {
+ "title": "1 · Open the Amazon RDS console",
+ "body": "Open https://console.aws.amazon.com/rds/."
+ },
+ "pickDb": {
+ "title": "2 · Pick the DB instance",
+ "body": "In the navigation pane, choose Databases and select the DB instance you want to modify."
+ },
+ "logExports": {
+ "title": "3 · Enable Log Exports",
+ "body": "In the Log exports section, choose the PostgreSQL log to publish to CloudWatch Logs."
+ },
+ "apply": {
+ "title": "4 · Apply changes",
+ "body": "Choose Continue, then Modify DB Instance on the summary page."
+ },
+ "activate": {
+ "title": "5 · Activate",
+ "body": "Activate the UTMStack module so PostgreSQL events start flowing."
+ }
+ }
+ },
+ "awsTrafficMirror": {
+ "sections": {
+ "createTarget": {
+ "title": "1 · Create a traffic mirror target",
+ "body": "In the VPC console, create a Traffic Mirror Target that points at the network interface of the UTMStack agent VM."
+ },
+ "createFilter": {
+ "title": "2 · Create a traffic mirror filter",
+ "body": "Create a Traffic Mirror Filter and add inbound/outbound rules for the protocols you want to mirror (e.g. all TCP, all UDP)."
+ },
+ "createSession": {
+ "title": "3 · Create a traffic mirror session",
+ "body": "Create a Traffic Mirror Session that pairs each source network interface with the target and filter you created."
+ },
+ "iamPrerequisite": {
+ "title": "4 · IAM user prerequisite",
+ "body": "Make sure the AWS IAM User module is also configured so UTMStack can read VPC flow logs if needed."
+ },
+ "activate": {
+ "title": "5 · Activate",
+ "body": "Activate the UTMStack module so mirrored traffic starts being parsed."
+ }
+ }
+ },
+ "forwarder": {
+ "intro": {
+ "title": "How it works",
+ "body": "Logs flow from {{source}} to the UTMStack Collector, which streams them securely into UTMStack for correlation and alerting. Nothing is installed on {{source}} — only the Collector needs to run on a host in your network."
+ },
+ "diagram": {
+ "sourceSub": "your logs",
+ "forwarder": "Collector",
+ "forwarderSub": "listens on {{port}}",
+ "utmstack": "UTMStack",
+ "utmstackSub": "alerts & correlation",
+ "flow1": "logs",
+ "flow2": "secure"
+ },
+ "noInstall": "Nothing is installed on {{source}} — you only redirect its logs to the Collector.",
+ "install": {
+ "title": "Install the UTMStack Collector",
+ "body": "The Collector is a Linux service that receives logs from your devices and sends them to UTMStack. A single Collector handles multiple integrations at the same time.",
+ "reuse": "Already have a Collector running? Skip this step — point {{source}} at the existing one using the host and port shown below."
+ },
+ "tls": {
+ "title": "Optional — Enable TLS encryption",
+ "intro": "By default the listener accepts plain TCP/UDP. To encrypt syslog traffic in transit, load your certificate files first, then re-enable the listener with the tls protocol.",
+ "step1": "1 · Load your certificate and key (once per Collector)",
+ "step1Note": "An optional CA certificate can be added as a third argument. Omit it to use the leaf certificate as CA.",
+ "step2": "2 · Re-enable the listener using TLS"
+ },
+ "httpsCerts": {
+ "title": "Load the TLS certificate on the Collector",
+ "body": "This integration uses an HTTPS listener on port {{port}}, so the Collector needs a certificate and key loaded before enabling it:"
+ },
+ "uninstall": {
+ "title": "Optional — Uninstall the Collector",
+ "body": "Run this command on the host where the Collector is installed to stop the service and remove all its files."
+ },
+ "manualCommand": {
+ "title": "Optional — Enable via the command line instead",
+ "intro": "Prefer the terminal? SSH into the Collector host and run the command below — it matches whatever protocol and port you have selected above.",
+ "certStep": "1 · Load your certificate and key (once per Collector)",
+ "enableStep": "2 · Enable the integration"
+ },
+ "instanceHeader": {
+ "title": "Authorization header",
+ "body": "Include this Authorization header on every request you send to the instance. The API key's secret is revealed only once when it is generated — copy it then and paste it in place of the placeholder below.",
+ "tabSimple": "Simple",
+ "tabBatch": "Batch"
+ }
+ },
+ "aix": {
+ "source": "AIX server",
+ "step1": {
+ "title": "Enable the AIX listener on the Collector",
+ "body": "On the host where the Collector is installed, run this command to open the AIX log listener:",
+ "note": "To use TCP instead of UDP, replace udp with tcp in the command above."
+ },
+ "step2": {
+ "title": "Configure AIX to forward logs",
+ "body": "On your AIX system, configure the syslog service to redirect its logs to the Collector host on port {{port}}. Refer to IBM’s documentation for the exact syntax — it varies between AIX versions."
+ }
+ },
+ "deceptivebytes": {
+ "source": "Deceptive Bytes",
+ "step1": {
+ "title": "Enable the Deceptive Bytes listener on the Collector",
+ "body": "On the host where the Collector is installed, run this command to open the Deceptive Bytes syslog listener:",
+ "note": "To use TCP instead of UDP, replace udp with tcp in the command above."
+ },
+ "step2": {
+ "title": "Configure Deceptive Bytes to forward logs",
+ "body": "In the Deceptive Bytes management console, configure syslog forwarding to send events to the Collector host on port {{port}} (UDP). Deceptive Bytes emits CEF-formatted syslog, which the Collector ingests as the deceptive-bytes data type."
+ }
+ },
+ "mikrotik": {
+ "source": "MikroTik router",
+ "step1": {
+ "title": "Enable the MikroTik listener on the Collector",
+ "body": "On the host where the Collector is installed, run this command to open the MikroTik syslog listener:",
+ "note": "To use TCP instead of UDP, replace udp with tcp in the command above."
+ },
+ "step2": {
+ "title": "Configure MikroTik to forward logs",
+ "body": "On the MikroTik router, create a remote logging action pointing at the Collector host on port {{port}} and attach it to the relevant log topics. Run the following from the RouterOS CLI (Terminal in Winbox):",
+ "note": "You can also configure this via Winbox: System → Logging → Actions tab (add a Remote action) → then the Rules tab (add rules pointing to the new action)."
+ }
+ },
+ "fortigate": {
+ "source": "FortiGate firewall",
+ "step1": {
+ "title": "Enable the FortiGate listener on the Collector",
+ "body": "On the host where the Collector is installed, run this command to open the FortiGate syslog listener:",
+ "note": "To use TCP instead of UDP, replace udp with tcp in the command above."
+ },
+ "step2": {
+ "title": "Configure FortiGate to forward logs",
+ "body": "On the FortiGate, point syslog at the Collector host on port {{port}}. Run the following from the FortiOS CLI (or use Log & Report → Log Settings → Syslog in the GUI):",
+ "note": "Replace the server address if the Collector runs on a different host. For multiple syslog collectors use syslogd2/syslogd3/syslogd4."
+ }
+ },
+ "fortiweb": {
+ "source": "FortiWeb WAF",
+ "step1": {
+ "title": "Enable the FortiWeb listener on the Collector",
+ "body": "On the host where the Collector is installed, run this command to open the FortiWeb syslog listener:",
+ "note": "To use TCP instead of UDP, replace udp with tcp in the command above."
+ },
+ "step2": {
+ "title": "Configure FortiWeb to forward logs",
+ "body": "On the FortiWeb, create a syslog policy pointing at the Collector host on port {{port}} and enable syslog logging. Run the following from the FortiWeb CLI (or use Log & Report → Log Policy → Syslog Policy in the GUI):",
+ "note": "Make sure the relevant log types (Attack, Event, Traffic) are enabled to be sent to syslog under Log & Report settings."
+ }
+ },
+ "paloalto": {
+ "source": "Palo Alto firewall",
+ "step1": {
+ "title": "Enable the Palo Alto listener on the Collector",
+ "body": "On the host where the Collector is installed, run this command to open the Palo Alto syslog listener:",
+ "note": "To use TCP instead of UDP, replace udp with tcp in the command above."
+ },
+ "step2": {
+ "title": "Create a Syslog Server Profile",
+ "body": "In PAN-OS, go to Device → Server Profiles → Syslog and add a profile. Set the server address to {{host}}, transport UDP, port {{port}} and format BSD."
+ },
+ "step3": {
+ "title": "Forward logs and commit",
+ "body": "Create a Log Forwarding profile (Objects → Log Forwarding) that sends Traffic, Threat and other log types to the syslog profile above, attach it to your Security policy rules (Policies → Security → rule → Actions → Log Forwarding), then Commit."
+ }
+ },
+ "pfsense": {
+ "source": "pfSense firewall",
+ "step1": {
+ "title": "Enable the pfSense listener on the Collector",
+ "body": "On the host where the Collector is installed, run this command to open the pfSense syslog listener:",
+ "note": "To use TCP instead of UDP, replace udp with tcp in the command above."
+ },
+ "step2": {
+ "title": "Enable Remote Logging in pfSense",
+ "body": "In the pfSense web UI, go to Status → System Logs → Settings. Under Remote Logging Options, check Enable Remote Logging, set a Remote log server to {{host}}:{{port}}, choose which logs to send (or Everything), and click Save."
+ }
+ },
+ "sonicwall": {
+ "source": "SonicWall firewall",
+ "step1": {
+ "title": "Enable the SonicWall listener on the Collector",
+ "body": "On the host where the Collector is installed, run this command to open the SonicWall syslog listener:",
+ "note": "To use TCP instead of UDP, replace udp with tcp in the command above."
+ },
+ "step2": {
+ "title": "Add a Syslog Server in SonicOS",
+ "body": "In SonicOS, go to Device → Log → Syslog (Manage → Log → Syslog on older firmware) and add a Syslog Server with address {{host}} and port {{port}}. Set the Syslog Format to ArcSight (CEF) — UTMStack parses SonicWall in CEF — then Apply."
+ }
+ },
+ "sophosxg": {
+ "source": "Sophos Firewall",
+ "step1": {
+ "title": "Enable the Sophos Firewall listener on the Collector",
+ "body": "On the host where the Collector is installed, run this command to open the Sophos Firewall syslog listener:",
+ "note": "To use TCP instead of UDP, replace udp with tcp in the command above."
+ },
+ "step2": {
+ "title": "Add a Syslog Server in Sophos Firewall",
+ "body": "In the Sophos Firewall (SFOS) console, go to System → System services → Log settings and add a Syslog Server with address {{host}} and port {{port}}. Choose the log types you want to forward (firewall, IPS, ATP, web, etc.) and click Apply."
+ }
+ },
+ "suricata": {
+ "source": "Suricata IDS",
+ "step1": {
+ "title": "Enable the Suricata listener on the Collector",
+ "body": "On the host where the Collector is installed, run this command to open the Suricata listener:",
+ "note": "To use TCP instead of UDP, replace udp with tcp in the command above."
+ },
+ "step2": {
+ "title": "Send Suricata EVE logs to syslog",
+ "body": "Suricata is ingested as JSON (EVE). On the Suricata host, edit suricata.yaml and configure the eve-log output to write to syslog:",
+ "note": "Then restart Suricata: sudo systemctl restart suricata"
+ },
+ "step3": {
+ "title": "Forward syslog to the Collector",
+ "body": "Point the local5 facility (where Suricata now writes) at the Collector. Add this rule to /etc/rsyslog.d/60-utmstack-suricata.conf on the Suricata host:",
+ "note": "Use @@ instead of @ for TCP. Then restart rsyslog: sudo systemctl restart rsyslog"
+ }
+ },
+ "o365_graph": {
+ "intro": {
+ "title": "How it works",
+ "body": "UTMStack connects to Microsoft 365 with a registered Azure AD app and polls Microsoft Graph for security events: alerts, incidents, directory audit, sign-ins, risk detections, hunting queries and Purview audit logs. No agent is installed in your tenant.",
+ "diagram": {
+ "source": "security events",
+ "edge": "Microsoft Graph",
+ "utmstackSub": "correlation & alerts"
+ },
+ "note": "UTMStack requires read-only Graph API access — no write permissions are requested."
+ },
+ "appSection": "Azure App Registration",
+ "steps": {
+ "azurePortal": {
+ "title": "Open Microsoft Entra ID",
+ "body": "Open the Azure Portal (portal.azure.com) and click on Microsoft Entra ID."
+ },
+ "appRegistrations": {
+ "title": "Go to App registrations",
+ "body": "In the left menu, click App registrations."
+ },
+ "registerApp": {
+ "title": "Register a new app",
+ "body": "Click New registration. Name it UTMStack Graph Dev, select Accounts in this organizational directory only (Single-tenant), and click Register."
+ },
+ "clientSecret": {
+ "title": "Create a client secret",
+ "body": "Go to Certificates & Secrets → New client secret. Add a description, set expiry to 730 days (24 months), and click Add.",
+ "copyNote": "Copy the secret Value immediately — it is only shown once and cannot be retrieved later."
+ },
+ "apiPermissions": {
+ "title": "Add Microsoft Graph permissions",
+ "body": "Go to API Permissions → Add a permission and select Microsoft Graph, then choose Application permissions."
+ },
+ "graphPermissions": {
+ "title": "Add the four Graph permissions",
+ "body": "Add SecurityEvents.Read.All, Directory.Read.All, AuditLog.Read.All and IdentityRiskEvent.Read.All."
+ },
+ "adminConsent": {
+ "title": "Grant admin consent",
+ "body": "Back in API Permissions, click Grant admin consent for {tenant} and confirm."
+ },
+ "noteIds": {
+ "title": "Copy the app IDs",
+ "body": "Go to the app Overview and copy the Application (client) ID and Directory (tenant) ID. You also need the secret value copied in step 4."
+ }
+ },
+ "credentialsSection": "Credentials",
+ "credentials": {
+ "title": "Connect your Microsoft 365 tenant",
+ "body": "Enter the details from the steps above. UTMStack verifies the credentials before saving. You can add multiple config groups."
+ },
+ "fields": {
+ "tenantId": {
+ "label": "Tenant ID (Directory ID)"
+ },
+ "clientId": {
+ "label": "Client ID (Application ID)"
+ },
+ "clientSecret": {
+ "label": "Client Secret"
+ },
+ "cloudEnv": {
+ "label": "Cloud Environment (optional)",
+ "hint": "Commercial (default), GCC, GCCHigh, or DoD"
+ }
+ }
+ }
+ },
+ "cloud": {
+ "howItWorksTitle": "How it works",
+ "howItWorksBody": "{{name}} runs entirely inside UTMStack — no agent or collector to deploy. Provide read-only API credentials and UTMStack will pull events on a schedule, parse them, and ingest them into Log Explorer.",
+ "connectionTitle": "Connection",
+ "noFields": "No connection fields configured.",
+ "testConnection": "Test connection",
+ "save": "Save",
+ "afterTitle": "What you'll see after connecting",
+ "after1": "UTMStack performs an initial backfill of recent events.",
+ "after2": "From then on, events are pulled every 1–5 minutes (depends on the API).",
+ "after3": "The integration appears under Data Sources with current pull status and lag.",
+ "tenants": {
+ "title": "Configured config groups",
+ "empty": "No config groups configured yet. Add your first one below.",
+ "loading": "Loading config groups…",
+ "nameLabel": "Config group name",
+ "namePlaceholder": "e.g. acme-prod",
+ "add": "Add config group",
+ "update": "Update config group",
+ "delete": "Delete",
+ "edit": "Edit",
+ "cancel": "Cancel",
+ "editing": "Editing: {{name}}",
+ "selectFile": "Select file",
+ "replaceFile": "Replace file",
+ "fileLoaded": "File loaded",
+ "invalidJson": "Could not parse the file as JSON.",
+ "createError": "Could not create the config group. Please try again.",
+ "updateError": "Could not update the config group. Please try again.",
+ "createSuccess": "Config group created successfully.",
+ "updateSuccess": "Config group updated successfully."
+ },
+ "google": {
+ "intro": {
+ "title": "How it works",
+ "body": "UTMStack reads audit activity directly from Google Cloud via Pub/Sub. A Logs Router sink streams your project logs into a Pub/Sub topic; UTMStack runs an internal puller that reads a Pull subscription on that topic using a service-account key. Nothing is installed in your GCP project.",
+ "diagram": {
+ "source": "Cloud Logging",
+ "edge1": "Logs Router",
+ "pubsub": "Pub/Sub",
+ "pubsubSub": "topic + subscription",
+ "edge2": "pulls",
+ "utmstackSub": "alerts & correlation"
+ },
+ "note": "No agent runs in GCP — UTMStack pulls messages from the Pub/Sub subscription using the service-account JSON key you provide below."
+ },
+ "sections": {
+ "createTopic": {
+ "title": "Create a Pub/Sub topic",
+ "body": "In the Google Cloud console, open Pub/Sub → Topics and create a new topic. The Logs Router sink will publish your project logs to it.",
+ "docLabel": "Open the Pub/Sub topics page"
+ },
+ "createSubscription": {
+ "title": "Create a subscription",
+ "body": "From the topic menu, create a subscription. UTMStack pulls messages from this subscription."
+ },
+ "configureSubscription": {
+ "title": "Configure the subscription",
+ "body": "Leave the Delivery type as Pull and the Expiration as Never expire. The default acknowledgement deadline (10s) and message retention are fine."
+ },
+ "logsRouter": {
+ "title": "Open Logs Router and create a sink",
+ "body": "Navigate to Logging → Logs Router and create a new sink. This is what forwards your project logs into the Pub/Sub topic above."
+ },
+ "sinkDestination": {
+ "title": "Point the sink at the topic",
+ "body": "Choose Cloud Pub/Sub topic as the sink destination and select the topic you created. Optionally use inclusion/exclusion filters to scope which logs are forwarded, then create the sink."
+ },
+ "serviceAccount": {
+ "title": "Create a service account",
+ "body": "Open IAM & Admin → Service Accounts in the project that holds your topic and sink, and create a new service account. Grant it the Pub/Sub Editor role so UTMStack can pull from the subscription.",
+ "docLabel": "Open the service accounts page"
+ },
+ "serviceAccountKey": {
+ "title": "Generate a key for the service account",
+ "body": "Open the service account, go to the Keys tab, and add a new key. Choose JSON as the key type."
+ },
+ "downloadKey": {
+ "title": "Download the JSON key",
+ "body": "Save the JSON file Google downloads — its contents go in the Service account JSON key field below. The key is shown only once."
+ }
+ },
+ "credentials": {
+ "title": "Pub/Sub configuration",
+ "body": "Use the values collected above to configure UTMStack. You can monitor more than one project by saving additional configurations.",
+ "mapping": {
+ "intro": "Field reference",
+ "projectId": "Project ID — the GCP project that holds your topic, subscription and sink",
+ "subscription": "Subscription name — the Pull subscription created in step 2",
+ "jsonKey": "Service account JSON key — the file downloaded in step 8"
+ }
+ },
+ "fields": {
+ "projectId": {
+ "label": "Project ID"
+ },
+ "subscription": {
+ "label": "Subscription name"
+ },
+ "jsonKey": {
+ "label": "Service account JSON key"
+ }
+ }
+ },
+ "azure": {
+ "intro": {
+ "title": "How it works",
+ "body": "UTMStack reads audit activity directly from an Azure Event Hub. You configure your Azure subscription to stream events into an Event Hub; UTMStack runs an internal puller that reads that hub and checkpoints its progress in a Storage Account. Nothing is installed in your Azure tenant.",
+ "diagram": {
+ "source": "subscription events",
+ "edge1": "streams to",
+ "eventHub": "Event Hub",
+ "eventHubSub": "event stream",
+ "edge2": "pulls",
+ "utmstackSub": "alerts & correlation"
+ },
+ "note": "No agent runs in Azure — UTMStack pulls events from the Event Hub using the connection strings you provide below."
+ },
+ "sections": {
+ "createEventHub": {
+ "title": "Create an Event Hub",
+ "body": "In the Azure Portal, create an Event Hubs namespace and an Event Hub inside it. UTMStack will read events from this hub.",
+ "docLabel": "Quickstart: Create an event hub using the Azure portal"
+ },
+ "sharedAccessPolicy": {
+ "title": "Add a Shared Access Policy",
+ "body": "Open the Event Hub → Shared access policies and create a new policy. Make sure you select the Listen permission."
+ },
+ "connectionString": {
+ "title": "Copy the primary connection string",
+ "body": "Open the Shared access policy you just created and copy the Connection string–primary key. You will use it to configure your config group below."
+ },
+ "consumerGroup": {
+ "title": "Create a dedicated consumer group",
+ "body": "Get the Consumer Group name in: All services → Event Hubs → your namespace → Event Hubs → your instance → Consumer groups. You will use it to configure your config group below.",
+ "warn": "Create a consumer group specifically for UTMStack. Do not use $Default or any other group already in use — reusing a consumer group across unrelated consumers can cause unexpected behavior and lost events. All UTMStack instances should share the same consumer group so they can process events together."
+ },
+ "createStorageAccount": {
+ "title": "Create a Storage Account",
+ "body": "UTMStack needs a Storage Account to checkpoint its read position. Create one in the same region as the Event Hub.",
+ "docLabel": "Quickstart: Create a storage account"
+ },
+ "storageContainer": {
+ "title": "Get the Storage Container name",
+ "body": "Get the Storage Container name in: All services → Storage accounts → your account → Containers. You will use it to configure your config group below."
+ },
+ "storageConnection": {
+ "title": "Copy the Storage Account connection string",
+ "body": "Get the Storage Account connection string with key in: All services → Storage accounts → your account → Access keys. UTMStack uses it to store Event Hub checkpoints."
+ },
+ "eventGrid": {
+ "title": "Register the Event Grid resource provider",
+ "body": "Configure your subscription to send logs to the Event Hub. Go to Subscriptions → Resource providers, search for Event Grid (Microsoft.EventGrid) and make sure it is registered."
+ },
+ "createEventSubscription": {
+ "title": "Create an Event Subscription",
+ "body": "In the subscription Events panel, create a new event by clicking Events → Event Subscription."
+ },
+ "configureEventSubscription": {
+ "title": "Point the Event Subscription at your Event Hub",
+ "body": "Configure the Event Subscription to send logs to the Event Hub you created in step 1."
+ }
+ },
+ "sampleLabel": "Sample connection string:",
+ "credentials": {
+ "title": "Event Hub configuration",
+ "body": "Use the data collected in the steps above to configure UTMStack. You can add more than one Event Hub by saving additional configurations.",
+ "mapping": {
+ "intro": "Field reference",
+ "eventHubConnection": "Event Hub connection string — value obtained in step 3",
+ "consumerGroup": "Consumer group — value obtained in step 4",
+ "storageContainer": "Storage container name — value obtained in step 6",
+ "storageConnection": "Storage account connection string — value obtained in step 7"
+ }
+ },
+ "fields": {
+ "eventHubConnection": {
+ "label": "Event Hub connection string"
+ },
+ "consumerGroup": {
+ "label": "Consumer group"
+ },
+ "storageContainer": {
+ "label": "Storage container name"
+ },
+ "storageConnection": {
+ "label": "Storage account connection string"
+ }
+ }
+ },
+ "aws": {
+ "intro": {
+ "title": "How it works",
+ "body": "UTMStack reads audit activity directly from AWS CloudWatch Logs. CloudTrail captures API calls and management events across your AWS account, forwards them to a CloudWatch log group, and UTMStack polls that group to ingest and correlate events.",
+ "diagram": {
+ "source": "API events",
+ "edge1": "CloudTrail",
+ "cloudwatchSub": "log groups",
+ "edge2": "polls",
+ "utmstackSub": "alerts & correlation"
+ },
+ "note": "No agent is installed on AWS — UTMStack pulls log events using read-only IAM credentials you provide below."
+ },
+ "iamSection": "Configure IAM User",
+ "iam": {
+ "dashboard": {
+ "title": "Open the IAM dashboard",
+ "body": "Open the AWS console, navigate to the IAM dashboard and select Users."
+ },
+ "addUser": {
+ "title": "Add a user",
+ "body": "Click Add user, enter a descriptive user name, and proceed to the next step."
+ },
+ "attachPolicy": {
+ "title": "Attach the read-only policy",
+ "body": "Under Permissions, attach the required policy. Select CloudWatchLogsReadOnlyAccess for read-only CloudWatch access."
+ },
+ "createUser": {
+ "title": "Create the user",
+ "body": "Review the configuration and click Create user to provision the account."
+ },
+ "openUser": {
+ "title": "Open the new user",
+ "body": "Open the newly created user by clicking its name to view details and manage credentials."
+ },
+ "securityTab": {
+ "title": "Go to Security credentials",
+ "body": "Select the Security credentials tab to create programmatic access keys."
+ },
+ "createKey": {
+ "title": "Create an access key",
+ "body": "Click Create access key and choose the option for an application running outside AWS (programmatic access)."
+ },
+ "confirmKey": {
+ "title": "Confirm creation",
+ "body": "Confirm creation of the access key. AWS will generate an Access Key ID and Secret Access Key."
+ },
+ "downloadKey": {
+ "title": "Save your credentials",
+ "body": "Download the credentials file or copy the Access Key ID and Secret Access Key to a secure location — the Secret Access Key is only shown once."
+ }
+ },
+ "credentials": {
+ "title": "Enter credentials",
+ "body": "Paste the Access Key ID and Secret Access Key obtained in the previous steps. UTMStack verifies the credentials against AWS before saving."
+ },
+ "cloudwatchSection": "Configure AWS CloudWatch",
+ "cloudwatch": {
+ "createGroup": {
+ "title": "Create a CloudWatch Log Group",
+ "body": "Open the CloudWatch console, choose Log management and click Create log group."
+ },
+ "nameGroup": {
+ "title": "Name the log group and set retention",
+ "body": "Enter the log group name utmstack and set retention to 1 day. Click Create log group."
+ },
+ "openTrail": {
+ "title": "Open CloudTrail and create a trail",
+ "body": "In the CloudTrail console click Create trail to begin configuring a new trail."
+ },
+ "configureTrail": {
+ "title": "Configure delivery, validation and CloudWatch integration",
+ "body": "On the CloudTrail creation form set the following options:",
+ "items": [
+ "Trail name and scope: enter a descriptive name; enable Apply trail to all accounts in my organization if you need org-wide collection.",
+ "S3 destination: choose Create new S3 bucket (or select an existing bucket) for raw log delivery.",
+ "Encryption: enable Log file SSE-KMS and select the appropriate KMS key.",
+ "Log file validation: enable to ensure integrity of delivered logs (recommended).",
+ "CloudWatch Logs: enable delivery to CloudWatch, select Use existing log group and enter the exact name utmstack.",
+ "IAM role: provide or create the role CloudTrail will assume to write to S3 and publish to CloudWatch."
+ ]
+ },
+ "eventTypes": {
+ "title": "Select event types",
+ "body": "Enable the event categories required for monitoring and auditing.",
+ "management": {
+ "label": "1 · Management events",
+ "body": "Enable Management events and select All to record all API activity that manages AWS resources (create, update, delete)."
+ },
+ "data": {
+ "label": "2 · Data events",
+ "body": "Add a Data event. Choose S3 and select Log all events to capture object-level operations such as GetObject and PutObject."
+ },
+ "network": {
+ "label": "3 · Network activity events",
+ "body": "In the Network Activities section add at least one service (e.g. ec2.amazonaws.com) and enable Log all events."
+ }
+ },
+ "review": {
+ "title": "Review and create the trail",
+ "body": "On the Configure event aggregation screen accept the defaults (or adjust if required). Review all settings and click Create trail."
+ }
+ },
+ "fields": {
+ "accessKeyId": {
+ "label": "AWS access key ID"
+ },
+ "secretAccessKey": {
+ "label": "AWS secret access key"
+ },
+ "region": {
+ "label": "AWS default region"
+ },
+ "logGroupName": {
+ "label": "Log group name"
+ }
+ }
+ },
+ "crowdstrike": {
+ "intro": {
+ "title": "How it works",
+ "body": "UTMStack reads detections and audit activity directly from the CrowdStrike Falcon Event Streams API. You create an API client in Falcon with Event Streams scope; UTMStack runs an internal puller that streams events using those credentials. Nothing is installed on your endpoints or in Falcon.",
+ "diagram": {
+ "source": "detections & events",
+ "edge1": "Event Streams API",
+ "api": "Falcon API",
+ "apiSub": "event stream",
+ "edge2": "pulls",
+ "utmstackSub": "alerts & correlation"
+ },
+ "note": "No agent is deployed by UTMStack — it pulls events from Falcon using the read-only API client credentials you provide below."
+ },
+ "sections": {
+ "apiClients": {
+ "title": "Open API Clients and Keys",
+ "body": "In the Falcon console, open the menu (hamburger icon, top-left) and go to Support and resources → API Clients and Keys."
+ },
+ "createClient": {
+ "title": "Create a new API client",
+ "body": "Click Create API Client to start a new client definition."
+ },
+ "scopes": {
+ "title": "Name the client and grant Event Streams scope",
+ "body": "Give the client a descriptive name (UTMStack uses it to identify the event source) and select the API scopes required for Event Streams. Click Create to generate the credentials."
+ },
+ "recordCredentials": {
+ "title": "Record the credentials",
+ "body": "Copy the Client ID, Client Secret and the Base URL for your CrowdStrike region. The secret is shown only once — store it securely. You will paste all three into the form below."
+ }
+ },
+ "credentials": {
+ "title": "API client configuration",
+ "body": "Use the credentials from the steps above to configure UTMStack. You can add more than one CrowdStrike client by saving additional configurations.",
+ "mapping": {
+ "intro": "Field reference",
+ "appName": "App name — the descriptive client name from step 3 (identifies the event source)",
+ "clientId": "Client ID — value recorded in step 4",
+ "clientSecret": "Client Secret — value recorded in step 4 (shown only once)",
+ "cloudRegionUrl": "Base URL — your region endpoint, e.g. https://api.crowdstrike.com (us-1), https://api.us-2.crowdstrike.com (us-2), https://api.eu-1.crowdstrike.com (eu-1)"
+ }
+ },
+ "fields": {
+ "appName": {
+ "label": "App name"
+ },
+ "clientId": {
+ "label": "Client ID"
+ },
+ "clientSecret": {
+ "label": "Client Secret"
+ },
+ "cloudRegionUrl": {
+ "label": "Base URL (cloud region)"
+ }
+ }
+ }
+ },
+ "custom": {
+ "intro": {
+ "title": "How it works",
+ "body": "A custom integration ingests logs from any source the built-in modules do not cover. You install the UTMStack Collector, register a listener for your data with the protocol of your choice, and point your source at it.",
+ "note": "Pick the protocol your source can send (syslog UDP/TCP/TLS, or HTTP/HTTPS for JSON) below — the Collector creates the data type automatically."
+ },
+ "diagram": {
+ "source": "Your source",
+ "sourceSub": "any app or device",
+ "forwarder": "Collector",
+ "ingests": "ingests",
+ "utmstackSub": "alerts & correlation"
+ },
+ "choose": {
+ "title": "Choose protocol and port",
+ "body": "Select how your source sends data and the port the Collector should listen on, then run the activation command on the Collector host.",
+ "portLabel": "Listener port",
+ "tlsFirst": "First load your TLS certificate and key on the Collector:",
+ "enableLabel": "Then enable the integration:",
+ "authNote": "To require authentication, append --auth bearer (token) or --auth hmac — the Collector prints a token to use in the Authorization header."
+ },
+ "send": {
+ "title": "Point your source at the Collector",
+ "bodyNetwork": "Configure your source to send {{proto}} syslog to {{host}}:{{port}}. Most devices have a remote-syslog or log-forwarding setting for this.",
+ "bodyHttp": "Send your events as JSON via HTTP POST to {{endpoint}}. Each request body is one JSON event:",
+ "httpBindNote": "The HTTP/HTTPS listener binds to 127.0.0.1 (the Collector host) by default, so post from an app running on that host — or front it with a reverse proxy. For remote sources, use syslog (UDP/TCP/TLS)."
+ },
+ "parserTitle": "Parsing",
+ "parserBody": "Incoming events are stored under the {{dataType}} data type. Add a parsing filter for it so the raw payload is mapped into structured fields, then build alert rules on top.",
+ "manualCommand": {
+ "title": "Optional — Enable via the command line instead",
+ "intro": "Prefer the terminal? SSH into the Collector host and run the command below — it matches whatever protocol and port you have selected above."
+ }
+ },
+ "remoteEnable": {
+ "title": "Enable this integration remotely",
+ "body": "Pick a Collector, choose the protocol and port, then enable the integration — no SSH needed.",
+ "noPermission": "You don't have permission to manage remote integrations. Ask an administrator to grant the integrations.write permission.",
+ "loadingCollectors": "Loading Collectors…",
+ "noCollectors": "No Collector is registered yet. Install one above to enable integrations remotely.",
+ "forwarderOffline": "This Collector is offline and can't receive configuration changes right now.",
+ "legendOnline": "{{count}} online",
+ "legendOffline": "{{count}} offline",
+ "legendTotal": "{{count}} total",
+ "forwarderLabel": "Collector",
+ "protoLabel": "Protocol",
+ "portLabel": "Port",
+ "currentStateLoading": "Checking current configuration…",
+ "currentlyEnabled": "Currently: enabled · {{proto}} · port {{port}}",
+ "currentlyDisabled": "Currently: disabled · {{proto}} · port {{port}}",
+ "authLabel": "Authentication",
+ "authNone": "None",
+ "authBearer": "Bearer token",
+ "authHmac": "HMAC signature",
+ "pathLabel": "Path",
+ "signatureHeaderLabel": "Signature header",
+ "certTitle": "TLS certificate",
+ "certLoading": "Checking certificate status…",
+ "certLoaded": "A valid certificate is already loaded on this Collector.",
+ "certMissing": "No certificate loaded yet — upload one to enable this protocol.",
+ "certInvalid": "The loaded certificate is invalid: {{error}}",
+ "certPemLabel": "Certificate",
+ "keyPemLabel": "Private key",
+ "caPemLabel": "CA certificate",
+ "uploadCertsButton": "Upload certificate",
+ "certUploadSuccess": "Certificate uploaded.",
+ "certUploadError": "Failed to upload the certificate.",
+ "certReadError": "Could not read the selected file(s).",
+ "enableButton": "Enable integration",
+ "disableButton": "Disable integration",
+ "enableSuccess": "Integration enabled.",
+ "disableSuccess": "Integration disabled.",
+ "enableError": "Failed to update the integration.",
+ "secretWarning": "Store this token securely — it won't be shown again.",
+ "sendToInstance": "Send to instance",
+ "enterpriseFeature": "This is an Enterprise feature.",
+ "addCollector": "Add Collector",
+ "addApiKey": "Add API key",
+ "apiKeyLabel": "API key",
+ "apiKeyHint": "First you'll need an API key.",
+ "apiKeyPlaceholder": "Select an API key",
+ "apiKeyAddNew": "Add API key…",
+ "apiKeyNone": "No API keys yet",
+ "forwarderNoRemoteControl": "This forwarder was installed with remote control disabled. It ignores configuration sent from here, which can only be changed on the machine itself."
+ }
+ },
+ "codeBlock": {
+ "copy": "Copy",
+ "copied": "Copied"
+ },
+ "createDrawer": {
+ "title": "New custom integration",
+ "moduleName": "Module name",
+ "moduleNameHint": "Unique identifier. No spaces.",
+ "moduleNamePlaceholder": "my-custom-app",
+ "prettyName": "Display name",
+ "prettyNamePlaceholder": "My Custom App",
+ "dataType": "Data type",
+ "dataTypePlaceholder": "Unique identifier for this data type",
+ "icon": "Icon",
+ "iconHint": "PNG, SVG, JPEG, GIF or WEBP. Max 3MB. Used as the integration logo.",
+ "iconPreview": "Icon preview",
+ "dataTypeExists": "This data type already exists",
+ "invalidFileType": "Icon must be a valid image file (PNG, JPEG, SVG, GIF, WEBP)",
+ "fileTooLarge": "Icon must not exceed 3MB",
+ "fileReadError": "Failed to read file",
+ "cancel": "Cancel",
+ "create": "Create integration",
+ "creating": "Creating…",
+ "editTitle": "Edit integration",
+ "save": "Save",
+ "saving": "Saving…",
+ "currentIcon": "Current icon — upload a file to replace it",
+ "name": "Integration name",
+ "namePlaceholder": "e.g. Acme Firewall",
+ "description": "Description",
+ "descriptionPlaceholder": "What this integration ingests and why (optional)",
+ "identifierHint": "Stored as “{{id}}” (derived from the name)",
+ "nameTaken": "That integration name can’t be used — an integration with that identifier already exists.",
+ "removeIcon": "Remove icon",
+ "defaultIconNote": "Default icon — upload a file to use your own."
+ },
+ "toast": {
+ "created": "Integration created",
+ "updated": "Integration updated",
+ "updateError": "Failed to update integration"
+ },
+ "delete": {
+ "title": "Delete integration",
+ "confirm": "Delete this integration?",
+ "yes": "Delete",
+ "no": "Cancel",
+ "deleted": "Integration deleted",
+ "error": "Failed to delete integration"
+ },
+ "modules": {
+ "WINDOWS_AGENT": {
+ "name": "Windows Agent",
+ "description": "Collect Windows system, security and event-log activity through the lightweight UTMStack agent installed on each host."
+ },
+ "LINUX_AGENT": {
+ "name": "Linux Agent",
+ "description": "Collect Linux system, authentication and audit logs through the lightweight UTMStack agent installed on each host."
+ },
+ "MACOS": {
+ "name": "macOS",
+ "description": "Collect macOS system and security log activity from Apple Mac endpoints through the lightweight UTMStack agent."
+ },
+ "VMWARE": {
+ "name": "VMware",
+ "description": "Ingest VMware ESXi hypervisor syslog so virtualization-host activity and events are monitored within UTMStack."
+ },
+ "NETFLOW": {
+ "name": "NetFlow",
+ "description": "Ingest NetFlow records from routers and switches to monitor network-traffic patterns and detect traffic anomalies."
+ },
+ "AWS_IAM_USER": {
+ "name": "AWS",
+ "description": "Ingest AWS account activity and API calls via CloudTrail and CloudWatch to audit cloud usage, access and changes."
+ },
+ "AZURE": {
+ "name": "Microsoft Azure",
+ "description": "Ingest Microsoft Azure platform and activity logs to monitor cloud workloads, identity and resource changes."
+ },
+ "O365": {
+ "name": "Microsoft 365",
+ "description": "Ingest Microsoft 365 audit logs across Exchange, Teams, SharePoint and OneDrive to monitor user and admin activity."
+ },
+ "O365_GRAPH": {
+ "name": "Microsoft 365 (Graph)",
+ "description": "Ingest Microsoft Graph security events — alerts, incidents, directory audit, sign-ins, risk detections and Purview audit logs — to monitor identity and threat activity across your tenant."
+ },
+ "GCP": {
+ "name": "Google Cloud Platform",
+ "description": "Ingest Google Cloud Platform audit and activity logs to monitor compute, storage and identity across projects."
+ },
+ "KASPERSKY": {
+ "name": "Kaspersky",
+ "description": "Ingest Kaspersky Security Center detections and endpoint telemetry to correlate malware activity across the network."
+ },
+ "ESET": {
+ "name": "ESET",
+ "description": "Ingest ESET PROTECT endpoint detections and telemetry to correlate multilayered malware defense across your estate."
+ },
+ "BITDEFENDER": {
+ "name": "Bitdefender",
+ "description": "Ingest Bitdefender GravityZone detections and endpoint telemetry to correlate threats across business devices."
+ },
+ "SENTINEL_ONE": {
+ "name": "SentinelOne",
+ "description": "Ingest SentinelOne endpoint detections and behavioral telemetry to correlate and investigate threats at scale."
+ },
+ "SOPHOS": {
+ "name": "Sophos Central",
+ "description": "Ingest Sophos Central detections across endpoint, server, firewall and email to correlate threats in one place."
+ },
+ "CROWDSTRIKE": {
+ "name": "CrowdStrike Falcon",
+ "description": "Ingest CrowdStrike Falcon endpoint and workload detections to correlate cloud-native threat activity in UTMStack."
+ },
+ "CISCO": {
+ "name": "Cisco ASA",
+ "description": "Ingest Cisco ASA firewall traffic, VPN and threat logs to monitor perimeter security and access within UTMStack."
+ },
+ "MERAKI": {
+ "name": "Cisco Meraki",
+ "description": "Ingest Cisco Meraki firewall and security-appliance syslog to monitor cloud-managed network traffic and threats."
+ },
+ "FIRE_POWER": {
+ "name": "Cisco Firepower",
+ "description": "Ingest Cisco Firepower NGFW and IPS logs to monitor intrusion attempts and threat activity at the perimeter."
+ },
+ "CISCO_SWITCH": {
+ "name": "Cisco Switch",
+ "description": "Ingest Cisco switch syslog and telemetry to monitor network performance, configuration changes and security."
+ },
+ "FORTIGATE": {
+ "name": "FortiGate",
+ "description": "Ingest Fortinet FortiGate NGFW traffic and threat logs to monitor perimeter security and network activity."
+ },
+ "FORTIWEB": {
+ "name": "FortiWeb",
+ "description": "Ingest Fortinet FortiWeb WAF logs to monitor web-application attacks and protect exposed services and APIs."
+ },
+ "SOPHOS_XG": {
+ "name": "Sophos XG",
+ "description": "Ingest Sophos XG firewall logs covering web filtering, IPS and VPN to monitor network traffic and threats."
+ },
+ "PALO_ALTO": {
+ "name": "Palo Alto Networks",
+ "description": "Ingest Palo Alto Networks NGFW traffic and threat logs to monitor application usage and perimeter security."
+ },
+ "SONIC_WALL": {
+ "name": "SonicWall",
+ "description": "Ingest SonicWall NGFW traffic and threat logs to monitor perimeter security and network activity in UTMStack."
+ },
+ "PFSENSE": {
+ "name": "pfSense",
+ "description": "Ingest pfSense firewall and router logs with unified threat management to monitor network traffic and threats."
+ },
+ "MIKROTIK": {
+ "name": "MikroTik",
+ "description": "Ingest MikroTik RouterOS firewall, routing and wireless logs to monitor network activity and configuration."
+ },
+ "AIX": {
+ "name": "IBM AIX",
+ "description": "Collect IBM AIX Unix system, security and audit logs to monitor activity on IBM Power platforms within UTMStack."
+ },
+ "AS_400": {
+ "name": "IBM i (AS/400)",
+ "description": "Collect IBM AS/400 (IBM i) system and audit journals to monitor user activity on midrange OS/400 platforms."
+ },
+ "ORACLE": {
+ "name": "Oracle Database",
+ "description": "Ingest Oracle Database audit logs to monitor queries, access and privileged activity across your databases."
+ },
+ "SURICATA": {
+ "name": "Suricata",
+ "description": "Ingest Suricata IDS/IPS alerts and network events to detect intrusions and malicious traffic across the network."
+ },
+ "DECEPTIVE_BYTES": {
+ "name": "Deceptive Bytes",
+ "description": "Ingest Deceptive Bytes alerts from its active endpoint-deception platform to surface attacker activity early."
+ },
+ "GITHUB": {
+ "name": "GitHub",
+ "description": "Ingest GitHub audit logs to monitor repository access, code changes and organization activity for source security."
+ },
+ "UTMSTACK": {
+ "name": "UTMStack",
+ "description": "Ingest UTMStack's own SIEM and XDR telemetry to monitor platform health, internal activity and self-audit events."
+ },
+ "NGINX": {
+ "name": "Nginx",
+ "description": "Ingest Nginx access and error logs to monitor web-serving activity, reverse-proxy traffic and client requests."
+ },
+ "APACHE": {
+ "name": "Apache",
+ "description": "Ingest Apache HTTPD access and error logs to monitor web-serving activity and client requests."
+ },
+ "APACHE2": {
+ "name": "Apache2",
+ "description": "Ingest Apache2 (HTTPD) web server logs to monitor request handling, errors and access on Linux hosts."
+ },
+ "IIS": {
+ "name": "IIS",
+ "description": "Ingest Internet Information Services (IIS) access and log-file activity to monitor Windows web serving."
+ },
+ "MYSQL": {
+ "name": "MySQL",
+ "description": "Ingest MySQL database log activity to monitor queries, authentication and data-store access."
+ },
+ "POSTGRESQL": {
+ "name": "PostgreSQL",
+ "description": "Ingest PostgreSQL database logs to monitor queries, access and activity across your data stores."
+ },
+ "MONGODB": {
+ "name": "MongoDB",
+ "description": "Ingest MongoDB log activity to monitor document-database access, queries and application behavior."
+ },
+ "REDIS": {
+ "name": "Redis",
+ "description": "Ingest Redis log and telemetry activity to monitor in-memory data store usage and real-time workloads."
+ },
+ "ELASTICSEARCH": {
+ "name": "Elasticsearch",
+ "description": "Ingest Elasticsearch logs to monitor the search and analytics engine and its application workloads."
+ },
+ "LOGSTASH": {
+ "name": "Logstash",
+ "description": "Ingest Logstash pipeline logs to monitor the data-processing pipeline and its event transformations."
+ },
+ "KIBANA": {
+ "name": "Kibana",
+ "description": "Ingest Kibana logs to monitor the data-visualization and exploration layer and its usage."
+ },
+ "KAFKA": {
+ "name": "Apache Kafka",
+ "description": "Ingest Apache Kafka logs to monitor real-time streaming pipelines, brokers and message flow."
+ },
+ "NATS": {
+ "name": "NATS",
+ "description": "Ingest NATS messaging logs to monitor the message bus, connectivity and event delivery."
+ },
+ "HAPROXY": {
+ "name": "HAProxy",
+ "description": "Ingest HAProxy logs to monitor load balancing, proxy traffic and network availability."
+ },
+ "TRAEFIK": {
+ "name": "Traefik",
+ "description": "Ingest Traefik logs to monitor routing, load balancing and proxy traffic across workloads."
+ },
+ "OSQUERY": {
+ "name": "osquery",
+ "description": "Ingest OsQuery logs to monitor endpoint state, queries and system inventory via SQL-style requests."
+ },
+ "SYSLOG": {
+ "name": "Syslog",
+ "description": "Send syslog (RFC 5424/3164) from any device or application to the collector endpoint for central log intake."
+ },
+ "JSON": {
+ "name": "JSON Input",
+ "description": "Send JSON log payloads to the ingestion endpoint for structured event intake from applications and scripts."
+ },
+ "WINDOWS_SQL_SERVER": {
+ "name": "SQL Server Event Logs",
+ "description": "Collect Microsoft SQL Server audit and event records through the Windows Event Log and UTMStack agent."
+ },
+ "WINDOWS_FILE_AUDITING": {
+ "name": "Windows File Access Auditing",
+ "description": "Collect Windows file access audit events through the Windows Event Log and UTMStack agent."
+ }
+ },
+ "edit": {
+ "title": "Edit integration"
+ },
+ "allCategories": "All categories",
+ "customOnly": "Custom"
+ },
+ "dataProcessing": {
+ "title": "Data processing",
+ "subtitle": "Ingestion and processing statistics: events received, dropped by stage, and the top sources and types.",
+ "ingestion": {
+ "title": "Ingestion",
+ "last24h": "last 24 hours",
+ "noData": "No data in this window.",
+ "loadError": "Could not load ingestion stats.",
+ "groupBy": {
+ "dataSource": "By data source",
+ "dataType": "By data type"
+ },
+ "status": {
+ "received": "Received",
+ "parsing_dropped": "Dropped (parsing)",
+ "analysis_dropped": "Dropped (analysis)",
+ "correlation_dropped": "Dropped (correlation)",
+ "all": "All events"
+ }
+ },
+ "filters": {
+ "title": "Filters",
+ "new": "New filter",
+ "search": "Search by path…",
+ "refresh": "Refresh",
+ "retry": "Retry",
+ "empty": "No filters match.",
+ "loadError": "Could not load filters.",
+ "toggleError": "Could not change the filter state",
+ "system": "System",
+ "custom": "Custom",
+ "systemReadonly": "System filters are read-only",
+ "view": "View",
+ "edit": "Edit",
+ "ownership": {
+ "all": "All",
+ "system": "System",
+ "custom": "Custom"
+ },
+ "state": {
+ "all": "All",
+ "active": "Active",
+ "inactive": "Inactive"
+ },
+ "col": {
+ "filter": "Filter",
+ "type": "Type",
+ "active": "Active",
+ "actions": "Actions"
+ },
+ "pageInfo": "{{from}}–{{to}} of {{count}}"
+ },
+ "editor": {
+ "createTitle": "New filter",
+ "editTitle": "Edit filter",
+ "viewTitle": "View filter",
+ "relPath": "Path",
+ "relPathHint": "Folder + file, e.g. syslog/my-filter.yaml",
+ "content": "Pipeline (YAML)",
+ "contentHint": "Steps run in order: grok, rename, delete, dynamic plugins, …",
+ "save": "Save",
+ "saving": "Saving…",
+ "saved": "Filter saved",
+ "saveError": "Could not save the filter",
+ "cancel": "Cancel",
+ "delete": "Delete",
+ "deleteConfirm": "Delete this filter?",
+ "deleted": "Filter deleted",
+ "deleteError": "Could not delete the filter"
+ },
+ "kpi": {
+ "received": "Received",
+ "dropped": "Dropped",
+ "dropRate": "{{rate}}% drop rate",
+ "stored": "Stored",
+ "throughput": "Throughput",
+ "perMin": "{{value}}/min",
+ "survival": "{{rate}}% kept"
+ },
+ "section": {
+ "overTime": "Events over time",
+ "top": "Top",
+ "dropReasons": "Drop reasons"
+ },
+ "live": {
+ "auto": "Auto"
+ },
+ "pipeline": {
+ "title": "Ingestion pipeline",
+ "stages": {
+ "received": "Received",
+ "parsed": "Parsed",
+ "analyzed": "Analyzed",
+ "stored": "Stored"
+ }
+ },
+ "chart": {
+ "title": "Throughput over time",
+ "received": "Received",
+ "dropped": "Dropped"
+ },
+ "donut": {
+ "title": "Drop composition",
+ "dropped": "dropped"
+ },
+ "breakdown": {
+ "title": "Top sources & types",
+ "bars": "Bars",
+ "treemap": "Treemap",
+ "showAll": "Show all {{count}}",
+ "showLess": "Show less",
+ "lastSeen": "Last seen",
+ "ago": "{{time}} ago"
+ }
+ },
+ "datasources": {
+ "limitBanner": {
+ "title": "Datasource limit exceeded.",
+ "message": "You have {{count}} datasources but your license covers {{limit}}. Logs from datasources beyond the limit are being dropped.",
+ "cta": "Manage license",
+ "dismiss": "Dismiss"
+ },
+ "title": "Data sources",
+ "total": "{{count}} total",
+ "subtitle": "Agents, integrations and direct sources feeding events. Status is derived from the last time each source was seen.",
+ "connectSource": "Connect a source",
+ "loading": "Loading data sources…",
+ "loadFailed": "Could not load data sources.",
+ "retry": "Retry",
+ "none": "No data sources match this view.",
+ "ingestion": {
+ "title": "Ingestion",
+ "received": "events received",
+ "none": "No ingestion in the last 24 hours.",
+ "ago24h": "24h ago",
+ "now": "now"
+ },
+ "usage": {
+ "title": "Data sources",
+ "ofUnlimited": "of unlimited",
+ "ofLimit": "of {{limit}}",
+ "overLimit": "Over the licensed limit — data beyond the cap is at risk.",
+ "configured": "configured"
+ },
+ "tabs": {
+ "all": "All",
+ "agent": "Agents",
+ "puller": "Integrations",
+ "direct": "Direct",
+ "offline": "Offline"
+ },
+ "toolbar": {
+ "searchPlaceholder": "Search by name…",
+ "list": "List",
+ "cards": "Cards",
+ "refresh": "Refresh"
+ },
+ "labels": {
+ "filteredBy": "Filtered by label",
+ "add": "Add label…",
+ "addFirst": "Add a label…",
+ "hint": "Type a label and press Enter to add it. Changes save automatically."
+ },
+ "status": {
+ "live": "Live",
+ "idle": "Idle",
+ "offline": "Offline"
+ },
+ "kind": {
+ "agent": "Agent",
+ "puller": "Integration",
+ "direct": "Direct"
+ },
+ "cols": {
+ "source": "Source",
+ "type": "Type",
+ "status": "Status",
+ "events24h": "Events 24h",
+ "lastSeen": "Last seen"
+ },
+ "time": {
+ "justNow": "just now",
+ "minutesAgo": "{{count}}m ago",
+ "hoursAgo": "{{count}}h ago",
+ "daysAgo": "{{count}}d ago"
+ },
+ "drawer": {
+ "loading": "Loading…",
+ "loadFailed": "Could not load the data source.",
+ "statsIdentity": "Stats & identity",
+ "metadata": "Metadata",
+ "labelsSection": "Labels",
+ "dangerZone": "Danger zone",
+ "rows": {
+ "events24h": "Events 24h",
+ "lastSeen": "Last seen",
+ "discovered": "Discovered",
+ "kind": "Kind",
+ "dataType": "Data type",
+ "ip": "IP",
+ "id": "ID"
+ },
+ "dangerText": "Deleting removes this source from the registry. Historical events stay searchable in the Log Explorer; if the source keeps sending data it will be rediscovered.",
+ "delete": "Delete data source",
+ "confirmDelete": "Confirm delete",
+ "cancel": "Cancel",
+ "viewLogs": "View logs",
+ "trend": "Ingestion trend",
+ "noTrend": "No events received in this window",
+ "logGap": "Last event {{since}} — possible log gap"
+ },
+ "toast": {
+ "labelsUpdated": "Labels updated",
+ "labelsFailed": "Failed to update labels",
+ "deleted": "Data source deleted",
+ "deleteFailed": "Failed to delete"
+ },
+ "console": {
+ "section": "Console",
+ "sectionHint": "Run commands on this host through its agent (live response).",
+ "open": "Open console",
+ "close": "Close",
+ "hint": "Type a command and press Enter to run it on the agent.",
+ "running": "Running…",
+ "placeholder": "Type a command…",
+ "offline": "This agent appears offline — it may not respond to commands.",
+ "vars": {
+ "button": "Variables",
+ "title": "Command variables",
+ "subtitle": "Reference these in commands as",
+ "add": "New variable",
+ "name": "Name",
+ "value": "Value",
+ "description": "Description",
+ "isSecret": "Secret (encrypted, masked in output)",
+ "secret": "secret",
+ "secretHint": "Leave blank to keep the stored value.",
+ "save": "Save",
+ "cancel": "Cancel",
+ "edit": "Edit",
+ "delete": "Delete",
+ "loading": "Loading…",
+ "empty": "No variables yet.",
+ "saved": "Variable saved",
+ "deleted": "Variable deleted",
+ "nameRequired": "Name is required",
+ "loadError": "Failed to load variables",
+ "saveError": "Failed to save variable",
+ "deleteError": "Failed to delete variable",
+ "insert": "Insert",
+ "valueRequired": "A value is required"
+ },
+ "disabled": "Agent offline — commands are disabled",
+ "connError": "Connection error",
+ "cmdError": "Command error",
+ "shellSelect": "Shell type",
+ "noRemoteControl": "This agent was installed with remote control disabled. It refuses commands, and that can only be changed on the machine itself.",
+ "noRemoteControlShort": "Remote control disabled on this agent"
+ },
+ "sensitivity": {
+ "section": "Asset sensitivity",
+ "hint": "Business criticality (CIA, 0–3) of this asset. Alerts targeting its host/IP are weighted by these values.",
+ "saved": "Sensitivity updated",
+ "failed": "Failed to update sensitivity",
+ "save": "Save",
+ "confidentiality": "Confidentiality",
+ "integrity": "Integrity",
+ "availability": "Availability",
+ "levels": {
+ "0": "None",
+ "1": "Low",
+ "2": "Medium",
+ "3": "High"
+ }
+ },
+ "health": {
+ "online": "online",
+ "offline": "offline",
+ "total": "total"
+ }
+ },
+ "adversaries": {
+ "title": "Adversary view",
+ "subtitle": "Every IP, host or user seen attacking your environment, with their techniques and targets.",
+ "countChip": "{{count}} adversaries",
+ "refresh": "Refresh",
+ "search": "Search by IP, host, user, country, ASO…",
+ "empty": "No adversaries match.",
+ "loadError": "Could not load adversaries.",
+ "retry": "Retry",
+ "views": {
+ "all": "All",
+ "high": "High severity",
+ "ip": "IPs",
+ "host": "Hosts",
+ "user": "Users"
+ },
+ "threat": {
+ "critical": "Critical",
+ "high": "High",
+ "medium": "Medium",
+ "low": "Low"
+ },
+ "kind": {
+ "ip": "IP",
+ "host": "Host",
+ "user": "User"
+ },
+ "layout": {
+ "list": "List",
+ "cards": "Cards"
+ },
+ "overview": {
+ "title": "Adversary activity · last 24 hours",
+ "high": "high severity",
+ "countries": "countries",
+ "alerts": "alerts",
+ "ago24": "24h ago",
+ "ago12": "12h ago",
+ "now": "now"
+ },
+ "col": {
+ "adversary": "Adversary",
+ "threat": "Threat",
+ "alerts": "Alerts",
+ "targets": "Targets",
+ "lastSeen": "Last seen",
+ "victims": "Victims"
+ },
+ "card": {
+ "alerts": "Alerts",
+ "techniques": "Techniques",
+ "targets": "Targets"
+ },
+ "tabs": {
+ "profile": "Profile",
+ "techniques": "Techniques",
+ "targets": "Targets",
+ "alerts": "Alerts"
+ },
+ "drawer": {
+ "activity": "Activity over 24 hours",
+ "identification": "Identification",
+ "kindLabel": "Type",
+ "identifier": "Identifier",
+ "firstSeen": "First seen",
+ "lastSeen": "Last seen",
+ "geolocation": "Geolocation",
+ "country": "Country",
+ "city": "City",
+ "topTechniques": "Top techniques",
+ "noTechniques": "No techniques recorded.",
+ "targets": "Targets",
+ "noTargets": "No targets recorded.",
+ "recentAlerts": "Recent alerts",
+ "noAlerts": "No alerts.",
+ "echoes": "{{count}} echoes"
+ },
+ "relative": {
+ "justNow": "just now",
+ "minutesAgo": "{{count}}m ago",
+ "hoursAgo": "{{count}}h ago",
+ "daysAgo": "{{count}}d ago"
+ },
+ "field": {
+ "ip": "IP",
+ "host": "Host",
+ "user": "User",
+ "port": "Port",
+ "domain": "Domain",
+ "mac": "MAC",
+ "country": "Country",
+ "city": "City",
+ "asn": "ASN",
+ "aso": "ASO"
+ }
+ },
+ "timeRange": {
+ "quick": "Quick ranges",
+ "relative": "Relative",
+ "absolute": "Absolute",
+ "last": "Last",
+ "apply": "Apply",
+ "allTime": "All time",
+ "from": "From",
+ "to": "To",
+ "now": "now",
+ "units": {
+ "minutes": "minutes",
+ "hours": "hours",
+ "days": "days",
+ "weeks": "weeks",
+ "months": "months"
+ },
+ "presets": {
+ "15m": "Last 15 minutes",
+ "1h": "Last 1 hour",
+ "6h": "Last 6 hours",
+ "24h": "Last 24 hours",
+ "7d": "Last 7 days",
+ "30d": "Last 30 days"
+ }
+ },
+ "socAi": {
+ "title": "SOC-AI Configuration",
+ "subtitle": "Configure the AI agent that triages alerts and powers the operations assistant.",
+ "section": {
+ "connection": "Model & connection",
+ "auth": "Authentication",
+ "behavior": "Alert triage behavior",
+ "advanced": "Advanced"
+ },
+ "usage": {
+ "title": "Usage",
+ "chat": "Chat completions (today)",
+ "unavailable": "Usage isn't available yet.",
+ "resetsIn": "Resets in {{time}}"
+ },
+ "provider": {
+ "label": "Provider",
+ "hint": "Selects the wire format. Anything other than Anthropic uses the OpenAI-compatible API."
+ },
+ "model": {
+ "label": "Model",
+ "hint": "Model identifier exposed by the provider.",
+ "customOption": "Custom model…",
+ "customPlaceholder": "Enter a model ID"
+ },
+ "url": {
+ "label": "API URL",
+ "hint": "Leave empty to use the provider's default endpoint."
+ },
+ "apiKey": {
+ "label": "API key",
+ "hint": "Credential sent to the provider.",
+ "setHint": "A key is stored. Leave blank to keep it."
+ },
+ "authType": {
+ "label": "Authentication type",
+ "hint": "How credentials are sent to your gateway.",
+ "options": {
+ "apiKey": "API Key",
+ "bearer": "Bearer",
+ "customHeaders": "Custom Headers",
+ "none": "None"
+ }
+ },
+ "authHeaderName": {
+ "label": "Auth header name",
+ "hint": "Header carrying the key (e.g. api-key for Azure)."
+ },
+ "authToken": {
+ "label": "Bearer token",
+ "hint": "Credential sent to the provider.",
+ "setHint": "A token is stored. Leave blank to keep it."
+ },
+ "customHeaders": {
+ "label": "Custom headers",
+ "hint": "Extra headers sent with every request. Values are encrypted; \"*****\" keeps the stored one.",
+ "keyPlaceholder": "Header name",
+ "valuePlaceholder": "Value",
+ "addRow": "Add header",
+ "remove": "Remove header"
+ },
+ "maxTokens": {
+ "label": "Max tokens",
+ "hint": "Maximum tokens per LLM response."
+ },
+ "maxToolIterations": {
+ "label": "Max tool iterations",
+ "hint": "Cap on the agent's plan -> tool -> observe loop."
+ },
+ "autoAnalyze": {
+ "label": "Auto-analyze alerts",
+ "hint": "Triage incoming alerts in real time."
+ },
+ "allowIncidents": {
+ "label": "Allow managing incidents",
+ "hint": "The triage agent may create or update incidents when it decides an alert warrants one."
+ },
+ "changeAlertStatus": {
+ "label": "Change alert status",
+ "hint": "Let the agent set an alert's status during triage."
+ },
+ "automaticIncidentCreation": {
+ "label": "Create incidents",
+ "hint": "Let the agent open incidents from triaged alerts."
+ },
+ "allowedWriteTools": {
+ "label": "Allowed write tools",
+ "hint": "One MCP tool name per line the triage agent may use (e.g. alerts.update_status). Notes are always allowed."
+ },
+ "save": "Save configuration",
+ "saving": "Verifying & saving...",
+ "saved": "SOC-AI configuration saved",
+ "saveError": "Failed to save configuration",
+ "loadError": "Failed to load configuration",
+ "modelRequired": "Model is required",
+ "applyTags": {
+ "label": "Apply tags",
+ "hint": "Let the agent tag alerts during triage."
+ },
+ "note": {
+ "azure": "Paste your full Azure deployment endpoint as the URL; the model is your deployment name. Auth uses the api-key header.",
+ "ollama": "Point the URL at your Ollama host. No API key is needed for a local instance.",
+ "custom": "Any OpenAI-compatible endpoint. Set the URL, auth and any extra headers your gateway needs.",
+ "threatwinds": "Uses your UTMStack license automatically — no API key needed. Billed through your ThreatWinds subscription."
+ },
+ "chat": {
+ "title": "SOC Assistant",
+ "dashboardCreateTitle": "Dashboard builder",
+ "empty": "Ask anything about your alerts, detections or the console — I can investigate and act on the SIEM.",
+ "tryPrefix": "Try",
+ "suggestion": "how many open alerts, grouped by adversary?",
+ "placeholder": "Ask a question…",
+ "ask": "Ask",
+ "send": "Send",
+ "collapse": "Collapse",
+ "expand": "Expand",
+ "clear": "Clear conversation",
+ "close": "Close",
+ "copy": "Copy",
+ "copied": "Copied",
+ "errorGeneric": "Something went wrong.",
+ "errorUnreachable": "Failed to reach the assistant.",
+ "compacting": "Compacting context…",
+ "dashboardEditTitle": "Dashboard editor",
+ "editingDashboard": "Editing: {{name}}",
+ "soarEditTitle": "SOAR flow editor",
+ "soarCreateTitle": "Create SOAR flow",
+ "editingFlow": "Editing flow: {{name}}"
+ },
+ "focus": {
+ "alert": "Alert",
+ "incident": "Incident",
+ "remove": "Stop sharing with the assistant"
+ },
+ "inheritance": {
+ "inherited": "Following the instance default. Saving here gives this tenant its own configuration.",
+ "own": "This tenant has its own configuration.",
+ "revert": "Follow the instance default",
+ "reverting": "Reverting…",
+ "reverted": "Now following the instance default"
+ },
+ "allowance": {
+ "title": "AI allowance today",
+ "ofLimit": "of {{limit}} requests",
+ "denied": "requests — the AI is not available to this tenant",
+ "hint": "Set by whoever runs the instance. It resets at midnight UTC."
+ }
+ },
+ "alerts": {
+ "title": "Alerts",
+ "matching": "{{count}} matching",
+ "subtitle": "Triage what matters.",
+ "openNow": "open right now.",
+ "view": {
+ "alerts": "Alerts",
+ "overview": "Overview"
+ },
+ "toolbar": {
+ "searchPlaceholder": "Search by alert name…",
+ "allSeverities": "All severities",
+ "export": "Export CSV",
+ "refresh": "Refresh"
+ },
+ "severity": {
+ "high": "High",
+ "medium": "Medium",
+ "low": "Low"
+ },
+ "status": {
+ "open": "Open",
+ "in_review": "In review",
+ "completed": "Completed",
+ "auto": "Automatic review"
+ },
+ "statusTabs": {
+ "all": "All"
+ },
+ "overview": {
+ "overTime": "Alerts over time",
+ "matchingAlerts": "matching alerts",
+ "noData": "No data.",
+ "bySeverity": "By severity",
+ "byStatus": "By status"
+ },
+ "filters": {
+ "add": "Add filter",
+ "clearAll": "Clear all",
+ "filterValues": "Filter values…",
+ "loadingValues": "Loading values…",
+ "noValues": "No values found.",
+ "pickValue": "Pick a value to add the filter.",
+ "empty": "(empty)",
+ "cancel": "Cancel",
+ "addBtn": "Add"
+ },
+ "ops": {
+ "CONTAIN": "contains",
+ "IS": "is",
+ "IS_NOT": "is not",
+ "EXIST": "exists",
+ "DOES_NOT_EXIST": "does not exist"
+ },
+ "fields": {
+ "adversary_domain": "Adversary domain",
+ "adversary_geolocation_asn": "Adversary ASN",
+ "adversary_geolocation_aso": "Adversary ASO",
+ "adversary_geolocation_country": "Adversary country",
+ "adversary_host": "Adversary host",
+ "adversary_ip": "Adversary IP",
+ "adversary_url": "Adversary URL",
+ "adversary_user": "Adversary user",
+ "assignee": "Assignee",
+ "category": "Category",
+ "dataSource": "Sensor",
+ "dataType": "Data type",
+ "description": "Description",
+ "id": "ID",
+ "impactScore": "Risk",
+ "impact_availability": "Availability",
+ "impact_confidentiality": "Confidentiality",
+ "impact_integrity": "Integrity",
+ "incidentDetail_incidentName": "Incident name",
+ "incidentDetail_incidentId": "Incident id",
+ "isIncident": "Is incident",
+ "name": "Alert name",
+ "notes": "Notes",
+ "severity": "Severity",
+ "status": "Status",
+ "tags": "Tags",
+ "target_domain": "Target domain",
+ "target_geolocation_asn": "Target ASN",
+ "target_geolocation_aso": "Target ASO",
+ "target_geolocation_country": "Target country",
+ "target_host": "Target host",
+ "target_ip": "Target IP",
+ "target_url": "Target URL",
+ "target_user": "Target user",
+ "technique": "Technique"
+ },
+ "tagFilter": {
+ "tags": "Tags",
+ "tag_one": "{{count}} tag",
+ "tag_other": "{{count}} tags",
+ "clearSelection": "Clear selection",
+ "noTags": "No tags"
+ },
+ "bulk": {
+ "selected": "{{count}} selected",
+ "setStatus": "Set status",
+ "addTag": "Add tag",
+ "noTags": "No tags",
+ "addToIncident": "Add to incident",
+ "clear": "Clear"
+ },
+ "tagEditor": {
+ "tag": "Tag",
+ "noTagsYet": "No tags yet",
+ "createTag": "Create tag",
+ "newTagName": "New tag name…",
+ "createApply": "Create and apply tag",
+ "save": "Save",
+ "cancel": "Cancel",
+ "edit": "Edit tag",
+ "delete": "Delete tag",
+ "createRule": "Create tagging rule with this tag",
+ "systemLocked": "System tag (locked)",
+ "alreadyExists": "That tag already exists.",
+ "color": "Color {{color}}"
+ },
+ "table": {
+ "actions": "Actions",
+ "alert": "Alert",
+ "status": "Status",
+ "technique": "Technique",
+ "severity": "Severity",
+ "risk": "Risk",
+ "echoes": "Echoes",
+ "time": "Time",
+ "riskHint": "Risk score (0–100), colored by severity",
+ "source": "Source",
+ "adversary": "Adversary"
+ },
+ "row": {
+ "createRuleFromAlert": "Create a tag from this alert",
+ "createIncident": "Create incident from this alert",
+ "viewIncident": "View incident details",
+ "assignedTo": "Assigned to {{user}}",
+ "echoesTooltip": "{{count}} echoes — click to expand",
+ "echoesEmpty": "No echoes recorded"
+ },
+ "echoes": {
+ "title": "{{count}} echoes",
+ "close": "Close",
+ "empty": "No echoes recorded for this alert.",
+ "loadError": "Could not load echoes."
+ },
+ "list": {
+ "loading": "Loading alerts…",
+ "loadError": "Could not load alerts.",
+ "retry": "Retry",
+ "empty": "No alerts match this view."
+ },
+ "badge": {
+ "incident": "Incident",
+ "aiAssessed": "AI assessed"
+ },
+ "drawer": {
+ "setStatus": "Set status",
+ "completeFalsePositive": "Complete + false positive",
+ "addToIncident": "Add to incident",
+ "partOfIncident": "Part of an incident",
+ "tabs": {
+ "summary": "Summary",
+ "parties": "Parties",
+ "events": "Events",
+ "history": "History"
+ },
+ "section": {
+ "description": "Description",
+ "solution": "Solution",
+ "references": "References",
+ "details": "Details",
+ "yourNotes": "Your notes",
+ "notes": "Notes"
+ },
+ "details": {
+ "severity": "Severity",
+ "risk": "Risk",
+ "category": "Category",
+ "technique": "Technique",
+ "sensor": "Sensor",
+ "dataType": "Data type",
+ "alertId": "Alert ID",
+ "statusNote": "Status note",
+ "assignee": "Assignee"
+ },
+ "incidentDetail": {
+ "incident": "Incident",
+ "id": "ID",
+ "createdBy": "Created by",
+ "created": "Created"
+ },
+ "notesPlaceholder": "Add investigation notes…",
+ "saveNotes": "Save notes",
+ "assignee": "Assign",
+ "assign": "Assign",
+ "unassign": "Unassign",
+ "unassigned": "Unassigned",
+ "loadingUsers": "Loading users…",
+ "observationLabel": "Observation",
+ "observationPlaceholder": "Add an observation…",
+ "cancel": "Cancel",
+ "continue": "Continue"
+ },
+ "related": {
+ "sample": "A sample of up to ~11 events the engine stored on this alert. Use “View all related logs” for the full, uncapped set.",
+ "loadingEchoes": "Loading the events of its echoes…",
+ "sampleWithEchoes": "The events stored on this alert and on its {{count}} echoes ({{read}} read). Use “View all related logs” for the full, uncapped set.",
+ "empty": "No sampled events stored on this alert. Load the full correlated set in the Log Explorer.",
+ "viewAll": "View all related logs"
+ },
+ "party": {
+ "source": "Source / target",
+ "adversary": "Adversary",
+ "noData": "No data.",
+ "ip": "IP",
+ "host": "Host",
+ "user": "User",
+ "domain": "Domain",
+ "country": "Country"
+ },
+ "history": {
+ "empty": "No history recorded.",
+ "by": "by {{user}}",
+ "actions": {
+ "UPDATE_STATUS": "Status updated",
+ "UPDATE_TAGS": "Tags updated",
+ "UPDATE_NOTES": "Notes updated",
+ "UPDATE_SOLUTION": "Solution updated",
+ "MARK_AS_INCIDENT": "Marked as incident"
+ },
+ "detail": {
+ "statusTo": "Status → {{status}}",
+ "tags": "Tags: {{tags}}",
+ "aiAdded": "AI assessment added",
+ "observationAdded": "Observation added",
+ "notesUpdated": "Notes updated"
+ }
+ },
+ "ai": {
+ "title": "SOC AI assessment",
+ "risk": "{{risk}} risk",
+ "score": "{{score}}/100",
+ "generate": "Generate AI summary",
+ "hint": "SOC-AI investigates this alert and adds an assessment.",
+ "generating": "Analyzing the alert… this can take a minute.",
+ "ready": "AI summary ready",
+ "failed": "Could not generate the AI summary",
+ "slow": "The AI summary is taking longer than expected. It will show up on the alert when it is ready."
+ },
+ "incident": {
+ "titleAdd_one": "Add {{count}} alert to an incident",
+ "titleAdd_other": "Add {{count}} alerts to an incident",
+ "new": "New incident",
+ "existing": "Existing incident",
+ "nameLabel": "Incident name",
+ "namePlaceholder": "e.g. Suspected Scattered Spider intrusion",
+ "descriptionLabel": "Description",
+ "descriptionPlaceholder": "Optional summary…",
+ "pickLabel": "Pick an incident",
+ "loading": "Loading…",
+ "selectPlaceholder": "Select an incident…",
+ "willLink_one": "{{count}} alert will be linked.",
+ "willLink_other": "{{count}} alerts will be linked.",
+ "cancel": "Cancel",
+ "create": "Create incident",
+ "add": "Add to incident"
+ },
+ "toast": {
+ "statusUpdated": "Status updated",
+ "statusFailed": "Failed to update status",
+ "tagsUpdated": "Tags updated",
+ "tagsFailed": "Failed to update tags",
+ "tagCreateFailed": "Failed to create tag",
+ "tagUpdated": "Tag updated",
+ "tagUpdateFailed": "Failed to update tag",
+ "tagDeleted": "Tag deleted",
+ "tagDeleteFailed": "Failed to delete tag",
+ "notesSaved": "Notes saved",
+ "notesFailed": "Failed to save notes",
+ "exportFailed": "Failed to export CSV",
+ "noRelatedLogs": "No related logs found for this alert",
+ "relatedLogsFailed": "Failed to load related logs",
+ "incidentCreated": "Incident created",
+ "alertsAdded": "Alerts added to incident",
+ "incidentFailed": "Failed to save incident",
+ "assigned": "Alert assigned",
+ "unassigned": "Alert unassigned",
+ "assignFailed": "Could not update assignee"
+ }
+ },
+ "taggingRules": {
+ "title": "Tagging Rules",
+ "subtitle": "Automatically tag alerts that match conditions.",
+ "new": "New rule",
+ "refresh": "Refresh",
+ "empty": "No tagging rules yet.",
+ "loadError": "Could not load tagging rules.",
+ "retry": "Retry",
+ "deleteConfirm": "Delete the rule \"{{name}}\"? Future alerts matching its conditions will stop being tagged.",
+ "toolbar": {
+ "search": "Search by rule name…",
+ "allTags": "All tags"
+ },
+ "table": {
+ "rule": "Rule",
+ "tags": "Tags",
+ "conditions": "Conditions",
+ "modifiedBy": "Modified by",
+ "modifiedDate": "Modified"
+ },
+ "drawer": {
+ "createTitle": "New tagging rule",
+ "edit": "Edit",
+ "delete": "Delete",
+ "save": "Save",
+ "create": "Create",
+ "cancel": "Cancel"
+ },
+ "form": {
+ "basics": "Basics",
+ "name": "Rule name",
+ "namePlaceholder": "e.g. Internal SSH brute-force",
+ "description": "Description",
+ "descriptionPlaceholder": "Why this rule exists and what it tags.",
+ "tags": "Tags to apply",
+ "noTags": "No tags selected.",
+ "addTag": "Add tag",
+ "removeTag": "Remove",
+ "noCatalog": "No tags in the catalog yet.",
+ "createTag": "Create tag",
+ "newTagName": "New tag name",
+ "conditions": "Conditions (ALL must match)",
+ "noConditions": "At least one condition is required.",
+ "addCondition": "Add condition",
+ "removeCondition": "Remove condition",
+ "valuePlaceholder": "Value",
+ "valueListPlaceholder": "Comma-separated values",
+ "incomplete": "Fill in the rule name, description, at least one tag and complete every condition."
+ },
+ "view": {
+ "description": "Description",
+ "tags": "Tags",
+ "conditions": "Conditions",
+ "audit": "Audit",
+ "createdBy": "Created by",
+ "createdDate": "Created",
+ "modifiedBy": "Modified by",
+ "modifiedDate": "Modified"
+ },
+ "toast": {
+ "created": "Rule \"{{name}}\" created.",
+ "updated": "Rule \"{{name}}\" updated.",
+ "deleted": "Rule \"{{name}}\" deleted.",
+ "createError": "Failed to create rule.",
+ "updateError": "Failed to update rule.",
+ "deleteError": "Failed to delete rule."
+ },
+ "deleteTitle": "Delete tagging rule"
+ },
+ "incidents": {
+ "title": "Incidents",
+ "subtitle": "Group, triage and resolve related alerts as incidents.",
+ "refresh": "Refresh",
+ "count_one": "{{count}} incident",
+ "count_other": "{{count}} incidents",
+ "openNow": "open now",
+ "empty": "No incidents match.",
+ "loadError": "Could not load incidents.",
+ "retry": "Retry",
+ "unassigned": "Unassigned",
+ "unknownUser": "Unknown",
+ "status": {
+ "open": "Open",
+ "in_review": "In review",
+ "completed": "Completed",
+ "merged": "Merged"
+ },
+ "sev": {
+ "high": "High",
+ "medium": "Medium",
+ "low": "Low",
+ "unknown": "Unrated"
+ },
+ "toolbar": {
+ "search": "Search incidents…",
+ "create": "Create incident",
+ "allSeverities": "All severities",
+ "export": "Export CSV"
+ },
+ "statusTabs": {
+ "all": "All"
+ },
+ "filters": {
+ "add": "Add filter",
+ "clearAll": "Clear all",
+ "filterValues": "Filter values…",
+ "loadingValues": "Loading values…",
+ "noValues": "No values found.",
+ "pickValue": "Pick a value to add the filter.",
+ "empty": "(empty)",
+ "cancel": "Cancel",
+ "addBtn": "Add"
+ },
+ "ops": {
+ "IS": "is"
+ },
+ "create": {
+ "title": "Create incident",
+ "stepIndicator": "Step {{current}} of {{total}}",
+ "selectedCount": "{{count}} alerts selected",
+ "submit": "Create",
+ "success": "Incident created",
+ "error": "Could not create the incident",
+ "details": {
+ "nameLabel": "Name",
+ "namePlaceholder": "Short, descriptive title",
+ "descriptionLabel": "Description",
+ "descriptionPlaceholder": "Context, scope, initial notes…"
+ }
+ },
+ "layout": {
+ "table": "Table",
+ "board": "Board"
+ },
+ "table": {
+ "name": "Incident",
+ "status": "Status",
+ "severity": "Severity",
+ "assignee": "Assignee",
+ "alerts": "Alerts",
+ "created": "Created"
+ },
+ "drawer": {
+ "created": "Created {{date}}",
+ "alertsCount": "{{count}} alerts",
+ "solutionPlaceholder": "Resolution / remediation notes…",
+ "solutionHint": "Saved when you move the incident to Completed.",
+ "tabs": {
+ "overview": "Overview",
+ "alerts": "Alerts",
+ "notes": "Notes",
+ "history": "History"
+ },
+ "section": {
+ "description": "Description",
+ "solution": "Solution",
+ "details": "Details"
+ },
+ "details": {
+ "id": "ID",
+ "status": "Status",
+ "severity": "Severity",
+ "assignee": "Assignee",
+ "created": "Created",
+ "alerts": "Linked alerts"
+ }
+ },
+ "alerts": {
+ "empty": "No alerts linked to this incident.",
+ "remove": "Unlink alert",
+ "removeConfirm": "Unlink “{{name}}” from this incident?",
+ "removed": "Alert unlinked",
+ "removeError": "Could not unlink the alert",
+ "loadingAlert": "Loading alert…",
+ "alertGone": "This alert is no longer in the store — retention may have dropped it.",
+ "alertFailed": "Could not load the alert.",
+ "openInAlerts": "Open in Alerts"
+ },
+ "notes": {
+ "empty": "No notes yet.",
+ "add": "Add note",
+ "addError": "Could not add the note",
+ "placeholder": "Write a note…"
+ },
+ "history": {
+ "empty": "No history yet."
+ },
+ "toast": {
+ "statusChanged": "Incident status updated",
+ "statusError": "Could not change the status",
+ "exportFailed": "Failed to export CSV"
+ },
+ "assign": {
+ "assign": "Assign",
+ "search": "Search users…",
+ "unassign": "Unassign",
+ "noUsers": "No users",
+ "assigned": "Assigned to {{user}}",
+ "unassigned": "Incident unassigned",
+ "error": "Could not change the assignee",
+ "custom": "Assign custom",
+ "customPlaceholder": "Type a login…"
+ },
+ "action": {
+ "INCIDENT_CREATED": "Incident created",
+ "INCIDENT_ALERT_ADD": "Alerts added",
+ "INCIDENT_ALERT_STATUS_CHANGED": "Alert status changed",
+ "INCIDENT_STATUS_CHANGE": "Status changed",
+ "INCIDENT_NOTE_ADD": "Note added",
+ "INCIDENT_NOTE_CHANGE": "Note edited",
+ "INCIDENT_ASSIGNED": "Assignee changed"
+ }
+ },
+ "parsingFilters": {
+ "title": "Pipelines",
+ "subtitle": "YAML pipelines applied to logs as they're parsed during ingestion.",
+ "new": "New pipeline",
+ "search": "Search pipelines…",
+ "refresh": "Refresh",
+ "view": "View",
+ "system": "System",
+ "user": "Custom",
+ "loading": "Loading pipelines…",
+ "loadError": "Could not load pipelines.",
+ "retry": "Retry",
+ "empty": "No pipelines match this view.",
+ "tabs": {
+ "all": "All",
+ "active": "Active",
+ "inactive": "Inactive",
+ "system": "System",
+ "user": "Custom"
+ },
+ "cols": {
+ "filter": "Pipeline",
+ "type": "Type",
+ "active": "Active",
+ "dataTypes": "Data types",
+ "order": "Order",
+ "moveUp": "Move up",
+ "moveDown": "Move down",
+ "actions": "Actions"
+ },
+ "editor": {
+ "titleNew": "New pipeline",
+ "titleEdit": "Edit pipeline",
+ "titleSystem": "Pipeline (system)",
+ "name": "Name",
+ "namePlaceholder": "My custom pipeline",
+ "nameHint": "Will be saved as {{file}}",
+ "namePending": "Pick a name — it will become the filename.",
+ "content": "Content (pipeline YAML)",
+ "contentHint": "A valid pipeline: YAML definition.",
+ "readOnly": "System pipeline — read-only. You can only enable or disable it.",
+ "test": "Test",
+ "save": "Save",
+ "saving": "Saving…",
+ "delete": "Delete",
+ "confirmDelete": "Confirm delete",
+ "cancel": "Cancel"
+ },
+ "toast": {
+ "saved": "Pipeline saved",
+ "saveError": "Failed to save pipeline",
+ "deleted": "Pipeline deleted",
+ "deleteError": "Failed to delete pipeline",
+ "activateError": "Failed to change pipeline state",
+ "nameRequired": "Name is required",
+ "contentRequired": "Content is required",
+ "orderError": "Failed to reorder pipeline"
+ },
+ "visual": {
+ "visualTab": "Visual",
+ "codeTab": "Code",
+ "codeOnly": "Switch to Code — this content can't be shown visually.",
+ "cantParse": "Can't open the visual editor: {{error}}",
+ "dataTypes": "Data types",
+ "steps": "Steps",
+ "noSteps": "No steps yet.",
+ "addStep": "Add step:",
+ "removeStep": "Remove step",
+ "moveUp": "Move up",
+ "moveDown": "Move down",
+ "whereHint": "optional condition (CEL)",
+ "addValue": "Add value",
+ "addPattern": "Add pattern",
+ "rawHint": "This processor is edited as raw YAML.",
+ "rawNotMap": "Must be a set of key: value fields.",
+ "dataTypesPick": "Choose data types",
+ "dataTypesSearch": "Search data types…",
+ "dataTypesNone": "No data types",
+ "dataTypesAdd": "Add \"{{value}}\"",
+ "insertPattern": "Insert regex pattern",
+ "patternSearch": "Search patterns…",
+ "patternNone": "No patterns",
+ "newPattern": "New pattern…",
+ "createInsert": "Create & insert",
+ "patternCreated": "Pattern \"{{name}}\" created",
+ "patternCreateError": "Failed to create pattern",
+ "patternIdInvalid": "Pattern ID must start with a letter or _ and use only letters, digits or _",
+ "patternDefRequired": "Definition is required",
+ "parameters": "Parameters",
+ "paramsKey": "Key",
+ "paramsValue": "Value",
+ "entry": "Entry {{n}}",
+ "order": "order {{n}}",
+ "orderLabel": "Order",
+ "removeEntry": "Remove entry",
+ "addEntry": "Add pipeline entry",
+ "collapse": "Collapse",
+ "expand": "Expand"
+ },
+ "allDataTypes": "All data types",
+ "testPipeline": "Test pipeline"
+ },
+ "playground": {
+ "titleFilter": "Test pipeline",
+ "titleRule": "Test rule",
+ "noDataTypes": "This pipeline has no data types assigned yet — add one to test it.",
+ "dataTypeLabel": "Data type",
+ "dataTypePlaceholder": "No data types available",
+ "dataTypeSingleHint": "This pipeline only has one data type — add more to choose between them.",
+ "rawLogLabel": "Raw log",
+ "rawLogPlaceholder": "Paste a sample raw log line…",
+ "rawLogCounter": "{{chars}} chars · {{kb}} KB",
+ "rawLogTooLarge": "This log exceeds the 1 MB limit — trim it before running the test.",
+ "run": {
+ "label": "Run",
+ "running": "Testing…",
+ "waitHint": "This can take up to 15 seconds while the pipeline processes the log."
+ },
+ "errors": {
+ "busy": "The playground is busy running another test — please try again shortly.",
+ "timeout": "The test timed out — this usually means the selected data type doesn't match the log format.",
+ "validation": "The request was invalid — check the raw log and pipeline content.",
+ "server": "The playground couldn't complete the test — please try again."
+ },
+ "notices": {
+ "geo": "The geolocation plugin isn't available in this lite version of the filter and rule test.",
+ "correlation": "Rules that reference prior events through afterEvent or correlation clauses require matching historical events to already exist in the system for the tested alert to trigger."
+ },
+ "result": {
+ "label": "Parsed result",
+ "empty": "Run a test to see the parsed event here.",
+ "loading": "Waiting for the parsed event…",
+ "tabs": {
+ "fields": "Fields",
+ "json": "JSON"
+ },
+ "fieldsCount_one": "{{count}} field",
+ "fieldsCount_other": "{{count}} fields",
+ "copy": "Copy",
+ "copied": "Copied",
+ "elapsed": "Parsed in {{time}}",
+ "elapsedHint": "Time from Run to the parsed result",
+ "searchPlaceholder": "Search fields…",
+ "noMatch": "No fields match your search."
"socAi": {
"title": "SOC-AI Configuration",
"subtitle": "Configure the AI agent that triages alerts and powers the operations assistant.",
diff --git a/frontend/src/shared/i18n/locales/es.json b/frontend/src/shared/i18n/locales/es.json
index 724c2c0e3..6b08b5023 100644
--- a/frontend/src/shared/i18n/locales/es.json
+++ b/frontend/src/shared/i18n/locales/es.json
@@ -4266,6 +4266,1815 @@
"hint": "Lo fija quien opera la instancia. Se reinicia a medianoche UTC."
}
},
+ "tabs": {
+ "dashboards": "Tableros",
+ "visualizations": "Widgets",
+ "newDashboard": "Nuevo tablero",
+ "unsetDefault": "Quitar predeterminado",
+ "options": "Opciones"
+ },
+ "picker": {
+ "none": "Seleccionar tablero",
+ "search": "Buscar tableros…",
+ "new": "Nuevo tablero",
+ "setDefault": "Marcar como predeterminado",
+ "empty": "Sin tableros"
+ },
+ "empty": {
+ "title": "Aún no hay tableros",
+ "body": "Crea tu primer tablero para ver tus datos de seguridad de un vistazo.",
+ "cta": "Crear tablero"
+ },
+ "filters": {
+ "addTitle": "Añadir filtro",
+ "editTitle": "Editar filtro",
+ "removeTitle": "Eliminar filtro",
+ "removeConfirm": "¿Eliminar el filtro \"{{label}}\"? Esta acción no se puede deshacer.",
+ "remove": "Eliminar",
+ "editAria": "Editar filtro",
+ "removeAria": "Eliminar filtro",
+ "saving": "Guardando…",
+ "addChip": "Añadir filtro",
+ "chooseValue": "Choose…",
+ "selected": "selected",
+ "loading": "Loading values…",
+ "searchPlaceholder": "Search values…",
+ "noValues": "No values available.",
+ "loadError": "Could not load values.",
+ "clear": "Clear",
+ "editorTitle": "Dashboard filters",
+ "editorHint": "Add dropdown chips that filter every widget on this dashboard.",
+ "emptyEditor": "No filter chips yet. Add one to get started.",
+ "cancel": "Cancel",
+ "save": "Save",
+ "field": {
+ "dataset": "Data set",
+ "field": "Field",
+ "chooseField": "Choose a field…",
+ "label": "Label",
+ "labelPlaceholder": "e.g. Host",
+ "placeholder": "Placeholder",
+ "placeholderPlaceholder": "e.g. Pick a host",
+ "multiple": "Multiple",
+ "searchable": "Searchable"
+ }
+ },
+ "duplicate": {
+ "copyName": "{{name}} (copia)"
+ }
+ },
+ "settings": {
+ "title": "Configuración",
+ "license": "Licencia",
+ "notifications": "Notificaciones",
+ "connectionKey": "Clave de conexión",
+ "dataRetention": "Retención de datos",
+ "indices": "Índices",
+ "theme": "Tema",
+ "branding": "Marca",
+ "apiKeys": "Claves API",
+ "identityProviders": "Proveedores de identidad",
+ "email": "Configuración de correo",
+ "dateFormat": "Formato de fecha",
+ "language": "Idioma",
+ "auditLogs": "Registros de auditoría",
+ "about": "Acerca de",
+ "socAi": "SOC-AI",
+ "supportAccess": "Acceso de soporte",
+ "threatwinds": "Integración de ThreatWinds"
+ },
+ "topbar": {
+ "theme": {
+ "light": "Modo claro",
+ "dark": "Modo oscuro"
+ },
+ "manageLicense": "Gestionar licencia",
+ "profile": {
+ "profile": "Perfil",
+ "license": "Licencia",
+ "logout": "Cerrar sesión"
+ }
+ },
+ "notifications": {
+ "title": "Notificaciones",
+ "markAllRead": "Marcar todas como leídas",
+ "empty": "No tienes notificaciones.",
+ "viewAll": "Ver todas",
+ "markRead": "Marcar como leída",
+ "markUnread": "Marcar como no leída",
+ "delete": "Eliminar",
+ "subtitle": "{{total}} en total · {{unread}} sin leer",
+ "allCaughtUp": "Todo al día.",
+ "loadFailed": "No se pudieron cargar las notificaciones."
+ },
+ "pagination": {
+ "perPage": "Por página",
+ "pageOf": "Página {{page}} de {{total}}",
+ "previous": "Anterior",
+ "next": "Siguiente"
+ },
+ "license": {
+ "title": "Licencia",
+ "subtitle": "Tu edición, capacidades y archivo de licencia.",
+ "loading": "Cargando licencia…",
+ "loadError": "No se pudo cargar la información de la licencia.",
+ "statusLabel": "Estado",
+ "status": {
+ "community": "Community",
+ "active": "Activa",
+ "expiring": "Por expirar",
+ "expired": "Expirada"
+ },
+ "edition": "Edición",
+ "enterprise": "Enterprise",
+ "community": "Community",
+ "editionLine": "Edición {{edition}}",
+ "datasourceLimit": "Límite de datasources",
+ "unlimited": "Ilimitado",
+ "mssp": "MSSP / multi-tenant",
+ "enabled": "Activado",
+ "licenseType": "Tipo de licencia",
+ "instanceId": "ID de instancia",
+ "enterpriseUnlocked": "Funciones Enterprise desbloqueadas",
+ "validUntil": "Válida hasta",
+ "noExpiry": "Sin expiración",
+ "timeRemaining": "Tiempo restante",
+ "expiredAgo": "Expiró hace {{days}}d",
+ "daysShort": "{{days}}d",
+ "msspShort": "MSSP",
+ "communityEdition": "Edición Community",
+ "communityBlurb": "Gratuita y de código abierto. Sube una licencia Enterprise abajo para desbloquear multi-tenancy, SSO, mayores límites de datasources y cumplimiento avanzado.",
+ "upgrade": "Actualizar a Enterprise",
+ "uploadTitle": "Subir una licencia",
+ "uploadBlurb": "Instala o reemplaza el archivo LICENSE firmado. El servidor valida la firma y la expiración antes de aplicarlo. Solo admin.",
+ "installLicense": "Instalar licencia",
+ "chooseFile": "Seleccionar archivo",
+ "noFileSelected": "Ningún archivo seleccionado",
+ "toast": {
+ "installed": "Licencia instalada — edición {{edition}}.",
+ "adminRequired": "Se requieren privilegios de administrador para subir una licencia.",
+ "invalid": "Archivo de licencia inválido o expirado.",
+ "installFailed": "No se pudo instalar la licencia."
+ },
+ "ingestLimit": "Volumen de ingesta",
+ "notMetered": "Sin medición",
+ "gbPerMonth": "{{gb}} GB/mes"
+ },
+ "audit": {
+ "title": "Registro de auditoría",
+ "subtitle": "Registro de cada acción relevante para la seguridad.",
+ "totalEntries": "{{total}} entradas en total.",
+ "loadError": "No se pudo cargar el registro de auditoría",
+ "stats": {
+ "totalEntries": "Entradas totales",
+ "acrossAllTime": "De todo el tiempo",
+ "successRate": "Tasa de éxito",
+ "failuresOnPage_one": "{{count}} fallo en esta página",
+ "failuresOnPage_other": "{{count}} fallos en esta página",
+ "topAction": "Acción principal",
+ "onPage": "{{count}} en esta página",
+ "uniqueActors": "Actores únicos",
+ "includingSystem": "Incluyendo el sistema"
+ },
+ "filters": {
+ "title": "Filtros",
+ "clear": "Limpiar",
+ "last24h": "Últimas 24h",
+ "failuresOnly": "Solo fallos",
+ "authEvents": "Eventos de autenticación",
+ "actionPrefix": "Prefijo de acción",
+ "actionPlaceholder": "p.ej. auth., user.update",
+ "status": "Estado",
+ "any": "Cualquiera",
+ "resourceType": "Tipo de recurso",
+ "resourceTypePlaceholder": "user, alert…",
+ "resourceId": "ID de recurso",
+ "user": "Usuario",
+ "userPlaceholder": "login…"
+ },
+ "statusValue": {
+ "success": "Éxito",
+ "failure": "Fallo"
+ },
+ "table": {
+ "timestamp": "Fecha y hora",
+ "actor": "Actor",
+ "action": "Acción",
+ "resource": "Recurso",
+ "status": "Estado",
+ "ip": "IP",
+ "loading": "Cargando…",
+ "emptyTitle": "Ninguna entrada coincide con estos filtros.",
+ "emptyHint": "Prueba a limpiar los filtros o ampliar el rango de fechas.",
+ "system": "sistema",
+ "view": "Ver"
+ },
+ "drawer": {
+ "entry": "entrada #{{id}}",
+ "overview": "Resumen",
+ "raw": "JSON crudo",
+ "error": "Error",
+ "actor": "Actor",
+ "resource": "Recurso",
+ "ip": "IP",
+ "userAgent": "Agente de usuario",
+ "session": "Sesión",
+ "metadata": "Metadatos",
+ "copy": "Copiar",
+ "copied": "Copiado",
+ "copyJson": "Copiar JSON"
+ }
+ },
+ "team": {
+ "title": "Equipo",
+ "subtitle": "Gestiona los usuarios y sus roles.",
+ "tabs": {
+ "members": "Miembros",
+ "roles": "Roles y permisos"
+ },
+ "toast": {
+ "rolesLoadFailed": "No se pudieron cargar los roles",
+ "userLoadFailed": "No se pudo cargar el usuario",
+ "rolesUpdated": "Roles actualizados",
+ "userReactivated": "Usuario reactivado",
+ "userDeactivated": "Usuario desactivado",
+ "tfaReset": "Autenticación en dos pasos restablecida",
+ "invitationSent": "Invitación enviada",
+ "loginOrEmailInUse": "Ese usuario o correo ya está en uso",
+ "invalidRequest": "Solicitud inválida",
+ "noPermission": "No tienes permiso para hacer eso",
+ "userNotFound": "Usuario no encontrado",
+ "operationFailed": "La operación falló",
+ "emailInUse": "Ese correo ya está en uso",
+ "roleCreated": "Rol creado",
+ "roleUpdated": "Rol actualizado",
+ "roleDeleted": "Rol eliminado",
+ "roleNameInUse": "Ya existe un rol con ese identificador",
+ "roleImmutable": "Los roles del sistema no se pueden modificar",
+ "permissionsLoadFailed": "No se pudieron cargar los permisos",
+ "localUserCreated": "Usuario local creado"
+ },
+ "members": {
+ "searchPlaceholder": "Buscar por nombre o correo…",
+ "invite": "Invitar usuario",
+ "colUser": "Usuario",
+ "colRoles": "Roles",
+ "col2fa": "2FA",
+ "colStatus": "Estado",
+ "loading": "Cargando usuarios…",
+ "loadFailed": "No se pudieron cargar los usuarios.",
+ "retry": "Reintentar",
+ "noSearchMatch": "Ningún usuario coincide con tu búsqueda.",
+ "none": "Aún no hay usuarios.",
+ "noRole": "ninguno",
+ "on": "Sí",
+ "off": "No",
+ "countLabel_one": "{{count}} usuario · página {{page}} de {{pages}}",
+ "countLabel_other": "{{count}} usuarios · página {{page}} de {{pages}}",
+ "federated": "SSO"
+ },
+ "status": {
+ "inactive": "Inactivo",
+ "pendingPassword": "Contraseña pendiente",
+ "active": "Activo",
+ "pending": "Invitación pendiente",
+ "suspended": "Suspendido"
+ },
+ "drawer": {
+ "createdBy": "creado por {{actor}}",
+ "loading": "Cargando…",
+ "profileTitle": "Perfil",
+ "profileSubtitle": "Solo el usuario puede editar esto, desde su propio perfil.",
+ "name": "Nombre",
+ "username": "Usuario",
+ "email": "Correo",
+ "language": "Idioma",
+ "accountTitle": "Cuenta",
+ "status": "Estado",
+ "statusActive": "Activo",
+ "statusInactive": "Inactivo",
+ "tfa": "2FA",
+ "tfaEnabled": "Activada",
+ "tfaNotConfigured": "No configurado",
+ "resetTfa": "Restablecer",
+ "resetTfaHint": "Desactiva el 2FA de este usuario para que lo reconfigure en su próximo inicio de sesión",
+ "resetTfaConfirmTitle": "¿Restablecer la autenticación en dos pasos?",
+ "resetTfaConfirmBody": "Esto desactiva el 2FA de {{name}}. Iniciará sesión solo con su contraseña y podrá configurarlo de nuevo desde su perfil.",
+ "resetTfaConfirm": "Restablecer 2FA",
+ "pendingPasswordNote": "Aún usa la contraseña temporal (invitación no completada).",
+ "lastModified": "Modificado {{time}}",
+ "rolesTitle": "Roles",
+ "rolesSubtitle": "Los roles otorgan permisos de módulo. Un usuario puede tener más de uno.",
+ "noRoleWarning": "Sin rol asignado — el usuario no tendrá acceso a ningún módulo.",
+ "deactivate": "Desactivar",
+ "reactivate": "Reactivar",
+ "waitingInvite": "Esperando a que el usuario acepte la invitación.",
+ "cancel": "Cancelar",
+ "saving": "Guardando…",
+ "saveRoles": "Guardar roles",
+ "created": "creado {{time}}",
+ "pendingNote": "La invitación aún no se ha aceptado.",
+ "federatedNote": "Inicia sesión mediante un proveedor de identidad."
+ },
+ "invite": {
+ "title": "Invitar usuario",
+ "description": "La cuenta se crea inactiva. El usuario recibe un correo para establecer su contraseña y activarla.",
+ "username": "Usuario",
+ "usernameHint": "Al menos 3 caracteres.",
+ "email": "Correo",
+ "firstName": "Nombre",
+ "lastName": "Apellido",
+ "roles": "Roles",
+ "cancel": "Cancelar",
+ "sending": "Enviando…",
+ "send": "Enviar invitación",
+ "name": "Nombre",
+ "emailHint": "Es la dirección con la que iniciará sesión.",
+ "localDescription": "La cuenta se crea con una contraseña y se activa de inmediato. No se envía ningún correo.",
+ "modeInvite": "Invitar usuario",
+ "modeLocal": "Crear usuario local",
+ "passwordLabel": "Contraseña",
+ "passwordPlaceholder": "Establezca una contraseña segura",
+ "localUserNote": "Este usuario no recibirá un correo y será activado automáticamente.",
+ "createLocal": "Crear usuario",
+ "passwordRules": {
+ "length": "Al menos 8 caracteres",
+ "case": "Al menos una mayúscula y una minúscula",
+ "special": "Al menos un carácter especial"
+ },
+ "emailInvalid": "Introduzca una dirección de correo válida"
+ },
+ "rolePicker": {
+ "none": "No hay roles disponibles."
+ },
+ "roles": {
+ "loading": "Cargando roles…",
+ "loadFailed": "No se pudieron cargar los permisos de los roles.",
+ "readonlyNote": "Los roles y sus permisos los define el sistema y son de solo lectura. Asígnalos a los usuarios desde la pestaña Miembros.",
+ "permissionsCount_one": "{{count}} permiso",
+ "permissionsCount_other": "{{count}} permisos",
+ "modulesCount_one": "{{count}} módulo",
+ "modulesCount_other": "{{count}} módulos",
+ "matrixTitle": "Matriz de permisos",
+ "matrixSubtitle": "Lo que cada rol puede hacer, por módulo.",
+ "permission": "Permiso",
+ "systemNote": "Los roles del sistema vienen con la plataforma y no se pueden editar. Los que crees pertenecen a este tenant.",
+ "newRole": "Nuevo rol",
+ "edit": "Editar",
+ "delete": "Eliminar",
+ "systemBadge": "Sistema",
+ "createTitle": "Nuevo rol",
+ "editTitle": "Editar rol",
+ "editorSubtitle": "Elige qué puede hacer este rol. Un usuario puede tener más de uno.",
+ "nameLabel": "Identificador",
+ "nameHint": "Se usa en el código y en la API. Por ejemplo, ROLE_AUDITOR.",
+ "displayNameLabel": "Nombre visible",
+ "descriptionLabel": "Descripción",
+ "permissionsLabel": "Permisos",
+ "selectedCount": "{{count}} seleccionados",
+ "toggleAll": "todos",
+ "loadingPermissions": "Cargando permisos…",
+ "save": "Guardar rol",
+ "deleteConfirmTitle": "¿Eliminar este rol?",
+ "deleteConfirmBody": "Se eliminará {{name}}. Los usuarios que solo tengan este rol se quedarán sin acceso a los módulos."
+ },
+ "langDefault": "Predeterminado del sistema",
+ "relative": {
+ "justNow": "ahora mismo",
+ "minutesAgo": "hace {{count}} min",
+ "hoursAgo": "hace {{count}} h",
+ "daysAgo": "hace {{count}} d"
+ },
+ "roleNames": {
+ "ROLE_ADMIN": "Administrador",
+ "ROLE_USER": "Usuario"
+ },
+ "roleDescriptions": {
+ "ROLE_ADMIN": "Acceso total a todos los recursos",
+ "ROLE_USER": "Usuario estándar con acceso de lectura a nivel de módulo"
+ },
+ "actions": {
+ "read": "Lectura",
+ "write": "Escritura",
+ "delete": "Eliminación"
+ },
+ "resources": {
+ "adaudit": "Auditoría AD",
+ "alerts": "Alertas",
+ "audit": "Registro de auditoría",
+ "compliance": "Cumplimiento",
+ "config": "Configuración",
+ "dashboards": "Paneles",
+ "datasources": "Datasources",
+ "eventprocessing": "Procesamiento de eventos",
+ "idp": "Proveedores de identidad",
+ "incidents": "Incidentes",
+ "integrations": "Integraciones",
+ "loganalyzer": "Analizador de logs",
+ "opensearch": "OpenSearch",
+ "roles": "Roles",
+ "soar": "SOAR",
+ "users": "Usuarios",
+ "notifications": "Notificaciones",
+ "socai": "SOC AI",
+ "tenant": "Tenants",
+ "threatintel": "Inteligencia de amenazas"
+ }
+ },
+ "apiKeys": {
+ "title": "Claves API",
+ "subtitle": "Tokens de acceso programático para la API de UTMStack.",
+ "new": "Nueva clave API",
+ "searchPlaceholder": "Buscar por nombre o IP permitida…",
+ "refresh": "Actualizar",
+ "loading": "Cargando claves API…",
+ "loadFailed": "No se pudieron cargar las claves API.",
+ "retry": "Reintentar",
+ "noSearchMatch": "Ninguna clave API coincide con tu búsqueda.",
+ "empty": "Aún no hay claves API. Crea una para empezar.",
+ "anyIp": "Cualquier IP",
+ "never": "Nunca",
+ "count_one": "{{count}} clave · página {{page}} de {{pages}}",
+ "count_other": "{{count}} claves · página {{page}} de {{pages}}",
+ "enterprise": {
+ "title": "Las claves API son una función Enterprise",
+ "body": "Emite, restringe y rota claves API para acceso programático a la API de UTMStack. Esta capacidad está disponible en la edición Enterprise.",
+ "upgrade": "Actualizar a Enterprise",
+ "manageLicense": "Gestionar tu licencia"
+ },
+ "col": {
+ "name": "Nombre",
+ "allowedIps": "IPs permitidas",
+ "created": "Creada",
+ "lastRotated": "Última rotación",
+ "expires": "Expira",
+ "status": "Estado",
+ "actions": "Acciones"
+ },
+ "status": {
+ "active": "Activa",
+ "expiring": "Por expirar",
+ "expired": "Expirada"
+ },
+ "action": {
+ "rotate": "Rotar",
+ "edit": "Editar",
+ "delete": "Eliminar"
+ },
+ "dialog": {
+ "editTitle": "Editar clave API",
+ "newTitle": "Nueva clave API",
+ "name": "Nombre",
+ "namePlaceholder": "ci-pipeline",
+ "allowedIps": "IPs permitidas",
+ "allowedIpsHint": "Separadas por comas. Deja vacío para permitir cualquier IP.",
+ "expires": "Expira",
+ "expiresHint": "Deja vacío para una clave que nunca expira.",
+ "secretNote": "El token secreto se muestra una sola vez, justo tras la creación. Cópialo entonces — no se puede recuperar después (solo rotar).",
+ "cancel": "Cancelar",
+ "saving": "Guardando…",
+ "saveChanges": "Guardar cambios",
+ "createKey": "Crear clave"
+ },
+ "confirm": {
+ "deleteTitle": "Eliminar clave API",
+ "rotateTitle": "Rotar clave API",
+ "deleteBody": "¿Eliminar {{name}}? Cualquier cliente que la use perderá el acceso de inmediato. Esto no se puede deshacer.",
+ "rotateBody": "¿Rotar {{name}}? Se emite un nuevo secreto y el actual deja de funcionar de inmediato. El nuevo token se muestra una sola vez.",
+ "cancel": "Cancelar",
+ "working": "Procesando…",
+ "delete": "Eliminar",
+ "rotate": "Rotar"
+ },
+ "reveal": {
+ "title": "Clave API creada",
+ "note": "Copia este secreto ahora — para {{name}}. No se volverá a mostrar. Si lo pierdes, rota la clave.",
+ "copied": "Copiado",
+ "copy": "Copiar",
+ "done": "Listo"
+ },
+ "toast": {
+ "updated": "Clave API actualizada",
+ "secretIssueFailed": "Clave creada, pero no se pudo emitir el secreto. Usa Rotar para obtener uno.",
+ "deleted": "Clave API eliminada"
+ },
+ "error": {
+ "nameTaken": "Ya existe una clave API con ese nombre",
+ "enterpriseRequired": "Las claves API requieren la edición Enterprise",
+ "notFound": "Clave API no encontrada",
+ "invalidRequest": "Solicitud inválida",
+ "failed": "Operación fallida"
+ }
+ },
+ "idp": {
+ "title": "Proveedores de identidad",
+ "subtitle": "Inicio de sesión único SAML 2.0 para tu organización.",
+ "add": "Agregar proveedor",
+ "enterprise": {
+ "title": "El SSO es una función Enterprise",
+ "body": "Conecta un proveedor de identidad SAML 2.0 (Entra ID, Okta, Google Workspace…) para que tu equipo inicie sesión con tu IdP. El inicio de sesión único está disponible en la edición Enterprise.",
+ "upgrade": "Actualizar a Enterprise"
+ },
+ "loading": "Cargando proveedores de identidad…",
+ "loadFailed": "No se pudieron cargar los proveedores de identidad.",
+ "retry": "Reintentar",
+ "empty": {
+ "title": "No hay proveedores de identidad configurados",
+ "body": "Agrega un proveedor SAML 2.0 para que tu equipo inicie sesión con tu IdP corporativo."
+ },
+ "card": {
+ "enable": "Habilitar",
+ "disable": "Deshabilitar",
+ "active": "Activo",
+ "disabled": "Deshabilitado",
+ "metadataUrl": "URL de metadatos",
+ "spEntityId": "SP Entity ID",
+ "spAcsUrl": "SP ACS URL",
+ "loginUrl": "URL de inicio de sesión",
+ "copy": "Copiar",
+ "edit": "Editar",
+ "delete": "Eliminar",
+ "jit": "Alta",
+ "jitOn": "crea cuentas en el primer acceso",
+ "sync": "Roles",
+ "syncOn": "se reaplican en cada acceso"
+ },
+ "form": {
+ "addTitle": "Agregar proveedor de identidad",
+ "editTitle": "Editar proveedor de identidad",
+ "name": "Nombre",
+ "nameHint": "Único. Se usa en la URL de SSO.",
+ "providerType": "Tipo de proveedor",
+ "providerTypeHint": "Una etiqueta, p. ej. azure, okta, google.",
+ "metadataUrl": "URL de metadatos del IdP",
+ "spEntityId": "SP Entity ID",
+ "spAcsUrl": "SP ACS URL",
+ "certificate": "Certificado SP (PEM)",
+ "privateKey": "Llave privada SP (PEM)",
+ "privateKeyHintEdit": "Déjalo vacío para conservar la llave guardada.",
+ "privateKeyHintCreate": "Requerida. Se guarda cifrada; no se vuelve a mostrar.",
+ "privateKeyUnchanged": "•••••••• (sin cambios)",
+ "active": "Activo (mostrar en la página de inicio de sesión)",
+ "cancel": "Cancelar",
+ "saving": "Guardando…",
+ "save": "Guardar cambios",
+ "create": "Crear proveedor",
+ "issuer": "URL del emisor",
+ "issuerHint": "El descubrimiento se hace contra esta URL; el proveedor debe servir /.well-known/openid-configuration bajo ella.",
+ "clientId": "ID de cliente",
+ "redirectUrl": "URL de retorno",
+ "redirectUrlHint": "Registra exactamente esta URL en el proveedor.",
+ "host": "Servidor",
+ "port": "Puerto",
+ "startTls": "TLS",
+ "startTlsOn": "Usar StartTLS",
+ "bindDn": "DN de conexión",
+ "bindDnHint": "Una cuenta de servicio que pueda buscar en el directorio.",
+ "baseDn": "DN base",
+ "userFilter": "Filtro de usuario",
+ "userFilterHint": "Debe contener %s, donde se sustituye la dirección escrita al entrar.",
+ "emailAttribute": "Atributo de correo",
+ "nameAttribute": "Atributo de nombre",
+ "groupAttribute": "Atributo de grupo",
+ "provisioning": "Cuentas y roles",
+ "provisioningHint": "Qué ocurre cuando entra alguien por quien responde el directorio.",
+ "jit": "Crear la cuenta en el primer acceso",
+ "defaultRole": "Rol por defecto",
+ "defaultRoleHint": "Se concede cuando ningún grupo casa. Sin él, un acceso sin coincidencia se rechaza.",
+ "noDefaultRole": "Ninguno",
+ "groupsAttribute": "Atributo de grupos",
+ "groupsAttributeHint": "Dónde pone el proveedor la pertenencia a grupos.",
+ "syncRoles": "Reaplicar roles en cada acceso",
+ "syncRolesHint": "Los roles que no estén en el mapeo se quitan, para que un cambio en el directorio llegue hasta aquí. Sin esto, una degradación no llega nunca.",
+ "mappings": "Grupo a rol",
+ "mappingsHint": "Un grupo del directorio a la izquierda, el rol que concede a la derecha.",
+ "addMapping": "Añadir",
+ "noMappings": "Sin mapeos. Todos reciben el rol por defecto.",
+ "groupPlaceholder": "Analistas SOC",
+ "pickRole": "Elige un rol",
+ "secret.saml": "Clave privada del SP",
+ "secret.oidc": "Secreto de cliente",
+ "secret.ldap": "Contraseña de conexión",
+ "secretHintCreate": "Se guarda cifrada y no se vuelve a mostrar.",
+ "secretHintEdit": "Déjalo en blanco para conservar la guardada.",
+ "secretUnchanged": "sin cambios",
+ "errors": {
+ "required": "Este campo es obligatorio.",
+ "url": "Debe ser una URL http(s) válida.",
+ "httpsUrl": "Debe ser una URL https válida.",
+ "hostname": "Introduce un host o IP sin esquema (p. ej. ldap.ejemplo.com).",
+ "port": "El puerto debe ser un número entero entre 0 y 65535.",
+ "pemCertificate": "No parece un certificado PEM (faltan -----BEGIN/END CERTIFICATE-----).",
+ "pemKey": "No parece una clave privada PEM (faltan -----BEGIN/END PRIVATE KEY-----).",
+ "userFilterPlaceholder": "El filtro debe contener %s, donde se sustituye la dirección de inicio de sesión.",
+ "userFilterUnbalanced": "Hay paréntesis desequilibrados: la búsqueda no devolverá nada.",
+ "nameFormat": "Usa letras, números, puntos, guiones o guiones bajos (máx. 64). Aparece en la URL de SSO, por lo que no admite espacios.",
+ "redirectUrl": "Debe ser una URL https válida, o una URL http de loopback (localhost / 127.0.0.1 / [::1]).",
+ "entityId": "Debe ser una URI válida, p. ej. https://utmstack.example.com/sp."
+ }
+ },
+ "delete": {
+ "title": "Eliminar proveedor de identidad",
+ "body": "¿Eliminar {{name}}? Los usuarios ya no podrán iniciar sesión a través de él. Esto no se puede deshacer.",
+ "cancel": "Cancelar",
+ "deleting": "Eliminando…",
+ "confirm": "Eliminar"
+ },
+ "toast": {
+ "enabled": "Proveedor habilitado",
+ "disabled": "Proveedor deshabilitado",
+ "created": "Proveedor de identidad creado",
+ "updated": "Proveedor de identidad actualizado",
+ "deleted": "Proveedor de identidad eliminado",
+ "paidPlan": "El SSO SAML requiere un plan de pago",
+ "enterpriseRequired": "El SSO requiere la edición Enterprise",
+ "notFound": "Proveedor de identidad no encontrado",
+ "invalid": "Configuración inválida",
+ "failed": "La operación falló"
+ },
+ "providerType": {
+ "saml": "SAML 2.0",
+ "oidc": "OpenID Connect",
+ "ldap": "LDAP / Active Directory",
+ "comingSoon": "aún no disponible"
+ }
+ },
+ "userAuditor": {
+ "title": "Auditor de usuarios",
+ "subtitle": "Cuentas de Active Directory observadas en tus logs de seguridad de Windows — descubiertas a partir de eventos de creación, inicio de sesión y borrado.",
+ "export": "Exportar",
+ "accountsChip": "{{count}} cuentas",
+ "overview": {
+ "title": "Inventario de cuentas",
+ "active": "activas",
+ "disabled": "deshabilitadas",
+ "deleted": "borradas",
+ "seen24h": "{{count}} vistas en las últimas 24 horas",
+ "byDomain": "Por dominio"
+ },
+ "views": {
+ "all": "Todas las cuentas",
+ "windows": "Windows",
+ "linux": "Linux",
+ "active": "Activas",
+ "disabled": "Deshabilitadas",
+ "deleted": "Borradas",
+ "service": "Cuentas de servicio",
+ "stale": "Inactivas (30d+)"
+ },
+ "searchPlaceholder": "Buscar por nombre de cuenta o SID…",
+ "allTenants": "Todos los tenants",
+ "filters": {
+ "add": "Añadir filtro",
+ "clearAll": "Limpiar todo",
+ "filterValues": "Filtrar valores…",
+ "loadingValues": "Cargando valores…",
+ "noValues": "No se encontraron valores.",
+ "pickValue": "Elige un valor para añadir el filtro.",
+ "empty": "(vacío)",
+ "cancel": "Cancelar",
+ "addBtn": "Añadir"
+ },
+ "filterFields": {
+ "status": "Estado de ciclo de vida"
+ },
+ "ops": {
+ "is": "es"
+ },
+ "refresh": "Actualizar",
+ "layout": {
+ "list": "Lista",
+ "cards": "Tarjetas"
+ },
+ "list": {
+ "account": "Cuenta",
+ "identity": "Identidad",
+ "sid": "SID",
+ "status": "Estado",
+ "lastLogon": "Último inicio",
+ "lastSeen": "Última vez vista",
+ "tenant": "Tenant"
+ },
+ "status": {
+ "active": "Activa",
+ "disabled": "Deshabilitada",
+ "deleted": "Borrada"
+ },
+ "badge": {
+ "service": "servicio",
+ "stale": "inactiva"
+ },
+ "empty": "Ninguna cuenta coincide con esta vista.",
+ "loadError": "No se pudieron cargar las cuentas de AD.",
+ "retry": "Reintentar",
+ "card": {
+ "lastLogon": "Último inicio"
+ },
+ "pageInfo": "{{from}}–{{to}} de {{count}}",
+ "drawer": {
+ "tenantInline": "tenant {{id}}",
+ "serviceAccount": "cuenta de servicio",
+ "stale": "inactiva 30d+",
+ "viewInLogs": "Ver eventos en el Log Explorer",
+ "copySid": "Copiar SID",
+ "copyUid": "Copiar identidad",
+ "copied": "Copiado",
+ "identity": "Identidad",
+ "accountName": "Nombre de cuenta",
+ "domain": "Dominio",
+ "hostname": "Hostname",
+ "sid": "SID",
+ "uidNumber": "UID",
+ "machineId": "ID de máquina",
+ "tenant": "Tenant",
+ "adStatus": "Estado en AD",
+ "enabled": "Habilitada",
+ "disabled": "Deshabilitada",
+ "lifecycle": "Ciclo de vida",
+ "created": "Cuenta creada",
+ "lastLogon": "Último inicio de sesión",
+ "lastSeen": "Última vez vista en logs",
+ "deleted": "Cuenta borrada",
+ "noLifecycle": "Sin eventos de ciclo de vida."
+ },
+ "relative": {
+ "justNow": "ahora mismo",
+ "minutesAgo": "hace {{count}}m",
+ "hoursAgo": "hace {{count}}h",
+ "daysAgo": "hace {{count}}d"
+ },
+ "none": "—"
+ },
+ "connectionKey": {
+ "title": "Clave de conexión",
+ "subtitle1": "La clave que los agentes presentan al registrarse en esta instancia.",
+ "subtitleEmphasis": "Solo se usa para la instalación de agentes",
+ "subtitle2": "— no para colectores, integraciones ni la API. La gestiona el agent-manager.",
+ "status": {
+ "label": "Estado",
+ "loading": "Cargando…",
+ "unavailable": "Agent-manager no disponible",
+ "active": "Activa",
+ "unavailableHint": "No se pudo contactar al agent-manager para leer la clave.",
+ "activeHint": "Los agentes pueden registrarse con esta clave."
+ },
+ "token": {
+ "title": "Clave de conexión",
+ "subtitle": "Trata este valor como una credencial. Rotarla genera una nueva clave para futuras instalaciones de agentes — los agentes ya registrados siguen funcionando.",
+ "loadFailedTitle": "No se pudo cargar la clave de conexión",
+ "unavailableTitle": "Clave de conexión no disponible",
+ "loadFailedHint": "La clave la gestiona el agent-manager, que no respondió. Inténtalo de nuevo en un momento.",
+ "retry": "Reintentar",
+ "show": "Mostrar clave",
+ "hide": "Ocultar clave",
+ "copy": "Copiar",
+ "copied": "Copiado",
+ "regenerate": "Regenerar clave de conexión",
+ "confirmTitle": "¿Regenerar la clave?",
+ "confirmBody": "Las nuevas instalaciones de agentes necesitarán la nueva clave. Los agentes ya registrados seguirán funcionando. No se puede deshacer.",
+ "regenerating": "Regenerando…",
+ "confirmYes": "Sí, regenerar",
+ "cancel": "Cancelar"
+ },
+ "security": {
+ "title": "Recomendaciones de seguridad",
+ "subtitle": "Buenas prácticas para proteger esta credencial.",
+ "rotateTitle": "Rota cada 90 días",
+ "rotateBody": "Programa una rotación periódica. UTMStack puede enviarte un recordatorio por correo cuando la clave tenga más de 90 días.",
+ "rotateAction": "Configurar recordatorio",
+ "secretTitle": "Guárdala como secreto",
+ "secretBody": "No la subas al control de versiones. Usa tu gestor de secretos (Vault, AWS SM, etc.) e inyéctala en el momento de la instalación.",
+ "auditTitle": "Audita quién la obtuvo",
+ "auditBody": "Cada obtención y rotación queda registrada en el journal de auditoría de la aplicación.",
+ "auditAction": "Ver journal de auditoría"
+ },
+ "toast": {
+ "loadFailed": "No se pudo cargar la clave de conexión",
+ "rotated": "Clave de conexión rotada",
+ "rotateFailed": "No se pudo rotar la clave de conexión",
+ "copyFailed": "No se pudo copiar"
+ }
+ },
+ "dataRetention": {
+ "title": "Retención de datos",
+ "subtitle": "Cuánto se guarda cada conjunto de datos y cuándo sus registros dejan de ocupar disco local.",
+ "loading": "Cargando…",
+ "loadFailed": "No se pudo leer el almacén.",
+ "retry": "Reintentar",
+ "datasets": {
+ "logs": "Logs",
+ "alerts": "Alertas",
+ "statistics": "Estadísticas de ingesta"
+ },
+ "holding": "{{documents}} registros · {{size}}",
+ "since": "desde {{date}}",
+ "diskUsed": "Disco al {{pct}}%",
+ "keep": "Eliminar después de",
+ "keepHint": "Un registro se elimina esos días después de ocurrir, esté donde esté guardado.",
+ "cold": "Mover a almacenamiento frío tras",
+ "coldHint": "Los registros antiguos pasan al object storage y siguen siendo consultables. 0 los deja siempre en disco local.",
+ "coldUnavailable": "Configura el almacenamiento frío abajo para sacar los registros antiguos del disco local.",
+ "coldBeforeDelete": "Los registros deben moverse antes de eliminarse: usa menos días que la vida total, o 0.",
+ "tieredNote": "Este conjunto mueve registros a almacenamiento frío. Volver a solo disco local exige reconstruir la tabla, así que no se puede apagar aquí.",
+ "days": "días",
+ "save": "Guardar",
+ "saving": "Guardando…",
+ "toast": {
+ "saved": "Retención guardada",
+ "noPermission": "No tienes permiso para cambiar la retención",
+ "saveFailed": "No se pudo guardar la retención"
+ },
+ "coldStorage": {
+ "title": "Almacenamiento frío",
+ "hint": "Un object storage que el almacén trata como un segundo disco más lento. Los registros antiguos se mueven allí y se consultan desde el mismo sitio: no es un archivo y no hay que restaurar nada.",
+ "active": "En uso",
+ "inactive": "Sin configurar",
+ "writtenNotReady": "El bucket está configurado pero el almacén no lo ha tomado. Comprueba que el despliegue comparte el directorio de configuración del almacén.",
+ "endpoint": "URL del bucket",
+ "accessKey": "Access key",
+ "secretKey": "Secret key",
+ "bucketLocked": "Las credenciales se pueden cambiar cuando quieras. El bucket no, una vez hay registros dentro: las partes ya movidas lo llevan.",
+ "enable": "Activar almacenamiento frío",
+ "update": "Actualizar credenciales",
+ "toast": {
+ "saved": "Almacenamiento frío configurado",
+ "failed": "No se pudo configurar el almacenamiento frío"
+ },
+ "kind": "Tipo",
+ "kind_s3": "Almacén de objetos compatible con S3",
+ "kind_local": "Carpeta local o NFS",
+ "kind_azure": "Azure Blob Storage",
+ "accountUrl": "URL de la cuenta de almacenamiento",
+ "container": "Contenedor",
+ "accountName": "Nombre de la cuenta",
+ "accountKey": "Clave de la cuenta",
+ "useRole": "Usar el rol IAM del servidor en lugar de claves",
+ "s3Hint": "Funciona con AWS S3 y cualquier almacén compatible con S3: MinIO, Ceph, Wasabi, Cloudflare R2 o Google Cloud Storage (endpoint https://storage.googleapis.com// con claves HMAC).",
+ "localHint": "Los registros pasan a la carpeta montada en /mnt/utmstack-cold dentro del almacén de eventos: un directorio normal en la carpeta de datos, o un recurso NFS montado en el host sobre /clickhouse/cold antes de iniciar el stack. No requiere credenciales.",
+ "changeWarning": "No migramos los datos que ya están en el destino actual. Se quedan allí y dejan de poder consultarse desde aquí hasta que copies a mano el destino anterior al nuevo."
+ },
+ "forbidden": {
+ "title": "Esta página es de la plataforma",
+ "body": "La retención se aplica a las tablas que comparten todos los tenants, así que solo un administrador de plataforma puede verla o cambiarla. Pídeselo a uno, o entra con una cuenta de plataforma."
+ }
+ },
+ "languageSettings": {
+ "title": "Idioma de la plataforma",
+ "subtitle": "Idioma por defecto para las pantallas pre-login, los correos del sistema y los usuarios nuevos. Cada usuario puede elegir el suyo en su perfil.",
+ "label": "Idioma por defecto",
+ "hint": "Se usa cuando un usuario no ha elegido su propio idioma.",
+ "save": "Guardar",
+ "saving": "Guardando…",
+ "saved": "Idioma de la plataforma actualizado",
+ "loadError": "No se pudo cargar la configuración de idioma",
+ "saveError": "No se pudo guardar la configuración de idioma"
+ },
+ "branding": {
+ "title": "Marca",
+ "subtitle": "Personaliza UTMStack con la identidad de tu organización — se aplica en todo: la pantalla de login, el menú lateral, los correos y los informes.",
+ "enterpriseRequired": "El white-label es una función Enterprise.",
+ "manageLicense": "Gestionar licencia",
+ "enable": {
+ "title": "White-label",
+ "description": "Reemplaza la marca UTMStack por la tuya en toda la plataforma.",
+ "label": "Activar white-label"
+ },
+ "identity": {
+ "title": "Identidad",
+ "productName": "Nombre del producto",
+ "productNameHint": "Se muestra en la barra de título, el menú lateral y los correos.",
+ "accent": "Color de acento",
+ "accentHint": "Color primario de botones, enlaces y estados activos.",
+ "custom": "Color personalizado"
+ },
+ "logos": {
+ "title": "Logos",
+ "hint": "PNG, SVG, WEBP, JPG o ICO. Hasta 5 MB.",
+ "logo": "Logo (claro)",
+ "logoDark": "Logo (oscuro)",
+ "favicon": "Favicon"
+ },
+ "reports": {
+ "title": "Recursos de informes",
+ "hint": "Incrustados en los informes PDF generados.",
+ "reportLogo": "Logo de informe",
+ "reportCover": "Portada de informe"
+ },
+ "asset": {
+ "upload": "Subir",
+ "replace": "Reemplazar"
+ },
+ "save": "Guardar cambios",
+ "saving": "Guardando…",
+ "saved": "Marca actualizada",
+ "saveError": "No se pudo guardar la marca",
+ "uploaded": "Imagen subida",
+ "uploadError": "No se pudo subir la imagen",
+ "loadError": "No se pudo cargar la marca",
+ "enterprise": {
+ "title": "La marca blanca es una función Enterprise",
+ "body": "Sustituye el nombre del producto, el logotipo y la portada de los informes por los tuyos, para que el panel y todo lo que genera lleven tu marca y no la de UTMStack.",
+ "upgrade": "Actualizar a Enterprise"
+ },
+ "restore": "Restaurar los valores de UTMStack",
+ "restored": "Marca restaurada a los valores de UTMStack"
+ },
+ "emailConfig": {
+ "title": "Configuración de correo",
+ "subtitle": "Servidor SMTP usado para enviar notificaciones de alertas, informes y correos de cuenta.",
+ "server": {
+ "title": "Servidor SMTP",
+ "host": "Host",
+ "hostHint": "Nombre del servidor SMTP.",
+ "port": "Puerto",
+ "encryption": "Cifrado",
+ "username": "Usuario",
+ "password": "Contraseña",
+ "passwordSetHint": "Hay una contraseña guardada. Déjalo vacío para conservarla, o escribe una nueva para cambiarla."
+ },
+ "encryptionOpt": {
+ "TLS": "TLS",
+ "SSL": "SSL",
+ "NONE": "Ninguno"
+ },
+ "sender": {
+ "title": "Remitente",
+ "from": "Dirección de origen",
+ "fromHint": "Dirección desde la que se envían los correos.",
+ "organization": "Nombre de la organización",
+ "organizationHint": "Se muestra en los correos de notificación de alertas e incidentes.",
+ "baseUrl": "URL base",
+ "baseUrlHint": "URL pública de esta instancia, usada en los enlaces de los correos."
+ },
+ "test": {
+ "button": "Enviar prueba",
+ "sending": "Enviando…",
+ "sentTo": "Se enviará un correo de prueba a {{email}}.",
+ "success": "Correo de prueba enviado a {{email}}",
+ "fail": "No se pudo enviar el correo de prueba",
+ "fromRequired": "Define una dirección de origen antes de probar"
+ },
+ "save": "Guardar cambios",
+ "saving": "Guardando…",
+ "saved": "Configuración de correo guardada",
+ "saveError": "No se pudo guardar la configuración",
+ "loadError": "No se pudo cargar la configuración",
+ "recipients": {
+ "alertsTitle": "Destinatarios de alertas",
+ "incidentsTitle": "Destinatarios de incidentes",
+ "to": "Para",
+ "cc": "CC",
+ "alertsHelper": "Direcciones avisadas cuando se generan nuevas alertas. Si lo dejas vacío, las alertas no se envían por correo.",
+ "incidentsHelper": "Direcciones avisadas cuando se crea un incidente. Si lo dejas vacío, los incidentes no se envían por correo.",
+ "add": "Añadir"
+ }
+ },
+ "dateFormat": {
+ "title": "Fecha y hora",
+ "subtitle": "Cómo se muestran los timestamps en toda la plataforma. Los logs siempre se almacenan en UTC.",
+ "timezone": {
+ "title": "Zona horaria",
+ "hint": "Los timestamps se muestran en esta zona horaria. Los datos se almacenan en UTC.",
+ "system": "Predeterminado del navegador",
+ "now": "Ahora: {{value}}"
+ },
+ "format": {
+ "title": "Formato de fecha",
+ "hint": "Estilo usado para fechas y horas."
+ },
+ "styles": {
+ "short": "Corto",
+ "medium": "Medio",
+ "long": "Largo",
+ "full": "Completo"
+ },
+ "save": "Guardar cambios",
+ "saving": "Guardando…",
+ "saved": "Configuración de fecha guardada",
+ "saveError": "No se pudo guardar la configuración",
+ "loadError": "No se pudo cargar la configuración"
+ },
+ "about": {
+ "title": "Acerca de esta instancia",
+ "subtitle": "Versión, licencia y estado del sistema de este despliegue de UTMStack.",
+ "loading": "Cargando información de la instancia…",
+ "edition": {
+ "enterprise": "Enterprise",
+ "community": "Community"
+ },
+ "fields": {
+ "hostname": "Servidor",
+ "instanceId": "ID de instancia",
+ "noInstanceMeta": "No hay metadatos de la instancia disponibles."
+ },
+ "license": {
+ "title": "Licencia",
+ "enterpriseMssp": "Enterprise · MSSP",
+ "datasources": "Datasources",
+ "communityLimited": "Límite Community",
+ "unlimited": "Ilimitado",
+ "expires": "Expira",
+ "managedNote": "La edición, los límites de datasources y la carga de licencia se gestionan en la página de Licencia.",
+ "view": "Ver licencia",
+ "ingest": "Volumen de ingesta",
+ "notMetered": "Sin medición",
+ "gbPerMonth": "{{gb}} GB/mes"
+ },
+ "services": {
+ "backend": {
+ "name": "Backend API",
+ "desc": "Gateway REST, autenticación y orquestación de módulos."
+ },
+ "opensearch": {
+ "name": "OpenSearch",
+ "desc": "Almacenamiento de logs y eventos.",
+ "detail": "{{nodes}} nodos · {{shards}} shards"
+ },
+ "unreachable": "Inaccesible"
+ },
+ "status": {
+ "up": "Saludable",
+ "degraded": "Degradado",
+ "down": "Caído",
+ "unknown": "Desconocido"
+ },
+ "health": {
+ "title": "Estado del sistema",
+ "allHealthy": "Todos los servicios saludables. Actualiza para revisar.",
+ "issues_one": "{{count}} servicio necesita atención.",
+ "issues_other": "{{count}} servicios necesitan atención.",
+ "refresh": "Actualizar"
+ },
+ "usage": {
+ "title": "Fuentes de datos",
+ "subtitle": "Fuentes de datos configuradas en esta instalación.",
+ "ofUnlimited": "de ilimitado",
+ "ofLimit": "de {{limit}}",
+ "overLimit": "Por encima del límite licenciado — los datos que excedan el tope están en riesgo.",
+ "configured": "configuradas"
+ },
+ "support": {
+ "title": "Soporte",
+ "docs": "Documentación",
+ "repo": "Repositorio en GitHub",
+ "issues": "Reportar un problema",
+ "website": "utmstack.com"
+ },
+ "legal": {
+ "title": "Legal",
+ "license": "Licencia",
+ "security": "Divulgación de seguridad",
+ "copyright": "© {{year}} UTMStack. Todos los derechos reservados."
+ }
+ },
+ "logExplorer": {
+ "title": "Explorador de logs",
+ "eventsIn": "eventos en",
+ "searching": "Buscando…",
+ "query": {
+ "allDataTypes": "Todos los tipos de dato",
+ "dataTypes": "Tipos de dato",
+ "exportCsv": "Exportar CSV",
+ "filterDataTypes": "Filtrar tipos de dato…",
+ "noDataTypes": "Sin tipos de dato",
+ "noDataTypesMatch": "Ningún tipo de dato coincide",
+ "noTextSearch": "Este origen no tiene campo de texto completo — filtra por campo",
+ "refresh": "Actualizar",
+ "run": "Ejecutar",
+ "search": "Buscar",
+ "searchPlaceholder": "Buscar en todos los campos…"
+ },
+ "time": {
+ "15m": "Últimos 15 minutos",
+ "1h": "Última hora",
+ "6h": "Últimas 6 horas",
+ "24h": "Últimas 24 horas",
+ "7d": "Últimos 7 días",
+ "30d": "Últimos 30 días"
+ },
+ "ops": {
+ "is": "es",
+ "isNot": "no es",
+ "contains": "contiene",
+ "exists": "existe",
+ "between": "entre",
+ "search": "busca",
+ "isOneOf": "es uno de",
+ "isNotOneOf": "no es ninguno de",
+ "doesNotContain": "no contiene",
+ "startsWith": "empieza con",
+ "doesNotStartWith": "no empieza con",
+ "endsWith": "termina con",
+ "doesNotEndWith": "no termina con",
+ "doesNotExist": "no existe",
+ "notBetween": "no está entre",
+ "greaterThan": "es mayor que",
+ "greaterThanOrEquals": "es mayor o igual que",
+ "lessThan": "es menor que",
+ "lessThanOrEquals": "es menor o igual que"
+ },
+ "filters": {
+ "label": "Filtros",
+ "clearAll": "Limpiar todo"
+ },
+ "fields": {
+ "title": "Campos",
+ "filterPlaceholder": "Filtrar campos…",
+ "none": "Sin campos",
+ "selected": "Campos seleccionados",
+ "available": "Campos disponibles",
+ "topValues_one": "Top {{count}} valor",
+ "topValues_other": "Top {{count}} valores",
+ "loading": "Cargando…",
+ "noValues": "Sin valores",
+ "addColumn": "Agregar como columna",
+ "removeColumn": "Quitar columna de la tabla",
+ "filterFor": "Filtrar por el valor",
+ "filterOut": "Excluir el valor",
+ "empty": "(vacío)"
+ },
+ "results": {
+ "dataTypesFailed": "No se pudieron cargar los tipos de dato.",
+ "endOfResults": "Cargados los {{count}} eventos",
+ "loadingMore": "Cargando más…",
+ "message": "Mensaje",
+ "none": "Ningún log coincide con esta consulta.",
+ "removeColumn": "Quitar {{field}}",
+ "retry": "Reintentar",
+ "searchFailed": "La búsqueda falló.",
+ "searching": "Buscando…",
+ "source": "Origen",
+ "time": "Hora",
+ "scope": "Buscado en {{dataset}} · {{dataType}}.",
+ "searchAllDataTypes": "Buscar en todos los tipos"
+ },
+ "detail": {
+ "fieldsCount_one": "{{count}} campo",
+ "fieldsCount_other": "{{count}} campos",
+ "copyJson": "Copiar JSON",
+ "copied": "Documento copiado",
+ "parsedFields": "Campos parseados",
+ "json": "JSON",
+ "filterFor": "Filtrar por",
+ "filterOut": "Excluir",
+ "surrounding": "Eventos alrededor",
+ "surroundingHint": "Mostrar eventos ±15 min alrededor de este, de la misma fuente"
+ },
+ "view": {
+ "table": "Tabla",
+ "chart": "Gráfico"
+ },
+ "chart": {
+ "aggregateOn": "Agregar por",
+ "per": "cada",
+ "topValues": "— top 20 valores",
+ "building": "Construyendo gráfico…",
+ "failed": "No se pudo construir el gráfico para este campo.",
+ "noData": "Sin datos para graficar."
+ },
+ "intervals": {
+ "minute": "Minuto",
+ "hour": "Hora",
+ "day": "Día",
+ "week": "Semana",
+ "month": "Mes",
+ "quarter": "Trimestre",
+ "year": "Año"
+ },
+ "toast": {
+ "exportFailed": "La exportación falló"
+ },
+ "builder": {
+ "add": "Agregar filtro",
+ "filterValues": "Filtrar valores…",
+ "loadingValues": "Cargando valores…",
+ "noValues": "Sin valores.",
+ "cancel": "Cancelar",
+ "confirm": "Agregar",
+ "pickValue": "Pick a value to add the filter."
+ },
+ "related": {
+ "nLogs_one": "{{count}} log",
+ "nLogs_other": "{{count}} logs",
+ "truncated": "Mostrando los primeros {{count}} logs relacionados (el conjunto completo es mayor)."
+ },
+ "saved": {
+ "title": "Guardadas",
+ "empty": "Aún no hay búsquedas guardadas",
+ "saveCurrent": "Guardar búsqueda actual",
+ "save": "Guardar",
+ "namePlaceholder": "Nombre de la búsqueda",
+ "delete": "Eliminar",
+ "saved": "Guardada «{{name}}»",
+ "loading": "Cargando…",
+ "loadFailed": "No se pudieron cargar las búsquedas guardadas",
+ "saveFailed": "No se pudo guardar la búsqueda",
+ "deleteFailed": "No se pudo eliminar la búsqueda",
+ "unreadable": "No se pudo leer esa búsqueda guardada"
+ }
+ },
+ "integrations": {
+ "title": "Integraciones",
+ "searchPlaceholder": "Buscar integraciones…",
+ "noMatch": "Ninguna integración coincide.",
+ "browseMarketplace": "Explorar marketplace",
+ "loading": "Cargando integraciones…",
+ "addCustom": {
+ "title": "Agregar integración personalizada",
+ "description": "Crear una nueva fuente personalizada",
+ "cta": "Crear"
+ },
+ "tabs": {
+ "all": "Todas",
+ "agents": "Agentes",
+ "collectors": "Colectores",
+ "cloud": "Cloud",
+ "custom": "Personalizada"
+ },
+ "kind": {
+ "agents & syslog": "Agente",
+ "device": "Colector",
+ "antivirus": "Colector",
+ "other": "Colector",
+ "custom": "Personalizada",
+ "cloud": "Cloud",
+ "utmstack modules": "Colector"
+ },
+ "status": {
+ "configured": "Configurada",
+ "available": "Disponible"
+ },
+ "card": {
+ "manage": "Gestionar →",
+ "setup": "Configurar →",
+ "eventsPerSec": "{{rate}} e/s",
+ "enabled": "Activado",
+ "setupShort": "Configurar"
+ },
+ "drawer": {
+ "manage": "Gestionar",
+ "openDashboard": "Abrir panel",
+ "viewEvents": "Ver eventos",
+ "documentation": "Documentación",
+ "getInstallCmd": "Obtener comando de instalación",
+ "setupCollector": "Configurar colector",
+ "connect": "Conectar",
+ "configureCustom": "Configurar fuente personalizada",
+ "eventsRate": "{{rate}} eventos/s · {{count}} en 24h",
+ "manageRules": "Reglas",
+ "manageFilters": "Filtros"
+ },
+ "setup": {
+ "agent": {
+ "howItWorksTitle": "Cómo funciona",
+ "howItWorksBody": "El agente {{name}} es un pequeño demonio que se ejecuta en el host y reenvía eventos locales a UTMStack sobre una conexión TLS autenticada. Se actualiza automáticamente e informa su estado de salud.",
+ "installTitle": "Instalar en {{name}}",
+ "installHint": "Ejecuta este comando en cada host {{name}} que desees monitorear. El token ya codifica tu workspace actual.",
+ "afterTitle": "Qué verás después de instalar",
+ "after1": "El host aparece bajo Fuentes de datos dentro de ~60 segundos después de que inicie el agente.",
+ "after2": "La telemetría comienza a fluir hacia el Log Explorer, limitada a tu workspace.",
+ "after3": "El agente auto-reporta CPU / memoria / estado del disco a UTMStack.",
+ "actionLabel": "Acción",
+ "platformLabel": "Plataforma",
+ "optionsLabel": "Opciones",
+ "skipCertValidation": "No validar el certificado TLS (servidor autofirmado)",
+ "noRemoteControl": "Deshabilitar la ejecución remota de comandos en este host",
+ "loadingToken": "Cargando token…",
+ "actions": {
+ "install": "Instalar",
+ "uninstall": "Desinstalar"
+ },
+ "prereqTitle": "Requisitos previos a la instalación",
+ "prereqBody": "El agente de UTMStack se comunica con el servidor a través de los siguientes puertos. Asegúrese de que estén abiertos entre el host y UTMStack antes de instalar:",
+ "sensitiveWarning": "El comando siguiente contiene un token de inscripción sensible — no lo comparta.",
+ "uninstall": {
+ "title": "Desinstalar el agente",
+ "body": "Ejecute esto en el host para detener y eliminar el agente de UTMStack y sus servicios. Utiliza la plataforma seleccionada anteriormente."
+ },
+ "macCompat": "Requiere macOS 11 (Big Sur) o posterior en Apple Silicon (M1/M2/M3 o más reciente). Los Mac basados en Intel no son compatibles."
+ },
+ "collector": {
+ "guideUnavailableTitle": "Guía de configuración no disponible",
+ "guideUnavailableBody": "Todavía no se configuró una guía para {{name}}. Contacta al administrador antes de habilitar esta integración.",
+ "genericSourceTitle": "Configurar {{name}}",
+ "genericSourceBody": "Configura la fuente para enviar eventos al Collector de UTMStack seleccionado usando estos datos de conexión.",
+ "howItWorksTitle": "Cómo funciona",
+ "howItWorksBody": "{{name}} no ejecuta un agente de UTMStack. En su lugar, instalas el colector de UTMStack en algún lugar de la red que tanto tu dispositivo {{name}} como UTMStack puedan alcanzar. {{name}} envía syslog al colector, el colector analiza, normaliza y reenvía eventos a UTMStack.",
+ "step1Title": "1 · Instalar el colector de UTMStack",
+ "step1Hint": "Ejecutar en un host Linux con acceso de red desde el dispositivo {{name}}.",
+ "step2Title": "2 · Configurar {{name}} para enviar syslog",
+ "step2Hint": "En el dispositivo {{name}}, apunta el reenvío de syslog a la dirección del colector en {{port}}.",
+ "vendorDocs": "Ver instrucciones específicas del proveedor",
+ "step3Title": "3 · Verificar",
+ "step3Body": "Dentro de algunos minutos deberías ver eventos de {{name}} bajo source: {{source}} en Log Explorer, y una nueva entrada en Fuentes de datos.",
+ "forwarder": {
+ "intro": {
+ "title": "Cómo funciona",
+ "body": "Los registros fluyen desde {{source}} hacia el UTMStack Collector, que los transmite de forma segura a UTMStack para correlación y alertas. No se instala nada en {{source}} — solo el Collector necesita ejecutarse en un host de tu red."
+ },
+ "diagram": {
+ "sourceSub": "tus registros",
+ "forwarder": "Collector",
+ "forwarderSub": "escucha en {{port}}",
+ "utmstack": "UTMStack",
+ "utmstackSub": "alertas y correlación",
+ "flow1": "registros",
+ "flow2": "seguro"
+ },
+ "noInstall": "No se instala nada en {{source}} — solo redirige sus registros al Collector.",
+ "install": {
+ "title": "Instalar el UTMStack Collector",
+ "body": "El Collector es un servicio Linux que recibe registros de tus dispositivos y los envía a UTMStack. Un solo Collector gestiona múltiples integraciones al mismo tiempo.",
+ "reuse": "¿Ya tienes un Collector en ejecución? Omite este paso — apunta {{source}} al existente usando el host y puerto indicados abajo."
+ },
+ "tls": {
+ "title": "Opcional — Habilitar cifrado TLS",
+ "intro": "Por defecto el listener acepta TCP/UDP sin cifrar. Para cifrar el tráfico syslog en tránsito, carga primero tus certificados y luego rehabilita el listener con el protocolo tls.",
+ "step1": "1 · Cargar tu certificado y clave (una vez por Collector)",
+ "step1Note": "Puedes agregar un certificado CA como tercer argumento. Si se omite, se usa el certificado hoja como CA.",
+ "step2": "2 · Rehabilitar el listener con TLS"
+ },
+ "httpsCerts": {
+ "title": "Carga el certificado TLS en el Collector",
+ "body": "Esta integración usa un listener HTTPS en el puerto {{port}}, por lo que el Collector necesita un certificado y una clave cargados antes de habilitarla:"
+ },
+ "uninstall": {
+ "title": "Opcional — Desinstalar el Collector",
+ "body": "Ejecuta este comando en el host donde está instalado el Collector para detener el servicio y eliminar todos sus archivos."
+ },
+ "instanceHeader": {
+ "title": "Cabecera de autorización",
+ "body": "Incluye esta cabecera Authorization en cada solicitud que envíes a la instancia. El secreto de la clave API solo se muestra una vez al generarla — cópialo entonces y pégalo en lugar del marcador de posición de abajo.",
+ "tabSimple": "Simple",
+ "tabBatch": "Lote"
+ },
+ "manualCommand": {
+ "title": "Optional — Enable via the command line instead",
+ "intro": "Prefer the terminal? SSH into the Collector host and run the command below — it matches whatever protocol and port you have selected above.",
+ "certStep": "1 · Load your certificate and key (once per Collector)",
+ "enableStep": "2 · Enable the integration"
+ }
+ },
+ "cisco": {
+ "source": "Cisco ASA",
+ "step1": {
+ "title": "Habilitar el listener Cisco ASA en el Collector",
+ "body": "En el host donde está instalado el Collector, ejecuta este comando para abrir el listener de registros Cisco ASA:",
+ "note": "Para usar TCP en lugar de UDP, reemplaza udp por tcp en el comando anterior."
+ },
+ "step2": {
+ "title": "Configurar Cisco ASA para reenviar registros",
+ "body": "En tu Cisco ASA, habilita syslog y apúntalo al host del Collector en el puerto {{port}}. Ejecuta estos comandos en modo EXEC privilegiado (reemplaza con el nombre de tu interfaz interna o de gestión):"
+ }
+ },
+ "ciscoSwitch": {
+ "source": "Cisco Switch",
+ "step1": {
+ "title": "Habilitar el listener Cisco Switch en el Collector",
+ "body": "En el host donde está instalado el Collector, ejecuta este comando para abrir el listener de registros Cisco Switch:",
+ "note": "Para usar TCP en lugar de UDP, reemplaza udp por tcp en el comando anterior."
+ },
+ "step2": {
+ "title": "Configurar el switch para reenviar registros",
+ "body": "En modo EXEC privilegiado de tu Cisco switch, habilita syslog y apúntalo al host del Collector en el puerto {{port}}:"
+ }
+ },
+ "ciscoMeraki": {
+ "source": "Cisco Meraki",
+ "step1": {
+ "title": "Habilitar el listener Cisco Meraki en el Collector",
+ "body": "En el host donde está instalado el Collector, ejecuta este comando para abrir el listener de registros Cisco Meraki:",
+ "note": "Para usar TCP en lugar de UDP, reemplaza udp por tcp en el comando anterior."
+ },
+ "step2": {
+ "title": "Configurar Meraki para reenviar registros",
+ "body": "En el Dashboard de Meraki, ve a Network-wide → Configure → General, desplázate a la sección Reporting y agrega un servidor syslog con la IP del Collector y el puerto {{port}}. Selecciona todos los roles que deseas reenviar."
+ }
+ },
+ "ciscoFirepower": {
+ "source": "Cisco Firepower",
+ "step1": {
+ "title": "Habilitar el listener Cisco Firepower en el Collector",
+ "body": "En el host donde está instalado el Collector, ejecuta este comando para abrir el listener de registros Cisco Firepower:",
+ "note": "Para usar TCP en lugar de UDP, reemplaza udp por tcp en el comando anterior."
+ },
+ "step2": {
+ "title": "Configurar Firepower para reenviar registros",
+ "body": "En Firepower Management Center (FMC), ve a Devices → Platform Settings, edita o crea una política y navega a Syslog → Syslog Servers. Agrega la IP del Collector con el puerto {{port}} (UDP), asigna la política a tus dispositivos y despliega."
+ }
+ },
+ "office365": {
+ "intro": {
+ "title": "Cómo funciona",
+ "body": "UTMStack se conecta a Microsoft 365 usando una app registrada en Azure AD y consulta la API de Actividad de Gestión de Office 365 para obtener eventos de auditoría y seguridad. No se instala ningún agente en tu tenant.",
+ "diagram": {
+ "source": "eventos de auditoría y seguridad",
+ "edge": "Management API",
+ "utmstackSub": "correlación y alertas"
+ },
+ "note": "UTMStack solo requiere permisos de lectura — no se solicitan permisos de escritura."
+ },
+ "appSection": "Registro de aplicación en Azure",
+ "steps": {
+ "azurePortal": {
+ "title": "Abrir Microsoft Entra ID",
+ "body": "Abre el Portal de Azure (portal.azure.com) y haz clic en Microsoft Entra ID."
+ },
+ "appRegistrations": {
+ "title": "Ir a Registros de aplicaciones",
+ "body": "En el menú izquierdo, haz clic en Registros de aplicaciones."
+ },
+ "registerApp": {
+ "title": "Registrar una nueva aplicación",
+ "body": "Haz clic en Nuevo registro. Nómbrala UTMStack O365 Agent, selecciona Solo cuentas en este directorio organizacional (Inquilino único) y haz clic en Registrar."
+ },
+ "clientSecret": {
+ "title": "Crear un secreto de cliente",
+ "body": "Ve a Certificados y secretos → Nuevo secreto de cliente. Añade una descripción, establece el vencimiento en 730 días (24 meses) y haz clic en Agregar.",
+ "copyNote": "Copia el Valor del secreto inmediatamente — solo se muestra una vez y no se puede recuperar después."
+ },
+ "apiPermissions": {
+ "title": "Agregar permisos de Office 365 Management API",
+ "body": "Ve a Permisos de API → Agregar un permiso y busca Office 365 Management APIs."
+ },
+ "activityFeed": {
+ "title": "Conceder permisos de ActivityFeed",
+ "body": "Selecciona Permisos de aplicación y añade ActivityFeed.Read y ActivityFeed.ReadDlp. Haz clic en Conceder consentimiento de administrador y confirma."
+ },
+ "graphPermissions": {
+ "title": "Agregar permisos de Microsoft Graph",
+ "body": "De vuelta en Agregar un permiso, haz clic en Microsoft Graph."
+ },
+ "delegatedPermissions": {
+ "title": "Agregar permisos delegados de SecurityAlert",
+ "body": "Selecciona Permisos delegados y añade SecurityAlert.Read.All y SecurityAlert.ReadWrite.All. Haz clic en Conceder consentimiento de administrador y confirma."
+ },
+ "appPermissions": {
+ "title": "Agregar permisos de aplicación de SecurityAlert",
+ "body": "Selecciona Permisos de aplicación y añade SecurityAlert.Read.All y SecurityAlert.ReadWrite.All. Haz clic en Conceder consentimiento de administrador y confirma."
+ },
+ "noteIds": {
+ "title": "Copiar los IDs de la aplicación",
+ "body": "Ve a la Información general de la app y copia el ID de aplicación (cliente) y el ID de directorio (inquilino). También necesitas el valor del secreto copiado en el paso 4."
+ }
+ },
+ "credentialsSection": "Credenciales",
+ "credentials": {
+ "title": "Conectar tu tenant de Microsoft 365",
+ "body": "Introduce los datos de los pasos anteriores. UTMStack verifica las credenciales antes de guardarlas. Puedes añadir múltiples grupos de configuración."
+ },
+ "fields": {
+ "tenantId": {
+ "label": "Tenant ID (ID de directorio)"
+ },
+ "clientId": {
+ "label": "Client ID (ID de aplicación)"
+ },
+ "clientSecret": {
+ "label": "Secreto de cliente"
+ },
+ "cloudEnv": {
+ "label": "Entorno de nube (opcional)",
+ "hint": "Commercial (por defecto), GCC, GCCHigh o DoD"
+ }
+ }
+ },
+ "github": {
+ "source": "GitHub",
+ "step1": {
+ "title": "Habilitar el listener de webhook de GitHub en el Collector",
+ "body": "En el host donde está instalado el Collector, ejecuta este comando para abrir el listener HTTPS de webhook para GitHub:",
+ "tokenNote": "El terminal imprimirá un token secreto — cópialo inmediatamente. No se volverá a mostrar."
+ },
+ "certWarning": {
+ "title": "GitHub requiere un certificado TLS firmado por una CA",
+ "body": "GitHub solo entrega webhooks a endpoints HTTPS con un certificado emitido por una CA pública (los certificados auto-firmados son rechazados). Asegúrate de que el host del Collector tenga un certificado de dominio válido antes de registrar el webhook."
+ },
+ "step2": {
+ "title": "Registrar el webhook en GitHub",
+ "body": "En tu repositorio u organización, ve a Settings → Webhooks → Add webhook y completa el formulario:",
+ "payloadUrl": "Payload URL",
+ "contentType": "Content type",
+ "secret": "Secret",
+ "secretHint": "Pega el token impreso por el Collector en el paso anterior.",
+ "events": "Which events",
+ "eventsHint": "Send me everything — o selecciona tipos de eventos específicos."
+ }
+ },
+ "aix": {
+ "source": "Servidor AIX",
+ "step1": {
+ "title": "Habilitar el listener AIX en el Collector",
+ "body": "En el host donde está instalado el Collector, ejecuta este comando para abrir el listener de registros AIX:",
+ "note": "Para usar TCP en lugar de UDP, reemplaza udp por tcp en el comando anterior."
+ },
+ "step2": {
+ "title": "Configurar AIX para reenviar registros",
+ "body": "En tu sistema AIX, configura el servicio syslog para redirigir sus registros al host del Collector en el puerto {{port}}. Consulta la documentación de IBM para la sintaxis exacta — varía entre versiones de AIX."
+ }
+ },
+ "as400": {
+ "intro": {
+ "title": "Cómo funciona",
+ "body": "El Colector AS/400 es un servicio Linux que se conecta directamente a tus sistemas AS/400 (IBM i) y extrae entradas del diario de seguridad, luego las envía de forma segura a UTMStack para correlación y alertas.",
+ "note": "No se instala nada en el AS/400 — el Colector se ejecuta en un host Linux que tenga acceso de red a tus sistemas AS/400.",
+ "diagram": {
+ "source": "tus diarios",
+ "edge1": "diarios",
+ "collector": "Colector AS/400",
+ "collectorSub": "extrae del AS/400",
+ "edge2": "seguro",
+ "utmstackSub": "alertas y correlación"
+ }
+ },
+ "install": {
+ "title": "Instalar el Colector AS/400",
+ "body": "Ejecuta este comando en un host Linux que pueda alcanzar tanto UTMStack como tus sistemas AS/400 por la red.",
+ "reuse": "¿Ya tienes el Colector AS/400 instalado? Omite este paso — solo agrega tus servidores al archivo de configuración en el siguiente paso."
+ },
+ "configure": {
+ "title": "Agregar tus servidores AS/400",
+ "body": "Edita as400-config.yaml en el directorio de instalación del colector y agrega cada sistema AS/400 que desees monitorear:",
+ "note": "Puedes listar múltiples servidores. El colector vigila este archivo y recarga automáticamente al guardar — sin necesidad de reinicio."
+ },
+ "journal": {
+ "title": "Habilitar el diario de auditoría en AS/400",
+ "body": "En cada sistema AS/400, asegúrate de que el diario de auditoría de seguridad QAUDJRN esté activo. Consulta la documentación de IBM para los pasos exactos — el procedimiento varía entre versiones de IBM i."
+ },
+ "uninstall": {
+ "title": "Opcional — Desinstalar el Colector",
+ "body": "Ejecuta este comando en el host donde está instalado el Colector AS/400 para detener el servicio y eliminar todos los archivos."
+ }
+ },
+ "bitdefender": {
+ "intro": {
+ "title": "Cómo funciona",
+ "body": "UTMStack se conecta a Bitdefender GravityZone usando tu clave API para configurar el Event Push Service. GravityZone envía entonces los eventos de seguridad directamente a UTMStack para correlación y alertas.",
+ "diagram": {
+ "source": "eventos de endpoints",
+ "edge": "Event Push Service",
+ "utmstackSub": "alertas y correlación"
+ },
+ "note": "No se instala nada en GravityZone — UTMStack se registra como destino de push usando credenciales de API de solo lectura."
+ },
+ "whitelist": {
+ "title": "Añadir IPs de Bitdefender a la whitelist",
+ "body": "Las siguientes IPs de Bitdefender GravityZone deben estar permitidas en tu firewall en el puerto 8000 para que el Event Push Service pueda alcanzar UTMStack:",
+ "note": "Añade estas IPs a tu firewall o grupo de seguridad antes de completar la configuración."
+ },
+ "apiSection": "Obtener credenciales API",
+ "api": {
+ "myAccount": {
+ "title": "Abrir Mi Cuenta",
+ "body": "En la consola de Bitdefender GravityZone, haz clic en My Account."
+ },
+ "accessUrl": {
+ "title": "Anotar la Access URL",
+ "body": "Desplázate hasta la sección Control Center API y guarda la Access URL — la introducirás en el formulario de credenciales. Luego abre la sección de claves API y haz clic en Add."
+ },
+ "createKey": {
+ "title": "Crear una clave API",
+ "body": "Escribe una descripción para la clave API, selecciona la opción Event Push Service API y haz clic en Save. Copia la clave generada."
+ }
+ },
+ "companySection": "Obtener IDs de empresa",
+ "company": {
+ "myCompany": {
+ "title": "Abrir Mi Empresa",
+ "body": "En la consola de GravityZone, haz clic en My Company."
+ },
+ "licensing": {
+ "title": "Anotar los IDs de empresa",
+ "body": "Abre la sección Licensing y guarda los Company IDs que quieres monitorizar — introdúcelos separados por comas en el formulario de credenciales."
+ }
+ },
+ "credentials": {
+ "title": "Introducir credenciales",
+ "body": "Rellena la Access URL, la clave API, la IP pública de UTMStack (donde GravityZone enviará los eventos) y los IDs de empresa a monitorizar. UTMStack verifica las credenciales antes de guardarlas."
+ },
+ "fields": {
+ "accessUrl": {
+ "label": "Access URL de GravityZone"
+ },
+ "connectionKey": {
+ "label": "Clave API"
+ },
+ "utmPublicIP": {
+ "label": "IP pública de UTMStack"
+ },
+ "companyIds": {
+ "label": "IDs de empresa (separados por comas)"
+ }
+ }
+ },
+ "netflow": {
+ "source": "Dispositivo de red",
+ "step1": {
+ "title": "Habilitar el listener de NetFlow en el Collector",
+ "body": "En el host donde está instalado el Collector, ejecuta este comando para abrir el colector NetFlow en el puerto 2055:",
+ "note": "NetFlow usa solo UDP — TCP y TLS no son compatibles con este protocolo."
+ },
+ "step2": {
+ "title": "Configurar el dispositivo para exportar NetFlow",
+ "body": "Apunta la exportación de NetFlow en tu router o firewall al host del Collector en el puerto {{port}} UDP. El ejemplo siguiente es para Cisco IOS — consulta la documentación de tu fabricante para otras plataformas:",
+ "note": "Reemplaza con el nombre de la interfaz donde se debe monitorizar el tráfico (p.ej. GigabitEthernet0/0). Aplica ingress/egress en cada interfaz relevante."
+ }
+ },
+ "sophos": {
+ "intro": {
+ "title": "Sophos Central — Plugin API",
+ "body": "Sophos Central proporciona APIs seguras para recuperar datos de eventos y alertas. UTMStack se conecta a esas APIs para centralizar la monitorización y mejorar la visibilidad de seguridad — sin agente ni collector.",
+ "diagram": {
+ "source": "API de Sophos Central",
+ "edge": "HTTPS API",
+ "utmstackSub": "Ingesta y correlaciona"
+ },
+ "note": "UTMStack consulta la API de Sophos Central periódicamente. Asegúrate de que las credenciales que crees tengan acceso de lectura a eventos y alertas."
+ },
+ "apiSection": "Generar credenciales API en Sophos Central",
+ "steps": {
+ "apiCredentials": {
+ "title": "Abrir la gestión de credenciales API",
+ "body": "En Sophos Central Admin, navega a Global Settings → API Credentials Management."
+ },
+ "addCredential": {
+ "title": "Crear una nueva credencial",
+ "body": "Haz clic en Add Credential. Proporciona un Nombre y una Descripción, selecciona el Rol apropiado y haz clic en Add."
+ },
+ "copyIds": {
+ "title": "Copiar el Client ID y el Client Secret",
+ "body": "Copia el Client ID y el Client Secret y guárdalos en un lugar seguro.",
+ "secretNote": "El Client Secret solo se muestra una vez. Guárdalo antes de cerrar este diálogo."
+ }
+ },
+ "credentialsSection": "Conectar con UTMStack",
+ "credentials": {
+ "title": "Añadir credenciales de Sophos Central",
+ "body": "Introduce las credenciales que acabas de crear. Puedes añadir más de una cuenta de Sophos haciendo clic en Añadir grupo de configuración."
+ },
+ "fields": {
+ "clientId": {
+ "label": "Client ID"
+ },
+ "apiKey": {
+ "label": "Client Secret / API Key"
+ }
+ }
+ },
+ "mikrotik": {
+ "source": "Router MikroTik",
+ "step1": {
+ "title": "Habilitar el listener de MikroTik en el Collector",
+ "body": "En el host donde está instalado el Collector, ejecuta este comando para abrir el listener syslog de MikroTik:",
+ "note": "Para usar TCP en lugar de UDP, reemplaza udp por tcp en el comando anterior."
+ },
+ "step2": {
+ "title": "Configurar MikroTik para reenviar registros",
+ "body": "En el router MikroTik, crea una acción de logging remota apuntando al host del Collector en el puerto {{port}} y asígnala a los topics relevantes. Ejecuta lo siguiente desde la CLI de RouterOS (Terminal en Winbox):",
+ "note": "También puedes configurarlo desde Winbox: System → Logging → pestaña Actions (añade una acción Remote) → luego la pestaña Rules (añade reglas apuntando a la nueva acción)."
+ }
+ },
+ "oracle": {
+ "source": "Servidor Oracle DB",
+ "step1": {
+ "title": "Habilitar la integración de Oracle en el Collector",
+ "body": "En el servidor donde está instalado el Collector, ejecuta el siguiente comando para comenzar a recibir logs de Oracle:",
+ "note": "El Collector comenzará a recibir eventos de syslog de Oracle en el puerto 7021."
+ },
+ "step2": {
+ "title": "Configurar rsyslog en el servidor Oracle",
+ "body": "Crea el archivo de configuración de rsyslog:",
+ "editBody": "Abre el archivo con tu editor preferido y añade la siguiente configuración. Reemplaza BASEDIR con la ruta de instalación de Oracle (p. ej., /u01/app/oracle) y con la IP o nombre de host del Collector:",
+ "note": "Usa @@:7021 en lugar de @ si prefieres entrega por TCP."
+ },
+ "step3": {
+ "title": "Reiniciar rsyslog",
+ "body": "Aplica la nueva configuración reiniciando el servicio rsyslog:"
+ },
+ "step4": {
+ "title": "Validar la configuración",
+ "body": "Envía mensajes de prueba para verificar que UTMStack está recibiendo eventos de las tres fuentes de logs de Oracle:",
+ "note": "Abre el Explorador de Logs y busca el texto del mensaje de prueba anterior para confirmar que llegaron."
+ }
+ },
+ "utmstack": {
+ "intro": {
+ "title": "Cómo funciona",
+ "body": "Esta integración automonitoriza tu despliegue de UTMStack. Un colector ligero instalado en el host de UTMStack lee los logs de los propios contenedores Docker de la plataforma y los envía de vuelta a UTMStack para correlación y alertas.",
+ "diagram": {
+ "source": "Logs de Docker",
+ "sourceSub": "Contenedores de UTMStack",
+ "edge1": "lee",
+ "collector": "Colector",
+ "collectorSub": "en el host",
+ "edge2": "ingesta",
+ "utmstackSub": "Correlaciona y alerta"
+ }
+ },
+ "requirements": {
+ "title": "Solo se ejecuta en el host de UTMStack",
+ "body": "Esta integración solo se puede instalar en una instancia de UTMStack que ejecute Ubuntu o una distribución de la familia Red Hat. Instala el colector directamente en el servidor de UTMStack."
+ },
+ "install": {
+ "title": "Instalar el colector",
+ "body": "En el host de UTMStack, elige tu sistema operativo y ejecuta el comando siguiente para descargar e instalar el colector de automonitorización:",
+ "sensitiveWarning": "Este comando contiene un token de conexión sensible. Trátalo como una contraseña y no lo compartas."
+ },
+ "after": {
+ "title": "Qué verás después de instalar",
+ "item1": "El colector se registra y aparece en Fuentes de datos.",
+ "item2": "Los logs de los contenedores de UTMStack empiezan a fluir en menos de un minuto.",
+ "item3": "Los eventos se pueden buscar en el Explorador de Logs bajo el tipo de dato utmstack."
+ },
+ "uninstall": {
+ "title": "Desinstalar el colector",
+ "body": "Para eliminar el colector de automonitorización del host de UTMStack, ejecuta:"
+ }
+ },
+ "endpoint": {
+ "title": "Detalles de conexión",
+ "hint": "Configure {{name}} para reenviar sus registros al Collector usando el host y el puerto indicados a continuación."
+ },
+ "syslog": {
+ "sections": {
+ "sendLogs": {
+ "title": "Enviar registros a UTMStack",
+ "body": "Configure su dispositivo para enviar mensajes syslog por UDP (514) o TCP (514) al agente de UTMStack."
+ },
+ "enableCollector": {
+ "title": "Habilitar el colector syslog",
+ "body": "Habilite el colector de registros y la integración syslog en el archivo de configuración donde está instalado su agente de UTMStack."
+ },
+ "activate": {
+ "title": "Activar",
+ "body": "Active el módulo de UTMStack para que los eventos comiencen a fluir en el Log Explorer."
+ }
+ }
+ },
+ "vmware": {
+ "source": "VMware ESXi",
+ "step1": {
+ "title": "Habilitar el listener de VMware en el Collector",
+ "body": "En el host donde está instalado el Collector, ejecute este comando para abrir el listener syslog de VMware ESXi. ESXi transmite por TCP:",
+ "note": "Para un canal cifrado use tls en lugar de tcp (cargue primero los certificados en el Collector)."
+ },
+ "step2": {
+ "title": "Apuntar el syslog de ESXi al Collector",
+ "body": "Abra una sesión SSH/ESXi Shell en el host (o use el vSphere Client: Host → Configure → Advanced System Settings → Syslog.global.logHost). Establezca el loghost remoto en {{host}}:{{port}} y recargue la configuración:",
+ "note": "En vSphere puede en cambio establecer Syslog.global.logHost con el mismo valor tcp://host:port en lugar de ejecutar esxcli."
+ },
+ "step3": {
+ "title": "Abrir el firewall de ESXi para syslog",
+ "body": "Permita el syslog saliente a través del firewall de ESXi para que el host pueda llegar al Collector:"
+ }
+ },
+ "eset": {
+ "source": "ESET Protect",
+ "step1": {
+ "title": "Habilitar el listener de ESET en el Collector",
+ "body": "En el host donde está instalado el Collector, ejecute este comando para abrir el listener syslog de ESET:",
+ "note": "Para usar TCP en lugar de UDP, reemplace udp por tcp en el comando anterior."
+ },
+ "console": {
+ "moreMenu": {
+ "title": "Abrir el menú More",
+ "body": "En la barra lateral de la consola ESET Protect, haga clic en el menú More."
+ },
+ "serverConfig": {
+ "title": "Abrir la configuración del servidor",
+ "body": "En More, abra la sección Server settings (Server configuration)."
+ },
+ "advanced": {
+ "title": "Expandir la configuración avanzada",
+ "body": "Haga clic en Advanced settings para expandir la lista completa de opciones de configuración."
+ },
+ "syslog": {
+ "title": "Configurar el servidor Syslog",
+ "body": "Desplácese hasta Syslog server, habilite Export logs to Syslog y establezca el destino en el host del Collector en el puerto {{port}} (UDP). ESET envía LEEF/syslog, que el Collector ingiere como el tipo de datos antivirus-esmc-eset."
+ }
+ }
+ },
+ "kaspersky": {
+ "source": "Kaspersky Security",
+ "step1": {
+ "title": "Habilitar el listener de Kaspersky en el Collector",
+ "body": "En el host donde está instalado el Collector, ejecute este comando para abrir el listener syslog de Kaspersky:",
+ "note": "Para usar TCP en lugar de UDP, reemplace udp por tcp en el comando anterior."
+ },
+ "console": {
+ "consoleSettings": {
+ "title": "Abrir Console settings → Integration",
+ "body": "En la barra lateral del Kaspersky Security Center, abra Console settings y haga clic en el submenú Integration."
+ },
+ "siem": {
+ "title": "Abrir la configuración de integración SIEM",
+ "body": "En Integration, seleccione SIEM y haga clic en el enlace Settings para abrir la configuración de exportación."
+ },
+ "configure": {
+ "title": "Configurar la exportación SIEM",
+ "body": "Habilite la exportación y configure Kaspersky para enviar eventos en formato Splunk (CEF) al host del Collector en el puerto {{port}} (UDP). El Collector los ingiere como el tipo de datos antivirus-kaspersky."
+ }
+ }
"alerts": {
"title": "Alertas",
"matching": "{{count}} coincidentes",