Skip to content
quarry Artifact [e16b93ffce]
Login

Artifact [e16b93ffce]

Artifact e16b93ffceef23b5bac0e2e8ef7e57ff1835c5111beec06e1f883cc2ff6b7a42:


package main

import (
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"
	"time"

	"craftdesign.group/quarry/internal/oltp"
)

// A RUN TOKEN'S LOGIN OPENS THE API DOOR AND THE SYNC LANE FOR ITS ONE
// REPOSITORY, WITH NO ACCOUNT BEHIND IT, UNTIL ITS RUN ENDS (RFC 0021
// §runs). Its letters are the run's: contents: write reaches the op
// needing i; a read-only one is refused it.
func TestARunLoginOpensItsRepositoryUntilItsRunEnds(t *testing.T) {
	g := newDoorRig(t)
	db := g.rg.odb
	db.SyncProjectCode = func(string) (string, bool) { return "CODE", true }
	for _, id := range []string{"r1", "r2"} {
		if err := db.AddCIRun(oltp.CIRun{RunID: id, Repo: "vault", Checkin: "c", Workflow: "w", Pipeline: "p", Status: "running"}); err != nil {
			t.Fatal(err)
		}
	}
	mint := func(run, letters string) (string, string) {
		login, value, _, err := db.MintRunToken(oltp.RunTokenSpec{Run: run, Repo: "vault", Job: "j" + letters, Letters: letters, Expires: time.Now().Add(time.Hour)})
		if err != nil {
			t.Fatal(err)
		}
		return login, value
	}
	writer, wv := mint("r1", "gio")
	reader, rv := mint("r2", "go")
	if code := g.callAPI("vault", writer, wv); code != http.StatusOK {
		t.Errorf("FAIL: a contents: write run token at the API door: %d", code)
	}
	if code := g.callAPI("vault", reader, rv); code != http.StatusForbidden {
		t.Errorf("FAIL: a contents: read run token on an op needing i: %d; want 403", code)
	}
	if code := g.callAPI("other", writer, wv); code == http.StatusOK {
		t.Errorf("FAIL: a run token reached a repository it does not name")
	}
	if !g.rg.SyncReadGate(basicReq(reader, rv), "vault", "") {
		t.Errorf("FAIL: a run token cannot clone its private repository over the sync lane's Basic round")
	}
	if g.rg.SyncReadGate(basicReq(reader, rv), "other", "") {
		t.Errorf("FAIL: a run token clones a private repository it does not name")
	}
	if err := db.CompleteCIRun("r1", "failed", ""); err != nil {
		t.Fatal(err)
	}
	if code := g.callAPI("vault", writer, wv); code != http.StatusUnauthorized {
		t.Errorf("FAIL: a failed run's token at the API door: %d; want 401", code)
	}
	req := httptest.NewRequest(http.MethodPost, "/api/v1/r/vault/door-test", nil)
	req.SetBasicAuth(writer, wv)
	w := httptest.NewRecorder()
	g.api.ServeHTTP(w, req)
	if w.Code != http.StatusUnauthorized || !strings.Contains(w.Body.String(), "is over") {
		t.Errorf("FAIL: a failed run's token was answered %d %q; want 401 saying the run is over", w.Code, w.Body)
	}
	if _, err := db.EndCIRun("r2", "cancelled", "timed out"); err != nil {
		t.Fatal(err)
	}
	if g.rg.SyncReadGate(basicReq(reader, rv), "vault", "") {
		t.Errorf("FAIL: an ended run's token still reads over sync")
	}
	if err := db.AddAccount("run-x", "pw-irrelevant-1", false); err == nil {
		t.Errorf("FAIL: an account named run-x was created")
	}
	t.Log("ok: run-<id> at the API door and the sync lane, its repository only, its letters only, ended with its run")
}