drone/internal/api/controller/check/check_report.go
2023-06-15 21:27:06 +00:00

124 lines
3.4 KiB
Go

// Copyright 2022 Harness Inc. All rights reserved.
// Use of this source code is governed by the Polyform Free Trial License
// that can be found in the LICENSE.md file for this repository.
package check
import (
"context"
"encoding/json"
"fmt"
"regexp"
"time"
"github.com/harness/gitness/gitrpc"
"github.com/harness/gitness/internal/api/usererror"
"github.com/harness/gitness/internal/auth"
"github.com/harness/gitness/types"
"github.com/harness/gitness/types/enum"
)
type ReportInput struct {
CheckUID string `json:"check_uid"`
Status enum.CheckStatus `json:"status"`
Summary string `json:"summary"`
Link string `json:"link"`
Payload types.CheckPayload `json:"payload"`
}
var regexpCheckUID = "^[a-zA-Z_][0-9a-zA-Z-_.$]{0,127}$"
var matcherCheckUID = regexp.MustCompile(regexpCheckUID)
// Validate validates and sanitizes the ReportInput data.
func (in *ReportInput) Validate() error {
if in.CheckUID == "" {
return usererror.BadRequest("Status check UID is missing")
}
if !matcherCheckUID.MatchString(in.CheckUID) {
return usererror.BadRequestf("Status check UID must match the regular expression: %s", regexpCheckUID)
}
_, ok := in.Status.Sanitize()
if !ok {
return usererror.BadRequest("Invalid value provided for status check status")
}
payloadKind, ok := in.Payload.Kind.Sanitize()
if !ok {
return usererror.BadRequest("Invalid value provided for the payload type")
}
in.Payload.Kind = payloadKind
//nolint:gocritic // more values to follow on the enum (we want linter warning in case it is missed)
switch in.Payload.Kind {
case enum.CheckPayloadKindExternal:
// the default external type does not support payload: clear it here
in.Payload.Version = ""
in.Payload.Data = []byte{'{', '}'}
if in.Link == "" { // the link is mandatory for the external
return usererror.BadRequest("Link is missing")
}
}
return nil
}
// Report modifies an existing or creates a new (if none yet exists) status check report for a specific commit.
func (c *Controller) Report(
ctx context.Context,
session *auth.Session,
repoRef string,
commitSHA string,
in *ReportInput,
metadata map[string]string,
) (*types.Check, error) {
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionCommitCheckReport)
if err != nil {
return nil, fmt.Errorf("failed to acquire access access to repo: %w", err)
}
if errValidate := in.Validate(); errValidate != nil {
return nil, errValidate
}
if !gitrpc.ValidateCommitSHA(commitSHA) {
return nil, usererror.BadRequest("invalid commit SHA provided")
}
_, err = c.gitRPCClient.GetCommit(ctx, &gitrpc.GetCommitParams{
ReadParams: gitrpc.ReadParams{RepoUID: repo.GitUID},
SHA: commitSHA,
})
if err != nil {
return nil, fmt.Errorf("failed to commit sha=%s: %w", commitSHA, err)
}
now := time.Now().UnixMilli()
metadataJSON, _ := json.Marshal(metadata)
statusCheckReport := &types.Check{
CreatedBy: session.Principal.ID,
Created: now,
Updated: now,
RepoID: repo.ID,
CommitSHA: commitSHA,
UID: in.CheckUID,
Status: in.Status,
Summary: in.Summary,
Link: in.Link,
Payload: in.Payload,
Metadata: metadataJSON,
ReportedBy: *session.Principal.ToPrincipalInfo(),
}
err = c.checkStore.Upsert(ctx, statusCheckReport)
if err != nil {
return nil, fmt.Errorf("failed to upsert status check result for repo=%s: %w", repo.UID, err)
}
return statusCheckReport, nil
}