add profile
This commit is contained in:
@@ -10,6 +10,7 @@ DEFAULT_CONFIG: dict[str, object] = {
|
|||||||
"graylog_mcp_url": "",
|
"graylog_mcp_url": "",
|
||||||
"graylog_stream": "",
|
"graylog_stream": "",
|
||||||
"graylog_streams": [],
|
"graylog_streams": [],
|
||||||
|
"graylog_stream_profiles": [],
|
||||||
"graylog_query": "*",
|
"graylog_query": "*",
|
||||||
"graylog_field_mapping": "",
|
"graylog_field_mapping": "",
|
||||||
"llm_enabled": False,
|
"llm_enabled": False,
|
||||||
@@ -52,6 +53,8 @@ class ConfigStore:
|
|||||||
{"id": str(item.get("id", "")), "title": str(item.get("title", "")), "enabled": bool(item.get("enabled"))}
|
{"id": str(item.get("id", "")), "title": str(item.get("title", "")), "enabled": bool(item.get("enabled"))}
|
||||||
for item in value if isinstance(item, dict) and item.get("id")
|
for item in value if isinstance(item, dict) and item.get("id")
|
||||||
]
|
]
|
||||||
|
elif key == "graylog_stream_profiles" and isinstance(value, list):
|
||||||
|
current[key] = [item for item in value if isinstance(item, dict) and item.get("stream_id")]
|
||||||
elif isinstance(value, str):
|
elif isinstance(value, str):
|
||||||
current[key] = value.strip()
|
current[key] = value.strip()
|
||||||
self.path.parent.mkdir(parents=True, exist_ok=True)
|
self.path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ HTML = """<!doctype html>
|
|||||||
<div data-view="overview" class="active"><section class="panel"><h2>AI Assessment</h2><div id="llmAssessment" class="muted">LLM assessment disabled.</div></section><section class="split"><div class="panel"><h2>Anomalies</h2><div id="anomalies"></div></div><div class="panel"><h2>Recommendations</h2><div id="recommendations"></div></div></section></div>
|
<div data-view="overview" class="active"><section class="panel"><h2>AI Assessment</h2><div id="llmAssessment" class="muted">LLM assessment disabled.</div></section><section class="split"><div class="panel"><h2>Anomalies</h2><div id="anomalies"></div></div><div class="panel"><h2>Recommendations</h2><div id="recommendations"></div></div></section></div>
|
||||||
<div data-view="findings"><section class="panel"><h2>Related Activity Across Sources</h2><div id="relatedActivity"></div></section><section class="split"><div class="panel"><h2>Block Candidates</h2><div id="blocks"></div></div><div class="panel"><h2>Threat Intelligence</h2><div id="reputation"></div></div></section><section class="panel"><h2>Policy Findings</h2><div id="policies"></div></section></div>
|
<div data-view="findings"><section class="panel"><h2>Related Activity Across Sources</h2><div id="relatedActivity"></div></section><section class="split"><div class="panel"><h2>Block Candidates</h2><div id="blocks"></div></div><div class="panel"><h2>Threat Intelligence</h2><div id="reputation"></div></div></section><section class="panel"><h2>Policy Findings</h2><div id="policies"></div></section></div>
|
||||||
<div data-view="diagnostics"><section class="panel"><h2>Diagnostics</h2><div id="diagnostics"></div></section></div>
|
<div data-view="diagnostics"><section class="panel"><h2>Diagnostics</h2><div id="diagnostics"></div></section></div>
|
||||||
<div data-view="settings"><section class="panel"><h2>Runtime Configuration</h2><form id="settingsForm"><div class="grid"><label>Log source<br><select name="log_source"><option value="local_syslog">Local syslog</option><option value="graylog_mcp">Graylog MCP</option></select></label><label>Graylog MCP URL<br><input name="graylog_mcp_url" type="url" placeholder="https://graylog.example/api/mcp"></label><label>Graylog streams<br><button type="button" id="loadStreams">Load streams</button><div id="streamPicker" class="muted">Load streams after URL and token are saved.</div></label><label>Graylog query<br><input name="graylog_query" placeholder="*"></label><label>Graylog field mapping (JSON)<br><textarea name="graylog_field_mapping" placeholder='{"srcip":"client_ip","dstip":"server_ip","action":"event_action"}'></textarea></label><label>Graylog MCP token<br><input name="graylog_mcp_token" type="password" placeholder="Leave blank to keep current token"></label><label>Ollama model<br><input name="llm_model" placeholder="llama3.1"></label><label><input name="llm_enabled" type="checkbox"> Enable Ollama analysis</label><label><input name="threat_intel_enabled" type="checkbox"> Enable threat intelligence</label></div><p><button type="submit">Save configuration</button> <span id="settingsResult" class="muted"></span></p></form></section></div>
|
<div data-view="settings"><section class="panel"><h2>Runtime Configuration</h2><form id="settingsForm"><div class="grid"><label>Log source<br><select name="log_source"><option value="local_syslog">Local syslog</option><option value="graylog_mcp">Graylog MCP</option></select></label><label>Graylog MCP URL<br><input name="graylog_mcp_url" type="url" placeholder="https://graylog.example/api/mcp"></label><label>Graylog streams<br><button type="button" id="loadStreams">Load streams</button><div id="streamPicker" class="muted">Load streams after URL and token are saved.</div></label><label>Discover fields<br><button type="button" id="loadFields">Load selected stream fields</button><div id="fieldPicker" class="muted">Select a stream first.</div></label><label>Graylog query<br><input name="graylog_query" placeholder="*"></label><label>Graylog field mapping (JSON)<br><textarea name="graylog_field_mapping" placeholder='{"srcip":"client_ip","dstip":"server_ip","action":"event_action"}'></textarea></label><label>Graylog MCP token<br><input name="graylog_mcp_token" type="password" placeholder="Leave blank to keep current token"></label><label>Ollama model<br><input name="llm_model" placeholder="llama3.1"></label><label><input name="llm_enabled" type="checkbox"> Enable Ollama analysis</label><label><input name="threat_intel_enabled" type="checkbox"> Enable threat intelligence</label></div><p><button type="submit">Save configuration</button> <span id="settingsResult" class="muted"></span></p></form></section></div>
|
||||||
</main>
|
</main>
|
||||||
<script>
|
<script>
|
||||||
function esc(value) {
|
function esc(value) {
|
||||||
@@ -192,6 +192,12 @@ async function loadStreams() {
|
|||||||
document.getElementById('streamPicker').innerHTML = (payload.streams || []).map(stream => `<label><input type="checkbox" class="graylog-stream" data-id="${esc(stream.id)}" data-title="${esc(stream.title)}" ${selected.has(stream.id) ? 'checked' : ''}> ${esc(stream.title)}</label><br>`).join('') || esc(payload.error || 'No streams found.');
|
document.getElementById('streamPicker').innerHTML = (payload.streams || []).map(stream => `<label><input type="checkbox" class="graylog-stream" data-id="${esc(stream.id)}" data-title="${esc(stream.title)}" ${selected.has(stream.id) ? 'checked' : ''}> ${esc(stream.title)}</label><br>`).join('') || esc(payload.error || 'No streams found.');
|
||||||
}
|
}
|
||||||
document.getElementById('loadStreams').addEventListener('click', loadStreams);
|
document.getElementById('loadStreams').addEventListener('click', loadStreams);
|
||||||
|
document.getElementById('loadFields').addEventListener('click', async () => {
|
||||||
|
const selected = document.querySelector('.graylog-stream:checked');
|
||||||
|
if (!selected) { document.getElementById('fieldPicker').textContent = 'Select and save one stream first.'; return; }
|
||||||
|
const payload = await (await fetch(`/api/graylog/fields?stream_id=${encodeURIComponent(selected.dataset.id)}`)).json();
|
||||||
|
document.getElementById('fieldPicker').innerHTML = (payload.fields || []).map(field => `<div><code>${esc(field.name || field.field)}</code> ${esc(field.type || '')} ${esc((field.capabilities || []).join(', '))}</div>`).join('') || esc(payload.error || 'No fields found.');
|
||||||
|
});
|
||||||
document.getElementById('settingsForm').addEventListener('submit', async event => {
|
document.getElementById('settingsForm').addEventListener('submit', async event => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
const form = event.currentTarget;
|
const form = event.currentTarget;
|
||||||
@@ -243,6 +249,19 @@ def serve_dashboard(host: str, port: int, status_file: str, *, image_dir: str |
|
|||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
self._send(400, "application/json", json.dumps({"error": str(exc)}).encode("utf-8"))
|
self._send(400, "application/json", json.dumps({"error": str(exc)}).encode("utf-8"))
|
||||||
return
|
return
|
||||||
|
if self.path.startswith("/api/graylog/fields?"):
|
||||||
|
stream_id = self.path.split("stream_id=", 1)[-1].split("&", 1)[0]
|
||||||
|
config = config_store.read()
|
||||||
|
try:
|
||||||
|
client = GraylogMcpClient(str(config.get("graylog_mcp_url", "")), str(config.get("graylog_mcp_token", "")))
|
||||||
|
client.probe()
|
||||||
|
result = client.call_tool("list_fields", {"streams": [stream_id]})
|
||||||
|
content = result.get("result", {}).get("content", [])
|
||||||
|
text = next((item.get("text", "") for item in content if isinstance(item, dict)), "")
|
||||||
|
self._send(200, "application/json", json.dumps({"fields": json.loads(text)}).encode("utf-8"))
|
||||||
|
except Exception as exc:
|
||||||
|
self._send(400, "application/json", json.dumps({"error": str(exc)}).encode("utf-8"))
|
||||||
|
return
|
||||||
if self.path == "/api/status":
|
if self.path == "/api/status":
|
||||||
if status_path.exists():
|
if status_path.exists():
|
||||||
body = status_path.read_bytes()
|
body = status_path.read_bytes()
|
||||||
|
|||||||
Reference in New Issue
Block a user