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
|
* @param {Object} details - The rule details object containing all rule metadata
|
||||||
* @returns {Array} Formatted Slack blocks ready for display
|
* @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'}`);
|
logger.debug(`${FILE_NAME}: Creating rule explanation blocks for rule: ${details?.id || 'unknown'}`);
|
||||||
|
|
||||||
if (!details) {
|
if (!details) {
|
||||||
|
@ -294,5 +294,5 @@ function getRuleExplanationBlocks(details) {
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
getRuleExplanationBlocks
|
getSigmaRuleDetailsBlocks
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,9 +5,9 @@
|
||||||
*/
|
*/
|
||||||
const logger = require('../../../utils/logger');
|
const logger = require('../../../utils/logger');
|
||||||
const { handleError } = require('../../../utils/error_handler');
|
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 { 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 { getConversionResultBlocks } = require('../../../blocks/sigma/sigma_conversion_block');
|
||||||
|
|
||||||
const { SIGMA_CLI_CONFIG } = require('../../../config/appConfig');
|
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}`);
|
logger.info(`${FILE_NAME}: Processing details for sigma rule: ${ruleId}`);
|
||||||
|
|
||||||
// Get Sigma rule details
|
// Get Sigma rule details
|
||||||
logger.info(`${FILE_NAME}: Calling explainSigmaRule with ID: '${ruleId}'`);
|
logger.info(`${FILE_NAME}: Calling getSigmaRuleDetails with ID: '${ruleId}'`);
|
||||||
const result = await explainSigmaRule(ruleId);
|
const result = await getSigmaRuleDetails(ruleId);
|
||||||
|
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
logger.error(`${FILE_NAME}: Rule details retrieval failed: ${result.message}`);
|
logger.error(`${FILE_NAME}: Rule details retrieval failed: ${result.message}`);
|
||||||
|
@ -66,7 +66,7 @@ const processRuleDetails = async (ruleId, respond, replaceOriginal = false, resp
|
||||||
// Generate blocks
|
// Generate blocks
|
||||||
let blocks;
|
let blocks;
|
||||||
try {
|
try {
|
||||||
blocks = getRuleExplanationBlocks(result.explanation);
|
blocks = getSigmaRuleDetailsBlocks(result.explanation);
|
||||||
} catch (blockError) {
|
} catch (blockError) {
|
||||||
await handleError(blockError, `${FILE_NAME}: Block generation`, respond, {
|
await handleError(blockError, `${FILE_NAME}: Block generation`, respond, {
|
||||||
replaceOriginal: replaceOriginal,
|
replaceOriginal: replaceOriginal,
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
*/
|
*/
|
||||||
const logger = require('../../../utils/logger');
|
const logger = require('../../../utils/logger');
|
||||||
const { handleError } = require('../../../utils/error_handler');
|
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 { convertRuleToBackend } = require('../../../services/sigma/sigma_backend_converter');
|
||||||
const { sendRuleToSiem } = require('../../../services/elastic/elastic_send_rule_to_siem_service');
|
const { sendRuleToSiem } = require('../../../services/elastic/elastic_send_rule_to_siem_service');
|
||||||
const { getAllSpaces } = require('../../../services/elastic/elastic_api_service');
|
const { getAllSpaces } = require('../../../services/elastic/elastic_api_service');
|
||||||
|
@ -210,8 +210,8 @@ const registerSiemActions = (app) => {
|
||||||
const ruleId = actionValue.replace('select_space_for_rule_', '');
|
const ruleId = actionValue.replace('select_space_for_rule_', '');
|
||||||
|
|
||||||
// Get rule information to display in the space selection message
|
// Get rule information to display in the space selection message
|
||||||
const explainResult = await explainSigmaRule(ruleId);
|
const sigmaRuleDetailsResult = await getSigmaRuleDetails(ruleId);
|
||||||
const ruleInfo = explainResult.success ? explainResult.explanation : { title: ruleId };
|
const ruleInfo = sigmaRuleDetailsResult.success ? sigmaRuleDetailsResult.explanation : { title: ruleId };
|
||||||
|
|
||||||
// Generate blocks for space selection
|
// Generate blocks for space selection
|
||||||
const blocks = getSpaceSelectionBlocks(ruleId, ruleInfo);
|
const blocks = getSpaceSelectionBlocks(ruleId, ruleInfo);
|
||||||
|
|
|
@ -1,27 +1,34 @@
|
||||||
/**
|
/**
|
||||||
* sigma_details_handler.js
|
* 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
|
* Processes requests for rule explanations
|
||||||
*/
|
*/
|
||||||
const logger = require('../../utils/logger');
|
const logger = require('../../utils/logger');
|
||||||
const { handleError } = require('../../utils/error_handler');
|
const { handleError } = require('../../utils/error_handler');
|
||||||
const { explainSigmaRule } = require('../../services/sigma/sigma_details_service');
|
const { getSigmaRuleDetails, getSigmaRuleYaml } = require('../../services/sigma/sigma_details_service');
|
||||||
const { processRuleDetails } = require('./actions/sigma_action_core');
|
const { getSigmaRuleDetailsBlocks } = require('../../blocks/sigma/sigma_details_block');
|
||||||
const FILE_NAME = 'sigma_details_handler.js';
|
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
|
* Handle the sigma-details command for Sigma rules
|
||||||
*
|
*
|
||||||
* @param {Object} command - The Slack command object
|
* @param {Object} command - The Slack command or CLI command object
|
||||||
* @param {Function} respond - Function to send response back to Slack
|
* @param {Function} respond - Function to send response back to Slack or CLI
|
||||||
*/
|
*/
|
||||||
const handleCommand = async (command, respond) => {
|
const handleCommand = async (command, respond) => {
|
||||||
try {
|
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) {
|
if (!command || !command.text) {
|
||||||
logger.warn(`${FILE_NAME}: Empty command received for sigma-details`);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,7 +37,10 @@ const handleCommand = async (command, respond) => {
|
||||||
|
|
||||||
if (!ruleId) {
|
if (!ruleId) {
|
||||||
logger.warn(`${FILE_NAME}: Missing rule ID in sigma-details command`);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,14 +50,44 @@ const handleCommand = async (command, respond) => {
|
||||||
response_type: 'ephemeral'
|
response_type: 'ephemeral'
|
||||||
});
|
});
|
||||||
|
|
||||||
// Use the shared processRuleDetails function from action handlers
|
// Get the rule explanation
|
||||||
await processRuleDetails(ruleId, respond, false, 'in_channel');
|
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) {
|
} catch (error) {
|
||||||
await handleError(error, `${FILE_NAME}: Details command handler`, respond, {
|
await handleError(error, `${FILE_NAME}: Details command handler`, respond, {
|
||||||
responseType: 'ephemeral'
|
responseType: 'ephemeral'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
handleCommand
|
handleCommand
|
||||||
};
|
};
|
|
@ -17,7 +17,7 @@ const FILE_NAME = getFileName(__filename);
|
||||||
* @param {string} ruleId - The ID of the rule to explain
|
* @param {string} ruleId - The ID of the rule to explain
|
||||||
* @returns {Promise<Object>} Result object with success flag and explanation or error message
|
* @returns {Promise<Object>} Result object with success flag and explanation or error message
|
||||||
*/
|
*/
|
||||||
async function explainSigmaRule(ruleId) {
|
async function getSigmaRuleDetails(ruleId) {
|
||||||
if (!ruleId) {
|
if (!ruleId) {
|
||||||
logger.warn(`${FILE_NAME}: Cannot explain rule: Missing rule ID`);
|
logger.warn(`${FILE_NAME}: Cannot explain rule: Missing rule ID`);
|
||||||
return {
|
return {
|
||||||
|
@ -145,6 +145,6 @@ async function getSigmaRuleYaml(ruleId) {
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
explainSigmaRule,
|
getSigmaRuleDetails,
|
||||||
getSigmaRuleYaml
|
getSigmaRuleYaml
|
||||||
};
|
};
|
|
@ -48,7 +48,9 @@ async function getSigmaStats() {
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
stats: formattedStats,
|
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
|
responseData: formattedStats
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
|
@ -6,6 +6,36 @@
|
||||||
*/
|
*/
|
||||||
const chalk = require('chalk');
|
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
|
* 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 = {
|
module.exports = {
|
||||||
formatSigmaStats,
|
formatSigmaStats,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue