mirror of
https://github.com/safedep/pmg.git
synced 2026-08-03 07:24:09 +02:00
› Tenant ID: fails on headless Linux (containers, VMs, CI) because no D-Bus Secret Service is available and the keychain resolver refuses to construct. Add an explicit --insecure-file-store flag that enables dry's plaintext file fallback (~/.config/safedep/creds.json, mode 0600) for writing. Reading is fallback-enabled unconditionally in the credential resolver chain, logout and setup info, so stored file credentials resolve with no extra flags and logout can always clear them. On systems with a working keychain the file provider is never constructed.
71 lines
2.5 KiB
Go
71 lines
2.5 KiB
Go
// Package cloudauth provides shared helpers for resolving SafeDep Cloud
|
|
// credentials from the local keychain or environment. It centralizes the
|
|
// credential resolver chain used by both audit sync and authenticated
|
|
// analyzers so the resolution behavior stays consistent.
|
|
package cloudauth
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/safedep/dry/cloud"
|
|
"github.com/safedep/dry/log"
|
|
)
|
|
|
|
// ResolveCredentials resolves SafeDep Cloud API key credentials using a
|
|
// keychain-first, environment-fallback chain. It returns the resolved
|
|
// credentials and a close function that releases keychain resources. The
|
|
// close function is always non-nil and safe to call regardless of the error.
|
|
//
|
|
// The insecure file fallback is always enabled for reading so credentials
|
|
// stored via `pmg cloud login --insecure-file-store` on systems without an
|
|
// OS keychain (headless Linux, containers) resolve without extra flags. On
|
|
// systems with a working keychain the file provider is never constructed.
|
|
//
|
|
// An error is returned when no credentials are available, which callers can
|
|
// use to decide whether authenticated cloud features should be enabled.
|
|
func ResolveCredentials(opts ...cloud.KeychainOption) (*cloud.Credentials, func() error, error) {
|
|
var resolvers []cloud.CredentialResolver
|
|
var keychainResolver cloud.CloseableCredentialResolver
|
|
|
|
keychainOpts := append([]cloud.KeychainOption{cloud.WithInsecureFileFallback()}, opts...)
|
|
|
|
keychainResolver, err := cloud.NewKeychainCredentialResolver(cloud.CredentialTypeAPIKey, keychainOpts...)
|
|
if err != nil {
|
|
log.Debugf("Keychain credential resolver not available, skipping: %v", err)
|
|
} else {
|
|
resolvers = append(resolvers, keychainResolver)
|
|
}
|
|
|
|
envResolver, err := cloud.NewEnvCredentialResolver()
|
|
if err != nil {
|
|
log.Debugf("Env credential resolver not available, skipping: %v", err)
|
|
} else {
|
|
resolvers = append(resolvers, envResolver)
|
|
}
|
|
|
|
closeFn := func() error {
|
|
if keychainResolver != nil {
|
|
return keychainResolver.Close()
|
|
}
|
|
return nil
|
|
}
|
|
|
|
if len(resolvers) == 0 {
|
|
if err := closeFn(); err != nil {
|
|
log.Warnf("failed to close keychain resolver: %v", err)
|
|
}
|
|
return nil, func() error { return nil }, fmt.Errorf("no credential resolvers available")
|
|
}
|
|
|
|
chain := cloud.NewChainCredentialResolver(resolvers...)
|
|
creds, err := chain.Resolve()
|
|
if err != nil {
|
|
if closeErr := closeFn(); closeErr != nil {
|
|
log.Warnf("failed to close keychain resolver: %v", closeErr)
|
|
}
|
|
return nil, func() error { return nil }, fmt.Errorf("failed to resolve cloud credentials: %w", err)
|
|
}
|
|
|
|
return creds, closeFn, nil
|
|
}
|