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

LaunchDarkly Token Analyzer #3948

Merged
Merged
Changes from 1 commit
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
36e64af
initial commit
kashifkhan0771 Feb 21, 2025
1c92298
initial commit
kashifkhan0771 Feb 24, 2025
f143fa8
initial commit
kashifkhan0771 Feb 25, 2025
b840782
inital commit
kashifkhan0771 Feb 26, 2025
aab2c0a
initial working structure for launchdarkly analyzer
kashifkhan0771 Feb 27, 2025
9806026
added more apis
kashifkhan0771 Mar 4, 2025
cc2ac00
Merge branch 'main' into feat/oss-95-launchdarkly-analyzer
kashifkhan0771 Mar 4, 2025
8ff00ae
added test cases
kashifkhan0771 Mar 4, 2025
745868e
removed imposter print statement
kashifkhan0771 Mar 4, 2025
6d3b8fa
updated some code
kashifkhan0771 Mar 4, 2025
6902b03
Merge branch 'main' into feat/oss-95-launchdarkly-analyzer
kashifkhan0771 Mar 5, 2025
746e4fb
removed id from printResources
kashifkhan0771 Mar 5, 2025
8452bdd
added nabeel suggestion and set analysis info
kashifkhan0771 Mar 5, 2025
d445b25
Merge branch 'main' into feat/oss-95-launchdarkly-analyzer
kashifkhan0771 Mar 5, 2025
25356be
Merge branch 'main' into feat/oss-95-launchdarkly-analyzer
kashifkhan0771 Mar 6, 2025
4235470
Merge branch 'main' into feat/oss-95-launchdarkly-analyzer
kashifkhan0771 Mar 6, 2025
143947a
Merge branch 'main' into feat/oss-95-launchdarkly-analyzer
kashifkhan0771 Mar 7, 2025
8a0561a
resolved ahrav comments
kashifkhan0771 Mar 7, 2025
deccdd9
Merge branch 'main' into feat/oss-95-launchdarkly-analyzer
kashifkhan0771 Mar 7, 2025
8d6265f
Merge branch 'main' into feat/oss-95-launchdarkly-analyzer
kashifkhan0771 Mar 10, 2025
08cdc2f
resolved ahrav comments
kashifkhan0771 Mar 10, 2025
47cdd0c
implemented ahrav's suggestion 🔥
kashifkhan0771 Mar 10, 2025
1c61fce
resolved linter error
kashifkhan0771 Mar 10, 2025
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
Prev Previous commit
Next Next commit
added test cases
  • Loading branch information
