Skip to content

Commit 8e1bd80

Browse files
dalpanclaude
andcommitted
feat: Pretexta v2 — major platform overhaul for DEF CON Singapore 2026
Complete platform rewrite with new features, Indonesian content, and fixes: PLATFORM ARCHITECTURE - Role-based access: admin / trainer / user with separate dashboards - Event-sourced simulation runtime with RiskVector (6 Cialdini dimensions) - AIGateway abstraction for 6 LLM providers (Gemini, OpenAI, Anthropic, etc.) - PersonaEngine for behavioral simulation state management - Training groups + assignment system (trainer → user workflow) NEW FEATURES - Glossary CRUD: admin-managed social engineering terminology - User History & Analytics: instructor view of any user's simulation logs - Campaign Gameplay: multi-stage attack chains with stage-by-stage progress - Indonesian Content Library: 6 scenarios + 3 quizzes in Indonesian context - 6 new AI personas with Indonesian workplace context (DJP, BRI CS, BEC WhatsApp) - 3 sample campaigns: BUMN infiltration, employee awareness, PNS red team INDONESIAN SCENARIOS (new) - Phishing DJP: NPWP verification scam - WhatsApp OTP hijacking - CEO Fraud targeting BUMN (Rp 4.75B transfer) - BRI bank vishing (caller ID spoofing) - BSSN spear phishing targeting PNS - Social engineering via rapport building BUG FIXES - Assignment deep-link: Start button now launches specific content directly - Mission logs: delete restricted to admin only - Scenarios/Quiz page: 0 nodes/questions display fixed (MongoDB aggregation) - Campaign stages: now actually playable end-to-end with auto-progress - Select.Item empty string error in Assignments page - Scenario player: no longer auto-navigates to History on load failure - Challenge/Quiz schema: all fields made optional (eliminates 422 errors) BACKEND - New routes: /glossary, /instructor/user-history, /campaigns/stage/*/start - YAML seeder runs on every startup (upsert-by-title, no duplicate imports) - Campaign YAML type support in import_yaml.py and server auto-import - Glossary seeded with 22 initial Indonesian + global terms on first run Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent bb5641a commit 8e1bd80

230 files changed

Lines changed: 44258 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"permissions": {
3+
"allow": [
4+
"Read(//mnt/d/DEFCON/Pretexta/**)",
5+
"Bash(python -c ' *)",
6+
"Bash(git -C \"d:/DEFCON\" show HEAD:PRETEXTA/backend/routes/campaigns.py)"
7+
]
8+
}
9+
}

PRETEXTA/.env.example

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# =============================================================
2+
# Pretexta — Environment Configuration
3+
# =============================================================
4+
# 1. Copy this file: cp .env.example .env
5+
# 2. Edit .env with your actual values
6+
# 3. NEVER commit .env to version control
7+
# =============================================================
8+
9+
# ---- Ports ----
10+
FRONTEND_PORT=9443
11+
BACKEND_PORT=9442
12+
MONGO_PORT=47017
13+
14+
# ---- MongoDB ----
15+
MONGO_USERNAME=soceng_admin
16+
MONGO_PASSWORD=soceng_secure_password_2025
17+
DB_NAME=Pretexta
18+
19+
# ---- JWT Secret (CHANGE IN PRODUCTION — use a long random string) ----
20+
# Generate: python3 -c "import secrets; print(secrets.token_hex(32))"
21+
JWT_SECRET=change-this-secret-key-in-production
22+
23+
# ---- CORS Origins (comma-separated list of allowed frontend origins) ----
24+
CORS_ORIGINS=http://localhost:9443,http://localhost:3000,http://localhost:80
25+
26+
# ---- Frontend → Backend URL (baked into React bundle at build time) ----
27+
# For Docker: use the backend container port that's mapped to the host
28+
# For local dev: http://localhost:8001
29+
REACT_APP_BACKEND_URL=http://localhost:9442
30+
31+
# ---- Seed Admin User (created on first run if DB is empty) ----
32+
# This user gets role=admin automatically.
33+
# Change before deploying to production!
34+
SEED_ADMIN_USERNAME=soceng
35+
SEED_ADMIN_PASSWORD=Cialdini@2025!
36+
SEED_ADMIN_DISPLAY_NAME=Admin

