From ab2cff55d8d5621167c8859d81bce63537bb843c Mon Sep 17 00:00:00 2001 From: Andrew Halberstadt Date: Wed, 17 Aug 2022 16:50:28 -0400 Subject: [PATCH] feat: verify decision task has sufficient scopes before submitting --- src/taskgraph/decision.py | 4 +++ src/taskgraph/util/taskcluster.py | 1 + src/taskgraph/util/verify.py | 45 +++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+) diff --git a/src/taskgraph/decision.py b/src/taskgraph/decision.py index 38071f1df..17af55a5d 100644 --- a/src/taskgraph/decision.py +++ b/src/taskgraph/decision.py @@ -22,6 +22,7 @@ from taskgraph.util.python_path import find_object from taskgraph.util.schema import Schema, validate_schema from taskgraph.util.vcs import Repository, get_repository +from taskgraph.util.verify import verifications from taskgraph.util.yaml import load_yaml logger = logging.getLogger(__name__) @@ -123,6 +124,9 @@ def taskgraph_decision(options, parameters=None): shutil.copy2(RUN_TASK_DIR / "run-task", ARTIFACTS_DIR) shutil.copy2(RUN_TASK_DIR / "fetch-content", ARTIFACTS_DIR) + # run 'decision' verifications + verifications("decision", tgg.morphed_task_graph, tgg.graph_config, tgg.parameters) + # actually create the graph create_tasks( tgg.graph_config, diff --git a/src/taskgraph/util/taskcluster.py b/src/taskgraph/util/taskcluster.py index a830a473b..a8b2fee66 100644 --- a/src/taskgraph/util/taskcluster.py +++ b/src/taskgraph/util/taskcluster.py @@ -309,6 +309,7 @@ def rerun_task(task_id): _do_request(get_task_url(task_id, use_proxy=True) + "/rerun", json={}) +@memoize def get_current_scopes(): """Get the current scopes. This only makes sense in a task with the Taskcluster proxy enabled, where it returns the actual scopes accorded to the task.""" diff --git a/src/taskgraph/util/verify.py b/src/taskgraph/util/verify.py index 5911914f1..aebdc19a7 100644 --- a/src/taskgraph/util/verify.py +++ b/src/taskgraph/util/verify.py @@ -6,6 +6,7 @@ import logging import sys from abc import ABC, abstractmethod +from textwrap import dedent import attr @@ -13,6 +14,7 @@ from taskgraph.parameters import Parameters from taskgraph.taskgraph import TaskGraph from taskgraph.util.attributes import match_run_on_projects +from taskgraph.util.taskcluster import get_current_scopes from taskgraph.util.treeherder import join_symbol logger = logging.getLogger(__name__) @@ -281,3 +283,46 @@ def verify_always_optimized(task, taskgraph, scratch_pad, graph_config, paramete return if task.task.get("workerType") == "always-optimized": raise Exception(f"Could not optimize the task {task.label!r}") + + +@verifications.add("decision") +def verify_scopes_satisfaction(task, taskgraph, scratch_pad, graph_config, parameters): + if task is None: + if not scratch_pad: + return + + s = "s" if len(scratch_pad) else "" + are = "are" if len(scratch_pad) else "is" + + failstr = "" + for label, scopes in scratch_pad.items(): + failstr += "\n" + f" {label}:" + failstr += ( + " \n" + "\n ".join([f" {s}" for s in sorted(scopes)]) + "\n" + ) + + msg = dedent( + f""" + Required scopes are missing! + + The Decision task does not have all of the scopes necessary to + perform this request. The following task{s} {are} requesting scopes + the Decision task does not have: + """ + ) + msg += failstr + raise Exception(msg) + + current_scopes = get_current_scopes() + missing = set() + for required in task.task["scopes"]: + for current in current_scopes: + if current == required: + break + if current[-1] == "*" and required.startswith(current[:-1]): + break + else: + missing.add(required) + + if missing: + scratch_pad[task.label] = sorted(missing)