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
8 changes: 7 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -607,4 +607,10 @@ upload-bombon:
.PHONY: openapi-validate
openapi-validate:
@echo -e "Make sure you are running the backend in another terminal (make cr)\n"
vacuum lint -a -d -w <(curl http://localhost:8082/v7/api/swagger.json)
vacuum lint -a -d -e <(curl http://localhost:8082/v7/api/swagger.json)
# vacuum lint -a -d -e <(curl http://localhost:8082/api-internal/swagger-ui/cannon-swagger.json)
# vacuum lint -a -d -e <(curl http://localhost:8082/api-internal/swagger-ui/cargohold-swagger.json)
# vacuum lint -a -d -e <(curl http://localhost:8082/api-internal/swagger-ui/spar-swagger.json)
# vacuum lint -a -d -e <(curl http://localhost:8082/api-internal/swagger-ui/gundeck-swagger.json)
# vacuum lint -a -d -e <(curl http://localhost:8082/api-internal/swagger-ui/brig-swagger.json)
# vacuum lint -a -d -e <(curl http://localhost:8082/api-internal/swagger-ui/galley-swagger.json)
2 changes: 1 addition & 1 deletion changelog.d/4-docs/openapi-validation
Original file line number Diff line number Diff line change
@@ -1 +1 @@
Fix openapi validation errors
Fix openapi validation errors (#4295, ##)
1 change: 1 addition & 0 deletions changelog.d/5-internal/openapi-validation
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add openapi validation test to integration
9 changes: 5 additions & 4 deletions charts/nginz/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,10 @@ nginx_conf:
envs:
- all
doc: true
- path: /handles
envs:
- all
doc: true
- path: /list-users
envs:
- all
Expand Down Expand Up @@ -291,9 +295,6 @@ nginx_conf:
- path: /bot/users
envs:
- all
- path: /conversations/([^/]*)/bots
envs:
- all
- path: /invitations/info
envs:
- all
Expand Down Expand Up @@ -479,7 +480,7 @@ nginx_conf:
- all
max_body_size: 40m
body_buffer_size: 256k
- path: /conversations/one2one/
- path: /one2one-conversations/
envs:
- all
# During MLS migration, this endpoint gets called _a lot_.
Expand Down
2 changes: 1 addition & 1 deletion integration/test/API/Brig.hs
Original file line number Diff line number Diff line change
Expand Up @@ -682,7 +682,7 @@ getCallsConfigV2 user = do

addBot :: (HasCallStack, MakesValue user) => user -> String -> String -> String -> App Response
addBot user providerId serviceId convId = do
req <- baseRequest user Brig Versioned $ joinHttpPath ["conversations", convId, "bots"]
req <- baseRequest user Brig Versioned $ joinHttpPath ["bot", "conversations", convId]
submit "POST" $
req
& zType "access"
Expand Down
14 changes: 13 additions & 1 deletion integration/test/API/Galley.hs
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,18 @@ deleteTeamConv team conv user = do
req <- baseRequest user Galley Versioned (joinHttpPath ["teams", teamId, "conversations", convId])
submit "DELETE" req

getMLSOne2OneConversationLegacy ::
(HasCallStack, MakesValue self, MakesValue other) =>
self ->
other ->
App Response
getMLSOne2OneConversationLegacy self other = do
(domain, uid) <- objQid other
req <-
baseRequest self Galley Versioned
$ joinHttpPath ["conversations", "one2one", domain, uid]
submit "GET" req

getMLSOne2OneConversation ::
(HasCallStack, MakesValue self, MakesValue other) =>
self ->
Expand All @@ -336,7 +348,7 @@ getMLSOne2OneConversation self other = do
(domain, uid) <- objQid other
req <-
baseRequest self Galley Versioned
$ joinHttpPath ["conversations", "one2one", domain, uid]
$ joinHttpPath ["one2one-conversations", domain, uid]
submit "GET" req

getGroupClients ::
Expand Down
1 change: 0 additions & 1 deletion integration/test/Test/Bot.hs
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,6 @@ onBotCreate chan _headers _req k = do
onBotMessage chan _headers req k = do
body <- liftIO $ Wai.strictRequestBody req
writeChan chan (BotMessage (cs body))
liftIO $ putStrLn $ cs body
k (responseLBS status200 mempty mempty)
onBotAlive _chan _headers _req k = do
k (responseLBS status200 mempty (cs "success"))
14 changes: 7 additions & 7 deletions integration/test/Test/MLS/One2One.hs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ testGetMLSOne2OneLocalV5 = withVersion5 Version5 $ do
conv %. "cipher_suite" `shouldMatchInt` 1

convId <-
getMLSOne2OneConversation alice bob `bindResponse` \resp -> do
getMLSOne2OneConversationLegacy alice bob `bindResponse` \resp -> do
conv <- getJSON 200 resp
conv %. "type" `shouldMatchInt` 2
shouldBeEmpty (conv %. "members.others")
Expand All @@ -53,7 +53,7 @@ testGetMLSOne2OneLocalV5 = withVersion5 Version5 $ do
conv %. "qualified_id"

-- check that the conversation has the same ID on the other side
conv2 <- bindResponse (getMLSOne2OneConversation bob alice) $ \resp -> do
conv2 <- bindResponse (getMLSOne2OneConversationLegacy bob alice) $ \resp -> do
resp.status `shouldMatchInt` 200
resp.json

Expand All @@ -64,11 +64,11 @@ testGetMLSOne2OneLocalV5 = withVersion5 Version5 $ do
testGetMLSOne2OneRemoteV5 :: (HasCallStack) => App ()
testGetMLSOne2OneRemoteV5 = withVersion5 Version5 $ do
[alice, bob] <- createAndConnectUsers [OwnDomain, OtherDomain]
getMLSOne2OneConversation alice bob `bindResponse` \resp -> do
getMLSOne2OneConversationLegacy alice bob `bindResponse` \resp -> do
resp.status `shouldMatchInt` 400
resp.jsonBody %. "label" `shouldMatch` "mls-federated-one2one-not-supported"

getMLSOne2OneConversation bob alice `bindResponse` \resp -> do
getMLSOne2OneConversationLegacy bob alice `bindResponse` \resp -> do
resp.status `shouldMatchInt` 400
resp.jsonBody %. "label" `shouldMatch` "mls-federated-one2one-not-supported"

Expand Down Expand Up @@ -149,7 +149,7 @@ testMLSOne2OneOtherMember scenario = do
testMLSOne2OneRemoveClientLocalV5 :: App ()
testMLSOne2OneRemoveClientLocalV5 = withVersion5 Version5 $ do
[alice, bob] <- createAndConnectUsers [OwnDomain, OwnDomain]
conv <- getMLSOne2OneConversation alice bob >>= getJSON 200
conv <- getMLSOne2OneConversationLegacy alice bob >>= getJSON 200

[alice1, bob1] <- traverse (createMLSClient def) [alice, bob]
traverse_ uploadNewKeyPackage [bob1]
Expand Down Expand Up @@ -416,7 +416,7 @@ testMLSFederationV1ConvOnOldBackend = do
fedError <- getJSON 533 resp
fedError %. "label" `shouldMatch` "federation-version-error"

conv <- getMLSOne2OneConversation bob alice >>= getJSON 200
conv <- getMLSOne2OneConversationLegacy bob alice >>= getJSON 200
keys <- getMLSPublicKeys bob >>= getJSON 200
resetOne2OneGroupGeneric bob1 conv keys

Expand Down Expand Up @@ -464,7 +464,7 @@ testMLSFederationV1ConvOnNewBackend = do

-- Bob cannot start this conversation because it would exist on Alice's
-- backend and Bob cannot get the MLS public keys of that backend.
getMLSOne2OneConversation bob alice `bindResponse` \resp -> do
getMLSOne2OneConversationLegacy bob alice `bindResponse` \resp -> do
fedError <- getJSON 533 resp
fedError %. "label" `shouldMatch` "federation-remote-error"

Expand Down
27 changes: 27 additions & 0 deletions integration/test/Test/Swagger.hs
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
module Test.Swagger where

import qualified API.Brig as BrigP
import qualified Data.ByteString as B
import qualified Data.Set as Set
import Data.String.Conversions
import GHC.Stack
import System.Exit
import System.FilePath
import System.Process
import Testlib.Assertions
import Testlib.Prelude
import UnliftIO.Temporary

existingVersions :: Set Int
existingVersions = Set.fromList [0, 1, 2, 3, 4, 5, 6, 7]
Expand Down Expand Up @@ -80,3 +85,25 @@ testSwaggerToc = do

html :: String
html = "<html><head></head><body><h2>please pick an api version</h2><a href=\"/v0/api/swagger-ui/\">/v0/api/swagger-ui/</a><br><a href=\"/v1/api/swagger-ui/\">/v1/api/swagger-ui/</a><br><a href=\"/v2/api/swagger-ui/\">/v2/api/swagger-ui/</a><br><a href=\"/v3/api/swagger-ui/\">/v3/api/swagger-ui/</a><br><a href=\"/v4/api/swagger-ui/\">/v4/api/swagger-ui/</a><br><a href=\"/v5/api/swagger-ui/\">/v5/api/swagger-ui/</a><br><a href=\"/v6/api/swagger-ui/\">/v6/api/swagger-ui/</a><br><a href=\"/v7/api/swagger-ui/\">/v7/api/swagger-ui/</a><br></body>"

-- | This runs the swagger linter [vacuum](https://quobix.com/vacuum/).
--
-- The reason for adding the linter in the integration tests, and not in the lint job, is that
-- it calls brig for the swagger docs it validates, but no running brig during linting.
--
-- There is also a make rule that does this, for convenience in your develop
-- flow. Make sure that brig is running before using the make rule.
testSwaggerLint :: (HasCallStack) => App ()
testSwaggerLint = do
withSystemTempDirectory "swagger" $ \tmp -> do
req <- baseRequest OwnDomain Brig Versioned $ joinHttpPath ["api", "swagger.json"]
swagger <- submit "GET" req >>= getBody 200
liftIO $ B.writeFile (tmp </> "swagger.json") swagger
let cmd = shell $ "vacuum lint -a -d -e " <> (tmp </> "swagger.json")
(exitCode, out, err) <- liftIO $ readCreateProcessWithExitCode cmd ""
case exitCode of
ExitSuccess -> pure ()
_ -> do
liftIO $ putStrLn out
liftIO $ putStrLn err
assertFailure "swagger validation errors"
107 changes: 62 additions & 45 deletions libs/wire-api/src/Wire/API/Routes/Internal/Brig.hs
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,14 @@ module Wire.API.Routes.Internal.Brig
GetAccountConferenceCallingConfig,
PutAccountConferenceCallingConfig,
DeleteAccountConferenceCallingConfig,
GetRichInfoMultiResponse (..),
swaggerDoc,
module Wire.API.Routes.Internal.Brig.EJPD,
FoundInvitationCode (..),
)
where

import Control.Lens ((.~))
import Control.Lens ((.~), (?~))
import Data.Aeson (FromJSON, ToJSON)
import Data.Code qualified as Code
import Data.CommaSeparatedList
Expand Down Expand Up @@ -71,7 +72,6 @@ import Wire.API.Routes.Internal.Brig.EJPD
import Wire.API.Routes.Internal.Brig.OAuth (OAuthAPI)
import Wire.API.Routes.Internal.Brig.SearchIndex (ISearchIndexAPI)
import Wire.API.Routes.Internal.Galley.TeamFeatureNoConfigMulti qualified as Multi
import Wire.API.Routes.Internal.LegalHold qualified as LegalHoldInternalAPI
import Wire.API.Routes.MultiVerb
import Wire.API.Routes.Named
import Wire.API.Routes.Public (ZUser)
Expand All @@ -90,22 +90,25 @@ import Wire.API.User.Client
import Wire.API.User.RichInfo

type EJPDRequest =
Summary
"Identify users for law enforcement. Wire has legal requirements to cooperate \
\with the authorities. The wire backend operations team uses this to answer \
\identification requests manually. It is our best-effort representation of the \
\minimum required information we need to hand over about targets and (in some \
\cases) their communication peers. For more information, consult ejpd.admin.ch."
:> "ejpd-request"
:> QueryParam'
[ Optional,
Strict,
Description "Also provide information about all contacts of the identified users"
]
"include_contacts"
Bool
:> Servant.ReqBody '[Servant.JSON] EJPDRequestBody
:> Post '[Servant.JSON] EJPDResponseBody
Named
"ejpd-request"
( Summary
"Identify users for law enforcement. Wire has legal requirements to cooperate \
\with the authorities. The wire backend operations team uses this to answer \
\identification requests manually. It is our best-effort representation of the \
\minimum required information we need to hand over about targets and (in some \
\cases) their communication peers. For more information, consult ejpd.admin.ch."
:> "ejpd-request"
:> QueryParam'
[ Optional,
Strict,
Description "Also provide information about all contacts of the identified users"
]
"include_contacts"
Bool
:> Servant.ReqBody '[Servant.JSON] EJPDRequestBody
:> Post '[Servant.JSON] EJPDResponseBody
)

type GetAccountConferenceCallingConfig =
Summary
Expand Down Expand Up @@ -159,10 +162,10 @@ type GetAllConnections =

type AccountAPI =
Named "get-account-conference-calling-config" GetAccountConferenceCallingConfig
:<|> PutAccountConferenceCallingConfig
:<|> DeleteAccountConferenceCallingConfig
:<|> GetAllConnectionsUnqualified
:<|> GetAllConnections
:<|> Named "i-put-account-conference-calling-config" PutAccountConferenceCallingConfig
:<|> Named "i-delete-account-conference-calling-config" DeleteAccountConferenceCallingConfig
:<|> Named "i-get-all-connections-unqualified" GetAllConnectionsUnqualified
:<|> Named "i-get-all-connections" GetAllConnections
:<|> Named
"createUserNoVerify"
-- This endpoint can lead to the following events being sent:
Expand Down Expand Up @@ -373,12 +376,11 @@ type AccountAPI =
( "users"
:> "rich-info"
:> QueryParam' '[Optional, Strict] "ids" (CommaSeparatedList UserId)
:> Get '[Servant.JSON] [(UserId, RichInfo)]
:> Get '[Servant.JSON] GetRichInfoMultiResponse
)
:<|> Named
"iHeadHandle"
( CanThrow 'InvalidHandle
:> "users"
:> "handles"
:> Capture "handle" Handle
:> MultiVerb
Expand Down Expand Up @@ -466,23 +468,29 @@ instance ToSchema NewKeyPackageRef where
type MLSAPI = "mls" :> GetMLSClients

type GetMLSClients =
Summary "Return all clients and all MLS-capable clients of a user"
:> "clients"
:> CanThrow 'UserNotFound
:> Capture "user" UserId
:> QueryParam' '[Required, Strict] "ciphersuite" CipherSuite
:> MultiVerb1
'GET
'[Servant.JSON]
(Respond 200 "MLS clients" (Set ClientInfo))
Named
"get-mls-clients"
( Summary "Return all clients and all MLS-capable clients of a user"
:> "clients"
:> CanThrow 'UserNotFound
:> Capture "user" UserId
:> QueryParam' '[Required, Strict] "ciphersuite" CipherSuite
:> MultiVerb1
'GET
'[Servant.JSON]
(Respond 200 "MLS clients" (Set ClientInfo))
)

type GetVerificationCode =
Summary "Get verification code for a given email and action"
:> "users"
:> Capture "uid" UserId
:> "verification-code"
:> Capture "action" VerificationAction
:> Get '[Servant.JSON] (Maybe Code.Value)
Named
"get-verification-code"
( Summary "Get verification code for a given email and action"
:> "users"
:> Capture "uid" UserId
:> "verification-code"
:> Capture "action" VerificationAction
:> Get '[Servant.JSON] (Maybe Code.Value)
)

type API =
"i"
Expand Down Expand Up @@ -594,9 +602,9 @@ type TeamInvitations =
)

type UserAPI =
UpdateUserLocale
:<|> DeleteUserLocale
:<|> GetDefaultLocale
Named "i-update-user-locale" UpdateUserLocale
:<|> Named "i-delete-user-locale" DeleteUserLocale
:<|> Named "i-get-default-locale" GetDefaultLocale
:<|> Named
"get-user-export-data"
( Summary "Get user export data"
Expand Down Expand Up @@ -745,10 +753,19 @@ type ProviderAPI =
type FederationRemotesAPIDescription =
"See https://docs.wire.com/understand/federation/backend-communication.html#configuring-remote-connections for background. "

newtype GetRichInfoMultiResponse
= GetRichInfoMultiResponse
[(UserId, RichInfo)]
deriving newtype (FromJSON, ToJSON)

instance S.ToSchema GetRichInfoMultiResponse where
declareNamedSchema _ =
pure $
S.NamedSchema (Just $ "GetRichInfoMultiResponse") $
mempty & S.description ?~ "List of pairs of UserId and RichInfo"

swaggerDoc :: OpenApi
swaggerDoc =
brigSwaggerDoc
<> LegalHoldInternalAPI.swaggerDoc
swaggerDoc = brigSwaggerDoc

brigSwaggerDoc :: OpenApi
brigSwaggerDoc =
Expand Down
4 changes: 2 additions & 2 deletions libs/wire-api/src/Wire/API/Routes/Internal/Cargohold.hs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ import Wire.API.Routes.Named

type InternalAPI =
"i"
:> ( "status" :> MultiVerb 'GET '() '[RespondEmpty 200 "OK"] ()
:<|> Named "iGetAsset" ("assets" :> Capture "key" AssetKey :> Get '[Servant.JSON] Text)
:> ( Named "i_status" ("status" :> MultiVerb 'GET '() '[RespondEmpty 200 "OK"] ())
:<|> Named "i_get_asset" ("assets" :> Capture "key" AssetKey :> Get '[Servant.JSON] Text)
)

swaggerDoc :: OpenApi
Expand Down
Loading