Skip to content

Commit 635b97e

Browse files
chenhaoxuaniseki0
authored andcommitted
feat(gem): 支持在没有.lock文件时扫描gemfile
1 parent 423927c commit 635b97e

File tree

4 files changed

+134
-2
lines changed

4 files changed

+134
-2
lines changed

module/bundler/Gemfile

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
source 'https://rubygems.org'
2+
3+
gem 'activesupport', '6.1.1'
4+
gem 'elasticsearch-xpack', '7.10.1'
5+
gem 'fluentd', '1.12.0'
6+
gem 'fluent-plugin-concat', '2.4.0'
7+
gem 'fluent-plugin-detect-exceptions', '0.0.13'
8+
gem 'fluent-plugin-elasticsearch', '4.3.3'
9+
gem 'fluent-plugin-kubernetes_metadata_filter', '2.6.0'
10+
gem 'fluent-plugin-multi-format-parser', '1.0.0'
11+
gem 'fluent-plugin-prometheus', '1.8.5'
12+
gem 'fluent-plugin-systemd', '1.0.2'
13+
gem 'oj', '3.11.0'

module/bundler/gem.go

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"github.com/murphysecurity/murphysec/utils"
88
"github.com/pkg/errors"
99
"go.uber.org/zap"
10+
"os"
1011
"path/filepath"
1112
)
1213

@@ -21,7 +22,7 @@ func (Inspector) String() string {
2122
}
2223

2324
func (Inspector) CheckDir(ctx context.Context, dir string) bool {
24-
return utils.IsFile(filepath.Join(dir, "Gemfile")) && utils.IsFile(filepath.Join(dir, "Gemfile.lock"))
25+
return utils.IsFile(filepath.Join(dir, "Gemfile")) || utils.IsFile(filepath.Join(dir, "Gemfile.lock"))
2526
}
2627

