docs: move the Learn page onto the Astro site and generate its statistics - #324
Conversation
ritiksah141
left a comment
There was a problem hiding this comment.
The updates are internally consistent and the mechanics are clean (docs-only, no leftover stale counts, DCO signed, CI green), but the numbers were computed against a dev snapshot from before #277 and #320 merged. Since your fork sync, #277 added 10 new perimeter rules (az_net_018 through az_net_027) plus 10 playbooks, so every headline number is wrong at the merge target:
| Stat | This PR | Actual at dev tip |
|---|---|---|
| Azure security rules | 96 | 106 |
| Remediation playbooks | 96 | 106 per-rule (107 .sh files including the review playbook) |
| HIGH checks | 58 | 67 |
| MEDIUM checks | 32 | 33 |
| Network category bar | 23 (untouched) | 33 |
Compute 5 is the only value that still matches. Related issues that come with the same root cause:
- The category bar widths are scaled to Network 23 as the max, so they need rescaling to 33 = 100% after the rebase.
- The severity boxes do not sum to the headline: 58 + 32 + 4 = 94 vs a headline of 96, because there is no CRITICAL box. The repo has 2 CRITICAL rules. At dev tip the real split is HIGH 67, MEDIUM 33, LOW 4, CRITICAL 2.
- The "4 Compliance frameworks" metric: compliance/frameworks/ now holds 6 JSON files (CIS, NIST CSF, ISO 27001, SOC 2, ENISA PQC, NCSC PQC). If 4 is deliberate (core mapper frameworks only), fine as-is; otherwise update to 6.
This is timing, not process: your sync landed before those merges. The fix is to rebase onto current dev and regenerate: rules and playbooks to 106, HIGH 67, MEDIUM 33, LOW 4, add a CRITICAL 2 severity box, Network bar to 33 with rescaled widths, and the README feature table plus mermaid diagram to 106. Happy to re-review once that lands.
|
@ritiksah141 Rebased onto current dev and recomputed everything against the real tip: rules/playbooks 106, HIGH 67, MEDIUM 33, added the missing CRITICAL box (2), Network bar rescaled to 33. On the "4 vs 6" compliance frameworks question — good catch flagging it rather than guessing. Turns out 4 is deliberate: CI's green on the current head. |
ritiksah141
left a comment
There was a problem hiding this comment.
All good from my side. approving it
There was a problem hiding this comment.
Docs-only change, clean diff, DCO signed, CI green. The internal consistency of the PR is good: the category bars sum to 106, bar widths are correctly scaled to Network=33 as 100%, and the severity boxes (CRITICAL 2 + HIGH 67 + MEDIUM 33 + LOW 4) sum exactly to 106. The addition of the CRITICAL severity box and the rescaling of bar widths are correct.
However, the headline number is stale. The PR was generated from a fork snapshot that matches dev after #277 (az_net_018..027, 10 new network rules) but before #279 (az_cache_001, az_cosmos_001, az_cosmos_002, az_db_005..007, az_idn_016..025, az_stor_006..009 20 rules across four categories). Current dev tip has 126 rules, not 106. The delta breaks down as:
| Category | This PR | dev tip | Delta |
|---|---|---|---|
| Network | 33 | 35 | +2 |
| Identity | 15 | 25 | +10 (AZ-IDN-016..025) |
| Database | 4 | 8 | +4 (cosmos_001, db_005..007) |
| Storage | 5 | 9 | +4 (stor_006..009) |
| Total | 106 | 126 | +20 |
Severity at dev tip: CRITICAL 3, HIGH 82, MEDIUM 37, LOW 4 (total 126). The PR's severity split is correct for its 106-rule snapshot but wrong relative to the actual merge target.
What needs updating before merge:
- README and
docs/learn/index.htmlheadline rule/playbook count: 106 → 126 - Category bars: Network 33→35, Identity 15→25, Database 4→8, Storage 5→9, with bar widths rescaled to Network=35 as 100%
- Severity boxes: CRITICAL 3, HIGH 82, MEDIUM 37, LOW 4
HIGH-severity checksmetric card: 67 → 82
The "4 Compliance frameworks" metric is fine as a deliberate choice (CIS, NIST CSF, ISO 27001, SOC 2 the two PQC-specific frameworks are not part of the general compliance mapper narrative).
Happy to re-review once rebased to current dev tip and statistics regenerated.
Signed-off-by: parthrohit22 <parthrohit60@gmail.com>
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Signed-off-by: parthrohit22 <parthrohit60@gmail.com>
|
@TFT444 rebased onto current Verified against the repo at dev tip:
Net diff vs |
|
@TFT444 re-review please. All four items from your Sep 4 review are on The branch is 0 commits behind Ground truth, via the repo's own What's rendered, item by item:
Internal consistency, checked rather than assumed — I parsed the rendered bars back out of Severity boxes sum to 3 + 82 + 37 + 4 = 126, and the category bars sum to 126 independently. Every bar width equals The Net diff against |
Signed-off-by: parthrohit22 <parthrohit60@gmail.com>
Signed-off-by: parthrohit22 <parthrohit60@gmail.com>
Signed-off-by: parthrohit22 <parthrohit60@gmail.com>
The statistics in this PR were computed from an older dev snapshot. Ran .github/scripts/update_learn_page.py against the current merge target: 143 rules and 143 matching playbooks, CRITICAL 5 / HIGH 94 / MEDIUM 40 / LOW 4 (sums to 143), and the category chart rescaled to Network 35 as 100% with Kubernetes and Compute moved into their correct positions. The script itself failed on the two README feature rows first: their prose had been reworded upstream (the category list gained 'Kubernetes workloads', the playbook row became 'review-gated remediation script'), and the patterns pinned the whole sentence. Both now anchor on the row label and the unit that follows the number instead, so an unrelated reword no longer blocks a count refresh while the counts go stale - losing the row or the count shape still fails loudly. Two tests cover both directions. Signed-off-by: parthrohit22 <parthrohit60@gmail.com>
|
@TFT444 @ritiksah141 statistics regenerated against the current Rather than hand-editing them again, I ran
The category chart rescaled and re-sorted itself — Kubernetes moved to 21 and Compute to 7, so both jumped several rows. README feature table and both Mermaid nodes updated to 143. Worth flagging, since it is the root cause of this PR going stale twice: the script failed before it could update anything. The two README feature rows had been reworded upstream (the category list gained "Kubernetes workloads", the playbook row became "review-gated remediation script"), and the patterns pinned the entire sentence, so both matched zero times and the script exited 1 by design. That is the failure mode where a count silently goes stale while the automation looks healthy. Both patterns are now anchored on the row label and the unit that follows the number instead of the surrounding prose — losing the row itself, or the Verification: the script is idempotent (second run produces no diff, so CI commits only on a real change); On the "4 Compliance frameworks" metric — keeping it at 4 as you both agreed: CIS, NIST CSF, ISO 27001, SOC 2, with the two PQC framework files deliberately outside that narrative. The PR description was still describing the old 96-rule docs-only change, so it has been rewritten to match what this diff actually is. Re-requesting review. |
|
All four items from my Sep 4 review are addressed and the numbers look correct at 143 rules on current dev. The branch is currently conflicting against dev. Please rebase onto current dev, re-run |
- docs/learn/index.html: kept this branch's deletion; the page now lives at website/src/pages/learn.astro, so dev's CRITICAL severity-box edit there is already covered by the Astro page. - .github/scripts/update_learn_page.py: kept this branch's version. It anchors README rows on their label and unit instead of the full prose (which is what OWASP#350 had to patch by hand) and validates that the CRITICAL/HIGH/MEDIUM/LOW boxes sum to the headline. - Regenerated statistics against current dev: 144 rules and 144 playbooks (AZ-STOR-010 from OWASP#327), CRITICAL 5 / HIGH 95 / MEDIUM 40 / LOW 4, Storage 10. Signed-off-by: parthrohit22 <parthrohit60@gmail.com>
|
Merged current
@TFT444 your 4 Sep request (stale numbers against the merge target) should be resolved now. Could you re-review? @ritiksah141 your approval was dismissed along the way, so re-requesting you too. One heads-up: rule counts drift every time a rule PR merges, so if something else lands first I'll just rerun the script. |
The "Update Learn Page and README Stats" workflow committed regenerated numbers and pushed them straight to dev. dev only accepts changes through pull requests, so the push was rejected (GH006) on every one of its 27 runs since it was added, and the numbers were never actually refreshed. - learn.astro now derives every count (rules, playbooks, severity boxes, category chart) from repoData at build time, the same source the rules page already uses. The build fails if the severity or category totals don't reconcile with the rule count, replacing validate_statistics(). - The script is now README-only (update_readme_stats.py) with a --check mode, since README.md is the one file that still states counts. - The workflow (readme-stats.yml) is read-only: after merges touching rules, playbooks or README it runs --check and reports drift as a warning plus job summary. It never pushes, so it needs no bypass of the dev ruleset. - repoData's Rule.severity type now includes CRITICAL. Signed-off-by: parthrohit22 <parthrohit60@gmail.com>
|
One more change in Why: the post-merge "Update Learn Page and README Stats" job has failed on every run since it was added (27 so far). It commits regenerated numbers and pushes straight to What changed:
|
|
@TFT444 @ritiksah141 - Guys do review this PR and take necessary action, I am planning to get the things on prod asap, so we don't want anything vulnerable going through! |
|
Full review of the current head (6dc8726) is done. I checked the branch out in a clean worktree, ran the new script in There is one robustness bug I would still like folded into this same PR before merging. It is small, it only touches files this PR already introduces, and doing it now saves a full follow-up PR cycle (branch, CI, review, merge) later. The bug: one INFO-severity rule breaks the entire website build
const SEVERITIES = ['CRITICAL', 'HIGH', 'MEDIUM', 'LOW'] as const;
...
if (severityTotal !== ruleCount || categoryTotal !== ruleCount) {
throw new Error(...);
}But The script this PR replaced handled INFO gracefully (it kept an INFO slot and printed an excluded-severities warning instead of failing). Today dev has zero INFO rules so CI is green, but the first INFO rule merged after this PR would break the Pages deployment and cost an urgent fix. The fix: three small edits, all in files this PR already touches
severity: 'CRITICAL' | 'HIGH' | 'MEDIUM' | 'LOW' | 'INFO';
const SEVERITIES = ['CRITICAL', 'HIGH', 'MEDIUM', 'LOW', 'INFO'] as const;
<div class="severity-box info"><strong>{severityCounts.INFO}</strong><span>INFO</span></div>and in the scoped style change the .info { background: #f1f5f9; color: #334155; }The 560px breakpoint ( Please sign the new commits ( Optional adjacent cleanup (pre-existing on dev, not introduced by this PR)
Validation after the change
Everything else looks right: moving the statistics to build time is the correct design, the new |
Resolve the modify/delete conflict on update-learn-page.yml by keeping this branch's deletion. OWASP#344 changed that job to open a bot PR instead of pushing to dev; this PR removes the need for it entirely, since the Learn page computes its statistics at build time and readme-stats.yml only reports README drift. docs/ci-pipeline.md now describes that flow. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JMtsuR7tvJTsoq5KueraLf Signed-off-by: parthrohit22 <parthrohit60@gmail.com>
INFO is a canonical level in contracts/severity.v1.json and CI accepts INFO rules, but learn.astro reconciled only CRITICAL/HIGH/MEDIUM/LOW against the rule total, so the first INFO rule would have failed the whole Pages build. Count INFO, render a fifth severity box (0 while no INFO rules exist) and widen the severity grid to five columns. The rules gallery and the homepage rules section had no CRITICAL or INFO entries in their severity maps, so the five CRITICAL rules on dev rendered with an empty label and an undefined colour (and as "Low" on the homepage). Add both levels with the contract colours, a CRITICAL filter button, and accept both in the ?severity= query parameter. Verified: npm run check passes (15 pages); marking one rule INFO locally builds cleanly and renders INFO 1 instead of failing reconciliation. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JMtsuR7tvJTsoq5KueraLf Signed-off-by: parthrohit22 <parthrohit60@gmail.com>
|
@ritiksah141 your INFO fix is in
Also merged current
@TFT444 your 4 Sep change request is still the formal blocker. The numbers now come from the build, so they can't go stale again. Could you re-review? |
Resolve modify/delete conflict on .github/scripts/update_learn_page.py: OWASP#362 refined the script's patterns, but this PR replaces the static Learn page and its update script with build-time stats in website/src/pages/ learn.astro (which already renders the CRITICAL severity box), so the deletion is kept. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MDxfYrq7uecZbnEkEesWbJ
Resolve the modify/delete conflict on .github/scripts/update_learn_page.py. OWASP#362 refined that script, but this PR replaces the static Learn page and its update script with build-time stats in website/src/pages/learn.astro, which already renders the CRITICAL severity box, so the deletion is kept. Signed-off-by: parthrohit22 <parthrohit60@gmail.com>
TFT444
left a comment
There was a problem hiding this comment.
All concerns from my 2026-09-04 review are addressed. The architectural fix is the right call: moving Learn page statistics to build-time derivation in repoData.ts and learn.astro eliminates the stale-stats problem structurally rather than patching it with a regeneration script. The old broken workflow (27 failed pushes to a protected branch) is gone. readme-stats.yml is read-only, correctly pinned, and surfaces README drift as a warning rather than a hard failure. Tests are solid. Approving.
Summary
Moves the Learn page onto the Astro site and computes its statistics when the site is built, so the page cannot go stale and nothing has to push generated numbers to
dev.Why this PR exists
The hosted Learn page was deployed from my fork rather than the upstream repository, so changes merged into
OWASP/openshielddid not appear there. The page also carried hand-maintained counts that went stale whenever a rule landed. The post-merge job meant to refresh them failed on every run becausedevonly accepts pull requests. #344 changed that job to open a bot PR instead (which produced #360). This PR removes the need for the job.Changes
docs/learn/index.htmlanddocs/_redirectsare removed. The page lives atwebsite/src/pages/learn.astroand computes every count fromwebsite/src/lib/repoData.ts, the same source/rules/uses. The build fails if the severity boxes or the category bars do not add up to the rule total.contracts/severity.v1.json, includingINFO. CI accepts INFO rules, so leaving INFO out would fail the whole Pages build on the first one. A fifth severity box shows INFO (0 today).devcurrently render with an empty label and an undefined colour, and as "Low" on the homepage. The gallery also gets a CRITICAL filter button and accepts?severity=CRITICAL|INFO.README.mdis the one file that still states counts..github/scripts/update_learn_page.pyis replaced byupdate_readme_stats.py, which rewrites only the README and has a--checkmode. Its patterns are anchored on the row label and the unit, not the whole sentence.update-learn-page.ymlis replaced byreadme-stats.yml(contents: read). It runs when rules, playbooks or the README change, and reports stale README counts as a warning with a job summary. It never pushes and never opens a PR, so there is no bypass of the ci: declare branch protection as rulesets and audit effective drift (#298) #344 rulesets and noSTATS_BOT_TOKENis needed.docs/ci-pipeline.mdis updated to match.website/scripts/verify-site.mjscovers the/learn/route and its canonical URL.Statistics on the merge target (current
dev)These are no longer committed to the page. They are what the build renders today.
Validation
npm run checkinwebsite/: build, configure-cms and verify pass for 15 HTML pages.SEVERITY = "INFO"locally, and the build still succeeded and rendered INFO 1 instead of failing reconciliation. Then I reverted the rule.python .github/scripts/update_readme_stats.py --check: README already current (144 / 144).pytest tests/test_update_readme_stats.py tests/test_check_branch_protection.py: 21 passed. Full backend suite: 1485 passed, 3 skipped.ruff check/ruff format --check: clean.npm run checkstill passes. The new route adds no inline script, so it satisfies fix(website): harden Astro CSP and verify the built output against it #318'sscript-src 'self'verifier.After merge
#360 is superseded and can be closed.