From fcc9481ad507e40249bef9565a4eabef834e9f0e Mon Sep 17 00:00:00 2001 From: Johan Lorenzo Date: Mon, 25 May 2026 12:02:20 +0200 Subject: [PATCH 1/2] bug 2037926 - landoscript: accept file-specific version_bump scopes --- landoscript/src/landoscript/script.py | 16 +++++---- landoscript/tests/test_script.py | 52 +++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 7 deletions(-) diff --git a/landoscript/src/landoscript/script.py b/landoscript/src/landoscript/script.py index f6b684ad9..ceded2088 100644 --- a/landoscript/src/landoscript/script.py +++ b/landoscript/src/landoscript/script.py @@ -29,11 +29,13 @@ def get_default_config(base_dir: str = "") -> dict: return default_config -def validate_scopes(scopes: set, lando_repo: str, actions: list[str]): - expected_scopes = { - f"project:releng:lando:repo:{lando_repo}", - *[f"project:releng:lando:action:{action}" for action in actions], - } +def validate_scopes(scopes: set, lando_repo: str, actions: list[str], version_bump_files: list[str] | None = None): + expected_scopes = {f"project:releng:lando:repo:{lando_repo}"} + expected_scopes.update(f"project:releng:lando:action:{a}" for a in actions if a != "version_bump") + if "version_bump" in actions and "project:releng:lando:action:version_bump" not in scopes: + expected_scopes.update( + f"project:releng:lando:action:version_bump:file:{f}" for f in (version_bump_files or []) + ) missing = expected_scopes - scopes if missing: raise scriptworker.client.TaskVerificationError(f"required scope(s) not present: {', '.join(missing)}") @@ -41,8 +43,8 @@ def validate_scopes(scopes: set, lando_repo: str, actions: list[str]): def sanity_check_payload(payload, scopes, lando_repo): """Additional verification past what the task schema does.""" - # validate scopes - these raise if there's any scope issues - validate_scopes(scopes, lando_repo, payload["actions"]) + version_bump_files = payload.get("version_bump_info", {}).get("files") if "version_bump" in payload["actions"] else None + validate_scopes(scopes, lando_repo, payload["actions"], version_bump_files) if len(payload["actions"]) < 1: raise TaskVerificationError("must provide at least one action!") diff --git a/landoscript/tests/test_script.py b/landoscript/tests/test_script.py index de64d5f51..c4be85d09 100644 --- a/landoscript/tests/test_script.py +++ b/landoscript/tests/test_script.py @@ -329,6 +329,58 @@ async def test_missing_scopes(aioresponses, github_installation_responses, conte assert m in e.args[0] +@pytest.mark.asyncio +async def test_file_specific_scope_allows_permitted_file(aioresponses, github_installation_responses, context): + payload = { + "actions": ["version_bump"], + "lando_repo": "repo_name", + "version_bump_info": { + "files": ["browser/config/version.txt"], + "next_version": "135.0", + }, + } + submit_uri, status_uri, job_id, _ = setup_test(aioresponses, github_installation_responses, context, payload, ["version_bump"]) + setup_github_graphql_responses(aioresponses, get_files_payload({"browser/config/version.txt": "134.0"})) + aioresponses.post(submit_uri, status=202, payload={"job_id": job_id, "status_url": str(status_uri), "message": "foo", "started_at": "2025-03-08T12:25:00Z"}) + aioresponses.get(status_uri, status=200, payload={"commits": ["abcdef123"], "push_id": job_id, "status": "LANDED"}) + + context.task = { + "payload": payload, + "scopes": [ + "project:releng:lando:repo:repo_name", + "project:releng:lando:action:version_bump:file:browser/config/version.txt", + ], + } + await async_main(context) + + +@pytest.mark.asyncio +async def test_file_specific_scope_rejects_non_permitted_file(aioresponses, github_installation_responses, context): + payload = { + "actions": ["version_bump"], + "lando_repo": "repo_name", + "version_bump_info": { + "files": ["config/milestone.txt"], + "next_version": "135.0", + }, + } + setup_test(aioresponses, github_installation_responses, context, payload, ["version_bump"]) + + context.task = { + "payload": payload, + "scopes": [ + "project:releng:lando:repo:repo_name", + "project:releng:lando:action:version_bump:file:browser/config/version.txt", + ], + } + try: + await async_main(context) + assert False, "should've raised TaskVerificationError" + except TaskVerificationError as e: + assert "required scope(s) not present" in e.args[0] + assert "project:releng:lando:action:version_bump:file:config/milestone.txt" in e.args[0] + + def test_task_schema(context): payload = { "actions": ["tag", "version_bump"], From 94037ce2d8cc86b0f66597b1c0aa689f4e951b46 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 25 May 2026 10:08:20 +0000 Subject: [PATCH 2/2] style: pre-commit.ci auto fixes [...] --- landoscript/src/landoscript/script.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/landoscript/src/landoscript/script.py b/landoscript/src/landoscript/script.py index ceded2088..582c675ca 100644 --- a/landoscript/src/landoscript/script.py +++ b/landoscript/src/landoscript/script.py @@ -33,9 +33,7 @@ def validate_scopes(scopes: set, lando_repo: str, actions: list[str], version_bu expected_scopes = {f"project:releng:lando:repo:{lando_repo}"} expected_scopes.update(f"project:releng:lando:action:{a}" for a in actions if a != "version_bump") if "version_bump" in actions and "project:releng:lando:action:version_bump" not in scopes: - expected_scopes.update( - f"project:releng:lando:action:version_bump:file:{f}" for f in (version_bump_files or []) - ) + expected_scopes.update(f"project:releng:lando:action:version_bump:file:{f}" for f in (version_bump_files or [])) missing = expected_scopes - scopes if missing: raise scriptworker.client.TaskVerificationError(f"required scope(s) not present: {', '.join(missing)}")