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

Skip to content

Commit c3c2702

Browse files
committed
Merge remote-tracking branch 'origin/main' into stevenmasley/rbac_views
2 parents 3ce72c5 + 1724cbf commit c3c2702

35 files changed

+735
-203
lines changed

.github/workflows/ci.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ jobs:
4141

4242
# Check for any typos!
4343
- name: Check for typos
44-
uses: crate-ci/[email protected].9
44+
uses: crate-ci/[email protected].14
4545
with:
4646
config: .github/workflows/typos.toml
4747
- name: Fix the typos

.github/workflows/contrib.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ jobs:
3333
steps:
3434
- name: cla
3535
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'
36-
uses: contributor-assistant/github-action@v2.2.1
36+
uses: contributor-assistant/github-action@v2.3.0
3737
env:
3838
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
3939
# the below token should have repo scope and must be manually added by you in the repository's secret

.github/workflows/docker-base.yaml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,38 @@ jobs:
5353
project: wl5hnrrkns
5454
context: base-build-context
5555
file: scripts/Dockerfile.base
56+
platforms: linux/amd64,linux/arm64,linux/arm/v7
5657
pull: true
5758
no-cache: true
5859
push: true
5960
tags: |
6061
ghcr.io/coder/coder-base:latest
62+
63+
- name: Verify that images are pushed properly
64+
run: |
65+
# retry 10 times with a 5 second delay as the images may not be
66+
# available immediately
67+
for i in {1..10}; do
68+
rc=0
69+
raw_manifests=$(docker buildx imagetools inspect --raw ghcr.io/coder/coder-base:latest) || rc=$?
70+
if [[ "$rc" -eq 0 ]]; then
71+
break
72+
fi
73+
if [[ "$i" -eq 10 ]]; then
74+
echo "Failed to pull manifests after 10 retries"
75+
exit 1
76+
fi
77+
echo "Failed to pull manifests, retrying in 5 seconds"
78+
sleep 5
79+
done
80+
81+
manifests=$(
82+
echo "$raw_manifests" | \
83+
jq -r '.manifests[].platform | .os + "/" + .architecture + (if .variant then "/" + .variant else "" end)'
84+
)
85+
86+
# Verify all 3 platforms are present.
87+
set -euxo pipefail
88+
echo "$manifests" | grep -q linux/amd64
89+
echo "$manifests" | grep -q linux/arm64
90+
echo "$manifests" | grep -q linux/arm/v7

.github/workflows/release.yaml

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,12 +188,42 @@ jobs:
188188
project: wl5hnrrkns
189189
context: base-build-context
190190
file: scripts/Dockerfile.base
191+
platforms: linux/amd64,linux/arm64,linux/arm/v7
191192
pull: true
192193
no-cache: true
193194
push: true
194195
tags: |
195196
${{ steps.image-base-tag.outputs.tag }}
196197
198+
- name: Verify that images are pushed properly
199+
run: |
200+
# retry 10 times with a 5 second delay as the images may not be
201+
# available immediately
202+
for i in {1..10}; do
203+
rc=0
204+
raw_manifests=$(docker buildx imagetools inspect --raw "${{ steps.image-base-tag.outputs.tag }}") || rc=$?
205+
if [[ "$rc" -eq 0 ]]; then
206+
break
207+
fi
208+
if [[ "$i" -eq 10 ]]; then
209+
echo "Failed to pull manifests after 10 retries"
210+
exit 1
211+
fi
212+
echo "Failed to pull manifests, retrying in 5 seconds"
213+
sleep 5
214+
done
215+
216+
manifests=$(
217+
echo "$raw_manifests" | \
218+
jq -r '.manifests[].platform | .os + "/" + .architecture + (if .variant then "/" + .variant else "" end)'
219+
)
220+
221+
# Verify all 3 platforms are present.
222+
set -euxo pipefail
223+
echo "$manifests" | grep -q linux/amd64
224+
echo "$manifests" | grep -q linux/arm64
225+
echo "$manifests" | grep -q linux/arm/v7
226+
197227
- name: Build Linux Docker images
198228
run: |
199229
set -euxo pipefail
@@ -275,7 +305,7 @@ jobs:
275305
276306
- name: Upload artifacts to actions (if dry-run)
277307
if: ${{ inputs.dry_run }}
278-
uses: actions/upload-artifact@v2
308+
uses: actions/upload-artifact@v3
279309
with:
280310
name: release-artifacts
281311
path: |

