Exemple #1
0
def build_worker_pool(workerPoolId, cfg, secret_values):
    try:
        wp = TYPES[cfg["type"]](secret_values=secret_values, **cfg)
    except Exception as e:
        raise RuntimeError(
            "Error generating worker pool configuration for {}".format(
                workerPoolId)) from e
    if secret_values:
        if "secret" in wp:
            secret = Secret(name="worker-pool:{}".format(workerPoolId),
                            secret=wp.pop("secret"))
        else:
            secret = None
    else:
        secret = Secret(name="worker-pool:{}".format(workerPoolId))

    workerpool = WorkerPool(
        workerPoolId=workerPoolId,
        description=cfg.get("description", ""),
        owner=cfg.get("owner", "*****@*****.**"),
        emailOnError=cfg.get("emailOnError", False),
        **wp,
    )

    return workerpool, secret
Exemple #2
0
async def build_worker_pool(workerPoolId, cfg, secret_values):
    try:
        image_set = await get_image_set(cfg["imageset"])
        wp = CLOUD_FUNCS[cfg["cloud"]](
            secret_values=secret_values,
            image_set=image_set,
            **cfg,
        )

        if wp.supports_worker_config():
            wp.merge_worker_config(
                # The order is important here: earlier entries take precendence
                # over later entries.
                cfg.get("workerConfig", {}),
                image_set.workerConfig,
                WorkerPoolSettings.EXISTING_CONFIG,
            )

        wp = WORKER_IMPLEMENTATION_FUNCS[
            image_set.workerImplementation.replace("-", "_")](
                secret_values=secret_values,
                wp=wp,
                **cfg,
            )
    except Exception as e:
        raise RuntimeError(
            "Error generating worker pool configuration for {}".format(
                workerPoolId)) from e
    if wp.secret_tpl:
        if secret_values:
            secret = Secret(
                name="worker-pool:{}".format(workerPoolId),
                secret=secret_values.render(wp.secret_tpl),
            )
        else:
            secret = Secret(name="worker-pool:{}".format(workerPoolId))
    else:
        secret = None

    if wp.scopes:
        role = Role(
            roleId="worker-pool:{}".format(workerPoolId),
            description="Scopes for image set `{}` and cloud `{}`.".format(
                image_set.name, cfg["cloud"]),
            scopes=wp.scopes,
        )
    else:
        role = None

    workerpool = WorkerPool(
        workerPoolId=workerPoolId,
        description=cfg.get("description", ""),
        owner=cfg.get("owner", "*****@*****.**"),
        emailOnError=cfg.get("emailOnError", False),
        providerId=wp.provider_id,
        config=wp.config,
    )

    return workerpool, secret, role
Exemple #3
0
def test_secret_formatter_different_secrets():
    "Secrets are properly formatted with a string"
    secret1 = Secret("my-secret1", {"password": "******"})
    secret2 = Secret("my-secret2", {"password": "******"})
    # even though these have the same value, they should format their last lines differently
    fmt1 = str(secret1)
    fmt2 = str(secret2)
    assert fmt1.split("\n")[-1] != fmt2.split("\n")[-1]
Exemple #4
0
def test_secret_to_api():
    "Secrets are properly output to the API, including the actual secret value"
    secret = Secret("my-secret", {"password": "******"})
    assert secret.to_api() == {
        "expires": FOREVER,
        "secret": {
            "password": "******"
        }
    }
Exemple #5
0
async def test_fetch_secrets_with_secrets(Secrets):
    "When there are secrets and --with-secrets, we get names and values"
    with test_options(with_secrets=True):
        Secrets.secrets.append({"name": "secret1", "secret": "AA"})
        Secrets.secrets.append({"name": "secret2", "secret": "BB"})
        resources = Resources([], [".*"])
        await fetch_secrets(resources)
        assert list(sorted(resources)) == [
            Secret(name="secret1", secret="AA"),
            Secret(name="secret2", secret="BB"),
        ]
Exemple #6
0
async def test_fetch_secrets_without_secrets(Secrets):
    "When there are secrets but --without-secrets, we just get names"
    with test_options(with_secrets=False):
        Secrets.secrets.append({"name": "secret1"})
        Secrets.secrets.append({"name": "secret2"})
        resources = Resources([], [".*"])
        await fetch_secrets(resources)
        assert list(sorted(resources)) == [
            Secret(name="secret1"),
            Secret(name="secret2"),
        ]
Exemple #7
0
async def test_fetch_secrets_managed(Secrets):
    "Only managed secrets are returned"
    with test_options(with_secrets=True):
        Secrets.secrets.append({"name": "secret1", "secret": "AA"})
        Secrets.secrets.append({"name": "unmanaged-secret2"})
        resources = Resources([], ["Secret=secret"])
        await fetch_secrets(resources)
        assert list(sorted(resources)) == [Secret(name="secret1", secret="AA")]
Exemple #8
0
def test_secret_formatter_no_secret():
    "Secrets with no secret are properly formatted with a string"
    secret = Secret("my-secret")
    # check that the formatter is stable
    assert str(secret) == str(secret)
    assert str(secret) == textwrap.dedent("""\
        Secret=my-secret:
          name: my-secret
          secret: <unknown>""")
Exemple #9
0
def test_secret_formatter():
    "Secrets are properly formatted with a string"
    secret = Secret("my-secret", {"password": "******"})
    # check that the formatter is stable
    assert str(secret) == str(secret)
    assert re.sub(r"secret: [a-z0-9]+", "secret: <hash>",
                  str(secret)) == textwrap.dedent("""\
        Secret=my-secret:
          name: my-secret
          secret: <hash>""")
Exemple #10
0
def test_secret_from_api():
    "Secrets are properly read from a Taskcluster API result"
    api_result = {
        "expires": datetime.datetime(3000, 1, 1, 0, 0, 0),
        "secret": {
            "password": "******"
        },
    }
    secret = Secret.from_api("my-secret", api_result)
    assert secret.name == "my-secret"
    assert secret.secret == {"password": "******"}
Exemple #11
0
async def test_registry_run():

    reg = CallbacksRegistry()

    # Simple case to trigger on a secret creation
    func = AsyncMock()
    reg.add("before_apply", func)
    await reg.run("before_apply", "create", Secret("xxx"))
    func.assert_called_once()

    # Should not run on resource mismatch
    func = AsyncMock()
    reg.add("after_apply", func, resources=[Role, Hook])
    await reg.run("before_apply", "delete", Secret("xxx"))
    await reg.run("after_apply", "delete", Secret("xxx"))
    assert not func.called

    # Should not run on action mismatch
    func = AsyncMock()
    reg.add("after_apply", func, actions=["delete"])
    await reg.run("before_apply", "update", Secret("xxx"))
    await reg.run("after_apply", "update", Secret("xxx"))
    assert not func.called
def build_worker_pool(workerPoolId, cfg, secret_values, image_set):
    try:
        wp = CLOUD_FUNCS[cfg["cloud"]](
            secret_values=secret_values,
            image_set=image_set,
            **cfg,
        )
        wp = WORKER_IMPLEMENTATION_FUNCS[
            image_set.workerImplementation.replace("-", "_")](
                secret_values=secret_values,
                image_set=image_set,
                wp=wp,
                **cfg,
            )
    except Exception as e:
        raise RuntimeError(
            "Error generating worker pool configuration for {}".format(
                workerPoolId)) from e
    if secret_values:
        if "secret" in wp:
            secret = Secret(name="worker-pool:{}".format(workerPoolId),
                            secret=wp.pop("secret"))
        else:
            secret = None
    else:
        secret = Secret(name="worker-pool:{}".format(workerPoolId))

    workerpool = WorkerPool(
        workerPoolId=workerPoolId,
        description=cfg.get("description", ""),
        owner=cfg.get("owner", "*****@*****.**"),
        emailOnError=cfg.get("emailOnError", False),
        **wp,
    )

    return workerpool, secret
