Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

fix: merge cherry-picked items for v2.26.0#19678

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
stirby merged 15 commits intorelease/2.26fromcherry-26
Sep 2, 2025
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
Show all changes
15 commits
Select commitHold shift + click to select a range
8e00fdf
fix(coderd/provisionerdserver): workaround lack of coder_ai_task reso…
johnstcnAug 27, 2025
290b949
fix(coderd): filter out non-task workspaces in api.tasksList (#19559)
johnstcnAug 27, 2025
98ef855
fix: revert github.com/mark3labs/mcp-go to 0.32.0 (#19578)
hugodutkaAug 27, 2025
568e48b
feat(docs): add docs for external workspaces (#19437)
kacpersawAug 28, 2025
9ad515d
fix(coderd/taskname): ensure generated name is within 32 byte limit (…
DanielleMaywoodAug 28, 2025
bc8a0e2
chore(docs): set external workspaces as premium feature in manifest.j…
kacpersawAug 28, 2025
193fda2
feat: add prebuild timing metrics to Prometheus (#19503)
ssncferreiraAug 28, 2025
67ee772
fix: set radio item to relative position (#19621)
brettkolodnyAug 28, 2025
2c5651e
fix: suppress license expiry warning if a new license covers the gap …
deansheatherAug 29, 2025
25d6722
fix(coderd): fix logic for reporting prebuilt workspace duration metr…
ssncferreiraAug 29, 2025
abe4eff
chore(docs): update external-workspace image (#19608)
matifaliAug 29, 2025
c5c92cc
chore: replace GetManagedAgentCount query with aggregate table (#19636)
deansheatherAug 29, 2025
1ed356e
fix: expire token for prebuilds user when regenerating session token …
johnstcnSep 2, 2025
3d2c3f1
fix(coderd): add audit log on creating a new session key (#19672)
johnstcnSep 2, 2025
0dadb8d
resolved go sum for preview v1.0.4
EmyrkSep 2, 2025
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
1 change: 1 addition & 0 deletions.github/dependabot.yaml
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -33,6 +33,7 @@ updates:
- dependency-name: "*"
update-types:
- version-update:semver-patch
- dependency-name: "github.com/mark3labs/mcp-go"

# Update our Dockerfile.
- package-ecosystem: "docker"
Expand Down
18 changes: 12 additions & 6 deletionscli/server.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -62,12 +62,6 @@ import (
"github.com/coder/serpent"
"github.com/coder/wgtunnel/tunnelsdk"

"github.com/coder/coder/v2/coderd/entitlements"
"github.com/coder/coder/v2/coderd/notifications/reports"
"github.com/coder/coder/v2/coderd/runtimeconfig"
"github.com/coder/coder/v2/coderd/webpush"
"github.com/coder/coder/v2/codersdk/drpcsdk"

"github.com/coder/coder/v2/buildinfo"
"github.com/coder/coder/v2/cli/clilog"
"github.com/coder/coder/v2/cli/cliui"
Expand All@@ -83,25 +77,31 @@ import (
"github.com/coder/coder/v2/coderd/database/migrations"
"github.com/coder/coder/v2/coderd/database/pubsub"
"github.com/coder/coder/v2/coderd/devtunnel"
"github.com/coder/coder/v2/coderd/entitlements"
"github.com/coder/coder/v2/coderd/externalauth"
"github.com/coder/coder/v2/coderd/gitsshkey"
"github.com/coder/coder/v2/coderd/httpmw"
"github.com/coder/coder/v2/coderd/jobreaper"
"github.com/coder/coder/v2/coderd/notifications"
"github.com/coder/coder/v2/coderd/notifications/reports"
"github.com/coder/coder/v2/coderd/oauthpki"
"github.com/coder/coder/v2/coderd/prometheusmetrics"
"github.com/coder/coder/v2/coderd/prometheusmetrics/insights"
"github.com/coder/coder/v2/coderd/promoauth"
"github.com/coder/coder/v2/coderd/provisionerdserver"
"github.com/coder/coder/v2/coderd/runtimeconfig"
"github.com/coder/coder/v2/coderd/schedule"
"github.com/coder/coder/v2/coderd/telemetry"
"github.com/coder/coder/v2/coderd/tracing"
"github.com/coder/coder/v2/coderd/updatecheck"
"github.com/coder/coder/v2/coderd/util/ptr"
"github.com/coder/coder/v2/coderd/util/slice"
stringutil "github.com/coder/coder/v2/coderd/util/strings"
"github.com/coder/coder/v2/coderd/webpush"
"github.com/coder/coder/v2/coderd/workspaceapps/appurl"
"github.com/coder/coder/v2/coderd/workspacestats"
"github.com/coder/coder/v2/codersdk"
"github.com/coder/coder/v2/codersdk/drpcsdk"
"github.com/coder/coder/v2/cryptorand"
"github.com/coder/coder/v2/provisioner/echo"
"github.com/coder/coder/v2/provisioner/terraform"
Expand DownExpand Up@@ -280,6 +280,12 @@ func enablePrometheus(
}
}

provisionerdserverMetrics := provisionerdserver.NewMetrics(logger)
if err := provisionerdserverMetrics.Register(options.PrometheusRegistry); err != nil {
return nil, xerrors.Errorf("failed to register provisionerd_server metrics: %w", err)
}
options.ProvisionerdServerMetrics = provisionerdserverMetrics

//nolint:revive
return ServeHandler(
ctx, logger, promhttp.InstrumentMetricHandler(
Expand Down
8 changes: 0 additions & 8 deletionscoderd/aitasks.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -11,7 +11,6 @@ import (

"github.com/go-chi/chi/v5"
"github.com/google/uuid"
"golang.org/x/xerrors"

"cdr.dev/slog"

Expand DownExpand Up@@ -196,13 +195,6 @@ func (api *API) tasksCreate(rw http.ResponseWriter, r *http.Request) {
// prompts and mapping status/state. This method enforces that only AI task
// workspaces are given.
func (api *API) tasksFromWorkspaces(ctx context.Context, apiWorkspaces []codersdk.Workspace) ([]codersdk.Task, error) {
// Enforce that only AI task workspaces are given.
for _, ws := range apiWorkspaces {
if ws.LatestBuild.HasAITask == nil || !*ws.LatestBuild.HasAITask {
return nil, xerrors.Errorf("workspace %s is not an AI task workspace", ws.ID)
}
}

// Fetch prompts for each workspace build and map by build ID.
buildIDs := make([]uuid.UUID, 0, len(apiWorkspaces))
for _, ws := range apiWorkspaces {
Expand Down
36 changes: 33 additions & 3 deletionscoderd/apikey.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -12,6 +12,8 @@ import (
"github.com/moby/moby/pkg/namesgenerator"
"golang.org/x/xerrors"

"cdr.dev/slog"

"github.com/coder/coder/v2/coderd/apikey"
"github.com/coder/coder/v2/coderd/audit"
"github.com/coder/coder/v2/coderd/database"
Expand DownExpand Up@@ -56,6 +58,14 @@ func (api *API) postToken(rw http.ResponseWriter, r *http.Request) {
return
}

// TODO(Cian): System users technically just have the 'member' role
// and we don't want to disallow all members from creating API keys.
if user.IsSystem {
api.Logger.Warn(ctx, "disallowed creating api key for system user", slog.F("user_id", user.ID))
httpapi.Forbidden(rw)
return
}

scope := database.APIKeyScopeAll
if scope != "" {
scope = database.APIKeyScope(createToken.Scope)
Expand DownExpand Up@@ -121,10 +131,29 @@ func (api *API) postToken(rw http.ResponseWriter, r *http.Request) {
// @Success 201 {object} codersdk.GenerateAPIKeyResponse
// @Router /users/{user}/keys [post]
func (api *API) postAPIKey(rw http.ResponseWriter, r *http.Request) {
ctx := r.Context()
user := httpmw.UserParam(r)
var (
ctx = r.Context()
user = httpmw.UserParam(r)
auditor = api.Auditor.Load()
aReq, commitAudit = audit.InitRequest[database.APIKey](rw, &audit.RequestParams{
Audit: *auditor,
Log: api.Logger,
Request: r,
Action: database.AuditActionCreate,
})
)
aReq.Old = database.APIKey{}
defer commitAudit()

cookie, _, err := api.createAPIKey(ctx, apikey.CreateParams{
// TODO(Cian): System users technically just have the 'member' role
// and we don't want to disallow all members from creating API keys.
if user.IsSystem {
api.Logger.Warn(ctx, "disallowed creating api key for system user", slog.F("user_id", user.ID))
httpapi.Forbidden(rw)
return
}

cookie, key, err := api.createAPIKey(ctx, apikey.CreateParams{
UserID: user.ID,
DefaultLifetime: api.DeploymentValues.Sessions.DefaultTokenDuration.Value(),
LoginType: database.LoginTypePassword,
Expand All@@ -138,6 +167,7 @@ func (api *API) postAPIKey(rw http.ResponseWriter, r *http.Request) {
return
}

aReq.New = *key
// We intentionally do not set the cookie on the response here.
// Setting the cookie will couple the browser session to the API
// key we return here, meaning logging out of the website would
Expand Down
56 changes: 54 additions & 2 deletionscoderd/apikey_test.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,6 +2,7 @@ package coderd_test

import (
"context"
"encoding/json"
"net/http"
"strings"
"testing"
Expand All@@ -13,8 +14,10 @@ import (
"github.com/coder/coder/v2/coderd/audit"
"github.com/coder/coder/v2/coderd/coderdtest"
"github.com/coder/coder/v2/coderd/database"
"github.com/coder/coder/v2/coderd/database/dbgen"
"github.com/coder/coder/v2/coderd/database/dbtestutil"
"github.com/coder/coder/v2/coderd/database/dbtime"
"github.com/coder/coder/v2/coderd/httpapi"
"github.com/coder/coder/v2/codersdk"
"github.com/coder/coder/v2/testutil"
"github.com/coder/serpent"
Expand DownExpand Up@@ -301,14 +304,32 @@ func TestSessionExpiry(t *testing.T) {

func TestAPIKey_OK(t *testing.T) {
t.Parallel()

// Given: a deployment with auditing enabled
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
defer cancel()
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
_ = coderdtest.CreateFirstUser(t, client)
auditor := audit.NewMock()
client := coderdtest.New(t, &coderdtest.Options{Auditor: auditor})
owner := coderdtest.CreateFirstUser(t, client)
auditor.ResetLogs()

// When: an API key is created
res, err := client.CreateAPIKey(ctx, codersdk.Me)
require.NoError(t, err)
require.Greater(t, len(res.Key), 2)

// Then: an audit log is generated
als := auditor.AuditLogs()
require.Len(t, als, 1)
al := als[0]
assert.Equal(t, owner.UserID, al.UserID)
assert.Equal(t, database.AuditActionCreate, al.Action)
assert.Equal(t, database.ResourceTypeApiKey, al.ResourceType)

// Then: the diff MUST NOT contain the generated key.
raw, err := json.Marshal(al)
require.NoError(t, err)
require.NotContains(t, res.Key, string(raw))
}

func TestAPIKey_Deleted(t *testing.T) {
Expand DownExpand Up@@ -351,3 +372,34 @@ func TestAPIKey_SetDefault(t *testing.T) {
require.NoError(t, err)
require.EqualValues(t, dc.Sessions.DefaultTokenDuration.Value().Seconds(), apiKey1.LifetimeSeconds)
}

func TestAPIKey_PrebuildsNotAllowed(t *testing.T) {
t.Parallel()

db, pubsub := dbtestutil.NewDB(t)
dc := coderdtest.DeploymentValues(t)
dc.Sessions.DefaultTokenDuration = serpent.Duration(time.Hour * 12)
client := coderdtest.New(t, &coderdtest.Options{
Database: db,
Pubsub: pubsub,
DeploymentValues: dc,
})

ctx := testutil.Context(t, testutil.WaitLong)

// Given: an existing api token for the prebuilds user
_, prebuildsToken := dbgen.APIKey(t, db, database.APIKey{
UserID: database.PrebuildsSystemUserID,
})
client.SetSessionToken(prebuildsToken)

// When: the prebuilds user tries to create an API key
_, err := client.CreateAPIKey(ctx, database.PrebuildsSystemUserID.String())
// Then: denied.
require.ErrorContains(t, err, httpapi.ResourceForbiddenResponse.Message)

// When: the prebuilds user tries to create a token
_, err = client.CreateToken(ctx, database.PrebuildsSystemUserID.String(), codersdk.CreateTokenRequest{})
// Then: also denied.
require.ErrorContains(t, err, httpapi.ResourceForbiddenResponse.Message)
}
3 changes: 3 additions & 0 deletionscoderd/coderd.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -241,6 +241,8 @@ type Options struct {
UpdateAgentMetrics func(ctx context.Context, labels prometheusmetrics.AgentMetricLabels, metrics []*agentproto.Stats_Metric)
StatsBatcher workspacestats.Batcher

ProvisionerdServerMetrics *provisionerdserver.Metrics

// WorkspaceAppAuditSessionTimeout allows changing the timeout for audit
// sessions. Raising or lowering this value will directly affect the write
// load of the audit log table. This is used for testing. Default 1 hour.
Expand DownExpand Up@@ -1930,6 +1932,7 @@ func (api *API) CreateInMemoryTaggedProvisionerDaemon(dialCtx context.Context, n
},
api.NotificationsEnqueuer,
&api.PrebuildsReconciler,
api.ProvisionerdServerMetrics,
)
if err != nil {
return nil, err
Expand Down
3 changes: 3 additions & 0 deletionscoderd/coderdtest/coderdtest.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -184,6 +184,8 @@ type Options struct {
OIDCConvertKeyCache cryptokeys.SigningKeycache
Clock quartz.Clock
TelemetryReporter telemetry.Reporter

ProvisionerdServerMetrics *provisionerdserver.Metrics
}

// New constructs a codersdk client connected to an in-memory API instance.
Expand DownExpand Up@@ -604,6 +606,7 @@ func NewOptions(t testing.TB, options *Options) (func(http.Handler), context.Can
Clock: options.Clock,
AppEncryptionKeyCache: options.APIKeyEncryptionCache,
OIDCConvertKeyCache: options.OIDCConvertKeyCache,
ProvisionerdServerMetrics: options.ProvisionerdServerMetrics,
}
}

Expand Down
37 changes: 29 additions & 8 deletionscoderd/database/dbauthz/dbauthz.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -1777,6 +1777,13 @@ func (q *querier) EnqueueNotificationMessage(ctx context.Context, arg database.E
return q.db.EnqueueNotificationMessage(ctx, arg)
}

func (q *querier) ExpirePrebuildsAPIKeys(ctx context.Context, now time.Time) error {
if err := q.authorizeContext(ctx, policy.ActionDelete, rbac.ResourceApiKey); err != nil {
return err
}
return q.db.ExpirePrebuildsAPIKeys(ctx, now)
}

func (q *querier) FavoriteWorkspace(ctx context.Context, id uuid.UUID) error {
fetch := func(ctx context.Context, id uuid.UUID) (database.Workspace, error) {
return q.db.GetWorkspaceByID(ctx, id)
Expand DownExpand Up@@ -2242,14 +2249,6 @@ func (q *querier) GetLogoURL(ctx context.Context) (string, error) {
return q.db.GetLogoURL(ctx)
}

func (q *querier) GetManagedAgentCount(ctx context.Context, arg database.GetManagedAgentCountParams) (int64, error) {
// Must be able to read all workspaces to check usage.
if err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceWorkspace); err != nil {
return 0, xerrors.Errorf("authorize read all workspaces: %w", err)
}
return q.db.GetManagedAgentCount(ctx, arg)
}

func (q *querier) GetNotificationMessagesByStatus(ctx context.Context, arg database.GetNotificationMessagesByStatusParams) ([]database.NotificationMessage, error) {
if err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceNotificationMessage); err != nil {
return nil, err
Expand DownExpand Up@@ -2689,6 +2688,13 @@ func (q *querier) GetQuotaConsumedForUser(ctx context.Context, params database.G
return q.db.GetQuotaConsumedForUser(ctx, params)
}

func (q *querier) GetRegularWorkspaceCreateMetrics(ctx context.Context) ([]database.GetRegularWorkspaceCreateMetricsRow, error) {
if err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceWorkspace.All()); err != nil {
return nil, err
}
return q.db.GetRegularWorkspaceCreateMetrics(ctx)
}

func (q *querier) GetReplicaByID(ctx context.Context, id uuid.UUID) (database.Replica, error) {
if err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceSystem); err != nil {
return database.Replica{}, err
Expand DownExpand Up@@ -3041,6 +3047,13 @@ func (q *querier) GetTemplatesWithFilter(ctx context.Context, arg database.GetTe
return q.db.GetAuthorizedTemplates(ctx, arg, prep)
}

func (q *querier) GetTotalUsageDCManagedAgentsV1(ctx context.Context, arg database.GetTotalUsageDCManagedAgentsV1Params) (int64, error) {
if err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceUsageEvent); err != nil {
return 0, err
}
return q.db.GetTotalUsageDCManagedAgentsV1(ctx, arg)
}

func (q *querier) GetUnexpiredLicenses(ctx context.Context) ([]database.License, error) {
if err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceLicense); err != nil {
return nil, err
Expand DownExpand Up@@ -3711,6 +3724,14 @@ func (q *querier) GetWorkspacesEligibleForTransition(ctx context.Context, now ti
}

func (q *querier) InsertAPIKey(ctx context.Context, arg database.InsertAPIKeyParams) (database.APIKey, error) {
// TODO(Cian): ideally this would be encoded in the policy, but system users are just members and we
// don't currently have a capability to conditionally deny creating resources by owner ID in a role.
// We also need to enrich rbac.Actor with IsSystem so that we can distinguish all system users.
// For now, there is only one system user (prebuilds).
if act, ok := ActorFromContext(ctx); ok && act.ID == database.PrebuildsSystemUserID.String() {
return database.APIKey{}, logNotAuthorizedError(ctx, q.log, NotAuthorizedError{Err: xerrors.Errorf("prebuild user may not create api keys")})
}

return insert(q.log, q.auth,
rbac.ResourceApiKey.WithOwner(arg.UserID.String()),
q.db.InsertAPIKey)(ctx, arg)
Expand Down
Loading

[8]ページ先頭

©2009-2025 Movatter.jp