Public Access
Post-merge / detect-type (push) Successful in 9s
Post-merge / validate-commit-msg (push) Successful in 9s
Build Images / detect-type (push) Successful in 42s
Post-merge / vikunja (push) Successful in 17s
Post-merge / release (push) Successful in 52s
Post-merge / configure-repo (push) Successful in 23s
Post-merge / badges (push) Successful in 55s
Post-merge / sync-wiki (push) Successful in 58s
Post-merge / publish (push) Successful in 21s
Build Images / build-and-push (push) Successful in 3m15s
Build Images / cleanup (push) Successful in 3m38s
91 lines
2.5 KiB
Python
91 lines
2.5 KiB
Python
#!/usr/bin/env python3
|
|
"""Set up SSH private key for CI jobs that need SSH access to remote hosts.
|
|
|
|
Writes the ``SSH_PRIVATE_KEY`` env var to ``~/.ssh/id_rsa``, starts
|
|
``ssh-agent``, and adds the key. Replaces the repeated inline shell
|
|
pattern in CI workflow files.
|
|
|
|
Usage::
|
|
|
|
python3 -m devx.tools.setup_ssh_key
|
|
|
|
Reads ``SSH_PRIVATE_KEY`` from the environment. Exits 0 on success,
|
|
1 on missing key.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
import subprocess # nosec B404
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
import click
|
|
|
|
from devx.i18n import _
|
|
|
|
|
|
def setup_ssh_key(private_key: str | None = None) -> bool:
|
|
"""Set up SSH private key and start ssh-agent.
|
|
|
|
Args:
|
|
private_key: The SSH private key content. If None, reads from
|
|
``SSH_PRIVATE_KEY`` environment variable.
|
|
|
|
Returns:
|
|
True if setup succeeded, False if key is missing.
|
|
"""
|
|
key = private_key or os.environ.get("SSH_PRIVATE_KEY", "")
|
|
if not key:
|
|
click.echo(_("SSH_PRIVATE_KEY not set — skipping SSH key setup"), err=True)
|
|
return False
|
|
|
|
ssh_dir = Path.home() / ".ssh"
|
|
ssh_dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
key_path = ssh_dir / "id_rsa"
|
|
key_path.write_text(f"{key}\n", encoding="utf-8")
|
|
key_path.chmod(0o600)
|
|
|
|
# Start ssh-agent and add the key
|
|
agent_result = subprocess.run( # nosec B603, B607
|
|
["ssh-agent", "-s"],
|
|
capture_output=True,
|
|
text=True,
|
|
check=False,
|
|
)
|
|
if agent_result.returncode != 0:
|
|
click.echo(_("Failed to start ssh-agent: {error}", error=agent_result.stderr), err=True)
|
|
return False
|
|
|
|
# Parse ssh-agent output to set env vars
|
|
for raw_line in agent_result.stdout.splitlines():
|
|
stripped = raw_line.strip()
|
|
if "=" in stripped and ";" in stripped:
|
|
var, val = stripped.split("=", 1)
|
|
val = val.rstrip(";")
|
|
os.environ[var] = val
|
|
|
|
# Add the key (non-fatal if it fails — key may already be loaded)
|
|
subprocess.run( # nosec B603, B607
|
|
["ssh-add", str(key_path)],
|
|
capture_output=True,
|
|
text=True,
|
|
check=False,
|
|
)
|
|
return True
|
|
|
|
|
|
@click.command()
|
|
def cli() -> None:
|
|
"""Set up SSH private key from SSH_PRIVATE_KEY env var."""
|
|
if setup_ssh_key():
|
|
click.echo(_("SSH key set up successfully"))
|
|
sys.exit(0)
|
|
click.echo(_("SSH key setup skipped (no key provided)"), err=True)
|
|
sys.exit(1)
|
|
|
|
|
|
if __name__ == "__main__": # pragma: no cover
|
|
cli() # pragma: no cover
|