v2026.4.20#37
Conversation
Greptile SummaryThis release migrates TLS management from cert-manager (Let's Encrypt) to a Bring-Your-Own certificate model, bumps spark-operator to 2.5.0 and ingress-nginx to 4.15.1, adds a spark-operator webhook readiness pre-flight hook, and introduces configurable frontend rate limiting.
Confidence Score: 4/5Safe to merge after fixing the ModSecurity chain rule; all other changes are well-structured and well-tested. One P1 finding: ModSecurity rule 14855 has t:length on the wrong rule in the chain, making the intended URI-length DDoS protection a no-op. The rest of the PR (BYO TLS refactor, spark webhook wait hook, dependency bumps, rate-limit configurability) is clean and backed by Helm unit tests. charts/qualytics/templates/ingress.yaml — the common.modsecurity.snippet template's new rule 14855 needs the t:length transformation moved to the first rule. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[helm upgrade --install] --> B{ingress.tls.secretName set?}
B -- Yes --> C[Both API + Frontend Ingresses\nuse secretName]
B -- No --> D{ingress.tls.apiSecretName set?}
D -- Yes --> E[API Ingresses use apiSecretName\nFrontend uses frontendSecretName]
D -- No --> F[API Ingresses use 'api-tls-cert'\nFrontend uses 'frontend-tls-cert']
C --> G[nginx reads k8s TLS Secret\ncreated by operator]
E --> G
F --> G
G --> H[HTTPS served to browser]
subgraph "Spark Readiness (new in this PR)"
S1[helm post-install hook] --> S2[spark-webhook-wait Job\nhook-weight -10]
S2 --> S3{webhook deployment\nrollout ready?}
S3 -- No, retry 5s --> S3
S3 -- Yes --> S4[SparkApplication\nhook-weight 0]
end
Reviews (1): Last reviewed commit: "Update v2026.4.20" | Re-trigger Greptile |
| SecRule REQUEST_URI_RAW "@gt 4096" "id:14855,phase:1,deny,status:414,chain" | ||
| SecRule REQUEST_URI_RAW "@unconditionalMatch" "t:length" |
There was a problem hiding this comment.
ModSecurity rule 14855 —
t:length in wrong chain position, URI length check never fires
@gt is a numeric operator: it converts REQUEST_URI_RAW to an integer before comparing. Without t:length on rule 1, a typical URI string (e.g. /api/foo?...) converts to 0, so 0 > 4096 is always false, the chain never continues, and the intended DDoS block is a no-op.
The t:length must be placed on the same rule as the @gt 4096 comparison. The simplest fix:
| SecRule REQUEST_URI_RAW "@gt 4096" "id:14855,phase:1,deny,status:414,chain" | |
| SecRule REQUEST_URI_RAW "@unconditionalMatch" "t:length" | |
| SecRule REQUEST_URI_RAW "@gt 4096" "id:14855,phase:1,deny,status:414,t:length" |
Alternatively, preserve the chain pattern with the operator order reversed (unconditional match first, length check in chain rule):
SecRule REQUEST_URI_RAW "@unconditionalMatch" "id:14855,phase:1,chain"
SecRule REQUEST_URI_RAW "@gt 4096" "t:length,deny,status:414"
| - **Infrastructure**: Ingress with ModSecurity WAF, BYO TLS certificates (customer-provided Secret), platform-specific storage classes (AWS/GCP/Azure) | ||
| - **Dependencies**: Spark Operator 2.5.0, nginx-ingress 4.15.1 (TLS is BYO — customer-provided `kubernetes.io/tls` Secret, see [docs/ingress-tls.md](docs/ingress-tls.md)) | ||
|
|
||
| Chart version: **2025.10.17** (application type) |
- ingress.yaml: place t:length on the same rule as @gt 4096 so the URI-length DDoS block actually fires. The previous chain evaluated @gt against the raw string (coerced to 0), making the rule a no-op. - CLAUDE.md: bump chart version reference from 2025.10.17 to 2026.4.20 to match Chart.yaml. Both flagged by Greptile review on #37. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
No description provided.