feat(security): support operator-managed network proxy routing (#70044)

* feat: support operator-managed proxy routing

* docs: add network proxy changelog entry

* fix(proxy): restrict gateway bypass to loopback IPs

* fix(cli): harden container proxy URL checks

* docs(proxy): clarify gateway bypass scope

* docs: remove proxy changelog entry

* fix(proxy): clear startup CI guard failures

* fix(proxy): harden gateway proxy policy parsing

* fix(proxy): honor update shorthand proxy policy

* fix(cli): redact proxy URL suffixes

* test(proxy): keep gateway help off proxy startup

* fix(proxy): keep overlapping lifecycle active

* docs: add proxy changelog entry

---------

Co-authored-by: joshavant <830519+joshavant@users.noreply.github.com>
This commit is contained in:
Jesse Merhi
2026-04-28 15:20:47 +10:00
committed by GitHub
parent 025081dbc5
commit 2633b14914
36 changed files with 2737 additions and 96 deletions

View File

@@ -1,5 +1,11 @@
import { hasFlag } from "./argv.js";
export type CliCommandPluginLoadPolicy = "never" | "always" | "text-only";
export type CliRouteConfigGuardPolicy = "never" | "always" | "when-suppressed";
export type CliNetworkProxyPolicy = "default" | "bypass";
export type CliNetworkProxyPolicyResolver =
| CliNetworkProxyPolicy
| ((ctx: { argv: string[]; commandPath: string[] }) => CliNetworkProxyPolicy);
export type CliRoutedCommandId =
| "health"
| "status"
@@ -21,6 +27,7 @@ export type CliCommandPathPolicy = {
loadPlugins: CliCommandPluginLoadPolicy;
hideBanner: boolean;
ensureCliPath: boolean;
networkProxy: CliNetworkProxyPolicyResolver;
};
export type CliCommandCatalogEntry = {
@@ -38,11 +45,17 @@ export const cliCommandCatalog: readonly CliCommandCatalogEntry[] = [
commandPath: ["crestodian"],
policy: { bypassConfigGuard: true, loadPlugins: "never", ensureCliPath: false },
},
{ commandPath: ["agent"], policy: { loadPlugins: "always" } },
{
commandPath: ["agent"],
policy: {
loadPlugins: "always",
networkProxy: ({ argv }) => (hasFlag(argv, "--local") ? "default" : "bypass"),
},
},
{ commandPath: ["message"], policy: { loadPlugins: "never" } },
{ commandPath: ["channels"], policy: { loadPlugins: "always" } },
{ commandPath: ["directory"], policy: { loadPlugins: "always" } },
{ commandPath: ["agents"], policy: { loadPlugins: "always" } },
{ commandPath: ["agents"], policy: { loadPlugins: "always", networkProxy: "bypass" } },
{
commandPath: ["agents", "bind"],
exact: true,
@@ -69,34 +82,59 @@ export const cliCommandCatalog: readonly CliCommandCatalogEntry[] = [
policy: { loadPlugins: "never" },
},
{ commandPath: ["configure"], policy: { bypassConfigGuard: true, loadPlugins: "never" } },
{ commandPath: ["migrate"], policy: { bypassConfigGuard: true, loadPlugins: "never" } },
{
commandPath: ["migrate"],
policy: { bypassConfigGuard: true, loadPlugins: "never", networkProxy: "bypass" },
},
{
commandPath: ["status"],
policy: {
loadPlugins: "never",
routeConfigGuard: "when-suppressed",
ensureCliPath: false,
networkProxy: "bypass",
},
route: { id: "status" },
},
{
commandPath: ["health"],
policy: { loadPlugins: "never", ensureCliPath: false },
policy: { loadPlugins: "never", ensureCliPath: false, networkProxy: "bypass" },
route: { id: "health" },
},
{
commandPath: ["gateway"],
policy: {
networkProxy: ({ commandPath }) =>
commandPath.length === 1 || commandPath[1] === "run" ? "default" : "bypass",
},
},
{
commandPath: ["gateway", "status"],
exact: true,
policy: {
routeConfigGuard: "always",
loadPlugins: "never",
networkProxy: "bypass",
},
route: { id: "gateway-status" },
},
{ commandPath: ["gateway", "call"], exact: true, policy: { networkProxy: "bypass" } },
{ commandPath: ["gateway", "diagnostics"], exact: true, policy: { networkProxy: "bypass" } },
{ commandPath: ["gateway", "discover"], exact: true, policy: { networkProxy: "bypass" } },
{ commandPath: ["gateway", "export"], exact: true, policy: { networkProxy: "bypass" } },
{ commandPath: ["gateway", "health"], exact: true, policy: { networkProxy: "bypass" } },
{ commandPath: ["gateway", "install"], exact: true, policy: { networkProxy: "bypass" } },
{ commandPath: ["gateway", "probe"], exact: true, policy: { networkProxy: "bypass" } },
{ commandPath: ["gateway", "restart"], exact: true, policy: { networkProxy: "bypass" } },
{ commandPath: ["gateway", "stability"], exact: true, policy: { networkProxy: "bypass" } },
{ commandPath: ["gateway", "start"], exact: true, policy: { networkProxy: "bypass" } },
{ commandPath: ["gateway", "stop"], exact: true, policy: { networkProxy: "bypass" } },
{ commandPath: ["gateway", "uninstall"], exact: true, policy: { networkProxy: "bypass" } },
{ commandPath: ["gateway", "usage-cost"], exact: true, policy: { networkProxy: "bypass" } },
{
commandPath: ["sessions"],
exact: true,
policy: { ensureCliPath: false },
policy: { ensureCliPath: false, networkProxy: "bypass" },
route: { id: "sessions" },
},
{
@@ -106,70 +144,121 @@ export const cliCommandCatalog: readonly CliCommandCatalogEntry[] = [
// is only used in human text output. text-only skips the bundled-plugin
// import waterfall in `--json` mode, mirroring what `channels list`
// already does. Human (non-JSON) invocations still load plugins. (#71739)
policy: { loadPlugins: "text-only" },
policy: { loadPlugins: "text-only", networkProxy: "bypass" },
route: { id: "agents-list" },
},
{
commandPath: ["config", "get"],
exact: true,
policy: { ensureCliPath: false },
policy: { ensureCliPath: false, networkProxy: "bypass" },
route: { id: "config-get" },
},
{
commandPath: ["config", "unset"],
exact: true,
policy: { ensureCliPath: false },
policy: { ensureCliPath: false, networkProxy: "bypass" },
route: { id: "config-unset" },
},
{
commandPath: ["models", "list"],
exact: true,
policy: { ensureCliPath: false, routeConfigGuard: "always" },
policy: { ensureCliPath: false, routeConfigGuard: "always", networkProxy: "bypass" },
route: { id: "models-list" },
},
{
commandPath: ["models", "status"],
exact: true,
policy: { ensureCliPath: false, routeConfigGuard: "always" },
policy: {
ensureCliPath: false,
routeConfigGuard: "always",
networkProxy: ({ argv }) => (hasFlag(argv, "--probe") ? "default" : "bypass"),
},
route: { id: "models-status" },
},
{
commandPath: ["tasks", "list"],
exact: true,
policy: { ensureCliPath: false, routeConfigGuard: "when-suppressed", loadPlugins: "never" },
policy: {
ensureCliPath: false,
routeConfigGuard: "when-suppressed",
loadPlugins: "never",
networkProxy: "bypass",
},
route: { id: "tasks-list" },
},
{
commandPath: ["tasks", "audit"],
exact: true,
policy: { ensureCliPath: false, routeConfigGuard: "when-suppressed", loadPlugins: "never" },
policy: {
ensureCliPath: false,
routeConfigGuard: "when-suppressed",
loadPlugins: "never",
networkProxy: "bypass",
},
route: { id: "tasks-audit" },
},
{
commandPath: ["tasks"],
policy: { ensureCliPath: false, routeConfigGuard: "when-suppressed", loadPlugins: "never" },
policy: {
ensureCliPath: false,
routeConfigGuard: "when-suppressed",
loadPlugins: "never",
networkProxy: "bypass",
},
route: { id: "tasks-list" },
},
{ commandPath: ["backup"], policy: { bypassConfigGuard: true } },
{ commandPath: ["acp"], policy: { networkProxy: "bypass" } },
{ commandPath: ["approvals"], policy: { networkProxy: "bypass" } },
{ commandPath: ["backup"], policy: { bypassConfigGuard: true, networkProxy: "bypass" } },
{ commandPath: ["chat"], policy: { networkProxy: "bypass" } },
{ commandPath: ["config"], policy: { networkProxy: "bypass" } },
{ commandPath: ["cron"], policy: { networkProxy: "bypass" } },
{ commandPath: ["dashboard"], policy: { networkProxy: "bypass" } },
{ commandPath: ["daemon"], policy: { networkProxy: "bypass" } },
{ commandPath: ["devices"], policy: { networkProxy: "bypass" } },
{ commandPath: ["doctor"], policy: { bypassConfigGuard: true } },
{ commandPath: ["exec-policy"], policy: { networkProxy: "bypass" } },
{ commandPath: ["hooks"], policy: { networkProxy: "bypass" } },
{ commandPath: ["logs"], policy: { networkProxy: "bypass" } },
{ commandPath: ["mcp"], policy: { networkProxy: "bypass" } },
{
commandPath: ["node"],
policy: { networkProxy: "bypass" },
},
{
commandPath: ["node", "run"],
exact: true,
policy: { networkProxy: "default" },
},
{ commandPath: ["nodes"], policy: { networkProxy: "bypass" } },
{ commandPath: ["pairing"], policy: { networkProxy: "bypass" } },
{ commandPath: ["proxy"], policy: { networkProxy: "bypass" } },
{ commandPath: ["qr"], policy: { networkProxy: "bypass" } },
{ commandPath: ["reset"], policy: { networkProxy: "bypass" } },
{
commandPath: ["completion"],
policy: {
bypassConfigGuard: true,
hideBanner: true,
networkProxy: "bypass",
},
},
{ commandPath: ["secrets"], policy: { bypassConfigGuard: true } },
{ commandPath: ["secrets"], policy: { bypassConfigGuard: true, networkProxy: "bypass" } },
{ commandPath: ["security"], policy: { networkProxy: "bypass" } },
{ commandPath: ["system"], policy: { networkProxy: "bypass" } },
{ commandPath: ["terminal"], policy: { networkProxy: "bypass" } },
{ commandPath: ["tui"], policy: { networkProxy: "bypass" } },
{ commandPath: ["uninstall"], policy: { networkProxy: "bypass" } },
{ commandPath: ["update"], policy: { hideBanner: true } },
{
commandPath: ["config", "validate"],
exact: true,
policy: { bypassConfigGuard: true },
policy: { bypassConfigGuard: true, networkProxy: "bypass" },
},
{
commandPath: ["config", "schema"],
exact: true,
policy: { bypassConfigGuard: true },
policy: { bypassConfigGuard: true, networkProxy: "bypass" },
},
{
commandPath: ["plugins", "update"],
@@ -184,23 +273,43 @@ export const cliCommandCatalog: readonly CliCommandCatalogEntry[] = [
{
commandPath: ["channels", "add"],
exact: true,
policy: { loadPlugins: "never" },
policy: { loadPlugins: "never", networkProxy: "bypass" },
},
{
commandPath: ["channels", "logs"],
exact: true,
policy: { loadPlugins: "never", networkProxy: "bypass" },
},
{
commandPath: ["channels", "remove"],
exact: true,
policy: { networkProxy: "bypass" },
},
{
commandPath: ["channels", "resolve"],
exact: true,
policy: { networkProxy: "bypass" },
},
{
commandPath: ["channels", "status"],
exact: true,
policy: { loadPlugins: "never" },
policy: {
loadPlugins: "never",
networkProxy: ({ argv }) => (hasFlag(argv, "--probe") ? "default" : "bypass"),
},
route: { id: "channels-status" },
},
{
commandPath: ["channels", "list"],
exact: true,
policy: { loadPlugins: "never" },
policy: { loadPlugins: "never", networkProxy: "bypass" },
route: { id: "channels-list" },
},
{
commandPath: ["channels", "logs"],
exact: true,
policy: { loadPlugins: "never" },
},
{ commandPath: ["skills"], exact: true, policy: { networkProxy: "bypass" } },
{ commandPath: ["skills", "check"], exact: true, policy: { networkProxy: "bypass" } },
{ commandPath: ["skills", "info"], exact: true, policy: { networkProxy: "bypass" } },
{ commandPath: ["skills", "install"], exact: true },
{ commandPath: ["skills", "list"], exact: true, policy: { networkProxy: "bypass" } },
{ commandPath: ["skills", "search"], exact: true },
{ commandPath: ["skills", "update"], exact: true },
];