Exemple #13
0
def test_secret_to_api_no_secret():
    "A secret with no value is not output to the API"
    secret = Secret("my-secret")

    with pytest.raises(ValueError):
        secret.to_api()
Exemple #14
0
def test_secret_from_api_no_secret():
    "Secrets are properly read from a Taskcluster API result"
    secret = Secret.from_api("my-secret")
    assert secret.name == "my-secret"
    assert secret.secret == NoSecret
Exemple #15
0
def test_secret_json():
    "Secrets are properly output as JSON, including the description preamble and sorted scopes"
    secret = Secret("my-secret", {"password": "******"})
    assert secret.to_json() == {"name": "my-secret", "kind": "Secret"}
Exemple #16
0
async def update_resources(resources, secret_values):
    projects = await Projects.load(loader)

    for project in projects.values():
        for roleId in project.adminRoles:
            assert any(roleId.startswith(p) for p in ADMIN_ROLE_PREFIXES)
            resources.add(
                Role(
                    roleId=roleId,
                    description="",
                    scopes=["assume:project-admin:{}".format(project.name)],
                ))
        if project.repos:
            for repo in project.repos:
                assert repo.endswith("/*") or repo.endswith(
                    ":*"
                ), "project.repos should end with `/*` or `:*`, got {}".format(
                    repo)
            resources.add(
                Role(
                    roleId="project-admin:{}".format(project.name),
                    description="",
                    scopes=[
                        "assume:repo-admin:{}".format(repo)
                        for repo in project.repos
                    ],
                ))
        if project.workerPools:
            for name, worker_pool in project.workerPools.items():
                worker_pool_id = "proj-{}/{}".format(project.name, name)
                worker_pool["description"] = "Workers for " + project.name
                worker_pool, secret = build_worker_pool(
                    worker_pool_id, worker_pool, secret_values)

                if project.externallyManaged.manage_individual_resources():
                    resources.manage("WorkerPool={}".format(worker_pool_id))
                    if secret:
                        resources.manage(
                            "Secret=worker-pool:{}".format(worker_pool_id))
                resources.add(worker_pool)
                if secret:
                    resources.add(secret)
        if project.clients:
            for name, info in project.clients.items():
                clientId = "project/{}/{}".format(project.name, name)
                if project.externallyManaged.manage_individual_resources():
                    resources.manage("Client={}".format(clientId))
                description = info.get("description", "")
                scopes = info["scopes"]
                resources.add(
                    Client(clientId=clientId,
                           description=description,
                           scopes=scopes))
        if project.secrets:
            for nameSuffix, info in project.secrets.items():
                if info is True:
                    continue
                name = "project/{}/{}".format(project.name, nameSuffix)
                if project.externallyManaged.manage_individual_resources():
                    resources.manage("Secret={}".format(name))
                if secret_values:
                    resources.add(
                        Secret(name=name, secret=secret_values.render(info)))
                else:
                    resources.add(Secret(name=name))
        if project.hooks:
            for hookId, info in project.hooks.items():
                hookGroupId = "project-{}".format(project.name)
                if project.externallyManaged.manage_individual_resources():
                    resources.manage("Hook={}/{}".format(hookGroupid, hookId))
                assert (
                    "bindings" not in info
                ), "Please add support for bindings to use this feature"
                resources.add(
                    Hook(
                        hookGroupId=hookGroupId,
                        hookId=hookId,
                        name=info.get("name", hookId),
                        description=info.get("description", ""),
                        owner=info["owner"],
                        emailOnError=info.get("emailOnError", False),
                        schedule=info.get("schedule", ()),
                        bindings=info.get("bindings", ()),
                        task=info["task"],
                        triggerSchema=info.get("triggerSchema", {}),
                    ))
        for grant in Grants.from_project(project):
            if project.externallyManaged.manage_individual_resources():
                for role in grant.to:
                    resources.manage("Role=" + re.escape(role))
            grant.update_resources(resources)