Skip to content

Commit 415cecb

Browse files
authored
Add Packagist feed support for analyzing PHP packages. (#307)
1 parent e120e9d commit 415cecb

File tree

3 files changed

+78
-8
lines changed

3 files changed

+78
-8
lines changed

cmd/scheduler/main.go

+16-5
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"fmt"
77
"math"
88
"os"
9+
"regexp"
910
"time"
1011

1112
"gocloud.dev/pubsub"
@@ -23,10 +24,14 @@ const (
2324
retryExpRate = 1.5
2425
)
2526

26-
var supportedPkgManagers = map[string]bool{
27-
"npm": true,
28-
"pypi": true,
29-
"rubygems": true,
27+
// supportedPkgManagers lists the package managers Package Analysis can
28+
// analyze. Each entry can contain zero or more regexp filters that exclude
29+
// unwanted versions to minimize noise.
30+
var supportedPkgManagers = map[string][]*regexp.Regexp{
31+
"npm": {},
32+
"pypi": {},
33+
"rubygems": {},
34+
"packagist": {regexp.MustCompile(`^dev-`), regexp.MustCompile(`\.x-dev$`)},
3035
}
3136

3237
func main() {
@@ -79,8 +84,14 @@ func listenLoop(subUrl, topicURL string) error {
7984
if err := json.Unmarshal(m.Body, &pkg); err != nil {
8085
return nil, fmt.Errorf("error unmarshalling json: %w", err)
8186
}
82-
if _, ok := supportedPkgManagers[pkg.Type]; !ok {
87+
if filters, ok := supportedPkgManagers[pkg.Type]; !ok {
8388
return nil, fmt.Errorf("package type is not supported: %v", pkg.Type)
89+
} else {
90+
for _, filter := range filters {
91+
if filter.MatchString(pkg.Version) {
92+
return nil, fmt.Errorf("package version '%v' is filtered for type: %v", pkg.Version, pkg.Type)
93+
}
94+
}
8495
}
8596
return &pubsub.Message{
8697
Body: []byte{},

internal/pkgecosystem/ecosystem.go

+4-3
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,10 @@ type PkgManager struct {
1414

1515
var (
1616
supportedPkgManagers = map[string]*PkgManager{
17-
npmPkgManager.name: &npmPkgManager,
18-
pypiPkgManager.name: &pypiPkgManager,
19-
rubygemsPkgManager.name: &rubygemsPkgManager,
17+
npmPkgManager.name: &npmPkgManager,
18+
pypiPkgManager.name: &pypiPkgManager,
19+
rubygemsPkgManager.name: &rubygemsPkgManager,
20+
packagistPkgManager.name: &packagistPkgManager,
2021
}
2122
)
2223

internal/pkgecosystem/packagist.go

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package pkgecosystem
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"net/http"
7+
"time"
8+
)
9+
10+
type packagistJSON struct {
11+
Packages map[string][]struct {
12+
Version string `json:"version"`
13+
VersionNormalized string `json:"version_normalized"`
14+
License []string `json:"license,omitempty"`
15+
Time time.Time `json:"time"`
16+
Name string `json:"name,omitempty"`
17+
} `json:"packages"`
18+
}
19+
20+
func getPackagistLatest(pkg string) (string, error) {
21+
resp, err := http.Get(fmt.Sprintf("https://repo.packagist.org/p2/%s.json", pkg))
22+
if err != nil {
23+
return "", err
24+
}
25+
defer resp.Body.Close()
26+
27+
decoder := json.NewDecoder(resp.Body)
28+
var details packagistJSON
29+
err = decoder.Decode(&details)
30+
if err != nil {
31+
return "", err
32+
}
33+
34+
latestVersion := ""
35+
var lastTime time.Time
36+
for _, versions := range details.Packages {
37+
for _, v := range versions {
38+
if v.Time.Before(lastTime) {
39+
continue
40+
}
41+
lastTime = v.Time
42+
latestVersion = v.Version
43+
}
44+
}
45+
46+
return latestVersion, nil
47+
}
48+
49+
var packagistPkgManager = PkgManager{
50+
name: "packagist",
51+
image: "gcr.io/ossf-malware-analysis/packagist",
52+
command: "/usr/local/bin/analyze.php",
53+
latest: getPackagistLatest,
54+
dynamicPhases: []string{
55+
"install",
56+
"import",
57+
},
58+
}

0 commit comments

Comments
 (0)