-
Notifications
You must be signed in to change notification settings - Fork 634
New LLM feature: Starred events to forensic report (stored as a Story) #3332
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 95 commits
b856f54
752ea57
5debf0f
70d0699
59ce086
9e2c294
5f252a9
c040159
7e4bed6
9ab391e
5d4746a
390cd09
ad4d70b
71fcdd9
aa267cc
bd8d6d2
290afc6
fb9b668
0858b7f
89c86d3
1bcd2b1
be335ae
f379b0e
2e669d0
1e58a28
3e21195
37481e2
d028f0f
f4471b2
e7e82d4
e171e4d
1cf49c0
0b3f251
bb2bc88
5bf333e
d55b7b7
9ebbb94
6814079
25e7042
222e9af
e76ffcf
d997d3f
a4276ee
8895e2a
766330e
7cac889
092711f
9922596
ef1219c
1bd252c
4f37d7f
0abd597
5df8c2e
a1e7a29
e2c3c66
6549bbd
9d8e343
1a213a2
3f9c7f0
2baf0af
e46be97
be0b2ef
56bcd6d
09bca8b
5478dcd
4f9a0b7
a82d776
75f55f1
317eec8
3086dee
2bb1b68
a2f675d
bc20bf0
27592c9
e794a0e
83bdf56
024e862
ed1d5f5
41e3512
e75f12d
7928776
3ffb54b
f3065b9
26701bf
4f2a4fc
b3c94f2
2e62649
85daa75
3451d56
3b2d35f
ad53af7
082c8e2
e8c2067
8689eae
6210d52
59b18a4
085caa5
04199c0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| You are a highly skilled digital forensic analyst. Your task is to analyze a set of security events, which have been identified as potentially significant ("starred events") in a Timesketch investigation. Based on these events, generate a concise forensic report summary, formatted in Markdown. | ||
|
|
||
| Focus on identifying: | ||
|
|
||
| * **Incident Overview:** Provide a brief summary of what appears to have happened based on these events. What type of incident is suggested (e.g., unauthorized access, malware infection, data breach attempt)? | ||
| * **Key Findings:** Highlight the most important observations and indicators from the events. Be specific and mention key entities (usernames, IP addresses, file paths, process names) involved. | ||
| * **Timeline of Significant Events (Chronological Order):** Briefly outline the sequence of key actions observed in the starred events. | ||
| * **Potential Impact/Severity:** Assess the potential impact or severity of the incident based on the available information. | ||
| * **Recommended Next Steps:** Suggest 2-3 concrete next steps for the investigation based on your analysis. | ||
|
|
||
| Use bolding (**...**) for key entities and findings. Format the output as a Markdown document. | ||
|
|
||
| Here are the events in JSON format: <events><EVENTS_JSON></events> |
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think for the prod deployment we also need add the prompt file to the |
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please remove |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -255,6 +255,17 @@ limitations under the License. | |
| <v-icon title="Download current view as CSV">mdi-download</v-icon> | ||
| </v-btn> | ||
|
|
||
| <v-btn | ||
| icon | ||
| @click="generateForensicReport()" | ||
| class="ml-2" | ||
| :loading="isGeneratingReport" | ||
| v-if="isStarredEventsFilterActive"> | ||
| <div class="ts-llm-icon-wrapper" v-if="!isGeneratingReport"> | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| <v-icon title="Generate forensic report with LLM from starred events">mdi-file-document-check</v-icon> | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| </div> | ||
| </v-btn> | ||
|
|
||
| <v-menu v-if="!disableSettings" offset-y :close-on-content-click="false"> | ||
| <template v-slot:activator="{ on, attrs }"> | ||
| <v-btn icon v-bind="attrs" v-on="on"> | ||
|
|
@@ -592,6 +603,7 @@ export default { | |
| itemsPerPage: this.itemsPerPage, | ||
| }, | ||
| isSummaryLoading: false, | ||
| isGeneratingReport: false, | ||
| currentItemsPerPage: this.itemsPerPage, | ||
| expandedRows: [], | ||
| selectedFields: [{ field: 'message', type: 'text' }], | ||
|
|
@@ -631,6 +643,11 @@ export default { | |
| } | ||
| }, | ||
| computed: { | ||
| isStarredEventsFilterActive() { | ||
| return this.filterChips.some(chip => | ||
| chip.type === 'label' && chip.value === '__ts_star' | ||
| ) | ||
| }, | ||
jkppr marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| summaryInfoMessage() { | ||
| const totalEvents = this.eventList.meta.summary_event_count | ||
| const uniqueEvents = this.eventList.meta.summary_unique_event_count | ||
|
|
@@ -964,7 +981,6 @@ export default { | |
| } else { | ||
| this.errorSnackBar(msg) | ||
| } | ||
| console.error('Error message: ' + msg) | ||
| console.error(e) | ||
| }) | ||
| }, | ||
|
|
@@ -986,6 +1002,35 @@ export default { | |
| this.isSummaryLoading = false | ||
| }) | ||
| }, | ||
| generateForensicReport() { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you really want to call it a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fair point, in that case I opt we go for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. agreed |
||
| if (this.totalHits > 1000) { | ||
| this.warningSnackBar('This feature is currently limited to a 1000 starred events, try setting a timerange filter. ' + | ||
| 'This limit will be increased soon.', 10000); | ||
|
Comment on lines
+1007
to
+1008
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What about making this limit configurable in the timesketch.conf? This would allow admins to increase it themself if the like to any time. In general: Lets remove the "This limit will be increased soon." part from the message. It is out of the control of the TS operator or user and we don't have a timeline for when we can increase it. So not having this, is long-term more reliable than having this and never increase the limit. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will remove this last part of the message. Making it configurable for an admin I'm not a fan of at the moment, because if they increase the limit to a size that won't fit inside the chosen LLM provider's context window, the feature will break. So better if we can control this setting for now until we can include such granular settings. |
||
| return; | ||
| } | ||
|
|
||
| this.isGeneratingReport = true; | ||
| const requestData = { | ||
| filter: this.currentQueryFilter | ||
| }; | ||
|
|
||
| ApiClient.llmRequest(this.sketch.id, 'llm_forensic_report', requestData) | ||
| .then((response) => { | ||
| this.isGeneratingReport = false; | ||
| if (response.data && response.data.story_id) { | ||
| this.$store.dispatch('updateSketch', this.sketch.id); | ||
| this.successSnackBar('Forensic report generated! You can find it in the "Stories" section.'); | ||
| } else { | ||
| this.errorSnackBar('Error generating report. No story was created.'); | ||
| } | ||
| }) | ||
| .catch((error) => { | ||
| this.isGeneratingReport = false; | ||
| const errorMessage = (error.response && error.response.data && error.response.data.message) || 'Unknown error occurred'; | ||
| this.errorSnackBar(`Error generating report: ${errorMessage}`); | ||
| console.error('Error generating starred events report:', error); | ||
| }); | ||
| }, | ||
| exportSearchResult: function () { | ||
| this.exportDialog = true | ||
| const now = new Date() | ||
|
|
@@ -1277,20 +1322,19 @@ th:first-child { | |
| padding: 0 0 0 10px !important; | ||
| } | ||
|
|
||
| .ts-event-list-container { | ||
| display: flex; | ||
| flex-direction: column; | ||
| width: 100%; | ||
| gap: 20px; | ||
| } | ||
|
Comment on lines
+1325
to
+1330
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you explain why this is needed? We have the same config further down already? |
||
| .ts-ai-summary-card { | ||
| border: 1px solid transparent !important; | ||
| border-radius: 8px; | ||
| background-color: #fafafa; | ||
| background-image: | ||
| linear-gradient(white, white), | ||
| linear-gradient(90deg, | ||
| #8ab4f8 0%, | ||
| #81c995 20%, | ||
| #f8c665 40%, | ||
| #ec7764 60%, | ||
| #b39ddb 80%, | ||
| #8ab4f8 100% | ||
| ); | ||
| linear-gradient(white, white), | ||
| var(--llm-gradient); | ||
| background-origin: border-box; | ||
| background-clip: content-box, border-box; | ||
| background-size: 300% 100%; | ||
|
|
@@ -1299,38 +1343,27 @@ th:first-child { | |
| display: block; | ||
| margin-bottom: 20px; | ||
| } | ||
|
|
||
| .v-data-table { | ||
| display: block; /* Ensure block display for data table */ | ||
| } | ||
|
|
||
| @keyframes borderBeamIridescent-subtle { | ||
| @keyframes borderBeamIridescent-subtle { | ||
| 0% { | ||
| background-position: 0% 50%; | ||
| } | ||
| 100% { | ||
| background-position: 100% 50%; | ||
| } | ||
| } | ||
|
|
||
| .theme--dark.ts-ai-summary-card { | ||
| background-color: #1e1e1e; | ||
| border-color: hsla(0,0%,100%,.12) !important; | ||
| background-image: | ||
| linear-gradient(#1e1e1e, #1e1e1e), | ||
| linear-gradient(90deg, | ||
| #8ab4f8 0%, | ||
| #81c995 20%, | ||
| #f8c665 40%, | ||
| #ec7764 60%, | ||
| #b39ddb 80%, | ||
| #8ab4f8 100% | ||
| ); | ||
| box-shadow: 0 2px 5px rgba(255, 255, 255, 0.08); | ||
| linear-gradient(#1e1e1e, #1e1e1e), | ||
| var(--llm-gradient);; | ||
| box-shadow: 0 2px 5px rgba(255, 255, 255, 0.08); | ||
| display: block; | ||
| margin-bottom: 20px; | ||
| } | ||
|
|
||
| .ts-ai-summary-text { | ||
| white-space: pre-line; | ||
| word-wrap: break-word; | ||
|
|
@@ -1339,37 +1372,30 @@ th:first-child { | |
| padding-left: 10px; | ||
| padding-right: 10px; | ||
| } | ||
|
|
||
| .ts-ai-summary-card .v-btn--icon { | ||
| cursor: pointer; | ||
| } | ||
|
|
||
| .ts-ai-summary-card .v-btn--icon:hover { | ||
| opacity: 0.8; | ||
| } | ||
|
|
||
| .ts-summary-placeholder-line { | ||
| height: 1em; | ||
| background-color: #e0e0e0; | ||
| margin-bottom: 0.5em; | ||
| border-radius: 4px; | ||
| width: 100%; | ||
| } | ||
|
|
||
| .ts-summary-placeholder-line.short { | ||
| width: 60%; | ||
| } | ||
|
|
||
| .ts-summary-placeholder-line.long { | ||
| width: 80%; | ||
| } | ||
|
|
||
| .shimmer { | ||
| background: linear-gradient(to right, #e0e0e0 8%, #f0f0f0 18%, #e0e0e0 33%); | ||
| background-size: 800px 100%; | ||
| animation: shimmer-animation 1.5s infinite linear forwards; | ||
| } | ||
|
|
||
| @keyframes shimmer-animation { | ||
| 0% { | ||
| background-position: -468px 0; | ||
|
|
@@ -1378,32 +1404,50 @@ th:first-child { | |
| background-position: 468px 0; | ||
| } | ||
| } | ||
|
|
||
| .ts-event-list-container { | ||
| display: flex; | ||
| flex-direction: column; | ||
| width: 100%; | ||
| gap: 20px; | ||
| } | ||
|
|
||
| ::v-deep .no-transition { | ||
| transition: none !important; | ||
| } | ||
|
|
||
| .ts-ai-summary-card-title { | ||
| display: flex; | ||
| align-items: baseline; | ||
| } | ||
|
|
||
| .ts-ai-summary-title { | ||
| margin-right: 8px; | ||
| font-weight: normal; | ||
| } | ||
|
|
||
| .ts-ai-summary-subtitle { | ||
| font-size: 0.7em; | ||
| color: grey; | ||
| vertical-align: middle; | ||
| display: inline-block; | ||
| } | ||
| .ts-llm-icon-wrapper { | ||
| position: relative; | ||
| display: inline-flex; | ||
| align-items: center; | ||
| justify-content: center; | ||
| } | ||
| .ts-llm-icon-wrapper::after { | ||
| content: ""; | ||
| position: absolute; | ||
| top: -4px; | ||
| left: -4px; | ||
| right: -4px; | ||
| bottom: -4px; | ||
| border-radius: 50%; | ||
| background: var(--llm-gradient); | ||
| background-size: 300% 100%; | ||
| opacity: 0.2; | ||
| animation: borderBeamIridescent-subtle 6s linear infinite; | ||
| z-index: -1; | ||
| } | ||
| .v-btn:hover .ts-llm-icon-wrapper::after { | ||
| opacity: 0.4; | ||
| } | ||
| </style> | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please rename variables as discussed.
llm_starred_events_reportetc