From b4d0fbfb5abbfc520d5463d058b91d098a2b40d5 Mon Sep 17 00:00:00 2001 From: Mark Mennell Date: Fri, 11 Sep 2026 10:11:01 +0800 Subject: [PATCH 1/2] Upgrade to Go 1.27 and standardize CI badges --- .../workflows/{go1.25.yml => build-test.yml} | 32 +++++++++++-------- .github/workflows/integration-test.yml | 6 +++- README.md | 5 +-- go.mod | 2 +- 4 files changed, 28 insertions(+), 17 deletions(-) rename .github/workflows/{go1.25.yml => build-test.yml} (56%) diff --git a/.github/workflows/go1.25.yml b/.github/workflows/build-test.yml similarity index 56% rename from .github/workflows/go1.25.yml rename to .github/workflows/build-test.yml index 5188b6a..91a97de 100644 --- a/.github/workflows/go1.25.yml +++ b/.github/workflows/build-test.yml @@ -1,13 +1,16 @@ -name: Go 1.25 Build and Test +name: Build & Test on: push: - branches: [ "main" ] + branches: [main] pull_request: - branches: [ "main" ] + branches: [main] + workflow_dispatch: -jobs: +permissions: + contents: read +jobs: build: runs-on: ubuntu-latest services: @@ -25,15 +28,18 @@ jobs: env: FMSG_TEST_DATABASE_URL: postgres://postgres@localhost:5432/postgres?sslmode=disable steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v7 + + - name: Set up Go + uses: actions/setup-go@v7 + with: + go-version: "1.27.x" - - name: Set up Go - uses: actions/setup-go@v3 - with: - go-version: '1.25' + - name: Build + run: go build ./... - - name: Build - run: go build -v ./... + - name: Test + run: go test -race ./... - - name: Test - run: go test -race ./... + - name: Vet + run: go vet ./... diff --git a/.github/workflows/integration-test.yml b/.github/workflows/integration-test.yml index 15d5db1..53e23e9 100644 --- a/.github/workflows/integration-test.yml +++ b/.github/workflows/integration-test.yml @@ -23,6 +23,8 @@ jobs: } DOCKER_REF=$(matching_ref fmsg-docker) WEBAPI_REF=$(matching_ref fmsg-webapi) + ID_REF=$(matching_ref fmsgid) + CLI_REF=$(matching_ref fmsg-cli) DISPATCH_STARTED=$(date -u +%Y-%m-%dT%H:%M:%SZ) # Coordinated schema/API changes use their companion branches. @@ -30,7 +32,9 @@ jobs: --repo markmnl/fmsg-docker \ --ref "$DOCKER_REF" \ -f fmsgd_ref="$FMSGD_REF" \ - -f fmsg_webapi_ref="$WEBAPI_REF" + -f fmsg_webapi_ref="$WEBAPI_REF" \ + -f fmsgid_ref="$ID_REF" \ + -f fmsg_cli_ref="$CLI_REF" echo "Triggered integration test for fmsgd_ref=$FMSGD_REF, polling for run..." diff --git a/README.md b/README.md index 396069e..9eca337 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ -[![Go 1.25](https://github.com/markmnl/fmsgd/actions/workflows/go1.25.yml/badge.svg)](https://github.com/markmnl/fmsgd/actions/workflows/go1.25.yml) +[![Build & Test](https://github.com/markmnl/fmsgd/actions/workflows/build-test.yml/badge.svg?branch=main)](https://github.com/markmnl/fmsgd/actions/workflows/build-test.yml?query=branch%3Amain) +[![Go 1.27+](https://img.shields.io/badge/Go-1.27%2B-00ADD8?logo=go&logoColor=white)](https://go.dev/dl/) # fmsgd @@ -6,7 +7,7 @@ Implementation of [fmsg](https://github.com/markmnl/fmsg) host written in Go! Us ## Building from source -Tested with Go 1.25 on Linux and Windows, AMD64 and ARM +Requires Go 1.27 or newer. 1. Clone this repository 2. Run `go build ./cmd/fmsgd/` diff --git a/go.mod b/go.mod index a27ea72..93fef7f 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/markmnl/fmsgd -go 1.25 +go 1.27.0 require ( github.com/caitlinelfring/go-env-default v1.1.0 From 6733b2629f900772fe0e05e090be9cb4c1306420 Mon Sep 17 00:00:00 2001 From: Mark Mennell Date: Fri, 11 Sep 2026 10:18:17 +0800 Subject: [PATCH 2/2] Apply Go 1.27 modernizations with go fix --- cmd/fmsg-backfill/migrate_test.go | 2 +- cmd/fmsgd/dns.go | 9 ++++----- cmd/fmsgd/host.go | 7 +++---- cmd/fmsgd/id.go | 2 +- cmd/fmsgd/sender.go | 2 +- cmd/fmsgd/store.go | 10 +++++----- pkg/fmsg/deflate.go | 5 +---- 7 files changed, 16 insertions(+), 21 deletions(-) diff --git a/cmd/fmsg-backfill/migrate_test.go b/cmd/fmsg-backfill/migrate_test.go index 9b2c374..cd36879 100644 --- a/cmd/fmsg-backfill/migrate_test.go +++ b/cmd/fmsg-backfill/migrate_test.go @@ -317,7 +317,7 @@ func TestMigrationFailureRollsBackEverything(t *testing.T) { func TestDecodeHeaderRejectsTruncation(t *testing.T) { h := prepared(t, rawMessage(t, "example.com", strings.Repeat("content ", 200))) data := h.Encode() - for i := 0; i < len(data); i++ { + for i := range data { if _, err := decodeHeader(data[:i]); err == nil { t.Fatalf("accepted prefix %d", i) } diff --git a/cmd/fmsgd/dns.go b/cmd/fmsgd/dns.go index a5e6daa..4e1a6a3 100644 --- a/cmd/fmsgd/dns.go +++ b/cmd/fmsgd/dns.go @@ -7,6 +7,7 @@ import ( "net" "net/http" "os" + "slices" "strings" "time" @@ -127,11 +128,9 @@ func verifyDomainIP(domain string) { log.Panicf("ERROR: failed to lookup fmsg.%s: %s", domain, err) } - for _, ip := range authorisedIPs { - if externalIP.Equal(ip) { - log.Printf("INFO: external IP %s found in fmsg.%s authorised IPs", externalIP, domain) - return - } + if slices.ContainsFunc(authorisedIPs, externalIP.Equal) { + log.Printf("INFO: external IP %s found in fmsg.%s authorised IPs", externalIP, domain) + return } log.Panicf("ERROR: external IP %s not found in fmsg.%s authorised IPs %v", externalIP, domain, authorisedIPs) diff --git a/cmd/fmsgd/host.go b/cmd/fmsgd/host.go index 091f6d9..fb97863 100644 --- a/cmd/fmsgd/host.go +++ b/cmd/fmsgd/host.go @@ -17,6 +17,7 @@ import ( "net/url" "os" "path/filepath" + "slices" "strings" "time" "unicode" @@ -559,10 +560,8 @@ func verifySenderIP(c net.Conn, senderDomain string) error { return fmt.Errorf("DNS verification failed") } - for _, ip := range authorisedIPs { - if remoteIP.Equal(ip) { - return nil - } + if slices.ContainsFunc(authorisedIPs, remoteIP.Equal) { + return nil } log.Printf("WARN: remote IP %s not in authorised IPs for fmsg.%s", remoteIP.String(), senderDomain) diff --git a/cmd/fmsgd/id.go b/cmd/fmsgd/id.go index 49c22e2..c639086 100644 --- a/cmd/fmsgd/id.go +++ b/cmd/fmsgd/id.go @@ -69,7 +69,7 @@ func postMsgStat(addr *FMsgAddress, timestamp float64, size int, isSending bool) } uri := fmt.Sprintf("%s/fmsgid/%s", IDURI, part) - payload := map[string]interface{}{ + payload := map[string]any{ "address": addr.ToString(), "ts": timestamp, "size": size} diff --git a/cmd/fmsgd/sender.go b/cmd/fmsgd/sender.go index a8eab6c..f0872a0 100644 --- a/cmd/fmsgd/sender.go +++ b/cmd/fmsgd/sender.go @@ -310,7 +310,7 @@ func lockPendingRecipients(tx *sql.Tx, table string, msgID int64, domain string, AND (r.response_code IS NULL OR r.response_code = ANY($5)) AND (r.time_last_attempt IS NULL OR ($2 - r.time_last_attempt) > LEAST($3 * POWER(2.0, GREATEST(r.attempt_count - 1, 0)::float), $4)) AND ($2 - %s) < $4`, table, joinBatch, ageRef) - args := []interface{}{msgID, now, RetryInterval, RetryMaxAge, pq.Array(retryableResponseCodes)} + args := []any{msgID, now, RetryInterval, RetryMaxAge, pq.Array(retryableResponseCodes)} if table == "msg_add_to" { q += " AND r.batch_id = $6" args = append(args, batchID) diff --git a/cmd/fmsgd/store.go b/cmd/fmsgd/store.go index 6df824c..12249fd 100644 --- a/cmd/fmsgd/store.go +++ b/cmd/fmsgd/store.go @@ -378,8 +378,8 @@ func attachAddToRecipients(tx *sql.Tx, msgID int64, msg *FMsgHeader) error { // domains are recorded with localResponseCodeNotOurDelivery so the // sender's pending queries never treat them as our delivery work. for _, addr := range msg.To { - var delivered interface{} - var code interface{} + var delivered any + var code any if addr.Domain == Domain { delivered = now } else { @@ -416,8 +416,8 @@ on conflict (msg_id, addr) do nothing`, msgID, addr.ToString(), delivered, code) } for _, addr := range msg.AddTo { - var delivered interface{} - var code interface{} + var delivered any + var code any if addr.Domain == Domain { delivered = now } else { @@ -450,7 +450,7 @@ func sealReceivedBatch(tx *sql.Tx, id int64, h *FMsgHeader, hash []byte) error { // this host rejected keep the per-recipient code it responded; recipients on // other domains are recorded for participant checks and faithful message // reconstruction (SPEC §10.3/§11) but are another host's delivery duty. -func inboundRecipientRow(addr FMsgAddress, localOutcome map[string]uint8, now float64) (delivered interface{}, code interface{}) { +func inboundRecipientRow(addr FMsgAddress, localOutcome map[string]uint8, now float64) (delivered any, code any) { c, ok := localOutcome[strings.ToLower(addr.ToString())] if !ok { return nil, int16(localResponseCodeNotOurDelivery) diff --git a/pkg/fmsg/deflate.go b/pkg/fmsg/deflate.go index bd9f2ae..4a3b5ce 100644 --- a/pkg/fmsg/deflate.go +++ b/pkg/fmsg/deflate.go @@ -71,10 +71,7 @@ const deflateSampleSize = 8192 // and reports whether the ratio looks promising (compressed < 80% of input). // src is seeked back to the start on return. func probeSample(src *os.File, srcSize uint32) (bool, error) { - sampleLen := int64(deflateSampleSize) - if int64(srcSize) < sampleLen { - sampleLen = int64(srcSize) - } + sampleLen := min(int64(srcSize), int64(deflateSampleSize)) var buf bytes.Buffer zw := zlib.NewWriter(&buf)