Skip to content

Commit e7276be

Browse files
authored
Merge branch 'main' into mafredri/chore-scripts-fix-release-promote-env
2 parents 7573dfc + 92c5dfa commit e7276be

File tree

341 files changed

+9777
-5183
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

341 files changed

+9777
-5183
lines changed

.github/actions/setup-tf/action.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,5 @@ runs:
77
- name: Install Terraform
88
uses: hashicorp/setup-terraform@v3
99
with:
10-
terraform_version: 1.6.6
10+
terraform_version: 1.7.5
1111
terraform_wrapper: false

.github/dependabot.yaml

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -112,17 +112,3 @@ updates:
112112
offlinedocs:
113113
patterns:
114114
- "*"
115-
116-
# Update dogfood.
117-
- package-ecosystem: "terraform"
118-
directory: "/dogfood/"
119-
schedule:
120-
interval: "weekly"
121-
time: "06:00"
122-
timezone: "America/Chicago"
123-
commit-message:
124-
prefix: "chore"
125-
labels: []
126-
ignore:
127-
# We likely want to update this ourselves.
128-
- dependency-name: "coder/coder"

.github/workflows/ci.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -910,7 +910,7 @@ jobs:
910910
# This action is not intended to do a vulnerability check since that is handled by a separate action.
911911
dependency-license-review:
912912
runs-on: ubuntu-latest
913-
if: github.ref != 'refs/heads/main'
913+
if: github.ref != 'refs/heads/main' && github.actor != 'dependabot[bot]'
914914
steps:
915915
- name: "Checkout Repository"
916916
uses: actions/checkout@v4

.github/workflows/contrib.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ jobs:
3434
steps:
3535
- name: cla
3636
if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target'
37-
uses: contributor-assistant/github-action@v2.3.2
37+
uses: contributor-assistant/github-action@v2.4.0
3838
env:
3939
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
4040
# the below token should have repo scope and must be manually added by you in the repository's secret

.github/workflows/security.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ jobs:
114114
echo "image=$(cat "$image_job")" >> $GITHUB_OUTPUT
115115
116116
- name: Run Trivy vulnerability scanner
117-
uses: aquasecurity/trivy-action@d710430a6722f083d3b36b8339ff66b32f22ee55
117+
uses: aquasecurity/trivy-action@b2933f565dbc598b29947660e66259e3c7bc8561
118118
with:
119119
image-ref: ${{ steps.build.outputs.image }}
120120
format: sarif

.vscode/settings.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,5 +222,7 @@
222222
"go.testFlags": ["-short", "-coverpkg=./..."],
223223
// We often use a version of TypeScript that's ahead of the version shipped
224224
// with VS Code.
225-
"typescript.tsdk": "./site/node_modules/typescript/lib"
225+
"typescript.tsdk": "./site/node_modules/typescript/lib",
226+
// Playwright tests in VSCode will open a browser to live "view" the test.
227+
"playwright.reuseBrowser": true
226228
}

