mirror of
https://github.com/netbirdio/netbird.git
synced 2026-09-21 22:29:08 +02:00
[management,client] Add anonymize level and upload URL to remote debug bundle jobs (#7147)
This extends the management-requested remote debug-bundle job with two new, optional parameters. anonymize_level selects how aggressively the bundle is scrubbed: "default" keeps internal (private) IP ranges readable, while "strict" also anonymizes private, CGNAT and link-local addresses; the value is trimmed and lowercased, and an unknown level is rejected at creation. upload_url lets an operator point the peer at a specific upload service instead of the default one; it must be a well-formed https URL with a host, and an empty value falls back to the default upload server. Both fields flow through the job workload API and are surfaced in the create-debug-job modal on the dashboard. Validation is shared so the client executor and the management boundary agree on what a valid upload URL is, preventing drift between the two checks.
This commit is contained in:
@@ -1373,7 +1373,17 @@ func (e *Engine) receiveJobEvents() {
|
||||
}
|
||||
|
||||
func (e *Engine) handleBundle(params *mgmProto.BundleParameters) (*mgmProto.JobResponse_Bundle, error) {
|
||||
log.Infof("handle remote debug bundle request: %s", params.String())
|
||||
// The upload URL can carry a host, credentials, or query tokens, so it is
|
||||
// kept out of the info-level line; the full parameters stay available at
|
||||
// debug level for troubleshooting.
|
||||
log.Infof("handle remote debug bundle request: anonymize=%v anonymize_level=%q log_file_count=%d bundle_for=%v bundle_for_time=%d",
|
||||
params.GetAnonymize(), params.GetAnonymizeLevel(), params.GetLogFileCount(), params.GetBundleFor(), params.GetBundleForTime())
|
||||
log.Debugf("remote debug bundle request parameters: %s", params.String())
|
||||
|
||||
if err := validateBundleUploadURL(params.GetUploadUrl()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
syncResponse, err := e.GetLatestSyncResponse()
|
||||
if err != nil {
|
||||
log.Warnf("get latest sync response: %v", err)
|
||||
@@ -1401,7 +1411,7 @@ func (e *Engine) handleBundle(params *mgmProto.BundleParameters) (*mgmProto.JobR
|
||||
|
||||
waitFor := time.Duration(params.BundleForTime) * time.Minute
|
||||
|
||||
uploadKey, err := e.jobExecutor.BundleJob(e.ctx, bundleDeps, bundleJobParams, waitFor, e.config.ProfileConfig.ManagementURL.String())
|
||||
uploadKey, err := e.jobExecutor.BundleJob(e.ctx, bundleDeps, bundleJobParams, waitFor, e.config.ProfileConfig.ManagementURL.String(), params.GetUploadUrl())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1414,6 +1424,26 @@ func (e *Engine) handleBundle(params *mgmProto.BundleParameters) (*mgmProto.JobR
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// validateBundleUploadURL sanity-checks a management-supplied upload URL for a
|
||||
// remote debug bundle job. An empty value is accepted — the executor falls back
|
||||
// to the default upload service. A non-empty value must be a well-formed https
|
||||
// URL with a host; a malformed value or a plaintext scheme is rejected. This
|
||||
// deliberately does not constrain which host may receive the bundle; that
|
||||
// policy is left open pending a decision on management-directed uploads.
|
||||
func validateBundleUploadURL(raw string) error {
|
||||
if raw == "" {
|
||||
return nil
|
||||
}
|
||||
parsed, err := url.Parse(raw)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parse upload URL: %w", err)
|
||||
}
|
||||
if parsed.Scheme != "https" || parsed.Host == "" {
|
||||
return fmt.Errorf("upload URL must be an https URL with a host")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// receiveManagementEvents connects to the Management Service event stream to receive updates from the management service
|
||||
// E.g. when a new peer has been registered and we are allowed to connect to it.
|
||||
func (e *Engine) receiveManagementEvents() {
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// TestValidateBundleUploadURL covers the sanity check applied to a
|
||||
// management-supplied upload URL before a remote debug bundle is generated.
|
||||
func TestValidateBundleUploadURL(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
raw string
|
||||
wantErr bool
|
||||
}{
|
||||
{name: "empty falls back to default", raw: ""},
|
||||
{name: "https with host", raw: "https://upload.debug.netbird.io/upload"},
|
||||
{name: "https self-hosted host", raw: "https://upload.example.com"},
|
||||
{name: "plaintext rejected", raw: "http://upload.example.com", wantErr: true},
|
||||
{name: "missing host rejected", raw: "https:///upload", wantErr: true},
|
||||
{name: "non-url scheme rejected", raw: "ftp://upload.example.com", wantErr: true},
|
||||
{name: "garbage rejected", raw: "://not a url", wantErr: true},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
err := validateBundleUploadURL(tc.raw)
|
||||
if tc.wantErr {
|
||||
require.Error(t, err, "an invalid upload URL must be rejected")
|
||||
return
|
||||
}
|
||||
assert.NoError(t, err, "a valid or empty upload URL must be accepted")
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,11 @@ func NewExecutor() *Executor {
|
||||
return &Executor{}
|
||||
}
|
||||
|
||||
func (e *Executor) BundleJob(ctx context.Context, debugBundleDependencies debug.GeneratorDependencies, params debug.BundleConfig, waitForDuration time.Duration, mgmURL string) (string, error) {
|
||||
func (e *Executor) BundleJob(ctx context.Context, debugBundleDependencies debug.GeneratorDependencies, params debug.BundleConfig, waitForDuration time.Duration, mgmURL, uploadURL string) (string, error) {
|
||||
if uploadURL == "" {
|
||||
uploadURL = types.DefaultBundleURL
|
||||
}
|
||||
|
||||
if waitForDuration > MaxBundleWaitTime {
|
||||
log.Warnf("bundle wait time %v exceeds maximum %v, capping to maximum", waitForDuration, MaxBundleWaitTime)
|
||||
waitForDuration = MaxBundleWaitTime
|
||||
@@ -54,7 +58,7 @@ func (e *Executor) BundleJob(ctx context.Context, debugBundleDependencies debug.
|
||||
}
|
||||
}()
|
||||
|
||||
key, err := debug.UploadDebugBundle(ctx, types.DefaultBundleURL, mgmURL, path, false)
|
||||
key, err := debug.UploadDebugBundle(ctx, uploadURL, mgmURL, path, false)
|
||||
if err != nil {
|
||||
log.Errorf("failed to upload debug bundle: %v", err)
|
||||
return "", fmt.Errorf("upload debug bundle: %w", err)
|
||||
|
||||
Reference in New Issue
Block a user