Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changes/908.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixed an object name containing a bracket raising `ValueError: Input line is malformed.` in `FortinetConfigParser` and losing the whole config. The restore of a `config system replacemsg` placeholder was guarded by the presence of a bracket alone, so any bracketed name was mistaken for one.
11 changes: 7 additions & 4 deletions netutils/config/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -1119,10 +1119,13 @@ def _build_nested_config(self, line: str) -> t.Optional[str]:
IndexError: When the number of parents does not match the expected deindent level.
"""
if "[" in line:
updated_line = self.uncommon_data.get(line.split('"')[1], None)
if not updated_line:
raise ValueError("Input line is malformed.")
line = updated_line
# Only a placeholder this parser put here, and nothing else. The
# guard used to be the bracket alone, so any object name containing
# one was taken for a placeholder and the lookup miss raised, losing
# the whole configuration.
parts = line.split('"')
if len(parts) > 2 and parts[1] in self.uncommon_data:
line = self.uncommon_data[parts[1]]
self._update_config_lines(line)
for line in self.generator_config:
if not line[0].isspace():
Expand Down
24 changes: 24 additions & 0 deletions tests/unit/test_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,30 @@ def test_incorrect_banner_ios():
compliance.parser_map["cisco_ios"](banner_cfg).config_lines # pylint: disable=expression-not-assigned


def test_fortinet_bracket_in_object_name():
"""A bracket in an object name is not a replacemsg placeholder.

_parse_out_offending replaces a `config system replacemsg` buffer with a
`["<name>"]` placeholder and _build_nested_config restores it, but the guard
was `"[" in line` alone. Any object name containing a bracket was taken for a
placeholder, and the lookup miss raised ValueError out of __init__.
"""
cfg = 'config firewall address\n edit "obj[1]"\n set subnet 10.0.0.0 255.0.0.0\n next\nend\n'
config_lines = compliance.parser_map["fortinet_fortios"](cfg).config_lines
assert [line.config_line for line in config_lines] == [
"config firewall address",
' edit "obj[1]"',
" set subnet 10.0.0.0 255.0.0.0",
]


def test_fortinet_replacemsg_buffer_still_restored():
"""The guard above must not stop a genuine placeholder being restored."""
cfg = 'config system replacemsg webproxy "deny"\n set buffer "<html>body</html>"\nend\n'
config_lines = compliance.parser_map["fortinet_fortios"](cfg).config_lines
assert any("set buffer" in line.config_line for line in config_lines)


def test_duplicate_line():
logging = (
"!\n"
Expand Down