Makefile

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ GO_SRC_FILES := $(shell find . $(FIND_EXCLUSIONS) -type f -name '*.go' -not -nam
5656
# All the shell files in the repo, excluding ignored files.
5757
SHELL_SRC_FILES := $(shell find . $(FIND_EXCLUSIONS) -type f -name '*.sh')
5858

59+
# Ensure we don't use the user's git configs which might cause side-effects
60+
GIT_FLAGS = GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_SYSTEM=/dev/null
61+
5962
# All ${OS}_${ARCH} combos we build for. Windows binaries have the .exe suffix.
6063
OS_ARCHES := \
6164
linux_amd64 linux_arm64 linux_armv7 \
@@ -483,6 +486,7 @@ gen: \
483486
$(DB_GEN_FILES) \
484487
site/src/api/typesGenerated.ts \
485488
coderd/rbac/object_gen.go \
489+
codersdk/rbacresources_gen.go \
486490
docs/admin/prometheus.md \
487491
docs/cli.md \
488492
docs/admin/audit-logs.md \
@@ -554,6 +558,9 @@ coderd/database/querier.go: coderd/database/sqlc.yaml coderd/database/dump.sql $
554558
coderd/database/dbmock/dbmock.go: coderd/database/db.go coderd/database/querier.go
555559
go generate ./coderd/database/dbmock/
556560

561+
coderd/database/pubsub/psmock/psmock.go: coderd/database/pubsub/pubsub.go
562+
go generate ./coderd/database/pubsub/psmock
563+
557564
tailnet/tailnettest/coordinatormock.go tailnet/tailnettest/multiagentmock.go tailnet/tailnettest/coordinateemock.go: tailnet/coordinator.go tailnet/multiagent.go
558565
go generate ./tailnet/tailnettest/
559566

@@ -608,7 +615,10 @@ examples/examples.gen.json: scripts/examplegen/main.go examples/examples.go $(sh
608615
go run ./scripts/examplegen/main.go > examples/examples.gen.json
609616

610617
coderd/rbac/object_gen.go: scripts/rbacgen/main.go coderd/rbac/object.go
611-
go run scripts/rbacgen/main.go ./coderd/rbac > coderd/rbac/object_gen.go
618+
go run scripts/rbacgen/main.go rbac > coderd/rbac/object_gen.go
619+
620+
codersdk/rbacresources_gen.go: scripts/rbacgen/main.go coderd/rbac/object.go
621+
go run scripts/rbacgen/main.go codersdk > codersdk/rbacresources_gen.go
612622

613623
docs/admin/prometheus.md: scripts/metricsdocgen/main.go scripts/metricsdocgen/metrics
614624
go run scripts/metricsdocgen/main.go
@@ -739,7 +749,7 @@ site/.eslintignore site/.prettierignore: .prettierignore Makefile
739749
done < "$<"
740750

741751
test:
742-
gotestsum --format standard-quiet -- -v -short -count=1 ./...
752+
$(GIT_FLAGS) gotestsum --format standard-quiet -- -v -short -count=1 ./...
743753
.PHONY: test
744754

745755
# sqlc-cloud-is-setup will fail if no SQLc auth token is set. Use this as a
@@ -775,7 +785,7 @@ sqlc-vet: test-postgres-docker
775785
test-postgres: test-postgres-docker
776786
# The postgres test is prone to failure, so we limit parallelism for
777787
# more consistent execution.
778-
DB=ci DB_FROM=$(shell go run scripts/migrate-ci/main.go) gotestsum \
788+
$(GIT_FLAGS) DB=ci DB_FROM=$(shell go run scripts/migrate-ci/main.go) gotestsum \
779789
--junitfile="gotests.xml" \
780790
--jsonfile="gotests.json" \
781791
--packages="./..." -- \
@@ -824,7 +834,7 @@ test-postgres-docker:
824834

825835
# Make sure to keep this in sync with test-go-race from .github/workflows/ci.yaml.
826836
test-race:
827-
gotestsum --junitfile="gotests.xml" -- -race -count=1 ./...
837+
$(GIT_FLAGS) gotestsum --junitfile="gotests.xml" -- -race -count=1 ./...
828838
.PHONY: test-race
829839

830840
test-tailnet-integration:

agent/agent.go

Lines changed: 58 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -155,35 +155,35 @@ func New(options Options) Agent {
155155
hardCtx, hardCancel := context.WithCancel(context.Background())
156156
gracefulCtx, gracefulCancel := context.WithCancel(hardCtx)
157157
a := &agent{
158-
tailnetListenPort: options.TailnetListenPort,
159-
reconnectingPTYTimeout: options.ReconnectingPTYTimeout,
160-
logger: options.Logger,
161-
gracefulCtx: gracefulCtx,
162-
gracefulCancel: gracefulCancel,
163-
hardCtx: hardCtx,
164-
hardCancel: hardCancel,
165-
coordDisconnected: make(chan struct{}),
166-
environmentVariables: options.EnvironmentVariables,
167-
client: options.Client,
168-
exchangeToken: options.ExchangeToken,
169-
filesystem: options.Filesystem,
170-
logDir: options.LogDir,
171-
tempDir: options.TempDir,
172-
scriptDataDir: options.ScriptDataDir,
173-
lifecycleUpdate: make(chan struct{}, 1),
174-
lifecycleReported: make(chan codersdk.WorkspaceAgentLifecycle, 1),
175-
lifecycleStates: []agentsdk.PostLifecycleRequest{{State: codersdk.WorkspaceAgentLifecycleCreated}},
176-
ignorePorts: options.IgnorePorts,
177-
portCacheDuration: options.PortCacheDuration,
178-
reportMetadataInterval: options.ReportMetadataInterval,
179-
serviceBannerRefreshInterval: options.ServiceBannerRefreshInterval,
180-
sshMaxTimeout: options.SSHMaxTimeout,
181-
subsystems: options.Subsystems,
182-
addresses: options.Addresses,
183-
syscaller: options.Syscaller,
184-
modifiedProcs: options.ModifiedProcesses,
185-
processManagementTick: options.ProcessManagementTick,
186-
logSender: agentsdk.NewLogSender(options.Logger),
158+
tailnetListenPort: options.TailnetListenPort,
159+
reconnectingPTYTimeout: options.ReconnectingPTYTimeout,
160+
logger: options.Logger,
161+
gracefulCtx: gracefulCtx,
162+
gracefulCancel: gracefulCancel,
163+
hardCtx: hardCtx,
164+
hardCancel: hardCancel,
165+
coordDisconnected: make(chan struct{}),
166+
environmentVariables: options.EnvironmentVariables,
167+
client: options.Client,
168+
exchangeToken: options.ExchangeToken,
169+
filesystem: options.Filesystem,
170+
logDir: options.LogDir,
171+
tempDir: options.TempDir,
172+
scriptDataDir: options.ScriptDataDir,
173+
lifecycleUpdate: make(chan struct{}, 1),
174+
lifecycleReported: make(chan codersdk.WorkspaceAgentLifecycle, 1),
175+
lifecycleStates: []agentsdk.PostLifecycleRequest{{State: codersdk.WorkspaceAgentLifecycleCreated}},
176+
ignorePorts: options.IgnorePorts,
177+
portCacheDuration: options.PortCacheDuration,
178+
reportMetadataInterval: options.ReportMetadataInterval,
179+
notificationBannersRefreshInterval: options.ServiceBannerRefreshInterval,
180+
sshMaxTimeout: options.SSHMaxTimeout,
181+
subsystems: options.Subsystems,
182+
addresses: options.Addresses,
183+
syscaller: options.Syscaller,
184+
modifiedProcs: options.ModifiedProcesses,
185+
processManagementTick: options.ProcessManagementTick,
186+
logSender: agentsdk.NewLogSender(options.Logger),
187187

188188
prometheusRegistry: prometheusRegistry,
189189
metrics: newAgentMetrics(prometheusRegistry),
@@ -193,7 +193,7 @@ func New(options Options) Agent {
193193
// that gets closed on disconnection. This is used to wait for graceful disconnection from the
194194
// coordinator during shut down.
195195
close(a.coordDisconnected)
196-
a.serviceBanner.Store(new(codersdk.ServiceBannerConfig))
196+
a.notificationBanners.Store(new([]codersdk.BannerConfig))
197197
a.sessionToken.Store(new(string))
198198
a.init()
199199
return a
@@ -231,14 +231,14 @@ type agent struct {
231231

232232
environmentVariables map[string]string
233233

234-
manifest atomic.Pointer[agentsdk.Manifest] // manifest is atomic because values can change after reconnection.
235-
reportMetadataInterval time.Duration
236-
scriptRunner *agentscripts.Runner
237-
serviceBanner atomic.Pointer[codersdk.ServiceBannerConfig] // serviceBanner is atomic because it is periodically updated.
238-
serviceBannerRefreshInterval time.Duration
239-
sessionToken atomic.Pointer[string]
240-
sshServer *agentssh.Server
241-
sshMaxTimeout time.Duration
234+
manifest atomic.Pointer[agentsdk.Manifest] // manifest is atomic because values can change after reconnection.
235+
reportMetadataInterval time.Duration
236+
scriptRunner *agentscripts.Runner
237+
notificationBanners atomic.Pointer[[]codersdk.BannerConfig] // notificationBanners is atomic because it is periodically updated.
238+
notificationBannersRefreshInterval time.Duration
239+
sessionToken atomic.Pointer[string]
240+
sshServer *agentssh.Server
241+
sshMaxTimeout time.Duration
242242

243243
lifecycleUpdate chan struct{}
244244
lifecycleReported chan codersdk.WorkspaceAgentLifecycle
@@ -272,11 +272,11 @@ func (a *agent) TailnetConn() *tailnet.Conn {
272272
func (a *agent) init() {
273273
// pass the "hard" context because we explicitly close the SSH server as part of graceful shutdown.
274274
sshSrv, err := agentssh.NewServer(a.hardCtx, a.logger.Named("ssh-server"), a.prometheusRegistry, a.filesystem, &agentssh.Config{
275-
MaxTimeout: a.sshMaxTimeout,
276-
MOTDFile: func() string { return a.manifest.Load().MOTDFile },
277-
ServiceBanner: func() *codersdk.ServiceBannerConfig { return a.serviceBanner.Load() },
278-
UpdateEnv: a.updateCommandEnv,
279-
WorkingDirectory: func() string { return a.manifest.Load().Directory },
275+
MaxTimeout: a.sshMaxTimeout,
276+
MOTDFile: func() string { return a.manifest.Load().MOTDFile },
277+
NotificationBanners: func() *[]codersdk.BannerConfig { return a.notificationBanners.Load() },
278+
UpdateEnv: a.updateCommandEnv,
279+
WorkingDirectory: func() string { return a.manifest.Load().Directory },
280280
})
281281
if err != nil {
282282
panic(err)
@@ -709,23 +709,26 @@ func (a *agent) setLifecycle(state codersdk.WorkspaceAgentLifecycle) {
709709
// (and must be done before the session actually starts).
710710
func (a *agent) fetchServiceBannerLoop(ctx context.Context, conn drpc.Conn) error {
711711
aAPI := proto.NewDRPCAgentClient(conn)
712-
ticker := time.NewTicker(a.serviceBannerRefreshInterval)
712+
ticker := time.NewTicker(a.notificationBannersRefreshInterval)
713713
defer ticker.Stop()
714714
for {
715715
select {
716716
case <-ctx.Done():
717717
return ctx.Err()
718718
case <-ticker.C:
719-
sbp, err := aAPI.GetServiceBanner(ctx, &proto.GetServiceBannerRequest{})
719+
bannersProto, err := aAPI.GetNotificationBanners(ctx, &proto.GetNotificationBannersRequest{})
720720
if err != nil {
721721
if ctx.Err() != nil {
722722
return ctx.Err()
723723
}
724-
a.logger.Error(ctx, "failed to update service banner", slog.Error(err))
724+
a.logger.Error(ctx, "failed to update notification banners", slog.Error(err))
725725
return err
726726
}
727-
serviceBanner := agentsdk.ServiceBannerFromProto(sbp)
728-
a.serviceBanner.Store(&serviceBanner)
727+
banners := make([]codersdk.BannerConfig, 0, len(bannersProto.NotificationBanners))
728+
for _, bannerProto := range bannersProto.NotificationBanners {
729+
banners = append(banners, agentsdk.BannerConfigFromProto(bannerProto))
730+
}
731+
a.notificationBanners.Store(&banners)
729732
}
730733
}
731734
}
@@ -757,15 +760,18 @@ func (a *agent) run() (retErr error) {
757760
// redial the coder server and retry.
758761
connMan := newAPIConnRoutineManager(a.gracefulCtx, a.hardCtx, a.logger, conn)
759762

760-
connMan.start("init service banner", gracefulShutdownBehaviorStop,
763+
connMan.start("init notification banners", gracefulShutdownBehaviorStop,
761764
func(ctx context.Context, conn drpc.Conn) error {
762765
aAPI := proto.NewDRPCAgentClient(conn)
763-
sbp, err := aAPI.GetServiceBanner(ctx, &proto.GetServiceBannerRequest{})
766+
bannersProto, err := aAPI.GetNotificationBanners(ctx, &proto.GetNotificationBannersRequest{})
764767
if err != nil {
765768
return xerrors.Errorf("fetch service banner: %w", err)
766769
}
767-
serviceBanner := agentsdk.ServiceBannerFromProto(sbp)
768-
a.serviceBanner.Store(&serviceBanner)
770+
banners := make([]codersdk.BannerConfig, 0, len(bannersProto.NotificationBanners))
771+
for _, bannerProto := range bannersProto.NotificationBanners {
772+
banners = append(banners, agentsdk.BannerConfigFromProto(bannerProto))
773+
}
774+
a.notificationBanners.Store(&banners)
769775
return nil
770776
},
771777
)

agent/agent_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -614,12 +614,12 @@ func TestAgent_Session_TTY_MOTD_Update(t *testing.T) {
614614
// Set new banner func and wait for the agent to call it to update the
615615
// banner.
616616
ready := make(chan struct{}, 2)
617-
client.SetServiceBannerFunc(func() (codersdk.ServiceBannerConfig, error) {
617+
client.SetNotificationBannersFunc(func() ([]codersdk.BannerConfig, error) {
618618
select {
619619
case ready <- struct{}{}:
620620
default:
621621
}
622-
return test.banner, nil
622+
return []codersdk.BannerConfig{test.banner}, nil
623623
})
624624
<-ready
625625
<-ready // Wait for two updates to ensure the value has propagated.
@@ -2193,15 +2193,15 @@ func setupAgentSSHClient(ctx context.Context, t *testing.T) *ssh.Client {
21932193
func setupSSHSession(
21942194
t *testing.T,
21952195
manifest agentsdk.Manifest,
2196-
serviceBanner codersdk.ServiceBannerConfig,
2196+
banner codersdk.BannerConfig,
21972197
prepareFS func(fs afero.Fs),
21982198
opts ...func(*agenttest.Client, *agent.Options),
21992199
) *ssh.Session {
22002200
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
22012201
defer cancel()
22022202
opts = append(opts, func(c *agenttest.Client, o *agent.Options) {
2203-
c.SetServiceBannerFunc(func() (codersdk.ServiceBannerConfig, error) {
2204-
return serviceBanner, nil
2203+
c.SetNotificationBannersFunc(func() ([]codersdk.BannerConfig, error) {
2204+
return []codersdk.BannerConfig{banner}, nil
22052205
})
22062206
})
22072207
//nolint:dogsled

agent/agentssh/agentssh.go

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ type Config struct {
6363
// file will be displayed to the user upon login.
6464
MOTDFile func() string
6565
// ServiceBanner returns the configuration for the Coder service banner.
66-
ServiceBanner func() *codersdk.ServiceBannerConfig
66+
NotificationBanners func() *[]codersdk.BannerConfig
6767
// UpdateEnv updates the environment variables for the command to be
6868
// executed. It can be used to add, modify or replace environment variables.
6969
UpdateEnv func(current []string) (updated []string, err error)
@@ -123,8 +123,8 @@ func NewServer(ctx context.Context, logger slog.Logger, prometheusRegistry *prom
123123
if config.MOTDFile == nil {
124124
config.MOTDFile = func() string { return "" }
125125
}
126-
if config.ServiceBanner == nil {
127-
config.ServiceBanner = func() *codersdk.ServiceBannerConfig { return &codersdk.ServiceBannerConfig{} }
126+
if config.NotificationBanners == nil {
127+
config.NotificationBanners = func() *[]codersdk.BannerConfig { return &[]codersdk.BannerConfig{} }
128128
}
129129
if config.WorkingDirectory == nil {
130130
config.WorkingDirectory = func() string {
@@ -441,12 +441,15 @@ func (s *Server) startPTYSession(logger slog.Logger, session ptySession, magicTy
441441
session.DisablePTYEmulation()
442442

443443
if isLoginShell(session.RawCommand()) {
444-
serviceBanner := s.config.ServiceBanner()
445-
if serviceBanner != nil {
446-
err := showServiceBanner(session, serviceBanner)
447-
if err != nil {
448-
logger.Error(ctx, "agent failed to show service banner", slog.Error(err))
449-
s.metrics.sessionErrors.WithLabelValues(magicTypeLabel, "yes", "service_banner").Add(1)
444+
banners := s.config.NotificationBanners()
445+
if banners != nil {
446+
for _, banner := range *banners {
447+
err := showNotificationBanner(session, banner)
448+
if err != nil {
449+
logger.Error(ctx, "agent failed to show service banner", slog.Error(err))
450+
s.metrics.sessionErrors.WithLabelValues(magicTypeLabel, "yes", "notification_banner").Add(1)
451+
break
452+
}
450453
}
451454
}
452455
}
@@ -891,9 +894,9 @@ func isQuietLogin(fs afero.Fs, rawCommand string) bool {
891894
return err == nil
892895
}
893896

894-
// showServiceBanner will write the service banner if enabled and not blank
897+
// showNotificationBanner will write the service banner if enabled and not blank
895898
// along with a blank line for spacing.
896-
func showServiceBanner(session io.Writer, banner *codersdk.ServiceBannerConfig) error {
899+
func showNotificationBanner(session io.Writer, banner codersdk.BannerConfig) error {
897900
if banner.Enabled && banner.Message != "" {
898901
// The banner supports Markdown so we might want to parse it but Markdown is
899902
// still fairly readable in its raw form.

0 commit comments

Comments
 (0)