Author | zPlus <zplus@peers.community> 2022-07-28 11:10:19 |
Committer | zPlus <zplus@peers.community> 2022-07-28 11:10:19 |
Commit | bcc46e1 (patch) |
Tree | 5d56a4c |
Parent(s) |
-rw-r--r-- | README | 151 | ||
-rw-r--r-- | documentation/administrators | 14 | ||
-rw-r--r-- | documentation/developers | 3 | ||
-rw-r--r-- | documentation/installation | 134 | ||
-rw-r--r-- | documentation/users | 72 | ||
-rw-r--r-- | templates/about.html | 37 | ||
-rw-r--r-- | web.py | 4 |
index cb4bfb2..c746ade | |||
old size: 4K - new size: 79B | |||
@@ -1,149 +1,4 @@ | |||
1 | - | # Installation | |
2 | - | ||
3 | - | 1. Install Gitolite | |
4 | - | ||
5 | - | Follow instructions at https://gitolite.com/gitolite/fool_proof_setup.html | |
6 | - | When Gitolite is installed, clone the gitolite-admin repository and add this to | |
7 | - | conf/gitolite.conf: | |
8 | - | ||
9 | - | repo CREATOR/..* | |
10 | - | C = @all | |
11 | - | RW+ = CREATOR | |
12 | - | R = @all | |
13 | - | ||
14 | - | The rule above will allow any registered user (@all) to create a repository. CREATOR | |
15 | - | is a gitolite keywords and it's replaced with the username who created the repo. | |
16 | - | To create a new repository, just use "git clone git@domain:username/reponame". | |
17 | - | Since the regexp CREATOR/..* will replace CREATOR with the user name, the logged | |
18 | - | in user will be allowed to create new repositories *only* under their username. | |
19 | - | ||
20 | - | Adding new users is as simple as adding their key to gitolite-admin/keydir/<username>.pub | |
21 | - | ||
22 | - | Gitolite does not do authentication, it only does authorization. The name of the | |
23 | - | logged in user is provided as an environment variable. In order to allow anonymous | |
24 | - | HTTP clones, ie. for allowing "git clone https://..." without any authentication, | |
25 | - | the web app automatically sets a generic username value of "anonymous". We need | |
26 | - | to let Gitolite know what the unauthenticated user is going to be called so that | |
27 | - | it can check authorization. To do this, just add the following to ~/.gitolite.rc | |
28 | - | in the section marked "rc variables used by various features". This is explained | |
29 | - | at https://gitolite.com/gitolite/http.html#allowing-unauthenticated-access | |
30 | - | ||
31 | - | HTTP_ANON_USER => 'anonymous', | |
32 | - | ||
33 | - | Enable some non-core commands that are useful to us. This is done by editing ~/.gitolite.rc: | |
34 | - | ||
35 | - | 'ENABLE' => [ | |
36 | - | ... existing commands | |
37 | - | ||
38 | - | # Allow to change HEAD reference (default branch) like this: | |
39 | - | # ssh git@host symbolic-ref <repo> HEAD refs/heads/<name> | |
40 | - | 'symbolic-ref', | |
41 | - | ] | |
42 | - | ||
43 | - | ||
44 | - | 2. Emails | |
45 | - | ||
46 | - | Start by downloading the clif repository: | |
47 | - | ||
48 | - | git clone <clif-url> /home/git | |
49 | - | ||
50 | - | Change the settings inside the emails.py file. | |
51 | - | ||
52 | - | Add the following to /etc/postfix/main.cf. This will forward all emails to the | |
53 | - | system user "git" | |
54 | - | ||
55 | - | luser_relay = git | |
56 | - | local_recipient_maps = | |
57 | - | ||
58 | - | Then add the following to /home/git/.forward. ".forward" is a sendmail file, also | |
59 | - | used by postfix, used for deciding how to deliver the message the the system user. | |
60 | - | For our purposes, we instruct postfix to pipe all the emails for user "git" to our | |
61 | - | script: | |
62 | - | ||
63 | - | |/home/git/clif/emails.py | |
64 | - | ||
65 | - | make sure the script is executable: | |
66 | - | ||
67 | - | chmod +x /home/git/clif/emails.py | |
68 | - | ||
69 | - | 3. Web UI | |
70 | - | ||
71 | - | Start by downloading the clif repository: | |
72 | - | ||
73 | - | git clone <clif-url> /home/git | |
74 | - | ||
75 | - | Install the requirements: | |
76 | - | ||
77 | - | cd /home/git/clif | |
78 | - | python3 -m venv venv | |
79 | - | source venv/bin/activate | |
80 | - | pip install -r requirements.txt | |
81 | - | ||
82 | - | Change the settings inside the web.py file. | |
83 | - | ||
84 | - | Install a SystemD service: | |
85 | - | ||
86 | - | cp web.service /etc/systemd/system/clif-web.service | |
87 | - | systemctl daemon-reload | |
88 | - | systemctl enable clif-web | |
89 | - | systemctl start clif-web | |
90 | - | ||
91 | - | 4. TLS certificate | |
92 | - | ||
93 | - | Now we create a new TLS certificate for supporting HTTPS connections: | |
94 | - | ||
95 | - | apt-get install certbot | |
96 | - | certbot certonly --webroot -w /var/www/html -d domain.tld | |
97 | - | ||
98 | - | The cert is created in /etc/letsencrypt/live/<domain.tld>/ | |
99 | - | ||
100 | - | Lighttpd requires the certificate and private key to be in a single file: | |
101 | - | ||
102 | - | cat privkey.pem cert.pem > privkey+cert.pem | |
103 | - | ||
104 | - | Configure lighttpd reverse proxy: | |
105 | - | ||
106 | - | vim /etc/lighttpd/lighttpd.conf | |
107 | - | ||
108 | - | server.modules += ( | |
109 | - | "mod_fastcgi", | |
110 | - | "mod_proxy", | |
111 | - | ) | |
112 | - | ||
113 | - | $HTTP["scheme"] == "http" { | |
114 | - | url.redirect = ("" => "https://${url.authority}${url.path}${qsa}") | |
115 | - | url.redirect-code = 308 | |
116 | - | } | |
117 | - | ||
118 | - | $SERVER["socket"] == ":443" { | |
119 | - | ssl.engine = "enable" | |
120 | - | ssl.pemfile = "/etc/letsencrypt/live/<domain.tld>/privkey+cert.pem" | |
121 | - | ssl.ca-file = "/etc/letsencrypt/live/<domain.tld>/chain.pem" | |
122 | - | ||
123 | - | $HTTP["host"] == "<domain.tld>" { | |
124 | - | proxy.server = ( | |
125 | - | "" => ( | |
126 | - | ( "host" => "127.0.0.1", "port" => 5000 ) | |
127 | - | ) | |
128 | - | ) | |
129 | - | # server.document-root = "/var/www/html" # Document Root | |
130 | - | # server.errorlog = "/" | |
131 | - | # accesslog.filename = "/" | |
132 | - | } | |
133 | - | } | |
134 | - | ||
135 | - | Let's Encrypt certificates expire every 90 days, so we need to setup a cron job | |
136 | - | that will generate a new privkey+cert.pem file, and reload lighttpd too. | |
137 | - | ||
138 | - | vim /etc/cron.weekly/clif-letsencrypt | |
139 | - | chmod +x /etc/cron.weekly/clif-letsencrypt | |
140 | - | ||
141 | - | certbot renew | |
142 | - | cd /etc/letsencrypt/live/<domain.tld> | |
143 | - | cat privkey.pem cert.pem > privkey+cert.pem | |
144 | - | service lighttpd restart | |
145 | - | ||
146 | - | # Development | |
147 | - | ||
148 | - | gunicorn --reload --bind localhost:5000 web:application | |
1 | + | CLI Forge | |
2 | + | ========= | |
149 | 3 | ||
4 | + | Documentation is available in the "documentation" folder. |
index 0000000..6d56364 | |||
old size: 0B - new size: 333B | |||
new file mode: -rw-r--r-- |
@@ -0,0 +1,14 @@ | |||
1 | + | # Adding new users | |
2 | + | ||
3 | + | 1. Clone gitolite-admin.git repository | |
4 | + | 2. Add user key into gitolite-admin/keydir/<username>.pub | |
5 | + | ||
6 | + | # Assign namespaces to users | |
7 | + | ||
8 | + | 1. Clone gitolite-admin.git repository | |
9 | + | 2. Add rule into gitolite-admin/conf/gitolite.conf | |
10 | + | ||
11 | + | repo namespace/..* | |
12 | + | C = username | |
13 | + | RW+ = username | |
14 | + | R = @all |
index 0000000..78fa605 | |||
old size: 0B - new size: 75B | |||
new file mode: -rw-r--r-- |
@@ -0,0 +1,3 @@ | |||
1 | + | # Test server | |
2 | + | ||
3 | + | gunicorn --reload --bind localhost:5000 web:application |
index 0000000..0fdaee7 | |||
old size: 0B - new size: 4K | |||
new file mode: -rw-r--r-- |
@@ -0,0 +1,134 @@ | |||
1 | + | Gitolite | |
2 | + | ------------------------------------------------------------------------------- | |
3 | + | ||
4 | + | Follow instructions at https://gitolite.com/gitolite/fool_proof_setup.html | |
5 | + | ||
6 | + | TL;DR: | |
7 | + | su - git | |
8 | + | git clone https://github.com/sitaramc/gitolite | |
9 | + | gitolite/install -to $HOME/bin | |
10 | + | $HOME/bin/gitolite setup -pk <admin_key>.pub | |
11 | + | ||
12 | + | Gitolite does not do authentication, it only does authorization. The name of the | |
13 | + | logged in user is provided as an environment variable. In order to allow anonymous | |
14 | + | HTTP clones, ie. for allowing "git clone https://..." without any authentication, | |
15 | + | the web app automatically sets a generic username value of "anonymous". We need | |
16 | + | to let Gitolite know what the unauthenticated user is going to be called so that | |
17 | + | it can check authorization. To do this, just add the following to ~/.gitolite.rc | |
18 | + | in the section marked "rc variables used by various features". This is explained | |
19 | + | at https://gitolite.com/gitolite/http.html#allowing-unauthenticated-access | |
20 | + | ||
21 | + | HTTP_ANON_USER => 'anonymous', | |
22 | + | ||
23 | + | Enable some non-core commands that are useful to us. This is done by editing ~/.gitolite.rc: | |
24 | + | ||
25 | + | 'ENABLE' => [ | |
26 | + | ... existing commands | |
27 | + | ||
28 | + | # Allow to change HEAD reference (default branch) like this: | |
29 | + | # ssh git@host symbolic-ref <repo> HEAD refs/heads/<name> | |
30 | + | 'symbolic-ref', | |
31 | + | ] | |
32 | + | ||
33 | + | ||
34 | + | ||
35 | + | ||
36 | + | Web UI | |
37 | + | ------------------------------------------------------------------------------- | |
38 | + | ||
39 | + | The CLIF repository is assumed to having been cloned into /home/git/clif. | |
40 | + | ||
41 | + | 1. There are a couple of settings at the top of web.py. Change them. | |
42 | + | ||
43 | + | 2. Install the Python dependencies: | |
44 | + | ||
45 | + | cd /home/git/clif | |
46 | + | python3 -m venv venv | |
47 | + | venv/bin/pip install -r requirements.txt | |
48 | + | ||
49 | + | 3. Install a SystemD service for controlling the UI: | |
50 | + | ||
51 | + | cp web.service /etc/systemd/system/clif-web.service | |
52 | + | systemctl daemon-reload | |
53 | + | systemctl enable clif-web | |
54 | + | systemctl start clif-web | |
55 | + | ||
56 | + | ||
57 | + | ||
58 | + | ||
59 | + | Mailing Lists | |
60 | + | ------------------------------------------------------------------------------- | |
61 | + | ||
62 | + | 1. There are a couple of settings at the top of emails.py. Change them. | |
63 | + | ||
64 | + | 2. Add the following to /etc/postfix/main.cf. This will forward all emails to the | |
65 | + | system user "git" | |
66 | + | ||
67 | + | luser_relay = git | |
68 | + | local_recipient_maps = | |
69 | + | ||
70 | + | 3. Create the file /home/git/.forward with the content: | |
71 | + | ||
72 | + | |/home/git/clif/emails.py | |
73 | + | ||
74 | + | This is a sendmail file, also used by postfix, for deciding how incoming messages | |
75 | + | shall be delivered to the the system user. For our purposes, we instruct postfix | |
76 | + | to pipe all the emails for user "git" to our script. Make sure the script is | |
77 | + | executable. | |
78 | + | ||
79 | + | ||
80 | + | ||
81 | + | ||
82 | + | Let's Encrypt certificate | |
83 | + | ------------------------------------------------------------------------------- | |
84 | + | ||
85 | + | apt-get install certbot | |
86 | + | certbot certonly --webroot -w /var/www/html -d your-domain.tld | |
87 | + | ||
88 | + | The cert is created in /etc/letsencrypt/live/<your-domain.tld>/ | |
89 | + | ||
90 | + | Lighttpd requires the certificate and private key to be in a single file: | |
91 | + | ||
92 | + | cat privkey.pem cert.pem > privkey+cert.pem | |
93 | + | ||
94 | + | Configure lighttpd reverse proxy: | |
95 | + | ||
96 | + | vim /etc/lighttpd/lighttpd.conf | |
97 | + | ||
98 | + | server.modules += ( | |
99 | + | "mod_fastcgi", | |
100 | + | "mod_proxy", | |
101 | + | ) | |
102 | + | ||
103 | + | $HTTP["scheme"] == "http" { | |
104 | + | url.redirect = ("" => "https://${url.authority}${url.path}${qsa}") | |
105 | + | url.redirect-code = 308 | |
106 | + | } | |
107 | + | ||
108 | + | $SERVER["socket"] == ":443" { | |
109 | + | ssl.engine = "enable" | |
110 | + | ssl.pemfile = "/etc/letsencrypt/live/<your-domain.tld>/privkey+cert.pem" | |
111 | + | ssl.ca-file = "/etc/letsencrypt/live/<your-domain.tld>/chain.pem" | |
112 | + | ||
113 | + | $HTTP["host"] == "<your-domain.tld>" { | |
114 | + | proxy.server = ( | |
115 | + | "" => ( | |
116 | + | ( "host" => "127.0.0.1", "port" => 5000 ) | |
117 | + | ) | |
118 | + | ) | |
119 | + | # server.document-root = "/var/www/html" # Document Root | |
120 | + | # server.errorlog = "/" | |
121 | + | # accesslog.filename = "/" | |
122 | + | } | |
123 | + | } | |
124 | + | ||
125 | + | Let's Encrypt certificates expire every 90 days, so we need to setup a cron job | |
126 | + | that will generate a new privkey+cert.pem file, and reload lighttpd too. | |
127 | + | ||
128 | + | vim /etc/cron.weekly/clif-letsencrypt | |
129 | + | chmod +x /etc/cron.weekly/clif-letsencrypt | |
130 | + | ||
131 | + | certbot renew | |
132 | + | cd /etc/letsencrypt/live/<your-domain.tld> | |
133 | + | cat privkey.pem cert.pem > privkey+cert.pem | |
134 | + | service lighttpd restart |
index 0000000..93db852 | |||
old size: 0B - new size: 2K | |||
new file mode: -rw-r--r-- |
@@ -0,0 +1,72 @@ | |||
1 | + | General usage | |
2 | + | ------------------------------------------------------------------------------- | |
3 | + | ||
4 | + | # List of available commands over SSH | |
5 | + | ||
6 | + | ssh git@example.org help | |
7 | + | ||
8 | + | # List of user repositories and access permissions | |
9 | + | ||
10 | + | ssh git@example.org info | |
11 | + | ||
12 | + | ||
13 | + | ||
14 | + | ||
15 | + | Repositories | |
16 | + | ------------------------------------------------------------------------------- | |
17 | + | ||
18 | + | # Cloning a repository anonymously | |
19 | + | ||
20 | + | git clone https://example.org/repository.git | |
21 | + | ||
22 | + | # Cloning a repository as registered users | |
23 | + | ||
24 | + | git clone git@example.org:repository | |
25 | + | ||
26 | + | # Creating a new repository | |
27 | + | Either clone, or push to, a nonexistent repository. It will be initiated automatically | |
28 | + | as long as the user has write permission. | |
29 | + | ||
30 | + | git clone git@example.org:repository | |
31 | + | git push git@example.org:repository master | |
32 | + | ||
33 | + | # Pushing to a repository | |
34 | + | ||
35 | + | git push git@example.org:repository.git | |
36 | + | ||
37 | + | # Change default branch by repoint HEAD to other branches | |
38 | + | ||
39 | + | ssh git@example.org symbolic-ref repository.git HEAD refs/heads/main | |
40 | + | ||
41 | + | # Delete repository (D command) | |
42 | + | ||
43 | + | ssh git@example.org D unlock <repository> | |
44 | + | ssh git@example.org D rm <repository> | |
45 | + | ||
46 | + | ||
47 | + | ||
48 | + | ||
49 | + | Mailing lists | |
50 | + | ------------------------------------------------------------------------------- | |
51 | + | ||
52 | + | Mailing lists are where collaboration happens, and they are stored in repositories | |
53 | + | too. | |
54 | + | ||
55 | + | # Create a new mailing list | |
56 | + | ||
57 | + | Create a new repository with the suffix ".mlist": | |
58 | + | ||
59 | + | git clone git@example.org:project.mlist | |
60 | + | ||
61 | + | CLIF will then begin accepting emails for project@example.org and store them | |
62 | + | inside the "project.mlist" repository. | |
63 | + | ||
64 | + | # New threads | |
65 | + | ||
66 | + | New threads are created simply by sending a new email to the list address. An account | |
67 | + | is not required for starting new threads and participating in discussions. | |
68 | + | ||
69 | + | # Join an existing thread | |
70 | + | ||
71 | + | It is possible to join an existing thread by sending an email containing the header | |
72 | + | "In-Reply-To: <Message-ID>", where <Message-ID> is the ID value of any previous message. |
index 6274389..3be41ba | |||
old size: 2K - new size: 821B | |||
@@ -10,47 +10,20 @@ | |||
10 | 10 | ||
11 | 11 | <p> | |
12 | 12 | This is a place for collaborative software development. It offers hosting for | |
13 | - | Git repositories and mailing lists, and it aims at being entirely usable from | |
13 | + | Git repositories and mailing lists, while aiming at being entirely usable from | |
14 | 14 | your CLI by leveraging existing tools and an email-driven workflow. | |
15 | - | Read on for a quick introduction to using this instace. | |
16 | 15 | </p> | |
17 | 16 | ||
18 | 17 | <br /> | |
19 | 18 | ||
20 | 19 | <p> | |
21 | - | <i>New users</i> | |
22 | - | <br /> | |
23 | - | You only need an account if you wish to host your repositories on this instance. | |
24 | - | Collaboration is done on mailing lists and you don't need an account for that. | |
25 | - | When new users join the instance, they are automatically assigned the namespace | |
26 | - | <code>/<username></code> under which they can add new repositories.<br /> | |
27 | - | Since this instance is still under testing it is not currently open for public | |
28 | - | registrations, but you can still get an account by asking in #peers at irc.libera.chat. | |
20 | + | Documentation about using CLIF is available for both users and administrators | |
21 | + | in the <a href="https://clif.peers.community/zplus/clif.git">CLIF repository</a>. | |
29 | 22 | </p> | |
30 | 23 | ||
31 | 24 | <p> | |
32 | - | <i>Adding repositories</i> | |
33 | - | <br /> | |
34 | - | If you have an account, you can use CLIF as a remote for sharing your repositories. | |
35 | - | Simply running <code>git clone git@{{ domain }}:<namespace>/<repository></code> | |
36 | - | will create a new empty repository that you can add to your list of remotes. | |
37 | - | </p> | |
38 | - | ||
39 | - | <p> | |
40 | - | <i>Mailing lists</i> | |
41 | - | <br /> | |
42 | - | Mailing lists are where collaboration happens, and they are stored in repositories | |
43 | - | too. All you have to do in order to create a new mailing list is to create | |
44 | - | a new repository with the suffix <code>.mlist</code>, for example | |
45 | - | <code>git clone git@{{ domain }}:alice/project.mlist</code>. CLIF then will | |
46 | - | begin accepting emails for <code>alice/project@{{ domain }}</code> and store | |
47 | - | them inside the <code>alice/project.mlist</code> repository. | |
48 | - | <br /> | |
49 | - | New threads are created simply by sending a new email to the list address. | |
50 | - | An account is not required. | |
51 | - | It is also possible to join an existing thread by sending an email containing | |
52 | - | the header <code>In-Reply-To: <Message-ID></code>, where <code>Message-ID</code> | |
53 | - | is the ID value of any previous message. | |
25 | + | This instance is still under testing and it is not currently open for public | |
26 | + | registration, but you can still get an account by asking in #peers at irc.libera.chat. | |
54 | 27 | </p> | |
55 | 28 | ||
56 | 29 | {% endblock %} |
index 879b5c9..771b355 | |||
old size: 21K - new size: 21K | |||
@@ -50,6 +50,10 @@ INSTANCE_DOMAIN = 'domain.local' | |||
50 | 50 | ############################################################################### | |
51 | 51 | ||
52 | 52 | def list_repositories(): | |
53 | + | """ | |
54 | + | Scan GITOLITE_REPOSITORIES_ROOT for Git repositories, and return a list of them. | |
55 | + | """ | |
56 | + | ||
53 | 57 | repositories = [] | |
54 | 58 | ||
55 | 59 | # When topdown is True, the caller can modify the dirnames list in-place and |