mirror of
https://github.com/safedep/pmg.git
synced 2026-08-03 07:24:09 +02:00
refactor : Refactor error handling to use dry/usefulerror (#283)
* update the go.sum Signed-off-by: DivyanshuVortex <divyanshuchandra9027@gmail.com> * migrate most of the files to dry errors Signed-off-by: DivyanshuVortex <divyanshuchandra9027@gmail.com> * update the rest of the files Signed-off-by: DivyanshuVortex <divyanshuchandra9027@gmail.com> * fixs the review comments Signed-off-by: DivyanshuVortex <divyanshuchandra9027@gmail.com> * chores Signed-off-by: DivyanshuVortex <divyanshuchandra9027@gmail.com> --------- Signed-off-by: DivyanshuVortex <divyanshuchandra9027@gmail.com> Co-authored-by: Abhisek Datta <abhisek.datta@gmail.com>
This commit is contained in:
co-authored by
Abhisek Datta
parent
e5fe0df82e
commit
20e01d5cae
+22
-21
@@ -4,7 +4,8 @@ import (
|
||||
"github.com/safedep/dry/cloud"
|
||||
"github.com/safedep/dry/log"
|
||||
"github.com/safedep/pmg/internal/ui"
|
||||
"github.com/safedep/pmg/usefulerror"
|
||||
"github.com/safedep/dry/usefulerror"
|
||||
"github.com/safedep/pmg/errcodes"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@@ -29,70 +30,70 @@ func runLogin(cmd *cobra.Command, args []string) error {
|
||||
if loginFromEnv {
|
||||
resolver, err := cloud.NewEnvCredentialResolver()
|
||||
if err != nil {
|
||||
ui.ErrorExit(usefulerror.Useful().
|
||||
ui.ErrorExit(usefulerror.NewUsefulError().
|
||||
Wrap(err).
|
||||
WithCode(usefulerror.ErrCodeLifecycle).
|
||||
WithCode(errcodes.Lifecycle).
|
||||
WithHumanError("Failed to create environment credential resolver"))
|
||||
}
|
||||
|
||||
creds, err := resolver.Resolve()
|
||||
if err != nil {
|
||||
ui.ErrorExit(usefulerror.Useful().
|
||||
ui.ErrorExit(usefulerror.NewUsefulError().
|
||||
Wrap(err).
|
||||
WithCode(usefulerror.ErrCodeInvalidArgument).
|
||||
WithCode(errcodes.InvalidArgument).
|
||||
WithHumanError("Failed to resolve credentials from environment").
|
||||
WithHelp("Set SAFEDEP_API_KEY and SAFEDEP_TENANT_ID environment variables"))
|
||||
}
|
||||
|
||||
apiKey, err = creds.GetAPIKey()
|
||||
if err != nil || apiKey == "" {
|
||||
ui.ErrorExit(usefulerror.Useful().
|
||||
WithCode(usefulerror.ErrCodeInvalidArgument).
|
||||
ui.ErrorExit(usefulerror.NewUsefulError().
|
||||
WithCode(errcodes.InvalidArgument).
|
||||
WithHumanError("SAFEDEP_API_KEY environment variable is not set"))
|
||||
}
|
||||
|
||||
tenantID, err = creds.GetTenantDomain()
|
||||
if err != nil || tenantID == "" {
|
||||
ui.ErrorExit(usefulerror.Useful().
|
||||
WithCode(usefulerror.ErrCodeInvalidArgument).
|
||||
ui.ErrorExit(usefulerror.NewUsefulError().
|
||||
WithCode(errcodes.InvalidArgument).
|
||||
WithHumanError("SAFEDEP_TENANT_ID environment variable is not set"))
|
||||
}
|
||||
} else {
|
||||
var err error
|
||||
tenantID, err = ui.PromptInput("Tenant ID: ")
|
||||
if err != nil {
|
||||
ui.ErrorExit(usefulerror.Useful().
|
||||
ui.ErrorExit(usefulerror.NewUsefulError().
|
||||
Wrap(err).
|
||||
WithCode(usefulerror.ErrCodeLifecycle).
|
||||
WithCode(errcodes.Lifecycle).
|
||||
WithHumanError("Failed to read Tenant ID"))
|
||||
}
|
||||
|
||||
if tenantID == "" {
|
||||
ui.ErrorExit(usefulerror.Useful().
|
||||
WithCode(usefulerror.ErrCodeInvalidArgument).
|
||||
ui.ErrorExit(usefulerror.NewUsefulError().
|
||||
WithCode(errcodes.InvalidArgument).
|
||||
WithHumanError("Tenant ID cannot be empty"))
|
||||
}
|
||||
|
||||
apiKey, err = ui.PromptSecret("API Key: ")
|
||||
if err != nil {
|
||||
ui.ErrorExit(usefulerror.Useful().
|
||||
ui.ErrorExit(usefulerror.NewUsefulError().
|
||||
Wrap(err).
|
||||
WithCode(usefulerror.ErrCodeLifecycle).
|
||||
WithCode(errcodes.Lifecycle).
|
||||
WithHumanError("Failed to read API Key"))
|
||||
}
|
||||
|
||||
if apiKey == "" {
|
||||
ui.ErrorExit(usefulerror.Useful().
|
||||
WithCode(usefulerror.ErrCodeInvalidArgument).
|
||||
ui.ErrorExit(usefulerror.NewUsefulError().
|
||||
WithCode(errcodes.InvalidArgument).
|
||||
WithHumanError("API Key cannot be empty"))
|
||||
}
|
||||
}
|
||||
|
||||
store, err := cloud.NewKeychainCredentialStore()
|
||||
if err != nil {
|
||||
ui.ErrorExit(usefulerror.Useful().
|
||||
ui.ErrorExit(usefulerror.NewUsefulError().
|
||||
Wrap(err).
|
||||
WithCode(usefulerror.ErrCodeLifecycle).
|
||||
WithCode(errcodes.Lifecycle).
|
||||
WithHumanError("Failed to initialize credential store").
|
||||
WithHelp("Your system may not support secure credential storage"))
|
||||
}
|
||||
@@ -103,9 +104,9 @@ func runLogin(cmd *cobra.Command, args []string) error {
|
||||
}()
|
||||
|
||||
if err := store.SaveAPIKeyCredential(apiKey, tenantID); err != nil {
|
||||
ui.ErrorExit(usefulerror.Useful().
|
||||
ui.ErrorExit(usefulerror.NewUsefulError().
|
||||
Wrap(err).
|
||||
WithCode(usefulerror.ErrCodeLifecycle).
|
||||
WithCode(errcodes.Lifecycle).
|
||||
WithHumanError("Failed to save credentials").
|
||||
WithHelp("Your system may not support secure credential storage"))
|
||||
}
|
||||
|
||||
+6
-5
@@ -4,7 +4,8 @@ import (
|
||||
"github.com/safedep/dry/cloud"
|
||||
"github.com/safedep/dry/log"
|
||||
"github.com/safedep/pmg/internal/ui"
|
||||
"github.com/safedep/pmg/usefulerror"
|
||||
"github.com/safedep/dry/usefulerror"
|
||||
"github.com/safedep/pmg/errcodes"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@@ -19,9 +20,9 @@ func newLogoutCommand() *cobra.Command {
|
||||
func runLogout(cmd *cobra.Command, args []string) error {
|
||||
store, err := cloud.NewKeychainCredentialStore()
|
||||
if err != nil {
|
||||
ui.ErrorExit(usefulerror.Useful().
|
||||
ui.ErrorExit(usefulerror.NewUsefulError().
|
||||
Wrap(err).
|
||||
WithCode(usefulerror.ErrCodeLifecycle).
|
||||
WithCode(errcodes.Lifecycle).
|
||||
WithHumanError("Failed to initialize credential store").
|
||||
WithHelp("Your system may not support secure credential storage"))
|
||||
}
|
||||
@@ -32,9 +33,9 @@ func runLogout(cmd *cobra.Command, args []string) error {
|
||||
}()
|
||||
|
||||
if err := store.Clear(); err != nil {
|
||||
ui.ErrorExit(usefulerror.Useful().
|
||||
ui.ErrorExit(usefulerror.NewUsefulError().
|
||||
Wrap(err).
|
||||
WithCode(usefulerror.ErrCodeLifecycle).
|
||||
WithCode(errcodes.Lifecycle).
|
||||
WithHumanError("Failed to clear credentials"))
|
||||
}
|
||||
|
||||
|
||||
+12
-11
@@ -9,7 +9,8 @@ import (
|
||||
"github.com/safedep/pmg/internal/analytics"
|
||||
"github.com/safedep/pmg/internal/audit"
|
||||
"github.com/safedep/pmg/internal/ui"
|
||||
"github.com/safedep/pmg/usefulerror"
|
||||
"github.com/safedep/dry/usefulerror"
|
||||
"github.com/safedep/pmg/errcodes"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@@ -42,8 +43,8 @@ func runSync(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
if !cfg.Config.Cloud.Enabled {
|
||||
ui.ErrorExit(usefulerror.Useful().
|
||||
WithCode(usefulerror.ErrCodeLifecycle).
|
||||
ui.ErrorExit(usefulerror.NewUsefulError().
|
||||
WithCode(errcodes.Lifecycle).
|
||||
WithHumanError("Cloud sync is not enabled").
|
||||
WithHelp("Set 'cloud.enabled: true' in PMG config to enable cloud sync"))
|
||||
}
|
||||
@@ -54,15 +55,15 @@ func runSync(cmd *cobra.Command, args []string) error {
|
||||
|
||||
locked, err := lock.TryLockContext(lockCtx, 250*time.Millisecond)
|
||||
if err != nil {
|
||||
ui.ErrorExit(usefulerror.Useful().
|
||||
ui.ErrorExit(usefulerror.NewUsefulError().
|
||||
Wrap(err).
|
||||
WithCode(usefulerror.ErrCodeLifecycle).
|
||||
WithCode(errcodes.Lifecycle).
|
||||
WithHumanError("Failed to acquire cloud sync lock").
|
||||
WithHelp("Another sync may be in progress; try again shortly"))
|
||||
}
|
||||
if !locked {
|
||||
ui.ErrorExit(usefulerror.Useful().
|
||||
WithCode(usefulerror.ErrCodeLifecycle).
|
||||
ui.ErrorExit(usefulerror.NewUsefulError().
|
||||
WithCode(errcodes.Lifecycle).
|
||||
WithHumanError("Another cloud sync is already in progress").
|
||||
WithHelp("Wait for the in-progress sync to finish, then try again"))
|
||||
}
|
||||
@@ -77,9 +78,9 @@ func runSync(cmd *cobra.Command, args []string) error {
|
||||
|
||||
bundle, err := audit.NewSyncClientBundle(cfg)
|
||||
if err != nil {
|
||||
ui.ErrorExit(usefulerror.Useful().
|
||||
ui.ErrorExit(usefulerror.NewUsefulError().
|
||||
Wrap(err).
|
||||
WithCode(usefulerror.ErrCodeLifecycle).
|
||||
WithCode(errcodes.Lifecycle).
|
||||
WithHumanError("Failed to initialize cloud sync client").
|
||||
WithHelp("Run 'pmg cloud login' to store credentials, or set SAFEDEP_API_KEY and SAFEDEP_TENANT_ID environment variables"))
|
||||
}
|
||||
@@ -92,9 +93,9 @@ func runSync(cmd *cobra.Command, args []string) error {
|
||||
synced, err := bundle.Sync(ctx)
|
||||
recordLastSyncAttempt(cfg)
|
||||
if err != nil {
|
||||
ui.ErrorExit(usefulerror.Useful().
|
||||
ui.ErrorExit(usefulerror.NewUsefulError().
|
||||
Wrap(err).
|
||||
WithCode(usefulerror.ErrCodeNetwork).
|
||||
WithCode(errcodes.Network).
|
||||
WithHumanError("Failed to sync events to SafeDep Cloud").
|
||||
WithHelp("Check your network connectivity and ensure SafeDep Cloud is reachable").
|
||||
WithAdditionalHelp("Override the cloud endpoint with SAFEDEP_CLOUD_DATA_ADDR if needed"))
|
||||
|
||||
@@ -12,7 +12,8 @@ import (
|
||||
|
||||
pmgsandbox "github.com/safedep/pmg/sandbox"
|
||||
"github.com/safedep/pmg/sandbox/platform"
|
||||
"github.com/safedep/pmg/usefulerror"
|
||||
"github.com/safedep/dry/usefulerror"
|
||||
"github.com/safedep/pmg/errcodes"
|
||||
)
|
||||
|
||||
// stubProbe is a minimal probe used by tests.
|
||||
@@ -169,7 +170,7 @@ func TestRunDoctor_UnknownDriver(t *testing.T) {
|
||||
assert.Contains(t, err.Error(), "unknown driver")
|
||||
usefulErr, ok := usefulerror.AsUsefulError(err)
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, usefulerror.ErrCodeInvalidArgument, usefulErr.Code())
|
||||
assert.Equal(t, errcodes.InvalidArgument, usefulErr.Code())
|
||||
}
|
||||
|
||||
func TestDoctorCommandRejectsUnexpectedArgsWithUsage(t *testing.T) {
|
||||
|
||||
+15
-14
@@ -11,7 +11,8 @@ import (
|
||||
"github.com/safedep/pmg/config"
|
||||
"github.com/safedep/pmg/internal/ui"
|
||||
pmgsandbox "github.com/safedep/pmg/sandbox"
|
||||
"github.com/safedep/pmg/usefulerror"
|
||||
"github.com/safedep/dry/usefulerror"
|
||||
"github.com/safedep/pmg/errcodes"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@@ -67,7 +68,7 @@ func (e *explainFailError) ExitCode() int { return ExitCodeExplainFail }
|
||||
|
||||
func newExplainFailError(code, msg, help string) *explainFailError {
|
||||
return &explainFailError{
|
||||
UsefulError: usefulerror.Useful().
|
||||
UsefulError: usefulerror.NewUsefulError().
|
||||
WithCode(code).
|
||||
WithHumanError(msg).
|
||||
WithHelp(help).
|
||||
@@ -80,7 +81,7 @@ func runExplain(out io.Writer, in io.Reader, args []string, opts *explainOptions
|
||||
|
||||
if len(args) == 1 && !stdinMode {
|
||||
return newExplainFailError(
|
||||
usefulerror.ErrCodeInvalidArgument,
|
||||
errcodes.InvalidArgument,
|
||||
fmt.Sprintf("unexpected argument %q (use --last or pipe JSON with `-`)", args[0]),
|
||||
explainUsageHelp(),
|
||||
)
|
||||
@@ -88,7 +89,7 @@ func runExplain(out io.Writer, in io.Reader, args []string, opts *explainOptions
|
||||
|
||||
if opts.last && stdinMode {
|
||||
return newExplainFailError(
|
||||
usefulerror.ErrCodeInvalidArgument,
|
||||
errcodes.InvalidArgument,
|
||||
"--last and `-` are mutually exclusive",
|
||||
explainUsageHelp(),
|
||||
)
|
||||
@@ -96,7 +97,7 @@ func runExplain(out io.Writer, in io.Reader, args []string, opts *explainOptions
|
||||
|
||||
if !opts.last && !stdinMode {
|
||||
return newExplainFailError(
|
||||
usefulerror.ErrCodeInvalidArgument,
|
||||
errcodes.InvalidArgument,
|
||||
"no input: pass --last to read the most recent cached violation, or pipe a violation record JSON on stdin with `-`",
|
||||
explainUsageHelp(),
|
||||
)
|
||||
@@ -128,14 +129,14 @@ func readLatestFromCache(factory cacheFactory) (*pmgsandbox.ViolationCacheRecord
|
||||
entry, err := cache.Latest()
|
||||
if err != nil {
|
||||
return nil, newExplainFailError(
|
||||
usefulerror.ErrCodeUnknown,
|
||||
errcodes.Unknown,
|
||||
fmt.Sprintf("read cache: %v", err),
|
||||
"Check the sandbox violation cache directory and retry.",
|
||||
)
|
||||
}
|
||||
if entry == nil {
|
||||
return nil, newExplainFailError(
|
||||
usefulerror.ErrCodeNotFound,
|
||||
errcodes.NotFound,
|
||||
"no violations cached yet — run a sandboxed command first",
|
||||
"Run a sandboxed package manager command first, then retry `pmg sandbox explain --last`.",
|
||||
)
|
||||
@@ -151,7 +152,7 @@ func readRecordFromStdin(in io.Reader) (*pmgsandbox.ViolationCacheRecord, error)
|
||||
data, err := io.ReadAll(in)
|
||||
if err != nil {
|
||||
return nil, newExplainFailError(
|
||||
usefulerror.ErrCodeInvalidArgument,
|
||||
errcodes.InvalidArgument,
|
||||
fmt.Sprintf("read stdin: %v", err),
|
||||
explainUsageHelp(),
|
||||
)
|
||||
@@ -159,7 +160,7 @@ func readRecordFromStdin(in io.Reader) (*pmgsandbox.ViolationCacheRecord, error)
|
||||
|
||||
if len(strings.TrimSpace(string(data))) == 0 {
|
||||
return nil, newExplainFailError(
|
||||
usefulerror.ErrCodeInvalidArgument,
|
||||
errcodes.InvalidArgument,
|
||||
"stdin is empty: pipe a ViolationCacheRecord JSON document",
|
||||
explainUsageHelp(),
|
||||
)
|
||||
@@ -168,7 +169,7 @@ func readRecordFromStdin(in io.Reader) (*pmgsandbox.ViolationCacheRecord, error)
|
||||
var rec pmgsandbox.ViolationCacheRecord
|
||||
if err := json.Unmarshal(data, &rec); err != nil {
|
||||
return nil, newExplainFailError(
|
||||
usefulerror.ErrCodeInvalidArgument,
|
||||
errcodes.InvalidArgument,
|
||||
fmt.Sprintf("parse stdin JSON: %v", err),
|
||||
"Pipe a valid ViolationCacheRecord JSON document to `pmg sandbox explain -`.",
|
||||
)
|
||||
@@ -183,16 +184,16 @@ func readRecordFromStdin(in io.Reader) (*pmgsandbox.ViolationCacheRecord, error)
|
||||
|
||||
func validateViolationCacheRecord(rec *pmgsandbox.ViolationCacheRecord, source string) error {
|
||||
if rec == nil {
|
||||
return newExplainFailError(usefulerror.ErrCodeInvalidArgument, fmt.Sprintf("%s is empty", source), explainUsageHelp())
|
||||
return newExplainFailError(errcodes.InvalidArgument, fmt.Sprintf("%s is empty", source), explainUsageHelp())
|
||||
}
|
||||
if rec.SchemaVersion == 0 {
|
||||
return newExplainFailError(usefulerror.ErrCodeInvalidArgument, fmt.Sprintf("%s is missing schema_version", source), explainUsageHelp())
|
||||
return newExplainFailError(errcodes.InvalidArgument, fmt.Sprintf("%s is missing schema_version", source), explainUsageHelp())
|
||||
}
|
||||
if rec.SchemaVersion != pmgsandbox.ViolationCacheSchemaVersion {
|
||||
return newExplainFailError(usefulerror.ErrCodeInvalidArgument, fmt.Sprintf("unknown schema_version %d (expected %d)", rec.SchemaVersion, pmgsandbox.ViolationCacheSchemaVersion), explainUsageHelp())
|
||||
return newExplainFailError(errcodes.InvalidArgument, fmt.Sprintf("unknown schema_version %d (expected %d)", rec.SchemaVersion, pmgsandbox.ViolationCacheSchemaVersion), explainUsageHelp())
|
||||
}
|
||||
if rec.Report == nil {
|
||||
return newExplainFailError(usefulerror.ErrCodeInvalidArgument, fmt.Sprintf("%s is missing report", source), explainUsageHelp())
|
||||
return newExplainFailError(errcodes.InvalidArgument, fmt.Sprintf("%s is missing report", source), explainUsageHelp())
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -13,7 +13,8 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
pmgsandbox "github.com/safedep/pmg/sandbox"
|
||||
"github.com/safedep/pmg/usefulerror"
|
||||
"github.com/safedep/dry/usefulerror"
|
||||
"github.com/safedep/pmg/errcodes"
|
||||
)
|
||||
|
||||
func sampleReport() *pmgsandbox.ViolationReport {
|
||||
@@ -67,7 +68,7 @@ func TestExplainLastEmptyCache(t *testing.T) {
|
||||
assert.Equal(t, ExitCodeExplainFail, fe.ExitCode())
|
||||
usefulErr, ok := usefulerror.AsUsefulError(err)
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, usefulerror.ErrCodeNotFound, usefulErr.Code())
|
||||
assert.Equal(t, errcodes.NotFound, usefulErr.Code())
|
||||
assert.Empty(t, stdout)
|
||||
assert.Contains(t, err.Error(), "no violations cached")
|
||||
}
|
||||
@@ -221,7 +222,7 @@ func TestExplainNoMode(t *testing.T) {
|
||||
require.Error(t, err)
|
||||
usefulErr, ok := usefulerror.AsUsefulError(err)
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, usefulerror.ErrCodeInvalidArgument, usefulErr.Code())
|
||||
assert.Equal(t, errcodes.InvalidArgument, usefulErr.Code())
|
||||
assert.Contains(t, err.Error(), "no input")
|
||||
assert.Contains(t, err.Error(), "--last")
|
||||
}
|
||||
|
||||
+13
-12
@@ -11,7 +11,8 @@ import (
|
||||
|
||||
"github.com/safedep/pmg/internal/ui"
|
||||
pmgsandbox "github.com/safedep/pmg/sandbox"
|
||||
"github.com/safedep/pmg/usefulerror"
|
||||
"github.com/safedep/dry/usefulerror"
|
||||
"github.com/safedep/pmg/errcodes"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@@ -48,16 +49,16 @@ func validateDriver(name string) error {
|
||||
}
|
||||
|
||||
func invalidArgumentError(message, help string) error {
|
||||
return usefulerror.Useful().
|
||||
WithCode(usefulerror.ErrCodeInvalidArgument).
|
||||
return usefulerror.NewUsefulError().
|
||||
WithCode(errcodes.InvalidArgument).
|
||||
WithHumanError(message).
|
||||
WithHelp(help).
|
||||
Wrap(errors.New(message))
|
||||
}
|
||||
|
||||
func notFoundError(message, help string) error {
|
||||
return usefulerror.Useful().
|
||||
WithCode(usefulerror.ErrCodeNotFound).
|
||||
return usefulerror.NewUsefulError().
|
||||
WithCode(errcodes.NotFound).
|
||||
WithHumanError(message).
|
||||
WithHelp(help).
|
||||
Wrap(errors.New(message))
|
||||
@@ -72,7 +73,7 @@ func wrapUseful(err error, code, help string) error {
|
||||
if _, ok := usefulerror.AsUsefulError(err); ok {
|
||||
return err
|
||||
}
|
||||
return usefulerror.Useful().
|
||||
return usefulerror.NewUsefulError().
|
||||
WithCode(code).
|
||||
WithHumanError(err.Error()).
|
||||
WithHelp(help).
|
||||
@@ -88,27 +89,27 @@ func profileLoadError(err error) error {
|
||||
}
|
||||
switch {
|
||||
case errors.Is(err, pmgsandbox.ErrProfileNotFound):
|
||||
return wrapUseful(err, usefulerror.ErrCodeNotFound,
|
||||
return wrapUseful(err, errcodes.NotFound,
|
||||
"Use `pmg sandbox profile list` to see available profiles, or pass an existing profile YAML path.")
|
||||
case errors.Is(err, pmgsandbox.ErrProfileInvalid):
|
||||
return wrapUseful(err, usefulerror.ErrCodeInvalidArgument,
|
||||
return wrapUseful(err, errcodes.InvalidArgument,
|
||||
"Check the profile YAML for syntax/schema issues and verify any 'inherits:' parent name.")
|
||||
}
|
||||
return wrapUseful(err, usefulerror.ErrCodeUnknown,
|
||||
return wrapUseful(err, errcodes.Unknown,
|
||||
"Failed to load the sandbox profile. Run with --verbose for the underlying cause.")
|
||||
}
|
||||
|
||||
func registryInitError(err error) error {
|
||||
return wrapUseful(err, ioErrorCode(err, usefulerror.ErrCodeUnknown),
|
||||
return wrapUseful(err, ioErrorCode(err, errcodes.Unknown),
|
||||
"Failed to initialise the sandbox profile registry. Run with --verbose for details.")
|
||||
}
|
||||
|
||||
func ioErrorCode(err error, fallback string) string {
|
||||
switch {
|
||||
case errors.Is(err, fs.ErrPermission):
|
||||
return usefulerror.ErrCodePermissionDenied
|
||||
return errcodes.PermissionDenied
|
||||
case errors.Is(err, fs.ErrNotExist):
|
||||
return usefulerror.ErrCodeNotFound
|
||||
return errcodes.NotFound
|
||||
}
|
||||
return fallback
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"github.com/pmezard/go-difflib/difflib"
|
||||
pmgsandbox "github.com/safedep/pmg/sandbox"
|
||||
"github.com/safedep/pmg/sandbox/platform"
|
||||
"github.com/safedep/pmg/usefulerror"
|
||||
"github.com/safedep/pmg/errcodes"
|
||||
"github.com/spf13/cobra"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
@@ -83,7 +83,7 @@ func runProfileDiff(out io.Writer, errOut io.Writer, nameA, nameB string, opts *
|
||||
|
||||
if bytes.Equal(dataA, dataB) {
|
||||
if _, err := fmt.Fprintln(errOut, "profiles are identical"); err != nil {
|
||||
return &diffOpError{err: wrapUseful(err, usefulerror.ErrCodeUnknown,
|
||||
return &diffOpError{err: wrapUseful(err, errcodes.Unknown,
|
||||
"Failed to write diff output. Check that stderr is writable.")}
|
||||
}
|
||||
return nil
|
||||
@@ -99,18 +99,18 @@ func runProfileDiff(out io.Writer, errOut io.Writer, nameA, nameB string, opts *
|
||||
text, err := difflib.GetUnifiedDiffString(diff)
|
||||
if err != nil {
|
||||
return &diffOpError{err: wrapUseful(fmt.Errorf("failed to render diff: %w", err),
|
||||
usefulerror.ErrCodeUnknown,
|
||||
errcodes.Unknown,
|
||||
"Could not render the unified diff. Re-run with --verbose for the underlying cause.")}
|
||||
}
|
||||
|
||||
if _, err := io.WriteString(out, text); err != nil {
|
||||
return &diffOpError{err: wrapUseful(err, usefulerror.ErrCodeUnknown,
|
||||
return &diffOpError{err: wrapUseful(err, errcodes.Unknown,
|
||||
"Failed to write diff output. Check that stdout is writable.")}
|
||||
}
|
||||
|
||||
if !strings.HasSuffix(text, "\n") {
|
||||
if _, err := fmt.Fprintln(out); err != nil {
|
||||
return &diffOpError{err: wrapUseful(err, usefulerror.ErrCodeUnknown,
|
||||
return &diffOpError{err: wrapUseful(err, errcodes.Unknown,
|
||||
"Failed to write diff output. Check that stdout is writable.")}
|
||||
}
|
||||
}
|
||||
@@ -130,7 +130,7 @@ func materialize(registry pmgsandbox.ProfileRegistry, name string, opts *profile
|
||||
if opts.driver != "" {
|
||||
rendered, err := platform.Render(pmgsandbox.DriverName(opts.driver), policy)
|
||||
if err != nil {
|
||||
return nil, wrapUseful(err, usefulerror.ErrCodeInvalidArgument,
|
||||
return nil, wrapUseful(err, errcodes.InvalidArgument,
|
||||
"Could not render the policy for the requested driver. Verify the driver is supported on this host.")
|
||||
}
|
||||
return rendered, nil
|
||||
@@ -142,7 +142,7 @@ func materialize(registry pmgsandbox.ProfileRegistry, name string, opts *profile
|
||||
data, err := yaml.Marshal(policy)
|
||||
if err != nil {
|
||||
return nil, wrapUseful(fmt.Errorf("failed to marshal resolved policy %s: %w", name, err),
|
||||
usefulerror.ErrCodeUnknown,
|
||||
errcodes.Unknown,
|
||||
"Failed to marshal the resolved policy to YAML. Re-run with --verbose for the underlying cause.")
|
||||
}
|
||||
return data, nil
|
||||
|
||||
@@ -8,7 +8,8 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/safedep/pmg/usefulerror"
|
||||
"github.com/safedep/dry/usefulerror"
|
||||
"github.com/safedep/pmg/errcodes"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
@@ -99,7 +100,7 @@ func TestProfileDiffUnknownProfile(t *testing.T) {
|
||||
assert.Contains(t, err.Error(), "no-such-profile-xyz")
|
||||
usefulErr, ok := usefulerror.AsUsefulError(err)
|
||||
require.True(t, ok, "diff error should expose a UsefulError through Unwrap")
|
||||
assert.Equal(t, usefulerror.ErrCodeNotFound, usefulErr.Code())
|
||||
assert.Equal(t, errcodes.NotFound, usefulErr.Code())
|
||||
}
|
||||
|
||||
func TestProfileDiffUnknownDriver(t *testing.T) {
|
||||
@@ -113,7 +114,7 @@ func TestProfileDiffUnknownDriver(t *testing.T) {
|
||||
assert.Contains(t, err.Error(), "unknown driver")
|
||||
usefulErr, ok := usefulerror.AsUsefulError(err)
|
||||
require.True(t, ok, "diff error should expose a UsefulError through Unwrap")
|
||||
assert.Equal(t, usefulerror.ErrCodeInvalidArgument, usefulErr.Code())
|
||||
assert.Equal(t, errcodes.InvalidArgument, usefulErr.Code())
|
||||
}
|
||||
|
||||
func TestProfileDiffMissingProfileShowsUsage(t *testing.T) {
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/safedep/pmg/usefulerror"
|
||||
"github.com/safedep/pmg/errcodes"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@@ -95,13 +95,13 @@ func runProfileInit(out io.Writer, name string, opts *profileInitOptions, factor
|
||||
)
|
||||
} else if !os.IsNotExist(err) {
|
||||
return wrapUseful(fmt.Errorf("failed to stat %s: %w", target, err),
|
||||
ioErrorCode(err, usefulerror.ErrCodeUnknown),
|
||||
ioErrorCode(err, errcodes.Unknown),
|
||||
"Could not stat the target profile path. Check the user profile directory permissions.")
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(userDir, 0o755); err != nil {
|
||||
return wrapUseful(fmt.Errorf("failed to create user profile directory %s: %w", userDir, err),
|
||||
ioErrorCode(err, usefulerror.ErrCodePermissionDenied),
|
||||
ioErrorCode(err, errcodes.PermissionDenied),
|
||||
"Could not create the user profile directory. Check filesystem permissions for "+userDir+".")
|
||||
}
|
||||
|
||||
@@ -109,7 +109,7 @@ func runProfileInit(out io.Writer, name string, opts *profileInitOptions, factor
|
||||
|
||||
if err := os.WriteFile(target, []byte(content), 0o644); err != nil {
|
||||
return wrapUseful(fmt.Errorf("failed to write %s: %w", target, err),
|
||||
ioErrorCode(err, usefulerror.ErrCodePermissionDenied),
|
||||
ioErrorCode(err, errcodes.PermissionDenied),
|
||||
"Could not write the scaffolded profile. Check filesystem permissions for "+target+".")
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,8 @@ import (
|
||||
"testing"
|
||||
|
||||
pmgsandbox "github.com/safedep/pmg/sandbox"
|
||||
"github.com/safedep/pmg/usefulerror"
|
||||
"github.com/safedep/dry/usefulerror"
|
||||
"github.com/safedep/pmg/errcodes"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -97,7 +98,7 @@ func TestProfileInit_RefuseOverwrite(t *testing.T) {
|
||||
assert.Contains(t, err.Error(), target)
|
||||
usefulErr, ok := usefulerror.AsUsefulError(err)
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, usefulerror.ErrCodeInvalidArgument, usefulErr.Code())
|
||||
assert.Equal(t, errcodes.InvalidArgument, usefulErr.Code())
|
||||
|
||||
data, err := os.ReadFile(target)
|
||||
require.NoError(t, err)
|
||||
@@ -153,7 +154,7 @@ func TestProfileInit_InvalidName(t *testing.T) {
|
||||
assert.Contains(t, err.Error(), "invalid profile name")
|
||||
usefulErr, ok := usefulerror.AsUsefulError(err)
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, usefulerror.ErrCodeInvalidArgument, usefulErr.Code())
|
||||
assert.Equal(t, errcodes.InvalidArgument, usefulErr.Code())
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -166,7 +167,7 @@ func TestProfileInit_UnknownBuiltin(t *testing.T) {
|
||||
assert.Contains(t, err.Error(), "unknown built-in profile")
|
||||
usefulErr, ok := usefulerror.AsUsefulError(err)
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, usefulerror.ErrCodeNotFound, usefulErr.Code())
|
||||
assert.Equal(t, errcodes.NotFound, usefulErr.Code())
|
||||
}
|
||||
|
||||
func TestProfileInit_StdoutIsExactlyThePath(t *testing.T) {
|
||||
|
||||
@@ -11,7 +11,8 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
pmgsandbox "github.com/safedep/pmg/sandbox"
|
||||
"github.com/safedep/pmg/usefulerror"
|
||||
"github.com/safedep/dry/usefulerror"
|
||||
"github.com/safedep/pmg/errcodes"
|
||||
)
|
||||
|
||||
func writeUserProfileLint(t *testing.T, dir, name, body string) string {
|
||||
@@ -178,7 +179,7 @@ func TestProfileLint_UnknownProfile(t *testing.T) {
|
||||
assert.Contains(t, err.Error(), "not found")
|
||||
usefulErr, ok := usefulerror.AsUsefulError(err)
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, usefulerror.ErrCodeNotFound, usefulErr.Code())
|
||||
assert.Equal(t, errcodes.NotFound, usefulErr.Code())
|
||||
}
|
||||
|
||||
func TestProfileLintMissingTargetShowsUsage(t *testing.T) {
|
||||
@@ -211,7 +212,7 @@ func TestProfileLint_InvalidYAMLReturnsInvalidArgument(t *testing.T) {
|
||||
require.Error(t, err)
|
||||
usefulErr, ok := usefulerror.AsUsefulError(err)
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, usefulerror.ErrCodeInvalidArgument, usefulErr.Code())
|
||||
assert.Equal(t, errcodes.InvalidArgument, usefulErr.Code())
|
||||
}
|
||||
|
||||
func TestProfileLint_LiteralPath(t *testing.T) {
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
|
||||
"github.com/safedep/pmg/internal/ui"
|
||||
pmgsandbox "github.com/safedep/pmg/sandbox"
|
||||
"github.com/safedep/pmg/usefulerror"
|
||||
"github.com/safedep/pmg/errcodes"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@@ -45,7 +45,7 @@ func runProfileList(out io.Writer, opts *profileListOptions, factory registryFac
|
||||
|
||||
summaries, err := registry.ListProfiles()
|
||||
if err != nil {
|
||||
return wrapUseful(err, ioErrorCode(err, usefulerror.ErrCodeUnknown),
|
||||
return wrapUseful(err, ioErrorCode(err, errcodes.Unknown),
|
||||
"Failed to enumerate sandbox profiles. Check the user profile directory permissions.")
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,8 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
pmgsandbox "github.com/safedep/pmg/sandbox"
|
||||
"github.com/safedep/pmg/usefulerror"
|
||||
"github.com/safedep/dry/usefulerror"
|
||||
"github.com/safedep/pmg/errcodes"
|
||||
)
|
||||
|
||||
func newTestRegistry(t *testing.T, userDir string) registryFactory {
|
||||
@@ -119,7 +120,7 @@ func TestProfileListRegistryFailureReturnsUseful(t *testing.T) {
|
||||
require.Error(t, err)
|
||||
usefulErr, ok := usefulerror.AsUsefulError(err)
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, usefulerror.ErrCodeUnknown, usefulErr.Code())
|
||||
assert.Equal(t, errcodes.Unknown, usefulErr.Code())
|
||||
assert.Contains(t, err.Error(), "boom")
|
||||
}
|
||||
|
||||
@@ -138,7 +139,7 @@ func TestProfileListRegistryPermissionErrorReturnsPermissionDenied(t *testing.T)
|
||||
require.Error(t, err)
|
||||
usefulErr, ok := usefulerror.AsUsefulError(err)
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, usefulerror.ErrCodePermissionDenied, usefulErr.Code())
|
||||
assert.Equal(t, errcodes.PermissionDenied, usefulErr.Code())
|
||||
}
|
||||
|
||||
func TestProfileListRejectsUnexpectedArgs(t *testing.T) {
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"github.com/safedep/dry/log"
|
||||
pmgsandbox "github.com/safedep/pmg/sandbox"
|
||||
"github.com/safedep/pmg/sandbox/platform"
|
||||
"github.com/safedep/pmg/usefulerror"
|
||||
"github.com/safedep/pmg/errcodes"
|
||||
"github.com/spf13/cobra"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
@@ -108,7 +108,7 @@ func runProfileShowResolved(out io.Writer, name string, opts *profileShowOptions
|
||||
data, err := yaml.Marshal(policy)
|
||||
if err != nil {
|
||||
return wrapUseful(fmt.Errorf("failed to marshal resolved policy: %w", err),
|
||||
usefulerror.ErrCodeUnknown,
|
||||
errcodes.Unknown,
|
||||
"Failed to marshal the resolved policy to YAML. Re-run with --verbose for the underlying cause.")
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ func runProfileShowDriver(out io.Writer, name string, opts *profileShowOptions,
|
||||
|
||||
rendered, err := platform.Render(pmgsandbox.DriverName(opts.driver), policy)
|
||||
if err != nil {
|
||||
return wrapUseful(err, usefulerror.ErrCodeInvalidArgument,
|
||||
return wrapUseful(err, errcodes.InvalidArgument,
|
||||
"Could not render the policy for the requested driver. Verify the driver is supported on this host.")
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,8 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/safedep/pmg/usefulerror"
|
||||
"github.com/safedep/dry/usefulerror"
|
||||
"github.com/safedep/pmg/errcodes"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
@@ -71,7 +72,7 @@ func TestProfileShowUnknownDriver(t *testing.T) {
|
||||
assert.Contains(t, err.Error(), "unknown driver")
|
||||
usefulErr, ok := usefulerror.AsUsefulError(err)
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, usefulerror.ErrCodeInvalidArgument, usefulErr.Code())
|
||||
assert.Equal(t, errcodes.InvalidArgument, usefulErr.Code())
|
||||
}
|
||||
|
||||
func TestProfileShowUnknownProfileReturnsNotFound(t *testing.T) {
|
||||
@@ -88,7 +89,7 @@ func TestProfileShowUnknownProfileReturnsNotFound(t *testing.T) {
|
||||
assert.Contains(t, err.Error(), "not found")
|
||||
usefulErr, ok := usefulerror.AsUsefulError(err)
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, usefulerror.ErrCodeNotFound, usefulErr.Code())
|
||||
assert.Equal(t, errcodes.NotFound, usefulErr.Code())
|
||||
}
|
||||
|
||||
func TestProfileShowMissingNameShowsUsage(t *testing.T) {
|
||||
@@ -150,5 +151,5 @@ func TestProfileShowDriverNonNativeErrors(t *testing.T) {
|
||||
assert.Contains(t, err.Error(), "not available")
|
||||
usefulErr, ok := usefulerror.AsUsefulError(err)
|
||||
require.True(t, ok, "non-native driver error should be reported as a UsefulError")
|
||||
assert.Equal(t, usefulerror.ErrCodeInvalidArgument, usefulErr.Code())
|
||||
assert.Equal(t, errcodes.InvalidArgument, usefulErr.Code())
|
||||
}
|
||||
|
||||
@@ -8,7 +8,8 @@ import (
|
||||
|
||||
"github.com/safedep/pmg/internal/ui"
|
||||
pmgsandbox "github.com/safedep/pmg/sandbox"
|
||||
"github.com/safedep/pmg/usefulerror"
|
||||
"github.com/safedep/dry/usefulerror"
|
||||
"github.com/safedep/pmg/errcodes"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@@ -27,7 +28,7 @@ func (e *violationsListFailError) ExitCode() int { return ExitCodeViolationsList
|
||||
|
||||
func newViolationsListFailError(code, msg, help string) *violationsListFailError {
|
||||
return &violationsListFailError{
|
||||
UsefulError: usefulerror.Useful().
|
||||
UsefulError: usefulerror.NewUsefulError().
|
||||
WithCode(code).
|
||||
WithHumanError(msg).
|
||||
WithHelp(help).
|
||||
@@ -61,7 +62,7 @@ func newViolationsListCommand(factory cacheFactory) *cobra.Command {
|
||||
func runViolationsList(out, errOut io.Writer, opts *violationsListOptions, factory cacheFactory) error {
|
||||
if opts.limit < 0 {
|
||||
return newViolationsListFailError(
|
||||
usefulerror.ErrCodeInvalidArgument,
|
||||
errcodes.InvalidArgument,
|
||||
fmt.Sprintf("invalid --limit %d (must be >= 0)", opts.limit),
|
||||
"Pass --limit 0 to show all entries, or a positive limit.",
|
||||
)
|
||||
@@ -71,7 +72,7 @@ func runViolationsList(out, errOut io.Writer, opts *violationsListOptions, facto
|
||||
entries, err := cache.List()
|
||||
if err != nil {
|
||||
return newViolationsListFailError(
|
||||
usefulerror.ErrCodeUnknown,
|
||||
errcodes.Unknown,
|
||||
fmt.Sprintf("read cache: %v", err),
|
||||
"Check the sandbox violation cache directory and retry.",
|
||||
)
|
||||
|
||||
@@ -7,7 +7,8 @@ import (
|
||||
"testing"
|
||||
|
||||
pmgsandbox "github.com/safedep/pmg/sandbox"
|
||||
"github.com/safedep/pmg/usefulerror"
|
||||
"github.com/safedep/dry/usefulerror"
|
||||
"github.com/safedep/pmg/errcodes"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
@@ -108,7 +109,7 @@ func TestViolationsListRejectsNegativeLimit(t *testing.T) {
|
||||
assert.Contains(t, err.Error(), "invalid --limit")
|
||||
usefulErr, ok := usefulerror.AsUsefulError(err)
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, usefulerror.ErrCodeInvalidArgument, usefulErr.Code())
|
||||
assert.Equal(t, errcodes.InvalidArgument, usefulErr.Code())
|
||||
}
|
||||
|
||||
func TestViolationsList_LimitZeroReturnsAll(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user