Make CSP header token ordering deterministic

Sort CSP directive tokens lexicographically (keeping 'self' first) to ensure
stable, reproducible Content-Security-Policy headers and avoid spurious
Ansible changes caused by ordering-only differences. Add unit tests to verify
sorted connect-src tokens and deterministic output for unsorted whitelists.

Reference: https://chatgpt.com/share/692af53f-c3a4-800f-bd28-cc7e0b6ff7ce
This commit is contained in:
2025-11-29 14:30:19 +01:00
parent 9314cab664
commit 7fa6b2d770
2 changed files with 85 additions and 2 deletions

View File

@@ -20,6 +20,26 @@ def _dedup_preserve(seq):
out.append(x)
return out
def _sort_tokens(tokens):
"""
Return a deterministically ordered list of CSP tokens.
- de-duplicates while preserving relative order
- then sorts lexicographically
- keeps 'self' as the first token if present
"""
uniq = _dedup_preserve(tokens)
if not uniq:
return uniq
# Lexicographically sort all tokens
uniq = sorted(uniq)
# Ensure "'self'" is always first if present
if "'self'" in uniq:
uniq.remove("'self'")
uniq.insert(0, "'self'")
return uniq
class FilterModule(object):
"""
@@ -297,6 +317,10 @@ class FilterModule(object):
# ----------------------------------------------------------
# Assemble header
# ----------------------------------------------------------
# Sort tokens per directive for deterministic output
for directive, toks in list(tokens_by_dir.items()):
tokens_by_dir[directive] = _sort_tokens(toks)
parts = []
for directive in directives:
if directive in tokens_by_dir: