Skip to content
Open
Show file tree
Hide file tree
Changes from 83 commits
Commits
Show all changes
86 commits
Select commit Hold shift + click to select a range
271c353
feat(procmgr): Windows spawn profiles foundation (split PR 1/4)
jose-manuel-almaza Aug 11, 2026
73c861c
fix(procmgr): fix gazelle and lint CI for spawn profiles E2E helpers
jose-manuel-almaza Aug 11, 2026
3dd8c35
test(e2e): reload procmgr after removing temp userprofile process
jose-manuel-almaza Aug 11, 2026
c77dc56
fix(procmgr): resolve duplicate platform modules for Linux Bazel CI
jose-manuel-almaza Aug 11, 2026
418bcc3
fix(procmgr): update CODEOWNERS for platform/windows directory
jose-manuel-almaza Aug 12, 2026
7971860
fix(procmgr): move config gate integration tests to stacked PR #54732
jose-manuel-almaza Aug 12, 2026
c7fa3a9
fix(procmgr): resolve Windows Clippy failures in spawn managed path
jose-manuel-almaza Aug 12, 2026
a11a45e
refactor(procmgr): keep spawn PR Windows platform code spawn-only
jose-manuel-almaza Aug 12, 2026
340e2f4
fix(procmgr): open redirected stdio logs with append-only access on W…
jose-manuel-almaza Aug 12, 2026
7e4dc39
fix(procmgr): fall back to inherit when Windows stdio file redirect f…
jose-manuel-almaza Aug 12, 2026
c1a0ded
fix(procmgr): terminate suspended child when ResumeThread fails on Wi…
jose-manuel-almaza Aug 12, 2026
5da693e
fix(procmgr): keep manually started auto_start=false processes on reload
jose-manuel-almaza Aug 12, 2026
e054a15
style(procmgr): fix rustfmt in Windows stdio test
jose-manuel-almaza Aug 12, 2026
c20757e
fix(procmgr): restart processes when condition_path_exists reopens on…
jose-manuel-almaza Aug 12, 2026
39c77f3
fix(procmgr): retain Windows user profile until child exit is observed
jose-manuel-almaza Aug 12, 2026
c4d5091
fix(procmgr): clear Windows profile after watcher observes stop exit
jose-manuel-almaza Aug 12, 2026
26c1916
fix(procmgr): honor restart policy for manually started processes
jose-manuel-almaza Aug 12, 2026
87b2fd0
fix(procmgr): restart running auto_start=false processes after config…
jose-manuel-almaza Aug 12, 2026
6a723f0
fix(procmgr): rustfmt reload test signatures in manager.rs
jose-manuel-almaza Aug 12, 2026
b8349df
refactor(procmgr): split coat linux tests into separate Bazel target
jose-manuel-almaza Aug 12, 2026
406a72f
refactor(procmgr): defer process-agent COAT catalog to integration PR
jose-manuel-almaza Aug 12, 2026
2ef857a
fix(procmgr): release Windows profile on late exit after force-kill t…
jose-manuel-almaza Aug 12, 2026
cf424a4
fix(procmgr): isolate deferred Windows profile from respawned child
jose-manuel-almaza Aug 12, 2026
f667a5d
fix(procmgr): stop manual processes when path gate closes on reload
jose-manuel-almaza Aug 12, 2026
925ca8d
fix(procmgr): retain deferred Windows profiles per PID
jose-manuel-almaza Aug 12, 2026
4b81e9f
fix(procmgr): retain orphaned Windows profiles after config removal
jose-manuel-almaza Aug 12, 2026
2a21793
fix(procmgr): wait for job descendants before Windows profile unload
jose-manuel-almaza Aug 12, 2026
6d1c1a2
fix(procmgr): retain Windows job handle through force-kill termination
jose-manuel-almaza Aug 12, 2026
98f8358
fix(procmgr): keep deferred Windows job drain polling until complete
jose-manuel-almaza Aug 12, 2026
c3ff729
fix(procmgr): defer Windows job drain without blocking event loop
jose-manuel-almaza Aug 12, 2026
dc4fc8f
fix(procmgr): satisfy rustfmt and clippy on Linux CI
jose-manuel-almaza Aug 12, 2026
788049f
fix(procmgr): await deferred job drains during daemon shutdown
jose-manuel-almaza Aug 12, 2026
4521df6
fix(procmgr): allow log rotation on Windows redirected stdout/stderr
jose-manuel-almaza Aug 12, 2026
c6038d6
fix(procmgr): fix Windows compile errors in deferred job drain
jose-manuel-almaza Aug 13, 2026
978cfca
fix(procmgr): terminate residual job members before deferred drain
jose-manuel-almaza Aug 13, 2026
699504e
fix(procmgr): invalidate stale restart retries after config reload
jose-manuel-almaza Aug 13, 2026
eb9b333
fix(procmgr): log state and restart policy on restart skip
jose-manuel-almaza Aug 13, 2026
f256e5b
refactor(procmgr): split restart policy from backoff scheduling
jose-manuel-almaza Aug 13, 2026
f475043
fix(procmgr): discard orphaned restarts after process removal
jose-manuel-almaza Aug 13, 2026
8b7b01a
fix(procmgr): defer Windows profile unload when job query fails
jose-manuel-almaza Aug 13, 2026
e276189
fix(procmgr): await orphaned job drains during Windows shutdown
jose-manuel-almaza Aug 13, 2026
6024728
fix(procmgr): retain orphaned cleanup when job query fails
jose-manuel-almaza Aug 13, 2026
b44d38d
fix(procmgr): check admin pipe clients via TokenGroups
jose-manuel-almaza Aug 13, 2026
bce4877
fix(procmgr): bound deferred job drain wait during shutdown
jose-manuel-almaza Aug 13, 2026
b299d07
fix(procmgr): preserve backoff across failed respawns
jose-manuel-almaza Aug 13, 2026
d49368b
fix(procmgr): bind late-exit cleanup to live process generation
jose-manuel-almaza Aug 13, 2026
dcd0542
test(procmgr): defer spawn-profile Windows E2E to process-agent PR
jose-manuel-almaza Aug 13, 2026
1472c76
fix(procmgr): preserve successful-run flag before restart delay
jose-manuel-almaza Aug 13, 2026
80ca5b8
fix(procmgr): revalidate restart policy before stale retries
jose-manuel-almaza Aug 13, 2026
ec1cc35
refactor(procmgr): move respawn policy checks onto ManagedProcess
jose-manuel-almaza Aug 13, 2026
4050f1f
chore(procmgr): drop redundant respawn helper docs
jose-manuel-almaza Aug 13, 2026
fe41829
refactor(procmgr): rename should_start to should_auto_start
jose-manuel-almaza Aug 13, 2026
9f504ec
refactor(procmgr): rename should_auto_start/should_respawn to may_*
jose-manuel-almaza Aug 13, 2026
5985b87
refactor(procmgr): replace restart Option<bool> with RestartDecision
jose-manuel-almaza Aug 13, 2026
62ac232
fix(procmgr): persist successful-run state across restart delays
jose-manuel-almaza Aug 13, 2026
6de562b
refactor(procmgr): extract try_spawn_and_watch helper in manager
jose-manuel-almaza Aug 13, 2026
48bd0ed
fix(procmgr): fail spawn when Windows job assignment fails
jose-manuel-almaza Aug 13, 2026
6af3dd2
fix(procmgr): preserve successful-run state across config reload
jose-manuel-almaza Aug 13, 2026
318241a
refactor(procmgr): rename restart_delay to schedule_restart
jose-manuel-almaza Aug 13, 2026
5d0be11
fix(procmgr): schedule job drain when stop watcher loses exit status
jose-manuel-almaza Aug 13, 2026
92c2d32
refactor(procmgr): extract find_index_by_name for process lookup
jose-manuel-almaza Aug 13, 2026
9d147a1
chore(procmgr): trim redundant comments in spawn-profile PR
jose-manuel-almaza Aug 13, 2026
224d54f
fix(procmgr): discard superseded restart timers after config reload
jose-manuel-almaza Aug 13, 2026
d86f5f5
refactor(procmgr): simplify reload restart handling
jose-manuel-almaza Aug 13, 2026
379e715
fix(procmgr): wait for suspended spawn failures before profile unload
jose-manuel-almaza Aug 13, 2026
004bdc3
Fix procmgr CI: rustfmt, clippy, and ddot e2e log expectation.
jose-manuel-almaza Aug 14, 2026
363a1d2
refactor(procmgr): unify process stop and sync Windows job drain
jose-manuel-almaza Aug 14, 2026
f1ce771
refactor(procmgr): clarify ManagedProcess stop flow
jose-manuel-almaza Aug 14, 2026
9b66dec
refactor(procmgr): rename shadowed handles in spawn_watcher
jose-manuel-almaza Aug 14, 2026
e046abe
fix(procmgr): bound wait after failed suspended-child spawn on Windows
jose-manuel-almaza Aug 14, 2026
ffb1991
fix(e2e): drop unused Windows procmgr helpers from spawn-profiles PR
jose-manuel-almaza Aug 14, 2026
8a0fb1a
refactor(procmgr): split handle_reload_config into manager helpers
jose-manuel-almaza Aug 14, 2026
2101886
fix(procmgr): resolve Windows suspended spawn borrow checker errors
jose-manuel-almaza Aug 14, 2026
e37aaca
refactor(procmgr): defer secret cache clear to secret-backend PR
jose-manuel-almaza Aug 14, 2026
86a6098
refactor(procmgr): defer config gates to config-gates PR
jose-manuel-almaza Aug 14, 2026
7084917
refactor(procmgr): centralize condition_path_exists logging
jose-manuel-almaza Aug 14, 2026
61f1872
refactor(procmgr): compare reload configs without redundant deref
jose-manuel-almaza Aug 14, 2026
b1095ea
refactor(procmgr): split ProcessManager runtime into Supervisor
jose-manuel-almaza Aug 14, 2026
300c6e5
refactor(procmgr): move ProcessManager into process_manager.rs
jose-manuel-almaza Aug 14, 2026
e7445b4
refactor(procmgr): colocate startup order helper with ProcessManager
jose-manuel-almaza Aug 14, 2026
1831290
fix(procmgr): satisfy Windows CI rustfmt and clippy checks
jose-manuel-almaza Aug 14, 2026
a5ef62f
test(procmgr): drop PAR Windows E2E from spawn-profiles PR
jose-manuel-almaza Aug 17, 2026
5de957c
test(procmgr): revert unrelated Windows E2E refactor from spawn-profi…
jose-manuel-almaza Aug 17, 2026
09d7171
fix(procmgr): restore signal-all phase in ordered shutdown
jose-manuel-almaza Aug 17, 2026
f370c8a
fix(procmgr): retry failed manual processes on config reload
jose-manuel-almaza Aug 17, 2026
705ed08
refactor(procmgr): remove config reload for follow-up PR
jose-manuel-almaza Aug 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -685,7 +685,7 @@
/pkg/pidfile/ @DataDog/agent-runtimes
/pkg/persistentcache/ @DataDog/agent-runtimes
/pkg/procmgr/ @DataDog/agent-runtimes
/pkg/procmgr/rust/src/platform/windows.rs @DataDog/agent-runtimes @DataDog/windows-products
/pkg/procmgr/rust/src/platform/windows/ @DataDog/agent-runtimes @DataDog/windows-products
/pkg/procmgr/rust/src/transport/named_pipe.rs @DataDog/agent-runtimes @DataDog/windows-products
/pkg/privateactionrunner/ @DataDog/action-platform
/pkg/privateactionrunner/bundles/remoteaction/rshell @DataDog/action-platform @DataDog/dd-agent-mcp @DataDog/fleet-remediation
Expand Down
15 changes: 15 additions & 0 deletions pkg/procmgr/coat/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -108,15 +108,30 @@ go_library(
"@com_github_microsoft_go_winio//:go-winio",
"@org_golang_google_grpc//:grpc",
"@org_golang_google_grpc//credentials/insecure",
"@org_golang_x_sys//windows",
],
"//conditions:default": [],
}),
)

