Repository: sphinx-doc/sphinx

Issue:
Sanity checking for html_static_path needed?
See https://bugs.gentoo.org/show_bug.cgi?id=509810. Their `html_static_path` starts with `../`, which is apparently not something Sphinx deals well with.

---
- Bitbucket: https://bitbucket.org/birkenfeld/sphinx/issue/1464
- Originally reported by: Dirkjan Ochtman
- Originally created at: 2014-05-09T09:08:17.404


Discussion:

Patch:
diff --git a/CHANGES b/CHANGES
index 6e38020e8..faa12bb10 100644
--- a/CHANGES
+++ b/CHANGES
@@ -25,6 +25,8 @@ Features added
 --------------
 
 * #5124: graphviz: ``:graphviz_dot:`` option is renamed to ``:layout:``
+* #1464: html: emit a warning if :confval:`html_static_path` and
+  :confval:`html_extra_path` directories are inside output directory
 
 Bugs fixed
 ----------
diff --git a/sphinx/builders/html.py b/sphinx/builders/html.py
index c8d330d2d..7c72ed785 100644
--- a/sphinx/builders/html.py
+++ b/sphinx/builders/html.py
@@ -1157,17 +1157,25 @@ def validate_math_renderer(app: Sphinx) -> None:
 def validate_html_extra_path(app: Sphinx, config: Config) -> None:
     """Check html_extra_paths setting."""
     for entry in config.html_extra_path[:]:
-        if not path.exists(path.join(app.confdir, entry)):
+        extra_path = path.normpath(path.join(app.confdir, entry))
+        if not path.exists(extra_path):
             logger.warning(__('html_extra_path entry %r does not exist'), entry)
             config.html_extra_path.remove(entry)
+        elif path.commonpath([app.outdir, extra_path]) == app.outdir:
+            logger.warning(__('html_extra_path entry %r is placed inside outdir'), entry)
+            config.html_extra_path.remove(entry)
 
 
 def validate_html_static_path(app: Sphinx, config: Config) -> None:
     """Check html_static_paths setting."""
     for entry in config.html_static_path[:]:
-        if not path.exists(path.join(app.confdir, entry)):
+        static_path = path.normpath(path.join(app.confdir, entry))
+        if not path.exists(static_path):
             logger.warning(__('html_static_path entry %r does not exist'), entry)
             config.html_static_path.remove(entry)
+        elif path.commonpath([app.outdir, static_path]) == app.outdir:
+            logger.warning(__('html_static_path entry %r is placed inside outdir'), entry)
+            config.html_static_path.remove(entry)
 
 
 def validate_html_logo(app: Sphinx, config: Config) -> None:


Test patch:
diff --git a/tests/test_build_html.py b/tests/test_build_html.py
index 677ca9de0..352166d94 100644
--- a/tests/test_build_html.py
+++ b/tests/test_build_html.py
@@ -16,6 +16,7 @@
 import pytest
 from html5lib import HTMLParser
 
+from sphinx.builders.html import validate_html_extra_path, validate_html_static_path
 from sphinx.errors import ConfigError
 from sphinx.testing.util import strip_escseq
 from sphinx.util import docutils
@@ -1496,3 +1497,29 @@ def test_html_pygments_style_manually(app):
 def test_html_pygments_for_classic_theme(app):
     style = app.builder.highlighter.formatter_args.get('style')
     assert style.__name__ == 'SphinxStyle'
+
+
+@pytest.mark.sphinx(testroot='basic', srcdir='validate_html_extra_path')
+def test_validate_html_extra_path(app):
+    (app.confdir / '_static').makedirs()
+    app.config.html_extra_path = [
+        '/path/to/not_found',       # not found
+        '_static',
+        app.outdir,                 # outdir
+        app.outdir / '_static',     # inside outdir
+    ]
+    validate_html_extra_path(app, app.config)
+    assert app.config.html_extra_path == ['_static']
+
+
+@pytest.mark.sphinx(testroot='basic', srcdir='validate_html_static_path')
+def test_validate_html_static_path(app):
+    (app.confdir / '_static').makedirs()
+    app.config.html_static_path = [
+        '/path/to/not_found',       # not found
+        '_static',
+        app.outdir,                 # outdir
+        app.outdir / '_static',     # inside outdir
+    ]
+    validate_html_static_path(app, app.config)
+    assert app.config.html_static_path == ['_static']