PRETEXTA/.github/workflows/ci.yml

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
jobs:
10+
backend-lint:
11+
name: Backend Lint
12+
runs-on: ubuntu-latest
13+
defaults:
14+
run:
15+
working-directory: backend
16+
steps:
17+
- uses: actions/checkout@v4
18+
19+
- uses: actions/setup-python@v5
20+
with:
21+
python-version: "3.11"
22+
23+
- name: Install ruff
24+
run: pip install ruff
25+
26+
- name: Lint
27+
run: ruff check .
28+
29+
- name: Format check
30+
run: ruff format --check .
31+
32+
frontend-lint:
33+
name: Frontend Lint & Build
34+
runs-on: ubuntu-latest
35+
defaults:
36+
run:
37+
working-directory: frontend
38+
steps:
39+
- uses: actions/checkout@v4
40+
41+
- uses: actions/setup-node@v4
42+
with:
43+
node-version: "20"
44+
cache: "yarn"
45+
cache-dependency-path: frontend/yarn.lock
46+
47+
- name: Install dependencies
48+
run: yarn install --frozen-lockfile
49+
50+
- name: Lint
51+
run: yarn lint 2>/dev/null || true
52+
53+
- name: Build
54+
run: yarn build
55+
56+
docker-build:
57+
name: Docker Build
58+
runs-on: ubuntu-latest
59+
needs: [backend-lint, frontend-lint]
60+
steps:
61+
- uses: actions/checkout@v4
62+
63+
- name: Build backend image
64+
run: docker build -f Dockerfile.backend -t pretexta-backend:test .
65+
66+
- name: Build frontend image
67+
run: docker build -f Dockerfile.frontend -t pretexta-frontend:test .

PRETEXTA/.gitignore

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
2+
# Node.js / TypeScript
3+
node_modules/
4+
dist/
5+
build/
6+
out/
7+
coverage/
8+
.env
9+
.DS_Store
10+
npm-debug.log*
11+
yarn-debug.log*
12+
yarn-error.log*
13+
pnpm-debug.log*
14+
15+
# Python
16+
__pycache__/
17+
*.py[cod]
18+
*$py.class
19+
venv/
20+
.venv/
21+
env/
22+
.env/
23+
*.so
24+
.Python
25+
build/
26+
develop-eggs/
27+
dist/
28+
downloads/
29+
eggs/
30+
.eggs/
31+
lib/
32+
lib64/
33+
parts/
34+
sdist/
35+
var/
36+
wheels/
37+
share/python-wheels/
38+
*.egg-info/
39+
.installed.cfg
40+
*.egg
41+
MANIFEST
42+
43+
# IDEs
44+
.vscode/
45+
.idea/

