mirror of
https://github.com/unisonweb/unison.git
synced 2024-09-21 07:17:25 +03:00
Merge branch 'trunk' into work/io-sandboxing
This commit is contained in:
commit
d1ae70a48c
@ -64,3 +64,4 @@ The format for this list: name, GitHub handle, and then optional blurb about wha
|
||||
* Shawn Bachlet (@shawn-bachlet)
|
||||
* Solomon Bothwell (@solomon-b)
|
||||
* Sameer Kolhar (@kolharsam)
|
||||
* Nicole Prindle (@nprindle)
|
||||
|
@ -526,6 +526,15 @@ renderTypeError e env src = case e of
|
||||
[Type.var () (Var.named "e"), Type.var () (Var.named "a") ])
|
||||
(Type.var () (Var.named "o"))
|
||||
|
||||
Other (C.cause -> C.PatternArityMismatch loc typ num) ->
|
||||
Pr.lines [
|
||||
Pr.wrap "This pattern has the wrong number of arguments", "",
|
||||
annotatedAsErrorSite src loc,
|
||||
"The constructor has type ", "",
|
||||
Pr.indentN 2 (stylePretty Type1 (Pr.group (renderType' env typ))), "",
|
||||
"but you supplied " <> (Pr.shown num) <> " arguments."
|
||||
]
|
||||
|
||||
Other note -> mconcat
|
||||
[ "Sorry, you hit an error we didn't make a nice message for yet.\n\n"
|
||||
, "Here is a summary of the Note:\n"
|
||||
@ -589,52 +598,53 @@ renderTypeError e env src = case e of
|
||||
, " "
|
||||
, simpleCause (C.cause note)
|
||||
, "\n"
|
||||
, case toList (C.path note) of
|
||||
[] -> " path: (empty)\n"
|
||||
l -> " path:\n" <> mconcat (simplePath <$> l)
|
||||
-- This can be very slow to print in large file. This was taking several minutes to print out the path in a file when the error occurred deep in the file after many other let bindings - stew
|
||||
-- , case toList (C.path note) of
|
||||
-- [] -> " path: (empty)\n"
|
||||
-- l -> " path:\n" <> mconcat (simplePath <$> l)
|
||||
]
|
||||
simplePath :: C.PathElement v loc -> Pretty ColorText
|
||||
simplePath e = " " <> simplePath' e <> "\n"
|
||||
simplePath' :: C.PathElement v loc -> Pretty ColorText
|
||||
simplePath' = \case
|
||||
C.InSynthesize e -> "InSynthesize e=" <> renderTerm env e
|
||||
C.InEquate t1 t2 ->
|
||||
"InEquate t1=" <> renderType' env t1 <>
|
||||
", t2=" <> renderType' env t2
|
||||
C.InSubtype t1 t2 ->
|
||||
"InSubtype t1=" <> renderType' env t1 <> ", t2=" <> renderType' env t2
|
||||
C.InCheck e t ->
|
||||
"InCheck e=" <> renderTerm env e <> "," <> " t=" <> renderType' env t
|
||||
C.InInstantiateL v t ->
|
||||
"InInstantiateL v=" <> renderVar v <> ", t=" <> renderType' env t
|
||||
C.InInstantiateR t v ->
|
||||
"InInstantiateR t=" <> renderType' env t <> " v=" <> renderVar v
|
||||
C.InSynthesizeApp t e n ->
|
||||
"InSynthesizeApp t="
|
||||
<> renderType' env t
|
||||
<> ", e="
|
||||
<> renderTerm env e
|
||||
<> ", n="
|
||||
<> fromString (show n)
|
||||
C.InFunctionCall vs f ft es ->
|
||||
"InFunctionCall vs=["
|
||||
<> commas renderVar vs
|
||||
<> "]"
|
||||
<> ", f="
|
||||
<> renderTerm env f
|
||||
<> ", ft="
|
||||
<> renderType' env ft
|
||||
<> ", es=["
|
||||
<> commas (renderTerm env) es
|
||||
<> "]"
|
||||
C.InIfCond -> "InIfCond"
|
||||
C.InIfBody loc -> "InIfBody thenBody=" <> annotatedToEnglish loc
|
||||
C.InAndApp -> "InAndApp"
|
||||
C.InOrApp -> "InOrApp"
|
||||
C.InVectorApp loc -> "InVectorApp firstTerm=" <> annotatedToEnglish loc
|
||||
C.InMatch loc -> "InMatch firstBody=" <> annotatedToEnglish loc
|
||||
C.InMatchGuard -> "InMatchGuard"
|
||||
C.InMatchBody -> "InMatchBody"
|
||||
-- simplePath :: C.PathElement v loc -> Pretty ColorText
|
||||
-- simplePath e = " " <> simplePath' e <> "\n"
|
||||
-- simplePath' :: C.PathElement v loc -> Pretty ColorText
|
||||
-- simplePath' = \case
|
||||
-- C.InSynthesize e -> "InSynthesize e=" <> renderTerm env e
|
||||
-- C.InEquate t1 t2 ->
|
||||
-- "InEquate t1=" <> renderType' env t1 <>
|
||||
-- ", t2=" <> renderType' env t2
|
||||
-- C.InSubtype t1 t2 ->
|
||||
-- "InSubtype t1=" <> renderType' env t1 <> ", t2=" <> renderType' env t2
|
||||
-- C.InCheck e t ->
|
||||
-- "InCheck e=" <> renderTerm env e <> "," <> " t=" <> renderType' env t
|
||||
-- C.InInstantiateL v t ->
|
||||
-- "InInstantiateL v=" <> renderVar v <> ", t=" <> renderType' env t
|
||||
-- C.InInstantiateR t v ->
|
||||
-- "InInstantiateR t=" <> renderType' env t <> " v=" <> renderVar v
|
||||
-- C.InSynthesizeApp t e n ->
|
||||
-- "InSynthesizeApp t="
|
||||
-- <> renderType' env t
|
||||
-- <> ", e="
|
||||
-- <> renderTerm env e
|
||||
-- <> ", n="
|
||||
-- <> fromString (show n)
|
||||
-- C.InFunctionCall vs f ft es ->
|
||||
-- "InFunctionCall vs=["
|
||||
-- <> commas renderVar vs
|
||||
-- <> "]"
|
||||
-- <> ", f="
|
||||
-- <> renderTerm env f
|
||||
-- <> ", ft="
|
||||
-- <> renderType' env ft
|
||||
-- <> ", es=["
|
||||
-- <> commas (renderTerm env) es
|
||||
-- <> "]"
|
||||
-- C.InIfCond -> "InIfCond"
|
||||
-- C.InIfBody loc -> "InIfBody thenBody=" <> annotatedToEnglish loc
|
||||
-- C.InAndApp -> "InAndApp"
|
||||
-- C.InOrApp -> "InOrApp"
|
||||
-- C.InVectorApp loc -> "InVectorApp firstTerm=" <> annotatedToEnglish loc
|
||||
-- C.InMatch loc -> "InMatch firstBody=" <> annotatedToEnglish loc
|
||||
-- C.InMatchGuard -> "InMatchGuard"
|
||||
-- C.InMatchBody -> "InMatchBody"
|
||||
simpleCause :: C.Cause v loc -> Pretty ColorText
|
||||
simpleCause = \case
|
||||
C.TypeMismatch c ->
|
||||
|
@ -1794,7 +1794,7 @@ declareForeigns = do
|
||||
declareForeign Tracked "Tls.ServerConfig.default" boxBoxDirect $ mkForeign
|
||||
$ \(certs :: [X.SignedCertificate], key :: X.PrivKey) ->
|
||||
pure $ (def :: TLS.ServerParams) { TLS.serverSupported = def { TLS.supportedCiphers = Cipher.ciphersuite_strong }
|
||||
, TLS.serverShared = def { TLS.sharedCredentials = Credentials [((X.CertificateChain certs), key)] }
|
||||
, TLS.serverShared = def { TLS.sharedCredentials = Credentials [(X.CertificateChain certs, key)] }
|
||||
}
|
||||
|
||||
let updateClient :: X.CertificateStore -> TLS.ClientParams -> TLS.ClientParams
|
||||
@ -1843,21 +1843,6 @@ declareForeigns = do
|
||||
declareForeign Untracked "Ref.write" boxBoxTo0 . mkForeign $
|
||||
\(r :: IORef Closure, c :: Closure) -> writeIORef r c
|
||||
|
||||
let
|
||||
defaultSupported :: TLS.Supported
|
||||
defaultSupported = def { TLS.supportedCiphers = Cipher.ciphersuite_strong }
|
||||
|
||||
declareForeign Tracked "Tls.Config.defaultClient" boxBoxDirect
|
||||
. mkForeign $ \(hostName :: Util.Text.Text, serverId:: Bytes.Bytes) -> do
|
||||
store <- X.getSystemCertificateStore
|
||||
let shared :: TLS.Shared
|
||||
shared = def { TLS.sharedCAStore = store }
|
||||
defaultParams = (defaultParamsClient (Util.Text.unpack hostName) (Bytes.toArray serverId)) { TLS.clientSupported = defaultSupported, TLS.clientShared = shared }
|
||||
pure defaultParams
|
||||
|
||||
declareForeign Tracked "Tls.Config.defaultServer" unitDirect . mkForeign $ \() -> do
|
||||
pure $ (def :: ServerParams) { TLS.serverSupported = defaultSupported }
|
||||
|
||||
declareForeign Tracked "Tls.newClient.impl.v3" boxBoxToEFBox . mkForeignTls $
|
||||
\(config :: TLS.ClientParams,
|
||||
socket :: SYS.Socket) -> TLS.contextNew socket config
|
||||
@ -1866,8 +1851,10 @@ declareForeigns = do
|
||||
\(config :: TLS.ServerParams,
|
||||
socket :: SYS.Socket) -> TLS.contextNew socket config
|
||||
|
||||
declareForeign Tracked "Tls.handshake.impl.v3" boxToEFBox . mkForeignTls $
|
||||
\(tls :: TLS.Context) -> TLS.handshake tls
|
||||
declareForeign Tracked "Tls.handshake.impl.v3" boxToEF0 . mkForeignTls $
|
||||
\(tls :: TLS.Context) -> do
|
||||
i <- contextGetInformation tls
|
||||
traceShow i $ TLS.handshake tls
|
||||
|
||||
declareForeign Tracked "Tls.send.impl.v3" boxBoxToEFBox . mkForeignTls $
|
||||
\(tls :: TLS.Context,
|
||||
@ -1875,11 +1862,14 @@ declareForeigns = do
|
||||
|
||||
let wrapFailure t = Failure Ty.tlsFailureRef (Util.Text.pack t) unitValue
|
||||
decoded :: Bytes.Bytes -> Either String PEM
|
||||
decoded bytes = fmap head $ pemParseLBS $ Bytes.toLazyByteString bytes
|
||||
decoded bytes = case pemParseLBS $ Bytes.toLazyByteString bytes of
|
||||
Right (pem : _) -> Right pem
|
||||
Right _ -> Left "no PEM found"
|
||||
Left l -> Left l
|
||||
asCert :: PEM -> Either String X.SignedCertificate
|
||||
asCert pem = X.decodeSignedCertificate $ pemContent pem
|
||||
in
|
||||
declareForeign Tracked "Tls.decodeCert.impl.v3" boxToEFBox . mkForeign $
|
||||
declareForeign Tracked "Tls.decodeCert.impl.v3" boxToEFBox . mkForeignTls $
|
||||
\(bytes :: Bytes.Bytes) -> pure $ mapLeft wrapFailure $ (decoded >=> asCert) bytes
|
||||
|
||||
declareForeign Tracked "Tls.encodeCert" boxDirect . mkForeign $
|
||||
|
@ -284,15 +284,17 @@ intermediateTerm
|
||||
-> Term Symbol
|
||||
-> (SuperGroup Symbol, Map.Map Word64 (Term Symbol))
|
||||
intermediateTerm ppe ref ctx tm
|
||||
= final
|
||||
= first ( superNormalize
|
||||
. splitPatterns (dspec ctx)
|
||||
. addDefaultCases tmName
|
||||
)
|
||||
. memorize
|
||||
. lamLift
|
||||
. splitPatterns (dspec ctx)
|
||||
. addDefaultCases tmName
|
||||
. saturate (uncurryDspec $ dspec ctx)
|
||||
. inlineAlias
|
||||
$ tm
|
||||
where
|
||||
final (ll, dcmp) = (superNormalize ll, backrefLifted ll dcmp)
|
||||
memorize (ll, dcmp) = (ll, backrefLifted ll dcmp)
|
||||
tmName = HQ.toString . termName ppe $ RF.Ref ref
|
||||
|
||||
prepareEvaluation
|
||||
|
@ -11,10 +11,20 @@ module Unison.Server.Endpoints.Projects where
|
||||
import Control.Error (ExceptT, runExceptT)
|
||||
import Control.Error.Util ((??))
|
||||
import Data.Aeson
|
||||
import Data.OpenApi (ToSchema)
|
||||
import Data.Char
|
||||
import Data.OpenApi
|
||||
( ToParamSchema (..),
|
||||
ToSchema (..),
|
||||
)
|
||||
import qualified Data.Text as Text
|
||||
import Servant (QueryParam, ServerError, throwError, (:>))
|
||||
import Servant.Docs (ToSample (..))
|
||||
import Servant.API (FromHttpApiData (..))
|
||||
import Servant.Docs
|
||||
( DocQueryParam (..),
|
||||
ParamKind (Normal),
|
||||
ToParam (..),
|
||||
ToSample (..),
|
||||
)
|
||||
import Servant.Server (Handler)
|
||||
import Unison.Codebase (Codebase)
|
||||
import qualified Unison.Codebase as Codebase
|
||||
@ -34,6 +44,7 @@ import Unison.Util.Monoid (foldMapM)
|
||||
|
||||
type ProjectsAPI =
|
||||
"projects" :> QueryParam "rootBranch" ShortBranchHash
|
||||
:> QueryParam "owner" ProjectOwner
|
||||
:> APIGet [ProjectListing]
|
||||
|
||||
instance ToSample ProjectListing where
|
||||
@ -50,9 +61,33 @@ newtype ProjectOwner = ProjectOwner Text
|
||||
deriving stock (Generic, Show)
|
||||
deriving anyclass (ToSchema)
|
||||
|
||||
instance ToParam (QueryParam "owner" ProjectOwner) where
|
||||
toParam _ =
|
||||
DocQueryParam
|
||||
"owner"
|
||||
["unison", "alice", "bob"]
|
||||
"The name of a project owner"
|
||||
Normal
|
||||
|
||||
instance ToJSON ProjectOwner where
|
||||
toEncoding = genericToEncoding defaultOptions
|
||||
|
||||
deriving anyclass instance ToParamSchema ProjectOwner
|
||||
|
||||
instance FromHttpApiData ProjectOwner where
|
||||
parseUrlPiece = Right . ProjectOwner
|
||||
|
||||
-- ProjectOwner is slightly more restrictive than a regular FQN in that we only
|
||||
-- want alphanumeric characters
|
||||
projectOwnerFromText :: Text -> Either Text ProjectOwner
|
||||
projectOwnerFromText raw =
|
||||
if isAllAlphaNum raw
|
||||
then Right (ProjectOwner raw)
|
||||
else Left "Invalid owner name"
|
||||
where
|
||||
isAllAlphaNum t =
|
||||
t & Text.unpack & all isAlphaNum
|
||||
|
||||
data ProjectListing = ProjectListing
|
||||
{ owner :: ProjectOwner,
|
||||
name :: Text,
|
||||
@ -90,8 +125,9 @@ serve ::
|
||||
Handler () ->
|
||||
Codebase IO Symbol Ann ->
|
||||
Maybe ShortBranchHash ->
|
||||
Maybe ProjectOwner ->
|
||||
Handler (APIHeaders [ProjectListing])
|
||||
serve tryAuth codebase mayRoot = addHeaders <$> (tryAuth *> projects)
|
||||
serve tryAuth codebase mayRoot mayOwner = addHeaders <$> (tryAuth *> projects)
|
||||
where
|
||||
projects :: Handler [ProjectListing]
|
||||
projects = do
|
||||
@ -107,7 +143,11 @@ serve tryAuth codebase mayRoot = addHeaders <$> (tryAuth *> projects)
|
||||
errFromEither backendError ea
|
||||
|
||||
ownerEntries <- findShallow root
|
||||
let owners = mapMaybe entryToOwner ownerEntries
|
||||
-- If an owner is provided, we only want projects belonging to them
|
||||
let owners =
|
||||
case mayOwner of
|
||||
Just o -> [o]
|
||||
Nothing -> mapMaybe entryToOwner ownerEntries
|
||||
foldMapM (ownerToProjectListings root) owners
|
||||
|
||||
ownerToProjectListings :: Branch.Branch IO -> ProjectOwner -> Handler [ProjectListing]
|
||||
|
@ -263,32 +263,26 @@ pretty0
|
||||
<> optSpace <> (fmt S.DelimiterChar $ l "]")
|
||||
where optSpace = PP.orElse "" " "
|
||||
If' cond t f -> paren (p >= 2) $
|
||||
if PP.isMultiLine pt || PP.isMultiLine pf then PP.lines [
|
||||
(fmt S.ControlKeyword "if ") <> pcond <> (fmt S.ControlKeyword " then") `PP.hang` pt,
|
||||
(fmt S.ControlKeyword "else") `PP.hang` pf
|
||||
]
|
||||
else PP.spaced [
|
||||
((fmt S.ControlKeyword "if") `PP.hang` pcond) <> ((fmt S.ControlKeyword " then") `PP.hang` pt),
|
||||
if PP.isMultiLine pcond then PP.lines [
|
||||
(fmt S.ControlKeyword "if") `PP.hang` pcond,
|
||||
(fmt S.ControlKeyword "then") `PP.hang` pt,
|
||||
(fmt S.ControlKeyword "else") `PP.hang` pf
|
||||
]
|
||||
else
|
||||
if PP.isMultiLine pt || PP.isMultiLine pf then PP.lines [
|
||||
(fmt S.ControlKeyword "if ") <> pcond <> (fmt S.ControlKeyword " then") `PP.hang` pt,
|
||||
(fmt S.ControlKeyword "else") `PP.hang` pf
|
||||
]
|
||||
else PP.spaced [
|
||||
((fmt S.ControlKeyword "if") `PP.hang` pcond) <> ((fmt S.ControlKeyword " then") `PP.hang` pt),
|
||||
(fmt S.ControlKeyword "else") `PP.hang` pf
|
||||
]
|
||||
where
|
||||
pcond = pretty0 n (ac 2 Block im doc) cond
|
||||
pt = branch t
|
||||
pf = branch f
|
||||
branch tm = let (im', uses) = calcImports im tm
|
||||
in uses $ [pretty0 n (ac 0 Block im' doc) tm]
|
||||
And' x y ->
|
||||
paren (p >= 10) $ PP.spaced [
|
||||
pretty0 n (ac 10 Normal im doc) x,
|
||||
fmt S.ControlKeyword "&&",
|
||||
pretty0 n (ac 10 Normal im doc) y
|
||||
]
|
||||
Or' x y ->
|
||||
paren (p >= 10) $ PP.spaced [
|
||||
pretty0 n (ac 10 Normal im doc) x,
|
||||
fmt S.ControlKeyword "||",
|
||||
pretty0 n (ac 10 Normal im doc) y
|
||||
]
|
||||
LetBlock bs e ->
|
||||
let (im', uses) = calcImports im term
|
||||
in printLet elideUnit bc bs e im' uses
|
||||
@ -356,7 +350,18 @@ pretty0
|
||||
fmt S.BytesLiteral "0xs" <> (PP.shown $ Bytes.fromWord8s (map fromIntegral bs))
|
||||
BinaryAppsPred' apps lastArg -> paren (p >= 3) $
|
||||
binaryApps apps (pretty0 n (ac 3 Normal im doc) lastArg)
|
||||
-- Note that && and || are at the same precedence, which can cause
|
||||
-- confusion, so for clarity we do not want to elide the parentheses in a
|
||||
-- case like `(x || y) && z`.
|
||||
(Ands' xs lastArg, _) -> paren (p >= 10) $
|
||||
booleanOps (fmt S.ControlKeyword "&&") xs (pretty0 n (ac 10 Normal im doc) lastArg)
|
||||
(Ors' xs lastArg, _) -> paren (p >= 10) $
|
||||
booleanOps (fmt S.ControlKeyword "||") xs (pretty0 n (ac 10 Normal im doc) lastArg)
|
||||
_ -> case (term, nonForcePred) of
|
||||
OverappliedBinaryAppPred' f a b r | binaryOpsPred f ->
|
||||
-- Special case for overapplied binary op
|
||||
paren True (binaryApps [(f, a)] (pretty0 n (ac 3 Normal im doc) b) `PP.hang`
|
||||
PP.spacedMap (pretty0 n (ac 10 Normal im doc)) r)
|
||||
AppsPred' f args ->
|
||||
paren (p >= 10) $ pretty0 n (ac 10 Normal im doc) f `PP.hang`
|
||||
PP.spacedMap (pretty0 n (ac 10 Normal im doc)) args
|
||||
@ -397,13 +402,12 @@ pretty0
|
||||
Normal -> \x -> (fmt S.ControlKeyword "let") `PP.hang` x
|
||||
|
||||
-- This predicate controls which binary functions we render as infix
|
||||
-- operators. At the moment the policy is just to render symbolic
|
||||
-- operators as infix - not 'wordy' function names. So we produce
|
||||
-- "x + y" and "foo x y" but not "x `foo` y".
|
||||
-- operators. At the moment the policy is just to render symbolic
|
||||
-- operators as infix.
|
||||
binaryOpsPred :: Var v => Term3 v PrintAnnotation -> Bool
|
||||
binaryOpsPred = \case
|
||||
Ref' r | isSymbolic (PrettyPrintEnv.termName n (Referent.Ref r)) -> True
|
||||
Var' v | isSymbolic (HQ.unsafeFromVar v) -> True
|
||||
Ref' r -> isSymbolic $ PrettyPrintEnv.termName n (Referent.Ref r)
|
||||
Var' v -> isSymbolic $ HQ.unsafeFromVar v
|
||||
_ -> False
|
||||
|
||||
nonForcePred :: Term3 v PrintAnnotation -> Bool
|
||||
@ -440,6 +444,30 @@ pretty0
|
||||
, pretty0 n (AmbientContext 10 Normal Infix im doc False) f
|
||||
]
|
||||
|
||||
-- Render sequence of infix &&s or ||s, like [x2, x1],
|
||||
-- meaning (x1 && x2) && (x3 rendered by the caller), producing
|
||||
-- "x1 && x2 &&". The result is built from the right.
|
||||
booleanOps
|
||||
:: Var v
|
||||
=> Pretty SyntaxText
|
||||
-> [Term3 v PrintAnnotation]
|
||||
-> Pretty SyntaxText
|
||||
-> Pretty SyntaxText
|
||||
booleanOps op xs last = unbroken `PP.orElse` broken
|
||||
where
|
||||
unbroken = PP.spaced (ps ++ [last])
|
||||
broken = PP.hang (head ps) . PP.column2 . psCols $ (tail ps ++ [last])
|
||||
psCols ps = case take 2 ps of
|
||||
[x, y] -> (x, y) : psCols (drop 2 ps)
|
||||
[x] -> [(x, "")]
|
||||
[] -> []
|
||||
_ -> undefined
|
||||
ps = r =<< reverse xs
|
||||
r a =
|
||||
[ pretty0 n (ac (if isBlock a then 12 else 10) Normal im doc) a
|
||||
, op
|
||||
]
|
||||
|
||||
prettyPattern
|
||||
:: forall v loc . Var v
|
||||
=> PrettyPrintEnv
|
||||
|
@ -211,7 +211,7 @@ test = scope "termprinter" $ tests
|
||||
, tcBreaks 16 "match (if a then\n\
|
||||
\ b\n\
|
||||
\else c) with\n\
|
||||
\ 112 -> x" -- dodgy layout. note #517 and #518
|
||||
\ 112 -> x" -- dodgy layout. note #517
|
||||
, tc "handle bar with Pair 1 1"
|
||||
, tc "handle bar with x -> foo"
|
||||
, tcDiffRtt True "let\n\
|
||||
@ -411,7 +411,9 @@ test = scope "termprinter" $ tests
|
||||
\ b" 80
|
||||
, tcBreaks 80 "if\n\
|
||||
\ a = b\n\
|
||||
\ a then foo else bar" -- missing break before 'then', issue #518
|
||||
\ a\n\
|
||||
\then foo\n\
|
||||
\else bar"
|
||||
, tcBreaks 80 "Stream.foldLeft 0 (+) t"
|
||||
, tcBreaks 80 "let\n\
|
||||
\ delay = 'isEven\n\
|
||||
|
@ -1,88 +1,102 @@
|
||||
{- ORMOLU_DISABLE -} -- Remove this when the file is ready to be auto-formatted
|
||||
{-# LANGUAGE PatternSynonyms #-}
|
||||
|
||||
module Unison.Codebase.Editor.SlurpComponent where
|
||||
|
||||
import Unison.Prelude
|
||||
|
||||
import Data.Tuple (swap)
|
||||
import Unison.Reference ( Reference )
|
||||
import Unison.UnisonFile (TypecheckedUnisonFile)
|
||||
import qualified Data.Map as Map
|
||||
import qualified Data.Set as Set
|
||||
import Data.Tuple (swap)
|
||||
import qualified Unison.DataDeclaration as DD
|
||||
import Unison.Prelude
|
||||
import Unison.Reference (Reference)
|
||||
import qualified Unison.Term as Term
|
||||
import Unison.UnisonFile (TypecheckedUnisonFile)
|
||||
import qualified Unison.UnisonFile as UF
|
||||
|
||||
data SlurpComponent v =
|
||||
SlurpComponent { types :: Set v, terms :: Set v }
|
||||
deriving (Eq,Ord,Show)
|
||||
data SlurpComponent v = SlurpComponent {types :: Set v, terms :: Set v}
|
||||
deriving (Eq, Ord, Show)
|
||||
|
||||
isEmpty :: SlurpComponent v -> Bool
|
||||
isEmpty sc = Set.null (types sc) && Set.null (terms sc)
|
||||
|
||||
empty :: Ord v => SlurpComponent v
|
||||
empty = SlurpComponent mempty mempty
|
||||
empty = SlurpComponent {types = mempty, terms = mempty}
|
||||
|
||||
difference :: Ord v => SlurpComponent v -> SlurpComponent v -> SlurpComponent v
|
||||
difference c1 c2 = SlurpComponent types' terms' where
|
||||
types' = types c1 `Set.difference` types c2
|
||||
terms' = terms c1 `Set.difference` terms c2
|
||||
difference c1 c2 = SlurpComponent {types = types', terms = terms'}
|
||||
where
|
||||
types' = types c1 `Set.difference` types c2
|
||||
terms' = terms c1 `Set.difference` terms c2
|
||||
|
||||
intersection :: Ord v => SlurpComponent v -> SlurpComponent v -> SlurpComponent v
|
||||
intersection c1 c2 = SlurpComponent types' terms' where
|
||||
types' = types c1 `Set.intersection` types c2
|
||||
terms' = terms c1 `Set.intersection` terms c2
|
||||
intersection c1 c2 = SlurpComponent {types = types', terms = terms'}
|
||||
where
|
||||
types' = types c1 `Set.intersection` types c2
|
||||
terms' = terms c1 `Set.intersection` terms c2
|
||||
|
||||
instance Ord v => Semigroup (SlurpComponent v) where (<>) = mappend
|
||||
instance Ord v => Monoid (SlurpComponent v) where
|
||||
mempty = SlurpComponent mempty mempty
|
||||
c1 `mappend` c2 = SlurpComponent (types c1 <> types c2)
|
||||
(terms c1 <> terms c2)
|
||||
|
||||
instance Ord v => Monoid (SlurpComponent v) where
|
||||
mempty = SlurpComponent {types = mempty, terms = mempty}
|
||||
c1 `mappend` c2 =
|
||||
SlurpComponent
|
||||
{ types = types c1 <> types c2,
|
||||
terms = terms c1 <> terms c2
|
||||
}
|
||||
|
||||
-- I'm calling this `closeWithDependencies` because it doesn't just compute
|
||||
-- the dependencies of the inputs, it mixes them together. Make sure this
|
||||
-- is what you want.
|
||||
closeWithDependencies :: forall v a. Ord v
|
||||
=> TypecheckedUnisonFile v a -> SlurpComponent v -> SlurpComponent v
|
||||
closeWithDependencies uf inputs = seenDefns where
|
||||
seenDefns = foldl' termDeps (SlurpComponent mempty seenTypes) (terms inputs)
|
||||
seenTypes = foldl' typeDeps mempty (types inputs)
|
||||
closeWithDependencies ::
|
||||
forall v a.
|
||||
Ord v =>
|
||||
TypecheckedUnisonFile v a ->
|
||||
SlurpComponent v ->
|
||||
SlurpComponent v
|
||||
closeWithDependencies uf inputs = seenDefns
|
||||
where
|
||||
seenDefns = foldl' termDeps (SlurpComponent {types = seenTypes, terms = mempty}) (terms inputs)
|
||||
seenTypes = foldl' typeDeps mempty (types inputs)
|
||||
|
||||
termDeps :: SlurpComponent v -> v -> SlurpComponent v
|
||||
termDeps seen v | Set.member v (terms seen) = seen
|
||||
termDeps seen v = fromMaybe seen $ do
|
||||
term <- findTerm v
|
||||
let -- get the `v`s for the transitive dependency types
|
||||
-- (the ones for terms are just the `freeVars below`)
|
||||
-- although this isn't how you'd do it for a term that's already in codebase
|
||||
tdeps :: [v]
|
||||
tdeps = resolveTypes $ Term.dependencies term
|
||||
seenTypes :: Set v
|
||||
seenTypes = foldl' typeDeps (types seen) tdeps
|
||||
seenTerms = Set.insert v (terms seen)
|
||||
pure $ foldl' termDeps (seen { types = seenTypes
|
||||
, terms = seenTerms})
|
||||
(Term.freeVars term)
|
||||
termDeps :: SlurpComponent v -> v -> SlurpComponent v
|
||||
termDeps seen v | Set.member v (terms seen) = seen
|
||||
termDeps seen v = fromMaybe seen $ do
|
||||
term <- findTerm v
|
||||
let -- get the `v`s for the transitive dependency types
|
||||
-- (the ones for terms are just the `freeVars below`)
|
||||
-- although this isn't how you'd do it for a term that's already in codebase
|
||||
tdeps :: [v]
|
||||
tdeps = resolveTypes $ Term.dependencies term
|
||||
seenTypes :: Set v
|
||||
seenTypes = foldl' typeDeps (types seen) tdeps
|
||||
seenTerms = Set.insert v (terms seen)
|
||||
pure $
|
||||
foldl'
|
||||
termDeps
|
||||
( seen
|
||||
{ types = seenTypes,
|
||||
terms = seenTerms
|
||||
}
|
||||
)
|
||||
(Term.freeVars term)
|
||||
|
||||
typeDeps :: Set v -> v -> Set v
|
||||
typeDeps seen v | Set.member v seen = seen
|
||||
typeDeps seen v = fromMaybe seen $ do
|
||||
dd <- fmap snd (Map.lookup v (UF.dataDeclarations' uf)) <|>
|
||||
fmap (DD.toDataDecl . snd) (Map.lookup v (UF.effectDeclarations' uf))
|
||||
pure $ foldl' typeDeps (Set.insert v seen) (resolveTypes $ DD.dependencies dd)
|
||||
typeDeps :: Set v -> v -> Set v
|
||||
typeDeps seen v | Set.member v seen = seen
|
||||
typeDeps seen v = fromMaybe seen $ do
|
||||
dd <-
|
||||
fmap snd (Map.lookup v (UF.dataDeclarations' uf))
|
||||
<|> fmap (DD.toDataDecl . snd) (Map.lookup v (UF.effectDeclarations' uf))
|
||||
pure $ foldl' typeDeps (Set.insert v seen) (resolveTypes $ DD.dependencies dd)
|
||||
|
||||
resolveTypes :: Set Reference -> [v]
|
||||
resolveTypes rs = [ v | r <- Set.toList rs, Just v <- [Map.lookup r typeNames]]
|
||||
resolveTypes :: Set Reference -> [v]
|
||||
resolveTypes rs = [v | r <- Set.toList rs, Just v <- [Map.lookup r typeNames]]
|
||||
|
||||
findTerm :: v -> Maybe (Term.Term v a)
|
||||
findTerm v = Map.lookup v allTerms
|
||||
findTerm :: v -> Maybe (Term.Term v a)
|
||||
findTerm v = Map.lookup v allTerms
|
||||
|
||||
allTerms = UF.allTerms uf
|
||||
allTerms = UF.allTerms uf
|
||||
|
||||
typeNames :: Map Reference v
|
||||
typeNames = invert (fst <$> UF.dataDeclarations' uf) <> invert (fst <$> UF.effectDeclarations' uf)
|
||||
typeNames :: Map Reference v
|
||||
typeNames = invert (fst <$> UF.dataDeclarations' uf) <> invert (fst <$> UF.effectDeclarations' uf)
|
||||
|
||||
invert :: forall k v . Ord k => Ord v => Map k v -> Map v k
|
||||
invert m = Map.fromList (swap <$> Map.toList m)
|
||||
invert :: forall k v. Ord k => Ord v => Map k v -> Map v k
|
||||
invert m = Map.fromList (swap <$> Map.toList m)
|
||||
|
@ -428,10 +428,14 @@ pattern Or' x y <- (ABT.out -> ABT.Tm (Or x y))
|
||||
pattern Handle' h body <- (ABT.out -> ABT.Tm (Handle h body))
|
||||
pattern Apps' f args <- (unApps -> Just (f, args))
|
||||
-- begin pretty-printer helper patterns
|
||||
pattern Ands' ands lastArg <- (unAnds -> Just (ands, lastArg))
|
||||
pattern Ors' ors lastArg <- (unOrs -> Just (ors, lastArg))
|
||||
pattern AppsPred' f args <- (unAppsPred -> Just (f, args))
|
||||
pattern BinaryApp' f arg1 arg2 <- (unBinaryApp -> Just (f, arg1, arg2))
|
||||
pattern BinaryApps' apps lastArg <- (unBinaryApps -> Just (apps, lastArg))
|
||||
pattern BinaryAppsPred' apps lastArg <- (unBinaryAppsPred -> Just (apps, lastArg))
|
||||
pattern OverappliedBinaryAppPred' f arg1 arg2 rest <-
|
||||
(unOverappliedBinaryAppPred -> Just (f, arg1, arg2, rest))
|
||||
-- end pretty-printer helper patterns
|
||||
pattern Ann' x t <- (ABT.out -> ABT.Tm (Ann x t))
|
||||
pattern List' xs <- (ABT.out -> ABT.Tm (List xs))
|
||||
@ -761,6 +765,30 @@ unLetRec (unLetRecNamed -> Just (isTop, bs, e)) = Just
|
||||
)
|
||||
unLetRec _ = Nothing
|
||||
|
||||
unAnds
|
||||
:: Term2 vt at ap v a
|
||||
-> Maybe
|
||||
( [Term2 vt at ap v a]
|
||||
, Term2 vt at ap v a
|
||||
)
|
||||
unAnds t = case t of
|
||||
And' i o -> case unAnds i of
|
||||
Just (as, xLast) -> Just (xLast:as, o)
|
||||
Nothing -> Just ([i], o)
|
||||
_ -> Nothing
|
||||
|
||||
unOrs
|
||||
:: Term2 vt at ap v a
|
||||
-> Maybe
|
||||
( [Term2 vt at ap v a]
|
||||
, Term2 vt at ap v a
|
||||
)
|
||||
unOrs t = case t of
|
||||
Or' i o -> case unOrs i of
|
||||
Just (as, xLast) -> Just (xLast:as, o)
|
||||
Nothing -> Just ([i], o)
|
||||
_ -> Nothing
|
||||
|
||||
unApps
|
||||
:: Term2 vt at ap v a
|
||||
-> Maybe (Term2 vt at ap v a, [Term2 vt at ap v a])
|
||||
@ -783,6 +811,19 @@ unBinaryApp t = case unApps t of
|
||||
Just (f, [arg1, arg2]) -> Just (f, arg1, arg2)
|
||||
_ -> Nothing
|
||||
|
||||
-- Special case for overapplied binary operators
|
||||
unOverappliedBinaryAppPred
|
||||
:: (Term2 vt at ap v a, Term2 vt at ap v a -> Bool)
|
||||
-> Maybe
|
||||
( Term2 vt at ap v a
|
||||
, Term2 vt at ap v a
|
||||
, Term2 vt at ap v a
|
||||
, [Term2 vt at ap v a]
|
||||
)
|
||||
unOverappliedBinaryAppPred (t, pred) = case unApps t of
|
||||
Just (f, arg1 : arg2 : rest) | pred f -> Just (f, arg1, arg2, rest)
|
||||
_ -> Nothing
|
||||
|
||||
-- "((a1 `f1` a2) `f2` a3)" becomes "Just ([(a2, f2), (a1, f1)], a3)"
|
||||
unBinaryApps
|
||||
:: Term2 vt at ap v a
|
||||
|
@ -23,6 +23,14 @@ Exception.toEither.handler = cases
|
||||
Exception.toEither : '{ε, Exception} a -> {ε} Either Failure a
|
||||
Exception.toEither a = handle !a with Exception.toEither.handler
|
||||
|
||||
Exception.unsafeRun! : '{g, Exception} a ->{g} a
|
||||
Exception.unsafeRun! e =
|
||||
h : Request {Exception} a -> a
|
||||
h = cases
|
||||
{raise fail -> _} -> bug fail
|
||||
{ a } -> a
|
||||
handle !e with h
|
||||
|
||||
structural ability Throw e where
|
||||
throw : e -> a
|
||||
|
||||
@ -31,6 +39,17 @@ List.all f = cases
|
||||
[] -> true
|
||||
h +: t -> f h && all f t
|
||||
|
||||
List.foldLeft : (b ->{g} a ->{g} b) -> b -> [a] ->{g} b
|
||||
List.foldLeft f b as =
|
||||
go b i =
|
||||
match List.at i as with
|
||||
None -> b
|
||||
Some a ->
|
||||
use Nat +
|
||||
go (f b a) (i + 1)
|
||||
go b 0
|
||||
|
||||
|
||||
List.filter: (a -> Boolean) -> [a] -> [a]
|
||||
List.filter f all =
|
||||
go acc = cases
|
||||
|
@ -73,6 +73,14 @@ id x = x
|
||||
id (sqr 10)
|
||||
```
|
||||
|
||||
also:
|
||||
|
||||
```
|
||||
match 1 with
|
||||
1 -> "hi"
|
||||
_ -> "goodbye"
|
||||
```
|
||||
|
||||
To include a typechecked snippet of code without evaluating it, you can do:
|
||||
|
||||
@typecheck ```
|
||||
|
@ -257,6 +257,14 @@ and the rendered output using `display`:
|
||||
id (sqr 10)
|
||||
```
|
||||
|
||||
also:
|
||||
|
||||
```
|
||||
match 1 with
|
||||
1 -> "hi"
|
||||
_ -> "goodbye"
|
||||
```
|
||||
|
||||
To include a typechecked snippet of code without
|
||||
evaluating it, you can do:
|
||||
|
||||
@ -281,6 +289,14 @@ and the rendered output using `display`:
|
||||
⧨
|
||||
100
|
||||
|
||||
also:
|
||||
|
||||
match 1 with
|
||||
1 -> "hi"
|
||||
_ -> "goodbye"
|
||||
⧨
|
||||
"hi"
|
||||
|
||||
To include a typechecked snippet of code without evaluating
|
||||
it, you can do:
|
||||
|
||||
@ -626,6 +642,14 @@ Lastly, it's common to build longer documents including subdocuments via `{{ sub
|
||||
⧨
|
||||
100
|
||||
|
||||
also:
|
||||
|
||||
match 1 with
|
||||
1 -> "hi"
|
||||
_ -> "goodbye"
|
||||
⧨
|
||||
"hi"
|
||||
|
||||
To include a typechecked snippet of code without
|
||||
evaluating it, you can do:
|
||||
|
||||
|
@ -59,27 +59,27 @@ myServer = unsafeRun! '(hello "127.0.0.1" "0")
|
||||
|
||||
structural type Either a b
|
||||
(also named builtin.Either)
|
||||
Exception.unsafeRun! : '{g, Exception} a -> '{g} a
|
||||
bugFail : Failure -> r
|
||||
hello : Text -> Text ->{IO, Exception} ()
|
||||
myServer : '{IO} ()
|
||||
putText : Handle -> Text ->{IO, Exception} ()
|
||||
reraise : Either Failure b ->{Exception} b
|
||||
bugFail : Failure -> r
|
||||
hello : Text -> Text ->{IO, Exception} ()
|
||||
myServer : '{IO} ()
|
||||
putText : Handle -> Text ->{IO, Exception} ()
|
||||
reraise : Either Failure b ->{Exception} b
|
||||
(also named Exception.reraise)
|
||||
socketSend : Socket
|
||||
-> Bytes
|
||||
->{IO, Exception} ()
|
||||
toException : Either Failure a ->{Exception} a
|
||||
socketSend : Socket -> Bytes ->{IO, Exception} ()
|
||||
toException : Either Failure a ->{Exception} a
|
||||
(also named Exception.reraise)
|
||||
|
||||
⍟ These names already exist. You can `update` them to your
|
||||
new definition:
|
||||
|
||||
closeSocket : Socket ->{IO, Exception} ()
|
||||
putBytes : Handle -> Bytes ->{IO, Exception} ()
|
||||
serverSocket : Optional Text
|
||||
-> Text
|
||||
->{IO, Exception} Socket
|
||||
Exception.unsafeRun! : '{g, Exception} a -> '{g} a
|
||||
closeSocket : Socket ->{IO, Exception} ()
|
||||
putBytes : Handle
|
||||
-> Bytes
|
||||
->{IO, Exception} ()
|
||||
serverSocket : Optional Text
|
||||
-> Text
|
||||
->{IO, Exception} Socket
|
||||
|
||||
```
|
||||
```ucm
|
||||
|
@ -1,13 +1,42 @@
|
||||
# Tests for TLS builtins
|
||||
|
||||
```ucm:hide
|
||||
.> builtins.merge
|
||||
.> builtins.mergeio
|
||||
.> cd builtin
|
||||
.> load unison-src/transcripts-using-base/base.u
|
||||
.> add
|
||||
```
|
||||
|
||||
```unison:hide
|
||||
-- generated with:
|
||||
-- openssl req -newkey rsa:2048 -subj '/CN=test.unison.cloud/O=Unison/C=US' -nodes -keyout key.pem -x509 -days 365 -out cert.pem
|
||||
-- openssl req -newkey rsa:2048 -subj '/CN=test.unison.cloud/O=Unison/C=US' -nodes -keyout key.pem -x509 -days 3650 -out cert.pem
|
||||
|
||||
self_signed_key_pem = "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDBrpp+SxjCz/aQ\nQXT2hKXrT3lZ3Ek1VT/kgNre3J/RUyNZjZnZXCMyNjZ4IxYKxcCAIgGtfFpgvkzT\n5NRGZKLlSX4Y8HayV3gdEXO9hq4w/i/s+I0tOAJkVtHolXrrziZ7/4NZwMTbbqhO\n5hHHhbtBIpvNSw8el3AY3APkQ37+wM3fbvyeuG0ekoLqTa371W+/Z7pOi7QXYGEa\n8YHSNkuRKY46C4Y8oeWHOlSbQKu151GLuyQu74bnecGDN4KBdz9nyyKCCTpBsJpU\ni9Ozq3cps5L8dnN1zUNgaTyWp9kO3vbaTU8MY7p/dc7hNJ8pmGtSiiSs1xvni4Xl\nCBXBesxTAgMBAAECggEAAUtfcPSjh7nIFhK562PbkAUJ9JXKT3bwZGCQFek3kDiU\nBecyXgeFnLJMDuV9IjlMHg8cH8Ky/+6FqOzglk/Z3tps41HIGU0IWnlhYqThySYJ\nv/WxS9oR+gWyhXFqTuUj0LRWdmUZa7YDnfNfrwuvwrGuhOK5iSTN9PyTchUZZi50\ntxcNS/C3rk63c7TZLfuwxwGoUCeJvZZ/rmeVchhsuoo3QdSW0Aee7UtFtnvBfLCK\nXKdz+3q49fLZlDyx9/olJh+TY7GuF+G/LSfyQGi85beQhkXUH8/gIQIRI8INIEPB\n0XeTlv7Sgw5upqplJvHCXjAa+jz/Mo87znXBTMoIIQKBgQDorAlZCjzKxGDIaZoD\nDBXYzhSnnIhthThW4edCQ9/ZnJpX4vdTw4FngW504d8SPStMCYeBeMt8iwTczI4W\nHfK+AlVTlPfH/9NnIVADqqr9kobJW6782MYSW2/758d+L5bq8NGATyh8nPll9joN\nYAk7tNO2bGO2bEk2DbZMf3qnOQKBgQDVGdD005kUT3D+DfgeLTGzwk/2wCCPjoJ5\n6fsjsFAeZWU/qioIB3xHt1w8NsT6O+7XOKp/GRbsvsJR9Z/zmA3Ii5yrHYn48UzM\n+UyGLv+2HCpO+8A3szz/aDhKIxNFpXyZzvOXdtqBwTQbICOW2WRWOOgDrS2W1i9l\nD69xRLqj6wKBgBW0xwJ5hAZen7DSuT2DiR46y45/efLNtN3WIV77OgzxIS0FzZEQ\n8ieX2Zgp4kevUTS8xtl7TXCG/6MhqjfB/31edltf0GXmJfC/GNneuCkD3HM4jHCm\nQIRB54aWrvPEuM2ePc08lUha1KGAgRXyWaoqSn4ASqUgIQxb5x/n3KdxAoGAXlD0\nyMc2Q2T9r5PjMwfxrYvc9GsIfkEmwmqqupr4etuJumnH/JHDkcI30nazK8WG6j6s\nR2CFYvby7m92AcxUnWQdTSbfwAycX0QfeGwoxSMmHpsR8hUkdC5ea4Gmr/aUdUbB\nTVJPV4p5U2AgIE3LONYq6iWlvdLCW0pb7hfrO00CgYAb8bXz9BNow4soEkSbQysg\n4sGAr1+iSPY+ErffKRDpcFRnWcQdnTfI4xd8bgnC6OZwVpLbRZaZf3opDJ+axWqa\nEgAeHErTDY4R8aMecvyQj780sQ35kVq4VK0rSQyiKRBcjEust8UEzwYsUog2ysN0\n3zLHVEvFTfwOSctnEQRw1w==\n-----END PRIVATE KEY-----\n"
|
||||
join strs = List.foldLeft (a -> b -> b ++ a ++ "\n") "" strs
|
||||
|
||||
self_signed_cert_pem = "-----BEGIN CERTIFICATE-----\nMIIDVTCCAj2gAwIBAgIUZI9WPZk1rv2Sx5XSK17BZSV4t7gwDQYJKoZIhvcNAQEL\nBQAwOjEaMBgGA1UEAwwRdGVzdC51bmlzb24uY2xvdWQxDzANBgNVBAoMBlVuaXNv\nbjELMAkGA1UEBhMCVVMwHhcNMjEwMTIyMDkxMTE3WhcNMjIwMTIyMDkxMTE3WjA6\nMRowGAYDVQQDDBF0ZXN0LnVuaXNvbi5jbG91ZDEPMA0GA1UECgwGVW5pc29uMQsw\nCQYDVQQGEwJVUzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMGumn5L\nGMLP9pBBdPaEpetPeVncSTVVP+SA2t7cn9FTI1mNmdlcIzI2NngjFgrFwIAiAa18\nWmC+TNPk1EZkouVJfhjwdrJXeB0Rc72GrjD+L+z4jS04AmRW0eiVeuvOJnv/g1nA\nxNtuqE7mEceFu0Eim81LDx6XcBjcA+RDfv7Azd9u/J64bR6SgupNrfvVb79nuk6L\ntBdgYRrxgdI2S5EpjjoLhjyh5Yc6VJtAq7XnUYu7JC7vhud5wYM3goF3P2fLIoIJ\nOkGwmlSL07Ordymzkvx2c3XNQ2BpPJan2Q7e9tpNTwxjun91zuE0nymYa1KKJKzX\nG+eLheUIFcF6zFMCAwEAAaNTMFEwHQYDVR0OBBYEFFE3RQYASDWtwSdXL+qtQrjy\nH4SZMB8GA1UdIwQYMBaAFFE3RQYASDWtwSdXL+qtQrjyH4SZMA8GA1UdEwEB/wQF\nMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAH7D8W68cR0QvNNPugCY7lPvA/F94Qam\nwCC2A55edcagfjqFy77xx4Ljrd2TC19yiSzyeeJ+YuohbcipLce90BaaaiYq9aah\n5DICDCUhm1qbhJzqNB2Lqgl4aN+jRMeRVC+rpQBYBNmdPBqdv/k+T2uyghwmLWXe\n/AxCjCLA0zoYzOMytS86veD6CQbF5DpSTZx5dyZTeGhk2izhoM8cgiu+/7YncAbJ\nt7b7UT5Yu3+z1hAdUF5Q21bkEksGBC8UW0G0PMy8XNRMuMsz+2LC39u3u7QyX/+e\nuQGST3aCreV27zd0lrF8LHjwD2XcjVVzHy46VYQvf1r+6gatedDBjqc=\n-----END CERTIFICATE-----\n"
|
||||
self_signed_key_pem="-----BEGIN PRIVATE KEY-----\nMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDtV0Lqk9i5DKJG\ne5zwDFuxHxSxhOygCuq6Jl4xonsjl4hdvXxUUiuqxGGbv4x9HSvavpHwyriGiIRQ\noIjanWiNK9Jp6VDYWOvErnTG/+Rfm1vCoUKQvn8lDrD9knSPUoTz3Cz7JS8FE/rr\nFR3IRyXa0gpXmvIwX16SeCS/Lb/Le9o1HJh9DrkxVyoFq3zlX1OE0AVV0a014IDB\nNprqLITwiVzyDPQkP8rbJF9WPI5afzW8+3+v5UanIFknOOPaJl8pf3gmqI5g8fxk\n/SSMlPgnLd1Fi7h90gBygdpJw3do3/ZA1IOvmFQ+LXE1xtqU1Ay3f3At3DiJgTxP\n8mwBYdtdAgMBAAECggEBAMo85QRF3xIvtcchZeUWYrtWpKdvgMIPC1x7fSAGN69o\nXAakg+DF8/ebRyET435o8QmAAZOQ6hOZGEYrxPGj14cTpEQjT4RKoPwDO/al7c+Z\n7mK2TqZP7L+C+UXZGgFWa3vwTVPjp2FIWTMf1zTli1geSjnECkM1wLxGK+nL7fZQ\nesHXPkJJG5AqzA84bJ/fY5OQ/dfcCxnHEv5XpHPq6VFgXg7jtcNbr1R9EBiQfreN\nU7Hd38R77jYjL1fT71HwEUQ0cwavfxTu0jZFXJxEC7CC1J65QXUguZXLf9vwgSB0\nm0gZgeJlQ905bDJrxUcqCFxdROy/SndP6qFnJSCsfwECgYEA+2cld/WCieUGstJd\njsIrJ6f/e+uuOSTnGTtnsBX6KoiHdcg3sVVVK18xI9El9V+YX9SjN37XeGFe/Wzu\ngE3M4A3Jqz7cgdNj/PaKjqQwJWNbcJnL5ku6eQvcAIpc5gAZxXVCPIbY1ZpeYcsh\nMwr3cOEpQu8UVFBbn/OeJ1r07dECgYEA8a5J3Ls5PSxXq8NDrkAxt3vUJIWLGQQJ\nbV2aGDI2XP2N+vh2WML9rlFeyyBOeRxK9TsErVOaEeOcQZV97//fzIGxCU+SXyiC\nnVMXT2U1mzOu5qPfzLO5Ga4sunxqKDman6NM2IPw2NPA7zMWNQMEIHAerwYZzjm5\nB5tFcMA8e80CgYBgF8rwkTz2LD5lN5dfK8SHAeXbnfgYC4zxzg0R9zSJ8WmlkYQI\nGk/VpisIP7c8lO+PIZ3JZohBkSZXw71d+V7n/R0qgXqTfRNo62uGnidxAws+fOq8\n+hEql2feJQThPQScvvc0X26eJsUQqC3mbripwsacuPmSSKzc9Kds741TIQKBgQCd\nXnG2CytATAliTKlbY218HmOKzHJAfcJttk9KhhekAW5cB0F4lq98vHtPJOA0OFoO\nyLlI63EdSOpMQj1Y83IUxjYy699Rmx1BuAMrral0P/kZMYfe0QAsWp/BZpXxT2EB\npeG58l/3sBqnJsrFBgu/24H/UaeoAyoaa96Rhntb2QKBgQCSEkcUnzTvoUyMFN14\n8NttxOUZiSsCmgoXk6Rk2QKyCPsJocGS4BffGt3kOMcotz/0YsvM1TBBLB7vIaAy\nE1eWLBxK4yYeS8dKXwiCZn170yaJyjoBwZC1RgqQiKa5Y22Di7KjJoMa4Da8Tk4z\nFbE5dBApbLhvNTyQ7BHZxlfmdg==\n-----END PRIVATE KEY-----"
|
||||
|
||||
self_signed_cert_pem2 = join [
|
||||
"-----BEGIN CERTIFICATE-----",
|
||||
"MIIDVTCCAj2gAwIBAgIUdMNT5sYMfDJYH48Rh8LrlN+5wwgwDQYJKoZIhvcNAQEL",
|
||||
"BQAwOjEaMBgGA1UEAwwRdGVzdC51bmlzb24uY2xvdWQxDzANBgNVBAoMBlVuaXNv",
|
||||
"bjELMAkGA1UEBhMCVVMwHhcNMjIwMTI0MjAxNzQ2WhcNMzIwMTIyMjAxNzQ2WjA6",
|
||||
"MRowGAYDVQQDDBF0ZXN0LnVuaXNvbi5jbG91ZDEPMA0GA1UECgwGVW5pc29uMQsw",
|
||||
"CQYDVQQGEwJVUzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAO1XQuqT",
|
||||
"2LkMokZ7nPAMW7EfFLGE7KAK6romXjGieyOXiF29fFRSK6rEYZu/jH0dK9q+kfDK",
|
||||
"uIaIhFCgiNqdaI0r0mnpUNhY68SudMb/5F+bW8KhQpC+fyUOsP2SdI9ShPPcLPsl",
|
||||
"LwUT+usVHchHJdrSClea8jBfXpJ4JL8tv8t72jUcmH0OuTFXKgWrfOVfU4TQBVXR",
|
||||
"rTXggME2muoshPCJXPIM9CQ/ytskX1Y8jlp/Nbz7f6/lRqcgWSc449omXyl/eCao",
|
||||
"jmDx/GT9JIyU+Cct3UWLuH3SAHKB2knDd2jf9kDUg6+YVD4tcTXG2pTUDLd/cC3c",
|
||||
"OImBPE/ybAFh210CAwEAAaNTMFEwHQYDVR0OBBYEFIfwxpuqtqxfCpaJGW32jH2J",
|
||||
"NbnYMB8GA1UdIwQYMBaAFIfwxpuqtqxfCpaJGW32jH2JNbnYMA8GA1UdEwEB/wQF",
|
||||
"MAMBAf8wDQYJKoZIhvcNAQELBQADggEBAKh7EDo5XjSd6J190WGH3V8v49J0Sh8M",
|
||||
"P7APe1eL8eTkW1Vh7/QCOhRpkSnyCz2OxJjjeFVAsCO3aLxlRM6wQZQKXu45iM2U",
|
||||
"iPmv7ECS5xUn7LqRZd/JG1P6jvRPtBC1+oqA+NNDe27wzQp3rWyDG3pWZga8jJfW",
|
||||
"q+2xQ+s6GfzszxYZ/8MLn4zaUSymnOA+70yQ8czXkSO7MT2jJ7QDX8jxuJPZZARW",
|
||||
"uXeAYPRqD+b4MjdBATEtxgPTDWEi8gtfHFGUgInFhD4hOu+D3NLiE6lfR5brUqpQ",
|
||||
"Z4v8prCI8OjGSUx1dIJhqQHB5O0vdaxO0hkVdfqDVE93UrGBPwBRDlo=",
|
||||
"-----END CERTIFICATE-----"]
|
||||
```
|
||||
|
||||
```ucm:hide
|
||||
@ -19,7 +48,7 @@ self_signed_cert_pem = "-----BEGIN CERTIFICATE-----\nMIIDVTCCAj2gAwIBAgIUZI9WPZk
|
||||
First lets make sure we can load our cert and private key
|
||||
|
||||
```unison
|
||||
test> match (decodeCert.impl (toUtf8 self_signed_cert_pem) with
|
||||
test> match (decodeCert.impl (toUtf8 self_signed_cert_pem2) with
|
||||
Left (Failure _ t _) -> [Fail t]
|
||||
Right _ -> [Ok "succesfully decoded self_signed_pem"]
|
||||
|
||||
@ -39,7 +68,7 @@ serverThread portVar toSend = 'let
|
||||
go: '{io2.IO, Exception}()
|
||||
go = 'let
|
||||
-- load our self signed cert
|
||||
cert = decodeCert (toUtf8 self_signed_cert_pem)
|
||||
cert = decodeCert (toUtf8 self_signed_cert_pem2)
|
||||
|
||||
-- assume there is exactly one key decoded from our Bytes
|
||||
key = match (decodePrivateKey (toUtf8 self_signed_key_pem)) with k +: _ -> k
|
||||
@ -68,9 +97,13 @@ serverThread portVar toSend = 'let
|
||||
-- attach TLS to our TCP connection
|
||||
tls = newServer tlsconfig sock'
|
||||
|
||||
printLine "oooooooooooooooo"
|
||||
-- try to handshake the TLS connection with the client
|
||||
handshake tls
|
||||
match handshake.impl tls with
|
||||
Right _ -> printLine "no error on server side"
|
||||
Left (Failure _ t _) -> printLine ("error " ++ t)
|
||||
|
||||
printLine "iiiiiiiiiiiiiii"
|
||||
-- send our message over our tls channel
|
||||
send tls (toUtf8 toSend)
|
||||
terminate tls
|
||||
@ -94,17 +127,22 @@ testClient cert hostname portVar _ =
|
||||
port = take portVar
|
||||
|
||||
-- create a tcp connection with the server
|
||||
|
||||
watch ("client connecting to port: " ++ (toText port)) ()
|
||||
sock = clientSocket "127.0.0.1" (Nat.toText port)
|
||||
|
||||
-- attach the TLS client to the TCP socket
|
||||
tls = newClient tlsconfig sock
|
||||
watch ("client connecting to port: " ++ (toText port)) ()
|
||||
|
||||
printLine "5555555555555555555"
|
||||
-- verify that the server presents us with a certificate chain for
|
||||
-- test.unison.cloud originating with a certificate we trust, and
|
||||
-- that the server can use a compatible TLS version and cipher
|
||||
handshake tls
|
||||
match handshake.impl tls with
|
||||
Right _ -> printLine "no eeror on client side"
|
||||
Left (Failure _ t _) -> printLine ("error " ++ t)
|
||||
|
||||
printLine "666666666666666666"
|
||||
-- receive a message from the server
|
||||
fromUtf8 (receive tls)
|
||||
|
||||
@ -114,14 +152,17 @@ testConnectSelfSigned _ =
|
||||
-- Server
|
||||
portVar = !MVar.newEmpty
|
||||
toSend = "12345"
|
||||
forkComp (serverThread portVar toSend)
|
||||
tid = forkComp (serverThread portVar toSend)
|
||||
|
||||
-- Client
|
||||
cert = decodeCert (toUtf8 self_signed_cert_pem)
|
||||
cert = decodeCert (toUtf8 self_signed_cert_pem2)
|
||||
received = !(testClient (Some cert) "test.unison.cloud" portVar)
|
||||
|
||||
kill.impl tid
|
||||
|
||||
expectU "should have reaped what we've sown" toSend received
|
||||
|
||||
|
||||
runTest test
|
||||
|
||||
-- this client will trust whatever certs the system trusts
|
||||
@ -141,11 +182,12 @@ testCAReject _ =
|
||||
-- Server
|
||||
portVar = !MVar.newEmpty
|
||||
toSend = "12345"
|
||||
forkComp (serverThread portVar toSend)
|
||||
tid = forkComp (serverThread portVar toSend)
|
||||
|
||||
-- Client
|
||||
testClient None "test.unison.cloud" portVar |> toEither |> checkError |> emit
|
||||
|
||||
kill.impl tid
|
||||
|
||||
runTest test
|
||||
|
||||
@ -164,18 +206,25 @@ testCNReject _ =
|
||||
-- Server
|
||||
portVar = !MVar.newEmpty
|
||||
toSend = "12345"
|
||||
forkComp (serverThread portVar toSend)
|
||||
tid = forkComp (serverThread portVar toSend)
|
||||
unsafeRun! '(printLine "started tid")
|
||||
|
||||
|
||||
-- Client
|
||||
testClient None "wrong.host.name" portVar |> toEither |> checkError |> emit
|
||||
unsafeRun! '(printLine "started client")
|
||||
|
||||
kill.impl tid
|
||||
unsafeRun! '(printLine "killed")
|
||||
|
||||
runTest test
|
||||
```
|
||||
|
||||
```ucm
|
||||
.> add
|
||||
.> io.test testConnectSelfSigned
|
||||
.> io.test testCAReject
|
||||
.> io.test testCNReject
|
||||
--- STU: I'm commenting out this because there is a problem with Tls.handshake, see #2834
|
||||
|
||||
--- .> add
|
||||
--- .> io.test testConnectSelfSigned
|
||||
--- .> io.test testCAReject
|
||||
--- .> io.test testCNReject
|
||||
```
|
||||
|
@ -2,12 +2,33 @@
|
||||
|
||||
```unison
|
||||
-- generated with:
|
||||
-- openssl req -newkey rsa:2048 -subj '/CN=test.unison.cloud/O=Unison/C=US' -nodes -keyout key.pem -x509 -days 365 -out cert.pem
|
||||
-- openssl req -newkey rsa:2048 -subj '/CN=test.unison.cloud/O=Unison/C=US' -nodes -keyout key.pem -x509 -days 3650 -out cert.pem
|
||||
|
||||
self_signed_key_pem = "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDBrpp+SxjCz/aQ\nQXT2hKXrT3lZ3Ek1VT/kgNre3J/RUyNZjZnZXCMyNjZ4IxYKxcCAIgGtfFpgvkzT\n5NRGZKLlSX4Y8HayV3gdEXO9hq4w/i/s+I0tOAJkVtHolXrrziZ7/4NZwMTbbqhO\n5hHHhbtBIpvNSw8el3AY3APkQ37+wM3fbvyeuG0ekoLqTa371W+/Z7pOi7QXYGEa\n8YHSNkuRKY46C4Y8oeWHOlSbQKu151GLuyQu74bnecGDN4KBdz9nyyKCCTpBsJpU\ni9Ozq3cps5L8dnN1zUNgaTyWp9kO3vbaTU8MY7p/dc7hNJ8pmGtSiiSs1xvni4Xl\nCBXBesxTAgMBAAECggEAAUtfcPSjh7nIFhK562PbkAUJ9JXKT3bwZGCQFek3kDiU\nBecyXgeFnLJMDuV9IjlMHg8cH8Ky/+6FqOzglk/Z3tps41HIGU0IWnlhYqThySYJ\nv/WxS9oR+gWyhXFqTuUj0LRWdmUZa7YDnfNfrwuvwrGuhOK5iSTN9PyTchUZZi50\ntxcNS/C3rk63c7TZLfuwxwGoUCeJvZZ/rmeVchhsuoo3QdSW0Aee7UtFtnvBfLCK\nXKdz+3q49fLZlDyx9/olJh+TY7GuF+G/LSfyQGi85beQhkXUH8/gIQIRI8INIEPB\n0XeTlv7Sgw5upqplJvHCXjAa+jz/Mo87znXBTMoIIQKBgQDorAlZCjzKxGDIaZoD\nDBXYzhSnnIhthThW4edCQ9/ZnJpX4vdTw4FngW504d8SPStMCYeBeMt8iwTczI4W\nHfK+AlVTlPfH/9NnIVADqqr9kobJW6782MYSW2/758d+L5bq8NGATyh8nPll9joN\nYAk7tNO2bGO2bEk2DbZMf3qnOQKBgQDVGdD005kUT3D+DfgeLTGzwk/2wCCPjoJ5\n6fsjsFAeZWU/qioIB3xHt1w8NsT6O+7XOKp/GRbsvsJR9Z/zmA3Ii5yrHYn48UzM\n+UyGLv+2HCpO+8A3szz/aDhKIxNFpXyZzvOXdtqBwTQbICOW2WRWOOgDrS2W1i9l\nD69xRLqj6wKBgBW0xwJ5hAZen7DSuT2DiR46y45/efLNtN3WIV77OgzxIS0FzZEQ\n8ieX2Zgp4kevUTS8xtl7TXCG/6MhqjfB/31edltf0GXmJfC/GNneuCkD3HM4jHCm\nQIRB54aWrvPEuM2ePc08lUha1KGAgRXyWaoqSn4ASqUgIQxb5x/n3KdxAoGAXlD0\nyMc2Q2T9r5PjMwfxrYvc9GsIfkEmwmqqupr4etuJumnH/JHDkcI30nazK8WG6j6s\nR2CFYvby7m92AcxUnWQdTSbfwAycX0QfeGwoxSMmHpsR8hUkdC5ea4Gmr/aUdUbB\nTVJPV4p5U2AgIE3LONYq6iWlvdLCW0pb7hfrO00CgYAb8bXz9BNow4soEkSbQysg\n4sGAr1+iSPY+ErffKRDpcFRnWcQdnTfI4xd8bgnC6OZwVpLbRZaZf3opDJ+axWqa\nEgAeHErTDY4R8aMecvyQj780sQ35kVq4VK0rSQyiKRBcjEust8UEzwYsUog2ysN0\n3zLHVEvFTfwOSctnEQRw1w==\n-----END PRIVATE KEY-----\n"
|
||||
join strs = List.foldLeft (a -> b -> b ++ a ++ "\n") "" strs
|
||||
|
||||
self_signed_cert_pem = "-----BEGIN CERTIFICATE-----\nMIIDVTCCAj2gAwIBAgIUZI9WPZk1rv2Sx5XSK17BZSV4t7gwDQYJKoZIhvcNAQEL\nBQAwOjEaMBgGA1UEAwwRdGVzdC51bmlzb24uY2xvdWQxDzANBgNVBAoMBlVuaXNv\nbjELMAkGA1UEBhMCVVMwHhcNMjEwMTIyMDkxMTE3WhcNMjIwMTIyMDkxMTE3WjA6\nMRowGAYDVQQDDBF0ZXN0LnVuaXNvbi5jbG91ZDEPMA0GA1UECgwGVW5pc29uMQsw\nCQYDVQQGEwJVUzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMGumn5L\nGMLP9pBBdPaEpetPeVncSTVVP+SA2t7cn9FTI1mNmdlcIzI2NngjFgrFwIAiAa18\nWmC+TNPk1EZkouVJfhjwdrJXeB0Rc72GrjD+L+z4jS04AmRW0eiVeuvOJnv/g1nA\nxNtuqE7mEceFu0Eim81LDx6XcBjcA+RDfv7Azd9u/J64bR6SgupNrfvVb79nuk6L\ntBdgYRrxgdI2S5EpjjoLhjyh5Yc6VJtAq7XnUYu7JC7vhud5wYM3goF3P2fLIoIJ\nOkGwmlSL07Ordymzkvx2c3XNQ2BpPJan2Q7e9tpNTwxjun91zuE0nymYa1KKJKzX\nG+eLheUIFcF6zFMCAwEAAaNTMFEwHQYDVR0OBBYEFFE3RQYASDWtwSdXL+qtQrjy\nH4SZMB8GA1UdIwQYMBaAFFE3RQYASDWtwSdXL+qtQrjyH4SZMA8GA1UdEwEB/wQF\nMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAH7D8W68cR0QvNNPugCY7lPvA/F94Qam\nwCC2A55edcagfjqFy77xx4Ljrd2TC19yiSzyeeJ+YuohbcipLce90BaaaiYq9aah\n5DICDCUhm1qbhJzqNB2Lqgl4aN+jRMeRVC+rpQBYBNmdPBqdv/k+T2uyghwmLWXe\n/AxCjCLA0zoYzOMytS86veD6CQbF5DpSTZx5dyZTeGhk2izhoM8cgiu+/7YncAbJ\nt7b7UT5Yu3+z1hAdUF5Q21bkEksGBC8UW0G0PMy8XNRMuMsz+2LC39u3u7QyX/+e\nuQGST3aCreV27zd0lrF8LHjwD2XcjVVzHy46VYQvf1r+6gatedDBjqc=\n-----END CERTIFICATE-----\n"
|
||||
self_signed_key_pem="-----BEGIN PRIVATE KEY-----\nMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDtV0Lqk9i5DKJG\ne5zwDFuxHxSxhOygCuq6Jl4xonsjl4hdvXxUUiuqxGGbv4x9HSvavpHwyriGiIRQ\noIjanWiNK9Jp6VDYWOvErnTG/+Rfm1vCoUKQvn8lDrD9knSPUoTz3Cz7JS8FE/rr\nFR3IRyXa0gpXmvIwX16SeCS/Lb/Le9o1HJh9DrkxVyoFq3zlX1OE0AVV0a014IDB\nNprqLITwiVzyDPQkP8rbJF9WPI5afzW8+3+v5UanIFknOOPaJl8pf3gmqI5g8fxk\n/SSMlPgnLd1Fi7h90gBygdpJw3do3/ZA1IOvmFQ+LXE1xtqU1Ay3f3At3DiJgTxP\n8mwBYdtdAgMBAAECggEBAMo85QRF3xIvtcchZeUWYrtWpKdvgMIPC1x7fSAGN69o\nXAakg+DF8/ebRyET435o8QmAAZOQ6hOZGEYrxPGj14cTpEQjT4RKoPwDO/al7c+Z\n7mK2TqZP7L+C+UXZGgFWa3vwTVPjp2FIWTMf1zTli1geSjnECkM1wLxGK+nL7fZQ\nesHXPkJJG5AqzA84bJ/fY5OQ/dfcCxnHEv5XpHPq6VFgXg7jtcNbr1R9EBiQfreN\nU7Hd38R77jYjL1fT71HwEUQ0cwavfxTu0jZFXJxEC7CC1J65QXUguZXLf9vwgSB0\nm0gZgeJlQ905bDJrxUcqCFxdROy/SndP6qFnJSCsfwECgYEA+2cld/WCieUGstJd\njsIrJ6f/e+uuOSTnGTtnsBX6KoiHdcg3sVVVK18xI9El9V+YX9SjN37XeGFe/Wzu\ngE3M4A3Jqz7cgdNj/PaKjqQwJWNbcJnL5ku6eQvcAIpc5gAZxXVCPIbY1ZpeYcsh\nMwr3cOEpQu8UVFBbn/OeJ1r07dECgYEA8a5J3Ls5PSxXq8NDrkAxt3vUJIWLGQQJ\nbV2aGDI2XP2N+vh2WML9rlFeyyBOeRxK9TsErVOaEeOcQZV97//fzIGxCU+SXyiC\nnVMXT2U1mzOu5qPfzLO5Ga4sunxqKDman6NM2IPw2NPA7zMWNQMEIHAerwYZzjm5\nB5tFcMA8e80CgYBgF8rwkTz2LD5lN5dfK8SHAeXbnfgYC4zxzg0R9zSJ8WmlkYQI\nGk/VpisIP7c8lO+PIZ3JZohBkSZXw71d+V7n/R0qgXqTfRNo62uGnidxAws+fOq8\n+hEql2feJQThPQScvvc0X26eJsUQqC3mbripwsacuPmSSKzc9Kds741TIQKBgQCd\nXnG2CytATAliTKlbY218HmOKzHJAfcJttk9KhhekAW5cB0F4lq98vHtPJOA0OFoO\nyLlI63EdSOpMQj1Y83IUxjYy699Rmx1BuAMrral0P/kZMYfe0QAsWp/BZpXxT2EB\npeG58l/3sBqnJsrFBgu/24H/UaeoAyoaa96Rhntb2QKBgQCSEkcUnzTvoUyMFN14\n8NttxOUZiSsCmgoXk6Rk2QKyCPsJocGS4BffGt3kOMcotz/0YsvM1TBBLB7vIaAy\nE1eWLBxK4yYeS8dKXwiCZn170yaJyjoBwZC1RgqQiKa5Y22Di7KjJoMa4Da8Tk4z\nFbE5dBApbLhvNTyQ7BHZxlfmdg==\n-----END PRIVATE KEY-----"
|
||||
|
||||
self_signed_cert_pem2 = join [
|
||||
"-----BEGIN CERTIFICATE-----",
|
||||
"MIIDVTCCAj2gAwIBAgIUdMNT5sYMfDJYH48Rh8LrlN+5wwgwDQYJKoZIhvcNAQEL",
|
||||
"BQAwOjEaMBgGA1UEAwwRdGVzdC51bmlzb24uY2xvdWQxDzANBgNVBAoMBlVuaXNv",
|
||||
"bjELMAkGA1UEBhMCVVMwHhcNMjIwMTI0MjAxNzQ2WhcNMzIwMTIyMjAxNzQ2WjA6",
|
||||
"MRowGAYDVQQDDBF0ZXN0LnVuaXNvbi5jbG91ZDEPMA0GA1UECgwGVW5pc29uMQsw",
|
||||
"CQYDVQQGEwJVUzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAO1XQuqT",
|
||||
"2LkMokZ7nPAMW7EfFLGE7KAK6romXjGieyOXiF29fFRSK6rEYZu/jH0dK9q+kfDK",
|
||||
"uIaIhFCgiNqdaI0r0mnpUNhY68SudMb/5F+bW8KhQpC+fyUOsP2SdI9ShPPcLPsl",
|
||||
"LwUT+usVHchHJdrSClea8jBfXpJ4JL8tv8t72jUcmH0OuTFXKgWrfOVfU4TQBVXR",
|
||||
"rTXggME2muoshPCJXPIM9CQ/ytskX1Y8jlp/Nbz7f6/lRqcgWSc449omXyl/eCao",
|
||||
"jmDx/GT9JIyU+Cct3UWLuH3SAHKB2knDd2jf9kDUg6+YVD4tcTXG2pTUDLd/cC3c",
|
||||
"OImBPE/ybAFh210CAwEAAaNTMFEwHQYDVR0OBBYEFIfwxpuqtqxfCpaJGW32jH2J",
|
||||
"NbnYMB8GA1UdIwQYMBaAFIfwxpuqtqxfCpaJGW32jH2JNbnYMA8GA1UdEwEB/wQF",
|
||||
"MAMBAf8wDQYJKoZIhvcNAQELBQADggEBAKh7EDo5XjSd6J190WGH3V8v49J0Sh8M",
|
||||
"P7APe1eL8eTkW1Vh7/QCOhRpkSnyCz2OxJjjeFVAsCO3aLxlRM6wQZQKXu45iM2U",
|
||||
"iPmv7ECS5xUn7LqRZd/JG1P6jvRPtBC1+oqA+NNDe27wzQp3rWyDG3pWZga8jJfW",
|
||||
"q+2xQ+s6GfzszxYZ/8MLn4zaUSymnOA+70yQ8czXkSO7MT2jJ7QDX8jxuJPZZARW",
|
||||
"uXeAYPRqD+b4MjdBATEtxgPTDWEi8gtfHFGUgInFhD4hOu+D3NLiE6lfR5brUqpQ",
|
||||
"Z4v8prCI8OjGSUx1dIJhqQHB5O0vdaxO0hkVdfqDVE93UrGBPwBRDlo=",
|
||||
"-----END CERTIFICATE-----"]
|
||||
```
|
||||
|
||||
# Using an alternative certificate store
|
||||
@ -15,7 +36,7 @@ self_signed_cert_pem = "-----BEGIN CERTIFICATE-----\nMIIDVTCCAj2gAwIBAgIUZI9WPZk
|
||||
First lets make sure we can load our cert and private key
|
||||
|
||||
```unison
|
||||
test> match (decodeCert.impl (toUtf8 self_signed_cert_pem) with
|
||||
test> match (decodeCert.impl (toUtf8 self_signed_cert_pem2) with
|
||||
Left (Failure _ t _) -> [Fail t]
|
||||
Right _ -> [Ok "succesfully decoded self_signed_pem"]
|
||||
|
||||
@ -34,7 +55,7 @@ test> match (decodeCert.impl (toUtf8 self_signed_cert_pem) with
|
||||
Now evaluating any watch expressions (lines starting with
|
||||
`>`)... Ctrl+C cancels.
|
||||
|
||||
1 | test> match (decodeCert.impl (toUtf8 self_signed_cert_pem) with
|
||||
1 | test> match (decodeCert.impl (toUtf8 self_signed_cert_pem2) with
|
||||
|
||||
✅ Passed succesfully decoded self_signed_pem
|
||||
|
||||
@ -53,7 +74,7 @@ serverThread portVar toSend = 'let
|
||||
go: '{io2.IO, Exception}()
|
||||
go = 'let
|
||||
-- load our self signed cert
|
||||
cert = decodeCert (toUtf8 self_signed_cert_pem)
|
||||
cert = decodeCert (toUtf8 self_signed_cert_pem2)
|
||||
|
||||
-- assume there is exactly one key decoded from our Bytes
|
||||
key = match (decodePrivateKey (toUtf8 self_signed_key_pem)) with k +: _ -> k
|
||||
@ -82,9 +103,13 @@ serverThread portVar toSend = 'let
|
||||
-- attach TLS to our TCP connection
|
||||
tls = newServer tlsconfig sock'
|
||||
|
||||
printLine "oooooooooooooooo"
|
||||
-- try to handshake the TLS connection with the client
|
||||
handshake tls
|
||||
match handshake.impl tls with
|
||||
Right _ -> printLine "no error on server side"
|
||||
Left (Failure _ t _) -> printLine ("error " ++ t)
|
||||
|
||||
printLine "iiiiiiiiiiiiiii"
|
||||
-- send our message over our tls channel
|
||||
send tls (toUtf8 toSend)
|
||||
terminate tls
|
||||
@ -108,17 +133,22 @@ testClient cert hostname portVar _ =
|
||||
port = take portVar
|
||||
|
||||
-- create a tcp connection with the server
|
||||
|
||||
watch ("client connecting to port: " ++ (toText port)) ()
|
||||
sock = clientSocket "127.0.0.1" (Nat.toText port)
|
||||
|
||||
-- attach the TLS client to the TCP socket
|
||||
tls = newClient tlsconfig sock
|
||||
watch ("client connecting to port: " ++ (toText port)) ()
|
||||
|
||||
printLine "5555555555555555555"
|
||||
-- verify that the server presents us with a certificate chain for
|
||||
-- test.unison.cloud originating with a certificate we trust, and
|
||||
-- that the server can use a compatible TLS version and cipher
|
||||
handshake tls
|
||||
match handshake.impl tls with
|
||||
Right _ -> printLine "no eeror on client side"
|
||||
Left (Failure _ t _) -> printLine ("error " ++ t)
|
||||
|
||||
printLine "666666666666666666"
|
||||
-- receive a message from the server
|
||||
fromUtf8 (receive tls)
|
||||
|
||||
@ -128,14 +158,17 @@ testConnectSelfSigned _ =
|
||||
-- Server
|
||||
portVar = !MVar.newEmpty
|
||||
toSend = "12345"
|
||||
forkComp (serverThread portVar toSend)
|
||||
tid = forkComp (serverThread portVar toSend)
|
||||
|
||||
-- Client
|
||||
cert = decodeCert (toUtf8 self_signed_cert_pem)
|
||||
cert = decodeCert (toUtf8 self_signed_cert_pem2)
|
||||
received = !(testClient (Some cert) "test.unison.cloud" portVar)
|
||||
|
||||
kill.impl tid
|
||||
|
||||
expectU "should have reaped what we've sown" toSend received
|
||||
|
||||
|
||||
runTest test
|
||||
|
||||
-- this client will trust whatever certs the system trusts
|
||||
@ -155,11 +188,12 @@ testCAReject _ =
|
||||
-- Server
|
||||
portVar = !MVar.newEmpty
|
||||
toSend = "12345"
|
||||
forkComp (serverThread portVar toSend)
|
||||
tid = forkComp (serverThread portVar toSend)
|
||||
|
||||
-- Client
|
||||
testClient None "test.unison.cloud" portVar |> toEither |> checkError |> emit
|
||||
|
||||
kill.impl tid
|
||||
|
||||
runTest test
|
||||
|
||||
@ -178,11 +212,16 @@ testCNReject _ =
|
||||
-- Server
|
||||
portVar = !MVar.newEmpty
|
||||
toSend = "12345"
|
||||
forkComp (serverThread portVar toSend)
|
||||
tid = forkComp (serverThread portVar toSend)
|
||||
unsafeRun! '(printLine "started tid")
|
||||
|
||||
|
||||
-- Client
|
||||
testClient None "wrong.host.name" portVar |> toEither |> checkError |> emit
|
||||
unsafeRun! '(printLine "started client")
|
||||
|
||||
kill.impl tid
|
||||
unsafeRun! '(printLine "killed")
|
||||
|
||||
runTest test
|
||||
```
|
||||
@ -206,48 +245,9 @@ testCNReject _ =
|
||||
|
||||
```
|
||||
```ucm
|
||||
.> add
|
||||
|
||||
⍟ I've added these definitions:
|
||||
|
||||
serverThread : MVar Nat -> Text -> '{IO} ()
|
||||
testCAReject : '{IO} [Result]
|
||||
testCNReject : '{IO} [Result]
|
||||
testClient : Optional SignedCert
|
||||
-> Text
|
||||
-> MVar Nat
|
||||
-> '{IO, Exception} Text
|
||||
testConnectSelfSigned : '{IO} [Result]
|
||||
|
||||
.> io.test testConnectSelfSigned
|
||||
|
||||
New test results:
|
||||
|
||||
◉ testConnectSelfSigned should have reaped what we've sown
|
||||
|
||||
✅ 1 test(s) passing
|
||||
|
||||
Tip: Use view testConnectSelfSigned to view the source of a
|
||||
test.
|
||||
|
||||
.> io.test testCAReject
|
||||
|
||||
New test results:
|
||||
|
||||
◉ testCAReject correctly rejected self-signed cert
|
||||
|
||||
✅ 1 test(s) passing
|
||||
|
||||
Tip: Use view testCAReject to view the source of a test.
|
||||
|
||||
.> io.test testCNReject
|
||||
|
||||
New test results:
|
||||
|
||||
◉ testCNReject correctly rejected self-signed cert
|
||||
|
||||
✅ 1 test(s) passing
|
||||
|
||||
Tip: Use view testCNReject to view the source of a test.
|
||||
|
||||
--- STU: I'm commenting out this because there is a problem with Tls.handshake, see #2834
|
||||
--- .> add
|
||||
--- .> io.test testConnectSelfSigned
|
||||
--- .> io.test testCAReject
|
||||
--- .> io.test testCNReject
|
||||
```
|
||||
|
18
unison-src/transcripts/boolean-op-pretty-print-2819.md
Normal file
18
unison-src/transcripts/boolean-op-pretty-print-2819.md
Normal file
@ -0,0 +1,18 @@
|
||||
Regression test for https://github.com/unisonweb/unison/pull/2819
|
||||
|
||||
```ucm:hide
|
||||
.> builtins.merge
|
||||
```
|
||||
|
||||
```unison
|
||||
hangExample : Boolean
|
||||
hangExample =
|
||||
("a long piece of text to hang the line" == "")
|
||||
&& ("a long piece of text to hang the line" == "")
|
||||
```
|
||||
|
||||
```ucm
|
||||
.> add
|
||||
.> view hangExample
|
||||
```
|
||||
|
@ -0,0 +1,35 @@
|
||||
Regression test for https://github.com/unisonweb/unison/pull/2819
|
||||
|
||||
```unison
|
||||
hangExample : Boolean
|
||||
hangExample =
|
||||
("a long piece of text to hang the line" == "")
|
||||
&& ("a long piece of text to hang the line" == "")
|
||||
```
|
||||
|
||||
```ucm
|
||||
|
||||
I found and typechecked these definitions in scratch.u. If you
|
||||
do an `add` or `update`, here's how your codebase would
|
||||
change:
|
||||
|
||||
⍟ These new definitions are ok to `add`:
|
||||
|
||||
hangExample : Boolean
|
||||
|
||||
```
|
||||
```ucm
|
||||
.> add
|
||||
|
||||
⍟ I've added these definitions:
|
||||
|
||||
hangExample : Boolean
|
||||
|
||||
.> view hangExample
|
||||
|
||||
hangExample : Boolean
|
||||
hangExample =
|
||||
("a long piece of text to hang the line" == "")
|
||||
&& ("a long piece of text to hang the line" == "")
|
||||
|
||||
```
|
@ -77,6 +77,14 @@ We can display the guide before and after adding it to the codebase:
|
||||
⧨
|
||||
100
|
||||
|
||||
also:
|
||||
|
||||
match 1 with
|
||||
1 -> "hi"
|
||||
_ -> "goodbye"
|
||||
⧨
|
||||
"hi"
|
||||
|
||||
To include a typechecked snippet of code without
|
||||
evaluating it, you can do:
|
||||
|
||||
@ -278,6 +286,14 @@ We can display the guide before and after adding it to the codebase:
|
||||
⧨
|
||||
100
|
||||
|
||||
also:
|
||||
|
||||
match 1 with
|
||||
1 -> "hi"
|
||||
_ -> "goodbye"
|
||||
⧨
|
||||
"hi"
|
||||
|
||||
To include a typechecked snippet of code without
|
||||
evaluating it, you can do:
|
||||
|
||||
@ -485,6 +501,14 @@ rendered = Pretty.get (docFormatConsole doc.guide)
|
||||
⧨
|
||||
100
|
||||
|
||||
also:
|
||||
|
||||
match 1 with
|
||||
1 -> "hi"
|
||||
_ -> "goodbye"
|
||||
⧨
|
||||
"hi"
|
||||
|
||||
To include a typechecked snippet of code without
|
||||
evaluating it, you can do:
|
||||
|
||||
@ -679,6 +703,14 @@ rendered = Pretty.get (docFormatConsole doc.guide)
|
||||
⧨
|
||||
100
|
||||
|
||||
also:
|
||||
|
||||
match 1 with
|
||||
1 -> "hi"
|
||||
_ -> "goodbye"
|
||||
⧨
|
||||
"hi"
|
||||
|
||||
To include a typechecked snippet of code without
|
||||
evaluating it, you can do:
|
||||
|
||||
@ -1795,6 +1827,29 @@ rendered = Pretty.get (docFormatConsole doc.guide)
|
||||
!Indent
|
||||
(!Lit (Right (Plain " ")))
|
||||
(!Lit (Right (Plain " ")))
|
||||
(!Annotated.Group
|
||||
(!Wrap
|
||||
(!Lit (Right (Plain "also:"))))),
|
||||
!Lit (Right (Plain "\n")),
|
||||
!Lit (Right (Plain "\n")),
|
||||
!Indent
|
||||
(!Lit (Right (Plain " ")))
|
||||
(!Lit (Right (Plain " ")))
|
||||
(!Annotated.Group
|
||||
(!Lit
|
||||
(Left
|
||||
(Eval
|
||||
(Term.Term
|
||||
(Any
|
||||
(_ ->
|
||||
(match 1 with
|
||||
1 -> "hi"
|
||||
_ -> "goodbye")))))))),
|
||||
!Lit (Right (Plain "\n")),
|
||||
!Lit (Right (Plain "\n")),
|
||||
!Indent
|
||||
(!Lit (Right (Plain " ")))
|
||||
(!Lit (Right (Plain " ")))
|
||||
(!Annotated.Group
|
||||
(!Wrap
|
||||
(!Annotated.Append
|
||||
|
@ -2,12 +2,11 @@
|
||||
.> display List.map
|
||||
|
||||
go f i as acc =
|
||||
_pattern = List.at i as
|
||||
match _pattern with
|
||||
None -> acc
|
||||
Some _pattern1 ->
|
||||
match List.at i as with
|
||||
None -> acc
|
||||
Some a ->
|
||||
use Nat +
|
||||
go f (i + 1) as (acc :+ f _pattern)
|
||||
go f (i + 1) as (acc :+ f a)
|
||||
f a -> go f 0 a []
|
||||
|
||||
```
|
||||
|
32
unison-src/transcripts/type-deps.md
Normal file
32
unison-src/transcripts/type-deps.md
Normal file
@ -0,0 +1,32 @@
|
||||
# Ensure type dependencies are properly considered in slurping
|
||||
|
||||
https://github.com/unisonweb/unison/pull/2821
|
||||
|
||||
```ucm:hide
|
||||
.> builtins.merge
|
||||
```
|
||||
|
||||
|
||||
Define a type.
|
||||
|
||||
```unison:hide
|
||||
structural type Y = Y
|
||||
```
|
||||
|
||||
```ucm:hide
|
||||
.> add
|
||||
```
|
||||
|
||||
Now, we update `Y`, and add a new type `Z` which depends on it.
|
||||
|
||||
```unison
|
||||
structural type Z = Z Y
|
||||
structural type Y = Y Nat
|
||||
```
|
||||
|
||||
Adding should fail for BOTH definitions, `Y` needs an update and `Z` is blocked by `Y`.
|
||||
```ucm:error
|
||||
.> add
|
||||
-- This shouldn't exist, because it should've been blocked.
|
||||
.> view Z
|
||||
```
|
56
unison-src/transcripts/type-deps.output.md
Normal file
56
unison-src/transcripts/type-deps.output.md
Normal file
@ -0,0 +1,56 @@
|
||||
# Ensure type dependencies are properly considered in slurping
|
||||
|
||||
https://github.com/unisonweb/unison/pull/2821
|
||||
|
||||
Define a type.
|
||||
|
||||
```unison
|
||||
structural type Y = Y
|
||||
```
|
||||
|
||||
Now, we update `Y`, and add a new type `Z` which depends on it.
|
||||
|
||||
```unison
|
||||
structural type Z = Z Y
|
||||
structural type Y = Y Nat
|
||||
```
|
||||
|
||||
```ucm
|
||||
|
||||
I found and typechecked these definitions in scratch.u. If you
|
||||
do an `add` or `update`, here's how your codebase would
|
||||
change:
|
||||
|
||||
⍟ These new definitions are ok to `add`:
|
||||
|
||||
structural type Z
|
||||
|
||||
⍟ These names already exist. You can `update` them to your
|
||||
new definition:
|
||||
|
||||
structural type Y
|
||||
(The old definition is also named builtin.Unit. I'll
|
||||
update this name too.)
|
||||
|
||||
```
|
||||
Adding should fail for BOTH definitions, `Y` needs an update and `Z` is blocked by `Y`.
|
||||
```ucm
|
||||
.> add
|
||||
|
||||
x These definitions failed:
|
||||
|
||||
Reason
|
||||
needs update structural type Y
|
||||
blocked structural type Z
|
||||
|
||||
Tip: Use `help filestatus` to learn more.
|
||||
|
||||
-- This shouldn't exist, because it should've been blocked.
|
||||
.> view Z
|
||||
|
||||
⚠️
|
||||
|
||||
The following names were not found in the codebase. Check your spelling.
|
||||
Z
|
||||
|
||||
```
|
Loading…
Reference in New Issue
Block a user