Block large files with the ability to exclude files

The following pre-hook makes it possible to block large files, but with the ability to exclude certain files with a regex.
The only wish I have is to make field mandatory or when checked, it should contain a value.

import com.atlassian.bitbucket.commit.Commit
import com.atlassian.bitbucket.content.Change
import com.atlassian.bitbucket.content.ContentService
import com.atlassian.bitbucket.hook.repository.RepositoryHookResult
import com.atlassian.bitbucket.repository.Repository
import com.atlassian.sal.api.component.ComponentLocator
import com.onresolve.scriptrunner.canned.bitbucket.util.LfsContentIdentifier
import com.onresolve.scriptrunner.parameters.annotation.ShortTextInput
import com.onresolve.scriptrunner.parameters.annotation.NumberInput
import com.onresolve.scriptrunner.parameters.annotation.Checkbox
import java.util.regex.Pattern

@NumberInput(label = 'Max file size for files', description = 'The maximum allowed file size.')
Integer maxFileSize

@Checkbox(label = 'Limit LFS file size', description = 'Limit the file size of LFS files.')
Boolean limitLFS

@NumberInput(label = 'Max file size for LFS files', description = 'The maximum allowed file size.')
Integer maxFileSizeLFS

@Checkbox(label = 'Exclude files with regex', description = 'Enable the option to exclude files from size limits.')
Boolean excludeFiles

@ShortTextInput(label = 'Regex', description = 'Regular expression used to exclude files from size limits. Please use <a href="https://regexr.com/">regexr.com</a> (javascript engine) for example to test your regular expression.')
String regexValue
def pattern = Pattern.compile(regexValue)

def contentService = ComponentLocator.getComponent(ContentService)
def rejectedFiles = []
def String outputMessage

def String lfsMessage
if (limitLFS) {
    lfsMessage= "LFS files are limited to " + maxFileSizeLFS + " bytes."
} else {
    lfsMessage= "No file size limit for LFS files."
}

// Function isInLfs() returns an error when file isn't stored in LFS
// Exception: com.atlassian.bitbucket.scm.CommandFailedException: '■■■ cat-file -p d2ebg338626f60egef98c424c6088e0a0e45a60' exited with code -1,001
def testIfLFS (com.atlassian.bitbucket.content.Change change, com.atlassian.bitbucket.repository.Repository repository) {
    try {
        return change.isInLfs(repository)
    } catch (Exception ex) {
        return false
    }
}

try {
    refChanges.any { refChange ->
        refChange.getChangesets(repository).each { changeSet ->
            changeSet.changes.values.each { change ->
                //log.warn("Full path to file: " + change.path.toString())
                // We do not check for delete operations.
                if (change.type.toString() != 'DELETE') {
                    if (excludeFiles && pattern.matcher(change.path.toString())) {
                        //log.warn("File is excluded from file size limits")
                    } else {
                        def boolean fileIsLFS = testIfLFS(change, repository)
                        def boolean fileToLarge = false
                        
                        def Integer currentFileSize = 0
                        if (fileIsLFS) {
                            if (limitLFS) {
                                currentFileSize = (LfsContentIdentifier.catFileAndReturnLfsContentCallback(change.contentId, repository)).getLfsFileSize()
                                
                                if (currentFileSize > maxFileSizeLFS) {
                                    fileToLarge = true
                                }
                            }
                        } else {
                            currentFileSize = ((contentService.getSize(repository, changeSet.toCommit.id, change.path.toString())).getAsLong()).toInteger()
                            
                            if (currentFileSize > maxFileSize) {
                                fileToLarge = true
                            }
                        }
                        
                        if (fileToLarge) {
                            //log.warn("Illegal large file \"" + change.path.toString() + "\" with a size of " + currentFileSize)
                            rejectedFiles.add(changeSet.toCommit.displayId + " contains large file " +
                                change.path.toString() +
                                " (" +
                                change.type.toString() +
                                ") " +
                                "by " +
                                changeSet.toCommit.author.name +
                                " with a size of " +
                                currentFileSize +
                                " bytes.")
                        }
                    }
                }
            }
        }
    }

    if (rejectedFiles.size() > 0) {

        outputMessage = "The Push is blocked because of the following files being larger then ${maxFileSize} bytes. " + lfsMessage
        rejectedFiles.each { line ->
            outputMessage = "${outputMessage}\n* ${line}"
        }
        
        //log.warn("New block message:\n" + outputMessage)
        return RepositoryHookResult.rejected("Push blocked", outputMessage)
    }

    return RepositoryHookResult.accepted()
}
catch (Exception ex) {
    log.error("Exception: ${ex}")
    return RepositoryHookResult.rejected("Push blocked", "Exception in pre-hook script for max file size")
}

Above script is broken, the function isInLfs doesn’t work, will try to fix it.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.