Skip to content

Add translations with language toggle support and locale-aware challenge content #201

Add translations with language toggle support and locale-aware challenge content

Add translations with language toggle support and locale-aware challenge content #201

name: GitHub Pages PR Preview
on:
pull_request:
paths:
- 'src/main/resources/templates/**'
- 'src/main/resources/static/**'
- 'src/main/resources/explanations/**'
- 'src/main/java/**'
permissions:
contents: read
pages: write
id-token: write
pull-requests: write
# Allow only one concurrent deployment per PR, but allow multiple PRs to deploy simultaneously
concurrency:
group: "pages-pr-${{ github.event.number }}"
cancel-in-progress: true
jobs:
generate-static-preview:
runs-on: ubuntu-latest
if: github.event.action != 'closed'
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}pr-${{ github.event.number }}/
outputs:
preview-url: ${{ steps.deployment.outputs.page_url }}pr-${{ github.event.number }}/
steps:
- name: Checkout
uses: actions/checkout@v5
- name: Set up JDK 25
uses: actions/setup-java@v5
with:
java-version: "25"
distribution: "temurin"
cache: "maven"
- name: Build application (JAR only)
run: |
echo "Building WrongSecrets application..."
./mvnw --no-transfer-progress clean package -DskipTests
# Verify JAR was created
find target -name "*.jar" -type f | head -5
- name: Generate Thymeleaf static previews
run: |
echo "Generating Thymeleaf static previews for PR #${{ github.event.number }}..."
# Generate static HTML from Thymeleaf templates
python3 .github/scripts/generate_thymeleaf_previews.py ${{ github.event.number }}
- name: Create static preview content
run: |
echo "Creating static preview for PR #${{ github.event.number }}..."
# Create the preview directory structure
mkdir -p static-site/pr-${{ github.event.number }}
# Copy static assets (CSS, JS, images, etc.)
echo "Copying static assets..."
cp -r src/main/resources/static/* static-site/pr-${{ github.event.number }}/ 2>/dev/null || true
# Create a simple landing page for this PR preview
cat > static-site/pr-${{ github.event.number }}/index.html << 'EOF'
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WrongSecrets PR Preview</title>
<link href="css/bootstrap.min.css" rel="stylesheet" />
<link href="css/custom.css" rel="stylesheet" />
<link rel="icon" type="image/png" href="favicon.png">
</head>
<body>
<div class="container-fluid mt-3">
<div class="row">
<div class="col-md-12">
<div class="display-5 mb-3">🔐 OWASP WrongSecrets</div>
<div class="alert alert-info" role="alert">
<h5 class="alert-heading">📋 PR Preview #${{ github.event.number }}</h5>
<p><strong>Static Preview Notice:</strong> This is a static preview of the UI changes in this pull request.</p>
<p><strong>Commit:</strong> <code>${{ github.sha }}</code></p>
<p><strong>For full functionality:</strong> Please use the Docker preview from the <a href="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" target="_blank">GitHub Actions build</a>.</p>
</div>
<div class="card">
<div class="card-header">
<h5>📁 Available Preview Content</h5>
</div>
<div class="card-body">
<p>This static preview includes:</p>
<ul>
<li>✅ All CSS stylesheets and themes</li>
<li>✅ JavaScript files and interactions</li>
<li>✅ Images, icons, and static assets</li>
<li>✅ Generated HTML from Thymeleaf templates</li>
</ul>
<h6 class="mt-3">🔗 Preview Pages:</h6>
<div class="row">
<div class="col-md-6">
<div class="list-group">
<a href="pages/welcome.html" class="list-group-item list-group-item-action">
🏠 Home/Welcome Page
</a>
<a href="pages/about.html" class="list-group-item list-group-item-action">
ℹ️ About Page
</a>
</div>
</div>
<div class="col-md-6">
<div class="list-group">
<a href="pages/stats.html" class="list-group-item list-group-item-action">
📊 Stats & Config Page
</a>
<a href="pages/challenge-57.html" class="list-group-item list-group-item-action">
🤖 <strong>Challenge 57: LLM Security (Latest)</strong>
</a>
<a href="pages/challenge-example.html" class="list-group-item list-group-item-action">
🧩 Challenge Example
</a>
</div>
</div>
</div>
<h6 class="mt-3">📋 Key Files Changed in This PR:</h6>
<div id="changed-files">
<em>Loading changed files...</em>
</div>
<div class="mt-3">
<a href="${{ github.server_url }}/${{ github.repository }}/pull/${{ github.event.number }}" class="btn btn-primary" target="_blank">
View Full PR Details
</a>
<a href="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" class="btn btn-secondary" target="_blank">
Docker Preview (Full Functionality)
</a>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
// Try to fetch and display changed files information
(async function() {
try {
const response = await fetch('${{ github.api_url }}/repos/${{ github.repository }}/pulls/${{ github.event.number }}/files');
const files = await response.json();
const relevantFiles = files.filter(file =>
file.filename.includes('templates/') ||
file.filename.includes('static/') ||
file.filename.includes('explanations/') ||
file.filename.includes('src/main/java/')
);
const changedFilesDiv = document.getElementById('changed-files');
if (relevantFiles.length > 0) {
changedFilesDiv.innerHTML = '<ul>' +
relevantFiles.slice(0, 10).map(file =>
`<li><code>${file.filename}</code> <span class="badge bg-${file.status === 'added' ? 'success' : file.status === 'removed' ? 'danger' : 'warning'}">${file.status}</span></li>`
).join('') +
(relevantFiles.length > 10 ? `<li><em>... and ${relevantFiles.length - 10} more files</em></li>` : '') +
'</ul>';
} else {
changedFilesDiv.innerHTML = '<em>No relevant UI/template files changed in this PR.</em>';
}
} catch (error) {
console.log('Could not load changed files information:', error);
document.getElementById('changed-files').innerHTML = '<em>Could not load changed files information.</em>';
}
})();
</script>
</body>
</html>
EOF
- name: Update main index page with current PR
run: |
# Download existing GitHub Pages content if it exists
EXISTING_INDEX=""
echo "Attempting to download existing index page..."
if curl -s -f -L --max-time 30 "https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/index.html" > /tmp/existing_index.html 2>/dev/null; then
# Verify the downloaded file has content and is HTML
if [ -s /tmp/existing_index.html ] && grep -q "<html" /tmp/existing_index.html; then
echo "✅ Found existing index page"
EXISTING_INDEX="/tmp/existing_index.html"
else
echo "⚠️ Downloaded file is empty or not valid HTML, starting fresh"
fi
else
echo "ℹ️ No existing index found or unable to download, starting fresh"
fi
# Run the script with environment variables
export PR_NUMBER="${{ github.event.number }}"
export PR_TITLE="${{ github.event.pull_request.title }}"
export PR_SHA="${{ github.sha }}"
export EXISTING_INDEX="$EXISTING_INDEX"
python3 .github/scripts/update_pr_index.py
- name: Setup Pages
uses: actions/configure-pages@v5
- name: Upload artifact
uses: actions/upload-pages-artifact@v4
with:
path: ./static-site
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
- name: Comment PR with preview link
uses: actions/github-script@v8
with:
script: |
const prNumber = context.issue.number;
const previewUrl = `${{ steps.deployment.outputs.page_url }}pr-${prNumber}/`;
const comment = `🌐 **GitHub Pages Preview Ready!**
Your static preview is now available at:
**🔗 [Preview PR #${prNumber}](${previewUrl})**
📄 **What's included:**
- ✅ All CSS, JavaScript, and static assets (embedded inline)
- ✅ Current styling and layout preview
- ✅ Images, icons, and UI components
- ✅ **NEW:** Generated HTML from Thymeleaf templates
- 🏠 [Home/Welcome Page](${previewUrl}pages/welcome.html)
- ℹ️ [About Page](${previewUrl}pages/about.html)
- 📊 [Stats & Config Page](${previewUrl}pages/stats.html)
- 🤖 **[Challenge 57: LLM Security (Latest)](${previewUrl}pages/challenge-57.html)**
- 🧩 [Challenge Example](${previewUrl}pages/challenge-example.html)
**For full functionality testing:** Use the [Docker preview](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) instead.
**🔄 Auto-updates:** This preview will be updated automatically when you push new commits to this PR.
---
<sub>Static preview with Thymeleaf generation by GitHub Actions</sub>`;
github.rest.issues.createComment({
issue_number: prNumber,
owner: context.repo.owner,
repo: context.repo.repo,
body: comment
});
cleanup-preview:
runs-on: ubuntu-latest
if: github.event.action == 'closed'
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
permissions:
contents: read
pages: write
id-token: write
pull-requests: write
steps:
- name: Checkout repository
uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Prepare cleanup for PR preview
run: |
PR_NUMBER=${{ github.event.number }}
echo "Preparing cleanup for PR #${PR_NUMBER}..."
# Check if gh-pages branch exists
if git ls-remote --exit-code --heads origin gh-pages >/dev/null 2>&1; then
echo "gh-pages branch exists, checking out..."
git checkout gh-pages || {
echo "Failed to checkout gh-pages branch"
exit 1
}
else
echo "gh-pages branch doesn't exist yet, nothing to clean up"
exit 0
fi
# Create temporary directory for the cleaned site
mkdir -p /tmp/cleaned-site
# Copy everything except the PR directory we want to remove
PR_DIR="pr-${PR_NUMBER}"
for item in *; do
if [ "$item" != "$PR_DIR" ] && [ "$item" != ".git" ]; then
cp -r "$item" /tmp/cleaned-site/ 2>/dev/null || true
fi
done
# Update main index if it exists
if [ -f "/tmp/cleaned-site/index.html" ]; then
echo "Updating main index to remove PR #${PR_NUMBER}..."
export PR_NUMBER="${PR_NUMBER}"
python3 .github/scripts/remove_pr_from_index.py
fi
# Move cleaned content to static-site for deployment
mkdir -p static-site
cp -r /tmp/cleaned-site/* static-site/ 2>/dev/null || true
echo "Cleanup preparation completed"
- name: Setup Pages for cleanup
uses: actions/configure-pages@v5
- name: Upload cleaned artifact
uses: actions/upload-pages-artifact@v4
with:
path: ./static-site
- name: Deploy cleaned pages
id: deployment
uses: actions/deploy-pages@v4
- name: Comment PR cleanup completion
uses: actions/github-script@v8
with:
script: |
const comment = `🧹 **Preview Cleanup Complete**
The static preview for this PR has been removed from GitHub Pages.
Thanks for contributing to WrongSecrets! 🎉
---
<sub>Cleanup completed by GitHub Actions</sub>`;
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: comment
});