Example #1
0
def test_preprocess_tasks():
    conf = PoolConfiguration.from_file(POOL_FIXTURES / "pre-pool.yml")

    task_ids, tasks = zip(*conf.build_tasks("someTaskId"))

    # Check we have 2 valid generated task ids
    assert len(task_ids) == 2
    assert all(map(slugid.decode, task_ids))

    # Check we have 2 valid task definitions
    assert len(tasks) == 2

    def _check_date(task, *keys):
        # Dates can not be checked directly as they are generated
        assert keys, "must specify at least one key"
        value = task
        for key in keys:
            obj = value
            assert isinstance(obj, dict)
            value = obj[key]
        assert isinstance(value, str)
        date = datetime.datetime.strptime(value, "%Y-%m-%dT%H:%M:%S.%fZ")
        del obj[key]
        return date

    expected = [
        {
            "deps": ["someTaskId"],
            "extra_env": {
                "TASKCLUSTER_FUZZING_PREPROCESS": "1"
            },
            "name": "preprocess",
        },
        {
            "deps": ["someTaskId", task_ids[0]],
            "extra_env": {},
            "name": "1/1"
        },
    ]
    for task, expect in zip(tasks, expected):
        created = _check_date(task, "created")
        deadline = _check_date(task, "deadline")
        expires = _check_date(task, "expires")
        assert expires >= deadline > created
        expected_env = {
            "TASKCLUSTER_FUZZING_POOL": "pre-pool",
            "TASKCLUSTER_SECRET": "project/fuzzing/decision",
        }
        expected_env.update(expect["extra_env"])

        log_expires = _check_date(task, "payload", "artifacts",
                                  "project/fuzzing/private/logs", "expires")
        assert log_expires == expires
        assert set(task["scopes"]) == set(
            ["secrets:get:project/fuzzing/decision"])
        # scopes are already asserted above
        # - read the value for comparison instead of deleting the key, so the object is
        #   printed in full on failure
        scopes = task["scopes"]
        assert task == {
            "dependencies": expect["deps"],
            "extra": {},
            "metadata": {
                "description":
                ("*DO NOT EDIT* - This resource is configured automatically.\n\n"
                 "Fuzzing resources generated by https://github.com/MozillaSecurity"
                 "/orion/tree/master/services/fuzzing-decision"),
                "name":
                f"Fuzzing task linux-pre-pool - {expect['name']}",
                "owner":
                "*****@*****.**",
                "source":
                "https://github.com/MozillaSecurity/orion",
            },
            "payload": {
                "artifacts": {
                    "project/fuzzing/private/logs": {
                        "path": "/logs/",
                        "type": "directory",
                    }
                },
                "cache": {},
                "capabilities": {},
                "env": expected_env,
                "features": {
                    "taskclusterProxy": True
                },
                "image": "MozillaSecurity/fuzzer:latest",
                "maxRunTime": 3600,
            },
            "priority": "high",
            "provisionerId": "proj-fuzzing",
            "retries": 5,
            "routes": [],
            "schedulerId": "-",
            "scopes": scopes,
            "tags": {},
            "taskGroupId": "someTaskId",
            "workerType": "linux-pre-pool",
        }
