Skip to content
Open
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
49 changes: 43 additions & 6 deletions python/samples/02-agents/security/README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
# FIDES security samples
# Security samples

This folder contains two runnable FIDES samples that use
`agent_framework.foundry.FoundryChatClient`. Keep this README as the quick
entry point for choosing and running a sample; use
[FIDES_DEVELOPER_GUIDE.md](FIDES_DEVELOPER_GUIDE.md) for the architecture,
security model, middleware behavior, and API reference.
This folder contains runnable security samples. For FIDES architecture, security
model, middleware behavior, and API reference see
[FIDES_DEVELOPER_GUIDE.md](FIDES_DEVELOPER_GUIDE.md).

## What each sample demonstrates

| Sample | Focus | Demonstrates |
|--------|-------|--------------|
| `email_security_example.py` | Prompt injection defense | `SecureAgentConfig`, Foundry-backed email handling, `quarantined_llm`, and approval on policy violations |
| `repo_confidentiality_example.py` | Data exfiltration prevention | Confidentiality labels, Foundry-backed repository access, `max_allowed_confidentiality`, and approval before leaking private data |
| `hdp_provenance.py` | Delegation provenance | Cryptographic audit trail from authorising human to every agent action, verifiable offline with a single public key |

## Prerequisites

Expand Down Expand Up @@ -72,6 +71,44 @@ What to look for:
- Reading private content taints the context as private
- Posting private data to a public destination triggers an approval request

### `hdp_provenance.py`

This sample attaches HDP (Human Delegation Provenance) to an agent-framework `Agent`.
Every chat call is recorded as a signed Ed25519 hop; the full chain is verifiable
offline with a single public key.

Prerequisites:

```bash
pip install "agent-framework-foundry" "hdp-agent-framework" "azure-identity" python-dotenv
```

Generate a signing key once and export it:

```bash
python -c "
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
import base64; k = Ed25519PrivateKey.generate()
print('HDP_SIGNING_KEY=' + base64.urlsafe_b64encode(k.private_bytes_raw()).decode())
"
export HDP_SIGNING_KEY=<value>
```

Run it with:

```bash
uv run samples/02-agents/security/hdp_provenance.py
```

What to look for:

- `HDP chain valid: True` printed after the agent run
- `Hops recorded: N` showing how many agent turns were captured

References: [helixar.ai/about/labs/hdp/](https://helixar.ai/about/labs/hdp/) · [arXiv:2604.04522](https://arxiv.org/abs/2604.04522) · [PyPI](https://pypi.org/project/hdp-agent-framework/)

---

## Where to find the details

For the full FIDES design and API details, see
Expand Down
124 changes: 124 additions & 0 deletions python/samples/02-agents/security/hdp_provenance.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
# Copyright (c) Microsoft. All rights reserved.
# SPDX-License-Identifier: MIT
#
# This sample requires:
# pip install "agent-framework-foundry" "hdp-agent-framework" "azure-identity" python-dotenv
#
# Generate an Ed25519 signing key once:
# python -c "
# from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
# import base64; k = Ed25519PrivateKey.generate()
# print('HDP_SIGNING_KEY=' + base64.urlsafe_b64encode(k.private_bytes_raw()).decode())
# "
# export HDP_SIGNING_KEY=<value>
#
# Reference: https://helixar.ai/about/labs/hdp/
# Package: https://pypi.org/project/hdp-agent-framework/

"""
HDP Delegation Provenance - agent-framework integration

Attaches a cryptographic audit trail to an agent-framework Agent.
Every chat call is recorded as a signed delegation hop verifiable
offline with a single public key.
"""

import asyncio
import base64
import os
import sys

from agent_framework import Agent
from agent_framework.foundry import FoundryChatClient
from azure.identity import AzureCliCredential
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from dotenv import load_dotenv

# HDP middleware - pip install hdp-agent-framework
# Docs: https://helixar.ai/about/labs/hdp/
from hdp_agent_framework import HdpMiddleware, HdpPrincipal, ScopePolicy, verify_chain

load_dotenv()


def _load_signing_key() -> Ed25519PrivateKey:
raw_b64 = os.getenv("HDP_SIGNING_KEY")
if not raw_b64:
print("ERROR: HDP_SIGNING_KEY not set. See comment at top of file.")
sys.exit(1)
padding = (4 - len(raw_b64) % 4) % 4
return Ed25519PrivateKey.from_private_bytes(
base64.urlsafe_b64decode(raw_b64 + "=" * padding)
)


async def main() -> None:
private_key = _load_signing_key()

# 1. Declare what the human is authorising
middleware = HdpMiddleware(
signing_key=private_key.private_bytes_raw(),
session_id="analysis-session-2026",
principal=HdpPrincipal(id="analyst@example.com", id_type="email"),
scope=ScopePolicy(
intent="Analyse sales data and produce a written summary",
authorized_tools=["fetch_data", "write_report"],
max_hops=5,
),
)

# 2. Build agent as normal
credential = AzureCliCredential()
agent = Agent(
client=FoundryChatClient(credential=credential),
name="sales_analyst",
instructions="You are a sales analyst. Fetch data, then write a summary.",
)

# 3. Attach HDP - one line, zero agent changes
middleware.configure(agent)

# 4. Run
result = await agent.run("Analyse Q1 EMEA sales and write a one-page summary.")
print(result.text)

# 5. Verify delegation chain offline
token = middleware.export_token()
verification = verify_chain(token, private_key.public_key())

print(f"\nHDP chain valid: {verification.valid}")
print(f"Hops recorded: {verification.hop_count}")
if verification.violations:
print(f"Violations: {verification.violations}")
Comment thread
asiridalugoda marked this conversation as resolved.

# --- Tamper resistance ---
# Mutating any hop signature causes verify_chain to return valid=False.
# The first invalid hop is flagged; subsequent hops are not re-checked
# (each is verified against the cumulative chain, so later results are
# unreliable once an earlier hop is broken).
if verification.hop_count > 0:
tampered = dict(token)
tampered["chain"] = [dict(h) for h in token["chain"]]
tampered["chain"][0]["hop_signature"] = "AAAA" # simulate attacker modifying chain
tampered_result = verify_chain(tampered, private_key.public_key())
print(f"\nTampered chain valid: {tampered_result.valid}") # False
print(f"Tampered violations: {tampered_result.violations}")

# --- max_hops ---
# ScopePolicy(max_hops=N) caps delegation depth. verify_chain adds a
# violation when len(chain) > max_hops, returning valid=False.
# Example: scope=ScopePolicy(intent="...", max_hops=2)

# --- Strict vs audit mode ---
# strict=False (default) - scope violations are recorded in the token
# for post-hoc audit; the agent continues running.
# strict=True - raises HDPScopeViolationError immediately on
# any out-of-scope tool call.
# Example: HdpMiddleware(..., strict=True)

# Full spec: https://helixar.ai/about/labs/hdp/
# arXiv paper: https://arxiv.org/abs/2604.04522


if __name__ == "__main__":
asyncio.run(main())