diff --git a/crowdsec-docs/docusaurus.config.ts b/crowdsec-docs/docusaurus.config.ts index 5a6133218..ab2b8fbc7 100644 --- a/crowdsec-docs/docusaurus.config.ts +++ b/crowdsec-docs/docusaurus.config.ts @@ -6,6 +6,8 @@ import { themes } from "prism-react-renderer"; import tailwindPlugin from "./plugins/tailwind-config"; import { ctiApiSidebar, guidesSideBar, remediationSideBar } from "./sidebarsUnversioned"; +const extractPreprocessor = require("./plugins/extract-preprocessor"); + const generateCurrentAndNextRedirects = (s) => [ { from: `/docs/${s}`, @@ -220,6 +222,7 @@ const config: Config = { admonitions: true, headingIds: true, }, + preprocessor: extractPreprocessor, }, stylesheets: [ { diff --git a/crowdsec-docs/plugins/extract-preprocessor.js b/crowdsec-docs/plugins/extract-preprocessor.js new file mode 100644 index 000000000..aaa07affc --- /dev/null +++ b/crowdsec-docs/plugins/extract-preprocessor.js @@ -0,0 +1,104 @@ +const fs = require('fs'); +const path = require('path'); + +// --- CONFIGURATION --- +// The directories to scan for snippets +const DOCS_DIRS = ['./docs', './unversioned']; +// --------------------- + +const snippetRegistry = new Map(); +let isIndexed = false; + +// Helper: Recursively find all .md/.mdx files +const getAllFiles = (dirPath, arrayOfFiles = []) => { + if (!fs.existsSync(dirPath)) return arrayOfFiles; + + const files = fs.readdirSync(dirPath); + files.forEach((file) => { + const fullPath = path.join(dirPath, file); + if (fs.statSync(fullPath).isDirectory()) { + getAllFiles(fullPath, arrayOfFiles); + } else if (file.endsWith('.md') || file.endsWith('.mdx')) { + arrayOfFiles.push(fullPath); + } + }); + return arrayOfFiles; +}; + +// Helper: Extract Doc ID from Frontmatter +const getDocId = (content, filename) => { + const idMatch = content.match(/^---\s+[\s\S]*?\nid:\s*(.*?)\s*[\n\r]/m); + if (idMatch && idMatch[1]) { + return idMatch[1].replace(/['"]/g, '').trim(); + } + return filename; +}; + +// --- CORE LOGIC --- +const buildIndex = () => { + if (isIndexed) return; + console.log('[ExtractPreprocessor] ⚡ Indexing snippets via Regex...'); + + const allFiles = []; + DOCS_DIRS.forEach(dir => getAllFiles(path.resolve(process.cwd(), dir), allFiles)); + + let count = 0; + + // Regex to find:
CONTENT
+ // We use [\s\S]*? to match content across multiple lines (lazy match) + const extractRegex = /]*>([\s\S]*?)<\/div>/g; + + allFiles.forEach(filePath => { + try { + const content = fs.readFileSync(filePath, 'utf8'); + const filename = path.basename(filePath, path.extname(filePath)); + const docId = getDocId(content, filename); + + let match; + // Loop through all matches in the file + while ((match = extractRegex.exec(content)) !== null) { + let [fullTag, extractId, snippetContent] = match; + + // Clean up the content (optional: trim leading/trailing newlines) + snippetContent = snippetContent.replace(/^\n+|\n+$/g, ''); + + // Generate Key: "docId:snippetId" + // If the ID already has a colon, assume user provided full ID + const key = extractId.includes(':') ? extractId : `${docId}:${extractId}`; + + snippetRegistry.set(key, snippetContent); + console.log(`[ExtractPreprocessor] ⚡ Indexed snippet: ${key}`); + count++; + } + } catch (e) { + console.warn(`[ExtractPreprocessor] Failed to read ${filePath}`); + } + }); + + isIndexed = true; + console.log(`[ExtractPreprocessor] ⚡ Indexed ${count} snippets.`); +}; + +// This function is called by Docusaurus for EVERY markdown file +const preprocessor = ({ filePath, fileContent }) => { + // 1. Ensure Index exists (runs once) + buildIndex(); + + // 2. Regex to find:
+ // Matches
OR
+ const copyRegex = /\s*(?:<\/div>)?/g; + + // 3. Replace with content + return fileContent.replace(copyRegex, (match, requestedId) => { + if (snippetRegistry.has(requestedId)) { + // Return the stored snippet content + return snippetRegistry.get(requestedId); + } else { + console.error(`[ExtractPreprocessor] ❌ Snippet not found: "${requestedId}" in ${path.basename(filePath)}`); + // Return an error message in the UI so you see it + return `> **Error: Snippet "${requestedId}" not found.**`; + } + }); +}; + +module.exports = preprocessor; \ No newline at end of file diff --git a/crowdsec-docs/unversioned/troubleshooting/console_issues.md b/crowdsec-docs/unversioned/troubleshooting/console_issues.md index 144d0cdc9..7140df999 100644 --- a/crowdsec-docs/unversioned/troubleshooting/console_issues.md +++ b/crowdsec-docs/unversioned/troubleshooting/console_issues.md @@ -14,6 +14,7 @@ This page lists all possible health check issues, their trigger conditions, and - 🌟 **Bonus** : Optimization advises and upper tier recommendation with great return on value *(comming in next iterations of Stack Health)* ## Health Check Issues Overview +
| Issue | Criticality | Summary | Resolution | |-------|-------------|---------|------------| @@ -27,6 +28,7 @@ This page lists all possible health check issues, their trigger conditions, and | **Security Engine Offline** | 🔥 Critical | Security Engine has not reported to Console for 24+ hours | [Troubleshooting](/u/troubleshooting/issue_se_offline) | | **Security Engine Too Many Alerts** | ⚠️ High | More than 250,000 alerts in 6 hours | [Troubleshooting](/u/troubleshooting/issue_se_too_many_alerts) | +
## Issue Dependencies Some issues are related and share common root causes: diff --git a/crowdsec-docs/unversioned/troubleshooting/intro.md b/crowdsec-docs/unversioned/troubleshooting/intro.md index 2d0f97695..36391ce7c 100644 --- a/crowdsec-docs/unversioned/troubleshooting/intro.md +++ b/crowdsec-docs/unversioned/troubleshooting/intro.md @@ -77,3 +77,7 @@ When using `cscli` to list your parsers, scenarios and collections, some might a ### Which information is sent to your services ? See [CAPI documentation](/docs/next/central_api/intro). + +### stack Health issues list + +
\ No newline at end of file