@@ -4,12 +4,15 @@ import (
44 "errors"
55 "fmt"
66 "net/url"
7+ "os"
78 "path/filepath"
89 "testing"
910
1011 "github.com/containerd/continuity/fs/fstest"
1112 "github.com/containerd/platforms"
1213 "github.com/distribution/reference"
14+ "github.com/docker/buildx/util/gitutil"
15+ "github.com/docker/buildx/util/gitutil/gittestutil"
1316 "github.com/moby/buildkit/identity"
1417 "github.com/moby/buildkit/util/contentutil"
1518 "github.com/moby/buildkit/util/testutil"
@@ -25,6 +28,7 @@ var policyBuildTests = []func(t *testing.T, sb integration.Sandbox){
2528 testBuildPolicyImageName ,
2629 testBuildPolicyEnv ,
2730 testBuildPolicyHTTP ,
31+ testBuildPolicyGit ,
2832 testBuildPolicyConfigFlags ,
2933}
3034
@@ -705,11 +709,15 @@ decision := {"allow": allow}
705709 fstest .CreateFile ("policy.rego" , []byte (tc .policy ), 0600 ),
706710 )
707711 policyPath := filepath .Join (dir , "policy.rego" )
712+ policyArg := "filename=" + policyPath
713+ if tc .name == "git-schema-allow" {
714+ policyArg = "log-level=debug," + policyArg
715+ }
708716
709717 cmd := buildxCmd (sb , withDir (dir ), withArgs (
710718 "build" ,
711719 "--progress=plain" ,
712- "--policy" , "filename=" + policyPath ,
720+ "--policy" , policyArg ,
713721 "--output=type=cacheonly" ,
714722 dir ,
715723 ))
@@ -725,6 +733,305 @@ decision := {"allow": allow}
725733 }
726734}
727735
736+ func testBuildPolicyGit (t * testing.T , sb integration.Sandbox ) {
737+ skipNoCompatBuildKit (t , sb , ">= 0.26.0-0" , "policy input requires BuildKit v0.26.0+" )
738+
739+ gitDir := t .TempDir ()
740+ require .NoError (t , os .WriteFile (filepath .Join (gitDir , "Dockerfile" ), []byte ("FROM busybox:latest\n RUN echo git\n " ), 0600 ))
741+ require .NoError (t , os .WriteFile (filepath .Join (gitDir , "a" ), []byte ("a" ), 0600 ))
742+
743+ git , err := gitutil .New (gitutil .WithWorkingDir (gitDir ))
744+ require .NoError (t , err )
745+
746+ gittestutil .GitInit (git , t )
747+ gittestutil .GitAdd (git , t , "Dockerfile" , "a" )
748+ gittestutil .GitCommit (git , t , "initial commit" )
749+
750+ _ , err = git .Run ("tag" , "-a" , "v0.1" , "-m" , "v0.1release" )
751+ require .NoError (t , err )
752+
753+ require .NoError (t , os .WriteFile (filepath .Join (gitDir , "b" ), []byte ("b" ), 0600 ))
754+ gittestutil .GitAdd (git , t , "b" )
755+ gittestutil .GitCommit (git , t , "b" )
756+ _ , err = git .Run ("checkout" , "-B" , "v2" )
757+ require .NoError (t , err )
758+
759+ commitHead , err := git .Run ("rev-parse" , "HEAD" )
760+ require .NoError (t , err )
761+ commitTag , err := git .Run ("rev-parse" , "v0.1" )
762+ require .NoError (t , err )
763+ commitTagCommit , err := git .Run ("rev-parse" , "v0.1^{commit}" )
764+ require .NoError (t , err )
765+ baseURL := gittestutil .GitServeHTTP (git , t )
766+ tagURL := baseURL + "#v0.1"
767+ branchURL := baseURL + "#v2"
768+ parsedURL , err := url .Parse (baseURL )
769+ require .NoError (t , err )
770+
771+ testCases := []struct {
772+ name string
773+ policy string
774+ context string
775+ wantErrContains string
776+ requiresGitResolve bool
777+ }{
778+ {
779+ name : "git-schema-allow" ,
780+ policy : `
781+ package docker
782+
783+ default allow = false
784+
785+ allow if not input.git
786+
787+ allow if input.git.schema != ""
788+
789+ decision := {"allow": allow}
790+ ` ,
791+ context : baseURL ,
792+ },
793+ {
794+ name : "git-host-allow" ,
795+ policy : fmt .Sprintf (`
796+ package docker
797+
798+ default allow = false
799+
800+ allow if not input.git
801+
802+ allow if input.git.host == "%s"
803+
804+ decision := {"allow": allow}
805+ ` , parsedURL .Host ),
806+ context : baseURL ,
807+ },
808+ {
809+ name : "git-remote-allow" ,
810+ policy : fmt .Sprintf (`
811+ package docker
812+
813+ default allow = false
814+
815+ allow if not input.git
816+
817+ allow if endswith(input.git.remote, "%s")
818+
819+ decision := {"allow": allow}
820+ ` , parsedURL .Path ),
821+ context : baseURL ,
822+ },
823+ {
824+ name : "git-ref-tag-allow" ,
825+ policy : `
826+ package docker
827+
828+ default allow = false
829+
830+ allow if not input.git
831+
832+ allow if input.git.ref == "refs/tags/v0.1"
833+
834+ decision := {"allow": allow}
835+ ` ,
836+ context : tagURL ,
837+ requiresGitResolve : true ,
838+ },
839+ {
840+ name : "git-branch-allow" ,
841+ policy : `
842+ package docker
843+
844+ default allow = false
845+
846+ allow if not input.git
847+
848+ allow if input.git.branch == "v2"
849+
850+ decision := {"allow": allow}
851+ ` ,
852+ context : branchURL ,
853+ requiresGitResolve : true ,
854+ },
855+ {
856+ name : "git-tagname-allow" ,
857+ policy : `
858+ package docker
859+
860+ default allow = false
861+
862+ allow if not input.git
863+
864+ allow if input.git.tagName == "v0.1"
865+
866+ decision := {"allow": allow}
867+ ` ,
868+ context : tagURL ,
869+ requiresGitResolve : true ,
870+ },
871+ {
872+ name : "git-checksum-allow" ,
873+ policy : fmt .Sprintf (`
874+ package docker
875+
876+ default allow = false
877+
878+ allow if not input.git
879+
880+ allow if input.git.checksum == "%s"
881+
882+ decision := {"allow": allow}
883+ ` , commitTag ),
884+ context : tagURL ,
885+ requiresGitResolve : true ,
886+ },
887+ {
888+ name : "git-commit-checksum-allow" ,
889+ policy : fmt .Sprintf (`
890+ package docker
891+
892+ default allow = false
893+
894+ allow if not input.git
895+
896+ allow if input.git.commitChecksum == "%s"
897+
898+ decision := {"allow": allow}
899+ ` , commitTagCommit ),
900+ context : tagURL ,
901+ requiresGitResolve : true ,
902+ },
903+ {
904+ name : "git-annotated-tag-allow" ,
905+ policy : `
906+ package docker
907+
908+ default allow = false
909+
910+ allow if not input.git
911+
912+ allow if input.git.isAnnotatedTag == true
913+
914+ decision := {"allow": allow}
915+ ` ,
916+ context : tagURL ,
917+ requiresGitResolve : true ,
918+ },
919+ {
920+ name : "git-commit-message-allow" ,
921+ policy : `
922+ package docker
923+
924+ default allow = false
925+
926+ allow if not input.git
927+
928+ allow if input.git.commit.message == "initial commit"
929+
930+ decision := {"allow": allow}
931+ ` ,
932+ context : tagURL ,
933+ requiresGitResolve : true ,
934+ },
935+ {
936+ name : "git-tag-object-allow" ,
937+ policy : `
938+ package docker
939+
940+ default allow = false
941+
942+ allow if not input.git
943+
944+ allow if input.git.tag.tag == "v0.1"
945+
946+ decision := {"allow": allow}
947+ ` ,
948+ context : tagURL ,
949+ requiresGitResolve : true ,
950+ },
951+ {
952+ name : "git-checksum-deny" ,
953+ policy : `
954+ package docker
955+
956+ default allow = false
957+
958+ allow if not input.git
959+
960+ allow if input.git.checksum == "deadbeef"
961+
962+ decision := {"allow": allow}
963+ ` ,
964+ context : tagURL ,
965+ wantErrContains : "not allowed by policy" ,
966+ requiresGitResolve : true ,
967+ },
968+ {
969+ name : "git-commit-ref-allow" ,
970+ policy : `
971+ package docker
972+
973+ default allow = false
974+
975+ allow if not input.git
976+
977+ allow if input.git.isCommitRef == true
978+
979+ decision := {"allow": allow}
980+ ` ,
981+ context : baseURL + "#" + commitHead ,
982+ requiresGitResolve : true ,
983+ },
984+ {
985+ name : "git-host-deny" ,
986+ policy : `
987+ package docker
988+
989+ default allow = false
990+
991+ allow if not input.git
992+
993+ allow if input.git.host == "example.invalid"
994+
995+ decision := {"allow": allow}
996+ ` ,
997+ context : tagURL ,
998+ wantErrContains : "not allowed by policy" ,
999+ },
1000+ }
1001+
1002+ for _ , tc := range testCases {
1003+ t .Run (tc .name , func (t * testing.T ) {
1004+ if tc .requiresGitResolve {
1005+ sbDriver , _ , _ := driverName (sb .Name ())
1006+ if sbDriver != "remote" {
1007+ t .Skip ("git policy metadata requires remote driver" )
1008+ }
1009+ }
1010+ dir := tmpdir (
1011+ t ,
1012+ fstest .CreateFile ("policy.rego" , []byte (tc .policy ), 0600 ),
1013+ )
1014+ policyPath := filepath .Join (dir , "policy.rego" )
1015+
1016+ cmd := buildxCmd (sb , withDir (dir ), withArgs (
1017+ "build" ,
1018+ "--progress=plain" ,
1019+ "--policy" , "filename=" + policyPath ,
1020+ "--output=type=cacheonly" ,
1021+ tc .context ,
1022+ ))
1023+ out , err := cmd .CombinedOutput ()
1024+ if tc .wantErrContains == "" {
1025+ require .NoError (t , err , string (out ))
1026+ require .Contains (t , string (out ), "loading policies " + policyPath )
1027+ } else {
1028+ require .Error (t , err , string (out ))
1029+ require .Contains (t , string (out ), tc .wantErrContains )
1030+ }
1031+ })
1032+ }
1033+ }
1034+
7281035func testBuildPolicyConfigFlags (t * testing.T , sb integration.Sandbox ) {
7291036 skipNoCompatBuildKit (t , sb , ">= 0.26.0-0" , "policy input requires BuildKit v0.26.0+" )
7301037
0 commit comments