@@ -50,7 +50,26 @@ flowchart TD
5050 CheckLinux -->|No| Exit3([Exit: Unsupported Linux])
5151 CheckLinux -->|Yes| Section3[Section 3: Dependency Checks]
5252
53- Section3 --> CheckGit{Git Installed?}
53+ Section3 --> LinuxSudo{Linux Platform?}
54+ LinuxSudo -->|Yes| CheckSudoCached{Sudo Cached?}
55+ LinuxSudo -->|No| CheckGit
56+
57+ CheckSudoCached -->|Yes| UseCachedSudo[Use existing sudo session]
58+ CheckSudoCached -->|No| CheckInteractive{Interactive Terminal?}
59+
60+ CheckInteractive -->|Yes| SudoPromptLocal[Request sudo password locally]
61+ CheckInteractive -->|No| CheckTTY{/dev/tty Available?}
62+
63+ CheckTTY -->|Yes| SudoPromptPipe[Reconnect to /dev/tty, request sudo]
64+ CheckTTY -->|No| SkipSudo[Skip upfront sudo, prompt per command]
65+
66+ UseCachedSudo --> StartSudoKeeper[Start 60s sudo keep-alive loop]
67+ SudoPromptLocal --> StartSudoKeeper
68+ SudoPromptPipe --> StartSudoKeeper
69+ SkipSudo --> CheckGit
70+ StartSudoKeeper --> CheckGit
71+
72+ CheckGit{Git Installed?}
5473 CheckGit -->|No| InstallGit[Install Git]
5574 CheckGit -->|Yes| CheckNode
5675
@@ -544,4 +563,177 @@ See [docs/deployment.md](./deployment.md#neo4j-configuration-notes) for complete
544563- **Reduced emoji usage** for professional environments
545564- **Clear node shapes** that indicate purpose (rectangles=actions, diamonds=decisions)
546565- **Logical flow direction** (top-down for processes, left-right for recovery)
547- - **Grouped elements** with subtle background differentiation
566+ - **Grouped elements** with subtle background differentiation
567+ ---
568+
569+ # # 🔐 Smart Sudo Authentication (Linux)
570+
571+ GraphDone implements intelligent sudo management that works seamlessly across all installation methods (curl/wget pipes and local execution).
572+
573+ # ## Authentication Flow
574+
575+ ` ` ` mermaid
576+ flowchart TD
577+ Start[Linux Dependency Installation] --> CheckCached{Sudo Already<br/>Cached?}
578+
579+ CheckCached -->|Yes| UseCached[Use Existing Session]
580+ CheckCached -->|No| CheckInteractive{Interactive<br/>Terminal?}
581+
582+ UseCached --> StartKeeper[Start 60s Keep-Alive Loop]
583+
584+ CheckInteractive -->|Yes - Local| PromptLocal[Show: Requesting privileges<br/>Prompt: Password]
585+ CheckInteractive -->|No - Piped| CheckTTY{/dev/tty<br/>Available?}
586+
587+ PromptLocal --> LocalAuth{Auth<br/>Success?}
588+ LocalAuth -->|Yes| ReplaceMsg[Replace line with:<br/>✓ Administrative access granted]
589+ LocalAuth -->|No| Fail[Show error, exit]
590+
591+ CheckTTY -->|Yes| Reconnect[Redirect stdin/stdout/stderr<br/>to /dev/tty in subshell]
592+ CheckTTY -->|No| SkipUpfront[Skip upfront sudo<br/>Each command prompts individually]
593+
594+ Reconnect --> PromptPipe[Show: Requesting privileges<br/>Prompt: Password]
595+ PromptPipe --> PipeAuth{Auth<br/>Success?}
596+ PipeAuth -->|Yes| RestoreIO[Subshell exits<br/>File descriptors restored]
597+ PipeAuth -->|No| Fail
598+
599+ ReplaceMsg --> StartKeeper
600+ RestoreIO --> StartKeeper
601+ SkipUpfront --> InstallDeps[Install Dependencies]
602+
603+ StartKeeper --> SetTrap[Set EXIT trap:<br/>sudo -k to clear cache]
604+ SetTrap --> InstallDeps
605+
606+ InstallDeps --> Complete[Installation Continues]
607+
608+ classDef startNode fill:#3B82F6,stroke:#1D4ED8,stroke-width:2px,color:#FFFFFF
609+ classDef processNode fill:#10B981,stroke:#059669,stroke-width:2px,color:#FFFFFF
610+ classDef decisionNode fill:#F59E0B,stroke:#D97706,stroke-width:2px,color:#FFFFFF
611+ classDef successNode fill:#22C55E,stroke:#16A34A,stroke-width:3px,color:#FFFFFF
612+ classDef errorNode fill:#EF4444,stroke:#DC2626,stroke-width:2px,color:#FFFFFF
613+ classDef securityNode fill:#8B5CF6,stroke:#7C3AED,stroke-width:2px,color:#FFFFFF
614+
615+ class Start startNode
616+ class PromptLocal,PromptPipe,Reconnect,RestoreIO,ReplaceMsg,StartKeeper,SetTrap,InstallDeps processNode
617+ class CheckCached,CheckInteractive,CheckTTY,LocalAuth,PipeAuth decisionNode
618+ class Complete successNode
619+ class Fail errorNode
620+ class UseCached,SkipUpfront securityNode
621+ ` ` `
622+
623+ # ## Key Features
624+
625+ # ### 1. **Smart Detection**
626+ - Checks if sudo is already cached (user authenticated recently)
627+ - No prompt needed if sudo session is fresh
628+ - Reduces interruptions during installation
629+
630+ # ### 2. **Universal Compatibility**
631+ Works with all installation methods :
632+
633+ | Method | How It Works |
634+ |--------|-------------|
635+ | **Local execution** (`sh install.sh`) | Normal prompt, clean line replacement |
636+ | **curl pipe** (`curl ... \| sh`) | Reconnects to `/dev/tty` in subshell |
637+ | **wget pipe** (`wget ... \| sh`) | Same as curl, automatic fallback |
638+ | **No TTY** (rare) | Skips upfront sudo, each command prompts |
639+
640+ # ### 3. **Secure Session Management**
641+ - **Single authentication**: Request sudo once upfront
642+ - **Keep-alive loop**: Refreshes sudo every 60 seconds during installation
643+ - **Automatic cleanup**: `EXIT` trap clears sudo cache when script exits
644+ - **No lingering permissions**: Security-first design
645+
646+ # ### 4. **Clean User Experience**
647+
648+ **Interactive Mode** (local execution):
649+ ```
650+ ──────────────────── 🔰 Dependency Checks ────────────────────
651+
652+ ✓ Administrative access granted
653+
654+ • Checking Git installation...
655+ ```
656+
657+ **Piped Mode** (curl/wget):
658+ ```
659+ ──────────────────── 🔰 Dependency Checks ────────────────────
660+
661+ ◉ Requesting administrative privileges for installations
662+ Password:
663+ ✓ Administrative access granted
664+
665+ • Checking Git installation...
666+ ```
667+
668+ ### Technical Implementation
669+
670+ #### File Descriptor Management (Piped Mode)
671+
672+ ```bash
673+ # Wrap in subshell to auto-restore file descriptors
674+ (
675+ exec < /dev/tty # Reconnect stdin to terminal
676+ exec > /dev/tty # Reconnect stdout to terminal
677+ exec 2> /dev/tty # Reconnect stderr to terminal
678+
679+ # Now sudo can prompt for password
680+ sudo -p " Password: " -v
681+
682+ # Show success message
683+ printf " ✓ Administrative access granted\n"
684+ )
685+ # After subshell exits, stdin/stdout/stderr automatically restored
686+ # Rest of installation output goes to original streams (curl/wget)
687+ ```
688+
689+ #### Keep-Alive Background Process
690+
691+ ``` bash
692+ # Refresh sudo every 60 seconds
693+ (while true ; do
694+ sudo -n true
695+ sleep 60
696+ kill -0 " $$ " || exit # Exit if parent died
697+ done 2> /dev/null) &
698+
699+ SUDO_KEEPER_PID=$!
700+ ```
701+
702+ #### Security Trap
703+
704+ ``` bash
705+ # Clear sudo cache on exit (success or failure)
706+ trap ' sudo -k; kill $SUDO_KEEPER_PID 2>/dev/null' EXIT
707+ ```
708+
709+ ### Why This Approach?
710+
711+ ** Industry Standard** : Used by professional installers like Homebrew, Docker, etc.
712+
713+ ** Benefits** :
714+ - ✅ Single password prompt (smooth UX)
715+ - ✅ Works everywhere (local, curl, wget)
716+ - ✅ Secure (clears cache on exit)
717+ - ✅ Efficient (no multiple prompts)
718+ - ✅ Transparent (shows what's happening)
719+
720+ ** Alternatives Considered** :
721+ - ❌ Multiple prompts per command (annoying)
722+ - ❌ Hardcode sudo in commands (doesn't work with pipes)
723+ - ❌ Skip sudo management (broken on curl/wget)
724+ - ❌ Cache sudo indefinitely (security risk)
725+
726+ ### Troubleshooting
727+
728+ #### "Failed to obtain sudo privileges"
729+ - ** Cause** : Incorrect password or sudo not configured
730+ - ** Solution** : Check password, verify user in sudoers file
731+
732+ #### Terminal hangs after password
733+ - ** Cause** : File descriptors not restored (fixed in v0.3.1-alpha)
734+ - ** Solution** : Update to latest version
735+
736+ #### Multiple password prompts
737+ - ** Cause** : Upfront sudo failed, falling back to per-command prompts
738+ - ** Solution** : This is expected behavior when ` /dev/tty ` unavailable
739+
0 commit comments