Skip to content

feat(coderd/agentapi): implement sub agent api #17823

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 34 commits into from
May 29, 2025

Conversation

DanielleMaywood
Copy link
Contributor

@DanielleMaywood DanielleMaywood commented May 14, 2025

Closes coder/internal#619

Implement the coderd side of the AgentAPI for the upcoming dev-container agents work.

agent/agenttest/client.go is left unimplemented for a future PR working to implement the agent side of this feature.

@DanielleMaywood DanielleMaywood force-pushed the dm-devcontainer-agents-coderd branch from 71493fe to 3a69abb Compare May 21, 2025 09:32
@DanielleMaywood DanielleMaywood changed the title draft: devcontainer agents api feat(coderd/agentapi): implement devcontainer agents api May 21, 2025
This definitely isn't an ideal test. It feels quite large. Maybe I'll
try to extract the different things being tested and move them into
their own tests.
Refactor the One Big Test into multiple separate unit tests
Begin validation of the agent name. This uses the same logic (with the
exception of duplicate agent name detection) as the provisioner.

A future commit will aim to rectify the duplicate agent name issue.
@DanielleMaywood DanielleMaywood force-pushed the dm-devcontainer-agents-coderd branch from c18f28a to eb881ea Compare May 21, 2025 15:19
@DanielleMaywood DanielleMaywood requested a review from Copilot May 21, 2025 15:19
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR implements a new Dev Container Agent API for managing workspace agents used by development containers in the system. Key changes include:

  • Adding a new subject type and authorization support for dev container agents.
  • Introducing SQL queries, querier methods, in-memory and mock DB implementations for workspace agent deletion and retrieval by parent ID.
  • Creating API endpoints and corresponding proto definitions/methods for creating, deleting, and listing dev container agents.

Reviewed Changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
coderd/rbac/authz.go Introduces a new subject type for dev container agent API authorization.
coderd/database/queries/workspaceagents.sql Adds SQL queries for workspace agent deletion and retrieval by parent ID.
coderd/database/queries.sql.go Adds new SQL constants and functions for workspace agent operations.
coderd/database/querier.go Updates the querier interface with new workspace agent methods.
coderd/database/dbmock/dbmock.go Updates mock implementations to support new workspace agent methods.
coderd/database/dbmetrics/querymetrics.go Adds metrics wrappers for the new workspace agent queries.
coderd/database/dbmem/dbmem.go Implements fake methods for deleting and retrieving workspace agents.
coderd/database/dbauthz/dbauthz_test.go Adds tests for workspace agent authorization actions.
coderd/database/dbauthz/dbauthz.go Implements authorization logic and API methods for workspace agent deletion/retrieval.
coderd/agentapi/devcontainer_agent_test.go Provides tests for creating, deleting, and listing dev container agents.
coderd/agentapi/devcontainer_agent.go Implements the Dev Container Agent API endpoints.
coderd/agentapi/api.go Integrates the Dev Container Agent API into the main API composition.
agent/proto/agent_drpc.pb.go Updates generated proto code with new DRPC client/server methods.
agent/proto/agent.proto Defines new RPC messages and endpoints for dev container agent operations.
agent/agenttest/client.go Adds stub implementations for new dev container agent methods in the fake client.

@DanielleMaywood DanielleMaywood requested a review from mafredri May 22, 2025 12:13
Copy link
Member

@mafredri mafredri left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This largely looks good to me, nice work!

Just so I'm understanding this correctly. This permission model works because the agentapi is unique for each agent talking to it and you can't fake being another agent. Hence the simple queries which only filter on id/parent_id, etc. are sufficient. And on top of this, dbauthz verifies that agent is allowed to modify the workspace.

AuthToken: uuid.New(),
AuthInstanceID: parentAgent.AuthInstanceID,
Architecture: req.Architecture,
EnvironmentVariables: pqtype.NullRawMessage{},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: I think this is correct, at least for now. If customers request inheritance we can look at it then, but ideally any envs needed are defined in devcontainer.json

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah we should definitely keep this in mind, or at least make sure to document that these variables aren't inherited.

@DanielleMaywood DanielleMaywood requested a review from Copilot May 22, 2025 17:22
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR implements the devcontainer agents API to support creating, deleting, and listing dev container agents while updating the corresponding database queries, authorization logic, and RPC interfaces.

  • Introduces new RPC endpoints and protobuf definitions for managing dev container agents.
  • Adds SQL queries, database functions, and mocks, as well as updates to RBAC, logging middleware, and tests to support the new API.

Reviewed Changes

Copilot reviewed 19 out of 19 changed files in this pull request and generated no comments.

