Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
451 changes: 451 additions & 0 deletions examples/oauth_client_complete_test.py

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions src/tfe/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from .resources.agents import Agents, AgentTokens
from .resources.apply import Applies
from .resources.configuration_version import ConfigurationVersions
from .resources.oauth_client import OAuthClients
from .resources.organizations import Organizations
from .resources.plan import Plans
from .resources.projects import Projects
Expand Down Expand Up @@ -40,6 +41,7 @@ def __init__(self, config: TFEConfig | None = None):
proxies=cfg.proxies,
ca_bundle=cfg.ca_bundle,
)
self.oauth_clients = OAuthClients(self._transport)
# Agent resources
self.agent_pools = AgentPools(self._transport)
self.agents = Agents(self._transport)
Expand Down
10 changes: 10 additions & 0 deletions src/tfe/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,16 @@ class ErrStateVersionUploadNotSupported(TFEError): ...
ERR_REQUIRED_KEY = "key is required"
ERR_REQUIRED_CATEGORY = "category is required"

# OAuth Client Error Constants
ERR_INVALID_OAUTH_CLIENT_ID = "invalid OAuth client ID"
ERR_REQUIRED_API_URL = "API URL is required"
ERR_REQUIRED_HTTP_URL = "HTTP URL is required"
ERR_REQUIRED_OAUTH_TOKEN = "OAuth token is required"
ERR_REQUIRED_SERVICE_PROVIDER = "service provider is required"
ERR_UNSUPPORTED_PRIVATE_KEY = "private key is not supported for this service provider"
ERR_REQUIRED_PROJECT = "projects are required"
ERR_PROJECT_MIN_LIMIT = "must specify at least one project"


class WorkspaceNotFound(NotFound): ...

Expand Down
25 changes: 25 additions & 0 deletions src/tfe/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,20 @@
IngressAttributes,
)

# Re-export all OAuth client types
from .oauth_client import (
OAuthClient,
OAuthClientAddProjectsOptions,
OAuthClientCreateOptions,
OAuthClientIncludeOpt,
OAuthClientList,
OAuthClientListOptions,
OAuthClientReadOptions,
OAuthClientRemoveProjectsOptions,
OAuthClientUpdateOptions,
ServiceProviderType,
)

