From 2105eb1d9ff88f59bf2a0ebc7b2e6e6778597c24 Mon Sep 17 00:00:00 2001 From: Fraser Tweedale Date: Fri, 2 Aug 2024 13:08:50 +1000 Subject: [PATCH] tools: add next-id command --- EXAMPLE_ADVISORY.md | 2 ++ README.md | 1 + code/hsec-tools/app/Command/NextID.hs | 24 ++++++++++++++++++++++++ code/hsec-tools/app/Main.hs | 10 +++++++++- code/hsec-tools/hsec-tools.cabal | 1 + 5 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 code/hsec-tools/app/Command/NextID.hs diff --git a/EXAMPLE_ADVISORY.md b/EXAMPLE_ADVISORY.md index b15f063f..f51778b5 100644 --- a/EXAMPLE_ADVISORY.md +++ b/EXAMPLE_ADVISORY.md @@ -1,6 +1,8 @@ ```toml [advisory] +# Submit PRs with HSEC-0000-0000, or run `hsec-tools next-id` to +# print the next available ID. id = "HSEC-0000-0000" cwe = [] diff --git a/README.md b/README.md index a1c857b1..95d75390 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,7 @@ to remove the explanatory comments for each field. [advisory] # Identifier for the advisory (mandatory). Will be assigned a "HSEC-YYYY-NNNN" # identifier e.g. HSEC-2022-0001. Please use "HSEC-0000-0000" in PRs. +# Or run `hsec-tools next-id` to print the next available ID. id = "HSEC-0000-0000" # Publication date of the advisory as an RFC 3339 date. diff --git a/code/hsec-tools/app/Command/NextID.hs b/code/hsec-tools/app/Command/NextID.hs new file mode 100644 index 00000000..a80bda99 --- /dev/null +++ b/code/hsec-tools/app/Command/NextID.hs @@ -0,0 +1,24 @@ +{-# LANGUAGE LambdaCase #-} + +module Command.NextID where + +import Control.Monad (unless) +import Data.Maybe (fromMaybe) +import System.Exit (die) + +import Security.Advisories.Git (getRepoRoot) +import Security.Advisories.Core.HsecId (printHsecId, getNextHsecId) +import Security.Advisories.Filesystem (isSecurityAdvisoriesRepo, getGreatestId) + +runNextIDCommand :: Maybe FilePath -> IO () +runNextIDCommand mPath = do + let + path = fromMaybe "." mPath + repoPath <- getRepoRoot path >>= \case + Left _ -> die "Not a git repo" + Right a -> pure a + isRepo <- isSecurityAdvisoriesRepo repoPath + unless isRepo $ + die "Not a security-advisories repo" + + getGreatestId repoPath >>= getNextHsecId >>= putStrLn . printHsecId diff --git a/code/hsec-tools/app/Main.hs b/code/hsec-tools/app/Main.hs index 2163aead..2eca100f 100644 --- a/code/hsec-tools/app/Main.hs +++ b/code/hsec-tools/app/Main.hs @@ -2,7 +2,6 @@ module Main where -import qualified Command.Reserve import Control.Monad (forM_, join, void, when) import Control.Monad.Trans.Except (runExceptT, ExceptT (ExceptT), withExceptT, throwE) import Control.Monad.IO.Class (liftIO) @@ -29,6 +28,9 @@ import System.FilePath (takeBaseName) import System.IO (hPrint, hPutStrLn, stderr) import Validation (Validation (..)) +import qualified Command.Reserve +import qualified Command.NextID + main :: IO () main = join $ @@ -43,6 +45,7 @@ cliOpts = info (commandsParser <**> helper) (fullDesc <> header "Haskell Advisor commandsParser = hsubparser ( command "check" (info commandCheck (progDesc "Syntax check a single advisory")) + <> command "next-id" (info commandNextID (progDesc "Print the next available HSEC ID")) <> command "reserve" (info commandReserve (progDesc "Reserve an HSEC ID")) <> command "osv" (info commandOsv (progDesc "Convert a single advisory to OSV")) <> command "render" (info commandRender (progDesc "Render a single advisory as HTML")) @@ -76,6 +79,11 @@ commandReserve = <> help "Commit the reservation file" ) +commandNextID :: Parser (IO ()) +commandNextID = + Command.NextID.runNextIDCommand + <$> optional (argument str (metavar "REPO")) + commandCheck :: Parser (IO ()) commandCheck = withAdvisory go diff --git a/code/hsec-tools/hsec-tools.cabal b/code/hsec-tools/hsec-tools.cabal index c09a30b8..18bf890a 100644 --- a/code/hsec-tools/hsec-tools.cabal +++ b/code/hsec-tools/hsec-tools.cabal @@ -91,6 +91,7 @@ library executable hsec-tools main-is: Main.hs other-modules: Command.Reserve + , Command.NextID -- Modules included in this executable, other than Main. -- other-modules: