Knowledge Base

Preserving for the future: Shell scripts, AoC, and more

Cgit solution for my network

History

Experimentation using gitweb and cgit was carried out on d2-02a at some point before 2020-10. Cgit on Devuan (d2-02a) was examined after investigating a key Stackoverflow post and determined to meet my needs.

Overview

Git-scm itself provides native mechanisms to allow operations through http, and basic Apache httpd configuration examples abound. Adding a decent web frontend with cgit is a small additional step. This setup also uses Apache httpd basic auth to limit read and write access to the true git projects, but not the cgit simple http clone operations.

Prerequisites

Apache httpd is installed. TLS certificate exists and is already in use.

Installing entire cgit solution

Installing and configuring cgit

Install cgit from stackrpms repo for el8, which uses https://src.fedoraproject.org/fork/tmz/rpms/cgit or https://src.fedoraproject.org/forks/tmz/rpms/cgit.git to build the rpm. Tmz is the Fedora maintainer of this package, so his adaptation of it for el8 is trustworthy.

sudo dnf install cgit

Modify /etc/cgitrc with my own customizations. See internal file /mnt/public/Support/Programs/cgit/files/cgitrc for the original configuration. Install a few dependencies. Python3-markdown is also from stackrpms for el8, because I had to build it on my copr, also from its source https://src.fedoraproject.org/rpms/python-markdown.

sudo dnf install python3-pygments python3-markdown

These dependencies support displaying markdown (.md) files as the cgit and repo "about" pages. I tend to use markdown for these types of files. Copy in a logo file for myself to /usr/share/cgit/bgstack15_64.png. The top-level readme file is configured in the example cgitrc to /var/www/git/readme.md

Configuring httpd

Set up file /etc/git_access.conf with snippets that will be included by the httpd config. This file will control access to the git repositories over git itself, not the cgit web presentation.

# File /etc/git_access.conf
# Part of cgit solution for Mersey network, 2021-04-15
# The last phrase can be "all granted" to allow anybody to read.
# Use httpd "Require" strings for param2, param3. Param2 grants read/write permission, Param3 is read-only.
#Use Project dirname "user alice bob charlie" "all granted"
#Use Project dirname "user charlie" "user bob alice"

Use Project certreq "user bgstack15" "all granted"

In the above example, the "certreq" is a project name (directory name under /var/www/git). The second and third parameters, the "user bgstack15" and "all granted" will be passed to Apache "Require" directives. They represent "read- write access" and "read-only access" respectively. Apache interprets the example, resolved "Required all granted" as anonymous read access is allowed. One of the main operations described under the Operations heading below is adding new entries to this list of projects. Set up file /etc/gitweb.conf which is traditionally for gitweb, a different implementation of serving git repos over http, but can also be used here.

