Pranoy Mukherjee commited on
Commit
3a95168
·
1 Parent(s): 9237011

Update SwarmAudit final demo

Browse files
Files changed (3) hide show
  1. README.md +4 -1
  2. app/ui/gradio_app.py +14 -14
  3. tests/test_gradio_app.py +78 -6
README.md CHANGED
@@ -1,10 +1,14 @@
1
  ---
2
  title: SwarmAudit
 
 
 
3
  sdk: gradio
4
  sdk_version: 6.14.0
5
  app_file: app.py
6
  pinned: false
7
  license: mit
 
8
  ---
9
 
10
  # SwarmAudit
@@ -301,4 +305,3 @@ For the hackathon submission, highlight:
301
  - Hugging Face Space deployment
302
  - practical business value: production readiness for AI-generated code
303
  - originality: combining security, operations, dependency, and CUDA-to-ROCm portability checks in one audit workflow
304
-
 
1
  ---
2
  title: SwarmAudit
3
+ emoji: 🚀
4
+ colorFrom: blue
5
+ colorTo: cyan
6
  sdk: gradio
7
  sdk_version: 6.14.0
8
  app_file: app.py
9
  pinned: false
10
  license: mit
11
+ short_description: Multi-agent production-readiness scanner for AI-generated code
12
  ---
13
 
14
  # SwarmAudit
 
305
  - Hugging Face Space deployment
306
  - practical business value: production readiness for AI-generated code
307
  - originality: combining security, operations, dependency, and CUDA-to-ROCm portability checks in one audit workflow
 
app/ui/gradio_app.py CHANGED
@@ -570,10 +570,10 @@ button.primary:hover,
570
  color: var(--sa-text) !important;
571
  }
572
 
573
- .severity-filter-radio label:has(input[value^="Critical"]) span { color: var(--sa-red) !important; }
574
- .severity-filter-radio label:has(input[value^="High"]) span { color: var(--sa-orange) !important; }
575
- .severity-filter-radio label:has(input[value^="Medium"]) span { color: var(--sa-yellow) !important; }
576
- .severity-filter-radio label:has(input[value^="Low"]) span { color: var(--sa-blue) !important; }
577
 
