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
7 changes: 7 additions & 0 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,13 @@ ENV PATH="/opt/venv/bin:$PATH"
# vscode user already exists in the base image, just ensure sudo access
RUN echo "vscode ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers

# Install Node.js 20.x and npm for frontend development
RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
&& apt-get install -y nodejs \
&& npm install -g npm@latest \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

# Pre-create common user caches and fix permissions
RUN mkdir -p /home/vscode/.cache/pre-commit \
&& mkdir -p /home/vscode/.vscode-server \
Expand Down
11 changes: 8 additions & 3 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,10 @@
"**/dist/**": true,
"**/pyrit/auxiliary_attacks/gcg/attack/**": true,
"**/doc/**": true,
"**/.mypy_cache/**": true
"**/.mypy_cache/**": true,
"**/frontend/node_modules/**": true,
"**/frontend/dist/**": true,
"**/dbdata/**": true
},
"search.exclude": {
"**/node_modules": true,
Expand All @@ -77,10 +80,12 @@
"ms-python.python",
"ms-toolsai.jupyter",
"ms-azuretools.vscode-docker",
"tamasfe.even-better-toml"
"tamasfe.even-better-toml",
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode"
]
}
},
"postCreateCommand": "/bin/bash -i .devcontainer/devcontainer_setup.sh",
"forwardPorts": [4213, 5000, 8888]
"forwardPorts": [3000, 4213, 5000, 8000, 8888]
}
16 changes: 16 additions & 0 deletions .devcontainer/devcontainer_setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,20 @@ else
echo "✅ pyproject.toml has not changed, skipping installation."
fi

# Install frontend dependencies
echo "📦 Installing frontend dependencies..."

# Fix node_modules permissions (volume is owned by root)
if [ -d "/workspace/frontend/node_modules" ]; then
echo "Fixing node_modules permissions..."
sudo chown -R vscode:vscode /workspace/frontend/node_modules
fi

cd /workspace/frontend
if [ -f "package.json" ]; then
npm install
echo "✅ Frontend dependencies installed."
fi
cd /workspace

echo "🚀 Dev container setup complete!"
2 changes: 2 additions & 0 deletions .devcontainer/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ services:
- precommit-cache:/home/vscode/.cache/pre-commit:cached
- mypy-cache:/workspace/.mypy_cache:cached
- pylance-cache:/home/vscode/.cache/pylance:cached
- node-modules:/workspace/frontend/node_modules:cached
- ~/.pyrit:/home/vscode/.pyrit:cached
network_mode: "host"
# Note: ports section is not needed with host network mode
Expand All @@ -29,3 +30,4 @@ volumes:
precommit-cache:
mypy-cache:
pylance-cache:
node-modules:
24 changes: 24 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,27 @@ build/
**/*$py.class
**/.pytest_cache/
**/.mypy_cache/

# Environment files with secrets
.env
.env.*
*.env

# Database files with conversation history
dbdata/
results/
default_memory.json.memory
*.db
*.sqlite

# Azure and other credentials
.azure/
*.pem
*.key
*.pfx
*.p12

# Frontend build artifacts (will be built inside Docker)
frontend/node_modules/
frontend/dist/
frontend/.vite/
28 changes: 28 additions & 0 deletions frontend/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Dependencies
node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

# Build outputs
dist/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering; do you think the existing cli code should go in frontend? I think so, but curious what you think

dist-ssr/
*.local

# Editor
.vscode/*
!.vscode/extensions.json
.idea/
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

# Environment
.env
.env.local
.env.*.local
48 changes: 48 additions & 0 deletions frontend/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# PyRIT Frontend

Modern TypeScript + React frontend for PyRIT, built with Fluent UI.

## Quick Start

### Installation

```bash
npm install
```

### Running the Frontend

```bash
# Start the frontend server
python dev.py start

# Stop the frontend server
python dev.py stop

# Restart the frontend server
python dev.py restart
```

The frontend will be available at `http://localhost:3000`

### Alternative: Using npm directly

```bash
npm run dev
```

### Building for Production

```bash
npm run build
```

The built files will be in the `dist/` directory.

## Tech Stack

- **React 18** - UI framework
- **TypeScript** - Type safety
- **Fluent UI v9** - Microsoft design system
- **Vite** - Fast build tool
Configure this in `vite.config.ts` if needed.
118 changes: 118 additions & 0 deletions frontend/dev.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT license.

"""
Minimal script to manage PyRIT frontend (no backend)
"""

import platform
import subprocess
import sys
import time
from pathlib import Path

# Determine workspace root (parent of frontend directory)
FRONTEND_DIR = Path(__file__).parent.absolute()


def is_windows():
return platform.system() == "Windows"


def kill_process_by_pattern(pattern):
"""Kill processes matching a pattern (cross-platform)"""
try:
if is_windows():
# Windows: use taskkill
subprocess.run(
f'taskkill /F /FI "COMMANDLINE like %{pattern}%" >nul 2>&1',
shell=True,
check=False,
)
else:
# Unix: use pkill
subprocess.run(["pkill", "-f", pattern], check=False, stderr=subprocess.DEVNULL)
except Exception as e:
print(f"Warning: Could not kill {pattern}: {e}")


def stop_frontend():
"""Stop the frontend server"""
print("🛑 Stopping frontend...")
kill_process_by_pattern("vite")
time.sleep(1)
print("✅ Frontend stopped")


def start_frontend():
"""Start the Vite frontend"""
print("🎨 Starting minimal PyRIT frontend on port 3000...")
print(" (No backend - this is a standalone demo)")

# Start frontend process
npm_cmd = "npm.cmd" if is_windows() else "npm"

if is_windows():
frontend = subprocess.Popen(
[npm_cmd, "run", "dev"],
cwd=FRONTEND_DIR,
creationflags=subprocess.CREATE_NEW_PROCESS_GROUP,
)
else:
frontend = subprocess.Popen([npm_cmd, "run", "dev"], cwd=FRONTEND_DIR)

time.sleep(2)
print()
print("✅ Frontend running!")
print(f" URL: http://localhost:3000 (PID: {frontend.pid})")
print()
print("Press Ctrl+C to stop")

return frontend


def wait_for_interrupt(frontend):
"""Wait for user interrupt and cleanup"""
try:
frontend.wait()
except KeyboardInterrupt:
print()
print("🛑 Stopping frontend...")

try:
if not is_windows():
frontend.terminate()
frontend.wait(timeout=5)
except: # noqa: E722
frontend.kill()

print("✅ Frontend stopped")


def main():
"""Main entry point"""
if len(sys.argv) > 1:
command = sys.argv[1].lower()

if command == "stop":
stop_frontend()
return
elif command == "restart":
stop_frontend()
time.sleep(1)
elif command in ["start", "frontend"]:
pass # Start frontend
else:
print(f"Unknown command: {command}")
print("Usage: python dev.py [start|stop|restart]")
sys.exit(1)

# Start frontend
frontend = start_frontend()

# Wait for interrupt
wait_for_interrupt(frontend)


if __name__ == "__main__":
main()
13 changes: 13 additions & 0 deletions frontend/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>PyRIT - Python Risk Identification Tool</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
Loading