Skip to content

Commit a019447

Browse files
authored
Merge pull request #5119 from rtfd/humitos/validate-mkdocs-configs
Validate mkdocs.yml config on values that we manipulate
2 parents 9563f0a + 2df203e commit a019447

File tree

3 files changed

+66
-2
lines changed

3 files changed

+66
-2
lines changed

readthedocs/doc_builder/backends/mkdocs.py

+22-2
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ def load_yaml_config(self):
8484
"""
8585
Load a YAML config.
8686
87-
Raise BuildEnvironmentError if failed due to syntax errors.
87+
:raises: ``MkDocsYAMLParseError`` if failed due to syntax errors.
8888
"""
8989
try:
9090
return yaml.safe_load(
@@ -105,20 +105,40 @@ def load_yaml_config(self):
105105
)
106106

107107
def append_conf(self, **__):
108-
"""Set mkdocs config values."""
108+
"""
109+
Set mkdocs config values.
110+
111+
:raises: ``MkDocsYAMLParseError`` if failed due to known type errors
112+
(i.e. expecting a list and a string is found).
113+
"""
109114
if not self.yaml_file:
110115
self.yaml_file = os.path.join(self.root_path, 'mkdocs.yml')
111116

112117
user_config = self.load_yaml_config()
113118

114119
# Handle custom docs dirs
115120
user_docs_dir = user_config.get('docs_dir')
121+
if not isinstance(user_docs_dir, (type(None), str)):
122+
raise MkDocsYAMLParseError(
123+
MkDocsYAMLParseError.INVALID_DOCS_DIR_CONFIG,
124+
)
125+
116126
docs_dir = self.docs_dir(docs_dir=user_docs_dir)
117127
self.create_index(extension='md')
118128
user_config['docs_dir'] = docs_dir
119129

120130
# Set mkdocs config values
121131
static_url = get_absolute_static_url()
132+
133+
for config in ('extra_css', 'extra_javascript'):
134+
user_value = user_config.get(config, [])
135+
if not isinstance(user_value, list):
136+
raise MkDocsYAMLParseError(
137+
MkDocsYAMLParseError.INVALID_EXTRA_CONFIG.format(
138+
config=config,
139+
),
140+
)
141+
122142
user_config.setdefault('extra_javascript', []).extend([
123143
'readthedocs-data.js',
124144
'%score/js/readthedocs-doc-embed.js' % static_url,

readthedocs/doc_builder/exceptions.py

+10
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,13 @@ class MkDocsYAMLParseError(BuildEnvironmentError):
5959
GENERIC_WITH_PARSE_EXCEPTION = ugettext_noop(
6060
'Problem parsing MkDocs YAML configuration. {exception}',
6161
)
62+
63+
INVALID_DOCS_DIR_CONFIG = ugettext_noop(
64+
'The "docs_dir" config from your MkDocs YAML config file has to be a '
65+
'string with relative or absolute path.',
66+
)
67+
68+
INVALID_EXTRA_CONFIG = ugettext_noop(
69+
'The "{config}" config from your MkDocs YAML config file has to be a '
70+
'a list of relative paths.',
71+
)

readthedocs/rtd_tests/tests/test_doc_builder.py

+34
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from readthedocs.builds.models import Version
1919
from readthedocs.doc_builder.backends.mkdocs import MkdocsHTML
2020
from readthedocs.doc_builder.backends.sphinx import BaseSphinx
21+
from readthedocs.doc_builder.exceptions import MkDocsYAMLParseError
2122
from readthedocs.doc_builder.python_environments import Virtualenv
2223
from readthedocs.projects.exceptions import ProjectConfigurationError
2324
from readthedocs.projects.models import Feature, Project
@@ -388,6 +389,39 @@ def test_append_conf_existing_yaml_on_root(self, checkout_path, run):
388389
'mkdocs'
389390
)
390391

392+
@patch('readthedocs.doc_builder.base.BaseBuilder.run')
393+
@patch('readthedocs.projects.models.Project.checkout_path')
394+
def test_append_conf_existing_yaml_on_root_with_invalid_setting(self, checkout_path, run):
395+
tmpdir = tempfile.mkdtemp()
396+
os.mkdir(os.path.join(tmpdir, 'docs'))
397+
yaml_file = os.path.join(tmpdir, 'mkdocs.yml')
398+
checkout_path.return_value = tmpdir
399+
400+
python_env = Virtualenv(
401+
version=self.version,
402+
build_env=self.build_env,
403+
config=None,
404+
)
405+
self.searchbuilder = MkdocsHTML(
406+
build_env=self.build_env,
407+
python_env=python_env,
408+
)
409+
410+
# We can't use ``@pytest.mark.parametrize`` on a Django test case
411+
yaml_contents = [
412+
{'docs_dir': ['docs']},
413+
{'extra_css': 'a string here'},
414+
{'extra_javascript': None},
415+
]
416+
for content in yaml_contents:
417+
yaml.safe_dump(
418+
content,
419+
open(yaml_file, 'w'),
420+
)
421+
with self.assertRaises(MkDocsYAMLParseError):
422+
self.searchbuilder.append_conf()
423+
424+
391425
@patch('readthedocs.doc_builder.base.BaseBuilder.run')
392426
@patch('readthedocs.projects.models.Project.checkout_path')
393427
def test_dont_override_theme(self, checkout_path, run):

0 commit comments

Comments
 (0)