Skip to content

Commit

A host a sandbox was refused is a note on the run, never what its card says it is doing, and tools in a sandbox with only allowed hosts are told not to send usage reports home

syntaqxcommitted Parentbee5a81Browse files
4 files+55−30/4 viewed
+8−1
8383
8484 Each refused host appears once as a step of the run, such as
8585 `Blocked: example.com (not an allowed domain)`, on the run's page under
86−**Agents**. If a run needs a host, allow it and start the work again.
86+**Agents**. It is a note, not the run's state: the run carries on, and its
87+card keeps showing what it is doing. If a run needs a host, allow it and
88+start the work again.
89+
90+Tools that send usage reports home are told not to in a sandbox with only
91+allowed hosts (`DO_NOT_TRACK=1`, and each common tool's own switch, such
92+as `WRANGLER_SEND_METRICS=false`), so those reports are not refused and
93+noted on every run.
8794
8895 Setting **Only allowed hosts** to Open gives that project's sandboxes the
8996 whole internet, as before guardrails.
+4−0
8080 defaultBranch: "trunk",
8181 });
8282 assert.equal(restricted.NODE_EXTRA_CA_CERTS, "/etc/cloudflare/certs/cloudflare-containers-ca.crt");
83+ // Tools that would report usage home are told not to: it would be refused.
84+ assert.equal(restricted.WRANGLER_SEND_METRICS, "false");
85+ assert.equal(restricted.DO_NOT_TRACK, "1");
8386 // Open, as the operator's switch makes it: no certificate to trust.
8487 const open = harnessEnv(guard, {}, false);
8588 assert.equal(JSON.parse(open.GUARDRAILS).restrictNetwork, false);
8689 assert.equal(open.NODE_EXTRA_CA_CERTS, undefined);
90+ assert.equal(open.DO_NOT_TRACK, undefined);
8791 });
8892
8993 test("each refused host is one step, up to a limit", () => {
+21−1
108108 GIT_SSL_CAINFO: SYSTEM_BUNDLE,
109109 };
110110
111+/**
112+ * Tools that report usage home by default, told not to: in a guarded
113+ * sandbox the report would only be refused, and a refused host is noted on
114+ * the run. `DO_NOT_TRACK` is the convention many tools follow; the rest are
115+ * the tools' own switches.
116+ */
117+export const QUIET_ENV: Record<string, string> = {
118+ DO_NOT_TRACK: "1",
119+ WRANGLER_SEND_METRICS: "false",
120+ NEXT_TELEMETRY_DISABLED: "1",
121+ ASTRO_TELEMETRY_DISABLED: "1",
122+ NUXT_TELEMETRY_DISABLED: "1",
123+ GATSBY_TELEMETRY_DISABLED: "1",
124+ STORYBOOK_DISABLE_TELEMETRY: "1",
125+ TURBO_TELEMETRY_DISABLED: "1",
126+ DOTNET_CLI_TELEMETRY_OPTOUT: "1",
127+ HOMEBREW_NO_ANALYTICS: "1",
128+ CHECKPOINT_DISABLE: "1",
129+};
130+
111131 /** What a sandbox's guardrails come to for one run. */
112132 export type RunGuard = {
113133 policy: Guardrails;
130150 defaultBranch: sandboxEnv.UPSTREAM_BRANCH ?? null,
131151 }),
132152 };
133− return restricted ? { ...vars, ...EGRESS_ENV } : vars;
153+ return restricted ? { ...vars, ...EGRESS_ENV, ...QUIET_ENV } : vars;
134154 }
135155
136156 /**
+22−1
2424 use crate::rows::SessionRow;
2525 use crate::{Work, optional};
2626
27+/// How the runner starts a step that notes something about the sandbox
28+/// rather than what the run is doing: a host it was refused (the runner's
29+/// egress.ts `blockedStep`).
30+const NOTE_PREFIXES: [&str; 1] = ["Blocked: "];
31+
32+/// Where a report leaves the run: its newest step that says what the run
33+/// is doing. A note (a refused host) stays in the steps but never stands
34+/// for the run, which carries on past it. `None` when there is only notes.
35+fn current_step(steps: &[String]) -> Option<String> {
36+ steps.iter().rev().find(|step| !NOTE_PREFIXES.iter().any(|prefix| step.starts_with(prefix))).cloned()
37+}
38+
2739 /// The most steps a run keeps; older ones fall off the start.
2840 const MAX_STEPS: u32 = 200;
2941 /// The most steps taken from one report.
343355 .as_deref()
344356 .map(|step| one_line(step, MAX_STEP_CHARS))
345357 .filter(|step| !step.is_empty())
346− .or_else(|| steps.last().cloned());
358+ .or_else(|| current_step(&steps));
347359 let outcome = a
348360 .outcome
349361 .filter(|outcome| matches!(outcome, RunStatus::Succeeded | RunStatus::Failed));
662674 use super::*;
663675
664676 #[test]
677+ fn a_refused_host_is_noted_but_never_where_the_run_is() {
678+ let steps = |list: &[&str]| list.iter().map(|step| (*step).to_owned()).collect::<Vec<String>>();
679+ assert_eq!(current_step(&steps(&["Running npm ci", "Blocked: sparrow.cloudflare.com (not an allowed domain)"])).as_deref(), Some("Running npm ci"));
680+ assert_eq!(current_step(&steps(&["Blocked: a.com (not an allowed domain)"])), None);
681+ assert_eq!(current_step(&steps(&["Blocked: a.com (not an allowed domain)", "Typecheck"])).as_deref(), Some("Typecheck"));
682+ assert_eq!(current_step(&[]), None);
683+ }
684+
685+ #[test]
665686 fn steps_are_one_short_line() {
666687 assert_eq!(one_line(" Read\n src/lib.rs ", 40), "Read src/lib.rs");
667688 let long = one_line(&"x".repeat(300), 10);