2 Commits
Author SHA1 Message Date
jmug 03247415b2 feat: Support configuration file for hmsecrets.
build-secretsserver / build (push) Successful in 1m39s
release-clis / release (push) Successful in 2m25s
2026-10-29 14:35:46 -07:00
jmug 3b29c2cb1d chore: Set up goreleaser to build and release binaries.
build-secretsserver / build (push) Successful in 1m23s
release-clis / release (push) Successful in 2m10s
2026-10-29 13:01:15 -07:00
16 changed files with 182 additions and 48 deletions

No files matched your search

+26
View File
@@ -0,0 +1,26 @@
name: release-clis
on:
push:
tags:
- "v*"
permissions:
code: read
releases: write
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version-file: go.mod
- uses: goreleaser/goreleaser-action@a4f02ab5355a589de60d917a659ce617ed19b3de # v7.3.0
with:
args: release --clean
env:
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
+2
View File
@@ -118,3 +118,5 @@ tags
# Persistent undo # Persistent undo
[._]*.un~ [._]*.un~
# Added by goreleaser init:
dist/
+47
View File
@@ -0,0 +1,47 @@
version: 2
gitea_urls:
api: https://git.handmadecities.com/api/v1
download: https://git.handmadecities.com/
before:
hooks:
- go mod tidy
builds:
- id: hmpki
main: ./cmd/hmpki
binary: hmpki
env:
- CGO_ENABLED=0
goos:
- linux
- windows
- darwin
goarch:
- arm64
- amd64
- id: hmsecrets
main: ./cmd/hmsecrets
binary: hmsecrets
env:
- CGO_ENABLED=0
goos:
- linux
- windows
- darwin
goarch:
- arm64
- amd64
archives:
- formats: [tar.gz]
name_template: >-
{{ .ProjectName }}_
{{- title .Os }}_
{{- if eq .Arch "amd64" }}x86_64
{{- else }}{{ .Arch }}{{ end }}
{{- if .Arm }}v{{ .Arm }}{{ end }}
format_overrides:
- goos: windows
formats: [zip]
+3 -1
View File
@@ -1,6 +1,8 @@
package main package main
import "git.handmadecities.com/HMC/shhh/internal/clis/hmsecrets" import (
"git.handmadecities.com/HMC/shhh/internal/clis/hmsecrets"
)
func main() { func main() {
hmsecrets.Execute() hmsecrets.Execute()
+1
View File
@@ -11,4 +11,5 @@ require (
github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/spf13/pflag v1.0.10 // indirect github.com/spf13/pflag v1.0.10 // indirect
golang.org/x/sys v0.45.0 // indirect golang.org/x/sys v0.45.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
) )
+2 -2
View File
@@ -2,8 +2,8 @@ package hmsecrets
import "git.handmadecities.com/HMC/shhh/pkg/secretsclient" import "git.handmadecities.com/HMC/shhh/pkg/secretsclient"
func getClient(base, ca, cert, certKey string) secretsclient.Client { func getClient() secretsclient.Client {
cli, err := secretsclient.New(base, ca, cert, certKey) cli, err := secretsclient.New(conf.APIBase, conf.CA, conf.ClientCert, conf.ClientKey)
if err != nil { if err != nil {
panic(err) panic(err)
} }
+83
View File
@@ -0,0 +1,83 @@
package hmsecrets
import (
"errors"
"fmt"
"os"
"path"
"runtime"
"gopkg.in/yaml.v3"
)
type config struct {
APIBase string `yaml:"api-base"`
CA string `yaml:"ca"`
ClientCert string `yaml:"client-cert"`
ClientKey string `yaml:"client-key"`
}
func mustLoadConfig() config {
var baseConfigDir string
var err error
switch runtime.GOOS {
case "windows":
fallthrough
case "linux":
baseConfigDir, err = os.UserConfigDir()
if err != nil {
panic(fmt.Errorf("determining user config dir: %w", err))
}
case "darwin":
// We want $HOME/.config in macOS.
homeDir, err := os.UserHomeDir()
if err != nil {
panic(fmt.Errorf("determining user home dir: %w", err))
}
baseConfigDir = path.Join(homeDir, ".config")
}
configDir := path.Join(baseConfigDir, "hmsecrets")
configBytes, err := os.ReadFile(path.Join(configDir, "config.yaml"))
if err != nil {
panic(fmt.Errorf("reading config file: %w", err))
}
var conf config
err = yaml.Unmarshal(configBytes, &conf)
if err != nil {
panic(fmt.Errorf("parsing config file: %w", err))
}
if conf.APIBase == "" {
panic(errors.New("api base must be present in config"))
}
if conf.CA == "" {
conf.CA = path.Join(configDir, "ca.crt")
}
if !fileAccesible(conf.CA) {
panic(fmt.Errorf("ca file '%s' does not exist or is inaccesible", conf.CA))
}
if conf.ClientCert == "" {
conf.ClientCert = path.Join(configDir, "client.crt")
}
if !fileAccesible(conf.ClientCert) {
panic(fmt.Errorf("client cert file '%s' does not exist or is inaccesible", conf.ClientCert))
}
if conf.ClientKey == "" {
conf.ClientKey = path.Join(configDir, "client.key")
}
if !fileAccesible(conf.ClientKey) {
panic(fmt.Errorf("client key file '%s' does not exist or is inaccesible", conf.ClientKey))
}
return conf
}
func fileAccesible(f string) bool {
_, err := os.Stat(f)
return err == nil
}
+1 -1
View File
@@ -13,7 +13,7 @@ var delCmd = &cobra.Command{
Short: "del [key]", Short: "del [key]",
Args: cobra.ExactArgs(1), Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
cli := getClient(apiBase, caFile, clientCert, clientKey) cli := getClient()
err := cli.Delete(args[0]) err := cli.Delete(args[0])
if err != nil { if err != nil {
return err return err
+1 -1
View File
@@ -15,7 +15,7 @@ var getArrCmd = &cobra.Command{
Short: "get-array [key]", Short: "get-array [key]",
Args: cobra.ExactArgs(1), Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
cli := getClient(apiBase, caFile, clientCert, clientKey) cli := getClient()
secret, err := cli.GetStringArr(args[0]) secret, err := cli.GetStringArr(args[0])
if err != nil { if err != nil {
return err return err
+1 -1
View File
@@ -15,7 +15,7 @@ var getMapCmd = &cobra.Command{
Short: "get-map [key]", Short: "get-map [key]",
Args: cobra.ExactArgs(1), Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
cli := getClient(apiBase, caFile, clientCert, clientKey) cli := getClient()
secret, err := cli.GetStringMap(args[0]) secret, err := cli.GetStringMap(args[0])
if err != nil { if err != nil {
return err return err
+1 -1
View File
@@ -15,7 +15,7 @@ var getCmd = &cobra.Command{
Short: "get [key]", Short: "get [key]",
Args: cobra.ExactArgs(1), Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
cli := getClient(apiBase, caFile, clientCert, clientKey) cli := getClient()
secret, err := cli.GetString(args[0]) secret, err := cli.GetString(args[0])
if err != nil { if err != nil {
return err return err
+10 -38
View File
@@ -7,44 +7,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
var apiBase string var conf config
var caFile string
var clientCert string
var clientKey string
func init() {
rootCmd.PersistentFlags().StringVar(
&apiBase,
"api-base",
"",
"base url for the service",
)
rootCmd.MarkPersistentFlagRequired("api-base")
rootCmd.PersistentFlags().StringVar(
&caFile,
"ca-file",
"",
"CA cert file",
)
rootCmd.MarkPersistentFlagRequired("ca-file")
rootCmd.PersistentFlags().StringVar(
&clientCert,
"client-cert",
"",
"certificate to be used for client mTLS auth",
)
rootCmd.MarkPersistentFlagRequired("client-cert")
rootCmd.PersistentFlags().StringVar(
&clientKey,
"client-key",
"",
"private key for the certificate to be used for client mTLS auth",
)
rootCmd.MarkPersistentFlagRequired("client-key")
}
var rootCmd = &cobra.Command{ var rootCmd = &cobra.Command{
Use: "hmsecrets", Use: "hmsecrets",
@@ -52,6 +15,15 @@ var rootCmd = &cobra.Command{
} }
func Execute() { func Execute() {
defer func() {
if r := recover(); r != nil {
fmt.Printf("%+v\n", r)
os.Exit(1)
}
}()
conf = mustLoadConfig()
if err := rootCmd.Execute(); err != nil { if err := rootCmd.Execute(); err != nil {
fmt.Fprintln(os.Stderr, err) fmt.Fprintln(os.Stderr, err)
os.Exit(1) os.Exit(1)
+1 -1
View File
@@ -24,7 +24,7 @@ var setArrCmd = &cobra.Command{
Short: "set-array [key]", Short: "set-array [key]",
Args: cobra.ExactArgs(1), Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
cli := getClient(apiBase, caFile, clientCert, clientKey) cli := getClient()
err := cli.PutStringArr(args[0], arrValue) err := cli.PutStringArr(args[0], arrValue)
if err != nil { if err != nil {
return err return err
+1 -1
View File
@@ -24,7 +24,7 @@ var setMapCmd = &cobra.Command{
Short: "set-map [key]", Short: "set-map [key]",
Args: cobra.ExactArgs(1), Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
cli := getClient(apiBase, caFile, clientCert, clientKey) cli := getClient()
err := cli.PutStringMap(args[0], mapValue) err := cli.PutStringMap(args[0], mapValue)
if err != nil { if err != nil {
return err return err
+1 -1
View File
@@ -13,7 +13,7 @@ var setCmd = &cobra.Command{
Short: "set [key] [value]", Short: "set [key] [value]",
Args: cobra.ExactArgs(2), Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
cli := getClient(apiBase, caFile, clientCert, clientKey) cli := getClient()
err := cli.PutString(args[0], args[1]) err := cli.PutString(args[0], args[1])
if err != nil { if err != nil {
return err return err
+1
View File
@@ -2,3 +2,4 @@
go = "1.27.2" go = "1.27.2"
"go:golang.org/x/tools/cmd/goimports" = "latest" "go:golang.org/x/tools/cmd/goimports" = "latest"
"go:golang.org/x/tools/gopls" = "latest" "go:golang.org/x/tools/gopls" = "latest"
goreleaser = "2.19.0"