code-intelligence.com/cifuzz@v0.40.0/internal/cmdutils/pflag.go (about) 1 package cmdutils 2 3 import ( 4 "runtime" 5 6 "github.com/spf13/cobra" 7 "github.com/spf13/pflag" 8 "github.com/spf13/viper" 9 ) 10 11 var BundleFlags = []string{ 12 "branch", 13 "build-command", 14 "build-jobs", 15 "commit", 16 "dict", 17 "docker-image", 18 "engine-arg", 19 "env", 20 "seed-corpus", 21 "timeout", 22 } 23 24 func MarkFlagsRequired(cmd *cobra.Command, flags ...string) { 25 for _, flag := range flags { 26 err := cmd.MarkFlagRequired(flag) 27 if err != nil { 28 panic(err) 29 } 30 } 31 } 32 33 func ViperMustBindPFlag(key string, flag *pflag.Flag) { 34 err := viper.BindPFlag(key, flag) 35 if err != nil { 36 panic(err) 37 } 38 } 39 40 // AddFlags executes the specified Add*Flag functions and returns a 41 // function which binds all those flags to viper 42 func AddFlags(cmd *cobra.Command, funcs ...func(cmd *cobra.Command) func()) (bindFlags func()) { // nolint:nonamedreturns 43 var bindFlagFuncs []func() 44 for _, f := range funcs { 45 bindFlagFunc := f(cmd) 46 bindFlagFuncs = append(bindFlagFuncs, bindFlagFunc) 47 } 48 return func() { 49 for _, f := range bindFlagFuncs { 50 f() 51 } 52 } 53 } 54 55 func AddAdditionalFilesFlag(cmd *cobra.Command) func() { 56 cmd.Flags().StringArray("add", nil, 57 "Add a file or directory to the bundle, defined in the format '--add=<source-path>;<target-path>'.\n"+ 58 "If <target-path> is missing the file gets copied to 'work_dir'.\n"+ 59 "This flag can be used multiple times.") 60 return func() { 61 ViperMustBindPFlag("add", cmd.Flags().Lookup("add")) 62 } 63 } 64 65 func AddBranchFlag(cmd *cobra.Command) func() { 66 cmd.Flags().String("branch", "", 67 "Branch name to use in the bundle config.\n"+ 68 "By default, the currently checked out git branch is used.") 69 return func() { 70 ViperMustBindPFlag("branch", cmd.Flags().Lookup("branch")) 71 } 72 } 73 74 func AddBuildCommandFlag(cmd *cobra.Command) func() { 75 cmd.Flags().String("build-command", "", 76 "The `command` to build the fuzz test for other build systems.") 77 return func() { 78 ViperMustBindPFlag("build-command", cmd.Flags().Lookup("build-command")) 79 } 80 } 81 82 func AddCleanCommandFlag(cmd *cobra.Command) func() { 83 cmd.Flags().String("clean-command", "", 84 "The `command` to clean the fuzz test and its dependencies for other build systems.") 85 return func() { 86 ViperMustBindPFlag("clean-command", cmd.Flags().Lookup("clean-command")) 87 } 88 } 89 90 func AddBuildJobsFlag(cmd *cobra.Command) func() { 91 cmd.Flags().Uint("build-jobs", 0, 92 "Maximum number of concurrent processes to use when building.\n"+ 93 "If argument is omitted the native build tool's default number is used.") 94 cmd.Flags().Lookup("build-jobs").NoOptDefVal = "0" 95 return func() { 96 ViperMustBindPFlag("build-jobs", cmd.Flags().Lookup("build-jobs")) 97 } 98 } 99 100 func AddBuildOnlyFlag(cmd *cobra.Command) func() { 101 cmd.Flags().Bool("build-only", false, 102 "Only build the fuzz test and don't execute it.") 103 return func() { 104 ViperMustBindPFlag("build-only", cmd.Flags().Lookup("build-only")) 105 } 106 } 107 108 func AddCommitFlag(cmd *cobra.Command) func() { 109 cmd.Flags().String("commit", "", 110 "Commit to use in the bundle config.\n"+ 111 "By default, the head of the currently checked out git branch is used.") 112 return func() { 113 ViperMustBindPFlag("commit", cmd.Flags().Lookup("commit")) 114 } 115 } 116 117 func AddDictFlag(cmd *cobra.Command) func() { 118 // TODO(afl): Also link to https://github.com/AFLplusplus/AFLplusplus/blob/stable/dictionaries/README.md 119 cmd.Flags().String("dict", "", 120 "A `file` containing input language keywords or other interesting byte sequences.\n"+ 121 "See https://llvm.org/docs/LibFuzzer.html#dictionaries.") 122 return func() { 123 ViperMustBindPFlag("dict", cmd.Flags().Lookup("dict")) 124 } 125 } 126 127 func AddDockerImageFlag(cmd *cobra.Command) func() { 128 // Default was originally set to "ubuntu:rolling", but this is not correct 129 // It will be set by the bundle command depending on the build system, unless user overrides it 130 cmd.Flags().String("docker-image", "", 131 "Docker image to use in the bundle config. This image will be used when\n"+ 132 "the bundle is executed on CI Sense.\n"+ 133 "By default, the image is chosen automatically based on the build system.") 134 return func() { 135 ViperMustBindPFlag("docker-image", cmd.Flags().Lookup("docker-image")) 136 } 137 } 138 139 func AddEngineArgFlag(cmd *cobra.Command) func() { 140 // TODO(afl): Also link to https://www.mankier.com/8/afl-fuzz 141 cmd.Flags().StringArray("engine-arg", nil, 142 "Command-line `argument` to pass to the fuzzing engine.\n"+ 143 "See https://llvm.org/docs/LibFuzzer.html#options.\n"+ 144 "This flag can be used multiple times.\n"+ 145 "Not supported for Node.js projects.") 146 return func() { 147 ViperMustBindPFlag("engine-args", cmd.Flags().Lookup("engine-arg")) 148 } 149 } 150 151 func AddEnvFlag(cmd *cobra.Command) func() { 152 cmd.Flags().StringArray("env", nil, 153 "Set environment variable when executing fuzz tests, e.g. '--env `VAR=value`'.\n"+ 154 "To use the value of VAR in the local environment, use '--env VAR'.\n"+ 155 "This flag can be used multiple times.") 156 return func() { 157 ViperMustBindPFlag("env", cmd.Flags().Lookup("env")) 158 } 159 } 160 161 func AddInteractiveFlag(cmd *cobra.Command) func() { 162 cmd.Flags().Bool("interactive", true, "Toggle interactive prompting in the terminal") 163 return func() { 164 ViperMustBindPFlag("interactive", cmd.Flags().Lookup("interactive")) 165 } 166 } 167 168 func AddPresetFlag(cmd *cobra.Command) func() { 169 cmd.Flags().String("preset", "", "Preset for a given environment to execute coverage with necessary flags.\n"+ 170 "We recommend not using this flag with '--format' or '--output' because the preset will set these accordingly.\n"+ 171 "If '--format' or '--output' are set, they will overwrite the preset.") 172 return func() { 173 ViperMustBindPFlag("preset", cmd.Flags().Lookup("preset")) 174 } 175 } 176 177 func AddPrintJSONFlag(cmd *cobra.Command) func() { 178 cmd.Flags().Bool("json", false, "Print output as JSON") 179 return func() { 180 ViperMustBindPFlag("print-json", cmd.Flags().Lookup("json")) 181 } 182 } 183 184 func AddProjectDirFlag(cmd *cobra.Command) func() { 185 cmd.Flags().String("project-dir", "", 186 "The project root which is the parent for all the project sources.\n"+ 187 "Defaults to the directory containing the cifuzz.yaml.") 188 return func() { 189 ViperMustBindPFlag("project-dir", cmd.Flags().Lookup("project-dir")) 190 } 191 } 192 193 func AddResolveSourceFileFlag(cmd *cobra.Command) func() { 194 cmd.Flags().BoolP("resolve", "r", false, 195 "Argument of the command is a path to a source file instead of a test identifier.\n"+ 196 "The path can be either absolute or relative to the current working directory and \n"+ 197 "will be resolved to the identifier of the corresponding fuzz test.") 198 return func() { 199 ViperMustBindPFlag("resolveSourceFilePath", cmd.Flags().Lookup("resolve")) 200 } 201 } 202 203 func AddProjectFlag(cmd *cobra.Command) func() { 204 // TODO: Make the project name more accessible in the web app (currently 205 // it's only shown in the URL) 206 cmd.Flags().StringP("project", "p", "", `The name of the CI Fuzz project you want to start a fuzzing run for, 207 e.g. "my-project-c170bc17".`) 208 return func() { 209 ViperMustBindPFlag("project", cmd.Flags().Lookup("project")) 210 } 211 } 212 213 func AddSeedCorpusFlag(cmd *cobra.Command) func() { 214 // TODO(afl): Also link to https://aflplus.plus/docs/fuzzing_in_depth/#a-collecting-inputs 215 cmd.Flags().StringArrayP("seed-corpus", "s", nil, 216 "A `directory` containing sample inputs for the code under test,\n"+ 217 "which is used in addition to inputs found in the inputs\n"+ 218 "directory of the fuzz test.\n"+ 219 "See https://github.com/CodeIntelligenceTesting/cifuzz/blob/main/docs/Glossary.md#seed-corpus.\n"+ 220 "This flag can be used multiple times.") 221 return func() { 222 ViperMustBindPFlag("seed-corpus-dirs", cmd.Flags().Lookup("seed-corpus")) 223 } 224 } 225 226 func AddServerFlag(cmd *cobra.Command) func() { 227 cmd.PersistentFlags().String("server", "https://app.code-intelligence.com", "Address of CI Sense") 228 return func() { 229 ViperMustBindPFlag("server", cmd.Flags().Lookup("server")) 230 } 231 } 232 233 func AddTimeoutFlag(cmd *cobra.Command) func() { 234 cmd.Flags().Duration("timeout", 0, 235 "Maximum time to run the fuzz test, e.g. \"30m\", \"1h\". The default is to run indefinitely.") 236 return func() { 237 ViperMustBindPFlag("timeout", cmd.Flags().Lookup("timeout")) 238 } 239 } 240 241 func AddUseSandboxFlag(cmd *cobra.Command) func() { 242 cmd.Flags().Bool("use-sandbox", false, 243 "By default, fuzz tests are executed in a sandbox to prevent accidental damage to the system.\n"+ 244 "Use --use-sandbox=false to run the fuzz test unsandboxed.\n"+ 245 "Only supported for c/c++ projects on Linux.") 246 viper.SetDefault("use-sandbox", runtime.GOOS == "linux") 247 return func() { 248 ViperMustBindPFlag("use-sandbox", cmd.Flags().Lookup("use-sandbox")) 249 } 250 }