2019-10-16 16:42:42 +03:00
// Copyright 2019 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package integrations
import (
"encoding/base64"
"fmt"
"net/url"
"os"
"testing"
2021-11-16 11:53:21 +03:00
"code.gitea.io/gitea/models/unittest"
2021-11-24 12:49:20 +03:00
user_model "code.gitea.io/gitea/models/user"
2019-10-16 16:42:42 +03:00
"code.gitea.io/gitea/modules/process"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
2020-08-11 23:05:34 +03:00
"code.gitea.io/gitea/modules/util"
2021-11-17 15:34:35 +03:00
2019-10-16 16:42:42 +03:00
"github.com/stretchr/testify/assert"
"golang.org/x/crypto/openpgp"
"golang.org/x/crypto/openpgp/armor"
)
func TestGPGGit ( t * testing . T ) {
2019-12-08 04:14:50 +03:00
defer prepareTestEnv ( t ) ( )
2019-10-16 16:42:42 +03:00
username := "user2"
// OK Set a new GPG home
2021-09-22 08:38:34 +03:00
tmpDir , err := os . MkdirTemp ( "" , "temp-gpg" )
2019-10-16 16:42:42 +03:00
assert . NoError ( t , err )
2020-08-11 23:05:34 +03:00
defer util . RemoveAll ( tmpDir )
2019-10-16 16:42:42 +03:00
2022-01-20 20:46:10 +03:00
err = os . Chmod ( tmpDir , 0 o700 )
2019-10-16 16:42:42 +03:00
assert . NoError ( t , err )
oldGNUPGHome := os . Getenv ( "GNUPGHOME" )
err = os . Setenv ( "GNUPGHOME" , tmpDir )
assert . NoError ( t , err )
defer os . Setenv ( "GNUPGHOME" , oldGNUPGHome )
// Need to create a root key
2019-12-15 19:21:16 +03:00
rootKeyPair , err := importTestingKey ( tmpDir , "gitea" , "gitea@fake.local" )
2019-10-16 16:42:42 +03:00
assert . NoError ( t , err )
2019-12-15 19:21:16 +03:00
if err != nil {
assert . FailNow ( t , "Unable to import rootKeyPair" )
}
2019-10-16 16:42:42 +03:00
rootKeyID := rootKeyPair . PrimaryKey . KeyIdShortString ( )
oldKeyID := setting . Repository . Signing . SigningKey
oldName := setting . Repository . Signing . SigningName
oldEmail := setting . Repository . Signing . SigningEmail
defer func ( ) {
setting . Repository . Signing . SigningKey = oldKeyID
setting . Repository . Signing . SigningName = oldName
setting . Repository . Signing . SigningEmail = oldEmail
} ( )
setting . Repository . Signing . SigningKey = rootKeyID
setting . Repository . Signing . SigningName = "gitea"
setting . Repository . Signing . SigningEmail = "gitea@fake.local"
2021-11-24 12:49:20 +03:00
user := unittest . AssertExistsAndLoadBean ( t , & user_model . User { Name : username } ) . ( * user_model . User )
2019-10-16 16:42:42 +03:00
2019-11-14 00:06:35 +03:00
setting . Repository . Signing . InitialCommit = [ ] string { "never" }
setting . Repository . Signing . CRUDActions = [ ] string { "never" }
baseAPITestContext := NewAPITestContext ( t , username , "repo1" )
onGiteaRun ( t , func ( t * testing . T , u * url . URL ) {
u . Path = baseAPITestContext . GitPath ( )
t . Run ( "Unsigned-Initial" , func ( t * testing . T ) {
2019-11-26 02:21:37 +03:00
defer PrintCurrentTest ( t ) ( )
2019-11-14 00:06:35 +03:00
testCtx := NewAPITestContext ( t , username , "initial-unsigned" )
t . Run ( "CreateRepository" , doAPICreateRepository ( testCtx , false ) )
t . Run ( "CheckMasterBranchUnsigned" , doAPIGetBranch ( testCtx , "master" , func ( t * testing . T , branch api . Branch ) {
assert . NotNil ( t , branch . Commit )
assert . NotNil ( t , branch . Commit . Verification )
assert . False ( t , branch . Commit . Verification . Verified )
assert . Empty ( t , branch . Commit . Verification . Signature )
2019-10-16 16:42:42 +03:00
} ) )
2019-11-14 00:06:35 +03:00
t . Run ( "CreateCRUDFile-Never" , crudActionCreateFile (
t , testCtx , user , "master" , "never" , "unsigned-never.txt" , func ( t * testing . T , response api . FileResponse ) {
assert . False ( t , response . Verification . Verified )
} ) )
t . Run ( "CreateCRUDFile-Never" , crudActionCreateFile (
t , testCtx , user , "never" , "never2" , "unsigned-never2.txt" , func ( t * testing . T , response api . FileResponse ) {
assert . False ( t , response . Verification . Verified )
} ) )
} )
} , false )
setting . Repository . Signing . CRUDActions = [ ] string { "parentsigned" }
onGiteaRun ( t , func ( t * testing . T , u * url . URL ) {
u . Path = baseAPITestContext . GitPath ( )
t . Run ( "Unsigned-Initial-CRUD-ParentSigned" , func ( t * testing . T ) {
2019-11-26 02:21:37 +03:00
defer PrintCurrentTest ( t ) ( )
2019-11-14 00:06:35 +03:00
testCtx := NewAPITestContext ( t , username , "initial-unsigned" )
t . Run ( "CreateCRUDFile-ParentSigned" , crudActionCreateFile (
t , testCtx , user , "master" , "parentsigned" , "signed-parent.txt" , func ( t * testing . T , response api . FileResponse ) {
assert . False ( t , response . Verification . Verified )
} ) )
t . Run ( "CreateCRUDFile-ParentSigned" , crudActionCreateFile (
t , testCtx , user , "parentsigned" , "parentsigned2" , "signed-parent2.txt" , func ( t * testing . T , response api . FileResponse ) {
assert . False ( t , response . Verification . Verified )
} ) )
} )
} , false )
setting . Repository . Signing . CRUDActions = [ ] string { "never" }
onGiteaRun ( t , func ( t * testing . T , u * url . URL ) {
u . Path = baseAPITestContext . GitPath ( )
t . Run ( "Unsigned-Initial-CRUD-Never" , func ( t * testing . T ) {
2019-11-26 02:21:37 +03:00
defer PrintCurrentTest ( t ) ( )
2019-11-14 00:06:35 +03:00
testCtx := NewAPITestContext ( t , username , "initial-unsigned" )
t . Run ( "CreateCRUDFile-Never" , crudActionCreateFile (
t , testCtx , user , "parentsigned" , "parentsigned-never" , "unsigned-never2.txt" , func ( t * testing . T , response api . FileResponse ) {
assert . False ( t , response . Verification . Verified )
} ) )
} )
} , false )
setting . Repository . Signing . CRUDActions = [ ] string { "always" }
onGiteaRun ( t , func ( t * testing . T , u * url . URL ) {
u . Path = baseAPITestContext . GitPath ( )
t . Run ( "Unsigned-Initial-CRUD-Always" , func ( t * testing . T ) {
2019-11-26 02:21:37 +03:00
defer PrintCurrentTest ( t ) ( )
2019-11-14 00:06:35 +03:00
testCtx := NewAPITestContext ( t , username , "initial-unsigned" )
t . Run ( "CreateCRUDFile-Always" , crudActionCreateFile (
t , testCtx , user , "master" , "always" , "signed-always.txt" , func ( t * testing . T , response api . FileResponse ) {
2019-12-15 19:21:16 +03:00
assert . NotNil ( t , response . Verification )
if response . Verification == nil {
assert . FailNow ( t , "no verification provided with response! %v" , response )
return
}
2019-11-14 00:06:35 +03:00
assert . True ( t , response . Verification . Verified )
2019-11-26 18:35:41 +03:00
if ! response . Verification . Verified {
t . FailNow ( )
return
}
2019-11-14 00:06:35 +03:00
assert . Equal ( t , "gitea@fake.local" , response . Verification . Signer . Email )
} ) )
t . Run ( "CreateCRUDFile-ParentSigned-always" , crudActionCreateFile (
t , testCtx , user , "parentsigned" , "parentsigned-always" , "signed-parent2.txt" , func ( t * testing . T , response api . FileResponse ) {
2019-12-15 19:21:16 +03:00
assert . NotNil ( t , response . Verification )
if response . Verification == nil {
assert . FailNow ( t , "no verification provided with response! %v" , response )
return
}
2019-11-14 00:06:35 +03:00
assert . True ( t , response . Verification . Verified )
2019-11-26 18:35:41 +03:00
if ! response . Verification . Verified {
t . FailNow ( )
return
}
2019-11-14 00:06:35 +03:00
assert . Equal ( t , "gitea@fake.local" , response . Verification . Signer . Email )
} ) )
} )
} , false )
setting . Repository . Signing . CRUDActions = [ ] string { "parentsigned" }
onGiteaRun ( t , func ( t * testing . T , u * url . URL ) {
u . Path = baseAPITestContext . GitPath ( )
t . Run ( "Unsigned-Initial-CRUD-ParentSigned" , func ( t * testing . T ) {
2019-11-26 02:21:37 +03:00
defer PrintCurrentTest ( t ) ( )
2019-11-14 00:06:35 +03:00
testCtx := NewAPITestContext ( t , username , "initial-unsigned" )
t . Run ( "CreateCRUDFile-Always-ParentSigned" , crudActionCreateFile (
t , testCtx , user , "always" , "always-parentsigned" , "signed-always-parentsigned.txt" , func ( t * testing . T , response api . FileResponse ) {
2019-12-15 19:21:16 +03:00
assert . NotNil ( t , response . Verification )
if response . Verification == nil {
assert . FailNow ( t , "no verification provided with response! %v" , response )
return
}
2019-11-14 00:06:35 +03:00
assert . True ( t , response . Verification . Verified )
2019-11-26 18:35:41 +03:00
if ! response . Verification . Verified {
t . FailNow ( )
return
}
2019-11-14 00:06:35 +03:00
assert . Equal ( t , "gitea@fake.local" , response . Verification . Signer . Email )
} ) )
} )
} , false )
setting . Repository . Signing . InitialCommit = [ ] string { "always" }
onGiteaRun ( t , func ( t * testing . T , u * url . URL ) {
u . Path = baseAPITestContext . GitPath ( )
t . Run ( "AlwaysSign-Initial" , func ( t * testing . T ) {
2019-11-26 02:21:37 +03:00
defer PrintCurrentTest ( t ) ( )
2019-11-14 00:06:35 +03:00
testCtx := NewAPITestContext ( t , username , "initial-always" )
t . Run ( "CreateRepository" , doAPICreateRepository ( testCtx , false ) )
t . Run ( "CheckMasterBranchSigned" , doAPIGetBranch ( testCtx , "master" , func ( t * testing . T , branch api . Branch ) {
assert . NotNil ( t , branch . Commit )
2019-12-15 19:21:16 +03:00
if branch . Commit == nil {
assert . FailNow ( t , "no commit provided with branch! %v" , branch )
return
}
2019-11-14 00:06:35 +03:00
assert . NotNil ( t , branch . Commit . Verification )
2019-12-15 19:21:16 +03:00
if branch . Commit . Verification == nil {
assert . FailNow ( t , "no verification provided with branch commit! %v" , branch . Commit )
return
}
2019-11-14 00:06:35 +03:00
assert . True ( t , branch . Commit . Verification . Verified )
2019-11-26 18:35:41 +03:00
if ! branch . Commit . Verification . Verified {
t . FailNow ( )
return
}
2019-11-14 00:06:35 +03:00
assert . Equal ( t , "gitea@fake.local" , branch . Commit . Verification . Signer . Email )
2019-10-16 16:42:42 +03:00
} ) )
2019-11-14 00:06:35 +03:00
} )
} , false )
setting . Repository . Signing . CRUDActions = [ ] string { "never" }
onGiteaRun ( t , func ( t * testing . T , u * url . URL ) {
u . Path = baseAPITestContext . GitPath ( )
t . Run ( "AlwaysSign-Initial-CRUD-Never" , func ( t * testing . T ) {
2019-11-26 02:21:37 +03:00
defer PrintCurrentTest ( t ) ( )
2019-11-26 18:35:41 +03:00
testCtx := NewAPITestContext ( t , username , "initial-always-never" )
t . Run ( "CreateRepository" , doAPICreateRepository ( testCtx , false ) )
2019-11-14 00:06:35 +03:00
t . Run ( "CreateCRUDFile-Never" , crudActionCreateFile (
t , testCtx , user , "master" , "never" , "unsigned-never.txt" , func ( t * testing . T , response api . FileResponse ) {
assert . False ( t , response . Verification . Verified )
} ) )
} )
} , false )
setting . Repository . Signing . CRUDActions = [ ] string { "parentsigned" }
onGiteaRun ( t , func ( t * testing . T , u * url . URL ) {
u . Path = baseAPITestContext . GitPath ( )
t . Run ( "AlwaysSign-Initial-CRUD-ParentSigned-On-Always" , func ( t * testing . T ) {
2019-11-26 02:21:37 +03:00
defer PrintCurrentTest ( t ) ( )
2019-11-26 18:35:41 +03:00
testCtx := NewAPITestContext ( t , username , "initial-always-parent" )
t . Run ( "CreateRepository" , doAPICreateRepository ( testCtx , false ) )
2019-11-14 00:06:35 +03:00
t . Run ( "CreateCRUDFile-ParentSigned" , crudActionCreateFile (
t , testCtx , user , "master" , "parentsigned" , "signed-parent.txt" , func ( t * testing . T , response api . FileResponse ) {
assert . True ( t , response . Verification . Verified )
2019-11-26 18:35:41 +03:00
if ! response . Verification . Verified {
t . FailNow ( )
return
}
2019-11-14 00:06:35 +03:00
assert . Equal ( t , "gitea@fake.local" , response . Verification . Signer . Email )
} ) )
} )
} , false )
setting . Repository . Signing . CRUDActions = [ ] string { "always" }
onGiteaRun ( t , func ( t * testing . T , u * url . URL ) {
u . Path = baseAPITestContext . GitPath ( )
t . Run ( "AlwaysSign-Initial-CRUD-Always" , func ( t * testing . T ) {
2019-11-26 02:21:37 +03:00
defer PrintCurrentTest ( t ) ( )
2019-11-26 18:35:41 +03:00
testCtx := NewAPITestContext ( t , username , "initial-always-always" )
t . Run ( "CreateRepository" , doAPICreateRepository ( testCtx , false ) )
2019-11-14 00:06:35 +03:00
t . Run ( "CreateCRUDFile-Always" , crudActionCreateFile (
t , testCtx , user , "master" , "always" , "signed-always.txt" , func ( t * testing . T , response api . FileResponse ) {
assert . True ( t , response . Verification . Verified )
2019-11-26 18:35:41 +03:00
if ! response . Verification . Verified {
t . FailNow ( )
return
}
2019-11-14 00:06:35 +03:00
assert . Equal ( t , "gitea@fake.local" , response . Verification . Signer . Email )
} ) )
} )
} , false )
var pr api . PullRequest
setting . Repository . Signing . Merges = [ ] string { "commitssigned" }
onGiteaRun ( t , func ( t * testing . T , u * url . URL ) {
u . Path = baseAPITestContext . GitPath ( )
t . Run ( "UnsignedMerging" , func ( t * testing . T ) {
2019-11-26 02:21:37 +03:00
defer PrintCurrentTest ( t ) ( )
2019-11-14 00:06:35 +03:00
testCtx := NewAPITestContext ( t , username , "initial-unsigned" )
var err error
t . Run ( "CreatePullRequest" , func ( t * testing . T ) {
pr , err = doAPICreatePullRequest ( testCtx , testCtx . Username , testCtx . Reponame , "master" , "never2" ) ( t )
assert . NoError ( t , err )
} )
t . Run ( "MergePR" , doAPIMergePullRequest ( testCtx , testCtx . Username , testCtx . Reponame , pr . Index ) )
t . Run ( "CheckMasterBranchUnsigned" , doAPIGetBranch ( testCtx , "master" , func ( t * testing . T , branch api . Branch ) {
assert . NotNil ( t , branch . Commit )
assert . NotNil ( t , branch . Commit . Verification )
assert . False ( t , branch . Commit . Verification . Verified )
assert . Empty ( t , branch . Commit . Verification . Signature )
2019-10-16 16:42:42 +03:00
} ) )
2019-11-14 00:06:35 +03:00
} )
} , false )
setting . Repository . Signing . Merges = [ ] string { "basesigned" }
onGiteaRun ( t , func ( t * testing . T , u * url . URL ) {
u . Path = baseAPITestContext . GitPath ( )
t . Run ( "BaseSignedMerging" , func ( t * testing . T ) {
2019-11-26 02:21:37 +03:00
defer PrintCurrentTest ( t ) ( )
2019-11-14 00:06:35 +03:00
testCtx := NewAPITestContext ( t , username , "initial-unsigned" )
var err error
t . Run ( "CreatePullRequest" , func ( t * testing . T ) {
pr , err = doAPICreatePullRequest ( testCtx , testCtx . Username , testCtx . Reponame , "master" , "parentsigned2" ) ( t )
assert . NoError ( t , err )
} )
t . Run ( "MergePR" , doAPIMergePullRequest ( testCtx , testCtx . Username , testCtx . Reponame , pr . Index ) )
t . Run ( "CheckMasterBranchUnsigned" , doAPIGetBranch ( testCtx , "master" , func ( t * testing . T , branch api . Branch ) {
assert . NotNil ( t , branch . Commit )
assert . NotNil ( t , branch . Commit . Verification )
assert . False ( t , branch . Commit . Verification . Verified )
assert . Empty ( t , branch . Commit . Verification . Signature )
2019-10-16 16:42:42 +03:00
} ) )
2019-11-14 00:06:35 +03:00
} )
} , false )
setting . Repository . Signing . Merges = [ ] string { "commitssigned" }
onGiteaRun ( t , func ( t * testing . T , u * url . URL ) {
u . Path = baseAPITestContext . GitPath ( )
t . Run ( "CommitsSignedMerging" , func ( t * testing . T ) {
2019-11-26 02:21:37 +03:00
defer PrintCurrentTest ( t ) ( )
2019-11-14 00:06:35 +03:00
testCtx := NewAPITestContext ( t , username , "initial-unsigned" )
var err error
t . Run ( "CreatePullRequest" , func ( t * testing . T ) {
pr , err = doAPICreatePullRequest ( testCtx , testCtx . Username , testCtx . Reponame , "master" , "always-parentsigned" ) ( t )
assert . NoError ( t , err )
} )
t . Run ( "MergePR" , doAPIMergePullRequest ( testCtx , testCtx . Username , testCtx . Reponame , pr . Index ) )
t . Run ( "CheckMasterBranchUnsigned" , doAPIGetBranch ( testCtx , "master" , func ( t * testing . T , branch api . Branch ) {
assert . NotNil ( t , branch . Commit )
assert . NotNil ( t , branch . Commit . Verification )
assert . True ( t , branch . Commit . Verification . Verified )
2019-10-16 16:42:42 +03:00
} ) )
} )
2019-11-14 00:06:35 +03:00
} , false )
2019-10-16 16:42:42 +03:00
}
2021-11-24 12:49:20 +03:00
func crudActionCreateFile ( t * testing . T , ctx APITestContext , user * user_model . User , from , to , path string , callback ... func ( * testing . T , api . FileResponse ) ) func ( * testing . T ) {
2019-10-16 16:42:42 +03:00
return doAPICreateFile ( ctx , path , & api . CreateFileOptions {
FileOptions : api . FileOptions {
BranchName : from ,
NewBranchName : to ,
Message : fmt . Sprintf ( "from:%s to:%s path:%s" , from , to , path ) ,
Author : api . Identity {
Name : user . FullName ,
Email : user . Email ,
} ,
Committer : api . Identity {
Name : user . FullName ,
Email : user . Email ,
} ,
} ,
2019-11-26 18:35:41 +03:00
Content : base64 . StdEncoding . EncodeToString ( [ ] byte ( fmt . Sprintf ( "This is new text for %s" , path ) ) ) ,
2019-10-16 16:42:42 +03:00
} , callback ... )
}
2019-12-15 19:21:16 +03:00
func importTestingKey ( tmpDir , name , email string ) ( * openpgp . Entity , error ) {
if _ , _ , err := process . GetManager ( ) . Exec ( "gpg --import integrations/private-testing.key" , "gpg" , "--import" , "integrations/private-testing.key" ) ; err != nil {
2019-10-16 16:42:42 +03:00
return nil , err
}
2019-12-15 19:21:16 +03:00
keyringFile , err := os . Open ( "integrations/private-testing.key" )
2019-10-16 16:42:42 +03:00
if err != nil {
return nil , err
}
2019-12-15 19:21:16 +03:00
defer keyringFile . Close ( )
2019-10-16 16:42:42 +03:00
2019-12-15 19:21:16 +03:00
block , err := armor . Decode ( keyringFile )
2019-10-16 16:42:42 +03:00
if err != nil {
return nil , err
}
2019-12-15 19:21:16 +03:00
keyring , err := openpgp . ReadKeyRing ( block . Body )
if err != nil {
return nil , fmt . Errorf ( "Keyring access failed: '%v'" , err )
2019-10-16 16:42:42 +03:00
}
2019-12-15 19:21:16 +03:00
// There should only be one entity in this file.
return keyring [ 0 ] , nil
2019-10-16 16:42:42 +03:00
}