kashifkhan0771 committed Mar 4, 2025
commit 8ff00aecd42ef4ab97ed066d7714636902123a53
10 changes: 6 additions & 4 deletions pkg/analyzer/analyzers/launchdarkly/launchdarkly.go
Original file line number Diff line number Diff line change
@@ -94,13 +94,15 @@ func secretInfoToAnalyzerResult(info *SecretInfo) *analyzers.AnalyzerResult {
// extract information from resource to create bindings and append to result bindings
for _, resource := range info.Resources {
binding := analyzers.Binding{
Resource: *secretInforesourceToAnalyzerResource(resource),
Resource: *secretInfoResourceToAnalyzerResource(resource),
Permission: analyzers.Permission{
Value: getPermissionType(info.User.Token),
},
}

binding.Resource.Parent = secretInforesourceToAnalyzerResource(*resource.ParentResource)
if resource.ParentResource != nil {
binding.Resource.Parent = secretInfoResourceToAnalyzerResource(*resource.ParentResource)
}

result.Bindings = append(result.Bindings, binding)

@@ -109,8 +111,8 @@ func secretInfoToAnalyzerResult(info *SecretInfo) *analyzers.AnalyzerResult {
return &result
}

// secretInforesourceToAnalyzerResource translate secret info resource to analyzer resource for binding
func secretInforesourceToAnalyzerResource(resource Resource) *analyzers.Resource {
// secretInfoResourceToAnalyzerResource translate secret info resource to analyzer resource for binding
func secretInfoResourceToAnalyzerResource(resource Resource) *analyzers.Resource {
analyzerRes := analyzers.Resource{
FullyQualifiedName: resource.ID,
Name: resource.Name,
105 changes: 105 additions & 0 deletions pkg/analyzer/analyzers/launchdarkly/launchdarkly_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package launchdarkly

import (
_ "embed"
"encoding/json"
"fmt"
"sort"
"testing"
"time"

"github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/analyzers"
"github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/config"
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
"github.com/trufflesecurity/trufflehog/v3/pkg/context"
)

//go:embed result_output.json
var expectedOutput []byte

func TestAnalyzer_Analyze(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), time.Minute*5)
defer cancel()
testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors3")
if err != nil {
t.Fatalf("could not get test secrets from GCP: %s", err)
}

key := testSecrets.MustGetField("LAUNCHDARKLY_TOKEN")

tests := []struct {
name string
key string
want []byte // JSON string
wantErr bool
}{
{
name: "valid LauncgDarkly token",
key: key,
want: expectedOutput,
wantErr: false,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
a := Analyzer{Cfg: &config.Config{}}
got, err := a.Analyze(ctx, map[string]string{"key": tt.key})
if (err != nil) != tt.wantErr {
t.Errorf("Analyzer.Analyze() error = %v, wantErr %v", err, tt.wantErr)
return
}

// Bindings need to be in the same order to be comparable
sortBindings(got.Bindings)

// Marshal the actual result to JSON
gotJSON, err := json.Marshal(got)
if err != nil {
t.Fatalf("could not marshal got to JSON: %s", err)
}

fmt.Println(string(gotJSON))

// Parse the expected JSON string
var wantObj analyzers.AnalyzerResult
if err := json.Unmarshal([]byte(tt.want), &wantObj); err != nil {
t.Fatalf("could not unmarshal want JSON string: %s", err)
}

// Bindings need to be in the same order to be comparable
sortBindings(wantObj.Bindings)

// Marshal the expected result to JSON (to normalize)
wantJSON, err := json.Marshal(wantObj)
if err != nil {
t.Fatalf("could not marshal want to JSON: %s", err)
}

// Compare the JSON strings
if string(gotJSON) != string(wantJSON) {
// Pretty-print both JSON strings for easier comparison
var gotIndented, wantIndented []byte
gotIndented, err = json.MarshalIndent(got, "", " ")
if err != nil {
t.Fatalf("could not marshal got to indented JSON: %s", err)
}
wantIndented, err = json.MarshalIndent(wantObj, "", " ")
if err != nil {
t.Fatalf("could not marshal want to indented JSON: %s", err)
}
t.Errorf("Analyzer.Analyze() = %s, want %s", gotIndented, wantIndented)
}
})
}
}

// Helper function to sort bindings
func sortBindings(bindings []analyzers.Binding) {
sort.SliceStable(bindings, func(i, j int) bool {
if bindings[i].Resource.Name == bindings[j].Resource.Name {
return bindings[i].Permission.Value < bindings[j].Permission.Value
}
return bindings[i].Resource.Name < bindings[j].Resource.Name
})
}
7 changes: 1 addition & 6 deletions pkg/analyzer/analyzers/launchdarkly/models.go
Original file line number Diff line number Diff line change
@@ -10,7 +10,7 @@ var (
repositoryKey = "Repository"
projectKey = "Project"
environmentKey = "Environment"
experimentKey = "Expirement"
experimentKey = "Experiment"
holdoutsKey = "Holdout"
membersKey = "Member"
destinationsKey = "Destination"
@@ -120,11 +120,6 @@ func (t Token) hasInlineRole() bool {
return len(t.InlineRole) > 0
}

// isAllowed check if policy allow the statement
func (p Policy) isAllowed() bool {
return p.Effect == "allow"
}

// setParentResource set parent resource for a resource
func (r Resource) setParentResource(resource, parent *Resource) {
resource.ParentResource = parent
96 changes: 96 additions & 0 deletions pkg/analyzer/analyzers/launchdarkly/result_output.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
{
"AnalyzerType": 6,
"Bindings": [
{
"Resource": {
"Name": "Production",
"FullyQualifiedName": "launchdarkly/default/env/61543c5956be602355624871",
"Type": "Environment",
"Metadata": {
"key": "production"
},
"Parent": {
"Name": "secretscanner",
"FullyQualifiedName": "launchdarkly/proj/61543c5956be60235562486e",
"Type": "Project",
"Metadata": {
"key": "default"
},
"Parent": null
}
},
"Permission": {
"Value": "admin",
"Parent": null
}
},
{
"Resource": {
"Name": "Roxanne Tampus",
"FullyQualifiedName": "launchdarkly/member/61543c5956be60235562486f",
"Type": "Member",
"Metadata": {},
"Parent": null
},
"Permission": {
"Value": "admin",
"Parent": null
}
},
{
"Resource": {
"Name": "Test",
"FullyQualifiedName": "launchdarkly/default/env/61543c5956be602355624870",
"Type": "Environment",
"Metadata": {
"key": "test"
},
"Parent": {
"Name": "secretscanner",
"FullyQualifiedName": "launchdarkly/proj/61543c5956be60235562486e",
"Type": "Project",
"Metadata": {
"key": "default"
},
"Parent": null
}
},
"Permission": {
"Value": "admin",
"Parent": null
}
},
{
"Resource": {
"Name": "secretscanner",
"FullyQualifiedName": "launchdarkly/proj/61543c5956be60235562486e",
"Type": "Project",
"Metadata": {
"key": "default"
},
"Parent": null
},
"Permission": {
"Value": "admin",
"Parent": null
}
},
{
"Resource": {
"Name": "secretscanner",
"FullyQualifiedName": "launchdarkly/proj/default/flag/secretscanner",
"Type": "Feature Flags",
"Metadata": {
"Kind": "boolean"
},
"Parent": null
},
"Permission": {
"Value": "admin",
"Parent": null
}
}
],
"UnboundedResources": null,
"Metadata": {}
}
Loading
Oops, something went wrong.