@@ -24,15 +24,18 @@ import (
2424 "io/ioutil"
2525 "os"
2626 "os/exec"
27+ "path"
2728 "path/filepath"
2829 "reflect"
2930 "testing"
3031 "time"
3132
3233 "github.com/google/go-cmp/cmp"
3334 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
35+ "github.com/tektoncd/pipeline/pkg/spire"
3436 "github.com/tektoncd/pipeline/pkg/termination"
3537 "github.com/tektoncd/pipeline/test/diff"
38+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3639 "knative.dev/pkg/logging"
3740)
3841
@@ -284,6 +287,7 @@ func TestReadResultsFromDisk(t *testing.T) {
284287 },
285288 } {
286289 t .Run (c .desc , func (t * testing.T ) {
290+ ctx := context .Background ()
287291 terminationPath := "termination"
288292 if terminationFile , err := ioutil .TempFile ("" , "termination" ); err != nil {
289293 t .Fatalf ("unexpected error creating temporary termination file: %v" , err )
@@ -314,7 +318,7 @@ func TestReadResultsFromDisk(t *testing.T) {
314318 Results : resultsFilePath ,
315319 TerminationPath : terminationPath ,
316320 }
317- if err := e .readResultsFromDisk ("" ); err != nil {
321+ if err := e .readResultsFromDisk (ctx , "" ); err != nil {
318322 t .Fatal (err )
319323 }
320324 msg , err := ioutil .ReadFile (terminationPath )
@@ -434,6 +438,167 @@ func TestEntrypointer_OnError(t *testing.T) {
434438 }
435439}
436440
441+ func TestEntrypointerResults (t * testing.T ) {
442+ for _ , c := range []struct {
443+ desc , entrypoint , postFile , stepDir , stepDirLink string
444+ waitFiles , args []string
445+ resultsToWrite map [string ]string
446+ resultsOverride []string
447+ breakpointOnFailure bool
448+ sign bool
449+ signVerify bool
450+ }{{
451+ desc : "do nothing" ,
452+ }, {
453+ desc : "no results" ,
454+ entrypoint : "echo" ,
455+ }, {
456+ desc : "write single result" ,
457+ entrypoint : "echo" ,
458+ resultsToWrite : map [string ]string {
459+ "foo" : "abc" ,
460+ },
461+ }, {
462+ desc : "write multiple result" ,
463+ entrypoint : "echo" ,
464+ resultsToWrite : map [string ]string {
465+ "foo" : "abc" ,
466+ "bar" : "def" ,
467+ },
468+ }, {
469+ // These next two tests show that if not results are defined in the entrypointer, then no signature is produced
470+ // indicating that no signature was created. However, it is important to note that results were defined,
471+ // but no results were created, that signature is still produced.
472+ desc : "no results signed" ,
473+ entrypoint : "echo" ,
474+ sign : true ,
475+ signVerify : false ,
476+ }, {
477+ desc : "defined results but no results produced signed" ,
478+ entrypoint : "echo" ,
479+ resultsOverride : []string {"foo" },
480+ sign : true ,
481+ signVerify : true ,
482+ }, {
483+ desc : "write single result" ,
484+ entrypoint : "echo" ,
485+ resultsToWrite : map [string ]string {
486+ "foo" : "abc" ,
487+ },
488+ sign : true ,
489+ signVerify : true ,
490+ }, {
491+ desc : "write multiple result" ,
492+ entrypoint : "echo" ,
493+ resultsToWrite : map [string ]string {
494+ "foo" : "abc" ,
495+ "bar" : "def" ,
496+ },
497+ sign : true ,
498+ signVerify : true ,
499+ }, {
500+ desc : "write n/m results" ,
501+ entrypoint : "echo" ,
502+ resultsToWrite : map [string ]string {
503+ "foo" : "abc" ,
504+ },
505+ resultsOverride : []string {"foo" , "bar" },
506+ sign : true ,
507+ signVerify : true ,
508+ }} {
509+ t .Run (c .desc , func (t * testing.T ) {
510+ ctx := context .Background ()
511+ fw , fpw := & fakeWaiter {}, & fakePostWriter {}
512+ var fr Runner = & fakeRunner {}
513+ timeout := time .Duration (0 )
514+ terminationPath := "termination"
515+ if terminationFile , err := ioutil .TempFile ("" , "termination" ); err != nil {
516+ t .Fatalf ("unexpected error creating temporary termination file: %v" , err )
517+ } else {
518+ terminationPath = terminationFile .Name ()
519+ defer os .Remove (terminationFile .Name ())
520+ }
521+
522+ resultsDir := createTmpDir (t , "results" )
523+ var results []string
524+ if c .resultsToWrite != nil {
525+ tmpResultsToWrite := map [string ]string {}
526+ for k , v := range c .resultsToWrite {
527+ resultFile := path .Join (resultsDir , k )
528+ tmpResultsToWrite [resultFile ] = v
529+ results = append (results , k )
530+ }
531+
532+ fr = & fakeResultsWriter {
533+ resultsToWrite : tmpResultsToWrite ,
534+ }
535+ }
536+
537+ signClient , verifyClient , tr := getMockSpireClient (ctx )
538+ if ! c .sign {
539+ signClient = nil
540+ }
541+
542+ if c .resultsOverride != nil {
543+ results = c .resultsOverride
544+ }
545+
546+ err := Entrypointer {
547+ Command : append ([]string {c .entrypoint }, c .args ... ),
548+ WaitFiles : c .waitFiles ,
549+ PostFile : c .postFile ,
550+ Waiter : fw ,
551+ Runner : fr ,
552+ PostWriter : fpw ,
553+ Results : results ,
554+ ResultsDirectory : resultsDir ,
555+ TerminationPath : terminationPath ,
556+ Timeout : & timeout ,
557+ BreakpointOnFailure : c .breakpointOnFailure ,
558+ StepMetadataDir : c .stepDir ,
559+ SpireWorkloadAPI : signClient ,
560+ }.Go ()
561+ if err != nil {
562+ t .Fatalf ("Entrypointer failed: %v" , err )
563+ }
564+
565+ fileContents , err := ioutil .ReadFile (terminationPath )
566+ if err == nil {
567+ resultCheck := map [string ]bool {}
568+ var entries []v1beta1.PipelineResourceResult
569+ if err := json .Unmarshal (fileContents , & entries ); err != nil {
570+ t .Fatalf ("failed to unmarshal results: %v" , err )
571+ }
572+
573+ for _ , result := range entries {
574+ if _ , ok := c .resultsToWrite [result .Key ]; ok {
575+ if c .resultsToWrite [result .Key ] == result .Value {
576+ resultCheck [result .Key ] = true
577+ } else {
578+ t .Errorf ("expected result (%v) to have value %v, got %v" , result .Key , result .Value , c .resultsToWrite [result .Key ])
579+ }
580+ }
581+ }
582+
583+ if len (resultCheck ) != len (c .resultsToWrite ) {
584+ t .Error ("number of results matching did not add up" )
585+ }
586+
587+ // Check signature
588+ verified := verifyClient .VerifyTaskRunResults (ctx , entries , tr ) == nil
589+ if verified != c .signVerify {
590+ t .Errorf ("expected signature verify result %v, got %v" , c .signVerify , verified )
591+ }
592+ } else if ! os .IsNotExist (err ) {
593+ t .Error ("Wanted termination file written, got nil" )
594+ }
595+ if err := os .Remove (terminationPath ); err != nil {
596+ t .Errorf ("Could not remove termination path: %s" , err )
597+ }
598+ })
599+ }
600+ }
601+
437602type fakeWaiter struct { waited []string }
438603
439604func (f * fakeWaiter ) Wait (file string , _ bool , _ bool ) error {
@@ -503,3 +668,55 @@ func (f *fakeExitErrorRunner) Run(ctx context.Context, args ...string) error {
503668 f .args = & args
504669 return exec .Command ("ls" , "/bogus/path" ).Run ()
505670}
671+
672+ type fakeResultsWriter struct {
673+ args * []string
674+ resultsToWrite map [string ]string
675+ }
676+
677+ func (f * fakeResultsWriter ) Run (ctx context.Context , args ... string ) error {
678+ f .args = & args
679+ for k , v := range f .resultsToWrite {
680+ err := ioutil .WriteFile (k , []byte (v ), 0666 )
681+ if err != nil {
682+ return err
683+ }
684+ }
685+ return nil
686+ }
687+
688+ func createTmpDir (t * testing.T , name string ) string {
689+ tmpDir , err := ioutil .TempDir ("" , name )
690+ if err != nil {
691+ t .Fatalf ("unexpected error creating temporary dir: %v" , err )
692+ }
693+ return tmpDir
694+ }
695+
696+ func getMockSpireClient (ctx context.Context ) (spire.EntrypointerAPIClient , spire.ControllerAPIClient , * v1beta1.TaskRun ) {
697+ tr := & v1beta1.TaskRun {
698+ ObjectMeta : metav1.ObjectMeta {
699+ Name : "taskrun-example" ,
700+ Namespace : "foo" ,
701+ },
702+ Spec : v1beta1.TaskRunSpec {
703+ TaskRef : & v1beta1.TaskRef {
704+ Name : "taskname" ,
705+ APIVersion : "a1" ,
706+ },
707+ ServiceAccountName : "test-sa" ,
708+ },
709+ }
710+
711+ sc := & spire.MockClient {}
712+
713+ _ = sc .CreateEntries (ctx , tr , nil , 10000 )
714+
715+ // bootstrap with about 20 calls to sign which should be enough for testing
716+ id := sc .GetIdentity (tr )
717+ for i := 0 ; i < 20 ; i ++ {
718+ sc .SignIdentities = append (sc .SignIdentities , id )
719+ }
720+
721+ return sc , sc , tr
722+ }
0 commit comments