@@ -6,6 +6,7 @@ package symbols
6
6
7
7
import (
8
8
"bytes"
9
+ "context"
9
10
"errors"
10
11
"fmt"
11
12
"go/ast"
@@ -19,9 +20,84 @@ import (
19
20
"reflect"
20
21
"strings"
21
22
23
+ "github.com/go-git/go-git/v5"
24
+ "github.com/go-git/go-git/v5/plumbing"
22
25
"golang.org/x/mod/modfile"
26
+ "golang.org/x/vulndb/internal/derrors"
27
+ "golang.org/x/vulndb/internal/gitrepo"
23
28
)
24
29
30
+ // Patched returns symbols of module patched in commit identified
31
+ // by commitHash. repoURL is URL of the git repository containing
32
+ // the module.
33
+ //
34
+ // Patched returns a map from package import paths to symbols
35
+ // patched in the package. Test packages and symbols are omitted.
36
+ //
37
+ // If the commit has more than one parent, an error is returned.
38
+ func Patched (module , repoURL , commitHash string ) (_ map [string ][]string , err error ) {
39
+ defer derrors .Wrap (& err , "Patched(%s ,%s, %s)" , module , repoURL , commitHash )
40
+
41
+ repoRoot , err := os .MkdirTemp ("" , commitHash )
42
+ if err != nil {
43
+ return nil , err
44
+ }
45
+ defer func () {
46
+ _ = os .RemoveAll (repoRoot )
47
+ }()
48
+
49
+ ctx := context .Background ()
50
+ repo , err := gitrepo .PlainClone (ctx , repoRoot , repoURL )
51
+ if err != nil {
52
+ return nil , err
53
+ }
54
+
55
+ w , err := repo .Worktree ()
56
+ if err != nil {
57
+ return nil , err
58
+ }
59
+
60
+ hash := plumbing .NewHash (commitHash )
61
+ commit , err := repo .CommitObject (hash )
62
+ if err != nil {
63
+ return nil , err
64
+ }
65
+
66
+ if commit .NumParents () != 1 {
67
+ return nil , fmt .Errorf ("more than 1 parent: %d" , commit .NumParents ())
68
+ }
69
+
70
+ parent , err := commit .Parent (0 )
71
+ if err != nil {
72
+ return nil , err
73
+ }
74
+
75
+ if err := w .Checkout (& git.CheckoutOptions {Hash : hash , Force : true }); err != nil {
76
+ return nil , err
77
+ }
78
+
79
+ newSymbols , err := moduleSymbols (repoRoot , module )
80
+ if err != nil {
81
+ return nil , err
82
+ }
83
+
84
+ if err := w .Checkout (& git.CheckoutOptions {Hash : parent .Hash , Force : true }); err != nil {
85
+ return nil , err
86
+ }
87
+
88
+ oldSymbols , err := moduleSymbols (repoRoot , module )
89
+ if err != nil {
90
+ return nil , err
91
+ }
92
+
93
+ patched := patchedSymbols (oldSymbols , newSymbols )
94
+ pkgSyms := make (map [string ][]string )
95
+ for _ , sym := range patched {
96
+ pkgSyms [sym .pkg ] = append (pkgSyms [sym .pkg ], sym .symbol )
97
+ }
98
+ return pkgSyms , nil
99
+ }
100
+
25
101
// patchedSymbols returns symbol indices in oldSymbols that either 1) cannot
26
102
// be identified in newSymbols or 2) the corresponding functions have their
27
103
// source code changed.
0 commit comments