)'
content, count = re.subn(
category_block,
lambda m: m.group(1) + category_rows + m.group(3),
@@ -229,16 +252,14 @@ def render(
def render_readme(content: str, rule_count: int, playbook_count: int) -> Tuple[str, List[str]]:
"""Return (updated_content, failed_pattern_names) for README.md."""
- feature_row = (
- r"(\| \*\*Misconfiguration Scanner\*\* \| Runs )\d+"
- r"( Azure security rules across storage, network, identity, database, "
- r"compute, Key Vault, AKS, post-quantum cryptography, backup, serverless, "
- r"private endpoint, and supply chain posture \|)"
- )
- playbook_row = (
- r"(\| \*\*Remediation Playbooks\*\* \| Every rule ships with a matching "
- r"Azure CLI remediation script \()\d+( playbooks\) \|)"
- )
+ # Anchored on the row label and the unit that follows the number, not on
+ # the full prose. The wording of these rows (the category list, how the
+ # scripts are described) is edited independently of the counts, and pinning
+ # the whole sentence made this script fail on every unrelated reword while
+ # the counts silently went stale. Losing the row itself, or the "Azure
+ # security rules"/"(N playbooks)" shape, still fails loudly.
+ feature_row = r"(\| \*\*Misconfiguration Scanner\*\* \| Runs )\d+( Azure security rules)"
+ playbook_row = r"(\| \*\*Remediation Playbooks\*\* \|[^|]*\()\d+( playbooks\) \|)"
mermaid_scanner = r'(C\["Scanner Engine\\n)\d+( Python rules"\])'
mermaid_playbooks = r'(G\["Azure CLI Playbooks\\n)\d+( remediation scripts"\])'
@@ -302,29 +323,21 @@ def main() -> int:
if missing_severity:
print(
- f"Warning: {len(missing_severity)} rule file(s) have no parseable SEVERITY "
- f"and are excluded from the severity counts: {', '.join(missing_severity)}",
+ f"Error: {len(missing_severity)} rule file(s) have no parseable SEVERITY: {', '.join(missing_severity)}",
file=sys.stderr,
)
+ return 1
if missing_category:
print(
- f"Warning: {len(missing_category)} rule file(s) have no parseable CATEGORY "
- f"and are excluded from the coverage-by-category chart: {', '.join(missing_category)}",
+ f"Error: {len(missing_category)} rule file(s) have no parseable CATEGORY: {', '.join(missing_category)}",
file=sys.stderr,
)
+ return 1
- chart_severities = {"HIGH", "MEDIUM", "LOW"}
- excluded_severities = {
- severity: count for severity, count in severities.items() if severity not in chart_severities and count
- }
- if excluded_severities:
- excluded_detail = ", ".join(f"{severity}: {count}" for severity, count in sorted(excluded_severities.items()))
- excluded_total = sum(excluded_severities.values())
- print(
- f"Warning: {excluded_total} rule(s) with severities outside the "
- f"HIGH/MEDIUM/LOW chart are excluded from the severity boxes: {excluded_detail}",
- file=sys.stderr,
- )
+ statistics_error = validate_statistics(rule_count, severities, categories)
+ if statistics_error:
+ print(f"Error: {statistics_error}", file=sys.stderr)
+ return 1
category_rows = render_category_rows(categories)
@@ -333,6 +346,7 @@ def main() -> int:
learn_original,
rule_count,
playbook_count,
+ severities["CRITICAL"],
severities["HIGH"],
severities["MEDIUM"],
severities["LOW"],
@@ -342,7 +356,7 @@ def main() -> int:
readme_original = README_PATH.read_text(encoding="utf-8")
readme_updated, readme_failures = render_readme(readme_original, rule_count, playbook_count)
- failures = [f"docs/learn/index.html -> {name}" for name in learn_failures]
+ failures = [f"website/src/pages/learn.astro -> {name}" for name in learn_failures]
failures += [f"README.md -> {name}" for name in readme_failures]
if failures:
@@ -369,7 +383,8 @@ def main() -> int:
print(
f"Updated {', '.join(changed)} - rules: {rule_count}, playbooks: {playbook_count}, "
- f"severity HIGH: {severities['HIGH']}, MEDIUM: {severities['MEDIUM']}, LOW: {severities['LOW']}"
+ f"severity CRITICAL: {severities['CRITICAL']}, HIGH: {severities['HIGH']}, "
+ f"MEDIUM: {severities['MEDIUM']}, LOW: {severities['LOW']}"
)
return 0
diff --git a/.github/workflows/update-learn-page.yml b/.github/workflows/update-learn-page.yml
index 92818c3c..a3499a01 100644
--- a/.github/workflows/update-learn-page.yml
+++ b/.github/workflows/update-learn-page.yml
@@ -31,7 +31,7 @@ jobs:
- name: Detect changes
id: diff
run: |
- if git diff --quiet -- docs/learn/index.html README.md; then
+ if git diff --quiet -- website/src/pages/learn.astro README.md; then
echo "changed=false" >> "$GITHUB_OUTPUT"
else
echo "changed=true" >> "$GITHUB_OUTPUT"
@@ -44,6 +44,6 @@ jobs:
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
- git add docs/learn/index.html README.md
+ git add website/src/pages/learn.astro README.md
git commit -s -m "docs: refresh learn page and README statistics [skip ci]"
git push origin "HEAD:$TARGET_REF"
diff --git a/README.md b/README.md
index 48ece101..5e020703 100644
--- a/README.md
+++ b/README.md
@@ -74,10 +74,10 @@ Findings map to NIST FIPS 203 (ML-KEM), FIPS 204 (ML-DSA), and FIPS 205 (SLH-DSA
| Feature | Description |
|---|---|
-| **Misconfiguration Scanner** | Runs 95 Azure security rules across storage, network, identity, database, compute, Key Vault, AKS, Kubernetes workloads, post-quantum cryptography, backup, serverless, private endpoint, and supply chain posture |
+| **Misconfiguration Scanner** | Runs 143 Azure security rules across storage, network, identity, database, compute, Key Vault, AKS, Kubernetes workloads, post-quantum cryptography, backup, serverless, private endpoint, and supply chain posture |
| **Compliance Mapper** | Maps findings to CIS Benchmarks, NIST CSF, ISO 27001, and SOC 2 framework JSON files |
| **Scan History API** | Stores scans and findings in PostgreSQL and exposes findings, score, scan history, compliance posture, drift, and resource inventory over REST |
-| **Remediation Playbooks** | Every documented rule ships with a matching review-gated remediation script (95 playbooks) |
+| **Remediation Playbooks** | Every documented rule ships with a matching review-gated remediation script (143 playbooks) |
| **Security Dashboard** | Full React dashboard deployed on Vercel - live monitoring, findings, compliance, drift, prioritization, and AI-layer views |
| **Project Website** | Documentation and reference site at [owasp.github.io/openshield](https://owasp.github.io/openshield/) - blog, rules gallery, architecture, evidence guides, roadmap, and releases |
| **Sentinel Integration** | Normalises findings and pushes them into Microsoft Sentinel via a Log Analytics custom table and KQL analytics rules |
@@ -119,11 +119,11 @@ Project policies and assurance evidence:
flowchart TD
A["React Dashboard\nVercel · Live"]
B["Flask REST API\nJWT · CORS · Blueprints"]
- C["Scanner Engine\n95 Python rules"]
+ C["Scanner Engine\n143 Python rules"]
D["Azure Subscription\nScanned via Azure SDK + Graph"]
E["Compliance Framework JSON\nCIS · NIST · ISO 27001 · SOC 2"]
F["PostgreSQL Database\nFindings · Scans"]
- G["Azure CLI Playbooks\n95 remediation scripts"]
+ G["Azure CLI Playbooks\n143 remediation scripts"]
H["sentinel/ingest.py\nNormalise + HMAC upload"]
I["Microsoft Sentinel\nOpenShieldFindings_CL · KQL rules"]
@@ -330,7 +330,7 @@ Learn OpenShield covers:
- Contributor onboarding
- Documentation navigation
-Live Learning Portal: https://openshieldlearn.netlify.app/learn/
+Live Learning Portal: https://owasp.github.io/openshield/learn/
Full documentation, the security rules gallery, architecture guide, evidence guide, and blog are available at the project website:
**[owasp.github.io/openshield](https://owasp.github.io/openshield/)**
diff --git a/docs/_redirects b/docs/_redirects
deleted file mode 100644
index fe0b625a..00000000
--- a/docs/_redirects
+++ /dev/null
@@ -1 +0,0 @@
-/ /learn/ 302
diff --git a/docs/learn/index.html b/docs/learn/index.html
deleted file mode 100644
index 891f19ef..00000000
--- a/docs/learn/index.html
+++ /dev/null
@@ -1,1041 +0,0 @@
-
-
-
-
-
-
- OpenShield Learn
-
-
-
- Skip to content
-
-
-
-
-
-
-
-
-
Open-source Azure CSPM platform
-
Learn Azure security posture with OpenShield.
-
- OpenShield scans Azure subscriptions for misconfigurations, enriches findings with CVE intelligence,
- maps risks to compliance frameworks, stores scan history, exposes a Flask API, and presents results through
- a React dashboard with demo and live modes.
-
Static learning hub. No backend, no login, no fake upload flows.
-
-
-
-
-
-
-
95Azure scan rules
-
95CLI remediation playbooks
-
4Compliance frameworks
-
8AI security skills
-
58High-severity checks
-
-
-
-
-
-
-
-
Overview
-
What OpenShield does
-
- OpenShield is built to help users identify risky Azure configurations, understand the impact, connect findings
- to compliance controls, and follow practical remediation guidance. It is not a cloud provider replacement or a SIEM;
- it is a focused Azure CSPM platform for posture visibility and learning.
-
-
-
-
-
-
-
Misconfiguration scanning
-
Dynamic Python rule modules inspect Azure resources through Azure SDK clients and return normalized security findings.
-
ScannerAzure SDKRules
-
-
-
CVE enrichment
-
Findings can be enriched with NVD/CVE context so security issues are easier to prioritize and explain.
-
NVDCVERisk context
-
-
-
Compliance mapping
-
Technical findings are mapped to CIS Azure, NIST CSF, ISO 27001, and SOC 2 for governance-oriented reporting.
-
CISNISTISO 27001SOC 2
-
-
-
Remediation guidance
-
Each rule is paired with a CLI playbook so contributors and users can move from detection to manual remediation.
-
Azure CLIPlaybooksValidation
-
-
-
-
-
-
Architecture
-
Production-shaped, MVP-friendly architecture
-
- The platform follows a simple pipeline: Azure credentials are resolved by DefaultAzureCredential, the scan engine loads
- rule files from scanner/rules/*.py, findings are enriched and stored, then exposed through the API and dashboard.
-
Flask REST API with JWT authentication, CORS, migrations, scans, findings, score, compliance, and AI routes.
-
Frontend
Vite, React, and Tailwind dashboard covering monitoring, discovery, prioritization, compliance, drift, and AI.
-
AI
RAG knowledge pipeline, ChromaDB vector store builder, retriever, and cloud-security knowledge skills.
-
Sentinel
Optional Log Analytics ingestion plus KQL analytics rules for detection workflows.
-
CI and docs
Checks syntax, secrets, rule structure, playbooks, compliance JSON, API syntax, and cross-references.
-
-
-
-
-
Rule coverage
-
95 Azure security rules
-
- OpenShield currently has 95 dynamic rules. The strongest contributor work improves rule accuracy, reduces false positives,
- strengthens validation, or improves remediation quality.
-
-
-
-
-
Coverage by category
-
-
Network
23
-
Identity
15
-
Security Operations
10
-
Supply Chain
8
-
KeyVault
6
-
Kubernetes
6
-
Serverless
5
-
Storage
5
-
Backup
4
-
Compute
4
-
Database
4
-
PostQuantum
3
-
Data Link
2
-
-
-
-
-
Severity distribution
-
Most checks are high severity. That makes validation important: high-severity false positives damage trust quickly.
-
-
58HIGH
-
31MEDIUM
-
4LOW
-
-
-
-
-
-
-
Learning roadmap
-
Recommended learning path
-
- Follow this path if you are new to OpenShield or preparing to contribute. Learn the security problem before touching code.
-
- Good contributions should improve detection accuracy, correctness of findings, remediation quality, documentation clarity,
- or system reliability. Cosmetic work is useful only when it supports those goals.
-
-
-
-
Rules
Add or improve Azure checks with accurate metadata, safe SDK usage, realistic test cases, and clear findings.
-
Playbooks
Keep remediation scripts aligned with rules. Every fix should include validation and avoid unsafe blanket changes.
-
Compliance
Improve CIS, NIST, ISO 27001, and SOC 2 mappings. Do not map controls just to inflate coverage.
-
Frontend
Connect live API flows carefully. Do not leave mock-backed UI pretending to be production data.
-
Backend
Implement missing endpoints consistently with JWT auth, error handling, data contracts, and PostgreSQL models.
-
AI and Sentinel
Improve RAG quality, knowledge loading, KQL rules, and ingestion without exposing sensitive findings unnecessarily.
-
-
-
-
-
Known gaps
-
Current cleanup items
-
- These are not failures; they are useful follow-up targets. Documenting them prevents contributors from pretending the platform is more complete than it is.
-
-
-
-
-
Documentation drift
-
-
Rule, playbook, and severity statistics on this page and in README.md are generated from scanner/rules/ and playbooks/cli/ by .github/scripts/update_learn_page.py on every push to dev.
-
Some startup commands assume python, but local environments may only expose python3.
-
API docs and implementation should stay aligned, especially score response shape.
-
-
-
-
Implementation gaps
-
-
Some frontend live pages depend on endpoints that may still be mock-backed.
-
Examples include resources, drift, prioritization, and finding-specific playbook routes.
-
Fix syntax issues before claiming AI pipeline readiness.
-
-
-
-
-
-
-
Documentation
-
Useful repo documents
-
- These relative links are intentionally static-hosting friendly when this file is served from the docs learning folder.
- Adjust paths if the Learn page is moved.
-
-
-
-
-
ArchitectureSystem design, scanner flow, platform components, and storage/API structure.
- Note: OpenShield Learn is a documentation and learning portal. Features such as authentication, file uploads, scan execution, and data persistence require backend services and are intentionally not implemented in this static site.
-
OpenShield turns Azure configuration evidence into findings, framework mappings, and explicit remediation. This guide connects the platform design to the repository that implements it.
OpenShield is a focused Azure CSPM platform for identifying risky configuration, understanding impact, connecting technical evidence to compliance controls, and following practical remediation guidance.
+
+
Scan
Python rules inspect Azure resources through SDK clients and normalize the resulting findings.
+
Explain
CVE enrichment and severity provide context without inferring evidence from absent findings.
+
Map
Framework reports distinguish technical evidence from mappings that are not yet independently reviewed.
+
Remediate
Each rule has a matching Azure CLI playbook with validation steps.
+
+
+
+
+
Architecture
+
Follow the evidence path
+
+
Azure subscriptionResource configuration
+
Scanner enginePython rule execution
+
Rule Evaluation143 dynamic checks
+
Flask APIFindings and posture data
+
React dashboardHuman review and action
+
+
+
+
+
Rule coverage
+
143 Azure security rules
+
OpenShield currently has 143 dynamic rules. The strongest contributor work improves rule accuracy, reduces false positives, strengthens validation, or improves remediation quality.
+
+
+
Coverage by category
+
+
Network
35
+
Identity
25
+
Kubernetes
21
+
Security Operations
10
+
Storage
9
+
Database
8
+
Supply Chain
8
+
Compute
7
+
KeyVault
6
+
Serverless
5
+
Backup
4
+
PostQuantum
3
+
Data Link
2
+
+
+
+
Severity distribution
+
Severity counts are generated from rule metadata and must reconcile with the headline rule total.