mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: add agentapi endpoint to report connections for audit (#16507)
This change adds a new `ReportConnection` endpoint to the `agentapi`. The protocol version was bumped previously, so it has been omitted here. This allows the agent to report connection events, for example when the user connects to the workspace via SSH or VS Code. Updates #15139
This commit is contained in:
@@ -372,7 +372,6 @@ func (a *agent) collectMetadata(ctx context.Context, md codersdk.WorkspaceAgentM
|
||||
// Important: if the command times out, we may see a misleading error like
|
||||
// "exit status 1", so it's important to include the context error.
|
||||
err = errors.Join(err, ctx.Err())
|
||||
|
||||
if err != nil {
|
||||
result.Error = fmt.Sprintf("run cmd: %+v", err)
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"golang.org/x/exp/slices"
|
||||
"golang.org/x/xerrors"
|
||||
"google.golang.org/protobuf/types/known/durationpb"
|
||||
"google.golang.org/protobuf/types/known/emptypb"
|
||||
"storj.io/drpc/drpcmux"
|
||||
"storj.io/drpc/drpcserver"
|
||||
"tailscale.com/tailcfg"
|
||||
@@ -170,6 +171,7 @@ type FakeAgentAPI struct {
|
||||
lifecycleStates []codersdk.WorkspaceAgentLifecycle
|
||||
metadata map[string]agentsdk.Metadata
|
||||
timings []*agentproto.Timing
|
||||
connections []*agentproto.Connection
|
||||
|
||||
getAnnouncementBannersFunc func() ([]codersdk.BannerConfig, error)
|
||||
getResourcesMonitoringConfigurationFunc func() (*agentproto.GetResourcesMonitoringConfigurationResponse, error)
|
||||
@@ -338,12 +340,20 @@ func (f *FakeAgentAPI) BatchCreateLogs(ctx context.Context, req *agentproto.Batc
|
||||
|
||||
func (f *FakeAgentAPI) ScriptCompleted(_ context.Context, req *agentproto.WorkspaceAgentScriptCompletedRequest) (*agentproto.WorkspaceAgentScriptCompletedResponse, error) {
|
||||
f.Lock()
|
||||
f.timings = append(f.timings, req.Timing)
|
||||
f.timings = append(f.timings, req.GetTiming())
|
||||
f.Unlock()
|
||||
|
||||
return &agentproto.WorkspaceAgentScriptCompletedResponse{}, nil
|
||||
}
|
||||
|
||||
func (f *FakeAgentAPI) ReportConnection(_ context.Context, req *agentproto.ReportConnectionRequest) (*emptypb.Empty, error) {
|
||||
f.Lock()
|
||||
f.connections = append(f.connections, req.GetConnection())
|
||||
f.Unlock()
|
||||
|
||||
return &emptypb.Empty{}, nil
|
||||
}
|
||||
|
||||
func NewFakeAgentAPI(t testing.TB, logger slog.Logger, manifest *agentproto.Manifest, statsCh chan *agentproto.Stats) *FakeAgentAPI {
|
||||
return &FakeAgentAPI{
|
||||
t: t,
|
||||
|
||||
+1025
-702
File diff suppressed because it is too large
Load Diff
@@ -6,6 +6,7 @@ package coder.agent.v2;
|
||||
import "tailnet/proto/tailnet.proto";
|
||||
import "google/protobuf/timestamp.proto";
|
||||
import "google/protobuf/duration.proto";
|
||||
import "google/protobuf/empty.proto";
|
||||
|
||||
message WorkspaceApp {
|
||||
bytes id = 1;
|
||||
@@ -340,6 +341,33 @@ message PushResourcesMonitoringUsageRequest {
|
||||
message PushResourcesMonitoringUsageResponse {
|
||||
}
|
||||
|
||||
message Connection {
|
||||
enum Action {
|
||||
ACTION_UNSPECIFIED = 0;
|
||||
CONNECT = 1;
|
||||
DISCONNECT = 2;
|
||||
}
|
||||
enum Type {
|
||||
TYPE_UNSPECIFIED = 0;
|
||||
SSH = 1;
|
||||
VSCODE = 2;
|
||||
JETBRAINS = 3;
|
||||
RECONNECTING_PTY = 4;
|
||||
}
|
||||
|
||||
bytes id = 1;
|
||||
Action action = 2;
|
||||
Type type = 3;
|
||||
google.protobuf.Timestamp timestamp = 4;
|
||||
string ip = 5;
|
||||
int32 status_code = 6;
|
||||
optional string reason = 7;
|
||||
}
|
||||
|
||||
message ReportConnectionRequest {
|
||||
Connection connection = 1;
|
||||
}
|
||||
|
||||
service Agent {
|
||||
rpc GetManifest(GetManifestRequest) returns (Manifest);
|
||||
rpc GetServiceBanner(GetServiceBannerRequest) returns (ServiceBanner);
|
||||
@@ -353,4 +381,5 @@ service Agent {
|
||||
rpc ScriptCompleted(WorkspaceAgentScriptCompletedRequest) returns (WorkspaceAgentScriptCompletedResponse);
|
||||
rpc GetResourcesMonitoringConfiguration(GetResourcesMonitoringConfigurationRequest) returns (GetResourcesMonitoringConfigurationResponse);
|
||||
rpc PushResourcesMonitoringUsage(PushResourcesMonitoringUsageRequest) returns (PushResourcesMonitoringUsageResponse);
|
||||
rpc ReportConnection(ReportConnectionRequest) returns (google.protobuf.Empty);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
errors "errors"
|
||||
protojson "google.golang.org/protobuf/encoding/protojson"
|
||||
proto "google.golang.org/protobuf/proto"
|
||||
emptypb "google.golang.org/protobuf/types/known/emptypb"
|
||||
drpc "storj.io/drpc"
|
||||
drpcerr "storj.io/drpc/drpcerr"
|
||||
)
|
||||
@@ -50,6 +51,7 @@ type DRPCAgentClient interface {
|
||||
ScriptCompleted(ctx context.Context, in *WorkspaceAgentScriptCompletedRequest) (*WorkspaceAgentScriptCompletedResponse, error)
|
||||
GetResourcesMonitoringConfiguration(ctx context.Context, in *GetResourcesMonitoringConfigurationRequest) (*GetResourcesMonitoringConfigurationResponse, error)
|
||||
PushResourcesMonitoringUsage(ctx context.Context, in *PushResourcesMonitoringUsageRequest) (*PushResourcesMonitoringUsageResponse, error)
|
||||
ReportConnection(ctx context.Context, in *ReportConnectionRequest) (*emptypb.Empty, error)
|
||||
}
|
||||
|
||||
type drpcAgentClient struct {
|
||||
@@ -170,6 +172,15 @@ func (c *drpcAgentClient) PushResourcesMonitoringUsage(ctx context.Context, in *
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *drpcAgentClient) ReportConnection(ctx context.Context, in *ReportConnectionRequest) (*emptypb.Empty, error) {
|
||||
out := new(emptypb.Empty)
|
||||
err := c.cc.Invoke(ctx, "/coder.agent.v2.Agent/ReportConnection", drpcEncoding_File_agent_proto_agent_proto{}, in, out)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
type DRPCAgentServer interface {
|
||||
GetManifest(context.Context, *GetManifestRequest) (*Manifest, error)
|
||||
GetServiceBanner(context.Context, *GetServiceBannerRequest) (*ServiceBanner, error)
|
||||
@@ -183,6 +194,7 @@ type DRPCAgentServer interface {
|
||||
ScriptCompleted(context.Context, *WorkspaceAgentScriptCompletedRequest) (*WorkspaceAgentScriptCompletedResponse, error)
|
||||
GetResourcesMonitoringConfiguration(context.Context, *GetResourcesMonitoringConfigurationRequest) (*GetResourcesMonitoringConfigurationResponse, error)
|
||||
PushResourcesMonitoringUsage(context.Context, *PushResourcesMonitoringUsageRequest) (*PushResourcesMonitoringUsageResponse, error)
|
||||
ReportConnection(context.Context, *ReportConnectionRequest) (*emptypb.Empty, error)
|
||||
}
|
||||
|
||||
type DRPCAgentUnimplementedServer struct{}
|
||||
@@ -235,9 +247,13 @@ func (s *DRPCAgentUnimplementedServer) PushResourcesMonitoringUsage(context.Cont
|
||||
return nil, drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented)
|
||||
}
|
||||
|
||||
func (s *DRPCAgentUnimplementedServer) ReportConnection(context.Context, *ReportConnectionRequest) (*emptypb.Empty, error) {
|
||||
return nil, drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented)
|
||||
}
|
||||
|
||||
type DRPCAgentDescription struct{}
|
||||
|
||||
func (DRPCAgentDescription) NumMethods() int { return 12 }
|
||||
func (DRPCAgentDescription) NumMethods() int { return 13 }
|
||||
|
||||
func (DRPCAgentDescription) Method(n int) (string, drpc.Encoding, drpc.Receiver, interface{}, bool) {
|
||||
switch n {
|
||||
@@ -349,6 +365,15 @@ func (DRPCAgentDescription) Method(n int) (string, drpc.Encoding, drpc.Receiver,
|
||||
in1.(*PushResourcesMonitoringUsageRequest),
|
||||
)
|
||||
}, DRPCAgentServer.PushResourcesMonitoringUsage, true
|
||||
case 12:
|
||||
return "/coder.agent.v2.Agent/ReportConnection", drpcEncoding_File_agent_proto_agent_proto{},
|
||||
func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) {
|
||||
return srv.(DRPCAgentServer).
|
||||
ReportConnection(
|
||||
ctx,
|
||||
in1.(*ReportConnectionRequest),
|
||||
)
|
||||
}, DRPCAgentServer.ReportConnection, true
|
||||
default:
|
||||
return "", nil, nil, nil, false
|
||||
}
|
||||
@@ -549,3 +574,19 @@ func (x *drpcAgent_PushResourcesMonitoringUsageStream) SendAndClose(m *PushResou
|
||||
}
|
||||
return x.CloseSend()
|
||||
}
|
||||
|
||||
type DRPCAgent_ReportConnectionStream interface {
|
||||
drpc.Stream
|
||||
SendAndClose(*emptypb.Empty) error
|
||||
}
|
||||
|
||||
type drpcAgent_ReportConnectionStream struct {
|
||||
drpc.Stream
|
||||
}
|
||||
|
||||
func (x *drpcAgent_ReportConnectionStream) SendAndClose(m *emptypb.Empty) error {
|
||||
if err := x.MsgSend(m, drpcEncoding_File_agent_proto_agent_proto{}); err != nil {
|
||||
return err
|
||||
}
|
||||
return x.CloseSend()
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package proto
|
||||
import (
|
||||
"context"
|
||||
|
||||
emptypb "google.golang.org/protobuf/types/known/emptypb"
|
||||
"storj.io/drpc"
|
||||
)
|
||||
|
||||
@@ -41,10 +42,11 @@ type DRPCAgentClient23 interface {
|
||||
ScriptCompleted(ctx context.Context, in *WorkspaceAgentScriptCompletedRequest) (*WorkspaceAgentScriptCompletedResponse, error)
|
||||
}
|
||||
|
||||
// DRPCAgentClient24 is the Agent API at v2.4. It adds the GetResourcesMonitoringConfiguration and
|
||||
// PushResourcesMonitoringUsage RPCs. Compatible with Coder v2.19+
|
||||
// DRPCAgentClient24 is the Agent API at v2.4. It adds the GetResourcesMonitoringConfiguration,
|
||||
// PushResourcesMonitoringUsage and ReportConnection RPCs. Compatible with Coder v2.19+
|
||||
type DRPCAgentClient24 interface {
|
||||
DRPCAgentClient23
|
||||
GetResourcesMonitoringConfiguration(ctx context.Context, in *GetResourcesMonitoringConfigurationRequest) (*GetResourcesMonitoringConfigurationResponse, error)
|
||||
PushResourcesMonitoringUsage(ctx context.Context, in *PushResourcesMonitoringUsageRequest) (*PushResourcesMonitoringUsageResponse, error)
|
||||
ReportConnection(ctx context.Context, in *ReportConnectionRequest) (*emptypb.Empty, error)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user