Skip to content

Commit 11e82f0

Browse files
authored
Merge pull request #1485 from haskell/master
master2central 4/5/26
2 parents 374498f + ddec48f commit 11e82f0

File tree

10 files changed

+148
-81
lines changed

10 files changed

+148
-81
lines changed

.github/workflows/nix-flake.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ jobs:
3030
extra_nix_config: |
3131
trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= hackage-server.cachix.org-1:iw0iRh6+gsFIrxROFaAt5gKNgIHejKjIfyRdbpPYevY=
3232
substituters = https://cache.nixos.org/ https://hackage-server.cachix.org/
33-
- uses: cachix/cachix-action@v16
33+
- uses: cachix/cachix-action@v17
3434
with:
3535
# https://nix.dev/tutorials/continuous-integration-github-actions#setting-up-github-actions
3636
name: hackage-server
@@ -65,7 +65,7 @@ jobs:
6565
extra_nix_config: |
6666
trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= hackage-server.cachix.org-1:iw0iRh6+gsFIrxROFaAt5gKNgIHejKjIfyRdbpPYevY=
6767
substituters = https://cache.nixos.org/ https://hackage-server.cachix.org/
68-
- uses: cachix/cachix-action@v16
68+
- uses: cachix/cachix-action@v17
6969
with:
7070
# https://nix.dev/tutorials/continuous-integration-github-actions#setting-up-github-actions
7171
name: hackage-server

exes/BuildClient.hs

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -611,7 +611,7 @@ processPkg verbosity opts config docInfo = do
611611
createDirectoryIfMissing True $ resultsDirectory opts
612612
notice verbosity $ "Writing cabal.project for " ++ display (docInfoPackage docInfo)
613613
let projectFile = installDirectory opts </> "cabal.project"
614-
cabal opts "unpack" [show (docInfoTarGzURI config docInfo)] Nothing
614+
cabal opts "unpack" [cabalPackageTarget config docInfo] Nothing
615615
writeFile projectFile $ "packages: */*.cabal" -- ++ show (docInfoTarGzURI config docInfo)
616616

617617
setTestOutcome :: String -> [String] -> [String]
@@ -756,14 +756,7 @@ buildPackage verbosity opts config docInfo = do
756756
"--haddock-hoogle",
757757
-- Generate the quickjump index files
758758
"--haddock-option=--quickjump",
759-
-- For candidates we need to use the full URL, because
760-
-- otherwise cabal-install will not find the package.
761-
-- For regular packages however we need to use just the
762-
-- package name, otherwise cabal-install will not
763-
-- generate a report
764-
if docInfoIsCandidate docInfo
765-
then show (docInfoTarGzURI config docInfo)
766-
else display pkgid
759+
cabalPackageTarget config docInfo
767760
]
768761

769762
-- The installDirectory is purely temporary, while the resultsDirectory is
@@ -830,6 +823,18 @@ cabal opts cmd args moutput = do
830823
Nothing Nothing moutput moutput
831824
waitForProcess ph
832825

826+
cabalPackageTarget :: BuildConfig -> DocInfo -> String
827+
cabalPackageTarget config docInfo =
828+
-- For candidates we need to use the full URL, because
829+
-- otherwise cabal install/unpack will not find the package.
830+
-- For regular packages however we need to use just the
831+
-- package name, otherwise cabal install will not
832+
-- generate a report and cabal unpack will not use the
833+
-- latest cabal file revision from the package archive.
834+
if docInfoIsCandidate docInfo
835+
then show (docInfoTarGzURI config docInfo)
836+
else display (docInfoPackage docInfo)
837+
833838
pruneHaddockFiles :: FilePath -> IO ()
834839
pruneHaddockFiles dir = do
835840
-- Hackage doesn't support the haddock frames view, so remove it

flake.lock

Lines changed: 9 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

flake.nix

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,9 @@
4949
hackage-server.check = false;
5050

5151
Cabal-syntax = { super, ... }:
52-
{ custom = _: super.Cabal-syntax_3_16_0_0; };
52+
{ custom = _: super.Cabal-syntax_3_16_1_0; };
5353
Cabal = { super, ... }:
54-
{ custom = _: super.Cabal_3_16_0_0; };
54+
{ custom = _: super.Cabal_3_16_1_0; };
5555

5656
sandwich.check = false;
5757

