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 = """
DevSecOps Pipeline Explorer — Built by AYI-NEDJIMI Consultants
🌐 ayinedjimi-consultants.fr | LinkedIn | GitHub | X / Twitter