start-command 0.7.6 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +297 -0
- package/CHANGELOG.md +46 -0
- package/README.md +68 -7
- package/REQUIREMENTS.md +72 -1
- package/experiments/user-isolation-research.md +83 -0
- package/package.json +1 -1
- package/src/bin/cli.js +131 -36
- package/src/lib/args-parser.js +95 -5
- package/src/lib/isolation.js +184 -43
- package/src/lib/user-manager.js +429 -0
- package/test/args-parser.test.js +309 -0
- package/test/docker-autoremove.test.js +169 -0
- package/test/isolation-cleanup.test.js +377 -0
- package/test/isolation.test.js +233 -0
- package/test/user-manager.test.js +286 -0
package/ARCHITECTURE.md
ADDED
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
# Architecture
|
|
2
|
+
|
|
3
|
+
This document describes the architecture of the `$` command (start-command).
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The start-command is a CLI tool that wraps shell commands to provide automatic logging, error reporting, natural language aliases, and process isolation capabilities.
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
┌─────────────────────────────────────────────────────────────────────┐
|
|
11
|
+
│ User Command │
|
|
12
|
+
│ $ [options] command [args] │
|
|
13
|
+
└──────────────────────────────┬──────────────────────────────────────┘
|
|
14
|
+
│
|
|
15
|
+
▼
|
|
16
|
+
┌─────────────────────────────────────────────────────────────────────┐
|
|
17
|
+
│ CLI Entry Point │
|
|
18
|
+
│ src/bin/cli.js │
|
|
19
|
+
├─────────────────────────────────────────────────────────────────────┤
|
|
20
|
+
│ • Parse command line arguments │
|
|
21
|
+
│ • Handle --version, --help flags │
|
|
22
|
+
│ • Route to isolation or direct execution │
|
|
23
|
+
└──────────────────────────────┬──────────────────────────────────────┘
|
|
24
|
+
│
|
|
25
|
+
┌────────────────┴────────────────┐
|
|
26
|
+
│ │
|
|
27
|
+
▼ ▼
|
|
28
|
+
┌─────────────────────────┐ ┌─────────────────────────────────────┐
|
|
29
|
+
│ Direct Execution │ │ Isolated Execution │
|
|
30
|
+
│ (no --isolated) │ │ (--isolated screen/tmux/docker) │
|
|
31
|
+
├─────────────────────────┤ ├─────────────────────────────────────┤
|
|
32
|
+
│ • Spawn shell process │ │ src/lib/isolation.js │
|
|
33
|
+
│ • Capture stdout/stderr │ │ • runInScreen() │
|
|
34
|
+
│ • Log to temp file │ │ • runInTmux() │
|
|
35
|
+
│ • Report failures │ │ • runInDocker() │
|
|
36
|
+
└─────────────────────────┘ └─────────────────────────────────────┘
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Core Modules
|
|
40
|
+
|
|
41
|
+
### 1. CLI Entry Point (`src/bin/cli.js`)
|
|
42
|
+
|
|
43
|
+
The main entry point that:
|
|
44
|
+
|
|
45
|
+
- Parses command line arguments using `args-parser.js`
|
|
46
|
+
- Processes command substitutions using `substitution.js`
|
|
47
|
+
- Routes execution to direct mode or isolation mode
|
|
48
|
+
- Handles logging and error reporting
|
|
49
|
+
|
|
50
|
+
### 2. Argument Parser (`src/lib/args-parser.js`)
|
|
51
|
+
|
|
52
|
+
Parses wrapper options and extracts the command to execute:
|
|
53
|
+
|
|
54
|
+
```javascript
|
|
55
|
+
{
|
|
56
|
+
isolated: null, // 'screen' | 'tmux' | 'docker' | null
|
|
57
|
+
attached: false, // Run in attached/foreground mode
|
|
58
|
+
detached: false, // Run in detached/background mode
|
|
59
|
+
session: null, // Custom session name
|
|
60
|
+
image: null, // Docker image name
|
|
61
|
+
keepAlive: false, // Keep environment alive after command exits
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### 3. Substitution Engine (`src/lib/substitution.js`)
|
|
66
|
+
|
|
67
|
+
Provides natural language command aliases:
|
|
68
|
+
|
|
69
|
+
- Loads patterns from `substitutions.lino`
|
|
70
|
+
- Matches user input against patterns with variables
|
|
71
|
+
- Returns substituted command or original if no match
|
|
72
|
+
|
|
73
|
+
### 4. Isolation Module (`src/lib/isolation.js`)
|
|
74
|
+
|
|
75
|
+
Handles process isolation in terminal multiplexers and containers:
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
┌────────────────────────────────────────────────────────────┐
|
|
79
|
+
│ runIsolated() │
|
|
80
|
+
│ (dispatcher function) │
|
|
81
|
+
└───────────────┬───────────────┬───────────────┬────────────┘
|
|
82
|
+
│ │ │
|
|
83
|
+
┌───────▼───────┐ ┌─────▼─────┐ ┌───────▼───────┐
|
|
84
|
+
│ runInScreen │ │runInTmux │ │ runInDocker │
|
|
85
|
+
│ │ │ │ │ │
|
|
86
|
+
│ GNU Screen │ │ tmux │ │ Docker │
|
|
87
|
+
│ multiplexer │ │ terminal │ │ containers │
|
|
88
|
+
└───────────────┘ └───────────┘ └───────────────┘
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Isolation Architecture
|
|
92
|
+
|
|
93
|
+
### Execution Modes
|
|
94
|
+
|
|
95
|
+
| Mode | Description | Default Behavior |
|
|
96
|
+
| ------------ | ------------------------------------------- | ------------------------------ |
|
|
97
|
+
| Attached | Command runs in foreground, interactive | Session exits after completion |
|
|
98
|
+
| Detached | Command runs in background | Session exits after completion |
|
|
99
|
+
| + Keep-Alive | Session stays alive after command completes | Requires `--keep-alive` flag |
|
|
100
|
+
|
|
101
|
+
### Auto-Exit Behavior
|
|
102
|
+
|
|
103
|
+
By default, all isolation environments automatically exit after command completion:
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
┌───────────────────────────────────────────────────────────────┐
|
|
107
|
+
│ Default (keepAlive=false) │
|
|
108
|
+
├───────────────────────────────────────────────────────────────┤
|
|
109
|
+
│ 1. Start isolation environment │
|
|
110
|
+
│ 2. Execute command │
|
|
111
|
+
│ 3. Capture output (if attached mode) │
|
|
112
|
+
│ 4. Environment exits automatically │
|
|
113
|
+
│ 5. Resources freed │
|
|
114
|
+
└───────────────────────────────────────────────────────────────┘
|
|
115
|
+
|
|
116
|
+
┌───────────────────────────────────────────────────────────────┐
|
|
117
|
+
│ With --keep-alive │
|
|
118
|
+
├───────────────────────────────────────────────────────────────┤
|
|
119
|
+
│ 1. Start isolation environment │
|
|
120
|
+
│ 2. Execute command │
|
|
121
|
+
│ 3. Command completes │
|
|
122
|
+
│ 4. Shell stays running in session │
|
|
123
|
+
│ 5. User can reattach and interact │
|
|
124
|
+
└───────────────────────────────────────────────────────────────┘
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Screen Isolation
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
131
|
+
│ Screen Execution Flow │
|
|
132
|
+
├─────────────────────────────────────────────────────────────────┤
|
|
133
|
+
│ │
|
|
134
|
+
│ Attached Mode: │
|
|
135
|
+
│ ┌─────────────────────────────────────────────────────────┐ │
|
|
136
|
+
│ │ Uses detached mode with log capture internally │ │
|
|
137
|
+
│ │ • Start: screen -dmS <session> -L -Logfile <log> │ │
|
|
138
|
+
│ │ • Poll for session completion │ │
|
|
139
|
+
│ │ • Read and display captured output │ │
|
|
140
|
+
│ │ • Clean up log file │ │
|
|
141
|
+
│ └─────────────────────────────────────────────────────────┘ │
|
|
142
|
+
│ │
|
|
143
|
+
│ Detached Mode: │
|
|
144
|
+
│ ┌─────────────────────────────────────────────────────────┐ │
|
|
145
|
+
│ │ • Without keep-alive: screen -dmS <session> sh -c cmd │ │
|
|
146
|
+
│ │ • With keep-alive: screen -dmS <session> sh -c "cmd; sh"│ │
|
|
147
|
+
│ └─────────────────────────────────────────────────────────┘ │
|
|
148
|
+
│ │
|
|
149
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### tmux Isolation
|
|
153
|
+
|
|
154
|
+
```
|
|
155
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
156
|
+
│ tmux Execution Flow │
|
|
157
|
+
├─────────────────────────────────────────────────────────────────┤
|
|
158
|
+
│ │
|
|
159
|
+
│ Attached Mode: │
|
|
160
|
+
│ ┌─────────────────────────────────────────────────────────┐ │
|
|
161
|
+
│ │ • tmux new-session -s <session> <command> │ │
|
|
162
|
+
│ │ • Interactive, exits when command completes │ │
|
|
163
|
+
│ └─────────────────────────────────────────────────────────┘ │
|
|
164
|
+
│ │
|
|
165
|
+
│ Detached Mode: │
|
|
166
|
+
│ ┌─────────────────────────────────────────────────────────┐ │
|
|
167
|
+
│ │ • Without keep-alive: tmux new-session -d -s <session> │ │
|
|
168
|
+
│ │ • With keep-alive: command followed by shell exec │ │
|
|
169
|
+
│ └─────────────────────────────────────────────────────────┘ │
|
|
170
|
+
│ │
|
|
171
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Docker Isolation
|
|
175
|
+
|
|
176
|
+
```
|
|
177
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
178
|
+
│ Docker Execution Flow │
|
|
179
|
+
├─────────────────────────────────────────────────────────────────┤
|
|
180
|
+
│ │
|
|
181
|
+
│ Attached Mode: │
|
|
182
|
+
│ ┌─────────────────────────────────────────────────────────┐ │
|
|
183
|
+
│ │ • docker run -it --rm --name <name> <image> sh -c cmd │ │
|
|
184
|
+
│ │ • Interactive, container auto-removed on exit │ │
|
|
185
|
+
│ └─────────────────────────────────────────────────────────┘ │
|
|
186
|
+
│ │
|
|
187
|
+
│ Detached Mode: │
|
|
188
|
+
│ ┌─────────────────────────────────────────────────────────┐ │
|
|
189
|
+
│ │ • Without keep-alive: docker run -d --name <name> ... │ │
|
|
190
|
+
│ │ • With keep-alive: command followed by shell exec │ │
|
|
191
|
+
│ └─────────────────────────────────────────────────────────┘ │
|
|
192
|
+
│ │
|
|
193
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## Logging Architecture
|
|
197
|
+
|
|
198
|
+
```
|
|
199
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
200
|
+
│ Logging Flow │
|
|
201
|
+
├─────────────────────────────────────────────────────────────────┤
|
|
202
|
+
│ │
|
|
203
|
+
│ ┌─────────────┐ ┌──────────────┐ ┌───────────────────┐ │
|
|
204
|
+
│ │ Command │───▶│ Capture │───▶│ Write to │ │
|
|
205
|
+
│ │ Execution │ │ stdout/stderr│ │ Temp Log File │ │
|
|
206
|
+
│ └─────────────┘ └──────────────┘ └───────────────────┘ │
|
|
207
|
+
│ │
|
|
208
|
+
│ Log File Format: │
|
|
209
|
+
│ ┌─────────────────────────────────────────────────────────┐ │
|
|
210
|
+
│ │ === Start Command Log === │ │
|
|
211
|
+
│ │ Timestamp: 2024-01-15 10:30:45 │ │
|
|
212
|
+
│ │ Command: <command> │ │
|
|
213
|
+
│ │ Shell: /bin/bash │ │
|
|
214
|
+
│ │ Platform: linux │ │
|
|
215
|
+
│ │ ================================================== │ │
|
|
216
|
+
│ │ <command output> │ │
|
|
217
|
+
│ │ ================================================== │ │
|
|
218
|
+
│ │ Finished: 2024-01-15 10:30:46 │ │
|
|
219
|
+
│ │ Exit Code: 0 │ │
|
|
220
|
+
│ └─────────────────────────────────────────────────────────┘ │
|
|
221
|
+
│ │
|
|
222
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## File Structure
|
|
226
|
+
|
|
227
|
+
```
|
|
228
|
+
start-command/
|
|
229
|
+
├── src/
|
|
230
|
+
│ ├── bin/
|
|
231
|
+
│ │ └── cli.js # Main entry point
|
|
232
|
+
│ └── lib/
|
|
233
|
+
│ ├── args-parser.js # Argument parsing
|
|
234
|
+
│ ├── isolation.js # Isolation backends
|
|
235
|
+
│ ├── substitution.js # Command aliases
|
|
236
|
+
│ └── substitutions.lino # Alias patterns
|
|
237
|
+
├── test/
|
|
238
|
+
│ ├── cli.test.js # CLI tests
|
|
239
|
+
│ ├── isolation.test.js # Isolation tests
|
|
240
|
+
│ ├── args-parser.test.js # Parser tests
|
|
241
|
+
│ └── substitution.test.js # Substitution tests
|
|
242
|
+
├── docs/
|
|
243
|
+
│ ├── PIPES.md # Piping documentation
|
|
244
|
+
│ └── USAGE.md # Usage examples
|
|
245
|
+
├── experiments/ # Experimental scripts
|
|
246
|
+
├── REQUIREMENTS.md # Requirements specification
|
|
247
|
+
├── ARCHITECTURE.md # This file
|
|
248
|
+
└── README.md # Project overview
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
## Design Decisions
|
|
252
|
+
|
|
253
|
+
### 1. Auto-Exit by Default
|
|
254
|
+
|
|
255
|
+
All isolation environments exit automatically after command completion to:
|
|
256
|
+
|
|
257
|
+
- Prevent resource leaks from orphaned sessions
|
|
258
|
+
- Ensure consistent behavior across backends
|
|
259
|
+
- Match user expectations for command execution
|
|
260
|
+
|
|
261
|
+
### 2. Log Capture in Attached Screen Mode
|
|
262
|
+
|
|
263
|
+
Screen's attached mode uses internal detached mode with log capture because:
|
|
264
|
+
|
|
265
|
+
- Direct attached mode loses output for quick commands
|
|
266
|
+
- Screen's virtual terminal is destroyed before output is visible
|
|
267
|
+
- Log capture ensures reliable output preservation
|
|
268
|
+
|
|
269
|
+
### 3. Keep-Alive as Opt-In
|
|
270
|
+
|
|
271
|
+
The `--keep-alive` flag is disabled by default because:
|
|
272
|
+
|
|
273
|
+
- Most use cases don't require persistent sessions
|
|
274
|
+
- Prevents accidental resource consumption
|
|
275
|
+
- Explicit opt-in for advanced workflows
|
|
276
|
+
|
|
277
|
+
### 4. Uniform Backend Interface
|
|
278
|
+
|
|
279
|
+
All isolation backends share a consistent interface:
|
|
280
|
+
|
|
281
|
+
```javascript
|
|
282
|
+
async function runInBackend(command, options) {
|
|
283
|
+
return {
|
|
284
|
+
success: boolean,
|
|
285
|
+
sessionName: string,
|
|
286
|
+
message: string,
|
|
287
|
+
exitCode?: number,
|
|
288
|
+
output?: string
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
This enables:
|
|
294
|
+
|
|
295
|
+
- Easy addition of new backends
|
|
296
|
+
- Consistent error handling
|
|
297
|
+
- Unified logging format
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,51 @@
|
|
|
1
1
|
# start-command
|
|
2
2
|
|
|
3
|
+
## 0.10.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 8ea5659: Add user isolation support with --isolated-user and --keep-user options
|
|
8
|
+
|
|
9
|
+
Implements user isolation that creates a new isolated user to run commands:
|
|
10
|
+
|
|
11
|
+
## --isolated-user option (create isolated user with same permissions)
|
|
12
|
+
- Add --isolated-user, -u option to create a new isolated user automatically
|
|
13
|
+
- New user inherits group memberships from current user (sudo, docker, wheel, etc.)
|
|
14
|
+
- User is automatically deleted after command completes (unless --keep-user)
|
|
15
|
+
- Works with screen and tmux isolation backends (not docker)
|
|
16
|
+
- Optional custom username via --isolated-user=myname or -u myname
|
|
17
|
+
- For screen/tmux: Wraps commands with sudo -n -u <user>
|
|
18
|
+
- Requires sudo NOPASSWD configuration for useradd/userdel/sudo
|
|
19
|
+
|
|
20
|
+
## --keep-user option
|
|
21
|
+
- Add --keep-user option to prevent user deletion after command completes
|
|
22
|
+
- Useful when you need to inspect files created during execution
|
|
23
|
+
- User must be manually deleted with: sudo userdel -r <username>
|
|
24
|
+
|
|
25
|
+
## Other improvements
|
|
26
|
+
- Add comprehensive tests for user isolation
|
|
27
|
+
- Update documentation with user isolation examples
|
|
28
|
+
- Integrate --keep-alive and --auto-remove-docker-container from main branch
|
|
29
|
+
|
|
30
|
+
Usage:
|
|
31
|
+
- $ --isolated-user -- npm test # Auto-generated username, auto-deleted
|
|
32
|
+
- $ --isolated-user myrunner -- npm start # Custom username
|
|
33
|
+
- $ -u myrunner -- npm start # Short form
|
|
34
|
+
- $ --isolated screen --isolated-user -- npm test # Combine with process isolation
|
|
35
|
+
- $ --isolated-user --keep-user -- npm test # Keep user after completion
|
|
36
|
+
|
|
37
|
+
Note: User isolation requires sudo NOPASSWD configuration.
|
|
38
|
+
|
|
39
|
+
## 0.9.0
|
|
40
|
+
|
|
41
|
+
### Minor Changes
|
|
42
|
+
|
|
43
|
+
- c484149: Add --keep-alive option for isolation environments
|
|
44
|
+
- All isolation environments (screen, tmux, docker) now automatically exit after command completion by default
|
|
45
|
+
- New --keep-alive (-k) flag keeps the isolation environment running after command completes
|
|
46
|
+
- Add ARCHITECTURE.md documentation describing system design
|
|
47
|
+
- Update REQUIREMENTS.md with new option and auto-exit behavior documentation
|
|
48
|
+
|
|
3
49
|
## 0.7.6
|
|
4
50
|
|
|
5
51
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -152,6 +152,44 @@ $ --isolated docker --image oven/bun:latest -- bun install
|
|
|
152
152
|
$ -i tmux -s my-session -d bun start
|
|
153
153
|
```
|
|
154
154
|
|
|
155
|
+
### User Isolation
|
|
156
|
+
|
|
157
|
+
Create a new isolated user with the same group permissions as your current user to run commands in complete isolation:
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
# Create an isolated user with same permissions and run command
|
|
161
|
+
$ --isolated-user -- npm test
|
|
162
|
+
|
|
163
|
+
# Specify custom username for the isolated user
|
|
164
|
+
$ --isolated-user myrunner -- npm start
|
|
165
|
+
$ -u myrunner -- npm start
|
|
166
|
+
|
|
167
|
+
# Combine with process isolation (screen or tmux)
|
|
168
|
+
$ --isolated screen --isolated-user -- npm test
|
|
169
|
+
|
|
170
|
+
# Keep the user after command completes (don't delete)
|
|
171
|
+
$ --isolated-user --keep-user -- npm start
|
|
172
|
+
|
|
173
|
+
# The isolated user inherits your group memberships:
|
|
174
|
+
# - sudo group (if you have it)
|
|
175
|
+
# - docker group (if you have it)
|
|
176
|
+
# - wheel, admin, and other privileged groups
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
The `--isolated-user` option:
|
|
180
|
+
|
|
181
|
+
- Creates a new system user with the same group memberships as your current user
|
|
182
|
+
- Runs the command as that user
|
|
183
|
+
- Automatically deletes the user after the command completes (unless `--keep-user` is specified)
|
|
184
|
+
- Requires sudo access without password (NOPASSWD configuration)
|
|
185
|
+
- Works with screen and tmux isolation backends (not docker)
|
|
186
|
+
|
|
187
|
+
This is useful for:
|
|
188
|
+
|
|
189
|
+
- Running untrusted code in isolation
|
|
190
|
+
- Testing with a clean user environment
|
|
191
|
+
- Ensuring commands don't affect your user's files
|
|
192
|
+
|
|
155
193
|
#### Supported Backends
|
|
156
194
|
|
|
157
195
|
| Backend | Description | Installation |
|
|
@@ -162,16 +200,39 @@ $ -i tmux -s my-session -d bun start
|
|
|
162
200
|
|
|
163
201
|
#### Isolation Options
|
|
164
202
|
|
|
165
|
-
| Option
|
|
166
|
-
|
|
|
167
|
-
| `--isolated, -i`
|
|
168
|
-
| `--attached, -a`
|
|
169
|
-
| `--detached, -d`
|
|
170
|
-
| `--session, -s`
|
|
171
|
-
| `--image`
|
|
203
|
+
| Option | Description |
|
|
204
|
+
| -------------------------------- | --------------------------------------------------------- |
|
|
205
|
+
| `--isolated, -i` | Isolation backend (screen, tmux, docker) |
|
|
206
|
+
| `--attached, -a` | Run in attached/foreground mode (default) |
|
|
207
|
+
| `--detached, -d` | Run in detached/background mode |
|
|
208
|
+
| `--session, -s` | Custom session/container name |
|
|
209
|
+
| `--image` | Docker image (required for docker isolation) |
|
|
210
|
+
| `--isolated-user, -u [name]` | Create isolated user with same permissions (screen/tmux) |
|
|
211
|
+
| `--keep-user` | Keep isolated user after command completes (don't delete) |
|
|
212
|
+
| `--keep-alive, -k` | Keep session alive after command completes |
|
|
213
|
+
| `--auto-remove-docker-container` | Auto-remove docker container after exit (docker only) |
|
|
172
214
|
|
|
173
215
|
**Note:** Using both `--attached` and `--detached` together will result in an error - you must choose one mode.
|
|
174
216
|
|
|
217
|
+
#### Auto-Exit Behavior
|
|
218
|
+
|
|
219
|
+
By default, all isolation environments (screen, tmux, docker) automatically exit after the target command completes. This ensures resources are freed immediately and provides uniform behavior across all backends.
|
|
220
|
+
|
|
221
|
+
Use `--keep-alive` (`-k`) to keep the session running after command completion:
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
# Default: session exits after command completes
|
|
225
|
+
$ -i screen -d -- echo "hello"
|
|
226
|
+
# Session will exit automatically after command completes.
|
|
227
|
+
|
|
228
|
+
# With --keep-alive: session stays running for interaction
|
|
229
|
+
$ -i screen -d -k -- echo "hello"
|
|
230
|
+
# Session will stay alive after command completes.
|
|
231
|
+
# You can reattach with: screen -r <session-name>
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
For Docker containers, by default the container filesystem is preserved (appears in `docker ps -a`) so you can re-enter it later. Use `--auto-remove-docker-container` to remove the container immediately after exit.
|
|
235
|
+
|
|
175
236
|
### Graceful Degradation
|
|
176
237
|
|
|
177
238
|
The tool works in any environment:
|
package/REQUIREMENTS.md
CHANGED
|
@@ -142,6 +142,10 @@ Support two patterns for passing wrapper options:
|
|
|
142
142
|
- `--detached, -d`: Run in detached/background mode
|
|
143
143
|
- `--session, -s <name>`: Custom session name
|
|
144
144
|
- `--image <image>`: Docker image (required for docker backend)
|
|
145
|
+
- `--isolated-user, -u [username]`: Create new isolated user with same group permissions as current user
|
|
146
|
+
- `--keep-user`: Keep isolated user after command completes (don't delete)
|
|
147
|
+
- `--keep-alive, -k`: Keep isolation environment alive after command exits (disabled by default)
|
|
148
|
+
- `--auto-remove-docker-container`: Automatically remove docker container after exit (disabled by default, only valid with --isolated docker)
|
|
145
149
|
|
|
146
150
|
#### 6.3 Supported Backends
|
|
147
151
|
|
|
@@ -155,10 +159,77 @@ Support two patterns for passing wrapper options:
|
|
|
155
159
|
- **Detached mode**: Command runs in background, session info displayed for reattachment
|
|
156
160
|
- **Conflict handling**: If both --attached and --detached are specified, show error asking user to choose one
|
|
157
161
|
|
|
158
|
-
#### 6.5
|
|
162
|
+
#### 6.5 User Isolation
|
|
163
|
+
|
|
164
|
+
- `--isolated-user, -u [username]`: Create a new isolated user with same permissions
|
|
165
|
+
- Creates user with same group memberships as current user (sudo, docker, wheel, etc.)
|
|
166
|
+
- Automatically generates username if not specified
|
|
167
|
+
- User is automatically deleted after command completes (unless `--keep-user` is specified)
|
|
168
|
+
- For screen/tmux: Wraps command with `sudo -n -u <username>`
|
|
169
|
+
- Requires sudo NOPASSWD for useradd/userdel commands
|
|
170
|
+
- Works with screen and tmux isolation (not docker)
|
|
171
|
+
|
|
172
|
+
#### 6.6 Keep User Option
|
|
173
|
+
|
|
174
|
+
- `--keep-user`: Keep the isolated user after command completes
|
|
175
|
+
- Only valid with `--isolated-user` option
|
|
176
|
+
- User must be manually deleted later with `sudo userdel -r <username>`
|
|
177
|
+
|
|
178
|
+
Example usage:
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
# Create isolated user and run command (user auto-deleted after)
|
|
182
|
+
$ --isolated-user -- npm test
|
|
183
|
+
|
|
184
|
+
# Custom username for isolated user
|
|
185
|
+
$ --isolated-user myrunner -- npm start
|
|
186
|
+
$ -u myrunner -- npm start
|
|
187
|
+
|
|
188
|
+
# Combine with screen isolation
|
|
189
|
+
$ --isolated screen --isolated-user -- npm test
|
|
190
|
+
|
|
191
|
+
# Combine with tmux detached mode
|
|
192
|
+
$ -i tmux -d --isolated-user testuser -- npm run build
|
|
193
|
+
|
|
194
|
+
# Keep user after command completes
|
|
195
|
+
$ --isolated-user --keep-user -- npm test
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Benefits:
|
|
199
|
+
|
|
200
|
+
- Clean user environment for each run
|
|
201
|
+
- Inherits sudo/docker access from current user
|
|
202
|
+
- Files created during execution belong to isolated user
|
|
203
|
+
- Automatic cleanup after execution (unless --keep-user)
|
|
204
|
+
|
|
205
|
+
#### 6.7 Auto-Exit Behavior
|
|
206
|
+
|
|
207
|
+
By default, all isolation environments (screen, tmux, docker) automatically exit after the target command completes execution. This ensures:
|
|
208
|
+
|
|
209
|
+
- Resources are freed immediately after command execution
|
|
210
|
+
- No orphaned sessions/containers remain running
|
|
211
|
+
- Uniform behavior across all isolation backends
|
|
212
|
+
- Command output is still captured and logged before exit
|
|
213
|
+
|
|
214
|
+
The `--keep-alive` flag can be used to override this behavior and keep the isolation environment running after command completion, useful for debugging or interactive workflows.
|
|
215
|
+
|
|
216
|
+
**Docker Container Filesystem Preservation:**
|
|
217
|
+
By default, when using Docker isolation, the container filesystem is preserved after the container exits. This allows you to re-enter the container and access any files created during command execution, which is useful for retrieving additional output files or debugging. The container appears in `docker ps -a` in an "exited" state but is not removed.
|
|
218
|
+
|
|
219
|
+
The `--auto-remove-docker-container` flag enables automatic removal of the container after exit, which is useful when you don't need to preserve the container filesystem and want to clean up resources completely. When this flag is enabled:
|
|
220
|
+
|
|
221
|
+
- The container is removed immediately after exiting (using docker's `--rm` flag)
|
|
222
|
+
- The container will not appear in `docker ps -a` after command completion
|
|
223
|
+
- You cannot re-enter the container to access files
|
|
224
|
+
- Resources are freed more aggressively
|
|
225
|
+
|
|
226
|
+
Note: `--auto-remove-docker-container` is only valid with `--isolated docker` and is independent of the `--keep-alive` flag.
|
|
227
|
+
|
|
228
|
+
#### 6.8 Graceful Degradation
|
|
159
229
|
|
|
160
230
|
- If isolation backend is not installed, show informative error with installation instructions
|
|
161
231
|
- If session creation fails, report error with details
|
|
232
|
+
- If sudo fails due to password requirement, command will fail with sudo error
|
|
162
233
|
|
|
163
234
|
## Configuration Options
|
|
164
235
|
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# User Isolation Research
|
|
2
|
+
|
|
3
|
+
## Issue #30: Support user isolation
|
|
4
|
+
|
|
5
|
+
### Understanding the Requirement
|
|
6
|
+
|
|
7
|
+
Based on the issue description:
|
|
8
|
+
|
|
9
|
+
> We need to find a way to support not only isolation in screen, but also isolation by user at the same time.
|
|
10
|
+
|
|
11
|
+
And the clarification from the user:
|
|
12
|
+
|
|
13
|
+
> No, there is no way to use existing user to run the command, user isolation should mean we create user - run command using this user, after command have finished we can delete user, unless we have `--keep-user` option.
|
|
14
|
+
|
|
15
|
+
This means:
|
|
16
|
+
|
|
17
|
+
1. Running commands in isolated environments (screen, tmux, docker) - **ALREADY IMPLEMENTED**
|
|
18
|
+
2. Creating new isolated users with same permissions as current user - **IMPLEMENTED**
|
|
19
|
+
3. Automatic cleanup of isolated users after command completes - **IMPLEMENTED**
|
|
20
|
+
4. Option to keep the user (`--keep-user`) - **IMPLEMENTED**
|
|
21
|
+
|
|
22
|
+
### Related Issues
|
|
23
|
+
|
|
24
|
+
- Issue #31: Support ssh isolation (execute commands on remote ssh servers)
|
|
25
|
+
- Issue #9: Isolation support (closed - implemented screen/tmux/docker)
|
|
26
|
+
|
|
27
|
+
### Final Implementation
|
|
28
|
+
|
|
29
|
+
The `--isolated-user` option creates a new isolated user with the same group memberships as the current user:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
# Create isolated user and run command (user auto-deleted after)
|
|
33
|
+
$ --isolated-user -- npm test
|
|
34
|
+
|
|
35
|
+
# Custom username for isolated user
|
|
36
|
+
$ --isolated-user myrunner -- npm start
|
|
37
|
+
$ -u myrunner -- npm start
|
|
38
|
+
|
|
39
|
+
# Combine with screen isolation
|
|
40
|
+
$ --isolated screen --isolated-user -- npm test
|
|
41
|
+
|
|
42
|
+
# Combine with tmux detached mode
|
|
43
|
+
$ -i tmux -d --isolated-user testuser -- npm run build
|
|
44
|
+
|
|
45
|
+
# Keep user after command completes
|
|
46
|
+
$ --isolated-user --keep-user -- npm test
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### How It Works
|
|
50
|
+
|
|
51
|
+
1. **User Creation**
|
|
52
|
+
- Creates new system user with same group memberships as current user
|
|
53
|
+
- Inherits sudo, docker, wheel, admin, and other groups
|
|
54
|
+
- Uses `sudo useradd` with `-G` flag for groups
|
|
55
|
+
|
|
56
|
+
2. **Command Execution**
|
|
57
|
+
- For screen/tmux: Wraps command with `sudo -n -u <user>`
|
|
58
|
+
- For standalone (no isolation backend): Uses `sudo -n -u <user> sh -c '<command>'`
|
|
59
|
+
|
|
60
|
+
3. **Cleanup**
|
|
61
|
+
- After command completes, user is deleted with `sudo userdel -r <user>`
|
|
62
|
+
- Unless `--keep-user` flag is specified
|
|
63
|
+
|
|
64
|
+
### Requirements
|
|
65
|
+
|
|
66
|
+
- `sudo` access with NOPASSWD configuration for:
|
|
67
|
+
- `useradd` - to create the isolated user
|
|
68
|
+
- `userdel` - to delete the isolated user
|
|
69
|
+
- `sudo -u` - to run commands as the isolated user
|
|
70
|
+
|
|
71
|
+
### Benefits
|
|
72
|
+
|
|
73
|
+
- Clean user environment for each run
|
|
74
|
+
- Inherits sudo/docker access from current user
|
|
75
|
+
- Files created during execution belong to isolated user
|
|
76
|
+
- Automatic cleanup after execution (unless --keep-user)
|
|
77
|
+
- Prevents untrusted code from affecting your user's files
|
|
78
|
+
|
|
79
|
+
### Limitations
|
|
80
|
+
|
|
81
|
+
- Not supported with Docker isolation (Docker has its own user isolation mechanism)
|
|
82
|
+
- Requires sudo NOPASSWD configuration
|
|
83
|
+
- Only works on Unix-like systems (Linux, macOS)
|