aboutsummaryrefslogtreecommitdiff
path: root/modules/cgit.nix
blob: 8c411a7d2d2397f3a8892ca4090f3c5cb1dd658e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
{ config, pkgs, lib, ... }:

# cgit - fast web interface for git repositories.
#
# Repositories live in /srv/git/<repo>.git (bare repos).
# Access model:
#   - Web browsing:  public, no auth  (https://git.karanj.com)
#   - git clone/pull over HTTPS: public, read-only via git-http-backend
#   - git push:      SSH only, using the "git" user + your authorized keys
#
# The NixOS cgit module serves both cgit browsing and git-http-backend
# (clone/pull, via gitHttpBackend.enable which defaults to true) on the
# *same* nginx vhost/location - nginx tells them apart by matching the
# request path against a regex (.../info/refs|git-upload-pack for the
# smart-HTTP protocol), not by a separate port. That combined vhost is
# bound to localhost:8086 below, and Caddy reverse-proxies everything
# for git.karanj.com straight to it. Only git-upload-pack is wired up, so
# push over HTTP is impossible regardless - push stays SSH-only.
{
  # Dedicated git user for SSH push access
  users.users.git = {
    isSystemUser = true;
    group = "git";
    home = "/srv/git";
    shell = pkgs.git;
    # Allow pushing from both your devices
    openssh.authorizedKeys.keys = [
      "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAwAgL0o4NVonSG07Xu4Eai84ns4AjoZj2V7dGC9nXit karanjayachandra@Einstein.local"
      "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIH+qnLTnorv+I2rSSfGjNiCuX/W5AxoNgAdu+cTOyKzW Galileo"
    ];
  };
  users.groups.git = {};

  # Repository root
  #
  # The git-shell-commands lines below add Git LFS support. git-shell's own
  # hardcoded allowlist is exactly three commands - git-receive-pack,
  # git-upload-pack, git-upload-archive (confirmed from git's own shell.c) -
  # so a plain LFS-tracked push fails with "unrecognized command
  # 'git-lfs-authenticate ...'" otherwise. The documented extension point is
  # an executable file matching the command name in ~/git-shell-commands
  # (~ being /srv/git, the git user's home above). Symlinking git-lfs-transfer
  # there - nixpkgs' server-side implementation of Git LFS's pure-SSH
  # protocol - is enough: git-lfs clients (v3.0+) already try this command
  # automatically for SSH remotes before falling back to the HTTP-based
  # git-lfs-authenticate flow, so nothing needs configuring client-side. This
  # keeps LFS on the same SSH-only path as normal pushes, with no HTTP LFS
  # server or tokens involved.
  systemd.tmpfiles.rules = [
    "d /srv/git 0755 git git -"
    "d /srv/git/git-shell-commands 0750 git git -"
    "L+ /srv/git/git-shell-commands/git-lfs-transfer - - - - ${pkgs.git-lfs-transfer}/bin/git-lfs-transfer"
  ];

  # cgit web interface served via nginx + fcgiwrap
  services.cgit."git.karanj.com" = {
    enable = true;
    scanPath = "/srv/git";
    gitHttpBackend.checkExportOkFiles = false; 
    settings = {

      # Site branding
      root-title = "karan's git";
      root-desc = "personal git repositories";

      # Enable common features
      enable-index-links = 1;
      enable-commit-graph = 1;
      enable-log-filecount = 1;
      enable-log-linecount = 1;
      enable-blame = 1;
      enable-http-clone = 1; # show clone URL in UI

      # Public clone URL prefix shown in the cgit UI
      clone-url = "https://git.karanj.com/$CGIT_REPO_URL";

      # Syntax highlighting
      source-filter = "${pkgs.cgit}/lib/cgit/filters/syntax-highlighting.py";
      about-filter = "${pkgs.cgit}/lib/cgit/filters/about-formatting.sh";

      # Which file about-filter renders on a repo's summary page - tried in
      # order, first match wins (a list here becomes repeated `readme=`
      # lines, cgitrc's own convention for this setting).
      readme = [
        ":README.md"
        ":readme.md"
        ":README"
      ];
    };
  };

  services.nginx.virtualHosts."git.karanj.com" = {
    forceSSL = false;
    enableACME = false;
    listen = [ { addr = "127.0.0.1"; port = 8086; } ];
    # Overrides the module's own `= /cgit.css` location (set with mkDefault,
    # so any concrete value here wins) to serve cgit.css below instead of
    # cgit's stock stylesheet - same variable-driven light/dark technique as
    # ~/workspace/homepage's stylesheet, switching automatically via
    # prefers-color-scheme with no JS or toggle.
    locations."= /cgit.css".alias = "${./cgit.css}";
  };
}