Remove 'enroll diff --enforce' option. Tighten yaml data re: handlers - use listen: instead of notify:
This commit is contained in:
parent
e9d7d74445
commit
903125976d
15 changed files with 851 additions and 1288 deletions
108
tests/test_render_safety.py
Normal file
108
tests/test_render_safety.py
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
"""Tests for the generation-time render-safety guardrails.
|
||||
|
||||
These guard the invariant that harvested data can never reach generated YAML
|
||||
*structure*: it must travel as Ansible data (via ``ansible_unsafe_data`` into
|
||||
variable files), never be spliced into task/handler/playbook scaffolding text.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
|
||||
from enroll.render_safety import (
|
||||
AnsibleUnsafeText,
|
||||
RenderSafetyError,
|
||||
ansible_unsafe_data,
|
||||
assert_generated_yaml_safe,
|
||||
is_ansible_template_like,
|
||||
scaffold_token,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"value",
|
||||
[
|
||||
"net",
|
||||
"admin",
|
||||
"section_misc_2",
|
||||
"docker_service",
|
||||
"enroll_restart_grouped_services_net",
|
||||
"host.example.com", # fqdn-like, dots/hyphens allowed
|
||||
"a-b_c.d",
|
||||
],
|
||||
)
|
||||
def test_scaffold_token_accepts_safe_identifiers(value):
|
||||
assert scaffold_token(value) == value
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"value",
|
||||
[
|
||||
"evil.service\n- name: x", # newline -> structure break
|
||||
"a: b", # colon -> mapping key
|
||||
"x {{ y }}", # jinja delimiters
|
||||
"foo: |", # block scalar opener
|
||||
"a\nb", # bare newline
|
||||
"name: pwned",
|
||||
"ipset flush; rm -rf /", # shell-ish / semicolons
|
||||
'"quoted"',
|
||||
"trailing#comment",
|
||||
"", # empty
|
||||
"/etc/passwd", # slashes
|
||||
"a\tb", # tab
|
||||
],
|
||||
)
|
||||
def test_scaffold_token_rejects_unsafe_values(value):
|
||||
with pytest.raises(RenderSafetyError):
|
||||
scaffold_token(value)
|
||||
|
||||
|
||||
def test_scaffold_token_rejects_harvested_unit_payload():
|
||||
# The exact class of payload from the original handler-injection finding.
|
||||
payload = (
|
||||
"evil.service\n"
|
||||
" ansible.builtin.command: touch /tmp/pwned\n"
|
||||
"- name: INJECTED\n"
|
||||
)
|
||||
with pytest.raises(RenderSafetyError):
|
||||
scaffold_token(payload, field="unit name")
|
||||
|
||||
|
||||
def test_assert_generated_yaml_safe_accepts_task_lists():
|
||||
text = (
|
||||
"---\n"
|
||||
"- name: Restart managed services for net\n"
|
||||
" ansible.builtin.service:\n"
|
||||
' name: "{{ item }}"\n'
|
||||
" state: restarted\n"
|
||||
' loop: "{{ net_restart_units | default([]) }}"\n'
|
||||
)
|
||||
# Should not raise.
|
||||
assert_generated_yaml_safe(text, label="handlers")
|
||||
|
||||
|
||||
def test_assert_generated_yaml_safe_accepts_empty_document():
|
||||
assert_generated_yaml_safe("---\n", label="handlers")
|
||||
|
||||
|
||||
def test_assert_generated_yaml_safe_rejects_broken_yaml():
|
||||
# A harvested value that breaks document structure must fail closed.
|
||||
broken = "---\n- name: a\n x: : :\n"
|
||||
with pytest.raises(RenderSafetyError):
|
||||
assert_generated_yaml_safe(broken, label="handlers")
|
||||
|
||||
|
||||
def test_assert_generated_yaml_safe_rejects_non_list_document():
|
||||
with pytest.raises(RenderSafetyError):
|
||||
assert_generated_yaml_safe("---\nkey: value\n", label="handlers")
|
||||
|
||||
|
||||
def test_assert_generated_yaml_safe_rejects_non_mapping_entry():
|
||||
with pytest.raises(RenderSafetyError):
|
||||
assert_generated_yaml_safe("---\n- just_a_string\n", label="handlers")
|
||||
|
||||
|
||||
def test_ansible_unsafe_data_still_tags_jinja_values():
|
||||
out = ansible_unsafe_data({"k": "{{ danger }}", "safe": "plain"})
|
||||
assert isinstance(out["k"], AnsibleUnsafeText)
|
||||
assert not isinstance(out["safe"], AnsibleUnsafeText)
|
||||
assert is_ansible_template_like("{{ x }}")
|
||||
assert not is_ansible_template_like("plain")
|
||||
Loading…
Add table
Add a link
Reference in a new issue