Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 17 additions & 15 deletions api/api.gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 24 additions & 0 deletions api/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,24 @@ func (s *Server) RatsdChares(w http.ResponseWriter, r *http.Request, param Ratsd
return
}

var options map[string]json.RawMessage
if len(requestData.AttesterSelection) > 0 {
err := json.Unmarshal(requestData.AttesterSelection, &options)
if err != nil {
errMsg := fmt.Sprintf(
"failed to parse attester selection: %s", err.Error())
p := &problems.DefaultProblem{
Type: string(TagGithubCom2024VeraisonratsdErrorInvalidrequest),
Title: string(InvalidRequest),
Detail: errMsg,
Status: http.StatusBadRequest,
}
s.reportProblem(w, p)
fmt.Println(errMsg)
return
}
}

for _, pn := range pl {
attester, err := s.manager.LookupByName(pn)
if err != nil {
Expand All @@ -130,10 +148,16 @@ func (s *Server) RatsdChares(w http.ResponseWriter, r *http.Request, param Ratsd
continue
}

params, hasOption := options[pn]
if !hasOption {
params = json.RawMessage{}
}

s.logger.Info("output content type: ", formatOut.Formats[0].ContentType)
in := &compositor.EvidenceIn{
ContentType: formatOut.Formats[0].ContentType,
Nonce: nonce,
Options: params,
}

out := attester.GetEvidence(in)
Expand Down
175 changes: 113 additions & 62 deletions api/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,34 +79,57 @@ func TestRatsdChares_wrong_accept_type(t *testing.T) {
assert.Equal(t, expectedBody, &body)
}

func TestRatsdChares_missing_nonce(t *testing.T) {
func TestRatsdChares_invalid_body(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()

var params RatsdCharesParams

param := fmt.Sprintf(`application/eat-ucs+json; eat_profile=%q`, TagGithubCom2024Veraisonratsd)
params.Accept = &param
logger := log.Named("test")
s := &Server{logger: logger}
w := httptest.NewRecorder()
rb := strings.NewReader("{\"noncee\": \"MIDBNH28iioisjPy\"}")
r, _ := http.NewRequest(http.MethodPost, "/ratsd/chares", rb)
r.Header.Add("Content-Type", ApplicationvndVeraisonCharesJson)
s.RatsdChares(w, r, params)

expectedCode := http.StatusBadRequest
expectedType := problems.ProblemMediaType
expectedBody := &problems.DefaultProblem{
Type: string(TagGithubCom2024VeraisonratsdErrorInvalidrequest),
Title: string(InvalidRequest),
Status: http.StatusBadRequest,
Detail: "fail to retrieve nonce from the request",
}
pluginList := []string{"mock-tsm"}
dm := mock_deps.NewMockIManager(ctrl)
dm.EXPECT().GetPluginList().Return(pluginList).AnyTimes()
dm.EXPECT().LookupByName("mock-tsm").Return(mocktsm.GetPlugin(), nil).AnyTimes()

var body problems.DefaultProblem
_ = json.Unmarshal(w.Body.Bytes(), &body)
s := NewServer(logger, dm)
tests := []struct{ name, body, msg string }{
{"missing nonce", `{"noncee": "MIDBNH28iioisjPy"}`,
"fail to retrieve nonce from the request"},
{"invlid attester selecton",
fmt.Sprintf(`{"nonce": "%s",
"attester-selection": "attester-slection"}`, validNonce),
"failed to parse attester selection: json: cannot unmarshal string into" +
` Go value of type map[string]json.RawMessage`},
}

assert.Equal(t, expectedCode, w.Code)
assert.Equal(t, expectedType, w.Result().Header.Get("Content-Type"))
assert.Equal(t, expectedBody, &body)
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
w := httptest.NewRecorder()
rb := strings.NewReader(tt.body)
r, _ := http.NewRequest(http.MethodPost, "/ratsd/chares", rb)
r.Header.Add("Content-Type", ApplicationvndVeraisonCharesJson)
s.RatsdChares(w, r, params)

expectedCode := http.StatusBadRequest
expectedType := problems.ProblemMediaType
expectedBody := &problems.DefaultProblem{
Type: string(TagGithubCom2024VeraisonratsdErrorInvalidrequest),
Title: string(InvalidRequest),
Status: http.StatusBadRequest,
Detail: tt.msg,
}

var body problems.DefaultProblem
_ = json.Unmarshal(w.Body.Bytes(), &body)

assert.Equal(t, expectedCode, w.Code)
assert.Equal(t, expectedType, w.Result().Header.Get("Content-Type"))
assert.Equal(t, expectedBody, &body)
})
}
}

