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

Skip to content

Commit fdbb8d3

Browse files
authored
Merge branch 'main' into mafredri/ci-fix-release-script
2 parents a53f5ef + f24547e commit fdbb8d3

37 files changed

+589
-75
lines changed

.github/workflows/security.yaml

+41-1
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,9 @@ jobs:
9292
restore-keys: |
9393
js-${{ runner.os }}-
9494
95+
- name: Install yq
96+
run: go run github.com/mikefarah/yq/[email protected]
97+
9598
- name: Build Coder linux amd64 Docker image
9699
id: build
97100
run: |
@@ -112,6 +115,17 @@ jobs:
112115
make -j "$image_job"
113116
echo "image=$(cat "$image_job")" >> $GITHUB_OUTPUT
114117
118+
- name: Build Coder linux amd64 Docker image (ironbank)
119+
id: build-ironbank
120+
run: |
121+
set -euo pipefail
122+
# NOTE: This is not a real image tag we publish.
123+
image_tag="${{ steps.build.outputs.image }}-ironbank"
124+
./scripts/ironbank/build_ironbank.sh \
125+
--target "$image_tag" \
126+
"build/coder_$(./scripts/version.sh)_linux_amd64"
127+
echo "image=$image_tag" >> $GITHUB_OUTPUT
128+
115129
- name: Run Trivy vulnerability scanner
116130
uses: aquasecurity/trivy-action@9ab158e8597f3b310480b9a69402b419bc03dbd5
117131
with:
@@ -124,10 +138,36 @@ jobs:
124138
uses: github/codeql-action/upload-sarif@v2
125139
with:
126140
sarif_file: trivy-results.sarif
141+
category: "Trivy"
142+
143+
- name: Run Trivy vulnerability scanner (ironbank)
144+
uses: aquasecurity/trivy-action@7b7aa264d83dc58691451798b4d117d53d21edfe
145+
with:
146+
image-ref: ${{ steps.build-ironbank.outputs.image }}
147+
format: sarif
148+
output: trivy-results-ironbank.sarif
149+
severity: "CRITICAL,HIGH"
150+
151+
# Update the tool name field in the ironbank SARIF file so it's not
152+
# indistinguishable from findings in the non-ironbank SARIF file in the
153+
# GitHub UI. Without this, findings from both scans would show up as
154+
# "Trivy".
155+
- name: Update tool name in SARIF file (ironbank)
156+
run: |
157+
set -euo pipefail
158+
yq eval -i '.runs[0].tool.driver.name = "Trivy Ironbank"' trivy-results-ironbank.sarif
159+
160+
- name: Upload Trivy scan results to GitHub Security tab (ironbank)
161+
uses: github/codeql-action/upload-sarif@v2
162+
with:
163+
sarif_file: trivy-results-ironbank.sarif
164+
category: "Trivy Ironbank"
127165

128166
- name: Upload Trivy scan results as an artifact
129167
uses: actions/upload-artifact@v2
130168
with:
131169
name: trivy
132-
path: trivy-results.sarif
170+
path: |
171+
trivy-results.sarif
172+
trivy-results-ironbank.sarif
133173
retention-days: 7

agent/agent.go

+41-7
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ type Client interface {
7575
ReportStats(ctx context.Context, log slog.Logger, stats func() *agentsdk.Stats) (io.Closer, error)
7676
PostLifecycle(ctx context.Context, state agentsdk.PostLifecycleRequest) error
7777
PostAppHealth(ctx context.Context, req agentsdk.PostAppHealthsRequest) error
78-
PostVersion(ctx context.Context, version string) error
78+
PostStartup(ctx context.Context, req agentsdk.PostStartupRequest) error
7979
}
8080

