Skip to content
Closed
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
103 changes: 103 additions & 0 deletions .github/scripts/update_learn_page.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
#!/usr/bin/env python3
"""
Script to update the OpenShield Learn page with current statistics from the codebase.
"""

import os
import re

def count_rules_and_playbooks():
"""Count the number of rules and playbooks."""
rules_dir = 'scanner/rules'
playbooks_dir = 'playbooks/cli'

rule_count = 0
if os.path.exists(rules_dir):
for root, dirs, files in os.walk(rules_dir):
for file in files:
if file.endswith('.py') and not file.endswith('_common.py'):
rule_count += 1

playbook_count = 0
if os.path.exists(playbooks_dir):
for root, dirs, files in os.walk(playbooks_dir):
for file in files:
if file.endswith('.sh'):
playbook_count += 1

return rule_count, playbook_count

def count_severities():
"""Count the number of rules by severity."""
severities = {'HIGH': 0, 'MEDIUM': 0, 'LOW': 0, 'INFO': 0}
rules_dir = 'scanner/rules'
if os.path.exists(rules_dir):
for root, dirs, files in os.walk(rules_dir):
for file in files:
if file.endswith('.py') and not file.endswith('_common.py'):
filepath = os.path.join(root, file)
with open(filepath, 'r') as f:
content = f.read()
# Extract SEVERITY
sev_match = re.search(r'SEVERITY\s*=\s*\"([^\"]+)\"', content)
if sev_match:
sev = sev_match.group(1).strip()
if sev in severities:
severities[sev] += 1
return severities

def update_learn_page():
"""Update the learn page with current statistics."""
learn_page_path = 'docs/learn/index.html'

if not os.path.exists(learn_page_path):
print(f"Error: {learn_page_path} not found")
return

# Read the current file
with open(learn_page_path, 'r') as f:
content = f.read()

# Get counts
rule_count, playbook_count = count_rules_and_playbooks()
severities = count_severities()
high_count = severities['HIGH']

# Update the metrics section
# Pattern for the metrics div
metrics_pattern = r'(<div class="metrics" aria-label="OpenShield project metrics">\s*<div class="metric"><strong>)\d+(</strong><span>Azure scan rules</span></div>\s*<div class="metric"><strong>)\d+(</strong><span>CLI remediation playbooks</span></div>\s*<div class="metric"><strong>)\d+(</strong><span>Compliance frameworks</span></div>\s*<div class="metric"><strong>)\d+(</strong><span>AI security skills</span></div>\s*<div class="metric"><strong>)\d+(</strong><span>High-severity checks</span></div>\s*</div>)'

# We'll do it step by step for simplicity
# Replace Azure scan rules
content = re.sub(r'(<div class="metric"><strong>)\d+(</strong><span>Azure scan rules</span></div>)',
rf'\1{rule_count}\2', content)
# Replace CLI remediation playbooks
content = re.sub(r'(<div class="metric"><strong>)\d+(</strong><span>CLI remediation playbooks</span></div>)',
rf'\1{playbook_count}\2', content)
# Replace Compliance frameworks (still 4)
# Replace AI security skills (still 8)
# Replace High-severity checks
content = re.sub(r'(<div class="metric"><strong>)\d+(</strong><span>High-severity checks</span></div>)',
rf'\1{high_count}\2', content)

# Update the pipeline step
content = re.sub(r'(<div class="pipeline-step"><strong>Rule Evaluation</strong><span>)\d+( dynamic checks</span></div>)',
rf'\1{rule_count}\2', content)

# Update the rules section title and intro
# First, the title
content = re.sub(r'(<h2 class="section-title">)\d+( Azure security rules</h2>)',
rf'\1{rule_count}\2', content)
# Then the intro paragraph
content = re.sub(r'(<p class="section-intro">\s*OpenShield currently has )\d+( dynamic rules\. The strongest contributor work improves rule accuracy, reduces false positives,)',
rf'\1{rule_count}\2', content)

# Write back
with open(learn_page_path, 'w') as f:
f.write(content)

print(f"Updated {learn_page_path}")
print(f"Rules: {rule_count}, Playbooks: {playbook_count}, High severity: {high_count}")

