diff options
| author | lassulus <lass@aidsballs.de> | 2015-07-27 10:09:13 +0200 | 
|---|---|---|
| committer | lassulus <lass@aidsballs.de> | 2015-07-27 10:09:13 +0200 | 
| commit | 54a01c0c74bdd4233962d62c4e6631f7f8b50f77 (patch) | |
| tree | 705a3f8307b49e52bd95ecac8cd6d6ca828921a4 /3modules/tv/git.nix | |
| parent | 6476abd6ac7e000d0759569a1e2754acb2f518ca (diff) | |
| parent | 3197897292f0fc8f38d30ad6ddc9742be4a7cc1d (diff) | |
Merge branch 'tv' into master
Diffstat (limited to '3modules/tv/git.nix')
| -rw-r--r-- | 3modules/tv/git.nix | 483 | 
1 files changed, 0 insertions, 483 deletions
| diff --git a/3modules/tv/git.nix b/3modules/tv/git.nix deleted file mode 100644 index 8c73d0354..000000000 --- a/3modules/tv/git.nix +++ /dev/null @@ -1,483 +0,0 @@ -{ config, pkgs, lib, ... }: - -# TODO unify logging of shell scripts to user and journal -# TODO move all scripts to ${etcDir}, so ControlMaster connections -#       immediately pick up new authenticators -# TODO when authorized_keys changes, then restart ssh -#       (or kill already connected users somehow) - -with builtins; -with lib; -let -  cfg = config.tv.git; - -  out = { -    imports = [ -      ../../3modules/tv/nginx.nix -    ]; -    options.tv.git = api; -    config = mkIf cfg.enable (mkMerge [ -      (mkIf cfg.cgit cgit-imp) -      git-imp -    ]); -  }; - -  api = { -    enable = mkEnableOption "tv.git"; - -    cgit = mkOption { -      type = types.bool; -      default = true; -      description = "Enable cgit."; # TODO better desc; talk about nginx -    }; -    dataDir = mkOption { -      type = types.str; -      default = "/var/lib/git"; -      description = "Directory used to store repositories."; -    }; -    etcDir = mkOption { -      type = types.str; -      default = "/etc/git"; -    }; -    repos = mkOption { -      type = types.attrsOf (types.submodule ({ -        options = { -          desc = mkOption { -            type = types.nullOr types.str; -            default = null; -            description = '' -              Repository description. -            ''; -          }; -          section = mkOption { -            type = types.nullOr types.str; -            default = null; -            description = '' -              Repository section. -            ''; -          }; -          name = mkOption { -            type = types.str; -            description = '' -              Repository name. -            ''; -          }; -          hooks = mkOption { -            type = types.attrsOf types.str; -            description = '' -              Repository-specific hooks. -            ''; -          }; -          public = mkOption { -            type = types.bool; -            default = false; -            description = '' -              Allow everybody to read the repository via HTTP if cgit enabled. -            ''; -            # TODO allow every configured user to fetch the repository via SSH. -          }; -        }; -      })); - -      default = {}; - -      example = literalExample '' -        { -          testing = { -            name = "testing"; -            hooks.post-update = ''' -              #! /bin/sh -              set -euf -              echo post-update hook: $* >&2 -            '''; -          }; -          testing2 = { name = "testing2"; }; -        } -      ''; - -      description = '' -        Repositories. -      ''; -    }; -    root-desc = mkOption { -      type = types.nullOr types.str; -      default = null; -      description = '' -        Text printed below the heading on the repository index page. -        Default value: "a fast webinterface for the git dscm". -      ''; -    }; -    root-title = mkOption { -      type = types.nullOr types.str; -      default = null; -      description = '' -        Text printed as heading on the repository index page. -        Default value: "Git Repository Browser". -      ''; -    }; -    rules = mkOption { -      type = types.unspecified; -    }; -    users = mkOption { -      type = types.unspecified; -    }; -  }; - -  git-imp = { -    system.activationScripts.git-init = "${init-script}"; -     -    # TODO maybe put all scripts here and then use PATH? -    environment.etc."${etc-base}".source = -      scriptFarm "git-ssh-authorizers" { -        authorize-command = makeAuthorizeScript (map ({ repo, user, perm }: [ -          (map getName (ensureList user)) -          (map getName (ensureList repo)) -          (map getName perm.allow-commands) -        ]) cfg.rules); -     -        authorize-push = makeAuthorizeScript (map ({ repo, user, perm }: [ -          (map getName (ensureList user)) -          (map getName (ensureList repo)) -          (ensureList perm.allow-receive-ref) -          (map getName perm.allow-receive-modes) -        ]) (filter (x: hasAttr "allow-receive-ref" x.perm) cfg.rules)); -      }; -     -    users.extraUsers = singleton { -      description = "Git repository hosting user"; -      name = "git"; -      shell = "/bin/sh"; -      openssh.authorizedKeys.keys = -        mapAttrsToList (_: makeAuthorizedKey git-ssh-command) cfg.users; -      uid = 129318403; # genid git -    }; -  }; - -  cgit-imp = { -    users.extraUsers = lib.singleton { -      inherit (fcgitwrap-user) group name uid; -      home = toString (pkgs.runCommand "empty" {} "mkdir -p $out"); -    }; - -    users.extraGroups = lib.singleton { -      inherit (fcgitwrap-group) gid name; -    }; - -    services.fcgiwrap = { -      enable = true; -      user = fcgitwrap-user.name; -      group = fcgitwrap-user.group; -      # socketAddress = "/run/fcgiwrap.sock" (default) -      # socketType = "unix" (default) -    }; - -    environment.etc."cgitrc".text = '' -      css=/static/cgit.css -      logo=/static/cgit.png - -      # if you do not want that webcrawler (like google) index your site -      robots=noindex, nofollow - -      virtual-root=/ - -      # TODO make this nicer (and/or somewhere else) -      cache-root=/tmp/cgit - -      cache-size=1000 -      enable-commit-graph=1 -      enable-index-links=1 -      enable-index-owner=0 -      enable-log-filecount=1 -      enable-log-linecount=1 -      enable-remote-branches=1 - -      ${optionalString (cfg.root-title != null) "root-title=${cfg.root-title}"} -      ${optionalString (cfg.root-desc != null) "root-desc=${cfg.root-desc}"} - -      snapshots=0 -      max-stats=year - -      ${concatMapStringsSep "\n" (repo: '' -        repo.url=${repo.name} -        repo.path=${cfg.dataDir}/${repo.name} -        ${optionalString (repo.section != null) "repo.section=${repo.section}"} -        ${optionalString (repo.desc != null) "repo.desc=${repo.desc}"} -      '') (filter isPublicRepo (attrValues cfg.repos))} -    ''; - -    system.activationScripts.cgit = '' -      mkdir -m 0700 -p /tmp/cgit -      chown ${toString fcgitwrap-user.uid}:${toString fcgitwrap-group.gid} /tmp/cgit -    ''; - -    tv.nginx = { -      enable = true; -      servers.cgit = { -        server-names = [ -          "cgit.${config.networking.hostName}" -          "cgit.${config.networking.hostName}.retiolum" -        ]; -        locations = [ -          (nameValuePair "/" '' -            include             ${pkgs.nginx}/conf/fastcgi_params; -            fastcgi_param       SCRIPT_FILENAME ${pkgs.cgit}/cgit/cgit.cgi; -            fastcgi_param       PATH_INFO       $uri; -            fastcgi_param       QUERY_STRING    $args; -            fastcgi_param       HTTP_HOST       $server_name; -            fastcgi_pass        unix:${config.services.fcgiwrap.socketAddress}; -          '') -          (nameValuePair "/static/" '' -            root ${pkgs.cgit}/cgit; -            rewrite ^/static(/.*)$ $1 break; -          '') -        ]; -      }; -    }; -  }; - -  fcgitwrap-user = { -    name = "fcgiwrap"; -    uid = 2867890860; # genid fcgiwrap -    group = "fcgiwrap"; -  }; - -  fcgitwrap-group = { -    name = fcgitwrap-user.name; -    gid = fcgitwrap-user.uid; -  }; - - -  ensureList = x: -    if typeOf x == "list" then x else [x]; - -  getName = x: x.name; - -  isPublicRepo = getAttr "public"; # TODO this is also in ./cgit.nix - -  makeAuthorizedKey = git-ssh-command: user@{ name, pubkey }: -    # TODO assert name -    # TODO assert pubkey -    let -      options = concatStringsSep "," [ -        ''command="exec ${git-ssh-command} ${name}"'' -        "no-agent-forwarding" -        "no-port-forwarding" -        "no-pty" -        "no-X11-forwarding" -      ]; -    in -    "${options} ${pubkey}"; - -  # [case-pattern] -> shell-script -  # Create a shell script that succeeds (exit 0) when all its arguments -  # match the case patterns (in the given order). -  makeAuthorizeScript = -    let -      # TODO escape -      to-pattern = x: concatStringsSep "|" (ensureList x); -      go = i: ps: -        if ps == [] -          then "exit 0" -          else '' -            case ''$${toString i} in ${to-pattern (head ps)}) -            ${go (i + 1) (tail ps)} -            esac''; -    in -    patterns: '' -      #! /bin/sh -      set -euf -      ${concatStringsSep "\n" (map (go 1) patterns)} -      exit -1 -    ''; - -  reponames = rules: sort lessThan (unique (map (x: x.repo.name) rules)); - -  # TODO makeGitHooks that uses runCommand instead of scriptFarm? -  scriptFarm = -    farm-name: scripts: -    let -      makeScript = script-name: script-string: { -        name = script-name; -        path = pkgs.writeScript "${farm-name}_${script-name}" script-string; -      }; -    in -    pkgs.linkFarm farm-name (mapAttrsToList makeScript scripts); - - -  git-ssh-command = pkgs.writeScript "git-ssh-command" '' -    #! /bin/sh -    set -euf - -    PATH=${makeSearchPath "bin" (with pkgs; [ -      coreutils -      git -      gnugrep -      gnused -      systemd -    ])} - -    abort() { -      echo "error: $1" >&2 -      systemd-cat -p err -t git echo "error: $1" -      exit -1 -    } - -    GIT_SSH_USER=$1 - -    systemd-cat -p info -t git echo \ -      "authorizing $GIT_SSH_USER $SSH_CONNECTION $SSH_ORIGINAL_COMMAND" - -    # References: The Base Definitions volume of -    # POSIX.1‐2013, Section 3.278, Portable Filename Character Set -    portable_filename_bre="^[A-Za-z0-9._-]\\+$" - -    command=$(echo "$SSH_ORIGINAL_COMMAND" \ -      | sed -n 's/^\([^ ]*\) '"'"'\(.*\)'"'"'/\1/p' \ -      | grep "$portable_filename_bre" \ -      || abort 'cannot read command') - -    GIT_SSH_REPO=$(echo "$SSH_ORIGINAL_COMMAND" \ -      | sed -n 's/^\([^ ]*\) '"'"'\(.*\)'"'"'/\2/p' \ -      | grep "$portable_filename_bre" \ -      || abort 'cannot read reponame') - -    ${cfg.etcDir}/authorize-command \ -        "$GIT_SSH_USER" "$GIT_SSH_REPO" "$command" \ -      || abort 'access denied' - -    repodir=${escapeShellArg cfg.dataDir}/$GIT_SSH_REPO - -    systemd-cat -p info -t git \ -      echo "authorized exec $command $repodir" - -    export GIT_SSH_USER -    export GIT_SSH_REPO -    exec "$command" "$repodir" -  ''; - -  init-script = pkgs.writeScript "git-init" '' -    #! /bin/sh -    set -euf - -    PATH=${makeSearchPath "bin" (with pkgs; [ -      coreutils -      findutils -      gawk -      git -      gnugrep -      gnused -    ])} - -    dataDir=${escapeShellArg cfg.dataDir} -    mkdir -p "$dataDir" - -    # Notice how the presence of hooks symlinks determine whether -    # we manage a repositry or not. - -    # Make sure that no existing repository has hooks.  We can delete -    # symlinks because we assume we created them. -    find "$dataDir" -mindepth 2 -maxdepth 2 -name hooks -type l -delete -    bad_hooks=$(find "$dataDir" -mindepth 2 -maxdepth 2 -name hooks) -    if echo "$bad_hooks" | grep -q .; then -      printf 'error: unknown hooks:\n%s\n' \ -        "$(echo "$bad_hooks" | sed 's/^/  /')" \ -        >&2 -      exit -1 -    fi - -    # Initialize repositories. -    ${concatMapStringsSep "\n" (repo: -      let -        hooks = scriptFarm "git-hooks" (makeHooks repo); -      in -      '' -        reponame=${escapeShellArg repo.name} -        repodir=$dataDir/$reponame -        mode=${toString (if isPublicRepo repo then 0711 else 0700)} -        if ! test -d "$repodir"; then -          mkdir -m "$mode" "$repodir" -          git init --bare --template=/var/empty "$repodir" -          chown -R git:nogroup "$repodir" -        fi -        ln -s ${hooks} "$repodir/hooks" -      '' -    ) (attrValues cfg.repos)} - -    # Warn about repositories that exist but aren't mentioned in the -    # current configuration (and thus didn't receive a hooks symlink). -    unknown_repos=$(find "$dataDir" -mindepth 1 -maxdepth 1 \ -      -type d \! -exec test -e '{}/hooks' \; -print) -    if echo "$unknown_repos" | grep -q .; then -      printf 'warning: stale repositories:\n%s\n' \ -        "$(echo "$unknown_repos" | sed 's/^/  /')" \ -        >&2 -    fi -  ''; - -  makeHooks = repo: removeAttrs repo.hooks [ "pre-receive" ] // { -    pre-receive = '' -      #! /bin/sh -      set -euf - -      PATH=${makeSearchPath "bin" (with pkgs; [ -        coreutils # env -        git -        systemd -      ])} - -      accept() { -        #systemd-cat -p info -t git echo "authorized $1" -        accept_string="''${accept_string+$accept_string -      }authorized $1" -      } -      reject() { -        #systemd-cat -p err -t git echo "denied $1" -        #echo 'access denied' >&2 -        #exit_code=-1 -        reject_string="''${reject_string+$reject_string -      }access denied: $1" -      } - -      empty=0000000000000000000000000000000000000000 - -      accept_string= -      reject_string= -      while read oldrev newrev ref; do - -        if [ $oldrev = $empty ]; then -          receive_mode=create -        elif [ $newrev = $empty ]; then -          receive_mode=delete -        elif [ "$(git merge-base $oldrev $newrev)" = $oldrev ]; then -          receive_mode=fast-forward -        else -          receive_mode=non-fast-forward -        fi - -        if ${cfg.etcDir}/authorize-push \ -            "$GIT_SSH_USER" "$GIT_SSH_REPO" "$ref" "$receive_mode"; then -          accept "$receive_mode $ref" -        else -          reject "$receive_mode $ref" -        fi -      done - -      if [ -n "$reject_string" ]; then -        systemd-cat -p err -t git echo "$reject_string" -        exit -1 -      fi - -      systemd-cat -p info -t git echo "$accept_string" - -      ${optionalString (hasAttr "post-receive" repo.hooks) '' -        # custom post-receive hook -        ${repo.hooks.post-receive}''} -    ''; -  }; - -  etc-base = -    assert (hasPrefix "/etc/" cfg.etcDir); -    removePrefix "/etc/" cfg.etcDir; - -in -out | 
