diff --git a/profile/README.md b/profile/README.md
index c9be240..53e3ce4 100644
--- a/profile/README.md
+++ b/profile/README.md
@@ -1,16 +1,16 @@
-
-
+
+
# SNode.C
-
-
+
+
@@ -23,10 +23,10 @@ SNode.C builds event-driven networking in C++. At its centre is [SNode.C](https:
-
-
-
-
+
+
+
+
diff --git a/profile/template.md b/profile/template.md
index 5760f1a..c9fca2f 100644
--- a/profile/template.md
+++ b/profile/template.md
@@ -1,16 +1,16 @@
-
+
-
-
+
+
# SNode.C
-
-
+
+
@@ -23,10 +23,10 @@ SNode.C builds event-driven networking in C++. At its centre is [SNode.C](https:
-
-
-
-
+
+
+
+
diff --git a/tests/test_navigation.py b/tests/test_navigation.py
index f94152b..879f0ed 100644
--- a/tests/test_navigation.py
+++ b/tests/test_navigation.py
@@ -74,6 +74,22 @@ def test_control_repository_uses_declared_navigation(self):
self.assertIn('SNode.C', (repo / 'docs/media/nav/up-snodec-light.svg').read_text())
self.assertEqual(page_headers(repo, check=True), [])
+ def test_absolute_profile_menu_keeps_local_generation_and_url(self):
+ repo = self.fixture('.github')
+ asset = repo / 'profile/media/menu/products.svg'
+ asset.parent.mkdir(parents=True)
+ asset.write_text(_menu_svg('Products', 274))
+ url = 'https://raw.githubusercontent.com/SNodeC/.github/refs/heads/main/profile/media/menu/products.svg'
+ foreign = 'https://example.com/menu.svg'
+ profile = repo / 'profile/README.md'
+ profile.write_text(f'# Organization\n\n
\n'
+ f'
\n')
+ page_headers(repo)
+ self.assertIn('width="160" height="28"', asset.read_text())
+ self.assertIn(f'src="{url}" width="160" height="28"', profile.read_text())
+ self.assertIn(f'src="{foreign}" width="274" height="28"', profile.read_text())
+ self.assertEqual(page_headers(repo, check=True), [])
+
def test_plan_chains_and_label_limit(self):
validate_plan(self.plan)
invalid = copy.deepcopy(self.plan)
diff --git a/tests/test_sync.py b/tests/test_sync.py
index 15ae615..19d388c 100644
--- a/tests/test_sync.py
+++ b/tests/test_sync.py
@@ -240,11 +240,13 @@ def test_template_markers_are_exactly_once_and_standalone(self):
with self.assertRaisesRegex(ValueError, 'exactly one standalone'):
render_profile(self.catalog, self.metadata, template)
- def test_relative_media_paths_exist(self):
- paths = re.findall(r'(?:src|srcset)="(media/[^"\s]+)"', self.profile)
+ def test_profile_images_use_absolute_public_urls_and_owned_assets(self):
+ prefix = 'https://raw.githubusercontent.com/SNodeC/.github/refs/heads/main/profile/'
+ paths = re.findall(r'(?:src|srcset)="([^"\s]+)"', self.profile)
self.assertTrue(paths)
for path in paths:
- self.assertTrue((ROOT / 'profile' / path).is_file(), path)
+ self.assertTrue(path.startswith(prefix), path)
+ self.assertTrue((ROOT / 'profile' / path.removeprefix(prefix)).is_file(), path)
def test_metadata_is_separate_and_complete(self):
self.assertEqual(set(self.metadata), {e['name'] for e in self.catalog})
diff --git a/tools/snodec_sync/navigation.py b/tools/snodec_sync/navigation.py
index 1831184..959f1a9 100644
--- a/tools/snodec_sync/navigation.py
+++ b/tools/snodec_sync/navigation.py
@@ -266,10 +266,9 @@ def anchor(match):
text = re.sub(r'\[!\[([^\]]*)\]\(([^)]+)\)\]\(([^)]+)\)',
lambda m: '' if _up_link(m[2], m[3], path, ancestors) else m[0], text)
for src in re.findall(r'(?:src="|!\[[^\]]*\]\()([^"\s)]+\.svg)', text):
- if src.startswith(('https:', 'http:', '/')):
- continue
- asset = posixpath.normpath(posixpath.join(posixpath.dirname(path), src))
- if '..' in PurePosixPath(asset).parts or not (checkout / asset).is_file():
+ asset = posixpath.normpath(posixpath.join(posixpath.dirname(path),
+ src.removeprefix('https://raw.githubusercontent.com/SNodeC/.github/refs/heads/main/profile/') if path == 'profile/README.md' else src))
+ if asset.startswith('/') or ':/' in asset or '..' in PurePosixPath(asset).parts or not (checkout / asset).is_file():
continue
svg = ET.parse(checkout / asset).getroot()
if svg.attrib.get('height') != '28' or 'nav' in PurePosixPath(asset).parts: