mirror of
https://github.com/lukaszraczylo/graphql-monitoring-proxy.git
synced 2026-10-21 06:37:21 +00:00
fix: recover introspection block across named fragment spreads; dedup cache hash; fix cache Set counter race
- graphql.go: parseGraphQLQuery now indexes top-level FragmentDefinition nodes
and checkSelections resolves FragmentSpread by name, closing an
introspection-blocking bypass (`{ ...F }` where F spreads __schema was
allowed because the spread carried no selection set and definitions loop
skipped fragments).
- proxy.go/server.go: handleCaching stores the computed cache hash on the
request context; performProxyRequest reuses it instead of recomputing a
full MD5 of the request body per proxied request (fallback preserved for
direct callers).
- cache/memory: Set serializes the exists-check + counter update + store
with the embedded mutex so concurrent Sets of the same new key can't
double-increment entryCount/memoryUsage; regression test added.
Verification: go build, go vet, gofmt clean; full go test ./... and
go test -race ./... green (9 packages); golangci-lint 0 issues; trufflehog clean.
This commit is contained in:
+31
-1
@@ -476,6 +476,30 @@ func (suite *Tests) Test_DeepIntrospectionQueries() {
|
||||
allowed: []string{},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "named fragment spreading introspection is blocked",
|
||||
query: "query Q { ...IntroFields } fragment IntroFields on Query { __schema { queryType { name } } }",
|
||||
allowed: []string{},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "named fragment spreading schema with allowlist is blocked",
|
||||
query: "query Q { ...IntroFields } fragment IntroFields on Query { __schema { queryType { name } } }",
|
||||
allowed: []string{"__typename"},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "named fragment without introspection is allowed",
|
||||
query: "query Q { ...Fields } fragment Fields on User { id name }",
|
||||
allowed: []string{},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "nested named fragment chain with introspection is blocked",
|
||||
query: "query Q { ...A } fragment A on Query { ...B } fragment B on Query { __schema { queryType { name } } }",
|
||||
allowed: []string{},
|
||||
expected: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
@@ -592,9 +616,15 @@ func TestIntrospectionQueryHandling(t *testing.T) {
|
||||
|
||||
// Check selections
|
||||
var blocked bool
|
||||
fragments := make(map[string]*ast.FragmentDefinition)
|
||||
for _, def := range p.Definitions {
|
||||
if fd, ok := def.(*ast.FragmentDefinition); ok && fd.Name != nil {
|
||||
fragments[fd.Name.Value] = fd
|
||||
}
|
||||
}
|
||||
for _, def := range p.Definitions {
|
||||
if op, ok := def.(*ast.OperationDefinition); ok {
|
||||
blocked = checkSelections(ctx, op.GetSelectionSet().Selections)
|
||||
blocked = checkSelections(ctx, op.GetSelectionSet().Selections, fragments)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user