diff --git a/cmd/setup/info.go b/cmd/setup/info.go index 4e70cb7..621ef77 100644 --- a/cmd/setup/info.go +++ b/cmd/setup/info.go @@ -6,6 +6,8 @@ import ( "strconv" "strings" + "github.com/safedep/dry/cloud" + "github.com/safedep/dry/log" "github.com/safedep/pmg/config" "github.com/safedep/pmg/internal/alias" "github.com/safedep/pmg/internal/analytics" @@ -136,8 +138,54 @@ func executeSetupInfo() error { if cfg.Config.Cloud.EndpointID != "" { cloudEntries["Endpoint ID"] = cfg.Config.Cloud.EndpointID } + cloudEntries["Credentials"] = describeCloudCredentials() ui.PrintInfoSection("Cloud Sync", cloudEntries) } return nil } + +// describeCloudCredentials reports whether SafeDep Cloud credentials can be +// resolved, and from where. The resolution order matches NewSyncClientBundle: +// keychain first, then environment variables. No network calls are made. +func describeCloudCredentials() string { + if source, ok := tryResolveKeychainCredentials(); ok { + return source + } + if source, ok := tryResolveEnvCredentials(); ok { + return source + } + return "not configured (run 'pmg cloud login' or set SAFEDEP_API_KEY and SAFEDEP_TENANT_ID)" +} + +func tryResolveKeychainCredentials() (string, bool) { + resolver, err := cloud.NewKeychainCredentialResolver(cloud.CredentialTypeAPIKey) + if err != nil { + log.Debugf("keychain credential resolver unavailable: %v", err) + return "", false + } + defer func() { + if err := resolver.Close(); err != nil { + log.Warnf("failed to close keychain resolver: %v", err) + } + }() + + if _, err := resolver.Resolve(); err != nil { + log.Debugf("no keychain credentials: %v", err) + return "", false + } + return "keychain", true +} + +func tryResolveEnvCredentials() (string, bool) { + resolver, err := cloud.NewEnvCredentialResolver() + if err != nil { + log.Debugf("env credential resolver unavailable: %v", err) + return "", false + } + if _, err := resolver.Resolve(); err != nil { + log.Debugf("no env credentials: %v", err) + return "", false + } + return "environment (SAFEDEP_API_KEY, SAFEDEP_TENANT_ID)", true +} diff --git a/sandbox/profiles/pnpm-restrictive.yml b/sandbox/profiles/pnpm-restrictive.yml index e4ac21b..b2a7946 100644 --- a/sandbox/profiles/pnpm-restrictive.yml +++ b/sandbox/profiles/pnpm-restrictive.yml @@ -19,6 +19,10 @@ filesystem: # which guarantees atomicity - ${CWD}/package.json.* + # pnpm install/update writes pnpm-lock.yaml atomically via a sibling + # temp file (e.g. pnpm-lock.yaml.139703784) followed by rename. + - ${CWD}/pnpm-lock.yaml.* + # Need access for dependency resolution - ${CWD}/.pnpm-store