Skip to content

Commit 95a2a2a

Browse files
Groq Analyzer (#3962)
* added groq analyzer * print resource if present
1 parent 3259c4b commit 95a2a2a

File tree

10 files changed

+493
-1
lines changed

10 files changed

+493
-1
lines changed

pkg/analyzer/analyzers/analyzers.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ const (
8989
AnalyzerTypePlanetScale
9090
AnalyzerTypeAirtableOAuth
9191
AnalyzerTypeAirtablePat
92+
AnalyzerTypeGroq
9293
// Add new items here with AnalyzerType prefix
9394
)
9495

@@ -124,6 +125,7 @@ var analyzerTypeStrings = map[AnalyzerType]string{
124125
AnalyzerTypePlanetScale: "PlanetScale",
125126
AnalyzerTypeAirtableOAuth: "AirtableOAuth",
126127
AnalyzerTypeAirtablePat: "AirtablePat",
128+
AnalyzerTypeGroq: "Groq",
127129
// Add new mappings here
128130
}
129131

pkg/analyzer/analyzers/anthropic/anthropic.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
//go:generate generate_permissions permissions.yaml permissions.go anthropic
12
package anthropic
23

34
import (

pkg/analyzer/analyzers/dockerhub/dockerhub.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//go:generate generate_permissions permissions.yaml permissions.go elevenlabs
1+
//go:generate generate_permissions permissions.yaml permissions.go dockerhub
22
package dockerhub
33

44
import (

pkg/analyzer/analyzers/groq/groq.go

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
//go:generate generate_permissions permissions.yaml permissions.go groq
2+
package groq
3+
4+
import (
5+
"errors"
6+
"os"
7+
8+
"github.com/fatih/color"
9+
"github.com/jedib0t/go-pretty/v6/table"
10+
11+
"github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/analyzers"
12+
"github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/config"
13+
"github.com/trufflesecurity/trufflehog/v3/pkg/context"
14+
)
15+
16+
var _ analyzers.Analyzer = (*Analyzer)(nil)
17+
18+
type Analyzer struct {
19+
Cfg *config.Config
20+
}
21+
22+
// SecretInfo hold the information about the anthropic key
23+
type SecretInfo struct {
24+
Valid bool
25+
Reference string
26+
GroqResources []GroqResource
27+
Permissions []string
28+
Misc map[string]string
29+
}
30+
31+
// GroqResource is a single groq resource which can be accessed with groq api key
32+
type GroqResource struct {
33+
ID string
34+
Name string
35+
Type string
36+
Permission string
37+
Metadata map[string]string
38+
}
39+
40+
// appendGroqResource append the single groq resource to secretinfo groqresources list
41+
func (s *SecretInfo) appendGroqResource(resource GroqResource) {
42+
s.GroqResources = append(s.GroqResources, resource)
43+
}
44+
45+
// updateMetadata safely update the metadata of the groq resource
46+
func (g GroqResource) updateMetadata(key, value string) {
47+
if g.Metadata == nil {
48+
g.Metadata = map[string]string{}
49+
}
50+
51+
g.Metadata[key] = value
52+
}
53+
54+
func (a Analyzer) Type() analyzers.AnalyzerType {
55+
return analyzers.AnalyzerTypeGroq
56+
}
57+
58+
func (a Analyzer) Analyze(_ context.Context, credInfo map[string]string) (*analyzers.AnalyzerResult, error) {
59+
key, exist := credInfo["key"]
60+
if !exist {
61+
return nil, errors.New("key not found in credentials info")
62+
}
63+
64+
secretInfo, err := AnalyzePermissions(a.Cfg, key)
65+
if err != nil {
66+
return nil, err
67+
}
68+
69+
return secretInfoToAnalyzerResult(secretInfo), nil
70+
}
71+
72+
func AnalyzeAndPrintPermissions(cfg *config.Config, key string) {
73+
info, err := AnalyzePermissions(cfg, key)
74+
if err != nil {
75+
// just print the error in cli and continue as a partial success
76+
color.Red("[x] Invalid Anthropic API key\n")
77+
color.Red("[x] Error : %s", err.Error())
78+
return
79+
}
80+
81+
if info == nil {
82+
color.Red("[x] Error : %s", "No information found")
83+
return
84+
}
85+
86+
color.Green("[i] Valid Anthropic API key\n")
87+
color.Yellow("\n[i] Permission: Full Access\n")
88+
89+
if len(info.GroqResources) > 0 {
90+
printGroqResources(info.GroqResources)
91+
}
92+
93+
color.Yellow("\n[!] Expires: Never")
94+
}
95+
96+
func AnalyzePermissions(cfg *config.Config, apiKey string) (*SecretInfo, error) {
97+
// create a HTTP client
98+
client := analyzers.NewAnalyzeClient(cfg)
99+
100+
var secretInfo = &SecretInfo{Valid: true}
101+
102+
if err := captureBatches(client, apiKey, secretInfo); err != nil {
103+
return nil, err
104+
}
105+
106+
if err := captureFiles(client, apiKey, secretInfo); err != nil {
107+
return nil, err
108+
}
109+
110+
return secretInfo, nil
111+
}
112+
113+
// secretInfoToAnalyzerResult translate secret info to Analyzer Result
114+
func secretInfoToAnalyzerResult(info *SecretInfo) *analyzers.AnalyzerResult {
115+
if info == nil {
116+
return nil
117+
}
118+
119+
result := analyzers.AnalyzerResult{
120+
AnalyzerType: analyzers.AnalyzerAnthropic,
121+
Metadata: map[string]any{"Valid_Key": info.Valid},
122+
Bindings: make([]analyzers.Binding, len(info.GroqResources)),
123+
}
124+
125+
// extract information to create bindings and append to result bindings
126+
for _, groqResource := range info.GroqResources {
127+
binding := analyzers.Binding{
128+
Resource: analyzers.Resource{
129+
Name: groqResource.Name,
130+
FullyQualifiedName: groqResource.ID,
131+
Type: groqResource.Type,
132+
Metadata: map[string]any{},
133+
},
134+
Permission: analyzers.Permission{
135+
Value: groqResource.Permission,
136+
},
137+
}
138+
139+
for key, value := range groqResource.Metadata {
140+
binding.Resource.Metadata[key] = value
141+
}
142+
143+
result.Bindings = append(result.Bindings, binding)
144+
}
145+
146+
return &result
147+
}
148+
149+
func printGroqResources(resources []GroqResource) {
150+
color.Green("\n[i] Resources:")
151+
t := table.NewWriter()
152+
t.SetOutputMirror(os.Stdout)
153+
t.AppendHeader(table.Row{"Name", "Type"})
154+
for _, resource := range resources {
155+
t.AppendRow(table.Row{color.GreenString(resource.Name), color.GreenString(resource.Type)})
156+
}
157+
t.Render()
158+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package groq
2+
3+
import (
4+
_ "embed"
5+
"encoding/json"
6+
"fmt"
7+
"testing"
8+
"time"
9+
10+
"github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/config"
11+
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
12+
"github.com/trufflesecurity/trufflehog/v3/pkg/context"
13+
)
14+
15+
func TestAnalyzer_Analyze(t *testing.T) {
16+
ctx, cancel := context.WithTimeout(context.Background(), time.Minute*5)
17+
defer cancel()
18+
testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors5")
19+
if err != nil {
20+
t.Fatalf("could not get test secrets from GCP: %s", err)
21+
}
22+
23+
apiKey := testSecrets.MustGetField("GROQ")
24+
25+
tests := []struct {
26+
name string
27+
apiKey string
28+
want string
29+
wantErr bool
30+
}{
31+
{
32+
name: "valid dockerhub credentials",
33+
apiKey: apiKey,
34+
want: `{"AnalyzerType":2,"Bindings":[],"UnboundedResources":null,"Metadata":{"Valid_Key":true}}`,
35+
wantErr: false,
36+
},
37+
}
38+
39+
for _, tt := range tests {
40+
t.Run(tt.name, func(t *testing.T) {
41+
a := Analyzer{Cfg: &config.Config{}}
42+
got, err := a.Analyze(ctx, map[string]string{"key": tt.apiKey})
43+
if (err != nil) != tt.wantErr {
44+
t.Errorf("Analyzer.Analyze() error = %v, wantErr %v", err, tt.wantErr)
45+
return
46+
}
47+
48+
// marshal the actual result to JSON
49+
gotJSON, err := json.Marshal(got)
50+
if err != nil {
51+
t.Fatalf("could not marshal got to JSON: %s", err)
52+
}
53+
54+
fmt.Println(string(gotJSON))
55+
56+
// compare the JSON strings
57+
if string(gotJSON) != string(tt.want) {
58+
// pretty-print both JSON strings for easier comparison
59+
var gotIndented, wantIndented []byte
60+
gotIndented, err = json.MarshalIndent(got, "", " ")
61+
if err != nil {
62+
t.Fatalf("could not marshal got to indented JSON: %s", err)
63+
}
64+
wantIndented, err = json.MarshalIndent(tt.want, "", " ")
65+
if err != nil {
66+
t.Fatalf("could not marshal want to indented JSON: %s", err)
67+
}
68+
t.Errorf("Analyzer.Analyze() = %s, want %s", gotIndented, wantIndented)
69+
}
70+
})
71+
}
72+
}

pkg/analyzer/analyzers/groq/permissions.go

Lines changed: 61 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
permissions:
2+
- full_access # by default groq api key has full access

0 commit comments

Comments
 (0)