AYI-NEDJIMI's picture
Initial DevSecOps Pipeline Explorer Space
fb81c82 verified
import gradio as gr
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
from datasets import load_dataset
# ---------------------------------------------------------------------------
# Data Loading
# ---------------------------------------------------------------------------
DATASETS = {
"FR": "AYI-NEDJIMI/devsecops-pipeline-fr",
"EN": "AYI-NEDJIMI/devsecops-pipeline-en",
}
_cache = {}
def _load(lang: str) -> pd.DataFrame:
if lang not in _cache:
try:
ds = load_dataset(DATASETS[lang], split="train")
_cache[lang] = ds.to_pandas()
except Exception as e:
print(f"Error loading {lang} dataset: {e}")
_cache[lang] = pd.DataFrame()
return _cache[lang]
def _safe(df: pd.DataFrame, col: str):
"""Return column values if it exists, else empty Series."""
if col in df.columns:
return df[col].fillna("")
return pd.Series([""] * len(df), index=df.index)
def _filter_type(lang, t):
df = _load(lang)
if "type" in df.columns:
return df[df["type"] == t].reset_index(drop=True)
return df
# ---------------------------------------------------------------------------
# Helper โ€“ build a display DataFrame with only the requested columns
# ---------------------------------------------------------------------------
def _display(df, cols):
present = [c for c in cols if c in df.columns]
out = df[present].copy() if present else pd.DataFrame()
return out
# ---------------------------------------------------------------------------
# Tab builders
# ---------------------------------------------------------------------------
def tab_practices(lang, maturity_filter):
df = _filter_type(lang, "practice")
if maturity_filter and maturity_filter != "All":
df = df[_safe(df, "maturity_level") == maturity_filter]
cols = ["practice_name", "description", "benefits", "tools", "metrics"]
return _display(df, cols)
def tab_sast(lang):
df = _filter_type(lang, "sast_tool")
cols = ["name", "vendor", "supported_languages", "ci_integration", "strengths", "weaknesses"]
return _display(df, cols)
def tab_dast(lang):
df = _filter_type(lang, "dast_tool")
cols = ["name", "vendor", "scan_types", "api_support", "strengths", "weaknesses"]
return _display(df, cols)
def tab_sca(lang):
df = _filter_type(lang, "sca_tool")
cols = ["name", "vendor", "package_managers_supported", "vulnerability_db", "strengths", "weaknesses"]
return _display(df, cols)
def tab_pipeline(lang, ci_filter):
df = _filter_type(lang, "pipeline_template")
if ci_filter and ci_filter != "All":
df = df[_safe(df, "ci_platform") == ci_filter]
cols = ["pipeline_name", "stages", "yaml_example", "security_gates"]
return _display(df, cols)
def tab_container(lang):
df = _filter_type(lang, "container_security")
cols = ["category", "name", "implementation", "best_practices", "common_misconfigurations"]
return _display(df, cols)
def tab_secret(lang):
df = _filter_type(lang, "secret_management")
cols = ["name", "vendor", "features", "integration", "strengths", "weaknesses"]
return _display(df, cols)
def tab_qa(lang):
df = _filter_type(lang, "qa")
cols = ["question", "answer", "difficulty"]
return _display(df, cols)
# ---------------------------------------------------------------------------
# Pipeline detail โ€“ show yaml_example in code block
# ---------------------------------------------------------------------------
def pipeline_detail(lang, ci_filter):
df = _filter_type(lang, "pipeline_template")
if ci_filter and ci_filter != "All":
df = df[_safe(df, "ci_platform") == ci_filter]
parts = []
for _, row in df.iterrows():
name = row.get("pipeline_name", "N/A")
stages = row.get("stages", "N/A")
gates = row.get("security_gates", "N/A")
yaml_ex = row.get("yaml_example", "")
parts.append(f"### {name}\n\n**Stages:** {stages}\n\n**Security Gates:** {gates}\n\n```yaml\n{yaml_ex}\n```\n\n---\n")
return "\n".join(parts) if parts else "No pipeline templates found."
# ---------------------------------------------------------------------------
# Statistics charts
# ---------------------------------------------------------------------------
def stats_type_chart(lang):
df = _load(lang)
if "type" not in df.columns:
return go.Figure()
counts = df["type"].value_counts().reset_index()
counts.columns = ["type", "count"]
fig = px.bar(counts, x="type", y="count", title="Entries by Type",
color="type", text_auto=True)
fig.update_layout(showlegend=False)
return fig
def stats_ci_chart(lang):
df = _load(lang)
if "ci_platform" not in df.columns:
return go.Figure()
sub = df[df["ci_platform"].notna() & (df["ci_platform"] != "")]
if sub.empty:
return go.Figure()
counts = sub["ci_platform"].value_counts().reset_index()
counts.columns = ["ci_platform", "count"]
fig = px.pie(counts, names="ci_platform", values="count", title="Pipeline Templates by CI Platform")
return fig
def stats_maturity_chart(lang):
df = _load(lang)
if "maturity_level" not in df.columns:
return go.Figure()
sub = df[df["maturity_level"].notna() & (df["maturity_level"] != "")]
if sub.empty:
return go.Figure()
counts = sub["maturity_level"].value_counts().reset_index()
counts.columns = ["maturity_level", "count"]
fig = px.bar(counts, x="maturity_level", y="count", title="Practices by Maturity Level",
color="maturity_level", text_auto=True)
fig.update_layout(showlegend=False)
return fig
# ---------------------------------------------------------------------------
# Dynamic dropdown choices
# ---------------------------------------------------------------------------
def _maturity_choices(lang):
df = _filter_type(lang, "practice")
if "maturity_level" in df.columns:
vals = sorted(df["maturity_level"].dropna().unique().tolist())
else:
vals = []
return ["All"] + vals
def _ci_choices(lang):
df = _filter_type(lang, "pipeline_template")
if "ci_platform" in df.columns:
vals = sorted(df["ci_platform"].dropna().unique().tolist())
else:
vals = []
return ["All"] + vals
# ---------------------------------------------------------------------------
# Footer HTML
# ---------------------------------------------------------------------------
FOOTER_HTML = """
<div style="text-align:center; padding:20px; margin-top:30px; border-top:1px solid #444; font-size:0.9em; color:#aaa;">
<p><strong>DevSecOps Pipeline Explorer</strong> โ€” Built by AYI-NEDJIMI Consultants</p>
<p>
<a href="https://ayinedjimi-consultants.fr" target="_blank" style="margin:0 8px;">๐ŸŒ ayinedjimi-consultants.fr</a> |
<a href="https://www.linkedin.com/company/ayi-nedjimi" target="_blank" style="margin:0 8px;">LinkedIn</a> |
<a href="https://github.com/AYI-NEDJIMI" target="_blank" style="margin:0 8px;">GitHub</a> |
<a href="https://x.com/AYI_NEDJIMI" target="_blank" style="margin:0 8px;">X / Twitter</a>
</p>
</div>
"""
# ---------------------------------------------------------------------------
# Gradio App
# ---------------------------------------------------------------------------
def build_app():
with gr.Blocks(
title="DevSecOps Pipeline Explorer",
theme=gr.themes.Soft(),
) as demo:
gr.Markdown("# DevSecOps Pipeline Explorer\nExplore 130 DevSecOps practices, tools, pipeline templates, and more.")
lang = gr.Radio(["EN", "FR"], value="EN", label="Language / Langue", interactive=True)
with gr.Tabs():
# ---- 1. Practices ----
with gr.Tab("DevSecOps Practices"):
maturity_dd = gr.Dropdown(choices=_maturity_choices("EN"), value="All", label="Filter by Maturity Level")
practices_table = gr.Dataframe(value=tab_practices("EN", "All"), label="Practices", wrap=True)
btn_practices = gr.Button("Refresh")
def _refresh_practices(l, m):
return tab_practices(l, m)
btn_practices.click(_refresh_practices, [lang, maturity_dd], practices_table)
lang.change(lambda l: gr.update(choices=_maturity_choices(l), value="All"), lang, maturity_dd)
lang.change(lambda l: tab_practices(l, "All"), lang, practices_table)
maturity_dd.change(_refresh_practices, [lang, maturity_dd], practices_table)
# ---- 2. SAST ----
with gr.Tab("SAST Tools"):
sast_table = gr.Dataframe(value=tab_sast("EN"), label="SAST Tools", wrap=True)
lang.change(lambda l: tab_sast(l), lang, sast_table)
# ---- 3. DAST ----
with gr.Tab("DAST Tools"):
dast_table = gr.Dataframe(value=tab_dast("EN"), label="DAST Tools", wrap=True)
lang.change(lambda l: tab_dast(l), lang, dast_table)
# ---- 4. SCA ----
with gr.Tab("SCA Tools"):
sca_table = gr.Dataframe(value=tab_sca("EN"), label="SCA Tools", wrap=True)
lang.change(lambda l: tab_sca(l), lang, sca_table)
# ---- 5. Pipeline Templates ----
with gr.Tab("Pipeline Templates"):
ci_dd = gr.Dropdown(choices=_ci_choices("EN"), value="All", label="Filter by CI Platform")
pipeline_table = gr.Dataframe(value=tab_pipeline("EN", "All"), label="Pipeline Templates", wrap=True)
pipeline_md = gr.Markdown(value=pipeline_detail("EN", "All"), label="YAML Details")
btn_pipeline = gr.Button("Refresh")
def _refresh_pipeline(l, c):
return tab_pipeline(l, c), pipeline_detail(l, c)
btn_pipeline.click(_refresh_pipeline, [lang, ci_dd], [pipeline_table, pipeline_md])
lang.change(lambda l: gr.update(choices=_ci_choices(l), value="All"), lang, ci_dd)
lang.change(lambda l: (tab_pipeline(l, "All"), pipeline_detail(l, "All")), lang, [pipeline_table, pipeline_md])
ci_dd.change(lambda l, c: (tab_pipeline(l, c), pipeline_detail(l, c)), [lang, ci_dd], [pipeline_table, pipeline_md])
# ---- 6. Container Security ----
with gr.Tab("Container Security"):
container_table = gr.Dataframe(value=tab_container("EN"), label="Container Security", wrap=True)
lang.change(lambda l: tab_container(l), lang, container_table)
# ---- 7. Secret Management ----
with gr.Tab("Secret Management"):
secret_table = gr.Dataframe(value=tab_secret("EN"), label="Secret Management", wrap=True)
lang.change(lambda l: tab_secret(l), lang, secret_table)
# ---- 8. Q&A ----
with gr.Tab("Q&A"):
qa_table = gr.Dataframe(value=tab_qa("EN"), label="Q&A", wrap=True)
lang.change(lambda l: tab_qa(l), lang, qa_table)
# ---- 9. Statistics ----
with gr.Tab("Statistics"):
chart_type = gr.Plot(value=stats_type_chart("EN"), label="By Type")
chart_ci = gr.Plot(value=stats_ci_chart("EN"), label="By CI Platform")
chart_maturity = gr.Plot(value=stats_maturity_chart("EN"), label="By Maturity Level")
lang.change(lambda l: stats_type_chart(l), lang, chart_type)
lang.change(lambda l: stats_ci_chart(l), lang, chart_ci)
lang.change(lambda l: stats_maturity_chart(l), lang, chart_maturity)
gr.HTML(FOOTER_HTML)
return demo
if __name__ == "__main__":
demo = build_app()
demo.launch()