# Re-export all query run types
from .query_run import (
QueryRun,
Expand Down Expand Up @@ -99,6 +113,17 @@

# Define what should be available when importing with *
__all__ = [
# OAuth client types
"OAuthClient",
"OAuthClientAddProjectsOptions",
"OAuthClientCreateOptions",
"OAuthClientIncludeOpt",
"OAuthClientList",
"OAuthClientListOptions",
"OAuthClientReadOptions",
"OAuthClientRemoveProjectsOptions",
"OAuthClientUpdateOptions",
"ServiceProviderType",
# Agent and agent pool types
"Agent",
"AgentPool",
Expand Down
174 changes: 174 additions & 0 deletions src/tfe/models/oauth_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
from __future__ import annotations

from datetime import datetime
from enum import Enum

from pydantic import BaseModel, ConfigDict, Field


class ServiceProviderType(str, Enum):
"""VCS service provider types."""

AZURE_DEVOPS_SERVER = "ado_server"
AZURE_DEVOPS_SERVICES = "ado_services"
BITBUCKET_DATA_CENTER = "bitbucket_data_center"
BITBUCKET_HOSTED = "bitbucket_hosted"
BITBUCKET_SERVER = "bitbucket_server"
BITBUCKET_SERVER_LEGACY = "bitbucket_server_legacy"
GITHUB = "github"
GITHUB_EE = "github_enterprise"
GITLAB_HOSTED = "gitlab_hosted"
GITLAB_CE = "gitlab_community_edition"
GITLAB_EE = "gitlab_enterprise_edition"


class OAuthClientIncludeOpt(str, Enum):
"""Include options for OAuth client queries."""

OAUTH_TOKENS = "oauth_tokens"
PROJECTS = "projects"


class OAuthClient(BaseModel):
"""OAuth client represents a connection between an organization and a VCS provider."""

id: str | None = None
api_url: str | None = Field(None, alias="api-url")
callback_url: str | None = Field(None, alias="callback-url")
connect_path: str | None = Field(None, alias="connect-path")
created_at: datetime | None = Field(None, alias="created-at")
http_url: str | None = Field(None, alias="http-url")
key: str | None = None
rsa_public_key: str | None = Field(None, alias="rsa-public-key")
name: str | None = None
secret: str | None = None
service_provider: ServiceProviderType | None = Field(None, alias="service-provider")
service_provider_name: str | None = Field(
None, alias="service-provider-display-name"
)
organization_scoped: bool | None = Field(None, alias="organization-scoped")

# Relations
organization: dict | None = None
oauth_tokens: list[dict] | None = Field(None, alias="oauth-tokens")
agent_pool: dict | None = Field(None, alias="agent-pool")
projects: list[dict] | None = None

model_config = ConfigDict(populate_by_name=True)


class OAuthClientList(BaseModel):
"""List of OAuth clients with pagination."""

data: list[OAuthClient] = []
pagination: dict | None = None


class OAuthClientListOptions(BaseModel):
"""Options for listing OAuth clients."""

# Pagination options
page_number: int | None = Field(None, alias="page[number]")
page_size: int | None = Field(None, alias="page[size]")

# Include options
include: list[OAuthClientIncludeOpt] | None = None

model_config = ConfigDict(populate_by_name=True)


class OAuthClientReadOptions(BaseModel):
"""Options for reading an OAuth client."""

include: list[OAuthClientIncludeOpt] | None = None

model_config = ConfigDict(populate_by_name=True)


class OAuthClientCreateOptions(BaseModel):
"""Options for creating an OAuth client."""

# Display name for the OAuth Client
name: str | None = None

# Required: The base URL of your VCS provider's API
api_url: str | None = Field(None, alias="api-url")

# Required: The homepage of your VCS provider
http_url: str | None = Field(None, alias="http-url")

# Optional: The OAuth Client key
key: str | None = None

# Optional: The token string you were given by your VCS provider
oauth_token: str | None = Field(None, alias="oauth-token-string")

# Optional: The initial list of projects for which the oauth client should be associated with
projects: list[dict] | None = None

# Optional: Private key associated with this vcs provider - only available for ado_server
private_key: str | None = Field(None, alias="private-key")

# Optional: Secret key associated with this vcs provider - only available for ado_server
secret: str | None = None

# Optional: RSAPublicKey the text of the SSH public key associated with your
# BitBucket Data Center Application Link
rsa_public_key: str | None = Field(None, alias="rsa-public-key")

# Required: The VCS provider being connected with
service_provider: ServiceProviderType | None = Field(None, alias="service-provider")

# Optional: AgentPool to associate the VCS Provider with, for PrivateVCS support
agent_pool: dict | None = Field(None, alias="agent-pool")

# Optional: Whether the OAuthClient is available to all workspaces in the organization
organization_scoped: bool | None = Field(None, alias="organization-scoped")

model_config = ConfigDict(populate_by_name=True)


class OAuthClientUpdateOptions(BaseModel):
"""Options for updating an OAuth client."""

# Optional: A display name for the OAuth Client
name: str | None = None

# Optional: The OAuth Client key
key: str | None = None

# Optional: Secret key associated with this vcs provider - only available for ado_server
secret: str | None = None

# Optional: RSAPublicKey the text of the SSH public key associated with your BitBucket
# Server Application Link
rsa_public_key: str | None = Field(None, alias="rsa-public-key")

# Optional: The token string you were given by your VCS provider
oauth_token: str | None = Field(None, alias="oauth-token-string")

# Optional: AgentPool to associate the VCS Provider with, for PrivateVCS support
agent_pool: dict | None = Field(None, alias="agent-pool")

# Optional: Whether the OAuthClient is available to all workspaces in the organization
organization_scoped: bool | None = Field(None, alias="organization-scoped")

model_config = ConfigDict(populate_by_name=True)


class OAuthClientAddProjectsOptions(BaseModel):
"""Options for adding projects to an OAuth client."""

# The projects to add to an OAuth client
projects: list[dict]

model_config = ConfigDict(populate_by_name=True)


class OAuthClientRemoveProjectsOptions(BaseModel):
"""Options for removing projects from an OAuth client."""

# The projects to remove from an OAuth client
projects: list[dict]

model_config = ConfigDict(populate_by_name=True)
Loading
Loading