PRETEXTA/CONTRIBUTING.md

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
# Contributing to Pretexta
2+
3+
Thank you for your interest in contributing! We welcome YAML-based scenarios and quizzes that help improve security awareness training.
4+
5+
## 🎯 What We're Looking For
6+
7+
- **Realistic** social engineering scenarios
8+
- Coverage of all 6 Cialdini principles:
9+
- Authority
10+
- Scarcity
11+
- Reciprocity
12+
- Commitment & Consistency
13+
- Liking
14+
- Social Proof
15+
- Diverse attack vectors: email, phone, chat, web
16+
- Bilingual content (EN/ID preferred)
17+
- Well-documented decision trees
18+
19+
## 📝 YAML Guidelines
20+
21+
### File Naming
22+
23+
```
24+
YYYY-MM-DD-brief-description-slug.yaml
25+
```
26+
27+
Examples:
28+
- `2025-01-15-ceo-fraud-wire-transfer.yaml`
29+
- `2025-01-16-it-support-password-reset.yaml`
30+
31+
### Challenge Template
32+
33+
See `templates/challenge_template.yaml`
34+
35+
```yaml
36+
type: challenge
37+
title: "Your Challenge Title"
38+
description: "Brief description for users"
39+
difficulty: easy|medium|hard
40+
cialdini_categories: [authority, scarcity]
41+
estimated_time: 10 # minutes
42+
metadata:
43+
author: "Your Name"
44+
license: "MIT"
45+
tags: [phishing, email, corporate]
46+
47+
nodes:
48+
- id: start
49+
type: message
50+
channel: email_inbox
51+
content_en:
52+
subject: "Email subject"
53+
from: "sender@example.com"
54+
body: "Email body"
55+
content_id: # Optional Indonesian
56+
subject: "Subjek email"
57+
from: "pengirim@example.com"
58+
body: "Isi email"
59+
next: choice_1
60+
61+
- id: choice_1
62+
type: question
63+
content_en:
64+
text: "What do you do?"
65+
options:
66+
- text: "Click the link"
67+
next: bad_outcome
68+
score_impact: -15
69+
- text: "Verify first"
70+
next: good_outcome
71+
score_impact: +10
72+
73+
- id: bad_outcome
74+
type: end
75+
result: failure
76+
content_en:
77+
title: "Compromised!"
78+
explanation: "Clicking unverified links can lead to credential theft."
79+
80+
- id: good_outcome
81+
type: end
82+
result: success
83+
content_en:
84+
title: "Well done!"
85+
explanation: "Always verify requests through known channels."
86+
```
87+
88+
### Quiz Template
89+
90+
See `templates/quiz_template.yaml`
91+
92+
```yaml
93+
type: quiz
94+
title: "Quiz Title"
95+
description: "Brief description"
96+
difficulty: easy|medium|hard
97+
cialdini_categories:
98+
- authority
99+
100+
metadata:
101+
author: "Pretexta"
102+
tags: [phishing, email, basics]
103+
104+
questions:
105+
- id: q1
106+
content_en:
107+
text: "Question text?"
108+
explanation: "Why this answer matters"
109+
options:
110+
- text: "Option A"
111+
correct: true
112+
- text: "Option B"
113+
correct: false
114+
points: 10
115+
```
116+
117+
## ✅ Validation
118+
119+
Before submitting:
120+
121+
```bash
122+
python bin/validate_yaml.py your_file.yaml
123+
```
124+
125+
## 🔄 Pull Request Process
126+
127+
1. **Fork** the repository
128+
2. **Create** a branch: `git checkout -b add-scenario-name`
129+
3. **Add** your YAML to `data/sample/`
130+
4. **Validate** using the CLI tool
131+
5. **Commit**: `git commit -m "Add: CEO fraud scenario"`
132+
6. **Push**: `git push origin add-scenario-name`
133+
7. **Submit** a Pull Request
134+
135+
### PR Guidelines
136+
137+
- **One YAML per PR** (easier to review)
138+
- Include brief description of scenario
139+
- Test locally before submitting
140+
- Follow existing naming conventions
141+
- Add yourself to metadata author field
142+
143+
## 🚫 What Not to Submit
144+
145+
- Scenarios targeting real individuals or organizations
146+
- Content promoting illegal activities
147+
- Scenarios that could cause harm if misused
148+
- Malicious payloads or actual exploits
149+
- Low-quality or joke submissions
150+
151+
## 📚 Resources
152+
153+
- [Cialdini's 6 Principles](https://en.wikipedia.org/wiki/Robert_Cialdini#6_key_principles_of_influence_by_Robert_Cialdini)
154+
- [Social Engineering Attacks](https://www.social-engineer.org/framework/attack-vectors/)
155+
- [YAML Syntax](https://yaml.org/spec/1.2.2/)
156+
157+
## 🤝 Code of Conduct
158+
159+
- Be respectful and professional
160+
- Focus on security awareness education
161+
- No discrimination or harassment
162+
- Constructive feedback only
163+
164+
## ❔ Questions?
165+
166+
Open an issue or reach out to the maintainers.
167+
168+
---
169+
170+
**Thank you for helping make security awareness training more effective!**

PRETEXTA/Dockerfile.backend

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# syntax=docker/dockerfile:1
2+
FROM python:3.11-slim
3+
4+
# Build-time DNS fix for environments with IPv6 issues (WSL2, certain CI systems)
5+
# Ensures pip install works even if the container's DNS is broken
6+
ARG PIP_INDEX_URL=https://pypi.org/simple/
7+
8+
WORKDIR /app
9+
10+
# Install system dependencies — cached separately from code changes
11+
RUN apt-get update && apt-get install -y --no-install-recommends \
12+
gcc \
13+
g++ \
14+
libffi-dev \
15+
libjpeg-dev \
16+
libopenjp2-7 \
17+
curl \
18+
&& rm -rf /var/lib/apt/lists/*
19+
20+
# Install Python dependencies before copying code (better layer cache)
21+
COPY backend/requirements.txt ./requirements.txt
22+
RUN pip install --no-cache-dir --timeout 120 -r requirements.txt
23+
24+
# Copy backend source code
25+
COPY backend/ /app/
26+
27+
# Create required directories
28+
RUN mkdir -p /app/data/sample /app/data/professionals /app/bin
29+
30+
EXPOSE 8001
31+
32+
HEALTHCHECK --interval=10s --timeout=5s --start-period=15s --retries=3 \
33+
CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8001/api/health')" || exit 1
34+
35+
CMD ["uvicorn", "server:app", "--host", "0.0.0.0", "--port", "8001"]

0 commit comments

Comments
 (0)