From ec4c836a778ca7282d1b7c9c1d1451c67623dd66 Mon Sep 17 00:00:00 2001 From: Richie Caputo Date: Wed, 14 Oct 2026 07:09:34 -0700 Subject: [PATCH 1/4] fix(deps): update Go and x/net for security fixes govulncheck fails on main with two reachable vulnerabilities: - GO-2026-6617 in golang.org/x/net v0.59.0, fixed in v0.60.0. - GO-2026-6613 in the Go 1.27.1 standard library (net/http), fixed in Go 1.27.2. Source and container builds now use Go 1.27.2, and x/net advances to v0.60.0. The linter advances to v2.14.0 so it can read Go 1.27.2's compiled package data; the remaining Go changes address the findings the newer linter reports. Backport of upstream kenn-io/msgvault#1185. (cherry picked from commit 7ca2f5156cb7e70872cbfd29eb3a85a2a9132125) Co-authored-by: Rod Boev Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01793XPgu1pMcfXjFd423RNP --- .custom-gcl.yml | 2 +- Dockerfile | 2 +- Makefile | 2 +- docs/screenshots/Dockerfile | 2 +- go.mod | 4 ++-- go.sum | 4 ++-- internal/api/settings_metadata.go | 4 ++-- internal/imap/client.go | 8 ++++---- internal/importer/pst_import.go | 4 ++-- internal/maildir/discover.go | 5 +---- internal/mime/date.go | 6 +++--- internal/mime/parse.go | 4 ++-- internal/oauth/oauth.go | 8 ++++---- internal/store/sender_repair.go | 4 ++-- internal/teams/participants.go | 6 ++---- 15 files changed, 30 insertions(+), 35 deletions(-) diff --git a/.custom-gcl.yml b/.custom-gcl.yml index a86822eff1..3772b97ca8 100644 --- a/.custom-gcl.yml +++ b/.custom-gcl.yml @@ -1,4 +1,4 @@ -version: v2.13.1 +version: v2.14.0 plugins: - module: "go.kenn.io/kit" import: "go.kenn.io/kit/lint/gclplugin" diff --git a/Dockerfile b/Dockerfile index c3b69d0221..fd4523e279 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,7 +11,7 @@ RUN cd web && bun run generate && bun run build # Go build stage. # Pin by digest for reproducibility; update periodically. -FROM golang:1.27.1-bookworm@sha256:69a7b9788769bec032d238959b61854e9ae87f57be9029ec04e9885fabf99195 AS builder +FROM golang:1.27.2-bookworm@sha256:5cf287a799e6b94384bad13d16b14904c531f51ba65792237e122ce42b392f61 AS builder # Install build dependencies for CGO (SQLite, DuckDB). # libsqlite3-dev provides sqlite3.h, required to compile the sqlite-vec diff --git a/Makefile b/Makefile index 7c8de0800b..3f8a60f0c2 100644 --- a/Makefile +++ b/Makefile @@ -41,7 +41,7 @@ TEST_PROFILE ?= auto # Only the automatic SQLite profile adds query and overlaps package jobs. SQLITE_SHARDED_TEST_PKGS := $(sort $(SHARDED_TEST_PKGS) ./internal/query) SQLITE_SHARD_TARGETS := $(addprefix test-sqlite-shard/,$(SQLITE_SHARDED_TEST_PKGS)) -GOLANGCI_LINT_VERSION ?= v2.13.1 +GOLANGCI_LINT_VERSION ?= v2.14.0 GOVULNCHECK_VERSION ?= v1.7.0 HUMA_CHECK_VERSION := 3e1f59e9011e878ec595aa04aebc8a77c5292c4d GO_INSTALL_BIN := $(shell go env GOBIN) diff --git a/docs/screenshots/Dockerfile b/docs/screenshots/Dockerfile index 0a1086e6e4..0230ef314d 100644 --- a/docs/screenshots/Dockerfile +++ b/docs/screenshots/Dockerfile @@ -1,6 +1,6 @@ # syntax=docker/dockerfile:1.4 # Stage 1: Build msgvault binary -FROM golang:1.27.1-bookworm AS builder +FROM golang:1.27.2-bookworm AS builder ARG MSGVAULT_VERSION=dev diff --git a/go.mod b/go.mod index 759de9aaf7..32d268048b 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module go.kenn.io/msgvault -go 1.27.1 +go 1.27.2 replace github.com/emersion/go-imap/v2 => github.com/rodboev/go-imap/v2 v2.0.0-beta.8.0.20260916140841-7dc6eaf3b23f @@ -52,7 +52,7 @@ require ( go.opentelemetry.io/otel/trace v1.45.0 golang.org/x/crypto v0.57.0 golang.org/x/mod v0.41.0 - golang.org/x/net v0.59.0 + golang.org/x/net v0.60.0 golang.org/x/oauth2 v0.36.0 golang.org/x/sync v0.23.0 golang.org/x/sys v0.48.0 diff --git a/go.sum b/go.sum index 01cbb461d6..84b80f85f0 100644 --- a/go.sum +++ b/go.sum @@ -436,8 +436,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.59.0 h1:5zfYln+w5XCxwrnMMJPufRgNoXEaGxl0wo5GqPXyues= -golang.org/x/net v0.59.0/go.mod h1:2DA/G1UfVbCpQPeWTmMPGY7Cs2PkBkwu743bVX5PIVg= +golang.org/x/net v0.60.0 h1:79p50tfZlm0J9YfoDsSi639qSXNGVwEzOPLCxM2FsYU= +golang.org/x/net v0.60.0/go.mod h1:2DA/G1UfVbCpQPeWTmMPGY7Cs2PkBkwu743bVX5PIVg= golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= diff --git a/internal/api/settings_metadata.go b/internal/api/settings_metadata.go index 553d76adaa..f8dea22ad1 100644 --- a/internal/api/settings_metadata.go +++ b/internal/api/settings_metadata.go @@ -406,8 +406,8 @@ func metadataForSetting(key string) settingMetadata { return metadata } last := key - if dot := strings.LastIndexByte(key, '.'); dot >= 0 { - last = key[dot+1:] + if _, suffix, ok := strings.CutLast(key, "."); ok { + last = suffix } words := strings.Fields(strings.ReplaceAll(last, "_", " ")) for index := range words { diff --git a/internal/imap/client.go b/internal/imap/client.go index 8b0f30f19e..e5443e2539 100644 --- a/internal/imap/client.go +++ b/internal/imap/client.go @@ -1718,15 +1718,15 @@ func compositeID(mailbox string, uid imap.UID) string { // parseCompositeID splits a composite message ID into mailbox and UID. func parseCompositeID(id string) (mailbox string, uid imap.UID, err error) { - idx := strings.LastIndexByte(id, '|') - if idx < 0 { + mailbox, rawUID, ok := strings.CutLast(id, "|") + if !ok { return "", 0, fmt.Errorf("invalid IMAP message ID %q (expected mailbox|uid)", id) } - n, parseErr := strconv.ParseUint(id[idx+1:], 10, 32) + n, parseErr := strconv.ParseUint(rawUID, 10, 32) if parseErr != nil { return "", 0, fmt.Errorf("invalid UID in message ID %q: %w", id, parseErr) } - return id[:idx], imap.UID(n), nil + return mailbox, imap.UID(n), nil } // GetProfile returns the IMAP account profile. diff --git a/internal/importer/pst_import.go b/internal/importer/pst_import.go index 4c093fe76a..0f56c20b26 100644 --- a/internal/importer/pst_import.go +++ b/internal/importer/pst_import.go @@ -208,7 +208,7 @@ func importPstWithBatchSize( if err := json.Unmarshal([]byte(active.CursorBefore.String), &saved); err == nil { sameFile := saved.File == absPath || saved.File == cpFile if !sameFile && saved.File != "" { - if curInfo, err := os.Stat(absPath); err == nil { + if curInfo, err := os.Stat(absPath); err == nil { // #nosec G703 -- The local CLI caller selects the PST file to import. if cpInfo, err := os.Stat(saved.File); err == nil && os.SameFile(curInfo, cpInfo) { sameFile = true } @@ -657,7 +657,7 @@ func finishPstThreads(ctx context.Context, st *store.Store, sourceID int64) erro // distinguishes archives. Re-importing the same bytes yields the same // fingerprint regardless of path, preserving idempotence. func pstArchiveFingerprint(path string) (string, error) { - f, err := os.Open(path) + f, err := os.Open(path) // #nosec G703 -- The local CLI caller selects the PST file to fingerprint. if err != nil { return "", err } diff --git a/internal/maildir/discover.go b/internal/maildir/discover.go index af95c87f4b..a00fdbad7e 100644 --- a/internal/maildir/discover.go +++ b/internal/maildir/discover.go @@ -106,10 +106,7 @@ func Discover(root string) ([]Mailbox, error) { // flags are ignored. Absence of the seen flag denotes an unread message. func Flags(path string) []string { name := filepath.Base(path) - flags := "" - if i := strings.LastIndex(name, ":2,"); i >= 0 { - flags = name[i+3:] - } + _, flags, _ := strings.CutLast(name, ":2,") var labels []string if !strings.Contains(flags, "S") { labels = append(labels, "UNREAD") diff --git a/internal/mime/date.go b/internal/mime/date.go index 4ad3b2835b..25bf1fdb44 100644 --- a/internal/mime/date.go +++ b/internal/mime/date.go @@ -43,11 +43,11 @@ func PlausibleDateBounds(now time.Time) (time.Time, time.Time) { func ParseReceivedChain(headers []string) []time.Time { dates := make([]time.Time, 0, len(headers)) for _, header := range headers { - semicolon := strings.LastIndex(header, ";") - if semicolon < 0 { + _, date, ok := strings.CutLast(header, ";") + if !ok { continue } - if parsed := parseDate(strings.TrimSpace(header[semicolon+1:])); !parsed.IsZero() { + if parsed := parseDate(strings.TrimSpace(date)); !parsed.IsZero() { dates = append(dates, parsed) } } diff --git a/internal/mime/parse.go b/internal/mime/parse.go index 073f537bf9..785453c839 100644 --- a/internal/mime/parse.go +++ b/internal/mime/parse.go @@ -553,8 +553,8 @@ func stripAddressDecorations(value string) string { // extractDomain extracts the domain from an email address. func extractDomain(email string) string { - if idx := strings.LastIndex(email, "@"); idx >= 0 { - return strings.ToLower(email[idx+1:]) + if _, domain, ok := strings.CutLast(email, "@"); ok { + return strings.ToLower(domain) } return "" } diff --git a/internal/oauth/oauth.go b/internal/oauth/oauth.go index 1cb3a8a042..122d6d597c 100644 --- a/internal/oauth/oauth.go +++ b/internal/oauth/oauth.go @@ -919,12 +919,12 @@ func SameGoogleAccount(expected, canonical string) bool { // from the local part, and mapping googlemail.com → gmail.com. // Returns "" for non-Gmail addresses. func normalizeGmailAddress(email string) string { - at := strings.LastIndex(email, "@") - if at < 0 { + local, domain, ok := strings.CutLast(email, "@") + if !ok { return "" } - local := strings.ToLower(email[:at]) - domain := strings.ToLower(email[at+1:]) + local = strings.ToLower(local) + domain = strings.ToLower(domain) if domain != "gmail.com" && domain != "googlemail.com" { return "" diff --git a/internal/store/sender_repair.go b/internal/store/sender_repair.go index ec8421686a..1f8e63b5ff 100644 --- a/internal/store/sender_repair.go +++ b/internal/store/sender_repair.go @@ -200,8 +200,8 @@ func normalizeRepairSender(sender mime.Address) (repairSender, error) { func lenientRepairAddress(addr mime.Address) repairSender { email := strings.ToLower(strings.TrimSpace(addr.Email)) domain := strings.ToLower(strings.TrimSpace(addr.Domain)) - if at := strings.LastIndex(email, "@"); at >= 0 { - domain = email[at+1:] + if _, suffix, ok := strings.CutLast(email, "@"); ok { + domain = suffix } return repairSender{ email: email, diff --git a/internal/teams/participants.go b/internal/teams/participants.go index b491a215f6..c9c30ce108 100644 --- a/internal/teams/participants.go +++ b/internal/teams/participants.go @@ -51,10 +51,8 @@ func (r *participantResolver) resolve(ctx context.Context, id *Identity) (int64, } func (r *participantResolver) byEmail(email, displayName string) (int64, error) { - domain := "" - if at := strings.LastIndex(email, "@"); at >= 0 { - domain = strings.ToLower(email[at+1:]) - } + _, domain, _ := strings.CutLast(email, "@") + domain = strings.ToLower(domain) return r.store.EnsureParticipant(strings.ToLower(email), displayName, domain) } From 1ae037e41005efff2eba50378a803757f14372a1 Mon Sep 17 00:00:00 2001 From: Richie Caputo Date: Wed, 14 Oct 2026 07:09:43 -0700 Subject: [PATCH 2/4] chore(deps): update grpc-go to v1.83.2 Updates the indirect google.golang.org/grpc dependency from v1.83.1 to v1.83.2, which fixes a server panic on HTTP/2 requests that carry neither :authority nor Host (GO-2026-6443). govulncheck reports the package as imported but not called; this is a preventive update. Only go.mod and go.sum change. Matches upstream kenn-io/msgvault#1220. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01793XPgu1pMcfXjFd423RNP --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 32d268048b..83f5c65b55 100644 --- a/go.mod +++ b/go.mod @@ -168,7 +168,7 @@ require ( golang.org/x/telemetry v0.0.0-20260811182544-a038080d80e5 // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260706201446-f0a921348800 // indirect - google.golang.org/grpc v1.83.1 // indirect + google.golang.org/grpc v1.83.2 // indirect google.golang.org/protobuf v1.36.11 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect modernc.org/libc v1.73.4 // indirect diff --git a/go.sum b/go.sum index 84b80f85f0..cc5db740b5 100644 --- a/go.sum +++ b/go.sum @@ -490,8 +490,8 @@ google.golang.org/genproto/googleapis/api v0.0.0-20260706201446-f0a921348800 h1: google.golang.org/genproto/googleapis/api v0.0.0-20260706201446-f0a921348800/go.mod h1:FPk7EXUKMtImne7AmknoYjT4QXqKIzzRbeQIXzLk6fQ= google.golang.org/genproto/googleapis/rpc v0.0.0-20260706201446-f0a921348800 h1:qEHAMpSaUhtD0p3NbEEI83HwNGFxEwaSJ1G9PLnCBZE= google.golang.org/genproto/googleapis/rpc v0.0.0-20260706201446-f0a921348800/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= -google.golang.org/grpc v1.83.1 h1:HIO0+BEtBP6soyqvqC8sNUjZ7bTs+0hFQuFF+RAy++Y= -google.golang.org/grpc v1.83.1/go.mod h1:kDyl6SKsiHKt0uylY5gtn5cEjkrIOhQOGDgIc4JGwzQ= +google.golang.org/grpc v1.83.2 h1:EManeRomTObA0BU7I8vXgg/78uE5MJ9M8B39EX2WscU= +google.golang.org/grpc v1.83.2/go.mod h1:YPI1hK3kDked6iHvgX3tR0y+nX/qpMFKhPgFsokw1S8= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From 029933074cb3b26360cb32c2e3d8bbc959f9951a Mon Sep 17 00:00:00 2001 From: Richie Caputo Date: Wed, 14 Oct 2026 07:15:21 -0700 Subject: [PATCH 3/4] chore(deps): update x/tools to v0.50.0 for Go 1.27.2 Go 1.27.2 writes export data version 5, which the x/tools v0.49.0 importer cannot read, so `make testify-helper-check` (and therefore `make lint-ci`) fails on every package. x/tools v0.50.0 reads the new format; x/telemetry follows as its indirect requirement. This matches the x/tools version upstream already uses. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01793XPgu1pMcfXjFd423RNP --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 83f5c65b55..82873d5cc6 100644 --- a/go.mod +++ b/go.mod @@ -58,7 +58,7 @@ require ( golang.org/x/sys v0.48.0 golang.org/x/text v0.42.0 golang.org/x/time v0.15.0 - golang.org/x/tools v0.49.0 + golang.org/x/tools v0.50.0 google.golang.org/api v0.287.0 howett.net/plist v1.0.1 ) @@ -165,7 +165,7 @@ require ( go.yaml.in/yaml/v4 v4.0.0-rc.6 // indirect golang.org/x/exp v0.0.0-20260112195511-716be5621a96 // indirect golang.org/x/image v0.45.0 // indirect - golang.org/x/telemetry v0.0.0-20260811182544-a038080d80e5 // indirect + golang.org/x/telemetry v0.0.0-20260908163034-4bcc4b2ee518 // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260706201446-f0a921348800 // indirect google.golang.org/grpc v1.83.2 // indirect diff --git a/go.sum b/go.sum index cc5db740b5..28e53bf2d4 100644 --- a/go.sum +++ b/go.sum @@ -457,8 +457,8 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.48.0 h1:bbX/i/6MgT9BVLM9RT1thmxL04yeTAhbEz4SyadbXoo= golang.org/x/sys v0.48.0/go.mod h1:hNLxWAXmnKAxqDtdwIYC4bM9oQPEecfsnNMuSxOs3og= -golang.org/x/telemetry v0.0.0-20260811182544-a038080d80e5 h1:ZUSxONxc981v7AW7QUg+I9WwZzSTTJ019ENBYr5pV/Q= -golang.org/x/telemetry v0.0.0-20260811182544-a038080d80e5/go.mod h1:LVehoXe41cL5SCVQilsV7Gg6BNG+Js6P9PhSbYTIUkQ= +golang.org/x/telemetry v0.0.0-20260908163034-4bcc4b2ee518 h1:F5BWKvW126NXR74uxkxuc1jQHhm/rwm/J3rSiFyuRs4= +golang.org/x/telemetry v0.0.0-20260908163034-4bcc4b2ee518/go.mod h1:i+ivNqjDnTF3WTElsdk5g9V5DTSBYgdNo7xTU9SDwYA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -475,8 +475,8 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.49.0 h1:3NI7VXzL9+1WZD52Dx2ttoPwD5DWrFGpl9mFZDlmisI= -golang.org/x/tools v0.49.0/go.mod h1:SJNXV9DBKT0UbdttsQjbfJlAE/q+y36++zo3uL3N0Oo= +golang.org/x/tools v0.50.0 h1:c2ifzfcuY7L90lZ2aKd8S4K2NpASF08SZx9ZuJkHmSU= +golang.org/x/tools v0.50.0/go.mod h1:7ulVMw3831Mwi5EZD6RomGyffr4VFjuNYXf2BbCEAV0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY= golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= From eec5676d485b5c4e52f6e9773f9922a3733dafd0 Mon Sep 17 00:00:00 2001 From: Richie Caputo Date: Wed, 14 Oct 2026 07:23:58 -0700 Subject: [PATCH 4/4] refactor(meetings): use strings.CutLast for attendee email domains golangci-lint v2.14.0's modernize check reports the LastIndex slicing in the Circleback and Granola importers' emailDomain helpers. CutLast returns the same suffix, and an empty string when the address has no "@", so behavior is unchanged. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01793XPgu1pMcfXjFd423RNP --- internal/circleback/importer.go | 6 ++---- internal/granola/importer.go | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/internal/circleback/importer.go b/internal/circleback/importer.go index 3283f35167..26c6da0e14 100644 --- a/internal/circleback/importer.go +++ b/internal/circleback/importer.go @@ -1136,8 +1136,6 @@ func normalizeEmail(email string) string { } func emailDomain(email string) string { - if i := strings.LastIndex(email, "@"); i >= 0 { - return email[i+1:] - } - return "" + _, domain, _ := strings.CutLast(email, "@") + return domain } diff --git a/internal/granola/importer.go b/internal/granola/importer.go index 0e78c9227e..8921ca7244 100644 --- a/internal/granola/importer.go +++ b/internal/granola/importer.go @@ -491,8 +491,6 @@ func normalizeEmail(email string) string { } func emailDomain(email string) string { - if i := strings.LastIndex(email, "@"); i >= 0 { - return email[i+1:] - } - return "" + _, domain, _ := strings.CutLast(email, "@") + return domain }