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
10 # [nixpkgs]$ nix-build -A nixosTests.gitlab
15 inherit (import ./ssh-keys.nix pkgs) snakeOilPrivateKey snakeOilPublicKey;
16 initialRootPassword = "notproduction";
19 aliceUsername = "alice";
21 alicePassword = "R5twyCgU0uXC71wT9BBTCqLs6HFZ7h3L";
23 aliceProjectName = "test-alice";
27 bobPassword = "XwkkBbl2SiIwabQzgcoaTbhsotijEEtF";
31 meta.maintainers = with lib.maintainers; [ globin yayayayaka ];
35 imports = [ common/user-account.nix ];
37 environment.systemPackages = with pkgs; [ git ];
39 virtualisation.memorySize = 6144;
40 virtualisation.cores = 4;
41 virtualisation.useNixStoreImage = true;
42 virtualisation.writableStore = false;
44 systemd.services.gitlab.serviceConfig.Restart = lib.mkForce "no";
45 systemd.services.gitlab-workhorse.serviceConfig.Restart = lib.mkForce "no";
46 systemd.services.gitaly.serviceConfig.Restart = lib.mkForce "no";
47 systemd.services.gitlab-sidekiq.serviceConfig.Restart = lib.mkForce "no";
51 recommendedProxySettings = true;
54 locations."/".proxyPass = "http://unix:/run/gitlab/gitlab-workhorse.socket";
59 services.openssh.enable = true;
66 systemd.services.gitlab-backup.environment.BACKUP = "dump";
70 databasePasswordFile = pkgs.writeText "dbPassword" "xo0daiF4";
71 initialRootPasswordFile = pkgs.writeText "rootPassword" initialRootPassword;
75 settings.pages-domain = "localhost";
81 address = "alice@localhost";
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";
96 sidekiq.concurrency = 1;
102 testScript = { nodes, ... }:
104 auth = pkgs.writeText "auth.json" (builtins.toJSON {
105 grant_type = "password";
107 password = initialRootPassword;
110 createUserAlice = pkgs.writeText "create-user-alice.json" (builtins.toJSON rec {
111 username = aliceUsername;
113 email = "alice@localhost";
114 password = alicePassword;
115 skip_confirmation = true;
118 createUserBob = pkgs.writeText "create-user-bob.json" (builtins.toJSON rec {
119 username = bobUsername;
121 email = "bob@localhost";
122 password = bobPassword;
123 skip_confirmation = true;
126 aliceAuth = pkgs.writeText "alice-auth.json" (builtins.toJSON {
127 grant_type = "password";
128 username = aliceUsername;
129 password = alicePassword;
132 bobAuth = pkgs.writeText "bob-auth.json" (builtins.toJSON {
133 grant_type = "password";
134 username = bobUsername;
135 password = bobPassword;
138 aliceAddSSHKey = pkgs.writeText "alice-add-ssh-key.json" (builtins.toJSON {
140 title = "snakeoil@nixos";
141 key = snakeOilPublicKey;
144 createProjectAlice = pkgs.writeText "create-project-alice.json" (builtins.toJSON {
145 name = aliceProjectName;
146 visibility = "public";
149 putFile = pkgs.writeText "put-file.json" (builtins.toJSON {
151 author_email = "author@example.com";
152 author_name = "Firstname Lastname";
153 content = "some content";
154 commit_message = "create a new file";
157 mergeRequest = pkgs.writeText "merge-request.json" (builtins.toJSON {
159 target_project_id = aliceProjectId;
160 source_branch = "master";
161 target_branch = "master";
162 title = "Add some other file";
165 newIssue = pkgs.writeText "new-issue.json" (builtins.toJSON {
166 title = "useful issue title";
169 closeIssue = pkgs.writeText "close-issue.json" (builtins.toJSON {
171 state_event = "close";
174 # Wait for all GitLab services to be fully started.
176 gitlab.wait_for_unit("gitaly.service")
177 gitlab.wait_for_unit("gitlab-workhorse.service")
178 gitlab.wait_for_unit("gitlab-mailroom.service")
179 gitlab.wait_for_unit("gitlab.service")
180 gitlab.wait_for_unit("gitlab-pages.service")
181 gitlab.wait_for_unit("gitlab-sidekiq.service")
182 gitlab.wait_for_file("${nodes.gitlab.services.gitlab.statePath}/tmp/sockets/gitlab.socket")
183 gitlab.wait_until_succeeds("curl -sSf http://gitlab/users/sign_in")
186 # The actual test of GitLab. Only push data to GitLab if
187 # `doSetup` is is true.
189 GIT_SSH_COMMAND = "ssh -o StrictHostKeyChecking=accept-new -o UserKnownHostsFile=/dev/null"
192 "curl -isSf http://gitlab | grep -i location | grep http://gitlab/users/sign_in"
195 "${pkgs.sudo}/bin/sudo -u gitlab -H gitlab-rake gitlab:check 1>&2"
198 "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"
200 '' + lib.optionalString doSetup ''
201 with subtest("Create user Alice"):
203 """[ "$(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" ]"""
206 "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"
209 with subtest("Create user Bob"):
211 """ [ "$(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" ]"""
214 "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"
217 with subtest("Setup Git and SSH for Alice"):
218 gitlab.succeed("git config --global user.name Alice")
219 gitlab.succeed("git config --global user.email alice@nixos.invalid")
220 gitlab.succeed("mkdir -m 700 /root/.ssh")
221 gitlab.succeed("cat ${snakeOilPrivateKey} > /root/.ssh/id_ecdsa")
222 gitlab.succeed("chmod 600 /root/.ssh/id_ecdsa")
229 -H 'Content-Type: application/json' \
230 -H @/tmp/headers-alice -d @${aliceAddSSHKey} \
231 http://gitlab/api/v4/user/keys)" = "201" ]
235 with subtest("Create a new repository"):
236 # Alice creates a new repository
243 -H 'Content-Type: application/json' \
244 -H @/tmp/headers-alice \
245 -d @${createProjectAlice} \
246 http://gitlab/api/v4/projects)" = "201" ]
250 # Alice commits an initial commit
257 -H 'Content-Type: application/json' \
258 -H @/tmp/headers-alice \
260 http://gitlab/api/v4/projects/${aliceProjectId}/repository/files/some-file.txt)" = "201" ]"""
263 with subtest("git clone over HTTP"):
265 """git clone http://gitlab/alice/${aliceProjectName}.git clone-via-http""",
269 with subtest("Push a commit via SSH"):
271 f"""GIT_SSH_COMMAND="{GIT_SSH_COMMAND}" git clone gitlab@gitlab:alice/${aliceProjectName}.git""",
275 """echo "a commit sent over ssh" > ${aliceProjectName}/ssh.txt"""
279 cd ${aliceProjectName} || exit 1
285 cd ${aliceProjectName} || exit 1
286 git commit -m "Add a commit to be sent over ssh"
291 cd ${aliceProjectName} || exit 1
292 GIT_SSH_COMMAND="{GIT_SSH_COMMAND}" git push --set-upstream origin master
297 with subtest("Fork a project"):
298 # Bob forks Alice's project
305 -H 'Content-Type: application/json' \
306 -H @/tmp/headers-bob \
307 http://gitlab/api/v4/projects/${aliceProjectId}/fork)" = "201" ]
311 # Bob creates a commit
312 gitlab.wait_until_succeeds(
318 -H 'Content-Type: application/json' \
319 -H @/tmp/headers-bob \
321 http://gitlab/api/v4/projects/${bobProjectId}/repository/files/some-other-file.txt)" = "201" ]
325 with subtest("Create a Merge Request"):
326 # Bob opens a merge request against Alice's repository
327 gitlab.wait_until_succeeds(
333 -H 'Content-Type: application/json' \
334 -H @/tmp/headers-bob \
335 -d @${mergeRequest} \
336 http://gitlab/api/v4/projects/${bobProjectId}/merge_requests)" = "201" ]
340 # Alice merges the MR
341 gitlab.wait_until_succeeds(
347 -H 'Content-Type: application/json' \
348 -H @/tmp/headers-alice \
349 -d @${mergeRequest} \
350 http://gitlab/api/v4/projects/${aliceProjectId}/merge_requests/1/merge)" = "200" ]
354 with subtest("Create an Issue"):
355 # Bob opens an issue on Alice's repository
361 -H 'Content-Type: application/json' \
362 -H @/tmp/headers-bob \
364 http://gitlab/api/v4/projects/${aliceProjectId}/issues)" = "201" ]
368 # Alice closes the issue
369 gitlab.wait_until_succeeds(
375 -H 'Content-Type: application/json' \
376 -H @/tmp/headers-alice -d @${closeIssue} http://gitlab/api/v4/projects/${aliceProjectId}/issues/1)" = "200" ]
380 with subtest("Download archive.tar.gz"):
386 -H @/tmp/headers-alice \
387 http://gitlab/api/v4/projects/${aliceProjectId}/repository/archive.tar.gz)" = "200" ]
393 -H @/tmp/headers-alice \
394 http://gitlab/api/v4/projects/${aliceProjectId}/repository/archive.tar.gz > /tmp/archive.tar.gz
397 gitlab.succeed("test -s /tmp/archive.tar.gz")
399 with subtest("Download archive.tar.bz2"):
405 -H @/tmp/headers-alice \
406 http://gitlab/api/v4/projects/${aliceProjectId}/repository/archive.tar.bz2)" = "200" ]
412 -H @/tmp/headers-alice \
413 http://gitlab/api/v4/projects/${aliceProjectId}/repository/archive.tar.bz2 > /tmp/archive.tar.bz2
416 gitlab.succeed("test -s /tmp/archive.tar.bz2")
425 gitlab.systemctl("start gitlab-backup.service")
426 gitlab.wait_for_unit("gitlab-backup.service")
427 gitlab.wait_for_file("${nodes.gitlab.services.gitlab.statePath}/backup/dump_gitlab_backup.tar")
428 gitlab.systemctl("stop postgresql.service gitlab-config.service gitlab.target")
430 "find ${nodes.gitlab.services.gitlab.statePath} -mindepth 1 -maxdepth 1 -not -name backup -execdir rm -r {} +"
432 gitlab.succeed("systemd-tmpfiles --create")
433 gitlab.succeed("rm -rf ${nodes.gitlab.services.postgresql.dataDir}")
434 gitlab.systemctl("start gitlab-config.service gitaly.service gitlab-postgresql.service")
435 gitlab.wait_for_file("${nodes.gitlab.services.gitlab.statePath}/tmp/sockets/gitaly.socket")
437 "sudo -u gitlab -H gitlab-rake gitlab:backup:restore RAILS_ENV=production BACKUP=dump force=yes"
439 gitlab.systemctl("start gitlab.target")