diff --git a/Makefile b/Makefile
index 9974f982b..f0724de4c 100644
--- a/Makefile
+++ b/Makefile
@@ -31,7 +31,7 @@ coverage-horusec-analytic:
deployments/scripts/coverage.sh 98 "./horusec-analytic"
coverage-horusec-auth:
chmod +x deployments/scripts/coverage.sh
- deployments/scripts/coverage.sh 97 "./horusec-auth"
+ deployments/scripts/coverage.sh 96 "./horusec-auth"
coverage-horusec-webhook:
chmod +x deployments/scripts/coverage.sh
deployments/scripts/coverage.sh 99 "./horusec-webhook"
diff --git a/README.md b/README.md
index 41434a422..563f88b71 100644
--- a/README.md
+++ b/README.md
@@ -62,8 +62,10 @@ Currently, performance analysis consists of:
* [GitLeaks][Gitleaks]
* PHP
* [Semgrep][Semgrep]
-* C
+ * [PHPCS][PHPCS]
+* C/C++
* [Semgrep][Semgrep]
+ * [Flawfinder][Flawfinder]
* HTML
* [Semgrep][Semgrep]
* JSON
@@ -185,3 +187,5 @@ This project exists thanks to all the [contributors]((https://github.com/ZupIT/h
[SecuriyCodeScan]: https://security-code-scan.github.io/
[Semgrep]: https://github.com/returntocorp/semgrep
[EsLint]: https://github.com/eslint/eslint
+[Flawfinder]: https://github.com/david-a-wheeler/flawfinder
+[PHPCS]: https://github.com/FloeDesignTechnologies/phpcs-security-audit
diff --git a/deployments/dockerfiles/flawfinder/.semver.yaml b/deployments/dockerfiles/flawfinder/.semver.yaml
new file mode 100644
index 000000000..36a2accc3
--- /dev/null
+++ b/deployments/dockerfiles/flawfinder/.semver.yaml
@@ -0,0 +1,4 @@
+alpha: 0
+beta: 0
+rc: 0
+release: v1.0.0
diff --git a/deployments/dockerfiles/flawfinder/Dockerfile b/deployments/dockerfiles/flawfinder/Dockerfile
new file mode 100644
index 000000000..d92cf144f
--- /dev/null
+++ b/deployments/dockerfiles/flawfinder/Dockerfile
@@ -0,0 +1,18 @@
+# Copyright 2020 ZUP IT SERVICOS EM TECNOLOGIA E INOVACAO SA
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+FROM python:3.7-alpine
+
+RUN apk add --no-cache git bash
+RUN pip install flawfinder
\ No newline at end of file
diff --git a/deployments/dockerfiles/phpcs/.semver.yaml b/deployments/dockerfiles/phpcs/.semver.yaml
new file mode 100644
index 000000000..36a2accc3
--- /dev/null
+++ b/deployments/dockerfiles/phpcs/.semver.yaml
@@ -0,0 +1,4 @@
+alpha: 0
+beta: 0
+rc: 0
+release: v1.0.0
diff --git a/deployments/dockerfiles/phpcs/Dockerfile b/deployments/dockerfiles/phpcs/Dockerfile
new file mode 100644
index 000000000..05cb3c0f7
--- /dev/null
+++ b/deployments/dockerfiles/phpcs/Dockerfile
@@ -0,0 +1,25 @@
+# Copyright 2020 ZUP IT SERVICOS EM TECNOLOGIA E INOVACAO SA
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+FROM php:7.4-alpine
+
+RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
+
+RUN composer global config bin-dir /usr/local/bin
+
+RUN composer global require "squizlabs/php_codesniffer=*"
+
+RUN composer require --dev pheromone/phpcs-security-audit
+
+RUN phpcs --config-set installed_paths /vendor/pheromone/phpcs-security-audit/Security
diff --git a/deployments/scripts/update-image-tool.sh b/deployments/scripts/update-image-tool.sh
index 091e8ea19..dcc0b4188 100755
--- a/deployments/scripts/update-image-tool.sh
+++ b/deployments/scripts/update-image-tool.sh
@@ -101,6 +101,14 @@ getDirectoryAndImageNameByToolName () {
IMAGE_NAME="horuszup/eslint"
DIRECTORY_CONFIG="$CURRENT_FOLDER/horusec-cli/internal/services/formatters/javascript/eslint/config.go"
DIRECTORY_SEMVER="$CURRENT_FOLDER/deployments/dockerfiles/eslint";;
+ "phpcs")
+ IMAGE_NAME="horuszup/horusec-phpcs"
+ DIRECTORY_CONFIG="$CURRENT_FOLDER/horusec-cli/internal/services/formatters/php/phpcs/config.go"
+ DIRECTORY_SEMVER="$CURRENT_FOLDER/deployments/dockerfiles/phpcs";;
+ "flawfinder")
+ IMAGE_NAME="horuszup/horusec-flawfinder"
+ DIRECTORY_CONFIG="$CURRENT_FOLDER/horusec-cli/internal/services/formatters/c/flawfinder/config.go"
+ DIRECTORY_SEMVER="$CURRENT_FOLDER/deployments/dockerfiles/flawfinder";;
"horusec-nodejs")
IMAGE_NAME="horuszup/horusec-nodejs"
DIRECTORY_CONFIG="$CURRENT_FOLDER/horusec-cli/internal/services/formatters/javascript/horusecnodejs/config.go"
@@ -111,7 +119,7 @@ getDirectoryAndImageNameByToolName () {
DIRECTORY_SEMVER="$CURRENT_FOLDER/horusec-kubernetes";;
*)
echo "Param Tool Name is invalid, please use the examples bellow allowed and try again!"
- echo "Params Tool Name allowed: bandit, brakeman, gitleaks, gosec, npmaudit, safety, securitycodescan, hcl, spotbugs, horusec-kotlin, horusec-java, horusec-leaks, horusec-csharp, horusec-nodejs, horusec-kubernetes"
+ echo "Params Tool Name allowed: bandit, brakeman, gitleaks, gosec, npmaudit, safety, securitycodescan, hcl, spotbugs, horusec-kotlin, horusec-java, horusec-leaks, horusec-csharp, horusec-nodejs, horusec-kubernetes, phpcs, flawfinder"
exit 1;;
esac
}
diff --git a/development-kit/pkg/databases/relational/repository/account/account.go b/development-kit/pkg/databases/relational/repository/account/account.go
index de076d5c0..7b081dcb6 100644
--- a/development-kit/pkg/databases/relational/repository/account/account.go
+++ b/development-kit/pkg/databases/relational/repository/account/account.go
@@ -25,6 +25,7 @@ type IAccount interface {
GetByAccountID(accountID uuid.UUID) (*authEntities.Account, error)
GetByEmail(email string) (*authEntities.Account, error)
Update(account *authEntities.Account) error
+ UpdatePassword(account *authEntities.Account) error
GetByUsername(username string) (*authEntities.Account, error)
DeleteAccount(accountID uuid.UUID) error
}
@@ -61,7 +62,13 @@ func (a *Account) GetByEmail(email string) (*authEntities.Account, error) {
func (a *Account) Update(account *authEntities.Account) error {
account.SetUpdatedAt()
- return a.databaseWrite.Update(account.ToMap(), map[string]interface{}{"account_id": account.AccountID},
+ return a.databaseWrite.Update(account.ToUpdateMap(), map[string]interface{}{"account_id": account.AccountID},
+ account.GetTable()).GetError()
+}
+
+func (a *Account) UpdatePassword(account *authEntities.Account) error {
+ account.SetUpdatedAt()
+ return a.databaseWrite.Update(account.ToUpdatePasswordMap(), map[string]interface{}{"account_id": account.AccountID},
account.GetTable()).GetError()
}
diff --git a/development-kit/pkg/engines/leaks/analysis/analysis_test.go b/development-kit/pkg/engines/leaks/analysis/analysis_test.go
index f5e66acd8..0a20af56f 100644
--- a/development-kit/pkg/engines/leaks/analysis/analysis_test.go
+++ b/development-kit/pkg/engines/leaks/analysis/analysis_test.go
@@ -41,7 +41,7 @@ func TestAnalysis_StartAnalysis(t *testing.T) {
data := []engine.Finding{}
_ = json.Unmarshal(fileBytes, &data)
assert.NoError(t, os.RemoveAll(configs.GetOutputFilePath()))
- assert.Equal(t, len(data), 17)
+ assert.Equal(t, len(data), 19)
})
t.Run("Should return success when read analysis and return two vulnerabilities", func(t *testing.T) {
configs := config.NewConfig()
@@ -117,6 +117,6 @@ func TestAnalysis_StartRegularAnalysis(t *testing.T) {
vulnCounter++
}
}
- assert.Equal(t, vulnCounter, 10)
+ assert.Equal(t, 12, vulnCounter)
})
}
diff --git a/development-kit/pkg/entities/analyser/c/result.go b/development-kit/pkg/entities/analyser/c/result.go
new file mode 100644
index 000000000..a78d1c40b
--- /dev/null
+++ b/development-kit/pkg/entities/analyser/c/result.go
@@ -0,0 +1,54 @@
+// Copyright 2020 ZUP IT SERVICOS EM TECNOLOGIA E INOVACAO SA
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package c
+
+import (
+ "fmt"
+ "github.com/ZupIT/horusec/development-kit/pkg/enums/severity"
+ "strconv"
+ "strings"
+)
+
+type Result struct {
+ File string `json:"file"`
+ Line string `json:"line"`
+ Column string `json:"column"`
+ Level string `json:"level"`
+ Warning string `json:"warning"`
+ Suggestion string `json:"suggestion"`
+ Note string `json:"note"`
+ Context string `json:"context"`
+}
+
+func (r *Result) GetDetails() string {
+ return fmt.Sprintf("%s %s %s", r.Warning, r.Suggestion, r.Note)
+}
+
+func (r *Result) GetSeverity() severity.Severity {
+ level, _ := strconv.Atoi(r.Level)
+ if level <= 2 {
+ return severity.Low
+ }
+
+ if level >= 3 && level <= 4 {
+ return severity.Medium
+ }
+
+ return severity.High
+}
+
+func (r *Result) GetFilename() string {
+ return strings.ReplaceAll(r.File, "./", "")
+}
diff --git a/development-kit/pkg/entities/analyser/c/result_test.go b/development-kit/pkg/entities/analyser/c/result_test.go
new file mode 100644
index 000000000..286f6b9b3
--- /dev/null
+++ b/development-kit/pkg/entities/analyser/c/result_test.go
@@ -0,0 +1,82 @@
+package c
+
+import (
+ "github.com/ZupIT/horusec/development-kit/pkg/enums/severity"
+ "github.com/stretchr/testify/assert"
+ "testing"
+)
+
+func TestGetDetails(t *testing.T) {
+ result := &Result{
+ Warning: "test",
+ Suggestion: "test",
+ Note: "test",
+ }
+
+ t.Run("should success get details", func(t *testing.T) {
+ details := result.GetDetails()
+
+ assert.NotEmpty(t, details)
+ assert.Equal(t, "test test test", details)
+ })
+
+}
+
+func TestGetSeverity(t *testing.T) {
+ result := &Result{
+ Level: "0",
+ }
+
+ t.Run("should get severity low", func(t *testing.T) {
+ assert.Equal(t, severity.Low, result.GetSeverity())
+
+ result.Level = "1"
+ assert.Equal(t, severity.Low, result.GetSeverity())
+
+ result.Level = "2"
+ assert.Equal(t, severity.Low, result.GetSeverity())
+ })
+
+ t.Run("should get severity medium", func(t *testing.T) {
+ result.Level = "3"
+ assert.Equal(t, severity.Medium, result.GetSeverity())
+
+ result.Level = "4"
+ assert.Equal(t, severity.Medium, result.GetSeverity())
+
+ result.Level = "2"
+ assert.NotEqual(t, severity.Medium, result.GetSeverity())
+
+ result.Level = "5"
+ assert.NotEqual(t, severity.Medium, result.GetSeverity())
+ })
+
+ t.Run("should get severity high", func(t *testing.T) {
+ result.Level = "5"
+ assert.Equal(t, severity.High, result.GetSeverity())
+
+ result.Level = "6"
+ assert.Equal(t, severity.High, result.GetSeverity())
+
+ result.Level = "1"
+ assert.NotEqual(t, severity.High, result.GetSeverity())
+
+ result.Level = "4"
+ assert.NotEqual(t, severity.High, result.GetSeverity())
+ })
+}
+
+func TestGetFilename(t *testing.T) {
+ result := &Result{
+ File: "./test.c",
+ }
+
+ t.Run("should success get filename", func(t *testing.T) {
+ filename := result.GetFilename()
+
+ assert.NotEmpty(t, filename)
+ assert.NotContains(t, filename, "./")
+ assert.Equal(t, "test.c", filename)
+ })
+
+}
diff --git a/development-kit/pkg/entities/analyser/php/phpcs/message.go b/development-kit/pkg/entities/analyser/php/phpcs/message.go
new file mode 100644
index 000000000..aba44416f
--- /dev/null
+++ b/development-kit/pkg/entities/analyser/php/phpcs/message.go
@@ -0,0 +1,26 @@
+package phpcs
+
+import (
+ "strconv"
+ "strings"
+)
+
+type Message struct {
+ Message string `json:"message"`
+ Line int `json:"line"`
+ Column int `json:"column"`
+ Type string `json:"type"`
+}
+
+func (m *Message) GetLine() string {
+ return strconv.Itoa(m.Line)
+}
+
+func (m *Message) GetColumn() string {
+ return strconv.Itoa(m.Column)
+}
+
+func (m *Message) IsValidMessage() bool {
+ return m.Type == "ERROR" &&
+ !strings.Contains(m.Message, "This implies that some PHP code is not scanned by PHPCS")
+}
diff --git a/development-kit/pkg/entities/analyser/php/phpcs/message_test.go b/development-kit/pkg/entities/analyser/php/phpcs/message_test.go
new file mode 100644
index 000000000..2936b114f
--- /dev/null
+++ b/development-kit/pkg/entities/analyser/php/phpcs/message_test.go
@@ -0,0 +1,52 @@
+package phpcs
+
+import (
+ "github.com/stretchr/testify/assert"
+ "testing"
+)
+
+func TestGetLine(t *testing.T) {
+ message := &Message{
+ Line: 1,
+ }
+
+ t.Run("should success get line", func(t *testing.T) {
+ line := message.GetLine()
+
+ assert.NotEmpty(t, line)
+ assert.Equal(t, "1", line)
+ })
+}
+
+func TestGetColumn(t *testing.T) {
+ message := &Message{
+ Column: 1,
+ }
+
+ t.Run("should success get column", func(t *testing.T) {
+ column := message.GetColumn()
+
+ assert.NotEmpty(t, column)
+ assert.Equal(t, "1", column)
+ })
+}
+
+func TestIsValidMessage(t *testing.T) {
+ t.Run("should return false if invalid message", func(t *testing.T) {
+ message := &Message{
+ Message: "This implies that some PHP code is not scanned by PHPCS",
+ Type: "ERROR",
+ }
+
+ assert.False(t, message.IsValidMessage())
+ })
+
+ t.Run("should return true if valid message", func(t *testing.T) {
+ message := &Message{
+ Message: "",
+ Type: "ERROR",
+ }
+
+ assert.True(t, message.IsValidMessage())
+ })
+}
diff --git a/development-kit/pkg/entities/analyser/php/phpcs/result.go b/development-kit/pkg/entities/analyser/php/phpcs/result.go
new file mode 100644
index 000000000..5fd5debb2
--- /dev/null
+++ b/development-kit/pkg/entities/analyser/php/phpcs/result.go
@@ -0,0 +1,5 @@
+package phpcs
+
+type Result struct {
+ Messages []Message `json:"messages"`
+}
diff --git a/development-kit/pkg/entities/auth/account.go b/development-kit/pkg/entities/auth/account.go
index 875e83f30..62672a26b 100644
--- a/development-kit/pkg/entities/auth/account.go
+++ b/development-kit/pkg/entities/auth/account.go
@@ -118,6 +118,21 @@ func (a *Account) ToMap() map[string]interface{} {
}
}
+func (a *Account) ToUpdateMap() map[string]interface{} {
+ return map[string]interface{}{
+ "email": a.Email,
+ "username": a.Username,
+ "updated_at": a.UpdatedAt,
+ "is_confirmed": a.IsConfirmed,
+ }
+}
+
+func (a *Account) ToUpdatePasswordMap() map[string]interface{} {
+ return map[string]interface{}{
+ "password": a.Password,
+ }
+}
+
func (a *Account) IsNotApplicationAdminAccount() bool {
return !a.IsApplicationAdmin
}
diff --git a/development-kit/pkg/entities/auth/account_test.go b/development-kit/pkg/entities/auth/account_test.go
index 21341d931..818e15f50 100644
--- a/development-kit/pkg/entities/auth/account_test.go
+++ b/development-kit/pkg/entities/auth/account_test.go
@@ -15,10 +15,11 @@
package auth
import (
- "github.com/google/uuid"
- "github.com/stretchr/testify/assert"
"testing"
"time"
+
+ "github.com/google/uuid"
+ "github.com/stretchr/testify/assert"
)
func TestSetPassword(t *testing.T) {
@@ -113,6 +114,25 @@ func TestToMap(t *testing.T) {
})
}
+func TestToUpdateMap(t *testing.T) {
+ t.Run("should success parse to map", func(t *testing.T) {
+ account := &Account{
+ AccountID: uuid.New(),
+ Email: "test",
+ Password: "test",
+ Username: "test",
+ IsConfirmed: false,
+ CreatedAt: time.Now(),
+ UpdatedAt: time.Now(),
+ }
+
+ accountMap := account.ToUpdateMap()
+
+ assert.NotEmpty(t, account)
+ assert.Empty(t, accountMap["password"])
+ })
+}
+
func TestIsNotApplicationAdminAccount(t *testing.T) {
t.Run("Should return true when get if user is application admin", func(t *testing.T) {
account := &Account{
diff --git a/development-kit/pkg/entities/auth/config_auth.go b/development-kit/pkg/entities/auth/config_auth.go
index 80b4b2e23..49c6bff3a 100644
--- a/development-kit/pkg/entities/auth/config_auth.go
+++ b/development-kit/pkg/entities/auth/config_auth.go
@@ -21,6 +21,7 @@ import (
type ConfigAuth struct {
ApplicationAdminEnable bool `json:"applicationAdminEnable"`
+ DisabledBroker bool `json:"disabledBroker"`
AuthType auth.AuthorizationType `json:"authType"`
}
diff --git a/development-kit/pkg/entities/webhook/headers_test.go b/development-kit/pkg/entities/webhook/headers_test.go
index fffa940b1..c8c6c11df 100644
--- a/development-kit/pkg/entities/webhook/headers_test.go
+++ b/development-kit/pkg/entities/webhook/headers_test.go
@@ -16,15 +16,16 @@ package webhook
import (
"encoding/json"
- "github.com/stretchr/testify/assert"
"testing"
+
+ "github.com/stretchr/testify/assert"
)
func TestHeaderType_Value(t *testing.T) {
var h HeaderType
h = []Headers{
{
- Key: "Authorization",
+ Key: "X-Horusec-Authorization",
Value: "Bearer Token",
},
}
@@ -42,7 +43,7 @@ func TestHeaderType_Scan(t *testing.T) {
var h HeaderType
bytes, err := json.Marshal([]Headers{
{
- Key: "Authorization",
+ Key: "X-Horusec-Authorization",
Value: "Bearer Token",
},
})
diff --git a/development-kit/pkg/entities/webhook/webhook_test.go b/development-kit/pkg/entities/webhook/webhook_test.go
index 13893c136..d2e5c4c44 100644
--- a/development-kit/pkg/entities/webhook/webhook_test.go
+++ b/development-kit/pkg/entities/webhook/webhook_test.go
@@ -15,11 +15,12 @@
package webhook
import (
+ "net/http"
+ "testing"
+
errorsEnum "github.com/ZupIT/horusec/development-kit/pkg/enums/errors"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
- "net/http"
- "testing"
)
func TestWebhook_GetMethod(t *testing.T) {
@@ -58,14 +59,14 @@ func TestWebhook_GetHeaders(t *testing.T) {
w := &Webhook{
Headers: []Headers{
{
- Key: "Authorization",
+ Key: "X-Horusec-Authorization",
Value: "Bearer token",
},
},
}
headerMap := w.GetHeaders()
assert.NotEmpty(t, headerMap)
- assert.Equal(t, "Bearer token", headerMap["Authorization"])
+ assert.Equal(t, "Bearer token", headerMap["X-Horusec-Authorization"])
}
func TestWebhook_Validate(t *testing.T) {
diff --git a/development-kit/pkg/enums/engine/advisories/leaks/regular/regular.go b/development-kit/pkg/enums/engine/advisories/leaks/regular/regular.go
index a8ddbcd00..8d105e197 100644
--- a/development-kit/pkg/enums/engine/advisories/leaks/regular/regular.go
+++ b/development-kit/pkg/enums/engine/advisories/leaks/regular/regular.go
@@ -249,7 +249,7 @@ func NewLeaksRegularGoogleGCPServiceAccount() text.TextRule {
Expressions: []*regexp.Regexp{
regexp.MustCompile(`"type": "service_account"`),
regexp.MustCompile(`(?i)(google|gcp|youtube|drive|yt)(.{0,20})?['\"][AIza[0-9a-z\\-_]{35}]['\"]`),
- regexp.MustCompile(`(?i)(google|gcp|auth)(.{0,20})?['\"][0-9]+-[0-9a-z_]{32}\\.apps\\.googleusercontent\\.com['\"]`),
+ regexp.MustCompile(`(?i)(google|gcp|auth)(.{0,20})?['\"][0-9]+-[0-9a-z_]{32}\.apps\.googleusercontent\.com['\"]`),
},
}
}
@@ -425,7 +425,7 @@ func NewLeaksRegularHardCodedCredentialGeneric() text.TextRule {
},
Type: text.Regular,
Expressions: []*regexp.Regexp{
- regexp.MustCompile(`(?i)(dbpasswd|dbuser|dbname|dbhost|api_key|apikey|client_secret|clientsecret|access_key|accesskey|secret_key|secretkey)(.{0,20})?['|"]([0-9a-zA-Z-_\/+!{}/=]{4,120})['|"]`),
+ regexp.MustCompile(`(?i)(dbpasswd|dbuser|dbname|dbhost|api_key|apikey|client_secret|clientsecret|access_key|accesskey|secret_key|secretkey)(.{0,20})?['|"]([0-9a-zA-Z-_\/+!{}/=:@#%\*]{4,120})['|"]`),
},
}
}
@@ -477,7 +477,7 @@ func NewLeaksRegularWPConfig() text.TextRule {
},
Type: text.Regular,
Expressions: []*regexp.Regexp{
- regexp.MustCompile(`define(.{0,20})?(DB_CHARSET|NONCE_SALT|LOGGED_IN_SALT|AUTH_SALT|NONCE_KEY|DB_HOST|DB_PASSWORD|AUTH_KEY|SECURE_AUTH_KEY|LOGGED_IN_KEY|DB_NAME|DB_USER)(.{0,20})?[''|"].{10,120}[''|"]`),
+ regexp.MustCompile(`define(.{0,20})?(DB_CHARSET|NONCE_SALT|LOGGED_IN_SALT|AUTH_SALT|NONCE_KEY|DB_HOST|DB_PASSWORD|AUTH_KEY|SECURE_AUTH_KEY|LOGGED_IN_KEY|DB_NAME|DB_USER).*,\s*[''|"].{6,120}[''|"]`),
},
}
}
diff --git a/development-kit/pkg/enums/engine/advisories/leaks/regular/regular_test.go b/development-kit/pkg/enums/engine/advisories/leaks/regular/regular_test.go
new file mode 100644
index 000000000..b047e5441
--- /dev/null
+++ b/development-kit/pkg/enums/engine/advisories/leaks/regular/regular_test.go
@@ -0,0 +1,1365 @@
+package regular
+
+import (
+ engine "github.com/ZupIT/horusec-engine"
+ "github.com/stretchr/testify/assert"
+ "testing"
+
+ "github.com/ZupIT/horusec-engine/text"
+)
+
+func parseTextUnitsToUnits(textUnits []text.TextUnit) (units []engine.Unit) {
+ for index := range textUnits {
+ units = append(units, textUnits[index])
+ }
+ return units
+}
+
+func TestNewLeaksRegularAWSManagerID(t *testing.T) {
+ t.Run("Should return vulnerable code NewLeaksRegularAWSManagerID", func(t *testing.T) {
+ code := `
+version: '3'
+services:
+ backend:
+ image: image/my-backend:latest
+ environment:
+ ACCESS_KEY: 'AKIAJSIE27KKMHXI3BJQ'
+`
+ rule := NewLeaksRegularAWSManagerID()
+ textFile, err := text.NewTextFile("deployments/docker-compose.yaml", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 1)
+ assert.Equal(t, engine.Finding{
+ ID: rule.ID,
+ Name: rule.Name,
+ Severity: rule.Severity,
+ CodeSample: "ACCESS_KEY: 'AKIAJSIE27KKMHXI3BJQ'",
+ Confidence: rule.Confidence,
+ Description: rule.Description,
+ SourceLocation: engine.Location{
+ Filename: "deployments/docker-compose.yaml",
+ Line: 7,
+ Column: 18,
+ },
+ }, findings[0])
+ })
+ t.Run("Should not return vulnerable code NewLeaksRegularAWSManagerID", func(t *testing.T) {
+ code := `
+version: '3'
+services:
+ backend:
+ image: image/my-backend:latest
+ environment:
+ ACCESS_KEY: ${SECRET_KEY}
+`
+ rule := NewLeaksRegularAWSManagerID()
+ textFile, err := text.NewTextFile("deployments/docker-compose.yaml", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 0)
+ })
+}
+
+func TestNewLeaksRegularAWSSecretKey(t *testing.T) {
+ t.Run("Should return vulnerable code NewLeaksRegularAWSSecretKey", func(t *testing.T) {
+ code := `
+version: '3'
+services:
+ backend:
+ image: image/my-backend:latest
+ environment:
+ AWS_SECRET_KEY: 'doc5eRXFpsWllGC5yKJV/Ymm5KwF+IRZo95EudOm'
+`
+ rule := NewLeaksRegularAWSSecretKey()
+ textFile, err := text.NewTextFile("deployments/docker-compose.yaml", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 1)
+ assert.Equal(t, engine.Finding{
+ ID: rule.ID,
+ Name: rule.Name,
+ Severity: rule.Severity,
+ CodeSample: `AWS_SECRET_KEY: 'doc5eRXFpsWllGC5yKJV/Ymm5KwF+IRZo95EudOm'`,
+ Confidence: rule.Confidence,
+ Description: rule.Description,
+ SourceLocation: engine.Location{
+ Filename: "deployments/docker-compose.yaml",
+ Line: 7,
+ Column: 6,
+ },
+ }, findings[0])
+ })
+ t.Run("Should not return vulnerable code NewLeaksRegularAWSSecretKey", func(t *testing.T) {
+ code := `
+version: '3'
+services:
+ backend:
+ image: image/my-backend:latest
+ environment:
+ SECRET_KEY: ${SECRET_KEY}
+`
+ rule := NewLeaksRegularAWSSecretKey()
+ textFile, err := text.NewTextFile("deployments/docker-compose.yaml", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 0)
+ })
+}
+
+func TestNewLeaksRegularAWSMWSKey(t *testing.T) {
+ t.Run("Should return vulnerable code NewLeaksRegularAWSMWSKey", func(t *testing.T) {
+ code := `
+version: '3'
+services:
+ backend:
+ image: image/my-backend:latest
+ environment:
+ AWS_WMS_KEY: 'amzn.mws.986478f0-9775-eabc-2af4-e499a8496828'
+`
+ rule := NewLeaksRegularAWSMWSKey()
+ textFile, err := text.NewTextFile("deployments/docker-compose.yaml", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 1)
+ assert.Equal(t, engine.Finding{
+ ID: rule.ID,
+ Name: rule.Name,
+ Severity: rule.Severity,
+ CodeSample: `AWS_WMS_KEY: 'amzn.mws.986478f0-9775-eabc-2af4-e499a8496828'`,
+ Confidence: rule.Confidence,
+ Description: rule.Description,
+ SourceLocation: engine.Location{
+ Filename: "deployments/docker-compose.yaml",
+ Line: 7,
+ Column: 20,
+ },
+ }, findings[0])
+ })
+ t.Run("Should not return vulnerable code NewLeaksRegularAWSMWSKey", func(t *testing.T) {
+ code := `
+version: '3'
+services:
+ backend:
+ image: image/my-backend:latest
+ environment:
+ WMS_KEY: ${SECRET_KEY}
+`
+ rule := NewLeaksRegularAWSMWSKey()
+ textFile, err := text.NewTextFile("deployments/docker-compose.yaml", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 0)
+ })
+}
+
+func TestNewLeaksRegularFacebookSecretKey(t *testing.T) {
+ t.Run("Should return vulnerable code NewLeaksRegularFacebookSecretKey", func(t *testing.T) {
+ code := `
+version: '3'
+services:
+ backend:
+ image: image/my-backend:latest
+ environment:
+ FB_SECRET_KEY: 'cb6f53505911332d30867f44a1c1b9b5'
+`
+ rule := NewLeaksRegularFacebookSecretKey()
+ textFile, err := text.NewTextFile("deployments/docker-compose.yaml", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 1)
+ assert.Equal(t, engine.Finding{
+ ID: rule.ID,
+ Name: rule.Name,
+ Severity: rule.Severity,
+ CodeSample: `FB_SECRET_KEY: 'cb6f53505911332d30867f44a1c1b9b5'`,
+ Confidence: rule.Confidence,
+ Description: rule.Description,
+ SourceLocation: engine.Location{
+ Filename: "deployments/docker-compose.yaml",
+ Line: 7,
+ Column: 6,
+ },
+ }, findings[0])
+ })
+ t.Run("Should not return vulnerable code NewLeaksRegularFacebookSecretKey", func(t *testing.T) {
+ code := `
+version: '3'
+services:
+ backend:
+ image: image/my-backend:latest
+ environment:
+ FB_SECRET_KEY: ${SECRET_KEY}
+`
+ rule := NewLeaksRegularFacebookSecretKey()
+ textFile, err := text.NewTextFile("deployments/docker-compose.yaml", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 0)
+ })
+}
+
+func TestNewLeaksRegularFacebookClientID(t *testing.T) {
+ t.Run("Should return vulnerable code NewLeaksRegularFacebookClientID", func(t *testing.T) {
+ code := `
+version: '3'
+services:
+ backend:
+ image: image/my-backend:latest
+ environment:
+ FB_CLIENT_ID: '148695999071979'
+`
+ rule := NewLeaksRegularFacebookClientID()
+ textFile, err := text.NewTextFile("deployments/docker-compose.yaml", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 1)
+ assert.Equal(t, engine.Finding{
+ ID: rule.ID,
+ Name: rule.Name,
+ Severity: rule.Severity,
+ CodeSample: `FB_CLIENT_ID: '148695999071979'`,
+ Confidence: rule.Confidence,
+ Description: rule.Description,
+ SourceLocation: engine.Location{
+ Filename: "deployments/docker-compose.yaml",
+ Line: 7,
+ Column: 6,
+ },
+ }, findings[0])
+ })
+ t.Run("Should not return vulnerable code NewLeaksRegularFacebookClientID", func(t *testing.T) {
+ code := `
+version: '3'
+services:
+ backend:
+ image: image/my-backend:latest
+ environment:
+ FB_CLIENT_ID: ${SECRET_KEY}
+`
+ rule := NewLeaksRegularFacebookClientID()
+ textFile, err := text.NewTextFile("deployments/docker-compose.yaml", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 0)
+ })
+}
+
+func TestNewLeaksRegularTwitterClientID(t *testing.T) {
+ t.Run("Should return vulnerable code NewLeaksRegularTwitterClientID", func(t *testing.T) {
+ code := `
+version: '3'
+services:
+ backend:
+ image: image/my-backend:latest
+ environment:
+ TWITTER_CLIENT_ID: '1h6433fsvygnyre5a40'
+`
+ rule := NewLeaksRegularTwitterClientID()
+ textFile, err := text.NewTextFile("deployments/docker-compose.yaml", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 1)
+ assert.Equal(t, engine.Finding{
+ ID: rule.ID,
+ Name: rule.Name,
+ Severity: rule.Severity,
+ CodeSample: `TWITTER_CLIENT_ID: '1h6433fsvygnyre5a40'`,
+ Confidence: rule.Confidence,
+ Description: rule.Description,
+ SourceLocation: engine.Location{
+ Filename: "deployments/docker-compose.yaml",
+ Line: 7,
+ Column: 6,
+ },
+ }, findings[0])
+ })
+ t.Run("Should not return vulnerable code NewLeaksRegularTwitterClientID", func(t *testing.T) {
+ code := `
+version: '3'
+services:
+ backend:
+ image: image/my-backend:latest
+ environment:
+ TWITTER_CLIENT_ID: ${SECRET_KEY}
+`
+ rule := NewLeaksRegularTwitterClientID()
+ textFile, err := text.NewTextFile("deployments/docker-compose.yaml", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 0)
+ })
+}
+
+func TestNewLeaksRegularTwitterSecretKey(t *testing.T) {
+ t.Run("Should return vulnerable code NewLeaksRegularTwitterSecretKey", func(t *testing.T) {
+ code := `
+version: '3'
+services:
+ backend:
+ image: image/my-backend:latest
+ environment:
+ TWITTER_SECRET_KEY: 'ej64cqk9k8px9ae3e47ip89l7if58tqhpxi1r'
+`
+ rule := NewLeaksRegularTwitterSecretKey()
+ textFile, err := text.NewTextFile("deployments/docker-compose.yaml", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 1)
+ assert.Equal(t, engine.Finding{
+ ID: rule.ID,
+ Name: rule.Name,
+ Severity: rule.Severity,
+ CodeSample: `TWITTER_SECRET_KEY: 'ej64cqk9k8px9ae3e47ip89l7if58tqhpxi1r'`,
+ Confidence: rule.Confidence,
+ Description: rule.Description,
+ SourceLocation: engine.Location{
+ Filename: "deployments/docker-compose.yaml",
+ Line: 7,
+ Column: 6,
+ },
+ }, findings[0])
+ })
+ t.Run("Should not return vulnerable code NewLeaksRegularTwitterSecretKey", func(t *testing.T) {
+ code := `
+version: '3'
+services:
+ backend:
+ image: image/my-backend:latest
+ environment:
+ TWITTER_SECRET_KEY: ${SECRET_KEY}
+`
+ rule := NewLeaksRegularTwitterSecretKey()
+ textFile, err := text.NewTextFile("deployments/docker-compose.yaml", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 0)
+ })
+}
+
+func TestNewLeaksRegularGithub(t *testing.T) {
+ t.Run("Should return vulnerable code NewLeaksRegularGithub", func(t *testing.T) {
+ code := `
+version: '3'
+services:
+ backend:
+ image: image/my-backend:latest
+ environment:
+ GITHUB_SECRET_KEY: 'edzvPbU3SYUc7pFc9le20lzIRErTOaxCABQ1'
+`
+ rule := NewLeaksRegularGithub()
+ textFile, err := text.NewTextFile("deployments/docker-compose.yaml", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 1)
+ assert.Equal(t, engine.Finding{
+ ID: rule.ID,
+ Name: rule.Name,
+ Severity: rule.Severity,
+ CodeSample: `GITHUB_SECRET_KEY: 'edzvPbU3SYUc7pFc9le20lzIRErTOaxCABQ1'`,
+ Confidence: rule.Confidence,
+ Description: rule.Description,
+ SourceLocation: engine.Location{
+ Filename: "deployments/docker-compose.yaml",
+ Line: 7,
+ Column: 6,
+ },
+ }, findings[0])
+ })
+ t.Run("Should not return vulnerable code NewLeaksRegularGithub", func(t *testing.T) {
+ code := `
+version: '3'
+services:
+ backend:
+ image: image/my-backend:latest
+ environment:
+ GITHUB_SECRET_KEY: ${SECRET_KEY}
+`
+ rule := NewLeaksRegularGithub()
+ textFile, err := text.NewTextFile("deployments/docker-compose.yaml", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 0)
+ })
+}
+
+func TestNewLeaksRegularLinkedInClientID(t *testing.T) {
+ t.Run("Should return vulnerable code NewLeaksRegularLinkedInClientID", func(t *testing.T) {
+ code := `
+version: '3'
+services:
+ backend:
+ image: image/my-backend:latest
+ environment:
+ LINKEDIN_CLIENT_ID: 'g309xttlaw25'
+`
+ rule := NewLeaksRegularLinkedInClientID()
+ textFile, err := text.NewTextFile("deployments/docker-compose.yaml", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 1)
+ assert.Equal(t, engine.Finding{
+ ID: rule.ID,
+ Name: rule.Name,
+ Severity: rule.Severity,
+ CodeSample: `LINKEDIN_CLIENT_ID: 'g309xttlaw25'`,
+ Confidence: rule.Confidence,
+ Description: rule.Description,
+ SourceLocation: engine.Location{
+ Filename: "deployments/docker-compose.yaml",
+ Line: 7,
+ Column: 6,
+ },
+ }, findings[0])
+ })
+ t.Run("Should not return vulnerable code NewLeaksRegularLinkedInClientID", func(t *testing.T) {
+ code := `
+version: '3'
+services:
+ backend:
+ image: image/my-backend:latest
+ environment:
+ LINKEDIN_CLIENT_ID: ${SECRET_KEY}
+`
+ rule := NewLeaksRegularLinkedInClientID()
+ textFile, err := text.NewTextFile("deployments/docker-compose.yaml", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 0)
+ })
+}
+
+func TestNewLeaksRegularLinkedInSecretKey(t *testing.T) {
+ t.Run("Should return vulnerable code NewLeaksRegularLinkedInSecretKey", func(t *testing.T) {
+ code := `
+version: '3'
+services:
+ backend:
+ image: image/my-backend:latest
+ environment:
+ LINKEDIN_SECRET_KEY: '0d16kcnjyfzmcmjp'
+`
+ rule := NewLeaksRegularLinkedInSecretKey()
+ textFile, err := text.NewTextFile("deployments/docker-compose.yaml", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 1)
+ assert.Equal(t, engine.Finding{
+ ID: rule.ID,
+ Name: rule.Name,
+ Severity: rule.Severity,
+ CodeSample: `LINKEDIN_SECRET_KEY: '0d16kcnjyfzmcmjp'`,
+ Confidence: rule.Confidence,
+ Description: rule.Description,
+ SourceLocation: engine.Location{
+ Filename: "deployments/docker-compose.yaml",
+ Line: 7,
+ Column: 6,
+ },
+ }, findings[0])
+ })
+ t.Run("Should not return vulnerable code NewLeaksRegularLinkedInSecretKey", func(t *testing.T) {
+ code := `
+version: '3'
+services:
+ backend:
+ image: image/my-backend:latest
+ environment:
+ LINKEDIN_SECRET_KEY: ${SECRET_KEY}
+`
+ rule := NewLeaksRegularLinkedInSecretKey()
+ textFile, err := text.NewTextFile("deployments/docker-compose.yaml", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 0)
+ })
+}
+
+func TestNewLeaksRegularSlack(t *testing.T) {
+ t.Run("Should return vulnerable code NewLeaksRegularSlack", func(t *testing.T) {
+ code := `
+version: '3'
+services:
+ backend:
+ image: image/my-backend:latest
+ environment:
+ SLACK_WEBHOOK: 'https://hooksWslackKcom/services/TNeqvYPeO/BncTJ74Hf/NlvFFKKAKPkd6h7FlQCz1Blu'
+`
+ rule := NewLeaksRegularSlack()
+ textFile, err := text.NewTextFile("deployments/docker-compose.yaml", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 1)
+ assert.Equal(t, engine.Finding{
+ ID: rule.ID,
+ Name: rule.Name,
+ Severity: rule.Severity,
+ CodeSample: `SLACK_WEBHOOK: 'https://hooksWslackKcom/services/TNeqvYPeO/BncTJ74Hf/NlvFFKKAKPkd6h7FlQCz1Blu'`,
+ Confidence: rule.Confidence,
+ Description: rule.Description,
+ SourceLocation: engine.Location{
+ Filename: "deployments/docker-compose.yaml",
+ Line: 7,
+ Column: 22,
+ },
+ }, findings[0])
+ })
+ t.Run("Should not return vulnerable code NewLeaksRegularSlack", func(t *testing.T) {
+ code := `
+version: '3'
+services:
+ backend:
+ image: image/my-backend:latest
+ environment:
+ SLACK_WEBHOOK: ${SECRET_KEY}
+`
+ rule := NewLeaksRegularSlack()
+ textFile, err := text.NewTextFile("deployments/docker-compose.yaml", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 0)
+ })
+}
+
+func TestNewLeaksRegularAsymmetricPrivateKey(t *testing.T) {
+ t.Run("Should return vulnerable code NewLeaksRegularAsymmetricPrivateKey", func(t *testing.T) {
+ code := `
+version: '3'
+services:
+ backend:
+ image: image/my-backend:latest
+ environment:
+ SSH_PRIVATE_KEY: '-----BEGIN PRIVATE KEY-----MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDBj08sp5++4anGcmQxJjAkBgNVBAoTHVByb2dyZXNzIFNvZnR3YXJlIENvcnBvcmF0aW9uMSAwHgYDVQQDDBcqLmF3cy10ZXN0LnByb2dyZXNzLmNvbTCCASIwDQYJKoZIhvcNAQEBBQAD...bml6YXRpb252YWxzaGEyZzIuY3JsMIGgBggrBgEFBQcBAQSBkzCBkDBNBggrBgEFBQcwAoZBaHR0cDovL3NlY3VyZS5nbG9iYWxzaWduLmNvbS9jYWNlcnQvZ3Nvcmdhz3P668YfhUbKdRF6S42Cg6zn-----END PRIVATE KEY-----'
+`
+ rule := NewLeaksRegularAsymmetricPrivateKey()
+ textFile, err := text.NewTextFile("deployments/docker-compose.yaml", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 1)
+ assert.Equal(t, engine.Finding{
+ ID: rule.ID,
+ Name: rule.Name,
+ Severity: rule.Severity,
+ CodeSample: `SSH_PRIVATE_KEY: '-----BEGIN PRIVATE KEY-----MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDBj08sp5++4anGcmQxJjAkBgNVBAoTHVByb2dyZXNzIFNvZnR3YXJlIENvcnBvcmF0aW9uMSAwHgYDVQQDDBcqLmF3cy10ZXN0LnByb2dyZXNzLmNvbTCCASIwDQYJKoZIhvcNAQEBBQAD...bml6YXRpb252YWxzaGEyZzIuY3JsMIGgBggrBgEFBQcBAQSBkzCBkDBNBggrBgEFBQcwAoZBaHR0cDovL3NlY3VyZS5nbG9iYWxzaWduLmNvbS9jYWNlcnQvZ3Nvcmdhz3P668YfhUbKdRF6S42Cg6zn-----END PRIVATE KEY-----'`,
+ Confidence: rule.Confidence,
+ Description: rule.Description,
+ SourceLocation: engine.Location{
+ Filename: "deployments/docker-compose.yaml",
+ Line: 7,
+ Column: 24,
+ },
+ }, findings[0])
+ })
+ t.Run("Should not return vulnerable code NewLeaksRegularAsymmetricPrivateKey", func(t *testing.T) {
+ code := `
+version: '3'
+services:
+ backend:
+ image: image/my-backend:latest
+ environment:
+ SSH_PRIVATE_KEY: ${SECRET_KEY}
+`
+ rule := NewLeaksRegularAsymmetricPrivateKey()
+ textFile, err := text.NewTextFile("deployments/docker-compose.yaml", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 0)
+ })
+}
+
+func TestNewLeaksRegularGoogleAPIKey(t *testing.T) {
+ t.Run("Should return vulnerable code NewLeaksRegularGoogleAPIKey", func(t *testing.T) {
+ code := `
+version: '3'
+services:
+ backend:
+ image: image/my-backend:latest
+ environment:
+ GCP_API_KEY: 'AIzaMPZHYiu1RdzE1nG2SaVyOoz244TuacQIR6m'
+`
+ rule := NewLeaksRegularGoogleAPIKey()
+ textFile, err := text.NewTextFile("deployments/docker-compose.yaml", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 1)
+ assert.Equal(t, engine.Finding{
+ ID: rule.ID,
+ Name: rule.Name,
+ Severity: rule.Severity,
+ CodeSample: `GCP_API_KEY: 'AIzaMPZHYiu1RdzE1nG2SaVyOoz244TuacQIR6m'`,
+ Confidence: rule.Confidence,
+ Description: rule.Description,
+ SourceLocation: engine.Location{
+ Filename: "deployments/docker-compose.yaml",
+ Line: 7,
+ Column: 20,
+ },
+ }, findings[0])
+ })
+ t.Run("Should not return vulnerable code NewLeaksRegularGoogleAPIKey", func(t *testing.T) {
+ code := `
+version: '3'
+services:
+ backend:
+ image: image/my-backend:latest
+ environment:
+ GCP_API_KEY: ${SECRET_KEY}
+`
+ rule := NewLeaksRegularGoogleAPIKey()
+ textFile, err := text.NewTextFile("deployments/docker-compose.yaml", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 0)
+ })
+}
+
+func TestNewLeaksRegularGoogleGCPServiceAccount(t *testing.T) {
+ t.Run("Should return vulnerable code NewLeaksRegularGoogleGCPServiceAccount", func(t *testing.T) {
+ code := `
+version: '3'
+services:
+ backend:
+ image: image/my-backend:latest
+ environment:
+ GCP_SERVICE_ACCOUNT: '18256698220617903267772185514630273595-oy8_uzouz8tyy46y84ckrwei9_6rq_pb.apps.googleusercontent.com'
+`
+ rule := NewLeaksRegularGoogleGCPServiceAccount()
+ textFile, err := text.NewTextFile("deployments/docker-compose.yaml", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 1)
+ assert.Equal(t, engine.Finding{
+ ID: rule.ID,
+ Name: rule.Name,
+ Severity: rule.Severity,
+ CodeSample: `GCP_SERVICE_ACCOUNT: '18256698220617903267772185514630273595-oy8_uzouz8tyy46y84ckrwei9_6rq_pb.apps.googleusercontent.com'`,
+ Confidence: rule.Confidence,
+ Description: rule.Description,
+ SourceLocation: engine.Location{
+ Filename: "deployments/docker-compose.yaml",
+ Line: 7,
+ Column: 6,
+ },
+ }, findings[0])
+ })
+ t.Run("Should not return vulnerable code NewLeaksRegularGoogleGCPServiceAccount", func(t *testing.T) {
+ code := `
+version: '3'
+services:
+ backend:
+ image: image/my-backend:latest
+ environment:
+ GCP_SERVICE_ACCOUNT: ${SECRET_KEY}
+`
+ rule := NewLeaksRegularGoogleGCPServiceAccount()
+ textFile, err := text.NewTextFile("deployments/docker-compose.yaml", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 0)
+ })
+}
+
+func TestNewLeaksRegularHerokuAPIKey(t *testing.T) {
+ t.Run("Should return vulnerable code NewLeaksRegularHerokuAPIKey", func(t *testing.T) {
+ code := `
+version: '3'
+services:
+ backend:
+ image: image/my-backend:latest
+ environment:
+ HEROKU_API_KEY: '3623f8e9-2d05-c9bb-2209082d6b5c'
+`
+ rule := NewLeaksRegularHerokuAPIKey()
+ textFile, err := text.NewTextFile("deployments/docker-compose.yaml", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 1)
+ assert.Equal(t, engine.Finding{
+ ID: rule.ID,
+ Name: rule.Name,
+ Severity: rule.Severity,
+ CodeSample: `HEROKU_API_KEY: '3623f8e9-2d05-c9bb-2209082d6b5c'`,
+ Confidence: rule.Confidence,
+ Description: rule.Description,
+ SourceLocation: engine.Location{
+ Filename: "deployments/docker-compose.yaml",
+ Line: 7,
+ Column: 6,
+ },
+ }, findings[0])
+ })
+ t.Run("Should not return vulnerable code NewLeaksRegularHerokuAPIKey", func(t *testing.T) {
+ code := `
+version: '3'
+services:
+ backend:
+ image: image/my-backend:latest
+ environment:
+ HEROKU_API_KEY: ${SECRET_KEY}
+`
+ rule := NewLeaksRegularHerokuAPIKey()
+ textFile, err := text.NewTextFile("deployments/docker-compose.yaml", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 0)
+ })
+}
+
+func TestNewLeaksRegularMailChimpAPIKey(t *testing.T) {
+ t.Run("Should return vulnerable code NewLeaksRegularMailChimpAPIKey", func(t *testing.T) {
+ code := `
+version: '3'
+services:
+ backend:
+ image: image/my-backend:latest
+ environment:
+ MAILCHIMP_API_KEY: 'f7e9c13c10d0b19c3bb003a9f635d488-us72'
+`
+ rule := NewLeaksRegularMailChimpAPIKey()
+ textFile, err := text.NewTextFile("deployments/docker-compose.yaml", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 1)
+ assert.Equal(t, engine.Finding{
+ ID: rule.ID,
+ Name: rule.Name,
+ Severity: rule.Severity,
+ CodeSample: `MAILCHIMP_API_KEY: 'f7e9c13c10d0b19c3bb003a9f635d488-us72'`,
+ Confidence: rule.Confidence,
+ Description: rule.Description,
+ SourceLocation: engine.Location{
+ Filename: "deployments/docker-compose.yaml",
+ Line: 7,
+ Column: 6,
+ },
+ }, findings[0])
+ })
+ t.Run("Should not return vulnerable code NewLeaksRegularMailChimpAPIKey", func(t *testing.T) {
+ code := `
+version: '3'
+services:
+ backend:
+ image: image/my-backend:latest
+ environment:
+ MAILCHIMP_API_KEY: ${SECRET_KEY}
+`
+ rule := NewLeaksRegularMailChimpAPIKey()
+ textFile, err := text.NewTextFile("deployments/docker-compose.yaml", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 0)
+ })
+}
+
+func TestNewLeaksRegularMailgunAPIKey(t *testing.T) {
+ t.Run("Should return vulnerable code NewLeaksRegularMailgunAPIKey", func(t *testing.T) {
+ code := `
+version: '3'
+services:
+ backend:
+ image: image/my-backend:latest
+ environment:
+ MAILGUN_API_KEY: 'key-xke9nbc2i5po5cjw3ngyxiz450zxpapu'
+`
+ rule := NewLeaksRegularMailgunAPIKey()
+ textFile, err := text.NewTextFile("deployments/docker-compose.yaml", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 1)
+ assert.Equal(t, engine.Finding{
+ ID: rule.ID,
+ Name: rule.Name,
+ Severity: rule.Severity,
+ CodeSample: `MAILGUN_API_KEY: 'key-xke9nbc2i5po5cjw3ngyxiz450zxpapu'`,
+ Confidence: rule.Confidence,
+ Description: rule.Description,
+ SourceLocation: engine.Location{
+ Filename: "deployments/docker-compose.yaml",
+ Line: 7,
+ Column: 6,
+ },
+ }, findings[0])
+ })
+ t.Run("Should not return vulnerable code NewLeaksRegularMailgunAPIKey", func(t *testing.T) {
+ code := `
+version: '3'
+services:
+ backend:
+ image: image/my-backend:latest
+ environment:
+ MAILGUN_API_KEY: ${SECRET_KEY}
+`
+ rule := NewLeaksRegularMailgunAPIKey()
+ textFile, err := text.NewTextFile("deployments/docker-compose.yaml", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 0)
+ })
+}
+
+func TestNewLeaksRegularPayPalBraintreeAccessToken(t *testing.T) {
+ t.Run("Should return vulnerable code NewLeaksRegularPayPalBraintreeAccessToken", func(t *testing.T) {
+ code := `
+version: '3'
+services:
+ backend:
+ image: image/my-backend:latest
+ environment:
+ PAY_PAL_ACCESS_TOKEN: 'access_token$production$mk0sech2v7qqsol3$db651af2221c22b4ca2f0f583798135e'
+`
+ rule := NewLeaksRegularPayPalBraintreeAccessToken()
+ textFile, err := text.NewTextFile("deployments/docker-compose.yaml", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 1)
+ assert.Equal(t, engine.Finding{
+ ID: rule.ID,
+ Name: rule.Name,
+ Severity: rule.Severity,
+ CodeSample: `PAY_PAL_ACCESS_TOKEN: 'access_token$production$mk0sech2v7qqsol3$db651af2221c22b4ca2f0f583798135e'`,
+ Confidence: rule.Confidence,
+ Description: rule.Description,
+ SourceLocation: engine.Location{
+ Filename: "deployments/docker-compose.yaml",
+ Line: 7,
+ Column: 29,
+ },
+ }, findings[0])
+ })
+ t.Run("Should not return vulnerable code NewLeaksRegularPayPalBraintreeAccessToken", func(t *testing.T) {
+ code := `
+version: '3'
+services:
+ backend:
+ image: image/my-backend:latest
+ environment:
+ PAY_PAL_ACCESS_TOKEN: ${SECRET_KEY}
+`
+ rule := NewLeaksRegularPayPalBraintreeAccessToken()
+ textFile, err := text.NewTextFile("deployments/docker-compose.yaml", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 0)
+ })
+}
+
+func TestNewLeaksRegularPicaticAPIKey(t *testing.T) {
+ t.Run("Should return vulnerable code NewLeaksRegularPicaticAPIKey", func(t *testing.T) {
+ code := `
+version: '3'
+services:
+ backend:
+ image: image/my-backend:latest
+ environment:
+ PICATIC_API_KEY: 'sk_live_voy1p9k7r9g9j8ezmif488nk2p8310nl'
+`
+ rule := NewLeaksRegularPicaticAPIKey()
+ textFile, err := text.NewTextFile("deployments/docker-compose.yaml", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 1)
+ assert.Equal(t, engine.Finding{
+ ID: rule.ID,
+ Name: rule.Name,
+ Severity: rule.Severity,
+ CodeSample: `PICATIC_API_KEY: 'sk_live_voy1p9k7r9g9j8ezmif488nk2p8310nl'`,
+ Confidence: rule.Confidence,
+ Description: rule.Description,
+ SourceLocation: engine.Location{
+ Filename: "deployments/docker-compose.yaml",
+ Line: 7,
+ Column: 24,
+ },
+ }, findings[0])
+ })
+ t.Run("Should not return vulnerable code NewLeaksRegularPicaticAPIKey", func(t *testing.T) {
+ code := `
+version: '3'
+services:
+ backend:
+ image: image/my-backend:latest
+ environment:
+ PICATIC_API_KEY: ${SECRET_KEY}
+`
+ rule := NewLeaksRegularPicaticAPIKey()
+ textFile, err := text.NewTextFile("deployments/docker-compose.yaml", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 0)
+ })
+}
+
+func TestNewLeaksRegularSendGridAPIKey(t *testing.T) {
+ t.Run("Should return vulnerable code NewLeaksRegularSendGridAPIKey", func(t *testing.T) {
+ code := `
+version: '3'
+services:
+ backend:
+ image: image/my-backend:latest
+ environment:
+ SEND_GRID_API_KEY: 'SG.44b7kq3FurdH0bSHBGjPSWhE8vJ.1evu4Un0TXFIb1_6zW4YOdjTMeE'
+`
+ rule := NewLeaksRegularSendGridAPIKey()
+ textFile, err := text.NewTextFile("deployments/docker-compose.yaml", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 1)
+ assert.Equal(t, engine.Finding{
+ ID: rule.ID,
+ Name: rule.Name,
+ Severity: rule.Severity,
+ CodeSample: `SEND_GRID_API_KEY: 'SG.44b7kq3FurdH0bSHBGjPSWhE8vJ.1evu4Un0TXFIb1_6zW4YOdjTMeE'`,
+ Confidence: rule.Confidence,
+ Description: rule.Description,
+ SourceLocation: engine.Location{
+ Filename: "deployments/docker-compose.yaml",
+ Line: 7,
+ Column: 26,
+ },
+ }, findings[0])
+ })
+ t.Run("Should not return vulnerable code NewLeaksRegularSendGridAPIKey", func(t *testing.T) {
+ code := `
+version: '3'
+services:
+ backend:
+ image: image/my-backend:latest
+ environment:
+ SEND_GRID_API_KEY: ${SECRET_KEY}
+`
+ rule := NewLeaksRegularSendGridAPIKey()
+ textFile, err := text.NewTextFile("deployments/docker-compose.yaml", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 0)
+ })
+}
+
+func TestNewLeaksRegularStripeAPIKey(t *testing.T) {
+ t.Run("Should return vulnerable code NewLeaksRegularStripeAPIKey", func(t *testing.T) {
+ code := `
+version: '3'
+services:
+ backend:
+ image: image/my-backend:latest
+ environment:
+ STRIPE_API_KEY: 'rk_live_8qSZpoI9t0BOGkOLVzvesc6K'
+`
+ rule := NewLeaksRegularStripeAPIKey()
+ textFile, err := text.NewTextFile("deployments/docker-compose.yaml", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 1)
+ assert.Equal(t, engine.Finding{
+ ID: rule.ID,
+ Name: rule.Name,
+ Severity: rule.Severity,
+ CodeSample: `STRIPE_API_KEY: 'rk_live_8qSZpoI9t0BOGkOLVzvesc6K'`,
+ Confidence: rule.Confidence,
+ Description: rule.Description,
+ SourceLocation: engine.Location{
+ Filename: "deployments/docker-compose.yaml",
+ Line: 7,
+ Column: 6,
+ },
+ }, findings[0])
+ })
+ t.Run("Should not return vulnerable code NewLeaksRegularStripeAPIKey", func(t *testing.T) {
+ code := `
+version: '3'
+services:
+ backend:
+ image: image/my-backend:latest
+ environment:
+ STRIPE_API_KEY: ${SECRET_KEY}
+`
+ rule := NewLeaksRegularStripeAPIKey()
+ textFile, err := text.NewTextFile("deployments/docker-compose.yaml", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 0)
+ })
+}
+
+func TestNewLeaksRegularSquareAccessToken(t *testing.T) {
+ t.Run("Should return vulnerable code NewLeaksRegularSquareAccessToken", func(t *testing.T) {
+ code := `
+version: '3'
+services:
+ backend:
+ image: image/my-backend:latest
+ environment:
+ SQUARE_ACCESS_TOKEN: 'sq0atp-clYRBSht6oefa7w_2R56ra'
+`
+ rule := NewLeaksRegularSquareAccessToken()
+ textFile, err := text.NewTextFile("deployments/docker-compose.yaml", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 1)
+ assert.Equal(t, engine.Finding{
+ ID: rule.ID,
+ Name: rule.Name,
+ Severity: rule.Severity,
+ CodeSample: `SQUARE_ACCESS_TOKEN: 'sq0atp-clYRBSht6oefa7w_2R56ra'`,
+ Confidence: rule.Confidence,
+ Description: rule.Description,
+ SourceLocation: engine.Location{
+ Filename: "deployments/docker-compose.yaml",
+ Line: 7,
+ Column: 28,
+ },
+ }, findings[0])
+ })
+ t.Run("Should not return vulnerable code NewLeaksRegularSquareAccessToken", func(t *testing.T) {
+ code := `
+version: '3'
+services:
+ backend:
+ image: image/my-backend:latest
+ environment:
+ SQUARE_ACCESS_TOKEN: ${SECRET_KEY}
+`
+ rule := NewLeaksRegularSquareAccessToken()
+ textFile, err := text.NewTextFile("deployments/docker-compose.yaml", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 0)
+ })
+}
+
+func TestNewLeaksRegularSquareOAuthSecret(t *testing.T) {
+ t.Run("Should return vulnerable code NewLeaksRegularSquareOAuthSecret", func(t *testing.T) {
+ code := `
+version: '3'
+services:
+ backend:
+ image: image/my-backend:latest
+ environment:
+ SQUARE_SECRET: 'sq0csp-LsEBYQNja]OgT3hRxjJV5cWX^XjpT12n3QkRY_vep2z'
+`
+ rule := NewLeaksRegularSquareOAuthSecret()
+ textFile, err := text.NewTextFile("deployments/docker-compose.yaml", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 1)
+ assert.Equal(t, engine.Finding{
+ ID: rule.ID,
+ Name: rule.Name,
+ Severity: rule.Severity,
+ CodeSample: `SQUARE_SECRET: 'sq0csp-LsEBYQNja]OgT3hRxjJV5cWX^XjpT12n3QkRY_vep2z'`,
+ Confidence: rule.Confidence,
+ Description: rule.Description,
+ SourceLocation: engine.Location{
+ Filename: "deployments/docker-compose.yaml",
+ Line: 7,
+ Column: 22,
+ },
+ }, findings[0])
+ })
+ t.Run("Should not return vulnerable code NewLeaksRegularSquareOAuthSecret", func(t *testing.T) {
+ code := `
+version: '3'
+services:
+ backend:
+ image: image/my-backend:latest
+ environment:
+ SQUARE_SECRET: ${SECRET_KEY}
+`
+ rule := NewLeaksRegularSquareOAuthSecret()
+ textFile, err := text.NewTextFile("deployments/docker-compose.yaml", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 0)
+ })
+}
+
+func TestNewLeaksRegularTwilioAPIKey(t *testing.T) {
+ t.Run("Should return vulnerable code NewLeaksRegularTwilioAPIKey", func(t *testing.T) {
+ code := `
+version: '3'
+services:
+ backend:
+ image: image/my-backend:latest
+ environment:
+ TWILIO_API_KEY: '^SK9ae6bd84ccd091eb6bfad8e2a474af95'
+`
+ rule := NewLeaksRegularTwilioAPIKey()
+ textFile, err := text.NewTextFile("deployments/docker-compose.yaml", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 1)
+ assert.Equal(t, engine.Finding{
+ ID: rule.ID,
+ Name: rule.Name,
+ Severity: rule.Severity,
+ CodeSample: `TWILIO_API_KEY: '^SK9ae6bd84ccd091eb6bfad8e2a474af95'`,
+ Confidence: rule.Confidence,
+ Description: rule.Description,
+ SourceLocation: engine.Location{
+ Filename: "deployments/docker-compose.yaml",
+ Line: 7,
+ Column: 6,
+ },
+ }, findings[0])
+ })
+ t.Run("Should not return vulnerable code NewLeaksRegularTwilioAPIKey", func(t *testing.T) {
+ code := `
+version: '3'
+services:
+ backend:
+ image: image/my-backend:latest
+ environment:
+ TWILIO_API_KEY: ${SECRET_KEY}
+`
+ rule := NewLeaksRegularTwilioAPIKey()
+ textFile, err := text.NewTextFile("deployments/docker-compose.yaml", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 0)
+ })
+}
+
+func TestNewLeaksRegularHardCodedCredentialGeneric(t *testing.T) {
+ t.Run("Should return vulnerable code NewLeaksRegularHardCodedCredentialGeneric", func(t *testing.T) {
+ code := `
+version: '3'
+services:
+ backend:
+ image: image/my-backend:latest
+ environment:
+ POSTGRES_DBPASSWD: 'Ch@ng3m3'
+`
+ rule := NewLeaksRegularHardCodedCredentialGeneric()
+ textFile, err := text.NewTextFile("deployments/docker-compose.yaml", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 1)
+ assert.Equal(t, engine.Finding{
+ ID: rule.ID,
+ Name: rule.Name,
+ Severity: rule.Severity,
+ CodeSample: `POSTGRES_DBPASSWD: 'Ch@ng3m3'`,
+ Confidence: rule.Confidence,
+ Description: rule.Description,
+ SourceLocation: engine.Location{
+ Filename: "deployments/docker-compose.yaml",
+ Line: 7,
+ Column: 15,
+ },
+ }, findings[0])
+ })
+ t.Run("Should not return vulnerable code NewLeaksRegularHardCodedCredentialGeneric", func(t *testing.T) {
+ code := `
+version: '3'
+services:
+ backend:
+ image: image/my-backend:latest
+ environment:
+ POSTGRES_DBPASSWD: ${SECRET_KEY}
+`
+ rule := NewLeaksRegularHardCodedCredentialGeneric()
+ textFile, err := text.NewTextFile("deployments/docker-compose.yaml", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 0)
+ })
+}
+
+func TestNewLeaksRegularHardCodedPassword(t *testing.T) {
+ t.Run("Should return vulnerable code NewLeaksRegularHardCodedPassword", func(t *testing.T) {
+ code := `
+package main
+
+import (
+ "fmt"
+ "gorm.io/gorm"
+ "gorm.io/driver/postgres"
+)
+
+func main() {
+ DB_USER="gorm"
+ DB_PASSWORD="gorm"
+ DB_NAME="gorm"
+ DB_PORT="9920"
+ dsn := fmt.Sprintf("user=%s password=%s dbname=%s port=%s sslmode=disable TimeZone=Asia/Shanghai", DB_USER, DB_PASSWORD, DB_NAME, DB_PORT)
+ db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
+ if err != nil {
+ panic(err)
+ }
+ print(db)
+}
+`
+ rule := NewLeaksRegularHardCodedPassword()
+ textFile, err := text.NewTextFile("main.go", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 1)
+ assert.Equal(t, engine.Finding{
+ ID: rule.ID,
+ Name: rule.Name,
+ Severity: rule.Severity,
+ CodeSample: `DB_PASSWORD="gorm"`,
+ Confidence: rule.Confidence,
+ Description: rule.Description,
+ SourceLocation: engine.Location{
+ Filename: "main.go",
+ Line: 12,
+ Column: 4,
+ },
+ }, findings[0])
+ })
+ t.Run("Should not return vulnerable code NewLeaksRegularHardCodedPassword", func(t *testing.T) {
+ code := `
+package main
+
+import (
+ "os"
+ "fmt"
+ "gorm.io/gorm"
+ "gorm.io/driver/postgres"
+)
+
+func main() {
+ DB_USER="gorm"
+ DB_PASSWORD=os.Getenv("DB_PASSWORD")
+ DB_NAME="gorm"
+ DB_PORT="9920"
+ dsn := fmt.Sprintf("user=%s password=%s dbname=%s port=%s sslmode=disable TimeZone=Asia/Shanghai", DB_USER, DB_PASSWORD, DB_NAME, DB_PORT)
+ db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
+ if err != nil {
+ panic(err)
+ }
+ print(db)
+}
+`
+ rule := NewLeaksRegularHardCodedPassword()
+ textFile, err := text.NewTextFile("main.go", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 0)
+ })
+}
+
+func TestNewLeaksRegularPasswordExposedInHardcodedURL(t *testing.T) {
+ t.Run("Should return vulnerable code NewLeaksRegularPasswordExposedInHardcodedURL", func(t *testing.T) {
+ code := `
+package main
+
+import (
+ "gorm.io/gorm"
+ "gorm.io/driver/postgres"
+)
+
+func main() {
+ dsn := "postgresql://gorm:gorm@127.0.0.1:5432/gorm?sslmode=disable"
+ db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
+ if err != nil {
+ panic(err)
+ }
+ print(db)
+}
+`
+ rule := NewLeaksRegularPasswordExposedInHardcodedURL()
+ textFile, err := text.NewTextFile("main.go", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 1)
+ assert.Equal(t, engine.Finding{
+ ID: rule.ID,
+ Name: rule.Name,
+ Severity: rule.Severity,
+ CodeSample: `dsn := "postgresql://gorm:gorm@127.0.0.1:5432/gorm?sslmode=disable"`,
+ Confidence: rule.Confidence,
+ Description: rule.Description,
+ SourceLocation: engine.Location{
+ Filename: "main.go",
+ Line: 10,
+ Column: 9,
+ },
+ }, findings[0])
+ })
+ t.Run("Should not return vulnerable code NewLeaksRegularPasswordExposedInHardcodedURL", func(t *testing.T) {
+ code := `
+package main
+
+import (
+ "os"
+ "gorm.io/gorm"
+ "gorm.io/driver/postgres"
+)
+
+func main() {
+ dsn := os.Getenv("DB_QUERY_STRING")
+ db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
+ if err != nil {
+ panic(err)
+ }
+ print(db)
+}
+`
+ rule := NewLeaksRegularPasswordExposedInHardcodedURL()
+ textFile, err := text.NewTextFile("main.go", []byte(code))
+ assert.NoError(t, err)
+ findings := engine.Run(parseTextUnitsToUnits([]text.TextUnit{{Files: []text.TextFile{textFile}}}), []engine.Rule{rule})
+ assert.Len(t, findings, 0)
+ })
+}
+
+func TestNewLeaksRegularWPConfig(t *testing.T) {
+ t.Run("Should return vulnerable code NewLeaksRegularWPConfig", func(t *testing.T) {
+ code := ` ./horusec-cli/deployments/version-cli-latest.txt
- aws s3 cp ./horusec-cli/deployments/version-cli-latest.txt s3://horusec-cli/version-cli-latest.txt
- aws s3 cp "./horusec-cli/bin/horusec/$ACTUAL_RELEASE_FORMATTED" "s3://horusec-cli/latest" --recursive
+ aws s3 cp ./horusec-cli/deployments/version-cli-latest.txt s3://horusec.io/bin/version-cli-latest.txt
+ aws s3 cp "./horusec-cli/bin/horusec/$ACTUAL_RELEASE_FORMATTED" "s3://horusec.io/bin/latest" --recursive
+ docker build -t "horuszup/horusec-cli:latest" -f horusec-cli/deployments/Dockerfile .
+ docker push "horuszup/horusec-cli:latest"
fi
echo "$ACTUAL_RELEASE_FORMATTED" >> ./horusec-cli/deployments/all-version-cli.txt
- aws s3 cp ./horusec-cli/deployments/all-version-cli.txt s3://horusec-cli/all-version-cli.txt
+ aws s3 cp ./horusec-cli/deployments/all-version-cli.txt s3://horusec.io/bin/all-version-cli.txt
}
resetAlphaRcToMaster () {
diff --git a/horusec-cli/deployments/version-cli-latest.txt b/horusec-cli/deployments/version-cli-latest.txt
index bb2fa5746..b85ad4e79 100644
--- a/horusec-cli/deployments/version-cli-latest.txt
+++ b/horusec-cli/deployments/version-cli-latest.txt
@@ -1 +1 @@
-v1-5-0
+v1-6-0
diff --git a/horusec-cli/internal/controllers/analyser/analyser.go b/horusec-cli/internal/controllers/analyser/analyser.go
index 1dcf0f3ba..e0ab81b64 100644
--- a/horusec-cli/internal/controllers/analyser/analyser.go
+++ b/horusec-cli/internal/controllers/analyser/analyser.go
@@ -24,6 +24,9 @@ import (
"strings"
"time"
+ "github.com/ZupIT/horusec/horusec-cli/internal/services/formatters/c/flawfinder"
+ "github.com/ZupIT/horusec/horusec-cli/internal/services/formatters/php/phpcs"
+
"github.com/ZupIT/horusec/horusec-cli/internal/services/formatters/csharp/horuseccsharp"
"github.com/ZupIT/horusec/horusec-cli/internal/services/formatters/javascript/horusecnodejs"
"github.com/ZupIT/horusec/horusec-cli/internal/services/formatters/yaml/horuseckubernetes"
@@ -189,6 +192,8 @@ func (a *Analyser) mapDetectVulnerabilityByLanguage() map[languages.Language]fun
languages.HCL: a.detectVulnerabilityHCL,
languages.Generic: a.detectVulnerabilityGeneric,
languages.Yaml: a.detectVulnerabilityYaml,
+ languages.C: a.detectVulnerabilityC,
+ languages.PHP: a.detectVulnerabilityPHP,
}
}
@@ -253,6 +258,16 @@ func (a *Analyser) detectVulnerabilityYaml(projectSubPath string) {
go horuseckubernetes.NewFormatter(a.formatterService).StartAnalysis(projectSubPath)
}
+func (a *Analyser) detectVulnerabilityC(projectSubPath string) {
+ a.monitor.AddProcess(1)
+ go flawfinder.NewFormatter(a.formatterService).StartAnalysis(projectSubPath)
+}
+
+func (a *Analyser) detectVulnerabilityPHP(projectSubPath string) {
+ a.monitor.AddProcess(1)
+ go phpcs.NewFormatter(a.formatterService).StartAnalysis(projectSubPath)
+}
+
func (a *Analyser) detectVulnerabilityGeneric(projectSubPath string) {
a.monitor.AddProcess(1)
go semgrep.NewFormatter(a.formatterService).StartAnalysis(projectSubPath)
diff --git a/horusec-cli/internal/controllers/language_detect/language_detect.go b/horusec-cli/internal/controllers/language_detect/language_detect.go
index 0f8242fc9..eab38d45f 100644
--- a/horusec-cli/internal/controllers/language_detect/language_detect.go
+++ b/horusec-cli/internal/controllers/language_detect/language_detect.go
@@ -205,18 +205,32 @@ func (ld *LanguageDetect) isSupportedLanguage(langName string) bool {
func (ld *LanguageDetect) appendLanguagesFound(existingLanguages, languagesFound []string) []string {
for _, lang := range languagesFound {
- if ld.isTypescriptOrJavascriptLang(lang) {
- existingLanguages = append(existingLanguages, languages.Javascript.ToString())
- } else {
- existingLanguages = append(existingLanguages, lang)
- }
+ existingLanguages = ld.updateExistingLanguages(lang, existingLanguages)
}
+
return ld.uniqueLanguages(existingLanguages)
}
+func (ld *LanguageDetect) updateExistingLanguages(lang string, existingLanguages []string) []string {
+ if ld.isTypescriptOrJavascriptLang(lang) {
+ return append(existingLanguages, languages.Javascript.ToString())
+ }
+
+ if ld.isCPlusPLusOrCLang(lang) {
+ return append(existingLanguages, languages.C.ToString())
+ }
+
+ return append(existingLanguages, lang)
+}
+
func (ld *LanguageDetect) isTypescriptOrJavascriptLang(lang string) bool {
return strings.EqualFold(lang, languages.Javascript.ToString()) ||
strings.EqualFold(lang, languages.TypeScript.ToString()) ||
strings.EqualFold(lang, "TSX") ||
strings.EqualFold(lang, "JSX")
}
+
+func (ld *LanguageDetect) isCPlusPLusOrCLang(lang string) bool {
+ return strings.EqualFold(lang, "C++") ||
+ strings.EqualFold(lang, "C")
+}
diff --git a/horusec-cli/internal/controllers/printresults/print_results.go b/horusec-cli/internal/controllers/printresults/print_results.go
index 0490fc736..75b75bfa8 100644
--- a/horusec-cli/internal/controllers/printresults/print_results.go
+++ b/horusec-cli/internal/controllers/printresults/print_results.go
@@ -238,7 +238,7 @@ func (pr *PrintResults) printTextOutputVulnerabilityData(vulnerability *horusecE
fmt.Println(fmt.Sprintf("Column: %s", vulnerability.Column))
fmt.Println(fmt.Sprintf("SecurityTool: %s", vulnerability.SecurityTool))
fmt.Println(fmt.Sprintf("Confidence: %s", vulnerability.Confidence))
- fmt.Println(fmt.Sprintf("File: %s", vulnerability.File))
+ fmt.Println(fmt.Sprintf("File: %s/%s", pr.configs.GetProjectPath(), vulnerability.File))
fmt.Println(fmt.Sprintf("Code: %s", vulnerability.Code))
fmt.Println(fmt.Sprintf("Details: %s", vulnerability.Details))
fmt.Println(fmt.Sprintf("Type: %s", vulnerability.Type))
diff --git a/horusec-cli/internal/services/formatters/c/flawfinder/config.go b/horusec-cli/internal/services/formatters/c/flawfinder/config.go
new file mode 100644
index 000000000..62abbbd72
--- /dev/null
+++ b/horusec-cli/internal/services/formatters/c/flawfinder/config.go
@@ -0,0 +1,26 @@
+// Copyright 2020 ZUP IT SERVICOS EM TECNOLOGIA E INOVACAO SA
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package flawfinder
+
+const (
+ ImageName = "horuszup/horusec-flawfinder"
+ ImageTag = "v1.0.0"
+ // nolint
+ ImageCmd = `
+ flawfinder --columns --singleline --dataonly --context --csv . > /tmp/result-ANALYSISID.json
+ cat /tmp/result-ANALYSISID.json
+ chmod -R 777 .
+ `
+)
diff --git a/horusec-cli/internal/services/formatters/c/flawfinder/formatter.go b/horusec-cli/internal/services/formatters/c/flawfinder/formatter.go
new file mode 100644
index 000000000..98ce09f1a
--- /dev/null
+++ b/horusec-cli/internal/services/formatters/c/flawfinder/formatter.go
@@ -0,0 +1,131 @@
+// Copyright 2020 ZUP IT SERVICOS EM TECNOLOGIA E INOVACAO SA
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package flawfinder
+
+import (
+ "fmt"
+ "github.com/ZupIT/horusec/development-kit/pkg/entities/analyser/c"
+ "github.com/ZupIT/horusec/development-kit/pkg/entities/horusec"
+ "github.com/ZupIT/horusec/development-kit/pkg/enums/languages"
+ "github.com/ZupIT/horusec/development-kit/pkg/enums/tools"
+ fileUtil "github.com/ZupIT/horusec/development-kit/pkg/utils/file"
+ "github.com/ZupIT/horusec/development-kit/pkg/utils/logger"
+ vulnhash "github.com/ZupIT/horusec/development-kit/pkg/utils/vuln_hash"
+ dockerEntities "github.com/ZupIT/horusec/horusec-cli/internal/entities/docker"
+ "github.com/ZupIT/horusec/horusec-cli/internal/helpers/messages"
+ "github.com/ZupIT/horusec/horusec-cli/internal/services/formatters"
+ "github.com/gocarina/gocsv"
+)
+
+type Formatter struct {
+ formatters.IService
+}
+
+func NewFormatter(service formatters.IService) formatters.IFormatter {
+ return &Formatter{
+ service,
+ }
+}
+
+func (f *Formatter) StartAnalysis(projectSubPath string) {
+ if f.ToolIsToIgnore(tools.Flawfinder) {
+ logger.LogDebugWithLevel(messages.MsgDebugToolIgnored+tools.Flawfinder.ToString(), logger.DebugLevel)
+ return
+ }
+
+ err := f.startFlawFinder(projectSubPath)
+ f.SetLanguageIsFinished()
+ f.LogAnalysisError(err, tools.Flawfinder, projectSubPath)
+}
+
+func (f *Formatter) startFlawFinder(projectSubPath string) error {
+ f.LogDebugWithReplace(messages.MsgDebugToolStartAnalysis, tools.Flawfinder)
+
+ output, err := f.ExecuteContainer(f.getConfigData(projectSubPath))
+ if err != nil {
+ f.SetAnalysisError(err)
+ return err
+ }
+
+ f.LogDebugWithReplace(messages.MsgDebugToolFinishAnalysis, tools.Flawfinder)
+ return f.parseOutput(output)
+}
+
+func (f *Formatter) getConfigData(projectSubPath string) *dockerEntities.AnalysisData {
+ return &dockerEntities.AnalysisData{
+ Image: ImageName,
+ Tag: ImageTag,
+ CMD: f.AddWorkDirInCmd(ImageCmd, projectSubPath, tools.Flawfinder),
+ Language: languages.C,
+ }
+}
+
+func (f *Formatter) parseOutput(output string) error {
+ var results []c.Result
+
+ if err := gocsv.UnmarshalString(output, &results); err != nil {
+ f.SetAnalysisError(fmt.Errorf("{HORUSEC_CLI} Error %s", output))
+ return err
+ }
+
+ f.appendResults(results)
+ return nil
+}
+
+func (f *Formatter) appendResults(results []c.Result) {
+ for index := range results {
+ f.GetAnalysis().AnalysisVulnerabilities = append(f.GetAnalysis().AnalysisVulnerabilities,
+ horusec.AnalysisVulnerabilities{
+ Vulnerability: *f.setVulnerabilityData(results, index),
+ })
+ }
+}
+
+func (f *Formatter) setVulnerabilityData(results []c.Result, index int) *horusec.Vulnerability {
+ vulnerability := f.getDefaultVulnerabilitySeverity()
+ vulnerability.Severity = results[index].GetSeverity()
+ vulnerability.Details = results[index].GetDetails()
+ vulnerability.Line = results[index].Line
+ vulnerability.Column = results[index].Column
+ vulnerability.Code = f.GetCodeWithMaxCharacters(results[index].Context, 0)
+ vulnerability.File = results[index].GetFilename()
+ vulnerability = vulnhash.Bind(vulnerability)
+
+ return f.setCommitAuthor(vulnerability)
+}
+
+func (f *Formatter) setCommitAuthor(vulnerability *horusec.Vulnerability) *horusec.Vulnerability {
+ commitAuthor := f.GetCommitAuthor(vulnerability.Line, f.getFilePathFromPackageName(vulnerability.File))
+
+ vulnerability.CommitAuthor = commitAuthor.Author
+ vulnerability.CommitHash = commitAuthor.CommitHash
+ vulnerability.CommitDate = commitAuthor.Date
+ vulnerability.CommitEmail = commitAuthor.Email
+ vulnerability.CommitMessage = commitAuthor.Message
+
+ return vulnerability
+}
+
+func (f *Formatter) getDefaultVulnerabilitySeverity() *horusec.Vulnerability {
+ vulnerabilitySeverity := &horusec.Vulnerability{}
+ vulnerabilitySeverity.SecurityTool = tools.Flawfinder
+ vulnerabilitySeverity.Language = languages.C
+ return vulnerabilitySeverity
+}
+
+func (f *Formatter) getFilePathFromPackageName(filePath string) string {
+ return fileUtil.GetPathIntoFilename(filePath,
+ fmt.Sprintf("%s/", f.GetConfigProjectPath()))
+}
diff --git a/horusec-cli/internal/services/formatters/c/flawfinder/formatter_test.go b/horusec-cli/internal/services/formatters/c/flawfinder/formatter_test.go
new file mode 100644
index 000000000..59597644f
--- /dev/null
+++ b/horusec-cli/internal/services/formatters/c/flawfinder/formatter_test.go
@@ -0,0 +1,120 @@
+// Copyright 2020 ZUP IT SERVICOS EM TECNOLOGIA E INOVACAO SA
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package flawfinder
+
+import (
+ "bytes"
+ "encoding/csv"
+ "errors"
+ "github.com/ZupIT/horusec/development-kit/pkg/entities/horusec"
+ cliConfig "github.com/ZupIT/horusec/horusec-cli/config"
+ "github.com/ZupIT/horusec/horusec-cli/internal/entities/workdir"
+ "github.com/ZupIT/horusec/horusec-cli/internal/services/docker"
+ "github.com/ZupIT/horusec/horusec-cli/internal/services/formatters"
+ "github.com/stretchr/testify/assert"
+ "testing"
+)
+
+func getCsvString() string {
+ pairs := [][]string{
+ {"File", "./test.c"},
+ {"Line", "16"},
+ {"Column", "9"},
+ {"Level", "5"},
+ {"Category", "4"},
+ {"Name", "test"},
+ {"Warning", "test"},
+ {"Suggestion", "test"},
+ {"Note", "test"},
+ {"CWEs", "test"},
+ {"Context", "test"},
+ {"Fingerprint", "test"},
+ }
+
+ buffer := new(bytes.Buffer)
+ writer := csv.NewWriter(buffer)
+
+ _ = writer.WriteAll(pairs)
+ return buffer.String()
+}
+
+func TestStartCFlawfinder(t *testing.T) {
+ t.Run("should success execute container and process output", func(t *testing.T) {
+ dockerAPIControllerMock := &docker.Mock{}
+ analysis := &horusec.Analysis{}
+ config := &cliConfig.Config{
+ WorkDir: &workdir.WorkDir{},
+ }
+
+ output := getCsvString()
+
+ dockerAPIControllerMock.On("CreateLanguageAnalysisContainer").Return(output, nil)
+
+ service := formatters.NewFormatterService(analysis, dockerAPIControllerMock, config, &horusec.Monitor{})
+ formatter := NewFormatter(service)
+
+ formatter.StartAnalysis("")
+
+ assert.NotEmpty(t, analysis)
+ assert.Len(t, analysis.AnalysisVulnerabilities, 11)
+ })
+
+ t.Run("should return error when invalid output", func(t *testing.T) {
+ dockerAPIControllerMock := &docker.Mock{}
+ analysis := &horusec.Analysis{}
+ config := &cliConfig.Config{
+ WorkDir: &workdir.WorkDir{},
+ }
+
+ output := ""
+
+ dockerAPIControllerMock.On("CreateLanguageAnalysisContainer").Return(output, nil)
+
+ service := formatters.NewFormatterService(analysis, dockerAPIControllerMock, config, &horusec.Monitor{})
+ formatter := NewFormatter(service)
+
+ assert.NotPanics(t, func() {
+ formatter.StartAnalysis("")
+ })
+ })
+
+ t.Run("should return error when executing container", func(t *testing.T) {
+ dockerAPIControllerMock := &docker.Mock{}
+ analysis := &horusec.Analysis{}
+ config := &cliConfig.Config{
+ WorkDir: &workdir.WorkDir{},
+ }
+
+ dockerAPIControllerMock.On("CreateLanguageAnalysisContainer").Return("", errors.New("test"))
+
+ service := formatters.NewFormatterService(analysis, dockerAPIControllerMock, config, &horusec.Monitor{})
+ formatter := NewFormatter(service)
+
+ assert.NotPanics(t, func() {
+ formatter.StartAnalysis("")
+ })
+ })
+ t.Run("Should not execute tool because it's ignored", func(t *testing.T) {
+ analysis := &horusec.Analysis{}
+ dockerAPIControllerMock := &docker.Mock{}
+ config := &cliConfig.Config{
+ ToolsToIgnore: "gosec,securitycodescan,brakeman,safety,bandit,npmaudit,yarnaudit,spotbugs,horuseckotlin,horusecjava,horusecleaks,gitleaks,tfsec,semgrep,flawfinder",
+ }
+ service := formatters.NewFormatterService(analysis, dockerAPIControllerMock, config, &horusec.Monitor{})
+ formatter := NewFormatter(service)
+
+ formatter.StartAnalysis("")
+ })
+}
diff --git a/horusec-cli/internal/services/formatters/leaks/horusecleaks/config.go b/horusec-cli/internal/services/formatters/leaks/horusecleaks/config.go
index d8aed4f1a..1dcf457b7 100644
--- a/horusec-cli/internal/services/formatters/leaks/horusecleaks/config.go
+++ b/horusec-cli/internal/services/formatters/leaks/horusecleaks/config.go
@@ -16,7 +16,7 @@ package horusecleaks
const (
ImageName = "horuszup/horusec-leaks"
- ImageTag = "v0.2.6"
+ ImageTag = "v0.3.0"
ImageCmd = `
{{WORK_DIR}}
horusec-leaks run -o="./output-ANALYSISID.json"
diff --git a/horusec-cli/internal/services/formatters/php/phpcs/config.go b/horusec-cli/internal/services/formatters/php/phpcs/config.go
new file mode 100644
index 000000000..f5ae837fe
--- /dev/null
+++ b/horusec-cli/internal/services/formatters/php/phpcs/config.go
@@ -0,0 +1,26 @@
+// Copyright 2020 ZUP IT SERVICOS EM TECNOLOGIA E INOVACAO SA
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package phpcs
+
+const (
+ ImageName = "horuszup/horusec-phpcs"
+ ImageTag = "v1.0.0"
+ // nolint
+ ImageCmd = `
+ phpcs --report=json --standard=/vendor/pheromone/phpcs-security-audit/example_drupal7_ruleset.xml . > /tmp/result-ANALYSISID.json
+ cat /tmp/result-ANALYSISID.json
+ chmod -R 777 .
+ `
+)
diff --git a/horusec-cli/internal/services/formatters/php/phpcs/formatter.go b/horusec-cli/internal/services/formatters/php/phpcs/formatter.go
new file mode 100644
index 000000000..508fc7661
--- /dev/null
+++ b/horusec-cli/internal/services/formatters/php/phpcs/formatter.go
@@ -0,0 +1,149 @@
+// Copyright 2020 ZUP IT SERVICOS EM TECNOLOGIA E INOVACAO SA
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package phpcs
+
+import (
+ "encoding/json"
+ "fmt"
+ phpEntities "github.com/ZupIT/horusec/development-kit/pkg/entities/analyser/php/phpcs"
+ "github.com/ZupIT/horusec/development-kit/pkg/entities/horusec"
+ "github.com/ZupIT/horusec/development-kit/pkg/enums/languages"
+ "github.com/ZupIT/horusec/development-kit/pkg/enums/severity"
+ "github.com/ZupIT/horusec/development-kit/pkg/enums/tools"
+ "github.com/ZupIT/horusec/development-kit/pkg/utils/logger"
+ vulnhash "github.com/ZupIT/horusec/development-kit/pkg/utils/vuln_hash"
+ dockerEntities "github.com/ZupIT/horusec/horusec-cli/internal/entities/docker"
+ "github.com/ZupIT/horusec/horusec-cli/internal/helpers/messages"
+ "github.com/ZupIT/horusec/horusec-cli/internal/services/formatters"
+)
+
+type Formatter struct {
+ formatters.IService
+}
+
+func NewFormatter(service formatters.IService) formatters.IFormatter {
+ return &Formatter{
+ service,
+ }
+}
+
+func (f *Formatter) StartAnalysis(projectSubPath string) {
+ if f.ToolIsToIgnore(tools.PhpCS) {
+ logger.LogDebugWithLevel(messages.MsgDebugToolIgnored+tools.PhpCS.ToString(), logger.DebugLevel)
+ return
+ }
+
+ err := f.startPhpCs(projectSubPath)
+ f.SetLanguageIsFinished()
+ f.LogAnalysisError(err, tools.PhpCS, projectSubPath)
+}
+
+func (f *Formatter) startPhpCs(projectSubPath string) error {
+ f.LogDebugWithReplace(messages.MsgDebugToolStartAnalysis, tools.PhpCS)
+
+ output, err := f.ExecuteContainer(f.getConfigData(projectSubPath))
+ if err != nil {
+ f.SetAnalysisError(err)
+ return err
+ }
+
+ f.LogDebugWithReplace(messages.MsgDebugToolFinishAnalysis, tools.PhpCS)
+ return f.parseOutput(output)
+}
+
+func (f *Formatter) getConfigData(projectSubPath string) *dockerEntities.AnalysisData {
+ return &dockerEntities.AnalysisData{
+ Image: ImageName,
+ Tag: ImageTag,
+ CMD: f.AddWorkDirInCmd(ImageCmd, projectSubPath, tools.PhpCS),
+ Language: languages.PHP,
+ }
+}
+
+func (f *Formatter) parseOutput(output string) error {
+ var results map[string]interface{}
+
+ if err := json.Unmarshal([]byte(output), &results); err != nil {
+ f.SetAnalysisError(fmt.Errorf("{HORUSEC_CLI} Error %s", output))
+ return err
+ }
+
+ f.parseResults(results)
+ return nil
+}
+
+func (f *Formatter) parseResults(results map[string]interface{}) {
+ if results != nil {
+ files := results["files"]
+ for filepath, result := range files.(map[string]interface{}) {
+ f.parseMessages(filepath, result)
+ }
+ }
+}
+
+func (f *Formatter) parseMessages(filepath string, result interface{}) {
+ for _, message := range f.parseToResult(result).Messages {
+ f.appendResults(filepath, message)
+ }
+}
+
+func (f *Formatter) appendResults(filepath string, message phpEntities.Message) {
+ if message.IsValidMessage() {
+ f.GetAnalysis().AnalysisVulnerabilities = append(f.GetAnalysis().AnalysisVulnerabilities,
+ horusec.AnalysisVulnerabilities{
+ Vulnerability: *f.setVulnerabilityData(filepath, message),
+ })
+ }
+}
+
+func (f *Formatter) setVulnerabilityData(filepath string, result phpEntities.Message) *horusec.Vulnerability {
+ vulnerability := f.getDefaultVulnerabilitySeverity()
+ vulnerability.Severity = severity.Info
+ vulnerability.Details = result.Message
+ vulnerability.Line = result.GetLine()
+ vulnerability.Column = result.GetColumn()
+ vulnerability.File = f.RemoveSrcFolderFromPath(filepath)
+ vulnerability = vulnhash.Bind(vulnerability)
+
+ return f.setCommitAuthor(vulnerability)
+}
+
+func (f *Formatter) setCommitAuthor(vulnerability *horusec.Vulnerability) *horusec.Vulnerability {
+ commitAuthor := f.GetCommitAuthor(vulnerability.Line, vulnerability.File)
+
+ vulnerability.CommitAuthor = commitAuthor.Author
+ vulnerability.CommitHash = commitAuthor.CommitHash
+ vulnerability.CommitDate = commitAuthor.Date
+ vulnerability.CommitEmail = commitAuthor.Email
+ vulnerability.CommitMessage = commitAuthor.Message
+
+ return vulnerability
+}
+
+func (f *Formatter) getDefaultVulnerabilitySeverity() *horusec.Vulnerability {
+ vulnerabilitySeverity := &horusec.Vulnerability{}
+ vulnerabilitySeverity.SecurityTool = tools.PhpCS
+ vulnerabilitySeverity.Language = languages.PHP
+ return vulnerabilitySeverity
+}
+
+func (f *Formatter) parseToResult(messageInterface interface{}) *phpEntities.Result {
+ var result *phpEntities.Result
+
+ bytes, _ := json.Marshal(messageInterface)
+ _ = json.Unmarshal(bytes, &result)
+
+ return result
+}
diff --git a/horusec-cli/internal/services/formatters/php/phpcs/formatter_test.go b/horusec-cli/internal/services/formatters/php/phpcs/formatter_test.go
new file mode 100644
index 000000000..46f14bd30
--- /dev/null
+++ b/horusec-cli/internal/services/formatters/php/phpcs/formatter_test.go
@@ -0,0 +1,95 @@
+// Copyright 2020 ZUP IT SERVICOS EM TECNOLOGIA E INOVACAO SA
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package phpcs
+
+import (
+ "errors"
+ "github.com/ZupIT/horusec/development-kit/pkg/entities/horusec"
+ cliConfig "github.com/ZupIT/horusec/horusec-cli/config"
+ "github.com/ZupIT/horusec/horusec-cli/internal/entities/workdir"
+ "github.com/ZupIT/horusec/horusec-cli/internal/services/docker"
+ "github.com/ZupIT/horusec/horusec-cli/internal/services/formatters"
+ "github.com/stretchr/testify/assert"
+ "testing"
+)
+
+func TestStartCFlawfinder(t *testing.T) {
+ t.Run("should success execute container and process output", func(t *testing.T) {
+ dockerAPIControllerMock := &docker.Mock{}
+ analysis := &horusec.Analysis{}
+ config := &cliConfig.Config{
+ WorkDir: &workdir.WorkDir{},
+ }
+
+ output := "{ \"files\":{ \"\\/src\\/XSS\\/XSS_level5.php\":{ \"errors\":1, \"warnings\":4, \"messages\":[ { \"message\":\"User input detetected with $_SERVER.\", \"source\":\"PHPCS_SecurityAudit.Drupal7.UserInputWatch.D7UserInWaWarn\", \"severity\":5, \"fixable\":false, \"type\":\"WARNING\", \"line\":14, \"column\":39 }, { \"message\":\"Easy XSS detected because of direct user input with $_SERVER on echo\", \"source\":\"PHPCS_SecurityAudit.BadFunctions.EasyXSS.EasyXSSerr\", \"severity\":5, \"fixable\":false, \"type\":\"ERROR\", \"line\":14, \"column\":39 } ] } } }"
+
+ dockerAPIControllerMock.On("CreateLanguageAnalysisContainer").Return(output, nil)
+
+ service := formatters.NewFormatterService(analysis, dockerAPIControllerMock, config, &horusec.Monitor{})
+ formatter := NewFormatter(service)
+
+ formatter.StartAnalysis("")
+
+ assert.NotEmpty(t, analysis)
+ assert.Len(t, analysis.AnalysisVulnerabilities, 1)
+ })
+
+ t.Run("should return error when invalid output", func(t *testing.T) {
+ dockerAPIControllerMock := &docker.Mock{}
+ analysis := &horusec.Analysis{}
+ config := &cliConfig.Config{
+ WorkDir: &workdir.WorkDir{},
+ }
+
+ output := ""
+
+ dockerAPIControllerMock.On("CreateLanguageAnalysisContainer").Return(output, nil)
+
+ service := formatters.NewFormatterService(analysis, dockerAPIControllerMock, config, &horusec.Monitor{})
+ formatter := NewFormatter(service)
+
+ assert.NotPanics(t, func() {
+ formatter.StartAnalysis("")
+ })
+ })
+
+ t.Run("should return error when executing container", func(t *testing.T) {
+ dockerAPIControllerMock := &docker.Mock{}
+ analysis := &horusec.Analysis{}
+ config := &cliConfig.Config{
+ WorkDir: &workdir.WorkDir{},
+ }
+
+ dockerAPIControllerMock.On("CreateLanguageAnalysisContainer").Return("", errors.New("test"))
+
+ service := formatters.NewFormatterService(analysis, dockerAPIControllerMock, config, &horusec.Monitor{})
+ formatter := NewFormatter(service)
+
+ assert.NotPanics(t, func() {
+ formatter.StartAnalysis("")
+ })
+ })
+ t.Run("Should not execute tool because it's ignored", func(t *testing.T) {
+ analysis := &horusec.Analysis{}
+ dockerAPIControllerMock := &docker.Mock{}
+ config := &cliConfig.Config{
+ ToolsToIgnore: "gosec,securitycodescan,brakeman,safety,bandit,npmaudit,yarnaudit,spotbugs,horuseckotlin,horusecjava,horusecleaks,gitleaks,tfsec,semgrep,flawfinder,phpcs",
+ }
+ service := formatters.NewFormatterService(analysis, dockerAPIControllerMock, config, &horusec.Monitor{})
+ formatter := NewFormatter(service)
+
+ formatter.StartAnalysis("")
+ })
+}
diff --git a/horusec-cli/internal/services/horusapi/horus_api.go b/horusec-cli/internal/services/horusapi/horus_api.go
index db13a4372..ce5267e3a 100644
--- a/horusec-cli/internal/services/horusapi/horus_api.go
+++ b/horusec-cli/internal/services/horusapi/horus_api.go
@@ -19,11 +19,12 @@ import (
"crypto/tls"
"crypto/x509"
"fmt"
- "github.com/ZupIT/horusec/development-kit/pkg/entities/api"
- "github.com/google/uuid"
"io/ioutil"
"net/http"
+ "github.com/ZupIT/horusec/development-kit/pkg/entities/api"
+ "github.com/google/uuid"
+
"github.com/ZupIT/horusec/development-kit/pkg/entities/horusec"
"github.com/ZupIT/horusec/development-kit/pkg/utils/http-request/client"
httpResponse "github.com/ZupIT/horusec/development-kit/pkg/utils/http-request/response"
@@ -90,7 +91,7 @@ func (s *Service) sendFindAnalysisRequest(analysisID uuid.UUID) (httpResponse.In
return nil, err
}
- req.Header.Add("Authorization", s.config.GetRepositoryAuthorization())
+ s.addHeaders(req)
return s.httpUtil.DoRequest(req, tlsConfig)
}
@@ -105,7 +106,7 @@ func (s *Service) sendCreateAnalysisRequest(analysis *horusec.Analysis) (httpRes
return nil, err
}
- req.Header.Add("Authorization", s.config.GetRepositoryAuthorization())
+ s.addHeaders(req)
return s.httpUtil.DoRequest(req, tlsConfig)
}
@@ -171,3 +172,10 @@ func (s *Service) newRequestData(analysis *horusec.Analysis) []byte {
return analysisData.ToBytes()
}
+
+func (s *Service) addHeaders(req *http.Request) {
+ req.Header.Add("X-Horusec-Authorization", s.config.GetRepositoryAuthorization())
+ for key, value := range s.config.GetHeaders() {
+ req.Header.Add(key, value)
+ }
+}
diff --git a/horusec-cli/internal/services/horusapi/horus_api_test.go b/horusec-cli/internal/services/horusapi/horus_api_test.go
index 54b65f816..309ed48d8 100644
--- a/horusec-cli/internal/services/horusapi/horus_api_test.go
+++ b/horusec-cli/internal/services/horusapi/horus_api_test.go
@@ -47,7 +47,7 @@ func TestSendAnalysis(t *testing.T) {
service := Service{
httpUtil: httpMock,
- config: &cliConfig.Config{RepositoryAuthorization: "test"},
+ config: &cliConfig.Config{RepositoryAuthorization: "test", Headers: `{"some-header": "some-value"}`},
}
assert.NotPanics(t, func() {
diff --git a/horusec-config.json b/horusec-config.json
index 67bdff4d5..15b01a905 100644
--- a/horusec-config.json
+++ b/horusec-config.json
@@ -10,8 +10,8 @@
"horusecCliFilesOrPathsToIgnore": "**/e2e/**, **/examples/**, **/*.toml, **/*_test.go, **/*_mock.go, **/*README.md, **/development-kit/pkg/enums/engine/advisories/**, **/horusec-lp/.cache/**, **/horusec-lp/public/**, **/deployments/docker-compose*, **/horusec-cli/cmd/horusec/start/analysis/*, **/horusec-manager/src/helpers/localStorage/**",
"horusecCliReturnErrorIfFoundVulnerability": false,
"horusecCliProjectPath": "./",
- "horusecCliFalsePositiveHashes": "b17a7ef9ebf374c594700c1bfbf9d3594de68f0fc23af6171269f1f629a8abcf, 0870cfa59cfe7ef087e45762ce1d66cb6fdc85196323fcfae2e90167f242e4b3, 3198f2595d15ba1a01174329c944e3af9f7b3a7af7914e857eb9b82684633236, b85977d0bc430b00f17bc9f431d70b272110afea2549ee41bf03369bf99572d2, 312a4ee6b6b74a8c667e6f907568d9feaa0f0a69091f322abbcdf0562b9a3914, a452ff6d2565d67f118c80866a38a25871606751421347211b8932eb55aed85b, 3a0c53aae9a54d01e97417f2e495ca74c1f8874b0e4805fc622e50f7633838a8, 6a669b83a533c64fccc304fd7dbf3d491e85ec0a852f0d154fe813704765da8e, 4d4cc9d51d9c049b4a7bcedd330445d54bab832a8760543ebf990e86c17fdca0, 4868ef9970205c00a1c48b0e3e0debccf5a31e2e68767e25bd1d6bab36966822, f4f5d429ea2a8cbed3813ee58bac655162c65e50c64f68b65de6cfe408ab91c1, 8fd7c193876b7a7d26936c897e15135693d26f55b3c7c91bbdd5024f8ce12f81, 87956a8852a3d1b4b904b48815904ecd8f8932cd577d3a109e4139b3b5955e2c",
- "horusecCliRiskAcceptHashes": "45aa5c46df5ba51d7e59da826544412352c189a6acf5707f941922181c94f989, ba56b6e4ac8f790026b82a488c5624d7e2d6f6dd60584a9375c3c8948b608dbf, 2ce87bddc40e085562618f441750eeefe3cffc79d0b05b2e07a98f644c55b2c5, e2eaa19612eed0124b1fec396f8d41381c618c677c2025fc07c1cd0ccbe92b3c, 0ffc51a6b0187bec02837cb1e8dddfa05519e83d861af3fbd553bc4d0fbe852d, 4294bf00b848d82c4e012f45e0747996eb75109e089a626af930580a7a179ea4, fa41e0534388707279458969d1dcdb58ff932357660e8855d2bb4170fdbcb391, 5114704fb26983f549c5f179a0a90d8e95c8db28f9e68d32d864b2a6743cb499, 068f660ece48b7ef680152a6553d6f231413712b5d228f68f6d70a4c10e2b00b, a438599f015899ab0ce0bc9030915a59629f978127e2eac2a6ea7caec974c8d6, ab8d60c9c0796a0d528faf6d0fcb8693388a7182f903046a4aa54ffd81e080c7, 000467d49617182841ba72f0b63ddd396e350356542342d60b957835e943fcdf, d057a467e98c66fa437c62b11afc3fbecbab63e2331fdfe299bad0a011e46707, 4530caeaffd6d7fa42cf73240710b141a455547d75dd643ecbdbc6adf7c66037",
+ "horusecCliFalsePositiveHashes": "b17a7ef9ebf374c594700c1bfbf9d3594de68f0fc23af6171269f1f629a8abcf, 0870cfa59cfe7ef087e45762ce1d66cb6fdc85196323fcfae2e90167f242e4b3, 3198f2595d15ba1a01174329c944e3af9f7b3a7af7914e857eb9b82684633236, b85977d0bc430b00f17bc9f431d70b272110afea2549ee41bf03369bf99572d2, 312a4ee6b6b74a8c667e6f907568d9feaa0f0a69091f322abbcdf0562b9a3914, a452ff6d2565d67f118c80866a38a25871606751421347211b8932eb55aed85b, 3a0c53aae9a54d01e97417f2e495ca74c1f8874b0e4805fc622e50f7633838a8, 6a669b83a533c64fccc304fd7dbf3d491e85ec0a852f0d154fe813704765da8e, 4d4cc9d51d9c049b4a7bcedd330445d54bab832a8760543ebf990e86c17fdca0, 4868ef9970205c00a1c48b0e3e0debccf5a31e2e68767e25bd1d6bab36966822, f4f5d429ea2a8cbed3813ee58bac655162c65e50c64f68b65de6cfe408ab91c1, 8fd7c193876b7a7d26936c897e15135693d26f55b3c7c91bbdd5024f8ce12f81, 87956a8852a3d1b4b904b48815904ecd8f8932cd577d3a109e4139b3b5955e2c, 020f321ecd79df4cde2d93a06e4e5ba711a315060d4a9ee167de518606ee853f",
+ "horusecCliRiskAcceptHashes": "ba56b6e4ac8f790026b82a488c5624d7e2d6f6dd60584a9375c3c8948b608dbf, 2ce87bddc40e085562618f441750eeefe3cffc79d0b05b2e07a98f644c55b2c5, e2eaa19612eed0124b1fec396f8d41381c618c677c2025fc07c1cd0ccbe92b3c, 0ffc51a6b0187bec02837cb1e8dddfa05519e83d861af3fbd553bc4d0fbe852d, 4294bf00b848d82c4e012f45e0747996eb75109e089a626af930580a7a179ea4, fa41e0534388707279458969d1dcdb58ff932357660e8855d2bb4170fdbcb391, 5114704fb26983f549c5f179a0a90d8e95c8db28f9e68d32d864b2a6743cb499, 068f660ece48b7ef680152a6553d6f231413712b5d228f68f6d70a4c10e2b00b, a438599f015899ab0ce0bc9030915a59629f978127e2eac2a6ea7caec974c8d6, ab8d60c9c0796a0d528faf6d0fcb8693388a7182f903046a4aa54ffd81e080c7, 000467d49617182841ba72f0b63ddd396e350356542342d60b957835e943fcdf, d057a467e98c66fa437c62b11afc3fbecbab63e2331fdfe299bad0a011e46707, 4530caeaffd6d7fa42cf73240710b141a455547d75dd643ecbdbc6adf7c66037, 1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ, 1e08930833e061f7e2e84d3a6fd51c25dd8528f06cad26828d7b782bf04caad3",
"horusecCliWorkDir": {
"go": [],
"csharp": [],
diff --git a/horusec-leaks/.semver.yaml b/horusec-leaks/.semver.yaml
index 7a248d181..de73c0435 100644
--- a/horusec-leaks/.semver.yaml
+++ b/horusec-leaks/.semver.yaml
@@ -1,4 +1,4 @@
alpha: 0
beta: 0
rc: 0
-release: v0.2.6
+release: v0.3.0
diff --git a/horusec-manager/.semver.yaml b/horusec-manager/.semver.yaml
index 661ea3c03..09212016b 100644
--- a/horusec-manager/.semver.yaml
+++ b/horusec-manager/.semver.yaml
@@ -1,4 +1,4 @@
alpha: 0
beta: 0
rc: 0
-release: v1.3.0
+release: v1.4.0
diff --git a/horusec-manager/src/assets/svg/config.svg b/horusec-manager/src/assets/svg/config.svg
new file mode 100644
index 000000000..9b6d4eec2
--- /dev/null
+++ b/horusec-manager/src/assets/svg/config.svg
@@ -0,0 +1,18 @@
+
+
diff --git a/horusec-manager/src/assets/svg/delete.svg b/horusec-manager/src/assets/svg/delete.svg
index 1940055d1..8a2c7e816 100644
--- a/horusec-manager/src/assets/svg/delete.svg
+++ b/horusec-manager/src/assets/svg/delete.svg
@@ -1,2 +1,2 @@
-
+
diff --git a/horusec-manager/src/assets/svg/edit.svg b/horusec-manager/src/assets/svg/edit.svg
index fe46c1a65..5eb94754f 100644
--- a/horusec-manager/src/assets/svg/edit.svg
+++ b/horusec-manager/src/assets/svg/edit.svg
@@ -3,8 +3,8 @@
-
-
+
+
diff --git a/horusec-manager/src/assets/svg/list.svg b/horusec-manager/src/assets/svg/list.svg
index 57d32a093..b4eae0f8c 100644
--- a/horusec-manager/src/assets/svg/list.svg
+++ b/horusec-manager/src/assets/svg/list.svg
@@ -1,7 +1,7 @@