bab29a83fa
Sweep all .go imports + go.mod, plus module-path refs in .golangci.yml, Dockerfile, swagger templates, locale example, and repo/wiki URLs (MokoGitea-Fork -> MokoGIT). Part of the MokoGIT rebrand. Claude-Session: https://claude.ai/code/session_01Bqe7fAuHQeiLueYfeHFrHw
121 lines
3.5 KiB
Go
121 lines
3.5 KiB
Go
// Copyright 2026 Moko Consulting <hello@mokoconsulting.tech>
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
package security
|
|
|
|
import (
|
|
"context"
|
|
|
|
git_model "code.mokoconsulting.tech/MokoConsulting/MokoGIT/models/git"
|
|
repo_model "code.mokoconsulting.tech/MokoConsulting/MokoGIT/models/repo"
|
|
security_model "code.mokoconsulting.tech/MokoConsulting/MokoGIT/models/security"
|
|
"code.mokoconsulting.tech/MokoConsulting/MokoGIT/modules/git"
|
|
"code.mokoconsulting.tech/MokoConsulting/MokoGIT/modules/log"
|
|
)
|
|
|
|
// ScanPushForSecrets checks a commit for secrets and returns findings.
|
|
// Used by the pre-receive hook to block pushes containing secrets.
|
|
func ScanPushForSecrets(ctx context.Context, repoID int64, commit *git.Commit) []Finding {
|
|
cfg, err := security_model.GetScannerConfig(ctx, repoID)
|
|
if err != nil {
|
|
log.Error("ScanPushForSecrets: GetScannerConfig: %v", err)
|
|
return nil
|
|
}
|
|
if !cfg.Enabled || !cfg.BlockOnPush || !cfg.SecretScanner {
|
|
// The owning organization may mandate secret blocking regardless of the
|
|
// repository's own scanner config (org push policy).
|
|
if !orgRequiresSecretBlock(ctx, repoID) {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
scanner := NewSecretScanner()
|
|
findings, err := scanner.ScanCommit(commit)
|
|
if err != nil {
|
|
log.Error("ScanPushForSecrets: ScanCommit: %v", err)
|
|
return nil
|
|
}
|
|
return findings
|
|
}
|
|
|
|
// orgRequiresSecretBlock reports whether the repo's owning organization mandates
|
|
// secret blocking on push via its org push policy.
|
|
func orgRequiresSecretBlock(ctx context.Context, repoID int64) bool {
|
|
repo, err := repo_model.GetRepositoryByID(ctx, repoID)
|
|
if err != nil {
|
|
log.Error("orgRequiresSecretBlock: GetRepositoryByID: %v", err)
|
|
return false
|
|
}
|
|
policy, err := git_model.GetOrgPushPolicyForRepo(ctx, repo)
|
|
if err != nil {
|
|
log.Error("orgRequiresSecretBlock: GetOrgPushPolicyForRepo: %v", err)
|
|
return false
|
|
}
|
|
return policy != nil && policy.RequireSecretBlock
|
|
}
|
|
|
|
// ScanOnPush runs enabled scanners against a commit pushed to the default branch.
|
|
// Called from services/repository/push.go on default branch pushes.
|
|
func ScanOnPush(ctx context.Context, repo *repo_model.Repository, commit *git.Commit) {
|
|
if commit == nil {
|
|
return
|
|
}
|
|
|
|
cfg, err := security_model.GetScannerConfig(ctx, repo.ID)
|
|
if err != nil {
|
|
log.Error("SecurityScan: GetScannerConfig for %s: %v", repo.FullName(), err)
|
|
return
|
|
}
|
|
if !cfg.Enabled {
|
|
return
|
|
}
|
|
|
|
var scanners []Scanner
|
|
if cfg.SecretScanner {
|
|
scanners = append(scanners, NewSecretScanner())
|
|
}
|
|
if cfg.DependScanner {
|
|
scanners = append(scanners, NewDependencyScanner())
|
|
}
|
|
if cfg.CodeScanner {
|
|
scanners = append(scanners, NewCodeScanner())
|
|
}
|
|
|
|
if len(scanners) == 0 {
|
|
return
|
|
}
|
|
|
|
totalFindings := 0
|
|
for _, s := range scanners {
|
|
findings, err := s.ScanTree(commit)
|
|
if err != nil {
|
|
log.Error("SecurityScan: %s scanner for %s: %v", s.Type(), repo.FullName(), err)
|
|
continue
|
|
}
|
|
|
|
for _, f := range findings {
|
|
alert := &security_model.SecurityAlert{
|
|
RepoID: repo.ID,
|
|
Scanner: f.Scanner,
|
|
Severity: f.Severity,
|
|
RuleID: f.RuleID,
|
|
Title: f.Title,
|
|
Description: f.Description,
|
|
FilePath: f.FilePath,
|
|
LineNumber: f.LineNumber,
|
|
CommitSHA: f.CommitSHA,
|
|
Fingerprint: f.Fingerprint,
|
|
Metadata: f.Metadata,
|
|
}
|
|
if err := security_model.CreateOrUpdateAlert(ctx, alert); err != nil {
|
|
log.Error("SecurityScan: CreateOrUpdateAlert: %v", err)
|
|
}
|
|
totalFindings++
|
|
}
|
|
}
|
|
|
|
if totalFindings > 0 {
|
|
log.Warn("SecurityScan: %d findings in %s", totalFindings, repo.FullName())
|
|
}
|
|
}
|