diff --git a/buildbot_nix/models.py b/buildbot_nix/models.py index 6198506..2acdcd9 100644 --- a/buildbot_nix/models.py +++ b/buildbot_nix/models.py @@ -1,23 +1,26 @@ from enum import Enum from pathlib import Path -from pydantic import BaseModel, Field, field_serializer, field_validator, ConfigDict -from buildbot.plugins import util, steps +from buildbot.plugins import steps, util +from pydantic import BaseModel, ConfigDict, Field from .secrets import read_secret_file -class InternalIssue(Exception): + +class InternalError(Exception): pass def exclude_fields(fields: list[str]) -> dict[str, dict[str, bool]]: - return dict(map(lambda k: (k, {"exclude": True}), fields)) + return {k: {"exclude": True} for k in fields} + class AuthBackendConfig(str, Enum): github = "github" gitea = "gitea" none = "none" + class CachixConfig(BaseModel): name: str @@ -27,13 +30,13 @@ class CachixConfig(BaseModel): @property def signing_key(self) -> str: if self.signing_key_file is None: - raise InternalIssue + raise InternalError return read_secret_file(self.signing_key_file) @property def auth_token(self) -> str: if self.auth_token_file is None: - raise InternalIssue + raise InternalError return read_secret_file(self.auth_token_file) # TODO why did the original implementation return an empty env if both files were missing? @@ -47,13 +50,14 @@ class CachixConfig(BaseModel): class Config: fields = exclude_fields(["singing_key", "auth_token"]) + class GiteaConfig(BaseModel): instance_url: str topic: str | None - token_file: Path = Field(default = Path("gitea-token")) - webhook_secret_file: Path = Field(default = Path("gitea-webhook-secret")) - project_cache_file: Path = Field(default = Path("gitea-project-cache.json")) + token_file: Path = Field(default=Path("gitea-token")) + webhook_secret_file: Path = Field(default=Path("gitea-webhook-secret")) + project_cache_file: Path = Field(default=Path("gitea-project-cache.json")) oauth_id: str | None oauth_secret_file: Path | None @@ -69,12 +73,13 @@ class GiteaConfig(BaseModel): @property def oauth_secret(self) -> str: if self.oauth_secret_file is None: - raise InternalIssue + raise InternalError return read_secret_file(self.oauth_secret_file) class Config: fields = exclude_fields(["token", "webhook_secret", "oauth_secret"]) + class GitHubLegacyConfig(BaseModel): token_file: Path @@ -85,19 +90,18 @@ class GitHubLegacyConfig(BaseModel): class Config: fields = exclude_fields(["token"]) + class GitHubAppConfig(BaseModel): id: int secret_key_file: Path - installation_token_map_file: Path = Field(default = Path( - "github-app-installation-token-map.json" - )) - project_id_map_file: Path = Field(default = Path( - "github-app-project-id-map-name.json" - )) - jwt_token_map: Path = Field(default = Path( - "github-app-jwt-token" - )) + installation_token_map_file: Path = Field( + default=Path("github-app-installation-token-map.json") + ) + project_id_map_file: Path = Field( + default=Path("github-app-project-id-map-name.json") + ) + jwt_token_map: Path = Field(default=Path("github-app-jwt-token")) @property def secret_key(self) -> str: @@ -106,12 +110,13 @@ class GitHubAppConfig(BaseModel): class Config: fields = exclude_fields(["secret_key"]) + class GitHubConfig(BaseModel): auth_type: GitHubLegacyConfig | GitHubAppConfig topic: str | None - project_cache_file: Path = Field(default = Path("github-project-cache-v1.json")) - webhook_secret_file: Path = Field(default = Path("github-webhook-secret")) + project_cache_file: Path = Field(default=Path("github-project-cache-v1.json")) + webhook_secret_file: Path = Field(default=Path("github-webhook-secret")) oauth_id: str | None oauth_secret_file: Path | None @@ -123,16 +128,17 @@ class GitHubConfig(BaseModel): @property def oauth_secret(self) -> str: if self.oauth_secret_file is None: - raise InternalIssue + raise InternalError return read_secret_file(self.oauth_secret_file) + # note that serialization isn't correct, as there is no way to *rename* the field `nix_type` to `_type`, # one must always specify `by_alias = True`, such as `model_dump(by_alias = True)`, relevant issue: # https://github.com/pydantic/pydantic/issues/8379 class Interpolate(BaseModel): model_config = ConfigDict(populate_by_name=True) - nix_type: str = Field(alias = "_type") + nix_type: str = Field(alias="_type") value: str @@ -148,15 +154,12 @@ class PostBuildStep(BaseModel): return util.Interpolate(value.value) return steps.ShellCommand( - name = self.name, - env = { - k: maybe_interpolate(k) for k in self.environment - }, - command = [ - maybe_interpolate(x) for x in self.command - ] + name=self.name, + env={k: maybe_interpolate(k) for k in self.environment}, + command=[maybe_interpolate(x) for x in self.command], ) + class BuildbotNixConfig(BaseModel): db_url: str auth_backend: AuthBackendConfig @@ -169,7 +172,7 @@ class BuildbotNixConfig(BaseModel): build_systems: list[str] eval_max_memory_size: int eval_worker_count: int | None - nix_workers_secret_file: Path = Field(default = Path("buildbot-nix-workers")) + nix_workers_secret_file: Path = Field(default=Path("buildbot-nix-workers")) domain: str webhook_base_url: str use_https: bool