Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 55340de

Browse files
feat: add deployment setting to disable the Codernauts game (#27662)
Adds a `codernauts_enabled` runtime setting (default: enabled) that controls whether the Codernauts game link appears in the user dropdown menu. A toggle at the bottom of the Deployment > Appearance page controls it, and the value persists in `site_configs`, so it survives restarts and upgrades without any CLI flags or environment variables. The setting works on all licenses: `GET /api/v2/appearance` reports it from both the enterprise and the default (AGPL) appearance fetchers, and `PUT /api/v2/appearance` persists it gated only by the deployment-config RBAC permission, not by an entitlement. On the Appearance page the toggle renders outside the Premium paywall introduced in #27948; the other appearance fields keep their existing licensing behavior. Note: a pure AGPL-only build of coderd does not register the `/api/v2/appearance` routes at all, so the toggle cannot be saved there. The standard `coder server` binary is unaffected regardless of license state. <details> <summary>Implementation notes</summary> - `coderd/database/queries/siteconfig.sql`: new `GetCodernautsEnabled` / `UpsertCodernautsEnabled` queries backed by a `codernauts_enabled` key in `site_configs`; defaults to `true` when unset (no migration needed). - `coderd/database/dbauthz`: read has no authz checks (matching other appearance reads); write requires `ResourceDeploymentConfig` update. Coverage added to `dbauthz_test.go`. - `codersdk`: `codernauts_enabled` added to `AppearanceConfig` and `UpdateAppearanceConfig`. - `coderd/appearance`: the default fetcher takes a `database.Store` and reads the setting from the database so unlicensed deployments serve it too. - `enterprise/coderd/appearance.go`: fetches the value in `Fetch` and persists it in `putAppearance`. - Frontend: "Codernauts game" toggle section on Deployment > Appearance saving immediately via the existing appearance mutation; `codernauts_enabled` threaded from `useDashboard().appearance` through Navbar to `UserDropdownContent`, which renders the menu item only when enabled. Storybook stories with `play` functions cover toggling (entitled and not) and the dropdown hiding the link when disabled. </details> --- 🤖 This PR was generated by Coder Agents on behalf of @bartekgatzcoder.
1 parent 805b47a commit 55340de

28 files changed

Lines changed: 321 additions & 14 deletions

File tree

coderd/apidoc/docs.go

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/apidoc/swagger.json

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/appearance/appearance.go

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ package appearance
33
import (
44
"context"
55

6+
"golang.org/x/xerrors"
7+
8+
"github.com/coder/coder/v2/coderd/database"
69
"github.com/coder/coder/v2/codersdk"
710
)
811

@@ -11,22 +14,29 @@ type Fetcher interface {
1114
}
1215

1316
type AGPLFetcher struct {
14-
docsURL string
17+
database database.Store
18+
docsURL string
1519
}
1620

17-
func (f AGPLFetcher) Fetch(context.Context) (codersdk.AppearanceConfig, error) {
21+
func (f AGPLFetcher) Fetch(ctx context.Context) (codersdk.AppearanceConfig, error) {
22+
codernautsEnabled, err := f.database.GetCodernautsEnabled(ctx)
23+
if err != nil {
24+
return codersdk.AppearanceConfig{}, xerrors.Errorf("get codernauts enabled: %w", err)
25+
}
1826
return codersdk.AppearanceConfig{
1927
AnnouncementBanners: []codersdk.BannerConfig{},
2028
SupportLinks: codersdk.DefaultSupportLinks(f.docsURL),
2129
DocsURL: f.docsURL,
30+
CodernautsEnabled: codernautsEnabled,
2231
}, nil
2332
}
2433

25-
func NewDefaultFetcher(docsURL string) Fetcher {
34+
func NewDefaultFetcher(db database.Store, docsURL string) Fetcher {
2635
if docsURL == "" {
2736
docsURL = codersdk.DefaultDocsURL()
2837
}
2938
return &AGPLFetcher{
30-
docsURL: docsURL,
39+
database: db,
40+
docsURL: docsURL,
3141
}
3242
}

coderd/coderd.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -758,7 +758,7 @@ func New(options *Options) *API {
758758
options.AppSigningKeyCache,
759759
)
760760

761-
f := appearance.NewDefaultFetcher(api.DeploymentValues.DocsURL.String())
761+
f := appearance.NewDefaultFetcher(options.Database, api.DeploymentValues.DocsURL.String())
762762
api.AppearanceFetcher.Store(&f)
763763
api.PortSharer.Store(&portsharing.DefaultPortSharer)
764764
api.PrebuildsClaimer.Store(&prebuilds.DefaultClaimer)

coderd/database/dbauthz/dbauthz.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3788,6 +3788,10 @@ func (q *querier) GetChildChatsByParentIDs(ctx context.Context, arg database.Get
37883788
return fetchWithPostFilter(q.auth, policy.ActionRead, q.db.GetChildChatsByParentIDs)(ctx, arg)
37893789
}
37903790

3791+
func (q *querier) GetCodernautsEnabled(ctx context.Context) (bool, error) {
3792+
return q.db.GetCodernautsEnabled(ctx)
3793+
}
3794+
37913795
func (q *querier) GetConnectionLogsOffset(ctx context.Context, arg database.GetConnectionLogsOffsetParams) ([]database.GetConnectionLogsOffsetRow, error) {
37923796
// Just like with the audit logs query, shortcut if the user is an owner.
37933797
err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceConnectionLog)
@@ -9199,6 +9203,13 @@ func (q *querier) UpsertChatWorkspaceTTL(ctx context.Context, workspaceTtl strin
91999203
return q.db.UpsertChatWorkspaceTTL(ctx, workspaceTtl)
92009204
}
92019205

9206+
func (q *querier) UpsertCodernautsEnabled(ctx context.Context, enabled bool) error {
9207+
if err := q.authorizeContext(ctx, policy.ActionUpdate, rbac.ResourceDeploymentConfig); err != nil {
9208+
return err
9209+
}
9210+
return q.db.UpsertCodernautsEnabled(ctx, enabled)
9211+
}
9212+
92029213
func (q *querier) UpsertDefaultProxy(ctx context.Context, arg database.UpsertDefaultProxyParams) error {
92039214
if err := q.authorizeContext(ctx, policy.ActionUpdate, rbac.ResourceSystem); err != nil {
92049215
return err

coderd/database/dbauthz/dbauthz_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5490,6 +5490,14 @@ func (s *MethodTestSuite) TestSystemFunctions() {
54905490
dbm.EXPECT().UpsertApplicationName(gomock.Any(), "").Return(nil).AnyTimes()
54915491
check.Args("").Asserts(rbac.ResourceDeploymentConfig, policy.ActionUpdate)
54925492
}))
5493+
s.Run("GetCodernautsEnabled", s.Mocked(func(dbm *dbmock.MockStore, _ *gofakeit.Faker, check *expects) {
5494+
dbm.EXPECT().GetCodernautsEnabled(gomock.Any()).Return(true, nil).AnyTimes()
5495+
check.Args().Asserts()
5496+
}))
5497+
s.Run("UpsertCodernautsEnabled", s.Mocked(func(dbm *dbmock.MockStore, _ *gofakeit.Faker, check *expects) {
5498+
dbm.EXPECT().UpsertCodernautsEnabled(gomock.Any(), false).Return(nil).AnyTimes()
5499+
check.Args(false).Asserts(rbac.ResourceDeploymentConfig, policy.ActionUpdate)
5500+
}))
54935501
s.Run("UpsertBoundaryUsageStats", s.Mocked(func(dbm *dbmock.MockStore, _ *gofakeit.Faker, check *expects) {
54945502
arg := database.UpsertBoundaryUsageStatsParams{ReplicaID: uuid.New()}
54955503
dbm.EXPECT().UpsertBoundaryUsageStats(gomock.Any(), arg).Return(false, nil).AnyTimes()

coderd/database/dbmetrics/querymetrics.go

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/dbmock/dbmock.go

Lines changed: 29 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/querier.go

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/queries.sql.go

Lines changed: 34 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)