mirror of
https://github.com/coder/coder.git
synced 2026-06-02 20:48:20 +00:00
feat: expose ai_providers_env_drift_detected on appearance config
Surface the deprecated-env-drift flag set at startup through a new read-only AppearanceConfig.ai_providers_env_drift_detected field. The AGPL and enterprise appearance fetchers read a process-local atomic (API.AIProvidersEnvDrift) so the dashboard can warn admins that their env changes are ineffective. Regenerated SDK types and swagger.
This commit is contained in:
Generated
+4
@@ -15840,6 +15840,10 @@ const docTemplate = `{
|
||||
"codersdk.AppearanceConfig": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"ai_providers_env_drift_detected": {
|
||||
"description": "AIProvidersEnvDriftDetected is true when deprecated CODER_AIBRIDGE_*\nenv configuration differs from the AI provider rows already stored in\nthe database, meaning those env changes are ineffective. It is\noutput-only and is not part of UpdateAppearanceConfig.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"announcement_banners": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
|
||||
Generated
+4
@@ -14211,6 +14211,10 @@
|
||||
"codersdk.AppearanceConfig": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"ai_providers_env_drift_detected": {
|
||||
"description": "AIProvidersEnvDriftDetected is true when deprecated CODER_AIBRIDGE_*\nenv configuration differs from the AI provider rows already stored in\nthe database, meaning those env changes are ineffective. It is\noutput-only and is not part of UpdateAppearanceConfig.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"announcement_banners": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
|
||||
@@ -2,6 +2,7 @@ package appearance
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/coder/coder/v2/codersdk"
|
||||
)
|
||||
@@ -12,21 +13,27 @@ type Fetcher interface {
|
||||
|
||||
type AGPLFetcher struct {
|
||||
docsURL string
|
||||
// aiProvidersEnvDrift reports whether deprecated CODER_AIBRIDGE_* env
|
||||
// configuration is ineffective because it differs from the database.
|
||||
// It may be nil when no source is wired in.
|
||||
aiProvidersEnvDrift *atomic.Bool
|
||||
}
|
||||
|
||||
func (f AGPLFetcher) Fetch(context.Context) (codersdk.AppearanceConfig, error) {
|
||||
return codersdk.AppearanceConfig{
|
||||
AnnouncementBanners: []codersdk.BannerConfig{},
|
||||
SupportLinks: codersdk.DefaultSupportLinks(f.docsURL),
|
||||
DocsURL: f.docsURL,
|
||||
AnnouncementBanners: []codersdk.BannerConfig{},
|
||||
SupportLinks: codersdk.DefaultSupportLinks(f.docsURL),
|
||||
DocsURL: f.docsURL,
|
||||
AIProvidersEnvDriftDetected: f.aiProvidersEnvDrift != nil && f.aiProvidersEnvDrift.Load(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func NewDefaultFetcher(docsURL string) Fetcher {
|
||||
func NewDefaultFetcher(docsURL string, aiProvidersEnvDrift *atomic.Bool) Fetcher {
|
||||
if docsURL == "" {
|
||||
docsURL = codersdk.DefaultDocsURL()
|
||||
}
|
||||
return &AGPLFetcher{
|
||||
docsURL: docsURL,
|
||||
docsURL: docsURL,
|
||||
aiProvidersEnvDrift: aiProvidersEnvDrift,
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -666,7 +666,7 @@ func New(options *Options) *API {
|
||||
options.AppSigningKeyCache,
|
||||
)
|
||||
|
||||
f := appearance.NewDefaultFetcher(api.DeploymentValues.DocsURL.String())
|
||||
f := appearance.NewDefaultFetcher(api.DeploymentValues.DocsURL.String(), &api.AIProvidersEnvDrift)
|
||||
api.AppearanceFetcher.Store(&f)
|
||||
api.PortSharer.Store(&portsharing.DefaultPortSharer)
|
||||
api.PrebuildsClaimer.Store(&prebuilds.DefaultClaimer)
|
||||
|
||||
@@ -4882,6 +4882,11 @@ type AppearanceConfig struct {
|
||||
ServiceBanner BannerConfig `json:"service_banner"`
|
||||
AnnouncementBanners []BannerConfig `json:"announcement_banners"`
|
||||
SupportLinks []LinkConfig `json:"support_links,omitempty"`
|
||||
// AIProvidersEnvDriftDetected is true when deprecated CODER_AIBRIDGE_*
|
||||
// env configuration differs from the AI provider rows already stored in
|
||||
// the database, meaning those env changes are ineffective. It is
|
||||
// output-only and is not part of UpdateAppearanceConfig.
|
||||
AIProvidersEnvDriftDetected bool `json:"ai_providers_env_drift_detected"`
|
||||
}
|
||||
|
||||
type UpdateAppearanceConfig struct {
|
||||
|
||||
Generated
+1
@@ -103,6 +103,7 @@ curl -X GET http://coder-server:8080/api/v2/appearance \
|
||||
|
||||
```json
|
||||
{
|
||||
"ai_providers_env_drift_detected": true,
|
||||
"announcement_banners": [
|
||||
{
|
||||
"background_color": "string",
|
||||
|
||||
Generated
+10
-8
@@ -1572,6 +1572,7 @@ None
|
||||
|
||||
```json
|
||||
{
|
||||
"ai_providers_env_drift_detected": true,
|
||||
"announcement_banners": [
|
||||
{
|
||||
"background_color": "string",
|
||||
@@ -1600,14 +1601,15 @@ None
|
||||
|
||||
### Properties
|
||||
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
|------------------------|---------------------------------------------------------|----------|--------------|---------------------------------------------------------------------|
|
||||
| `announcement_banners` | array of [codersdk.BannerConfig](#codersdkbannerconfig) | false | | |
|
||||
| `application_name` | string | false | | |
|
||||
| `docs_url` | string | false | | |
|
||||
| `logo_url` | string | false | | |
|
||||
| `service_banner` | [codersdk.BannerConfig](#codersdkbannerconfig) | false | | Deprecated: ServiceBanner has been replaced by AnnouncementBanners. |
|
||||
| `support_links` | array of [codersdk.LinkConfig](#codersdklinkconfig) | false | | |
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
|-----------------------------------|---------------------------------------------------------|----------|--------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `ai_providers_env_drift_detected` | boolean | false | | Ai providers env drift detected is true when deprecated CODER_AIBRIDGE_* env configuration differs from the AI provider rows already stored in the database, meaning those env changes are ineffective. It is output-only and is not part of UpdateAppearanceConfig. |
|
||||
| `announcement_banners` | array of [codersdk.BannerConfig](#codersdkbannerconfig) | false | | |
|
||||
| `application_name` | string | false | | |
|
||||
| `docs_url` | string | false | | |
|
||||
| `logo_url` | string | false | | |
|
||||
| `service_banner` | [codersdk.BannerConfig](#codersdkbannerconfig) | false | | Deprecated: ServiceBanner has been replaced by AnnouncementBanners. |
|
||||
| `support_links` | array of [codersdk.LinkConfig](#codersdklinkconfig) | false | | |
|
||||
|
||||
## codersdk.ArchiveTemplateVersionsRequest
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sync/atomic"
|
||||
|
||||
"golang.org/x/sync/errgroup"
|
||||
"golang.org/x/xerrors"
|
||||
@@ -42,21 +43,23 @@ func (api *API) appearance(rw http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
type appearanceFetcher struct {
|
||||
database database.Store
|
||||
supportLinks []codersdk.LinkConfig
|
||||
docsURL string
|
||||
coderVersion string
|
||||
database database.Store
|
||||
supportLinks []codersdk.LinkConfig
|
||||
docsURL string
|
||||
coderVersion string
|
||||
aiProvidersEnvDrift *atomic.Bool
|
||||
}
|
||||
|
||||
func newAppearanceFetcher(store database.Store, links []codersdk.LinkConfig, docsURL, coderVersion string) agpl.Fetcher {
|
||||
func newAppearanceFetcher(store database.Store, links []codersdk.LinkConfig, docsURL, coderVersion string, aiProvidersEnvDrift *atomic.Bool) agpl.Fetcher {
|
||||
if docsURL == "" {
|
||||
docsURL = codersdk.DefaultDocsURL()
|
||||
}
|
||||
return &appearanceFetcher{
|
||||
database: store,
|
||||
supportLinks: links,
|
||||
docsURL: docsURL,
|
||||
coderVersion: coderVersion,
|
||||
database: store,
|
||||
supportLinks: links,
|
||||
docsURL: docsURL,
|
||||
coderVersion: coderVersion,
|
||||
aiProvidersEnvDrift: aiProvidersEnvDrift,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,11 +97,12 @@ func (f *appearanceFetcher) Fetch(ctx context.Context) (codersdk.AppearanceConfi
|
||||
}
|
||||
|
||||
cfg := codersdk.AppearanceConfig{
|
||||
ApplicationName: applicationName,
|
||||
LogoURL: logoURL,
|
||||
AnnouncementBanners: []codersdk.BannerConfig{},
|
||||
SupportLinks: codersdk.DefaultSupportLinks(f.docsURL),
|
||||
DocsURL: f.docsURL,
|
||||
ApplicationName: applicationName,
|
||||
LogoURL: logoURL,
|
||||
AnnouncementBanners: []codersdk.BannerConfig{},
|
||||
SupportLinks: codersdk.DefaultSupportLinks(f.docsURL),
|
||||
DocsURL: f.docsURL,
|
||||
AIProvidersEnvDriftDetected: f.aiProvidersEnvDrift != nil && f.aiProvidersEnvDrift.Load(),
|
||||
}
|
||||
|
||||
if announcementBannersJSON != "" {
|
||||
|
||||
@@ -1014,10 +1014,11 @@ func (api *API) updateEntitlements(ctx context.Context) error {
|
||||
api.DeploymentValues.Support.Links.Value,
|
||||
api.DeploymentValues.DocsURL.String(),
|
||||
buildinfo.Version(),
|
||||
&api.AGPL.AIProvidersEnvDrift,
|
||||
)
|
||||
api.AGPL.AppearanceFetcher.Store(&f)
|
||||
} else {
|
||||
f := appearance.NewDefaultFetcher(api.DeploymentValues.DocsURL.String())
|
||||
f := appearance.NewDefaultFetcher(api.DeploymentValues.DocsURL.String(), &api.AGPL.AIProvidersEnvDrift)
|
||||
api.AGPL.AppearanceFetcher.Store(&f)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -88,7 +88,7 @@ type Options struct {
|
||||
func New(opts *Options) (*Handler, error) {
|
||||
if opts.AppearanceFetcher == nil {
|
||||
daf := atomic.Pointer[appearance.Fetcher]{}
|
||||
f := appearance.NewDefaultFetcher(opts.DocsURL)
|
||||
f := appearance.NewDefaultFetcher(opts.DocsURL, nil)
|
||||
daf.Store(&f)
|
||||
opts.AppearanceFetcher = &daf
|
||||
}
|
||||
|
||||
@@ -2393,6 +2393,7 @@ class ApiMethods {
|
||||
service_banner: {
|
||||
enabled: false,
|
||||
},
|
||||
ai_providers_env_drift_detected: false,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Generated
+7
@@ -1132,6 +1132,13 @@ export interface AppearanceConfig {
|
||||
readonly service_banner: BannerConfig;
|
||||
readonly announcement_banners: readonly BannerConfig[];
|
||||
readonly support_links?: readonly LinkConfig[];
|
||||
/**
|
||||
* AIProvidersEnvDriftDetected is true when deprecated CODER_AIBRIDGE_*
|
||||
* env configuration differs from the AI provider rows already stored in
|
||||
* the database, meaning those env changes are ineffective. It is
|
||||
* output-only and is not part of UpdateAppearanceConfig.
|
||||
*/
|
||||
readonly ai_providers_env_drift_detected: boolean;
|
||||
}
|
||||
|
||||
// From codersdk/templates.go
|
||||
|
||||
@@ -3392,6 +3392,7 @@ export const MockAppearanceConfig: TypesGen.AppearanceConfig = {
|
||||
},
|
||||
announcement_banners: [],
|
||||
docs_url: "https://coder.com/docs/@main/",
|
||||
ai_providers_env_drift_detected: false,
|
||||
};
|
||||
|
||||
export const MockWorkspaceBuildParameter1: TypesGen.WorkspaceBuildParameter = {
|
||||
|
||||
Reference in New Issue
Block a user