at 23.05-pre 16 kB view raw
1# This test runs gitlab and performs the following tests: 2# - Creating users 3# - Pushing commits 4# - over the API 5# - over SSH 6# - Creating Merge Requests and merging them 7# - Opening and closing issues. 8# - Downloading repository archives as tar.gz and tar.bz2 9import ./make-test-python.nix ({ pkgs, lib, ... }: 10 11with lib; 12 13let 14 inherit (import ./ssh-keys.nix pkgs) snakeOilPrivateKey snakeOilPublicKey; 15 initialRootPassword = "notproduction"; 16 rootProjectId = "2"; 17 18 aliceUsername = "alice"; 19 aliceUserId = "2"; 20 alicePassword = "alicepassword"; 21 aliceProjectId = "2"; 22 aliceProjectName = "test-alice"; 23 24 bobUsername = "bob"; 25 bobUserId = "3"; 26 bobPassword = "bobpassword"; 27 bobProjectId = "3"; 28in { 29 name = "gitlab"; 30 meta = with pkgs.lib.maintainers; { 31 maintainers = [ globin yayayayaka ]; 32 }; 33 34 nodes = { 35 gitlab = { ... }: { 36 imports = [ common/user-account.nix ]; 37 38 virtualisation.memorySize = if pkgs.stdenv.is64bit then 4096 else 2047; 39 virtualisation.cores = 4; 40 virtualisation.useNixStoreImage = true; 41 virtualisation.writableStore = false; 42 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"; 47 48 services.nginx = { 49 enable = true; 50 recommendedProxySettings = true; 51 virtualHosts = { 52 localhost = { 53 locations."/".proxyPass = "http://unix:/run/gitlab/gitlab-workhorse.socket"; 54 }; 55 }; 56 }; 57 58 services.openssh.enable = true; 59 60 services.dovecot2 = { 61 enable = true; 62 enableImap = true; 63 }; 64 65 systemd.services.gitlab-backup.environment.BACKUP = "dump"; 66 67 services.gitlab = { 68 enable = true; 69 databasePasswordFile = pkgs.writeText "dbPassword" "xo0daiF4"; 70 initialRootPasswordFile = pkgs.writeText "rootPassword" initialRootPassword; 71 smtp.enable = true; 72 extraConfig = { 73 incoming_email = { 74 enabled = true; 75 mailbox = "inbox"; 76 address = "alice@localhost"; 77 user = "alice"; 78 password = "foobar"; 79 host = "localhost"; 80 port = 143; 81 }; 82 # https://github.com/NixOS/nixpkgs/issues/132295 83 # pages = { 84 # enabled = true; 85 # host = "localhost"; 86 # }; 87 }; 88 secrets = { 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"; 93 }; 94 }; 95 }; 96 }; 97 98 testScript = { nodes, ... }: 99 let 100 auth = pkgs.writeText "auth.json" (builtins.toJSON { 101 grant_type = "password"; 102 username = "root"; 103 password = initialRootPassword; 104 }); 105 106 createUserAlice = pkgs.writeText "create-user-alice.json" (builtins.toJSON rec { 107 username = aliceUsername; 108 name = username; 109 email = "alice@localhost"; 110 password = alicePassword; 111 skip_confirmation = true; 112 }); 113 114 createUserBob = pkgs.writeText "create-user-bob.json" (builtins.toJSON rec { 115 username = bobUsername; 116 name = username; 117 email = "bob@localhost"; 118 password = bobPassword; 119 skip_confirmation = true; 120 }); 121 122 aliceAuth = pkgs.writeText "alice-auth.json" (builtins.toJSON { 123 grant_type = "password"; 124 username = aliceUsername; 125 password = alicePassword; 126 }); 127 128 bobAuth = pkgs.writeText "bob-auth.json" (builtins.toJSON { 129 grant_type = "password"; 130 username = bobUsername; 131 password = bobPassword; 132 }); 133 134 aliceAddSSHKey = pkgs.writeText "alice-add-ssh-key.json" (builtins.toJSON { 135 id = aliceUserId; 136 title = "snakeoil@nixos"; 137 key = snakeOilPublicKey; 138 }); 139 140 createProjectAlice = pkgs.writeText "create-project-alice.json" (builtins.toJSON { 141 name = aliceProjectName; 142 visibility = "public"; 143 }); 144 145 putFile = pkgs.writeText "put-file.json" (builtins.toJSON { 146 branch = "master"; 147 author_email = "author@example.com"; 148 author_name = "Firstname Lastname"; 149 content = "some content"; 150 commit_message = "create a new file"; 151 }); 152 153 mergeRequest = pkgs.writeText "merge-request.json" (builtins.toJSON { 154 id = bobProjectId; 155 target_project_id = aliceProjectId; 156 source_branch = "master"; 157 target_branch = "master"; 158 title = "Add some other file"; 159 }); 160 161 newIssue = pkgs.writeText "new-issue.json" (builtins.toJSON { 162 title = "useful issue title"; 163 }); 164 165 closeIssue = pkgs.writeText "close-issue.json" (builtins.toJSON { 166 issue_iid = 1; 167 state_event = "close"; 168 }); 169 170 # Wait for all GitLab services to be fully started. 171 waitForServices = '' 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") 181 ''; 182 183 # The actual test of GitLab. Only push data to GitLab if 184 # `doSetup` is is true. 185 test = doSetup: '' 186 GIT_SSH_COMMAND = "ssh -o StrictHostKeyChecking=accept-new -o UserKnownHostsFile=/dev/null" 187 188 gitlab.succeed( 189 "curl -isSf http://gitlab | grep -i location | grep http://gitlab/users/sign_in" 190 ) 191 gitlab.succeed( 192 "${pkgs.sudo}/bin/sudo -u gitlab -H gitlab-rake gitlab:check 1>&2" 193 ) 194 gitlab.succeed( 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" 196 ) 197 '' + optionalString doSetup '' 198 with subtest("Create user Alice"): 199 gitlab.succeed( 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" ]""" 201 ) 202 gitlab.succeed( 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" 204 ) 205 206 with subtest("Create user Bob"): 207 gitlab.succeed( 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" ]""" 209 ) 210 gitlab.succeed( 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" 212 ) 213 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") 220 gitlab.succeed( 221 """ 222 [ "$(curl \ 223 -o /dev/null \ 224 -w '%{http_code}' \ 225 -X POST \ 226 -H 'Content-Type: application/json' \ 227 -H @/tmp/headers-alice -d @${aliceAddSSHKey} \ 228 http://gitlab/api/v4/user/keys)" = "201" ] 229 """ 230 ) 231 232 with subtest("Create a new repository"): 233 # Alice creates a new repository 234 gitlab.succeed( 235 """ 236 [ "$(curl \ 237 -o /dev/null \ 238 -w '%{http_code}' \ 239 -X POST \ 240 -H 'Content-Type: application/json' \ 241 -H @/tmp/headers-alice \ 242 -d @${createProjectAlice} \ 243 http://gitlab/api/v4/projects)" = "201" ] 244 """ 245 ) 246 247 # Alice commits an initial commit 248 gitlab.succeed( 249 """ 250 [ "$(curl \ 251 -o /dev/null \ 252 -w '%{http_code}' \ 253 -X POST \ 254 -H 'Content-Type: application/json' \ 255 -H @/tmp/headers-alice \ 256 -d @${putFile} \ 257 http://gitlab/api/v4/projects/${aliceProjectId}/repository/files/some-file.txt)" = "201" ]""" 258 ) 259 260 with subtest("git clone over HTTP"): 261 gitlab.succeed( 262 """git clone http://gitlab/alice/${aliceProjectName}.git clone-via-http""", 263 timeout=15 264 ) 265 266 with subtest("Push a commit via SSH"): 267 gitlab.succeed( 268 f"""GIT_SSH_COMMAND="{GIT_SSH_COMMAND}" git clone gitlab@gitlab:alice/${aliceProjectName}.git""", 269 timeout=15 270 ) 271 gitlab.succeed( 272 """echo "a commit sent over ssh" > ${aliceProjectName}/ssh.txt""" 273 ) 274 gitlab.succeed( 275 """ 276 cd ${aliceProjectName} || exit 1 277 git add . 278 """ 279 ) 280 gitlab.succeed( 281 """ 282 cd ${aliceProjectName} || exit 1 283 git commit -m "Add a commit to be sent over ssh" 284 """ 285 ) 286 gitlab.succeed( 287 f""" 288 cd ${aliceProjectName} || exit 1 289 GIT_SSH_COMMAND="{GIT_SSH_COMMAND}" git push --set-upstream origin master 290 """, 291 timeout=15 292 ) 293 294 with subtest("Fork a project"): 295 # Bob forks Alice's project 296 gitlab.succeed( 297 """ 298 [ "$(curl \ 299 -o /dev/null \ 300 -w '%{http_code}' \ 301 -X POST \ 302 -H 'Content-Type: application/json' \ 303 -H @/tmp/headers-bob \ 304 http://gitlab/api/v4/projects/${aliceProjectId}/fork)" = "201" ] 305 """ 306 ) 307 308 # Bob creates a commit 309 gitlab.wait_until_succeeds( 310 """ 311 [ "$(curl \ 312 -o /dev/null \ 313 -w '%{http_code}' \ 314 -X POST \ 315 -H 'Content-Type: application/json' \ 316 -H @/tmp/headers-bob \ 317 -d @${putFile} \ 318 http://gitlab/api/v4/projects/${bobProjectId}/repository/files/some-other-file.txt)" = "201" ] 319 """ 320 ) 321 322 with subtest("Create a Merge Request"): 323 # Bob opens a merge request against Alice's repository 324 gitlab.wait_until_succeeds( 325 """ 326 [ "$(curl \ 327 -o /dev/null \ 328 -w '%{http_code}' \ 329 -X POST \ 330 -H 'Content-Type: application/json' \ 331 -H @/tmp/headers-bob \ 332 -d @${mergeRequest} \ 333 http://gitlab/api/v4/projects/${bobProjectId}/merge_requests)" = "201" ] 334 """ 335 ) 336 337 # Alice merges the MR 338 gitlab.wait_until_succeeds( 339 """ 340 [ "$(curl \ 341 -o /dev/null \ 342 -w '%{http_code}' \ 343 -X PUT \ 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" ] 348 """ 349 ) 350 351 with subtest("Create an Issue"): 352 # Bob opens an issue on Alice's repository 353 gitlab.succeed( 354 """[ "$(curl \ 355 -o /dev/null \ 356 -w '%{http_code}' \ 357 -X POST \ 358 -H 'Content-Type: application/json' \ 359 -H @/tmp/headers-bob \ 360 -d @${newIssue} \ 361 http://gitlab/api/v4/projects/${aliceProjectId}/issues)" = "201" ] 362 """ 363 ) 364 365 # Alice closes the issue 366 gitlab.wait_until_succeeds( 367 """ 368 [ "$(curl \ 369 -o /dev/null \ 370 -w '%{http_code}' \ 371 -X PUT \ 372 -H 'Content-Type: application/json' \ 373 -H @/tmp/headers-alice -d @${closeIssue} http://gitlab/api/v4/projects/${aliceProjectId}/issues/1)" = "200" ] 374 """ 375 ) 376 '' + '' 377 with subtest("Download archive.tar.gz"): 378 gitlab.succeed( 379 """ 380 [ "$(curl \ 381 -o /dev/null \ 382 -w '%{http_code}' \ 383 -H @/tmp/headers-alice \ 384 http://gitlab/api/v4/projects/${aliceProjectId}/repository/archive.tar.gz)" = "200" ] 385 """ 386 ) 387 gitlab.succeed( 388 """ 389 curl \ 390 -H @/tmp/headers-alice \ 391 http://gitlab/api/v4/projects/${aliceProjectId}/repository/archive.tar.gz > /tmp/archive.tar.gz 392 """ 393 ) 394 gitlab.succeed("test -s /tmp/archive.tar.gz") 395 396 with subtest("Download archive.tar.bz2"): 397 gitlab.succeed( 398 """ 399 [ "$(curl \ 400 -o /dev/null \ 401 -w '%{http_code}' \ 402 -H @/tmp/headers-alice \ 403 http://gitlab/api/v4/projects/${aliceProjectId}/repository/archive.tar.bz2)" = "200" ] 404 """ 405 ) 406 gitlab.succeed( 407 """ 408 curl \ 409 -H @/tmp/headers-alice \ 410 http://gitlab/api/v4/projects/${aliceProjectId}/repository/archive.tar.bz2 > /tmp/archive.tar.bz2 411 """ 412 ) 413 gitlab.succeed("test -s /tmp/archive.tar.bz2") 414 ''; 415 416 in '' 417 gitlab.start() 418 '' 419 + waitForServices 420 + test true 421 + '' 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") 426 gitlab.succeed( 427 "find ${nodes.gitlab.config.services.gitlab.statePath} -mindepth 1 -maxdepth 1 -not -name backup -execdir rm -r {} +" 428 ) 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") 433 gitlab.succeed( 434 "sudo -u gitlab -H gitlab-rake gitlab:backup:restore RAILS_ENV=production BACKUP=dump force=yes" 435 ) 436 gitlab.systemctl("start gitlab.target") 437 '' 438 + waitForServices 439 + test false; 440})