Skip to content

Commit edfdd54

Browse files
abhisekCopilot
andauthored
chore: README update demo and Error Fix (#126)
* docs: Update README with demo gif * fix: Proxy remove dependency on interaction * fix: Update demo gif width * Update docs/demo/pmg-intro.tape Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Abhisek Datta <abhisek.datta@gmail.com> * fix: PMG demo --------- Signed-off-by: Abhisek Datta <abhisek.datta@gmail.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 6a3821d commit edfdd54

File tree

16 files changed

+163
-38
lines changed

16 files changed

+163
-38
lines changed

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,11 @@ matches the source code they reviewed, eliminating the risk of tampered or malic
2424

2525
## PMG in Action
2626

27-
<img src="./docs/assets/pmg-intro.png" width="600" alt="pmg in action">
27+
<img src="./docs/demo/pmg-intro.gif" width="800" alt="pmg in action">
2828

2929
## TL;DR
3030

31-
Install `pmg` using Homebrew:
31+
Install `pmg` using your favorite package manager:
3232

3333
```shell
3434
# MacOS/Linux with Homebrew
@@ -63,6 +63,7 @@ uv pip install <package-name>
6363
- Malicious package identification using [SafeDep Cloud](https://docs.safedep.io/cloud/malware-analysis) with realtime threat detection
6464
- Deep dependency analysis and transitive dependency resolution
6565
- Fast and efficient package verification
66+
- Defense in depth using OS native sandboxing
6667
- Seamless integration with existing package managers
6768
- Automated shell integration with cross-shell support
6869
- Package installation tracking and event logging

docs/demo/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package.json
2+
package-lock.json
3+
node_modules

docs/demo/build.sh

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#!/bin/bash
2+
3+
# Check if vhs is installed
4+
if ! command -v vhs &> /dev/null; then
5+
echo "vhs could not be found"
6+
exit 1
7+
fi
8+
9+
# Switch to the script directory
10+
cd "$(dirname "$0")"
11+
12+
# Enumerate all .tape files in the current directory
13+
for file in *.tape; do
14+
vhs "$file"
15+
done

docs/demo/pmg-intro.gif

283 KB
Loading

docs/demo/pmg-intro.tape

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
Output pmg-intro.gif
2+
3+
Set FontSize 28
4+
Set Width 1400
5+
Set Height 1000
6+
7+
Set WindowBar Colorful
8+
9+
Type "pmg setup install"
10+
Enter
11+
Sleep 2s
12+
13+
Enter
14+
15+
Type "source ~/.pmg.rc"
16+
Enter
17+
Sleep 2s
18+
19+
Enter
20+
21+
Type "npm install safedep-test-pkg"
22+
Enter
23+
Sleep 5s
24+

docs/demo/pmg-sandbox.gif

153 KB
Loading

docs/demo/pmg-sandbox.tape

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
Output pmg-sandbox.gif
2+
3+
Set FontSize 28
4+
Set Width 1400
5+
Set Height 1000
6+
7+
Set WindowBar Colorful
8+
9+
Hide
10+
Type "export CI=true"
11+
Enter
12+
13+
Type "clear"
14+
Enter
15+
16+
Sleep 0.5s
17+
Show
18+
19+
Type "pmg setup install"
20+
Enter
21+
Sleep 2s
22+
23+
Enter
24+
25+
Type "source ~/.pmg.rc"
26+
Enter
27+
Sleep 2s
28+
29+
Enter
30+
31+
Type `npm exec -- \` Enter
32+
Type `node -e "require('child_process').execSync('curl')" \` Enter
33+
Type ` 2>&1 | head -n 8` Enter
34+
35+
Sleep 5s
36+

guard/guard.go

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"github.com/safedep/pmg/internal/ui"
2020
"github.com/safedep/pmg/packagemanager"
2121
"github.com/safedep/pmg/sandbox/executor"
22+
"github.com/safedep/pmg/usefulerror"
2223
)
2324

2425
type PackageManagerGuardInteraction struct {
@@ -254,7 +255,21 @@ func (g *packageManagerGuard) continueExecution(ctx context.Context, pc *package
254255
}()
255256

256257
if result.ShouldRun() {
257-
return cmd.Run()
258+
err := cmd.Run()
259+
if err != nil {
260+
humanError := "Failed to execute package manager command"
261+
if exitErr, ok := err.(*exec.ExitError); ok {
262+
humanError = fmt.Sprintf("Package manager command exited with code: %d", exitErr.ExitCode())
263+
}
264+
265+
return usefulerror.Useful().
266+
WithCode(usefulerror.ErrCodePackageManagerExecutionFailed).
267+
WithHumanError(humanError).
268+
WithHelp("Check the package manager command and its arguments").
269+
Wrap(err)
270+
}
271+
272+
return nil
258273
}
259274

260275
return nil

internal/flows/proxy_flow.go

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,6 @@ func (f *proxyFlow) Run(ctx context.Context, args []string, parsedCmd *packagema
5555
log.Infof("Dry-run mode: Would execute %s with experimental proxy protection", f.pm.Name())
5656
log.Infof("Dry-run mode: Command would be: %s %v", parsedCmd.Command.Exe, parsedCmd.Command.Args)
5757

58-
ui.SetStatus("Running in dry-run mode (proxy mode)")
59-
ui.ClearStatus()
6058
return nil
6159
}
6260

@@ -102,7 +100,7 @@ func (f *proxyFlow) Run(ctx context.Context, args []string, parsedCmd *packagema
102100
SetStatus: ui.SetStatus,
103101
ClearStatus: ui.ClearStatus,
104102
ShowWarning: ui.ShowWarning,
105-
Block: ui.Block,
103+
Block: ui.BlockNoExit,
106104
}
107105

108106
// Create ecosystem-specific interceptor using factory
@@ -307,7 +305,7 @@ func (f *proxyFlow) executeWithProxyForNonInteractiveTTY(
307305

308306
err = cmd.Run()
309307
if err != nil {
310-
return fmt.Errorf("failed to execute %s: %w", f.pm.Name(), err)
308+
return f.handlePackageManagerExecutionError(err)
311309
}
312310
}
313311

@@ -454,8 +452,32 @@ func (f *proxyFlow) executeWithProxy(
454452
}
455453

456454
if sessionError != nil {
457-
return fmt.Errorf("failed to wait for session: %w", sessionError)
455+
return f.handlePackageManagerExecutionError(sessionError)
458456
}
459457

460458
return nil
461459
}
460+
461+
func (f *proxyFlow) handlePackageManagerExecutionError(err error) error {
462+
if exitErr, ok := err.(*exec.ExitError); ok {
463+
return usefulerror.Useful().
464+
WithCode(usefulerror.ErrCodePackageManagerExecutionFailed).
465+
WithHumanError(fmt.Sprintf("Package manager command exited with code: %d", exitErr.ExitCode())).
466+
WithHelp("Check the package manager command and its arguments").
467+
Wrap(err)
468+
}
469+
470+
if sessionError, ok := err.(*pty.ExitError); ok {
471+
return usefulerror.Useful().
472+
WithCode(usefulerror.ErrCodePackageManagerExecutionFailed).
473+
WithHumanError(fmt.Sprintf("Package manager command exited with code: %d", sessionError.Code)).
474+
WithHelp("Check the package manager command and its arguments").
475+
Wrap(sessionError.Err)
476+
}
477+
478+
return usefulerror.Useful().
479+
WithCode(usefulerror.ErrCodePackageManagerExecutionFailed).
480+
WithHumanError("Failed to execute package manager command").
481+
WithHelp("Check the package manager command and its arguments").
482+
Wrap(err)
483+
}

internal/ui/error.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,9 @@ func ErrorExit(err error) {
3333
}
3434

3535
// printMinimalError prints error in minimal two-line format:
36-
// Line 1: Error code (red background) + message (red)
37-
// Line 2: Actionable hint with arrow prefix (dimmed)
3836
func printMinimalError(code, message, hint string) {
39-
// Line 1: Error code + message
4037
fmt.Printf("%s %s\n", Colors.ErrorCode(" %s ", code), Colors.Red(message))
4138

42-
// Line 2: Actionable hint with arrow (only if meaningful)
4339
if hint != "" && hint != "No additional help is available for this error." {
4440
fmt.Printf(" %s %s\n", Colors.Dim("→"), Colors.Dim(hint))
4541
}

0 commit comments

Comments
 (0)