Files
computer-playbook/plugins/filter/ruby.py
T
kevinveenbirkenbachandClaude Opus 4.8 6a0ab683df fix(web-app-gitlab): fold GITLAB_OMNIBUS_CONFIG to one line for the swarm env-file
A swarm docker stack deploy env-file value must be a single physical line; the
multi-line GITLAB_OMNIBUS_CONFIG was read as separate whitespace-named env
entries and aborted the deploy. Add a depth-aware ruby_single_line filter that
collapses the Ruby program to one line (statement-boundary newlines at bracket
depth 0 become ';', newlines inside an open bracket or a string become a space
so hash/array literals like the OIDC omniauth_providers stay valid) and apply it
on the swarm branch only; compose keeps the multi-line value unchanged.

Covered by tests/unit/plugins/filter/test_ruby.py (10 cases incl. a realistic
omnibus config, escaped quotes and nested literals).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 18:31:36 +02:00

120 lines
3.2 KiB
Python

#
# Ansible filter for safely embedding values into Ruby double-quoted strings.
#
# Example:
# {{ my_password | ruby_dq }}
#
# Output:
# "escaped_value"
#
# Safe for GitLab Omnibus (gitlab.rb), Chef, Ruby DSLs.
class FilterModule:
def filters(self):
return {
"ruby_dq": self.ruby_double_quoted_string,
"ruby_single_line": self.ruby_single_line,
}
@staticmethod
def ruby_single_line(value):
"""Collapse a multi-line Ruby program to a single physical line.
A swarm ``docker stack deploy`` env-file value MUST be one physical
line; embedded newlines are read as separate (whitespace-named)
env entries and abort the deploy. Newlines at bracket depth 0 are
statement boundaries and become ``;``; newlines inside an open
``(``/``[``/``{`` (or a quoted string) are continuations and become
a space, which keeps Ruby hash/array literals valid.
Args:
value: Multi-line Ruby source (e.g. GITLAB_OMNIBUS_CONFIG).
Returns:
The same program as a single line.
"""
if value is None:
return ""
s = str(value)
out = []
depth = 0
in_str = False
quote = ""
i = 0
n = len(s)
while i < n:
c = s[i]
if in_str:
if c == "\\" and i + 1 < n:
out.append(c)
out.append(s[i + 1])
i += 2
continue
if c == "\n":
# A literal newline inside a string would still corrupt the
# single-line env-file; collapse it to a space.
out.append(" ")
i += 1
continue
out.append(c)
if c == quote:
in_str = False
i += 1
continue
if c in ("'", '"'):
in_str = True
quote = c
out.append(c)
elif c in "([{":
depth += 1
out.append(c)
elif c in ")]}":
depth = max(0, depth - 1)
out.append(c)
elif c == "\n":
out.append(";" if depth == 0 else " ")
else:
out.append(c)
i += 1
return "".join(out)
@staticmethod
def ruby_double_quoted_string(value):
"""
Escape a value for use inside a Ruby double-quoted string
and wrap it in double quotes.
Ruby rules handled:
- " -> \"
- \\ -> \\\\
- newlines -> \n
- carriage return -> \r
- tab -> \t
NOT escaped on purpose:
- $
- €
- !
- '
"""
if value is None:
return '""'
s = str(value)
# Escape backslash first
s = s.replace("\\", "\\\\")
# Escape double quotes
s = s.replace('"', '\\"')
# Escape control characters
s = s.replace("\n", "\\n")
s = s.replace("\r", "\\r")
s = s.replace("\t", "\\t")
return f'"{s}"'