lucifer-gate 0.1.0-alpha.1
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/LICENSE +21 -0
- package/README.md +174 -0
- package/dist/server/cli.js +220 -0
- package/dist/server/cli.js.map +1 -0
- package/dist/server/create_app.js +95 -0
- package/dist/server/create_app.js.map +1 -0
- package/dist/server/domains/command-gateway/api/register_execute_routes.js +338 -0
- package/dist/server/domains/command-gateway/api/register_execute_routes.js.map +1 -0
- package/dist/server/domains/command-gateway/config/gateway_config.js +46 -0
- package/dist/server/domains/command-gateway/config/gateway_config.js.map +1 -0
- package/dist/server/domains/command-gateway/repository/api_key_store.js +44 -0
- package/dist/server/domains/command-gateway/repository/api_key_store.js.map +1 -0
- package/dist/server/domains/command-gateway/repository/approval_store.js +83 -0
- package/dist/server/domains/command-gateway/repository/approval_store.js.map +1 -0
- package/dist/server/domains/command-gateway/repository/audit_log.js +24 -0
- package/dist/server/domains/command-gateway/repository/audit_log.js.map +1 -0
- package/dist/server/domains/command-gateway/repository/command_rules_store.js +42 -0
- package/dist/server/domains/command-gateway/repository/command_rules_store.js.map +1 -0
- package/dist/server/domains/command-gateway/repository/database.js +59 -0
- package/dist/server/domains/command-gateway/repository/database.js.map +1 -0
- package/dist/server/domains/command-gateway/repository/pending_request_store.js +61 -0
- package/dist/server/domains/command-gateway/repository/pending_request_store.js.map +1 -0
- package/dist/server/domains/command-gateway/service/analyze_command_risk.js +44 -0
- package/dist/server/domains/command-gateway/service/analyze_command_risk.js.map +1 -0
- package/dist/server/domains/command-gateway/service/authenticate_request.js +71 -0
- package/dist/server/domains/command-gateway/service/authenticate_request.js.map +1 -0
- package/dist/server/domains/command-gateway/service/auto_approve_channel.js +24 -0
- package/dist/server/domains/command-gateway/service/auto_approve_channel.js.map +1 -0
- package/dist/server/domains/command-gateway/service/execute_command.js +139 -0
- package/dist/server/domains/command-gateway/service/execute_command.js.map +1 -0
- package/dist/server/domains/command-gateway/service/request_telegram_approval.js +126 -0
- package/dist/server/domains/command-gateway/service/request_telegram_approval.js.map +1 -0
- package/dist/server/domains/command-gateway/types/command_types.js +2 -0
- package/dist/server/domains/command-gateway/types/command_types.js.map +1 -0
- package/dist/server/domains/command-gateway/types/store_interfaces.js +2 -0
- package/dist/server/domains/command-gateway/types/store_interfaces.js.map +1 -0
- package/dist/server/domains/platform-api/api/register_health_routes.js +6 -0
- package/dist/server/domains/platform-api/api/register_health_routes.js.map +1 -0
- package/dist/server/domains/platform-api/config/server_config.js +17 -0
- package/dist/server/domains/platform-api/config/server_config.js.map +1 -0
- package/dist/server/domains/platform-api/repository/runtime_metadata_repository.js +7 -0
- package/dist/server/domains/platform-api/repository/runtime_metadata_repository.js.map +1 -0
- package/dist/server/domains/platform-api/service/create_health_report.js +10 -0
- package/dist/server/domains/platform-api/service/create_health_report.js.map +1 -0
- package/dist/server/domains/platform-api/types/health_report.js +2 -0
- package/dist/server/domains/platform-api/types/health_report.js.map +1 -0
- package/dist/server/index.js +18 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/lib/json_config_loader.js +31 -0
- package/dist/server/lib/json_config_loader.js.map +1 -0
- package/dist/server/lib/logger.js +12 -0
- package/dist/server/lib/logger.js.map +1 -0
- package/package.json +78 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Gian Maria
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# Lucifer Gate
|
|
2
|
+
|
|
3
|
+
AI agent command firewall with Telegram-based human approval.
|
|
4
|
+
|
|
5
|
+
Lucifer sits between your AI agent and the shell. It authenticates callers via API keys, matches commands against a policy file, and gates unknown commands through Telegram for human approval. Approved commands build up a permission library over time. Think "sudo via Telegram."
|
|
6
|
+
|
|
7
|
+
## Quick start (2 minutes, no Telegram needed)
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# Generate config files + API key
|
|
11
|
+
npx lucifer-gate --init .
|
|
12
|
+
|
|
13
|
+
# Start in dev mode (auto-approves everything, no Telegram)
|
|
14
|
+
LUCIFER_TELEGRAM_TOKEN=skip npx lucifer-gate --config ./config/lucifer.json --auto-approve
|
|
15
|
+
|
|
16
|
+
# In another terminal, test it:
|
|
17
|
+
curl -X POST http://localhost:3001/api/v1/execute \
|
|
18
|
+
-H "Content-Type: application/json" \
|
|
19
|
+
-H "x-api-key: YOUR_KEY_FROM_INIT" \
|
|
20
|
+
-d '{"command":"echo hello"}'
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## How it works
|
|
24
|
+
|
|
25
|
+
1. Caller sends `POST /api/v1/execute` with API key + command
|
|
26
|
+
2. Lucifer authenticates the key and checks IP allowlist
|
|
27
|
+
3. Command is matched against `config/command-rules.json`:
|
|
28
|
+
- `always_approve` -> execute immediately
|
|
29
|
+
- `always_deny` -> reject (403)
|
|
30
|
+
- `telegram_approve` -> check SQLite for cached approval, or send to Telegram
|
|
31
|
+
4. If Telegram approval needed, human sees the command with risk warnings and taps a button
|
|
32
|
+
5. Approved commands execute and results are returned to the caller
|
|
33
|
+
|
|
34
|
+
## Config files
|
|
35
|
+
|
|
36
|
+
Generated by `--init`, hand-editable:
|
|
37
|
+
|
|
38
|
+
**config/lucifer.json** - Server settings (port, timeouts, limits)
|
|
39
|
+
|
|
40
|
+
**config/api-keys.json** - API key definitions (hashed, with optional IP allowlists)
|
|
41
|
+
|
|
42
|
+
**config/command-rules.json** - Command policy:
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"rules": [
|
|
46
|
+
{ "prefix": "echo ", "action": "always_approve" },
|
|
47
|
+
{ "prefix": "git pull", "action": "telegram_approve" },
|
|
48
|
+
{ "prefix": "rm ", "action": "always_deny" }
|
|
49
|
+
],
|
|
50
|
+
"defaultAction": "always_deny"
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Rules matched top-to-bottom, first match wins.
|
|
55
|
+
|
|
56
|
+
## Production setup (with Telegram)
|
|
57
|
+
|
|
58
|
+
1. Create a Telegram bot via [@BotFather](https://t.me/BotFather) and get the token
|
|
59
|
+
2. Send any message to your bot, then get your chat ID from `https://api.telegram.org/bot<TOKEN>/getUpdates`
|
|
60
|
+
3. Run:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
LUCIFER_TELEGRAM_TOKEN=your_bot_token \
|
|
64
|
+
LUCIFER_TELEGRAM_CHAT_ID=your_chat_id \
|
|
65
|
+
npx lucifer-gate --config ./config/lucifer.json
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
When a `telegram_approve` command arrives, you'll see an inline keyboard in Telegram:
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
Command Request from key-name (192.168.1.5)
|
|
72
|
+
git push origin main
|
|
73
|
+
|
|
74
|
+
[Exact 2h] [Exact 8h] [Exact forever]
|
|
75
|
+
["git push" 2h] ["git push" 8h]
|
|
76
|
+
[Deny]
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## API
|
|
80
|
+
|
|
81
|
+
### POST /api/v1/execute
|
|
82
|
+
|
|
83
|
+
Execute a command. Async by default (returns requestId).
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
curl -X POST http://localhost:3001/api/v1/execute \
|
|
87
|
+
-H "Content-Type: application/json" \
|
|
88
|
+
-H "x-api-key: luc_yourkey" \
|
|
89
|
+
-d '{"command":"git status"}'
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Response (async, default):
|
|
93
|
+
```json
|
|
94
|
+
{ "requestId": "uuid", "status": "pending_approval" }
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Response (sync, `?sync=true`):
|
|
98
|
+
```json
|
|
99
|
+
{ "requestId": "uuid", "status": "completed", "exitCode": 0, "stdout": "...", "stderr": "", "durationMs": 42 }
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### GET /api/v1/status/:requestId
|
|
103
|
+
|
|
104
|
+
Poll for result (requires same API key).
|
|
105
|
+
|
|
106
|
+
```json
|
|
107
|
+
{ "requestId": "uuid", "status": "completed", "exitCode": 0, "stdout": "...", "durationMs": 42 }
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Status values: `pending_approval`, `approved`, `denied`, `executing`, `completed`, `failed`, `timed_out`, `expired`
|
|
111
|
+
|
|
112
|
+
### Error responses
|
|
113
|
+
|
|
114
|
+
All errors return:
|
|
115
|
+
```json
|
|
116
|
+
{ "code": "ERROR_CODE", "message": "Human readable", "retryable": true }
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Codes: `MISSING_API_KEY`, `INVALID_API_KEY`, `IP_NOT_ALLOWED`, `RATE_LIMITED`, `COMMAND_DENIED`, `COMMAND_TOO_LONG`, `APPROVAL_TIMEOUT`, `APPROVAL_ERROR`
|
|
120
|
+
|
|
121
|
+
## CLI
|
|
122
|
+
|
|
123
|
+
```
|
|
124
|
+
lucifer-gate --init [dir] Generate starter config + API key
|
|
125
|
+
lucifer-gate --config <path> Start server with config
|
|
126
|
+
lucifer-gate --auto-approve Dev mode (no Telegram)
|
|
127
|
+
lucifer-gate log [--limit N] Query audit log
|
|
128
|
+
lucifer-gate stats Show approval statistics
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Docker
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
docker build -t lucifer-gate .
|
|
135
|
+
docker run -p 3001:3001 \
|
|
136
|
+
-e LUCIFER_TELEGRAM_TOKEN=your_token \
|
|
137
|
+
-e LUCIFER_TELEGRAM_CHAT_ID=your_chat_id \
|
|
138
|
+
-v ./config:/app/config \
|
|
139
|
+
-v ./data:/app/data \
|
|
140
|
+
lucifer-gate
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Environment variables
|
|
144
|
+
|
|
145
|
+
| Variable | Required | Description |
|
|
146
|
+
|---|---|---|
|
|
147
|
+
| `LUCIFER_TELEGRAM_TOKEN` | Yes (prod) | Telegram bot token from @BotFather |
|
|
148
|
+
| `LUCIFER_TELEGRAM_CHAT_ID` | Yes (prod) | Telegram chat ID for approvals |
|
|
149
|
+
| `LUCIFER_ADMIN_SECRET` | No | Bearer token for admin endpoints |
|
|
150
|
+
| `PORT` | No | Server port (default: 3001) |
|
|
151
|
+
|
|
152
|
+
## Architecture
|
|
153
|
+
|
|
154
|
+
```
|
|
155
|
+
server/src/domains/
|
|
156
|
+
command-gateway/ Core domain
|
|
157
|
+
types/ CommandRequest, Approval, types
|
|
158
|
+
config/ Gateway configuration
|
|
159
|
+
repository/ SQLite stores, JSON config readers
|
|
160
|
+
service/ Auth, rules, risk analysis, execution
|
|
161
|
+
api/ Express routes
|
|
162
|
+
platform-api/ Health check (existing)
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Dependency flow: Types -> Config -> Repository -> Service -> API
|
|
166
|
+
|
|
167
|
+
## Stack
|
|
168
|
+
|
|
169
|
+
- Express 5 + TypeScript
|
|
170
|
+
- SQLite (better-sqlite3) for approvals + audit
|
|
171
|
+
- Telegraf for Telegram bot
|
|
172
|
+
- Pino for structured logging
|
|
173
|
+
- Vitest for testing
|
|
174
|
+
- React 19 + Vite 8 (admin UI planned for v1.1)
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { writeFileSync, existsSync, mkdirSync } from 'node:fs';
|
|
3
|
+
import { resolve, join } from 'node:path';
|
|
4
|
+
import { createApp } from './create_app.js';
|
|
5
|
+
import { generateApiKey } from './domains/command-gateway/repository/api_key_store.js';
|
|
6
|
+
import { getDatabase } from './domains/command-gateway/repository/database.js';
|
|
7
|
+
import { createAuditLog } from './domains/command-gateway/repository/audit_log.js';
|
|
8
|
+
import { createApprovalStore } from './domains/command-gateway/repository/approval_store.js';
|
|
9
|
+
import { logger } from './lib/logger.js';
|
|
10
|
+
const args = process.argv.slice(2);
|
|
11
|
+
function printHelp() {
|
|
12
|
+
console.log(`
|
|
13
|
+
lucifer-gate - AI Agent Command Firewall
|
|
14
|
+
|
|
15
|
+
Usage:
|
|
16
|
+
lucifer-gate [options] Start the server
|
|
17
|
+
lucifer-gate --init [dir] Generate starter config files
|
|
18
|
+
lucifer-gate log [--limit N] Query audit log
|
|
19
|
+
lucifer-gate stats Show approval statistics
|
|
20
|
+
|
|
21
|
+
Server options:
|
|
22
|
+
--config <path> Path to lucifer.json (default: ./config/lucifer.json)
|
|
23
|
+
--port <number> Server port (default: 3001, or PORT env var)
|
|
24
|
+
--data-dir <path> Directory for SQLite database (default: ./data)
|
|
25
|
+
--auto-approve Auto-approve all commands (dev mode, no Telegram needed)
|
|
26
|
+
--help Show this help
|
|
27
|
+
|
|
28
|
+
Environment variables:
|
|
29
|
+
LUCIFER_TELEGRAM_TOKEN Telegram bot token (required for production)
|
|
30
|
+
LUCIFER_TELEGRAM_CHAT_ID Telegram chat ID for approvals
|
|
31
|
+
LUCIFER_ADMIN_SECRET Admin API bearer token (optional)
|
|
32
|
+
PORT Server port (default: 3001)
|
|
33
|
+
`);
|
|
34
|
+
}
|
|
35
|
+
function initConfig(targetDir) {
|
|
36
|
+
const configDir = resolve(targetDir, 'config');
|
|
37
|
+
const dataDir = resolve(targetDir, 'data');
|
|
38
|
+
mkdirSync(configDir, { recursive: true });
|
|
39
|
+
mkdirSync(dataDir, { recursive: true });
|
|
40
|
+
const luciferJsonPath = join(configDir, 'lucifer.json');
|
|
41
|
+
const apiKeysPath = join(configDir, 'api-keys.json');
|
|
42
|
+
const commandRulesPath = join(configDir, 'command-rules.json');
|
|
43
|
+
if (existsSync(luciferJsonPath)) {
|
|
44
|
+
console.log(`Config already exists: ${luciferJsonPath}`);
|
|
45
|
+
console.log('Delete it first if you want to regenerate.');
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const { key, salt, keyHash } = generateApiKey();
|
|
49
|
+
writeFileSync(luciferJsonPath, JSON.stringify({
|
|
50
|
+
port: 3001,
|
|
51
|
+
approvalTimeoutSeconds: 300,
|
|
52
|
+
executionTimeoutSeconds: 120,
|
|
53
|
+
maxConcurrentExecutions: 5,
|
|
54
|
+
maxOutputBytes: 10485760,
|
|
55
|
+
rateLimitPerMinute: 10,
|
|
56
|
+
onApprovalTimeout: 'deny',
|
|
57
|
+
dataDir: '../data',
|
|
58
|
+
}, null, 2) + '\n');
|
|
59
|
+
writeFileSync(apiKeysPath, JSON.stringify({
|
|
60
|
+
keys: [{
|
|
61
|
+
id: crypto.randomUUID(),
|
|
62
|
+
name: 'default',
|
|
63
|
+
keyHash,
|
|
64
|
+
salt,
|
|
65
|
+
allowedIps: [],
|
|
66
|
+
createdAt: new Date().toISOString(),
|
|
67
|
+
active: true,
|
|
68
|
+
}],
|
|
69
|
+
}, null, 2) + '\n');
|
|
70
|
+
writeFileSync(commandRulesPath, JSON.stringify({
|
|
71
|
+
rules: [
|
|
72
|
+
{ prefix: 'echo ', action: 'always_approve' },
|
|
73
|
+
{ prefix: 'git status', action: 'always_approve' },
|
|
74
|
+
{ prefix: 'git pull', action: 'telegram_approve' },
|
|
75
|
+
{ prefix: 'git push', action: 'telegram_approve' },
|
|
76
|
+
{ prefix: 'npm test', action: 'always_approve' },
|
|
77
|
+
{ prefix: 'npm run', action: 'telegram_approve' },
|
|
78
|
+
{ prefix: 'rm ', action: 'always_deny' },
|
|
79
|
+
],
|
|
80
|
+
defaultAction: 'always_deny',
|
|
81
|
+
}, null, 2) + '\n');
|
|
82
|
+
console.log('Config files generated:');
|
|
83
|
+
console.log(` ${luciferJsonPath}`);
|
|
84
|
+
console.log(` ${apiKeysPath}`);
|
|
85
|
+
console.log(` ${commandRulesPath}`);
|
|
86
|
+
console.log('');
|
|
87
|
+
console.log('Your API key (save this, it cannot be recovered):');
|
|
88
|
+
console.log(` ${key}`);
|
|
89
|
+
console.log('');
|
|
90
|
+
console.log('Quick start:');
|
|
91
|
+
console.log(' # Dev mode (no Telegram needed):');
|
|
92
|
+
console.log(` LUCIFER_TELEGRAM_TOKEN=skip lucifer-gate --config ${luciferJsonPath} --auto-approve`);
|
|
93
|
+
console.log('');
|
|
94
|
+
console.log(' # Production (set your Telegram bot token):');
|
|
95
|
+
console.log(` LUCIFER_TELEGRAM_TOKEN=your_token LUCIFER_TELEGRAM_CHAT_ID=your_chat_id lucifer-gate --config ${luciferJsonPath}`);
|
|
96
|
+
}
|
|
97
|
+
async function runLog(limit) {
|
|
98
|
+
const dataDir = getArgValue('--data-dir') ?? './data';
|
|
99
|
+
const db = getDatabase(dataDir);
|
|
100
|
+
const auditLog = createAuditLog(db);
|
|
101
|
+
const entries = auditLog.query(limit);
|
|
102
|
+
if (entries.length === 0) {
|
|
103
|
+
console.log('No audit log entries found.');
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
for (const entry of entries.reverse()) {
|
|
107
|
+
const time = entry.ts.replace('T', ' ').replace(/\.\d+Z$/, 'Z');
|
|
108
|
+
const parts = [time, entry.type.toUpperCase().padEnd(16)];
|
|
109
|
+
if (entry.command)
|
|
110
|
+
parts.push(entry.command);
|
|
111
|
+
if (entry.apiKeyName)
|
|
112
|
+
parts.push(`key=${entry.apiKeyName}`);
|
|
113
|
+
if (entry.exitCode !== undefined && entry.exitCode !== null)
|
|
114
|
+
parts.push(`exit=${entry.exitCode}`);
|
|
115
|
+
if (entry.durationMs !== undefined && entry.durationMs !== null)
|
|
116
|
+
parts.push(`${entry.durationMs}ms`);
|
|
117
|
+
if (entry.error)
|
|
118
|
+
parts.push(`error: ${entry.error}`);
|
|
119
|
+
console.log(parts.join(' '));
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
async function runStats() {
|
|
123
|
+
const dataDir = getArgValue('--data-dir') ?? './data';
|
|
124
|
+
const db = getDatabase(dataDir);
|
|
125
|
+
const auditLog = createAuditLog(db);
|
|
126
|
+
const approvalStore = createApprovalStore(db);
|
|
127
|
+
const allEntries = auditLog.query(10000);
|
|
128
|
+
const requests = allEntries.filter(e => e.type === 'request');
|
|
129
|
+
const approvals = allEntries.filter(e => e.type === 'approved');
|
|
130
|
+
const denials = allEntries.filter(e => e.type === 'denied');
|
|
131
|
+
const executions = allEntries.filter(e => e.type === 'executed');
|
|
132
|
+
const activeApprovals = approvalStore.listAll(10000);
|
|
133
|
+
const expired = activeApprovals.filter(a => a.expiresAt && new Date(a.expiresAt) < new Date());
|
|
134
|
+
console.log('Lucifer Stats');
|
|
135
|
+
console.log('=============');
|
|
136
|
+
console.log(`Total requests: ${requests.length}`);
|
|
137
|
+
console.log(`Approved: ${approvals.length}`);
|
|
138
|
+
console.log(`Denied: ${denials.length}`);
|
|
139
|
+
console.log(`Executed: ${executions.length}`);
|
|
140
|
+
console.log(`Active approvals: ${activeApprovals.length - expired.length}`);
|
|
141
|
+
console.log(`Expired approvals: ${expired.length}`);
|
|
142
|
+
if (executions.length > 0) {
|
|
143
|
+
const durations = executions.filter(e => e.durationMs != null).map(e => e.durationMs);
|
|
144
|
+
if (durations.length > 0) {
|
|
145
|
+
const avg = Math.round(durations.reduce((a, b) => a + b, 0) / durations.length);
|
|
146
|
+
const max = Math.max(...durations);
|
|
147
|
+
console.log(`Avg exec time: ${avg}ms`);
|
|
148
|
+
console.log(`Max exec time: ${max}ms`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
// Top commands
|
|
152
|
+
const cmdCounts = new Map();
|
|
153
|
+
for (const r of requests) {
|
|
154
|
+
if (r.command) {
|
|
155
|
+
const cmd = r.command.split(/\s+/).slice(0, 2).join(' ');
|
|
156
|
+
cmdCounts.set(cmd, (cmdCounts.get(cmd) ?? 0) + 1);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
const topCmds = [...cmdCounts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 10);
|
|
160
|
+
if (topCmds.length > 0) {
|
|
161
|
+
console.log('\nTop commands:');
|
|
162
|
+
for (const [cmd, count] of topCmds) {
|
|
163
|
+
console.log(` ${count.toString().padStart(5)} ${cmd}`);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
function getArgValue(flag) {
|
|
168
|
+
const idx = args.indexOf(flag);
|
|
169
|
+
if (idx === -1 || idx >= args.length - 1)
|
|
170
|
+
return undefined;
|
|
171
|
+
return args[idx + 1];
|
|
172
|
+
}
|
|
173
|
+
async function main() {
|
|
174
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
175
|
+
printHelp();
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
if (args[0] === '--init' || args[0] === 'init') {
|
|
179
|
+
const dir = args[1] ?? '.';
|
|
180
|
+
initConfig(dir);
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
if (args[0] === 'log') {
|
|
184
|
+
const limitStr = getArgValue('--limit');
|
|
185
|
+
await runLog(limitStr ? parseInt(limitStr, 10) : 50);
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
if (args[0] === 'stats') {
|
|
189
|
+
await runStats();
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
// Server mode
|
|
193
|
+
const configPath = getArgValue('--config');
|
|
194
|
+
const port = getArgValue('--port');
|
|
195
|
+
const autoApprove = args.includes('--auto-approve');
|
|
196
|
+
if (port) {
|
|
197
|
+
process.env.PORT = port;
|
|
198
|
+
}
|
|
199
|
+
const { app, config, start, stop } = createApp({
|
|
200
|
+
configPath,
|
|
201
|
+
autoApprove,
|
|
202
|
+
});
|
|
203
|
+
const server = app.listen(config.port, async () => {
|
|
204
|
+
logger.info({ port: config.port, autoApprove }, 'Lucifer listening');
|
|
205
|
+
await start();
|
|
206
|
+
});
|
|
207
|
+
const shutdown = async () => {
|
|
208
|
+
logger.info('Shutting down');
|
|
209
|
+
await stop();
|
|
210
|
+
server.close();
|
|
211
|
+
process.exit(0);
|
|
212
|
+
};
|
|
213
|
+
process.on('SIGTERM', shutdown);
|
|
214
|
+
process.on('SIGINT', shutdown);
|
|
215
|
+
}
|
|
216
|
+
main().catch(err => {
|
|
217
|
+
console.error('Fatal error:', err);
|
|
218
|
+
process.exit(1);
|
|
219
|
+
});
|
|
220
|
+
//# sourceMappingURL=cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../server/src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import express from 'express';
|
|
4
|
+
import { getServerConfig } from './domains/platform-api/config/server_config.js';
|
|
5
|
+
import { registerHealthRoutes } from './domains/platform-api/api/register_health_routes.js';
|
|
6
|
+
import { createRuntimeMetadataRepository } from './domains/platform-api/repository/runtime_metadata_repository.js';
|
|
7
|
+
import { createHealthReportService } from './domains/platform-api/service/create_health_report.js';
|
|
8
|
+
import { loadGatewayConfig, getTelegramToken } from './domains/command-gateway/config/gateway_config.js';
|
|
9
|
+
import { getDatabase, closeDatabase } from './domains/command-gateway/repository/database.js';
|
|
10
|
+
import { createApprovalStore } from './domains/command-gateway/repository/approval_store.js';
|
|
11
|
+
import { createAuditLog } from './domains/command-gateway/repository/audit_log.js';
|
|
12
|
+
import { createApiKeyStore } from './domains/command-gateway/repository/api_key_store.js';
|
|
13
|
+
import { createCommandRulesStore } from './domains/command-gateway/repository/command_rules_store.js';
|
|
14
|
+
import { createPendingRequestStore } from './domains/command-gateway/repository/pending_request_store.js';
|
|
15
|
+
import { registerExecuteRoutes } from './domains/command-gateway/api/register_execute_routes.js';
|
|
16
|
+
import { createTelegramApprovalChannel } from './domains/command-gateway/service/request_telegram_approval.js';
|
|
17
|
+
import { createAutoApproveChannel } from './domains/command-gateway/service/auto_approve_channel.js';
|
|
18
|
+
import { createChildLogger } from './lib/logger.js';
|
|
19
|
+
const log = createChildLogger('app');
|
|
20
|
+
export function createApp(options = {}) {
|
|
21
|
+
const serverConfig = getServerConfig();
|
|
22
|
+
const metadataRepository = createRuntimeMetadataRepository();
|
|
23
|
+
const getHealthReport = createHealthReportService(serverConfig, metadataRepository);
|
|
24
|
+
const app = express();
|
|
25
|
+
const indexPath = path.join(serverConfig.clientDistPath, 'index.html');
|
|
26
|
+
const hasBuiltClient = fs.existsSync(indexPath);
|
|
27
|
+
const indexMarkup = hasBuiltClient ? fs.readFileSync(indexPath, 'utf8') : null;
|
|
28
|
+
app.disable('x-powered-by');
|
|
29
|
+
app.use(express.json());
|
|
30
|
+
registerHealthRoutes(app, getHealthReport);
|
|
31
|
+
// Initialize Lucifer command gateway
|
|
32
|
+
const gatewayConfig = loadGatewayConfig(options.configPath);
|
|
33
|
+
const configDir = options.configPath ? path.dirname(path.resolve(options.configPath)) : process.cwd();
|
|
34
|
+
const apiKeysPath = path.join(configDir, 'api-keys.json');
|
|
35
|
+
const commandRulesPath = path.join(configDir, 'command-rules.json');
|
|
36
|
+
// Resolve dataDir relative to config directory
|
|
37
|
+
const resolvedDataDir = path.resolve(configDir, gatewayConfig.dataDir);
|
|
38
|
+
gatewayConfig.dataDir = resolvedDataDir;
|
|
39
|
+
let approvalChannel;
|
|
40
|
+
let cleanupInterval;
|
|
41
|
+
// Only initialize gateway if config files exist
|
|
42
|
+
if (fs.existsSync(apiKeysPath) && fs.existsSync(commandRulesPath)) {
|
|
43
|
+
const db = getDatabase(gatewayConfig.dataDir);
|
|
44
|
+
const approvalStore = createApprovalStore(db);
|
|
45
|
+
const auditLog = createAuditLog(db);
|
|
46
|
+
const apiKeyStore = createApiKeyStore(apiKeysPath);
|
|
47
|
+
const commandRulesStore = createCommandRulesStore(commandRulesPath);
|
|
48
|
+
const pendingStore = createPendingRequestStore();
|
|
49
|
+
if (options.autoApprove) {
|
|
50
|
+
approvalChannel = createAutoApproveChannel();
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
const token = getTelegramToken();
|
|
54
|
+
const chatId = gatewayConfig.telegramChatId ?? process.env.LUCIFER_TELEGRAM_CHAT_ID;
|
|
55
|
+
if (!chatId) {
|
|
56
|
+
throw new Error('Telegram chat ID is required. Set LUCIFER_TELEGRAM_CHAT_ID env var or telegramChatId in config.');
|
|
57
|
+
}
|
|
58
|
+
approvalChannel = createTelegramApprovalChannel(token, chatId, pendingStore, approvalStore, auditLog);
|
|
59
|
+
}
|
|
60
|
+
registerExecuteRoutes(app, gatewayConfig, apiKeyStore, commandRulesStore, approvalStore, pendingStore, auditLog, approvalChannel);
|
|
61
|
+
// Clean up expired approvals and stale pending requests periodically
|
|
62
|
+
cleanupInterval = setInterval(() => {
|
|
63
|
+
approvalStore.removeExpired();
|
|
64
|
+
pendingStore.cleanup(gatewayConfig.approvalTimeoutSeconds * 1000);
|
|
65
|
+
}, 60_000);
|
|
66
|
+
log.info('Command gateway initialized');
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
log.warn({ apiKeysPath, commandRulesPath }, 'Config files not found. Run with --init to generate them. Gateway disabled.');
|
|
70
|
+
}
|
|
71
|
+
// TLS warning
|
|
72
|
+
if (process.env.NODE_ENV === 'production') {
|
|
73
|
+
log.warn('Ensure HTTPS is configured for production. API keys are transmitted in headers.');
|
|
74
|
+
}
|
|
75
|
+
if (hasBuiltClient && indexMarkup !== null) {
|
|
76
|
+
app.use(express.static(serverConfig.clientDistPath));
|
|
77
|
+
app.get(/^(?!\/api\/).*/, (_request, response) => {
|
|
78
|
+
response.type('html').send(indexMarkup);
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
async function start() {
|
|
82
|
+
if (approvalChannel) {
|
|
83
|
+
await approvalChannel.start();
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
async function stop() {
|
|
87
|
+
if (cleanupInterval)
|
|
88
|
+
clearInterval(cleanupInterval);
|
|
89
|
+
if (approvalChannel)
|
|
90
|
+
await approvalChannel.stop();
|
|
91
|
+
closeDatabase();
|
|
92
|
+
}
|
|
93
|
+
return { app, config: serverConfig, gatewayConfig, start, stop };
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=create_app.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create_app.js","sourceRoot":"","sources":["../../server/src/create_app.ts"],"names":[],"mappings":"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"}
|