mirror of
https://github.com/DeBrosOfficial/network.git
synced 2025-10-06 17:49:07 +00:00
Improve gateway auth middleware to use internal auth context
Enforce GATEWAY_API_KEY in Makefile E2E test target Fix gateway E2E test payload reading to use io.ReadAll Remove deprecated multi-node test targets and cleanup Makefile comments
This commit is contained in:
parent
895f1d5dff
commit
03b3b38967
37
Makefile
37
Makefile
@ -5,9 +5,15 @@ test:
|
|||||||
@echo Running tests...
|
@echo Running tests...
|
||||||
go test -v $(TEST)
|
go test -v $(TEST)
|
||||||
|
|
||||||
|
# Gateway-focused E2E tests assume gateway and nodes are already running
|
||||||
|
# Configure via env:
|
||||||
|
# GATEWAY_BASE_URL (default http://127.0.0.1:8080)
|
||||||
|
# GATEWAY_API_KEY (required for auth-protected routes)
|
||||||
.PHONY: test-e2e
|
.PHONY: test-e2e
|
||||||
test-e2e:
|
test-e2e:
|
||||||
@echo Running E2E tests...
|
@echo "Running gateway E2E tests (HTTP/WS only)..."
|
||||||
|
@echo "Base URL: $${GATEWAY_BASE_URL:-http://127.0.0.1:8080}"
|
||||||
|
@test -n "$$GATEWAY_API_KEY" || (echo "GATEWAY_API_KEY must be set" && exit 1)
|
||||||
go test -v -tags e2e ./e2e
|
go test -v -tags e2e ./e2e
|
||||||
|
|
||||||
# Network - Distributed P2P Database System
|
# Network - Distributed P2P Database System
|
||||||
@ -37,11 +43,6 @@ clean:
|
|||||||
rm -rf data/
|
rm -rf data/
|
||||||
@echo "Clean complete!"
|
@echo "Clean complete!"
|
||||||
|
|
||||||
# Run tests
|
|
||||||
test:
|
|
||||||
@echo "Running tests..."
|
|
||||||
go test -v ./...
|
|
||||||
|
|
||||||
# Run bootstrap node (auto-selects identity and data dir)
|
# Run bootstrap node (auto-selects identity and data dir)
|
||||||
run-node:
|
run-node:
|
||||||
@echo "Starting bootstrap node with config..."
|
@echo "Starting bootstrap node with config..."
|
||||||
@ -151,30 +152,6 @@ dev-setup: deps
|
|||||||
@mkdir -p data/test-bootstrap data/test-node1 data/test-node2
|
@mkdir -p data/test-bootstrap data/test-node1 data/test-node2
|
||||||
@echo "Development setup complete!"
|
@echo "Development setup complete!"
|
||||||
|
|
||||||
# Multi-node testing
|
|
||||||
test-multinode: build
|
|
||||||
@echo "🧪 Starting comprehensive multi-node test..."
|
|
||||||
@chmod +x scripts/test-multinode.sh
|
|
||||||
@./scripts/test-multinode.sh
|
|
||||||
|
|
||||||
test-peer-discovery: build
|
|
||||||
@echo "🔍 Testing peer discovery (requires running nodes)..."
|
|
||||||
@echo "Connected peers:"
|
|
||||||
@./bin/network-cli peers --timeout 10s
|
|
||||||
|
|
||||||
test-replication: build
|
|
||||||
@echo "🔄 Testing data replication (requires running nodes)..."
|
|
||||||
@./bin/network-cli storage put "replication:test:$$(date +%s)" "Test data - $$(date)"
|
|
||||||
@sleep 2
|
|
||||||
@echo "Retrieving replicated data:"
|
|
||||||
@./bin/network-cli storage list replication:test:
|
|
||||||
|
|
||||||
test-consensus: build
|
|
||||||
@echo "🗄️ Testing database consensus (requires running nodes)..."
|
|
||||||
@./bin/network-cli query "CREATE TABLE IF NOT EXISTS consensus_test (id INTEGER PRIMARY KEY, test_data TEXT, timestamp TEXT)"
|
|
||||||
@./bin/network-cli query "INSERT INTO consensus_test (test_data, timestamp) VALUES ('Makefile test', '$$(date)')"
|
|
||||||
@./bin/network-cli query "SELECT * FROM consensus_test ORDER BY id DESC LIMIT 5"
|
|
||||||
|
|
||||||
# Start development cluster (requires multiple terminals)
|
# Start development cluster (requires multiple terminals)
|
||||||
dev-cluster:
|
dev-cluster:
|
||||||
@echo "To start a development cluster, run these commands in separate terminals:"
|
@echo "To start a development cluster, run these commands in separate terminals:"
|
||||||
|
@ -3,11 +3,11 @@
|
|||||||
package e2e
|
package e2e
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
@ -111,10 +111,9 @@ func TestGateway_Storage_PutGetListExistsDelete(t *testing.T) {
|
|||||||
if err != nil { t.Fatalf("get do: %v", err) }
|
if err != nil { t.Fatalf("get do: %v", err) }
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
if resp.StatusCode != http.StatusOK { t.Fatalf("get status: %d", resp.StatusCode) }
|
if resp.StatusCode != http.StatusOK { t.Fatalf("get status: %d", resp.StatusCode) }
|
||||||
got := make([]byte, len(payload))
|
got, _ := io.ReadAll(resp.Body)
|
||||||
n, _ := resp.Body.Read(got)
|
if string(got) != string(payload) {
|
||||||
if n == 0 || string(got[:n]) != string(payload[:n]) {
|
t.Fatalf("payload mismatch: want %q got %q", string(payload), string(got))
|
||||||
t.Fatalf("payload mismatch: want %q got %q", string(payload), string(got[:n]))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"git.debros.io/DeBros/network/pkg/client"
|
||||||
"git.debros.io/DeBros/network/pkg/logging"
|
"git.debros.io/DeBros/network/pkg/logging"
|
||||||
"git.debros.io/DeBros/network/pkg/storage"
|
"git.debros.io/DeBros/network/pkg/storage"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
@ -97,10 +98,11 @@ func (g *Gateway) authMiddleware(next http.Handler) http.Handler {
|
|||||||
|
|
||||||
// Look up API key in DB and derive namespace
|
// Look up API key in DB and derive namespace
|
||||||
db := g.client.Database()
|
db := g.client.Database()
|
||||||
ctx := r.Context()
|
// Use internal auth for DB validation (auth not established yet)
|
||||||
|
internalCtx := client.WithInternalAuth(r.Context())
|
||||||
// Join to namespaces to resolve name in one query
|
// Join to namespaces to resolve name in one query
|
||||||
q := "SELECT namespaces.name FROM api_keys JOIN namespaces ON api_keys.namespace_id = namespaces.id WHERE api_keys.key = ? LIMIT 1"
|
q := "SELECT namespaces.name FROM api_keys JOIN namespaces ON api_keys.namespace_id = namespaces.id WHERE api_keys.key = ? LIMIT 1"
|
||||||
res, err := db.Query(ctx, q, key)
|
res, err := db.Query(internalCtx, q, key)
|
||||||
if err != nil || res == nil || res.Count == 0 || len(res.Rows) == 0 || len(res.Rows[0]) == 0 {
|
if err != nil || res == nil || res.Count == 0 || len(res.Rows) == 0 || len(res.Rows[0]) == 0 {
|
||||||
w.Header().Set("WWW-Authenticate", "Bearer error=\"invalid_token\"")
|
w.Header().Set("WWW-Authenticate", "Bearer error=\"invalid_token\"")
|
||||||
writeError(w, http.StatusUnauthorized, "invalid API key")
|
writeError(w, http.StatusUnauthorized, "invalid API key")
|
||||||
@ -122,9 +124,9 @@ func (g *Gateway) authMiddleware(next http.Handler) http.Handler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Attach auth metadata to context for downstream use
|
// Attach auth metadata to context for downstream use
|
||||||
ctx = context.WithValue(ctx, ctxKeyAPIKey, key)
|
reqCtx := context.WithValue(r.Context(), ctxKeyAPIKey, key)
|
||||||
ctx = storage.WithNamespace(ctx, ns)
|
reqCtx = storage.WithNamespace(reqCtx, ns)
|
||||||
next.ServeHTTP(w, r.WithContext(ctx))
|
next.ServeHTTP(w, r.WithContext(reqCtx))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -224,14 +226,15 @@ func (g *Gateway) authorizationMiddleware(next http.Handler) http.Handler {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check ownership in DB
|
// Check ownership in DB using internal auth context
|
||||||
db := g.client.Database()
|
db := g.client.Database()
|
||||||
|
internalCtx := client.WithInternalAuth(ctx)
|
||||||
// Ensure namespace exists and get id
|
// Ensure namespace exists and get id
|
||||||
if _, err := db.Query(ctx, "INSERT OR IGNORE INTO namespaces(name) VALUES (?)", ns); err != nil {
|
if _, err := db.Query(internalCtx, "INSERT OR IGNORE INTO namespaces(name) VALUES (?)", ns); err != nil {
|
||||||
writeError(w, http.StatusInternalServerError, err.Error())
|
writeError(w, http.StatusInternalServerError, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
nres, err := db.Query(ctx, "SELECT id FROM namespaces WHERE name = ? LIMIT 1", ns)
|
nres, err := db.Query(internalCtx, "SELECT id FROM namespaces WHERE name = ? LIMIT 1", ns)
|
||||||
if err != nil || nres == nil || nres.Count == 0 || len(nres.Rows) == 0 || len(nres.Rows[0]) == 0 {
|
if err != nil || nres == nil || nres.Count == 0 || len(nres.Rows) == 0 || len(nres.Rows[0]) == 0 {
|
||||||
writeError(w, http.StatusForbidden, "namespace not found")
|
writeError(w, http.StatusForbidden, "namespace not found")
|
||||||
return
|
return
|
||||||
@ -239,7 +242,7 @@ func (g *Gateway) authorizationMiddleware(next http.Handler) http.Handler {
|
|||||||
nsID := nres.Rows[0][0]
|
nsID := nres.Rows[0][0]
|
||||||
|
|
||||||
q := "SELECT 1 FROM namespace_ownership WHERE namespace_id = ? AND owner_type = ? AND owner_id = ? LIMIT 1"
|
q := "SELECT 1 FROM namespace_ownership WHERE namespace_id = ? AND owner_type = ? AND owner_id = ? LIMIT 1"
|
||||||
res, err := db.Query(ctx, q, nsID, ownerType, ownerID)
|
res, err := db.Query(internalCtx, q, nsID, ownerType, ownerID)
|
||||||
if err != nil || res == nil || res.Count == 0 {
|
if err != nil || res == nil || res.Count == 0 {
|
||||||
writeError(w, http.StatusForbidden, "forbidden: not an owner of namespace")
|
writeError(w, http.StatusForbidden, "forbidden: not an owner of namespace")
|
||||||
return
|
return
|
||||||
|
Loading…
x
Reference in New Issue
Block a user