gitlab.com/jfprevost/gitlab-runner-notlscheck@v11.11.4+incompatible/common/support.go (about)

     1  package common
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/rand"
     6  	"crypto/rsa"
     7  	"crypto/x509"
     8  	"crypto/x509/pkix"
     9  	"encoding/pem"
    10  	"fmt"
    11  	"math/big"
    12  	"net/http"
    13  	"os"
    14  	"path"
    15  	"runtime"
    16  	"strings"
    17  	"time"
    18  
    19  	"github.com/tevino/abool"
    20  )
    21  
    22  const (
    23  	repoRemoteURL = "https://gitlab.com/gitlab-org/ci-cd/tests/gitlab-test.git"
    24  
    25  	repoRefType = RefTypeBranch
    26  
    27  	repoSHA       = "91956efe32fb7bef54f378d90c9bd74c19025872"
    28  	repoBeforeSHA = "ca50079dac5293292f83a4d454922ba8db44e7a3"
    29  	repoRefName   = "master"
    30  
    31  	repoLFSSHA       = "2371dd05e426fca09b0d2ec5d9ed757559035e2f"
    32  	repoLFSBeforeSHA = "91956efe32fb7bef54f378d90c9bd74c19025872"
    33  	repoLFSRefName   = "add-lfs-object"
    34  
    35  	repoSubmoduleLFSSHA       = "d0cb7ff49b5c4fcf159e860fd6b30ef40731c435"
    36  	repoSubmoduleLFSBeforeSHA = "dcbc4f0c93cb1731eeac4e3a70a55a991838e137"
    37  	repoSubmoduleLFSRefName   = "add-lfs-submodule"
    38  
    39  	FilesLFSFile1LFSsize = int64(2097152)
    40  )
    41  
    42  var (
    43  	gitLabComChain        string
    44  	gitLabComChainFetched *abool.AtomicBool
    45  )
    46  
    47  func init() {
    48  	gitLabComChainFetched = abool.New()
    49  }
    50  
    51  func GetGitInfo(url string) GitInfo {
    52  	return GitInfo{
    53  		RepoURL:   url,
    54  		Sha:       repoSHA,
    55  		BeforeSha: repoBeforeSHA,
    56  		Ref:       repoRefName,
    57  		RefType:   repoRefType,
    58  		Refspecs:  []string{"+refs/heads/*:refs/origin/heads/*", "+refs/tags/*:refs/tags/*"},
    59  	}
    60  }
    61  
    62  func GetLFSGitInfo(url string) GitInfo {
    63  	return GitInfo{
    64  		RepoURL:   url,
    65  		Sha:       repoLFSSHA,
    66  		BeforeSha: repoLFSBeforeSHA,
    67  		Ref:       repoLFSRefName,
    68  		RefType:   repoRefType,
    69  		Refspecs:  []string{"+refs/heads/*:refs/origin/heads/*", "+refs/tags/*:refs/tags/*"},
    70  	}
    71  }
    72  
    73  func GetSubmoduleLFSGitInfo(url string) GitInfo {
    74  	return GitInfo{
    75  		RepoURL:   url,
    76  		Sha:       repoSubmoduleLFSSHA,
    77  		BeforeSha: repoSubmoduleLFSBeforeSHA,
    78  		Ref:       repoSubmoduleLFSRefName,
    79  		RefType:   repoRefType,
    80  		Refspecs:  []string{"+refs/heads/*:refs/origin/heads/*", "+refs/tags/*:refs/tags/*"},
    81  	}
    82  }
    83  
    84  func GetSuccessfulBuild() (JobResponse, error) {
    85  	return GetLocalBuildResponse("echo Hello World")
    86  }
    87  
    88  func GetRemoteSuccessfulBuild() (JobResponse, error) {
    89  	return GetRemoteBuildResponse("echo Hello World")
    90  }
    91  
    92  func GetRemoteSuccessfulLFSBuild() (JobResponse, error) {
    93  	response, err := GetRemoteBuildResponse("echo Hello World")
    94  	response.GitInfo = GetLFSGitInfo(repoRemoteURL)
    95  
    96  	return response, err
    97  }
    98  
    99  func GetRemoteSuccessfulBuildWithAfterScript() (JobResponse, error) {
   100  	jobResponse, err := GetRemoteBuildResponse("echo Hello World")
   101  	jobResponse.Steps = append(jobResponse.Steps,
   102  		Step{
   103  			Name:   StepNameAfterScript,
   104  			Script: []string{"echo Hello World"},
   105  			When:   StepWhenAlways,
   106  		},
   107  	)
   108  	return jobResponse, err
   109  }
   110  
   111  func GetRemoteSuccessfulBuildWithDumpedVariables() (JobResponse, error) {
   112  	variableName := "test_dump"
   113  	variableValue := "test"
   114  
   115  	response, err := GetRemoteBuildResponse(
   116  		fmt.Sprintf("[[ \"${%s}\" != \"\" ]]", variableName),
   117  		fmt.Sprintf("[[ $(cat $%s) == \"%s\" ]]", variableName, variableValue),
   118  	)
   119  
   120  	if err != nil {
   121  		return JobResponse{}, err
   122  	}
   123  
   124  	dumpedVariable := JobVariable{
   125  		Key: variableName, Value: variableValue,
   126  		Internal: true, Public: true, File: true,
   127  	}
   128  	response.Variables = append(response.Variables, dumpedVariable)
   129  
   130  	return response, nil
   131  }
   132  
   133  func GetFailedBuild() (JobResponse, error) {
   134  	return GetLocalBuildResponse("exit 1")
   135  }
   136  
   137  func GetRemoteFailedBuild() (JobResponse, error) {
   138  	return GetRemoteBuildResponse("exit 1")
   139  }
   140  
   141  func GetLongRunningBuild() (JobResponse, error) {
   142  	return GetLocalBuildResponse("sleep 3600")
   143  }
   144  
   145  func GetRemoteLongRunningBuild() (JobResponse, error) {
   146  	return GetRemoteBuildResponse("sleep 3600")
   147  }
   148  
   149  func GetMultilineBashBuild() (JobResponse, error) {
   150  	return GetRemoteBuildResponse(`if true; then
   151  	bash \
   152  		--login \
   153  		-c 'echo Hello World'
   154  fi
   155  `)
   156  }
   157  
   158  func GetRemoteBrokenTLSBuild() (JobResponse, error) {
   159  	invalidCert, err := buildSnakeOilCert()
   160  	if err != nil {
   161  		return JobResponse{}, err
   162  	}
   163  
   164  	return getRemoteCustomTLSBuild(invalidCert)
   165  }
   166  
   167  func GetRemoteGitLabComTLSBuild() (JobResponse, error) {
   168  	cert, err := getGitLabComTLSChain()
   169  	if err != nil {
   170  		return JobResponse{}, err
   171  	}
   172  
   173  	return getRemoteCustomTLSBuild(cert)
   174  }
   175  
   176  func getRemoteCustomTLSBuild(chain string) (JobResponse, error) {
   177  	job, err := GetRemoteBuildResponse("echo Hello World")
   178  	if err != nil {
   179  		return JobResponse{}, err
   180  	}
   181  
   182  	job.TLSCAChain = chain
   183  	job.Variables = append(job.Variables,
   184  		JobVariable{Key: "GIT_STRATEGY", Value: "clone"},
   185  		JobVariable{Key: "GIT_SUBMODULE_STRATEGY", Value: "normal"})
   186  
   187  	return job, nil
   188  }
   189  
   190  func getBuildResponse(repoURL string, commands []string) JobResponse {
   191  	return JobResponse{
   192  		GitInfo: GetGitInfo(repoURL),
   193  		Steps: Steps{
   194  			Step{
   195  				Name:         StepNameScript,
   196  				Script:       commands,
   197  				When:         StepWhenAlways,
   198  				AllowFailure: false,
   199  			},
   200  		},
   201  	}
   202  }
   203  
   204  func GetRemoteBuildResponse(commands ...string) (JobResponse, error) {
   205  	return getBuildResponse(repoRemoteURL, commands), nil
   206  }
   207  
   208  func GetLocalBuildResponse(commands ...string) (JobResponse, error) {
   209  	localRepoURL, err := getLocalRepoURL()
   210  	if err != nil {
   211  		return JobResponse{}, err
   212  	}
   213  
   214  	return getBuildResponse(localRepoURL, commands), nil
   215  }
   216  
   217  func getLocalRepoURL() (string, error) {
   218  	_, filename, _, _ := runtime.Caller(0)
   219  
   220  	directory := path.Dir(filename)
   221  	if strings.Contains(directory, "_test/_obj_test") {
   222  		pwd, err := os.Getwd()
   223  		if err != nil {
   224  			return "", err
   225  		}
   226  		directory = pwd
   227  	}
   228  
   229  	localRepoURL := path.Clean(directory + "/../tmp/gitlab-test/.git")
   230  
   231  	_, err := os.Stat(localRepoURL)
   232  	if err != nil {
   233  		return "", err
   234  	}
   235  
   236  	return localRepoURL, nil
   237  }
   238  
   239  func buildSnakeOilCert() (string, error) {
   240  	priv, err := rsa.GenerateKey(rand.Reader, 1024)
   241  	if err != nil {
   242  		return "", err
   243  	}
   244  
   245  	notBefore := time.Now()
   246  	notAfter := notBefore.Add(time.Hour)
   247  
   248  	template := x509.Certificate{
   249  		SerialNumber: big.NewInt(1),
   250  		Subject: pkix.Name{
   251  			Organization: []string{"Snake Oil Co"},
   252  		},
   253  		NotBefore: notBefore,
   254  		NotAfter:  notAfter,
   255  
   256  		IsCA:                  true,
   257  		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
   258  		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
   259  		BasicConstraintsValid: true,
   260  	}
   261  
   262  	derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
   263  	if err != nil {
   264  		return "", err
   265  	}
   266  
   267  	certificate := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
   268  
   269  	return string(certificate), nil
   270  }
   271  
   272  func getGitLabComTLSChain() (string, error) {
   273  	if gitLabComChainFetched.IsSet() {
   274  		return gitLabComChain, nil
   275  	}
   276  
   277  	resp, err := http.Head("https://gitlab.com/users/sign_in")
   278  	if err != nil {
   279  		return "", err
   280  	}
   281  
   282  	var buff bytes.Buffer
   283  	for _, certs := range resp.TLS.VerifiedChains {
   284  		for _, cert := range certs {
   285  			err = pem.Encode(&buff, &pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw})
   286  			if err != nil {
   287  				return "", err
   288  			}
   289  		}
   290  	}
   291  
   292  	gitLabComChain = buff.String()
   293  	gitLabComChainFetched.Set()
   294  
   295  	return gitLabComChain, nil
   296  }