mirror of
https://github.com/safedep/pmg.git
synced 2026-08-03 07:24:09 +02:00
* 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>
81 lines
2.3 KiB
Go
81 lines
2.3 KiB
Go
package executor
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/safedep/dry/log"
|
|
"github.com/safedep/pmg/config"
|
|
"github.com/safedep/pmg/sandbox"
|
|
"github.com/safedep/dry/usefulerror"
|
|
"github.com/safedep/pmg/errcodes"
|
|
)
|
|
|
|
// WrapCommandExecutionError converts a package manager execution error into a
|
|
// user-facing error. It never attributes the failure to the sandbox: causation
|
|
// cannot be inferred from EPERM/EACCES returns alone, and a security tool
|
|
// should not make best-effort claims. Any observed sandbox denials are
|
|
// persisted to the violation cache for forensic review via
|
|
// `pmg sandbox violations list` and `pmg sandbox explain`.
|
|
func WrapCommandExecutionError(err error, result *sandbox.ExecutionResult, exitCode int) error {
|
|
if err == nil {
|
|
return nil
|
|
}
|
|
|
|
observed := observeAndPersistViolations(result, err)
|
|
|
|
humanError := "Failed to execute package manager command"
|
|
if exitCode >= 0 {
|
|
humanError = fmt.Sprintf("Package manager command exited with code: %d", exitCode)
|
|
}
|
|
|
|
help := "Check the package manager command and its arguments"
|
|
builder := usefulerror.NewUsefulError().
|
|
WithCode(errcodes.PackageManagerExecutionFailed).
|
|
WithHumanError(humanError).
|
|
WithHelp(help)
|
|
|
|
if observed > 0 {
|
|
builder = builder.WithAdditionalHelp(fmt.Sprintf(
|
|
"Sandbox observed %d denied operation(s) during this run. Run `pmg sandbox violations list` to investigate.",
|
|
observed,
|
|
))
|
|
}
|
|
|
|
return builder.Wrap(err)
|
|
}
|
|
|
|
// observeAndPersistViolations collects any sandbox violation report associated
|
|
// with the run and writes it to the violation cache. Returns the number of
|
|
// violations observed. Failures are logged and swallowed; observability MUST
|
|
// NOT affect command exit.
|
|
func observeAndPersistViolations(result *sandbox.ExecutionResult, runErr error) int {
|
|
if result == nil {
|
|
return 0
|
|
}
|
|
|
|
report, diagErr := result.BestEffortViolation(runErr)
|
|
if diagErr != nil {
|
|
log.Warnf("failed to collect sandbox diagnostics: %v", diagErr)
|
|
return 0
|
|
}
|
|
if report == nil || len(report.Violations) == 0 {
|
|
return 0
|
|
}
|
|
|
|
cfg := config.Get()
|
|
if cfg == nil {
|
|
return len(report.Violations)
|
|
}
|
|
|
|
dir := cfg.SandboxViolationCacheDir()
|
|
if dir == "" {
|
|
return len(report.Violations)
|
|
}
|
|
|
|
if _, err := sandbox.NewViolationCache(dir).Write(report); err != nil {
|
|
log.Warnf("failed to persist sandbox violation report: %v", err)
|
|
}
|
|
|
|
return len(report.Violations)
|
|
}
|