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.
- orchestr8_platform-3.0.0/PKG-INFO +164 -0
- orchestr8_platform-3.0.0/README.md +126 -0
- orchestr8_platform-3.0.0/pyproject.toml +105 -0
- orchestr8_platform-3.0.0/setup.cfg +4 -0
- orchestr8_platform-3.0.0/src/orchestr8/__init__.py +1 -0
- orchestr8_platform-3.0.0/src/orchestr8/auth/__init__.py +16 -0
- orchestr8_platform-3.0.0/src/orchestr8/auth/github_oauth.py +215 -0
- orchestr8_platform-3.0.0/src/orchestr8/auth/keycloak_idp.py +519 -0
- orchestr8_platform-3.0.0/src/orchestr8/cli/module.py +469 -0
- orchestr8_platform-3.0.0/src/orchestr8/cli.py +1174 -0
- orchestr8_platform-3.0.0/src/orchestr8/commands/argocd.py +484 -0
- orchestr8_platform-3.0.0/src/orchestr8/commands/bootstrap.py +1582 -0
- orchestr8_platform-3.0.0/src/orchestr8/commands/branch.py +387 -0
- orchestr8_platform-3.0.0/src/orchestr8/commands/doctor.py +374 -0
- orchestr8_platform-3.0.0/src/orchestr8/commands/module.py +763 -0
- orchestr8_platform-3.0.0/src/orchestr8/commands/secrets.py +996 -0
- orchestr8_platform-3.0.0/src/orchestr8/core/__init__.py +7 -0
- orchestr8_platform-3.0.0/src/orchestr8/core/config.py +85 -0
- orchestr8_platform-3.0.0/src/orchestr8/core/orchestrator.py +1794 -0
- orchestr8_platform-3.0.0/src/orchestr8/core/secrets.py +150 -0
- orchestr8_platform-3.0.0/src/orchestr8/core/terraform.py +551 -0
- orchestr8_platform-3.0.0/src/orchestr8/core/validator.py +567 -0
- orchestr8_platform-3.0.0/src/orchestr8/providers/__init__.py +7 -0
- orchestr8_platform-3.0.0/src/orchestr8/providers/aws.py +89 -0
- orchestr8_platform-3.0.0/src/orchestr8/providers/azure.py +567 -0
- orchestr8_platform-3.0.0/src/orchestr8/providers/github.py +97 -0
- orchestr8_platform-3.0.0/src/orchestr8/providers/local.py +73 -0
- orchestr8_platform-3.0.0/src/orchestr8/sdk.py +156 -0
- orchestr8_platform-3.0.0/src/orchestr8/utils/azure_cli.py +117 -0
- orchestr8_platform-3.0.0/src/orchestr8_platform.egg-info/PKG-INFO +164 -0
- orchestr8_platform-3.0.0/src/orchestr8_platform.egg-info/SOURCES.txt +40 -0
- orchestr8_platform-3.0.0/src/orchestr8_platform.egg-info/dependency_links.txt +1 -0
- orchestr8_platform-3.0.0/src/orchestr8_platform.egg-info/entry_points.txt +2 -0
- orchestr8_platform-3.0.0/src/orchestr8_platform.egg-info/requires.txt +16 -0
- orchestr8_platform-3.0.0/src/orchestr8_platform.egg-info/top_level.txt +1 -0
- orchestr8_platform-3.0.0/tests/test_azure_integration.py +283 -0
- orchestr8_platform-3.0.0/tests/test_cli.py +262 -0
- orchestr8_platform-3.0.0/tests/test_integration.py +225 -0
- orchestr8_platform-3.0.0/tests/test_module_commands.py +147 -0
- orchestr8_platform-3.0.0/tests/test_orchestrator.py +300 -0
- orchestr8_platform-3.0.0/tests/test_providers.py +295 -0
- 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 @@
|
|
|
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
|