From d76ca9ec81086e486a50a4aa03126271a3e520de Mon Sep 17 00:00:00 2001 From: a73x Date: Sun, 25 Aug 2024 13:21:16 +0100 Subject: now with a go bashscript and hooks --- Dockerfile | 19 +++++++-- README | 1 + README.md | 1 - go.mod | 3 ++ main.go | 141 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 161 insertions(+), 4 deletions(-) create mode 100644 README delete mode 100644 README.md create mode 100644 go.mod create mode 100644 main.go diff --git a/Dockerfile b/Dockerfile index b8039db..5dca0e0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,3 +1,15 @@ +FROM golang:1.23.0-alpine3.20 + +WORKDIR /usr/src/app + +# COPY go.mod go.sum ./ +COPY go.mod . +RUN go mod download && go mod verify + +COPY . . + +RUN CGO_ENABLED=0 go build -ldflags="-s -w" -o /usr/local/bin/app . + FROM alpine:latest # Install necessary packages @@ -35,13 +47,14 @@ RUN echo "PasswordAuthentication no" >> /etc/ssh/sshd_config # Set MOTD -run echo "Connection successful!" > /etc/motd +RUN echo "Connection successful!" > /etc/motd # Expose SSH port EXPOSE 22 -COPY git-wrapper.sh /usr/local/bin/git-wrapper -RUN chmod +x /usr/local/bin/git-wrapper +COPY --from=0 /usr/local/bin/app /usr/local/bin/git-wrapper +# COPY git-wrapper.sh /usr/local/bin/git-wrapper +# RUN chmod +x /usr/local/bin/git-wrapper # Copy the entrypoint script COPY entrypoint.sh /entrypoint.sh diff --git a/README b/README new file mode 100644 index 0000000..7a07164 --- /dev/null +++ b/README @@ -0,0 +1 @@ +self hosted git server with a cgit ui diff --git a/README.md b/README.md deleted file mode 100644 index 7a07164..0000000 --- a/README.md +++ /dev/null @@ -1 +0,0 @@ -self hosted git server with a cgit ui diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..f109fad --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module git.sr.ht/~a73x/git + +go 1.23.0 diff --git a/main.go b/main.go new file mode 100644 index 0000000..4902f8b --- /dev/null +++ b/main.go @@ -0,0 +1,141 @@ +package main + +import ( + "fmt" + "log" + "os" + "os/exec" + "path/filepath" + "strings" + "syscall" +) + +var logger *log.Logger +var logf *os.File + +func main() { + var err error + logf, err = os.OpenFile("loggy.boi", + os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644) + if err != nil { + log.Fatal(err) + } + + defer logf.Close() + + logger = log.New(logf, "", log.LstdFlags) + sshOriginalCommand := os.Getenv("SSH_ORIGINAL_COMMAND") + if sshOriginalCommand == "" { + log.Fatal("SSH_ORIGINAL_COMMAND is not set") + } + + if err := Run(sshOriginalCommand); err != nil { + logger.Fatal(err) + } +} + +type Mkdir func([]string) error + +func mkdir(path string) error { + return os.MkdirAll(path, 0755) +} + +func Run(sshCmd string) error { + parts := strings.Split(sshCmd, " ") + if len(parts) != 2 { + return fmt.Errorf("expected 2 args: %s", sshCmd) + } + + command := parts[0] + repo := parts[1] + + remmappedRepo := RemapRepoPath(repo, "repos") + // creates repos if they don't exist + if _, err := os.Stat(remmappedRepo); os.IsNotExist(err) { + if err := setupRepo(remmappedRepo); err != nil { + return fmt.Errorf("failed to setup repo: %v", err) + } + } + + bin, err := exec.LookPath(command) + if err != nil { + return fmt.Errorf("failed to lookup %s:%v", command, err) + } + + // Execute the git-shell command + return syscall.Exec(bin, []string{command, remmappedRepo}, os.Environ()) +} + +func setupRepo(repo string) error { + // Create the directory (and any necessary parent directories) + if err := mkdir(repo); err != nil { + return fmt.Errorf("failed to create directory: %v", err) + } + + cmd := exec.Command("git", "init", "--bare", "--initial-branch=main", repo) + cmd.Stdout = logf + cmd.Stderr = logf + if err := cmd.Run(); err != nil { + return fmt.Errorf("failed to run initialize git repository: %v", err) + } + + if err := writeDescriptionHook(repo); err != nil { + logger.Printf("failed to create description hook: %v\n", err) + } + + return nil +} + +// 'a73x/cgit.git' => repos/a73x/cgit.git +func RemapRepoPath(repo string, path string) string { + return filepath.Join(path, strings.Trim(repo, "'")) +} + +var descriptionHook = `#!/bin/bash + +BRANCH="main" +FILE=README +while read oldrev newrev ref +do + # only checking out the master (or whatever branch you would like to deploy) + if [ "$ref" = "refs/heads/$BRANCH" ]; + then + changed=$(git ls-tree $REV $FILE) + if [ -n $changed ]; then + echo "Ref $ref received. updating description" + git show HEAD:README | head -n1 > description + fi + else + echo "Ref $ref received. Doing nothing: only the ${BRANCH} branch may be deployed on this server." + fi +done` + +func writeDescriptionHook(path string) error { + hooksDir := filepath.Join(path, "hooks") + scriptPath := filepath.Join(hooksDir, "post-receive") + err := os.MkdirAll(hooksDir, 0755) + if err != nil { + return fmt.Errorf("error creating hooks directory: %v", err) + } + + file, err := os.Create(scriptPath) + if err != nil { + return fmt.Errorf("error creating post-receive file: %v", err) + } + + defer file.Close() + + // Write the script to the file + _, err = file.WriteString(descriptionHook) + if err != nil { + return fmt.Errorf("error writing script to file: %v", err) + } + + // Set the file permissions to be executable + err = os.Chmod(scriptPath, 0755) + if err != nil { + return fmt.Errorf("error setting file permissions: %v", err) + } + + return nil +} -- cgit v1.2.3