From 23763c82107f4fe618abab4994c35acddc6db0fe Mon Sep 17 00:00:00 2001 From: naiba Date: Mon, 20 Jul 2026 17:04:52 +0000 Subject: [PATCH] fix(agentcompat): secure legacy file manager boundaries Co-authored-by: naiba/CloudCode --- .../agentcompat/internal/scenario/legacy_fm.go | 14 ++++++++------ .../internal/scenario/legacy_fm_support.go | 9 +++++---- .../internal/scenario/legacy_fm_verification.go | 6 +++--- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/integration/agentcompat/internal/scenario/legacy_fm.go b/integration/agentcompat/internal/scenario/legacy_fm.go index 6703f56e..0c6ce812 100644 --- a/integration/agentcompat/internal/scenario/legacy_fm.go +++ b/integration/agentcompat/internal/scenario/legacy_fm.go @@ -101,12 +101,14 @@ func (LegacyFM) Run(ctx context.Context, input LegacyFMInput) (result Result, ru payload := bytes.Repeat(payloadPattern, (1<<20+257)/len(payloadPattern)+1) payload = payload[:1<<20+257] sentinel := []byte("outside-fm-root-sentinel") - sentinelPaths := []string{ - filepath.Join(agentInstance.WorkspaceRoot(), "outside-fm-root-a.txt"), - filepath.Join(agentInstance.WorkspaceRoot(), "outside-fm-root-b.txt"), + workspaceRoot, err := os.OpenRoot(agentInstance.WorkspaceRoot()) + if err != nil { + return finishLegacyFM(assertions, err) } - for _, path := range sentinelPaths { - if err := os.WriteFile(path, sentinel, 0o600); err != nil { + defer workspaceRoot.Close() + sentinelNames := []string{"outside-fm-root-a.txt", "outside-fm-root-b.txt"} + for _, name := range sentinelNames { + if err := workspaceRoot.WriteFile(name, sentinel, 0o600); err != nil { return finishLegacyFM(assertions, err) } } @@ -252,7 +254,7 @@ func (LegacyFM) Run(ctx context.Context, input LegacyFMInput) (result Result, ru return finishLegacyFM(assertions, err) } - sentinelErr := verifyLegacyFMSentinels(sentinelPaths, sentinel) + sentinelErr := verifyLegacyFMSentinels(workspaceRoot, sentinelNames, sentinel) assertions.Record("outside-root sentinels remain unchanged", sentinelErr == nil, errorText(sentinelErr)) if sentinelErr != nil { return finishLegacyFM(assertions, sentinelErr) diff --git a/integration/agentcompat/internal/scenario/legacy_fm_support.go b/integration/agentcompat/internal/scenario/legacy_fm_support.go index 3ebeb9a9..bb907210 100644 --- a/integration/agentcompat/internal/scenario/legacy_fm_support.go +++ b/integration/agentcompat/internal/scenario/legacy_fm_support.go @@ -21,6 +21,9 @@ type legacyFMUserForm struct { Password string `json:"password"` } +const legacyFMForeignUsername = "agentcompat-fm-foreign" +const legacyFMForeignPassword = "agentcompat-fm-password" // #nosec G101 -- Ephemeral localhost integration fixture, not a production credential. + type legacyFMFrameWriter interface { WriteFrame(context.Context, client.Frame) error } @@ -116,13 +119,11 @@ func findLegacyFMServerID(ctx context.Context, dashboardInstance *dashboard.Dash } func createForeignLegacyFMClient(ctx context.Context, dashboardInstance *dashboard.Dashboard) (*client.Client, func() error, error) { - const username = "agentcompat-fm-foreign" - const password = "agentcompat-fm-password" admin := dashboardInstance.Clients().REST userID, err := client.DoREST[legacyFMUserForm, uint64](ctx, admin, client.RESTRequest[legacyFMUserForm]{ Method: http.MethodPost, Path: "/api/v1/user", - Body: &legacyFMUserForm{Role: 1, Username: username, Password: password}, + Body: &legacyFMUserForm{Role: 1, Username: legacyFMForeignUsername, Password: legacyFMForeignPassword}, }) if err != nil { return nil, func() error { return nil }, err @@ -137,7 +138,7 @@ func createForeignLegacyFMClient(ctx context.Context, dashboardInstance *dashboa if err != nil { return nil, func() error { return nil }, errors.Join(err, cleanup()) } - if _, err := loginClient.Login(ctx, client.LoginRequest{Username: username, Password: password}); err != nil { + if _, err := loginClient.Login(ctx, client.LoginRequest{Username: legacyFMForeignUsername, Password: legacyFMForeignPassword}); err != nil { return nil, func() error { return nil }, errors.Join(err, cleanup()) } pat, err := client.DoREST[patRequest, patResponse](ctx, loginClient, client.RESTRequest[patRequest]{ diff --git a/integration/agentcompat/internal/scenario/legacy_fm_verification.go b/integration/agentcompat/internal/scenario/legacy_fm_verification.go index d6cfe472..4632b9c6 100644 --- a/integration/agentcompat/internal/scenario/legacy_fm_verification.go +++ b/integration/agentcompat/internal/scenario/legacy_fm_verification.go @@ -133,9 +133,9 @@ func newLegacyFMRunID() (string, error) { return hex.EncodeToString(bytes), nil } -func verifyLegacyFMSentinels(sentinelPaths []string, sentinel []byte) error { - for _, path := range sentinelPaths { - content, err := os.ReadFile(path) +func verifyLegacyFMSentinels(root *os.Root, sentinelNames []string, sentinel []byte) error { + for _, name := range sentinelNames { + content, err := root.ReadFile(name) if err != nil { return err }