@friggframework/admin-scripts 2.0.0--canary.517.300ded3.0 → 2.0.0--canary.522.cbd3d5a.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/index.js +2 -2
- package/package.json +8 -6
- package/src/application/__tests__/admin-frigg-commands.test.js +18 -18
- package/src/application/__tests__/dry-run-http-interceptor.test.js +313 -0
- package/src/application/__tests__/dry-run-repository-wrapper.test.js +257 -0
- package/src/application/__tests__/script-runner.test.js +14 -144
- package/src/application/admin-frigg-commands.js +7 -7
- package/src/application/admin-script-base.js +4 -2
- package/src/application/dry-run-http-interceptor.js +296 -0
- package/src/application/dry-run-repository-wrapper.js +261 -0
- package/src/application/script-runner.js +127 -121
- package/src/infrastructure/__tests__/admin-auth-middleware.test.js +95 -32
- package/src/infrastructure/__tests__/admin-script-router.test.js +25 -24
- package/src/infrastructure/admin-auth-middleware.js +43 -5
- package/src/infrastructure/admin-script-router.js +16 -14
- package/src/infrastructure/script-executor-handler.js +2 -2
|
@@ -1,11 +1,49 @@
|
|
|
1
|
+
const { createAdminScriptCommands } = require('@friggframework/core/application/commands/admin-script-commands');
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Admin API Key Authentication Middleware
|
|
3
5
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* Expects: x-frigg-admin-api-key header
|
|
6
|
+
* Validates admin API keys for script endpoints.
|
|
7
|
+
* Expects: Authorization: Bearer <api-key>
|
|
7
8
|
*/
|
|
9
|
+
async function adminAuthMiddleware(req, res, next) {
|
|
10
|
+
try {
|
|
11
|
+
const authHeader = req.headers.authorization;
|
|
12
|
+
|
|
13
|
+
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
|
14
|
+
return res.status(401).json({
|
|
15
|
+
error: 'Missing or invalid Authorization header',
|
|
16
|
+
code: 'MISSING_AUTH'
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const apiKey = authHeader.substring(7); // Remove 'Bearer '
|
|
21
|
+
const commands = createAdminScriptCommands();
|
|
22
|
+
const result = await commands.validateAdminApiKey(apiKey);
|
|
23
|
+
|
|
24
|
+
if (result.error) {
|
|
25
|
+
return res.status(result.error).json({
|
|
26
|
+
error: result.reason,
|
|
27
|
+
code: result.code
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Attach validated key info to request for audit trail
|
|
32
|
+
req.adminApiKey = result.apiKey;
|
|
33
|
+
req.adminAudit = {
|
|
34
|
+
apiKeyName: result.apiKey.name,
|
|
35
|
+
apiKeyLast4: result.apiKey.keyLast4,
|
|
36
|
+
ipAddress: req.ip || req.connection?.remoteAddress || 'unknown'
|
|
37
|
+
};
|
|
8
38
|
|
|
9
|
-
|
|
39
|
+
next();
|
|
40
|
+
} catch (error) {
|
|
41
|
+
console.error('Admin auth middleware error:', error);
|
|
42
|
+
res.status(500).json({
|
|
43
|
+
error: 'Authentication failed',
|
|
44
|
+
code: 'AUTH_ERROR'
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
10
48
|
|
|
11
|
-
module.exports = {
|
|
49
|
+
module.exports = { adminAuthMiddleware };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const express = require('express');
|
|
2
2
|
const serverless = require('serverless-http');
|
|
3
|
-
const {
|
|
3
|
+
const { adminAuthMiddleware } = require('./admin-auth-middleware');
|
|
4
4
|
const { getScriptFactory } = require('../application/script-factory');
|
|
5
5
|
const { createScriptRunner } = require('../application/script-runner');
|
|
6
6
|
const { createAdminScriptCommands } = require('@friggframework/core/application/commands/admin-script-commands');
|
|
@@ -11,7 +11,7 @@ const { ScheduleManagementUseCase } = require('../application/schedule-managemen
|
|
|
11
11
|
const router = express.Router();
|
|
12
12
|
|
|
13
13
|
// Apply auth middleware to all admin routes
|
|
14
|
-
router.use(
|
|
14
|
+
router.use(adminAuthMiddleware);
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* Create ScheduleManagementUseCase instance
|
|
@@ -87,10 +87,10 @@ router.get('/scripts/:scriptName', async (req, res) => {
|
|
|
87
87
|
});
|
|
88
88
|
|
|
89
89
|
/**
|
|
90
|
-
* POST /admin/scripts/:scriptName
|
|
90
|
+
* POST /admin/scripts/:scriptName/execute
|
|
91
91
|
* Execute a script (sync, async, or dry-run)
|
|
92
92
|
*/
|
|
93
|
-
router.post('/scripts/:scriptName', async (req, res) => {
|
|
93
|
+
router.post('/scripts/:scriptName/execute', async (req, res) => {
|
|
94
94
|
try {
|
|
95
95
|
const { scriptName } = req.params;
|
|
96
96
|
const { params = {}, mode = 'async', dryRun = false } = req.body;
|
|
@@ -110,6 +110,7 @@ router.post('/scripts/:scriptName', async (req, res) => {
|
|
|
110
110
|
trigger: 'MANUAL',
|
|
111
111
|
mode: 'sync',
|
|
112
112
|
dryRun: true,
|
|
113
|
+
audit: req.adminAudit,
|
|
113
114
|
});
|
|
114
115
|
return res.json(result);
|
|
115
116
|
}
|
|
@@ -120,18 +121,20 @@ router.post('/scripts/:scriptName', async (req, res) => {
|
|
|
120
121
|
const result = await runner.execute(scriptName, params, {
|
|
121
122
|
trigger: 'MANUAL',
|
|
122
123
|
mode: 'sync',
|
|
124
|
+
audit: req.adminAudit,
|
|
123
125
|
});
|
|
124
126
|
return res.json(result);
|
|
125
127
|
}
|
|
126
128
|
|
|
127
129
|
// Async execution - queue and return immediately
|
|
128
130
|
const commands = createAdminScriptCommands();
|
|
129
|
-
const execution = await commands.
|
|
131
|
+
const execution = await commands.createScriptExecution({
|
|
130
132
|
scriptName,
|
|
131
133
|
scriptVersion: factory.get(scriptName).Definition.version,
|
|
132
134
|
trigger: 'MANUAL',
|
|
133
135
|
mode: 'async',
|
|
134
136
|
input: params,
|
|
137
|
+
audit: req.adminAudit,
|
|
135
138
|
});
|
|
136
139
|
|
|
137
140
|
// Queue the execution
|
|
@@ -158,14 +161,14 @@ router.post('/scripts/:scriptName', async (req, res) => {
|
|
|
158
161
|
});
|
|
159
162
|
|
|
160
163
|
/**
|
|
161
|
-
* GET /admin/
|
|
162
|
-
* Get execution status
|
|
164
|
+
* GET /admin/executions/:executionId
|
|
165
|
+
* Get execution status
|
|
163
166
|
*/
|
|
164
|
-
router.get('/
|
|
167
|
+
router.get('/executions/:executionId', async (req, res) => {
|
|
165
168
|
try {
|
|
166
169
|
const { executionId } = req.params;
|
|
167
170
|
const commands = createAdminScriptCommands();
|
|
168
|
-
const execution = await commands.
|
|
171
|
+
const execution = await commands.findScriptExecutionById(executionId);
|
|
169
172
|
|
|
170
173
|
if (execution.error) {
|
|
171
174
|
return res.status(execution.error).json({
|
|
@@ -182,13 +185,12 @@ router.get('/scripts/:scriptName/executions/:executionId', async (req, res) => {
|
|
|
182
185
|
});
|
|
183
186
|
|
|
184
187
|
/**
|
|
185
|
-
* GET /admin/
|
|
186
|
-
* List recent executions
|
|
188
|
+
* GET /admin/executions
|
|
189
|
+
* List recent executions
|
|
187
190
|
*/
|
|
188
|
-
router.get('/
|
|
191
|
+
router.get('/executions', async (req, res) => {
|
|
189
192
|
try {
|
|
190
|
-
const { scriptName } = req.
|
|
191
|
-
const { status, limit = 50 } = req.query;
|
|
193
|
+
const { scriptName, status, limit = 50 } = req.query;
|
|
192
194
|
const commands = createAdminScriptCommands();
|
|
193
195
|
|
|
194
196
|
const executions = await commands.findRecentExecutions({
|
|
@@ -21,7 +21,7 @@ async function handler(event) {
|
|
|
21
21
|
|
|
22
22
|
// If executionId provided (async from API), update existing record
|
|
23
23
|
if (executionId) {
|
|
24
|
-
await commands.
|
|
24
|
+
await commands.updateScriptExecutionStatus(executionId, 'RUNNING');
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
const result = await runner.execute(scriptName, params, {
|
|
@@ -45,7 +45,7 @@ async function handler(event) {
|
|
|
45
45
|
if (executionId) {
|
|
46
46
|
const commands = createAdminScriptCommands();
|
|
47
47
|
await commands
|
|
48
|
-
.
|
|
48
|
+
.completeScriptExecution(executionId, {
|
|
49
49
|
status: 'FAILED',
|
|
50
50
|
error: {
|
|
51
51
|
name: error.name,
|