Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 6 additions & 7 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ jobs:
outputs:
release_created: ${{ steps.release.outputs.release_created }}
tag_name: ${{ steps.release.outputs.tag_name }}
version: ${{ steps.release.outputs.version }}
steps:
- uses: googleapis/release-please-action@v5
id: release
Expand Down Expand Up @@ -70,10 +71,8 @@ jobs:
SENTRY_URL: https://glitch.grounds.gg/
with:
environment: production
# release-please tag_name is e.g. `v0.1.7`; sentry-go's
# Release field is set from internal/version.Version which
# ldflags-baked equals goreleaser's .Version (no `v`). Strip
# the prefix here so the marker matches what the binary
# reports at runtime.
version: ${{ needs.release-please.outputs.tag_name }}
version_prefix: v
# release-please's `version` output is the bare semver
# (e.g. 0.1.8); the binary's runtime release tag also has
# no `v` prefix. Use `version` not `tag_name` so the
# GlitchTip marker matches what the SDK reports at runtime.
version: ${{ needs.release-please.outputs.version }}
9 changes: 7 additions & 2 deletions internal/auth/device.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,13 @@ func (d *DeviceClient) StartDevice(ctx context.Context) (*DeviceCodeResponse, er
return nil, fmt.Errorf("pkce: %w", err)
}
body := url.Values{
"client_id": {d.ClientID},
"scope": {"openid profile email"},
"client_id": {d.ClientID},
// `offline_access` upgrades the refresh_token to an "offline
// token" with a 30-day default TTL, decoupled from the SSO
// session-idle window (Keycloak default 30 minutes). Without
// it a user who runs `grounds login` once in the morning
// would have to re-authenticate after lunch.
"scope": {"openid profile email offline_access"},
"code_challenge": {challenge},
"code_challenge_method": {"S256"},
}
Expand Down
9 changes: 8 additions & 1 deletion internal/auth/device_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,15 @@ import (
)

func TestStartDevice(t *testing.T) {
var gotChallenge, gotMethod string
var gotChallenge, gotMethod, gotScope string
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if !strings.HasSuffix(r.URL.Path, "/auth/device") {
t.Fatalf("path = %s", r.URL.Path)
}
r.ParseForm()
gotChallenge = r.Form.Get("code_challenge")
gotMethod = r.Form.Get("code_challenge_method")
gotScope = r.Form.Get("scope")
json.NewEncoder(w).Encode(DeviceCodeResponse{
DeviceCode: "dc",
UserCode: "ABCD-EFGH",
Expand Down Expand Up @@ -48,6 +49,12 @@ func TestStartDevice(t *testing.T) {
if res.CodeVerifier == "" {
t.Error("CodeVerifier should be populated for PollToken")
}
// offline_access keeps the refresh token alive past the SSO
// session-idle window so the CLI doesn't ask for a re-login
// after a few minutes of inactivity.
if !strings.Contains(gotScope, "offline_access") {
t.Errorf("scope = %q, want it to contain offline_access", gotScope)
}
}

func TestPollToken_Success(t *testing.T) {
Expand Down
Loading