From 1665aed5e302f213db048a38af44021b5e815d80 Mon Sep 17 00:00:00 2001 From: Rick van Schijndel Date: Wed, 3 Apr 2024 22:45:53 +0200 Subject: [PATCH 1/6] t: content-addressed: add test for caDependingOnFailingCA This uncovers an issue with the front-end. --- t/content-addressed/basic.t | 4 ++-- t/jobs/content-addressed.nix | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/t/content-addressed/basic.t b/t/content-addressed/basic.t index 6597e727..4f92b1dc 100644 --- a/t/content-addressed/basic.t +++ b/t/content-addressed/basic.t @@ -27,13 +27,13 @@ my $project = $db->resultset('Projects')->create({name => "tests", displayname = my $jobset = createBaseJobset("content-addressed", "content-addressed.nix", $ctx{jobsdir}); ok(evalSucceeds($jobset), "Evaluating jobs/content-addressed.nix should exit with return code 0"); -is(nrQueuedBuildsForJobset($jobset), 5, "Evaluating jobs/content-addressed.nix should result in 4 builds"); +is(nrQueuedBuildsForJobset($jobset), 6, "Evaluating jobs/content-addressed.nix should result in 6 builds"); for my $build (queuedBuildsForJobset($jobset)) { ok(runBuild($build), "Build '".$build->job."' from jobs/content-addressed.nix should exit with code 0"); my $newbuild = $db->resultset('Builds')->find($build->id); is($newbuild->finished, 1, "Build '".$build->job."' from jobs/content-addressed.nix should be finished."); - my $expected = $build->job eq "fails" ? 1 : $build->job =~ /with_failed/ ? 6 : 0; + my $expected = $build->job eq "fails" ? 1 : $build->job =~ /with_failed/ ? 6 : $build->job =~ /FailingCA/ ? 2 : 0; is($newbuild->buildstatus, $expected, "Build '".$build->job."' from jobs/content-addressed.nix should have buildstatus $expected."); my $response = request("/build/".$build->id); diff --git a/t/jobs/content-addressed.nix b/t/jobs/content-addressed.nix index 65496df5..03bb56e7 100644 --- a/t/jobs/content-addressed.nix +++ b/t/jobs/content-addressed.nix @@ -25,6 +25,13 @@ rec { FOO = empty_dir; }; + caDependingOnFailingCA = + cfg.mkContentAddressedDerivation { + name = "ca-depending-on-failing-ca"; + builder = ./dir-with-file-builder.sh; + FOO = fails; + }; + nonCaDependingOnCA = cfg.mkDerivation { name = "non-ca-depending-on-ca"; From 71986632ced0dcaa0bf8262d2f41e52d3216c39d Mon Sep 17 00:00:00 2001 From: Rick van Schijndel Date: Wed, 3 Apr 2024 22:47:22 +0200 Subject: [PATCH 2/6] hydra-server: findLog: fix issue with ca-derivations enabled When content addressed derivations are built on the hydra server, one may run into an issue where some builds suddenly don't load anymore. This seems to be caused by outPaths that are NULL (which is allowed for ca-derivations). Filter them out to prevent querying the database for them, which is not supported by the database abstraction layer that's currently in use. On my instance this appears to resolve the issue. I feel like I might be doing this at the wrong abstraction layer, but on the other hand -- it seems to resolve it and it also doesn't really look like it will hurt anything. The test added in a previous commit uncovers this issue, and this commit resolves it. So I'm happy with this patch for now. The issue I was seeing on my server: hydra-server[2549]: [error] Couldn't render template "undef error - DBIx::Class::SQLMaker::ClassicExtensions::puke(): Fatal: NULL-within-IN not implemented: The upcoming SQL::Abstract::Classic 2.0 will emit the logically correct SQL instead of raising this exception. at /nix/store/-hydra-unstable-2024-03-08_nix_2_20/libexec/hydra/lib/Hydra/Helper/Nix.pm line 190 See also short discussion here: https://github.com/NixOS/nixpkgs/pull/297392#issuecomment-2035366263 --- src/lib/Hydra/Helper/Nix.pm | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/lib/Hydra/Helper/Nix.pm b/src/lib/Hydra/Helper/Nix.pm index 71a8a7d7..7b16b1be 100644 --- a/src/lib/Hydra/Helper/Nix.pm +++ b/src/lib/Hydra/Helper/Nix.pm @@ -187,6 +187,10 @@ sub findLog { return undef if scalar @outPaths == 0; + # Filter out any NULLs. Content-addressed derivations + # that haven't built yet or failed to build may have a NULL outPath. + @outPaths = grep {defined} @outPaths; + my @steps = $c->model('DB::BuildSteps')->search( { path => { -in => [@outPaths] } }, { select => ["drvpath"] From 3f913a771d1cdfba004a3639fc109e57bf3dae8e Mon Sep 17 00:00:00 2001 From: Rick van Schijndel Date: Wed, 3 Apr 2024 22:55:00 +0200 Subject: [PATCH 3/6] t: content-addressed: add a comment about a misleading testcase --- t/content-addressed/basic.t | 2 ++ 1 file changed, 2 insertions(+) diff --git a/t/content-addressed/basic.t b/t/content-addressed/basic.t index 4f92b1dc..aefb457b 100644 --- a/t/content-addressed/basic.t +++ b/t/content-addressed/basic.t @@ -55,6 +55,8 @@ for my $build (queuedBuildsForJobset($jobset)) { } +# XXX: deststoredir is undefined: Use of uninitialized value $ctx{"deststoredir"} in concatenation (.) or string at t/content-addressed/basic.t line 58. +# XXX: This test seems to not do what it seems to be doing. See documentation: https://metacpan.org/pod/Test2::V0#isnt($got,-$do_not_want,-$name) isnt(<$ctx{deststoredir}/realisations/*>, "", "The destination store should have the realisations of the built derivations registered"); done_testing; From b72528be5074f3e62e9ae2c2ae8ef9c07a0b4dd3 Mon Sep 17 00:00:00 2001 From: Pierre Bourdon Date: Sun, 21 Apr 2024 16:14:24 +0200 Subject: [PATCH 4/6] web: serveFile: also serve a CSP putting served HTML in its own origin --- src/lib/Hydra/Controller/Build.pm | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lib/Hydra/Controller/Build.pm b/src/lib/Hydra/Controller/Build.pm index f8587169..de2c204d 100644 --- a/src/lib/Hydra/Controller/Build.pm +++ b/src/lib/Hydra/Controller/Build.pm @@ -234,6 +234,9 @@ sub serveFile { } elsif ($ls->{type} eq "regular") { + # Have the hosted data considered its own origin to avoid being a giant + # XSS hole. + $c->response->header('Content-Security-Policy' => 'sandbox allow-scripts'); $c->stash->{'plain'} = { data => grab(cmd => ["nix", "--experimental-features", "nix-command", "store", "cat", "--store", getStoreUri(), "$path"]) }; From 92155f9a07f5fe32e0778e474e7313997811e635 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Fri, 3 May 2024 11:41:42 -0400 Subject: [PATCH 5/6] Remove `PrometheusTiny` from overlay It's in Nixpkgs for a good while now. --- flake.nix | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/flake.nix b/flake.nix index 82824733..b3de3d73 100644 --- a/flake.nix +++ b/flake.nix @@ -40,27 +40,6 @@ # A Nixpkgs overlay that provides a 'hydra' package. overlays.default = final: prev: { - - # Add LDAP dependencies that aren't currently found within nixpkgs. - perlPackages = prev.perlPackages // { - - PrometheusTiny = final.perlPackages.buildPerlPackage { - pname = "Prometheus-Tiny"; - version = "0.007"; - src = final.fetchurl { - url = "mirror://cpan/authors/id/R/RO/ROBN/Prometheus-Tiny-0.007.tar.gz"; - sha256 = "0ef8b226a2025cdde4df80129dd319aa29e884e653c17dc96f4823d985c028ec"; - }; - buildInputs = with final.perlPackages; [ HTTPMessage Plack TestException ]; - meta = { - homepage = "https://github.com/robn/Prometheus-Tiny"; - description = "A tiny Prometheus client"; - license = with final.lib.licenses; [ artistic1 gpl1Plus ]; - }; - }; - - }; - hydra = final.callPackage ./package.nix { inherit (nixpkgs.lib) fileset; rawSrc = self; From 743795b2b090a5cdfe8bd90120add8db7770086a Mon Sep 17 00:00:00 2001 From: John Ericson Date: Fri, 3 May 2024 12:07:05 -0400 Subject: [PATCH 6/6] Factor out NixOS tests, and clean up Due to newer nixpkgs, there were a number of things that could be cleaned up in the process. --- flake.nix | 299 +----------------------------------- nixos-modules/default.nix | 11 +- nixos-tests.nix | 309 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 319 insertions(+), 300 deletions(-) create mode 100644 nixos-tests.nix diff --git a/flake.nix b/flake.nix index b3de3d73..7e2f3f67 100644 --- a/flake.nix +++ b/flake.nix @@ -17,24 +17,6 @@ overlays = overlayList; }); - # NixOS configuration used for VM tests. - hydraServer = - { config, pkgs, ... }: - { - imports = [ self.nixosModules.hydraTest ]; - - virtualisation.memorySize = 1024; - virtualisation.writableStore = true; - - environment.systemPackages = [ pkgs.perlPackages.LWP pkgs.perlPackages.JSON ]; - - nix = { - # Without this nix tries to fetch packages from the default - # cache.nixos.org which is not reachable from this sandboxed NixOS test. - binaryCaches = [ ]; - }; - }; - in rec { @@ -67,282 +49,9 @@ echo "doc manual $out/share/doc/hydra" >> $out/nix-support/hydra-build-products ''); - tests.install = forEachSystem (system: - with import (nixpkgs + "/nixos/lib/testing-python.nix") { inherit system; }; - simpleTest { - name = "hydra-install"; - nodes.machine = hydraServer; - testScript = - '' - machine.wait_for_job("hydra-init") - machine.wait_for_job("hydra-server") - machine.wait_for_job("hydra-evaluator") - machine.wait_for_job("hydra-queue-runner") - machine.wait_for_open_port(3000) - machine.succeed("curl --fail http://localhost:3000/") - ''; - }); - - tests.notifications = forEachSystem (system: - let pkgs = pkgsBySystem.${system}; in - with import (nixpkgs + "/nixos/lib/testing-python.nix") { inherit system; }; - simpleTest { - name = "hydra-notifications"; - nodes.machine = { pkgs, ... }: { - imports = [ hydraServer ]; - services.hydra-dev.extraConfig = '' - - url = http://127.0.0.1:8086 - db = hydra - - ''; - services.influxdb.enable = true; - }; - testScript = '' - machine.wait_for_job("hydra-init") - - # Create an admin account and some other state. - machine.succeed( - """ - su - hydra -c "hydra-create-user root --email-address 'alice@example.org' --password foobar --role admin" - mkdir /run/jobset - chmod 755 /run/jobset - cp ${./t/jobs/api-test.nix} /run/jobset/default.nix - chmod 644 /run/jobset/default.nix - chown -R hydra /run/jobset - """ - ) - - # Wait until InfluxDB can receive web requests - machine.wait_for_job("influxdb") - machine.wait_for_open_port(8086) - - # Create an InfluxDB database where hydra will write to - machine.succeed( - "curl -XPOST 'http://127.0.0.1:8086/query' " - + "--data-urlencode 'q=CREATE DATABASE hydra'" - ) - - # Wait until hydra-server can receive HTTP requests - machine.wait_for_job("hydra-server") - machine.wait_for_open_port(3000) - - # Setup the project and jobset - machine.succeed( - "su - hydra -c 'perl -I ${pkgs.hydra.perlDeps}/lib/perl5/site_perl ${./t/setup-notifications-jobset.pl}' >&2" - ) - - # Wait until hydra has build the job and - # the InfluxDBNotification plugin uploaded its notification to InfluxDB - machine.wait_until_succeeds( - "curl -s -H 'Accept: application/csv' " - + "-G 'http://127.0.0.1:8086/query?db=hydra' " - + "--data-urlencode 'q=SELECT * FROM hydra_build_status' | grep success" - ) - ''; - }); - - tests.gitea = forEachSystem (system: - let pkgs = pkgsBySystem.${system}; in - with import (nixpkgs + "/nixos/lib/testing-python.nix") { inherit system; }; - makeTest { - name = "hydra-gitea"; - nodes.machine = { pkgs, ... }: { - imports = [ hydraServer ]; - services.hydra-dev.extraConfig = '' - - root=d7f16a3412e01a43a414535b16007c6931d3a9c7 - - ''; - nixpkgs.config.permittedInsecurePackages = [ "gitea-1.19.4" ]; - nix = { - settings.substituters = [ ]; - }; - services.gitea = { - enable = true; - database.type = "postgres"; - disableRegistration = true; - httpPort = 3001; - }; - services.openssh.enable = true; - environment.systemPackages = with pkgs; [ gitea git jq gawk ]; - networking.firewall.allowedTCPPorts = [ 3000 ]; - }; - skipLint = true; - testScript = - let - scripts.mktoken = pkgs.writeText "token.sql" '' - INSERT INTO access_token (id, uid, name, created_unix, updated_unix, token_hash, token_salt, token_last_eight, scope) VALUES (1, 1, 'hydra', 1617107360, 1617107360, 'a930f319ca362d7b49a4040ac0af74521c3a3c3303a86f327b01994430672d33b6ec53e4ea774253208686c712495e12a486', 'XRjWE9YW0g', '31d3a9c7', 'all'); - ''; - - scripts.git-setup = pkgs.writeShellScript "setup.sh" '' - set -x - mkdir -p /tmp/repo $HOME/.ssh - cat ${snakeoilKeypair.privkey} > $HOME/.ssh/privk - chmod 0400 $HOME/.ssh/privk - git -C /tmp/repo init - cp ${smallDrv} /tmp/repo/jobset.nix - git -C /tmp/repo add . - git config --global user.email test@localhost - git config --global user.name test - git -C /tmp/repo commit -m 'Initial import' - git -C /tmp/repo remote add origin gitea@machine:root/repo - GIT_SSH_COMMAND='ssh -i $HOME/.ssh/privk -o StrictHostKeyChecking=no' \ - git -C /tmp/repo push origin master - git -C /tmp/repo log >&2 - ''; - - scripts.hydra-setup = pkgs.writeShellScript "hydra.sh" '' - set -x - su -l hydra -c "hydra-create-user root --email-address \ - 'alice@example.org' --password foobar --role admin" - - URL=http://localhost:3000 - USERNAME="root" - PASSWORD="foobar" - PROJECT_NAME="trivial" - JOBSET_NAME="trivial" - mycurl() { - curl --referer $URL -H "Accept: application/json" \ - -H "Content-Type: application/json" $@ - } - - cat >data.json <data.json <data.json < $out; exit 0"]; - }; - } - ''; - in - '' - import json - - machine.start() - machine.wait_for_unit("multi-user.target") - machine.wait_for_open_port(3000) - machine.wait_for_open_port(3001) - - machine.succeed( - "su -l gitea -c 'GITEA_WORK_DIR=/var/lib/gitea gitea admin user create " - + "--username root --password root --email test@localhost'" - ) - machine.succeed("su -l postgres -c 'psql gitea < ${scripts.mktoken}'") - - machine.succeed( - "curl --fail -X POST http://localhost:3001/api/v1/user/repos " - + "-H 'Accept: application/json' -H 'Content-Type: application/json' " - + f"-H 'Authorization: token ${api_token}'" - + ' -d \'{"auto_init":false, "description":"string", "license":"mit", "name":"repo", "private":false}\''' - ) - - machine.succeed( - "curl --fail -X POST http://localhost:3001/api/v1/user/keys " - + "-H 'Accept: application/json' -H 'Content-Type: application/json' " - + f"-H 'Authorization: token ${api_token}'" - + ' -d \'{"key":"${snakeoilKeypair.pubkey}","read_only":true,"title":"SSH"}\''' - ) - - machine.succeed( - "${scripts.git-setup}" - ) - - machine.succeed( - "${scripts.hydra-setup}" - ) - - machine.wait_until_succeeds( - 'curl -Lf -s http://localhost:3000/build/1 -H "Accept: application/json" ' - + '| jq .buildstatus | xargs test 0 -eq' - ) - - data = machine.succeed( - 'curl -Lf -s "http://localhost:3001/api/v1/repos/root/repo/statuses/$(cd /tmp/repo && git show | head -n1 | awk "{print \\$2}")" ' - + "-H 'Accept: application/json' -H 'Content-Type: application/json' " - + f"-H 'Authorization: token ${api_token}'" - ) - - response = json.loads(data) - - assert len(response) == 2, "Expected exactly three status updates for latest commit (queued, finished)!" - assert response[0]['status'] == "success", "Expected finished status to be success!" - assert response[1]['status'] == "pending", "Expected queued status to be pending!" - - machine.shutdown() - ''; - }); - - tests.validate-openapi = forEachSystem (system: - let pkgs = pkgsBySystem.${system}; in - pkgs.runCommand "validate-openapi" - { buildInputs = [ pkgs.openapi-generator-cli ]; } - '' - openapi-generator-cli validate -i ${./hydra-api.yaml} - touch $out - ''); + tests = import ./nixos-tests.nix { + inherit forEachSystem nixpkgs pkgsBySystem nixosModules; + }; container = nixosConfigurations.container.config.system.build.toplevel; }; @@ -366,6 +75,8 @@ system = "x86_64-linux"; modules = [ + self.nixosModules.hydra + self.nixosModules.overlayNixpkgsForThisHyydra self.nixosModules.hydraTest self.nixosModules.hydraProxy { diff --git a/nixos-modules/default.nix b/nixos-modules/default.nix index 6fc19d31..f44d7808 100644 --- a/nixos-modules/default.nix +++ b/nixos-modules/default.nix @@ -1,14 +1,13 @@ { overlays }: -rec { - hydra = { - imports = [ ./hydra.nix ]; +{ + hydra = import ./hydra.nix; + + overlayNixpkgsForThisHyydra = { nixpkgs = { inherit overlays; }; }; hydraTest = { pkgs, ... }: { - imports = [ hydra ]; - services.hydra-dev.enable = true; services.hydra-dev.hydraURL = "http://hydra.example.org"; services.hydra-dev.notificationSender = "admin@hydra.example.org"; @@ -16,7 +15,7 @@ rec { systemd.services.hydra-send-stats.enable = false; services.postgresql.enable = true; - services.postgresql.package = pkgs.postgresql_11; + services.postgresql.package = pkgs.postgresql_12; # The following is to work around the following error from hydra-server: # [error] Caught exception in engine "Cannot determine local time zone" diff --git a/nixos-tests.nix b/nixos-tests.nix new file mode 100644 index 00000000..3c9dc6c8 --- /dev/null +++ b/nixos-tests.nix @@ -0,0 +1,309 @@ +{ forEachSystem, nixpkgs, pkgsBySystem, nixosModules }: + +let + # NixOS configuration used for VM tests. + hydraServer = + { config, pkgs, ... }: + { + imports = [ + nixosModules.hydra + nixosModules.overlayNixpkgsForThisHyydra + nixosModules.hydraTest + ]; + + virtualisation.memorySize = 1024; + virtualisation.writableStore = true; + + environment.systemPackages = [ pkgs.perlPackages.LWP pkgs.perlPackages.JSON ]; + + nix = { + # Without this nix tries to fetch packages from the default + # cache.nixos.org which is not reachable from this sandboxed NixOS test. + settings.substituters = [ ]; + }; + }; + +in + +{ + + install = forEachSystem (system: + with import (nixpkgs + "/nixos/lib/testing-python.nix") { inherit system; }; + simpleTest { + name = "hydra-install"; + nodes.machine = hydraServer; + testScript = + '' + machine.wait_for_job("hydra-init") + machine.wait_for_job("hydra-server") + machine.wait_for_job("hydra-evaluator") + machine.wait_for_job("hydra-queue-runner") + machine.wait_for_open_port(3000) + machine.succeed("curl --fail http://localhost:3000/") + ''; + }); + + notifications = forEachSystem (system: + let pkgs = pkgsBySystem.${system}; in + with import (nixpkgs + "/nixos/lib/testing-python.nix") { inherit system; }; + simpleTest { + name = "hydra-notifications"; + nodes.machine = { pkgs, ... }: { + imports = [ hydraServer ]; + services.hydra-dev.extraConfig = '' + + url = http://127.0.0.1:8086 + db = hydra + + ''; + services.influxdb.enable = true; + }; + testScript = '' + machine.wait_for_job("hydra-init") + + # Create an admin account and some other state. + machine.succeed( + """ + su - hydra -c "hydra-create-user root --email-address 'alice@example.org' --password foobar --role admin" + mkdir /run/jobset + chmod 755 /run/jobset + cp ${./t/jobs/api-test.nix} /run/jobset/default.nix + chmod 644 /run/jobset/default.nix + chown -R hydra /run/jobset + """ + ) + + # Wait until InfluxDB can receive web requests + machine.wait_for_job("influxdb") + machine.wait_for_open_port(8086) + + # Create an InfluxDB database where hydra will write to + machine.succeed( + "curl -XPOST 'http://127.0.0.1:8086/query' " + + "--data-urlencode 'q=CREATE DATABASE hydra'" + ) + + # Wait until hydra-server can receive HTTP requests + machine.wait_for_job("hydra-server") + machine.wait_for_open_port(3000) + + # Setup the project and jobset + machine.succeed( + "su - hydra -c 'perl -I ${pkgs.hydra.perlDeps}/lib/perl5/site_perl ${./t/setup-notifications-jobset.pl}' >&2" + ) + + # Wait until hydra has build the job and + # the InfluxDBNotification plugin uploaded its notification to InfluxDB + machine.wait_until_succeeds( + "curl -s -H 'Accept: application/csv' " + + "-G 'http://127.0.0.1:8086/query?db=hydra' " + + "--data-urlencode 'q=SELECT * FROM hydra_build_status' | grep success" + ) + ''; + }); + + gitea = forEachSystem (system: + let pkgs = pkgsBySystem.${system}; in + with import (nixpkgs + "/nixos/lib/testing-python.nix") { inherit system; }; + makeTest { + name = "hydra-gitea"; + nodes.machine = { pkgs, ... }: { + imports = [ hydraServer ]; + services.hydra-dev.extraConfig = '' + + root=d7f16a3412e01a43a414535b16007c6931d3a9c7 + + ''; + nixpkgs.config.permittedInsecurePackages = [ "gitea-1.19.4" ]; + nix = { + settings.substituters = [ ]; + }; + services.gitea = { + enable = true; + database.type = "postgres"; + settings = { + service.DISABLE_REGISTRATION = true; + server.HTTP_PORT = 3001; + }; + }; + services.openssh.enable = true; + environment.systemPackages = with pkgs; [ gitea git jq gawk ]; + networking.firewall.allowedTCPPorts = [ 3000 ]; + }; + skipLint = true; + testScript = + let + scripts.mktoken = pkgs.writeText "token.sql" '' + INSERT INTO access_token (id, uid, name, created_unix, updated_unix, token_hash, token_salt, token_last_eight, scope) VALUES (1, 1, 'hydra', 1617107360, 1617107360, 'a930f319ca362d7b49a4040ac0af74521c3a3c3303a86f327b01994430672d33b6ec53e4ea774253208686c712495e12a486', 'XRjWE9YW0g', '31d3a9c7', 'all'); + ''; + + scripts.git-setup = pkgs.writeShellScript "setup.sh" '' + set -x + mkdir -p /tmp/repo $HOME/.ssh + cat ${snakeoilKeypair.privkey} > $HOME/.ssh/privk + chmod 0400 $HOME/.ssh/privk + git -C /tmp/repo init + cp ${smallDrv} /tmp/repo/jobset.nix + git -C /tmp/repo add . + git config --global user.email test@localhost + git config --global user.name test + git -C /tmp/repo commit -m 'Initial import' + git -C /tmp/repo remote add origin gitea@machine:root/repo + GIT_SSH_COMMAND='ssh -i $HOME/.ssh/privk -o StrictHostKeyChecking=no' \ + git -C /tmp/repo push origin master + git -C /tmp/repo log >&2 + ''; + + scripts.hydra-setup = pkgs.writeShellScript "hydra.sh" '' + set -x + su -l hydra -c "hydra-create-user root --email-address \ + 'alice@example.org' --password foobar --role admin" + + URL=http://localhost:3000 + USERNAME="root" + PASSWORD="foobar" + PROJECT_NAME="trivial" + JOBSET_NAME="trivial" + mycurl() { + curl --referer $URL -H "Accept: application/json" \ + -H "Content-Type: application/json" $@ + } + + cat >data.json <data.json <data.json < $out; exit 0"]; + }; + } + ''; + in + '' + import json + + machine.start() + machine.wait_for_unit("multi-user.target") + machine.wait_for_open_port(3000) + machine.wait_for_open_port(3001) + + machine.succeed( + "su -l gitea -c 'GITEA_WORK_DIR=/var/lib/gitea gitea admin user create " + + "--username root --password root --email test@localhost'" + ) + machine.succeed("su -l postgres -c 'psql gitea < ${scripts.mktoken}'") + + machine.succeed( + "curl --fail -X POST http://localhost:3001/api/v1/user/repos " + + "-H 'Accept: application/json' -H 'Content-Type: application/json' " + + f"-H 'Authorization: token ${api_token}'" + + ' -d \'{"auto_init":false, "description":"string", "license":"mit", "name":"repo", "private":false}\''' + ) + + machine.succeed( + "curl --fail -X POST http://localhost:3001/api/v1/user/keys " + + "-H 'Accept: application/json' -H 'Content-Type: application/json' " + + f"-H 'Authorization: token ${api_token}'" + + ' -d \'{"key":"${snakeoilKeypair.pubkey}","read_only":true,"title":"SSH"}\''' + ) + + machine.succeed( + "${scripts.git-setup}" + ) + + machine.succeed( + "${scripts.hydra-setup}" + ) + + machine.wait_until_succeeds( + 'curl -Lf -s http://localhost:3000/build/1 -H "Accept: application/json" ' + + '| jq .buildstatus | xargs test 0 -eq' + ) + + data = machine.succeed( + 'curl -Lf -s "http://localhost:3001/api/v1/repos/root/repo/statuses/$(cd /tmp/repo && git show | head -n1 | awk "{print \\$2}")" ' + + "-H 'Accept: application/json' -H 'Content-Type: application/json' " + + f"-H 'Authorization: token ${api_token}'" + ) + + response = json.loads(data) + + assert len(response) == 2, "Expected exactly three status updates for latest commit (queued, finished)!" + assert response[0]['status'] == "success", "Expected finished status to be success!" + assert response[1]['status'] == "pending", "Expected queued status to be pending!" + + machine.shutdown() + ''; + }); + + validate-openapi = forEachSystem (system: + let pkgs = pkgsBySystem.${system}; in + pkgs.runCommand "validate-openapi" + { buildInputs = [ pkgs.openapi-generator-cli ]; } + '' + openapi-generator-cli validate -i ${./hydra-api.yaml} + touch $out + ''); + +}