Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Backport remaining framework classifiers from Bearer Rails app #155

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions pkg/classification/frameworks/frameworks.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@ import (

"github.com/bearer/curio/pkg/classification/db"
"github.com/bearer/curio/pkg/report/detections"
"github.com/bearer/curio/pkg/report/frameworks/rails"
"github.com/bearer/curio/pkg/util/classify"
)

type classifiableFramework interface{
GetTechnologyKey() string
}

type ClassifiedFramework struct {
*detections.Detection
Classification *Classification `json:"classification" yaml:"classification"`
Expand Down Expand Up @@ -59,20 +62,17 @@ func (classifier *Classifier) Classify(data detections.Detection) (*ClassifiedFr
}

var technologyKey string
switch value := data.Value.(type) {
case rails.Cache:
technologyKey = value.GetTechnologyKey()
case rails.Database:
technologyKey = value.GetTechnologyKey()
case rails.Storage:
technologyKey = value.GetTechnologyKey()
default:

value, ok := data.Value.(classifiableFramework)
if !ok {
return &ClassifiedFramework{
Detection: &data,
Classification: classification,
}, errors.New("detection is not for a framework")
}

technologyKey = value.GetTechnologyKey()

if technologyKey != "" {
for _, recipe := range classifier.config.Recipes {
if isRecipeMatch(recipe, technologyKey) {
Expand All @@ -97,5 +97,5 @@ func (classifier *Classifier) Classify(data detections.Detection) (*ClassifiedFr
}

func isRecipeMatch(recipe db.Recipe, technologyKey string) bool {
return recipe.Name == technologyKey
return recipe.UUID == technologyKey
}
157 changes: 157 additions & 0 deletions pkg/classification/frameworks/frameworks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@ import (

"github.com/bearer/curio/pkg/classification/frameworks"
"github.com/bearer/curio/pkg/report/detections"
"github.com/bearer/curio/pkg/report/frameworks/beego"
"github.com/bearer/curio/pkg/report/frameworks/django"
"github.com/bearer/curio/pkg/report/frameworks/dotnet"
"github.com/bearer/curio/pkg/report/frameworks/rails"
"github.com/bearer/curio/pkg/report/frameworks/spring"
"github.com/bearer/curio/pkg/report/frameworks/symfony"
"github.com/bearer/curio/pkg/report/source"
"github.com/bearer/curio/pkg/util/classify"

Expand Down Expand Up @@ -181,6 +186,158 @@ func TestFrameworks(t *testing.T) {
Want: nil,
ShouldSucceed: true,
},
{
Name: "Beego: driver name defined",
Input: detections.Detection{
Source: source.Source{
Filename: "orm.go",
Language: "Go",
LanguageType: "programming",
},
Value: beego.Database{
Name: "default",
DriverName: "mysql",
Package: "",
TypeConstant: "",
},
Type: detections.TypeFramework,
},
Want: &frameworks.Classification{
RecipeMatch: true,
RecipeName: "MySQL",
RecipeUUID: "ffa70264-2b19-445d-a5c9-be82b64fe750",
Decision: classify.ClassificationDecision{
State: classify.Valid,
Reason: "recipe_match",
},
},
ShouldSucceed: true,
},
{
Name: "Beego: package defined",
Input: detections.Detection{
Source: source.Source{
Filename: "orm.go",
Language: "Go",
LanguageType: "programming",
},
Value: beego.Database{
Name: "default",
DriverName: "",
Package: "github.com/beego/beego/v2/client/orm",
TypeConstant: "DRSqlite",
},
Type: detections.TypeFramework,
},
Want: &frameworks.Classification{
RecipeMatch: true,
RecipeName: "SQLite",
RecipeUUID: "aa706b3c-0f6d-4a7b-a7a5-71ee0c5b6c00",
Decision: classify.ClassificationDecision{
State: classify.Valid,
Reason: "recipe_match",
},
},
ShouldSucceed: true,
},
{
Name: "Django: database match",
Input: detections.Detection{
Source: source.Source{
Filename: "orm.py",
Language: "Python",
LanguageType: "programming",
},
Value: django.Database{
Name: "default",
Engine: "django.db.backends.mysql",
},
Type: detections.TypeFramework,
},
Want: &frameworks.Classification{
RecipeMatch: true,
RecipeName: "MySQL",
RecipeUUID: "ffa70264-2b19-445d-a5c9-be82b64fe750",
Decision: classify.ClassificationDecision{
State: classify.Valid,
Reason: "recipe_match",
},
},
ShouldSucceed: true,
},
{
Name: ".NET: database match",
Input: detections.Detection{
Source: source.Source{
Filename: "Startup.cs",
Language: "C#",
LanguageType: "programming",
},
Value: dotnet.DBContext{
UseDbMethodName: "UseSqlServer",
},
Type: detections.TypeFramework,
},
Want: &frameworks.Classification{
RecipeMatch: true,
RecipeName: "Microsoft SQL Server",
RecipeUUID: "e4db4505-b837-4b76-9184-c3cec3b5e522",
Decision: classify.ClassificationDecision{
State: classify.Valid,
Reason: "recipe_match",
},
},
ShouldSucceed: true,
},
{
Name: "Spring: database match",
Input: detections.Detection{
Source: source.Source{
Filename: "src/main/application.properties",
Language: "Properties",
LanguageType: "config",
},
Value: spring.DataStore{
Driver: "com.mysql.jdbc.Driver",
},
Type: detections.TypeFramework,
},
Want: &frameworks.Classification{
RecipeMatch: true,
RecipeName: "MySQL",
RecipeUUID: "ffa70264-2b19-445d-a5c9-be82b64fe750",
Decision: classify.ClassificationDecision{
State: classify.Valid,
Reason: "recipe_match",
},
},
ShouldSucceed: true,
},
{
Name: "Symfony: database match",
Input: detections.Detection{
Source: source.Source{
Filename: "config/packages/doctrine.yml",
Language: "YAML",
LanguageType: "config",
},
Value: symfony.Database{
Name: "production",
Driver: "oci8",
},
Type: detections.TypeFramework,
},
Want: &frameworks.Classification{
RecipeMatch: true,
RecipeName: "Oracle",
RecipeUUID: "80886e2a-ee2c-423d-98bc-0a3d743787b4",
Decision: classify.ClassificationDecision{
State: classify.Valid,
Reason: "recipe_match",
},
},
ShouldSucceed: true,
},
}

classifier := frameworks.NewDefault()
Expand Down
38 changes: 38 additions & 0 deletions pkg/report/frameworks/beego/beego.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,41 @@ type Database struct {
Package string `json:"package" yaml:"package"`
TypeConstant string `json:"type_constant" yaml:"type_constant"`
}

func (value Database) GetTechnologyKey() string {
if value.Package != "" {
return technologyForDriverLib(value.Package, value.TypeConstant)
}

return technologyForDriverName(value.DriverName)
}

func technologyForDriverLib(packageName string, typeConstant string) string {
if packageName != "github.com/beego/beego/v2/client/orm" {
return "unidentified_data_store"
}

switch typeConstant {
case "DRMySQL", "DR_MySQL":
return "ffa70264-2b19-445d-a5c9-be82b64fe750"
case "DRPostgres", "DR_Postgres":
return "428ff7dd-22ea-4e80-8755-84c70cf460db"
case "DRSqlite", "DR_Sqlite":
return "aa706b3c-0f6d-4a7b-a7a5-71ee0c5b6c00"
default:
return "unidentified_data_store"
}
}

func technologyForDriverName(driverName string) string {
switch driverName {
case "mysql":
return "ffa70264-2b19-445d-a5c9-be82b64fe750"
case "postgres":
return "428ff7dd-22ea-4e80-8755-84c70cf460db"
case "sqlite3":
return "aa706b3c-0f6d-4a7b-a7a5-71ee0c5b6c00"
default:
return "unidentified_data_store"
}
}
17 changes: 17 additions & 0 deletions pkg/report/frameworks/django/django.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,20 @@ type Database struct {
Name string `json:"name" yaml:"name"`
Engine string `json:"engine" yaml:"engine"`
}

func (value Database) GetTechnologyKey() string {
switch value.Engine {
case "sql_server.pyodbc":
return "e4db4505-b837-4b76-9184-c3cec3b5e522"
case "django.db.backends.mysql":
return "ffa70264-2b19-445d-a5c9-be82b64fe750"
case "django.db.backends.oracle":
return "80886e2a-ee2c-423d-98bc-0a3d743787b4"
case "django.db.backends.postgresql":
return "428ff7dd-22ea-4e80-8755-84c70cf460db"
case "django.db.backends.sqlite3":
return "aa706b3c-0f6d-4a7b-a7a5-71ee0c5b6c00"
default:
return "unidentified_data_store"
}
}
17 changes: 17 additions & 0 deletions pkg/report/frameworks/dotnet/dotnet.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,20 @@ type DBContext struct {
UseDbMethodName string `json:"use_db_method_name" yaml:"use_db_method_name"`
TypeName string `json:"type_name" yaml:"type_name"`
}

func (value DBContext) GetTechnologyKey() string {
switch value.UseDbMethodName {
case "UseSqlServer":
return "e4db4505-b837-4b76-9184-c3cec3b5e522"
case "UseMySQL":
return "ffa70264-2b19-445d-a5c9-be82b64fe750"
case "UseOracle":
return "80886e2a-ee2c-423d-98bc-0a3d743787b4"
case "UseNpgsql":
return "428ff7dd-22ea-4e80-8755-84c70cf460db"
case "UseSqlite":
return "aa706b3c-0f6d-4a7b-a7a5-71ee0c5b6c00"
default:
return "unidentified_data_store"
}
}
26 changes: 13 additions & 13 deletions pkg/report/frameworks/rails/rails.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,36 +25,36 @@ type Storage struct {
Encryption string `json:"encryption" yaml:"encryption"`
}

func (value *Cache) GetTechnologyKey() string {
func (value Cache) GetTechnologyKey() string {
switch value.Type {
case "memory_store", "null_store":
// Ignored cache types
return ""
case "file_store":
return "Disk"
return "39747024-c306-4a95-a0df-7e585a33a86f"
case "mem_cache_store":
return "Memcached"
return "42908ccc-4f0f-419e-9ba0-f25121fd15b7"
case "redis_cache_store":
return "Redis"
return "62c20409-c1bf-4be9-a859-6fe6be7b11e3"
default:
return "unidentified_data_store"
}
}

func (value *Database) GetTechnologyKey() string {
func (value Database) GetTechnologyKey() string {
switch strings.ToLower(value.Adapter) {
case "mysql2", "jdbcmysql":
return "MySQL"
return "ffa70264-2b19-445d-a5c9-be82b64fe750"
case "postgresql", "jdbcpostgresql":
return "PostgreSQL"
return "428ff7dd-22ea-4e80-8755-84c70cf460db"
case "sqlite3", "jdbcsqlite3":
return "SQLite"
return "aa706b3c-0f6d-4a7b-a7a5-71ee0c5b6c00"
default:
return "unidentified_data_store"
}
}

func (value *Storage) GetTechnologyKey() string {
func (value Storage) GetTechnologyKey() string {
if strings.Contains(value.Name, "test") {
// Ignored storage types
return ""
Expand All @@ -65,13 +65,13 @@ func (value *Storage) GetTechnologyKey() string {
// Ignored storage types
return ""
case "AzureStorage":
return "Azure Storage"
return "f0f43ee7-7f6b-4572-aaa0-6b207146912b"
case "Disk":
return "Disk"
return "39747024-c306-4a95-a0df-7e585a33a86f"
case "GCS":
return "Google Cloud Storage"
return "3a154582-174f-4ef7-90a2-f654435c23cb"
case "S3":
return "AWS S3"
return "4e5a3a3a-47cd-4b0e-b0a6-fa30a0a62499"
default:
return "unidentified_data_store"
}
Expand Down
23 changes: 22 additions & 1 deletion pkg/report/frameworks/spring/spring.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,30 @@
package spring

import "github.com/bearer/curio/pkg/report/frameworks"
import (
"github.com/bearer/curio/pkg/report/frameworks"
)

const TypeDatabase frameworks.Type = "database"

type DataStore struct {
Driver string `json:"driver" yaml:"driver"`
}

func (value DataStore) GetTechnologyKey() string {
switch value.Driver {
case "db2", "com.ibm.db2.jcc.DB2Driver":
return "b9bbbbb8-cb8b-4ffb-997f-e0d1e9050a96"
case "sqlserver", "com.microsoft.sqlserver.jdbc.SQLServerDriver":
return "e4db4505-b837-4b76-9184-c3cec3b5e522"
case "mysql", "com.mysql.jdbc.Driver", "mariadb", "org.mariadb.jdbc.Driver":
return "ffa70264-2b19-445d-a5c9-be82b64fe750"
case "oracle", "oracle.jdbc.OracleDriver":
return "80886e2a-ee2c-423d-98bc-0a3d743787b4"
case "postgresql", "com.postgresql.jdbc.Driver":
return "428ff7dd-22ea-4e80-8755-84c70cf460db"
case "sqlite", "org.sqlite.JDBC":
return "aa706b3c-0f6d-4a7b-a7a5-71ee0c5b6c00"
default:
return "unidentified_data_store"
}
}
Loading