Show a summary per file
File Description
coderd/workspaceagentsrpc.go Adds OrganizationID to the RPC payload for workspace agents.
coderd/rbac/authz.go Introduces a new subject type for the dev container agent API.
coderd/httpmw/loggermw/logger.go Updates logger middleware to accommodate the new subject type.
coderd/database/queries/*.sql Adds new SQL queries for fetching agents by parent and deleting agents.
coderd/database/queries.sql.go Implements new constants and methods for the workspace agent queries.
coderd/database/querier.go Adds new querier interface methods for dev container agent operations.
coderd/database/dbmock/dbmock.go Adds mocks for the new database methods.
coderd/database/dbmetrics/querymetrics.go Includes metrics wrappers for the new database operations.
coderd/database/dbmem/dbmem.go Implements in-memory versions of the new database methods.
coderd/database/dbauthz/dbauthz_test.go Introduces tests to verify authorization for the new API methods.
coderd/database/dbauthz/dbauthz.go Adds authorization logic and a helper for dev container agent API.
coderd/agentapi/devcontainer_agent.go Implements the new dev container agent API endpoints.
coderd/agentapi/api.go Integrates DevContainerAgentAPI into the main API.
agent/proto/agent.proto, agent_drpc*.go Updates prototype and DRPC definitions to add the new RPC endpoints.
agent/agenttest/client.go Adds stub (unimplemented) methods for the new dev container API.
Comments suppressed due to low confidence (2)

coderd/database/queries.sql.go:14583

  • [nitpick] Consider renaming the parameter 'dollar_1' to a more descriptive name (e.g., 'parentID') to improve clarity.
func (q *sqlQuerier) GetWorkspaceAgentsByParentID(ctx context.Context, dollar_1 uuid.UUID) ([]WorkspaceAgent, error) {

coderd/database/querier.go:416

  • [nitpick] Consider renaming the parameter 'dollar_1' to a more meaningful name (e.g., 'parentID') for better readability and consistency.
GetWorkspaceAgentsByParentID(ctx context.Context, dollar_1 uuid.UUID) ([]WorkspaceAgent, error)

@DanielleMaywood DanielleMaywood force-pushed the dm-devcontainer-agents-coderd branch from b8675f2 to ec4dda9 Compare May 22, 2025 17:25
@DanielleMaywood DanielleMaywood marked this pull request as ready for review May 28, 2025 13:40
@DanielleMaywood DanielleMaywood requested a review from mafredri May 28, 2025 13:40
Copy link
Member

@mafredri mafredri left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks largely good IMO. I suggest adding a bit more paranoia to the agent deletion query, but otherwise only minor suggestions and discussion points.

Pre-approving but deferring final approval to @spikecurtis and @johnstcn.

for i, agent := range workspaceAgents {
agents[i] = &agentproto.ListDevContainerAgentsResponse_DevContainerAgent{
Name: agent.Name,
Id: agent.ID[:],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Discussion: Since we don't output a token here, if the agent ever crashes and is restarted, I suppose it will have to start by querying this list, deleting each agent, and then create new ones. I think that's probably best, but thought I'd raise this anyway.

@@ -319,6 +319,28 @@ var (
Scope: rbac.ScopeAll,
}.WithCachedASTValue()

subjectDevContainerAgentAPI = func(userID uuid.UUID, orgID uuid.UUID) rbac.Subject {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
subjectDevContainerAgentAPI = func(userID uuid.UUID, orgID uuid.UUID) rbac.Subject {
subjectDevContainerAgentAPI = func(orgID uuid.UUID, userID uuid.UUID) rbac.Subject {

I think re-ordering here would make sense (argument of larger scope, followed by smaller scope).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of scope of this PR, but there's an argument to be made for something like this:

type OrganizationID uuid.UUID
type UserID uuid.UUID

You could also have something like:

type UserOrgID struct {
  OrgID uuid.UUID
  UserID uuid.UUID
}
subjectDevContainerAgentAPI = func(UserOrgID) rbac.Subject { ... }

For the purposes of AsDevcontainerAgentAPI, you could maybe do something like the below, but it feels like overkill:

AsDevcontainerAgentAPI(ctx).InOrg(orgID).ForUser(userID)

We'll just need to be careful not to mix up OrgID and UserID.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've re-ordered it. It would definitely be nice if we could have some type-safety on IDs.

@@ -319,6 +319,28 @@ var (
Scope: rbac.ScopeAll,
}.WithCachedASTValue()

subjectDevContainerAgentAPI = func(userID uuid.UUID, orgID uuid.UUID) rbac.Subject {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of scope of this PR, but there's an argument to be made for something like this:

type OrganizationID uuid.UUID
type UserID uuid.UUID

You could also have something like:

type UserOrgID struct {
  OrgID uuid.UUID
  UserID uuid.UUID
}
subjectDevContainerAgentAPI = func(UserOrgID) rbac.Subject { ... }

For the purposes of AsDevcontainerAgentAPI, you could maybe do something like the below, but it feels like overkill:

AsDevcontainerAgentAPI(ctx).InOrg(orgID).ForUser(userID)

We'll just need to be careful not to mix up OrgID and UserID.

@@ -330,3 +330,9 @@ INNER JOIN workspace_resources ON workspace_resources.id = workspace_agents.reso
INNER JOIN workspace_builds ON workspace_builds.job_id = workspace_resources.job_id
WHERE workspace_builds.id = $1
ORDER BY workspace_agent_script_timings.script_id, workspace_agent_script_timings.started_at;

-- name: GetWorkspaceAgentsByParentID :many
SELECT * FROM workspace_agents WHERE parent_id = @parent_id::uuid;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More paranoia: given that parent_id is nullable, what happens if someone calls this with uuid.Nil? Should we do a similar check for AND parent_id IS NOT NULL?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If parent_id was NULL then it should return nothing (assuming my Postgres knowledge is correct).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added a test to verify this behavior is what we'd want.

Replace all naming of Dev Container Agent to Sub Agent.
Refactor the DeleteWorkspaceAgentByID query to be
DeleteWorkspaceSubAgentByID and add a filter that only allows it to
delete an agent that has a non-NULL parent id.
Accidentally left some unused code in dbmem.go
@DanielleMaywood DanielleMaywood changed the title feat(coderd/agentapi): implement devcontainer agents api feat(coderd/agentapi): implement sub agent api May 29, 2025
@DanielleMaywood DanielleMaywood merged commit b712d0b into main May 29, 2025
36 checks passed
@DanielleMaywood DanielleMaywood deleted the dm-devcontainer-agents-coderd branch May 29, 2025 11:15
@github-actions github-actions bot locked and limited conversation to collaborators May 29, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Implement coderd side of RPC communication
4 participants