src/Distribution/Server/Features/Distro.hs

Lines changed: 46 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
{-# LANGUAGE RankNTypes, NamedFieldPuns, RecordWildCards #-}
1+
{-# LANGUAGE RankNTypes, NamedFieldPuns, RecordWildCards, RecursiveDo #-}
22
module Distribution.Server.Features.Distro (
33
DistroFeature(..),
44
DistroResource(..),
@@ -20,6 +20,7 @@ import Distribution.Text (display, simpleParse)
2020
import Distribution.Package
2121

2222
import Data.List (intercalate)
23+
import qualified Data.Text as T
2324
import Text.CSV (parseCSV)
2425

2526
-- TODO:
@@ -29,7 +30,6 @@ import Text.CSV (parseCSV)
2930
data DistroFeature = DistroFeature {
3031
distroFeatureInterface :: HackageFeature,
3132
distroResource :: DistroResource,
32-
maintainersGroup :: DynamicPath -> IO (Maybe UserGroup),
3333
queryPackageStatus :: forall m. MonadIO m => PackageName -> m [(DistroName, DistroPackageInfo)]
3434
}
3535

@@ -48,8 +48,28 @@ initDistroFeature :: ServerEnv
4848
initDistroFeature ServerEnv{serverStateDir} = do
4949
distrosState <- distrosStateComponent serverStateDir
5050

51-
return $ \user core -> do
52-
let feature = distroFeature user core distrosState
51+
return $ \user@UserFeature{adminGroup, groupResourcesAt} core@CoreFeature{coreResource} -> do
52+
rec
53+
let
54+
maintainersUserGroup :: DistroName -> UserGroup
55+
maintainersUserGroup name =
56+
UserGroup {
57+
groupDesc = maintainerGroupDescription name,
58+
queryUserGroup = queryState distrosState $ GetDistroMaintainers name,
59+
addUserToGroup = updateState distrosState . AddDistroMaintainer name,
60+
removeUserFromGroup = updateState distrosState . RemoveDistroMaintainer name,
61+
groupsAllowedToAdd = [adminGroup],
62+
groupsAllowedToDelete = [adminGroup]
63+
}
64+
feature = distroFeature user core distrosState maintainersGroupResource maintainersUserGroup
65+
distroNames <- queryState distrosState EnumerateDistros
66+
(_maintainersGroup, maintainersGroupResource) <-
67+
groupResourcesAt "/distro/:package/maintainers"
68+
maintainersUserGroup
69+
(\distroName -> [("package", display distroName)])
70+
(packageInPath coreResource)
71+
distroNames
72+
5373
return feature
5474

5575
distrosStateComponent :: FilePath -> IO (StateComponent AcidState Distros)
@@ -68,15 +88,21 @@ distrosStateComponent stateDir = do
6888
distroFeature :: UserFeature
6989
-> CoreFeature
7090
-> StateComponent AcidState Distros
91+
-> GroupResource
92+
-> (DistroName -> UserGroup)
7193
-> DistroFeature
7294
distroFeature UserFeature{..}
7395
CoreFeature{coreResource=CoreResource{packageInPath}}
7496
distrosState
97+
maintainersGroupResource
98+
distroGroup
7599
= DistroFeature{..}
76100
where
77101
distroFeatureInterface = (emptyHackageFeature "distro") {
78102
featureResources =
79-
map ($ distroResource) [
103+
groupResource maintainersGroupResource
104+
: groupUserResource maintainersGroupResource
105+
: map ($ distroResource) [
80106
distroIndexPage
81107
, distroAllPage
82108
, distroPackages
@@ -109,10 +135,6 @@ distroFeature UserFeature{..}
109135
}
110136
}
111137

112-
maintainersGroup = \dpath -> case simpleParse =<< lookup "distro" dpath of
113-
Nothing -> return Nothing
114-
Just dname -> getMaintainersGroup adminGroup dname
115-
116138
textEnumDistros _ = fmap (toResponse . intercalate ", " . map display) (queryState distrosState EnumerateDistros)
117139
textDistroPkgs dpath = withDistroPath dpath $ \dname pkgs -> do
118140
let pkglines = map (\(name, info) -> display name ++ " at " ++ display (distroVersion info) ++ ": " ++ distroUrl info) pkgs
@@ -124,15 +146,15 @@ distroFeature UserFeature{..}
124146
-- result: see-other uri, or an error: not authenticated or not found (todo)
125147
distroDelete dpath =
126148
withDistroNamePath dpath $ \distro -> do
127-
guardAuthorised_ [InGroup adminGroup] --TODO: use the per-distro maintainer groups
149+
guardAuthorised_ [InGroup adminGroup]
128150
-- should also check for existence here of distro here
129151
void $ updateState distrosState $ RemoveDistro distro
130152
seeOther "/distros/" (toResponse ())
131153

132154
-- result: ok response or not-found error
133155
distroPackageDelete dpath =
134156
withDistroPackagePath dpath $ \dname pkgname info -> do
135-
guardAuthorised_ [AnyKnownUser] --TODO: use the per-distro maintainer groups
157+
guardAuthorised_ [InGroup $ distroGroup dname]
136158
case info of
137159
Nothing -> notFound . toResponse $ "Package not found for " ++ display pkgname
138160
Just {} -> do
@@ -142,30 +164,30 @@ distroFeature UserFeature{..}
142164
-- result: see-other response, or an error: not authenticated or not found (todo)
143165
distroPackagePut dpath =
144166
withDistroPackagePath dpath $ \dname pkgname _ -> lookPackageInfo $ \newPkgInfo -> do
145-
guardAuthorised_ [AnyKnownUser] --TODO: use the per-distro maintainer groups
167+
guardAuthorised_ [InGroup $ distroGroup dname]
146168
void $ updateState distrosState $ AddPackage dname pkgname newPkgInfo
147169
seeOther ("/distro/" ++ display dname ++ "/" ++ display pkgname) $ toResponse "Ok!"
148170

149171
-- result: see-other response, or an error: not authentcated or bad request
150172
distroPostNew _ =
151173
lookDistroName $ \dname -> do
152-
guardAuthorised_ [AnyKnownUser] --TODO: use the per-distro maintainer groups
174+
guardAuthorised_ [InGroup adminGroup]
153175
success <- updateState distrosState $ AddDistro dname
154176
if success
155177
then seeOther ("/distro/" ++ display dname) $ toResponse "Ok!"
156178
else badRequest $ toResponse "Selected distribution name is already in use"
157179

158180
distroPutNew dpath =
159181
withDistroNamePath dpath $ \dname -> do
160-
guardAuthorised_ [AnyKnownUser] --TODO: use the per-distro maintainer groups
182+
guardAuthorised_ [InGroup adminGroup]
161183
_success <- updateState distrosState $ AddDistro dname
162184
-- it doesn't matter if it exists already or not
163185
ok $ toResponse "Ok!"
164186

165187
-- result: ok repsonse or not-found error
166188
distroPackageListPut dpath =
167189
withDistroPath dpath $ \dname _pkgs -> do
168-
guardAuthorised_ [AnyKnownUser] --TODO: use the per-distro maintainer groups
190+
guardAuthorised_ [InGroup $ distroGroup dname]
169191
lookCSVFile $ \csv ->
170192
case csvToPackageList csv of
171193
Left msg ->
@@ -205,8 +227,8 @@ distroFeature UserFeature{..}
205227
pVerStr <- look "version"
206228
pUriStr <- look "uri"
207229
case simpleParse pVerStr of
208-
Nothing -> mzero
209-
Just pVer -> return $ DistroPackageInfo pVer pUriStr
230+
Just pVer | isValidDistroURI pUriStr -> return $ DistroPackageInfo pVer pUriStr
231+
_ -> mzero
210232
case mInfo of
211233
(Left errs) -> ok $ toResponse $ unlines $ "Sorry, something went wrong there." : errs
212234
(Right pInfo) -> func pInfo
@@ -216,21 +238,6 @@ distroFeature UserFeature{..}
216238
Just distro -> func distro
217239
_ -> badRequest $ toResponse "Not a valid distro name"
218240

219-
getMaintainersGroup :: UserGroup -> DistroName -> IO (Maybe UserGroup)
220-
getMaintainersGroup admins dname = do
221-
isDist <- queryState distrosState (IsDistribution dname)
222-
case isDist of
223-
False -> return Nothing
224-
True -> return . Just $ UserGroup
225-
{ groupDesc = maintainerGroupDescription dname
226-
, queryUserGroup = queryState distrosState $ GetDistroMaintainers dname
227-
, addUserToGroup = updateState distrosState . AddDistroMaintainer dname
228-
, removeUserFromGroup = updateState distrosState . RemoveDistroMaintainer dname
229-
, groupsAllowedToAdd = [admins]
230-
, groupsAllowedToDelete = [admins]
231-
}
232-
233-
234241
maintainerGroupDescription :: DistroName -> GroupDescription
235242
maintainerGroupDescription dname = nullDescription
236243
{ groupTitle = "Maintainers"
@@ -253,13 +260,18 @@ packageListToCSV :: [(PackageName, DistroPackageInfo)] -> CSVFile
253260
packageListToCSV entries
254261
= CSVFile $ map (\(pn,DistroPackageInfo version url) -> [display pn, display version, url]) entries
255262

263+
isValidDistroURI :: String -> Bool
264+
isValidDistroURI uri =
265+
T.pack "https:" `T.isPrefixOf` T.pack uri
266+
256267
csvToPackageList :: CSVFile -> Either String [(PackageName, DistroPackageInfo)]
257268
csvToPackageList (CSVFile records)
258269
= mapM fromRecord records
259270
where
260271
fromRecord [packageStr, versionStr, uri]
261272
| Just package <- simpleParse packageStr
262273
, Just version <- simpleParse versionStr
274+
, isValidDistroURI uri
263275
= return (package, DistroPackageInfo version uri)
264-
fromRecord rec
265-
= Left $ "Invalid distro package entry: " ++ show rec
276+
fromRecord record
277+
= Left $ "Invalid distro package entry: " ++ show record

src/Distribution/Server/Features/Distro/Types.hs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
module Distribution.Server.Features.Distro.Types where
1010

11+
import Distribution.Server.Framework (FromReqURI(..))
1112
import Distribution.Server.Framework.Instances ()
1213
import Distribution.Server.Framework.MemSize
1314
import Distribution.Server.Users.State()
@@ -22,6 +23,7 @@ import Distribution.Package
2223
import Distribution.Pretty (Pretty(..))
2324
import Distribution.Parsec (Parsec(..))
2425
import qualified Distribution.Compat.CharParsing as P
26+
import Distribution.Text (simpleParse)
2527

2628
import qualified Text.PrettyPrint as Disp
2729
import qualified Data.Char as Char
@@ -39,6 +41,9 @@ instance Pretty DistroName where
3941
instance Parsec DistroName where
4042
parsec = DistroName <$> P.munch1 (\c -> Char.isAlphaNum c || c `elem` "-_()[]{}=$,;")
4143

44+
instance FromReqURI DistroName where
45+
fromReqURI = simpleParse
46+
4247
-- | Listing of known distributions and their maintainers
4348
data Distributions = Distributions {
4449
nameMap :: !(Map.Map DistroName UserIdSet)

src/Distribution/Server/Framework/CSRF.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ isCsrfSafe req
2424
(`BS.isPrefixOf` ua)
2525
-- UA set by `cabal upload` and such
2626
[ BS.pack "cabal-install/"
27+
-- UA set by Stack
28+
, BS.pack "The Haskell Stack"
2729
, -- Add some other common CLI tools here too?
2830
BS.pack "curl/"
2931
, -- referenced in this repository. Unclear whether strictly needed, but whitelisting just in case:

src/Distribution/Server/Util/CabalRevisions.hs

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -250,21 +250,6 @@ checkFlag flagOld flagNew = do
250250
checkSame "Cannot change ordering of flags"
251251
(flagName flagOld) (flagName flagNew)
252252

253-
-- Automatic flags' defaults may be changed as they don't make new
254-
-- configurations reachable by the solver that weren't before
255-
--
256-
-- Moreover, automatic flags may be converted into manual flags
257-
-- but not the other way round.
258-
--
259-
-- NB: We always allow to change the flag description as it has
260-
-- purely informational value
261-
when (flagManual flagOld) $ do
262-
checkSame "Cannot change the default of a manual flag"
263-
(flagDefault flagOld) (flagDefault flagNew)
264-
265-
checkSame "Cannot change a manual flag into an automatic flag"
266-
(flagManual flagOld) (flagManual flagNew)
267-
268253
let fname = unFlagName (flagName flagOld)
269254

270255
changesOk ("type of flag '" ++ fname ++ "'")

0 commit comments

Comments
 (0)