module Ecluse.Composition.BootError (
BootError (..),
StoreMaintenanceReason (..),
Advisory (..),
refuseOnThrow,
renderBootError,
renderBootErrors,
renderAdvisory,
) where
import Data.Text qualified as T
import Data.Time (NominalDiffTime)
import UnliftIO (tryAny)
import Ecluse.Config (
PolicyError,
StoreTag,
renderPolicyError,
storeTagName,
)
import Ecluse.Config.Resolve (mountKeyRef)
import Ecluse.Core.Credential (Secret)
import Ecluse.Core.Ecosystem (Ecosystem, ecosystemName)
import Ecluse.Core.Registry.Maintenance.Upstream (
ExternalConnection (externalConnectionText),
PermissionName (permissionNameText),
RepositoryName (repositoryNameText),
UndecidabilityReason (ChainBoundExceeded, NetworkFailure, NoMechanism),
UnsafeReason (ConfigurationEvidence, InsufficientPermissions),
)
import Ecluse.Core.Security (authorityLabel)
import Ecluse.Core.Security.Egress (RegistryUrl, registryUrlText)
import Ecluse.Core.Text (displayExceptionT)
data BootError
=
PolicyBootError PolicyError
|
MissingAdapter Ecosystem
|
UnresolvedCredential Ecosystem
|
QueueProviderUnavailable Text
|
QueueRegionMissing
|
QueueUrlUnrecognised Text
|
QueueEndpointMalformed Secret
|
AwsEndpointMalformed Secret
|
CodeArtifactMintFailed (NonEmpty Text) Text
|
MirrorTargetWithoutPublish Ecosystem
|
PublicationTargetWithoutPublish Ecosystem
|
FirstPartyMissing Ecosystem
|
FirstPartyWithoutPrivateUpstream Ecosystem
|
PublishStaticCredentialNeedsEdge Ecosystem StoreTag
|
PublicationTargetOnPublicUpstream Ecosystem Ecosystem Text
|
PublicationTargetOnMountEndpoint Ecosystem Ecosystem Text Text
|
MirrorTargetOnPublicUpstream Ecosystem Ecosystem Text
|
MirrorTargetOnMountEndpoint Ecosystem Ecosystem Text Text
|
PrivateUpstreamOnPublicUpstream Ecosystem Text
|
PrivateUpstreamUnsafe Ecosystem UnsafeReason
|
PrivateUpstreamProbeFailed Ecosystem Text
|
StoreTagConflict Ecosystem Text Ecosystem Text Text
|
MemoryPlanOverrideUnsafe [Text]
|
SplitRoleNeedsDurableQueue Text
|
MirrorRoleWithoutMirroring
|
MirrorQueueUnavailable Text
|
AdvisorySyncUnavailable Text
|
StoreMaintenanceUnavailable Ecosystem StoreMaintenanceReason
|
DredgerQuotaScopeConflict Text Text Text
|
DredgerChunkPauseBeneathFloor NominalDiffTime NominalDiffTime
|
AdvisoryDenyWithoutStore Ecosystem (NonEmpty Text)
|
PilotWithoutEcosystem
|
ProgressWindowNotPositive Int
|
ProgressWindowNotBelowServeCap Int Int
|
MinProgressBytesNotPositive Int
deriving stock (BootError -> BootError -> Bool
(BootError -> BootError -> Bool)
-> (BootError -> BootError -> Bool) -> Eq BootError
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: BootError -> BootError -> Bool
== :: BootError -> BootError -> Bool
$c/= :: BootError -> BootError -> Bool
/= :: BootError -> BootError -> Bool
Eq, Int -> BootError -> ShowS
[BootError] -> ShowS
BootError -> String
(Int -> BootError -> ShowS)
-> (BootError -> String)
-> ([BootError] -> ShowS)
-> Show BootError
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> BootError -> ShowS
showsPrec :: Int -> BootError -> ShowS
$cshow :: BootError -> String
show :: BootError -> String
$cshowList :: [BootError] -> ShowS
showList :: [BootError] -> ShowS
Show)
data StoreMaintenanceReason
=
NoControlPlane StoreTag
|
DeletionNotPermitted StoreTag
|
NoProtocolMaintenance
|
PrivateCacheUnavailable Text
|
ClientBuildFailed Text
deriving stock (StoreMaintenanceReason -> StoreMaintenanceReason -> Bool
(StoreMaintenanceReason -> StoreMaintenanceReason -> Bool)
-> (StoreMaintenanceReason -> StoreMaintenanceReason -> Bool)
-> Eq StoreMaintenanceReason
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: StoreMaintenanceReason -> StoreMaintenanceReason -> Bool
== :: StoreMaintenanceReason -> StoreMaintenanceReason -> Bool
$c/= :: StoreMaintenanceReason -> StoreMaintenanceReason -> Bool
/= :: StoreMaintenanceReason -> StoreMaintenanceReason -> Bool
Eq, Int -> StoreMaintenanceReason -> ShowS
[StoreMaintenanceReason] -> ShowS
StoreMaintenanceReason -> String
(Int -> StoreMaintenanceReason -> ShowS)
-> (StoreMaintenanceReason -> String)
-> ([StoreMaintenanceReason] -> ShowS)
-> Show StoreMaintenanceReason
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> StoreMaintenanceReason -> ShowS
showsPrec :: Int -> StoreMaintenanceReason -> ShowS
$cshow :: StoreMaintenanceReason -> String
show :: StoreMaintenanceReason -> String
$cshowList :: [StoreMaintenanceReason] -> ShowS
showList :: [StoreMaintenanceReason] -> ShowS
Show)
data Advisory
=
MirrorTargetOnPrivateUpstream Ecosystem Ecosystem RegistryUrl
|
MirrorTargetOnOwnPublicationTarget Ecosystem RegistryUrl
|
DredgerQuotaOverrideUnmatched Text
|
PrivateUpstreamUndecided Ecosystem UndecidabilityReason
deriving stock (Advisory -> Advisory -> Bool
(Advisory -> Advisory -> Bool)
-> (Advisory -> Advisory -> Bool) -> Eq Advisory
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Advisory -> Advisory -> Bool
== :: Advisory -> Advisory -> Bool
$c/= :: Advisory -> Advisory -> Bool
/= :: Advisory -> Advisory -> Bool
Eq, Int -> Advisory -> ShowS
[Advisory] -> ShowS
Advisory -> String
(Int -> Advisory -> ShowS)
-> (Advisory -> String) -> ([Advisory] -> ShowS) -> Show Advisory
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Advisory -> ShowS
showsPrec :: Int -> Advisory -> ShowS
$cshow :: Advisory -> String
show :: Advisory -> String
$cshowList :: [Advisory] -> ShowS
showList :: [Advisory] -> ShowS
Show)
refuseOnThrow :: (Text -> BootError) -> IO a -> IO (Either [BootError] a)
refuseOnThrow :: forall a. (Text -> BootError) -> IO a -> IO (Either [BootError] a)
refuseOnThrow Text -> BootError
refusal IO a
action = (SomeException -> [BootError])
-> Either SomeException a -> Either [BootError] a
forall a b c. (a -> b) -> Either a c -> Either b c
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first (BootError -> [BootError]
forall a. a -> [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure (BootError -> [BootError])
-> (SomeException -> BootError) -> SomeException -> [BootError]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> BootError
refusal (Text -> BootError)
-> (SomeException -> Text) -> SomeException -> BootError
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SomeException -> Text
forall e. Exception e => e -> Text
displayExceptionT) (Either SomeException a -> Either [BootError] a)
-> IO (Either SomeException a) -> IO (Either [BootError] a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IO a -> IO (Either SomeException a)
forall (m :: * -> *) a.
MonadUnliftIO m =>
m a -> m (Either SomeException a)
tryAny IO a
action
renderBootErrors :: [BootError] -> Text
renderBootErrors :: [BootError] -> Text
renderBootErrors = [Text] -> Text
T.unlines ([Text] -> Text) -> ([BootError] -> [Text]) -> [BootError] -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (BootError -> Text) -> [BootError] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map BootError -> Text
renderBootError
renderBootError :: BootError -> Text
renderBootError :: BootError -> Text
renderBootError = \case
PolicyBootError PolicyError
err -> PolicyError -> Text
renderPolicyError PolicyError
err
MissingAdapter Ecosystem
eco ->
Text
"mount " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Ecosystem -> Text
ecosystemName Ecosystem
eco Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" has no adapter wired in this build"
UnresolvedCredential Ecosystem
eco ->
Text
"mount "
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Ecosystem -> Text
ecosystemName Ecosystem
eco
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" has no initialised mirror-write credential in this build"
QueueProviderUnavailable Text
provider ->
Text
"mirror queue provider "
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
provider
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" (named by the ECLUSE_QUEUE__URL shape) is not available in this build"
BootError
QueueRegionMissing ->
Text
"the SQS endpoint override (AWS_ENDPOINT_URL_SQS) is set but AWS_REGION is not: an emulator or VPC endpoint does not carry its region, so AWS_REGION must scope it"
QueueUrlUnrecognised Text
url ->
Text
"ECLUSE_QUEUE__URL names no queue backend this build knows: "
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
url
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" (expected an SQS queue URL, https://sqs.{region}.amazonaws.com/{account}/{queue}, or a Pub/Sub topic resource, projects/{project}/topics/{topic}; unset it to run the bounded in-memory queue)"
QueueEndpointMalformed{} ->
Text
"the SQS endpoint override (AWS_ENDPOINT_URL_SQS) is not a valid endpoint URL"
AwsEndpointMalformed{} ->
Text
"the AWS endpoint override (AWS_ENDPOINT_URL) is not a valid endpoint URL"
CodeArtifactMintFailed NonEmpty Text
targets Text
detail ->
Text
"credential provider codeartifact for "
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> [Text] -> Text
T.intercalate Text
", " (NonEmpty Text -> [Text]
forall a. NonEmpty a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList NonEmpty Text
targets)
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" failed to mint an initial token at boot: "
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
detail
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" (a transient AWS error may clear on retry. A permanent one, such as a bad domain or region or a missing permission, must be fixed)"
MirrorTargetWithoutPublish Ecosystem
eco ->
Ecosystem -> Text -> Text
mountKeyRef Ecosystem
eco Text
"mirrorTarget"
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" is set but this build writes nothing for the "
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Ecosystem -> Text
ecosystemName Ecosystem
eco
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" protocol: the mirror would drain its queue with no way to publish, so the mount is refused rather than served with a mirror that fails every job."
PublicationTargetWithoutPublish Ecosystem
eco ->
Ecosystem -> Text -> Text
mountKeyRef Ecosystem
eco Text
"publicationTarget"
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" is set but this build writes nothing for the "
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Ecosystem -> Text
ecosystemName Ecosystem
eco
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" protocol: a publish would have no adapter to relay through, so the mount is refused rather than served with a publish route that refuses every attempt."
FirstPartyMissing Ecosystem
eco ->
Ecosystem -> Text -> Text
mountKeyRef Ecosystem
eco Text
"publicationTarget" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" is set but " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Ecosystem -> Text -> Text
mountKeyRef Ecosystem
eco Text
"firstParty" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" is not: a publication target needs the namespaces this deployment owns, written in the ecosystem's own shape (npm scopes such as @acme, PyPI distribution names and acme-* prefixes), for the anti-shadowing guard."
FirstPartyWithoutPrivateUpstream Ecosystem
eco ->
Ecosystem -> Text -> Text
mountKeyRef Ecosystem
eco Text
"firstParty"
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" is set but "
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Ecosystem -> Text -> Text
mountKeyRef Ecosystem
eco Text
"privateUpstream"
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" is not: first-party names resolve from the private upstream alone. Configure privateUpstream for these names, or remove firstParty."
PublishStaticCredentialNeedsEdge Ecosystem
eco StoreTag
tag ->
Ecosystem -> Text -> Text
mountKeyRef Ecosystem
eco (Text
"publicationTarget." Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> StoreTag -> Text
storeTagName StoreTag
tag Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
".token")
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" is set but ECLUSE_SERVER__AUTH_TOKEN is not: a static publish credential needs a verifiable inbound edge."
PublicationTargetOnPublicUpstream Ecosystem
eco Ecosystem
other Text
url ->
Ecosystem -> Text -> Text
mountKeyRef Ecosystem
eco Text
"publicationTarget"
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" ("
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
url
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
") shares a host with "
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Ecosystem -> Text -> Text
mountKeyRef Ecosystem
other Text
"publicUpstream"
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
": a publish carries the publisher's own credential, which must never reach a public upstream, so point it at a registry that shares a host with no public upstream"
PublicationTargetOnMountEndpoint Ecosystem
eco Ecosystem
other Text
key Text
url ->
Ecosystem -> Text -> Text
mountKeyRef Ecosystem
eco Text
"publicationTarget"
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" is also "
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Ecosystem -> Text -> Text
mountKeyRef Ecosystem
other Text
key
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" ("
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
url
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"): point it at a registry that holds no other role, so a publish is never relayed into one"
MirrorTargetOnPublicUpstream Ecosystem
eco Ecosystem
other Text
url ->
Ecosystem -> Text -> Text
mountKeyRef Ecosystem
eco Text
"mirrorTarget"
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" ("
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
url
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
") shares a host with "
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Ecosystem -> Text -> Text
mountKeyRef Ecosystem
other Text
"publicUpstream"
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
": the mirror write carries this proxy's own credential, which must never reach a public upstream, so point it at a registry that shares a host with no public upstream"
MirrorTargetOnMountEndpoint Ecosystem
eco Ecosystem
other Text
key Text
url ->
Ecosystem -> Text -> Text
mountKeyRef Ecosystem
eco Text
"mirrorTarget"
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" is also "
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Ecosystem -> Text -> Text
mountKeyRef Ecosystem
other Text
key
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" ("
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
url
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"): the Dredger permanently deletes from the mirror target, so point it at a registry that holds no other role, or run no Dredger against this configuration"
PrivateUpstreamOnPublicUpstream Ecosystem
eco Text
url ->
Ecosystem -> Text -> Text
mountKeyRef Ecosystem
eco Text
"privateUpstream"
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" and "
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Ecosystem -> Text -> Text
mountKeyRef Ecosystem
eco Text
"publicUpstream"
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" resolve to the same registry ("
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
url
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"): the private leg forwards caller credentials and admits versions without the public rules. Configure distinct repositories."
PrivateUpstreamUnsafe Ecosystem
eco (ConfigurationEvidence RepositoryName
repository ExternalConnection
connection) ->
Ecosystem -> Text -> Text
mountKeyRef Ecosystem
eco Text
"privateUpstream"
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" admits public content: repository "
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> RepositoryName -> Text
repositoryNameText RepositoryName
repository
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" carries the external connection "
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> ExternalConnection -> Text
externalConnectionText ExternalConnection
connection
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
", so public packages reach clients as trusted private content, past the public rules, the integrity floor and the quarantine. Remove that connection from the repository and its upstream chain, or point privateUpstream at a repository that has none"
PrivateUpstreamUnsafe Ecosystem
eco (InsufficientPermissions PermissionName
permission) ->
Ecosystem -> Text -> Text
mountKeyRef Ecosystem
eco Text
"privateUpstream"
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" could not be read: this role's identity is refused "
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> PermissionName -> Text
permissionNameText PermissionName
permission
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" on that repository or one in its upstream chain. Or this role resolved no identity at all. An identity that cannot ask cannot clear the repository, so give this role an AWS identity carrying that grant, or point privateUpstream at a repository this role may read"
PrivateUpstreamProbeFailed Ecosystem
eco Text
detail ->
Text
"the check for a connection to a public registry on "
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Ecosystem -> Text -> Text
mountKeyRef Ecosystem
eco Text
"privateUpstream"
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" threw: "
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
detail
StoreTagConflict Ecosystem
eco Text
key Ecosystem
other Text
otherKey Text
url ->
Ecosystem -> Text -> Text
mountKeyRef Ecosystem
eco Text
key
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" and "
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Ecosystem -> Text -> Text
mountKeyRef Ecosystem
other Text
otherKey
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" name the same registry ("
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
url
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
") under two tags: one store has one backend, so declare both endpoints under the same tag"
MemoryPlanOverrideUnsafe [Text]
details ->
Text
"memory plan refused: " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> [Text] -> Text
T.intercalate Text
"; " [Text]
details
SplitRoleNeedsDurableQueue Text
invocation ->
Text
invocation
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" splits the mirror worker from the proxy, but ECLUSE_QUEUE__URL is unset, so mirroring runs on the bounded in-memory queue whose jobs never leave the process that enqueued them: point ECLUSE_QUEUE__URL at a durable queue, or run the single-process ecluse proxy"
BootError
MirrorRoleWithoutMirroring ->
Text
"ecluse mirror runs the mirror worker alone, but no mount declares a mirror target, so it has nothing to mirror: set ECLUSE_MOUNTS__<ECOSYSTEM>__MIRROR_TARGET__<TAG>__URL, or run a role that needs no mirror queue"
MirrorQueueUnavailable Text
detail ->
Text
"the mirror queue backend named by ECLUSE_QUEUE__URL could not be built at boot: "
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
detail
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" (a transient AWS or network error may clear on retry. A permanent one, such as unresolvable AWS credentials or a queue URL naming no reachable queue, must be fixed)"
AdvisorySyncUnavailable Text
detail ->
Text
"the advisory sync named by ECLUSE_ADVISORIES__URL could not be prepared at boot: "
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
detail
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" (a transient AWS or network error may clear on retry. A permanent one, such as unresolvable AWS credentials or an ECLUSE_ADVISORIES__DATA_DIR this process cannot create, must be fixed)"
StoreMaintenanceUnavailable Ecosystem
eco (PrivateCacheUnavailable Text
detail) ->
Ecosystem -> Text -> Text
mountKeyRef Ecosystem
eco Text
"privateUpstream" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" has no usable observation backend: " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
detail
StoreMaintenanceUnavailable Ecosystem
eco StoreMaintenanceReason
reason ->
Ecosystem -> Text -> Text
mountKeyRef Ecosystem
eco Text
"mirrorTarget"
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" has no usable store maintenance backend: "
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Ecosystem -> StoreMaintenanceReason -> Text
renderStoreMaintenanceReason Ecosystem
eco StoreMaintenanceReason
reason
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" (the Dredger deletes from every mount's mirror target, so it refuses rather than starting against a store it cannot sweep)"
DredgerQuotaScopeConflict Text
scope Text
oneKey Text
otherKey ->
Text
"dredger.quotaOverrides: "
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text
authorityLabel Text
oneKey
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" and "
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text
authorityLabel Text
otherKey
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" both define the capacity pool \""
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text
scopeLabel Text
scope
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\" and define it differently: one pool takes one definition, so give the two entries the same quotas and weights or separate scopes"
DredgerChunkPauseBeneathFloor NominalDiffTime
configured NominalDiffTime
floorPause ->
Text
"ECLUSE_DREDGER__CHUNK_PAUSE (dredger.chunkPause) is "
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> NominalDiffTime -> Text
forall b a. (Show a, IsString b) => a -> b
show NominalDiffTime
configured
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
", beneath the floor of "
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> NominalDiffTime -> Text
forall b a. (Show a, IsString b) => a -> b
show NominalDiffTime
floorPause
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
": the pause between chunks is what leaves time to stop a mistaken sweep. Deletion is permanent, so the pause may be raised and never lowered"
AdvisoryDenyWithoutStore Ecosystem
eco NonEmpty Text
rules ->
Text
"mount \""
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Ecosystem -> Text
ecosystemName Ecosystem
eco
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\" enables the advisory deny rules "
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> [Text] -> Text
T.intercalate Text
", " (NonEmpty Text -> [Text]
forall a. NonEmpty a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList NonEmpty Text
rules)
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
", but ECLUSE_ADVISORIES__URL (advisories.url) is unset: those rules have no advisory database to read, so every version they evaluate would refuse. Set the advisory store and run ecluse pilot to publish an artifact for this mount, or remove these rules from its policy"
BootError
PilotWithoutEcosystem ->
Text
"ECLUSE_ADVISORIES__URL is set but no mount is declared, so ecluse pilot has no ecosystem to compile an advisory artifact for: declare the mounts this deployment serves under ECLUSE_MOUNTS__<ECOSYSTEM>__, or run a role this configuration has work for"
ProgressWindowNotPositive Int
configured ->
Text
"ECLUSE_LIMITS__PROGRESS_WINDOW (limits.progressWindow) is "
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Int -> Text
forall b a. (Show a, IsString b) => a -> b
show Int
configured
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
": the window within which an upstream must deliver its minimum bytes must be a positive number of seconds"
ProgressWindowNotBelowServeCap Int
configured Int
cap ->
Text
"ECLUSE_LIMITS__PROGRESS_WINDOW (limits.progressWindow) is "
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Int -> Text
forall b a. (Show a, IsString b) => a -> b
show Int
configured
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
", not below the "
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Int -> Text
forall b a. (Show a, IsString b) => a -> b
show Int
cap
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"-second cap on each upstream exchange of a served request: a slow upstream must fail the floor before the cap ends it, so set it below "
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Int -> Text
forall b a. (Show a, IsString b) => a -> b
show Int
cap
MinProgressBytesNotPositive Int
configured ->
Text
"ECLUSE_LIMITS__MIN_PROGRESS_BYTES (limits.minProgressBytes) is "
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Int -> Text
forall b a. (Show a, IsString b) => a -> b
show Int
configured
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
": the bytes an upstream must deliver in each progress window must be a positive count"
renderStoreMaintenanceReason :: Ecosystem -> StoreMaintenanceReason -> Text
renderStoreMaintenanceReason :: Ecosystem -> StoreMaintenanceReason -> Text
renderStoreMaintenanceReason Ecosystem
eco = \case
NoControlPlane StoreTag
tag ->
Text
"its target is a " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> StoreTag -> Text
storeTagName StoreTag
tag Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" store, which carries no store maintenance backend this build can sweep"
DeletionNotPermitted StoreTag
tag ->
Text
"its target is a "
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> StoreTag -> Text
storeTagName StoreTag
tag
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" store and "
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Ecosystem -> Text -> Text
mountKeyRef Ecosystem
eco (Text
"mirrorTarget." Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> StoreTag -> Text
storeTagName StoreTag
tag Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
".permitDeletion")
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" is not set: that key is your consent for the Dredger to delete from this store"
StoreMaintenanceReason
NoProtocolMaintenance ->
Text
"its store has no control plane, and the "
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Ecosystem -> Text
ecosystemName Ecosystem
eco
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" protocol carries no package listing or version delete for one"
PrivateCacheUnavailable Text
detail -> Text
"privateUpstream cannot be previewed: " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
detail
ClientBuildFailed Text
detail -> Text
"building its client failed: " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
detail
renderAdvisory :: Advisory -> Text
renderAdvisory :: Advisory -> Text
renderAdvisory = \case
MirrorTargetOnPrivateUpstream Ecosystem
eco Ecosystem
other RegistryUrl
url ->
Ecosystem -> Text -> RegistryUrl -> Text
mirrorCollapseLine Ecosystem
eco (Ecosystem -> Ecosystem -> Text -> Text
endpointRef Ecosystem
eco Ecosystem
other Text
"privateUpstream") RegistryUrl
url
MirrorTargetOnOwnPublicationTarget Ecosystem
eco RegistryUrl
url ->
Ecosystem -> Text -> RegistryUrl -> Text
mirrorCollapseLine Ecosystem
eco Text
"publicationTarget" RegistryUrl
url
DredgerQuotaOverrideUnmatched Text
key ->
Text
"dredger.quotaOverrides: "
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text
authorityLabel Text
key
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" names no store this deployment declares, so it paces nothing"
PrivateUpstreamUndecided Ecosystem
eco UndecidabilityReason
reason ->
Ecosystem -> Text -> Text
mountKeyRef Ecosystem
eco Text
"privateUpstream"
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" was not checked for a connection to a public registry: "
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> UndecidabilityReason -> Text
renderUndecidability UndecidabilityReason
reason
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
". A repository that aggregates a public registry serves public packages as trusted private content, so confirming that this one does not stays yours"
renderUndecidability :: UndecidabilityReason -> Text
renderUndecidability :: UndecidabilityReason -> Text
renderUndecidability = \case
UndecidabilityReason
NoMechanism -> Text
"its backend does not report the repositories and registries it aggregates"
UndecidabilityReason
NetworkFailure -> Text
"its backend did not answer"
UndecidabilityReason
ChainBoundExceeded -> Text
"its upstream chain crossed this walk's bounds before it was read whole"
mirrorCollapseLine :: Ecosystem -> Text -> RegistryUrl -> Text
mirrorCollapseLine :: Ecosystem -> Text -> RegistryUrl -> Text
mirrorCollapseLine Ecosystem
eco Text
otherRef RegistryUrl
url =
Text
"mount \""
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Ecosystem -> Text
ecosystemName Ecosystem
eco
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\": mirrorTarget and "
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
otherRef
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" resolve to the same registry ("
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> RegistryUrl -> Text
registryUrlText RegistryUrl
url
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"); the Dredger refuses this configuration, so pruning this mirror stays manual"
scopeLabel :: Text -> Text
scopeLabel :: Text -> Text
scopeLabel Text
raw
| Text
"://" Text -> Text -> Bool
`T.isInfixOf` Text
raw = Text -> Text
authorityLabel Text
raw
| Bool
otherwise = Text
raw
endpointRef :: Ecosystem -> Ecosystem -> Text -> Text
endpointRef :: Ecosystem -> Ecosystem -> Text -> Text
endpointRef Ecosystem
eco Ecosystem
other Text
key
| Ecosystem
eco Ecosystem -> Ecosystem -> Bool
forall a. Eq a => a -> a -> Bool
== Ecosystem
other = Text
key
| Bool
otherwise = Text
"mount \"" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Ecosystem -> Text
ecosystemName Ecosystem
other Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\" " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
key