waf: managed rules (OWASP Core Rule Set) card, feature-flag pre-flight, CRS column#331
Open
acoshift wants to merge 2 commits into
Open
waf: managed rules (OWASP Core Rule Set) card, feature-flag pre-flight, CRS column#331acoshift wants to merge 2 commits into
acoshift wants to merge 2 commits into
Conversation
Preview
|
The WAF zone gains a managedRules block (apiserver waf.set/waf.get); this is
the console leg:
- Manage page: a Managed rules card between the rules list and rate limits —
enable toggle, enforce/detect mode, paranoia level 1-4 segmented picker,
anomaly threshold, and an excluded-CRS-rule-id chip editor with client-side
range validation (911100-948999, max 50). Saving echoes the whole zone
(rules + limits + managed block) per waf.set's whole-replace contract, and
unrelated rule/limit writes echo the last-SAVED managed block so a dirty
card edit never rides along. Toggling off keeps the tuning visible
(persisted server-side for re-enable).
- Loader pre-flight: location.get gates the card on
features.waf.managedRules — unsupported locations render a disabled
"Not available in this location" state instead of failing on save.
- Firewall index: CRS column (on / off / —) mirroring the api Table() column.
- $lib/waf/managed.ts: form <-> api normalization beside limits.ts.
- api.d.ts: WafManagedRules, WafZone.managedRules, Location features.waf
widened to { managedRules?: boolean }.
- Dev mock: seed location flags managedRules, seed zone carries a
session-mutable block so enable -> save -> reload round-trips offline;
location.get accepts the id arg the console actually sends.
- Playwright: tests/waf-managed.spec.js covers the unavailable state, enable/
tune/save payload, detect mode, round-trip, disabled-but-tuned freeze,
exclusion validation, whole-replace echo/omission, and the CRS column.
…n exit Review fixes on the managed-rules card: - The rule and limit editor pages rewrite the WHOLE zone on save but omitted managedRules — under waf.set's whole-replace contract that silently disabled AND cleared the stored block (tuning destroyed) on any rule/limit edit. Both pages now echo the loaded zone's block verbatim, same as the manage page's persistZone. One Playwright echo case per page. - A location can lose the features.waf.managedRules flag while a zone still carries an ENABLED block (ops un-flag, or a block set via CLI); the server rejects any save echoing enabled:true there, leaving the manage page unsaveable. The unavailable state now shows the stored block read-only and, when it is enabled, offers "Disable managed rules" (enabled:false with tuning kept — the one write the gate accepts). - The frozen excluded-rules list was only mouse-frozen (pointer-events); the TagInput now takes a real disabled prop (inner input + chip-remove buttons), so keyboard users can't edit the kept tuning while the block is off.
3084a1d to
4375f50
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
The console slice of WAF managed rules (OWASP Core Rule Set) — see
SPEC-waf-managed-rules.md§5 (console UX) and §14 row 4. The WAF zone gains a typedmanagedRulesblock (waf.set/waf.get, whole-replace); this PR is the UI for it. No SecLang anywhere in the console — generation is deployer-side (§4.2); the API surface is typed knobs only.waf/manage/+page.svelte): a Managed rules card between the rules list and rate limits — enable toggle, Enforce/Detect mode (with the v1 "detect matches are ops-visible only" caveat verbatim from §5), paranoia level 1–4 segmented picker, anomaly threshold, and an excluded-CRS-rule-id chip editor with client-side range validation (911100–948999, max 50). Toggling off keeps the tuning visible-but-frozen ("Disabled — your tuning is kept for re-enable", §2.2 semantics).waf/edit,waf/limit) echodata.zone.managedRuleson save. Omitting the field means "disabled and cleared" server-side, so a missing echo would destroy tuning on any unrelated edit.location.getand gates the card onfeatures.waf.managedRules— unsupported locations render "Not available in this location" instead of failing on save. If an un-flagged location still carries a stored enabled block (ops un-flag, or a block set via CLI), the card shows the stored state read-only and offers Disable managed rules (sendsenabled:falsewith tuning kept — the one write the server gate accepts; without it every rule/limit save in that location would be rejected).waf/+page.svelte):CRScolumn (on / off / —), mirroring the apiTable()column.$lib/waf/managed.ts: form ⇄ api normalization besidelimits.ts; exclusions dedupe + ascending sort so a rule-only save echoing the server block stays byte-identical (supports the apiserver DeepEqual no-op guard, §3.3).TagInputgains a realdisabledprop (inner input + chip-remove buttons) so the frozen exclusion list is keyboard-frozen too, not justpointer-events: none.api.d.ts), dev mock (session-mutable managed block so enable → save → reload round-trips offline), Playwright spectests/waf-managed.spec.js(12 cases).Deliberate deviation from spec letter: §5 says the Enabled toggle itself goes through
GuardedButton/can('waf.set'); here the toggle is a plain checkbox and only Save managed rules is permission-guarded — matching this page's existing convention (rule/limit drafts are also freely editable with a guarded submit). The write is gated either way.Tests
bun run lint/bun run check: 0 errors.bun run test: 343 passed (full suite), includingtests/waf-managed.spec.js12/12: unavailable state, enable/tune/save payload, detect mode, stored round-trip, disabled-but-tuned freeze (incl. keyboard), exclusion range validation, whole-replace echo from the manage page AND both editor pages, never-configured omission, un-flagged-location disable exit, CRS column.Rollout (spec §10; this PR is step 4 — deploy last)
Everything gates on a parapet release: moonrhythm/parapet-ingress-controller#181 (unconditional phase-2 evaluation,
zonelabel onparapet_coraza_matches, resolving Include forms + CRS compile test) must be merged, released, and rolled out withCORAZA_ENABLED=true(+CORAZA_REQUEST_BODY_LIMIT) on the flagged clusters before any deploys-side deploy — a merely Coraza-capable image is not sufficient (§10 step 0).Order: parapet release +
CORAZA_ENABLED→ api PR → deployer binary → apiserver (migrationmanaged_rulescolumn, then binary) → flipfeatures.waf.managedRulesper location (ops SQL, by name) → console (this PR) / docs / mcp / CLI api re-pin, any order.Safe to merge/deploy early regardless: pre-flag no location advertises
features.waf.managedRules, so the card renders "Not available in this location" everywhere and the editors'managedRulesecho isundefined(field omitted) for zones that have no block — byte-identicalwaf.setpayloads against an old apiserver.The deploys CLI re-pin gate (§6) applies to the CLI, not this repo:
deploysmust re-pin the api module beforewaf set -f zone.yamlpasses the field through; until then CLI zone rewrites drop managed rules the same way the docs warning (§7) describes for scripts.Expected conflicts with sibling WAF branches
Sibling branches in flight (api/apiserver:
waf-test,waf-ip-lists,waf-events; console worktrees:waf-copy-zone,waf-events,waf-ip-lists,waf-test) overlap this diff; first merged wins, the rest rebase with semantic resolution:waf/manage/+page.svelte— touched by all four siblings. Resolution: keep each feature's card/section additive; any zone rewrite they add must echomanagedRules(thepersistZone(nextRules, nextLimits, nextManaged)helper here is the pattern to adopt).waf/edit/+page.svelte,waf/limit/+page.svelte—waf-testtouches both, exactly where this PR adds themanagedRulesecho to thewaf.setbody. Resolution: keep the echo line; it must survive any refactor of the save body.waf/+page.svelte— this PR widens the table to 8 columns (EmptyRow/ErrorRowcolspan 7→8).waf-ip-lists/waf-copy-zoneadding columns is a semantic conflict: recount the colspan, don't take either side textually.mock.ts/api.d.ts— three branches touch them; unions are additive, merge both sides.waf-copy-zone's cross-location copy modal must decide copy-vs-drop formanagedRulesand handle a target location without the flag (same hazard class as the editor-echo fix in this PR): suggested resolution — copy the block withenabled:falsewhen the target lacksfeatures.waf.managedRules, copy verbatim otherwise.Screenshots
Generated via the Playwright mock harness (
bun run test, mock fixtures), published on thescreenshotsbranch.