11import gixy
22from gixy .plugins .plugin import Plugin
3+ from gixy .directives .directive import MapDirective
4+ from gixy .directives .block import MapBlock , GeoBlock
35
46class hash_without_default (Plugin ):
57 summary = "Detect when a hash block (map, geo) is used without a default value."
@@ -12,10 +14,43 @@ def __init__(self, config):
1214 super (hash_without_default , self ).__init__ (config )
1315
1416 def audit (self , directive ):
17+ # Collect entries from this block, following includes when present
18+ if isinstance (directive , MapBlock ):
19+ entries = list (directive .gather_map_directives (directive .children ))
20+ elif isinstance (directive , GeoBlock ):
21+ entries = list (directive .gather_geo_directives (directive .children ))
22+ else :
23+ entries = directive .children
24+
1525 found_default = False
16- for child in directive . children :
17- if child .src_val == 'default' and child .dest_val is not None :
26+ for child in entries :
27+ if isinstance ( child , MapDirective ) and child .src_val == 'default' and child .dest_val is not None :
1828 found_default = True
1929 break
20- if not found_default :
21- self .add_issue (directive = [directive ] + directive .children , reason = "Missing default value in {0} ${1}" .format (directive .name , directive .variable ))
30+
31+ if found_default :
32+ return
33+
34+ # Special-case: for map blocks, a single mapping entry without an explicit default
35+ # is commonly used to intentionally yield an empty string for all other cases.
36+ # This is especially useful with limit_req/limit_conn where empty keys disable limits.
37+ # In that scenario, requiring an explicit default creates noise. Therefore, only warn
38+ # for map when there are two or more mapping entries and no explicit default.
39+ if directive .name == 'map' :
40+ entries_count = 0
41+ for child in entries :
42+ if not isinstance (child , MapDirective ):
43+ continue
44+ if child .src_val == 'default' :
45+ continue
46+ entries_count += 1
47+
48+ # Do not warn for single-entry maps without default
49+ if entries_count <= 1 :
50+ return
51+
52+ # geo continues to require an explicit default regardless of entries count
53+ self .add_issue (
54+ directive = [directive ] + directive .children ,
55+ reason = "Missing default value in {0} ${1}" .format (directive .name , directive .variable ),
56+ )
0 commit comments