mirror of
https://github.com/coder/coder.git
synced 2026-10-16 14:48:56 +08:00
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.
418 lines
15 KiB
SQL
418 lines
15 KiB
SQL
-- name: UpsertDefaultProxy :exec
|
|
-- The default proxy is implied and not actually stored in the database.
|
|
-- So we need to store it's configuration here for display purposes.
|
|
-- The functional values are immutable and controlled implicitly.
|
|
INSERT INTO site_configs (key, value)
|
|
VALUES
|
|
('default_proxy_display_name', @display_name :: text),
|
|
('default_proxy_icon_url', @icon_url :: text)
|
|
ON CONFLICT
|
|
(key)
|
|
DO UPDATE SET value = EXCLUDED.value WHERE site_configs.key = EXCLUDED.key
|
|
;
|
|
|
|
-- name: GetDefaultProxyConfig :one
|
|
SELECT
|
|
COALESCE((SELECT value FROM site_configs WHERE key = 'default_proxy_display_name'), 'Default') :: text AS display_name,
|
|
COALESCE((SELECT value FROM site_configs WHERE key = 'default_proxy_icon_url'), '/emojis/1f3e1.png') :: text AS icon_url
|
|
;
|
|
|
|
-- name: InsertDeploymentID :exec
|
|
INSERT INTO site_configs (key, value) VALUES ('deployment_id', $1);
|
|
|
|
-- name: GetDeploymentID :one
|
|
SELECT value FROM site_configs WHERE key = 'deployment_id';
|
|
|
|
-- name: InsertDERPMeshKey :exec
|
|
INSERT INTO site_configs (key, value) VALUES ('derp_mesh_key', $1);
|
|
|
|
-- name: GetDERPMeshKey :one
|
|
SELECT value FROM site_configs WHERE key = 'derp_mesh_key';
|
|
|
|
-- name: UpsertLastUpdateCheck :exec
|
|
INSERT INTO site_configs (key, value) VALUES ('last_update_check', $1)
|
|
ON CONFLICT (key) DO UPDATE SET value = $1 WHERE site_configs.key = 'last_update_check';
|
|
|
|
-- name: GetLastUpdateCheck :one
|
|
SELECT value FROM site_configs WHERE key = 'last_update_check';
|
|
|
|
-- name: UpsertAnnouncementBanners :exec
|
|
INSERT INTO site_configs (key, value) VALUES ('announcement_banners', $1)
|
|
ON CONFLICT (key) DO UPDATE SET value = $1 WHERE site_configs.key = 'announcement_banners';
|
|
|
|
-- name: GetAnnouncementBanners :one
|
|
SELECT value FROM site_configs WHERE key = 'announcement_banners';
|
|
|
|
-- name: UpsertLogoURL :exec
|
|
INSERT INTO site_configs (key, value) VALUES ('logo_url', $1)
|
|
ON CONFLICT (key) DO UPDATE SET value = $1 WHERE site_configs.key = 'logo_url';
|
|
|
|
-- name: GetLogoURL :one
|
|
SELECT value FROM site_configs WHERE key = 'logo_url';
|
|
|
|
-- name: UpsertApplicationName :exec
|
|
INSERT INTO site_configs (key, value) VALUES ('application_name', $1)
|
|
ON CONFLICT (key) DO UPDATE SET value = $1 WHERE site_configs.key = 'application_name';
|
|
|
|
-- name: GetApplicationName :one
|
|
SELECT value FROM site_configs WHERE key = 'application_name';
|
|
|
|
-- name: GetCodernautsEnabled :one
|
|
SELECT
|
|
COALESCE((SELECT value = 'true' FROM site_configs WHERE key = 'codernauts_enabled'), true) :: boolean AS codernauts_enabled;
|
|
|
|
-- name: UpsertCodernautsEnabled :exec
|
|
INSERT INTO site_configs (key, value)
|
|
VALUES (
|
|
'codernauts_enabled',
|
|
CASE
|
|
WHEN @enabled::bool THEN 'true'
|
|
ELSE 'false'
|
|
END
|
|
)
|
|
ON CONFLICT (key) DO UPDATE
|
|
SET value = CASE
|
|
WHEN @enabled::bool THEN 'true'
|
|
ELSE 'false'
|
|
END
|
|
WHERE site_configs.key = 'codernauts_enabled';
|
|
|
|
-- name: GetHealthSettings :one
|
|
SELECT
|
|
COALESCE((SELECT value FROM site_configs WHERE key = 'health_settings'), '{}') :: text AS health_settings
|
|
;
|
|
|
|
-- name: UpsertHealthSettings :exec
|
|
INSERT INTO site_configs (key, value) VALUES ('health_settings', $1)
|
|
ON CONFLICT (key) DO UPDATE SET value = $1 WHERE site_configs.key = 'health_settings';
|
|
|
|
-- name: GetNotificationsSettings :one
|
|
SELECT
|
|
COALESCE((SELECT value FROM site_configs WHERE key = 'notifications_settings'), '{}') :: text AS notifications_settings
|
|
;
|
|
|
|
-- name: UpsertNotificationsSettings :exec
|
|
INSERT INTO site_configs (key, value) VALUES ('notifications_settings', $1)
|
|
ON CONFLICT (key) DO UPDATE SET value = $1 WHERE site_configs.key = 'notifications_settings';
|
|
|
|
-- name: GetPrebuildsSettings :one
|
|
SELECT
|
|
COALESCE((SELECT value FROM site_configs WHERE key = 'prebuilds_settings'), '{}') :: text AS prebuilds_settings
|
|
;
|
|
|
|
-- name: UpsertPrebuildsSettings :exec
|
|
INSERT INTO site_configs (key, value) VALUES ('prebuilds_settings', $1)
|
|
ON CONFLICT (key) DO UPDATE SET value = $1 WHERE site_configs.key = 'prebuilds_settings';
|
|
|
|
-- name: GetRuntimeConfig :one
|
|
SELECT value FROM site_configs WHERE site_configs.key = $1;
|
|
|
|
-- name: UpsertRuntimeConfig :exec
|
|
INSERT INTO site_configs (key, value) VALUES ($1, $2)
|
|
ON CONFLICT (key) DO UPDATE SET value = $2 WHERE site_configs.key = $1;
|
|
|
|
-- name: DeleteRuntimeConfig :exec
|
|
DELETE FROM site_configs
|
|
WHERE site_configs.key = $1;
|
|
|
|
-- name: GetOAuth2GithubDefaultEligible :one
|
|
SELECT
|
|
CASE
|
|
WHEN value = 'true' THEN TRUE
|
|
ELSE FALSE
|
|
END
|
|
FROM site_configs
|
|
WHERE key = 'oauth2_github_default_eligible';
|
|
|
|
-- name: UpsertOAuth2GithubDefaultEligible :exec
|
|
INSERT INTO site_configs (key, value)
|
|
VALUES (
|
|
'oauth2_github_default_eligible',
|
|
CASE
|
|
WHEN sqlc.arg(eligible)::bool THEN 'true'
|
|
ELSE 'false'
|
|
END
|
|
)
|
|
ON CONFLICT (key) DO UPDATE
|
|
SET value = CASE
|
|
WHEN sqlc.arg(eligible)::bool THEN 'true'
|
|
ELSE 'false'
|
|
END
|
|
WHERE site_configs.key = 'oauth2_github_default_eligible';
|
|
|
|
-- name: GetOAuth2DCREnabled :one
|
|
SELECT COALESCE(
|
|
(SELECT value = 'true' FROM site_configs WHERE key = 'oauth2_dcr_enabled'),
|
|
false
|
|
)::bool;
|
|
|
|
-- name: UpsertOAuth2DCREnabled :exec
|
|
INSERT INTO site_configs (key, value)
|
|
VALUES (
|
|
'oauth2_dcr_enabled',
|
|
CASE
|
|
WHEN sqlc.arg(enabled)::bool THEN 'true'
|
|
ELSE 'false'
|
|
END
|
|
)
|
|
ON CONFLICT (key) DO UPDATE
|
|
SET value = CASE
|
|
WHEN sqlc.arg(enabled)::bool THEN 'true'
|
|
ELSE 'false'
|
|
END
|
|
WHERE site_configs.key = 'oauth2_dcr_enabled';
|
|
|
|
-- name: UpsertWebpushVAPIDKeys :exec
|
|
INSERT INTO site_configs (key, value)
|
|
VALUES
|
|
('webpush_vapid_public_key', @vapid_public_key :: text),
|
|
('webpush_vapid_private_key', @vapid_private_key :: text)
|
|
ON CONFLICT (key)
|
|
DO UPDATE SET value = EXCLUDED.value WHERE site_configs.key = EXCLUDED.key;
|
|
|
|
-- name: GetWebpushVAPIDKeys :one
|
|
SELECT
|
|
COALESCE((SELECT value FROM site_configs WHERE key = 'webpush_vapid_public_key'), '') :: text AS vapid_public_key,
|
|
COALESCE((SELECT value FROM site_configs WHERE key = 'webpush_vapid_private_key'), '') :: text AS vapid_private_key;
|
|
|
|
-- name: GetChatSystemPrompt :one
|
|
SELECT
|
|
COALESCE((SELECT value FROM site_configs WHERE key = 'agents_chat_system_prompt'), '') :: text AS chat_system_prompt;
|
|
|
|
-- GetChatSystemPromptConfig returns both chat system prompt settings in a
|
|
-- single read to avoid torn reads between separate site-config lookups.
|
|
-- The include-default fallback preserves the legacy behavior where a
|
|
-- non-empty custom prompt implied opting out before the explicit toggle
|
|
-- existed.
|
|
-- name: GetChatSystemPromptConfig :one
|
|
SELECT
|
|
COALESCE((SELECT value FROM site_configs WHERE key = 'agents_chat_system_prompt'), '') :: text AS chat_system_prompt,
|
|
COALESCE(
|
|
(SELECT value = 'true' FROM site_configs WHERE key = 'agents_chat_include_default_system_prompt'),
|
|
NOT EXISTS (
|
|
SELECT 1
|
|
FROM site_configs
|
|
WHERE key = 'agents_chat_system_prompt'
|
|
AND value != ''
|
|
)
|
|
) :: boolean AS include_default_system_prompt,
|
|
EXISTS (
|
|
SELECT 1
|
|
FROM site_configs
|
|
WHERE key = 'agents_chat_include_default_system_prompt'
|
|
) :: boolean AS include_default_system_prompt_set;
|
|
|
|
-- name: UpsertChatSystemPrompt :exec
|
|
INSERT INTO site_configs (key, value) VALUES ('agents_chat_system_prompt', $1)
|
|
ON CONFLICT (key) DO UPDATE SET value = $1 WHERE site_configs.key = 'agents_chat_system_prompt';
|
|
|
|
-- name: GetChatPlanModeInstructions :one
|
|
SELECT
|
|
COALESCE((SELECT value FROM site_configs WHERE key = 'agents_chat_plan_mode_instructions'), '') :: text AS plan_mode_instructions;
|
|
|
|
-- name: UpsertChatPlanModeInstructions :exec
|
|
INSERT INTO site_configs (key, value) VALUES ('agents_chat_plan_mode_instructions', $1)
|
|
ON CONFLICT (key) DO UPDATE SET value = $1 WHERE site_configs.key = 'agents_chat_plan_mode_instructions';
|
|
|
|
-- name: GetChatDesktopEnabled :one
|
|
SELECT
|
|
COALESCE((SELECT value = 'true' FROM site_configs WHERE key = 'agents_desktop_enabled'), false) :: boolean AS enable_desktop;
|
|
|
|
-- name: UpsertChatDesktopEnabled :exec
|
|
INSERT INTO site_configs (key, value)
|
|
VALUES (
|
|
'agents_desktop_enabled',
|
|
CASE
|
|
WHEN sqlc.arg(enable_desktop)::bool THEN 'true'
|
|
ELSE 'false'
|
|
END
|
|
)
|
|
ON CONFLICT (key) DO UPDATE
|
|
SET value = CASE
|
|
WHEN sqlc.arg(enable_desktop)::bool THEN 'true'
|
|
ELSE 'false'
|
|
END
|
|
WHERE site_configs.key = 'agents_desktop_enabled';
|
|
|
|
-- GetChatAdvisorConfig returns the deployment-wide runtime configuration
|
|
-- for the experimental chat advisor as a JSON blob. Callers unmarshal the
|
|
-- result into codersdk.AdvisorConfig. Returns '{}' when unset so zero
|
|
-- values apply by default.
|
|
-- name: GetChatAdvisorConfig :one
|
|
SELECT
|
|
COALESCE((SELECT value FROM site_configs WHERE key = 'agents_advisor_config'), '{}') :: text AS advisor_config;
|
|
|
|
-- UpsertChatAdvisorConfig stores the deployment-wide runtime configuration
|
|
-- for the experimental chat advisor. Callers marshal codersdk.AdvisorConfig
|
|
-- to JSON before invoking this query.
|
|
-- name: UpsertChatAdvisorConfig :exec
|
|
INSERT INTO site_configs (key, value) VALUES ('agents_advisor_config', $1)
|
|
ON CONFLICT (key) DO UPDATE SET value = $1 WHERE site_configs.key = 'agents_advisor_config';
|
|
|
|
-- name: GetChatComputerUseProvider :one
|
|
SELECT
|
|
COALESCE((SELECT value FROM site_configs WHERE key = 'agents_computer_use_provider'), '') :: text AS provider;
|
|
|
|
-- name: UpsertChatComputerUseProvider :exec
|
|
INSERT INTO site_configs (key, value) VALUES ('agents_computer_use_provider', sqlc.arg(provider))
|
|
ON CONFLICT (key) DO UPDATE SET value = sqlc.arg(provider) WHERE site_configs.key = 'agents_computer_use_provider';
|
|
|
|
-- GetChatDebugLoggingAllowUsers returns the runtime admin setting that
|
|
-- allows users to opt into chat debug logging when the deployment does
|
|
-- not already force debug logging on globally.
|
|
-- name: GetChatDebugLoggingAllowUsers :one
|
|
SELECT
|
|
COALESCE((SELECT value = 'true' FROM site_configs WHERE key = 'agents_chat_debug_logging_allow_users'), false) :: boolean AS allow_users;
|
|
|
|
-- UpsertChatDebugLoggingAllowUsers updates the runtime admin setting that
|
|
-- allows users to opt into chat debug logging.
|
|
-- name: UpsertChatDebugLoggingAllowUsers :exec
|
|
INSERT INTO site_configs (key, value)
|
|
VALUES (
|
|
'agents_chat_debug_logging_allow_users',
|
|
CASE
|
|
WHEN sqlc.arg(allow_users)::bool THEN 'true'
|
|
ELSE 'false'
|
|
END
|
|
)
|
|
ON CONFLICT (key) DO UPDATE
|
|
SET value = CASE
|
|
WHEN sqlc.arg(allow_users)::bool THEN 'true'
|
|
ELSE 'false'
|
|
END
|
|
WHERE site_configs.key = 'agents_chat_debug_logging_allow_users';
|
|
|
|
-- GetChatPersonalModelOverridesEnabled returns whether users may configure
|
|
-- personal chat model overrides. It defaults to false when unset.
|
|
-- name: GetChatPersonalModelOverridesEnabled :one
|
|
SELECT
|
|
COALESCE((SELECT value = 'true' FROM site_configs WHERE key = 'agents_chat_personal_model_overrides_enabled'), false) :: boolean AS enabled;
|
|
|
|
-- UpsertChatPersonalModelOverridesEnabled updates whether users may configure
|
|
-- personal chat model overrides.
|
|
-- name: UpsertChatPersonalModelOverridesEnabled :exec
|
|
INSERT INTO site_configs (key, value)
|
|
VALUES (
|
|
'agents_chat_personal_model_overrides_enabled',
|
|
CASE
|
|
WHEN sqlc.arg(enabled)::bool THEN 'true'
|
|
ELSE 'false'
|
|
END
|
|
)
|
|
ON CONFLICT (key) DO UPDATE
|
|
SET value = CASE
|
|
WHEN sqlc.arg(enabled)::bool THEN 'true'
|
|
ELSE 'false'
|
|
END
|
|
WHERE site_configs.key = 'agents_chat_personal_model_overrides_enabled';
|
|
|
|
-- GetChatIncludeDefaultSystemPrompt preserves the legacy default
|
|
-- for deployments created before the explicit include-default toggle.
|
|
-- When the toggle is unset, a non-empty custom prompt implies false;
|
|
-- otherwise the setting defaults to true.
|
|
-- name: GetChatIncludeDefaultSystemPrompt :one
|
|
SELECT
|
|
COALESCE(
|
|
(SELECT value = 'true' FROM site_configs WHERE key = 'agents_chat_include_default_system_prompt'),
|
|
NOT EXISTS (
|
|
SELECT 1
|
|
FROM site_configs
|
|
WHERE key = 'agents_chat_system_prompt'
|
|
AND value != ''
|
|
)
|
|
) :: boolean AS include_default_system_prompt;
|
|
|
|
-- name: UpsertChatIncludeDefaultSystemPrompt :exec
|
|
INSERT INTO site_configs (key, value)
|
|
VALUES (
|
|
'agents_chat_include_default_system_prompt',
|
|
CASE
|
|
WHEN sqlc.arg(include_default_system_prompt)::bool THEN 'true'
|
|
ELSE 'false'
|
|
END
|
|
)
|
|
ON CONFLICT (key) DO UPDATE
|
|
SET value = CASE
|
|
WHEN sqlc.arg(include_default_system_prompt)::bool THEN 'true'
|
|
ELSE 'false'
|
|
END
|
|
WHERE site_configs.key = 'agents_chat_include_default_system_prompt';
|
|
|
|
-- name: GetChatWorkspaceTTL :one
|
|
-- Returns the global TTL for chat workspaces as a Go duration string.
|
|
-- Returns "0s" (disabled) when no value has been configured.
|
|
SELECT
|
|
COALESCE(
|
|
(SELECT value FROM site_configs WHERE key = 'agents_workspace_ttl'),
|
|
'0s'
|
|
)::text AS workspace_ttl;
|
|
|
|
-- name: UpsertChatWorkspaceTTL :exec
|
|
INSERT INTO site_configs (key, value)
|
|
VALUES ('agents_workspace_ttl', @workspace_ttl::text)
|
|
ON CONFLICT (key) DO UPDATE
|
|
SET value = @workspace_ttl::text
|
|
WHERE site_configs.key = 'agents_workspace_ttl';
|
|
|
|
-- name: GetChatRetentionDays :one
|
|
-- Returns the chat retention period in days. Chats archived longer
|
|
-- than this and orphaned chat files older than this are purged by
|
|
-- dbpurge. Returns 30 (days) when no value has been configured.
|
|
-- A value of 0 disables chat purging entirely.
|
|
SELECT COALESCE(
|
|
(SELECT value::integer FROM site_configs
|
|
WHERE key = 'agents_chat_retention_days'),
|
|
30
|
|
) :: integer AS retention_days;
|
|
|
|
-- name: UpsertChatRetentionDays :exec
|
|
INSERT INTO site_configs (key, value)
|
|
VALUES ('agents_chat_retention_days', CAST(@retention_days AS integer)::text)
|
|
ON CONFLICT (key) DO UPDATE SET value = CAST(@retention_days AS integer)::text
|
|
WHERE site_configs.key = 'agents_chat_retention_days';
|
|
|
|
-- name: GetChatDebugRetentionDays :one
|
|
-- Chat debug run retention window in days. 0 disables.
|
|
SELECT COALESCE(
|
|
(SELECT value::integer FROM site_configs
|
|
WHERE key = 'agents_chat_debug_retention_days'),
|
|
@default_debug_retention_days::integer
|
|
) :: integer AS debug_retention_days;
|
|
|
|
-- name: UpsertChatDebugRetentionDays :exec
|
|
INSERT INTO site_configs (key, value)
|
|
VALUES ('agents_chat_debug_retention_days', CAST(@debug_retention_days AS integer)::text)
|
|
ON CONFLICT (key) DO UPDATE SET value = CAST(@debug_retention_days AS integer)::text
|
|
WHERE site_configs.key = 'agents_chat_debug_retention_days';
|
|
|
|
-- name: GetChatAutoArchiveDays :one
|
|
-- Auto-archive window in days. 0 disables.
|
|
SELECT COALESCE(
|
|
(SELECT value::integer FROM site_configs
|
|
WHERE key = 'agents_chat_auto_archive_days'),
|
|
@default_auto_archive_days::integer
|
|
) :: integer AS auto_archive_days;
|
|
|
|
-- name: UpsertChatAutoArchiveDays :exec
|
|
INSERT INTO site_configs (key, value)
|
|
VALUES ('agents_chat_auto_archive_days', CAST(@auto_archive_days AS integer)::text)
|
|
ON CONFLICT (key) DO UPDATE SET value = CAST(@auto_archive_days AS integer)::text
|
|
WHERE site_configs.key = 'agents_chat_auto_archive_days';
|
|
|
|
-- GetChatSiteConfigValue returns raw text and row presence for an audited chat site configuration.
|
|
-- name: GetChatSiteConfigValue :one
|
|
SELECT
|
|
COALESCE(MAX(site_configs.value), '')::text AS value,
|
|
COUNT(*) > 0 AS exists
|
|
FROM site_configs
|
|
WHERE site_configs.key = sqlc.arg(config_key)
|
|
AND site_configs.key IN (
|
|
'agents_chat_retention_days',
|
|
'agents_chat_debug_retention_days',
|
|
'agents_chat_auto_archive_days',
|
|
'agents_workspace_ttl',
|
|
'agents_computer_use_provider',
|
|
'agents_chat_debug_logging_allow_users',
|
|
'agents_chat_personal_model_overrides_enabled'
|
|
);
|