package cibridge
import (
"encoding/json"
"net/http"
"net/http/httptest"
"strings"
"testing"
)
// A RUNNER GETS ITS JOB'S RUN TOKEN ONLY FOR A TASK IT HOLDS (RFC 0021
// §runs). The body names nothing: what is minted is the forge's call
// from its own records, and a refusal is a note for the job's log.
func TestARunTokenGoesOnlyToTheRunnerHoldingTheTask(t *testing.T) {
engine := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/v1/tasks/run1.publish/resolve" || r.Header.Get("Authorization") != "Bearer CLAIMER" {
http.Error(w, "task not claimed by this token", http.StatusForbidden)
return
}
w.WriteHeader(http.StatusOK)
}))
defer engine.Close()
var asked []string
token := func(repo, taskID string) (map[string]string, string, error) {
asked = append(asked, repo+" "+taskID)
return map[string]string{"QUARRY_USER": "run-abc", "QUARRY_TOKEN": "qrt_abc_s3cret"}, "", nil
}
h, err := Handler(engine.URL, "ADMIN", func(string) string { return "g" }, func(r string) bool { return r == "alpha" }, nil, token)
if err != nil {
t.Fatal(err)
}
ask := func(bearer string) *httptest.ResponseRecorder {
req := httptest.NewRequest("POST", "/r/alpha/ci/bridge/v1/tasks/run1.publish/token", strings.NewReader(`{}`))
if bearer != "" {
req.Header.Set("Authorization", "Bearer "+bearer)
}
rec := httptest.NewRecorder()
h.ServeHTTP(rec, req)
return rec
}
rec := ask("CLAIMER")
var out struct {
Env map[string]string `json:"env"`
Note string `json:"note"`
}
json.Unmarshal(rec.Body.Bytes(), &out)
if rec.Code != 200 || out.Env["QUARRY_TOKEN"] != "qrt_abc_s3cret" || out.Env["QUARRY_USER"] != "run-abc" || rec.Header().Get("Cache-Control") != "no-store" {
t.Errorf("FAIL: the claiming runner got %d %q; want the token, uncached", rec.Code, rec.Body)
}
for _, b := range []string{"OTHER", "ADMIN", ""} {
if rec := ask(b); rec.Code < 400 || strings.Contains(rec.Body.String(), "s3cret") {
t.Errorf("FAIL: bearer %q got %d %q; want a refusal and no token", b, rec.Code, rec.Body)
}
}
if len(asked) != 1 {
t.Errorf("FAIL: the forge was asked %v; want only for the claiming runner", asked)
}
t.Log("ok: the token goes to the claiming runner alone, uncached")
}