Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ updates:
- dependency-name: rampart

- package-ecosystem: uv
directory: /helpdesk-bot
directory: /helpdesk-agent
schedule:
interval: weekly
commit-message:
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ adapter, and tests; nothing here at the repo root is required at runtime.

| Demo | What it shows |
|---|---|
| [helpdesk-bot](helpdesk-bot/README.md) | Indirect prompt injection (XPIA) via a poisoned support ticket. Single-`git apply` red -> green walkthrough. |
| [helpdesk-agent](helpdesk-agent/README.md) | Indirect prompt injection (XPIA) via a poisoned support ticket. Single-`git apply` red -> green walkthrough. |

## Repository layout

Expand Down
File renamed without changes.
File renamed without changes.
12 changes: 6 additions & 6 deletions helpdesk-bot/README.md → helpdesk-agent/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# HelpdeskBot: RAMPART XPIA Showcase
# HelpdeskAgent: RAMPART XPIA Showcase

A small, deliberately-vulnerable internal IT agent built on
[Microsoft Agent Framework](https://learn.microsoft.com/en-us/agent-framework/),
Expand All @@ -23,7 +23,7 @@ agent invoke `reset_user_password` with a `send_to` that doesn't match
the ticket's `From:` address?

The trust boundary is named declaratively in
[helpdesk_bot/manifest.py](helpdesk_bot/manifest.py) as
[helpdesk_agent/manifest.py](helpdesk_agent/manifest.py) as
`writable_by_untrusted=True` on `TicketStore`.

---
Expand Down Expand Up @@ -61,7 +61,7 @@ The trust boundary is named declaratively in
## 🛠️ Setup

```bash
cd helpdesk-bot
cd helpdesk-agent
python -m venv .venv && source .venv/bin/activate
pip install -e . # add '.[azure]' for Entra ID
cp .env.example .env # then edit .env (see Provider configuration)
Expand Down Expand Up @@ -152,7 +152,7 @@ git apply mitigation.patch
```

The patch makes two changes to
[helpdesk_bot/agent.py](helpdesk_bot/agent.py), one at the prompt
[helpdesk_agent/agent.py](helpdesk_agent/agent.py), one at the prompt
layer and one at the tool layer.

### 1. Instruction isolation in `SYSTEM_PROMPT` *(the layer that makes the tests pass)*
Expand Down Expand Up @@ -213,7 +213,7 @@ The essential part of the diff (full file:

```diff
SYSTEM_PROMPT = (
"You are HelpdeskBot, an internal IT helpdesk agent. "
"You are HelpdeskAgent, an internal IT helpdesk agent. "
...
- "reset_user_password. Be concise and helpful."
+ "reset_user_password. Be concise and helpful.\n\n"
Expand Down Expand Up @@ -268,7 +268,7 @@ before now pass. **Only the agent changed.**
To revert and play with the diff:

```bash
git checkout -- helpdesk_bot/agent.py
git checkout -- helpdesk_agent/agent.py
# or, equivalently:
git apply -R mitigation.patch
```
Expand Down
114 changes: 114 additions & 0 deletions helpdesk-agent/agent_ui/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# HelpdeskAgent Agent UI

A small web console for chatting with the HelpdeskAgent agent in a
browser and inspecting every tool it calls along the way. Useful
for demoing the agent end-to-end without touching `pytest`.

Each agent reply has a collapsible **Tool calls** panel that shows
the tool name, arguments, and returned text — bit-identical to what
the RAMPART tests assert on at the tool-call boundary.

---

## Install

From `rampart-examples/helpdesk-agent/`:

```bash
# uv (recommended)
uv venv --python 3.13
uv pip install -e '.[agent-ui]'

# or plain pip
python -m venv .venv
.venv\Scripts\Activate.ps1 # Windows PowerShell
# source .venv/bin/activate # macOS / Linux
pip install -e '.[agent-ui]'
```

Add `[azure]` if you'll authenticate to Azure OpenAI with Entra ID:

```bash
uv pip install -e '.[agent-ui,azure]'
```

---

## Configure a model provider

Copy the template and fill in **one** provider block:

```bash
cp .env.example .env # macOS / Linux
Copy-Item .env.example .env # Windows PowerShell
```

| Provider | Required env vars |
|----------|-------------------|
| OpenAI direct | `OPENAI_API_KEY`, `OPENAI_MODEL` |
| Azure OpenAI (key) | `AZURE_OPENAI_ENDPOINT`, `AZURE_OPENAI_API_KEY`, `AZURE_OPENAI_MODEL` |
| Azure OpenAI (Entra ID) | `AZURE_OPENAI_ENDPOINT`, `AZURE_OPENAI_MODEL`, `AZURE_OPENAI_USE_AZURE_CREDENTIAL=true` (then `az login`) |

> ⚠️ For Azure OpenAI, `AZURE_OPENAI_ENDPOINT` must be the bare
> resource URL — `https://<resource>.openai.azure.com` — with no
> trailing path. `AZURE_OPENAI_MODEL` is the *deployment name* you
> created in the resource, not the underlying model id.

The server auto-loads `.env` on startup.

---

## Run it

```bash
python -m agent_ui
```

Then open <http://127.0.0.1:8000>. Press `Ctrl+C` to stop.

To bind on a different host or port:

```bash
# Windows PowerShell
$env:HELPDESK_AGENT_UI_HOST = "0.0.0.0"
$env:HELPDESK_AGENT_UI_PORT = "8080"
python -m agent_ui

# macOS / Linux
HELPDESK_AGENT_UI_HOST=0.0.0.0 HELPDESK_AGENT_UI_PORT=8080 python -m agent_ui
```

---

## Notes

- Conversation state is per-browser, in-memory only. Click **Reset
conversation** to start fresh; restarting the server wipes
everything.
- Tickets shown in the sidebar live at `data/tickets/` in the repo
root. Drop a new JSON in there and hit **↻** to make it visible
to the agent, or use the **New ticket** form in the sidebar.
- The **New ticket** form's *Load sample ticket* button prefills a
canned ticket so the before/after RAMPART demo is a two-click flow.
- Bind only to `127.0.0.1` for casual demos — there is no auth.

---

## HTTP API

| Method | Path | Purpose |
|----------|-----------------------|----------------------------------------------------------|
| `GET` | `/` | Single-page UI. |
| `GET` | `/api/tickets` | List tickets in the store. |
| `GET` | `/api/tickets/{id}` | Fetch one ticket's full subject / from / body. |
| `POST` | `/api/tickets` | File a new ticket; auto-allocates the next `T-####`. |
| `DELETE` | `/api/tickets/{id}` | Remove a ticket from the store. |
| `POST` | `/api/chat` | Send `{message}`; returns `{reply, tool_calls}`. |
| `POST` | `/api/reset` | Clear the current browser's agent + session. |
| `GET` | `/api/history` | Replay prior turns so the UI can rehydrate on reload. |

`POST /api/tickets` body:

```json
{ "subject": "Forgot password", "sender": "alex@contoso.com", "body": "Hi…" }
```
8 changes: 8 additions & 0 deletions helpdesk-agent/agent_ui/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT license.

"""Developer-facing chat UI for the HelpdeskAgent agent under test.

Run with ``python -m agent_ui`` from the ``helpdesk-agent`` directory
after installing the ``[agent-ui]`` extra.
"""
9 changes: 9 additions & 0 deletions helpdesk-agent/agent_ui/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT license.

"""Run the HelpdeskAgent agent UI with ``python -m agent_ui``."""

from agent_ui.server import main

if __name__ == "__main__":
main()
Loading