@geekbeer/minion 2.57.0 → 2.59.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/core/routes/sudoers.js +70 -0
- package/linux/minion-cli.sh +3 -0
- package/linux/server.js +3 -0
- package/package.json +1 -1
- package/rules/core.md +1 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sudoers endpoint
|
|
3
|
+
*
|
|
4
|
+
* Endpoints:
|
|
5
|
+
* - GET /api/sudoers - List sudo permissions for the current user
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const { exec } = require('child_process')
|
|
9
|
+
const { promisify } = require('util')
|
|
10
|
+
const execAsync = promisify(exec)
|
|
11
|
+
|
|
12
|
+
const { verifyToken } = require('../lib/auth')
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Parse `sudo -l` output into structured permission entries
|
|
16
|
+
* @param {string} output - Raw output from `sudo -l`
|
|
17
|
+
* @returns {string[]} List of allowed commands
|
|
18
|
+
*/
|
|
19
|
+
function parseSudoList(output) {
|
|
20
|
+
const lines = output.split('\n')
|
|
21
|
+
const commands = []
|
|
22
|
+
|
|
23
|
+
for (const line of lines) {
|
|
24
|
+
const trimmed = line.trim()
|
|
25
|
+
// Lines starting with (root) contain permission entries
|
|
26
|
+
if (trimmed.startsWith('(root)') || trimmed.startsWith('(ALL)')) {
|
|
27
|
+
// Extract the command part after NOPASSWD: or the run-as spec
|
|
28
|
+
const match = trimmed.match(/(?:NOPASSWD:\s*)(.+)$/)
|
|
29
|
+
if (match) {
|
|
30
|
+
commands.push(match[1].trim())
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return commands
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Register sudoers routes as Fastify plugin
|
|
40
|
+
* @param {import('fastify').FastifyInstance} fastify
|
|
41
|
+
*/
|
|
42
|
+
async function sudoersRoutes(fastify) {
|
|
43
|
+
fastify.get('/api/sudoers', async (request, reply) => {
|
|
44
|
+
if (!verifyToken(request)) {
|
|
45
|
+
reply.code(401)
|
|
46
|
+
return { success: false, error: 'Unauthorized' }
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
try {
|
|
50
|
+
const { stdout } = await execAsync('sudo -n -l 2>/dev/null', { timeout: 5000 })
|
|
51
|
+
const commands = parseSudoList(stdout)
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
success: true,
|
|
55
|
+
commands,
|
|
56
|
+
raw: stdout.trim(),
|
|
57
|
+
}
|
|
58
|
+
} catch (error) {
|
|
59
|
+
// sudo -l may fail if sudo is not configured at all
|
|
60
|
+
return {
|
|
61
|
+
success: true,
|
|
62
|
+
commands: [],
|
|
63
|
+
raw: '',
|
|
64
|
+
note: 'sudo is not configured or no permissions granted',
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
})
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
module.exports = { sudoersRoutes }
|
package/linux/minion-cli.sh
CHANGED
|
@@ -320,6 +320,9 @@ do_setup() {
|
|
|
320
320
|
local SUDOERS_FILE="/etc/sudoers.d/minion-agent"
|
|
321
321
|
|
|
322
322
|
{
|
|
323
|
+
# Fail immediately instead of prompting for password (safety net for LLM agents)
|
|
324
|
+
echo "Defaults:${TARGET_USER} passwd_tries=0"
|
|
325
|
+
echo ""
|
|
323
326
|
echo "${TARGET_USER} ALL=(root) NOPASSWD: ${NPM_BIN} install -g @geekbeer/minion@latest"
|
|
324
327
|
echo "${TARGET_USER} ALL=(root) NOPASSWD: ${NPM_BIN} install -g @geekbeer/minion@latest --registry *"
|
|
325
328
|
echo "${TARGET_USER} ALL=(root) NOPASSWD: /usr/bin/apt-get install *"
|
package/linux/server.js
CHANGED
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
* Secrets: GET /api/secrets, PUT/DELETE /api/secrets/:key
|
|
21
21
|
* Config: GET /api/config/backup, GET/PUT /api/config/env
|
|
22
22
|
* Executions: GET /api/executions, GET /api/executions/:id, etc.
|
|
23
|
+
* Sudoers: GET /api/sudoers
|
|
23
24
|
* ─────────────────────────────────────────────────────────────────────────────
|
|
24
25
|
*/
|
|
25
26
|
|
|
@@ -65,6 +66,7 @@ const { authRoutes } = require('../core/routes/auth')
|
|
|
65
66
|
const { variableRoutes } = require('../core/routes/variables')
|
|
66
67
|
const { memoryRoutes } = require('../core/routes/memory')
|
|
67
68
|
const { dailyLogRoutes } = require('../core/routes/daily-logs')
|
|
69
|
+
const { sudoersRoutes } = require('../core/routes/sudoers')
|
|
68
70
|
|
|
69
71
|
// Linux-specific routes
|
|
70
72
|
const { commandRoutes, getProcessManager, getAllowedCommands } = require('./routes/commands')
|
|
@@ -265,6 +267,7 @@ async function registerAllRoutes(app) {
|
|
|
265
267
|
await app.register(variableRoutes)
|
|
266
268
|
await app.register(memoryRoutes)
|
|
267
269
|
await app.register(dailyLogRoutes)
|
|
270
|
+
await app.register(sudoersRoutes)
|
|
268
271
|
|
|
269
272
|
// Linux-specific routes
|
|
270
273
|
await app.register(commandRoutes)
|
package/package.json
CHANGED
package/rules/core.md
CHANGED
|
@@ -7,6 +7,7 @@ You are an AI agent running on a Minion VPS, managed by @geekbeer/minion.
|
|
|
7
7
|
- **HQサーバーのソースコードを読みに行く必要はありません。** 必要なAPI仕様はすべてドキュメントに記載されています。
|
|
8
8
|
- API の詳細仕様が必要な場合は `~/.minion/docs/api-reference.md` を参照してください。
|
|
9
9
|
- タスクの手順が不明な場合は `~/.minion/docs/task-guides.md` を参照してください。
|
|
10
|
+
- **`sudo` を使用しないこと。** 必要なツール・ライブラリはすべてセットアップ済みです。`sudo` はパスワード未設定のため実行できません。パッケージのインストールや環境構築が必要に見える場合でも、既にインストール済みであることを前提に作業を進めてください。
|
|
10
11
|
|
|
11
12
|
## Architecture
|
|
12
13
|
|