Skip to content

Commit 3e7dfae

Browse files
dbantyemann
andauthored
Merge pull request from GHSA-7wgr-7666-7pwj
* All strings used as file/directory names are now sanitized to address the path traversal vulnerabilities * Switched calls to utils.spinal_case to utils.kebab_case Co-authored-by: Ethan Mann <[email protected]>
1 parent d6970d6 commit 3e7dfae

File tree

7 files changed

+23
-17
lines changed

7 files changed

+23
-17
lines changed

end_to_end_tests/regen_golden_master.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,6 @@
77
from openapi_python_client.cli import app
88

99
if __name__ == "__main__":
10-
from .fastapi_app import generate_openapi_json
11-
12-
generate_openapi_json()
1310
runner = CliRunner()
1411
openapi_path = Path(__file__).parent / "fastapi_app" / "openapi.json"
1512
gm_path = Path(__file__).parent / "golden-master"

openapi_python_client/__init__.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,15 +83,15 @@ def _get_document(*, url: Optional[str], path: Optional[Path]) -> Union[Dict[str
8383

8484

8585
class Project:
86-
TEMPLATE_FILTERS = {"snakecase": utils.snake_case, "spinalcase": utils.spinal_case}
86+
TEMPLATE_FILTERS = {"snakecase": utils.snake_case, "kebabcase": utils.kebab_case}
8787
project_name_override: Optional[str] = None
8888
package_name_override: Optional[str] = None
8989

9090
def __init__(self, *, openapi: GeneratorData) -> None:
9191
self.openapi: GeneratorData = openapi
9292
self.env: Environment = Environment(loader=PackageLoader(__package__), trim_blocks=True, lstrip_blocks=True)
9393

94-
self.project_name: str = self.project_name_override or f"{openapi.title.replace(' ', '-').lower()}-client"
94+
self.project_name: str = self.project_name_override or f"{utils.kebab_case(openapi.title).lower()}-client"
9595
self.project_dir: Path = Path.cwd() / self.project_name
9696

9797
self.package_name: str = self.package_name_override or self.project_name.replace("-", "_")
@@ -231,6 +231,7 @@ def _build_api(self) -> None:
231231
endpoint_template = self.env.get_template("endpoint_module.pyi")
232232
async_endpoint_template = self.env.get_template("async_endpoint_module.pyi")
233233
for tag, collection in self.openapi.endpoint_collections_by_tag.items():
234+
tag = utils.snake_case(tag)
234235
module_path = api_dir / f"{tag}.py"
235236
module_path.write_text(endpoint_template.render(collection=collection))
236237
async_module_path = async_api_dir / f"{tag}.py"

openapi_python_client/templates/endpoint_macros.pyi

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
{% if endpoint.header_parameters %}
33
{% for parameter in endpoint.header_parameters %}
44
{% if parameter.required %}
5-
headers["{{ parameter.python_name | spinalcase}}"] = {{ parameter.python_name }}
5+
headers["{{ parameter.python_name | kebabcase}}"] = {{ parameter.python_name }}
66
{% else %}
77
if {{ parameter.python_name }} is not None:
8-
headers["{{ parameter.python_name | spinalcase}}"] = {{ parameter.python_name }}
8+
headers["{{ parameter.python_name | kebabcase}}"] = {{ parameter.python_name }}
99
{% endif %}
1010
{% endfor %}
1111
{% endif %}

openapi_python_client/utils.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,23 @@
33
import stringcase
44

55

6-
def snake_case(value: str) -> str:
6+
def _sanitize(value: str) -> str:
7+
return re.sub(r"[^\w _-]+", "", value)
8+
9+
10+
def group_title(value: str) -> str:
711
value = re.sub(r"([A-Z]{2,})([A-Z][a-z]|[ -_]|$)", lambda m: m.group(1).title() + m.group(2), value.strip())
812
value = re.sub(r"(^|[ _-])([A-Z])", lambda m: m.group(1) + m.group(2).lower(), value)
9-
return stringcase.snakecase(value)
13+
return value
14+
15+
16+
def snake_case(value: str) -> str:
17+
return stringcase.snakecase(group_title(_sanitize(value)))
1018

1119

1220
def pascal_case(value: str) -> str:
13-
return stringcase.pascalcase(value)
21+
return stringcase.pascalcase(_sanitize(value))
1422

1523

16-
def spinal_case(value: str) -> str:
17-
return stringcase.spinalcase(value)
24+
def kebab_case(value: str) -> str:
25+
return stringcase.spinalcase(group_title(_sanitize(value)))

tests/test___init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -486,8 +486,8 @@ def test__build_api(self, mocker):
486486
from openapi_python_client import GeneratorData, Project
487487

488488
openapi = mocker.MagicMock(autospec=GeneratorData, title="My Test API")
489-
tag_1 = mocker.MagicMock(autospec=str)
490-
tag_2 = mocker.MagicMock(autospec=str)
489+
tag_1 = "a_tag"
490+
tag_2 = "another_tag"
491491
collection_1 = mocker.MagicMock()
492492
collection_2 = mocker.MagicMock()
493493
openapi.endpoint_collections_by_tag = {tag_1: collection_1, tag_2: collection_2}

tests/test_templates/conftest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
def env() -> Environment:
77
from openapi_python_client import utils
88

9-
TEMPLATE_FILTERS = {"snakecase": utils.snake_case, "spinalcase": utils.spinal_case}
9+
TEMPLATE_FILTERS = {"snakecase": utils.snake_case, "kebabcase": utils.kebab_case}
1010
env = Environment(loader=PackageLoader("openapi_python_client"), trim_blocks=True, lstrip_blocks=True)
1111
env.filters.update(TEMPLATE_FILTERS)
1212
return env

tests/test_utils.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,5 @@ def test_snake_case_from_camel():
2020
assert utils.snake_case("httpResponseLowerCamel") == "http_response_lower_camel"
2121

2222

23-
def test_spinal_case():
24-
assert utils.spinal_case("keep_alive") == "keep-alive"
23+
def test_kebab_case():
24+
assert utils.kebab_case("keep_alive") == "keep-alive"

0 commit comments

Comments
 (0)