feat: added cacerts and some tidying

This commit is contained in:
David Allen 2025-08-31 22:02:10 -06:00
parent 2112e7eefd
commit bdd85b01ff
Signed by: towk
GPG key ID: 0430CDBE22619155
8 changed files with 279 additions and 59 deletions

View file

@ -24,17 +24,29 @@ var deleteCmd = &cobra.Command{
PersistentPreRun: func(cmd *cobra.Command, args []string) {
setenv(cmd, "host", "MAKESHIFT_HOST")
setenv(cmd, "path", "MAKESHIFT_PATH")
setenv(cmd, "cacert", "MAKESHIFT_CACERT")
},
Run: func(cmd *cobra.Command, args []string) {
var (
host, _ = cmd.Flags().GetString("host")
paths, _ = cmd.Flags().GetStringSlice("path")
cacertPath, _ = cmd.Flags().GetString("cacert")
c = client.New(host)
res *http.Response
query string
err error
)
log.Debug().
Str("host", host).
Str("cacert", cacertPath).
Send()
if cacertPath != "" {
c.LoadCertificateFromPath(cacertPath)
}
for _, path := range paths {
if path == "" {
log.Warn().Msg("skipping empty path")
@ -62,6 +74,7 @@ var deleteProfilesCmd = &cobra.Command{
Run: func(cmd *cobra.Command, args []string) {
var (
host, _ = cmd.Flags().GetString("host")
cacertPath, _ = cmd.Flags().GetString("cacert")
c = client.New(host)
res *http.Response
@ -69,6 +82,14 @@ var deleteProfilesCmd = &cobra.Command{
err error
)
log.Debug().
Str("host", host).
Str("cacert", cacertPath).
Send()
if cacertPath != "" {
c.LoadCertificateFromPath(cacertPath)
}
for _, profileID := range args {
if profileID == "default" {
log.Warn().Msg("cannot delete the default profile")
@ -96,6 +117,7 @@ var deletePluginsCmd = &cobra.Command{
Run: func(cmd *cobra.Command, args []string) {
var (
host, _ = cmd.Flags().GetString("host")
cacertPath, _ = cmd.Flags().GetString("cacert")
c = client.New(host)
res *http.Response
@ -103,6 +125,15 @@ var deletePluginsCmd = &cobra.Command{
err error
)
log.Debug().
Str("host", host).
Str("cacert", cacertPath).
Send()
if cacertPath != "" {
c.LoadCertificateFromPath(cacertPath)
}
for _, pluginName := range args {
query = fmt.Sprintf("/plugins/%s", pluginName)
res, _, err = c.MakeRequest(client.HTTPEnvelope{
@ -116,6 +147,7 @@ var deletePluginsCmd = &cobra.Command{
func init() {
deleteCmd.PersistentFlags().String("host", "http://localhost:5050", "Set the makeshift server host (can be set with MAKESHIFT_HOST)")
deleteCmd.PersistentFlags().String("cacert", "", "Set the CA certificate path to load")
deleteCmd.Flags().StringSliceP("path", "p", []string{}, "Set the paths to delete files and directories")
deleteCmd.AddCommand(deleteProfilesCmd, deletePluginsCmd)

View file

@ -37,12 +37,14 @@ var downloadCmd = cobra.Command{
PersistentPreRun: func(cmd *cobra.Command, args []string) {
setenv(cmd, "host", "MAKESHIFT_HOST")
setenv(cmd, "path", "MAKESHIFT_PATH")
setenv(cmd, "cacert", "MAKESHIFT_CACERT")
},
Run: func(cmd *cobra.Command, args []string) {
var (
host, _ = cmd.Flags().GetString("host")
path, _ = cmd.Flags().GetString("path")
outputPath, _ = cmd.Flags().GetString("output")
cacertPath, _ = cmd.Flags().GetString("cacert")
pluginNames, _ = cmd.Flags().GetStringSlice("plugins")
profileIDs, _ = cmd.Flags().GetStringSlice("profiles")
extract, _ = cmd.Flags().GetBool("extract")
@ -72,6 +74,10 @@ var downloadCmd = cobra.Command{
Strs("plugins", pluginNames).
Send()
if cacertPath != "" {
c.LoadCertificateFromPath(cacertPath)
}
res, body, err = c.MakeRequest(client.HTTPEnvelope{
Path: query,
Method: http.MethodGet,
@ -163,6 +169,7 @@ var downloadProfileCmd = &cobra.Command{
var (
host, _ = cmd.Flags().GetString("host")
outputPath, _ = cmd.Flags().GetString("output")
cacertPath, _ = cmd.Flags().GetString("cacert")
c = client.New(host)
res *http.Response
@ -176,6 +183,10 @@ var downloadProfileCmd = &cobra.Command{
Str("output", outputPath).
Send()
if cacertPath != "" {
c.LoadCertificateFromPath(cacertPath)
}
for _, profileID := range args {
query = fmt.Sprintf("/profiles/%s", profileID)
res, body, err = c.MakeRequest(client.HTTPEnvelope{
@ -219,6 +230,7 @@ var downloadPluginCmd = &cobra.Command{
var (
host, _ = cmd.Flags().GetString("host")
outputPath, _ = cmd.Flags().GetString("output")
cacertPath, _ = cmd.Flags().GetString("cacert")
c = client.New(host)
res *http.Response
@ -232,6 +244,10 @@ var downloadPluginCmd = &cobra.Command{
Str("output", outputPath).
Send()
if cacertPath != "" {
c.LoadCertificateFromPath(cacertPath)
}
for _, pluginName := range args {
query = fmt.Sprintf("/plugins/%s/raw", pluginName)
res, body, err = c.MakeRequest(client.HTTPEnvelope{
@ -267,6 +283,7 @@ var downloadPluginCmd = &cobra.Command{
func init() {
downloadCmd.PersistentFlags().String("host", "http://localhost:5050", "Set the makeshift remote host (can be set with MAKESHIFT_HOST)")
downloadCmd.PersistentFlags().StringP("output", "o", "", "Set the output path to write files")
downloadCmd.PersistentFlags().String("cacert", "", "Set the CA certificate path to load")
downloadCmd.Flags().StringP("path", "p", ".", "Set the path to list files (can be set with MAKESHIFT_PATH)")
downloadCmd.Flags().StringSlice("profiles", []string{}, "Set the profile(s) to use to populate data store")
downloadCmd.Flags().StringSlice("plugins", []string{}, "Set the plugin(s) to run before downloading files")

View file

@ -24,14 +24,16 @@ var listCmd = &cobra.Command{
`,
Args: cobra.NoArgs,
Short: "List all files in a remote data directory",
PreRun: func(cmd *cobra.Command, args []string) {
PersistentPreRun: func(cmd *cobra.Command, args []string) {
setenv(cmd, "host", "MAKESHIFT_HOST")
setenv(cmd, "path", "MAKESHIFT_PATH")
setenv(cmd, "cacert", "MAKESHIFT_CACERT")
},
Run: func(cmd *cobra.Command, args []string) {
var (
host, _ = cmd.Flags().GetString("host")
path, _ = cmd.Flags().GetString("path")
cacertPath, _ = cmd.Flags().GetString("cacert")
c = client.New(host)
body []byte
@ -42,8 +44,13 @@ var listCmd = &cobra.Command{
log.Debug().
Str("host", host).
Str("path", path).
Str("cacert", cacertPath).
Send()
if cacertPath != "" {
c.LoadCertificateFromPath(cacertPath)
}
// make request to /list endpoint
_, body, err = c.MakeRequest(client.HTTPEnvelope{
Path: fmt.Sprintf("/list/%s", path),
@ -81,6 +88,7 @@ var listPluginsCmd = &cobra.Command{
Run: func(cmd *cobra.Command, args []string) {
var (
host, _ = cmd.Flags().GetString("host")
cacertPath, _ = cmd.Flags().GetString("cacert")
c = client.New(host)
res *http.Response
@ -90,6 +98,15 @@ var listPluginsCmd = &cobra.Command{
err error
)
log.Debug().
Str("host", host).
Str("cacert", cacertPath).
Send()
if cacertPath != "" {
c.LoadCertificateFromPath(cacertPath)
}
if len(args) == 0 {
// make request to /list endpoint
res, body, err = c.MakeRequest(client.HTTPEnvelope{
@ -122,10 +139,18 @@ var listPluginsCmd = &cobra.Command{
var listProfilesCmd = &cobra.Command{
Use: "profiles",
Example: `
# list all profiles
makeshift list profiles
# live individual profiles
makeshift list profiles default custom
`,
Short: "Show all available profiles",
Run: func(cmd *cobra.Command, args []string) {
var (
host, _ = cmd.Flags().GetString("host")
cacertPath, _ = cmd.Flags().GetString("cacert")
c = client.New(host)
res *http.Response
@ -135,6 +160,15 @@ var listProfilesCmd = &cobra.Command{
err error
)
log.Debug().
Str("host", host).
Str("cacert", cacertPath).
Send()
if cacertPath != "" {
c.LoadCertificateFromPath(cacertPath)
}
if len(args) == 0 {
// make request to /list endpoint
res, body, err = c.MakeRequest(client.HTTPEnvelope{
@ -154,7 +188,7 @@ var listProfilesCmd = &cobra.Command{
// make request to /list endpoint
query = fmt.Sprintf("/profiles/%s", profileID)
res, body, err = c.MakeRequest(client.HTTPEnvelope{
Path: fmt.Sprintf(query),
Path: query,
Method: http.MethodGet,
})
handleResponseError(res, host, query, err)
@ -174,6 +208,7 @@ var listProfilesCmd = &cobra.Command{
func init() {
listCmd.PersistentFlags().String("host", "http://localhost:5050", "Set the configurator remote host (can be set with MAKESHIFT_HOST)")
listCmd.PersistentFlags().String("cacert", "", "Set the CA certificate path to load")
listCmd.Flags().StringP("path", "p", ".", "Set the path to list files (can be set with MAKESHIFT_PATH)")
listCmd.AddCommand(listPluginsCmd, listProfilesCmd)

View file

@ -23,11 +23,15 @@ var serveCmd = &cobra.Command{
setenv(cmd, "host", "MAKESHIFT_HOST")
setenv(cmd, "root", "MAKESHIFT_ROOT")
setenv(cmd, "timeout", "MAKESHIFT_TIMEOUT")
setenv(cmd, "cacert", "MAKESHIFT_CACERT")
setenv(cmd, "keyfile", "MAKESHIFT_KEYFILE")
},
Run: func(cmd *cobra.Command, args []string) {
var (
host, _ = cmd.Flags().GetString("host")
rootPath, _ = cmd.Flags().GetString("root")
cacertPath, _ = cmd.Flags().GetString("cacert")
keyfile, _ = cmd.Flags().GetString("keyfile")
timeout, _ = cmd.Flags().GetInt("timeout")
parsed *url.URL
@ -47,6 +51,8 @@ var serveCmd = &cobra.Command{
server = service.New()
server.Addr = parsed.Host
server.RootPath = rootPath
server.CACertFile = cacertPath
server.CACertKeyfile = keyfile
server.Timeout = time.Duration(timeout) * time.Second
// show some debugging information
@ -54,6 +60,8 @@ var serveCmd = &cobra.Command{
Str("host", parsed.Host).
Any("paths", map[string]string{
"root": rootPath,
"cacert": cacertPath,
"keyfile": keyfile,
"data": server.PathForData(),
"profiles": server.PathForProfiles(),
"plugins": server.PathForPlugins(),
@ -84,6 +92,10 @@ func init() {
serveCmd.Flags().String("host", "localhost:5050", "Set the configurator server host (can be set with MAKESHIFT_HOST)")
serveCmd.Flags().String("root", "./", "Set the root path to serve files (can be set with MAKESHIFT_ROOT)")
serveCmd.Flags().IntP("timeout", "t", 60, "Set the timeout in seconds for requests (can be set with MAKESHIFT_TIMEOUT)")
serveCmd.Flags().String("cacert", "", "Set the CA certificate path to load (can be set with MAKESHIFT_CACERT)")
serveCmd.Flags().String("keyfile", "", "Set the CA key file to use (can be set with MAKESHIFT_KEYFILE)")
serveCmd.MarkFlagsRequiredTogether("cacert", "keyfile")
rootCmd.AddCommand(serveCmd)
}

View file

@ -4,6 +4,8 @@ import (
"bufio"
"encoding/json"
"fmt"
"io/fs"
"maps"
"net/http"
"os"
"path/filepath"
@ -41,11 +43,13 @@ var uploadCmd = &cobra.Command{
PersistentPreRun: func(cmd *cobra.Command, args []string) {
setenv(cmd, "host", "MAKESHIFT_HOST")
setenv(cmd, "path", "MAKESHIFT_PATH")
setenv(cmd, "cacert", "MAKESHIFT_CACERT")
},
Run: func(cmd *cobra.Command, args []string) {
var (
host, _ = cmd.Flags().GetString("host")
path, _ = cmd.Flags().GetString("path")
cacertPath, _ = cmd.Flags().GetString("cacert")
dataArgs, _ = cmd.Flags().GetStringArray("data")
inputData = processFiles(dataArgs)
@ -55,8 +59,21 @@ var uploadCmd = &cobra.Command{
query string
err error
)
log.Debug().
Str("host", host).
Str("path", path).
Str("query", query).
Str("cacert", cacertPath).
Any("input", inputData).
Send()
if cacertPath != "" {
c.LoadCertificateFromPath(cacertPath)
}
for inputPath, contents := range inputData {
log.Info().Str("path", path).Int("size", len(contents)).Send()
log.Debug().Str("path", path).Int("size", len(contents)).Send()
if useDirectoryPath {
query = path + "/" + filepath.Clean(inputPath)
} else {
@ -94,6 +111,7 @@ var uploadProfilesCmd = &cobra.Command{
var (
host, _ = cmd.Flags().GetString("host")
dataArgs, _ = cmd.Flags().GetStringArray("data")
cacertPath, _ = cmd.Flags().GetString("cacert")
profiles = processProfiles(dataArgs)
c = client.New(host)
@ -103,6 +121,16 @@ var uploadProfilesCmd = &cobra.Command{
err error
)
log.Debug().
Str("host", host).
Str("query", query).
Str("cacert", cacertPath).
Send()
if cacertPath != "" {
c.LoadCertificateFromPath(cacertPath)
}
// load files from args
for i, path := range args {
body, err = os.ReadFile(path)
@ -162,6 +190,7 @@ var uploadPluginsCmd = &cobra.Command{
var (
host, _ = cmd.Flags().GetString("host")
dataArgs, _ = cmd.Flags().GetStringArray("data")
cacertPath, _ = cmd.Flags().GetString("cacert")
plugins = processFiles(dataArgs)
c = client.New(host)
@ -172,6 +201,16 @@ var uploadPluginsCmd = &cobra.Command{
err error
)
log.Debug().
Str("host", host).
Str("query", query).
Str("cacert", cacertPath).
Send()
if cacertPath != "" {
c.LoadCertificateFromPath(cacertPath)
}
// load files from args
for i, path := range args {
body, err = os.ReadFile(path)
@ -208,6 +247,8 @@ var uploadPluginsCmd = &cobra.Command{
func init() {
uploadCmd.PersistentFlags().String("host", "http://localhost:5050", "Set the makeshift remote host (can be set with MAKESHIFT_HOST)")
uploadCmd.PersistentFlags().StringArrayP("data", "d", []string{}, "Set the data to send to specified host (prepend @ for files)")
uploadCmd.PersistentFlags().String("cacert", "", "Set the CA certificate path to load")
uploadCmd.Flags().StringP("path", "p", ".", "Set the path to list files (can be set with MAKESHIFT_PATH)")
uploadProfilesCmd.Flags().VarP(&inputFormat, "format", "F", "Set the input format for profile")
@ -220,31 +261,27 @@ func processFiles(args []string) map[string][]byte {
// load data either from file or directly from args
var collection = make(map[string][]byte, len(args))
for _, arg := range args {
// if arg is empty string, then skip and continue
// skip empty string args
if len(arg) > 0 {
// determine if we're reading from file to load contents
if strings.HasPrefix(arg, "@") {
var (
path string = strings.TrimLeft(arg, "@")
contents []byte
err error
)
contents, err = os.ReadFile(path)
var path string = strings.TrimLeft(arg, "@")
// process sub-directories recursively
newCollection, err := processDir(path)
if err != nil {
log.Error().Err(err).Str("path", path).Msg("failed to read file")
continue
log.Warn().
Err(err).
Str("path", path).
Msg("failed to process directory at path")
}
log.Trace().
Str("path", path).
Msg("new collection added at path")
maps.Copy(collection, newCollection)
// skip empty files
if len(contents) == 0 {
log.Warn().Str("path", path).Msg("file is empty")
continue
}
// add loaded data to collection of all data
collection[path] = contents
} else {
log.Warn().Msg("only files can be uploaded (add @ before the path)")
log.Warn().Msg("only files can be uploaded (add @ before the path with '--data' flag)")
continue
}
@ -275,20 +312,28 @@ func processProfiles(args []string) []*makeshift.Profile {
)
contents, err = os.ReadFile(path)
if err != nil {
log.Error().Err(err).Str("path", path).Msg("failed to read file")
log.Error().
Err(err).
Str("path", path).
Msg("failed to read file")
continue
}
// skip empty files
if len(contents) == 0 {
log.Warn().Str("path", path).Msg("file is empty")
log.Warn().
Str("path", path).
Msg("file is empty")
continue
}
// convert/validate input data
data, err = parseProfile(contents, format.DataFormatFromFileExt(path, inputFormat))
if err != nil {
log.Error().Err(err).Str("path", path).Msg("failed to validate input from file")
log.Error().
Err(err).
Str("path", path).
Msg("failed to validate input from file")
}
// add loaded data to collection of all data
@ -306,7 +351,9 @@ func processProfiles(args []string) []*makeshift.Profile {
}
err = json.Unmarshal(input, &data)
if err != nil {
log.Error().Err(err).Msgf("failed to unmarshal input for argument %d", i)
log.Error().
Err(err).
Msgf("failed to unmarshal input for argument %d", i)
}
return []*makeshift.Profile{data}
}
@ -315,6 +362,73 @@ func processProfiles(args []string) []*makeshift.Profile {
return collection
}
func processDir(path string) (map[string][]byte, error) {
var (
collection = map[string][]byte{}
fileInfo os.FileInfo
contents []byte
err error
)
// determine if path is directory
if fileInfo, err = os.Stat(path); err == nil {
if fileInfo.IsDir() {
filepath.WalkDir(path, func(path string, d fs.DirEntry, err error) error {
if !d.IsDir() {
contents, err = os.ReadFile(path)
if err != nil {
log.Error().Err(err).Str("path", path).Msg("failed to read file")
return nil
}
// skip empty files
if len(contents) == 0 {
log.Warn().Str("path", path).Msg("file is empty")
return nil
}
log.Debug().
Str("path", path).
Msg("file added to collection")
// add loaded data to collection of all data
collection[path] = contents
} else {
// process sub-directories recursively
newCollection, err := processDir(path)
if err != nil {
return fmt.Errorf("failed to process directory at path '%s': %v", path, err)
}
log.Trace().
Str("path", path).
Msg("new collection added from nested directory")
maps.Copy(collection, newCollection)
}
return nil
})
} else {
contents, err = os.ReadFile(path)
if err != nil {
return collection, fmt.Errorf("failed to read file at path '%s': %v", path, err)
}
// skip empty files
if len(contents) == 0 {
return collection, fmt.Errorf("file is empty")
}
log.Debug().
Str("path", path).
Msg("file added to collection")
// add loaded data to collection of all data
collection[path] = contents
}
} else {
return nil, fmt.Errorf("failed to stat file: %v", err)
}
return collection, nil
}
func parseProfile(contents []byte, dataFormat format.DataFormat) (*makeshift.Profile, error) {
var (
data *makeshift.Profile

View file

@ -29,10 +29,18 @@ type Hook struct {
Plugin Plugin
}
func (h *Hook) Init() error {
return h.Plugin.Init()
}
func (h *Hook) Run() error {
return h.Plugin.Run(h.Data, h.Args)
}
func (h *Hook) Cleanup() error {
return h.Plugin.Cleanup()
}
func PluginToMap(p Plugin) map[string]any {
return map[string]any{
"name": p.Name(),

View file

@ -190,7 +190,9 @@ func (s *Service) Upload() http.HandlerFunc {
)
// show what we're uploading
log.Debug().Str("path", path).Msg("Service.Upload()")
log.Debug().
Str("path", path).
Msg("Service.Upload()")
// take the provided path and store the file contents
dirpath = filepath.Dir(path)
@ -296,7 +298,7 @@ func (s *Service) loadProfiles(profileIDs []string, store storage.KVStore, errs
profile *makeshift.Profile
err error
)
if i > DEFAULT_PROFILES_MAX_COUNT {
if i > s.ProfilesMaxCount {
log.Warn().Msg("max profiles count reached...stopping")
return errs
}
@ -329,7 +331,7 @@ func (s *Service) loadPlugins(pluginNames []string, store storage.KVStore, args
plugin makeshift.Plugin
err error
)
if i > DEFAULT_PLUGINS_MAX_COUNT {
if i > s.PluginsMaxCount {
log.Warn().Msg("max plugins count reached or exceeded...stopping")
return hooks, errs
}

View file

@ -21,7 +21,8 @@ import (
type Service struct {
Addr string
RootPath string `yaml:"root,omitempty"`
Environment map[string]string
CACertFile string `yaml:"cacert,omitempty"`
CACertKeyfile string `yaml:"keyfile,omitempty"`
// max counts
PluginsMaxCount int
@ -34,11 +35,6 @@ func New() *Service {
return &Service{
Addr: ":5050",
RootPath: "./",
Environment: map[string]string{
"MAKESHIFT_HOST": "",
"MAKESHIFT_ROOT": "",
"ACCESS_TOKEN": "",
},
PluginsMaxCount: DEFAULT_PLUGINS_MAX_COUNT,
ProfilesMaxCount: DEFAULT_PROFILES_MAX_COUNT,
Timeout: DEFAULT_TIMEOUT_IN_SECS,
@ -121,7 +117,11 @@ func (s *Service) Serve() error {
// always available public routes go here
router.HandleFunc("/status", s.GetStatus)
if s.CACertFile != "" && s.CACertKeyfile != "" {
return http.ListenAndServeTLS(s.Addr, s.CACertFile, s.CACertKeyfile, router)
} else {
return http.ListenAndServe(s.Addr, router)
}
}
func (s *Service) requireAuth() bool {