FI-WP-0005 T01-T03: owner declaration, publication decision, egress hosts.

- Owner declaration for the profiled fi-daily-research-brief (proposed):
  inputs, single-commit briefs/** grant, fast-forward-only publication,
  quality rules, model requirements without env selection, completion
  evidence and rollback pins.
- Decision: origin publication is a typed grant on the run, not an
  executor default.
- docs/sources-egress.yaml: 17 exact host:443 entries for the sandbox,
  tested for sand-boxer format and drift against the prose allowlist.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 51320@bnt-lap001
Assistant-Session: 9d40b4c7-8e3c-42ee-b755-d658d4640d6c
This commit is contained in:
tegwick 2026-09-22 12:00:59 +02:00
parent 7009521fdc
commit 5c5c298643
8 changed files with 396 additions and 4 deletions

View file

@ -0,0 +1,51 @@
"""docs/sources-egress.yaml stays valid for sand-boxer and in step with the prose allowlist."""
from pathlib import Path
import re
import unittest
import yaml
ROOT = Path(__file__).resolve().parent.parent
EGRESS = ROOT / 'docs' / 'sources-egress.yaml'
ALLOWLIST = ROOT / 'docs' / 'sources-allowlist.md'
# sand-boxer bwrap-egress: exact lowercase DNS name, port 443, no wildcard or IP literal.
HOST = re.compile(r'^(?=.{1,253}:443$)([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]{2,63}:443$')
MAX_HOSTS = 24 # every host is a whole-host trust decision; raise only deliberately
class SourcesEgressTests(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.doc = yaml.safe_load(EGRESS.read_text(encoding='utf-8'))
cls.hosts = cls.doc['hosts']
cls.prose = ALLOWLIST.read_text(encoding='utf-8')
def test_version(self):
self.assertEqual(self.doc['version'], 1)
def test_host_format(self):
for entry in self.hosts:
self.assertRegex(entry['host'], HOST)
def test_no_duplicates_and_bounded(self):
names = [e['host'] for e in self.hosts]
self.assertEqual(len(names), len(set(names)))
self.assertLessEqual(len(names), MAX_HOSTS)
def test_entries_complete(self):
for entry in self.hosts:
self.assertEqual(set(entry), {'host', 'axes', 'channel', 'why'}, entry['host'])
self.assertTrue(entry['why'].strip(), entry['host'])
self.assertTrue(set(entry['axes']) <= set('ABCD'), entry['host'])
def test_every_axis_covered(self):
covered = {axis for e in self.hosts for axis in e['axes']}
self.assertEqual(covered, set('ABCD'))
def test_channel_named_in_prose_allowlist(self):
for entry in self.hosts:
self.assertIn(entry['channel'], self.prose, entry['host'])
if __name__ == '__main__':
unittest.main()