diff --git a/README.md b/README.md index 9edbe7930601b16af937ca1ab5082916a4d28e09..1d69b99fd409c8675a6e15c11d518580722f7d7e 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,10 @@ inspected by pre-defined aggregations (*queries*), that are shipped with the server configuration and can be queried via the RPC interface, which can take advantage of the SQLITE JSON extensions. +The *application-specific key* is a separate and independent key space +hooked off the primary (shard / type / resource_id) key, which allows +one to store multiple entries for the same type and resource. + Q: Isn't this just a way to achieve SQL sharding? A: In a sense, yes, but with RPC APIs tuned to a very specific use diff --git a/server_test.go b/server_test.go index ce7ae4abf11c7ae53a3b8b2fc4fcaeeef9cd8ba5..98329a8530bdaa94226e31f72c1a91d15e8be0fc 100644 --- a/server_test.go +++ b/server_test.go @@ -26,11 +26,11 @@ var ( Results: []QueryParam{ { Name: "resource_id", - Type: "string", + Type: TypeString, }, { Name: "usage", - Type: "int", + Type: TypeInt, }, }, } @@ -39,11 +39,11 @@ var ( Results: []QueryParam{ { Name: "timestamp", - Type: "timestamp", + Type: TypeTimestamp, }, { Name: "usage", - Type: "int", + Type: TypeInt, }, }, } diff --git a/server_webappdb_test.go b/server_webappdb_test.go index 24400f6e03066ae097d74ab494c71ded45af1cf1..eb2c5690b899ef9bcb003f66a4d5cb004aa022da 100644 --- a/server_webappdb_test.go +++ b/server_webappdb_test.go @@ -13,25 +13,25 @@ var ( SELECT resource_id, app_key, - json_extract(value_json, '$.name') as name, + json_extract(value_json, '$.appname') as appname, json_extract(value_json, '$.version') as version, - json_extract(value_json, '$.safe_version') as version, + json_extract(value_json, '$.safeversion') as safeversion, json_extract(value_json, '$.state') as state, json_extract(value_json, '$.vulninfo') as vulninfo FROM latest WHERE type = 'webapp' AND - name = :app + appname = :app `, Results: []QueryParam{ - {Name: "resource_id", Type: "string"}, - {Name: "app_key", Type: "string"}, - {Name: "name", Type: "string"}, - {Name: "version", Type: "string"}, - {Name: "safe_version", Type: "string"}, - {Name: "state", Type: "string"}, - {Name: "vulninfo", Type: "string"}, + {Name: "resource_id", Type: TypeString}, + {Name: "app_key", Type: TypeString}, + {Name: "appname", Type: TypeString}, + {Name: "version", Type: TypeString}, + {Name: "safeversion", Type: TypeString}, + {Name: "state", Type: TypeString}, + {Name: "vulninfo", Type: TypeString}, }, } @@ -39,18 +39,18 @@ WHERE SQL: ` SELECT COUNT(*) AS c, - json_extract(value_json, '$.name') as name, + json_extract(value_json, '$.appname') as appname, json_extract(value_json, '$.version') as version FROM latest WHERE type = 'webapp' - AND name = :app + AND appname = :app ORDER BY c DESC `, Results: []QueryParam{ - {Name: "count", Type: "int"}, - {Name: "name", Type: "string"}, - {Name: "version", Type: "string"}, + {Name: "count", Type: TypeInt}, + {Name: "appname", Type: TypeString}, + {Name: "version", Type: TypeString}, }, } ) @@ -63,24 +63,23 @@ func (c *testCtx) loadWebappTestData(t testing.TB) { Entries: []auxpb.LoadEntry{ { ResourceID: "website1", - AppKey: "path/1", + AppKey: "/path/1", ValueJSON: ` -{"name": "Wordpress", "version": "4.5.1", "safe_version": "5.6", - "state": "vulnerable", "vulninfo": "FOO BAR PHP SHELL"}`, +{"appname": "Wordpress", "version": "4.5.1", "safeversion": "5.6", + "state": "vulnerable", "vulninfo": "CVE-2019-17672"}`, }, { ResourceID: "website1", - AppKey: "path/2", + AppKey: "/path/2", ValueJSON: ` -{"name": "Wordpress-plugin", "version": "0.1", "safe_version": "0.2", - "state": "vulnerable", "vulninfo": "FOO BAR PHP SHELL"}`, +{"appname": "Wordpress-plugin", "version": "0.1", "state": "ok"}`, }, { ResourceID: "website2", - AppKey: "path/3", + AppKey: "/path/3", ValueJSON: ` -{"name": "Wordpress", "version": "4.5.1", "safe_version": "5.6", - "state": "vulnerable", "vulninfo": "FOO BAR PHP SHELL"}`, +{"appname": "Wordpress", "version": "4.5.1", "safeversion": "5.6", + "state": "vulnerable", "vulninfo": "CVE-2019-17672"}`, }, }, }, nil) @@ -113,6 +112,11 @@ func TestWebapp_Get(t *testing.T) { if len(resp.Results) != 2 { t.Fatalf("expected 2 results, got %d: %v", len(resp.Results), resp.Results) } + for _, entry := range resp.Results { + if entry.Key.AppKey != "/path/1" && entry.Key.AppKey != "/path/2" { + t.Errorf("invalid app_key in result: %s", entry.Key.AppKey) + } + } } func TestWebapp_Query_Find(t *testing.T) { @@ -137,6 +141,12 @@ func TestWebapp_Query_Find(t *testing.T) { if resp.Results[0][3].(string) != "4.5.1" { t.Fatalf("bad result: %v", resp.Results[0]) } + for _, r := range resp.Results { + appKey := r[1].(string) + if appKey != "/path/1" && appKey != "/path/3" { + t.Errorf("invalid app_key in result: %s", appKey) + } + } } func TestWebapp_Query_Count(t *testing.T) {