mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: add api-rate-limit flag (#5013)
This commit is contained in:
@@ -372,6 +372,12 @@ func newConfig() *codersdk.DeploymentConfig {
|
||||
Default: 10 * time.Minute,
|
||||
},
|
||||
},
|
||||
APIRateLimit: &codersdk.DeploymentConfigField[int]{
|
||||
Name: "API Rate Limit",
|
||||
Usage: "Maximum number of requests per minute allowed to the API per user, or per IP address for unauthenticated users. Negative values mean no rate limit. Some API endpoints are always rate limited regardless of this value to prevent denial-of-service attacks.",
|
||||
Flag: "api-rate-limit",
|
||||
Default: 512,
|
||||
},
|
||||
Experimental: &codersdk.DeploymentConfigField[bool]{
|
||||
Name: "Experimental",
|
||||
Usage: "Enable experimental features. Experimental features are not ready for production.",
|
||||
|
||||
@@ -363,6 +363,7 @@ func Server(vip *viper.Viper, newAPI func(context.Context, *coderd.Options) (*co
|
||||
AgentStatsRefreshInterval: cfg.AgentStatRefreshInterval.Value,
|
||||
DeploymentConfig: cfg,
|
||||
PrometheusRegistry: prometheus.NewRegistry(),
|
||||
APIRateLimit: cfg.APIRateLimit.Value,
|
||||
}
|
||||
if tlsConfig != nil {
|
||||
options.TLSCertificates = tlsConfig.Certificates
|
||||
|
||||
@@ -633,6 +633,94 @@ func TestServer(t *testing.T) {
|
||||
cancelFunc()
|
||||
<-serverErr
|
||||
})
|
||||
|
||||
t.Run("RateLimit", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
t.Run("Default", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
|
||||
root, cfg := clitest.New(t,
|
||||
"server",
|
||||
"--in-memory",
|
||||
"--address", ":0",
|
||||
"--access-url", "http://example.com",
|
||||
)
|
||||
serverErr := make(chan error, 1)
|
||||
go func() {
|
||||
serverErr <- root.ExecuteContext(ctx)
|
||||
}()
|
||||
accessURL := waitAccessURL(t, cfg)
|
||||
client := codersdk.New(accessURL)
|
||||
|
||||
resp, err := client.Request(ctx, http.MethodGet, "/api/v2/buildinfo", nil)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
require.Equal(t, http.StatusOK, resp.StatusCode)
|
||||
require.Equal(t, "512", resp.Header.Get("X-Ratelimit-Limit"))
|
||||
cancelFunc()
|
||||
<-serverErr
|
||||
})
|
||||
|
||||
t.Run("Changed", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
|
||||
val := "100"
|
||||
root, cfg := clitest.New(t,
|
||||
"server",
|
||||
"--in-memory",
|
||||
"--address", ":0",
|
||||
"--access-url", "http://example.com",
|
||||
"--api-rate-limit", val,
|
||||
)
|
||||
serverErr := make(chan error, 1)
|
||||
go func() {
|
||||
serverErr <- root.ExecuteContext(ctx)
|
||||
}()
|
||||
accessURL := waitAccessURL(t, cfg)
|
||||
client := codersdk.New(accessURL)
|
||||
|
||||
resp, err := client.Request(ctx, http.MethodGet, "/api/v2/buildinfo", nil)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
require.Equal(t, http.StatusOK, resp.StatusCode)
|
||||
require.Equal(t, val, resp.Header.Get("X-Ratelimit-Limit"))
|
||||
cancelFunc()
|
||||
<-serverErr
|
||||
})
|
||||
|
||||
t.Run("Disabled", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
|
||||
root, cfg := clitest.New(t,
|
||||
"server",
|
||||
"--in-memory",
|
||||
"--address", ":0",
|
||||
"--access-url", "http://example.com",
|
||||
"--api-rate-limit", "-1",
|
||||
)
|
||||
serverErr := make(chan error, 1)
|
||||
go func() {
|
||||
serverErr <- root.ExecuteContext(ctx)
|
||||
}()
|
||||
accessURL := waitAccessURL(t, cfg)
|
||||
client := codersdk.New(accessURL)
|
||||
|
||||
resp, err := client.Request(ctx, http.MethodGet, "/api/v2/buildinfo", nil)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
require.Equal(t, http.StatusOK, resp.StatusCode)
|
||||
require.Equal(t, "", resp.Header.Get("X-Ratelimit-Limit"))
|
||||
cancelFunc()
|
||||
<-serverErr
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func generateTLSCertificate(t testing.TB, commonName ...string) (certPath, keyPath string) {
|
||||
|
||||
+8
@@ -17,6 +17,14 @@ Flags:
|
||||
-a, --address string Bind address of the server.
|
||||
Consumes $CODER_ADDRESS (default
|
||||
"127.0.0.1:3000")
|
||||
--api-rate-limit int Maximum number of requests per minute
|
||||
allowed to the API per user, or per IP
|
||||
address for unauthenticated users.
|
||||
Negative values mean no rate limit. Some
|
||||
API endpoints are always rate limited
|
||||
regardless of this value to prevent
|
||||
denial-of-service attacks.
|
||||
Consumes $CODER_API_RATE_LIMIT (default 512)
|
||||
--cache-dir string The directory to cache temporary files.
|
||||
If unspecified and $CACHE_DIRECTORY is
|
||||
set, it will be used for compatibility
|
||||
|
||||
Reference in New Issue
Block a user