.github/workflows/security.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ jobs:
116116
echo "image=$(cat "$image_job")" >> $GITHUB_OUTPUT
117117
118118
- name: Run Trivy vulnerability scanner
119-
uses: aquasecurity/trivy-action@9ab158e8597f3b310480b9a69402b419bc03dbd5
119+
uses: aquasecurity/trivy-action@8bd2f9fbda2109502356ff8a6a89da55b1ead252
120120
with:
121121
image-ref: ${{ steps.build.outputs.image }}
122122
format: sarif
@@ -130,7 +130,7 @@ jobs:
130130
category: "Trivy"
131131

132132
- name: Upload Trivy scan results as an artifact
133-
uses: actions/upload-artifact@v2
133+
uses: actions/upload-artifact@v3
134134
with:
135135
name: trivy
136136
path: trivy-results.sarif

.vscode/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"agentsdk",
55
"apps",
66
"ASKPASS",
7+
"authcheck",
78
"autostop",
89
"awsidentity",
910
"bodyclose",

cli/tokens.go

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import (
66
"strings"
77
"time"
88

9-
"github.com/google/uuid"
109
"github.com/spf13/cobra"
1110
"golang.org/x/exp/slices"
1211
"golang.org/x/xerrors"
@@ -99,16 +98,14 @@ type tokenListRow struct {
9998
Owner string `json:"-" table:"owner"`
10099
}
101100

102-
func tokenListRowFromToken(token codersdk.APIKey, usersByID map[uuid.UUID]codersdk.User) tokenListRow {
103-
user := usersByID[token.UserID]
104-
101+
func tokenListRowFromToken(token codersdk.APIKeyWithOwner) tokenListRow {
105102
return tokenListRow{
106-
APIKey: token,
103+
APIKey: token.APIKey,
107104
ID: token.ID,
108105
LastUsed: token.LastUsed,
109106
ExpiresAt: token.ExpiresAt,
110107
CreatedAt: token.CreatedAt,
111-
Owner: user.Username,
108+
Owner: token.Username,
112109
}
113110
}
114111

@@ -150,20 +147,10 @@ func listTokens() *cobra.Command {
150147
))
151148
}
152149

153-
userRes, err := client.Users(cmd.Context(), codersdk.UsersRequest{})
154-
if err != nil {
155-
return err
156-
}
157-
158-
usersByID := map[uuid.UUID]codersdk.User{}
159-
for _, user := range userRes.Users {
160-
usersByID[user.ID] = user
161-
}
162-
163150
displayTokens = make([]tokenListRow, len(tokens))
164151

165152
for i, token := range tokens {
166-
displayTokens[i] = tokenListRowFromToken(token, usersByID)
153+
displayTokens[i] = tokenListRowFromToken(token)
167154
}
168155

169156
out, err := formatter.Format(cmd.Context(), displayTokens)

coderd/apikey.go

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -216,9 +216,30 @@ func (api *API) tokens(rw http.ResponseWriter, r *http.Request) {
216216
return
217217
}
218218

219-
var apiKeys []codersdk.APIKey
219+
var userIds []uuid.UUID
220220
for _, key := range keys {
221-
apiKeys = append(apiKeys, convertAPIKey(key))
221+
userIds = append(userIds, key.UserID)
222+
}
223+
224+
users, _ := api.Database.GetUsersByIDs(ctx, userIds)
225+
usersByID := map[uuid.UUID]database.User{}
226+
for _, user := range users {
227+
usersByID[user.ID] = user
228+
}
229+
230+
var apiKeys []codersdk.APIKeyWithOwner
231+
for _, key := range keys {
232+
if user, exists := usersByID[key.UserID]; exists {
233+
apiKeys = append(apiKeys, codersdk.APIKeyWithOwner{
234+
APIKey: convertAPIKey(key),
235+
Username: user.Username,
236+
})
237+
} else {
238+
apiKeys = append(apiKeys, codersdk.APIKeyWithOwner{
239+
APIKey: convertAPIKey(key),
240+
Username: "",
241+
})
242+
}
222243
}
223244

224245
httpapi.Write(ctx, rw, http.StatusOK, apiKeys)

coderd/azureidentity/azureidentity.go

Lines changed: 73 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
package azureidentity
22