Example #2
0
def test_tasks(env, scope_caps):
    scopes, expected_capabilities = scope_caps
    conf = PoolConfiguration(
        "test",
        {
            "artifacts": {
                "/some-file.txt": {
                    "type": "file",
                    "url": "project/fuzzing/private/file.txt",
                },
                "/var/log/": {
                    "type": "directory",
                    "url": "project/fuzzing/private/var-log",
                },
            },
            "cloud": "gcp",
            "command": ["run-fuzzing.sh"],
            "container": "MozillaSecurity/fuzzer:latest",
            "cores_per_task": 1,
            "cpu": "x64",
            "cycle_time": "1h",
            "disk_size": "10g",
            "imageset": "anything",
            "macros": {},
            "max_run_time": "30s",
            "metal": False,
            "minimum_memory_per_core": "1g",
            "name": "Amazing fuzzing pool",
            "parents": [],
            "platform": "linux",
            "preprocess": None,
            "schedule_start": None,
            "scopes": scopes,
            "tasks": 2,
        },
    )

    task_ids, tasks = zip(*conf.build_tasks("someTaskId", env=env))

    # Check we have 2 valid generated task ids
    assert len(task_ids) == 2
    assert all(map(slugid.decode, task_ids))

    # Check we have 2 valid task definitions
    assert len(tasks) == 2

    def _check_date(task, *keys):
        # Dates can not be checked directly as they are generated
        assert keys, "must specify at least one key"
        value = task
        for key in keys:
            obj = value
            assert isinstance(obj, dict)
            value = obj[key]
        assert isinstance(value, str)
        date = datetime.datetime.strptime(value, "%Y-%m-%dT%H:%M:%S.%fZ")
        del obj[key]
        return date

    for i, task in enumerate(tasks):
        created = _check_date(task, "created")
        deadline = _check_date(task, "deadline")
        expires = _check_date(task, "expires")
        assert expires >= deadline > created
        expected_env = {
            "TASKCLUSTER_FUZZING_POOL": "test",
            "TASKCLUSTER_SECRET": "project/fuzzing/decision",
        }
        if env is not None:
            expected_env.update(env)

        log_expires = _check_date(task, "payload", "artifacts",
                                  "project/fuzzing/private/logs", "expires")
        assert log_expires == expires
        log_expires = _check_date(task, "payload", "artifacts",
                                  "project/fuzzing/private/file.txt",
                                  "expires")
        assert log_expires == expires
        log_expires = _check_date(task, "payload", "artifacts",
                                  "project/fuzzing/private/var-log", "expires")
        assert log_expires == expires
        assert set(
            task["scopes"]) == set(["secrets:get:project/fuzzing/decision"] +
                                   scopes)
        # scopes are already asserted above
        # - read the value for comparison instead of deleting the key, so the object is
        #   printed in full on failure
        scopes = task["scopes"]
        assert task == {
            "dependencies": ["someTaskId"],
            "extra": {},
            "metadata": {
                "description":
                ("*DO NOT EDIT* - This resource is configured automatically.\n\n"
                 "Fuzzing resources generated by https://github.com/MozillaSecurity"
                 "/orion/tree/master/services/fuzzing-decision"),
                "name":
                f"Fuzzing task linux-test - {i+1}/2",
                "owner":
                "*****@*****.**",
                "source":
                "https://github.com/MozillaSecurity/orion",
            },
            "payload": {
                "artifacts": {
                    "project/fuzzing/private/logs": {
                        "path": "/logs/",
                        "type": "directory",
                    },
                    "project/fuzzing/private/file.txt": {
                        "path": "/some-file.txt",
                        "type": "file",
                    },
                    "project/fuzzing/private/var-log": {
                        "path": "/var/log/",
                        "type": "directory",
                    },
                },
                "cache": {},
                "capabilities": expected_capabilities,
                "env": expected_env,
                "features": {
                    "taskclusterProxy": True
                },
                "image": "MozillaSecurity/fuzzer:latest",
                "maxRunTime": 30,
            },
            "priority": "high",
            "provisionerId": "proj-fuzzing",
            "retries": 5,
            "routes": [],
            "schedulerId": "-",
            "scopes": scopes,
            "tags": {},
            "taskGroupId": "someTaskId",
            "workerType": "linux-test",
        }
