Skip to content

Commit c7ba616

Browse files
authored
Merge pull request #38 from veraison/tsm-report-token
Tsm report token
2 parents 6c72c4f + 27cc0bc commit c7ba616

File tree

6 files changed

+212
-3
lines changed

6 files changed

+212
-3
lines changed

.github/workflows/ci.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ jobs:
1717
- uses: actions/checkout@v4
1818

1919
- name: Set up Go
20-
uses: actions/setup-go@v4
20+
uses: actions/setup-go@v5
2121
with:
22-
go-version: '1.22'
22+
go-version: '1.24.1'
2323

2424
- name: Install Protoc
2525
uses: arduino/setup-protoc@v3

Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ build:
2222
.PHONY: test
2323
test:
2424
go test -v github.com/veraison/ratsd/api
25+
go test -v github.com/veraison/ratsd/tokens
2526

2627
.PHONY: clean
2728
clean:

go.mod

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
module github.com/veraison/ratsd
22

3-
go 1.22.7
3+
go 1.24.1
44

55
require (
6+
github.com/fxamacker/cbor/v2 v2.5.0
67
github.com/getkin/kin-openapi v0.128.0
78
github.com/hashicorp/go-plugin v1.4.4
89
github.com/moogar0880/problems v0.1.1
@@ -69,6 +70,7 @@ require (
6970
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
7071
github.com/ugorji/go/codec v1.2.11 // indirect
7172
github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect
73+
github.com/x448/float16 v0.8.4 // indirect
7274
go.uber.org/atomic v1.10.0 // indirect
7375
go.uber.org/multierr v1.11.0 // indirect
7476
golang.org/x/arch v0.7.0 // indirect
@@ -83,3 +85,5 @@ require (
8385
gopkg.in/yaml.v2 v2.4.0 // indirect
8486
gopkg.in/yaml.v3 v3.0.1 // indirect
8587
)
88+
89+
tool github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen

go.sum

+12
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo
8585
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
8686
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
8787
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
88+
github.com/fxamacker/cbor/v2 v2.5.0 h1:oHsG0V/Q6E/wqTS2O1Cozzsy69nqCiguo5Q1a1ADivE=
89+
github.com/fxamacker/cbor/v2 v2.5.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo=
8890
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
8991
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
9092
github.com/getkin/kin-openapi v0.128.0 h1:jqq3D9vC9pPq1dGcOCv7yOp1DaEe7c/T1vzcLbITSp4=
@@ -246,6 +248,7 @@ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwd
246248
github.com/moogar0880/problems v0.1.1 h1:bktLhq8NDG/czU2ZziYNigBFksx13RaYe5AVdNmHDT4=
247249
github.com/moogar0880/problems v0.1.1/go.mod h1:5Dxrk2sD7BfBAgnOzQ1yaTiuCYdGPUh49L8Vhfky62c=
248250
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
251+
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
249252
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
250253
github.com/oapi-codegen/oapi-codegen/v2 v2.4.1 h1:ykgG34472DWey7TSjd8vIfNykXgjOgYJZoQbKfEeY/Q=
251254
github.com/oapi-codegen/oapi-codegen/v2 v2.4.1/go.mod h1:N5+lY1tiTDV3V1BeHtOxeWXHoPVeApvsvjJqegfoaz8=
@@ -256,13 +259,16 @@ github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQ
256259
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
257260
github.com/onsi/ginkgo v1.10.2/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
258261
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
262+
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
259263
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
260264
github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
261265
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
262266
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
263267
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
264268
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
265269
github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
270+
github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE=
271+
github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg=
266272
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
267273
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
268274
github.com/pelletier/go-toml/v2 v2.2.0 h1:QLgLl2yMN7N+ruc31VynXs1vhMZa7CeHHejIeBAsoHo=
@@ -280,6 +286,7 @@ github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:
280286
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
281287
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
282288
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
289+
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
283290
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
284291
github.com/speakeasy-api/openapi-overlay v0.9.0 h1:Wrz6NO02cNlLzx1fB093lBlYxSI54VRhy1aSutx0PQg=
285292
github.com/speakeasy-api/openapi-overlay v0.9.0/go.mod h1:f5FloQrHA7MsxYg9djzMD5h6dxrHjVVByWKh7an8TRc=
@@ -319,6 +326,8 @@ github.com/veraison/services v0.0.2501 h1:tK4a92RvceURIlT0pEkz3fU0TpaZ9jbcWqkPRk
319326
github.com/veraison/services v0.0.2501/go.mod h1:snBdw93xJ4j9sSrYueT3QlAB8oWGePwkq7H+kYf/lLc=
320327
github.com/vmware-labs/yaml-jsonpath v0.3.2 h1:/5QKeCBGdsInyDCyVNLbXyilb61MXGi9NP674f9Hobk=
321328
github.com/vmware-labs/yaml-jsonpath v0.3.2/go.mod h1:U6whw1z03QyqgWdgXxvVnQ90zN1BWz5V+51Ewf8k+rQ=
329+
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
330+
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
322331
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
323332
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
324333
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@@ -440,6 +449,8 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ
440449
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
441450
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
442451
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
452+
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
453+
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
443454
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
444455
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
445456
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -665,6 +676,7 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
665676
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
666677
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
667678
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
679+
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
668680
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
669681
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
670682
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

tokens/tsm-report.go

+113
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
package tokens
2+
3+
import (
4+
"encoding/base64"
5+
"encoding/json"
6+
"errors"
7+
"fmt"
8+
9+
"github.com/fxamacker/cbor/v2"
10+
)
11+
12+
const (
13+
TSMReportMediaTypeCBOR = "application/vnd.veraison.tsm-report+cbor"
14+
TSMReportMediaTypeJSON = "application/vnd.veraison.tsm-report+json"
15+
)
16+
17+
// BinaryString is base64url (§5 of RFC4648) without padding.
18+
type BinaryString []byte
19+
20+
// MarshalJSON encodes BinaryString as JSON
21+
func (o BinaryString) MarshalJSON() ([]byte, error) {
22+
return json.Marshal(
23+
base64.RawURLEncoding.EncodeToString(o),
24+
)
25+
}
26+
27+
// UnmarshalJSON decodes BinaryString from JSON
28+
func (o *BinaryString) UnmarshalJSON(b []byte) error {
29+
var s string
30+
31+
if err := json.Unmarshal(b, &s); err != nil {
32+
return err
33+
}
34+
35+
decoded, err := base64.RawURLEncoding.DecodeString(s)
36+
if err != nil {
37+
return err
38+
}
39+
40+
*o = decoded
41+
return nil
42+
}
43+
44+
// TSMReport represents the TSM report generated by Linux
45+
// see docs/tsm-report.cddl for definition
46+
type TSMReport struct {
47+
AuxBlob BinaryString `json:"auxblob,omitempty"`
48+
OutBlob BinaryString `json:"outblob"`
49+
Provider string `json:"provider"`
50+
ManifestBlob BinaryString `json:"manifestblob,omitempty"`
51+
ServiceProvider *string `json:"service_provider,omitempty"`
52+
}
53+
54+
// Valid checks if the TSMReport is populated correctly
55+
func (t *TSMReport) Valid() error {
56+
if len(t.OutBlob) == 0 {
57+
return errors.New(`missing mandatory field "outblob"`)
58+
}
59+
60+
if t.Provider == "" {
61+
return errors.New(`missing mandatory field "provider"`)
62+
}
63+
64+
if len(t.ManifestBlob) > 0 && (t.ServiceProvider == nil || len(*t.ServiceProvider) == 0) {
65+
return errors.New(`stray field "manifestblob"`)
66+
}
67+
68+
return nil
69+
}
70+
71+
// ToJSON encodes TSMReport as JSON
72+
func (t *TSMReport) ToJSON() ([]byte, error) {
73+
if err := t.Valid(); err != nil {
74+
return nil, fmt.Errorf("JSON encoding failed: %w", err)
75+
}
76+
77+
return json.Marshal(t)
78+
}
79+
80+
// FromJSON decodes TSMReport from JSON
81+
func (t *TSMReport) FromJSON(data []byte) error {
82+
if err := json.Unmarshal(data, t); err != nil {
83+
return fmt.Errorf("JSON decoding failed: %w", err)
84+
}
85+
86+
if err := t.Valid(); err != nil {
87+
return fmt.Errorf("JSON decoding failed: %w", err)
88+
}
89+
90+
return nil
91+
}
92+
93+
// ToCBOR encodes TSMReport as CBOR
94+
func (t *TSMReport) ToCBOR() ([]byte, error) {
95+
if err := t.Valid(); err != nil {
96+
return nil, fmt.Errorf("CBOR encoding failed: %w", err)
97+
}
98+
99+
return cbor.Marshal(t)
100+
}
101+
102+
// FromCBOR decodes TSMReport from CBOR
103+
func (t *TSMReport) FromCBOR(data []byte) error {
104+
if err := cbor.Unmarshal(data, t); err != nil {
105+
return fmt.Errorf("CBOR decoding failed: %w", err)
106+
}
107+
108+
if err := t.Valid(); err != nil {
109+
return fmt.Errorf("CBOR decoding failed: %w", err)
110+
}
111+
112+
return nil
113+
}

tokens/tsm-report_test.go

+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// Copyright 2025 Contributors to the Veraison project.
2+
// SPDX-License-Identifier: Apache-2.0
3+
package tokens
4+
5+
import (
6+
"github.com/stretchr/testify/assert"
7+
"reflect"
8+
"testing"
9+
)
10+
11+
var provider = "sev_guest"
12+
var serviceProvider = "svsm"
13+
var outblob = []byte{117, 24, 74, 133, 21, 198, 189, 177, 81, 18, 129, 84}
14+
var auxblob = []byte{120, 112, 34, 102, 228, 162, 111, 217, 232, 169, 167, 213, 197, 209, 94, 121, 161, 231, 170, 64}
15+
var manifestblob = []byte{170, 13, 189, 115, 132, 249, 168, 13, 253, 229, 76, 198}
16+
17+
func Test_TSMReport_Valid_Pass(t *testing.T) {
18+
report := &TSMReport{
19+
Provider: provider,
20+
OutBlob: outblob,
21+
AuxBlob: auxblob,
22+
ServiceProvider: &serviceProvider,
23+
ManifestBlob: manifestblob,
24+
}
25+
26+
assert.NoError(t, report.Valid())
27+
}
28+
29+
func Test_TSMReport_Valid_Fail_ManifestBlob(t *testing.T) {
30+
report := &TSMReport{
31+
Provider: provider,
32+
OutBlob: outblob,
33+
AuxBlob: auxblob,
34+
ManifestBlob: manifestblob,
35+
}
36+
37+
assert.EqualError(t, report.Valid(), `stray field "manifestblob"`)
38+
}
39+
40+
func Test_TSMReport_Valid_Fail_MandatoryField(t *testing.T) {
41+
report := &TSMReport{
42+
OutBlob: outblob,
43+
AuxBlob: auxblob,
44+
}
45+
46+
assert.EqualError(t, report.Valid(), `missing mandatory field "provider"`)
47+
}
48+
49+
func Test_TSMReport_JSON_SerDes_Pass(t *testing.T) {
50+
report := &TSMReport{
51+
Provider: provider,
52+
OutBlob: outblob,
53+
AuxBlob: auxblob,
54+
}
55+
56+
encodedJson, err := report.ToJSON()
57+
assert.NoError(t, err)
58+
59+
decodedReport := &TSMReport{}
60+
assert.NoError(t, decodedReport.FromJSON(encodedJson))
61+
62+
assert.True(t, reflect.DeepEqual(report, decodedReport))
63+
}
64+
65+
func Test_TSMReport_CBOR_SerDes_Pass(t *testing.T) {
66+
report := &TSMReport{
67+
Provider: provider,
68+
OutBlob: outblob,
69+
AuxBlob: auxblob,
70+
}
71+
72+
encodedCbor, err := report.ToCBOR()
73+
assert.NoError(t, err)
74+
75+
decodedReport := &TSMReport{}
76+
assert.NoError(t, decodedReport.FromCBOR(encodedCbor))
77+
78+
assert.True(t, reflect.DeepEqual(report, decodedReport))
79+
}

0 commit comments

Comments
 (0)