33
import (
4-
"context"
54
"crypto/x509"
65
"encoding/base64"
76
"encoding/json"
8-
"io"
9-
"net/http"
7+
"encoding/pem"
108
"regexp"
119

1210
"go.mozilla.org/pkcs7"
@@ -23,7 +21,7 @@ type metadata struct {
2321

2422
// Validate ensures the signature was signed by an Azure certificate.
2523
// It returns the associated VM ID if successful.
26-
func Validate(ctx context.Context, signature string, options x509.VerifyOptions) (string, error) {
24+
func Validate(signature string, options x509.VerifyOptions) (string, error) {
2725
data, err := base64.StdEncoding.DecodeString(signature)
2826
if err != nil {
2927
return "", xerrors.Errorf("decode base64: %w", err)
@@ -41,24 +39,14 @@ func Validate(ctx context.Context, signature string, options x509.VerifyOptions)
4139
}
4240
if options.Intermediates == nil {
4341
options.Intermediates = x509.NewCertPool()
44-
for _, certURL := range signer.IssuingCertificateURL {
45-
req, err := http.NewRequestWithContext(ctx, "GET", certURL, nil)
46-
if err != nil {
47-
return "", xerrors.Errorf("new request %q: %w", certURL, err)
48-
}
49-
res, err := http.DefaultClient.Do(req)
50-
if err != nil {
51-
return "", xerrors.Errorf("perform request %q: %w", certURL, err)
42+
for _, cert := range certificates {
43+
block, rest := pem.Decode([]byte(cert))
44+
if len(rest) != 0 {
45+
return "", xerrors.Errorf("invalid certificate. %d bytes remain", len(rest))
5246
}
53-
data, err := io.ReadAll(res.Body)
47+
cert, err := x509.ParseCertificate(block.Bytes)
5448
if err != nil {
55-
_ = res.Body.Close()
56-
return "", xerrors.Errorf("read body %q: %w", certURL, err)
57-
}
58-
_ = res.Body.Close()
59-
cert, err := x509.ParseCertificate(data)
60-
if err != nil {
61-
return "", xerrors.Errorf("parse certificate %q: %w", certURL, err)
49+
return "", xerrors.Errorf("parse certificate: %w", err)
6250
}
6351
options.Intermediates.AddCert(cert)
6452
}
@@ -76,3 +64,68 @@ func Validate(ctx context.Context, signature string, options x509.VerifyOptions)
7664
}
7765
return metadata.VMID, nil
7866
}
67+
68+
var certificates = []string{
69+
`-----BEGIN CERTIFICATE-----
70+
MIIFWjCCBEKgAwIBAgIQDxSWXyAgaZlP1ceseIlB4jANBgkqhkiG9w0BAQsFADBa
71+
MQswCQYDVQQGEwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJl
72+
clRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTIw
73+
MDcyMTIzMDAwMFoXDTI0MTAwODA3MDAwMFowTzELMAkGA1UEBhMCVVMxHjAcBgNV
74+
BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEgMB4GA1UEAxMXTWljcm9zb2Z0IFJT
75+
QSBUTFMgQ0EgMDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCqYnfP
76+
mmOyBoTzkDb0mfMUUavqlQo7Rgb9EUEf/lsGWMk4bgj8T0RIzTqk970eouKVuL5R
77+
IMW/snBjXXgMQ8ApzWRJCZbar879BV8rKpHoAW4uGJssnNABf2n17j9TiFy6BWy+
78+
IhVnFILyLNK+W2M3zK9gheiWa2uACKhuvgCca5Vw/OQYErEdG7LBEzFnMzTmJcli
79+
W1iCdXby/vI/OxbfqkKD4zJtm45DJvC9Dh+hpzqvLMiK5uo/+aXSJY+SqhoIEpz+
80+
rErHw+uAlKuHFtEjSeeku8eR3+Z5ND9BSqc6JtLqb0bjOHPm5dSRrgt4nnil75bj
81+
c9j3lWXpBb9PXP9Sp/nPCK+nTQmZwHGjUnqlO9ebAVQD47ZisFonnDAmjrZNVqEX
82+
F3p7laEHrFMxttYuD81BdOzxAbL9Rb/8MeFGQjE2Qx65qgVfhH+RsYuuD9dUw/3w
83+
ZAhq05yO6nk07AM9c+AbNtRoEcdZcLCHfMDcbkXKNs5DJncCqXAN6LhXVERCw/us
84+
G2MmCMLSIx9/kwt8bwhUmitOXc6fpT7SmFvRAtvxg84wUkg4Y/Gx++0j0z6StSeN
85+
0EJz150jaHG6WV4HUqaWTb98Tm90IgXAU4AW2GBOlzFPiU5IY9jt+eXC2Q6yC/Zp
86+
TL1LAcnL3Qa/OgLrHN0wiw1KFGD51WRPQ0Sh7QIDAQABo4IBJTCCASEwHQYDVR0O
87+
BBYEFLV2DDARzseSQk1Mx1wsyKkM6AtkMB8GA1UdIwQYMBaAFOWdWTCCR1jMrPoI
88+
VDaGezq1BE3wMA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYI
89+
KwYBBQUHAwIwEgYDVR0TAQH/BAgwBgEB/wIBADA0BggrBgEFBQcBAQQoMCYwJAYI
90+
KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTA6BgNVHR8EMzAxMC+g
91+
LaArhilodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vT21uaXJvb3QyMDI1LmNybDAq
92+
BgNVHSAEIzAhMAgGBmeBDAECATAIBgZngQwBAgIwCwYJKwYBBAGCNyoBMA0GCSqG
93+
SIb3DQEBCwUAA4IBAQCfK76SZ1vae4qt6P+dTQUO7bYNFUHR5hXcA2D59CJWnEj5
94+
na7aKzyowKvQupW4yMH9fGNxtsh6iJswRqOOfZYC4/giBO/gNsBvwr8uDW7t1nYo
95+
DYGHPpvnpxCM2mYfQFHq576/TmeYu1RZY29C4w8xYBlkAA8mDJfRhMCmehk7cN5F
96+
JtyWRj2cZj/hOoI45TYDBChXpOlLZKIYiG1giY16vhCRi6zmPzEwv+tk156N6cGS
97+
Vm44jTQ/rs1sa0JSYjzUaYngoFdZC4OfxnIkQvUIA4TOFmPzNPEFdjcZsgbeEz4T
98+
cGHTBPK4R28F44qIMCtHRV55VMX53ev6P3hRddJb
99+
-----END CERTIFICATE-----`,
100+
`-----BEGIN CERTIFICATE-----
101+
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
130+
-----END CERTIFICATE-----`,
131+
}

coderd/azureidentity/azureidentity_test.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package azureidentity_test
22

33
import (
4-
"context"
54
"crypto/x509"
65
"testing"
76
"time"
@@ -19,7 +18,7 @@ func TestValidate(t *testing.T) {
1918
t.Parallel()
2019
ct, err := time.Parse(time.RFC3339, "2023-02-01T00:00:00Z")
2120
require.NoError(t, err)
22-
vm, err := azureidentity.Validate(context.Background(), signature, x509.VerifyOptions{
21+
vm, err := azureidentity.Validate(signature, x509.VerifyOptions{
2322
CurrentTime: ct,
2423
})
2524
require.NoError(t, err)

coderd/coderd.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,9 @@ func New(options *Options) *API {
284284
// replicas or instances of this middleware.
285285
apiRateLimiter := httpmw.RateLimit(options.APIRateLimit, time.Minute)
286286

287+
derpHandler := derphttp.Handler(api.DERPServer)
288+
derpHandler, api.derpCloseFunc = tailnet.WithWebsocketSupport(api.DERPServer, derpHandler)
289+
287290
r.Use(
288291
httpmw.Recover(api.Logger),
289292
tracing.StatusWriterMiddleware,
@@ -363,7 +366,7 @@ func New(options *Options) *API {
363366
r.Route("/%40{user}/{workspace_and_agent}/apps/{workspaceapp}", apps)
364367
r.Route("/@{user}/{workspace_and_agent}/apps/{workspaceapp}", apps)
365368
r.Route("/derp", func(r chi.Router) {
366-
r.Get("/", derphttp.Handler(api.DERPServer).ServeHTTP)
369+
r.Get("/", derpHandler.ServeHTTP)
367370
// This is used when UDP is blocked, and latency must be checked via HTTP(s).
368371
r.Get("/latency-check", func(w http.ResponseWriter, r *http.Request) {
369372
w.WriteHeader(http.StatusOK)
@@ -726,6 +729,7 @@ type API struct {
726729

727730
WebsocketWaitMutex sync.Mutex
728731
WebsocketWaitGroup sync.WaitGroup
732+
derpCloseFunc func()
729733

730734
metricsCache *metricscache.Cache
731735
workspaceAgentCache *wsconncache.Cache
@@ -739,6 +743,7 @@ type API struct {
739743
// Close waits for all WebSocket connections to drain before returning.
740744
func (api *API) Close() error {
741745
api.cancel()
746+
api.derpCloseFunc()
742747

743748
api.WebsocketWaitMutex.Lock()
744749
api.WebsocketWaitGroup.Wait()

0 commit comments

Comments
 (0)