Skip to content

Commit 20f160b

Browse files
scotwellsclaude
andcommitted
Gate the programmed-set debug endpoint to the test environment
The endpoint that reports what the last build intended to change exists only so a test can confirm the proxy is running exactly that set. Serve it (and do the per-build recording that backs it) only when NSO_DEBUG_PROGRAMMED_SET is set, so production exposes nothing and does no extra work on the build path. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JbCy8vy66RdNYzGSgqH6P6
1 parent e6ffdae commit 20f160b

3 files changed

Lines changed: 44 additions & 11 deletions

File tree

internal/extensionserver/cmd/run.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,9 @@ func run(o options) {
258258
ConnectorInternalListener: serverConfig.Gateway.ConnectorTunnelListenerName(),
259259
CorazaRouteBaseDirectives: coraza.RouteBaseDirectives,
260260
LocalReply: buildLocalReplyConfig(serverConfig.Gateway.ErrorPage, log),
261+
// The programmed-set debug endpoint is for the test environment only; it
262+
// stays off in production unless NSO_DEBUG_PROGRAMMED_SET is set.
263+
EnableProgrammedSet: envBool("NSO_DEBUG_PROGRAMMED_SET", false),
261264
}
262265

263266
// --- gRPC panic recovery interceptor ---
@@ -450,9 +453,12 @@ func run(o options) {
450453
}
451454
})
452455
mux.Handle("/metrics", promhttp.Handler())
453-
// Debug endpoint that reports what the last build changed, so a test can
454-
// confirm the proxy is running exactly that. Read-only; keeps only the last build.
455-
mux.HandleFunc(extserver.ProgrammedSetEndpointPath, extSrv.ProgrammedSetHandler())
456+
// Read-only debug endpoint that reports what the last build changed, so a test
457+
// can confirm the proxy is running exactly that. Test environment only; it is
458+
// not served in production. Keeps only the last build.
459+
if srvCfg.EnableProgrammedSet {
460+
mux.HandleFunc(extserver.ProgrammedSetEndpointPath, extSrv.ProgrammedSetHandler())
461+
}
456462
healthServer := &http.Server{
457463
Addr: healthAddr,
458464
Handler: mux,

internal/extensionserver/server/programmedset_test.go

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,10 @@ func TestPostTranslateModify_RecordsProgrammedSet(t *testing.T) {
306306
cl := fake.NewClientBuilder().WithScheme(scheme).
307307
WithObjects(ns, tpp, proxy).
308308
WithStatusSubresource(connector).WithObjects(connector).Build()
309-
srv := New(cl, testServerConfig(), discardLogger())
309+
// Recording only happens when the test-environment endpoint is enabled.
310+
cfg := testServerConfig()
311+
cfg.EnableProgrammedSet = true
312+
srv := New(cl, cfg, discardLogger())
310313

311314
req := &pb.PostTranslateModifyRequest{
312315
Clusters: []*clusterv3.Cluster{{Name: connCluster}, {Name: "infra-cluster"}},
@@ -342,3 +345,19 @@ func TestPostTranslateModify_RecordsProgrammedSet(t *testing.T) {
342345
require.Len(t, ps.Keys[FamilyWAFRoute], 1)
343346
assert.Contains(t, ps.Keys[FamilyWAFRoute][0], "test-project/test-tpp/Observe")
344347
}
348+
349+
// TestPostTranslateModify_NoRecordingWhenDisabled proves the production default:
350+
// with the test-only endpoint off, a build records nothing, so the snapshot
351+
// stays empty and no per-build work is done.
352+
func TestPostTranslateModify_NoRecordingWhenDisabled(t *testing.T) {
353+
cl := fake.NewClientBuilder().WithScheme(testServerScheme(t)).Build()
354+
// testServerConfig() leaves EnableProgrammedSet at its false default.
355+
srv := New(cl, testServerConfig(), discardLogger())
356+
357+
_, err := srv.PostTranslateModify(context.Background(), &pb.PostTranslateModifyRequest{})
358+
require.NoError(t, err)
359+
360+
ps := srv.programmed.snapshot()
361+
assert.Equal(t, uint64(0), ps.BuildID, "no build was recorded")
362+
assert.Empty(t, ps.Keys, "nothing recorded while the endpoint is disabled")
363+
}

internal/extensionserver/server/server.go

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@ type ServerConfig struct {
3737
// empty, local-reply injection is a no-op. Sourced from
3838
// GatewayConfig.ErrorPage + the embedded/override HTML body.
3939
LocalReply mutate.LocalReplyConfig
40+
// EnableProgrammedSet turns on the read-only /debug/programmed-set endpoint
41+
// and the per-build recording that backs it. It exists only to let a test
42+
// confirm the proxy is running exactly the set the build intended, so it is
43+
// off in production and enabled only in the test environment. When off, the
44+
// build does no extra work and the endpoint is not served.
45+
EnableProgrammedSet bool
4046
}
4147

4248
// Server implements pb.EnvoyGatewayExtensionServer for the NSO production
@@ -332,13 +338,15 @@ func (s *Server) PostTranslateModify(
332338
extmetrics.ConnectorRoutesTotal.Add(float64(vhCount))
333339
extmetrics.ConnectorOfflineRoutesTotal.Add(float64(offlineRtCount))
334340

335-
// Record what this build changed so a test can later confirm the proxy is
336-
// running exactly that. This only reads the configuration just produced; it
337-
// changes nothing.
338-
s.programmed.record(
339-
listeners, routes, clusters, s.cfg.Coraza.FilterName,
340-
prunedChains, prunedSecrets, listenersLeftIntact,
341-
)
341+
// In the test environment, record what this build changed so a test can later
342+
// confirm the proxy is running exactly that. This only reads the configuration
343+
// just produced; it changes nothing. Off in production, where it does no work.
344+
if s.cfg.EnableProgrammedSet {
345+
s.programmed.record(
346+
listeners, routes, clusters, s.cfg.Coraza.FilterName,
347+
prunedChains, prunedSecrets, listenersLeftIntact,
348+
)
349+
}
342350

343351
s.log.Info("PostTranslateModify",
344352
"clusters", len(clusters),

0 commit comments

Comments
 (0)