orchestr8-platform 3.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. orchestr8_platform-3.0.0/PKG-INFO +164 -0
  2. orchestr8_platform-3.0.0/README.md +126 -0
  3. orchestr8_platform-3.0.0/pyproject.toml +105 -0
  4. orchestr8_platform-3.0.0/setup.cfg +4 -0
  5. orchestr8_platform-3.0.0/src/orchestr8/__init__.py +1 -0
  6. orchestr8_platform-3.0.0/src/orchestr8/auth/__init__.py +16 -0
  7. orchestr8_platform-3.0.0/src/orchestr8/auth/github_oauth.py +215 -0
  8. orchestr8_platform-3.0.0/src/orchestr8/auth/keycloak_idp.py +519 -0
  9. orchestr8_platform-3.0.0/src/orchestr8/cli/module.py +469 -0
  10. orchestr8_platform-3.0.0/src/orchestr8/cli.py +1174 -0
  11. orchestr8_platform-3.0.0/src/orchestr8/commands/argocd.py +484 -0
  12. orchestr8_platform-3.0.0/src/orchestr8/commands/bootstrap.py +1582 -0
  13. orchestr8_platform-3.0.0/src/orchestr8/commands/branch.py +387 -0
  14. orchestr8_platform-3.0.0/src/orchestr8/commands/doctor.py +374 -0
  15. orchestr8_platform-3.0.0/src/orchestr8/commands/module.py +763 -0
  16. orchestr8_platform-3.0.0/src/orchestr8/commands/secrets.py +996 -0
  17. orchestr8_platform-3.0.0/src/orchestr8/core/__init__.py +7 -0
  18. orchestr8_platform-3.0.0/src/orchestr8/core/config.py +85 -0
  19. orchestr8_platform-3.0.0/src/orchestr8/core/orchestrator.py +1794 -0
  20. orchestr8_platform-3.0.0/src/orchestr8/core/secrets.py +150 -0
  21. orchestr8_platform-3.0.0/src/orchestr8/core/terraform.py +551 -0
  22. orchestr8_platform-3.0.0/src/orchestr8/core/validator.py +567 -0
  23. orchestr8_platform-3.0.0/src/orchestr8/providers/__init__.py +7 -0
  24. orchestr8_platform-3.0.0/src/orchestr8/providers/aws.py +89 -0
  25. orchestr8_platform-3.0.0/src/orchestr8/providers/azure.py +567 -0
  26. orchestr8_platform-3.0.0/src/orchestr8/providers/github.py +97 -0
  27. orchestr8_platform-3.0.0/src/orchestr8/providers/local.py +73 -0
  28. orchestr8_platform-3.0.0/src/orchestr8/sdk.py +156 -0
  29. orchestr8_platform-3.0.0/src/orchestr8/utils/azure_cli.py +117 -0
  30. orchestr8_platform-3.0.0/src/orchestr8_platform.egg-info/PKG-INFO +164 -0
  31. orchestr8_platform-3.0.0/src/orchestr8_platform.egg-info/SOURCES.txt +40 -0
  32. orchestr8_platform-3.0.0/src/orchestr8_platform.egg-info/dependency_links.txt +1 -0
  33. orchestr8_platform-3.0.0/src/orchestr8_platform.egg-info/entry_points.txt +2 -0
  34. orchestr8_platform-3.0.0/src/orchestr8_platform.egg-info/requires.txt +16 -0
  35. orchestr8_platform-3.0.0/src/orchestr8_platform.egg-info/top_level.txt +1 -0
  36. orchestr8_platform-3.0.0/tests/test_azure_integration.py +283 -0
  37. orchestr8_platform-3.0.0/tests/test_cli.py +262 -0
  38. orchestr8_platform-3.0.0/tests/test_integration.py +225 -0
  39. orchestr8_platform-3.0.0/tests/test_module_commands.py +147 -0
  40. orchestr8_platform-3.0.0/tests/test_orchestrator.py +300 -0
  41. orchestr8_platform-3.0.0/tests/test_providers.py +295 -0
  42. orchestr8_platform-3.0.0/tests/test_secrets.py +202 -0
