|
| 1 | +# AI Agent Context |
| 2 | + |
| 3 | +## What This Repo Is |
| 4 | + |
| 5 | +This repo contains **two independent integrations** for running |
| 6 | +[Garak](https://github.com/NVIDIA/garak) LLM red-teaming scans. They share |
| 7 | +core logic but serve different orchestration surfaces: |
| 8 | + |
| 9 | +1. **Llama Stack Provider** — An out-of-tree eval provider for the |
| 10 | + [Llama Stack](https://llamastack.github.io/) framework. Exposes garak |
| 11 | + through the Llama Stack `benchmarks.register` / `eval.run_eval` API. |
| 12 | + |
| 13 | +2. **Eval-Hub Adapter** — A `FrameworkAdapter` for the eval-hub SDK. |
| 14 | + Completely independent of Llama Stack. Used by the RHOAI evaluation |
| 15 | + platform to orchestrate garak scans via K8s jobs. |
| 16 | + |
| 17 | +## Four Execution Modes |
| 18 | + |
| 19 | +``` |
| 20 | + Llama Stack Eval-Hub |
| 21 | + (Llama Stack API) (eval-hub SDK) |
| 22 | + ┌────────┬────────┐ ┌────────┬────────┐ |
| 23 | + │ Inline │ Remote │ │ Simple │ KFP │ |
| 24 | + │ │ KFP │ │ (pod) │ (pod + │ |
| 25 | + │ │ │ │ │ KFP) │ |
| 26 | + └────────┴────────┘ └────────┴────────┘ |
| 27 | + local KFP in-pod K8s job |
| 28 | + garak pipelines garak submits to |
| 29 | + KFP, polls |
| 30 | +``` |
| 31 | + |
| 32 | +| Mode | Code Location | How Garak Runs | Intents Support | |
| 33 | +|------|--------------|----------------|-----------------| |
| 34 | +| **Llama Stack Inline** | `inline/` | Locally in the Llama Stack server process | No | |
| 35 | +| **Llama Stack Remote KFP** | `remote/` | As KFP pipeline steps on Kubernetes | **Yes** | |
| 36 | +| **Eval-Hub Simple** | `evalhub/` (simple mode) | Directly in the eval-hub K8s job pod | No | |
| 37 | +| **Eval-Hub KFP** | `evalhub/` (KFP mode) | K8s job submits to KFP, polls status, pulls artifacts via S3 | **Yes** | |
| 38 | + |
| 39 | +**Intents** is a key upcoming feature — it uses SDG (synthetic data generation), |
| 40 | +TAPIntent probes, and MulticlassJudge detectors to test model behavior against |
| 41 | +policy taxonomies. Only the two KFP-based modes support it because it requires |
| 42 | +the six-step pipeline (`core/pipeline_steps.py`) running as KFP components. |
| 43 | + |
| 44 | +## Code Layout |
| 45 | + |
| 46 | +``` |
| 47 | +src/llama_stack_provider_trustyai_garak/ |
| 48 | +├── core/ # Shared logic used by ALL modes |
| 49 | +│ ├── config_resolution.py # Deep-merge user overrides onto benchmark profiles |
| 50 | +│ ├── command_builder.py # Build garak CLI args for OpenAI-compatible endpoints |
| 51 | +│ ├── garak_runner.py # Subprocess runner for garak CLI |
| 52 | +│ └── pipeline_steps.py # Six-step pipeline (validate→taxonomy→SDG→prompts→scan→parse) |
| 53 | +│ |
| 54 | +├── inline/ # Llama Stack Inline mode |
| 55 | +│ ├── garak_eval.py # Async adapter wrapping garak subprocess |
| 56 | +│ └── provider.py # Provider spec with pip dependencies |
| 57 | +│ |
| 58 | +├── remote/ # Llama Stack Remote KFP mode |
| 59 | +│ ├── garak_remote_eval.py # Async adapter managing KFP job lifecycle |
| 60 | +│ └── kfp_utils/ # KFP pipeline DAG and @dsl.component steps |
| 61 | +│ |
| 62 | +├── evalhub/ # Eval-Hub integration (NO Llama Stack dependency) |
| 63 | +│ ├── garak_adapter.py # FrameworkAdapter: benchmark resolution, intents overlay, callbacks |
| 64 | +│ ├── kfp_adapter.py # KFP-specific adapter (forces KFP execution mode) |
| 65 | +│ ├── kfp_pipeline.py # Eval-hub KFP pipeline with S3 artifact flow |
| 66 | +│ └── s3_utils.py # S3/Data Connection client |
| 67 | +│ |
| 68 | +├── base_eval.py # Shared Llama Stack eval lifecycle (NOT used by eval-hub) |
| 69 | +├── garak_command_config.py # Pydantic models for garak YAML config |
| 70 | +├── intents.py # Policy taxonomy dataset loading (SDG/intents flows) |
| 71 | +├── sdg.py # Synthetic data generation via sdg-hub |
| 72 | +├── result_utils.py # Parse garak outputs, TBSA scoring, HTML reports |
| 73 | +└── resources/ # Jinja2 templates and Vega chart specs |
| 74 | +``` |
| 75 | + |
| 76 | +## Key Conventions |
| 77 | + |
| 78 | +- **Config merging**: User overrides are deep-merged onto benchmark profiles via |
| 79 | + `deep_merge_dicts` in `core/config_resolution.py`. Only leaf values are replaced. |
| 80 | +- **Intents model overlay**: When `intents_models` is provided, model endpoints |
| 81 | + are applied using `x.get("key") or default` pattern — fills empty slots but |
| 82 | + preserves user-configured values. `api_key` is always forced to `__FROM_ENV__` |
| 83 | + (K8s Secret injection). |
| 84 | +- **Benchmark profiles**: Predefined configs live in `base_eval.py` (Llama Stack) |
| 85 | + and `evalhub/garak_adapter.py` (eval-hub). The `intents` profile is the most |
| 86 | + complex — it includes TAPIntent, MulticlassJudge, and SDG configuration. |
| 87 | +- **Provider specs**: `inline/provider.py` and `remote/provider.py` define Llama |
| 88 | + Stack provider specs. `pip_packages` is auto-populated from `get_garak_version()`. |
| 89 | + |
| 90 | +## Build & Install |
| 91 | + |
| 92 | +```bash |
| 93 | +pip install -e . # Core (Llama Stack remote mode) |
| 94 | +pip install -e ".[inline]" # With garak for local scans |
| 95 | +pip install -e ".[dev]" # Dev (tests + ruff + pre-commit) |
| 96 | +``` |
| 97 | + |
| 98 | +## Running Tests |
| 99 | + |
| 100 | +```bash |
| 101 | +make test # All tests (no cluster/GPU/network needed) |
| 102 | +make coverage # With coverage report |
| 103 | +make lint # ruff check |
| 104 | +``` |
| 105 | + |
| 106 | +Tests are 100% unit tests. Garak is mocked — it does not need to be installed. |
| 107 | + |
| 108 | +## Debugging |
| 109 | + |
| 110 | +- `GARAK_SCAN_DIR` — controls where scan artifacts land |
| 111 | +- `LOG_LEVEL=DEBUG` — verbose eval-hub adapter logging |
| 112 | +- `scan.log` in scan directory — garak subprocess output |
| 113 | +- `__FROM_ENV__` in configs — placeholder for K8s Secret api_key injection |
0 commit comments