Example #3
0
def test_gcp_resources(env, mock_clouds, mock_machines):
    conf = PoolConfiguration(
        "test",
        {
            "cloud": "gcp",
            "command": ["run-fuzzing.sh"],
            "container": "MozillaSecurity/fuzzer:latest",
            "cores_per_task": 2,
            "cpu": "x64",
            "cycle_time": "12h",
            "disk_size": "120g",
            "imageset": "docker-worker",
            "macros": {},
            "max_run_time": "12h",
            "metal": False,
            "minimum_memory_per_core": "1g",
            "name": "Amazing fuzzing pool",
            "parents": [],
            "platform": "linux",
            "preprocess": None,
            "schedule_start": "1970-01-01T00:00:00Z",
            "scopes": [],
            "tasks": 3,
        },
    )
    resources = conf.build_resources(mock_clouds, mock_machines, env=env)
    assert len(resources) == 3
    pool, hook, role = resources

    assert pool.to_json() == {
        "config": {
            "launchConfigs": [
                {
                    "capacityPerInstance":
                    1,
                    "disks": [{
                        "autoDelete": True,
                        "boot": True,
                        "initializeParams": {
                            "diskSizeGb": 120,
                            "sourceImage": "path/to/image",
                        },
                        "type": "PERSISTENT",
                    }],
                    "machineType":
                    "zones/us-west1-a/machineTypes/2-cpus",
                    "networkInterfaces": [{
                        "accessConfigs": [{
                            "type": "ONE_TO_ONE_NAT"
                        }]
                    }],
                    "region":
                    "us-west1",
                    "scheduling": {
                        "onHostMaintenance": "terminate"
                    },
                    "workerConfig": {
                        "dockerConfig": {
                            "allowDisableSeccomp": True,
                            "allowPrivileged": True,
                        },
                        "genericWorker": {
                            "config": {
                                "deploymentId": "ff173b0660475975",
                                "wstAudience": "communitytc",
                                "wstServerURL": WST_URL,
                            },
                        },
                        "shutdown": {
                            "afterIdleSeconds": 15,
                            "enabled": True
                        },
                    },
                    "zone":
                    "us-west1-a",
                },
                {
                    "capacityPerInstance":
                    1,
                    "disks": [{
                        "autoDelete": True,
                        "boot": True,
                        "initializeParams": {
                            "diskSizeGb": 120,
                            "sourceImage": "path/to/image",
                        },
                        "type": "PERSISTENT",
                    }],
                    "machineType":
                    "zones/us-west1-b/machineTypes/2-cpus",
                    "networkInterfaces": [{
                        "accessConfigs": [{
                            "type": "ONE_TO_ONE_NAT"
                        }]
                    }],
                    "region":
                    "us-west1",
                    "scheduling": {
                        "onHostMaintenance": "terminate"
                    },
                    "workerConfig": {
                        "dockerConfig": {
                            "allowDisableSeccomp": True,
                            "allowPrivileged": True,
                        },
                        "genericWorker": {
                            "config": {
                                "deploymentId": "ff173b0660475975",
                                "wstAudience": "communitytc",
                                "wstServerURL": WST_URL,
                            },
                        },
                        "shutdown": {
                            "afterIdleSeconds": 15,
                            "enabled": True
                        },
                    },
                    "zone":
                    "us-west1-b",
                },
                {
                    "capacityPerInstance":
                    1,
                    "disks": [{
                        "autoDelete": True,
                        "boot": True,
                        "initializeParams": {
                            "diskSizeGb": 120,
                            "sourceImage": "path/to/image",
                        },
                        "type": "PERSISTENT",
                    }],
                    "machineType":
                    "zones/us-west1-a/machineTypes/more-ram",
                    "networkInterfaces": [{
                        "accessConfigs": [{
                            "type": "ONE_TO_ONE_NAT"
                        }]
                    }],
                    "region":
                    "us-west1",
                    "scheduling": {
                        "onHostMaintenance": "terminate"
                    },
                    "workerConfig": {
                        "dockerConfig": {
                            "allowDisableSeccomp": True,
                            "allowPrivileged": True,
                        },
                        "genericWorker": {
                            "config": {
                                "deploymentId": "ff173b0660475975",
                                "wstAudience": "communitytc",
                                "wstServerURL": WST_URL,
                            },
                        },
                        "shutdown": {
                            "afterIdleSeconds": 15,
                            "enabled": True
                        },
                    },
                    "zone":
                    "us-west1-a",
                },
            ],
            "lifecycle": {
                "registrationTimeout": 900,
                "reregistrationTimeout": 345600
            },
            "maxCapacity":
            7,
            "minCapacity":
            0,
        },
        "description":
        ("*DO NOT EDIT* - This resource is configured automatically.\n\nFuzzing "
         "resources generated by https://github.com/MozillaSecurity/orion/tree"
         "/master/services/fuzzing-decision"),
        "emailOnError":
        True,
        "kind":
        "WorkerPool",
        "owner":
        "*****@*****.**",
        "providerId":
        "community-tc-workers-google",
        "workerPoolId":
        "proj-fuzzing/linux-test",
    }

    # Update env in valid hook
    valid_hook = copy.deepcopy(VALID_HOOK)
    if env is not None:
        valid_hook["task"]["payload"]["env"].update(env)
    assert hook.to_json() == valid_hook
    assert role.to_json() == VALID_ROLE
