switch from client_secret to client_secret_file
This commit is contained in:
parent
ec2cdb0700
commit
a11adaa58b
4 changed files with 54 additions and 12 deletions
|
|
@ -43,7 +43,7 @@ Create `$XDG_CONFIG_HOME/nix-cache-login/config.toml` (default `~/.config/nix-ca
|
||||||
```toml
|
```toml
|
||||||
issuer = "https://id.guardianproject.info/realms/gp"
|
issuer = "https://id.guardianproject.info/realms/gp"
|
||||||
client_id = "nix-cache"
|
client_id = "nix-cache"
|
||||||
cache_host = "cache.guardianproject.info"
|
cache_host = "cache.guardianproject.dev"
|
||||||
netrc_path = "$XDG_CONFIG_HOME/nix/netrc"
|
netrc_path = "$XDG_CONFIG_HOME/nix/netrc"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -51,8 +51,8 @@ netrc_path = "$XDG_CONFIG_HOME/nix/netrc"
|
||||||
```toml
|
```toml
|
||||||
issuer = "https://id.guardianproject.info/realms/gp"
|
issuer = "https://id.guardianproject.info/realms/gp"
|
||||||
client_id = "nix-cache-server"
|
client_id = "nix-cache-server"
|
||||||
client_secret = "..."
|
client_secret_file = "/run/secrets/nix-cache-client-secret"
|
||||||
cache_host = "cache.guardianproject.info"
|
cache_host = "cache.guardianproject.dev"
|
||||||
netrc_path = "$XDG_CONFIG_HOME/nix/netrc"
|
netrc_path = "$XDG_CONFIG_HOME/nix/netrc"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ var serviceAccountCmd = &cobra.Command{
|
||||||
Use: "service-account",
|
Use: "service-account",
|
||||||
Short: "Authenticate using client credentials (for servers)",
|
Short: "Authenticate using client credentials (for servers)",
|
||||||
Long: `Authenticates using the OAuth2 client credentials flow for headless
|
Long: `Authenticates using the OAuth2 client credentials flow for headless
|
||||||
server environments. Requires client_secret in the config file.
|
server environments. Requires client_secret_file in the config file.
|
||||||
Exits 0 on success, 1 on failure. Designed to be called from a systemd timer.`,
|
Exits 0 on success, 1 on failure. Designed to be called from a systemd timer.`,
|
||||||
RunE: runServiceAccount,
|
RunE: runServiceAccount,
|
||||||
}
|
}
|
||||||
|
|
@ -31,7 +31,7 @@ func runServiceAccount(cmd *cobra.Command, args []string) error {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
if cfg.ClientSecret == "" {
|
if cfg.ClientSecret == "" {
|
||||||
fmt.Fprintln(os.Stderr, "Error: client_secret is required in config for service-account mode.")
|
fmt.Fprintln(os.Stderr, "Error: client_secret_file is required in config for service-account mode.")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/adrg/xdg"
|
"github.com/adrg/xdg"
|
||||||
toml "github.com/pelletier/go-toml/v2"
|
toml "github.com/pelletier/go-toml/v2"
|
||||||
|
|
@ -12,9 +13,12 @@ import (
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Issuer string `toml:"issuer"`
|
Issuer string `toml:"issuer"`
|
||||||
ClientID string `toml:"client_id"`
|
ClientID string `toml:"client_id"`
|
||||||
ClientSecret string `toml:"client_secret,omitempty"`
|
ClientSecretFile string `toml:"client_secret_file,omitempty"`
|
||||||
CacheHost string `toml:"cache_host"`
|
CacheHost string `toml:"cache_host"`
|
||||||
NetrcPath string `toml:"netrc_path"`
|
NetrcPath string `toml:"netrc_path"`
|
||||||
|
|
||||||
|
// ClientSecret is populated at load time by reading ClientSecretFile.
|
||||||
|
ClientSecret string `toml:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load reads the config from the given path, or from the default XDG location.
|
// Load reads the config from the given path, or from the default XDG location.
|
||||||
|
|
@ -34,6 +38,15 @@ func Load(path string) (*Config, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg.NetrcPath = os.ExpandEnv(cfg.NetrcPath)
|
cfg.NetrcPath = os.ExpandEnv(cfg.NetrcPath)
|
||||||
|
cfg.ClientSecretFile = os.ExpandEnv(cfg.ClientSecretFile)
|
||||||
|
|
||||||
|
if cfg.ClientSecretFile != "" {
|
||||||
|
secret, err := os.ReadFile(cfg.ClientSecretFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("reading client_secret_file: %w", err)
|
||||||
|
}
|
||||||
|
cfg.ClientSecret = strings.TrimSpace(string(secret))
|
||||||
|
}
|
||||||
|
|
||||||
if err := cfg.validate(); err != nil {
|
if err := cfg.validate(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
||||||
|
|
@ -39,14 +39,19 @@ netrc_path = "/home/user/.config/nix/netrc"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLoadConfigWithClientSecret(t *testing.T) {
|
func TestLoadConfigWithClientSecretFile(t *testing.T) {
|
||||||
dir := t.TempDir()
|
dir := t.TempDir()
|
||||||
cfgFile := filepath.Join(dir, "config.toml")
|
cfgFile := filepath.Join(dir, "config.toml")
|
||||||
|
secretFile := filepath.Join(dir, "secret")
|
||||||
|
|
||||||
|
if err := os.WriteFile(secretFile, []byte("super-secret\n"), 0600); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
content := `
|
content := `
|
||||||
issuer = "https://id.example.com/realms/test"
|
issuer = "https://id.example.com/realms/test"
|
||||||
client_id = "nix-cache-server"
|
client_id = "nix-cache-server"
|
||||||
client_secret = "super-secret"
|
client_secret_file = "` + secretFile + `"
|
||||||
cache_host = "cache.example.com"
|
cache_host = "cache.example.com"
|
||||||
netrc_path = "/tmp/netrc"
|
netrc_path = "/tmp/netrc"
|
||||||
`
|
`
|
||||||
|
|
@ -64,6 +69,30 @@ netrc_path = "/tmp/netrc"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLoadConfigClientSecretFileMissing(t *testing.T) {
|
||||||
|
dir := t.TempDir()
|
||||||
|
cfgFile := filepath.Join(dir, "config.toml")
|
||||||
|
|
||||||
|
content := `
|
||||||
|
issuer = "https://id.example.com/realms/test"
|
||||||
|
client_id = "nix-cache-server"
|
||||||
|
client_secret_file = "/nonexistent/secret"
|
||||||
|
cache_host = "cache.example.com"
|
||||||
|
netrc_path = "/tmp/netrc"
|
||||||
|
`
|
||||||
|
if err := os.WriteFile(cfgFile, []byte(content), 0644); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := Load(cfgFile)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("expected error, got nil")
|
||||||
|
}
|
||||||
|
if !contains(err.Error(), "client_secret_file") {
|
||||||
|
t.Errorf("error = %q, want to contain %q", err.Error(), "client_secret_file")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestEnvVarExpansionInNetrcPath(t *testing.T) {
|
func TestEnvVarExpansionInNetrcPath(t *testing.T) {
|
||||||
dir := t.TempDir()
|
dir := t.TempDir()
|
||||||
cfgFile := filepath.Join(dir, "config.toml")
|
cfgFile := filepath.Join(dir, "config.toml")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue