1 # This test runs gitlab and performs the following tests:
6 # - Creating Merge Requests and merging them
7 # - Opening and closing issues.
8 # - Downloading repository archives as tar.gz and tar.bz2
9 import ./make-test-python.nix ({ pkgs, lib, ... }:
14 inherit (import ./ssh-keys.nix pkgs) snakeOilPrivateKey snakeOilPublicKey;
15 initialRootPassword = "notproduction";
18 aliceUsername = "alice";
20 alicePassword = "alicepassword";
22 aliceProjectName = "test-alice";
26 bobPassword = "bobpassword";
30 meta = with pkgs.lib.maintainers; {
31 maintainers = [ globin yayayayaka ];
36 imports = [ common/user-account.nix ];
38 virtualisation.memorySize = if pkgs.stdenv.is64bit then 4096 else 2047;
39 virtualisation.cores = 4;
40 virtualisation.useNixStoreImage = true;
41 virtualisation.writableStore = false;
43 systemd.services.gitlab.serviceConfig.Restart = mkForce "no";
44 systemd.services.gitlab-workhorse.serviceConfig.Restart = mkForce "no";
45 systemd.services.gitaly.serviceConfig.Restart = mkForce "no";
46 systemd.services.gitlab-sidekiq.serviceConfig.Restart = mkForce "no";
50 recommendedProxySettings = true;
53 locations."/".proxyPass = "http://unix:/run/gitlab/gitlab-workhorse.socket";
58 services.openssh.enable = true;
65 systemd.services.gitlab-backup.environment.BACKUP = "dump";
69 databasePasswordFile = pkgs.writeText "dbPassword" "xo0daiF4";
70 initialRootPasswordFile = pkgs.writeText "rootPassword" initialRootPassword;
76 address = "alice@localhost";
82 # https://github.com/NixOS/nixpkgs/issues/132295
89 secretFile = pkgs.writeText "secret" "Aig5zaic";
90 otpFile = pkgs.writeText "otpsecret" "Riew9mue";
91 dbFile = pkgs.writeText "dbsecret" "we2quaeZ";
92 jwsFile = pkgs.runCommand "oidcKeyBase" {} "${pkgs.openssl}/bin/openssl genrsa 2048 > $out";
98 testScript = { nodes, ... }:
100 auth = pkgs.writeText "auth.json" (builtins.toJSON {
101 grant_type = "password";
103 password = initialRootPassword;
106 createUserAlice = pkgs.writeText "create-user-alice.json" (builtins.toJSON rec {
107 username = aliceUsername;
109 email = "alice@localhost";
110 password = alicePassword;
111 skip_confirmation = true;
114 createUserBob = pkgs.writeText "create-user-bob.json" (builtins.toJSON rec {
115 username = bobUsername;
117 email = "bob@localhost";
118 password = bobPassword;
119 skip_confirmation = true;
122 aliceAuth = pkgs.writeText "alice-auth.json" (builtins.toJSON {
123 grant_type = "password";
124 username = aliceUsername;
125 password = alicePassword;
128 bobAuth = pkgs.writeText "bob-auth.json" (builtins.toJSON {
129 grant_type = "password";
130 username = bobUsername;
131 password = bobPassword;
134 aliceAddSSHKey = pkgs.writeText "alice-add-ssh-key.json" (builtins.toJSON {
136 title = "snakeoil@nixos";
137 key = snakeOilPublicKey;
140 createProjectAlice = pkgs.writeText "create-project-alice.json" (builtins.toJSON {
141 name = aliceProjectName;
142 visibility = "public";
145 putFile = pkgs.writeText "put-file.json" (builtins.toJSON {
147 author_email = "author@example.com";
148 author_name = "Firstname Lastname";
149 content = "some content";
150 commit_message = "create a new file";
153 mergeRequest = pkgs.writeText "merge-request.json" (builtins.toJSON {
155 target_project_id = aliceProjectId;
156 source_branch = "master";
157 target_branch = "master";
158 title = "Add some other file";
161 newIssue = pkgs.writeText "new-issue.json" (builtins.toJSON {
162 title = "useful issue title";
165 closeIssue = pkgs.writeText "close-issue.json" (builtins.toJSON {
167 state_event = "close";
170 # Wait for all GitLab services to be fully started.
172 gitlab.wait_for_unit("gitaly.service")
173 gitlab.wait_for_unit("gitlab-workhorse.service")
174 # https://github.com/NixOS/nixpkgs/issues/132295
175 # gitlab.wait_for_unit("gitlab-pages.service")
176 gitlab.wait_for_unit("gitlab-mailroom.service")
177 gitlab.wait_for_unit("gitlab.service")
178 gitlab.wait_for_unit("gitlab-sidekiq.service")
179 gitlab.wait_for_file("${nodes.gitlab.config.services.gitlab.statePath}/tmp/sockets/gitlab.socket")
180 gitlab.wait_until_succeeds("curl -sSf http://gitlab/users/sign_in")
183 # The actual test of GitLab. Only push data to GitLab if
184 # `doSetup` is is true.
186 GIT_SSH_COMMAND = "ssh -o StrictHostKeyChecking=accept-new -o UserKnownHostsFile=/dev/null"
189 "curl -isSf http://gitlab | grep -i location | grep http://gitlab/users/sign_in"
192 "${pkgs.sudo}/bin/sudo -u gitlab -H gitlab-rake gitlab:check 1>&2"
195 "echo \"Authorization: Bearer $(curl -X POST -H 'Content-Type: application/json' -d @${auth} http://gitlab/oauth/token | ${pkgs.jq}/bin/jq -r '.access_token')\" >/tmp/headers"
197 '' + optionalString doSetup ''
198 with subtest("Create user Alice"):
200 """[ "$(curl -o /dev/null -w '%{http_code}' -X POST -H 'Content-Type: application/json' -H @/tmp/headers -d @${createUserAlice} http://gitlab/api/v4/users)" = "201" ]"""
203 "echo \"Authorization: Bearer $(curl -X POST -H 'Content-Type: application/json' -d @${aliceAuth} http://gitlab/oauth/token | ${pkgs.jq}/bin/jq -r '.access_token')\" >/tmp/headers-alice"
206 with subtest("Create user Bob"):
208 """ [ "$(curl -o /dev/null -w '%{http_code}' -X POST -H 'Content-Type: application/json' -H @/tmp/headers -d @${createUserBob} http://gitlab/api/v4/users)" = "201" ]"""
211 "echo \"Authorization: Bearer $(curl -X POST -H 'Content-Type: application/json' -d @${bobAuth} http://gitlab/oauth/token | ${pkgs.jq}/bin/jq -r '.access_token')\" >/tmp/headers-bob"
214 with subtest("Setup Git and SSH for Alice"):
215 gitlab.succeed("git config --global user.name Alice")
216 gitlab.succeed("git config --global user.email alice@nixos.invalid")
217 gitlab.succeed("mkdir -m 700 /root/.ssh")
218 gitlab.succeed("cat ${snakeOilPrivateKey} > /root/.ssh/id_ecdsa")
219 gitlab.succeed("chmod 600 /root/.ssh/id_ecdsa")
226 -H 'Content-Type: application/json' \
227 -H @/tmp/headers-alice -d @${aliceAddSSHKey} \
228 http://gitlab/api/v4/user/keys)" = "201" ]
232 with subtest("Create a new repository"):
233 # Alice creates a new repository
240 -H 'Content-Type: application/json' \
241 -H @/tmp/headers-alice \
242 -d @${createProjectAlice} \
243 http://gitlab/api/v4/projects)" = "201" ]
247 # Alice commits an initial commit
254 -H 'Content-Type: application/json' \
255 -H @/tmp/headers-alice \
257 http://gitlab/api/v4/projects/${aliceProjectId}/repository/files/some-file.txt)" = "201" ]"""
260 with subtest("git clone over HTTP"):
262 """git clone http://gitlab/alice/${aliceProjectName}.git clone-via-http""",
266 with subtest("Push a commit via SSH"):
268 f"""GIT_SSH_COMMAND="{GIT_SSH_COMMAND}" git clone gitlab@gitlab:alice/${aliceProjectName}.git""",
272 """echo "a commit sent over ssh" > ${aliceProjectName}/ssh.txt"""
276 cd ${aliceProjectName} || exit 1
282 cd ${aliceProjectName} || exit 1
283 git commit -m "Add a commit to be sent over ssh"
288 cd ${aliceProjectName} || exit 1
289 GIT_SSH_COMMAND="{GIT_SSH_COMMAND}" git push --set-upstream origin master
294 with subtest("Fork a project"):
295 # Bob forks Alice's project
302 -H 'Content-Type: application/json' \
303 -H @/tmp/headers-bob \
304 http://gitlab/api/v4/projects/${aliceProjectId}/fork)" = "201" ]
308 # Bob creates a commit
309 gitlab.wait_until_succeeds(
315 -H 'Content-Type: application/json' \
316 -H @/tmp/headers-bob \
318 http://gitlab/api/v4/projects/${bobProjectId}/repository/files/some-other-file.txt)" = "201" ]
322 with subtest("Create a Merge Request"):
323 # Bob opens a merge request against Alice's repository
324 gitlab.wait_until_succeeds(
330 -H 'Content-Type: application/json' \
331 -H @/tmp/headers-bob \
332 -d @${mergeRequest} \
333 http://gitlab/api/v4/projects/${bobProjectId}/merge_requests)" = "201" ]
337 # Alice merges the MR
338 gitlab.wait_until_succeeds(
344 -H 'Content-Type: application/json' \
345 -H @/tmp/headers-alice \
346 -d @${mergeRequest} \
347 http://gitlab/api/v4/projects/${aliceProjectId}/merge_requests/1/merge)" = "200" ]
351 with subtest("Create an Issue"):
352 # Bob opens an issue on Alice's repository
358 -H 'Content-Type: application/json' \
359 -H @/tmp/headers-bob \
361 http://gitlab/api/v4/projects/${aliceProjectId}/issues)" = "201" ]
365 # Alice closes the issue
366 gitlab.wait_until_succeeds(
372 -H 'Content-Type: application/json' \
373 -H @/tmp/headers-alice -d @${closeIssue} http://gitlab/api/v4/projects/${aliceProjectId}/issues/1)" = "200" ]
377 with subtest("Download archive.tar.gz"):
383 -H @/tmp/headers-alice \
384 http://gitlab/api/v4/projects/${aliceProjectId}/repository/archive.tar.gz)" = "200" ]
390 -H @/tmp/headers-alice \
391 http://gitlab/api/v4/projects/${aliceProjectId}/repository/archive.tar.gz > /tmp/archive.tar.gz
394 gitlab.succeed("test -s /tmp/archive.tar.gz")
396 with subtest("Download archive.tar.bz2"):
402 -H @/tmp/headers-alice \
403 http://gitlab/api/v4/projects/${aliceProjectId}/repository/archive.tar.bz2)" = "200" ]
409 -H @/tmp/headers-alice \
410 http://gitlab/api/v4/projects/${aliceProjectId}/repository/archive.tar.bz2 > /tmp/archive.tar.bz2
413 gitlab.succeed("test -s /tmp/archive.tar.bz2")
422 gitlab.systemctl("start gitlab-backup.service")
423 gitlab.wait_for_unit("gitlab-backup.service")
424 gitlab.wait_for_file("${nodes.gitlab.config.services.gitlab.statePath}/backup/dump_gitlab_backup.tar")
425 gitlab.systemctl("stop postgresql.service gitlab.target")
427 "find ${nodes.gitlab.config.services.gitlab.statePath} -mindepth 1 -maxdepth 1 -not -name backup -execdir rm -r {} +"
429 gitlab.succeed("systemd-tmpfiles --create")
430 gitlab.succeed("rm -rf ${nodes.gitlab.config.services.postgresql.dataDir}")
431 gitlab.systemctl("start gitlab-config.service gitaly.service gitlab-postgresql.service")
432 gitlab.wait_for_file("${nodes.gitlab.config.services.gitlab.statePath}/tmp/sockets/gitaly.socket")
434 "sudo -u gitlab -H gitlab-rake gitlab:backup:restore RAILS_ENV=production BACKUP=dump force=yes"
436 gitlab.systemctl("start gitlab.target")