rename explain-sigma-rules to sigma-rule-details
This commit is contained in:
parent
519c87fb04
commit
657a33a189
7 changed files with 96 additions and 95 deletions
|
@ -15,7 +15,7 @@ const FILE_NAME = getFileName(__filename);
|
|||
* @param {Object} details - The rule details object containing all rule metadata
|
||||
* @returns {Array} Formatted Slack blocks ready for display
|
||||
*/
|
||||
function getRuleExplanationBlocks(details) {
|
||||
function getSigmaRuleDetailsBlocks(details) {
|
||||
logger.debug(`${FILE_NAME}: Creating rule explanation blocks for rule: ${details?.id || 'unknown'}`);
|
||||
|
||||
if (!details) {
|
||||
|
@ -294,5 +294,5 @@ function getRuleExplanationBlocks(details) {
|
|||
}
|
||||
|
||||
module.exports = {
|
||||
getRuleExplanationBlocks
|
||||
getSigmaRuleDetailsBlocks
|
||||
};
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
*/
|
||||
const logger = require('../../../utils/logger');
|
||||
const { handleError } = require('../../../utils/error_handler');
|
||||
const { explainSigmaRule } = require('../../../services/sigma/sigma_details_service');
|
||||
const { getSigmaRuleDetails } = require('../../../services/sigma/sigma_details_service');
|
||||
const { convertRuleToBackend } = require('../../../services/sigma/sigma_backend_converter');
|
||||
const { getRuleExplanationBlocks } = require('../../../blocks/sigma/sigma_details_block');
|
||||
const { getSigmaRuleDetailsBlocks } = require('../../../blocks/sigma/sigma_details_block');
|
||||
const { getConversionResultBlocks } = require('../../../blocks/sigma/sigma_conversion_block');
|
||||
|
||||
const { SIGMA_CLI_CONFIG } = require('../../../config/appConfig');
|
||||
|
@ -38,8 +38,8 @@ const processRuleDetails = async (ruleId, respond, replaceOriginal = false, resp
|
|||
logger.info(`${FILE_NAME}: Processing details for sigma rule: ${ruleId}`);
|
||||
|
||||
// Get Sigma rule details
|
||||
logger.info(`${FILE_NAME}: Calling explainSigmaRule with ID: '${ruleId}'`);
|
||||
const result = await explainSigmaRule(ruleId);
|
||||
logger.info(`${FILE_NAME}: Calling getSigmaRuleDetails with ID: '${ruleId}'`);
|
||||
const result = await getSigmaRuleDetails(ruleId);
|
||||
|
||||
if (!result.success) {
|
||||
logger.error(`${FILE_NAME}: Rule details retrieval failed: ${result.message}`);
|
||||
|
@ -66,7 +66,7 @@ const processRuleDetails = async (ruleId, respond, replaceOriginal = false, resp
|
|||
// Generate blocks
|
||||
let blocks;
|
||||
try {
|
||||
blocks = getRuleExplanationBlocks(result.explanation);
|
||||
blocks = getSigmaRuleDetailsBlocks(result.explanation);
|
||||
} catch (blockError) {
|
||||
await handleError(blockError, `${FILE_NAME}: Block generation`, respond, {
|
||||
replaceOriginal: replaceOriginal,
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
const logger = require('../../../utils/logger');
|
||||
const { handleError } = require('../../../utils/error_handler');
|
||||
const { explainSigmaRule } = require('../../../services/sigma/sigma_details_service');
|
||||
const { getSigmaRuleDetails } = require('../../../services/sigma/sigma_details_service');
|
||||
const { convertRuleToBackend } = require('../../../services/sigma/sigma_backend_converter');
|
||||
const { sendRuleToSiem } = require('../../../services/elastic/elastic_send_rule_to_siem_service');
|
||||
const { getAllSpaces } = require('../../../services/elastic/elastic_api_service');
|
||||
|
@ -210,8 +210,8 @@ const registerSiemActions = (app) => {
|
|||
const ruleId = actionValue.replace('select_space_for_rule_', '');
|
||||
|
||||
// Get rule information to display in the space selection message
|
||||
const explainResult = await explainSigmaRule(ruleId);
|
||||
const ruleInfo = explainResult.success ? explainResult.explanation : { title: ruleId };
|
||||
const sigmaRuleDetailsResult = await getSigmaRuleDetails(ruleId);
|
||||
const ruleInfo = sigmaRuleDetailsResult.success ? sigmaRuleDetailsResult.explanation : { title: ruleId };
|
||||
|
||||
// Generate blocks for space selection
|
||||
const blocks = getSpaceSelectionBlocks(ruleId, ruleInfo);
|
||||
|
|
|
@ -1,27 +1,34 @@
|
|||
/**
|
||||
* sigma_details_handler.js
|
||||
*
|
||||
* Handles Sigma rule details requests from Slack commands
|
||||
* Handles Sigma rule details requests from both Slack commands and CLI
|
||||
* Processes requests for rule explanations
|
||||
*/
|
||||
const logger = require('../../utils/logger');
|
||||
const { handleError } = require('../../utils/error_handler');
|
||||
const { explainSigmaRule } = require('../../services/sigma/sigma_details_service');
|
||||
const { processRuleDetails } = require('./actions/sigma_action_core');
|
||||
const FILE_NAME = 'sigma_details_handler.js';
|
||||
const { getSigmaRuleDetails, getSigmaRuleYaml } = require('../../services/sigma/sigma_details_service');
|
||||
const { getSigmaRuleDetailsBlocks } = require('../../blocks/sigma/sigma_details_block');
|
||||
const { formatSigmaDetails } = require('../../utils/cli_formatters');
|
||||
|
||||
const { getFileName } = require('../../utils/file_utils');
|
||||
const FILE_NAME = getFileName(__filename);
|
||||
|
||||
/**
|
||||
* Handle the sigma-details command for Sigma rules
|
||||
*
|
||||
* @param {Object} command - The Slack command object
|
||||
* @param {Function} respond - Function to send response back to Slack
|
||||
* @param {Object} command - The Slack command or CLI command object
|
||||
* @param {Function} respond - Function to send response back to Slack or CLI
|
||||
*/
|
||||
const handleCommand = async (command, respond) => {
|
||||
try {
|
||||
logger.debug(`${FILE_NAME}: Processing sigma-details command: ${JSON.stringify(command.text)}`);
|
||||
logger.debug(`${FILE_NAME}: Processing sigma-details command: ${command.text}`);
|
||||
|
||||
if (!command || !command.text) {
|
||||
logger.warn(`${FILE_NAME}: Empty command received for sigma-details`);
|
||||
await respond('Invalid command. Usage: /sigma-details [id]');
|
||||
await respond({
|
||||
text: 'Invalid command. Usage: /sigma-details [id] or "details sigma [id]"',
|
||||
response_type: 'ephemeral'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -30,7 +37,10 @@ const handleCommand = async (command, respond) => {
|
|||
|
||||
if (!ruleId) {
|
||||
logger.warn(`${FILE_NAME}: Missing rule ID in sigma-details command`);
|
||||
await respond('Invalid command: missing rule ID. Usage: /sigma-details [id]');
|
||||
await respond({
|
||||
text: 'Invalid command: missing rule ID. Usage: /sigma-details [id] or "details sigma [id]"',
|
||||
response_type: 'ephemeral'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -40,14 +50,44 @@ const handleCommand = async (command, respond) => {
|
|||
response_type: 'ephemeral'
|
||||
});
|
||||
|
||||
// Use the shared processRuleDetails function from action handlers
|
||||
await processRuleDetails(ruleId, respond, false, 'in_channel');
|
||||
// Get the rule explanation
|
||||
const sigmaRuleDetailsResult = await getSigmaRuleDetails(ruleId);
|
||||
|
||||
if (!sigmaRuleDetailsResult.success) {
|
||||
logger.warn(`${FILE_NAME}: Failed to explain rule ${ruleId}: ${sigmaRuleDetailsResult.message}`);
|
||||
await respond({
|
||||
text: `Error: ${sigmaRuleDetailsResult.message}`,
|
||||
response_type: 'ephemeral'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// For Slack responses, generate Block Kit blocks
|
||||
let blocks;
|
||||
try {
|
||||
// This is for Slack - get the Block Kit UI components
|
||||
blocks = getSigmaRuleDetailsBlocks(sigmaRuleDetailsResult.explanation);
|
||||
} catch (blockError) {
|
||||
await handleError(blockError, `${FILE_NAME}: Block generation`, respond, {
|
||||
responseType: 'ephemeral',
|
||||
customMessage: 'Error generating rule details view'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Return the response with both blocks for Slack and responseData for CLI
|
||||
await respond({
|
||||
blocks: blocks, // For Slack
|
||||
responseData: sigmaRuleDetailsResult.explanation, // For CLI
|
||||
response_type: 'in_channel'
|
||||
});
|
||||
} catch (error) {
|
||||
await handleError(error, `${FILE_NAME}: Details command handler`, respond, {
|
||||
responseType: 'ephemeral'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
handleCommand
|
||||
};
|
|
@ -17,7 +17,7 @@ const FILE_NAME = getFileName(__filename);
|
|||
* @param {string} ruleId - The ID of the rule to explain
|
||||
* @returns {Promise<Object>} Result object with success flag and explanation or error message
|
||||
*/
|
||||
async function explainSigmaRule(ruleId) {
|
||||
async function getSigmaRuleDetails(ruleId) {
|
||||
if (!ruleId) {
|
||||
logger.warn(`${FILE_NAME}: Cannot explain rule: Missing rule ID`);
|
||||
return {
|
||||
|
@ -145,6 +145,6 @@ async function getSigmaRuleYaml(ruleId) {
|
|||
}
|
||||
|
||||
module.exports = {
|
||||
explainSigmaRule,
|
||||
getSigmaRuleDetails,
|
||||
getSigmaRuleYaml
|
||||
};
|
|
@ -48,7 +48,9 @@ async function getSigmaStats() {
|
|||
return {
|
||||
success: true,
|
||||
stats: formattedStats,
|
||||
// Include raw response data for direct use by CLI
|
||||
// Include raw response data for direct use by CLI.
|
||||
// We have one universal function in the CLI to receive responses,
|
||||
// and the CLI will then format each result differently
|
||||
responseData: formattedStats
|
||||
};
|
||||
} catch (error) {
|
||||
|
|
|
@ -6,6 +6,36 @@
|
|||
*/
|
||||
const chalk = require('chalk');
|
||||
|
||||
|
||||
/**
|
||||
* Format Sigma rule details for CLI display
|
||||
* @param {Object} ruleDetails - The rule details to format
|
||||
* @returns {Object} Formatted rule details for CLI display
|
||||
*/
|
||||
function formatSigmaDetails(ruleDetails) {
|
||||
if (!ruleDetails) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Create a flattened object for display in CLI table format
|
||||
const formattedDetails = {
|
||||
'ID': ruleDetails.id || 'Unknown',
|
||||
'Title': ruleDetails.title || 'Untitled Rule',
|
||||
'Description': ruleDetails.description || 'No description provided',
|
||||
'Author': ruleDetails.author || 'Unknown author',
|
||||
'Severity': ruleDetails.severity || 'Unknown',
|
||||
'Detection': ruleDetails.detectionExplanation || 'No detection specified',
|
||||
'False Positives': Array.isArray(ruleDetails.falsePositives) ?
|
||||
ruleDetails.falsePositives.join(', ') : 'None specified',
|
||||
'Tags': Array.isArray(ruleDetails.tags) ?
|
||||
ruleDetails.tags.join(', ') : 'None',
|
||||
'References': Array.isArray(ruleDetails.references) ?
|
||||
ruleDetails.references.join(', ') : 'None'
|
||||
};
|
||||
|
||||
return formattedDetails;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format Sigma statistics for CLI display
|
||||
*
|
||||
|
@ -92,77 +122,6 @@ function formatSigmaSearchResults(searchResults) {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Format Sigma rule details for CLI display
|
||||
*
|
||||
* @param {Object} ruleDetails - The rule details object
|
||||
* @returns {Object} Formatted details ready for CLI display
|
||||
*/
|
||||
function formatSigmaDetails(ruleDetails) {
|
||||
if (!ruleDetails) {
|
||||
return { error: 'No rule details available' };
|
||||
}
|
||||
|
||||
// Filter and format the rule details for CLI display
|
||||
const formattedDetails = {};
|
||||
|
||||
// Include only the most important fields for display
|
||||
const fieldsToInclude = [
|
||||
'id', 'title', 'description', 'status', 'author',
|
||||
'level', 'falsepositives', 'references',
|
||||
'created', 'modified'
|
||||
];
|
||||
|
||||
// Add detection information if available
|
||||
if (ruleDetails.detection && ruleDetails.detection.condition) {
|
||||
fieldsToInclude.push('detection_condition');
|
||||
formattedDetails['detection_condition'] = ruleDetails.detection.condition;
|
||||
}
|
||||
|
||||
// Add logsource information if available
|
||||
if (ruleDetails.logsource) {
|
||||
if (ruleDetails.logsource.product) {
|
||||
fieldsToInclude.push('logsource_product');
|
||||
formattedDetails['logsource_product'] = ruleDetails.logsource.product;
|
||||
}
|
||||
|
||||
if (ruleDetails.logsource.category) {
|
||||
fieldsToInclude.push('logsource_category');
|
||||
formattedDetails['logsource_category'] = ruleDetails.logsource.category;
|
||||
}
|
||||
|
||||
if (ruleDetails.logsource.service) {
|
||||
fieldsToInclude.push('logsource_service');
|
||||
formattedDetails['logsource_service'] = ruleDetails.logsource.service;
|
||||
}
|
||||
}
|
||||
|
||||
// Format date fields
|
||||
const dateFields = ['created', 'modified'];
|
||||
|
||||
for (const [key, value] of Object.entries(ruleDetails)) {
|
||||
if (fieldsToInclude.includes(key)) {
|
||||
// Format dates
|
||||
if (dateFields.includes(key) && value) {
|
||||
try {
|
||||
formattedDetails[key] = new Date(value).toLocaleString();
|
||||
} catch (e) {
|
||||
formattedDetails[key] = value;
|
||||
}
|
||||
}
|
||||
// Format arrays
|
||||
else if (Array.isArray(value)) {
|
||||
formattedDetails[key] = value.join(', ');
|
||||
}
|
||||
// Default handling
|
||||
else {
|
||||
formattedDetails[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return formattedDetails;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
formatSigmaStats,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue