feat: add GITHUB_TOKEN configuration for git auth

This allows using a personal access token for private repositories and higher API rate limits.

Fixes #501
This commit is contained in:
Ingmar Stein
2025-12-18 19:42:14 +01:00
parent fec37e2c21
commit d8ff51ca8e
6 changed files with 35 additions and 15 deletions

View File

@@ -221,7 +221,7 @@ func main() {
// Clone/Update System Apps Repo
systemAppsDir := filepath.Join(*dataDir, "system-apps")
shouldUpdate := cfg.Production == "1"
if err := gitutils.EnsureRepo(systemAppsDir, cfg.SystemAppsRepo, shouldUpdate); err != nil {
if err := gitutils.EnsureRepo(systemAppsDir, cfg.SystemAppsRepo, cfg.GitHubToken, shouldUpdate); err != nil {
slog.Error("Failed to update system apps repo", "error", err)
// Continue anyway
}

View File

@@ -16,6 +16,7 @@ type Settings struct {
MaxUsers int `env:"MAX_USERS" envDefault:"0"`
SingleUserAutoLogin string `env:"SINGLE_USER_AUTO_LOGIN" envDefault:"0"`
SystemAppsRepo string `env:"SYSTEM_APPS_REPO" envDefault:"https://github.com/tronbyt/apps.git"`
GitHubToken string `env:"GITHUB_TOKEN"`
RedisURL string `env:"REDIS_URL"`
Host string `env:"TRONBYT_HOST" envDefault:""`
Port string `env:"TRONBYT_PORT" envDefault:"8000"`

View File

@@ -4,11 +4,14 @@ import (
"errors"
"fmt"
"log/slog"
"net/url"
"os"
"strings"
"github.com/go-git/go-git/v6"
"github.com/go-git/go-git/v6/plumbing"
"github.com/go-git/go-git/v6/plumbing/transport"
"github.com/go-git/go-git/v6/plumbing/transport/http"
)
// logWriter implements io.Writer to redirect git progress to slog.
@@ -89,16 +92,31 @@ func GetRepoInfo(path string, remoteURL string) (*RepoInfo, error) {
}
// EnsureRepo clones a repo if it doesn't exist, or pulls if it does and update is true.
func EnsureRepo(path string, url string, update bool) error {
slog.Info("Checking git repo", "path", path, "url", url)
func EnsureRepo(path string, repoURL string, token string, update bool) error {
slog.Info("Checking git repo", "path", path, "url", repoURL)
var auth transport.AuthMethod
u, err := url.Parse(repoURL)
if err == nil && u.User == nil {
if token != "" && (u.Scheme == "http" || u.Scheme == "https") && u.Host == "github.com" {
auth = &http.BasicAuth{
Username: token,
Password: "", // For GitHub PATs, the password can be empty.
}
}
} else if err != nil {
slog.Warn("Failed to parse repo URL", "url", repoURL, "error", err)
}
// Check if path exists
if _, err := os.Stat(path); os.IsNotExist(err) {
slog.Info("Cloning repo", "url", url)
slog.Info("Cloning repo", "url", repoURL)
_, err := git.PlainClone(path, &git.CloneOptions{
URL: url,
URL: repoURL,
Progress: &logWriter{},
Depth: 1,
Auth: auth,
})
return err
@@ -116,14 +134,14 @@ func EnsureRepo(path string, url string, update bool) error {
rem, err := r.Remote("origin")
if err == nil {
urls := rem.Config().URLs
if len(urls) > 0 && urls[0] != url {
slog.Warn("Repo remote URL mismatch, re-cloning", "current", urls[0], "new", url)
if len(urls) > 0 && urls[0] != repoURL {
slog.Warn("Repo remote URL mismatch, re-cloning", "current", urls[0], "new", repoURL)
// Remove and re-clone
if err := os.RemoveAll(path); err != nil {
return fmt.Errorf("failed to remove old repo: %w", err)
}
return EnsureRepo(path, url, update)
return EnsureRepo(path, repoURL, token, update)
}
}
@@ -145,6 +163,7 @@ func EnsureRepo(path string, url string, update bool) error {
Progress: &logWriter{},
Depth: 1,
Force: true,
Auth: auth,
})
// Handle fetch errors
@@ -155,7 +174,7 @@ func EnsureRepo(path string, url string, update bool) error {
if err := os.RemoveAll(path); err != nil {
return fmt.Errorf("failed to remove broken repo: %w", err)
}
return EnsureRepo(path, url, update)
return EnsureRepo(path, repoURL, token, update)
}
return fmt.Errorf("failed to fetch repo: %w", err)
}

View File

@@ -39,7 +39,7 @@ func (s *Server) UpdateFirmwareBinaries() error {
return err
}
token := os.Getenv("GITHUB_TOKEN")
token := s.Config.GitHubToken
if token != "" {
req.Header.Set("Authorization", "Bearer "+token)
}

View File

@@ -65,7 +65,7 @@ func (s *Server) doUpdateCheck() {
return
}
githubToken := os.Getenv("GITHUB_TOKEN")
githubToken := s.Config.GitHubToken
if githubToken != "" {
req.Header.Set("Authorization", "Bearer "+githubToken)
}

View File

@@ -187,7 +187,7 @@ func (s *Server) handleSetUserRepo(w http.ResponseWriter, r *http.Request) {
}
appsPath := filepath.Join(s.DataDir, "users", user.Username, "apps")
if err := gitutils.EnsureRepo(appsPath, repoURL, true); err != nil {
if err := gitutils.EnsureRepo(appsPath, repoURL, s.Config.GitHubToken, true); err != nil {
slog.Error("Failed to sync user repo", "error", err)
}
@@ -199,7 +199,7 @@ func (s *Server) handleRefreshUserRepo(w http.ResponseWriter, r *http.Request) {
if user.AppRepoURL != "" {
appsPath := filepath.Join(s.DataDir, "users", user.Username, "apps")
if err := gitutils.EnsureRepo(appsPath, user.AppRepoURL, true); err != nil {
if err := gitutils.EnsureRepo(appsPath, user.AppRepoURL, s.Config.GitHubToken, true); err != nil {
slog.Error("Failed to refresh user repo", "error", err)
}
}
@@ -355,7 +355,7 @@ func (s *Server) handleSetSystemRepo(w http.ResponseWriter, r *http.Request) {
}
appsPath := filepath.Join(s.DataDir, "system-apps")
if err := gitutils.EnsureRepo(appsPath, repoURL, true); err != nil {
if err := gitutils.EnsureRepo(appsPath, repoURL, s.Config.GitHubToken, true); err != nil {
slog.Error("Failed to update system repo", "error", err)
}
@@ -385,7 +385,7 @@ func (s *Server) handleRefreshSystemRepo(w http.ResponseWriter, r *http.Request)
}
appsPath := filepath.Join(s.DataDir, "system-apps")
if err := gitutils.EnsureRepo(appsPath, repoURL, true); err != nil {
if err := gitutils.EnsureRepo(appsPath, repoURL, s.Config.GitHubToken, true); err != nil {
slog.Error("Failed to refresh system repo", "error", err)
}