$export_auth_hook = sub {
    my $repo = shift;
    my $user = $cgi->remote_user;
    if($repo =~ s/\/var\/www\/git\///) {
        open FILE, '/etc/git_access.conf'; 
        while(<FILE>) {
            if ($_ =~ m/Use Project $repo \"(.*)\" \"(.*)\"/)
            {
                my $users = $1 . ' ' . $2;
                $users =~ s/all granted/$user/;
                $users =~ s/user//;
                if ( $users =~ m/$user/ ) {
                    return 1;
                }
            }              
        }
    }
    return 0;
};

I do not understand this perl file: It came straight from reference 2. Set up file /etc/git_access with htpasswd(1).

sudo htpasswd -c /etc/git_access bgstack15

Set up file /etc/httpd/conf.d/cgit.conf with modifications. This file is laid down by the cgit rpm, but might need some adjustments. The exact contents as of the time of this writing are the following.

Alias /cgit-data /usr/share/cgit
ScriptAlias /cgit /var/www/cgi-bin/cgit
RedirectMatch ^/cgit$ /git/
<Directory "/usr/share/cgit/">
    AllowOverride None
    Require all granted
</Directory>

Set up the apache virtualhost. For server storage1, this means modifying extant file /etc/httpd/conf.d/local_mirror.conf. Inside the main VirtualHost definition (the port 80 one), add contents:

# cgit + git. See /mnt/public/Support/Programs/cgit/cgit-README.md
SetEnv GIT_PROJECT_ROOT /var/www/git
SetEnv GIT_HTTP_EXPORT_ALL
SetEnv REMOTE_USER=$REDIRECT_REMOTE_USER
SetEnv GITWEB_CONFIG /etc/gitweb.conf

ScriptAlias /git/ /usr/libexec/git-core/git-http-backend/
<Directory "/usr/libexec/git-core*">
    Options +ExecCGI +Indexes
    Order allow,deny
    Allow from all
    Require all granted
</Directory>

# a2enmod macro # for Devuan
<Macro Project $repository $rwstring $rostring>
    <LocationMatch "^/git/$repository.*$">
        AuthType Basic
        AuthName "Git Access"
        AuthUserFile /etc/git_access
        Require $rwstring
        Require $rostring
    </LocationMatch>
    <LocationMatch "^/git/$repository/git-receive-pack$">
        AuthType Basic
        AuthName "Git Access"
        AuthUserFile /etc/git_access
        Require $rwstring
    </LocationMatch>
</Macro>
# Devuan apache2 works with IncludeOptional but EL8 httpd doesn't work with it.
Include /etc/git_access.conf

# https://ic3man5.wordpress.com/2013/01/26/installing-cgit-on-debian/
# depends on conf-enabled/cgit.conf (available as cgit.conf.devuan)
<Directory "/usr/share/cgit/">
    SetEnv CGIT_CONFIG /etc/cgitrc
    SetEnv GIT_URL cgit
    AllowOverride all
    Options +ExecCGI +FollowSymLinks +Indexes
    DirectoryIndex cgit.cgi
    AddHandler cgi-script .cgi
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule (.*) /cgit/cgit.cgi/$1 [END,QSA]
</Directory>

After making changes to these files, test (sudo httpd -t), and then reload or restart httpd.

Configure SELinux

I used the standard mechanisms to troubleshoot SELinux.

sudo setenforce 0
semodule --disable_dontaudit --build
echo "" | sudo tee /var/log/audit/audit.log 1>/dev/null
# perform a large number of git and cgit operations
sudo tail -n15000 /var/log/audit/audit.log | audit2allow -M foo
# manually merge any new entries into cgitmersey.te
semodule --build
_func() {sudo checkmodule -M -m -o cgitmersey.mod cgitmersey.te && sudo semodule_package -o cgitmersey.pp -m cgitmersey.mod && sudo semodule -i cgitmersey.pp ; } ; time _func

Final asset is cgitmersey.te which can be loaded and installed with the last line of the above command block.

module cgitmersey 1.0;

require {
type git_script_t;
type httpd_t;
type httpd_cache_t;
type var_t;
class process { noatsecure rlimitinh siginh };
class file { getattr map open read };
class dir { getattr open read search };
}

#============= git_script_t ==============
allow git_script_t var_t:dir read;
allow git_script_t var_t:file { read getattr open };
allow git_script_t httpd_cache_t:dir { getattr open read search };
allow git_script_t httpd_cache_t:file { map getattr open read };

#============= httpd_t ==============
allow httpd_t git_script_t:process { noatsecure rlimitinh siginh };

Populating cgit with my content

See separate blog post Populating my New Cgit Instance for this whole task.

Summary of associated files

  • /etc/gitweb.conf
  • /usr/share/cgit/bgstack15_64.png
  • /etc/git_access.conf
  • /etc/git_access
  • /etc/cgitrc

    cache-size=300
    

    clone-prefix=https://www.example.com/git css=/cgit-data/cgit.css

    Disable owner on index page

    enable-index-owner=0 enable-index-links=1

    Allow http transport git clone

    enable-http-clone=1

    Show extra links for each repository on the index page

    enable-index-links=0

    Enable blame page and create links to it from tree page

    enable-blame=0

    Enable ASCII art commit history graph on the log pages

    enable-commit-graph=0

    Show number of affected files per commit on the log pages

    enable-log-filecount=0

    Show number of added/removed lines per commit on the log pages

    enable-log-linecount=0

    Sort branches by age or name

    branch-sort=name

    favicon=/favicon.ico

    Use a custom logo

    logo=/cgit-data/bgstack15_64.png

    Enable statistics per week, month, quarter, or year

    max-stats=

    Set the title and heading of the repository index page

    root-title=Stackrpms git root-readme=/var/www/git/readme.md root-desc=Bgstack15 local repos

    Allow download of tar.gz, tar.bz2 and zip-files

    snapshots=tar.gz tar.bz2 zip mimetype.gif=image/gif mimetype.html=text/html mimetype.jpg=image/jpeg mimetype.jpeg=image/jpeg mimetype.pdf=application/pdf mimetype.png=image/png mimetype.svg=image/svg+xml

    Enable syntax highlighting (requires the highlight package)

    source-filter=/usr/libexec/cgit/filters/syntax-highlighting.sh

    Format markdown, restructuredtext, manpages, text files, and html files

    through the right converters

    about-filter=/usr/libexec/cgit/filters/about-formatting.sh readme=:README.md readme=:readme.md readme=:README.mkd readme=:readme.mkd readme=:README.rst readme=:readme.rst readme=:README.html readme=:readme.html readme=:README.htm readme=:readme.htm readme=:README.txt readme=:readme.txt readme=:README readme=:readme readme=:INSTALL.md readme=:install.md readme=:INSTALL.mkd readme=:install.mkd readme=:INSTALL.rst readme=:install.rst readme=:INSTALL.html readme=:install.html readme=:INSTALL.htm readme=:install.htm readme=:INSTALL.txt readme=:install.txt readme=:INSTALL readme=:install section-from-path=1 enable-subject-links=1 virtual-root=/cgit/ scan-path=/var/www/git/

  • /etc/httpd/conf.d/cgit.conf

  • /var/www/git/readme.md
  • /mnt/public/Support/Programs/cgit/cgitmersey.te

Operations

Some useful operations are described here.

Making a new project

To set up a new project that can receive pushes, you need to initialize a new git bare repo. Make the "newname" project in /var/www/git, and grant access to the apache user.

cd /var/www/git ; git init --bare newname ; sudo chgrp apache -R newname

Set up permissions for the new project in /etc/git_access.conf. For example:

Use Project "newname" "user adminuser1 adminuser2 adminuser3" "user1 user2 user3"

After making changes, ensure httpd accepts the new config (because it loads /etc/git_access.conf as an included file), and then reload httpd.

sudo httpd -t
sudo systemctl reload httpd

Changing cgit-related attributes of a project

Cgit can be configured to read a file named cgitrc within a git repository. I tend to use just the top directory of these bare git repos, so for project certreq, use /var/www/git/certreq/cgitrc. See cgitrc(5) for more info, but a brief list of useful attributes (var=value) include: defbranch, desc, hide, homepage, ignore, logo, name, owner, readme, section, url. For the description of a repo that appears in the main index, use regular file in a git bare repo: description.

Adding a new user

Use regular htpasswd mechanism to add users or change passwords. See htpasswd(1).

htpasswd /etc/git_access bgstack15

Removing a project

Just delete the project directory.

Changing cgitrc values

Changing cgitrc values take effect immediately (when caching is set to 0); no httpd reload is necessary.

References

  1. https://stackoverflow.com/questions/26734933/how-to-set-up-git-over-http git_access.conf
  2. https://stackoverflow.com/a/50317063/3569534 /etc/gitweb.conf and httpd.conf macro and other snippets
  3. https://stackoverflow.com/questions/40924641/setting-up-git-http-backend-with-apache-2-4
  4. https://stackoverflow.com/a/2200662/3569534 had to convert my sample project to a bare git one

Auxiliary reading

  1. https://ic3man5.wordpress.com/2013/01/26/installing-cgit-on-debian/

Alternatives

added 2022-01-18
  1. Shreyas Minocha's Replacing Gitea

Comments