Example #4
0
def test_aws_resources(env, mock_clouds, mock_machines):

    conf = PoolConfiguration(
        "test",
        {
            "cloud": "aws",
            "command": ["run-fuzzing.sh"],
            "container": "MozillaSecurity/fuzzer:latest",
            "cores_per_task": 2,
            "cpu": "arm64",
            "cycle_time": "12h",
            "disk_size": "120g",
            "imageset": "generic-worker-A",
            "macros": {},
            "max_run_time": "12h",
            "metal": False,
            "minimum_memory_per_core": "1g",
            "name": "Amazing fuzzing pool",
            "parents": [],
            "platform": "linux",
            "preprocess": None,
            "schedule_start": "1970-01-01T00:00:00Z",
            "scopes": [],
            "tasks": 3,
        },
    )
    resources = conf.build_resources(mock_clouds, mock_machines, env=env)
    assert len(resources) == 3
    pool, hook, role = resources

    assert pool.to_json() == {
        "config": {
            "launchConfigs": [{
                "capacityPerInstance": 1,
                "launchConfig": {
                    "ImageId": "ami-1234",
                    "InstanceMarketOptions": {
                        "MarketType": "spot"
                    },
                    "InstanceType": "a2",
                    "Placement": {
                        "AvailabilityZone": "us-west-1a"
                    },
                    "SecurityGroupIds": ["sg-A"],
                    "SubnetId": "subnet-XXX",
                },
                "region": "us-west-1",
                "workerConfig": {
                    "dockerConfig": {
                        "allowDisableSeccomp": True,
                        "allowPrivileged": True,
                    },
                    "genericWorker": {
                        "config": {
                            "anyKey": "anyValue",
                            "deploymentId": "d9465de45bdee4be",
                            "os": "linux",
                            "wstAudience": "communitytc",
                            "wstServerURL": WST_URL,
                        },
                    },
                    "shutdown": {
                        "afterIdleSeconds": 15,
                        "enabled": True
                    },
                },
            }],
            "lifecycle": {
                "registrationTimeout": 900,
                "reregistrationTimeout": 345600
            },
            "maxCapacity":
            7,
            "minCapacity":
            0,
        },
        "description":
        ("*DO NOT EDIT* - This resource is configured automatically.\n\nFuzzing "
         "resources generated by https://github.com/MozillaSecurity/orion/tree"
         "/master/services/fuzzing-decision"),
        "emailOnError":
        True,
        "kind":
        "WorkerPool",
        "owner":
        "*****@*****.**",
        "providerId":
        "community-tc-workers-aws",
        "workerPoolId":
        "proj-fuzzing/linux-test",
    }

    # Update env in valid hook
    valid_hook = copy.deepcopy(VALID_HOOK)
    if env is not None:
        valid_hook["task"]["payload"]["env"].update(env)
    assert hook.to_json() == valid_hook
    assert role.to_json() == VALID_ROLE
