-
Notifications
You must be signed in to change notification settings - Fork 5
dawgs Version 2 #10
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
base: main
Are you sure you want to change the base?
dawgs Version 2 #10
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,13 +6,13 @@ import ( | |
|
|
||
| type threadSafeDuplex[T uint32 | uint64] struct { | ||
| provider Duplex[T] | ||
| lock *sync.Mutex | ||
| lock *sync.RWMutex | ||
| } | ||
|
|
||
| func ThreadSafeDuplex[T uint32 | uint64](provider Duplex[T]) Duplex[T] { | ||
| return threadSafeDuplex[T]{ | ||
| provider: provider, | ||
| lock: &sync.Mutex{}, | ||
| lock: &sync.RWMutex{}, | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -66,56 +66,60 @@ func (s threadSafeDuplex[T]) Or(other Provider[T]) { | |
| } | ||
|
|
||
| func (s threadSafeDuplex[T]) Cardinality() uint64 { | ||
| s.lock.Lock() | ||
| defer s.lock.Unlock() | ||
| s.lock.RLock() | ||
| defer s.lock.RUnlock() | ||
|
|
||
| return s.provider.Cardinality() | ||
| } | ||
|
|
||
| func (s threadSafeDuplex[T]) Slice() []T { | ||
| s.lock.Lock() | ||
| defer s.lock.Unlock() | ||
| s.lock.RLock() | ||
| defer s.lock.RUnlock() | ||
|
|
||
| return s.provider.Slice() | ||
| } | ||
|
|
||
| func (s threadSafeDuplex[T]) Contains(value T) bool { | ||
| s.lock.Lock() | ||
| defer s.lock.Unlock() | ||
| s.lock.RLock() | ||
| defer s.lock.RUnlock() | ||
|
|
||
| return s.provider.Contains(value) | ||
| } | ||
|
|
||
| func (s threadSafeDuplex[T]) Each(delegate func(value T) bool) { | ||
| s.lock.Lock() | ||
| defer s.lock.Unlock() | ||
| s.lock.RLock() | ||
| defer s.lock.RUnlock() | ||
|
|
||
| s.provider.Each(delegate) | ||
| } | ||
|
|
||
| func (s threadSafeDuplex[T]) CheckedAdd(value T) bool { | ||
| if s.Contains(value) { | ||
| return false | ||
| } | ||
|
|
||
| s.lock.Lock() | ||
| defer s.lock.Unlock() | ||
|
|
||
| return s.provider.CheckedAdd(value) | ||
| } | ||
|
Comment on lines
96
to
105
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Critical: TOCTOU race condition in CheckedAdd. The pre-check at lines 97-99 creates a time-of-check to time-of-use race condition. Between releasing Scenario:
Apply this diff to fix using the double-check pattern: func (s threadSafeDuplex[T]) CheckedAdd(value T) bool {
- if s.Contains(value) {
+ s.lock.RLock()
+ alreadyExists := s.provider.Contains(value)
+ s.lock.RUnlock()
+
+ if alreadyExists {
return false
}
s.lock.Lock()
defer s.lock.Unlock()
-
+
+ // Double-check after acquiring write lock
+ if s.provider.Contains(value) {
+ return false
+ }
+
return s.provider.CheckedAdd(value)
}Alternatively, if func (s threadSafeDuplex[T]) CheckedAdd(value T) bool {
- if s.Contains(value) {
- return false
- }
-
s.lock.Lock()
defer s.lock.Unlock()
return s.provider.CheckedAdd(value)
}🤖 Prompt for AI Agents |
||
|
|
||
| func (s threadSafeDuplex[T]) Clone() Duplex[T] { | ||
| s.lock.Lock() | ||
| defer s.lock.Unlock() | ||
| s.lock.RLock() | ||
| defer s.lock.RUnlock() | ||
|
|
||
| return ThreadSafeDuplex(s.provider.Clone()) | ||
| } | ||
|
|
||
| type threadSafeSimplex[T uint32 | uint64] struct { | ||
| provider Simplex[T] | ||
| lock *sync.Mutex | ||
| lock *sync.RWMutex | ||
| } | ||
|
|
||
| func ThreadSafeSimplex[T uint32 | uint64](provider Simplex[T]) Simplex[T] { | ||
| return threadSafeSimplex[T]{ | ||
| provider: provider, | ||
| lock: &sync.Mutex{}, | ||
| lock: &sync.RWMutex{}, | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -141,15 +145,15 @@ func (s threadSafeSimplex[T]) Or(other Provider[T]) { | |
| } | ||
|
|
||
| func (s threadSafeSimplex[T]) Cardinality() uint64 { | ||
| s.lock.Lock() | ||
| defer s.lock.Unlock() | ||
| s.lock.RLock() | ||
| defer s.lock.RUnlock() | ||
|
|
||
| return s.provider.Cardinality() | ||
| } | ||
|
|
||
| func (s threadSafeSimplex[T]) Clone() Simplex[T] { | ||
| s.lock.Lock() | ||
| defer s.lock.Unlock() | ||
| s.lock.RLock() | ||
| defer s.lock.RUnlock() | ||
|
|
||
| return ThreadSafeSimplex(s.provider.Clone()) | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,120 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| package main | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "io" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "os" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "strconv" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "github.com/go-echarts/go-echarts/v2/charts" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "github.com/go-echarts/go-echarts/v2/components" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "github.com/go-echarts/go-echarts/v2/opts" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "github.com/specterops/dawgs/container" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "github.com/specterops/dawgs/graph" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var graphNodes = []opts.GraphNode{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {Name: "Node1"}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {Name: "Node2"}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {Name: "Node3"}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {Name: "Node4"}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {Name: "Node5"}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {Name: "Node6"}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {Name: "Node7"}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {Name: "Node8"}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func genLinks() []opts.GraphLink { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| links := make([]opts.GraphLink, 0) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for i := 0; i < len(graphNodes); i++ { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for j := 0; j < len(graphNodes); j++ { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| links = append(links, opts.GraphLink{Source: graphNodes[i].Name, Target: graphNodes[j].Name}) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return links | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func graphBase() *charts.Graph { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| graph := charts.NewGraph() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| graph.SetGlobalOptions( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| charts.WithTitleOpts(opts.Title{Title: "basic graph example"}), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| graph.AddSeries("graph", graphNodes, genLinks(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| charts.WithGraphChartOpts( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| opts.GraphChart{Force: &opts.GraphForce{Repulsion: 8000}}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return graph | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func graphCircle() *charts.Graph { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| graph := charts.NewGraph() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| graph.SetGlobalOptions( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| charts.WithTitleOpts(opts.Title{Title: "Circular layout"}), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| graph.AddSeries("graph", graphNodes, genLinks()). | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SetSeriesOptions( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| charts.WithGraphChartOpts( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| opts.GraphChart{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Force: &opts.GraphForce{Repulsion: 8000}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Layout: "circular", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| charts.WithLabelOpts(opts.Label{Show: opts.Bool(true), Position: "right"}), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return graph | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+36
to
+65
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Check if graphBase or graphCircle are used elsewhere in the codebase
rg -n '\b(graphBase|graphCircle)\b' --type=goRepository: SpecterOps/DAWGS Length of output: 167 Remove unused functions These functions are defined but never called anywhere in the codebase. If they're needed for future work, they should be re-added with clear context rather than kept as dead code. 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func graphDigraph(digraph container.DirectedGraph, direction graph.Direction) *charts.Graph { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| graph := charts.NewGraph() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| graph.SetGlobalOptions( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| charts.WithTitleOpts(opts.Title{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Title: "demo", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| })) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| nodes []opts.GraphNode | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| links []opts.GraphLink | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| digraph.EachNode(func(node uint64) bool { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sourceNode := strconv.FormatUint(node, 10) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| nodes = append(nodes, opts.GraphNode{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Name: sourceNode, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| digraph.EachAdjacentNode(node, direction, func(adjacent uint64) bool { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| links = append(links, opts.GraphLink{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Source: sourceNode, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Target: strconv.FormatUint(adjacent, 10), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return true | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return true | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| graph.AddSeries("graph", nodes, links). | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SetSeriesOptions( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| charts.WithGraphChartOpts(opts.GraphChart{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Force: &opts.GraphForce{Repulsion: 8000}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return graph | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func doTheGraph(digraph container.DirectedGraph, direction graph.Direction) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| page := components.NewPage() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| page.AddCharts( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| graphDigraph(digraph, direction), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| f, err := os.Create("graph.html") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| panic(err) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| page.Render(io.MultiWriter(f)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| f.Close() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+107
to
+119
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Resource leak and missing error handling in
func doTheGraph(digraph container.DirectedGraph, direction graph.Direction) {
page := components.NewPage()
page.AddCharts(
graphDigraph(digraph, direction),
)
f, err := os.Create("graph.html")
if err != nil {
panic(err)
-
}
- page.Render(io.MultiWriter(f))
- f.Close()
+ defer f.Close()
+
+ if err := page.Render(io.MultiWriter(f)); err != nil {
+ panic(err)
+ }
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| package main | ||
|
|
||
| import ( | ||
| "context" | ||
| "fmt" | ||
|
|
||
| "github.com/specterops/dawgs" | ||
| "github.com/specterops/dawgs/container" | ||
| "github.com/specterops/dawgs/database/pg" | ||
| "github.com/specterops/dawgs/graph" | ||
| "github.com/specterops/dawgs/query" | ||
| ) | ||
|
|
||
| func main() { | ||
| ctx, done := context.WithCancel(context.Background()) | ||
| defer done() | ||
|
|
||
| dbInst, err := dawgs.Open(ctx, pg.DriverName, dawgs.Config{ | ||
| ConnectionString: "user=postgres dbname=bhe password=bhe4eva host=localhost", | ||
| }) | ||
|
Comment on lines
+18
to
+20
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove hardcoded database credentials. The connection string contains hardcoded credentials ( Apply this diff to use environment variables: + import "os"
+
- dbInst, err := dawgs.Open(ctx, pg.DriverName, dawgs.Config{
- ConnectionString: "user=postgres dbname=bhe password=bhe4eva host=localhost",
- })
+ connStr := os.Getenv("DATABASE_URL")
+ if connStr == "" {
+ connStr = "user=postgres dbname=bhe host=localhost" // fallback without password
+ }
+
+ dbInst, err := dawgs.Open(ctx, pg.DriverName, dawgs.Config{
+ ConnectionString: connStr,
+ })
🤖 Prompt for AI Agents |
||
|
|
||
| if err != nil { | ||
| panic(err) | ||
| } | ||
|
|
||
| metaKinds := graph.Kinds{ | ||
| graph.StringKind("Meta"), | ||
| graph.StringKind("MetaDetail"), | ||
| } | ||
|
|
||
| kindFilter := query.And( | ||
| query.Not(query.Start().Kinds().HasOneOf(metaKinds)), | ||
| query.Not(query.End().Kinds().HasOneOf(metaKinds)), | ||
| ) | ||
|
|
||
| if digraph, err := container.FetchTSDB(ctx, dbInst, kindFilter); err != nil { | ||
| panic(err) | ||
| } else { | ||
| fmt.Printf("Loaded %d nodes\n", digraph.Triplestore.NumNodes()) | ||
|
|
||
| // algo.CalculateKatzCentrality(digraph, 0.01, 1, 0.01, 1000) | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Declare the new command targets as phony.
If a file named
update,mod_update, ormod_tidyexists,makewill skip the recipes. Add them to.PHONY(and optionally existing command targets).✅ Proposed change
Also applies to: 23-27
🧰 Tools
🪛 checkmake (0.2.2)
[warning] 10-10: Target "update" should be declared PHONY.
(phonydeclared)
🤖 Prompt for AI Agents