drone/git/pre_receive_pre_processor.go
Darko Draskovic 07224c37de feat: [CODE-3352]: Add git pre-receive preprocessor (#3535)
* Replace map[string]string with []CommitInfo in FindCommitterMismatchOutput
* Merge remote-tracking branch 'origin/main' into dd/pre-preceive-preprocessor
* Merge remote-tracking branch 'origin/main' into dd/pre-preceive-preprocessor
* Add total to FindCommitterMismatchOutput
* Reuse changedRefs for only deleted branches on push check
* Merge remote-tracking branch 'origin/main' into dd/pre-preceive-preprocessor
* Fix typo commiter -> committer
* Rename listAllObjects in listGitObjDir and loop thru dirs outside listGitObjDir
* Use line with commiter prefix to find commiter email
* Merge remote-tracking branch 'origin/main' into dd/pre-preceive-preprocessor
* Merge remote-tracking branch 'origin/main' into dd/pre-preceive-preprocessor
* Rename vars and add total to findOversizeFiles
* Use CatFileBatch instead of git show info to find commiter emails and remove unused CatFileBatchCheck
* Use WithAlternateObjectDirs in findCommiterEmailsMismatch
* Merge remote-tracking branch 'origin/mai
2025-03-18 20:21:28 +00:00

209 lines
5.0 KiB
Go

// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package git
import (
"context"
"fmt"
"io"
"strings"
"github.com/harness/gitness/git/api"
"github.com/harness/gitness/git/parser"
"github.com/harness/gitness/git/sha"
)
const (
maxOversizeFiles = 10
maxCommitterMismatches = 10
)
type FindOversizeFilesParams struct {
// TODO: remove. Kept for backward compatibility
RepoUID string
GitObjectDirs []string
SizeLimit int64
}
type FileInfo struct {
SHA sha.SHA
Size int64
}
type FindOversizeFilesOutput struct {
FileInfos []FileInfo
Total int64
}
type FindCommitterMismatchParams struct {
PrincipalEmail string
}
type CommitInfo struct {
SHA sha.SHA
Committer string
}
type FindCommitterMismatchOutput struct {
CommitInfos []CommitInfo
Total int64
}
type ProcessPreReceiveObjectsParams struct {
ReadParams
FindOversizeFilesParams *FindOversizeFilesParams
FindCommitterMismatchParams *FindCommitterMismatchParams
}
type ProcessPreReceiveObjectsOutput struct {
FindOversizeFilesOutput *FindOversizeFilesOutput
FindCommitterMismatchOutput *FindCommitterMismatchOutput
}
func (s *Service) ProcessPreReceiveObjects(
ctx context.Context,
params ProcessPreReceiveObjectsParams,
) (ProcessPreReceiveObjectsOutput, error) {
repoPath := getFullPathForRepo(s.reposRoot, params.RepoUID)
var objects []parser.BatchCheckObject
for _, gitObjDir := range params.AlternateObjectDirs {
objs, err := s.listGitObjDir(ctx, repoPath, gitObjDir)
if err != nil {
return ProcessPreReceiveObjectsOutput{}, err
}
objects = append(objects, objs...)
}
var output ProcessPreReceiveObjectsOutput
if params.FindOversizeFilesParams != nil {
output.FindOversizeFilesOutput = findOversizeFiles(
objects, params.FindOversizeFilesParams,
)
}
if params.FindCommitterMismatchParams != nil {
out, err := findCommitterMismatch(
ctx,
objects,
repoPath,
params.ReadParams.AlternateObjectDirs,
params.FindCommitterMismatchParams,
)
if err != nil {
return ProcessPreReceiveObjectsOutput{}, err
}
output.FindCommitterMismatchOutput = out
}
return output, nil
}
func findOversizeFiles(
objects []parser.BatchCheckObject,
findOversizeFilesParams *FindOversizeFilesParams,
) *FindOversizeFilesOutput {
var fileInfos []FileInfo
var total int64 // limit the total num of objects returned
for _, obj := range objects {
if obj.Type == string(TreeNodeTypeBlob) && obj.Size > findOversizeFilesParams.SizeLimit {
if total < maxOversizeFiles {
fileInfos = append(fileInfos, FileInfo{
SHA: obj.SHA,
Size: obj.Size,
})
}
total++
}
}
return &FindOversizeFilesOutput{
FileInfos: fileInfos,
Total: total,
}
}
func findCommitterMismatch(
ctx context.Context,
objects []parser.BatchCheckObject,
repoPath string,
alternateObjectDirs []string,
findCommitterEmailsMismatchParams *FindCommitterMismatchParams,
) (*FindCommitterMismatchOutput, error) {
var commitSHAs []string
for _, obj := range objects {
if obj.Type == string(TreeNodeTypeCommit) {
commitSHAs = append(commitSHAs, obj.SHA.String())
}
}
writer, reader, cancel := api.CatFileBatch(ctx, repoPath, alternateObjectDirs)
defer cancel()
defer writer.Close()
var total int64
var commitInfos []CommitInfo
for _, commitSHA := range commitSHAs {
_, writeErr := writer.Write([]byte(commitSHA + "\n"))
if writeErr != nil {
return nil, fmt.Errorf("failed to write to cat-file batch: %w", writeErr)
}
output, err := api.ReadBatchHeaderLine(reader)
if err != nil {
return nil, fmt.Errorf("failed to read cat-file batch header: %w", err)
}
limitedReader := io.LimitReader(reader, output.Size+1) // plus eol
data, err := io.ReadAll(limitedReader)
if err != nil {
return nil, fmt.Errorf("failed to read: %w", err)
}
text := strings.Split(string(data), "\n")
for _, line := range text {
if !strings.HasPrefix(line, "committer ") {
continue
}
committerEmail := line[strings.Index(line, "<")+1 : strings.Index(line, ">")]
if !strings.EqualFold(committerEmail, findCommitterEmailsMismatchParams.PrincipalEmail) {
if total < maxCommitterMismatches {
sha, err := sha.New(commitSHA)
if err != nil {
return nil, fmt.Errorf("failed to create new sha: %w", err)
}
commitInfos = append(commitInfos, CommitInfo{
SHA: sha,
Committer: committerEmail,
})
}
total++
}
break
}
}
return &FindCommitterMismatchOutput{
CommitInfos: commitInfos,
Total: total,
}, nil
}