Skip to content

Commit 5ced794

Browse files
committed
docs: Update documentation for smart sudo authentication
- Added sudo authentication flow diagram to installation-flow.md - Updated README.md with smart sudo handling details - Enhanced deployment.md with Linux sudo management section - Documented curl/wget pipe compatibility - Added technical implementation details and troubleshooting Key changes: - Smart detection of cached sudo sessions - /dev/tty reconnection for piped execution - 60-second keep-alive loop with security cleanup - Universal compatibility (local, curl, wget)
1 parent 0a47640 commit 5ced794

File tree

3 files changed

+206
-6
lines changed

3 files changed

+206
-6
lines changed

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ wget -qO- https://raw.githubusercontent.com/GraphDone/GraphDone-Core/main/public
6262
2. **System Detection** - Detects platform (macOS 10.15+, Linux distros)
6363
3. **Dependency Installation** - Installs Git, Node.js 18+, Docker if needed
6464
- macOS: Uses Homebrew + OrbStack (Docker alternative)
65-
- Linux: Uses apt/dnf/yum + Docker Engine (15+ distributions supported)
65+
- Linux: Smart sudo authentication (works with curl/wget pipes), uses apt/dnf/yum + Docker Engine (15+ distributions supported)
6666
4. **Code Setup** - Clones repository to `~/graphdone`, installs npm dependencies
6767
5. **Security Config** - Generates self-signed TLS certificates for HTTPS
6868
6. **Service Deployment** - Starts Neo4j, Redis, GraphQL API, React Web App
@@ -95,8 +95,9 @@ sh install.sh
9595

9696
**What the installation script does:**
9797
- ✅ Installs to `~/graphdone` (visible, user-owned directory)
98-
- ✅ Never requires sudo for core installation
99-
- ✅ Only asks for permission when installing system dependencies (Docker, Git)
98+
- ✅ Smart sudo handling - works with curl/wget pipes and local execution
99+
- ✅ Only requests administrative privileges once for system dependencies (Docker, Git)
100+
- ✅ Sudo access kept alive during installation, cleared on exit for security
100101
- ✅ All source code is open and auditable
101102
- ✅ No telemetry or data collection
102103
- ⚠️ Generates self-signed TLS certificates (you'll see browser warnings - this is expected)

docs/deployment.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,21 @@ The installation script performs 9 automated steps:
4141
- Shell environment validation
4242

4343
### 3. Dependency Installation
44-
Automatically installs missing dependencies:
44+
Automatically installs missing dependencies with smart sudo authentication:
4545

4646
**macOS:**
4747
- Git via Homebrew
4848
- Node.js 18+ via Homebrew
4949
- OrbStack (lightweight Docker alternative) via Homebrew
5050

5151
**Linux (15+ distributions):**
52+
- **Smart Sudo Management**:
53+
- Checks if sudo is already cached (no prompt if recently authenticated)
54+
- Works with curl/wget pipes via `/dev/tty` reconnection
55+
- Works with local execution (`sh install.sh`)
56+
- Requests administrative privileges once upfront
57+
- Keeps sudo alive (60-second refresh) during installation
58+
- Automatically clears sudo cache on exit for security
5259
- Git via apt-get/dnf/yum
5360
- Node.js 22 LTS via nvm
5461
- Docker Engine via Snap (preferred) or apt-get/dnf/yum

docs/installation-flow.md

Lines changed: 194 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)