Example #5
0
def test_tasks(
    env: Optional[Dict[str, str]],
    scope_caps,
    platform: str,
    run_as_admin: bool,
    mocker: MockerFixture,
) -> None:
    mocker.patch.dict(
        "fuzzing_decision.decision.pool.MountArtifactResolver.CACHE",
        {"orion.fuzzer.main": "task-mount-abc"},
    )
    scopes, expected_capabilities = scope_caps
    if run_as_admin:
        scopes.extend((
            "generic-worker:os-group:proj-fuzzing/windows-test/Administrators",
            "generic-worker:run-as-administrator:proj-fuzzing/windows-test",
        ))
    conf = PoolConfiguration(
        "test",
        {
            "artifacts": {
                "/some-file.txt": {
                    "type": "file",
                    "url": "project/fuzzing/private/file.txt",
                },
                "/var/log/": {
                    "type": "directory",
                    "url": "project/fuzzing/private/var-log",
                },
            },
            "cloud": "gcp",
            "command": ["run-fuzzing.sh"],
            "container":
            "MozillaSecurity/fuzzer:latest" if platform != "windows" else {
                "namespace": "orion.fuzzer.main",
                "type": "indexed-image",
                "path": "public/msys2.tar.bz2",
            },
            "cores_per_task": 1,
            "cpu": "x64",
            "cycle_time": "1h",
            "disk_size": "10g",
            "imageset": "anything",
            "macros": {},
            "max_run_time": "30s",
            "metal": False,
            "minimum_memory_per_core": "1g",
            "name": "Amazing fuzzing pool",
            "parents": [],
            "platform": platform,
            "preprocess": None,
            "schedule_start": None,
            "scopes": scopes,
            "tasks": 2,
            "run_as_admin": run_as_admin,
        },
    )

    task_ids, tasks = zip(*conf.build_tasks("someTaskId", env=env))

    # Check we have 2 valid generated task ids
    assert len(task_ids) == 2
    assert all(map(slugid.decode, task_ids))

    # Check we have 2 valid task definitions
    assert len(tasks) == 2

    def _get_date(value: str) -> datetime.datetime:
        assert isinstance(value, str)
        return datetime.datetime.strptime(value, "%Y-%m-%dT%H:%M:%S.%fZ")

    for i, task in enumerate(tasks):
        created = _get_date(task.pop("created"))
        deadline = _get_date(task.pop("deadline"))
        expires = _get_date(task.pop("expires"))
        assert expires >= deadline > created
        expected_env = {
            "TASKCLUSTER_FUZZING_POOL": "test",
            "TASKCLUSTER_SECRET": "project/fuzzing/decision",
        }
        if env is not None:
            expected_env.update(env)

        if platform == "windows":
            # translate to docker-worker style dict
            task["payload"]["artifacts"] = {
                artifact.pop("name"): artifact
                for artifact in task["payload"]["artifacts"]
            }
        assert expires == _get_date(
            task["payload"]["artifacts"]["project/fuzzing/private/logs"].pop(
                "expires"))
        assert expires == _get_date(
            task["payload"]["artifacts"]
            ["project/fuzzing/private/file.txt"].pop("expires"))
        assert expires == _get_date(
            task["payload"]["artifacts"]
            ["project/fuzzing/private/var-log"].pop("expires"))
        assert set(
            task["scopes"]) == set(["secrets:get:project/fuzzing/decision"] +
                                   scopes)
        # scopes are already asserted above
        # - read the value for comparison instead of deleting the key, so the object is
        #   printed in full on failure
        scopes = task["scopes"]
        expected = {
            "dependencies": ["someTaskId"],
            "extra": {},
            "metadata": {
                "description":
                ("*DO NOT EDIT* - This resource is configured automatically.\n\n"
                 "Fuzzing resources generated by https://github.com/MozillaSecurity"
                 "/orion/tree/master/services/fuzzing-decision"),
                "name":
                f"Fuzzing task {platform}-test - {i+1}/2",
                "owner":
                "*****@*****.**",
                "source":
                "https://github.com/MozillaSecurity/orion",
            },
            "payload": {
                "artifacts": {
                    "project/fuzzing/private/logs": {
                        "path": "logs" if platform == "windows" else "/logs/",
                        "type": "directory",
                    },
                    "project/fuzzing/private/file.txt": {
                        "path": "/some-file.txt",
                        "type": "file",
                    },
                    "project/fuzzing/private/var-log": {
                        "path": "/var/log/",
                        "type": "directory",
                    },
                },
                "env": expected_env,
                "features": {
                    "taskclusterProxy": True
                },
                "maxRunTime": 30,
            },
            "priority": "high",
            "provisionerId": "proj-fuzzing",
            "retries": 5,
            "routes": [],
            "schedulerId": "-",
            "scopes": scopes,
            "tags": {},
            "taskGroupId": "someTaskId",
            "workerType": f"{platform}-test",
        }

        if platform == "windows":
            expected["dependencies"].append("task-mount-abc")
            expected["payload"]["mounts"] = [
                {
                    "content": {
                        "artifact": "public/msys2.tar.bz2",
                        "taskId": "task-mount-abc",
                    },
                    "directory": ".",
                    "format": "tar.bz2",
                },
            ]
            if run_as_admin:
                expected["payload"]["osGroups"] = ["Administrators"]
                expected["payload"]["features"]["runAsAdministrator"] = True
            expected["payload"]["env"]["MSYSTEM"] = "MINGW64"
            # command is unique to windows, since we have no Docker entrypoint
            assert task["payload"]["command"]
            for cmd in task["payload"]["command"][:-1]:
                assert cmd.startswith("set ")
            assert task["payload"]["command"][-1] == "fuzzing-pool-launch"
            expected["payload"]["command"] = task["payload"]["command"]
        else:
            expected["payload"]["image"] = "MozillaSecurity/fuzzer:latest"
        if expected_capabilities:
            expected["payload"]["capabilities"] = expected_capabilities
        assert task == expected
