@@ -425,7 +425,7 @@ func NewProvenanceCreator(ctx context.Context, cp *provenance.Capture, res solve
425
425
pr .Invocation .Parameters .Secrets = nil
426
426
pr .Invocation .Parameters .SSH = nil
427
427
case "max" :
428
- dgsts , err := provenance . AddBuildConfig (ctx , pr , res )
428
+ dgsts , err := AddBuildConfig (ctx , pr , res )
429
429
if err != nil {
430
430
return nil , err
431
431
}
@@ -571,3 +571,157 @@ func resolveRemotes(ctx context.Context, res solver.Result) ([]*solver.Remote, e
571
571
}
572
572
return remotes , nil
573
573
}
574
+
575
+ func AddBuildConfig (ctx context.Context , p * provenance.ProvenancePredicate , rp solver.ResultProxy ) (map [digest.Digest ]int , error ) {
576
+ def := rp .Definition ()
577
+ steps , indexes , err := toBuildSteps (def )
578
+ if err != nil {
579
+ return nil , err
580
+ }
581
+
582
+ bc := & provenance.BuildConfig {
583
+ Definition : steps ,
584
+ DigestMapping : digestMap (indexes ),
585
+ }
586
+
587
+ p .BuildConfig = bc
588
+
589
+ if def .Source != nil {
590
+ sis := make ([]provenance.SourceInfo , len (def .Source .Infos ))
591
+ for i , si := range def .Source .Infos {
592
+ steps , indexes , err := toBuildSteps (si .Definition )
593
+ if err != nil {
594
+ return nil , err
595
+ }
596
+ s := provenance.SourceInfo {
597
+ Filename : si .Filename ,
598
+ Data : si .Data ,
599
+ Language : si .Language ,
600
+ Definition : steps ,
601
+ DigestMapping : digestMap (indexes ),
602
+ }
603
+ sis [i ] = s
604
+ }
605
+
606
+ if len (def .Source .Infos ) != 0 {
607
+ locs := map [string ]* pb.Locations {}
608
+ for k , l := range def .Source .Locations {
609
+ idx , ok := indexes [digest .Digest (k )]
610
+ if ! ok {
611
+ continue
612
+ }
613
+ locs [fmt .Sprintf ("step%d" , idx )] = l
614
+ }
615
+
616
+ if p .Metadata == nil {
617
+ p .Metadata = & provenance.ProvenanceMetadata {}
618
+ }
619
+ p .Metadata .BuildKitMetadata .Source = & provenance.Source {
620
+ Infos : sis ,
621
+ Locations : locs ,
622
+ }
623
+ }
624
+ }
625
+
626
+ return indexes , nil
627
+ }
628
+
629
+ func digestMap (idx map [digest.Digest ]int ) map [digest.Digest ]string {
630
+ m := map [digest.Digest ]string {}
631
+ for k , v := range idx {
632
+ m [k ] = fmt .Sprintf ("step%d" , v )
633
+ }
634
+ return m
635
+ }
636
+
637
+ func toBuildSteps (def * pb.Definition ) ([]provenance.BuildStep , map [digest.Digest ]int , error ) {
638
+ if def == nil || len (def .Def ) == 0 {
639
+ return nil , nil , nil
640
+ }
641
+
642
+ ops := make (map [digest.Digest ]* pb.Op )
643
+ defs := make (map [digest.Digest ][]byte )
644
+
645
+ var dgst digest.Digest
646
+ for _ , dt := range def .Def {
647
+ var op pb.Op
648
+ if err := (& op ).Unmarshal (dt ); err != nil {
649
+ return nil , nil , errors .Wrap (err , "failed to parse llb proto op" )
650
+ }
651
+ if src := op .GetSource (); src != nil {
652
+ for k := range src .Attrs {
653
+ if k == "local.session" || k == "local.unique" {
654
+ delete (src .Attrs , k )
655
+ }
656
+ }
657
+ }
658
+ dgst = digest .FromBytes (dt )
659
+ ops [dgst ] = & op
660
+ defs [dgst ] = dt
661
+ }
662
+
663
+ if dgst == "" {
664
+ return nil , nil , nil
665
+ }
666
+
667
+ // depth first backwards
668
+ dgsts := make ([]digest.Digest , 0 , len (def .Def ))
669
+ op := ops [dgst ]
670
+
671
+ if op .Op != nil {
672
+ return nil , nil , errors .Errorf ("invalid last vertex: %T" , op .Op )
673
+ }
674
+
675
+ if len (op .Inputs ) != 1 {
676
+ return nil , nil , errors .Errorf ("invalid last vertex inputs: %v" , len (op .Inputs ))
677
+ }
678
+
679
+ visited := map [digest.Digest ]struct {}{}
680
+ dgsts , err := walkDigests (dgsts , ops , dgst , visited )
681
+ if err != nil {
682
+ return nil , nil , err
683
+ }
684
+ indexes := map [digest.Digest ]int {}
685
+ for i , dgst := range dgsts {
686
+ indexes [dgst ] = i
687
+ }
688
+
689
+ out := make ([]provenance.BuildStep , 0 , len (dgsts ))
690
+ for i , dgst := range dgsts {
691
+ op := * ops [dgst ]
692
+ inputs := make ([]string , len (op .Inputs ))
693
+ for i , inp := range op .Inputs {
694
+ inputs [i ] = fmt .Sprintf ("step%d:%d" , indexes [inp .Digest ], inp .Index )
695
+ }
696
+ op .Inputs = nil
697
+ out = append (out , provenance.BuildStep {
698
+ ID : fmt .Sprintf ("step%d" , i ),
699
+ Inputs : inputs ,
700
+ Op : op ,
701
+ })
702
+ }
703
+ return out , indexes , nil
704
+ }
705
+
706
+ func walkDigests (dgsts []digest.Digest , ops map [digest.Digest ]* pb.Op , dgst digest.Digest , visited map [digest.Digest ]struct {}) ([]digest.Digest , error ) {
707
+ if _ , ok := visited [dgst ]; ok {
708
+ return dgsts , nil
709
+ }
710
+ op , ok := ops [dgst ]
711
+ if ! ok {
712
+ return nil , errors .Errorf ("failed to find input %v" , dgst )
713
+ }
714
+ if op == nil {
715
+ return nil , errors .Errorf ("invalid nil input %v" , dgst )
716
+ }
717
+ visited [dgst ] = struct {}{}
718
+ for _ , inp := range op .Inputs {
719
+ var err error
720
+ dgsts , err = walkDigests (dgsts , ops , inp .Digest , visited )
721
+ if err != nil {
722
+ return nil , err
723
+ }
724
+ }
725
+ dgsts = append (dgsts , dgst )
726
+ return dgsts , nil
727
+ }
0 commit comments