#!/usr/bin/env python3
"""gitrepo-shell — SSH forced-command wrapper for git access control."""
import os
import re
import sys

sys.path.insert(0, "/usr/lib/gitrepo")

from gitrepo.config import load_config
from gitrepo.permissions import check_permission

COMMAND_RE = re.compile(r"^(git-(?:upload|receive)-pack) '(.+)'$")
DEFAULT_CONFIG = "/etc/gitrepo/config.yaml"


def die(message):
    print(f"gitrepo-shell: {message}", file=sys.stderr)
    sys.exit(1)


def main():
    if len(sys.argv) < 2:
        die("No username provided")

    # Handle login shell invocation: sshd calls <shell> -c "<forced-command>"
    if sys.argv[1] == "-c":
        if len(sys.argv) < 3:
            die("Interactive shell access is not permitted")
        os.execvp("/bin/sh", ["/bin/sh", "-c", sys.argv[2]])

    username = sys.argv[1]
    config_path = os.environ.get("GITREPO_CONFIG", DEFAULT_CONFIG)

    ssh_cmd = os.environ.get("SSH_ORIGINAL_COMMAND", "")
    if not ssh_cmd:
        die("Interactive shell access is not permitted")

    match = COMMAND_RE.match(ssh_cmd)
    if not match:
        die(f"Invalid git command: {ssh_cmd}")

    git_command = match.group(1)
    repo_path = match.group(2)

    config = load_config(config_path)
    repo_root = config.get("repo_root", "/var/lib/gitrepo/repos")

    if os.path.isabs(repo_path):
        real_path = os.path.realpath(repo_path)
        real_root = os.path.realpath(repo_root)
        if not real_path.startswith(real_root + "/"):
            die("Permission denied: repo path outside repo root")
        relative = os.path.relpath(real_path, real_root)
    else:
        if ".." in repo_path.split("/"):
            die("Permission denied: path traversal not allowed")
        relative = repo_path

    repo_name = relative.removesuffix(".git")

    if not check_permission(config_path, repo_name, username, git_command):
        die(f"Permission denied: {username} cannot {git_command} on {repo_name}")

    full_repo_path = os.path.join(repo_root, relative)
    if not relative.endswith(".git"):
        full_repo_path += ".git"

    os.execvp(git_command, [git_command, full_repo_path])


main()
