feat(hostinfo): detect Container + Env to match Go hostinfo.New#255
Conversation
Fill the HostInfo.Container and HostInfo.Env fields the map-poll path was leaving at their wire-omitted defaults, mirroring Go hostinfo.New's inContainer() and getEnvType(). A real tailscaled in a container or a managed environment (k8s, Cloud Run, Lambda, Fargate, fly.io, Heroku, Azure App Service, repl.it, Home Assistant, Docker Desktop) reports these; sending nothing while running in one is a fingerprint. - inContainer() (hostinfo.rs): Linux-only (None off Linux, matching Go's empty opt.Bool), Some(false) unless a container signal is present — /.dockerenv or /run/.containerenv exists, /proc/1/cgroup mentions /docker/ or /lxc/, or /proc/mounts carries the lxcfs cpuinfo bind. All the no-network signals Go checks. - env_type() (hostinfo.rs): Go getEnvType()'s first-match env-var cascade in Go's exact order. Factored into a pure env_type_from(get) core so the cascade is unit-tested without mutating the racy, unsafe, process-global real environment. - Threaded through MapRequestBuilder::host_environment (the map-poll path), alongside the existing distro fields. Register/logout keep their thinner identity-only HostInfo (they already omit distro too) — Container/Env default to the wire-omitted values there, so no regression. - Re-export ts_control_serde::EnvType (it was the type of the public HostInfo.env field but lived in a private module, unreachable by name). Wire parity verified: Container marshals as the JSON bool true/false under the Go key `Container` (Go opt.Bool.MarshalJSON), Env as its short code under `Env`; an unset container (None) and Unknown env are BOTH omitted by the struct's apply(Option/default => skip) rules, matching Go's `,omitzero` (never `"Container":null` or `"Env":""`, which would themselves be tells). GoArchVar and Cloud are deliberately NOT filled: GoArchVar (GOAMD64/GOARM) is a Go-toolchain build var this non-Go fork cannot report truthfully, and Cloud needs metadata probes (network); leaving them empty is honest and a real possibility a Go node also emits. Tracked as the remaining tsr-ajyc tail. Signed-off-by: Sergio <sergio@geiser.cloud>
📝 WalkthroughWalkthroughAdds ChangesContainer and EnvType host detection
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (2)
ts_control/src/map_request_builder.rs (1)
155-156: ⚡ Quick winAdd a regression assertion for these two new host-environment fields.
host_environmentnow copiescontainerandenv, but the existing test only checks older identity fields. Extendhost_environment_populates_identity_fieldsto assert these two assignments too.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ts_control/src/map_request_builder.rs` around lines 155 - 156, The code now copies two new fields, container and env, from host to host_info, but the existing test host_environment_populates_identity_fields does not verify these assignments. Extend the host_environment_populates_identity_fields test to include assertions that verify the container and env fields are correctly populated in host_info after calling the function that performs these assignments.ts_control/src/hostinfo.rs (1)
467-557: ⚡ Quick winAdd an explicit Azure App Service case to the env cascade test.
env_type_fromhas a dedicated Azure branch, but this test doesn’t assert it. Add one case forAPPSVC_RUN_ZIP+WEBSITE_STACK+WEBSITE_AUTH_AUTO_AADto prevent silent regressions.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ts_control/src/hostinfo.rs` around lines 467 - 557, The env_type_detects_known_environments test function does not include an assertion for Azure App Service, even though env_type_from has a dedicated branch for it. Add a new assert_eq! case in the test that passes the three Azure environment variables (APPSVC_RUN_ZIP, WEBSITE_STACK, and WEBSITE_AUTH_AUTO_AAD) with non-empty values to env_type_from and asserts the result equals the Azure EnvType variant. Place this assertion among the other managed environment test cases to ensure the Azure branch is properly covered and prevent silent regressions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@ts_control/src/hostinfo.rs`:
- Around line 467-557: The env_type_detects_known_environments test function
does not include an assertion for Azure App Service, even though env_type_from
has a dedicated branch for it. Add a new assert_eq! case in the test that passes
the three Azure environment variables (APPSVC_RUN_ZIP, WEBSITE_STACK, and
WEBSITE_AUTH_AUTO_AAD) with non-empty values to env_type_from and asserts the
result equals the Azure EnvType variant. Place this assertion among the other
managed environment test cases to ensure the Azure branch is properly covered
and prevent silent regressions.
In `@ts_control/src/map_request_builder.rs`:
- Around line 155-156: The code now copies two new fields, container and env,
from host to host_info, but the existing test
host_environment_populates_identity_fields does not verify these assignments.
Extend the host_environment_populates_identity_fields test to include assertions
that verify the container and env fields are correctly populated in host_info
after calling the function that performs these assignments.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 388223bf-4379-4ae7-a615-83ce998911f9
📒 Files selected for processing (4)
ts_control/src/hostinfo.rsts_control/src/map_request_builder.rsts_control_serde/src/host_info.rsts_control_serde/src/lib.rs
What
Fill the
HostInfo.ContainerandHostInfo.Envfields the map-poll path was leaving at their wire-omitted defaults, mirroring Gohostinfo.New'sinContainer()+getEnvType(). A realtailscaledin a container or a managed environment (k8s, Cloud Run, AWS Lambda/Fargate, fly.io, Heroku, Azure App Service, repl.it, Home Assistant, Docker Desktop) reports these — sending nothing while running in one is a fingerprint. (Remainingtsr-ajycitems after #238 shipped the macOS-OSVersion + Linux-Distro fields.)How
in_container()(hostinfo.rs): Linux-only (Noneoff Linux, matching Go's emptyopt.Bool),Some(false)unless a container signal is present —/.dockerenvor/run/.containerenvexists,/proc/1/cgroupmentions/docker/or/lxc/, or/proc/mountscarries the lxcfs cpuinfo bind. The no-network signals Go checks.env_type()(hostinfo.rs): GogetEnvType()'s first-match env-var cascade, in Go's exact order. Factored into a pureenv_type_from(get)core so the cascade is unit-tested without mutating the racy/unsafe/process-global real environment.MapRequestBuilder::host_environment(the map-poll path), alongside the existing distro fields. Register/logout keep their thinner identity-only HostInfo (they already omit distro too);Container/Envdefault to the wire-omitted values there → no regression.ts_control_serde::EnvType(it was the type of the publicHostInfo.envfield but lived in a private module, unreachable by name).Wire parity (verified by test)
Containermarshals as the JSON booltrue/falseunder the Go keyContainer(Goopt.Bool.MarshalJSON),Envas its short code (k8s, …) underEnv; an unset container (None) andUnknownenv are both omitted by the struct'sapply(Option/_=>skip)rules, matching Go'sjson:",omitzero"(never"Container":nullor"Env":"", which would be tells). The wire-key test asserts both the populated keys and the omit behavior.Not filled (deliberate, honest)
cloudenv.Get): needs cloud-metadata probes (network); deferred. Both tracked as thetsr-ajyctail.Verification
cargo test -p geiserx_ts_control(234, incl. the env-cascade test) +geiserx_ts_control_serde(78, incl. the Container/Env wire-parity test) +geiserx_ts_runtime(328);clippy -D warnings(0);fmt;cargo run -p checksall green.Created using Claude Code (Opus 4.8)
Summary by CodeRabbit
Release Notes