Skip to content

Commit 46cad28

Browse files
authored
get compliance check results from ccp (#4177)
1 parent 75a906f commit 46cad28

File tree

7 files changed

+270
-1122
lines changed

7 files changed

+270
-1122
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ openapi.yaml
1818
.idea
1919
portercli
2020
local
21-
21+
go.work.sum
2222

2323
vendor
2424
**/*.env
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
package cluster
2+
3+
import (
4+
"net/http"
5+
6+
"connectrpc.com/connect"
7+
porterv1 "github.com/porter-dev/api-contracts/generated/go/porter/v1"
8+
"github.com/porter-dev/porter/api/server/handlers"
9+
"github.com/porter-dev/porter/api/server/shared"
10+
"github.com/porter-dev/porter/api/server/shared/apierrors"
11+
"github.com/porter-dev/porter/api/server/shared/config"
12+
"github.com/porter-dev/porter/api/types"
13+
"github.com/porter-dev/porter/internal/compliance"
14+
"github.com/porter-dev/porter/internal/models"
15+
"github.com/porter-dev/porter/internal/telemetry"
16+
)
17+
18+
// ListComplianceChecksHandler is the handler for /compliance/checks
19+
type ListComplianceChecksHandler struct {
20+
handlers.PorterHandlerReadWriter
21+
}
22+
23+
// NewListComplianceChecksHandler returns a new ListComplianceChecksHandler
24+
func NewListComplianceChecksHandler(
25+
config *config.Config,
26+
decoderValidator shared.RequestDecoderValidator,
27+
writer shared.ResultWriter,
28+
) *ListComplianceChecksHandler {
29+
return &ListComplianceChecksHandler{
30+
PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
31+
}
32+
}
33+
34+
// ListComplianceChecksRequest is the expected format for a request to /compliance/checks
35+
type ListComplianceChecksRequest struct {
36+
Vendor compliance.Vendor `schema:"vendor"`
37+
}
38+
39+
// ListComplianceChecksResponse is the expected format for a response from /compliance/checks
40+
type ListComplianceChecksResponse struct {
41+
CheckGroups []compliance.CheckGroup `json:"check_groups,omitempty"`
42+
VendorChecks []compliance.VendorComplianceCheck `json:"vendor_checks,omitempty"`
43+
}
44+
45+
// ServeHTTP retrieves the evaluated compliance checks for a cluster
46+
func (c *ListComplianceChecksHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
47+
ctx, span := telemetry.NewSpan(r.Context(), "serve-compliance-checks")
48+
defer span.End()
49+
50+
project, _ := ctx.Value(types.ProjectScope).(*models.Project)
51+
cluster, _ := ctx.Value(types.ClusterScope).(*models.Cluster)
52+
53+
request := &ListComplianceChecksRequest{}
54+
if ok := c.DecodeAndValidate(w, r, request); !ok {
55+
err := telemetry.Error(ctx, span, nil, "error decoding request")
56+
c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusBadRequest))
57+
return
58+
}
59+
60+
var vendor porterv1.EnumComplianceVendor
61+
if request.Vendor != "" {
62+
switch request.Vendor {
63+
case compliance.Vendor_Vanta:
64+
vendor = porterv1.EnumComplianceVendor_ENUM_COMPLIANCE_VENDOR_VANTA
65+
default:
66+
err := telemetry.Error(ctx, span, nil, "invalid vendor")
67+
c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusBadRequest))
68+
return
69+
}
70+
}
71+
72+
req := connect.NewRequest(&porterv1.ContractComplianceChecksRequest{
73+
ProjectId: int64(project.ID),
74+
ClusterId: int64(cluster.ID),
75+
Vendor: vendor,
76+
})
77+
78+
ccpResp, err := c.Config().ClusterControlPlaneClient.ContractComplianceChecks(ctx, req)
79+
if err != nil {
80+
err := telemetry.Error(ctx, span, err, "error calling ccp for contract compliance checks")
81+
c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError))
82+
return
83+
}
84+
if ccpResp == nil {
85+
err := telemetry.Error(ctx, span, err, "ccp resp is nil")
86+
c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError))
87+
return
88+
}
89+
if ccpResp.Msg == nil {
90+
err := telemetry.Error(ctx, span, err, "ccp resp msg is nil")
91+
c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError))
92+
return
93+
}
94+
95+
cgs, err := compliance.CheckGroupsFromProto(ctx, ccpResp.Msg.CheckGroups)
96+
if err != nil {
97+
err := telemetry.Error(ctx, span, err, "error converting compliance check groups from proto")
98+
c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError))
99+
return
100+
}
101+
telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "num-check-groups", Value: len(cgs)})
102+
103+
vendorChecks, err := compliance.VendorCheckGroupsFromProto(ctx, ccpResp.Msg.VendorChecks)
104+
if err != nil {
105+
err := telemetry.Error(ctx, span, err, "error converting vendor compliance check groups from proto")
106+
c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError))
107+
return
108+
}
109+
telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "num-vendor-checks", Value: len(vendorChecks)})
110+
111+
resp := &ListComplianceChecksResponse{
112+
CheckGroups: cgs,
113+
VendorChecks: vendorChecks,
114+
}
115+
116+
c.WriteResult(w, r, resp)
117+
w.WriteHeader(http.StatusOK)
118+
}

api/server/router/cluster.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,35 @@ func getClusterRoutes(
319319
Router: r,
320320
})
321321

322+
// GET /api/projects/{project_id}/clusters/{cluster_id}/compliance/checks -> cluster.NewListComplianceChecksHandler
323+
listComplianceChecksEndpoint := factory.NewAPIEndpoint(
324+
&types.APIRequestMetadata{
325+
Verb: types.APIVerbList,
326+
Method: types.HTTPVerbGet,
327+
Path: &types.Path{
328+
Parent: basePath,
329+
RelativePath: relPath + "/compliance/checks",
330+
},
331+
Scopes: []types.PermissionScope{
332+
types.UserScope,
333+
types.ProjectScope,
334+
types.ClusterScope,
335+
},
336+
},
337+
)
338+
339+
listComplianceChecksHandler := cluster.NewListComplianceChecksHandler(
340+
config,
341+
factory.GetDecoderValidator(),
342+
factory.GetResultWriter(),
343+
)
344+
345+
routes = append(routes, &router.Route{
346+
Endpoint: listComplianceChecksEndpoint,
347+
Handler: listComplianceChecksHandler,
348+
Router: r,
349+
})
350+
322351
if config.ServerConf.GithubIncomingWebhookSecret != "" {
323352

324353
// GET /api/projects/{project_id}/clusters/{cluster_id}/environments -> environment.NewListEnvironmentHandler

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ require (
8383
github.com/matryer/is v1.4.0
8484
github.com/nats-io/nats.go v1.24.0
8585
github.com/open-policy-agent/opa v0.44.0
86-
github.com/porter-dev/api-contracts v0.2.89
86+
github.com/porter-dev/api-contracts v0.2.90
8787
github.com/riandyrn/otelchi v0.5.1
8888
github.com/santhosh-tekuri/jsonschema/v5 v5.0.1
8989
github.com/stefanmcshane/helm v0.0.0-20221213002717-88a4a2c6e77d

go.sum

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1523,10 +1523,8 @@ github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77
15231523
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
15241524
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
15251525
github.com/polyfloyd/go-errorlint v0.0.0-20210722154253-910bb7978349/go.mod h1:wi9BfjxjF/bwiZ701TzmfKu6UKC357IOAtNr0Td0Lvw=
1526-
github.com/porter-dev/api-contracts v0.2.86 h1:uH6beKklp1YCzLBrtuuFVDwWfvQnlBWbxZBtDsO3+AI=
1527-
github.com/porter-dev/api-contracts v0.2.86/go.mod h1:fX6JmP5QuzxDLvqP3evFOTXjI4dHxsG0+VKNTjImZU8=
1528-
github.com/porter-dev/api-contracts v0.2.89 h1:ugkZr7aaANWdRFbkpeEHReyG1nWr31gx9c9dPvgkKMw=
1529-
github.com/porter-dev/api-contracts v0.2.89/go.mod h1:fX6JmP5QuzxDLvqP3evFOTXjI4dHxsG0+VKNTjImZU8=
1526+
github.com/porter-dev/api-contracts v0.2.90 h1:0ceIXz0xWNQpqVqhUMt3/RDeEawccfXx3KgM/tRg638=
1527+
github.com/porter-dev/api-contracts v0.2.90/go.mod h1:fX6JmP5QuzxDLvqP3evFOTXjI4dHxsG0+VKNTjImZU8=
15301528
github.com/porter-dev/switchboard v0.0.3 h1:dBuYkiVLa5Ce7059d6qTe9a1C2XEORFEanhbtV92R+M=
15311529
github.com/porter-dev/switchboard v0.0.3/go.mod h1:xSPzqSFMQ6OSbp42fhCi4AbGbQbsm6nRvOkrblFeXU4=
15321530
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=

0 commit comments

Comments
 (0)