hub-natixis 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of hub-natixis might be problematic. Click here for more details.
- package/.github/workflows/codeql-analysis.yml +67 -0
- package/.github/workflows/golangci-lint.yml +22 -0
- package/.goreleaser.yml +40 -0
- package/CHANGELOG.md +31 -0
- package/LICENSE +21 -0
- package/README.md +103 -0
- package/composer.go +105 -0
- package/confused +0 -0
- package/go.mod +3 -0
- package/index.js +47 -0
- package/interfaces.go +11 -0
- package/main.go +109 -0
- package/mvn.go +120 -0
- package/mvnparser.go +139 -0
- package/npm.go +210 -0
- package/package-lock-2.json +111 -0
- package/package-lock.json.1 +35006 -0
- package/package.json +20 -0
- package/pip.go +99 -0
- package/rubygems.go +149 -0
- package/util.go +16 -0
package/mvnparser.go
ADDED
@@ -0,0 +1,139 @@
|
|
1
|
+
//
|
2
|
+
// https://raw.githubusercontent.com/creekorful/mvnparser/master/parser.go
|
3
|
+
//
|
4
|
+
// MIT License
|
5
|
+
//
|
6
|
+
// Copyright (c) 2019 Aloïs Micard
|
7
|
+
//
|
8
|
+
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
9
|
+
// of this software and associated documentation files (the "Software"), to deal
|
10
|
+
// in the Software without restriction, including without limitation the rights
|
11
|
+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
12
|
+
// copies of the Software, and to permit persons to whom the Software is
|
13
|
+
// furnished to do so, subject to the following conditions:
|
14
|
+
//
|
15
|
+
// The above copyright notice and this permission notice shall be included in all
|
16
|
+
// copies or substantial portions of the Software.
|
17
|
+
//
|
18
|
+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
19
|
+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
20
|
+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
21
|
+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
22
|
+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
23
|
+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
24
|
+
// SOFTWARE.
|
25
|
+
|
26
|
+
package main
|
27
|
+
|
28
|
+
import (
|
29
|
+
"encoding/xml"
|
30
|
+
"io"
|
31
|
+
)
|
32
|
+
|
33
|
+
// Represent a POM file
|
34
|
+
type MavenProject struct {
|
35
|
+
XMLName xml.Name `xml:"project"`
|
36
|
+
ModelVersion string `xml:"modelVersion"`
|
37
|
+
Parent Parent `xml:"parent"`
|
38
|
+
GroupId string `xml:"groupId"`
|
39
|
+
ArtifactId string `xml:"artifactId"`
|
40
|
+
Version string `xml:"version"`
|
41
|
+
Packaging string `xml:"packaging"`
|
42
|
+
Name string `xml:"name"`
|
43
|
+
Repositories []Repository `xml:"repositories>repository"`
|
44
|
+
Properties Properties `xml:"properties"`
|
45
|
+
DependencyManagement DependencyManagement `xml:"dependencyManagement"`
|
46
|
+
Dependencies []Dependency `xml:"dependencies>dependency"`
|
47
|
+
Profiles []Profile `xml:"profiles"`
|
48
|
+
Build Build `xml:"build"`
|
49
|
+
PluginRepositories []PluginRepository `xml:"pluginRepositories>pluginRepository"`
|
50
|
+
Modules []string `xml:"modules>module"`
|
51
|
+
}
|
52
|
+
|
53
|
+
// Represent the parent of the project
|
54
|
+
type Parent struct {
|
55
|
+
GroupId string `xml:"groupId"`
|
56
|
+
ArtifactId string `xml:"artifactId"`
|
57
|
+
Version string `xml:"version"`
|
58
|
+
}
|
59
|
+
|
60
|
+
// Represent a dependency of the project
|
61
|
+
type Dependency struct {
|
62
|
+
XMLName xml.Name `xml:"dependency"`
|
63
|
+
GroupId string `xml:"groupId"`
|
64
|
+
ArtifactId string `xml:"artifactId"`
|
65
|
+
Version string `xml:"version"`
|
66
|
+
Classifier string `xml:"classifier"`
|
67
|
+
Type string `xml:"type"`
|
68
|
+
Scope string `xml:"scope"`
|
69
|
+
Exclusions []Exclusion `xml:"exclusions>exclusion"`
|
70
|
+
}
|
71
|
+
|
72
|
+
// Represent an exclusion
|
73
|
+
type Exclusion struct {
|
74
|
+
XMLName xml.Name `xml:"exclusion"`
|
75
|
+
GroupId string `xml:"groupId"`
|
76
|
+
ArtifactId string `xml:"artifactId"`
|
77
|
+
}
|
78
|
+
|
79
|
+
type DependencyManagement struct {
|
80
|
+
Dependencies []Dependency `xml:"dependencies>dependency"`
|
81
|
+
}
|
82
|
+
|
83
|
+
// Represent a repository
|
84
|
+
type Repository struct {
|
85
|
+
Id string `xml:"id"`
|
86
|
+
Name string `xml:"name"`
|
87
|
+
Url string `xml:"url"`
|
88
|
+
}
|
89
|
+
|
90
|
+
type Profile struct {
|
91
|
+
Id string `xml:"id"`
|
92
|
+
Build Build `xml:"build"`
|
93
|
+
}
|
94
|
+
|
95
|
+
type Build struct {
|
96
|
+
// todo: final name ?
|
97
|
+
Plugins []Plugin `xml:"plugins>plugin"`
|
98
|
+
}
|
99
|
+
|
100
|
+
type Plugin struct {
|
101
|
+
XMLName xml.Name `xml:"plugin"`
|
102
|
+
GroupId string `xml:"groupId"`
|
103
|
+
ArtifactId string `xml:"artifactId"`
|
104
|
+
Version string `xml:"version"`
|
105
|
+
//todo something like: Configuration map[string]string `xml:"configuration"`
|
106
|
+
// todo executions
|
107
|
+
}
|
108
|
+
|
109
|
+
// Represent a pluginRepository
|
110
|
+
type PluginRepository struct {
|
111
|
+
Id string `xml:"id"`
|
112
|
+
Name string `xml:"name"`
|
113
|
+
Url string `xml:"url"`
|
114
|
+
}
|
115
|
+
|
116
|
+
// Represent Properties
|
117
|
+
type Properties map[string]string
|
118
|
+
|
119
|
+
func (p *Properties) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
120
|
+
*p = map[string]string{}
|
121
|
+
for {
|
122
|
+
key := ""
|
123
|
+
value := ""
|
124
|
+
token, err := d.Token()
|
125
|
+
if err == io.EOF {
|
126
|
+
break
|
127
|
+
}
|
128
|
+
switch tokenType := token.(type) {
|
129
|
+
case xml.StartElement:
|
130
|
+
key = tokenType.Name.Local
|
131
|
+
err := d.DecodeElement(&value, &start)
|
132
|
+
if err != nil {
|
133
|
+
return err
|
134
|
+
}
|
135
|
+
(*p)[key] = value
|
136
|
+
}
|
137
|
+
}
|
138
|
+
return nil
|
139
|
+
}
|
package/npm.go
ADDED
@@ -0,0 +1,210 @@
|
|
1
|
+
package main
|
2
|
+
|
3
|
+
import (
|
4
|
+
"encoding/json"
|
5
|
+
"fmt"
|
6
|
+
"io/ioutil"
|
7
|
+
"net/http"
|
8
|
+
"strings"
|
9
|
+
"time"
|
10
|
+
)
|
11
|
+
|
12
|
+
// PackageJSON represents the dependencies of an npm package
|
13
|
+
type PackageJSON struct {
|
14
|
+
Dependencies map[string]string `json:"dependencies,omitempty"`
|
15
|
+
DevDependencies map[string]string `json:"devDependencies,omitempty"`
|
16
|
+
PeerDependencies map[string]string `json:"peerDependencies,omitempty"`
|
17
|
+
BundledDependencies []string `json:"bundledDependencies,omitempty"`
|
18
|
+
BundleDependencies []string `json:"bundleDependencies,omitempty"`
|
19
|
+
OptionalDependencies map[string]string `json:"optionalDependencies,omitempty"`
|
20
|
+
}
|
21
|
+
|
22
|
+
type NpmResponse struct {
|
23
|
+
ID string `json:"_id"`
|
24
|
+
Name string `json:"name"`
|
25
|
+
Time struct {
|
26
|
+
Unpublished NpmResponseUnpublished `json:"unpublished"`
|
27
|
+
} `json:"time"`
|
28
|
+
}
|
29
|
+
|
30
|
+
type NpmResponseUnpublished struct {
|
31
|
+
Maintainers []struct {
|
32
|
+
Email string `json:"email"`
|
33
|
+
Name string `json:"name"`
|
34
|
+
} `json:"maintainers"`
|
35
|
+
Name string `json:"name"`
|
36
|
+
Tags struct {
|
37
|
+
Latest string `json:"latest"`
|
38
|
+
} `json:"tags"`
|
39
|
+
Time time.Time `json:"time"`
|
40
|
+
Versions []string `json:"versions"`
|
41
|
+
}
|
42
|
+
|
43
|
+
// NotAvailable returns true if the package has its all versions unpublished making it susceptible for takeover
|
44
|
+
func (n *NpmResponse) NotAvailable() bool {
|
45
|
+
// Check if a known field has a value
|
46
|
+
return len(n.Time.Unpublished.Name) > 0
|
47
|
+
}
|
48
|
+
|
49
|
+
// NPMLookup represents a collection of npm packages to be tested for dependency confusion.
|
50
|
+
type NPMLookup struct {
|
51
|
+
Packages []NPMPackage
|
52
|
+
Verbose bool
|
53
|
+
}
|
54
|
+
|
55
|
+
type NPMPackage struct {
|
56
|
+
Name string
|
57
|
+
Version string
|
58
|
+
}
|
59
|
+
|
60
|
+
// NewNPMLookup constructs an `NPMLookup` struct and returns it.
|
61
|
+
func NewNPMLookup(verbose bool) PackageResolver {
|
62
|
+
return &NPMLookup{Packages: []NPMPackage{}, Verbose: verbose}
|
63
|
+
}
|
64
|
+
|
65
|
+
// ReadPackagesFromFile reads package information from an npm package.json file
|
66
|
+
//
|
67
|
+
// Returns any errors encountered
|
68
|
+
func (n *NPMLookup) ReadPackagesFromFile(filename string) error {
|
69
|
+
rawfile, err := ioutil.ReadFile(filename)
|
70
|
+
if err != nil {
|
71
|
+
return err
|
72
|
+
}
|
73
|
+
data := PackageJSON{}
|
74
|
+
err = json.Unmarshal([]byte(rawfile), &data)
|
75
|
+
if err != nil {
|
76
|
+
fmt.Printf(" [W] Non-fatal issue encountered while reading %s : %s\n", filename, err)
|
77
|
+
}
|
78
|
+
for pkgname, pkgversion := range data.Dependencies {
|
79
|
+
n.Packages = append(n.Packages, NPMPackage{pkgname, pkgversion})
|
80
|
+
}
|
81
|
+
for pkgname, pkgversion := range data.DevDependencies {
|
82
|
+
n.Packages = append(n.Packages, NPMPackage{pkgname, pkgversion})
|
83
|
+
}
|
84
|
+
for pkgname, pkgversion := range data.PeerDependencies {
|
85
|
+
n.Packages = append(n.Packages, NPMPackage{pkgname, pkgversion})
|
86
|
+
}
|
87
|
+
for pkgname, pkgversion := range data.OptionalDependencies {
|
88
|
+
n.Packages = append(n.Packages, NPMPackage{pkgname, pkgversion})
|
89
|
+
}
|
90
|
+
for _, pkgname := range data.BundledDependencies {
|
91
|
+
n.Packages = append(n.Packages, NPMPackage{pkgname, ""})
|
92
|
+
}
|
93
|
+
for _, pkgname := range data.BundleDependencies {
|
94
|
+
n.Packages = append(n.Packages, NPMPackage{pkgname, ""})
|
95
|
+
}
|
96
|
+
return nil
|
97
|
+
}
|
98
|
+
|
99
|
+
// PackagesNotInPublic determines if an npm package does not exist in the public npm package repository.
|
100
|
+
//
|
101
|
+
// Returns a slice of strings with any npm packages not in the public npm package repository
|
102
|
+
func (n *NPMLookup) PackagesNotInPublic() []string {
|
103
|
+
notavail := []string{}
|
104
|
+
for _, pkg := range n.Packages {
|
105
|
+
if n.localReference(pkg.Version) || n.urlReference(pkg.Version) || n.gitReference(pkg.Version) {
|
106
|
+
continue
|
107
|
+
}
|
108
|
+
if n.gitHubReference(pkg.Version) {
|
109
|
+
if !n.gitHubOrgExists(pkg.Version) {
|
110
|
+
notavail = append(notavail, pkg.Name)
|
111
|
+
continue
|
112
|
+
} else {
|
113
|
+
continue
|
114
|
+
}
|
115
|
+
}
|
116
|
+
if !n.isAvailableInPublic(pkg.Name, 0) {
|
117
|
+
notavail = append(notavail, pkg.Name)
|
118
|
+
}
|
119
|
+
}
|
120
|
+
return notavail
|
121
|
+
}
|
122
|
+
|
123
|
+
// isAvailableInPublic determines if an npm package exists in the public npm package repository.
|
124
|
+
//
|
125
|
+
// Returns true if the package exists in the public npm package repository.
|
126
|
+
func (n *NPMLookup) isAvailableInPublic(pkgname string, retry int) bool {
|
127
|
+
if retry > 3 {
|
128
|
+
fmt.Printf(" [W] Maximum number of retries exhausted for package: %s\n", pkgname)
|
129
|
+
return false
|
130
|
+
}
|
131
|
+
if n.Verbose {
|
132
|
+
fmt.Print("Checking: https://registry.npmjs.org/" + pkgname + "/ : ")
|
133
|
+
}
|
134
|
+
resp, err := http.Get("https://registry.npmjs.org/" + pkgname + "/")
|
135
|
+
if err != nil {
|
136
|
+
fmt.Printf(" [W] Error when trying to request https://registry.npmjs.org/"+pkgname+"/ : %s\n", err)
|
137
|
+
return false
|
138
|
+
}
|
139
|
+
defer resp.Body.Close()
|
140
|
+
if n.Verbose {
|
141
|
+
fmt.Printf("%s\n", resp.Status)
|
142
|
+
}
|
143
|
+
if resp.StatusCode == http.StatusOK {
|
144
|
+
npmResp := NpmResponse{}
|
145
|
+
body, _ := ioutil.ReadAll(resp.Body)
|
146
|
+
_ = json.Unmarshal(body, &npmResp)
|
147
|
+
if npmResp.NotAvailable() {
|
148
|
+
if n.Verbose {
|
149
|
+
fmt.Printf("[W] Package %s was found, but all its versions are unpublished, making anyone able to takeover the namespace.\n", pkgname)
|
150
|
+
}
|
151
|
+
return false
|
152
|
+
}
|
153
|
+
return true
|
154
|
+
} else if resp.StatusCode == 429 {
|
155
|
+
fmt.Printf(" [!] Server responded with 429 (Too many requests), throttling and retrying...\n")
|
156
|
+
time.Sleep(10 * time.Second)
|
157
|
+
retry = retry + 1
|
158
|
+
return n.isAvailableInPublic(pkgname, retry)
|
159
|
+
}
|
160
|
+
return false
|
161
|
+
}
|
162
|
+
|
163
|
+
// localReference checks if the package version is in fact a reference to filesystem
|
164
|
+
func (n *NPMLookup) localReference(pkgversion string) bool {
|
165
|
+
return strings.HasPrefix(strings.ToLower(pkgversion), "file:")
|
166
|
+
}
|
167
|
+
|
168
|
+
// urlReference checks if the package version is in fact a reference to a direct URL
|
169
|
+
func (n *NPMLookup) urlReference(pkgversion string) bool {
|
170
|
+
pkgversion = strings.ToLower(pkgversion)
|
171
|
+
return strings.HasPrefix(pkgversion, "http:") || strings.HasPrefix(pkgversion, "https:")
|
172
|
+
}
|
173
|
+
|
174
|
+
// gitReference checks if the package version is in fact a reference to a remote git repository
|
175
|
+
func (n *NPMLookup) gitReference(pkgversion string) bool {
|
176
|
+
pkgversion = strings.ToLower(pkgversion)
|
177
|
+
gitResources := []string{"git+ssh:", "git+http:", "git+https:", "git:"}
|
178
|
+
for _, r := range gitResources {
|
179
|
+
if strings.HasPrefix(pkgversion, r) {
|
180
|
+
return true
|
181
|
+
}
|
182
|
+
}
|
183
|
+
return false
|
184
|
+
}
|
185
|
+
|
186
|
+
// gitHubReference checks if the package version refers to a GitHub repository
|
187
|
+
func (n *NPMLookup) gitHubReference(pkgversion string) bool {
|
188
|
+
return !strings.HasPrefix(pkgversion, "@") && strings.Contains(pkgversion, "/")
|
189
|
+
}
|
190
|
+
|
191
|
+
// gitHubOrgExists returns true if GitHub organization / user exists
|
192
|
+
func (n NPMLookup) gitHubOrgExists(pkgversion string) bool {
|
193
|
+
orgName := strings.Split(pkgversion, "/")[0]
|
194
|
+
if len(orgName) > 0 {
|
195
|
+
if n.Verbose {
|
196
|
+
fmt.Print("Checking: https://github.com/" + orgName + " : ")
|
197
|
+
}
|
198
|
+
resp, err := http.Get("https://github.com/" + orgName)
|
199
|
+
if err != nil {
|
200
|
+
fmt.Printf(" [W] Error while trying to request https://github.com/"+orgName+" : %s\n", err)
|
201
|
+
return false
|
202
|
+
}
|
203
|
+
defer resp.Body.Close()
|
204
|
+
if n.Verbose {
|
205
|
+
fmt.Printf("%d\n", resp.StatusCode)
|
206
|
+
}
|
207
|
+
return resp.StatusCode == 200
|
208
|
+
}
|
209
|
+
return false
|
210
|
+
}
|
@@ -0,0 +1,111 @@
|
|
1
|
+
{
|
2
|
+
"name": "walkme-killer",
|
3
|
+
"version": "1.0.0",
|
4
|
+
"description": "",
|
5
|
+
"main": "index.js",
|
6
|
+
"babel": {
|
7
|
+
"presets": [
|
8
|
+
"@babel/preset-env",
|
9
|
+
"@babel/preset-react"
|
10
|
+
]
|
11
|
+
},
|
12
|
+
"scripts": {
|
13
|
+
"dev": "concurrently --kill-others-on-fail \"nodemon server.js\" \"webpack --watch --config webpack.dev.js\"",
|
14
|
+
"test": "jest test",
|
15
|
+
"test:coverage": "jest --coverage",
|
16
|
+
"test:ci": "jest --verbose 2>&1 | tee unit_test_results.log",
|
17
|
+
"bundle": "webpack --config webpack.prod.js",
|
18
|
+
"clean": "rm -rf node_modules",
|
19
|
+
"start": "node server.js",
|
20
|
+
"lint": "eslint src __tests__ --fix",
|
21
|
+
"prepare": "husky install"
|
22
|
+
},
|
23
|
+
"keywords": [],
|
24
|
+
"author": "",
|
25
|
+
"license": "ISC",
|
26
|
+
"dependencies": {
|
27
|
+
"@babel/core": "^7.24.0",
|
28
|
+
"@babel/preset-env": "^7.24.0",
|
29
|
+
"@babel/preset-react": "^7.23.3",
|
30
|
+
"axios": "^0.21.4",
|
31
|
+
"babel-loader": "^8.3.0",
|
32
|
+
"body-parser": "^1.19.0",
|
33
|
+
"bowser": "^2.9.0",
|
34
|
+
"clean-webpack-plugin": "^4.0.0",
|
35
|
+
"core-js": "3.32.2",
|
36
|
+
"cors": "^2.8.5",
|
37
|
+
"css-loader": "^3.6.0",
|
38
|
+
"css-minimizer-webpack-plugin": "^5.0.1",
|
39
|
+
"dotenv": "^8.2.0",
|
40
|
+
"ejs": "^3.1.9",
|
41
|
+
"express": "^4.17.1",
|
42
|
+
"express-healthcheck": "^0.1.0",
|
43
|
+
"extract-loader": "^5.1.0",
|
44
|
+
"focus-trap-react": "^8.9.2",
|
45
|
+
"formdata-polyfill": "^3.0.19",
|
46
|
+
"husky": "^8.0.3",
|
47
|
+
"jsonwebtoken": "^9.0.0",
|
48
|
+
"memory-cache": "^0.2.0",
|
49
|
+
"morgan": "^1.10.0",
|
50
|
+
"newrelic": "^11.1.0",
|
51
|
+
"passport": "^0.6.0",
|
52
|
+
"passport-jwt": "^4.0.1",
|
53
|
+
"passport-local": "^1.0.0",
|
54
|
+
"pg": "^8.10.0",
|
55
|
+
"pg-hstore": "^2.3.4",
|
56
|
+
"prop-types": "^15.8.1",
|
57
|
+
"raw-loader": "^4.0.1",
|
58
|
+
"react": "^16.13.1",
|
59
|
+
"react-bootstrap": "^1.0.0",
|
60
|
+
"react-dom": "^16.13.1",
|
61
|
+
"redact-pii-light": "^1.0.0",
|
62
|
+
"resolve-url-loader": "^5.0.0",
|
63
|
+
"sass": "^1.26.3",
|
64
|
+
"sass-loader": "^8.0.2",
|
65
|
+
"sequelize": "^6.30.0",
|
66
|
+
"style-loader": "^1.1.4",
|
67
|
+
"terser-webpack-plugin": "^4.2.3",
|
68
|
+
"webpack": "^5.88.2",
|
69
|
+
"webpack-cli": "^5.1.4",
|
70
|
+
"webpack-merge": "^5.9.0",
|
71
|
+
"winston": "^3.2.1"
|
72
|
+
},
|
73
|
+
"devDependencies": {
|
74
|
+
"@testing-library/dom": "^7.12.0",
|
75
|
+
"@testing-library/jest-dom": "^5.9.0",
|
76
|
+
"@testing-library/react": "^10.2.1",
|
77
|
+
"babel-core": "^7.0.0-bridge.0",
|
78
|
+
"babel-jest": "^23.4.2",
|
79
|
+
"concurrently": "^5.2.0",
|
80
|
+
"eslint": "8.22.0",
|
81
|
+
"eslint-config-prettier": "^8.5.0",
|
82
|
+
"eslint-plugin-jest": "^27.0.4",
|
83
|
+
"eslint-plugin-prettier": "^4.2.1",
|
84
|
+
"eslint-plugin-react": "^7.31.10",
|
85
|
+
"husky": "^8.0.0",
|
86
|
+
"jest": "^26.4.2",
|
87
|
+
"jira-prepare-commit-msg": "^1.7.2",
|
88
|
+
"lint-staged": "^10.4.2",
|
89
|
+
"msw": "^0.19.0",
|
90
|
+
"nodemon": "^3.0.1",
|
91
|
+
"prettier": "^2.7.1"
|
92
|
+
},
|
93
|
+
"jest": {
|
94
|
+
"setupFilesAfterEnv": [
|
95
|
+
"<rootDir>/setUpTests.js"
|
96
|
+
],
|
97
|
+
"moduleNameMapper": {
|
98
|
+
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/__mocks__/fileMock.js",
|
99
|
+
"\\.(css|less|scss)$": "<rootDir>/__mocks__/styleMock.js"
|
100
|
+
},
|
101
|
+
"testPathIgnorePatterns": [
|
102
|
+
"/__fixtures__/"
|
103
|
+
]
|
104
|
+
},
|
105
|
+
"lint-staged": {
|
106
|
+
"*.js": [
|
107
|
+
"npm run lint",
|
108
|
+
"git add"
|
109
|
+
]
|
110
|
+
}
|
111
|
+
}
|