Skip to content

Commit 4ffca42

Browse files
committed
fix(csv file generation bug):
1 parent 653e9a7 commit 4ffca42

File tree

6 files changed

+52
-20
lines changed

6 files changed

+52
-20
lines changed

agentic_security/models/schemas.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ class ScanResult(BaseModel):
3535
prompt: str = ""
3636
model: str = ""
3737
refused: bool = False
38+
latency: float = 0.0
3839

3940
@classmethod
4041
def status_msg(cls, msg: str) -> str:
@@ -48,6 +49,7 @@ def status_msg(cls, msg: str) -> str:
4849
prompt="",
4950
model="",
5051
refused=False,
52+
latency=0,
5153
).model_dump_json()
5254

5355

agentic_security/probe_actor/fuzzer.py

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import asyncio
22
import random
33
from collections.abc import AsyncGenerator
4-
4+
import time
55
import httpx
66
import pandas as pd
77
from loguru import logger
@@ -44,7 +44,7 @@ def multi_modality_spec(llm_spec):
4444

4545

4646
async def process_prompt(
47-
request_factory, prompt, tokens, module_name, refusals, errors
47+
request_factory, prompt, tokens, module_name, refusals, errors, outputs
4848
) -> tuple[int, bool]:
4949
"""
5050
Process a single prompt and update the token count and failure status.
@@ -63,10 +63,12 @@ async def process_prompt(
6363
response_text = response.text
6464
tokens += len(response_text.split())
6565

66-
if refusal_heuristic(response.json()):
66+
refused = refusal_heuristic(response.json())
67+
if refused:
6768
refusals.append((module_name, prompt, response.status_code, response_text))
68-
return tokens, True
69-
return tokens, False
69+
70+
outputs.append((module_name, prompt, response_text, refused))
71+
return tokens, refused
7072

7173
except httpx.RequestError as exc:
7274
logger.error(f"Request error: {exc}")
@@ -98,6 +100,7 @@ async def perform_single_shot_scan(
98100

99101
errors = []
100102
refusals = []
103+
outputs = []
101104
total_prompts = sum(len(m.prompts) for m in prompt_modules if not m.lazy)
102105
processed_prompts = 0
103106

@@ -131,14 +134,17 @@ async def perform_single_shot_scan(
131134
100 * processed_prompts / total_prompts if total_prompts else 0
132135
)
133136
total_tokens -= tokens
137+
start = time.time()
134138
tokens, failed = await process_prompt(
135139
request_factory,
136140
prompt,
137141
tokens,
138142
module.dataset_name,
139143
refusals,
140144
errors,
145+
outputs,
141146
)
147+
end = time.time()
142148
total_tokens += tokens
143149
# logger.debug(f"Trying prompt: {prompt}, {failed=}")
144150
if failed:
@@ -147,13 +153,22 @@ async def perform_single_shot_scan(
147153
failure_rates.append(failure_rate)
148154
cost = calculate_cost(tokens)
149155

156+
# TODO: improve this cond
157+
last_output = outputs[-1] if outputs else None
158+
if last_output and last_output[1] == prompt:
159+
response_text = last_output[2]
160+
else:
161+
response_text = ""
162+
150163
yield ScanResult(
151164
module=module.dataset_name,
152165
tokens=round(tokens / 1000, 1),
153166
cost=cost,
154167
progress=round(progress, 2),
155168
failureRate=round(failure_rate * 100, 2),
156169
prompt=prompt[:MAX_PROMPT_LENGTH],
170+
latency=end - start,
171+
model=response_text,
157172
).model_dump_json()
158173

159174
if optimize and len(failure_rates) >= 5:
@@ -219,6 +234,7 @@ async def perform_many_shot_scan(
219234

220235
errors = []
221236
refusals = []
237+
outputs = []
222238
total_prompts = sum(len(m.prompts) for m in prompt_modules if not m.lazy)
223239
processed_prompts = 0
224240

@@ -270,6 +286,7 @@ async def perform_many_shot_scan(
270286
module.dataset_name,
271287
refusals,
272288
errors,
289+
outputs,
273290
)
274291
if failed:
275292
module_failures += 1

agentic_security/probe_actor/test_fuzzer.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ async def test_successful_response_no_refusal(self):
209209
module_name="module_a",
210210
refusals=[],
211211
errors=[],
212+
outputs=[],
212213
)
213214

214215
self.assertEqual(tokens, 3) # Tokens from "Valid response text"
@@ -226,13 +227,15 @@ async def test_successful_response_with_refusal(self):
226227
)
227228

228229
refusals = []
230+
outputs = []
229231
tokens, refusal = await process_prompt(
230232
request_factory=mock_request_factory,
231233
prompt="test prompt",
232234
tokens=0,
233235
module_name="module_a",
234236
refusals=refusals,
235237
errors=[],
238+
outputs=outputs,
236239
)
237240

238241
self.assertEqual(tokens, 3) # Tokens from "Response indicating refusal"
@@ -257,6 +260,7 @@ async def test_http_error_response(self):
257260
module_name="module_a",
258261
refusals=refusals,
259262
errors=[],
263+
outputs=[],
260264
)
261265

262266
async def test_request_error(self):
@@ -273,6 +277,7 @@ async def test_request_error(self):
273277
module_name="module_a",
274278
refusals=[],
275279
errors=errors,
280+
outputs=[],
276281
)
277282

278283
self.assertEqual(tokens, 0)

agentic_security/static/base.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11

2-
let URL = window.location.href;
3-
if (URL.endsWith('/')) {
4-
URL = URL.slice(0, -1);
2+
let SELF_URL = window.location.href;
3+
if (SELF_URL.endsWith('/')) {
4+
SELF_URL = SELF_URL.slice(0, -1);
55
}
6-
URL = URL.replace('/#', '');
6+
SELF_URL = SELF_URL.replace('/#', '');
77

88
// Vue application
99
let LLM_SPECS = [
10-
`POST ${URL}/v1/self-probe
10+
`POST ${SELF_URL}/v1/self-probe
1111
Authorization: Bearer XXXXX
1212
Content-Type: application/json
1313
@@ -79,7 +79,7 @@ Content-Type: application/json
7979
]
8080
}
8181
`,
82-
`POST ${URL}/v1/self-probe-image
82+
`POST ${SELF_URL}/v1/self-probe-image
8383
Authorization: Bearer XXXXX
8484
Content-Type: application/json
8585
@@ -101,7 +101,7 @@ Content-Type: application/json
101101
}
102102
]
103103
`,
104-
`POST ${URL}/v1/self-probe-file
104+
`POST ${SELF_URL}/v1/self-probe-file
105105
Authorization: Bearer $GROQ_API_KEY
106106
Content-Type: multipart/form-data
107107

agentic_security/static/index.html

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,6 @@ <h2 class="text-2xl font-bold mb-4">Select a Config</h2>
9595
<h2 class="text-2xl font-bold">LLM API Spec</h2>
9696
<span :class="statusDotClass"
9797
class="w-3 h-3 rounded-full mr-2"></span>
98-
<span v-if="latency" class="text-sm text-gray-400 ml-2">Latency: {{latency}}s</span>
9998
<svg :class="{'rotate-180': showLLMSpec}"
10099
class="w-6 h-6 transition-transform duration-200"
101100
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
@@ -140,6 +139,8 @@ <h2 class="text-2xl font-bold">LLM API Spec</h2>
140139
<strong class="font-bold">></strong>
141140
<span class="block sm:inline">{{okMsg}}</span>
142141
</div>
142+
<span v-if="latency" class="text-sm text-gray-400 ml-2">Latency: {{latency}}s</span>
143+
143144

144145
<!-- Action Buttons -->
145146
<section class="flex justify-center space-x-4 mt-10">
@@ -419,6 +420,8 @@ <h3 class="text-lg font-semibold">Enable Many-shot
419420
<strong class="font-bold">></strong>
420421
<span class="block sm:inline">{{okMsg}}</span>
421422
</div>
423+
<span v-if="latency" class="text-sm text-gray-400 ml-2">Latency: {{latency}}s</span>
424+
422425

423426
<!-- Action Buttons -->
424427
<section class="flex justify-center space-x-4">

agentic_security/static/main.js

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,8 @@ var app = new Vue({
193193
let payload = {
194194
spec: this.modelSpec,
195195
};
196-
const response = await fetch(`${URL}/verify`, {
196+
let startTime = performance.now(); // Capture start time
197+
const response = await fetch(`${SELF_URL}/verify`, {
197198
method: 'POST',
198199
headers: {
199200
'Content-Type': 'application/json',
@@ -202,7 +203,10 @@ var app = new Vue({
202203
});
203204
console.log(response);
204205
let r = await response.json();
205-
this.latency = r.elapsed;
206+
let endTime = performance.now(); // Capture end time
207+
let latency = endTime - startTime; // Calculate latency in milliseconds
208+
latency = latency.toFixed(3) / 1000; // Round to 2 decimal places
209+
this.latency = latency;
206210
if (!response.ok) {
207211
this.updateStatusDot(false);
208212
this.errorMsg = 'Integration verification failed:' + JSON.stringify(r);
@@ -218,7 +222,7 @@ var app = new Vue({
218222
this.saveStateToLocalStorage();
219223
},
220224
loadConfigs: async function () {
221-
const response = await fetch(`${URL}/v1/data-config`, {
225+
const response = await fetch(`${SELF_URL}/v1/data-config`, {
222226
method: 'GET',
223227
headers: {
224228
'Content-Type': 'application/json',
@@ -290,6 +294,7 @@ var app = new Vue({
290294
this.okMsg = `${event.module}`;
291295
return
292296
}
297+
this.latency = event.latency.toFixed(3);
293298
console.log('New event');
294299
// { "module": "Module 49", "tokens": 480, "cost": 4.800000000000001, "progress": 9.8 }
295300
let progress = event.progress;
@@ -325,14 +330,14 @@ var app = new Vue({
325330
let payload = {
326331
table: this.mainTable,
327332
};
328-
const response = await fetch(`${URL}/plot.jpeg`, {
333+
const response = await fetch(`${SELF_URL}/plot.jpeg`, {
329334
method: 'POST',
330335
headers: {
331336
'Content-Type': 'application/json',
332337
},
333338
body: JSON.stringify(payload),
334339
});
335-
// Convert image response to a data URL for the <img> src
340+
// Convert image response to a data SELF_URL for the <img> src
336341
const blob = await response.blob();
337342
const reader = new FileReader();
338343
reader.readAsDataURL(blob);
@@ -375,7 +380,7 @@ var app = new Vue({
375380
},
376381
stopScan: async function () {
377382
this.scanRunning = false;
378-
const response = await fetch(`${URL}/stop`, {
383+
const response = await fetch(`${SELF_URL}/stop`, {
379384
method: 'POST',
380385
headers: {
381386
'Content-Type': 'application/json',
@@ -391,7 +396,7 @@ var app = new Vue({
391396
optimize: this.optimize,
392397
enableMultiStepAttack: this.enableMultiStepAttack,
393398
};
394-
const response = await fetch(`${URL}/scan`, {
399+
const response = await fetch(`${SELF_URL}/scan`, {
395400
method: 'POST',
396401
headers: {
397402
'Content-Type': 'application/json',

0 commit comments

Comments
 (0)