@@ -0,0 +1,164 @@
1
+ Metadata-Version: 2.4
2
+ Name: orchestr8-platform
3
+ Version: 3.0.0
4
+ Summary: Orchestr8 - Enterprise GitOps platform for Kubernetes orchestration
5
+ Author-email: Orchestr8 Team <dev@agenticinsights.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/killerapp/orchestr8
8
+ Project-URL: Documentation, https://orchestr8.agenticinsights.com
9
+ Project-URL: Repository, https://github.com/killerapp/orchestr8
10
+ Project-URL: Issues, https://github.com/killerapp/orchestr8/issues
11
+ Keywords: kubernetes,gitops,argocd,platform,orchestration
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
19
+ Classifier: Topic :: System :: Systems Administration
20
+ Requires-Python: >=3.11
21
+ Description-Content-Type: text/markdown
22
+ Requires-Dist: typer>=0.9.0
23
+ Requires-Dist: rich>=13.7.0
24
+ Requires-Dist: boto3>=1.34.0
25
+ Requires-Dist: google-cloud-secret-manager>=2.16.0
26
+ Requires-Dist: google-cloud-container>=2.35.0
27
+ Requires-Dist: kubernetes>=29.0.0
28
+ Requires-Dist: pyyaml>=6.0.1
29
+ Requires-Dist: pydantic>=2.5.0
30
+ Requires-Dist: pygithub>=2.1.1
31
+ Requires-Dist: requests>=2.31.0
32
+ Requires-Dist: requests-oauthlib>=2.0.0
33
+ Requires-Dist: httpx>=0.28.1
34
+ Requires-Dist: bcrypt>=4.1.0
35
+ Requires-Dist: pyjwt>=2.8.0
36
+ Requires-Dist: azure-keyvault-secrets>=4.10.0
37
+ Requires-Dist: azure-identity>=1.24.0
38
+
39
+ # Orchestr8
40
+
41
+ A unified SDK and CLI for automated Kubernetes platform management using GitOps principles.
42
+
43
+ ## Features
44
+
45
+ - 🚀 **Zero-touch cluster bootstrapping** - Automated setup with minimal manual steps
46
+ - 🔐 **Integrated secrets management** - AWS/GCP Secrets Manager support with automatic generation
47
+ - 🤖 **Multiple interfaces** - Use as CLI or SDK for programmatic access
48
+ - ☁️ **Multi-cloud ready** - Support for AWS, GCP, Azure, and local development
49
+ - 🔄 **GitOps native** - Built on ArgoCD with the app-of-apps pattern
50
+ - 🩺 **Built-in diagnostics** - Auto-running health checks and environment validation
51
+
52
+ ## Installation
53
+
54
+ ```bash
55
+ # Install from PyPI
56
+ uv tool install orchestr8-platform
57
+
58
+ # Or add to your project
59
+ uv add orchestr8-platform
60
+ ```
61
+
62
+ ## Quick Start
63
+
64
+ ### CLI Usage
65
+
66
+ ```bash
67
+ # Interactive setup
68
+ o8 setup
69
+
70
+ # Non-interactive setup
71
+ o8 setup \
72
+ --provider aws \
73
+ --cluster my-cluster \
74
+ --domain platform.example.com \
75
+ --github-org my-org \
76
+ --region us-east-1
77
+
78
+ # Check status and validate environment
79
+ o8 status
80
+ o8 doctor
81
+
82
+ # Validate prerequisites
83
+ o8 validate
84
+ ```
85
+
86
+ ### SDK Usage
87
+
88
+ ```python
89
+ from orchestr8 import Orchestr8SDK, Config, CloudProvider
90
+ from orchestr8.core.config import GitHubConfig
91
+
92
+ # Create configuration
93
+ config = Config(
94
+ provider=CloudProvider.AWS,
95
+ region="us-east-1",
96
+ cluster_name="my-cluster",
97
+ domain="platform.example.com",
98
+ github=GitHubConfig(
99
+ org="my-org",
100
+ token="ghp_..."
101
+ )
102
+ )
103
+
104
+ # Initialize SDK
105
+ sdk = Orchestr8SDK(config)
106
+
107
+ # Run setup
108
+ await sdk.setup()
109
+
110
+ # Check status
111
+ status = await sdk.get_status()
112
+ ```
113
+
114
+ ## Architecture
115
+
116
+ Orchestr8 sets up:
117
+
118
+ - **ArgoCD** - GitOps continuous delivery
119
+ - **Istio** - Service mesh for traffic management
120
+ - **Keycloak** - Identity and access management
121
+ - **Prometheus/Grafana** - Monitoring and observability
122
+ - **Cert-Manager** - Automatic TLS certificate management
123
+
124
+ ## Migration from Orchestr8
125
+
126
+ If you're migrating from Orchestr8 Orchestrator (Orchestr8):
127
+
128
+ 1. **Install Orchestr8**: `uv tool install orchestr8-platform`
129
+ 2. **Update scripts**: Replace `orchestr8` commands with `o8`
130
+ 3. **Validate setup**: Run `o8 doctor` to check your environment
131
+ 4. **Update repositories**: Change repo references from `orchestr8` to `orchestr8`
132
+
133
+ Your existing configurations will be automatically detected and migration prompts provided.
134
+
135
+ ## Development
136
+
137
+ ```bash
138
+ # Clone the repository
139
+ git clone https://github.com/killerapp/orchestr8
140
+ cd orchestr8/o8-cli
141
+
142
+ # Install dependencies
143
+ uv sync
144
+
145
+ # Run tests
146
+ uv run pytest
147
+
148
+ # Run CLI in development
149
+ uv run python -m orchestr8.cli
150
+ ```
151
+
152
+ ## Publishing to PyPI
153
+
154
+ ```bash
155
+ # Build the package
156
+ uv build
157
+
158
+ # Publish to PyPI
159
+ uv publish
160
+ ```
161
+
162
+ ## License
163
+
164
+ MIT
@@ -0,0 +1,126 @@
1
+ # Orchestr8
2
+
3
+ A unified SDK and CLI for automated Kubernetes platform management using GitOps principles.
4
+
5
+ ## Features
6
+
7
+ - 🚀 **Zero-touch cluster bootstrapping** - Automated setup with minimal manual steps
8
+ - 🔐 **Integrated secrets management** - AWS/GCP Secrets Manager support with automatic generation
9
+ - 🤖 **Multiple interfaces** - Use as CLI or SDK for programmatic access
10
+ - ☁️ **Multi-cloud ready** - Support for AWS, GCP, Azure, and local development
11
+ - 🔄 **GitOps native** - Built on ArgoCD with the app-of-apps pattern
12
+ - 🩺 **Built-in diagnostics** - Auto-running health checks and environment validation
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ # Install from PyPI
18
+ uv tool install orchestr8-platform
19
+
20
+ # Or add to your project
21
+ uv add orchestr8-platform
22
+ ```
23
+
24
+ ## Quick Start
25
+
26
+ ### CLI Usage
27
+
28
+ ```bash
29
+ # Interactive setup
30
+ o8 setup
31
+
32
+ # Non-interactive setup
33
+ o8 setup \
34
+ --provider aws \
35
+ --cluster my-cluster \
36
+ --domain platform.example.com \
37
+ --github-org my-org \
38
+ --region us-east-1
39
+
40
+ # Check status and validate environment
41
+ o8 status
42
+ o8 doctor
43
+
44
+ # Validate prerequisites
45
+ o8 validate
46
+ ```
47
+
48
+ ### SDK Usage
49
+
50
+ ```python
51
+ from orchestr8 import Orchestr8SDK, Config, CloudProvider
52
+ from orchestr8.core.config import GitHubConfig
53
+
54
+ # Create configuration
55
+ config = Config(
56
+ provider=CloudProvider.AWS,
57
+ region="us-east-1",
58
+ cluster_name="my-cluster",
59
+ domain="platform.example.com",
60
+ github=GitHubConfig(
61
+ org="my-org",
62
+ token="ghp_..."
63
+ )
64
+ )
65
+
66
+ # Initialize SDK
67
+ sdk = Orchestr8SDK(config)
68
+
69
+ # Run setup
70
+ await sdk.setup()
71
+
72
+ # Check status
73
+ status = await sdk.get_status()
74
+ ```
75
+
76
+ ## Architecture
77
+
78
+ Orchestr8 sets up:
79
+
80
+ - **ArgoCD** - GitOps continuous delivery
81
+ - **Istio** - Service mesh for traffic management
82
+ - **Keycloak** - Identity and access management
83
+ - **Prometheus/Grafana** - Monitoring and observability
84
+ - **Cert-Manager** - Automatic TLS certificate management
85
+
86
+ ## Migration from Orchestr8
87
+
88
+ If you're migrating from Orchestr8 Orchestrator (Orchestr8):
89
+
90
+ 1. **Install Orchestr8**: `uv tool install orchestr8-platform`
91
+ 2. **Update scripts**: Replace `orchestr8` commands with `o8`
92
+ 3. **Validate setup**: Run `o8 doctor` to check your environment
93
+ 4. **Update repositories**: Change repo references from `orchestr8` to `orchestr8`
94
+
95
+ Your existing configurations will be automatically detected and migration prompts provided.
96
+
97
+ ## Development
98
+
99
+ ```bash
100
+ # Clone the repository
101
+ git clone https://github.com/killerapp/orchestr8
102
+ cd orchestr8/o8-cli
103
+
104
+ # Install dependencies
105
+ uv sync
106
+
107
+ # Run tests
108
+ uv run pytest
109
+
110
+ # Run CLI in development
111
+ uv run python -m orchestr8.cli
112
+ ```
113
+
114
+ ## Publishing to PyPI
115
+
116
+ ```bash
117
+ # Build the package
118
+ uv build
119
+
120
+ # Publish to PyPI
121
+ uv publish
122
+ ```
123
+
124
+ ## License
125
+
126
+ MIT
@@ -0,0 +1,105 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "orchestr8-platform"
7
+ version = "3.0.0"
8
+ description = "Orchestr8 - Enterprise GitOps platform for Kubernetes orchestration"
9
+ readme = "README.md"
10
+ authors = [
11
+ {name = "Orchestr8 Team", email = "dev@agenticinsights.com"},
12
+ ]
13
+ license = {text = "MIT"}
14
+ classifiers = [
15
+ "Development Status :: 4 - Beta",
16
+ "Intended Audience :: Developers",
17
+ "License :: OSI Approved :: MIT License",
18
+ "Programming Language :: Python :: 3",
19
+ "Programming Language :: Python :: 3.11",
20
+ "Programming Language :: Python :: 3.12",
21
+ "Topic :: Software Development :: Libraries :: Python Modules",
22
+ "Topic :: System :: Systems Administration",
23
+ ]
24
+ keywords = ["kubernetes", "gitops", "argocd", "platform", "orchestration"]
25
+ requires-python = ">=3.11"
26
+ dependencies = [
27
+ "typer>=0.9.0",
28
+ "rich>=13.7.0",
29
+ "boto3>=1.34.0",
30
+ "google-cloud-secret-manager>=2.16.0",
31
+ "google-cloud-container>=2.35.0",
32
+ "kubernetes>=29.0.0",
33
+ "pyyaml>=6.0.1",
34
+ "pydantic>=2.5.0",
35
+ "pygithub>=2.1.1",
36
+ "requests>=2.31.0",
37
+ "requests-oauthlib>=2.0.0",
38
+ "httpx>=0.28.1",
39
+ "bcrypt>=4.1.0",
40
+ "pyjwt>=2.8.0",
41
+ "azure-keyvault-secrets>=4.10.0",
42
+ "azure-identity>=1.24.0",
43
+ ]
44
+
45
+ [project.urls]
46
+ Homepage = "https://github.com/killerapp/orchestr8"
47
+ Documentation = "https://orchestr8.agenticinsights.com"
48
+ Repository = "https://github.com/killerapp/orchestr8"
49
+ Issues = "https://github.com/killerapp/orchestr8/issues"
50
+
51
+ [project.scripts]
52
+ o8 = "orchestr8.cli:app"
53
+
54
+ [project.optional-dependencies]
55
+ # mcp = ["mcp>=0.1.0", "websockets>=12.0"] # TODO: Enable when MCP is implemented
56
+
57
+ [tool.uv]
58
+ dev-dependencies = [
59
+ "pytest>=7.4.0",
60
+ "pytest-asyncio>=0.21.0",
61
+ "pytest-cov>=4.1.0",
62
+ "ruff>=0.1.0",
63
+ "mypy>=1.8.0",
64
+ "black>=23.12.0",
65
+ "python-semantic-release>=9.0.0",
66
+ ]
67
+
68
+ [tool.semantic_release]
69
+ version_variables = [
70
+ "src/orchestr8/__init__.py:__version__",
71
+ ]
72
+ version_toml = [
73
+ "pyproject.toml:project.version",
74
+ ]
75
+ build_command = "python -m build"
76
+ commit_message = "chore(release): {version} [skip ci]\n\nAutomatically generated by python-semantic-release"
77
+ tag_format = "v{version}"
78
+
79
+ [tool.semantic_release.branches.main]
80
+ match = "main"
81
+
82
+ [tool.semantic_release.commit_parser_options]
83
+ major_tags = ["BREAKING CHANGE", "BREAKING-CHANGE"]
84
+ minor_tags = ["feat"]
85
+ patch_tags = ["fix", "perf"]
86
+ allowed_tags = ["build", "chore", "ci", "docs", "feat", "fix", "perf", "style", "refactor", "test"]
87
+
88
+ [tool.pytest.ini_options]
89
+ minversion = "3.0.0"
90
+ addopts = "-ra -q --tb=short"
91
+ testpaths = ["tests"]
92
+ markers = [
93
+ "smoke: Quick smoke tests (unit tests, mocked APIs)",
94
+ "integration: Integration tests that may make real API calls",
95
+ "slow: Slow tests that set up/tear down infrastructure",
96
+ "cluster: Tests requiring actual Kubernetes cluster access",
97
+ "external: Tests requiring external services (AWS, GCP, Azure)",
98
+ "local: Tests for local development (Docker Desktop, minikube, kind)",
99
+ "docker: Tests requiring Docker Desktop Kubernetes",
100
+ "minikube: Tests requiring minikube cluster",
101
+ "kind: Tests requiring kind cluster",
102
+ "aws: Tests specific to AWS provider",
103
+ "gcp: Tests specific to GCP provider",
104
+ "azure: Tests specific to Azure provider"
105
+ ]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1 @@
1
+ __version__ = "3.0.0"
@@ -0,0 +1,16 @@
1
+ """Authentication module for Orchestr8."""
2
+
3
+ from .github_oauth import GitHubDeviceFlow, GitHubAuthResult
4
+ from .keycloak_idp import (
5
+ KeycloakIdentityProviderManager,
6
+ IdentityProviderType,
7
+ IdentityProviderConfig,
8
+ )
9
+
10
+ __all__ = [
11
+ "GitHubDeviceFlow",
12
+ "GitHubAuthResult",
13
+ "KeycloakIdentityProviderManager",
14
+ "IdentityProviderType",
15
+ "IdentityProviderConfig",
16
+ ]
@@ -0,0 +1,215 @@
1
+ """GitHub OAuth Device Flow implementation for Orchestr8."""
2
+
3
+ import time
4
+ import webbrowser
5
+ from typing import Dict, Optional
6
+ from dataclasses import dataclass
7
+ import requests
8
+ from rich.console import Console
9
+ from rich.panel import Panel
10
+ from rich.progress import Progress, SpinnerColumn, TextColumn
11
+
12
+
13
+ @dataclass
14
+ class GitHubAuthResult:
15
+ """Result of GitHub authentication."""
16
+
17
+ access_token: str
18
+ token_type: str
19
+ scope: str
20
+
21
+
22
+ class GitHubDeviceFlow:
23
+ """GitHub OAuth Device Flow implementation."""
24
+
25
+ # GitHub OAuth endpoints
26
+ DEVICE_CODE_URL = "https://github.com/login/device/code"
27
+ TOKEN_URL = "https://github.com/login/oauth/access_token"
28
+
29
+ # Default Orchestr8 OAuth App Client ID
30
+ DEFAULT_CLIENT_ID = "Ov23liefXYUwEpx4AMWz"
31
+
32
+ def __init__(
33
+ self, console: Optional[Console] = None, client_id: Optional[str] = None
34
+ ):
35
+ self.console = console or Console()
36
+ self.client_id = client_id or self.DEFAULT_CLIENT_ID
37
+
38
+ def authenticate(self, scopes: Optional[str] = None) -> Optional[GitHubAuthResult]:
39
+ """
40
+ Perform GitHub OAuth device flow authentication.
41
+
42
+ Args:
43
+ scopes: OAuth scopes to request (e.g., "repo", "user:email")
44
+
45
+ Returns:
46
+ GitHubAuthResult with access token if successful, None otherwise
47
+ """
48
+ # Request device code
49
+ device_code_data = self._request_device_code(scopes)
50
+ if not device_code_data:
51
+ return None
52
+
53
+ # Show user instructions
54
+ self._display_auth_instructions(
55
+ device_code_data["user_code"], device_code_data["verification_uri"]
56
+ )
57
+
58
+ # Poll for token
59
+ token_data = self._poll_for_token(
60
+ device_code_data["device_code"], device_code_data["interval"]
61
+ )
62
+
63
+ if token_data:
64
+ return GitHubAuthResult(
65
+ access_token=token_data["access_token"],
66
+ token_type=token_data.get("token_type", "bearer"),
67
+ scope=token_data.get("scope", ""),
68
+ )
69
+
70
+ return None
71
+
72
+ def _request_device_code(self, scopes: Optional[str]) -> Optional[Dict]:
73
+ """Request device and user codes from GitHub."""
74
+ headers = {"Accept": "application/json"}
75
+ data = {"client_id": self.client_id}
76
+
77
+ if scopes:
78
+ data["scope"] = scopes
79
+
80
+ try:
81
+ response = requests.post(self.DEVICE_CODE_URL, headers=headers, data=data)
82
+ response.raise_for_status()
83
+ return response.json()
84
+ except requests.exceptions.RequestException as e:
85
+ self.console.print(f"[red]Failed to request device code: {e}[/red]")
86
+ return None
87
+
88
+ def _display_auth_instructions(self, user_code: str, verification_uri: str):
89
+ """Display authentication instructions to the user."""
90
+ self.console.print()
91
+ panel = Panel(
92
+ f"[bold cyan]Please visit:[/bold cyan] {verification_uri}\n"
93
+ f"[bold cyan]Enter code:[/bold cyan] [bold yellow]{user_code}[/bold yellow]",
94
+ title="🔐 GitHub Authentication Required",
95
+ border_style="cyan",
96
+ )
97
+ self.console.print(panel)
98
+
99
+ # Try to open browser automatically
100
+ try:
101
+ webbrowser.open(verification_uri)
102
+ except Exception:
103
+ pass
104
+
105
+ def _poll_for_token(self, device_code: str, interval: int) -> Optional[Dict]:
106
+ """Poll GitHub for access token."""
107
+ headers = {"Accept": "application/json"}
108
+ data = {
109
+ "client_id": self.client_id,
110
+ "device_code": device_code,
111
+ "grant_type": "urn:ietf:params:oauth:grant-type:device_code",
112
+ }
113
+
114
+ with Progress(
115
+ SpinnerColumn(),
116
+ TextColumn("[progress.description]{task.description}"),
117
+ console=self.console,
118
+ transient=True,
119
+ ) as progress:
120
+ task = progress.add_task("Waiting for authentication...", total=None)
121
+
122
+ while True:
123
+ try:
124
+ response = requests.post(self.TOKEN_URL, headers=headers, data=data)
125
+ response_data = response.json()
126
+
127
+ if "access_token" in response_data:
128
+ progress.update(task, completed=True)
129
+ return response_data
130
+
131
+ error = response_data.get("error")
132
+
133
+ if error == "authorization_pending":
134
+ # Still waiting for user to authorize
135
+ time.sleep(interval)
136
+
137
+ elif error == "slow_down":
138
+ # Rate limited, increase interval
139
+ interval = response_data.get("interval", interval + 5)
140
+ time.sleep(interval)
141
+
142
+ elif error == "expired_token":
143
+ progress.update(
144
+ task, description="[red]❌ Authentication expired[/red]"
145
+ )
146
+ self.console.print(
147
+ "[red]The device code has expired. Please try again.[/red]"
148
+ )
149
+ return None
150
+
151
+ elif error == "access_denied":
152
+ progress.update(task, description="[red]❌ Access denied[/red]")
153
+ self.console.print("[red]Authentication was denied.[/red]")
154
+ return None
155
+
156
+ else:
157
+ # Unknown error
158
+ progress.update(
159
+ task, description=f"[red]❌ Error: {error}[/red]"
160
+ )
161
+ return None
162
+
163
+ except requests.exceptions.RequestException as e:
164
+ progress.update(task, description="[red]❌ Network error[/red]")
165
+ self.console.print(f"[red]Network error: {e}[/red]")
166
+ return None
167
+
168
+ @staticmethod
169
+ def recommend_scopes(private_repos: bool = True) -> str:
170
+ """
171
+ Recommend OAuth scopes based on usage.
172
+
173
+ Args:
174
+ private_repos: Whether access to private repositories is needed
175
+
176
+ Returns:
177
+ Recommended scope string
178
+ """
179
+ if private_repos:
180
+ return "repo" # Full repo access including private repos
181
+ else:
182
+ return "" # No scope needed for public repos
183
+
184
+ def validate_token(self, token: str) -> bool:
185
+ """
186
+ Validate that a token has access to the required repository.
187
+
188
+ Args:
189
+ token: GitHub access token to validate
190
+
191
+ Returns:
192
+ True if token is valid and has repo access
193
+ """
194
+ headers = {
195
+ "Authorization": f"token {token}",
196
+ "Accept": "application/vnd.github.v3+json",
197
+ }
198
+
199
+ try:
200
+ # Check token validity and scopes
201
+ response = requests.get("https://api.github.com/user", headers=headers)
202
+
203
+ if response.status_code == 200:
204
+ # Check scopes from response headers (for debugging)
205
+ # scopes = response.headers.get("X-OAuth-Scopes", "")
206
+ return True
207
+ else:
208
+ self.console.print(
209
+ f"[red]Token validation failed: {response.status_code}[/red]"
210
+ )
211
+ return False
212
+
213
+ except requests.exceptions.RequestException as e:
214
+ self.console.print(f"[red]Error validating token: {e}[/red]")
215
+ return False