-
Notifications
You must be signed in to change notification settings - Fork 87
feat(runner,api,cli): add kubeconfig credential provider for OpenShift MCP auth #1276
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -23,6 +23,14 @@ | |
| "READ_ONLY_MODE": "${JIRA_READ_ONLY_MODE:-true}" | ||
| } | ||
| }, | ||
| "openshift": { | ||
| "command": "uvx", | ||
| "args": [ | ||
| "kubernetes-mcp-server@latest", | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
# Verify floating MCP package versions in runner MCP configs
fd -i '.mcp.json$' --exec rg -n '"[^"]+@latest"' {}Repository: ambient-code/platform Length of output: 47 🏁 Script executed: # Check if the file exists and read its contents
if [ -f "components/runners/ambient-runner/.mcp.json" ]; then
echo "=== File exists, reading contents ==="
cat -n "components/runners/ambient-runner/.mcp.json"
else
echo "=== File does not exist at specified path ==="
# Search for any .mcp.json files
echo "=== Searching for .mcp.json files ==="
find . -name ".mcp.json" -o -name "*.mcp.json" 2>/dev/null | head -20
fiRepository: ambient-code/platform Length of output: 1776 Pin Line 29 uses 🤖 Prompt for AI Agents |
||
| "--kubeconfig", "/tmp/.ambient_kubeconfig", | ||
| "--disable-multi-cluster" | ||
| ] | ||
| }, | ||
| "google-workspace": { | ||
| "command": "uvx", | ||
| "args": [ | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -41,6 +41,7 @@ | |
| # time), so updating os.environ mid-run would not reach it without these files. | ||
| _GITHUB_TOKEN_FILE = Path("/tmp/.ambient_github_token") | ||
| _GITLAB_TOKEN_FILE = Path("/tmp/.ambient_gitlab_token") | ||
| _KUBECONFIG_FILE = Path("/tmp/.ambient_kubeconfig") | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use symlink-safe file creation for kubeconfig secret material. Lines 44 and 440-443 write sensitive kubeconfig content to a predictable Suggested secure write pattern- _KUBECONFIG_FILE.write_text(kubeconfig_creds["token"])
- _KUBECONFIG_FILE.chmod(0o600)
+ flags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC
+ if hasattr(os, "O_NOFOLLOW"):
+ flags |= os.O_NOFOLLOW
+ fd = os.open(_KUBECONFIG_FILE, flags, 0o600)
+ with os.fdopen(fd, "w", encoding="utf-8") as f:
+ f.write(kubeconfig_creds["token"])As per coding guidelines, "Flag only errors, security risks, or functionality-breaking problems." Also applies to: 440-443 🧰 Tools🪛 Ruff (0.15.9)[error] 44-44: Probable insecure usage of temporary file or directory: "/tmp/.ambient_kubeconfig" (S108) 🤖 Prompt for AI Agents |
||
|
|
||
|
|
||
| # --------------------------------------------------------------------------- | ||
|
|
@@ -315,6 +316,10 @@ async def fetch_gitlab_token(context: RunnerContext) -> str: | |
| return data.get("token", "") | ||
|
|
||
|
|
||
| async def fetch_kubeconfig_credential(context: RunnerContext) -> dict: | ||
| return await _fetch_credential(context, "kubeconfig") | ||
|
|
||
|
|
||
| async def fetch_token_for_url(context: RunnerContext, url: str) -> str: | ||
| """Fetch appropriate token based on repository URL host.""" | ||
| try: | ||
|
|
@@ -337,11 +342,12 @@ async def populate_runtime_credentials(context: RunnerContext) -> None: | |
| logger.info("Fetching fresh credentials from backend API...") | ||
|
|
||
| # Fetch all credentials concurrently | ||
| google_creds, jira_creds, gitlab_creds, github_creds = await asyncio.gather( | ||
| google_creds, jira_creds, gitlab_creds, github_creds, kubeconfig_creds = await asyncio.gather( | ||
| fetch_google_credentials(context), | ||
| fetch_jira_credentials(context), | ||
| fetch_gitlab_credentials(context), | ||
| fetch_github_credentials(context), | ||
| fetch_kubeconfig_credential(context), | ||
| return_exceptions=True, | ||
| ) | ||
|
|
||
|
|
@@ -425,6 +431,25 @@ async def populate_runtime_credentials(context: RunnerContext) -> None: | |
| if github_creds.get("email"): | ||
| git_user_email = github_creds["email"] | ||
|
|
||
| if isinstance(kubeconfig_creds, Exception): | ||
| logger.warning(f"Failed to refresh kubeconfig credentials: {kubeconfig_creds}") | ||
| if isinstance(kubeconfig_creds, PermissionError): | ||
| auth_failures.append(str(kubeconfig_creds)) | ||
| elif kubeconfig_creds.get("token"): | ||
| # Setting KUBECONFIG in os.environ is safe here: the runner's own platform | ||
| # communication (backend REST API, gRPC to API server) uses the mounted SA | ||
| # token and CA cert directly from /var/run/secrets/..., not via any kube | ||
| # client library or KUBECONFIG. This env var only affects child processes | ||
| # (Claude CLI, MCP servers, kubectl/oc) so they can reach the user's | ||
| # remote cluster without interfering with the pod's own identity. | ||
| try: | ||
| _KUBECONFIG_FILE.write_text(kubeconfig_creds["token"]) | ||
| _KUBECONFIG_FILE.chmod(0o600) | ||
| os.environ["KUBECONFIG"] = str(_KUBECONFIG_FILE) | ||
| logger.info(f"Written kubeconfig to {_KUBECONFIG_FILE}") | ||
| except OSError as e: | ||
| logger.warning(f"Failed to write kubeconfig file: {e}") | ||
|
|
||
| # Configure git identity and credential helper | ||
| await configure_git_identity(git_user_name, git_user_email) | ||
| install_git_credential_helper() | ||
|
|
@@ -452,6 +477,7 @@ def clear_runtime_credentials() -> None: | |
| "JIRA_URL", | ||
| "JIRA_EMAIL", | ||
| "USER_GOOGLE_EMAIL", | ||
| "KUBECONFIG", | ||
| ]: | ||
| if os.environ.pop(key, None) is not None: | ||
| cleared.append(key) | ||
|
|
@@ -468,7 +494,7 @@ def clear_runtime_credentials() -> None: | |
| cleared.append(key) | ||
|
|
||
| # Remove token files used by the git credential helper. | ||
| for token_file in (_GITHUB_TOKEN_FILE, _GITLAB_TOKEN_FILE): | ||
| for token_file in (_GITHUB_TOKEN_FILE, _GITLAB_TOKEN_FILE, _KUBECONFIG_FILE): | ||
| try: | ||
| token_file.unlink(missing_ok=True) | ||
| cleared.append(token_file.name) | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.