if __name__ == '__main__':
update_learn_page()
42 changes: 42 additions & 0 deletions .github/workflows/update-learn-page.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: Update Learn Page

on:
push:
branches:
- dev

jobs:
update-learn-page:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
# We need to fetch the entire history to get the correct diff
fetch-depth: 0

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.x'

- name: Install dependencies
run: |
python -m pip install --upgrade pip

- name: Update learn page statistics
run: |
python .github/scripts/update_learn_page.py

- name: Commit and push changes
run: |
git config user.name github-actions
git config user.email github-actions@github.com
git add docs/learn/index.html
# Check if there are changes to commit
if ! git diff --cached --quiet; then
git commit -m "docs: update learn page statistics [skip ci]"
git push origin HEAD:${{ github.ref }}
else
echo "No changes to learn page"
fi
Comment on lines +32 to +42
14 changes: 7 additions & 7 deletions docs/learn/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -752,7 +752,7 @@ <h1><span class="gradient-text">Learn Azure security posture with OpenShield.</s
<div class="terminal-top" aria-hidden="true"><span class="dot"></span><span class="dot"></span><span class="dot"></span></div>
<div class="terminal-body">
<p><span class="prompt">openshield</span> scan --subscription Azure</p>
<p><span class="dim">loading rules:</span> <span class="cyan">39 dynamic checks</span></p>
<p><span class="dim">loading rules:</span> <span class="cyan">73 dynamic checks</span></p>
<p><span class="dim">enrichment:</span> NVD / CVE intelligence</p>
<p><span class="dim">storage:</span> PostgreSQL scan history</p>
<p><span class="dim">api:</span> Flask + JWT + CORS</p>
Expand All @@ -764,11 +764,11 @@ <h1><span class="gradient-text">Learn Azure security posture with OpenShield.</s
</div>

<div class="metrics" aria-label="OpenShield project metrics">
<div class="metric"><strong>39</strong><span>Azure scan rules</span></div>
<div class="metric"><strong>39</strong><span>CLI remediation playbooks</span></div>
<div class="metric"><strong>65</strong><span>Azure scan rules</span></div>
<div class="metric"><strong>65</strong><span>CLI remediation playbooks</span></div>
<div class="metric"><strong>4</strong><span>Compliance frameworks</span></div>
<div class="metric"><strong>8</strong><span>AI security skills</span></div>
<div class="metric"><strong>22</strong><span>High-severity checks</span></div>
<div class="metric"><strong>38</strong><span>High-severity checks</span></div>
</div>
</header>

Expand Down Expand Up @@ -821,7 +821,7 @@ <h2 class="section-title">Production-shaped, MVP-friendly architecture</h2>
<div class="pipeline" aria-label="OpenShield platform pipeline">
<div class="pipeline-step"><strong>Azure Subscription</strong><span>Resources and configuration</span></div>
<div class="pipeline-step"><strong>Scanner Engine</strong><span>Python rule execution</span></div>
<div class="pipeline-step"><strong>Rule Evaluation</strong><span>39 dynamic checks</span></div>
<div class="pipeline-step"><strong>Rule Evaluation</strong><span>65 dynamic checks</span></div>
<div class="pipeline-step"><strong>CVE Enrichment</strong><span>NVD risk context</span></div>
<div class="pipeline-step"><strong>PostgreSQL</strong><span>Findings and scan history</span></div>
<div class="pipeline-step"><strong>Flask API</strong><span>JWT-protected REST routes</span></div>
Expand All @@ -841,9 +841,9 @@ <h2 class="section-title">Production-shaped, MVP-friendly architecture</h2>

<section id="rules" class="learn-section" data-search="rules coverage network storage compute database identity key vault post quantum severity high medium low findings">
<p class="section-kicker">Rule coverage</p>
<h2 class="section-title">51 Azure security rules</h2>
<h2 class="section-title">65 Azure security rules</h2>
<p class="section-intro">
OpenShield currently has 39 dynamic rules. The strongest contributor work improves rule accuracy, reduces false positives,
OpenShield currently has 65 dynamic rules. The strongest contributor work improves rule accuracy, reduces false positives,
strengthens validation, or improves remediation quality.
</p>

Expand Down
Loading