2728
func (Inspector) InspectProject(ctx context.Context) error {
@@ -30,7 +31,30 @@ func (Inspector) InspectProject(ctx context.Context) error {
3031
scanDir := task.Dir()
3132
gemFile := filepath.Join(scanDir, "Gemfile")
3233
gemLockFile := filepath.Join(scanDir, "Gemfile.lock")
33-
if !utils.IsFile(gemFile) || !utils.IsFile(gemLockFile) {
34+
if utils.IsFile(gemFile) && !utils.IsFile(gemLockFile) {
35+
var m gemfile
36+
var dep []model.DependencyItem
37+
file, _ := os.Open(gemFile)
38+
m.Parse(file)
39+
for _, j := range m.Gems {
40+
dep = append(dep, model.DependencyItem{
41+
Component: model.Component{
42+
CompName: j.Name,
43+
CompVersion: j.Version,
44+
EcoRepo: EcoRepo,
45+
},
46+
IsDirectDependency: true,
47+
})
48+
}
49+
task.AddModule(model.Module{
50+
PackageManager: "bundler",
51+
ModuleName: "Gemfile",
52+
Dependencies: dep,
53+
ModulePath: gemFile,
54+
})
55+
return nil
56+
}
57+
if !utils.IsFile(gemFile) && !utils.IsFile(gemLockFile) {
3458
return nil
3559
}
3660
logger.Debug("Reading Gemfile.lock", zap.String("path", gemLockFile))

module/bundler/gemfile_parser.go

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package bundler
2+
3+
import (
4+
"bufio"
5+
"fmt"
6+
"io"
7+
"regexp"
8+
)
9+
10+
type gem struct {
11+
Name string
12+
Git string
13+
Version string
14+
Tag string
15+
Groups string
16+
Require string
17+
}
18+
type gemfile struct {
19+
Source string
20+
Ruby string
21+
Gems []*gem
22+
}
23+
24+
var (
25+
// Gem attributes
26+
REGEX_GEM = regexp.MustCompile(`gem\s*['|"](.*?)['|"]`)
27+
REGEX_VERSION = regexp.MustCompile(`,\s*["|'](.*?)['|"]`)
28+
REGEX_GIT = regexp.MustCompile(`git:\s*["|'](.*?)['|"]`)
29+
REGEX_TAG = regexp.MustCompile(`tag:\s*["|'](.*?)['|"]`)
30+
REGEX_REQUIRE_STRING = regexp.MustCompile(`require:\s*["|'](.*?)['|"]`)
31+
REGEX_REQUIRE_BOOL = regexp.MustCompile(`require:\s*(false|true)`)
32+
// Gemfile header
33+
REGEX_SOURCE = regexp.MustCompile(`source\s*['|"](.*?)['|"]`)
34+
REGEX_RUBY = regexp.MustCompile(`ruby\s*['|"](.*?)['|"]`)
35+
// Gem Groups
36+
REGEX_GROUP = regexp.MustCompile(`group\s(.*?)\sdo`)
37+
REGEX_END_GROUP = regexp.MustCompile(`^end$`)
38+
)
39+
40+
func (gf *gemfile) Parse(file io.Reader) {
41+
scanner := bufio.NewScanner(file)
42+
gf.parseGemfile(scanner, "")
43+
}
44+
45+
func (gf *gemfile) parseGemfile(scanner *bufio.Scanner, groups string) {
46+
for scanner.Scan() {
47+
line := scanner.Text()
48+
gem := gem{}
49+
50+
if REGEX_RUBY.MatchString(line) {
51+
gf.Ruby = REGEX_RUBY.FindStringSubmatch(line)[1]
52+
}
53+
if REGEX_SOURCE.MatchString(line) {
54+
gf.Source = REGEX_SOURCE.FindStringSubmatch(line)[1]
55+
}
56+
if REGEX_GEM.MatchString(line) {
57+
gem.Name = REGEX_GEM.FindStringSubmatch(line)[1]
58+
}
59+
if REGEX_VERSION.MatchString(line) {
60+
gem.Version = REGEX_VERSION.FindStringSubmatch(line)[1]
61+
}
62+
if REGEX_GIT.MatchString(line) {
63+
gem.Git = REGEX_GIT.FindStringSubmatch(line)[1]
64+
}
65+
if REGEX_TAG.MatchString(line) {
66+
gem.Tag = REGEX_TAG.FindStringSubmatch(line)[1]
67+
}
68+
if REGEX_GROUP.MatchString(line) {
69+
gf.parseGemfile(scanner, REGEX_GROUP.FindStringSubmatch(line)[1])
70+
}
71+
if REGEX_REQUIRE_STRING.MatchString(line) {
72+
gem.Require = fmt.Sprintf(`"%s"`, REGEX_REQUIRE_STRING.FindStringSubmatch(line)[1])
73+
}
74+
if REGEX_REQUIRE_BOOL.MatchString(line) {
75+
gem.Require = REGEX_REQUIRE_BOOL.FindStringSubmatch(line)[1]
76+
}
77+
if REGEX_END_GROUP.MatchString(line) && groups != "" {
78+
gf.parseGemfile(scanner, "")
79+
}
80+
if gem.Name != "" {
81+
gem.Groups = groups
82+
gf.Gems = append(gf.Gems, &gem)
83+
}
84+
}
85+
}

module/bundler/gemlock_parser_test.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ package bundler
22

33
import (
44
_ "embed"
5+
"fmt"
56
"github.com/stretchr/testify/assert"
7+
"os"
68
"testing"
79
)
810

@@ -35,3 +37,11 @@ DEPENDENCIES
3537
assert.NoError(t, e)
3638
t.Log(tree)
3739
}
40+
func TestParseGem(t *testing.T) {
41+
var m gemfile
42+
file, _ := os.Open("E:\\Desktop\\kubernetes-1.22.1\\cluster\\addons\\fluentd-elasticsearch\\fluentd-es-image\\Gemfile")
43+
m.Parse(file)
44+
for _, m := range m.Gems {
45+
fmt.Printf("%s :%s \n", m.Name, m.Version)
46+
}
47+
}

0 commit comments

Comments
 (0)