Custom Plugins
Plugin Development Guide
This document is your definitive guide to writing a plugin that works with the Sentinel system. Follow it carefully to ensure your plugin passes verification and integrates smoothly.
1. Overview
A plugin in our system is a Python module that transforms uploaded CSV data into a Polars LazyFrame (pl.LazyFrame) with a specific schema. Your plugin will be run through a verification step to ensure:
1. It can process uploaded files without error.
2. It produces the expected columns and data types.
3. It follows specific rules for VA (Vulnerability Assessment) or Compliance workflows.
2. Plugin Lifecycle
Here’s what happens under the hood when your plugin runs:
File ingestion
The system reads one or more uploaded CSV files.
Plugin execution
Your plugin’s
process(data: bytes)function is called.The function must return either:
A
Polars LazyFrame(pl.LazyFrame)A
Polars DataFrame(pl.DataFrame) – will be converted toLazyFrameA
Pandas DataFrame– will be converted toPolars LazyFrame
Schema verification
The system validates your output against the required schema.
If column names or data types do not match, the system raises an
InvalidInputexception.
3. Required Schema
Your plugin must produce a DataFrame or LazyFrame with these exact columns and types.
✅ Order does not matter, but names and types must match. ❌ Extra or missing columns are not allowed.
VA Schema
cve
pl.String()
CVE identifier (e.g., CVE-2023-12345)
risk
pl.String()
Risk level (see acceptable values below)
host
pl.String()
Host/IP where the issue was found
port
pl.Int64()
Port number
name
pl.String()
Finding name
description
pl.String()
Human-readable explanation of the finding
remediation
pl.String()
How to fix the issue
evidence
pl.String()
Proof/details of the finding
vpr_score
pl.String()
Vendor or risk score
Compliance Schema
risk
pl.String()
Risk level (see acceptable values below)
host
pl.String()
Host/IP where the issue was found
port
pl.Int64()
Port number
name
pl.String()
Finding name
description
pl.String()
Human-readable explanation of the finding
remediation
pl.String()
How to fix the issue
evidence
pl.String()
Proof/details of the finding
status
pl.String()
Finding status (see acceptable values below)
4. Acceptable Values
Risk
CRITICAL
HIGH
MEDIUM
LOW
None (Only for Compliance)
None must not be a string. Make sure that it's not be stringify.
For compliance: None will be defaulted to MEDIUM
For VA: None is not valid value
*Risk will be referred as severity internally
Status
VA
NEW
OPEN
CLOSED
EXEMPTION
OTHERS
Even EXEMPTION and OTHERS are valid values but these typically set manually rather than uploaded.
Compliance
PASSED
FAILED
WARNING
5. VA vs Compliance Plugins
Your plugin’s output is treated differently depending on whether it’s used for VA or Compliance (HA).
VA Plugins
Everything must be provided by the plugin.
All fields (risk, description, etc.) must already be populated.
The system does not fill defaults for you.
Compliance Plugins
For compliance plugins, the system will apply post-processing before saving findings:
# Example of what happens automatically
self.finding_lf = self.finding_lf.with_columns(
# Default severity
severity=pl.col("risk").fill_null(SeverityEnum.MEDIUM.value),
# Ensure evidence not null
evidence=pl.col("evidence").fill_null(""),
)You should output risk as null if unknown, not as ""
6. Example Plugin Template
Note that the file need to accept bytes not the filename.
Using polars
import polars as pl
def process(data: bytes) -> pl.LazyFrame:
df = pl.read_csv(file)
df = df.with_columns(
risk=pl.when(pl.col("risk") == "")
.then(None) # Ensure null for HA workflow
.otherwise(pl.col("risk"))
)
# Optional can just return the dataframe
return df.lazy()
Using Pandas
Note that in pandas you need to convert bytes into BytesIO
import pandas as pd
import io
def process(data: bytes) -> pd.DataFrame:
data_csv = io.BytesIO(data)
df = pd.read_csv(data_csv)
# Do necessary transformation
return df
7. Checklist
✅ Before submitting your plugin, verify:
Last updated