Skip to content

Commit 4fb2ffe

Browse files
committed
update
1 parent 4e5356b commit 4fb2ffe

File tree

1 file changed

+169
-0
lines changed

1 file changed

+169
-0
lines changed

experimental/rest/service.go

+169
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
package rest
2+
3+
import (
4+
"context"
5+
"encoding/base64"
6+
"encoding/json"
7+
"errors"
8+
"fmt"
9+
"io"
10+
"net/http"
11+
12+
"github.com/slsa-framework/slsa-verifier/verification"
13+
)
14+
15+
var errInvalid = errors.New("invalid")
16+
17+
type v1Query struct {
18+
// Compulsory fields.
19+
Source string `json:"source"`
20+
ArtifactHash string `json:"artifactHash"`
21+
DsseEnvelope string `json:"provenanceContent"`
22+
// Optional fields.
23+
Tag *string `json:"tag"`
24+
Branch *string `json:"branch"`
25+
VersionedTag *string `json:"versionedTag"`
26+
PrintProvenance *bool `json:"printProvenance"`
27+
}
28+
29+
type validation string
30+
31+
var (
32+
validationSuccess = validation("success")
33+
validationFailure = validation("failure")
34+
)
35+
36+
type v1Result struct {
37+
Version uint `json:"version"`
38+
Error *string `json:"error,omitempty"`
39+
Validation validation `json:"validation"`
40+
IntotoStatement *string `json:"provenanceContent,omitempty"`
41+
}
42+
43+
func VerifyHandlerV1(w http.ResponseWriter, r *http.Request) {
44+
if r == nil {
45+
http.Error(w, "empty request", http.StatusInternalServerError)
46+
return
47+
}
48+
49+
results := verifyHandlerV1(r)
50+
encoder := json.NewEncoder(w)
51+
if err := encoder.Encode(results); err != nil {
52+
http.Error(w, err.Error(), http.StatusInternalServerError)
53+
return
54+
}
55+
}
56+
57+
func toStringPtr(e error) *string {
58+
if e != nil {
59+
s := e.Error()
60+
return &s
61+
}
62+
return nil
63+
}
64+
65+
func v1ResultNew() *v1Result {
66+
return &v1Result{
67+
Version: 1,
68+
Error: nil,
69+
Validation: validationFailure,
70+
IntotoStatement: nil,
71+
}
72+
}
73+
74+
func (r *v1Result) withError(e error) *v1Result {
75+
r.Error = toStringPtr(e)
76+
return r
77+
}
78+
79+
func (r *v1Result) withValidation(v validation) *v1Result {
80+
r.Validation = v
81+
return r
82+
}
83+
84+
func (r *v1Result) withIntotoStatement(c []byte) *v1Result {
85+
b := base64.StdEncoding.EncodeToString(c)
86+
r.IntotoStatement = &b
87+
return r
88+
}
89+
90+
func verifyHandlerV1(r *http.Request) *v1Result {
91+
results := v1ResultNew()
92+
93+
body, err := io.ReadAll(r.Body)
94+
if err != nil {
95+
return results.withError(err)
96+
}
97+
r.Body.Close()
98+
99+
// Create a query.
100+
query, err := queryFromString(body)
101+
if err != nil {
102+
return results.withError(err)
103+
}
104+
105+
// Validate it.
106+
if err := query.validate(); err != nil {
107+
return results.withError(err)
108+
}
109+
110+
// Run the verification.
111+
branch := "main"
112+
if query.Branch != nil {
113+
branch = *query.Branch
114+
}
115+
provenanceOpts := &verification.ProvenanceOpts{
116+
ExpectedBranch: branch,
117+
ExpectedDigest: query.ArtifactHash,
118+
ExpectedVersionedTag: query.VersionedTag,
119+
ExpectedTag: query.Tag,
120+
}
121+
122+
ctx := context.Background()
123+
p, err := verification.Verify(ctx, []byte(query.DsseEnvelope),
124+
query.ArtifactHash, query.Source, provenanceOpts)
125+
if err != nil {
126+
return results.withError(err)
127+
}
128+
129+
if query.PrintProvenance != nil && *query.PrintProvenance {
130+
results = results.withIntotoStatement(p)
131+
}
132+
133+
return results.withValidation(validationSuccess)
134+
}
135+
136+
func queryFromString(content []byte) (*v1Query, error) {
137+
var query v1Query
138+
err := json.Unmarshal(content, &query)
139+
if err != nil {
140+
return nil, err
141+
}
142+
143+
env, err := base64.StdEncoding.DecodeString(query.DsseEnvelope)
144+
if err != nil {
145+
return nil, fmt.Errorf("%w: decoding payload", errInvalid)
146+
}
147+
query.DsseEnvelope = string(env)
148+
return &query, nil
149+
}
150+
151+
func (q *v1Query) validate() error {
152+
if q.Source == "" {
153+
return fmt.Errorf("%w: empty source", errInvalid)
154+
}
155+
156+
if q.ArtifactHash == "" {
157+
return fmt.Errorf("%w: empty artifactHash", errInvalid)
158+
}
159+
160+
if q.DsseEnvelope == "" {
161+
return fmt.Errorf("%w: empty dsseEnvelope", errInvalid)
162+
}
163+
164+
if q.Tag != nil && q.VersionedTag != nil {
165+
return fmt.Errorf("%w: tag and versionedTag are mutually exclusive", errInvalid)
166+
}
167+
168+
return nil
169+
}

0 commit comments

Comments
 (0)