Files
trivy/magefiles/docs.go
DmitriyLewen 4316bcbc5b feat: add support for registry mirrors (#8244)
Signed-off-by: knqyf263 <knqyf263@gmail.com>
Co-authored-by: Teppei Fukuda <knqyf263@gmail.com>
2025-01-22 07:46:02 +00:00

164 lines
4.3 KiB
Go

//go:build mage_docs
package main
import (
"cmp"
"fmt"
"os"
"slices"
"strings"
"github.com/spf13/cobra/doc"
"github.com/aquasecurity/trivy/pkg/commands"
"github.com/aquasecurity/trivy/pkg/flag"
"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
flag.CacheDirFlag.Default = "/path/to/cache"
flag.ModuleDirFlag.Default = "$HOME/.trivy/modules"
// Set a dummy path not to load plugins
os.Setenv("XDG_DATA_HOME", os.TempDir())
cmd := commands.NewApp()
cmd.DisableAutoGenTag = true
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.NewPackageFlagGroup(),
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() == "" || flg.Hidden() {
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 map[string][]string:
w.WriteString("\n")
for k, vv := range v {
fmt.Fprintf(w, "%s %s:\n", ind, k)
for _, vvv := range vv {
fmt.Fprintf(w, " %s - %s\n", ind, vvv)
}
}
case string:
fmt.Fprintf(w, " %q\n", v)
default:
fmt.Fprintf(w, " %v\n", v)
}
}