func TestRatsdChares_valid_request_no_available_attester(t *testing.T) {
Expand All @@ -125,7 +148,7 @@ func TestRatsdChares_valid_request_no_available_attester(t *testing.T) {

s := NewServer(logger, dm)
w := httptest.NewRecorder()
rs := fmt.Sprintf("{\"nonce\": \"%s\"}", validNonce)
rs := fmt.Sprintf(`{"nonce": "%s"}`, validNonce)
rb := strings.NewReader(rs)
r, _ := http.NewRequest(http.MethodPost, "/ratsd/chares", rb)
r.Header.Add("Content-Type", ApplicationvndVeraisonCharesJson)
Expand Down Expand Up @@ -156,49 +179,77 @@ func TestRatsdChares_valid_request(t *testing.T) {

pluginList := []string{"mock-tsm"}
dm := mock_deps.NewMockIManager(ctrl)
dm.EXPECT().GetPluginList().Return(pluginList)
dm.EXPECT().LookupByName("mock-tsm").Return(mocktsm.GetPlugin(), nil)
dm.EXPECT().GetPluginList().Return(pluginList).AnyTimes()
dm.EXPECT().LookupByName("mock-tsm").Return(mocktsm.GetPlugin(), nil).AnyTimes()

s := NewServer(logger, dm)
w := httptest.NewRecorder()
rs := fmt.Sprintf("{\"nonce\": \"%s\"}", validNonce)
rb := strings.NewReader(rs)
r, _ := http.NewRequest(http.MethodPost, "/ratsd/chares", rb)
r.Header.Add("Content-Type", ApplicationvndVeraisonCharesJson)
s.RatsdChares(w, r, params)

expectedCode := http.StatusOK
expectedType := param

assert.Equal(t, expectedCode, w.Code)
assert.Equal(t, expectedType, w.Result().Header.Get("Content-Type"))

var out map[string]string
json.Unmarshal(w.Body.Bytes(), &out)
assert.Equal(t, string(TagGithubCom2024Veraisonratsd), out["eat_profile"])
assert.Equal(t, validNonce, out["eat_nonce"])
assert.Contains(t, out, "cmw")

data, err := base64.StdEncoding.DecodeString(out["cmw"])
assert.NoError(t, err)

collection := &cmw.CMW{}
err = collection.UnmarshalJSON([]byte(data))
assert.NoError(t, err)
assert.Equal(t, cmw.KindCollection, collection.GetKind())

c, err := collection.GetCollectionItem("mock-tsm")
assert.NoError(t, err)
assert.Equal(t, cmw.KindMonad, c.GetKind())
assert.Equal(t, c.GetMonadType(), "application/vnd.veraison.configfs-tsm+json")

tsmout := &tokens.TSMReport{}
tsmout.FromJSON(c.GetMonadValue())
assert.Equal(t, "fake\n", tsmout.Provider)
realNonce, _ := base64.RawURLEncoding.DecodeString(validNonce)

assert.Equal(t, tokens.BinaryString("auxblob"), tsmout.AuxBlob)
tests := []struct {
name, query string
privlevel int
}{
{
"no params",
fmt.Sprintf(`{"nonce": "%s"}`, validNonce),
0,
},
{
"with params",
fmt.Sprintf(`{"nonce": "%s",
"attester-selection":{
"mock-tsm":{
"privilege_level":"1"
}
}
}`, validNonce),
1,
},
}

realNonce, _ := base64.RawURLEncoding.DecodeString(validNonce)
expectedOutblob := fmt.Sprintf("privlevel: 0\ninblob: %s", hex.EncodeToString([]byte(realNonce)))
assert.Equal(t, tokens.BinaryString(expectedOutblob), tsmout.OutBlob)
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
w := httptest.NewRecorder()
rb := strings.NewReader(tt.query)
r, _ := http.NewRequest(http.MethodPost, "/ratsd/chares", rb)
r.Header.Add("Content-Type", ApplicationvndVeraisonCharesJson)
s.RatsdChares(w, r, params)

expectedCode := http.StatusOK
expectedType := param

assert.Equal(t, expectedCode, w.Code)
assert.Equal(t, expectedType, w.Result().Header.Get("Content-Type"))

var out map[string]string
err := json.Unmarshal(w.Body.Bytes(), &out)
assert.NoError(t, err)
assert.Equal(t, string(TagGithubCom2024Veraisonratsd), out["eat_profile"])
assert.Equal(t, validNonce, out["eat_nonce"])
assert.Contains(t, out, "cmw")

data, err := base64.StdEncoding.DecodeString(out["cmw"])
assert.NoError(t, err)

collection := &cmw.CMW{}
err = collection.UnmarshalJSON([]byte(data))
assert.NoError(t, err)
assert.Equal(t, cmw.KindCollection, collection.GetKind())

c, err := collection.GetCollectionItem("mock-tsm")
assert.NoError(t, err)
assert.Equal(t, cmw.KindMonad, c.GetKind())
assert.Equal(t, c.GetMonadType(), "application/vnd.veraison.configfs-tsm+json")

tsmout := &tokens.TSMReport{}
tsmout.FromJSON(c.GetMonadValue())
assert.Equal(t, "fake\n", tsmout.Provider)

assert.Equal(t, tokens.BinaryString("auxblob"), tsmout.AuxBlob)

expectedOutblob := fmt.Sprintf("privlevel: %d\ninblob: %s", tt.privlevel,
hex.EncodeToString([]byte(realNonce)))
assert.Equal(t, tokens.BinaryString(expectedOutblob), tsmout.OutBlob)
})
}
}
21 changes: 21 additions & 0 deletions attesters/mocktsm/mocktsm.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
package mocktsm

import (
"encoding/json"
"fmt"
"strconv"

"github.com/google/go-configfs-tsm/configfs/configfsi"
"github.com/google/go-configfs-tsm/configfs/faketsm"
Expand Down Expand Up @@ -77,6 +79,25 @@ func (m *MockPlugin) GetEvidence(in *compositor.EvidenceIn) *compositor.Evidence
GetAuxBlob: true,
}

options := make(map[string]string)
if len(in.Options) > 0 {
if err := json.Unmarshal(in.Options, &options); err != nil {
errMsg := fmt.Errorf(
"failed to parse %s: %v", in.Options, err)
return getEvidenceError(errMsg)
}
}

if privlevel, ok := options["privilege_level"]; ok {
level, err := strconv.Atoi(privlevel)
if err != nil || level < 0 {
errMsg := fmt.Errorf("privilege_level %s is invalid",
privlevel)
return getEvidenceError(errMsg)
}
req.Privilege = &report.Privilege{Level: uint(level)}
}

resp, err := report.Get(m.client, req)
if err != nil {
errMsg := fmt.Errorf("failed to get mock TSM report: %v", err)
Expand Down
Loading