--- - name: Install cgit and FastCGI dependencies ansible.builtin.apt: name: - cgit - fcgiwrap - git - python3-docutils - python3-markdown - python3-pygments state: present - name: Ensure dedicated git system group exists ansible.builtin.group: name: "{{ cgit_group }}" system: true state: present - name: Ensure dedicated git system user exists ansible.builtin.user: name: "{{ cgit_user }}" group: "{{ cgit_group }}" home: "{{ cgit_repos_path }}" shell: /usr/bin/git-shell comment: "Git version control user" system: true create_home: true state: present - name: Add www-data to git group so Nginx/fcgiwrap can read repositories ansible.builtin.user: name: www-data groups: "{{ cgit_group }}" append: true notify: Restart fcgiwrap - name: Ensure Git repositories root directory permissions (setgid for group inheritance) ansible.builtin.file: path: "{{ cgit_repos_path }}" state: directory owner: "{{ cgit_user }}" group: "{{ cgit_group }}" mode: "02750" - name: Configure git user safe.directory for cgit (www-data) ansible.builtin.copy: dest: /var/www/.gitconfig owner: www-data group: www-data mode: "0644" content: | [safe] directory = * - name: Ensure git-shell-commands directory exists (disables interactive shell login and provides helpers) ansible.builtin.file: path: "{{ cgit_repos_path }}/git-shell-commands" state: directory owner: root group: "{{ cgit_group }}" mode: "0755" - name: Deploy git-shell helper commands (no-interactive-login, init, list) ansible.builtin.copy: dest: "{{ cgit_repos_path }}/git-shell-commands/{{ item.name }}" owner: root group: "{{ cgit_group }}" mode: "0755" content: "{{ item.content }}" loop: - name: no-interactive-login content: | #!/bin/sh printf '%s\n' "Hi! You've successfully authenticated as '{{ cgit_user }}', but interactive shell access is disabled." printf '%s\n' "Tip: Run 'ssh {{ cgit_user }}@{{ primary_domain }} init .git [description]' to create a new repository." exit 128 - name: list content: | #!/bin/sh find "{{ cgit_repos_path }}" -maxdepth 2 -name "*.git" -type d -printf "%P\n" | sort - name: init content: | #!/bin/sh set -e REPO="$1" DESC="$2" if [ -z "$REPO" ]; then echo "Usage: ssh {{ cgit_user }}@{{ primary_domain }} init .git [description]" exit 1 fi case "$REPO" in *.git) ;; *) REPO="${REPO}.git" ;; esac TARGET="{{ cgit_repos_path }}/${REPO}" if [ -d "$TARGET" ]; then echo "Error: Repository ${REPO} already exists." exit 1 fi git init --bare --shared=group "$TARGET" if [ -n "$DESC" ]; then echo "$DESC" > "$TARGET/description" else echo "${REPO%.git}" > "$TARGET/description" fi echo "Initialized bare repository at {{ cgit_user }}@{{ primary_domain }}:${REPO}" - name: Ensure .ssh directory exists for git user ansible.builtin.file: path: "{{ cgit_repos_path }}/.ssh" state: directory owner: "{{ cgit_user }}" group: "{{ cgit_group }}" mode: "0700" - name: Configure authorized SSH keys for git user ansible.builtin.copy: dest: "{{ cgit_repos_path }}/.ssh/authorized_keys" owner: "{{ cgit_user }}" group: "{{ cgit_group }}" mode: "0600" content: | {% for key in cgit_ssh_authorized_keys %} {{ key }} {% endfor %} - name: Deploy /etc/cgitrc configuration ansible.builtin.template: src: cgitrc.j2 dest: /etc/cgitrc owner: root group: root mode: "0644" - name: Ensure fcgiwrap socket and service are enabled and running ansible.builtin.systemd: name: "{{ item }}" enabled: true state: started loop: - fcgiwrap.socket - fcgiwrap.service - name: Check if TLS certificate exists for {{ cgit_domain }} ansible.builtin.stat: path: "/etc/letsencrypt/live/{{ cgit_domain }}/fullchain.pem" register: cgit_tls_cert - name: Deploy Nginx virtual host for cgit ansible.builtin.template: src: site-cgit.conf.j2 dest: /etc/nginx/sites-available/cgit.conf owner: root group: root mode: "0644" notify: Reload nginx - name: Enable Nginx virtual host for cgit ansible.builtin.file: src: /etc/nginx/sites-available/cgit.conf dest: /etc/nginx/sites-enabled/cgit.conf state: link notify: Reload nginx