578
  .severity-filter-radio span {
579
  font: 700 10px/14px JetBrains Mono, monospace !important;
@@ -1053,15 +1053,15 @@ def render_report_toolbar(report: AuditReport | None) -> str:
1053
  """
1054
 
1055
 
1056
- def build_severity_filter_choices(report: AuditReport | None) -> list[str]:
1057
  if report is None:
1058
- return ["All 0"]
1059
 
1060
  displayed_counts = {severity: 0 for severity in Severity}
1061
  for finding in report.findings:
1062
  displayed_counts[finding.severity] += 1
1063
 
1064
- choices = [f"All {len(report.findings)}"]
1065
  for severity, label in [
1066
  (Severity.critical, "Critical"),
1067
  (Severity.high, "High"),
@@ -1070,7 +1070,7 @@ def build_severity_filter_choices(report: AuditReport | None) -> list[str]:
1070
  ]:
1071
  count = displayed_counts.get(severity, 0)
1072
  if count > 0:
1073
- choices.append(f"{label} {count}")
1074
  return choices
1075
 
1076
 
@@ -1110,7 +1110,7 @@ async def analyze_repo(repo_url: str):
1110
  render_agent_swarm(),
1111
  render_empty_summary(),
1112
  render_report_toolbar(None),
1113
- gr.update(choices=["All 0"], value="All 0"),
1114
  format_report_overview_html(None),
1115
  gr.update(choices=[], value=None),
1116
  format_empty_finding_detail_html(),
@@ -1124,7 +1124,7 @@ async def analyze_repo(repo_url: str):
1124
  agent_html = render_agent_swarm(progress)
1125
  summary_html = render_empty_summary()
1126
  report_toolbar_html = render_report_toolbar(None)
1127
- severity_filter_update = gr.update(choices=["All 0"], value="All 0")
1128
  report_overview_html = format_report_overview_html(None)
1129
  finding_choice_update = gr.update(choices=[], value=None)
1130
  finding_detail_html = format_empty_finding_detail_html()
@@ -1136,7 +1136,7 @@ async def analyze_repo(repo_url: str):
1136
  if isinstance(event, AuditReport):
1137
  report_state = event
1138
  filter_choices = build_severity_filter_choices(event)
1139
- selected_filter = filter_choices[0]
1140
  severity_filter_update = gr.update(choices=filter_choices, value=selected_filter)
1141
  finding_choices = build_finding_choices(event, selected_filter)
1142
  finding_choice_update = gr.update(
@@ -1171,7 +1171,7 @@ async def analyze_repo(repo_url: str):
1171
  render_agent_swarm(progress),
1172
  render_empty_summary(),
1173
  render_report_toolbar(None),
1174
- gr.update(choices=["All 0"], value="All 0"),
1175
  format_report_overview_html(None),
1176
  gr.update(choices=[], value=None),
1177
  format_empty_finding_detail_html(),
@@ -1374,8 +1374,8 @@ def build_app() -> gr.Blocks:
1374
  with gr.Row(elem_classes=["report-header-row"]):
1375
  report_toolbar = gr.HTML(render_report_toolbar(None), scale=1)
1376
  severity_filter = gr.Radio(
1377
- choices=["All 0"],
1378
- value="All 0",
1379
  interactive=True,
1380
  show_label=False,
1381
  scale=0,
 
570
  color: var(--sa-text) !important;
571
  }
572
 
573
+ .severity-filter-radio label:has(input[value="critical"]) span { color: var(--sa-red) !important; }
574
+ .severity-filter-radio label:has(input[value="high"]) span { color: var(--sa-orange) !important; }
575
+ .severity-filter-radio label:has(input[value="medium"]) span { color: var(--sa-yellow) !important; }
576
+ .severity-filter-radio label:has(input[value="low"]) span { color: var(--sa-blue) !important; }
577
 
578
  .severity-filter-radio span {
579
  font: 700 10px/14px JetBrains Mono, monospace !important;
 
1053
  """
1054
 
1055
 
1056
+ def build_severity_filter_choices(report: AuditReport | None) -> list[tuple[str, str]]:
1057
  if report is None:
1058
+ return [("All 0", "all")]
1059
 
1060
  displayed_counts = {severity: 0 for severity in Severity}
1061
  for finding in report.findings:
1062
  displayed_counts[finding.severity] += 1
1063
 
1064
+ choices: list[tuple[str, str]] = [(f"All {len(report.findings)}", "all")]
1065
  for severity, label in [
1066
  (Severity.critical, "Critical"),
1067
  (Severity.high, "High"),
 
1070
  ]:
1071
  count = displayed_counts.get(severity, 0)
1072
  if count > 0:
1073
+ choices.append((f"{label} {count}", severity.value.lower()))
1074
  return choices
1075
 
1076
 
 
1110
  render_agent_swarm(),
1111
  render_empty_summary(),
1112
  render_report_toolbar(None),
1113
+ gr.update(choices=[("All 0", "all")], value="all"),
1114
  format_report_overview_html(None),
1115
  gr.update(choices=[], value=None),
1116
  format_empty_finding_detail_html(),
 
1124
  agent_html = render_agent_swarm(progress)
1125
  summary_html = render_empty_summary()
1126
  report_toolbar_html = render_report_toolbar(None)
1127
+ severity_filter_update = gr.update(choices=[("All 0", "all")], value="all")
1128
  report_overview_html = format_report_overview_html(None)
1129
  finding_choice_update = gr.update(choices=[], value=None)
1130
  finding_detail_html = format_empty_finding_detail_html()
 
1136
  if isinstance(event, AuditReport):
1137
  report_state = event
1138
  filter_choices = build_severity_filter_choices(event)
1139
+ selected_filter = "all"
1140
  severity_filter_update = gr.update(choices=filter_choices, value=selected_filter)
1141
  finding_choices = build_finding_choices(event, selected_filter)
1142
  finding_choice_update = gr.update(
 
1171
  render_agent_swarm(progress),
1172
  render_empty_summary(),
1173
  render_report_toolbar(None),
1174
+ gr.update(choices=[("All 0", "all")], value="all"),
1175
  format_report_overview_html(None),
1176
  gr.update(choices=[], value=None),
1177
  format_empty_finding_detail_html(),
 
1374
  with gr.Row(elem_classes=["report-header-row"]):
1375
  report_toolbar = gr.HTML(render_report_toolbar(None), scale=1)
1376
  severity_filter = gr.Radio(
1377
+ choices=[("All 0", "all")],
1378
+ value="all",
1379
  interactive=True,
1380
  show_label=False,
1381
  scale=0,
tests/test_gradio_app.py CHANGED
@@ -80,7 +80,41 @@ def test_render_report_summary_uses_report_counts():
80
  repo_url="https://github.com/example/project",
81
  scanned_file_count=4,
82
  skipped_file_count=1,
83
- findings=[],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
  severity_summary={
85
  Severity.critical: 1,
86
  Severity.high: 2,
@@ -133,7 +167,41 @@ def test_build_severity_filter_choices_uses_actual_counts():
133
  repo_url="https://github.com/example/project",
134
  scanned_file_count=4,
135
  skipped_file_count=1,
136
- findings=[],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
137
  severity_summary={
138
  Severity.critical: 1,
139
  Severity.high: 2,
@@ -144,7 +212,11 @@ def test_build_severity_filter_choices_uses_actual_counts():
144
  agents_run=["Synthesizer Agent"],
145
  )
146
 
147
- assert build_severity_filter_choices(report) == ["All 3", "Critical 1", "High 2"]
 
 
 
 
148
 
149
 
150
  def make_report_with_findings() -> AuditReport:
@@ -205,7 +277,7 @@ def test_filter_findings_returns_only_selected_severity():
205
  report = make_report_with_findings()
206
  report.findings.append(high)
207
 
208
- update, html = filter_findings("High 1", report)
209
 
210
  assert update["choices"] == ["HIGH High risk\napp.py:20 | Security Agent"]
211
  assert "High risk" in html
@@ -309,7 +381,7 @@ async def test_analyze_repo_empty_input_clears_report_exports():
309
  assert "Agent swarm" in result[1]
310
  assert "Files scanned" in result[2]
311
  assert "Audit report" in result[3]
312
- assert result[4]["choices"] == ["All 0"]
313
  assert "Security Score" in result[5]
314
  assert result[6]["choices"] == []
315
  assert result[6]["value"] is None
@@ -334,7 +406,7 @@ async def test_analyze_repo_failure_clears_report_exports(monkeypatch):
334
  assert "Agent swarm" in updates[-1][1]
335
  assert "Files scanned" in updates[-1][2]
336
  assert "Audit report" in updates[-1][3]
337
- assert updates[-1][4]["choices"] == ["All 0"]
338
  assert "Security Score" in updates[-1][5]
339
  assert updates[-1][6]["choices"] == []
340
  assert updates[-1][6]["value"] is None
 
80
  repo_url="https://github.com/example/project",
81
  scanned_file_count=4,
82
  skipped_file_count=1,
83
+ findings=[
84
+ Finding(
85
+ title="Critical issue",
86
+ severity=Severity.critical,
87
+ file_path="app.py",
88
+ line_start=1,
89
+ line_end=1,
90
+ description="Critical.",
91
+ why_it_matters="Important.",
92
+ suggested_fix="Fix.",
93
+ agent_source="Security Agent",
94
+ ),
95
+ Finding(
96
+ title="High issue one",
97
+ severity=Severity.high,
98
+ file_path="app.py",
99
+ line_start=2,
100
+ line_end=2,
101
+ description="High.",
102
+ why_it_matters="Important.",
103
+ suggested_fix="Fix.",
104
+ agent_source="Security Agent",
105
+ ),
106
+ Finding(
107
+ title="High issue two",
108
+ severity=Severity.high,
109
+ file_path="app.py",
110
+ line_start=3,
111
+ line_end=3,
112
+ description="High.",
113
+ why_it_matters="Important.",
114
+ suggested_fix="Fix.",
115
+ agent_source="Security Agent",
116
+ ),
117
+ ],
118
  severity_summary={
119
  Severity.critical: 1,
120
  Severity.high: 2,
 
167
  repo_url="https://github.com/example/project",
168
  scanned_file_count=4,
169
  skipped_file_count=1,
170
+ findings=[
171
+ Finding(
172
+ title="Critical issue",
173
+ severity=Severity.critical,
174
+ file_path="app.py",
175
+ line_start=1,
176
+ line_end=1,
177
+ description="Critical.",
178
+ why_it_matters="Important.",
179
+ suggested_fix="Fix.",
180
+ agent_source="Security Agent",
181
+ ),
182
+ Finding(
183
+ title="High issue one",
184
+ severity=Severity.high,
185
+ file_path="app.py",
186
+ line_start=2,
187
+ line_end=2,
188
+ description="High.",
189
+ why_it_matters="Important.",
190
+ suggested_fix="Fix.",
191
+ agent_source="Security Agent",
192
+ ),
193
+ Finding(
194
+ title="High issue two",
195
+ severity=Severity.high,
196
+ file_path="app.py",
197
+ line_start=3,
198
+ line_end=3,
199
+ description="High.",
200
+ why_it_matters="Important.",
201
+ suggested_fix="Fix.",
202
+ agent_source="Security Agent",
203
+ ),
204
+ ],
205
  severity_summary={
206
  Severity.critical: 1,
207
  Severity.high: 2,
 
212
  agents_run=["Synthesizer Agent"],
213
  )
214
 
215
+ assert build_severity_filter_choices(report) == [
216
+ ("All 3", "all"),
217
+ ("Critical 1", "critical"),
218
+ ("High 2", "high"),
219
+ ]
220
 
221
 
222
  def make_report_with_findings() -> AuditReport:
 
277
  report = make_report_with_findings()
278
  report.findings.append(high)
279
 
280
+ update, html = filter_findings("high", report)
281
 
282
  assert update["choices"] == ["HIGH High risk\napp.py:20 | Security Agent"]
283
  assert "High risk" in html
 
381
  assert "Agent swarm" in result[1]
382
  assert "Files scanned" in result[2]
383
  assert "Audit report" in result[3]
384
+ assert result[4]["choices"] == [("All 0", "all")]
385
  assert "Security Score" in result[5]
386
  assert result[6]["choices"] == []
387
  assert result[6]["value"] is None
 
406
  assert "Agent swarm" in updates[-1][1]
407
  assert "Files scanned" in updates[-1][2]
408
  assert "Audit report" in updates[-1][3]
409
+ assert updates[-1][4]["choices"] == [("All 0", "all")]
410
  assert "Security Score" in updates[-1][5]
411
  assert updates[-1][6]["choices"] == []
412
  assert updates[-1][6]["value"] is None