|
1 | | -import fs from "node:fs"; |
2 | 1 | import type { IncomingMessage } from "node:http"; |
3 | 2 | import net from "node:net"; |
4 | 3 | import type { GatewayBindMode } from "../config/types.gateway.js"; |
| 4 | +import { |
| 5 | + __resetContainerEnvironmentCacheForTest, |
| 6 | + isContainerEnvironment, |
| 7 | +} from "../infra/container-environment.js"; |
5 | 8 | import { |
6 | 9 | pickMatchingExternalInterfaceAddress, |
7 | 10 | readNetworkInterfaces, |
@@ -228,60 +231,10 @@ export function isLocalGatewayAddress(ip: string | undefined): boolean { |
228 | 231 | return false; |
229 | 232 | } |
230 | 233 |
|
231 | | -/** |
232 | | - * Detect whether the current process is running inside a container |
233 | | - * (Docker, Podman, or Kubernetes). |
234 | | - * |
235 | | - * Uses two reliable heuristics: |
236 | | - * 1. Presence of well-known container sentinel files such as `/.dockerenv` |
237 | | - * (Docker) or `/run/.containerenv` (Podman). |
238 | | - * 2. Presence of container-related cgroup entries in `/proc/1/cgroup` |
239 | | - * (covers Docker, containerd, and Kubernetes pods). |
240 | | - * |
241 | | - * The result is cached after the first call so filesystem access |
242 | | - * happens at most once per process lifetime. |
243 | | - */ |
244 | | -let _containerCacheResult: boolean | undefined; |
245 | | -export function isContainerEnvironment(): boolean { |
246 | | - if (_containerCacheResult !== undefined) { |
247 | | - return _containerCacheResult; |
248 | | - } |
249 | | - _containerCacheResult = detectContainerEnvironment(); |
250 | | - return _containerCacheResult; |
251 | | -} |
252 | | - |
253 | | -function detectContainerEnvironment(): boolean { |
254 | | - // 1. Check common Docker/Podman container sentinel files. |
255 | | - for (const sentinelPath of ["/.dockerenv", "/run/.containerenv", "/var/run/.containerenv"]) { |
256 | | - try { |
257 | | - fs.accessSync(sentinelPath, fs.constants.F_OK); |
258 | | - return true; |
259 | | - } catch { |
260 | | - // not present — continue |
261 | | - } |
262 | | - } |
263 | | - // 2. /proc/1/cgroup contains docker, containerd, kubepods, or lxc markers. |
264 | | - // Covers both cgroup v1 (/docker/<id>, /kubepods/...) and cgroup v2 |
265 | | - // (kubepods.slice, cri-containerd-<id>.scope) path formats. |
266 | | - try { |
267 | | - const cgroup = fs.readFileSync("/proc/1/cgroup", "utf8"); |
268 | | - if ( |
269 | | - /\/docker\/|cri-containerd-[0-9a-f]|containerd\/[0-9a-f]{64}|\/kubepods[/.]|\blxc\b/.test( |
270 | | - cgroup, |
271 | | - ) |
272 | | - ) { |
273 | | - return true; |
274 | | - } |
275 | | - } catch { |
276 | | - // /proc may not exist (macOS, Windows) — not a container |
277 | | - } |
278 | | - return false; |
279 | | -} |
280 | | - |
281 | | -/** @internal — test-only helper to reset the cached container detection result. */ |
282 | | -export function __resetContainerCacheForTest(): void { |
283 | | - _containerCacheResult = undefined; |
284 | | -} |
| 234 | +export { |
| 235 | + isContainerEnvironment, |
| 236 | + __resetContainerEnvironmentCacheForTest as __resetContainerCacheForTest, |
| 237 | +}; |
285 | 238 |
|
286 | 239 | /** |
287 | 240 | * Resolves gateway bind host with fallback strategy. |
|
0 commit comments