Example #6
0
def test_aws_resources(
    env: Optional[Dict[str, str]],
    mock_clouds: Dict[str, Provider],
    mock_machines: MachineTypes,
    platform: str,
) -> None:

    conf = PoolConfiguration(
        "test",
        {
            "cloud": "aws",
            "command": ["run-fuzzing.sh"],
            "container": "MozillaSecurity/fuzzer:latest",
            "cores_per_task": 2,
            "cpu": "arm64",
            "cycle_time": "12h",
            "disk_size": "120g",
            "imageset": "generic-worker-A",
            "macros": {},
            "max_run_time": "12h",
            "metal": False,
            "minimum_memory_per_core": "1g",
            "name": "Amazing fuzzing pool",
            "parents": [],
            "platform": platform,
            "preprocess": None,
            "schedule_start": "1970-01-01T00:00:00Z",
            "scopes": [],
            "tasks": 3,
            "run_as_admin": False,
        },
    )
    resources = list(conf.build_resources(mock_clouds, mock_machines, env=env))
    assert len(resources) == 3
    pool, hook, role = resources

    empty_str_dict: Dict[str, str] = {}
    expected: Dict[str, Any] = {
        "config": {
            "launchConfigs": [{
                "capacityPerInstance": 1,
                "launchConfig": {
                    "ImageId": "ami-1234",
                    "InstanceMarketOptions": {
                        "MarketType": "spot"
                    },
                    "InstanceType": "a2",
                    "Placement": {
                        "AvailabilityZone": "us-west-1a"
                    },
                    "SecurityGroupIds": ["sg-A"],
                    "SubnetId": "subnet-XXX",
                },
                "region": "us-west-1",
                "workerConfig": empty_str_dict,
            }],
            "maxCapacity":
            6,
            "minCapacity":
            0,
        },
        "description":
        ("*DO NOT EDIT* - This resource is configured automatically.\n\nFuzzing "
         "resources generated by https://github.com/MozillaSecurity/orion/tree"
         "/master/services/fuzzing-decision"),
        "emailOnError":
        True,
        "kind":
        "WorkerPool",
        "owner":
        "*****@*****.**",
        "providerId":
        "community-tc-workers-aws",
        "workerPoolId":
        f"proj-fuzzing/{platform}-test",
    }
    if platform == "linux":
        expected["config"]["lifecycle"] = {
            "registrationTimeout": 900,
            "reregistrationTimeout": 345600,
        }
        expected["config"]["launchConfigs"][0]["workerConfig"].update({
            "dockerConfig": {
                "allowDisableSeccomp": True,
                "allowPrivileged": True,
            },
            "shutdown": {
                "afterIdleSeconds": 180,
                "enabled": True
            },
        })
    else:
        expected["config"]["launchConfigs"][0]["workerConfig"].update(
            {
                "genericWorker": {
                    "config": {
                        "anyKey":
                        "anyValue",
                        "deploymentId":
                        "d82eac5c561913ee",
                        "wstAudience":
                        "communitytc",
                        "wstServerURL":
                        ("https://community-websocktunnel.services.mozilla.com"
                         ),
                    },
                },
            }, )

    assert pool.to_json() == expected

    # Update env in valid hook
    valid_hook = _get_expected_hook(platform)
    if env is not None:
        valid_hook["task"]["payload"]["env"].update(env)
    assert hook.to_json() == valid_hook
    assert role.to_json() == _get_expected_role(platform)