Skip to content

Commit cf41254

Browse files
test(stations/notify): clear ambient channel env
Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 42f7cf0 commit cf41254

1 file changed

Lines changed: 60 additions & 0 deletions

File tree

stations/notify/cmd/agent-notify/main_test.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,20 @@ func withIsolatedConfig(t *testing.T, args []string) []string {
7373
// stdin, and env vars, returning the exit code, stdout, and stderr.
7474
func runMain(t *testing.T, args []string, stdin string, env map[string]string) (int, string, string) {
7575
t.Helper()
76+
// Clear ambient notification env vars before applying the test's env
77+
// map. config.Load discovers DISCORD_WEBHOOK_URL, TELEGRAM_BOT_TOKEN +
78+
// TELEGRAM_CHAT_ID, and SIGNAL_CLI_URL + SIGNAL_FROM + SIGNAL_TO from
79+
// the process env, so a developer's exported credentials would otherwise
80+
// add channels to tests and could send real notifications. t.Setenv
81+
// records the prior value and restores it automatically when the test
82+
// ends.
83+
for _, k := range []string{
84+
"DISCORD_WEBHOOK_URL",
85+
"TELEGRAM_BOT_TOKEN", "TELEGRAM_CHAT_ID",
86+
"SIGNAL_CLI_URL", "SIGNAL_FROM", "SIGNAL_TO",
87+
} {
88+
t.Setenv(k, "")
89+
}
7690
for k, v := range env {
7791
t.Setenv(k, v)
7892
}
@@ -104,6 +118,52 @@ func TestRun_PlainStringToDiscord_ExitsZero(t *testing.T) {
104118
}
105119
}
106120

121+
// TestRunMainClearsAmbientChannelEnv verifies that runMain clears ambient
122+
// notification environment variables before applying the test's env map, so a
123+
// developer's exported credentials cannot add channels to a test run or send
124+
// real notifications. A complete Signal configuration is set as ambient
125+
// process env (outside the env map passed to runMain); only a local Discord
126+
// endpoint is passed through the env map. The ambient Signal server must
127+
// receive zero requests while the intended Discord send succeeds.
128+
func TestRunMainClearsAmbientChannelEnv(t *testing.T) {
129+
var signalHits int
130+
signalSrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
131+
signalHits++
132+
w.WriteHeader(http.StatusNoContent)
133+
}))
134+
defer signalSrv.Close()
135+
136+
var discordGot map[string]interface{}
137+
discordSrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
138+
body, _ := io.ReadAll(r.Body)
139+
_ = json.Unmarshal(body, &discordGot)
140+
w.WriteHeader(http.StatusNoContent)
141+
}))
142+
defer discordSrv.Close()
143+
144+
// Ambient Signal configuration lives in the process env, NOT in the env
145+
// map handed to runMain. Without clearing, config.Load discovers it and
146+
// the Signal channel sends to signalSrv.
147+
t.Setenv("SIGNAL_CLI_URL", signalSrv.URL)
148+
t.Setenv("SIGNAL_FROM", "+15551234567")
149+
t.Setenv("SIGNAL_TO", "+15557654321")
150+
151+
code, _, stderr := runMain(t,
152+
[]string{"agent-notify", "ambient clear check"},
153+
"",
154+
map[string]string{"DISCORD_WEBHOOK_URL": discordSrv.URL},
155+
)
156+
if code != 0 {
157+
t.Fatalf("exit = %d, stderr = %s", code, stderr)
158+
}
159+
if discordGot == nil {
160+
t.Fatal("Discord webhook never received the intended request")
161+
}
162+
if signalHits != 0 {
163+
t.Fatalf("ambient Signal server received %d request(s); runMain did not clear ambient channel env", signalHits)
164+
}
165+
}
166+
107167
func TestRun_NoChannelsConfigured_Exit2(t *testing.T) {
108168
for _, k := range []string{"DISCORD_WEBHOOK_URL", "TELEGRAM_BOT_TOKEN", "TELEGRAM_CHAT_ID", "SIGNAL_CLI_URL", "SIGNAL_FROM", "SIGNAL_TO"} {
109169
os.Unsetenv(k)

0 commit comments

Comments
 (0)