From bc2ff8ea495aee12ad3c77074b6be1fbf85e5ef2 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Fri, 21 Jan 2022 17:18:31 +0000 Subject: [PATCH 01/20] Don't listen on :8448 for the Complement federation server Instead, listen on a random OS-allocated high numbered port then do a switcheroo on the `ServerName` so it reads correctly e.g `host.docker.internal:56185`. This means the server name will be invalid if it is read before `Server.Listen()` is called so we now guard common access points in `Server` which rely on the server name and fail tests if the server is not yet listening when those functions are called. To further guard against misuse of server name whilst it isn't valid, turn it into a private field. --- internal/federation/handle.go | 24 ++++----- internal/federation/server.go | 50 ++++++++++++++----- tests/federation_query_profile_test.go | 3 +- tests/federation_room_event_auth_test.go | 5 +- ...federation_room_get_missing_events_test.go | 2 +- tests/federation_room_join_test.go | 4 +- tests/media_nofilename_test.go | 2 +- tests/msc2836_test.go | 5 +- tests/room_hierarchy_test.go | 1 + 9 files changed, 62 insertions(+), 34 deletions(-) diff --git a/internal/federation/handle.go b/internal/federation/handle.go index 2859752e..2b821bc0 100644 --- a/internal/federation/handle.go +++ b/internal/federation/handle.go @@ -18,7 +18,7 @@ import ( func MakeJoinRequestsHandler(s *Server, w http.ResponseWriter, req *http.Request) { // Check federation signature fedReq, errResp := gomatrixserverlib.VerifyHTTPRequest( - req, time.Now(), gomatrixserverlib.ServerName(s.ServerName), s.keyRing, + req, time.Now(), gomatrixserverlib.ServerName(s.serverName), s.keyRing, ) if fedReq == nil { w.WriteHeader(errResp.Code) @@ -74,7 +74,7 @@ func MakeJoinRequestsHandler(s *Server, w http.ResponseWriter, req *http.Request // HandleMakeSendJoinRequests. func SendJoinRequestsHandler(s *Server, w http.ResponseWriter, req *http.Request) { fedReq, errResp := gomatrixserverlib.VerifyHTTPRequest( - req, time.Now(), gomatrixserverlib.ServerName(s.ServerName), s.keyRing, + req, time.Now(), gomatrixserverlib.ServerName(s.serverName), s.keyRing, ) if fedReq == nil { w.WriteHeader(errResp.Code) @@ -103,7 +103,7 @@ func SendJoinRequestsHandler(s *Server, w http.ResponseWriter, req *http.Request b, err := json.Marshal(gomatrixserverlib.RespSendJoin{ AuthEvents: room.AuthChain(), StateEvents: room.AllCurrentState(), - Origin: gomatrixserverlib.ServerName(s.ServerName), + Origin: gomatrixserverlib.ServerName(s.serverName), }) if err != nil { w.WriteHeader(500) @@ -136,7 +136,7 @@ func HandleInviteRequests(inviteCallback func(*gomatrixserverlib.Event)) func(*S // https://matrix.org/docs/spec/server_server/r0.1.4#put-matrix-federation-v2-invite-roomid-eventid s.mux.Handle("/_matrix/federation/v2/invite/{roomID}/{eventID}", http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { fedReq, errResp := gomatrixserverlib.VerifyHTTPRequest( - req, time.Now(), gomatrixserverlib.ServerName(s.ServerName), s.keyRing, + req, time.Now(), gomatrixserverlib.ServerName(s.serverName), s.keyRing, ) if fedReq == nil { w.WriteHeader(errResp.Code) @@ -164,7 +164,7 @@ func HandleInviteRequests(inviteCallback func(*gomatrixserverlib.Event)) func(*S } // Sign the event before we send it back - signedEvent := inviteRequest.Event().Sign(s.ServerName, s.KeyID, s.Priv) + signedEvent := inviteRequest.Event().Sign(s.serverName, s.KeyID, s.Priv) // Send the response res := map[string]interface{}{ @@ -190,7 +190,7 @@ func HandleDirectoryLookups() func(*Server) { b, err := json.Marshal(gomatrixserverlib.RespDirectory{ RoomID: roomID, Servers: []gomatrixserverlib.ServerName{ - gomatrixserverlib.ServerName(s.ServerName), + gomatrixserverlib.ServerName(s.serverName), }, }) if err != nil { @@ -230,7 +230,7 @@ func HandleEventRequests() func(*Server) { } txn := gomatrixserverlib.Transaction{ - Origin: gomatrixserverlib.ServerName(srv.ServerName), + Origin: gomatrixserverlib.ServerName(srv.serverName), OriginServerTS: gomatrixserverlib.AsTimestamp(time.Now()), PDUs: []json.RawMessage{ event.JSON(), @@ -254,7 +254,7 @@ func HandleKeyRequests() func(*Server) { keymux := srv.mux.PathPrefix("/_matrix/key/v2").Subrouter() keyFn := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { k := gomatrixserverlib.ServerKeys{} - k.ServerName = gomatrixserverlib.ServerName(srv.ServerName) + k.ServerName = gomatrixserverlib.ServerName(srv.serverName) publicKey := srv.Priv.Public().(ed25519.PublicKey) k.VerifyKeys = map[gomatrixserverlib.KeyID]gomatrixserverlib.VerifyKey{ srv.KeyID: { @@ -271,7 +271,7 @@ func HandleKeyRequests() func(*Server) { } k.Raw, err = gomatrixserverlib.SignJSON( - string(srv.ServerName), srv.KeyID, srv.Priv, toSign, + string(srv.serverName), srv.KeyID, srv.Priv, toSign, ) if err != nil { w.WriteHeader(500) @@ -299,9 +299,9 @@ func HandleMediaRequests(mediaIds map[string]func(w http.ResponseWriter)) func(* origin := vars["origin"] mediaId := vars["mediaId"] - if origin != srv.ServerName { + if origin != srv.serverName { w.WriteHeader(400) - w.Write([]byte("complement: Invalid Origin; Expected " + srv.ServerName)) + w.Write([]byte("complement: Invalid Origin; Expected " + srv.serverName)) return } @@ -333,7 +333,7 @@ func HandleTransactionRequests(pduCallback func(*gomatrixserverlib.Event), eduCa // Check federation signature fedReq, errResp := gomatrixserverlib.VerifyHTTPRequest( - req, time.Now(), gomatrixserverlib.ServerName(srv.ServerName), srv.keyRing, + req, time.Now(), gomatrixserverlib.ServerName(srv.serverName), srv.keyRing, ) if fedReq == nil { log.Printf( diff --git a/internal/federation/server.go b/internal/federation/server.go index f35e6897..7c096a7a 100644 --- a/internal/federation/server.go +++ b/internal/federation/server.go @@ -37,7 +37,8 @@ type Server struct { Priv ed25519.PrivateKey KeyID gomatrixserverlib.KeyID - ServerName string + serverName string + listening bool certPath string keyPath string @@ -63,7 +64,7 @@ func NewServer(t *testing.T, deployment *docker.Deployment, opts ...func(*Server Priv: priv, KeyID: "ed25519:complement", mux: mux.NewRouter(), - ServerName: docker.HostnameRunningComplement, + serverName: docker.HostnameRunningComplement, rooms: make(map[string]*ServerRoom), aliases: make(map[string]string), UnexpectedRequestsAreErrors: true, @@ -114,16 +115,29 @@ func NewServer(t *testing.T, deployment *docker.Deployment, opts ...func(*Server return srv } +func (s *Server) ServerName() string { + if !s.listening { + s.t.Fatalf("ServerName() called before Listen() - this is not supported because Listen() chooses a high-numbered port and thus changes the server name. Ensure you Listen() first!") + } + return s.serverName +} + // UserID returns the complete user ID for the given localpart func (s *Server) UserID(localpart string) string { - return fmt.Sprintf("@%s:%s", localpart, s.ServerName) + if !s.listening { + s.t.Fatalf("UserID() called before Listen() - this is not supported because Listen() chooses a high-numbered port and thus changes the server name and thus changes the user ID. Ensure you Listen() first!") + } + return fmt.Sprintf("@%s:%s", localpart, s.serverName) } // MakeAliasMapping will create a mapping of room alias to room ID on this server. Returns the alias. // If this is the first time calling this function, a directory lookup handler will be added to // handle alias requests over federation. func (s *Server) MakeAliasMapping(aliasLocalpart, roomID string) string { - alias := fmt.Sprintf("#%s:%s", aliasLocalpart, s.ServerName) + if !s.listening { + s.t.Fatalf("MakeAliasMapping() called before Listen() - this is not supported because Listen() chooses a high-numbered port and thus changes the server name and thus changes the room alias. Ensure you Listen() first!") + } + alias := fmt.Sprintf("#%s:%s", aliasLocalpart, s.serverName) s.aliases[alias] = roomID HandleDirectoryLookups()(s) return alias @@ -132,7 +146,10 @@ func (s *Server) MakeAliasMapping(aliasLocalpart, roomID string) string { // MustMakeRoom will add a room to this server so it is accessible to other servers when prompted via federation. // The `events` will be added to this room. Returns the created room. func (s *Server) MustMakeRoom(t *testing.T, roomVer gomatrixserverlib.RoomVersion, events []b.Event) *ServerRoom { - roomID := fmt.Sprintf("!%d:%s", len(s.rooms), s.ServerName) + if !s.listening { + s.t.Fatalf("MustMakeRoom() called before Listen() - this is not supported because Listen() chooses a high-numbered port and thus changes the server name and thus changes the room ID. Ensure you Listen() first!") + } + roomID := fmt.Sprintf("!%d:%s", len(s.rooms), s.serverName) t.Logf("Creating room %s with version %s", roomID, roomVer) room := newRoom(roomVer, roomID) @@ -149,8 +166,11 @@ func (s *Server) MustMakeRoom(t *testing.T, roomVer gomatrixserverlib.RoomVersio // // The requests will be routed according to the deployment map in `deployment`. func (s *Server) FederationClient(deployment *docker.Deployment) *gomatrixserverlib.FederationClient { + if !s.listening { + s.t.Fatalf("FederationClient() called before Listen() - this is not supported because Listen() chooses a high-numbered port and thus changes the server name and thus changes the way federation requests are signed. Ensure you Listen() first!") + } f := gomatrixserverlib.NewFederationClient( - gomatrixserverlib.ServerName(s.ServerName), s.KeyID, s.Priv, + gomatrixserverlib.ServerName(s.serverName), s.KeyID, s.Priv, gomatrixserverlib.WithTransport(&docker.RoundTripper{Deployment: deployment}), ) return f @@ -160,7 +180,7 @@ func (s *Server) FederationClient(deployment *docker.Deployment) *gomatrixserver // // The requests will be routed according to the deployment map in `deployment`. func (s *Server) SendFederationRequest(deployment *docker.Deployment, req gomatrixserverlib.FederationRequest, resBody interface{}) error { - if err := req.Sign(gomatrixserverlib.ServerName(s.ServerName), s.KeyID, s.Priv); err != nil { + if err := req.Sign(gomatrixserverlib.ServerName(s.serverName), s.KeyID, s.Priv); err != nil { return err } @@ -207,7 +227,7 @@ func (s *Server) MustCreateEvent(t *testing.T, room *ServerRoom, ev b.Event) *go } eb.AuthEvents = room.AuthEvents(stateNeeded) } - signedEvent, err := eb.Build(time.Now(), gomatrixserverlib.ServerName(s.ServerName), s.KeyID, s.Priv, room.Version) + signedEvent, err := eb.Build(time.Now(), gomatrixserverlib.ServerName(s.serverName), s.KeyID, s.Priv, room.Version) if err != nil { t.Fatalf("MustCreateEvent: failed to sign event: %s", err) } @@ -224,7 +244,7 @@ func (s *Server) MustJoinRoom(t *testing.T, deployment *docker.Deployment, remot t.Fatalf("MustJoinRoom: make_join failed: %v", err) } roomVer := makeJoinResp.RoomVersion - joinEvent, err := makeJoinResp.JoinEvent.Build(time.Now(), gomatrixserverlib.ServerName(s.ServerName), s.KeyID, s.Priv, roomVer) + joinEvent, err := makeJoinResp.JoinEvent.Build(time.Now(), gomatrixserverlib.ServerName(s.serverName), s.KeyID, s.Priv, roomVer) if err != nil { t.Fatalf("MustJoinRoom: failed to sign event: %v", err) } @@ -258,7 +278,7 @@ func (s *Server) MustLeaveRoom(t *testing.T, deployment *docker.Deployment, remo t.Fatalf("MustLeaveRoom: (rejecting invite) make_leave failed: %v", err) } roomVer := makeLeaveResp.RoomVersion - leaveEvent, err = makeLeaveResp.LeaveEvent.Build(time.Now(), gomatrixserverlib.ServerName(s.ServerName), s.KeyID, s.Priv, roomVer) + leaveEvent, err = makeLeaveResp.LeaveEvent.Build(time.Now(), gomatrixserverlib.ServerName(s.serverName), s.KeyID, s.Priv, roomVer) if err != nil { t.Fatalf("MustLeaveRoom: (rejecting invite) failed to sign event: %v", err) } @@ -290,13 +310,19 @@ func (s *Server) Mux() *mux.Router { // Listen for federation server requests - call the returned function to gracefully close the server. func (s *Server) Listen() (cancel func()) { + if s.listening { + return + } var wg sync.WaitGroup wg.Add(1) - ln, err := net.Listen("tcp", s.srv.Addr) + ln, err := net.Listen("tcp", ":0") if err != nil { s.t.Fatalf("ListenFederationServer: net.Listen failed: %s", err) } + port := ln.Addr().(*net.TCPAddr).Port + s.serverName += fmt.Sprintf(":%d", port) + s.listening = true go func() { defer ln.Close() @@ -548,7 +574,7 @@ func (f *basicKeyFetcher) FetchKeys( ) { result := make(map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.PublicKeyLookupResult, len(requests)) for req := range requests { - if string(req.ServerName) == f.srv.ServerName && req.KeyID == f.srv.KeyID { + if string(req.ServerName) == f.srv.serverName && req.KeyID == f.srv.KeyID { publicKey := f.srv.Priv.Public().(ed25519.PublicKey) result[req] = gomatrixserverlib.PublicKeyLookupResult{ ValidUntilTS: gomatrixserverlib.AsTimestamp(time.Now().Add(24 * time.Hour)), diff --git a/tests/federation_query_profile_test.go b/tests/federation_query_profile_test.go index fc6849b2..657ac25d 100644 --- a/tests/federation_query_profile_test.go +++ b/tests/federation_query_profile_test.go @@ -6,7 +6,6 @@ import ( "testing" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/docker" "github.com/matrix-org/complement/internal/federation" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" @@ -29,7 +28,7 @@ func TestOutboundFederationProfile(t *testing.T) { // sytest: Outbound federation can query profile data t.Run("Outbound federation can query profile data", func(t *testing.T) { - remoteUserID := "@user:" + docker.HostnameRunningComplement + remoteUserID := srv.UserID("user") remoteDisplayName := "my remote display name" srv.Mux().Handle("/_matrix/federation/v1/query/profile", http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { diff --git a/tests/federation_room_event_auth_test.go b/tests/federation_room_event_auth_test.go index 2777c5a1..5189a139 100644 --- a/tests/federation_room_event_auth_test.go +++ b/tests/federation_room_event_auth_test.go @@ -1,4 +1,5 @@ // These tests currently fail on Dendrite, due to Dendrite bugs. +//go:build !dendrite_blacklist // +build !dendrite_blacklist package tests @@ -125,7 +126,7 @@ func TestInboundFederationRejectsEventsWithRejectedAuthEvents(t *testing.T) { }) _, err := fedClient.SendTransaction(context.Background(), gomatrixserverlib.Transaction{ TransactionID: "complement1", - Origin: gomatrixserverlib.ServerName(srv.ServerName), + Origin: gomatrixserverlib.ServerName(srv.ServerName()), Destination: "hs1", OriginServerTS: gomatrixserverlib.AsTimestamp(time.Now()), PDUs: []json.RawMessage{ @@ -196,7 +197,7 @@ func TestInboundFederationRejectsEventsWithRejectedAuthEvents(t *testing.T) { _, err = fedClient.SendTransaction(context.Background(), gomatrixserverlib.Transaction{ TransactionID: "complement2", - Origin: gomatrixserverlib.ServerName(srv.ServerName), + Origin: gomatrixserverlib.ServerName(srv.ServerName()), Destination: "hs1", OriginServerTS: gomatrixserverlib.AsTimestamp(time.Now()), PDUs: []json.RawMessage{ diff --git a/tests/federation_room_get_missing_events_test.go b/tests/federation_room_get_missing_events_test.go index 6ce4b7f2..c0108335 100644 --- a/tests/federation_room_get_missing_events_test.go +++ b/tests/federation_room_get_missing_events_test.go @@ -92,7 +92,7 @@ func TestOutboundFederationIgnoresMissingEventWithBadJSONForRoomVersion6(t *test } eb.AuthEvents = room.AuthEvents(stateNeeded) // we have to create this event as a v5 event which doesn't assert floats yet - signedBadEvent, err := eb.Build(time.Now(), gomatrixserverlib.ServerName(srv.ServerName), srv.KeyID, srv.Priv, gomatrixserverlib.RoomVersionV5) + signedBadEvent, err := eb.Build(time.Now(), gomatrixserverlib.ServerName(srv.ServerName()), srv.KeyID, srv.Priv, gomatrixserverlib.RoomVersionV5) if err != nil { t.Fatalf("failed to sign event: %s", err) } diff --git a/tests/federation_room_join_test.go b/tests/federation_room_join_test.go index 743bfe8f..1db02be6 100644 --- a/tests/federation_room_join_test.go +++ b/tests/federation_room_join_test.go @@ -67,7 +67,7 @@ func TestJoinViaRoomIDAndServerName(t *testing.T) { serverRoom := srv.MustMakeRoom(t, ver, federation.InitialRoomEvents(ver, charlie)) // join the room by room ID, providing the serverName to join via - alice.JoinRoom(t, serverRoom.RoomID, []string{srv.ServerName}) + alice.JoinRoom(t, serverRoom.RoomID, []string{srv.ServerName()}) // remove the make/send join paths from the Complement server to force HS2 to join via HS1 acceptMakeSendJoinRequests = false @@ -290,7 +290,7 @@ func TestBannedUserCannotSendJoin(t *testing.T) { // ... and does a switcheroo to turn it into a join for himself makeJoinResp.JoinEvent.Sender = charlie makeJoinResp.JoinEvent.StateKey = &charlie - joinEvent, err := makeJoinResp.JoinEvent.Build(time.Now(), gomatrixserverlib.ServerName(srv.ServerName), srv.KeyID, srv.Priv, makeJoinResp.RoomVersion) + joinEvent, err := makeJoinResp.JoinEvent.Build(time.Now(), gomatrixserverlib.ServerName(srv.ServerName()), srv.KeyID, srv.Priv, makeJoinResp.RoomVersion) must.NotError(t, "JoinEvent.Build", err) // SendJoin should return a 403. diff --git a/tests/media_nofilename_test.go b/tests/media_nofilename_test.go index c50a1660..ebb038b5 100644 --- a/tests/media_nofilename_test.go +++ b/tests/media_nofilename_test.go @@ -77,7 +77,7 @@ func TestMediaWithoutFileName(t *testing.T) { t.Parallel() alice := deployment.Client(t, "hs1", userID) - b, ct := alice.DownloadContent(t, fmt.Sprintf("mxc://%s/%s", srv.ServerName, remoteMediaId)) + b, ct := alice.DownloadContent(t, fmt.Sprintf("mxc://%s/%s", srv.ServerName(), remoteMediaId)) // Check the Content-Type response header. // NOTSPEC: There is ambiguity over whether the homeserver is allowed to change the diff --git a/tests/msc2836_test.go b/tests/msc2836_test.go index e1336c43..327c8e78 100644 --- a/tests/msc2836_test.go +++ b/tests/msc2836_test.go @@ -1,3 +1,4 @@ +//go:build msc2836 // +build msc2836 package tests @@ -296,7 +297,7 @@ func TestFederatedEventRelationships(t *testing.T) { // join the room on HS1 // HS1 will not have any of these messages, only the room state. - alice.JoinRoom(t, room.RoomID, []string{srv.ServerName}) + alice.JoinRoom(t, room.RoomID, []string{srv.ServerName()}) // send a new child in the thread (child of D) so the HS has something to latch on to. eventE := srv.MustCreateEvent(t, room, b.Event{ @@ -315,7 +316,7 @@ func TestFederatedEventRelationships(t *testing.T) { fedClient := srv.FederationClient(deployment) _, err := fedClient.SendTransaction(context.Background(), gomatrixserverlib.Transaction{ TransactionID: "complement", - Origin: gomatrixserverlib.ServerName(srv.ServerName), + Origin: gomatrixserverlib.ServerName(srv.ServerName()), Destination: gomatrixserverlib.ServerName("hs1"), OriginServerTS: gomatrixserverlib.AsTimestamp(time.Now()), PDUs: []json.RawMessage{ diff --git a/tests/room_hierarchy_test.go b/tests/room_hierarchy_test.go index ab54d512..cbbb5157 100644 --- a/tests/room_hierarchy_test.go +++ b/tests/room_hierarchy_test.go @@ -1,3 +1,4 @@ +//go:build !dendrite_blacklist // +build !dendrite_blacklist // This file includes tests for MSC2946, the spaces summary API. From 28ce4cb6b76c73463cd3a925d9c6490f5e86295b Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Fri, 21 Jan 2022 17:39:16 +0000 Subject: [PATCH 02/20] Bind to localhost --- internal/federation/server.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/federation/server.go b/internal/federation/server.go index 7c096a7a..21fde8b3 100644 --- a/internal/federation/server.go +++ b/internal/federation/server.go @@ -316,7 +316,7 @@ func (s *Server) Listen() (cancel func()) { var wg sync.WaitGroup wg.Add(1) - ln, err := net.Listen("tcp", ":0") + ln, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { s.t.Fatalf("ListenFederationServer: net.Listen failed: %s", err) } From 0009ebf92ecd72fe93c3e2a07c1f0d7110366c2c Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Fri, 21 Jan 2022 17:46:44 +0000 Subject: [PATCH 03/20] Listen on all interfaces again as we need it to listen on Docker interfaces in CI --- internal/federation/server.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/federation/server.go b/internal/federation/server.go index 21fde8b3..fedab5f0 100644 --- a/internal/federation/server.go +++ b/internal/federation/server.go @@ -316,7 +316,7 @@ func (s *Server) Listen() (cancel func()) { var wg sync.WaitGroup wg.Add(1) - ln, err := net.Listen("tcp", "127.0.0.1:0") + ln, err := net.Listen("tcp", ":0") //nolint if err != nil { s.t.Fatalf("ListenFederationServer: net.Listen failed: %s", err) } From d04a03210e386231c7bc43aa30a639a7b18ab451 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Fri, 21 Jan 2022 18:22:01 +0000 Subject: [PATCH 04/20] Experimental support for Complement on ubuntu VM in GHA --- .github/workflows/ci.yaml | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 4baaebe6..2a083710 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -42,6 +42,18 @@ jobs: - /var/run/docker.sock:/var/run/docker.sock steps: + # TODO: Make a shell script to install all Complement deps and use that here and in the Dockerfile + # Exactly the same steps as dockerfiles/ComplementCIBuildkite.Dockerfile but on the host. We need + # to do this so we can _be_ the host when running Complement so we can snaffle all the ports. If + # we run Complement _in_ Docker then we can't -p all high numbered ports which then breaks federation + # servers which listen on random high numbered ports. + - run: | + echo "deb http://deb.debian.org/debian buster-backports main" > /etc/apt/sources.list.d/complement.list && add-apt-repository ppa:longsleep/golang-backports && apt-get update && apt-get install -y libolm3 golang-go libolm-dev/buster-backports + curl -fsSL https://get.docker.com -o get-docker.sh && sh get-docker.sh + wget https://github.com/matrix-org/complement/archive/master.tar.gz + tar -xzf master.tar.gz && cd complement-master && go mod download + cd complement-master && go get github.com/haveyoudebuggedit/gotestfmt/v2/cmd/gotestfmt@latest + - uses: actions/checkout@v2 - name: "Checkout corresponding ${{ matrix.homeserver }} branch" @@ -82,7 +94,7 @@ jobs: working-directory: homeserver - run: docker build -t homeserver -f dockerfiles/${{ matrix.homeserver }}.Dockerfile dockerfiles/ - - run: set -o pipefail && go test -p 2 -v -json -tags "${{ matrix.tags }}" ./tests/... 2>&1 | gotestfmt + - run: set -o pipefail && cd complement-master && go test -p 2 -v -json -tags "${{ matrix.tags }}" ./tests/... 2>&1 | gotestfmt shell: bash # required for pipefail to be A Thing. pipefail is required to stop gotestfmt swallowing non-zero exit codes env: COMPLEMENT_BASE_IMAGE: homeserver From 42218c003662f044f7d4e1a0687769e1b58a4065 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Fri, 21 Jan 2022 18:28:12 +0000 Subject: [PATCH 05/20] Tweak --- .github/workflows/ci.yaml | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 2a083710..9b8bc1a9 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -31,30 +31,20 @@ jobs: tags: msc2836 dendrite_blacklist default_branch: master - container: - image: matrixdotorg/complement # dockerfiles/ComplementCIBuildkite.Dockerfile - env: - CI: true - DOCKER_BUILDKIT: 1 - ports: - - 8448:8448 - volumes: - - /var/run/docker.sock:/var/run/docker.sock - steps: + - uses: actions/checkout@v2 + # TODO: Make a shell script to install all Complement deps and use that here and in the Dockerfile # Exactly the same steps as dockerfiles/ComplementCIBuildkite.Dockerfile but on the host. We need # to do this so we can _be_ the host when running Complement so we can snaffle all the ports. If # we run Complement _in_ Docker then we can't -p all high numbered ports which then breaks federation # servers which listen on random high numbered ports. - - run: | + - name: "Install Complement Dependencies" + run: | echo "deb http://deb.debian.org/debian buster-backports main" > /etc/apt/sources.list.d/complement.list && add-apt-repository ppa:longsleep/golang-backports && apt-get update && apt-get install -y libolm3 golang-go libolm-dev/buster-backports curl -fsSL https://get.docker.com -o get-docker.sh && sh get-docker.sh - wget https://github.com/matrix-org/complement/archive/master.tar.gz - tar -xzf master.tar.gz && cd complement-master && go mod download - cd complement-master && go get github.com/haveyoudebuggedit/gotestfmt/v2/cmd/gotestfmt@latest + go get github.com/haveyoudebuggedit/gotestfmt/v2/cmd/gotestfmt@latest - - uses: actions/checkout@v2 - name: "Checkout corresponding ${{ matrix.homeserver }} branch" # This is only done for Synapse since Dendrite's docker file pulls in From 8bc1538dee5a6c642899c63e84275dd84113b1ba Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Fri, 21 Jan 2022 18:33:32 +0000 Subject: [PATCH 06/20] More tweaking --- .github/workflows/ci.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 9b8bc1a9..19c27ebc 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -41,8 +41,7 @@ jobs: # servers which listen on random high numbered ports. - name: "Install Complement Dependencies" run: | - echo "deb http://deb.debian.org/debian buster-backports main" > /etc/apt/sources.list.d/complement.list && add-apt-repository ppa:longsleep/golang-backports && apt-get update && apt-get install -y libolm3 golang-go libolm-dev/buster-backports - curl -fsSL https://get.docker.com -o get-docker.sh && sh get-docker.sh + sudo echo "deb http://deb.debian.org/debian buster-backports main" > /etc/apt/sources.list.d/complement.list && sudo add-apt-repository ppa:longsleep/golang-backports && sudo apt-get update && sudo apt-get install -y libolm3 golang-go libolm-dev/buster-backports go get github.com/haveyoudebuggedit/gotestfmt/v2/cmd/gotestfmt@latest From f905479409def9b80a546fa4e8458d643b446ea0 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Fri, 21 Jan 2022 18:36:49 +0000 Subject: [PATCH 07/20] More tweaks --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 19c27ebc..f0832dfb 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -41,7 +41,7 @@ jobs: # servers which listen on random high numbered ports. - name: "Install Complement Dependencies" run: | - sudo echo "deb http://deb.debian.org/debian buster-backports main" > /etc/apt/sources.list.d/complement.list && sudo add-apt-repository ppa:longsleep/golang-backports && sudo apt-get update && sudo apt-get install -y libolm3 golang-go libolm-dev/buster-backports + sudo apt-get update && sudo apt-get install -y libolm3 golang-go libolm-dev/buster-backports go get github.com/haveyoudebuggedit/gotestfmt/v2/cmd/gotestfmt@latest From a4fc424f26e8fa675857b69490d42a57cd2a6f74 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Fri, 21 Jan 2022 18:39:21 +0000 Subject: [PATCH 08/20] More --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index f0832dfb..1fcb2d97 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -41,7 +41,7 @@ jobs: # servers which listen on random high numbered ports. - name: "Install Complement Dependencies" run: | - sudo apt-get update && sudo apt-get install -y libolm3 golang-go libolm-dev/buster-backports + sudo apt-get update && sudo apt-get install -y libolm3 golang-go go get github.com/haveyoudebuggedit/gotestfmt/v2/cmd/gotestfmt@latest From 22c5d321cf8e0db493683141c78b9f7aebf2c268 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Fri, 21 Jan 2022 18:48:37 +0000 Subject: [PATCH 09/20] Guessing at this point --- .github/workflows/ci.yaml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 1fcb2d97..78b4c183 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -41,7 +41,12 @@ jobs: # servers which listen on random high numbered ports. - name: "Install Complement Dependencies" run: | - sudo apt-get update && sudo apt-get install -y libolm3 golang-go + sudo apt-get update && sudo apt-get install -y libolm3 + sudo apt-get remove golang-go + wget https://dl.google.com/go/go1.16.4.linux-amd64.tar.gz + tar -xvf go1.16.4.linux-amd64.tar.gz + mv go /usr/local + export PATH=$PATH:/usr/local/go/bin go get github.com/haveyoudebuggedit/gotestfmt/v2/cmd/gotestfmt@latest @@ -83,7 +88,7 @@ jobs: working-directory: homeserver - run: docker build -t homeserver -f dockerfiles/${{ matrix.homeserver }}.Dockerfile dockerfiles/ - - run: set -o pipefail && cd complement-master && go test -p 2 -v -json -tags "${{ matrix.tags }}" ./tests/... 2>&1 | gotestfmt + - run: export PATH=$PATH:/usr/local/go/bin && set -o pipefail && cd complement-master && go test -p 2 -v -json -tags "${{ matrix.tags }}" ./tests/... 2>&1 | gotestfmt shell: bash # required for pipefail to be A Thing. pipefail is required to stop gotestfmt swallowing non-zero exit codes env: COMPLEMENT_BASE_IMAGE: homeserver From c8956441e2100053ac6ed7d0edc01dec9b888b9a Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Mon, 24 Jan 2022 12:51:50 +0000 Subject: [PATCH 10/20] Maybe --- .github/workflows/ci.yaml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 78b4c183..98368280 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -35,18 +35,16 @@ jobs: - uses: actions/checkout@v2 # TODO: Make a shell script to install all Complement deps and use that here and in the Dockerfile - # Exactly the same steps as dockerfiles/ComplementCIBuildkite.Dockerfile but on the host. We need + # Similar steps as dockerfiles/ComplementCIBuildkite.Dockerfile but on the host. We need # to do this so we can _be_ the host when running Complement so we can snaffle all the ports. If # we run Complement _in_ Docker then we can't -p all high numbered ports which then breaks federation # servers which listen on random high numbered ports. - name: "Install Complement Dependencies" + # We don't need to install Go because it is included on the Ubuntu 20.04 image: + # See https://github.com/actions/virtual-environments/blob/main/images/linux/Ubuntu2004-Readme.md specifically GOROOT_1_17_X64 run: | sudo apt-get update && sudo apt-get install -y libolm3 - sudo apt-get remove golang-go - wget https://dl.google.com/go/go1.16.4.linux-amd64.tar.gz - tar -xvf go1.16.4.linux-amd64.tar.gz - mv go /usr/local - export PATH=$PATH:/usr/local/go/bin + echo "$GOROOT_1_17_X64/bin" >> $GITHUB_PATH go get github.com/haveyoudebuggedit/gotestfmt/v2/cmd/gotestfmt@latest From f3bae9f42d15021ba1afc5d3576cd89ad09a7e98 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Mon, 24 Jan 2022 13:07:27 +0000 Subject: [PATCH 11/20] Modify GOROOT --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 98368280..174e4d0f 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -45,7 +45,7 @@ jobs: run: | sudo apt-get update && sudo apt-get install -y libolm3 echo "$GOROOT_1_17_X64/bin" >> $GITHUB_PATH - go get github.com/haveyoudebuggedit/gotestfmt/v2/cmd/gotestfmt@latest + GOROOT=$GOROOT_1_17_X64 go get github.com/haveyoudebuggedit/gotestfmt/v2/cmd/gotestfmt@latest - name: "Checkout corresponding ${{ matrix.homeserver }} branch" From 7b218ca05c8e529ecf6d85975db173ab7fe2df7a Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Mon, 24 Jan 2022 13:14:49 +0000 Subject: [PATCH 12/20] Set go version before running other complement install commands --- .github/workflows/ci.yaml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 174e4d0f..41288cd7 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -34,7 +34,11 @@ jobs: steps: - uses: actions/checkout@v2 - # TODO: Make a shell script to install all Complement deps and use that here and in the Dockerfile + # Env vars are set file a file given by $GITHUB_PATH + # See https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#adding-a-system-path + - name: "Set Go Version" + run: echo "$GOROOT_1_17_X64/bin" >> $GITHUB_PATH + # Similar steps as dockerfiles/ComplementCIBuildkite.Dockerfile but on the host. We need # to do this so we can _be_ the host when running Complement so we can snaffle all the ports. If # we run Complement _in_ Docker then we can't -p all high numbered ports which then breaks federation @@ -44,8 +48,7 @@ jobs: # See https://github.com/actions/virtual-environments/blob/main/images/linux/Ubuntu2004-Readme.md specifically GOROOT_1_17_X64 run: | sudo apt-get update && sudo apt-get install -y libolm3 - echo "$GOROOT_1_17_X64/bin" >> $GITHUB_PATH - GOROOT=$GOROOT_1_17_X64 go get github.com/haveyoudebuggedit/gotestfmt/v2/cmd/gotestfmt@latest + go get github.com/haveyoudebuggedit/gotestfmt/v2/cmd/gotestfmt@latest - name: "Checkout corresponding ${{ matrix.homeserver }} branch" From 5818ded01701e5e3b6eb9ba10acbcd7c980cd4bf Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Mon, 24 Jan 2022 13:20:32 +0000 Subject: [PATCH 13/20] Docstrings and BUILDKIT=1 --- .github/workflows/ci.yaml | 3 +++ internal/federation/server.go | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 41288cd7..0d6a3090 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -87,9 +87,12 @@ jobs: # built docker image). if: ${{ matrix.homeserver == 'Synapse' }} working-directory: homeserver + env: + DOCKER_BUILDKIT: 1 - run: docker build -t homeserver -f dockerfiles/${{ matrix.homeserver }}.Dockerfile dockerfiles/ - run: export PATH=$PATH:/usr/local/go/bin && set -o pipefail && cd complement-master && go test -p 2 -v -json -tags "${{ matrix.tags }}" ./tests/... 2>&1 | gotestfmt shell: bash # required for pipefail to be A Thing. pipefail is required to stop gotestfmt swallowing non-zero exit codes env: COMPLEMENT_BASE_IMAGE: homeserver + DOCKER_BUILDKIT: 1 diff --git a/internal/federation/server.go b/internal/federation/server.go index fedab5f0..92025a65 100644 --- a/internal/federation/server.go +++ b/internal/federation/server.go @@ -115,6 +115,12 @@ func NewServer(t *testing.T, deployment *docker.Deployment, opts ...func(*Server return srv } +// Return the server name of this federation server. Only valid AFTER calling Listen() - doing so +// before will produce an error. +// +// It is not supported to call ServerName() before Listen() because Listen() modifies the server name. +// Listen() will select a random OS-provided high-numbered port to listen on, which then needs to be +// retrofitted into the server name so containers know how to route to it. func (s *Server) ServerName() string { if !s.listening { s.t.Fatalf("ServerName() called before Listen() - this is not supported because Listen() chooses a high-numbered port and thus changes the server name. Ensure you Listen() first!") From 2588f7f2419a01f08b49f84578410eeb1f95be4b Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Mon, 24 Jan 2022 13:26:43 +0000 Subject: [PATCH 14/20] No need to cd complement-master --- .github/workflows/ci.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 0d6a3090..e3013d6c 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -91,7 +91,9 @@ jobs: DOCKER_BUILDKIT: 1 - run: docker build -t homeserver -f dockerfiles/${{ matrix.homeserver }}.Dockerfile dockerfiles/ - - run: export PATH=$PATH:/usr/local/go/bin && set -o pipefail && cd complement-master && go test -p 2 -v -json -tags "${{ matrix.tags }}" ./tests/... 2>&1 | gotestfmt + - run: | + set -o pipefail && + go test -p 2 -v -json -tags "${{ matrix.tags }}" ./tests/... 2>&1 | gotestfmt shell: bash # required for pipefail to be A Thing. pipefail is required to stop gotestfmt swallowing non-zero exit codes env: COMPLEMENT_BASE_IMAGE: homeserver From de07d492371777e759d395409cb54c98e5497350 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Mon, 24 Jan 2022 13:32:52 +0000 Subject: [PATCH 15/20] Add GOPATH --- .github/workflows/ci.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index e3013d6c..fcfb5c0e 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -37,7 +37,9 @@ jobs: # Env vars are set file a file given by $GITHUB_PATH # See https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#adding-a-system-path - name: "Set Go Version" - run: echo "$GOROOT_1_17_X64/bin" >> $GITHUB_PATH + run: | + echo "$GOROOT_1_17_X64/bin" >> $GITHUB_PATH + echo "~/go/bin" >> $GITHUB_PATH # Similar steps as dockerfiles/ComplementCIBuildkite.Dockerfile but on the host. We need # to do this so we can _be_ the host when running Complement so we can snaffle all the ports. If @@ -48,7 +50,7 @@ jobs: # See https://github.com/actions/virtual-environments/blob/main/images/linux/Ubuntu2004-Readme.md specifically GOROOT_1_17_X64 run: | sudo apt-get update && sudo apt-get install -y libolm3 - go get github.com/haveyoudebuggedit/gotestfmt/v2/cmd/gotestfmt@latest + go get -v github.com/haveyoudebuggedit/gotestfmt/v2/cmd/gotestfmt@latest - name: "Checkout corresponding ${{ matrix.homeserver }} branch" From 5788b06d15bf40b8c88e31dca649e545ad94da70 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Mon, 24 Jan 2022 13:39:14 +0000 Subject: [PATCH 16/20] Install libolm-dev; more docs --- .github/workflows/ci.yaml | 7 +++---- internal/federation/server.go | 10 ++++++---- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index fcfb5c0e..06e4f6cf 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -32,9 +32,9 @@ jobs: default_branch: master steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v2 # Checkout complement - # Env vars are set file a file given by $GITHUB_PATH + # Env vars are set file a file given by $GITHUB_PATH. We need both Go 1.17 and GOPATH on env. # See https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#adding-a-system-path - name: "Set Go Version" run: | @@ -49,10 +49,9 @@ jobs: # We don't need to install Go because it is included on the Ubuntu 20.04 image: # See https://github.com/actions/virtual-environments/blob/main/images/linux/Ubuntu2004-Readme.md specifically GOROOT_1_17_X64 run: | - sudo apt-get update && sudo apt-get install -y libolm3 + sudo apt-get update && sudo apt-get install -y libolm3 libolm-dev go get -v github.com/haveyoudebuggedit/gotestfmt/v2/cmd/gotestfmt@latest - - name: "Checkout corresponding ${{ matrix.homeserver }} branch" # This is only done for Synapse since Dendrite's docker file pulls in # the Dendrite sources directly. diff --git a/internal/federation/server.go b/internal/federation/server.go index 92025a65..1b97691d 100644 --- a/internal/federation/server.go +++ b/internal/federation/server.go @@ -60,10 +60,12 @@ func NewServer(t *testing.T, deployment *docker.Deployment, opts ...func(*Server } srv := &Server{ - t: t, - Priv: priv, - KeyID: "ed25519:complement", - mux: mux.NewRouter(), + t: t, + Priv: priv, + KeyID: "ed25519:complement", + mux: mux.NewRouter(), + // The server name will be updated when the caller calls Listen() to include the port number + // of the HTTP server e.g "host.docker.internal:56353" serverName: docker.HostnameRunningComplement, rooms: make(map[string]*ServerRoom), aliases: make(map[string]string), From e7bffa2e33737d0569444f9324699a75d8de4edb Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Mon, 24 Jan 2022 13:47:27 +0000 Subject: [PATCH 17/20] Say we're not running under CI --- .github/workflows/ci.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 06e4f6cf..dd6165ca 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -99,3 +99,4 @@ jobs: env: COMPLEMENT_BASE_IMAGE: homeserver DOCKER_BUILDKIT: 1 + CI: false # hacky hack hack to avoid talking to 172. addresses and assuming /ca/crt exists. We should remove this env var entirely From 0bdcc5172d2b0205740f23441046cfa88ad21e79 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Mon, 24 Jan 2022 15:50:48 +0000 Subject: [PATCH 18/20] Remove CI flag We don't need it anymore as CI does not run Complement inside Docker --- .github/workflows/ci.yaml | 2 +- internal/docker/builder.go | 10 --- internal/docker/volumes.go | 112 ++++------------------------------ internal/federation/server.go | 23 +++---- 4 files changed, 21 insertions(+), 126 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index dd6165ca..ee264b71 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -96,7 +96,7 @@ jobs: set -o pipefail && go test -p 2 -v -json -tags "${{ matrix.tags }}" ./tests/... 2>&1 | gotestfmt shell: bash # required for pipefail to be A Thing. pipefail is required to stop gotestfmt swallowing non-zero exit codes + name: Run Complement Tests env: COMPLEMENT_BASE_IMAGE: homeserver DOCKER_BUILDKIT: 1 - CI: false # hacky hack hack to avoid talking to 172. addresses and assuming /ca/crt exists. We should remove this env var entirely diff --git a/internal/docker/builder.go b/internal/docker/builder.go index 8bec0c4b..96557821 100644 --- a/internal/docker/builder.go +++ b/internal/docker/builder.go @@ -17,7 +17,6 @@ import ( "context" "fmt" "log" - "os" "strings" "time" @@ -39,15 +38,6 @@ var ( HostnameRunningDocker = "localhost" ) -func init() { - if os.Getenv("CI") == "true" { - log.Println("Running under CI: redirecting localhost to docker host on 172.17.0.1") - // this assumes we are running inside docker so they have - // forwarded the docker socket to us and we're in a container. - HostnameRunningDocker = "172.17.0.1" - } -} - const complementLabel = "complement_context" type Builder struct { diff --git a/internal/docker/volumes.go b/internal/docker/volumes.go index 0fc78cdc..0e06ee5d 100644 --- a/internal/docker/volumes.go +++ b/internal/docker/volumes.go @@ -1,13 +1,9 @@ package docker import ( - "bufio" "context" - "fmt" - "io/ioutil" "os" "path" - "strings" "github.com/docker/docker/api/types/mount" "github.com/docker/docker/api/types/volume" @@ -31,50 +27,21 @@ type VolumeCA struct { // Prepare the Certificate Authority volume. This is independent of the homeserver calling Prepare // hence the contextual string is unused. func (v *VolumeCA) Prepare(ctx context.Context, docker *client.Client, x string) error { - // TODO: wrap in a lockfile - if os.Getenv("CI") == "true" { - // When in CI, Complement itself is a container with the CA volume mounted at /ca. - // We need to mount this volume to all homeserver containers to synchronize the CA cert. - // This is needed to establish trust among all containers. - - containerID := getContainerID() - if containerID == "" { - return fmt.Errorf("failed to get container ID") - } - container, err := docker.ContainerInspect(ctx, containerID) - if err != nil { - return err - } - // Get the volume that matches the destination in our complement container - for i := range container.Mounts { - if container.Mounts[i].Destination == "/ca" { - v.source = container.Mounts[i].Name - v.typ = container.Mounts[i].Type - break - } - } - if v.source == "" { - // We did not find a volume. This container might be created without a volume, - // or CI=true is passed but we are not running in a container. - return fmt.Errorf("CI=true but there is no /ca mounted to Complement's container") - } - } else { - // When not in CI, our CA cert is placed in the current working dir. - // We bind mount this directory to all homeserver containers. - cwd, err := os.Getwd() + // Our CA cert is placed in the current working dir. + // We bind mount this directory to all homeserver containers. + cwd, err := os.Getwd() + if err != nil { + return err + } + caCertificateDirHost := path.Join(cwd, "ca") + if _, err := os.Stat(caCertificateDirHost); os.IsNotExist(err) { + err = os.Mkdir(caCertificateDirHost, 0770) if err != nil { return err } - caCertificateDirHost := path.Join(cwd, "ca") - if _, err := os.Stat(caCertificateDirHost); os.IsNotExist(err) { - err = os.Mkdir(caCertificateDirHost, 0770) - if err != nil { - return err - } - } - v.source = path.Join(cwd, "ca") - v.typ = mount.TypeBind } + v.source = path.Join(cwd, "ca") + v.typ = mount.TypeBind return nil } @@ -108,60 +75,3 @@ func (v *VolumeAppService) Mount() mount.Mount { Target: "/appservices", } } - -func getContainerID() string { - cid, err := getContainerIDViaCPUSet() - if err == nil { - return cid - } - fmt.Printf("failed to get container ID via cpuset, trying alternatives: %s\n", err) - - cid, err = getContainerIDViaCGroups() - if err == nil { - return cid - } - - fmt.Printf("failed to get container ID via cgroups, out of options: %s\n", err) - return "" -} - -func getContainerIDViaCGroups() (string, error) { - file, err := os.Open("/proc/self/cgroup") - if err != nil { - return "", err - } - - scanner := bufio.NewScanner(file) - defer file.Close() - - scanner.Split(bufio.ScanLines) - for scanner.Scan() { - // Returns entries like this on github actions - // 9:memory:/actions_job/c8d555525bad6cd896c5aa985ef68010be47b1fb321c95547761c8f1a053b86e - line := scanner.Text() - segments := strings.Split(line, "/") - containerID := segments[len(segments)-1] - if containerID == "" || len(containerID) < 64 { - continue - } - return containerID, nil - } - return "", fmt.Errorf("faild to find container id in cgroups") -} - -func getContainerIDViaCPUSet() (string, error) { - // /proc/1/cpuset should be /docker/ - cpuset, err := ioutil.ReadFile("/proc/1/cpuset") - if err != nil { - return "", err - } - if !strings.Contains(string(cpuset), "docker") { - return "", fmt.Errorf("could not identify container ID using /proc/1/cpuset - cpuset=%s", string(cpuset)) - } - cpusetList := strings.Split(strings.TrimSpace(string(cpuset)), "/") - containerID := cpusetList[len(cpusetList)-1] - if len(containerID) == 0 { - return "", fmt.Errorf("cpuset missing container ID") - } - return containerID, nil -} diff --git a/internal/federation/server.go b/internal/federation/server.go index 1b97691d..a8804cc6 100644 --- a/internal/federation/server.go +++ b/internal/federation/server.go @@ -358,24 +358,19 @@ func (s *Server) Listen() (cancel func()) { // This basically acts as a test only valid PKI. func GetOrCreateCaCert() (*x509.Certificate, *rsa.PrivateKey, error) { var tlsCACertPath, tlsCAKeyPath string - if os.Getenv("CI") == "true" { - // When in CI we create the cert dir in the root directory instead. - tlsCACertPath = path.Join("/ca", "ca.crt") - tlsCAKeyPath = path.Join("/ca", "ca.key") - } else { - wd, err := os.Getwd() + wd, err := os.Getwd() + if err != nil { + return nil, nil, err + } + tlsCACertPath = path.Join(wd, "ca", "ca.crt") + tlsCAKeyPath = path.Join(wd, "ca", "ca.key") + if _, err := os.Stat(path.Join(wd, "ca")); os.IsNotExist(err) { + err = os.Mkdir(path.Join(wd, "ca"), 0770) if err != nil { return nil, nil, err } - tlsCACertPath = path.Join(wd, "ca", "ca.crt") - tlsCAKeyPath = path.Join(wd, "ca", "ca.key") - if _, err := os.Stat(path.Join(wd, "ca")); os.IsNotExist(err) { - err = os.Mkdir(path.Join(wd, "ca"), 0770) - if err != nil { - return nil, nil, err - } - } } + if _, err := os.Stat(tlsCACertPath); err == nil { if _, err := os.Stat(tlsCAKeyPath); err == nil { // We already created a CA cert, let's use that. From 66a9024ac4e049c12601fd6a635d49f3d8273b81 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Mon, 24 Jan 2022 15:54:37 +0000 Subject: [PATCH 19/20] Shadow lint --- internal/federation/server.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/federation/server.go b/internal/federation/server.go index a8804cc6..84a86749 100644 --- a/internal/federation/server.go +++ b/internal/federation/server.go @@ -364,15 +364,15 @@ func GetOrCreateCaCert() (*x509.Certificate, *rsa.PrivateKey, error) { } tlsCACertPath = path.Join(wd, "ca", "ca.crt") tlsCAKeyPath = path.Join(wd, "ca", "ca.key") - if _, err := os.Stat(path.Join(wd, "ca")); os.IsNotExist(err) { + if _, err = os.Stat(path.Join(wd, "ca")); os.IsNotExist(err) { err = os.Mkdir(path.Join(wd, "ca"), 0770) if err != nil { return nil, nil, err } } - if _, err := os.Stat(tlsCACertPath); err == nil { - if _, err := os.Stat(tlsCAKeyPath); err == nil { + if _, err = os.Stat(tlsCACertPath); err == nil { + if _, err = os.Stat(tlsCAKeyPath); err == nil { // We already created a CA cert, let's use that. dat, err := ioutil.ReadFile(tlsCACertPath) if err != nil { From 835bf7f74c318ea2afd61477f6d959b318e185d0 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Mon, 24 Jan 2022 16:02:29 +0000 Subject: [PATCH 20/20] Fix shadowing --- internal/federation/server.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/internal/federation/server.go b/internal/federation/server.go index 84a86749..ed828668 100644 --- a/internal/federation/server.go +++ b/internal/federation/server.go @@ -374,7 +374,8 @@ func GetOrCreateCaCert() (*x509.Certificate, *rsa.PrivateKey, error) { if _, err = os.Stat(tlsCACertPath); err == nil { if _, err = os.Stat(tlsCAKeyPath); err == nil { // We already created a CA cert, let's use that. - dat, err := ioutil.ReadFile(tlsCACertPath) + var dat []byte + dat, err = ioutil.ReadFile(tlsCACertPath) if err != nil { return nil, nil, err } @@ -382,7 +383,8 @@ func GetOrCreateCaCert() (*x509.Certificate, *rsa.PrivateKey, error) { if block == nil || block.Type != "CERTIFICATE" { return nil, nil, errors.New("ca.crt is not a valid pem encoded x509 cert") } - caCerts, err := x509.ParseCertificates(block.Bytes) + var caCerts []*x509.Certificate + caCerts, err = x509.ParseCertificates(block.Bytes) if err != nil { return nil, nil, err } @@ -398,7 +400,8 @@ func GetOrCreateCaCert() (*x509.Certificate, *rsa.PrivateKey, error) { if block == nil || block.Type != "RSA PRIVATE KEY" { return nil, nil, errors.New("ca.key is not a valid pem encoded rsa private key") } - priv, err := x509.ParsePKCS1PrivateKey(block.Bytes) + var priv *rsa.PrivateKey + priv, err = x509.ParsePKCS1PrivateKey(block.Bytes) if err != nil { return nil, nil, err }