Skip to content

Commit e87d675

Browse files
committed
Return meaningful EAT in chares
Endpoint chares now gathers the output of GetEvidence() from each sub-attesters, combines them into a CMW collection, and wrap it as an EAT in its response. If there are multiple supported format available from a sub-attesters, ratsd core picks the first available format from GetSupportedFormats() Signed-off-by: Ian Chin Wang <[email protected]>
1 parent 3497638 commit e87d675

File tree

10 files changed

+300
-16
lines changed

10 files changed

+300
-16
lines changed

.github/workflows/ci.yml

+3
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ jobs:
3333
- name: Install protoc-gen-go-grpc
3434
run: go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
3535

36+
- name: Install mockgen
37+
run: go install github.com/golang/mock/[email protected]
38+
3639
- name: Generate protobufs and ratsd server
3740
run: go generate ./...
3841

api/mocks/imanager.go

+92
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/mocks/ipluggable.go

+77
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/server.go

+82-4
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,16 @@
33
package api
44

55
import (
6+
"encoding/base64"
67
"encoding/json"
78
"fmt"
89
"io"
910
"net/http"
1011

1112
"github.com/moogar0880/problems"
13+
"github.com/veraison/cmw"
14+
"github.com/veraison/ratsd/plugin"
15+
"github.com/veraison/ratsd/proto/compositor"
1216
"go.uber.org/zap"
1317
)
1418

@@ -18,12 +22,14 @@ const (
1822
)
1923

2024
type Server struct {
21-
logger *zap.SugaredLogger
25+
logger *zap.SugaredLogger
26+
manager plugin.IManager
2227
}
2328

24-
func NewServer(logger *zap.SugaredLogger) *Server {
29+
func NewServer(logger *zap.SugaredLogger, manager plugin.IManager) *Server {
2530
return &Server{
26-
logger: logger,
31+
logger: logger,
32+
manager: manager,
2733
}
2834
}
2935

@@ -77,8 +83,80 @@ func (s *Server) RatsdChares(w http.ResponseWriter, r *http.Request, param Ratsd
7783
return
7884
}
7985

86+
nonce, err := base64.RawURLEncoding.DecodeString(requestData.Nonce)
87+
if err != nil {
88+
errMsg := fmt.Sprintf("fail to decode nonce from the request: %s", err.Error())
89+
p := &problems.DefaultProblem{
90+
Type: string(TagGithubCom2024VeraisonratsdErrorInvalidrequest),
91+
Title: string(InvalidRequest),
92+
Detail: errMsg,
93+
Status: http.StatusBadRequest,
94+
}
95+
s.reportProblem(w, p)
96+
return
97+
}
8098
s.logger.Info("request nonce: ", requestData.Nonce)
99+
s.logger.Info("request media type: ", *(param.Accept))
100+
101+
// Use a map until we finalize ratsd output format
102+
eat := make(map[string]interface{})
103+
collection := cmw.NewCollection("tag:ietf.org,2025:ratsd")
104+
eat["eat_profile"] = TagGithubCom2024Veraisonratsd
105+
eat["eat_nonce"] = requestData.Nonce
106+
pl := s.manager.GetPluginList()
107+
if len(pl) == 0 {
108+
errMsg := "no sub-attester available"
109+
p := problems.NewDetailedProblem(http.StatusInternalServerError, errMsg)
110+
s.reportProblem(w, p)
111+
return
112+
}
113+
114+
for _, pn := range s.manager.GetPluginList() {
115+
attester, err := s.manager.LookupByName(pn)
116+
if err != nil {
117+
errMsg := fmt.Sprintf(
118+
"failed to get handle from %s: %s", pn, err.Error())
119+
p := problems.NewDetailedProblem(http.StatusInternalServerError, errMsg)
120+
s.reportProblem(w, p)
121+
return
122+
}
123+
124+
formatOut := attester.GetSupportedFormats()
125+
if !formatOut.Status.Result || len(formatOut.Formats) == 0 {
126+
errMsg := fmt.Sprintf("no supported formats from attester %s: %s ",
127+
pn, formatOut.Status.Error)
128+
s.logger.Info(errMsg)
129+
continue
130+
}
131+
132+
s.logger.Info("output content type: ", formatOut.Formats[0].ContentType)
133+
in := &compositor.EvidenceIn{
134+
ContentType: formatOut.Formats[0].ContentType,
135+
Nonce: nonce,
136+
}
137+
138+
out := attester.GetEvidence(in)
139+
if !out.Status.Result {
140+
errMsg := fmt.Sprintf(
141+
"failed to get attestation report from %s: %s ", pn, out.Status.Error)
142+
p := problems.NewDetailedProblem(http.StatusInternalServerError, errMsg)
143+
s.reportProblem(w, p)
144+
return
145+
}
146+
147+
c := cmw.NewMonad(in.ContentType, out.Evidence)
148+
collection.AddCollectionItem(pn, c)
149+
}
150+
151+
serialized, err := collection.MarshalJSON()
152+
if err != nil {
153+
errMsg := fmt.Sprintf("failed to serialize CMW collection: %s", err.Error())
154+
p := problems.NewDetailedProblem(http.StatusInternalServerError, errMsg)
155+
s.reportProblem(w, p)
156+
return
157+
}
158+
eat["cmw"] = serialized
81159
w.Header().Set("Content-Type", respCt)
82160
w.WriteHeader(http.StatusOK)
83-
w.Write([]byte("hello from ratsd!"))
161+
json.NewEncoder(w).Encode(eat)
84162
}

