mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-05 20:40:16 -08:00
docs: add auto-generated config (#7261)
Signed-off-by: knqyf263 <knqyf263@gmail.com> Co-authored-by: knqyf263 <knqyf263@gmail.com>
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"fmt"
|
||||
"os"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra/doc"
|
||||
|
||||
@@ -12,6 +16,15 @@ import (
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
)
|
||||
|
||||
const (
|
||||
title = "Config file"
|
||||
description = "Trivy can be customized by tweaking a `trivy.yaml` file.\n" +
|
||||
"The config path can be overridden by the `--config` flag.\n\n" +
|
||||
"An example is [here][example].\n\n" +
|
||||
"These samples contain default values for flags."
|
||||
footer = "[example]: https://github.com/aquasecurity/trivy/tree/{{ git.tag }}/examples/trivy-conf/trivy.yaml"
|
||||
)
|
||||
|
||||
// Generate CLI references
|
||||
func main() {
|
||||
// Set a dummy path for the documents
|
||||
@@ -26,4 +39,116 @@ func main() {
|
||||
if err := doc.GenMarkdownTree(cmd, "./docs/docs/references/configuration/cli"); err != nil {
|
||||
log.Fatal("Fatal error", log.Err(err))
|
||||
}
|
||||
if err := generateConfigDocs("./docs/docs/references/configuration/config-file.md"); err != nil {
|
||||
log.Fatal("Fatal error in config file generation", log.Err(err))
|
||||
}
|
||||
}
|
||||
|
||||
// generateConfigDocs creates markdown file for Trivy config.
|
||||
func generateConfigDocs(filename string) error {
|
||||
// remoteFlags should contain Client and Server flags.
|
||||
// NewClientFlags doesn't initialize `Listen` field
|
||||
remoteFlags := flag.NewClientFlags()
|
||||
remoteFlags.Listen = flag.ServerListenFlag.Clone()
|
||||
|
||||
// These flags don't work from config file.
|
||||
// Clear configName to skip them later.
|
||||
globalFlags := flag.NewGlobalFlagGroup()
|
||||
globalFlags.ConfigFile.ConfigName = ""
|
||||
globalFlags.ShowVersion.ConfigName = ""
|
||||
globalFlags.GenerateDefaultConfig.ConfigName = ""
|
||||
|
||||
var allFlagGroups = []flag.FlagGroup{
|
||||
globalFlags,
|
||||
flag.NewCacheFlagGroup(),
|
||||
flag.NewCleanFlagGroup(),
|
||||
remoteFlags,
|
||||
flag.NewDBFlagGroup(),
|
||||
flag.NewImageFlagGroup(),
|
||||
flag.NewK8sFlagGroup(),
|
||||
flag.NewLicenseFlagGroup(),
|
||||
flag.NewMisconfFlagGroup(),
|
||||
flag.NewModuleFlagGroup(),
|
||||
flag.NewRegistryFlagGroup(),
|
||||
flag.NewRegoFlagGroup(),
|
||||
flag.NewReportFlagGroup(),
|
||||
flag.NewRepoFlagGroup(),
|
||||
flag.NewScanFlagGroup(),
|
||||
flag.NewSecretFlagGroup(),
|
||||
flag.NewVulnerabilityFlagGroup(),
|
||||
}
|
||||
|
||||
f, err := os.Create(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
f.WriteString("# " + title + "\n\n")
|
||||
f.WriteString(description + "\n")
|
||||
|
||||
for _, group := range allFlagGroups {
|
||||
f.WriteString("## " + group.Name() + " options\n")
|
||||
writeFlags(group, f)
|
||||
}
|
||||
|
||||
f.WriteString(footer)
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeFlags(group flag.FlagGroup, w *os.File) {
|
||||
flags := group.Flags()
|
||||
// Sort flags to avoid duplicates of non-last parts of config file
|
||||
slices.SortFunc(flags, func(a, b flag.Flagger) int {
|
||||
return cmp.Compare(a.GetConfigName(), b.GetConfigName())
|
||||
})
|
||||
w.WriteString("\n```yaml\n")
|
||||
|
||||
var lastParts []string
|
||||
for _, flg := range flags {
|
||||
if flg.GetConfigName() == "" {
|
||||
continue
|
||||
}
|
||||
// We need to split the config name on `.` to make the indentations needed in yaml.
|
||||
parts := strings.Split(flg.GetConfigName(), ".")
|
||||
for i := range parts {
|
||||
// Skip already added part
|
||||
if len(lastParts) >= i+1 && parts[i] == lastParts[i] {
|
||||
continue
|
||||
}
|
||||
ind := strings.Repeat(" ", i)
|
||||
// We need to add a comment and example values only for the last part of the config name.
|
||||
isLastPart := i == len(parts)-1
|
||||
if isLastPart {
|
||||
// Some `Flags` don't support flag for CLI. (e.g.`LicenseForbidden`).
|
||||
if flg.GetName() != "" {
|
||||
fmt.Fprintf(w, "%s# Same as '--%s'\n", ind, flg.GetName())
|
||||
}
|
||||
}
|
||||
w.WriteString(ind + parts[i] + ":")
|
||||
if isLastPart {
|
||||
writeFlagValue(flg.GetDefaultValue(), ind, w)
|
||||
}
|
||||
w.WriteString("\n")
|
||||
}
|
||||
lastParts = parts
|
||||
}
|
||||
w.WriteString("```\n")
|
||||
}
|
||||
|
||||
func writeFlagValue(val any, ind string, w *os.File) {
|
||||
switch v := val.(type) {
|
||||
case []string:
|
||||
if len(v) > 0 {
|
||||
w.WriteString("\n")
|
||||
for _, vv := range v {
|
||||
fmt.Fprintf(w, "%s - %s\n", ind, vv)
|
||||
}
|
||||
} else {
|
||||
w.WriteString(" []\n")
|
||||
}
|
||||
case string:
|
||||
fmt.Fprintf(w, " %q\n", v)
|
||||
default:
|
||||
fmt.Fprintf(w, " %v\n", v)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ func NewGlobalFlagGroup() *GlobalFlagGroup {
|
||||
}
|
||||
|
||||
func (f *GlobalFlagGroup) Name() string {
|
||||
return "global"
|
||||
return "Global"
|
||||
}
|
||||
|
||||
func (f *GlobalFlagGroup) Flags() []Flagger {
|
||||
|
||||
@@ -196,6 +196,14 @@ func (f *Flag[T]) GetName() string {
|
||||
return f.Name
|
||||
}
|
||||
|
||||
func (f *Flag[T]) GetConfigName() string {
|
||||
return f.ConfigName
|
||||
}
|
||||
|
||||
func (f *Flag[T]) GetDefaultValue() any {
|
||||
return f.Default
|
||||
}
|
||||
|
||||
func (f *Flag[T]) GetAliases() []Alias {
|
||||
return f.Aliases
|
||||
}
|
||||
@@ -302,6 +310,8 @@ type FlagGroup interface {
|
||||
|
||||
type Flagger interface {
|
||||
GetName() string
|
||||
GetConfigName() string
|
||||
GetDefaultValue() any
|
||||
GetAliases() []Alias
|
||||
|
||||
Parse() error
|
||||
|
||||
Reference in New Issue
Block a user