From 180b4f9cc81372ee3049432fd484ec3cc4280d1e Mon Sep 17 00:00:00 2001 From: Parth Rohit Date: Wed, 5 Aug 2026 12:35:14 +0100 Subject: [PATCH 1/2] docs: update learn page statistics and add CI/CD workflow --- .github/scripts/update_learn_page.py | 103 ++++++++++++++++++++++++ .github/workflows/update-learn-page.yml | 42 ++++++++++ 2 files changed, 145 insertions(+) create mode 100644 .github/scripts/update_learn_page.py create mode 100644 .github/workflows/update-learn-page.yml diff --git a/.github/scripts/update_learn_page.py b/.github/scripts/update_learn_page.py new file mode 100644 index 0000000..b5ce243 --- /dev/null +++ b/.github/scripts/update_learn_page.py @@ -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'(
\s*
)\d+(Azure scan rules
\s*
)\d+(CLI remediation playbooks
\s*
)\d+(Compliance frameworks
\s*
)\d+(AI security skills
\s*
)\d+(High-severity checks
\s*
)' + + # We'll do it step by step for simplicity + # Replace Azure scan rules + content = re.sub(r'(
)\d+(Azure scan rules
)', + rf'\1{rule_count}\2', content) + # Replace CLI remediation playbooks + content = re.sub(r'(
)\d+(CLI remediation playbooks
)', + 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'(
)\d+(High-severity checks
)', + rf'\1{high_count}\2', content) + + # Update the pipeline step + content = re.sub(r'(
Rule Evaluation)\d+( dynamic checks
)', + rf'\1{rule_count}\2', content) + + # Update the rules section title and intro + # First, the title + content = re.sub(r'(

)\d+( Azure security rules

)', + rf'\1{rule_count}\2', content) + # Then the intro paragraph + content = re.sub(r'(

\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() \ No newline at end of file diff --git a/.github/workflows/update-learn-page.yml b/.github/workflows/update-learn-page.yml new file mode 100644 index 0000000..56bbb0c --- /dev/null +++ b/.github/workflows/update-learn-page.yml @@ -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 \ No newline at end of file From 9a435c2592d421676eae795b57afaaf76b924cf8 Mon Sep 17 00:00:00 2001 From: Parth Rohit Date: Wed, 5 Aug 2026 12:39:10 +0100 Subject: [PATCH 2/2] docs: update learn page statistics and add CI/CD workflow --- docs/learn/index.html | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/learn/index.html b/docs/learn/index.html index a9aaa4f..083c591 100644 --- a/docs/learn/index.html +++ b/docs/learn/index.html @@ -752,7 +752,7 @@

Learn Azure security posture with OpenShield.

openshield scan --subscription Azure

-

loading rules: 39 dynamic checks

+

loading rules: 73 dynamic checks

enrichment: NVD / CVE intelligence

storage: PostgreSQL scan history

api: Flask + JWT + CORS

@@ -764,11 +764,11 @@

Learn Azure security posture with OpenShield.
-
39Azure scan rules
-
39CLI remediation playbooks
+
65Azure scan rules
+
65CLI remediation playbooks
4Compliance frameworks
8AI security skills
-
22High-severity checks
+
38High-severity checks
@@ -821,7 +821,7 @@

Production-shaped, MVP-friendly architecture

Azure SubscriptionResources and configuration
Scanner EnginePython rule execution
-
Rule Evaluation39 dynamic checks
+
Rule Evaluation65 dynamic checks
CVE EnrichmentNVD risk context
PostgreSQLFindings and scan history
Flask APIJWT-protected REST routes
@@ -841,9 +841,9 @@

Production-shaped, MVP-friendly architecture

Rule coverage

-

51 Azure security rules

+

65 Azure security rules

- 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.