waf: managed rules (OWASP CRS) contract — WAFManagedRules, location feature flag, deployer command fields#132
Open
acoshift wants to merge 2 commits into
Open
waf: managed rules (OWASP CRS) contract — WAFManagedRules, location feature flag, deployer command fields#132acoshift wants to merge 2 commits into
acoshift wants to merge 2 commits into
Conversation
…ag, deployer command fields
The api leg of WAF managed rules (SPEC-waf-managed-rules.md §2, §2.4):
- WAFManagedRules (enabled, mode enforce|detect, paranoiaLevel 1-4,
anomalyThreshold 1-100, excludedRules capped at 50 and bounded to CRS
detection ids 911100..948999) as managedRules on WAFSet/WAFItem.
Whole-replace semantics: nil clears; enabled:false keeps tuning.
- validWAFManagedRules structural validation; a disabled block is still
fully validated so bad tuning can't hide behind a toggle-off.
- CRS table column (on / off / -) between LIMITS and STATUS.
- LocationFeatures.WAF widens *struct{} -> *WAFLocationFeature
{managedRules bool}; legacy {"waf": {}} stays JSON-compatible.
- DeployerCommandWAFSet gains CorazaZoneID + ManagedRules,
DeployerCommandWAFDelete gains CorazaZoneID — empty CorazaZoneID means
a pre-managed-rules apiserver, deployer leaves Coraza state untouched
(the RateLimitZoneID mixed-version pattern).
Client passthrough needs no code change (fields ride the existing
waf.set/waf.get payloads).
…g marshal shape
Review polish before downstream consumers pin the wire shape:
- WAFItem.ManagedRules and WAFManagedRules.ExcludedRules gain json
omitempty so unconfigured zones don't emit "managedRules": null and
stored blocks don't emit "excludedRules": null in waf.get/waf.list.
- WAFItem doc now states the all-zero normalization (spec §3.2):
managedRules:{} reads back as unset, not as "off".
- Tests: WAFItem omission pinned in TestWAFManagedRulesWire; marshal
direction of the widened feature flag pinned in
TestWAFLocationFeatureCompat (zero WAFLocationFeature -> {"waf":{}}).
35a41f9 to
76df2fb
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.
WAF managed rules (OWASP CRS) — API contract
Implements row 1 (api repo) of SPEC-waf-managed-rules.md (§2): the pure contract for managed signature rules on the existing WAF zone. Typed knobs only — the platform generates SecLang downstream (deployer); raw SecLang is never accepted. No new RPC verbs and no new resource.
What's in here
WAFManagedRules(waf.go):enabled,mode(enforce/detect),paranoiaLevel(1..4),anomalyThreshold(1..100),excludedRules(CRS detection-rule ids only).WAFSet/WAFItemgain the field; whole-replace semantics — omitted/nil clears the block,enabled:falsekeeps the tuning stored (spec §2.2). Unset blocks are omitted fromwaf.get/waf.listJSON (no"managedRules": null).validWAFManagedRules(spec §2.2): structural validation, applied identically to enabled and disabled blocks so garbage tuning can't hide behindenabled:false. Exclusion ids bounded to911100..948999— the platform SecActions/CRS setup (≤901xxx) and the anomaly scoring/blocking machinery (949110+) are unreachable by exclusion.constraint.go):WAFManagedMaxExcludedRules(50),WAFManagedExcludedRuleIDMin/Max.location.go):LocationFeatures.WAFwidens*struct{}→*WAFLocationFeature{ManagedRules bool}. JSON-compatible both directions: legacy{"waf":{}}unmarshals to the zero feature, and the zero feature marshals back to{"waf":{}}(both pinned by tests).deployer.go):DeployerCommandWAFSet.CorazaZoneID+.ManagedRules,DeployerCommandWAFDelete.CorazaZoneID. EmptyCorazaZoneID= command from a pre-managed-rules apiserver → deployer leaves Coraza state untouched (theRateLimitZoneIDmixed-version pattern, spec §4.6).CRScolumn (on/offdisabled-but-tuned /-unset) inwaf.listandwaf.gettables.Breaking change (Go source only)
LocationFeatures.WAFchanges type*struct{}→*WAFLocationFeature. Wire/JSON is fully compatible; external Go consumers comparing or constructing the old anonymous type must switch to the named type (spec §2.3). Flagging here since the repo has no changelog file.Test evidence
gofmtclean;go build ./... && go vet ./... && go test ./...green — 70 tests pass across 2 packages. New coverage inwaf_managedrules_test.go:TestWAFSetValidManagedRules— valid/invalid matrix incl. bounds by literal (900000/901100/949110 rejected), duplicates, max-exclusions, and disabled-block-still-validated.TestWAFTableCRSColumn— on/off/- three-state cell in both tables.TestWAFManagedRulesWire— pins exact wire keys, omission of unsetmanagedRules/emptyexcludedRules, and that old-apiserver payloads unmarshalCorazaZoneIDto""andManagedRulesto nil (the deployer's mixed-version guard).TestWAFLocationFeatureCompat— legacy{"waf":{}}, flag-set, absent, and the marshal direction back to{"waf":{}}.Rollout (spec §10 / §14)
This feature gates on a parapet release: moonrhythm/parapet-ingress-controller#181 (spec §9a — unconditional phase-2 evaluation,
zonelabel onparapet_coraza_matches, resolving CRS include forms + compile test) must be merged, released, and rolled out withCORAZA_ENABLED=trueon the waf-flagged clusters before anything materializes. This api PR itself is rollout step 1 and is safe to merge/tag first — it adds contract only.Order after that: deployer PR (deploy binary before apiserver — spec §4.6 mixed-version matrix) → apiserver PR (migration before binary, then flip
features.waf.managedRulesper location via ops SQL, values not in PR text) → console/docs/mcp → deploys CLI re-pin gate: the CLI re-pins this api module only after the apiserver is deployed, sowaf.setwithmanagedRulesnever validates client-side against a server that drops it.Rollback note for downstream PRs: an apiserver rollback past this contract leaves stale Coraza ConfigMaps enforcing (empty-
CorazaZoneID= leave untouched); the runbook sweep lives in the apiserver/deployer PR descriptions (spec §4.6).Expected conflicts with sibling WAF branches
Three open contract branches touch the same files: #129 (
waf-test), #130 (waf-ip-lists), #131 (waf-events). All append to the sameconstraint.goconst block and editwaf.go, so whichever lands second gets trivial textual conflicts — intended resolution: keep both hunks (the additions are disjoint). One semantic overlap: #129'sWAFTestdoc says a zone draft is "the same payload as WAFSet"; oncemanagedRuleslands that is no longer exact (the Coraza engine has no CEL dry-run path) — the second-lander should amend that comment to scope waf.test to rules/limits. No semantic overlap with #130/#131.