8181
func New(options Options) io.Closer {
@@ -236,16 +236,29 @@ func (a *agent) run(ctx context.Context) error {
236236
}
237237
a.sessionToken.Store(&sessionToken)
238238

239-
err = a.client.PostVersion(ctx, buildinfo.Version())
240-
if err != nil {
241-
return xerrors.Errorf("update workspace agent version: %w", err)
242-
}
243-
244239
metadata, err := a.client.Metadata(ctx)
245240
if err != nil {
246241
return xerrors.Errorf("fetch metadata: %w", err)
247242
}
248243
a.logger.Info(ctx, "fetched metadata")
244+
245+
// Expand the directory and send it back to coderd so external
246+
// applications that rely on the directory can use it.
247+
//
248+
// An example is VS Code Remote, which must know the directory
249+
// before initializing a connection.
250+
metadata.Directory, err = expandDirectory(metadata.Directory)
251+
if err != nil {
252+
return xerrors.Errorf("expand directory: %w", err)
253+
}
254+
err = a.client.PostStartup(ctx, agentsdk.PostStartupRequest{
255+
Version: buildinfo.Version(),
256+
ExpandedDirectory: metadata.Directory,
257+
})
258+
if err != nil {
259+
return xerrors.Errorf("update workspace agent version: %w", err)
260+
}
261+
249262
oldMetadata := a.metadata.Swap(metadata)
250263

251264
// The startup script should only execute on the first run!
@@ -803,7 +816,11 @@ func (a *agent) createCommand(ctx context.Context, rawCommand string, env []stri
803816

804817
cmd := exec.CommandContext(ctx, shell, args...)
805818
cmd.Dir = metadata.Directory
806-
if cmd.Dir == "" {
819+
820+
// If the metadata directory doesn't exist, we run the command
821+
// in the users home directory.
822+
_, err = os.Stat(cmd.Dir)
823+
if cmd.Dir == "" || err != nil {
807824
// Default to user home if a directory is not set.
808825
homedir, err := userHomeDir()
809826
if err != nil {
@@ -1314,3 +1331,20 @@ func userHomeDir() (string, error) {
13141331
}
13151332
return u.HomeDir, nil
13161333
}
1334+
1335+
// expandDirectory converts a directory path to an absolute path.
1336+
// It primarily resolves the home directory and any environment
1337+
// variables that may be set
1338+
func expandDirectory(dir string) (string, error) {
1339+
if dir == "" {
1340+
return "", nil
1341+
}
1342+
if dir[0] == '~' {
1343+
home, err := userHomeDir()
1344+
if err != nil {
1345+
return "", err
1346+
}
1347+
dir = filepath.Join(home, dir[1:])
1348+
}
1349+
return os.ExpandEnv(dir), nil
1350+
}

agent/agent_test.go

+61-1
Original file line numberDiff line numberDiff line change
@@ -787,6 +787,56 @@ func TestAgent_Lifecycle(t *testing.T) {
787787
})
788788
}
789789

790+
func TestAgent_Startup(t *testing.T) {
791+
t.Parallel()
792+
793+
t.Run("EmptyDirectory", func(t *testing.T) {
794+
t.Parallel()
795+
796+
_, client, _, _ := setupAgent(t, agentsdk.Metadata{
797+
StartupScript: "true",
798+
StartupScriptTimeout: 30 * time.Second,
799+
Directory: "",
800+
}, 0)
801+
assert.Eventually(t, func() bool {
802+
return client.getStartup().Version != ""
803+
}, testutil.WaitShort, testutil.IntervalFast)
804+
require.Equal(t, "", client.getStartup().ExpandedDirectory)
805+
})
806+
807+
t.Run("HomeDirectory", func(t *testing.T) {
808+
t.Parallel()
809+
810+
_, client, _, _ := setupAgent(t, agentsdk.Metadata{
811+
StartupScript: "true",
812+
StartupScriptTimeout: 30 * time.Second,
813+
Directory: "~",
814+
}, 0)
815+
assert.Eventually(t, func() bool {
816+
return client.getStartup().Version != ""
817+
}, testutil.WaitShort, testutil.IntervalFast)
818+
homeDir, err := os.UserHomeDir()
819+
require.NoError(t, err)
820+
require.Equal(t, homeDir, client.getStartup().ExpandedDirectory)
821+
})
822+
823+
t.Run("HomeEnvironmentVariable", func(t *testing.T) {
824+
t.Parallel()
825+
826+
_, client, _, _ := setupAgent(t, agentsdk.Metadata{
827+
StartupScript: "true",
828+
StartupScriptTimeout: 30 * time.Second,
829+
Directory: "$HOME",
830+
}, 0)
831+
assert.Eventually(t, func() bool {
832+
return client.getStartup().Version != ""
833+
}, testutil.WaitShort, testutil.IntervalFast)
834+
homeDir, err := os.UserHomeDir()
835+
require.NoError(t, err)
836+
require.Equal(t, homeDir, client.getStartup().ExpandedDirectory)
837+
})
838+
}
839+
790840
func TestAgent_ReconnectingPTY(t *testing.T) {
791841
t.Parallel()
792842
if runtime.GOOS == "windows" {
@@ -1178,6 +1228,7 @@ type client struct {
11781228

11791229
mu sync.Mutex // Protects following.
11801230
lifecycleStates []codersdk.WorkspaceAgentLifecycle
1231+
startup agentsdk.PostStartupRequest
11811232
}
11821233

11831234
func (c *client) Metadata(_ context.Context) (agentsdk.Metadata, error) {
@@ -1250,7 +1301,16 @@ func (*client) PostAppHealth(_ context.Context, _ agentsdk.PostAppHealthsRequest
12501301
return nil
12511302
}
12521303

1253-
func (*client) PostVersion(_ context.Context, _ string) error {
1304+
func (c *client) getStartup() agentsdk.PostStartupRequest {
1305+
c.mu.Lock()
1306+
defer c.mu.Unlock()
1307+
return c.startup
1308+
}
1309+
1310+
func (c *client) PostStartup(_ context.Context, startup agentsdk.PostStartupRequest) error {
1311+
c.mu.Lock()
1312+
defer c.mu.Unlock()
1313+
c.startup = startup
12541314
return nil
12551315
}
12561316

coderd/apidoc/docs.go

+12-6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/apidoc/swagger.json

+12-6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/coderd.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -553,7 +553,7 @@ func New(options *Options) *API {
553553
r.Route("/me", func(r chi.Router) {
554554
r.Use(httpmw.ExtractWorkspaceAgent(options.Database))
555555
r.Get("/metadata", api.workspaceAgentMetadata)
556-
r.Post("/version", api.postWorkspaceAgentVersion)
556+
r.Post("/startup", api.postWorkspaceAgentStartup)
557557
r.Post("/app-health", api.postWorkspaceAppHealth)
558558
r.Get("/gitauth", api.workspaceAgentsGitAuth)
559559
r.Get("/gitsshkey", api.agentGitSSHKey)

coderd/coderdtest/authorize.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ func AGPLRoutes(a *AuthTester) (map[string]string, map[string]RouteCheck) {
7373
"GET:/api/v2/workspaceagents/me/gitsshkey": {NoAuthorize: true},
7474
"GET:/api/v2/workspaceagents/me/metadata": {NoAuthorize: true},
7575
"GET:/api/v2/workspaceagents/me/coordinate": {NoAuthorize: true},
76-
"POST:/api/v2/workspaceagents/me/version": {NoAuthorize: true},
76+
"POST:/api/v2/workspaceagents/me/startup": {NoAuthorize: true},
7777
"POST:/api/v2/workspaceagents/me/app-health": {NoAuthorize: true},
7878
"POST:/api/v2/workspaceagents/me/report-stats": {NoAuthorize: true},
7979
"POST:/api/v2/workspaceagents/me/report-lifecycle": {NoAuthorize: true},

coderd/coderdtest/swaggerparser.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,7 @@ func assertProduce(t *testing.T, comment SwaggerComment) {
344344
assert.Contains(t, allowedProduceTypes, comment.produce, "@Produce value is limited to specific types: %s", strings.Join(allowedProduceTypes, ","))
345345
} else {
346346
if (comment.router == "/workspaceagents/me/app-health" && comment.method == "post") ||
347-
(comment.router == "/workspaceagents/me/version" && comment.method == "post") ||
347+
(comment.router == "/workspaceagents/me/startup" && comment.method == "post") ||
348348
(comment.router == "/licenses/{id}" && comment.method == "delete") ||
349349
(comment.router == "/debug/coordinator" && comment.method == "get") {
350350
return // Exception: HTTP 200 is returned without response entity

coderd/database/dbfake/databasefake.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -3192,7 +3192,7 @@ func (q *fakeQuerier) UpdateWorkspaceAgentConnectionByID(_ context.Context, arg
31923192
return sql.ErrNoRows
31933193
}
31943194

3195-
func (q *fakeQuerier) UpdateWorkspaceAgentVersionByID(_ context.Context, arg database.UpdateWorkspaceAgentVersionByIDParams) error {
3195+
func (q *fakeQuerier) UpdateWorkspaceAgentStartupByID(_ context.Context, arg database.UpdateWorkspaceAgentStartupByIDParams) error {
31963196
if err := validateDatabaseType(arg); err != nil {
31973197
return err
31983198
}
@@ -3206,6 +3206,7 @@ func (q *fakeQuerier) UpdateWorkspaceAgentVersionByID(_ context.Context, arg dat
32063206
}
32073207

32083208
agent.Version = arg.Version
3209+
agent.ExpandedDirectory = arg.ExpandedDirectory
32093210
q.workspaceAgents[index] = agent
32103211
return nil
32113212
}

coderd/database/dump.sql

+4-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)