dd_agent_go_test(
name = "coat_test",
# keep: split from coat_linux_test.
srcs = ["services_test.go"],
embed = [":coat"],
# keep: procmgr dep is in coat_linux_test only.
deps = [
"@com_github_stretchr_testify//assert",
"@com_github_stretchr_testify//require",
],
)

dd_agent_go_test(
name = "coat_linux_test",
# keep: split from coat_test.
srcs = ["collector_test.go"],
embed = [":coat"],
target_compatible_with = ["@platforms//os:linux"],
deps = [
"//pkg/proto/pbgo/procmgr",
"@com_github_stretchr_testify//assert",
Expand Down
10 changes: 8 additions & 2 deletions pkg/procmgr/coat/client_grpc_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"net"

"github.com/Microsoft/go-winio"
"golang.org/x/sys/windows"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
)
Expand All @@ -21,8 +22,13 @@ func dialProcmgrGRPC(socketPath string) (*grpc.ClientConn, error) {
conn, err := grpc.NewClient(
"passthrough:///procmgr",
grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithContextDialer(func(_ context.Context, _ string) (net.Conn, error) {
return winio.DialPipe(socketPath, nil)
grpc.WithContextDialer(func(ctx context.Context, _ string) (net.Conn, error) {
return winio.DialPipeAccessImpLevel(
ctx,
socketPath,
uint32(windows.GENERIC_READ|windows.GENERIC_WRITE),
winio.PipeImpLevelIdentification,
)
}),
)
if err != nil {
Expand Down
61 changes: 38 additions & 23 deletions pkg/procmgr/coat/collector_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2026-present Datadog, Inc.

//go:build linux

package coat

import (
Expand Down Expand Up @@ -59,9 +61,13 @@ func (s *mockSession) Disconnect() error {
return nil
}

func serviceSnapshotByID(t *testing.T, snapshot Snapshot, id string) ServiceSnapshot {
func requireServiceCount(t *testing.T, snapshot Snapshot) {
t.Helper()
require.Len(t, snapshot.Services, len(migratableServices))
}

func serviceSnapshotByID(t *testing.T, snapshot Snapshot, id string) ServiceSnapshot {
t.Helper()
for _, service := range snapshot.Services {
if service.ID == id {
return service
Expand All @@ -79,43 +85,41 @@ func installMarkerForTest(t *testing.T, root string, service MigratableService,
return markers[index]
}

func setupDDOTInstallFixture(t *testing.T) string {
func setupInstallFixture(t *testing.T, service MigratableService, markerRel string) string {
t.Helper()

ddot, ok := serviceByID("ddot")
require.True(t, ok)

root := t.TempDir()
marker := installMarkerForTest(t, root, ddot, 0)
marker := filepath.Join(root, markerRel)
require.NoError(t, os.MkdirAll(filepath.Dir(marker), 0o755))
require.NoError(t, os.WriteFile(marker, []byte("bin"), 0o644))
require.NoError(t, os.MkdirAll(filepath.Join(root, processesDirRel), 0o755))
require.NoError(t, os.WriteFile(
filepath.Join(root, processesDirRel, ddot.ProcmgrConfigFile),
filepath.Join(root, processesDirRel, service.ProcmgrConfigFile),
[]byte("cfg"),
0o644,
))
return root
}

func setupDDOTInstallFixture(t *testing.T) string {
t.Helper()

ddot, ok := serviceByID("ddot")
require.True(t, ok)
return setupInstallFixture(t, ddot, ddot.InstallMarkerRels[0])
}

func TestCollectInstalledViaStandaloneMarkerOnly(t *testing.T) {
ddot, ok := serviceByID("ddot")
require.True(t, ok)

root := t.TempDir()
standalone := installMarkerForTest(t, root, ddot, 1)
require.NoError(t, os.MkdirAll(filepath.Dir(standalone), 0o755))
require.NoError(t, os.WriteFile(standalone, []byte("bin"), 0o644))
require.NoError(t, os.MkdirAll(filepath.Join(root, processesDirRel), 0o755))
require.NoError(t, os.WriteFile(
filepath.Join(root, processesDirRel, ddot.ProcmgrConfigFile),
[]byte("cfg"),
0o644,
))
root := setupInstallFixture(t, ddot, ddot.InstallMarkerRels[1])

collector := NewCollectorWithClient(root, &mockClient{})

snapshot := collector.Collect(context.Background())
requireServiceCount(t, snapshot)

service := serviceSnapshotByID(t, snapshot, "ddot")
assert.True(t, service.Installed,
"standalone datadog-agent-ddot layout uses embedded/bin/otel-agent without ext/ddot")
Expand All @@ -132,6 +136,7 @@ func TestCollectServiceProcmgrRunning(t *testing.T) {
})

snapshot := collector.Collect(context.Background())
requireServiceCount(t, snapshot)

service := serviceSnapshotByID(t, snapshot, "ddot")
assert.Equal(t, "ddot", service.ID)
Expand All @@ -153,7 +158,7 @@ func TestCollectADPProcmgrRunning(t *testing.T) {
require.NoError(t, os.WriteFile(marker, []byte("bin"), 0o644))
require.NoError(t, os.MkdirAll(filepath.Join(root, processesDirRel), 0o755))
require.NoError(t, os.WriteFile(
filepath.Join(root, processesDirRel, "datadog-agent-data-plane.yaml"),
filepath.Join(root, processesDirRel, adp.ProcmgrConfigFile),
[]byte("cfg"),
0o644,
))
Expand All @@ -166,6 +171,7 @@ func TestCollectADPProcmgrRunning(t *testing.T) {
})

snapshot := collector.Collect(context.Background())
requireServiceCount(t, snapshot)

service := serviceSnapshotByID(t, snapshot, "agent-data-plane")
assert.Equal(t, "agent-data-plane", service.ID)
Expand All @@ -185,6 +191,7 @@ func TestCollectServiceProcmgrNotRunningStillManaged(t *testing.T) {
})

snapshot := collector.Collect(context.Background())
requireServiceCount(t, snapshot)

service := serviceSnapshotByID(t, snapshot, "ddot")
assert.Equal(t, ManagementModeProcmgr, service.ManagementMode)
Expand All @@ -197,12 +204,14 @@ func TestCollectNoProcmgrNoLegacy(t *testing.T) {
collector := NewCollectorWithClient(root, &mockClient{})

snapshot := collector.Collect(context.Background())
requireServiceCount(t, snapshot)

service := serviceSnapshotByID(t, snapshot, "ddot")
assert.False(t, service.Installed)
assert.False(t, service.ProcmgrConfigured)
assert.Equal(t, ManagementModeNone, service.ManagementMode)
assert.Equal(t, pb.ProcessState_UNKNOWN, service.ProcmgrState)
for _, service := range snapshot.Services {
assert.False(t, service.Installed)
assert.False(t, service.ProcmgrConfigured)
assert.Equal(t, ManagementModeNone, service.ManagementMode)
assert.Equal(t, pb.ProcessState_UNKNOWN, service.ProcmgrState)
}
}

func TestCollectInstallMarkerAbsent(t *testing.T) {
Expand All @@ -220,6 +229,7 @@ func TestCollectInstallMarkerAbsent(t *testing.T) {
collector := NewCollectorWithClient(root, &mockClient{})

snapshot := collector.Collect(context.Background())
requireServiceCount(t, snapshot)

service := serviceSnapshotByID(t, snapshot, "ddot")
assert.False(t, service.Installed, "without install marker, Installed must stay false")
Expand All @@ -239,6 +249,7 @@ func TestCollectProcmgrConfigAbsent(t *testing.T) {
collector := NewCollectorWithClient(root, &mockClient{})

snapshot := collector.Collect(context.Background())
requireServiceCount(t, snapshot)

service := serviceSnapshotByID(t, snapshot, "ddot")
assert.True(t, service.Installed)
Expand All @@ -260,6 +271,8 @@ func TestCollectDaemonUnreachable(t *testing.T) {

assert.False(t, snapshot.Daemon.Reachable, "daemon status error should yield empty snapshot")
assert.False(t, snapshot.Daemon.Ready)
requireServiceCount(t, snapshot)

service := serviceSnapshotByID(t, snapshot, "ddot")
assert.Equal(t, ManagementModeNone, service.ManagementMode,
"daemon failure prevents listing processes")
Expand All @@ -279,6 +292,8 @@ func TestCollectDaemonReachableListFails(t *testing.T) {

assert.True(t, snapshot.Daemon.Reachable)
assert.True(t, snapshot.Daemon.Ready)
requireServiceCount(t, snapshot)

service := serviceSnapshotByID(t, snapshot, "ddot")
assert.Equal(t, ManagementModeNone, service.ManagementMode)
assert.Equal(t, pb.ProcessState_UNKNOWN, service.ProcmgrState)
Expand Down
35 changes: 35 additions & 0 deletions pkg/procmgr/coat/services_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Unless explicitly stated otherwise all files in this repository are licensed
// under the Apache License Version 2.0.
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2026-present Datadog, Inc.

package coat

import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestMigratableServicesCatalog(t *testing.T) {
require.NotEmpty(t, migratableServices)

seen := make(map[string]struct{}, len(migratableServices))
for _, service := range migratableServices {
_, dup := seen[service.ID]
assert.False(t, dup, "duplicate service id %q", service.ID)
seen[service.ID] = struct{}{}

assert.NotEmpty(t, service.ProcmgrProcessName)
assert.NotEmpty(t, service.ProcmgrConfigFile)
assert.NotEmpty(t, service.InstallMarkerRels)
assert.NotEmpty(t, service.LegacySystemdUnits)
}
}

func TestServiceByID(t *testing.T) {
service, ok := serviceByID("ddot")
require.True(t, ok)
assert.Equal(t, "datadog-agent-ddot", service.ProcmgrProcessName)
}
9 changes: 8 additions & 1 deletion pkg/procmgr/rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ tonic-reflection.workspace = true
uuid.workspace = true

[target.'cfg(unix)'.dependencies]
nix = { workspace = true, features = ["signal", "process"] }
nix = { workspace = true, features = ["signal", "process", "user"] }

[target.'cfg(windows)'.dependencies]
windows-registry.workspace = true
Expand All @@ -48,9 +48,16 @@ windows-sys = { workspace = true, features = [
"Win32_System_Threading",
"Win32_System_Console",
"Win32_System_Environment",
"Win32_UI_Shell",
"Win32_Security",
"Win32_Security_Authentication_Identity",
"Win32_Security_Authorization",
"Win32_System_Pipes",
"Win32_System_Registry",
"Win32_System_SystemInformation",
"Win32_System_WindowsProgramming",
"Win32_Storage_FileSystem",
"Win32_NetworkManagement_NetManagement",
] }

[target.'cfg(unix)'.dev-dependencies]
Expand Down
4 changes: 2 additions & 2 deletions pkg/procmgr/rust/src/bins/dd-procmgrd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ fn main() {

#[cfg(windows)]
fn run() -> anyhow::Result<()> {
dd_procmgrd::service::run_as_service()
dd_procmgrd::platform::run_as_service()
}

#[cfg(not(windows))]
Expand All @@ -41,6 +41,6 @@ fn run() -> anyhow::Result<()> {
runtime.block_on(async {
let loader = Arc::new(YamlConfigLoader::from_env());
let mgr = ProcessManager::new(loader, Arc::new(V4UuidGenerator));
mgr.run().await
mgr.supervisor().run().await
})
}
36 changes: 36 additions & 0 deletions pkg/procmgr/rust/src/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,42 @@
// Copyright 2026-present Datadog, Inc.

use anyhow::{Context, Result};
use log::warn;

pub(crate) fn expand_env_vars(input: &str) -> String {
expand_vars_with(input, |name| std::env::var(name).ok())
}

pub(crate) fn expand_vars_with(input: &str, lookup: impl Fn(&str) -> Option<String>) -> String {
let mut out = String::with_capacity(input.len());
let mut rest = input;
while let Some(start) = rest.find("${") {
out.push_str(&rest[..start]);
let after = &rest[start + 2..];
match after.find('}') {
Some(end) => {
let name = &after[..end];
match lookup(name) {
Some(val) => out.push_str(&val),
None => {
warn!(
"process config references unset variable ${{{name}}}, leaving it literal"
);
out.push_str(&rest[start..start + 2 + end + 1]);
}
}
rest = &after[end + 1..];
}
None => {
// No closing brace: emit verbatim.
out.push_str(&rest[start..]);
return out;
}
}
}
out.push_str(rest);
out
}

/// Parse a systemd-style environment file into key-value pairs.
/// Supports `KEY=VALUE`, `KEY="VALUE"`, `KEY='VALUE'`, comments (#), and blank lines.
Expand Down
30 changes: 30 additions & 0 deletions pkg/procmgr/rust/src/grpc/caller_auth.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Unless explicitly stated otherwise all files in this repository are licensed
// under the Apache License Version 2.0.
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2026-present Datadog, Inc.

use tonic::{Request, Status};

#[cfg(windows)]
use crate::transport::PipeCallerAuth;

/// Windows: `Create` requires Administrator or LocalSystem pipe client.
#[cfg(windows)]
pub(crate) fn require_privileged_pipe_client<T>(request: &Request<T>) -> Result<(), Status> {
let may_mutate = request
.extensions()
.get::<PipeCallerAuth>()
.map(PipeCallerAuth::may_mutate)
.unwrap_or(false);
if !may_mutate {
return Err(Status::permission_denied(
"operation requires an Administrator or LocalSystem pipe client",
));
}
Ok(())
}

#[cfg(not(windows))]
pub(crate) fn require_privileged_pipe_client<T>(_request: &Request<T>) -> Result<(), Status> {
Ok(())
}
Loading
Loading