Thanks for posting what you’ve tried.
You discovered that {{ item }} returns nginx-includes/example.com/csp.conf.j2. This is because the template task creating that file is using with_items (a standard loop), where each item is a template file name.
If you switch your strategy from include-files to child-templates, the template task creating your child template will use with_dict (thus looping over hashes), where each item.value.somevar is the value of somevar in a site from wordpress_sites. See example usages of item.value in the wordpress-site.conf.j2 template.
Follow the docs for creating a child template, maybe something like this (untested):
{% extends 'roles/nginx/templates/nginx.conf.j2' %}
{% block server_basic -%}
{{ super() }}
add_header Content-Security-Policy "default-src 'none'; script-src https://{{ site_hosts_canonical | join(' https://') }};
{% endblock %}
(see jinja2 join filter)
You’ll see how site_hosts_canonical is just a helper variable that itself uses item.value.site_hosts and the jinja2 map filter.
P.S., If your Trellis is up-to-date, you can apply the nginx changes more quickly than
vagrant reload --provision because reloading (rebooting) the VM is not necessary, nor is most of the provision process. Try this:
ANSIBLE_TAGS=nginx-includes vagrant provision