api/server_test.go

+24-8
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,16 @@ import (
1010
"strings"
1111
"testing"
1212

13+
"github.com/golang/mock/gomock"
1314
"github.com/moogar0880/problems"
1415
"github.com/stretchr/testify/assert"
16+
mock_deps "github.com/veraison/ratsd/api/mocks"
1517
"github.com/veraison/services/log"
1618
)
1719

1820
const (
19-
jsonType = "application/json"
21+
jsonType = "application/json"
22+
validNonce = "TUlEQk5IMjhpaW9pc2pQeXh4eHh4eHh4eHh4eHh4eHg"
2023
)
2124

2225
func TestRatsdChares_wrong_content_type(t *testing.T) {
@@ -101,24 +104,37 @@ func TestRatsdChares_missing_nonce(t *testing.T) {
101104
assert.Equal(t, expectedBody, &body)
102105
}
103106

104-
func TestRatsdChares_valid_request(t *testing.T) {
107+
func TestRatsdChares_valid_request_no_available_attester(t *testing.T) {
108+
ctrl := gomock.NewController(t)
109+
defer ctrl.Finish()
110+
105111
var params RatsdCharesParams
106112

107113
param := fmt.Sprintf(`application/eat+jwt; eat_profile=%q`, TagGithubCom2024Veraisonratsd)
108114
params.Accept = &param
109115
logger := log.Named("test")
110-
s := &Server{logger: logger}
116+
117+
pluginList := []string{}
118+
dm := mock_deps.NewMockIManager(ctrl)
119+
dm.EXPECT().GetPluginList().Return(pluginList)
120+
121+
s := NewServer(logger, dm)
111122
w := httptest.NewRecorder()
112-
rb := strings.NewReader("{\"nonce\": \"MIDBNH28iioisjPy\"}")
123+
rs := fmt.Sprintf("{\"nonce\": \"%s\"}", validNonce)
124+
rb := strings.NewReader(rs)
113125
r, _ := http.NewRequest(http.MethodPost, "/ratsd/chares", rb)
114126
r.Header.Add("Content-Type", ApplicationvndVeraisonCharesJson)
115127
s.RatsdChares(w, r, params)
116128

117-
expectedCode := http.StatusOK
118-
expectedType := param
119-
expectedBody := "hello from ratsd!"
129+
expectedCode := http.StatusInternalServerError
130+
expectedType := problems.ProblemMediaType
131+
expectedDetail := "no sub-attester available"
132+
expectedBody := problems.NewDetailedProblem(http.StatusInternalServerError, expectedDetail)
133+
134+
var body problems.DefaultProblem
135+
_ = json.Unmarshal(w.Body.Bytes(), &body)
120136

121137
assert.Equal(t, expectedCode, w.Code)
122138
assert.Equal(t, expectedType, w.Result().Header.Get("Content-Type"))
123-
assert.Equal(t, expectedBody, w.Body.String())
139+
assert.Equal(t, expectedBody, &body)
124140
}

cmd/main.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ func main() {
8484

8585
log.Info("Loaded sub-attesters:", pluginManager.GetPluginList())
8686

87-
svr := api.NewServer(log.Named("api"))
87+
svr := api.NewServer(log.Named("api"), pluginManager)
8888
r := http.NewServeMux()
8989
options := api.StdHTTPServerOptions{
9090
BaseRouter: r,

go.mod

+3-1
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@ module github.com/veraison/ratsd
33
go 1.24.1
44

55
require (
6-
github.com/fxamacker/cbor/v2 v2.5.0
6+
github.com/fxamacker/cbor/v2 v2.7.0
77
github.com/getkin/kin-openapi v0.128.0
8+
github.com/golang/mock v1.6.0
89
github.com/google/go-configfs-tsm v0.3.2
910
github.com/hashicorp/go-plugin v1.4.4
1011
github.com/moogar0880/problems v0.1.1
1112
github.com/oapi-codegen/runtime v1.1.1
1213
github.com/stretchr/testify v1.9.0
14+
github.com/veraison/cmw v0.1.2-0.20250109140511-d907dcce0c61
1315
github.com/veraison/services v0.0.2501
1416
go.uber.org/zap v1.23.0
1517
google.golang.org/grpc v1.64.0

0 commit comments

Comments
 (0)