PIIDetector and SandboxEscapeDetector were wired directly in
probe_actor/refusal.py and the refusal classifier manager was populated from
a hardcoded list, so the only way to toggle a bundled detector or add an
organization-specific signature was to patch the module.
Add a DetectorRegistry mapping plugin names to factories, assembled from an
agentic_security.toml [detectors] section via build_from_config. Custom
detectors load by import path ("pkg.module:ClassName"). refusal.py gains
build_refusal_manager(config=None) reading the [detectors] table; all public
symbols are preserved. Built-in leak detectors ship registered but disabled,
so default refusal_heuristic behaviour is unchanged.
Closes#82
Signed-off-by: Devam Shah <devamshah91@gmail.com>
Closes#307
Agno was imported by nothing, had undefined-variable bugs,
and was not a declared dependency.
Removed:
- agentic_security/agents/ (operator_agno.py)
- docs/mcp_agno_integration.md
- .gitignore reference to operator_agno.py
No agno references remain in source code.
Pre-existing test failures (missing tabulate module) confirmed
unrelated to this change via git stash verification.
Previously, calculate_cost() was always called without a model parameter,
causing all scans to report costs based on deepseek-chat pricing regardless
of the actual target model (e.g. gpt-4, claude-3-opus).
Changes:
- http_spec.py: Add 'model_name' property to LLMSpec that extracts the
model field from the JSON request body. Returns 'unknown' if the body
is not valid JSON or has no 'model' field.
- probe_data/image_generator.py: Add 'model_name' pass-through property
to RequestAdapter, delegating to the underlying LLMSpec.
- probe_data/audio_generator.py: Same as above - add 'model_name'
pass-through property to RequestAdapter.
- probe_actor/cost_module.py:
- Change return type from float to float | None.
- Unknown models now log a warning and return None instead of raising
ValueError, so scans are not interrupted by unsupported model names.
- Add logger import for the warning message.
- probe_actor/fuzzer.py: Pass model_name to calculate_cost() in both
scan_module() and perform_many_shot_scan() using
getattr(request_factory, 'model_name', 'unknown').
- primitives/models.py: Update ScanResult.cost type from float to
float | None to accommodate unknown model pricing.
msj_data.py contained a full copy of the ProbeDataset dataclass that
was already defined canonically in probe_data/models.py, violating DRY
and leaving a stale TODO comment in the source.
Changes:
- probe_data/msj_data.py: delete the 19-line duplicate ProbeDataset
definition and the now-unused 'from dataclasses import dataclass'
import; replace with a single re-export:
from agentic_security.probe_data.models import ProbeDataset
All call-sites inside the file (load_dataset_generic, prepare_prompts)
continue to work unchanged because the field signatures are identical.
The TODO comment is removed as the refactor is now complete.
No changes required in consumers (fuzzer.py, test_msj_data.py) because
they access ProbeDataset through msj_data's re-export.
The /scan-csv endpoint was reading the uploaded CSV file but discarding
the content (TODO comment), resulting in scans that ran with zero prompts.
Changes:
- routes/scan.py: parse uploaded CSV via parse_csv_content(), pass the
extracted prompts as inline_datasets to the Scan model; also fix the
maxBudget query parameter being silently ignored (hardcoded to 1000).
- probe_data/data.py: add parse_csv_content(bytes) -> ProbeDataset that
looks for a 'prompt' column first, falls back to the first text column,
and raises ValueError when no suitable column is found.
- primitives/models.py: add inline_datasets: list[dict] field to Scan
model for carrying uploaded prompts through the scan pipeline.
- probe_actor/fuzzer.py: perform_single_shot_scan now accepts
inline_datasets and appends them as ProbeDataset objects to the scan
modules; scan_router transparently forwards the field.
Removes Content-Length from request headers before sending with httpx
to prevent LocalProtocolError when placeholder replacement (e.g.
<<PROMPT>>) changes the body size. httpx calculates the correct
Content-Length from the actual content.
Closes#139
Closes#193
Expands the MCP server section with:
- what tools are exposed and what each one does
- step-by-step Claude Desktop setup
- the three built-in prompt templates and when to use them
- a short example conversation showing natural-language scan control
- Claude Code CLI setup for terminal-based workflows
Closes#192
Three prompt templates via @mcp.prompt():
- security_scan_prompt: full scan with configurable probe budget
- verify_llm_prompt: quick reachability check before committing to a scan
- adversarial_probe_prompt: multi-step attack session with findings summary
Placed before the tool definitions with a clear section comment.
No existing tool behaviour changed.