From e6dff2bc00b8ffa0deab7d22d062f72282f05f35 Mon Sep 17 00:00:00 2001 From: Edward Oliveira Date: Sat, 25 Apr 2026 00:01:02 -0300 Subject: [PATCH] Fix Redis configmap inline comment, clean cache key format, add blocked-IP scan to plan - redis-configmap: move inline comment to its own line (Redis fatal parse error) - settings: add CACHE_MIDDLEWARE_KEY_PREFIX='p' to remove double-dot in cache_page keys - settings: monkey-patch _i18n_cache_key_suffix to strip pt-br/timezone suffix from keys - ratelimit.py, settings: update example namespace from patobranco-pr to sapl31demo-df - robots.txt: add AwarioSmartBot block - plan: add rl:ip:*:blocked scan commands with TTL/value output Co-Authored-By: Claude Sonnet 4.6 --- docker/k8s/redis/redis-configmap.yaml | 3 ++- plan/RATE-LIMITER-PLAN.md | 14 ++++++++++++++ plan/rate-limiter-v2.md | 2 +- sapl/middleware/ratelimit.py | 2 +- sapl/settings.py | 16 +++++++++++++++- sapl/static/robots.txt | 4 ++++ 6 files changed, 37 insertions(+), 4 deletions(-) diff --git a/docker/k8s/redis/redis-configmap.yaml b/docker/k8s/redis/redis-configmap.yaml index 558cd7146..4c2b8fe1a 100644 --- a/docker/k8s/redis/redis-configmap.yaml +++ b/docker/k8s/redis/redis-configmap.yaml @@ -28,7 +28,8 @@ data: bind 0.0.0.0 protected-mode no - databases 4 # DB0: cache, DB1: rate limiter, DB2: channels (future) + # DB0: cache DB1: rate limiter DB2: channels (future) + databases 2 activedefrag yes active-defrag-ignore-bytes 100mb diff --git a/plan/RATE-LIMITER-PLAN.md b/plan/RATE-LIMITER-PLAN.md index d82d3ac92..e22444fa0 100644 --- a/plan/RATE-LIMITER-PLAN.md +++ b/plan/RATE-LIMITER-PLAN.md @@ -324,8 +324,22 @@ rancher kubectl exec -n sapl-redis deploy/sapl-redis -- redis-cli --latency-hist rancher kubectl exec -n sapl-redis deploy/sapl-redis -- \ redis-cli -n 1 dbsize +# All rate-limiter keys for an IP prefix rancher kubectl exec -n sapl-redis deploy/sapl-redis -- \ redis-cli -n 1 --scan --pattern 'rl:ip:*' | head -20 + +# All currently blocked IPs +rancher kubectl exec -n sapl-redis deploy/sapl-redis -- \ + redis-cli -n 1 --scan --pattern 'rl:ip:*:blocked' +``` + +Via port-forward (local machine — run `kubectl port-forward svc/redis -n sapl-redis 6379:6379` first): + +```bash +# All blocked IPs with value and remaining TTL +redis-cli -n 1 --scan --pattern 'rl:ip:*:blocked' | while read key; do + echo "$key → $(redis-cli -n 1 GET $key) (TTL: $(redis-cli -n 1 TTL $key)s)" +done ``` --- diff --git a/plan/rate-limiter-v2.md b/plan/rate-limiter-v2.md index ecbfcc3fd..27aee807a 100644 --- a/plan/rate-limiter-v2.md +++ b/plan/rate-limiter-v2.md @@ -662,7 +662,7 @@ CACHES = { else 'django.core.cache.backends.filebased.FileBasedCache' ), 'LOCATION': REDIS_URL + '/0' if _redis_ready else '/var/tmp/django_cache', - 'KEY_PREFIX': f'cache:{POD_NAMESPACE}', # e.g. "cache:sapl:" or "cache:patobranco-pr:" + 'KEY_PREFIX': f'cache:{POD_NAMESPACE}', # e.g. "cache:sapl:" or "cache:sapl31demo-df:" **( { 'OPTIONS': { diff --git a/sapl/middleware/ratelimit.py b/sapl/middleware/ratelimit.py index 070fb2f45..03647bced 100644 --- a/sapl/middleware/ratelimit.py +++ b/sapl/middleware/ratelimit.py @@ -40,7 +40,7 @@ logger = logging.getLogger('sapl.ratelimit') # --------------------------------------------------------------------------- # Tenant namespace — resolved once at startup from settings.POD_NAMESPACE. -# On K8s: the k8s namespace (e.g. "patobranco-pr"), set by start.sh. +# On K8s: the k8s namespace (e.g. "sapl31demo-df"), set by start.sh. # On bare-metal / VM / docker-compose: the machine hostname (default). # --------------------------------------------------------------------------- diff --git a/sapl/settings.py b/sapl/settings.py index 4137b2f35..0e5135e90 100644 --- a/sapl/settings.py +++ b/sapl/settings.py @@ -209,7 +209,7 @@ SPECTACULAR_SETTINGS = { # Defaults to the machine hostname so self-hosted (bare-metal / VM / # docker-compose) deployments work without any extra config. # On Kubernetes, POD_NAMESPACE is set by start.sh via the Downward API or -# the service-account namespace file (e.g. "patobranco-pr"). +# the service-account namespace file (e.g. "sapl31demo-df"). # --------------------------------------------------------------------------- POD_NAMESPACE = config('POD_NAMESPACE', default=host) @@ -221,6 +221,11 @@ POD_NAMESPACE = config('POD_NAMESPACE', default=host) REDIS_URL = config('REDIS_URL', default='') CACHE_BACKEND = config('CACHE_BACKEND', default='file') +# Avoid the double-dot in cache_page keys that occurs when this is '' (default). +# Namespace isolation is already handled by CACHES['default']['KEY_PREFIX']; +# this 'p' just fills the empty slot in Django's key format string. +CACHE_MIDDLEWARE_KEY_PREFIX = 'p' + def _build_cache_layer(pod_namespace, cache_backend, redis_url): """ @@ -488,6 +493,15 @@ def _compat_utc_tzinfo_factory(offset): pg_utils.utc_tzinfo_factory = _compat_utc_tzinfo_factory +## +## Strip the language/timezone suffix from Django page-cache keys. +## Django's _i18n_cache_key_suffix appends ".pt-br.America/Sao_Paulo" when +## USE_I18N and USE_TZ are True. SAPL is monolingual (always pt-br / +## America/Sao_Paulo), so the suffix is constant noise that bloats key names. +## +import django.utils.cache as _dj_cache +_dj_cache._i18n_cache_key_suffix = lambda request, cache_key: cache_key + # DATE_FORMAT = 'N j, Y' DATE_FORMAT = 'd/m/Y' SHORT_DATE_FORMAT = 'd/m/Y' diff --git a/sapl/static/robots.txt b/sapl/static/robots.txt index 109d3986f..4b791ce0b 100644 --- a/sapl/static/robots.txt +++ b/sapl/static/robots.txt @@ -26,6 +26,10 @@ User-agent: anthropic-python Disallow: / Crawl-delay: 10 +User-agent: AwarioSmartBot +Disallow: / +Crawl-delay: 10 + User-agent: * Disallow: /relatorios/ Crawl-delay: 10