chore: update golang to 1.24.1 (#17035)

- Update go.mod to use Go 1.24.1
- Update GitHub Actions setup-go action to use Go 1.24.1
- Fix linting issues with golangci-lint by:
  - Updating to golangci-lint v1.57.1 (more compatible with Go 1.24.1)

🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <claude@anthropic.com>
This commit is contained in:
Jon Ayers
2025-03-26 01:56:39 -05:00
committed by GitHub
co-authored by Claude
parent c131d01cfd
commit 17ddee05e5
187 changed files with 650 additions and 531 deletions
+6 -5
View File
@@ -101,11 +101,12 @@ func (a *LogsAPI) BatchCreateLogs(ctx context.Context, req *agentproto.BatchCrea
}
logs, err := a.Database.InsertWorkspaceAgentLogs(ctx, database.InsertWorkspaceAgentLogsParams{
AgentID: workspaceAgent.ID,
CreatedAt: a.now(),
Output: output,
Level: level,
LogSourceID: logSourceID,
AgentID: workspaceAgent.ID,
CreatedAt: a.now(),
Output: output,
Level: level,
LogSourceID: logSourceID,
// #nosec G115 - Safe conversion as output length is expected to be within int32 range
OutputLength: int32(outputLength),
})
if err != nil {
+1 -1
View File
@@ -11561,7 +11561,7 @@ const docTemplate = `{
}
},
"address": {
"description": "DEPRECATED: Use HTTPAddress or TLS.Address instead.",
"description": "Deprecated: Use HTTPAddress or TLS.Address instead.",
"allOf": [
{
"$ref": "#/definitions/serpent.HostPort"
+1 -1
View File
@@ -10325,7 +10325,7 @@
}
},
"address": {
"description": "DEPRECATED: Use HTTPAddress or TLS.Address instead.",
"description": "Deprecated: Use HTTPAddress or TLS.Address instead.",
"allOf": [
{
"$ref": "#/definitions/serpent.HostPort"
+3 -3
View File
@@ -257,12 +257,12 @@ func (api *API) tokens(rw http.ResponseWriter, r *http.Request) {
return
}
var userIds []uuid.UUID
var userIDs []uuid.UUID
for _, key := range keys {
userIds = append(userIds, key.UserID)
userIDs = append(userIDs, key.UserID)
}
users, _ := api.Database.GetUsersByIDs(ctx, userIds)
users, _ := api.Database.GetUsersByIDs(ctx, userIDs)
usersByID := map[uuid.UUID]database.User{}
for _, user := range users {
usersByID[user.ID] = user
+8 -6
View File
@@ -134,20 +134,22 @@ func TestGenerate(t *testing.T) {
assert.WithinDuration(t, dbtime.Now(), key.CreatedAt, time.Second*5)
assert.WithinDuration(t, dbtime.Now(), key.UpdatedAt, time.Second*5)
if tc.params.LifetimeSeconds > 0 {
switch {
case tc.params.LifetimeSeconds > 0:
assert.Equal(t, tc.params.LifetimeSeconds, key.LifetimeSeconds)
} else if !tc.params.ExpiresAt.IsZero() {
case !tc.params.ExpiresAt.IsZero():
// Should not be a delta greater than 5 seconds.
assert.InDelta(t, time.Until(tc.params.ExpiresAt).Seconds(), key.LifetimeSeconds, 5)
} else {
default:
assert.Equal(t, int64(tc.params.DefaultLifetime.Seconds()), key.LifetimeSeconds)
}
if !tc.params.ExpiresAt.IsZero() {
switch {
case !tc.params.ExpiresAt.IsZero():
assert.Equal(t, tc.params.ExpiresAt.UTC(), key.ExpiresAt)
} else if tc.params.LifetimeSeconds > 0 {
case tc.params.LifetimeSeconds > 0:
assert.WithinDuration(t, dbtime.Now().Add(time.Duration(tc.params.LifetimeSeconds)*time.Second), key.ExpiresAt, time.Second*5)
} else {
default:
assert.WithinDuration(t, dbtime.Now().Add(tc.params.DefaultLifetime), key.ExpiresAt, time.Second*5)
}
+2
View File
@@ -54,7 +54,9 @@ func (api *API) auditLogs(rw http.ResponseWriter, r *http.Request) {
})
return
}
// #nosec G115 - Safe conversion as pagination offset is expected to be within int32 range
filter.OffsetOpt = int32(page.Offset)
// #nosec G115 - Safe conversion as pagination limit is expected to be within int32 range
filter.LimitOpt = int32(page.Limit)
if filter.Username == "me" {
+1 -1
View File
@@ -13,7 +13,7 @@ import (
type Auditor interface {
Export(ctx context.Context, alog database.AuditLog) error
diff(old, new any) Map
diff(old, newVal any) Map
}
type AdditionalFields struct {
+3 -3
View File
@@ -60,10 +60,10 @@ func Diff[T Auditable](a Auditor, left, right T) Map { return a.diff(left, right
// the Auditor feature interface. Only types in the same package as the
// interface can implement unexported methods.
type Differ struct {
DiffFn func(old, new any) Map
DiffFn func(old, newVal any) Map
}
//nolint:unused
func (d Differ) diff(old, new any) Map {
return d.DiffFn(old, new)
func (d Differ) diff(old, newVal any) Map {
return d.DiffFn(old, newVal)
}
+35 -30
View File
@@ -407,11 +407,12 @@ func InitRequest[T Auditable](w http.ResponseWriter, p *RequestParams) (*Request
var userID uuid.UUID
key, ok := httpmw.APIKeyOptional(p.Request)
if ok {
switch {
case ok:
userID = key.UserID
} else if req.UserID != uuid.Nil {
case req.UserID != uuid.Nil:
userID = req.UserID
} else {
default:
// if we do not have a user associated with the audit action
// we do not want to audit
// (this pertains to logins; we don't want to capture non-user login attempts)
@@ -425,16 +426,17 @@ func InitRequest[T Auditable](w http.ResponseWriter, p *RequestParams) (*Request
ip := ParseIP(p.Request.RemoteAddr)
auditLog := database.AuditLog{
ID: uuid.New(),
Time: dbtime.Now(),
UserID: userID,
Ip: ip,
UserAgent: sql.NullString{String: p.Request.UserAgent(), Valid: true},
ResourceType: either(req.Old, req.New, ResourceType[T], req.params.Action),
ResourceID: either(req.Old, req.New, ResourceID[T], req.params.Action),
ResourceTarget: either(req.Old, req.New, ResourceTarget[T], req.params.Action),
Action: action,
Diff: diffRaw,
ID: uuid.New(),
Time: dbtime.Now(),
UserID: userID,
Ip: ip,
UserAgent: sql.NullString{String: p.Request.UserAgent(), Valid: true},
ResourceType: either(req.Old, req.New, ResourceType[T], req.params.Action),
ResourceID: either(req.Old, req.New, ResourceID[T], req.params.Action),
ResourceTarget: either(req.Old, req.New, ResourceTarget[T], req.params.Action),
Action: action,
Diff: diffRaw,
// #nosec G115 - Safe conversion as HTTP status code is expected to be within int32 range (typically 100-599)
StatusCode: int32(sw.Status),
RequestID: httpmw.RequestID(p.Request),
AdditionalFields: additionalFieldsRaw,
@@ -475,17 +477,18 @@ func BackgroundAudit[T Auditable](ctx context.Context, p *BackgroundAuditParams[
}
auditLog := database.AuditLog{
ID: uuid.New(),
Time: p.Time,
UserID: p.UserID,
OrganizationID: requireOrgID[T](ctx, p.OrganizationID, p.Log),
Ip: ip,
UserAgent: sql.NullString{Valid: p.UserAgent != "", String: p.UserAgent},
ResourceType: either(p.Old, p.New, ResourceType[T], p.Action),
ResourceID: either(p.Old, p.New, ResourceID[T], p.Action),
ResourceTarget: either(p.Old, p.New, ResourceTarget[T], p.Action),
Action: p.Action,
Diff: diffRaw,
ID: uuid.New(),
Time: p.Time,
UserID: p.UserID,
OrganizationID: requireOrgID[T](ctx, p.OrganizationID, p.Log),
Ip: ip,
UserAgent: sql.NullString{Valid: p.UserAgent != "", String: p.UserAgent},
ResourceType: either(p.Old, p.New, ResourceType[T], p.Action),
ResourceID: either(p.Old, p.New, ResourceID[T], p.Action),
ResourceTarget: either(p.Old, p.New, ResourceTarget[T], p.Action),
Action: p.Action,
Diff: diffRaw,
// #nosec G115 - Safe conversion as HTTP status code is expected to be within int32 range (typically 100-599)
StatusCode: int32(p.Status),
RequestID: p.RequestID,
AdditionalFields: p.AdditionalFields,
@@ -554,17 +557,19 @@ func BaggageFromContext(ctx context.Context) WorkspaceBuildBaggage {
return d
}
func either[T Auditable, R any](old, new T, fn func(T) R, auditAction database.AuditAction) R {
if ResourceID(new) != uuid.Nil {
return fn(new)
} else if ResourceID(old) != uuid.Nil {
func either[T Auditable, R any](old, newVal T, fn func(T) R, auditAction database.AuditAction) R {
switch {
case ResourceID(newVal) != uuid.Nil:
return fn(newVal)
case ResourceID(old) != uuid.Nil:
return fn(old)
} else if auditAction == database.AuditActionLogin || auditAction == database.AuditActionLogout {
case auditAction == database.AuditActionLogin || auditAction == database.AuditActionLogout:
// If the request action is a login or logout, we always want to audit it even if
// there is no diff. See the comment in audit.InitRequest for more detail.
return fn(old)
default:
panic("both old and new are nil")
}
panic("both old and new are nil")
}
func ParseIP(ipStr string) pqtype.Inet {
@@ -52,6 +52,7 @@ func Test_isEligibleForAutostart(t *testing.T) {
for i, weekday := range schedule.DaysOfWeek {
// Find the local weekday
if okTick.In(localLocation).Weekday() == weekday {
// #nosec G115 - Safe conversion as i is the index of a 7-day week and will be in the range 0-6
okWeekdayBit = 1 << uint(i)
}
}
+4 -4
View File
@@ -829,7 +829,7 @@ func New(options *Options) *API {
// we do not override subdomain app routes.
r.Get("/latency-check", tracing.StatusWriterMiddleware(prometheusMW(LatencyCheck())).ServeHTTP)
r.Get("/healthz", func(w http.ResponseWriter, r *http.Request) { _, _ = w.Write([]byte("OK")) })
r.Get("/healthz", func(w http.ResponseWriter, _ *http.Request) { _, _ = w.Write([]byte("OK")) })
// Attach workspace apps routes.
r.Group(func(r chi.Router) {
@@ -844,7 +844,7 @@ func New(options *Options) *API {
r.Route("/derp", func(r chi.Router) {
r.Get("/", derpHandler.ServeHTTP)
// This is used when UDP is blocked, and latency must be checked via HTTP(s).
r.Get("/latency-check", func(w http.ResponseWriter, r *http.Request) {
r.Get("/latency-check", func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusOK)
})
})
@@ -901,7 +901,7 @@ func New(options *Options) *API {
r.Route("/api/v2", func(r chi.Router) {
api.APIHandler = r
r.NotFound(func(rw http.ResponseWriter, r *http.Request) { httpapi.RouteNotFound(rw) })
r.NotFound(func(rw http.ResponseWriter, _ *http.Request) { httpapi.RouteNotFound(rw) })
r.Use(
// Specific routes can specify different limits, but every rate
// limit must be configurable by the admin.
@@ -1421,7 +1421,7 @@ func New(options *Options) *API {
// global variable here.
r.Get("/swagger/*", globalHTTPSwaggerHandler)
} else {
swaggerDisabled := http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
swaggerDisabled := http.HandlerFunc(func(rw http.ResponseWriter, _ *http.Request) {
httpapi.Write(context.Background(), rw, http.StatusNotFound, codersdk.Response{
Message: "Swagger documentation is disabled.",
})
+1 -1
View File
@@ -1194,7 +1194,7 @@ func MustWorkspace(t testing.TB, client *codersdk.Client, workspaceID uuid.UUID)
// RequestExternalAuthCallback makes a request with the proper OAuth2 state cookie
// to the external auth callback endpoint.
func RequestExternalAuthCallback(t testing.TB, providerID string, client *codersdk.Client, opts ...func(*http.Request)) *http.Response {
client.HTTPClient.CheckRedirect = func(req *http.Request, via []*http.Request) error {
client.HTTPClient.CheckRedirect = func(_ *http.Request, _ []*http.Request) error {
return http.ErrUseLastResponse
}
state := "somestate"
+4 -4
View File
@@ -339,8 +339,8 @@ func NewFakeIDP(t testing.TB, opts ...FakeIDPOpt) *FakeIDP {
refreshIDTokenClaims: syncmap.New[string, jwt.MapClaims](),
deviceCode: syncmap.New[string, deviceFlow](),
hookOnRefresh: func(_ string) error { return nil },
hookUserInfo: func(email string) (jwt.MapClaims, error) { return jwt.MapClaims{}, nil },
hookValidRedirectURL: func(redirectURL string) error { return nil },
hookUserInfo: func(_ string) (jwt.MapClaims, error) { return jwt.MapClaims{}, nil },
hookValidRedirectURL: func(_ string) error { return nil },
defaultExpire: time.Minute * 5,
}
@@ -553,7 +553,7 @@ func (f *FakeIDP) ExternalLogin(t testing.TB, client *codersdk.Client, opts ...f
f.SetRedirect(t, coderOauthURL.String())
cli := f.HTTPClient(client.HTTPClient)
cli.CheckRedirect = func(req *http.Request, via []*http.Request) error {
cli.CheckRedirect = func(req *http.Request, _ []*http.Request) error {
// Store the idTokenClaims to the specific state request. This ties
// the claims 1:1 with a given authentication flow.
state := req.URL.Query().Get("state")
@@ -1210,7 +1210,7 @@ func (f *FakeIDP) httpHandler(t testing.TB) http.Handler {
}.Encode())
}))
mux.NotFound(func(rw http.ResponseWriter, r *http.Request) {
mux.NotFound(func(_ http.ResponseWriter, r *http.Request) {
f.logger.Error(r.Context(), "http call not found", slogRequestFields(r)...)
t.Errorf("unexpected request to IDP at path %q. Not supported", r.URL.Path)
})
+1 -1
View File
@@ -151,7 +151,7 @@ func VerifySwaggerDefinitions(t *testing.T, router chi.Router, swaggerComments [
assertUniqueRoutes(t, swaggerComments)
assertSingleAnnotations(t, swaggerComments)
err := chi.Walk(router, func(method, route string, handler http.Handler, middlewares ...func(http.Handler) http.Handler) error {
err := chi.Walk(router, func(method, route string, _ http.Handler, _ ...func(http.Handler) http.Handler) error {
method = strings.ToLower(method)
if route != "/" && strings.HasSuffix(route, "/") {
route = route[:len(route)-1]
+19 -17
View File
@@ -33,8 +33,8 @@ var _ database.Store = (*querier)(nil)
const wrapname = "dbauthz.querier"
// NoActorError is returned if no actor is present in the context.
var NoActorError = xerrors.Errorf("no authorization actor in context")
// ErrNoActor is returned if no actor is present in the context.
var ErrNoActor = xerrors.Errorf("no authorization actor in context")
// NotAuthorizedError is a sentinel error that unwraps to sql.ErrNoRows.
// This allows the internal error to be read by the caller if needed. Otherwise
@@ -69,7 +69,7 @@ func IsNotAuthorizedError(err error) bool {
if err == nil {
return false
}
if xerrors.Is(err, NoActorError) {
if xerrors.Is(err, ErrNoActor) {
return true
}
@@ -140,7 +140,7 @@ func (q *querier) Wrappers() []string {
func (q *querier) authorizeContext(ctx context.Context, action policy.Action, object rbac.Objecter) error {
act, ok := ActorFromContext(ctx)
if !ok {
return NoActorError
return ErrNoActor
}
err := q.auth.Authorize(ctx, act, action, object.RBACObject())
@@ -466,7 +466,7 @@ func insertWithAction[
// Fetch the rbac subject
act, ok := ActorFromContext(ctx)
if !ok {
return empty, NoActorError
return empty, ErrNoActor
}
// Authorize the action
@@ -544,7 +544,7 @@ func fetchWithAction[
// Fetch the rbac subject
act, ok := ActorFromContext(ctx)
if !ok {
return empty, NoActorError
return empty, ErrNoActor
}
// Fetch the database object
@@ -620,7 +620,7 @@ func fetchAndQuery[
// Fetch the rbac subject
act, ok := ActorFromContext(ctx)
if !ok {
return empty, NoActorError
return empty, ErrNoActor
}
// Fetch the database object
@@ -654,7 +654,7 @@ func fetchWithPostFilter[
// Fetch the rbac subject
act, ok := ActorFromContext(ctx)
if !ok {
return empty, NoActorError
return empty, ErrNoActor
}
// Fetch the database object
@@ -673,7 +673,7 @@ func fetchWithPostFilter[
func prepareSQLFilter(ctx context.Context, authorizer rbac.Authorizer, action policy.Action, resourceType string) (rbac.PreparedAuthorized, error) {
act, ok := ActorFromContext(ctx)
if !ok {
return nil, NoActorError
return nil, ErrNoActor
}
return authorizer.Prepare(ctx, act, action, resourceType)
@@ -752,7 +752,7 @@ func (*querier) convertToDeploymentRoles(names []string) []rbac.RoleIdentifier {
func (q *querier) canAssignRoles(ctx context.Context, orgID uuid.UUID, added, removed []rbac.RoleIdentifier) error {
actor, ok := ActorFromContext(ctx)
if !ok {
return NoActorError
return ErrNoActor
}
roleAssign := rbac.ResourceAssignRole
@@ -961,7 +961,7 @@ func (q *querier) customRoleEscalationCheck(ctx context.Context, actor rbac.Subj
func (q *querier) customRoleCheck(ctx context.Context, role database.CustomRole) error {
act, ok := ActorFromContext(ctx)
if !ok {
return NoActorError
return ErrNoActor
}
// Org permissions require an org role
@@ -1667,8 +1667,8 @@ func (q *querier) GetDeploymentWorkspaceStats(ctx context.Context) (database.Get
return q.db.GetDeploymentWorkspaceStats(ctx)
}
func (q *querier) GetEligibleProvisionerDaemonsByProvisionerJobIDs(ctx context.Context, provisionerJobIds []uuid.UUID) ([]database.GetEligibleProvisionerDaemonsByProvisionerJobIDsRow, error) {
return fetchWithPostFilter(q.auth, policy.ActionRead, q.db.GetEligibleProvisionerDaemonsByProvisionerJobIDs)(ctx, provisionerJobIds)
func (q *querier) GetEligibleProvisionerDaemonsByProvisionerJobIDs(ctx context.Context, provisionerJobIDs []uuid.UUID) ([]database.GetEligibleProvisionerDaemonsByProvisionerJobIDsRow, error) {
return fetchWithPostFilter(q.auth, policy.ActionRead, q.db.GetEligibleProvisionerDaemonsByProvisionerJobIDs)(ctx, provisionerJobIDs)
}
func (q *querier) GetExternalAuthLink(ctx context.Context, arg database.GetExternalAuthLinkParams) (database.ExternalAuthLink, error) {
@@ -3050,11 +3050,11 @@ func (q *querier) GetWorkspaceResourcesCreatedAfter(ctx context.Context, created
return q.db.GetWorkspaceResourcesCreatedAfter(ctx, createdAt)
}
func (q *querier) GetWorkspaceUniqueOwnerCountByTemplateIDs(ctx context.Context, templateIds []uuid.UUID) ([]database.GetWorkspaceUniqueOwnerCountByTemplateIDsRow, error) {
func (q *querier) GetWorkspaceUniqueOwnerCountByTemplateIDs(ctx context.Context, templateIDs []uuid.UUID) ([]database.GetWorkspaceUniqueOwnerCountByTemplateIDsRow, error) {
if err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceSystem); err != nil {
return nil, err
}
return q.db.GetWorkspaceUniqueOwnerCountByTemplateIDs(ctx, templateIds)
return q.db.GetWorkspaceUniqueOwnerCountByTemplateIDs(ctx, templateIDs)
}
func (q *querier) GetWorkspaces(ctx context.Context, arg database.GetWorkspacesParams) ([]database.GetWorkspacesRow, error) {
@@ -3245,6 +3245,7 @@ func (q *querier) InsertOrganizationMember(ctx context.Context, arg database.Ins
}
// All roles are added roles. Org member is always implied.
//nolint:gocritic
addedRoles := append(orgRoles, rbac.ScopedRoleOrgMember(arg.OrganizationID))
err = q.canAssignRoles(ctx, arg.OrganizationID, addedRoles, []rbac.RoleIdentifier{})
if err != nil {
@@ -3397,7 +3398,7 @@ func (q *querier) InsertUserGroupsByName(ctx context.Context, arg database.Inser
// This will add the user to all named groups. This counts as updating a group.
// NOTE: instead of checking if the user has permission to update each group, we instead
// check if the user has permission to update *a* group in the org.
fetch := func(ctx context.Context, arg database.InsertUserGroupsByNameParams) (rbac.Objecter, error) {
fetch := func(_ context.Context, arg database.InsertUserGroupsByNameParams) (rbac.Objecter, error) {
return rbac.ResourceGroup.InOrg(arg.OrganizationID), nil
}
return update(q.log, q.auth, fetch, q.db.InsertUserGroupsByName)(ctx, arg)
@@ -3830,6 +3831,7 @@ func (q *querier) UpdateMemberRoles(ctx context.Context, arg database.UpdateMemb
}
// The org member role is always implied.
//nolint:gocritic
impliedTypes := append(scopedGranted, rbac.ScopedRoleOrgMember(arg.OrgID))
added, removed := rbac.ChangeRoleSet(originalRoles, impliedTypes)
@@ -3930,7 +3932,7 @@ func (q *querier) UpdateProvisionerJobWithCancelByID(ctx context.Context, arg da
// Only owners can cancel workspace builds
actor, ok := ActorFromContext(ctx)
if !ok {
return NoActorError
return ErrNoActor
}
if !slice.Contains(actor.Roles.Names(), rbac.RoleOwner()) {
return xerrors.Errorf("only owners can cancel workspace builds")
+1 -1
View File
@@ -252,7 +252,7 @@ func (s *MethodTestSuite) NoActorErrorTest(callMethod func(ctx context.Context)
s.Run("AsRemoveActor", func() {
// Call without any actor
_, err := callMethod(context.Background())
s.ErrorIs(err, dbauthz.NoActorError, "method should return NoActorError error when no actor is provided")
s.ErrorIs(err, dbauthz.ErrNoActor, "method should return NoActorError error when no actor is provided")
})
}
+1
View File
@@ -40,6 +40,7 @@ type OrganizationResponse struct {
func (b OrganizationBuilder) EveryoneAllowance(allowance int) OrganizationBuilder {
//nolint: revive // returns modified struct
// #nosec G115 - Safe conversion as allowance is expected to be within int32 range
b.allUsersAllowance = int32(allowance)
return b
}
+20 -10
View File
@@ -6057,6 +6057,7 @@ func (q *FakeQuerier) GetTemplateVersionsByTemplateID(_ context.Context, arg dat
if arg.LimitOpt > 0 {
if int(arg.LimitOpt) > len(version) {
// #nosec G115 - Safe conversion as version slice length is expected to be within int32 range
arg.LimitOpt = int32(len(version))
}
version = version[:arg.LimitOpt]
@@ -6691,6 +6692,7 @@ func (q *FakeQuerier) GetUsers(_ context.Context, params database.GetUsersParams
if params.LimitOpt > 0 {
if int(params.LimitOpt) > len(users) {
// #nosec G115 - Safe conversion as users slice length is expected to be within int32 range
params.LimitOpt = int32(len(users))
}
users = users[:params.LimitOpt]
@@ -7618,6 +7620,7 @@ func (q *FakeQuerier) GetWorkspaceBuildsByWorkspaceID(_ context.Context,
if params.LimitOpt > 0 {
if int(params.LimitOpt) > len(history) {
// #nosec G115 - Safe conversion as history slice length is expected to be within int32 range
params.LimitOpt = int32(len(history))
}
history = history[:params.LimitOpt]
@@ -9280,6 +9283,7 @@ func (q *FakeQuerier) InsertWorkspaceAgentLogs(_ context.Context, arg database.I
LogSourceID: arg.LogSourceID,
Output: output,
})
// #nosec G115 - Safe conversion as log output length is expected to be within int32 range
outputLength += int32(len(output))
}
for index, agent := range q.workspaceAgents {
@@ -12415,17 +12419,23 @@ TemplateUsageStatsInsertLoop:
// SELECT
tus := database.TemplateUsageStat{
StartTime: stat.TimeBucket,
EndTime: stat.TimeBucket.Add(30 * time.Minute),
TemplateID: stat.TemplateID,
UserID: stat.UserID,
UsageMins: int16(stat.UsageMins),
MedianLatencyMs: sql.NullFloat64{Float64: latency.MedianLatencyMS, Valid: latencyOk},
SshMins: int16(stat.SSHMins),
SftpMins: int16(stat.SFTPMins),
StartTime: stat.TimeBucket,
EndTime: stat.TimeBucket.Add(30 * time.Minute),
TemplateID: stat.TemplateID,
UserID: stat.UserID,
// #nosec G115 - Safe conversion for usage minutes which are expected to be within int16 range
UsageMins: int16(stat.UsageMins),
MedianLatencyMs: sql.NullFloat64{Float64: latency.MedianLatencyMS, Valid: latencyOk},
// #nosec G115 - Safe conversion for SSH minutes which are expected to be within int16 range
SshMins: int16(stat.SSHMins),
// #nosec G115 - Safe conversion for SFTP minutes which are expected to be within int16 range
SftpMins: int16(stat.SFTPMins),
// #nosec G115 - Safe conversion for ReconnectingPTY minutes which are expected to be within int16 range
ReconnectingPtyMins: int16(stat.ReconnectingPTYMins),
VscodeMins: int16(stat.VSCodeMins),
JetbrainsMins: int16(stat.JetBrainsMins),
// #nosec G115 - Safe conversion for VSCode minutes which are expected to be within int16 range
VscodeMins: int16(stat.VSCodeMins),
// #nosec G115 - Safe conversion for JetBrains minutes which are expected to be within int16 range
JetbrainsMins: int16(stat.JetBrainsMins),
}
if len(stat.AppUsageMinutes) > 0 {
tus.AppUsageMins = make(map[string]int64, len(stat.AppUsageMinutes))
+1
View File
@@ -18,5 +18,6 @@ const (
func GenLockID(name string) int64 {
hash := fnv.New64()
_, _ = hash.Write([]byte(name))
// #nosec G115 - Safe conversion as FNV hash should be treated as random value and both uint64/int64 have the same range of unique values
return int64(hash.Sum64())
}
+1 -1
View File
@@ -199,7 +199,7 @@ func (s *tableStats) Add(table string, n int) {
s.mu.Lock()
defer s.mu.Unlock()
s.s[table] = s.s[table] + n
s.s[table] += n
}
func (s *tableStats) Empty() []string {
+1
View File
@@ -160,6 +160,7 @@ func (t Template) DeepCopy() Template {
func (t Template) AutostartAllowedDays() uint8 {
// Just flip the binary 0s to 1s and vice versa.
// There is an extra day with the 8th bit that needs to be zeroed.
// #nosec G115 - Safe conversion for AutostartBlockDaysOfWeek which is 7 bits
return ^uint8(t.AutostartBlockDaysOfWeek) & 0b01111111
}
+1 -1
View File
@@ -112,7 +112,7 @@ func (l PGLocks) String() string {
// Difference returns the difference between two sets of locks.
// This is helpful to determine what changed between the two sets.
func (l PGLocks) Difference(to PGLocks) (new PGLocks, removed PGLocks) {
func (l PGLocks) Difference(to PGLocks) (newVal PGLocks, removed PGLocks) {
return slice.SymmetricDifferenceFunc(l, to, func(a, b PGLock) bool {
return a.Equal(b)
})
+20 -16
View File
@@ -2119,10 +2119,11 @@ func createTemplateVersion(t testing.TB, db database.Store, tpl database.Templat
dbgen.WorkspaceBuild(t, db, database.WorkspaceBuild{
WorkspaceID: wrk.ID,
TemplateVersionID: version.ID,
BuildNumber: int32(i) + 2,
Transition: trans,
InitiatorID: tpl.CreatedBy,
JobID: latestJob.ID,
// #nosec G115 - Safe conversion as build number is expected to be within int32 range
BuildNumber: int32(i) + 2,
Transition: trans,
InitiatorID: tpl.CreatedBy,
JobID: latestJob.ID,
})
}
@@ -3182,21 +3183,22 @@ func TestGetUserStatusCounts(t *testing.T) {
row.Date.In(location).String(),
i,
)
if row.Date.Before(createdAt) {
switch {
case row.Date.Before(createdAt):
require.Equal(t, int64(0), row.Count)
} else if row.Date.Before(firstTransitionTime) {
case row.Date.Before(firstTransitionTime):
if row.Status == tc.initialStatus {
require.Equal(t, int64(1), row.Count)
} else if row.Status == tc.targetStatus {
require.Equal(t, int64(0), row.Count)
}
} else if !row.Date.After(today) {
case !row.Date.After(today):
if row.Status == tc.initialStatus {
require.Equal(t, int64(0), row.Count)
} else if row.Status == tc.targetStatus {
require.Equal(t, int64(1), row.Count)
}
} else {
default:
t.Errorf("date %q beyond expected range end %q", row.Date, today)
}
}
@@ -3337,18 +3339,19 @@ func TestGetUserStatusCounts(t *testing.T) {
expectedCounts[d][tc.user2Transition.to] = 0
// Counted Values
if d.Before(createdAt) {
switch {
case d.Before(createdAt):
continue
} else if d.Before(firstTransitionTime) {
case d.Before(firstTransitionTime):
expectedCounts[d][tc.user1Transition.from]++
expectedCounts[d][tc.user2Transition.from]++
} else if d.Before(secondTransitionTime) {
case d.Before(secondTransitionTime):
expectedCounts[d][tc.user1Transition.to]++
expectedCounts[d][tc.user2Transition.from]++
} else if d.Before(today) {
case d.Before(today):
expectedCounts[d][tc.user1Transition.to]++
expectedCounts[d][tc.user2Transition.to]++
} else {
default:
t.Fatalf("date %q beyond expected range end %q", d, today)
}
}
@@ -3441,11 +3444,12 @@ func TestGetUserStatusCounts(t *testing.T) {
i,
)
require.Equal(t, database.UserStatusActive, row.Status)
if row.Date.Before(createdAt) {
switch {
case row.Date.Before(createdAt):
require.Equal(t, int64(0), row.Count)
} else if i == len(userStatusChanges)-1 {
case i == len(userStatusChanges)-1:
require.Equal(t, int64(0), row.Count)
} else {
default:
require.Equal(t, int64(1), row.Count)
}
}
+2 -2
View File
@@ -664,7 +664,7 @@ func copyDefaultSettings(config *codersdk.ExternalAuthConfig, defaults codersdk.
if config.Regex == "" {
config.Regex = defaults.Regex
}
if config.Scopes == nil || len(config.Scopes) == 0 {
if len(config.Scopes) == 0 {
config.Scopes = defaults.Scopes
}
if config.DeviceCodeURL == "" {
@@ -676,7 +676,7 @@ func copyDefaultSettings(config *codersdk.ExternalAuthConfig, defaults codersdk.
if config.DisplayIcon == "" {
config.DisplayIcon = defaults.DisplayIcon
}
if config.ExtraTokenKeys == nil || len(config.ExtraTokenKeys) == 0 {
if len(config.ExtraTokenKeys) == 0 {
config.ExtraTokenKeys = defaults.ExtraTokenKeys
}
+4 -3
View File
@@ -197,14 +197,15 @@ func (r *RegionReport) Run(ctx context.Context) {
return
}
if len(r.Region.Nodes) == 1 {
switch {
case len(r.Region.Nodes) == 1:
r.Healthy = r.NodeReports[0].Severity != health.SeverityError
r.Severity = r.NodeReports[0].Severity
} else if unhealthyNodes == 1 {
case unhealthyNodes == 1:
// r.Healthy = true (by default)
r.Severity = health.SeverityWarning
r.Warnings = append(r.Warnings, health.Messagef(health.CodeDERPOneNodeUnhealthy, oneNodeUnhealthy))
} else if unhealthyNodes > 1 {
case unhealthyNodes > 1:
r.Healthy = false
// Review node reports and select the highest severity.
+2 -4
View File
@@ -195,10 +195,8 @@ func TestWorkspaceProxies(t *testing.T) {
assert.Equal(t, tt.expectedSeverity, rpt.Severity)
if tt.expectedError != "" && assert.NotNil(t, rpt.Error) {
assert.Contains(t, *rpt.Error, tt.expectedError)
} else {
if !assert.Nil(t, rpt.Error) {
t.Logf("error: %v", *rpt.Error)
}
} else if !assert.Nil(t, rpt.Error) {
t.Logf("error: %v", *rpt.Error)
}
if tt.expectedWarningCode != "" && assert.NotEmpty(t, rpt.Warnings) {
var found bool
+3 -5
View File
@@ -226,11 +226,9 @@ func (p *QueryParamParser) Time(vals url.Values, def time.Time, queryParam, layo
// Time uses the default time format of RFC3339Nano and always returns a UTC time.
func (p *QueryParamParser) Time3339Nano(vals url.Values, def time.Time, queryParam string) time.Time {
layout := time.RFC3339Nano
return p.timeWithMutate(vals, def, queryParam, layout, func(term string) string {
// All search queries are forced to lowercase. But the RFC format requires
// upper case letters. So just uppercase the term.
return strings.ToUpper(term)
})
// All search queries are forced to lowercase. But the RFC format requires
// upper case letters. So just uppercase the term.
return p.timeWithMutate(vals, def, queryParam, layout, strings.ToUpper)
}
func (p *QueryParamParser) timeWithMutate(vals url.Values, def time.Time, queryParam, layout string, mutate func(term string) string) time.Time {
+1 -1
View File
@@ -203,7 +203,7 @@ func ExtractAPIKey(rw http.ResponseWriter, r *http.Request, cfg ExtractAPIKeyCon
// Write wraps writing a response to redirect if the handler
// specified it should. This redirect is used for user-facing pages
// like workspace applications.
write := func(code int, response codersdk.Response) (*database.APIKey, *rbac.Subject, bool) {
write := func(code int, response codersdk.Response) (apiKey *database.APIKey, subject *rbac.Subject, ok bool) {
if cfg.RedirectToLogin {
RedirectToLogin(rw, r, nil, response.Message)
return nil, nil, false
+1 -1
View File
@@ -46,7 +46,7 @@ func Cors(allowAll bool, origins ...string) func(next http.Handler) http.Handler
func WorkspaceAppCors(regex *regexp.Regexp, app appurl.ApplicationURL) func(next http.Handler) http.Handler {
return cors.Handler(cors.Options{
AllowOriginFunc: func(r *http.Request, rawOrigin string) bool {
AllowOriginFunc: func(_ *http.Request, rawOrigin string) bool {
origin, err := url.Parse(rawOrigin)
if rawOrigin == "" || origin.Host == "" || err != nil {
return false
+1 -1
View File
@@ -15,7 +15,7 @@ import (
func TestRecover(t *testing.T) {
t.Parallel()
handler := func(isPanic, hijack bool) http.Handler {
handler := func(isPanic, _ bool) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if isPanic {
panic("Oh no!")
+2 -1
View File
@@ -325,7 +325,8 @@ func (api *API) insightsUserStatusCounts(rw http.ResponseWriter, r *http.Request
rows, err := api.Database.GetUserStatusCounts(ctx, database.GetUserStatusCountsParams{
StartTime: sixtyDaysAgo,
EndTime: nextHourInLoc,
Interval: int32(interval),
// #nosec G115 - Interval value is small and fits in int32 (typically days or hours)
Interval: int32(interval),
})
if err != nil {
if httpapi.IsUnauthorizedError(err) {
+4 -2
View File
@@ -202,8 +202,10 @@ func (api *API) paginatedMembers(rw http.ResponseWriter, r *http.Request) {
paginatedMemberRows, err := api.Database.PaginatedOrganizationMembers(ctx, database.PaginatedOrganizationMembersParams{
OrganizationID: organization.ID,
LimitOpt: int32(paginationParams.Limit),
OffsetOpt: int32(paginationParams.Offset),
// #nosec G115 - Pagination limits are small and fit in int32
LimitOpt: int32(paginationParams.Limit),
// #nosec G115 - Pagination offsets are small and fit in int32
OffsetOpt: int32(paginationParams.Offset),
})
if httpapi.Is404Error(err) {
httpapi.ResourceNotFound(rw)
+8 -8
View File
@@ -34,10 +34,10 @@ import (
)
var (
ValidationNoFromAddressErr = xerrors.New("'from' address not defined")
ValidationNoToAddressErr = xerrors.New("'to' address(es) not defined")
ValidationNoSmarthostErr = xerrors.New("'smarthost' address not defined")
ValidationNoHelloErr = xerrors.New("'hello' not defined")
ErrValidationNoFromAddress = xerrors.New("'from' address not defined")
ErrValidationNoToAddress = xerrors.New("'to' address(es) not defined")
ErrValidationNoSmarthost = xerrors.New("'smarthost' address not defined")
ErrValidationNoHello = xerrors.New("'hello' not defined")
//go:embed smtp/html.gotmpl
htmlTemplate string
@@ -493,7 +493,7 @@ func (*SMTPHandler) validateFromAddr(from string) (string, error) {
return "", xerrors.Errorf("parse 'from' address: %w", err)
}
if len(addrs) != 1 {
return "", ValidationNoFromAddressErr
return "", ErrValidationNoFromAddress
}
return from, nil
}
@@ -505,7 +505,7 @@ func (s *SMTPHandler) validateToAddrs(to string) ([]string, error) {
}
if len(addrs) == 0 {
s.log.Warn(context.Background(), "no valid 'to' address(es) defined; some may be invalid", slog.F("defined", to))
return nil, ValidationNoToAddressErr
return nil, ErrValidationNoToAddress
}
var out []string
@@ -522,7 +522,7 @@ func (s *SMTPHandler) validateToAddrs(to string) ([]string, error) {
func (s *SMTPHandler) smarthost() (string, string, error) {
smarthost := strings.TrimSpace(string(s.cfg.Smarthost))
if smarthost == "" {
return "", "", ValidationNoSmarthostErr
return "", "", ErrValidationNoSmarthost
}
host, port, err := net.SplitHostPort(string(s.cfg.Smarthost))
@@ -538,7 +538,7 @@ func (s *SMTPHandler) smarthost() (string, string, error) {
func (s *SMTPHandler) hello() (string, error) {
val := s.cfg.Hello.String()
if val == "" {
return "", ValidationNoHelloErr
return "", ErrValidationNoHello
}
return val, nil
}
+1
View File
@@ -337,6 +337,7 @@ func (m *Manager) syncUpdates(ctx context.Context) {
uctx, cancel := context.WithTimeout(ctx, time.Second*30)
defer cancel()
// #nosec G115 - Safe conversion for max send attempts which is expected to be within int32 range
failureParams.MaxAttempts = int32(m.cfg.MaxSendAttempts)
failureParams.RetryInterval = int32(m.cfg.RetryInterval.Value().Seconds())
n, err := m.store.BulkMarkNotificationMessagesFailed(uctx, failureParams)
+2
View File
@@ -192,6 +192,7 @@ type syncInterceptor struct {
func (b *syncInterceptor) BulkMarkNotificationMessagesSent(ctx context.Context, arg database.BulkMarkNotificationMessagesSentParams) (int64, error) {
updated, err := b.Store.BulkMarkNotificationMessagesSent(ctx, arg)
// #nosec G115 - Safe conversion as the count of updated notification messages is expected to be within int32 range
b.sent.Add(int32(updated))
if err != nil {
b.err.Store(err)
@@ -201,6 +202,7 @@ func (b *syncInterceptor) BulkMarkNotificationMessagesSent(ctx context.Context,
func (b *syncInterceptor) BulkMarkNotificationMessagesFailed(ctx context.Context, arg database.BulkMarkNotificationMessagesFailedParams) (int64, error) {
updated, err := b.Store.BulkMarkNotificationMessagesFailed(ctx, arg)
// #nosec G115 - Safe conversion as the count of updated notification messages is expected to be within int32 range
b.failed.Add(int32(updated))
if err != nil {
b.err.Store(err)
+1 -1
View File
@@ -169,7 +169,7 @@ func TestMetrics(t *testing.T) {
// See TestPendingUpdatesMetric for a more precise test.
return true
},
"coderd_notifications_synced_updates_total": func(metric *dto.Metric, series string) bool {
"coderd_notifications_synced_updates_total": func(metric *dto.Metric, _ string) bool {
if debug {
t.Logf("coderd_notifications_synced_updates_total = %v: %v", maxAttempts+1, metric.Counter.GetValue())
}
+4 -1
View File
@@ -209,7 +209,9 @@ func (n *notifier) process(ctx context.Context, success chan<- dispatchResult, f
// messages until they are dispatched - or until the lease expires (in exceptional cases).
func (n *notifier) fetch(ctx context.Context) ([]database.AcquireNotificationMessagesRow, error) {
msgs, err := n.store.AcquireNotificationMessages(ctx, database.AcquireNotificationMessagesParams{
Count: int32(n.cfg.LeaseCount),
// #nosec G115 - Safe conversion for lease count which is expected to be within int32 range
Count: int32(n.cfg.LeaseCount),
// #nosec G115 - Safe conversion for max send attempts which is expected to be within int32 range
MaxAttemptCount: int32(n.cfg.MaxSendAttempts),
NotifierID: n.id,
LeaseSeconds: int32(n.cfg.LeasePeriod.Value().Seconds()),
@@ -336,6 +338,7 @@ func (n *notifier) newFailedDispatch(msg database.AcquireNotificationMessagesRow
var result string
// If retryable and not the last attempt, it's a temporary failure.
// #nosec G115 - Safe conversion as MaxSendAttempts is expected to be small enough to fit in int32
if retryable && msg.AttemptCount < int32(n.cfg.MaxSendAttempts)-1 {
result = ResultTempFail
} else {
+4 -3
View File
@@ -196,11 +196,12 @@ func verifyCollectedMetrics(t *testing.T, expected []*agentproto.Stats_Metric, a
err := actual[i].Write(&d)
require.NoError(t, err)
if e.Type == agentproto.Stats_Metric_COUNTER {
switch e.Type {
case agentproto.Stats_Metric_COUNTER:
require.Equal(t, e.Value, d.Counter.GetValue())
} else if e.Type == agentproto.Stats_Metric_GAUGE {
case agentproto.Stats_Metric_GAUGE:
require.Equal(t, e.Value, d.Gauge.GetValue())
} else {
default:
require.Failf(t, "unsupported type: %s", string(e.Type))
}
@@ -287,7 +287,7 @@ func convertParameterInsights(rows []database.GetTemplateParameterInsightsRow) [
if _, ok := m[key]; !ok {
m[key] = 0
}
m[key] = m[key] + r.Count
m[key] += r.Count
}
}
@@ -216,11 +216,9 @@ func TestWorkspaceLatestBuildTotals(t *testing.T) {
Total int
Status map[codersdk.ProvisionerJobStatus]int
}{{
Name: "None",
Database: func() database.Store {
return dbmem.New()
},
Total: 0,
Name: "None",
Database: dbmem.New,
Total: 0,
}, {
Name: "Multiple",
Database: func() database.Store {
@@ -289,10 +287,8 @@ func TestWorkspaceLatestBuildStatuses(t *testing.T) {
ExpectedWorkspaces int
ExpectedStatuses map[codersdk.ProvisionerJobStatus]int
}{{
Name: "None",
Database: func() database.Store {
return dbmem.New()
},
Name: "None",
Database: dbmem.New,
ExpectedWorkspaces: 0,
}, {
Name: "Multiple",
@@ -121,7 +121,7 @@ type server struct {
// We use the null byte (0x00) in generating a canonical map key for tags, so
// it cannot be used in the tag keys or values.
var ErrorTagsContainNullByte = xerrors.New("tags cannot contain the null byte (0x00)")
var ErrTagsContainNullByte = xerrors.New("tags cannot contain the null byte (0x00)")
type Tags map[string]string
@@ -136,7 +136,7 @@ func (t Tags) ToJSON() (json.RawMessage, error) {
func (t Tags) Valid() error {
for k, v := range t {
if slices.Contains([]byte(k), 0x00) || slices.Contains([]byte(v), 0x00) {
return ErrorTagsContainNullByte
return ErrTagsContainNullByte
}
}
return nil
@@ -1996,7 +1996,8 @@ func InsertWorkspaceResource(ctx context.Context, db database.Store, jobID uuid.
DisplayApps: convertDisplayApps(prAgent.GetDisplayApps()),
InstanceMetadata: pqtype.NullRawMessage{},
ResourceMetadata: pqtype.NullRawMessage{},
DisplayOrder: int32(prAgent.Order),
// #nosec G115 - Order represents a display order value that's always small and fits in int32
DisplayOrder: int32(prAgent.Order),
})
if err != nil {
return xerrors.Errorf("insert agent: %w", err)
@@ -2011,7 +2012,8 @@ func InsertWorkspaceResource(ctx context.Context, db database.Store, jobID uuid.
Key: md.Key,
Timeout: md.Timeout,
Interval: md.Interval,
DisplayOrder: int32(md.Order),
// #nosec G115 - Order represents a display order value that's always small and fits in int32
DisplayOrder: int32(md.Order),
}
err := db.InsertWorkspaceAgentMetadata(ctx, p)
if err != nil {
@@ -2197,9 +2199,10 @@ func InsertWorkspaceResource(ctx context.Context, db database.Store, jobID uuid.
HealthcheckInterval: app.Healthcheck.Interval,
HealthcheckThreshold: app.Healthcheck.Threshold,
Health: health,
DisplayOrder: int32(app.Order),
Hidden: app.Hidden,
OpenIn: openIn,
// #nosec G115 - Order represents a display order value that's always small and fits in int32
DisplayOrder: int32(app.Order),
Hidden: app.Hidden,
OpenIn: openIn,
})
if err != nil {
return xerrors.Errorf("insert app: %w", err)
+1
View File
@@ -78,6 +78,7 @@ func convertQuery(cfg ConvertConfig, q ast.Body) (sqltypes.BooleanNode, error) {
func convertExpression(cfg ConvertConfig, e *ast.Expr) (sqltypes.BooleanNode, error) {
if e.IsCall() {
//nolint:forcetypeassert
n, err := convertCall(cfg, e.Terms.([]*ast.Term))
if err != nil {
return nil, xerrors.Errorf("call: %w", err)
+3
View File
@@ -77,6 +77,7 @@ func (r TemplateAutostopRequirement) DaysMap() map[time.Weekday]bool {
func daysMap(daysOfWeek uint8) map[time.Weekday]bool {
days := make(map[time.Weekday]bool)
for i, day := range DaysOfWeek {
// #nosec G115 - Safe conversion, i ranges from 0-6 for days of the week
days[day] = daysOfWeek&(1<<uint(i)) != 0
}
return days
@@ -88,6 +89,7 @@ func VerifyTemplateAutostopRequirement(days uint8, weeks int64) error {
if days&0b10000000 != 0 {
return xerrors.New("invalid autostop requirement days, last bit is set")
}
//nolint:staticcheck
if days > 0b11111111 {
return xerrors.New("invalid autostop requirement days, too large")
}
@@ -106,6 +108,7 @@ func VerifyTemplateAutostartRequirement(days uint8) error {
if days&0b10000000 != 0 {
return xerrors.New("invalid autostart requirement days, last bit is set")
}
//nolint:staticcheck
if days > 0b11111111 {
return xerrors.New("invalid autostart requirement days, too large")
}
+3 -1
View File
@@ -97,8 +97,10 @@ func Workspaces(ctx context.Context, db database.Store, query string, page coder
filter := database.GetWorkspacesParams{
AgentInactiveDisconnectTimeoutSeconds: int64(agentInactiveDisconnectTimeout.Seconds()),
// #nosec G115 - Safe conversion for pagination offset which is expected to be within int32 range
Offset: int32(page.Offset),
Limit: int32(page.Limit),
// #nosec G115 - Safe conversion for pagination limit which is expected to be within int32 range
Limit: int32(page.Limit),
}
if query == "" {
+8 -6
View File
@@ -729,7 +729,8 @@ func ConvertWorkspaceBuild(build database.WorkspaceBuild) WorkspaceBuild {
WorkspaceID: build.WorkspaceID,
JobID: build.JobID,
TemplateVersionID: build.TemplateVersionID,
BuildNumber: uint32(build.BuildNumber),
// #nosec G115 - Safe conversion as build numbers are expected to be positive and within uint32 range
BuildNumber: uint32(build.BuildNumber),
}
}
@@ -1035,11 +1036,12 @@ func ConvertTemplate(dbTemplate database.Template) Template {
FailureTTLMillis: time.Duration(dbTemplate.FailureTTL).Milliseconds(),
TimeTilDormantMillis: time.Duration(dbTemplate.TimeTilDormant).Milliseconds(),
TimeTilDormantAutoDeleteMillis: time.Duration(dbTemplate.TimeTilDormantAutoDelete).Milliseconds(),
AutostopRequirementDaysOfWeek: codersdk.BitmapToWeekdays(uint8(dbTemplate.AutostopRequirementDaysOfWeek)),
AutostopRequirementWeeks: dbTemplate.AutostopRequirementWeeks,
AutostartAllowedDays: codersdk.BitmapToWeekdays(dbTemplate.AutostartAllowedDays()),
RequireActiveVersion: dbTemplate.RequireActiveVersion,
Deprecated: dbTemplate.Deprecated != "",
// #nosec G115 - Safe conversion as AutostopRequirementDaysOfWeek is a bitmap of 7 days, easily within uint8 range
AutostopRequirementDaysOfWeek: codersdk.BitmapToWeekdays(uint8(dbTemplate.AutostopRequirementDaysOfWeek)),
AutostopRequirementWeeks: dbTemplate.AutostopRequirementWeeks,
AutostartAllowedDays: codersdk.BitmapToWeekdays(dbTemplate.AutostartAllowedDays()),
RequireActiveVersion: dbTemplate.RequireActiveVersion,
Deprecated: dbTemplate.Deprecated != "",
}
}
+1 -1
View File
@@ -1045,7 +1045,7 @@ func (api *API) convertTemplate(
TimeTilDormantMillis: time.Duration(template.TimeTilDormant).Milliseconds(),
TimeTilDormantAutoDeleteMillis: time.Duration(template.TimeTilDormantAutoDelete).Milliseconds(),
AutostopRequirement: codersdk.TemplateAutostopRequirement{
DaysOfWeek: codersdk.BitmapToWeekdays(uint8(template.AutostopRequirementDaysOfWeek)),
DaysOfWeek: codersdk.BitmapToWeekdays(uint8(template.AutostopRequirementDaysOfWeek)), // #nosec G115 - Safe conversion as AutostopRequirementDaysOfWeek is a 7-bit bitmap
Weeks: autostopRequirementWeeks,
},
AutostartRequirement: codersdk.TemplateAutostartRequirement{
+7 -7
View File
@@ -843,9 +843,11 @@ func (api *API) templateVersionsByTemplate(rw http.ResponseWriter, r *http.Reque
versions, err := store.GetTemplateVersionsByTemplateID(ctx, database.GetTemplateVersionsByTemplateIDParams{
TemplateID: template.ID,
AfterID: paginationParams.AfterID,
LimitOpt: int32(paginationParams.Limit),
OffsetOpt: int32(paginationParams.Offset),
Archived: archiveFilter,
// #nosec G115 - Pagination limits are small and fit in int32
LimitOpt: int32(paginationParams.Limit),
// #nosec G115 - Pagination offsets are small and fit in int32
OffsetOpt: int32(paginationParams.Offset),
Archived: archiveFilter,
})
if errors.Is(err, sql.ErrNoRows) {
httpapi.Write(ctx, rw, http.StatusOK, apiVersions)
@@ -1280,10 +1282,8 @@ func (api *API) setArchiveTemplateVersion(archive bool) func(rw http.ResponseWri
if archiveError != nil {
err = archiveError
} else {
if len(archived) == 0 {
err = xerrors.New("Unable to archive specified version, the version is likely in use by a workspace or currently set to the active version")
}
} else if len(archived) == 0 {
err = xerrors.New("Unable to archive specified version, the version is likely in use by a workspace or currently set to the active version")
}
} else {
err = api.Database.UnarchiveTemplateVersion(ctx, database.UnarchiveTemplateVersionParams{
+1 -1
View File
@@ -98,7 +98,7 @@ func TracerProvider(ctx context.Context, service string, opts TracerOpts) (*sdkt
tracerProvider := sdktrace.NewTracerProvider(tracerOpts...)
otel.SetTracerProvider(tracerProvider)
// Ignore otel errors!
otel.SetErrorHandler(otel.ErrorHandlerFunc(func(err error) {}))
otel.SetErrorHandler(otel.ErrorHandlerFunc(func(_ error) {}))
otel.SetTextMapPropagator(
propagation.NewCompositeTextMapPropagator(
propagation.TraceContext{},
+3
View File
@@ -78,6 +78,7 @@ func slogFieldsToAttributes(m slog.Map) []attribute.KeyValue {
case []int64:
value = attribute.Int64SliceValue(v)
case uint:
// #nosec G115 - Safe conversion from uint to int64 as we're only using this for non-critical logging/tracing
value = attribute.Int64Value(int64(v))
// no uint slice method
case uint8:
@@ -90,6 +91,8 @@ func slogFieldsToAttributes(m slog.Map) []attribute.KeyValue {
value = attribute.Int64Value(int64(v))
// no uint32 slice method
case uint64:
// #nosec G115 - Safe conversion from uint64 to int64 as we're only using this for non-critical logging/tracing
// This is intentionally lossy for very large values, but acceptable for tracing purposes
value = attribute.Int64Value(int64(v))
// no uint64 slice method
case string:
+2
View File
@@ -176,6 +176,7 @@ func mapToBasicMap(m map[string]interface{}) map[string]interface{} {
case int32:
val = int64(v)
case uint:
// #nosec G115 - Safe conversion for test data
val = int64(v)
case uint8:
val = int64(v)
@@ -184,6 +185,7 @@ func mapToBasicMap(m map[string]interface{}) map[string]interface{} {
case uint32:
val = int64(v)
case uint64:
// #nosec G115 - Safe conversion for test data with small test values
val = int64(v)
case time.Duration:
val = v.String()
+1 -1
View File
@@ -73,7 +73,7 @@ func New(db database.Store, log slog.Logger, opts Options) *Checker {
opts.UpdateTimeout = 30 * time.Second
}
if opts.Notify == nil {
opts.Notify = func(r Result) {}
opts.Notify = func(_ Result) {}
}
ctx, cancel := context.WithCancel(context.Background())
+4 -3
View File
@@ -1509,7 +1509,8 @@ func (api *API) accessTokenClaims(ctx context.Context, rw http.ResponseWriter, s
func (api *API) userInfoClaims(ctx context.Context, rw http.ResponseWriter, state httpmw.OAuth2State, logger slog.Logger) (userInfoClaims map[string]interface{}, ok bool) {
userInfoClaims = make(map[string]interface{})
userInfo, err := api.OIDCConfig.Provider.UserInfo(ctx, oauth2.StaticTokenSource(state.Token))
if err == nil {
switch {
case err == nil:
err = userInfo.Claims(&userInfoClaims)
if err != nil {
logger.Error(ctx, "oauth2: unable to unmarshal user info claims", slog.Error(err))
@@ -1524,14 +1525,14 @@ func (api *API) userInfoClaims(ctx context.Context, rw http.ResponseWriter, stat
slog.F("claim_fields", claimFields(userInfoClaims)),
slog.F("blank", blankFields(userInfoClaims)),
)
} else if !strings.Contains(err.Error(), "user info endpoint is not supported by this provider") {
case !strings.Contains(err.Error(), "user info endpoint is not supported by this provider"):
logger.Error(ctx, "oauth2: unable to obtain user information claims", slog.Error(err))
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
Message: "Failed to obtain user information claims.",
Detail: "The attempt to fetch claims via the UserInfo endpoint failed: " + err.Error(),
})
return nil, false
} else {
default:
// The OIDC provider does not support the UserInfo endpoint.
// This is not an error, but we should log it as it may mean
// that some claims are missing.
+1 -1
View File
@@ -1453,7 +1453,7 @@ func TestUserOIDC(t *testing.T) {
oidctest.WithStaticUserInfo(tc.UserInfoClaims),
}
if tc.AccessTokenClaims != nil && len(tc.AccessTokenClaims) > 0 {
if len(tc.AccessTokenClaims) > 0 {
opts = append(opts, oidctest.WithAccessTokenJWTHook(func(email string, exp time.Time) jwt.MapClaims {
return tc.AccessTokenClaims
}))
+4 -2
View File
@@ -306,8 +306,10 @@ func (api *API) GetUsers(rw http.ResponseWriter, r *http.Request) ([]database.Us
CreatedAfter: params.CreatedAfter,
CreatedBefore: params.CreatedBefore,
GithubComUserID: params.GithubComUserID,
OffsetOpt: int32(paginationParams.Offset),
LimitOpt: int32(paginationParams.Limit),
// #nosec G115 - Pagination offsets are small and fit in int32
OffsetOpt: int32(paginationParams.Offset),
// #nosec G115 - Pagination limits are small and fit in int32
LimitOpt: int32(paginationParams.Limit),
})
if err != nil {
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
+2 -2
View File
@@ -51,8 +51,8 @@ func (m *Map[K, V]) LoadOrStore(key K, value V) (actual V, loaded bool) {
return act.(V), loaded
}
func (m *Map[K, V]) CompareAndSwap(key K, old V, new V) bool {
return m.m.CompareAndSwap(key, old, new)
func (m *Map[K, V]) CompareAndSwap(key K, old V, newVal V) bool {
return m.m.CompareAndSwap(key, old, newVal)
}
func (m *Map[K, V]) CompareAndDelete(key K, old V) (deleted bool) {
+1 -1
View File
@@ -35,7 +35,7 @@ func TimezoneIANA() (*time.Location, error) {
if err != nil {
return nil, xerrors.Errorf("read location of %s: %w", etcLocaltime, err)
}
stripped := strings.Replace(lp, zoneInfoPath, "", -1)
stripped := strings.ReplaceAll(lp, zoneInfoPath, "")
stripped = strings.TrimPrefix(stripped, string(filepath.Separator))
loc, err = time.LoadLocation(stripped)
if err != nil {
+10 -8
View File
@@ -215,11 +215,12 @@ func (api *API) patchWorkspaceAgentLogs(rw http.ResponseWriter, r *http.Request)
}
logs, err := api.Database.InsertWorkspaceAgentLogs(ctx, database.InsertWorkspaceAgentLogsParams{
AgentID: workspaceAgent.ID,
CreatedAt: dbtime.Now(),
Output: output,
Level: level,
LogSourceID: req.LogSourceID,
AgentID: workspaceAgent.ID,
CreatedAt: dbtime.Now(),
Output: output,
Level: level,
LogSourceID: req.LogSourceID,
// #nosec G115 - Log output length is limited and fits in int32
OutputLength: int32(outputLength),
})
if err != nil {
@@ -979,10 +980,11 @@ func (api *API) handleResumeToken(ctx context.Context, rw http.ResponseWriter, r
peerID, err = api.Options.CoordinatorResumeTokenProvider.VerifyResumeToken(ctx, resumeToken)
// If the token is missing the key ID, it's probably an old token in which
// case we just want to generate a new peer ID.
if xerrors.Is(err, jwtutils.ErrMissingKeyID) {
switch {
case xerrors.Is(err, jwtutils.ErrMissingKeyID):
peerID = uuid.New()
err = nil
} else if err != nil {
case err != nil:
httpapi.Write(ctx, rw, http.StatusUnauthorized, codersdk.Response{
Message: workspacesdk.CoordinateAPIInvalidResumeToken,
Detail: err.Error(),
@@ -991,7 +993,7 @@ func (api *API) handleResumeToken(ctx context.Context, rw http.ResponseWriter, r
},
})
return peerID, err
} else {
default:
api.Logger.Debug(ctx, "accepted coordinate resume token for peer",
slog.F("peer_id", peerID.String()))
}
+2
View File
@@ -844,6 +844,7 @@ func TestWorkspaceAgentListeningPorts(t *testing.T) {
o.PortCacheDuration = time.Millisecond
})
resources := coderdtest.AwaitWorkspaceAgents(t, client, r.Workspace.ID)
// #nosec G115 - Safe conversion as TCP port numbers are within uint16 range (0-65535)
return client, uint16(coderdPort), resources[0].Agents[0].ID
}
@@ -878,6 +879,7 @@ func TestWorkspaceAgentListeningPorts(t *testing.T) {
_ = l.Close()
})
// #nosec G115 - Safe conversion as TCP port numbers are within uint16 range (0-65535)
port = uint16(tcpAddr.Port)
return true
}, testutil.WaitShort, testutil.IntervalFast)
+1
View File
@@ -1667,6 +1667,7 @@ func Run(t *testing.T, appHostIsPrimary bool, factory DeploymentFactory) {
require.True(t, ok)
appDetails := setupProxyTest(t, &DeploymentOptions{
// #nosec G115 - Safe conversion as TCP port numbers are within uint16 range (0-65535)
port: uint16(tcpAddr.Port),
})
+2 -2
View File
@@ -127,7 +127,7 @@ func (d *Details) AppClient(t *testing.T) *codersdk.Client {
client := codersdk.New(d.PathAppBaseURL)
client.SetSessionToken(d.SDKClient.SessionToken())
forceURLTransport(t, client)
client.HTTPClient.CheckRedirect = func(req *http.Request, via []*http.Request) error {
client.HTTPClient.CheckRedirect = func(_ *http.Request, _ []*http.Request) error {
return http.ErrUseLastResponse
}
@@ -182,7 +182,7 @@ func setupProxyTestWithFactory(t *testing.T, factory DeploymentFactory, opts *De
// Configure the HTTP client to not follow redirects and to route all
// requests regardless of hostname to the coderd test server.
deployment.SDKClient.HTTPClient.CheckRedirect = func(req *http.Request, via []*http.Request) error {
deployment.SDKClient.HTTPClient.CheckRedirect = func(_ *http.Request, _ []*http.Request) error {
return http.ErrUseLastResponse
}
forceURLTransport(t, deployment.SDKClient)
+1 -1
View File
@@ -267,7 +267,7 @@ func CompileHostnamePattern(pattern string) (*regexp.Regexp, error) {
regexPattern = strings.Replace(regexPattern, "*", "([^.]+)", 1)
// Allow trailing period.
regexPattern = regexPattern + "\\.?"
regexPattern += "\\.?"
// Allow optional port number.
regexPattern += "(:\\d+)?"
+6 -4
View File
@@ -120,7 +120,7 @@ func (p *DBTokenProvider) Issue(ctx context.Context, rw http.ResponseWriter, r *
// (later on) fails and the user is not authenticated, they will be
// redirected to the login page or app auth endpoint using code below.
Optional: true,
SessionTokenFunc: func(r *http.Request) string {
SessionTokenFunc: func(_ *http.Request) string {
return issueReq.SessionToken
},
})
@@ -132,13 +132,14 @@ func (p *DBTokenProvider) Issue(ctx context.Context, rw http.ResponseWriter, r *
// Lookup workspace app details from DB.
dbReq, err := appReq.getDatabase(dangerousSystemCtx, p.Database)
if xerrors.Is(err, sql.ErrNoRows) {
switch {
case xerrors.Is(err, sql.ErrNoRows):
WriteWorkspaceApp404(p.Logger, p.DashboardURL, rw, r, &appReq, nil, err.Error())
return nil, "", false
} else if xerrors.Is(err, errWorkspaceStopped) {
case xerrors.Is(err, errWorkspaceStopped):
WriteWorkspaceOffline(p.Logger, p.DashboardURL, rw, r, &appReq)
return nil, "", false
} else if err != nil {
case err != nil:
WriteWorkspaceApp500(p.Logger, p.DashboardURL, rw, r, &appReq, err, "get app details from database")
return nil, "", false
}
@@ -464,6 +465,7 @@ func (p *DBTokenProvider) auditInitRequest(ctx context.Context, w http.ResponseW
Ip: ip,
UserAgent: userAgent,
SlugOrPort: appInfo.SlugOrPort,
// #nosec G115 - Safe conversion as HTTP status code is expected to be within int32 range (typically 100-599)
StatusCode: int32(statusCode),
StartedAt: aReq.time,
UpdatedAt: aReq.time,
+2 -1
View File
@@ -45,7 +45,7 @@ const (
// login page.
// It is important that this URL can never match a valid app hostname.
//
// DEPRECATED: we no longer use this, but we still redirect from it to the
// Deprecated: we no longer use this, but we still redirect from it to the
// main login page.
appLogoutHostname = "coder-logout"
)
@@ -693,6 +693,7 @@ func (s *Server) workspaceAgentPTY(rw http.ResponseWriter, r *http.Request) {
}
defer release()
log.Debug(ctx, "dialed workspace agent")
// #nosec G115 - Safe conversion for terminal height/width which are expected to be within uint16 range (0-65535)
ptNetConn, err := agentConn.ReconnectingPTY(ctx, reconnect, uint16(height), uint16(width), r.URL.Query().Get("command"), func(arp *workspacesdk.AgentReconnectingPTYInit) {
arp.Container = container
arp.ContainerUser = containerUser
+5 -3
View File
@@ -161,9 +161,11 @@ func (api *API) workspaceBuilds(rw http.ResponseWriter, r *http.Request) {
req := database.GetWorkspaceBuildsByWorkspaceIDParams{
WorkspaceID: workspace.ID,
AfterID: paginationParams.AfterID,
OffsetOpt: int32(paginationParams.Offset),
LimitOpt: int32(paginationParams.Limit),
Since: dbtime.Time(since),
// #nosec G115 - Pagination offsets are small and fit in int32
OffsetOpt: int32(paginationParams.Offset),
// #nosec G115 - Pagination limits are small and fit in int32
LimitOpt: int32(paginationParams.Limit),
Since: dbtime.Time(since),
}
workspaceBuilds, err = store.GetWorkspaceBuildsByWorkspaceID(ctx, req)
if xerrors.Is(err, sql.ErrNoRows) {
+1 -1
View File
@@ -129,7 +129,7 @@ func TestWorkspace(t *testing.T) {
want = want[:32-5] + "-test"
}
// Sometimes truncated names result in `--test` which is not an allowed name.
want = strings.Replace(want, "--", "-", -1)
want = strings.ReplaceAll(want, "--", "-")
err := client.UpdateWorkspace(ctx, ws1.ID, codersdk.UpdateWorkspaceRequest{
Name: want,
})
+5 -3
View File
@@ -68,6 +68,7 @@ func (r *Reporter) ReportAppStats(ctx context.Context, stats []workspaceapps.Sta
batch.SessionID = append(batch.SessionID, stat.SessionID)
batch.SessionStartedAt = append(batch.SessionStartedAt, stat.SessionStartedAt)
batch.SessionEndedAt = append(batch.SessionEndedAt, stat.SessionEndedAt)
// #nosec G115 - Safe conversion as request count is expected to be within int32 range
batch.Requests = append(batch.Requests, int32(stat.Requests))
if len(batch.UserID) >= r.opts.AppStatBatchSize {
@@ -154,16 +155,17 @@ func (r *Reporter) ReportAgentStats(ctx context.Context, now time.Time, workspac
templateSchedule, err := (*(r.opts.TemplateScheduleStore.Load())).Get(ctx, r.opts.Database, workspace.TemplateID)
// If the template schedule fails to load, just default to bumping
// without the next transition and log it.
if err == nil {
switch {
case err == nil:
next, allowed := schedule.NextAutostart(now, workspace.AutostartSchedule.String, templateSchedule)
if allowed {
nextAutostart = next
}
} else if database.IsQueryCanceledError(err) {
case database.IsQueryCanceledError(err):
r.opts.Logger.Debug(ctx, "query canceled while loading template schedule",
slog.F("workspace_id", workspace.ID),
slog.F("template_id", workspace.TemplateID))
} else {
default:
r.opts.Logger.Error(ctx, "failed to load template schedule bumping activity, defaulting to bumping by 60min",
slog.F("workspace_id", workspace.ID),
slog.F("template_id", workspace.TemplateID),
+7 -8
View File
@@ -70,10 +70,9 @@ func (s *sub) handleEvent(ctx context.Context, event wspubsub.WorkspaceEvent, er
default:
if err == nil {
return
} else {
// Always attempt an update if the pubsub lost connection
s.logger.Warn(ctx, "failed to handle workspace event", slog.Error(err))
}
// Always attempt an update if the pubsub lost connection
s.logger.Warn(ctx, "failed to handle workspace event", slog.Error(err))
}
// Use context containing actor
@@ -199,7 +198,7 @@ func (u *updatesProvider) Subscribe(ctx context.Context, userID uuid.UUID) (tail
return sub, nil
}
func produceUpdate(old, new workspacesByID) (out *proto.WorkspaceUpdate, updated bool) {
func produceUpdate(oldWS, newWS workspacesByID) (out *proto.WorkspaceUpdate, updated bool) {
out = &proto.WorkspaceUpdate{
UpsertedWorkspaces: []*proto.Workspace{},
UpsertedAgents: []*proto.Agent{},
@@ -207,8 +206,8 @@ func produceUpdate(old, new workspacesByID) (out *proto.WorkspaceUpdate, updated
DeletedAgents: []*proto.Agent{},
}
for wsID, newWorkspace := range new {
oldWorkspace, exists := old[wsID]
for wsID, newWorkspace := range newWS {
oldWorkspace, exists := oldWS[wsID]
// Upsert both workspace and agents if the workspace is new
if !exists {
out.UpsertedWorkspaces = append(out.UpsertedWorkspaces, &proto.Workspace{
@@ -256,8 +255,8 @@ func produceUpdate(old, new workspacesByID) (out *proto.WorkspaceUpdate, updated
}
// Delete workspace and agents if the workspace is deleted
for wsID, oldWorkspace := range old {
if _, exists := new[wsID]; !exists {
for wsID, oldWorkspace := range oldWS {
if _, exists := newWS[wsID]; !exists {
out.DeletedWorkspaces = append(out.DeletedWorkspaces, &proto.Workspace{
Id: tailnet.UUIDToByteSlice(wsID),
Name: oldWorkspace.WorkspaceName,
+1
View File
@@ -364,6 +364,7 @@ func (*mockAuthorizer) Authorize(context.Context, rbac.Subject, policy.Action, r
// Prepare implements rbac.Authorizer.
func (*mockAuthorizer) Prepare(context.Context, rbac.Subject, policy.Action, string) (rbac.PreparedAuthorized, error) {
//nolint:nilnil
return nil, nil
}