From 86fab6c80b0c4fe6c93637a6f35186914d351be5 Mon Sep 17 00:00:00 2001 From: daniel-rdt Date: Fri, 3 Jul 2026 12:20:10 +0200 Subject: [PATCH 1/6] feat: add validation of Zenodo API URL and deposition_id --- utils/create_zenodo_deposition_cli.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/utils/create_zenodo_deposition_cli.py b/utils/create_zenodo_deposition_cli.py index ebfc404b23..0af57fb09b 100644 --- a/utils/create_zenodo_deposition_cli.py +++ b/utils/create_zenodo_deposition_cli.py @@ -232,6 +232,21 @@ def get_archive_folders(dataset): return sorted([f.name for f in archive_path.iterdir() if f.is_dir()]) +def validate_api_url() -> None: + """ + Validate the configured Zenodo API base URL against the allowlist. + + Ensures the scheme and authority match a known Zenodo API endpoint before it + is used to build request URLs, guarding against URL manipulation. Raises a + ``ValueError`` if the URL is not recognised. + """ + if ZENODO_API_URL not in API_URLS.values(): + raise ValueError( + f"Refusing to use unrecognised Zenodo API URL: {ZENODO_API_URL!r}. " + f"Expected one of {sorted(API_URLS.values())}." + ) + + def create_zenodo_deposition(metadata: dict, files: list[Path]) -> requests.Response: """ Create a new Zenodo deposition with the specified metadata and files. @@ -310,6 +325,13 @@ def publish_zenodo_deposition(deposition_id: int) -> requests.Response: Response The response from the Zenodo API after publishing the deposition. """ + # Validate id to be positive integer (rejecting bool, int-like strings and traversals) + if ( + isinstance(deposition_id, bool) + or not isinstance(deposition_id, int) + or deposition_id <= 0 + ): + raise ValueError(f"Invalid Zenodo deposition ID: {deposition_id!r}") r = requests.post( f"{ZENODO_API_URL}/deposit/depositions/{deposition_id}/actions/publish", params={"access_token": ZENODO_API_KEY}, @@ -453,6 +475,7 @@ def main( """ global ZENODO_API_URL ZENODO_API_URL = API_URLS["sandbox"] if sandbox else API_URLS["production"] + validate_api_url() if sandbox: typer.secho( From 30c1579132d4aeaf9fb3804d9e10c442c15a7a85 Mon Sep 17 00:00:00 2001 From: daniel-rdt Date: Fri, 3 Jul 2026 12:31:26 +0200 Subject: [PATCH 2/6] improve wording --- utils/create_zenodo_deposition_cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/create_zenodo_deposition_cli.py b/utils/create_zenodo_deposition_cli.py index 0af57fb09b..bce72d7026 100644 --- a/utils/create_zenodo_deposition_cli.py +++ b/utils/create_zenodo_deposition_cli.py @@ -242,7 +242,7 @@ def validate_api_url() -> None: """ if ZENODO_API_URL not in API_URLS.values(): raise ValueError( - f"Refusing to use unrecognised Zenodo API URL: {ZENODO_API_URL!r}. " + f"Invalid Zenodo API URL: {ZENODO_API_URL!r}. " f"Expected one of {sorted(API_URLS.values())}." ) From e937ddf0dd34fe346877ec1c5d23ccc0c8906487 Mon Sep 17 00:00:00 2001 From: daniel-rdt Date: Fri, 3 Jul 2026 12:34:10 +0200 Subject: [PATCH 3/6] doc: add release note --- doc/release_notes.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/release_notes.rst b/doc/release_notes.rst index 05c2ce4933..917910f268 100644 --- a/doc/release_notes.rst +++ b/doc/release_notes.rst @@ -43,6 +43,8 @@ Upcoming Open-TYNDP Release * Change GitHub issue templates to comply with ISO security checks (https://github.com/open-energy-transition/open-tyndp/pull/714, https://github.com/open-energy-transition/open-tyndp/pull/730). +* Add validation of Zenodo API base URL and deposition ID in ``create_zenodo_deposition_cli`` to close URL-manipulation finding (https://github.com/open-energy-transition/open-tyndp/pull/780). + Upcoming PyPSA-Eur Release ================ From c5c86f75f0b2c0d7adec908cb088f4082a3f8ef6 Mon Sep 17 00:00:00 2001 From: daniel-rdt Date: Tue, 7 Jul 2026 11:56:20 +0200 Subject: [PATCH 4/6] fix: remove redundant validation of API_URL --- utils/create_zenodo_deposition_cli.py | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/utils/create_zenodo_deposition_cli.py b/utils/create_zenodo_deposition_cli.py index bce72d7026..eb9d0c50e9 100644 --- a/utils/create_zenodo_deposition_cli.py +++ b/utils/create_zenodo_deposition_cli.py @@ -232,21 +232,6 @@ def get_archive_folders(dataset): return sorted([f.name for f in archive_path.iterdir() if f.is_dir()]) -def validate_api_url() -> None: - """ - Validate the configured Zenodo API base URL against the allowlist. - - Ensures the scheme and authority match a known Zenodo API endpoint before it - is used to build request URLs, guarding against URL manipulation. Raises a - ``ValueError`` if the URL is not recognised. - """ - if ZENODO_API_URL not in API_URLS.values(): - raise ValueError( - f"Invalid Zenodo API URL: {ZENODO_API_URL!r}. " - f"Expected one of {sorted(API_URLS.values())}." - ) - - def create_zenodo_deposition(metadata: dict, files: list[Path]) -> requests.Response: """ Create a new Zenodo deposition with the specified metadata and files. @@ -475,7 +460,6 @@ def main( """ global ZENODO_API_URL ZENODO_API_URL = API_URLS["sandbox"] if sandbox else API_URLS["production"] - validate_api_url() if sandbox: typer.secho( From cdad9e47cfeaf5b33157544fc7bcbf32ca318a52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20R=C3=BCdt?= <117752024+daniel-rdt@users.noreply.github.com> Date: Wed, 8 Jul 2026 16:57:18 +0200 Subject: [PATCH 5/6] Update doc/release_notes.md Co-authored-by: Thomas Gilon --- doc/release_notes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/release_notes.md b/doc/release_notes.md index 4db277d0e0..ed95c477ab 100644 --- a/doc/release_notes.md +++ b/doc/release_notes.md @@ -47,7 +47,7 @@ * Add missing regex anchors with `re.fullmatch` to `create_zenodo_deposition_cli` utils script ([778](https://github.com/open-energy-transition/open-tyndp/pull/778)). -* Add validation of Zenodo API base URL and deposition ID in `create_zenodo_deposition_cli` to close URL-manipulation finding ([780](https://github.com/open-energy-transition/open-tyndp/pull/780)). +* Add validation of Zenodo deposition ID in `create_zenodo_deposition_cli` to close URL-manipulation finding ([#780](https://github.com/open-energy-transition/open-tyndp/pull/780)). ## Upcoming PyPSA-Eur Release From 095aa1e892c12ccc2ce09ecbcecdfde4784f176f Mon Sep 17 00:00:00 2001 From: daniel-rdt Date: Wed, 8 Jul 2026 16:59:27 +0200 Subject: [PATCH 6/6] doc: fix formatting of release note --- doc/release_notes.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/release_notes.md b/doc/release_notes.md index ed95c477ab..1b0d0cfe42 100644 --- a/doc/release_notes.md +++ b/doc/release_notes.md @@ -35,17 +35,17 @@ * Update benchmarking documentation tables and figures for v0.7.1 ([#711](https://github.com/open-energy-transition/open-tyndp/pull/711)). -* Migrate the Sphinx/RST-based documentation to MkDocs/Markdown, as a follow-up to the [upstream migration](https://github.com/PyPSA/pypsa-eur/pull/2162) ([754](https://github.com/open-energy-transition/open-tyndp/pull/754)). +* Migrate the Sphinx/RST-based documentation to MkDocs/Markdown, as a follow-up to the [upstream migration](https://github.com/PyPSA/pypsa-eur/pull/2162) ([#754](https://github.com/open-energy-transition/open-tyndp/pull/754)). **Developers Note** * Change GitHub issue templates to comply with ISO security checks ([#714](https://github.com/open-energy-transition/open-tyndp/pull/714), [#730](https://github.com/open-energy-transition/open-tyndp/pull/730)). -* Introduce SBOM/Grype vulnerability scanning workflow, as a follow-up to the [upstream addition](https://github.com/PyPSA/pypsa-eur/pull/2164) ([754](https://github.com/open-energy-transition/open-tyndp/pull/754)). +* Introduce SBOM/Grype vulnerability scanning workflow, as a follow-up to the [upstream addition](https://github.com/PyPSA/pypsa-eur/pull/2164) ([#754](https://github.com/open-energy-transition/open-tyndp/pull/754)). -* Ensure `inflow_t` is always defined in `attach_hydro`, resolving a pylint use-before-assignment issue ([777](https://github.com/open-energy-transition/open-tyndp/pull/777)). +* Ensure `inflow_t` is always defined in `attach_hydro`, resolving a pylint use-before-assignment issue ([#777](https://github.com/open-energy-transition/open-tyndp/pull/777)). -* Add missing regex anchors with `re.fullmatch` to `create_zenodo_deposition_cli` utils script ([778](https://github.com/open-energy-transition/open-tyndp/pull/778)). +* Add missing regex anchors with `re.fullmatch` to `create_zenodo_deposition_cli` utils script ([#778](https://github.com/open-energy-transition/open-tyndp/pull/778)). * Add validation of Zenodo deposition ID in `create_zenodo_deposition_cli` to close URL-manipulation finding ([#780](https://github.com/open-energy-transition/open-tyndp/pull/780)).