1+ #!/usr/bin/env python3
2+ import re
3+ import sys
4+ import os
5+ from datetime import datetime
6+ import html
7+
8+ def main ():
9+ # Get environment variables
10+ pr_number = os .environ .get ('PR_NUMBER' , 'unknown' )
11+ pr_title = os .environ .get ('PR_TITLE' , 'Unknown PR' )
12+ pr_sha = os .environ .get ('PR_SHA' , 'unknown' )
13+ existing_index_file = os .environ .get ('EXISTING_INDEX' , '' )
14+
15+ # Escape HTML characters in PR title
16+ pr_title_escaped = html .escape (pr_title .strip ())
17+
18+ # HTML template for PR card
19+ pr_card_template = f""" <div class="pr-card" data-pr="{ pr_number } ">
20+ <a href="pr-{ pr_number } /" class="pr-link">PR #{ pr_number } Preview</a>
21+ <div class="meta">
22+ <span class="badge">Active</span><br>
23+ { pr_title_escaped } <br>
24+ Updated: { datetime .now ().strftime ("%Y-%m-%d %H:%M UTC" )} | Commit: { pr_sha [:8 ]}
25+ </div>
26+ </div>"""
27+
28+ # Base HTML template
29+ base_html = """<!DOCTYPE html>
30+ <html lang="en">
31+ <head>
32+ <meta charset="UTF-8">
33+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
34+ <title>OWASP WrongSecrets - PR Previews</title>
35+ <style>
36+ body {
37+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
38+ margin: 40px;
39+ background-color: #f8f9fa;
40+ }
41+ .container { max-width: 1200px; margin: 0 auto; }
42+ .header { text-align: center; margin-bottom: 40px; }
43+ .pr-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 20px; }
44+ .pr-card {
45+ background: white;
46+ padding: 20px;
47+ border-radius: 8px;
48+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
49+ border-left: 4px solid #0366d6;
50+ }
51+ .pr-link { text-decoration: none; color: #0366d6; font-weight: bold; font-size: 1.2em; }
52+ .pr-link:hover { text-decoration: underline; }
53+ .meta { color: #666; font-size: 0.9em; margin-top: 10px; }
54+ .badge {
55+ background: #e1f5fe;
56+ color: #01579b;
57+ padding: 2px 8px;
58+ border-radius: 12px;
59+ font-size: 0.8em;
60+ }
61+ .no-previews {
62+ text-align: center;
63+ color: #666;
64+ font-style: italic;
65+ grid-column: 1 / -1;
66+ }
67+ </style>
68+ </head>
69+ <body>
70+ <div class="container">
71+ <div class="header">
72+ <h1>🔐 OWASP WrongSecrets</h1>
73+ <h2>Pull Request Previews</h2>
74+ <p>Static previews of pull requests for UI and template changes</p>
75+ </div>
76+
77+ <div id="pr-list">
78+ <div class="pr-grid">
79+ <!-- PR_CARDS_PLACEHOLDER -->
80+ </div>
81+ </div>
82+
83+ <div style="text-align: center; margin-top: 40px; color: #666;">
84+ <p>
85+ <a href="https://github.com/OWASP/wrongsecrets" target="_blank">View Repository</a> |
86+ <a href="https://github.com/OWASP/wrongsecrets/pulls" target="_blank">All Pull Requests</a>
87+ </p>
88+ <small>Generated by GitHub Actions • Last updated: """ + datetime .now ().strftime ("%Y-%m-%d %H:%M UTC" ) + """</small>
89+ </div>
90+ </div>
91+ </body>
92+ </html>"""
93+
94+ try :
95+ # Try to read existing index
96+ if existing_index_file and os .path .exists (existing_index_file ):
97+ with open (existing_index_file , 'r' ) as f :
98+ existing_content = f .read ()
99+
100+ # Extract existing PR cards
101+ card_pattern = r'<div class="pr-card"[^>]*>.*?</div>\\s*</div>'
102+ existing_cards = re .findall (card_pattern , existing_content , re .DOTALL )
103+
104+ # Remove the current PR card if it exists
105+ filtered_cards = []
106+ for card in existing_cards :
107+ if f'data-pr="{ pr_number } "' not in card :
108+ filtered_cards .append (card )
109+
110+ # Add current PR card at the beginning
111+ all_cards = [pr_card_template ] + filtered_cards
112+
113+ else :
114+ # No existing index, start fresh
115+ all_cards = [pr_card_template ]
116+
117+ # Generate final HTML
118+ if all_cards :
119+ cards_html = '\n ' .join (all_cards )
120+ else :
121+ cards_html = ' <div class="no-previews">No active PR previews</div>'
122+
123+ final_html = base_html .replace ('<!-- PR_CARDS_PLACEHOLDER -->' , cards_html )
124+
125+ with open ('static-site/index.html' , 'w' ) as f :
126+ f .write (final_html )
127+
128+ print (f"Successfully updated index with PR #{ pr_number } " )
129+
130+ except Exception as e :
131+ print (f"Error updating index: { e } " )
132+ # Fallback to simple index
133+ fallback_html = base_html .replace ('<!-- PR_CARDS_PLACEHOLDER -->' , pr_card_template )
134+ with open ('static-site/index.html' , 'w' ) as f :
135+ f .write (fallback_html )
136+ print ("Created fallback index" )
137+
138+ if __name__ == "__main__" :
139+ main ()
0 commit comments