Merge pull request #186 from PatchMon/feature/go-agent

Bull Board
This commit is contained in:
9 Technology Group LTD
2025-10-19 20:58:03 +01:00
committed by GitHub
5 changed files with 190 additions and 77 deletions

View File

@@ -570,22 +570,25 @@ router.post(
os_version: "unknown",
api_id: api_id,
api_key: api_key,
host_group_id: req.auto_enrollment_token.default_host_group_id,
status: "pending",
notes: `Auto-enrolled via ${req.auto_enrollment_token.token_name} on ${new Date().toISOString()}`,
updated_at: new Date(),
},
include: {
host_groups: {
select: {
id: true,
name: true,
color: true,
},
},
},
});
// Create host group membership if default host group is specified
let hostGroupMembership = null;
if (req.auto_enrollment_token.default_host_group_id) {
hostGroupMembership = await prisma.host_group_memberships.create({
data: {
id: uuidv4(),
host_id: host.id,
host_group_id: req.auto_enrollment_token.default_host_group_id,
created_at: new Date(),
},
});
}
// Update token usage stats
await prisma.auto_enrollment_tokens.update({
where: { id: req.auto_enrollment_token.id },
@@ -600,6 +603,19 @@ router.post(
`Auto-enrolled host: ${friendly_name} (${host.id}) via token: ${req.auto_enrollment_token.token_name}`,
);
// Get host group details for response if membership was created
let hostGroup = null;
if (hostGroupMembership) {
hostGroup = await prisma.host_groups.findUnique({
where: { id: req.auto_enrollment_token.default_host_group_id },
select: {
id: true,
name: true,
color: true,
},
});
}
res.status(201).json({
message: "Host enrolled successfully",
host: {
@@ -607,7 +623,7 @@ router.post(
friendly_name: host.friendly_name,
api_id: api_id,
api_key: api_key,
host_group: host.host_groups,
host_group: hostGroup,
status: host.status,
},
});
@@ -698,13 +714,24 @@ router.post(
os_version: "unknown",
api_id: api_id,
api_key: api_key,
host_group_id: req.auto_enrollment_token.default_host_group_id,
status: "pending",
notes: `Auto-enrolled via ${req.auto_enrollment_token.token_name} on ${new Date().toISOString()}`,
updated_at: new Date(),
},
});
// Create host group membership if default host group is specified
if (req.auto_enrollment_token.default_host_group_id) {
await prisma.host_group_memberships.create({
data: {
id: uuidv4(),
host_id: host.id,
host_group_id: req.auto_enrollment_token.default_host_group_id,
created_at: new Date(),
},
});
}
results.success.push({
id: host.id,
friendly_name: host.friendly_name,

View File

@@ -445,8 +445,8 @@ app.use(`/api/${apiVersion}/ws`, wsRoutes);
let bullBoardRouter = null;
const bullBoardSessions = new Map(); // Store authenticated sessions
// Mount Bull Board at /admin instead of /api/v1/admin to avoid path conflicts
app.use(`/admin/queues`, (_req, res, next) => {
// Mount Bull Board at /bullboard for cleaner URL
app.use(`/bullboard`, (_req, res, next) => {
// Relax COOP/COEP for Bull Board in non-production to avoid browser warnings
if (process.env.NODE_ENV !== "production") {
res.setHeader("Cross-Origin-Opener-Policy", "same-origin-allow-popups");
@@ -457,7 +457,7 @@ app.use(`/admin/queues`, (_req, res, next) => {
});
// Authentication middleware for Bull Board
app.use(`/admin/queues`, async (req, res, next) => {
app.use(`/bullboard`, async (req, res, next) => {
// Skip authentication for static assets only
if (req.path.includes("/static/") || req.path.includes("/favicon")) {
return next();
@@ -534,7 +534,7 @@ app.use(`/admin/queues`, async (req, res, next) => {
});
});
app.use(`/admin/queues`, (req, res, next) => {
app.use(`/bullboard`, (req, res, next) => {
if (bullBoardRouter) {
return bullBoardRouter(req, res, next);
}
@@ -542,7 +542,7 @@ app.use(`/admin/queues`, (req, res, next) => {
});
// Error handler specifically for Bull Board routes
app.use("/admin/queues", (err, req, res, _next) => {
app.use("/bullboard", (err, req, res, _next) => {
console.error("Bull Board error on", req.method, req.url);
console.error("Error details:", err.message);
console.error("Stack:", err.stack);
@@ -874,7 +874,7 @@ async function startServer() {
// Set up Bull Board for queue monitoring
const serverAdapter = new ExpressAdapter();
// Set basePath to match where we mount the router
serverAdapter.setBasePath("/admin/queues");
serverAdapter.setBasePath("/bullboard");
const { QUEUE_NAMES } = require("./services/automation");
const bullAdapters = Object.values(QUEUE_NAMES).map(
@@ -888,7 +888,7 @@ async function startServer() {
// Set the router for the Bull Board middleware (secured middleware above)
bullBoardRouter = serverAdapter.getRouter();
console.log("✅ Bull Board mounted at /admin/queues (secured)");
console.log("✅ Bull Board mounted at /bullboard (secured)");
// Initialize WS layer with the underlying HTTP server
initAgentWs(server, prisma);

View File

@@ -29,6 +29,29 @@ server {
try_files $uri $uri/ /index.html;
}
# Bull Board proxy
location /bullboard {
proxy_pass http://${BACKEND_HOST}:${BACKEND_PORT};
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
# Preserve original client IP through proxy chain
proxy_set_header X-Original-Forwarded-For $http_x_forwarded_for;
# CORS headers for Bull Board
add_header Access-Control-Allow-Origin * always;
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
add_header Access-Control-Allow-Headers "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization" always;
# Handle preflight requests
if ($request_method = 'OPTIONS') {
return 204;
}
}
# API proxy
location /api/ {
proxy_pass http://${BACKEND_HOST}:${BACKEND_PORT};
@@ -52,63 +75,6 @@ server {
}
}
# SSE (Server-Sent Events) specific configuration
location /api/v1/ws/status/ {
proxy_pass http://${BACKEND_HOST}:${BACKEND_PORT};
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
# Critical SSE settings
proxy_buffering off;
proxy_cache off;
proxy_set_header Connection '';
proxy_http_version 1.1;
chunked_transfer_encoding off;
# Timeout settings for long-lived connections
proxy_read_timeout 24h;
proxy_send_timeout 24h;
proxy_connect_timeout 60s;
# Disable nginx buffering for real-time streaming
proxy_request_buffering off;
proxy_max_temp_file_size 0;
# CORS headers for SSE - commented out to let backend handle CORS
# add_header Access-Control-Allow-Origin * always;
# add_header Access-Control-Allow-Methods "GET, OPTIONS" always;
# add_header Access-Control-Allow-Headers "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization" always;
# Handle preflight requests
if ($request_method = 'OPTIONS') {
return 204;
}
}
# WebSocket upgrade handling
location /api/v1/agents/ws {
proxy_pass http://${BACKEND_HOST}:${BACKEND_PORT};
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
# WebSocket timeout settings
proxy_read_timeout 24h;
proxy_send_timeout 24h;
proxy_connect_timeout 60s;
# Disable buffering for WebSocket
proxy_buffering off;
proxy_cache off;
}
# Static assets caching
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {

View File

@@ -227,7 +227,7 @@ const Automation = () => {
// Use the proxied URL through the frontend (port 3000)
// This avoids CORS issues as everything goes through the same origin
const url = `/admin/queues?token=${encodeURIComponent(token)}`;
const url = `/bullboard?token=${encodeURIComponent(token)}`;
window.open(url, "_blank", "width=1200,height=800");
};

120
setup.sh
View File

@@ -1169,7 +1169,47 @@ server {
add_header X-XSS-Protection "1; mode=block";
}
# Bull Board proxy
location /bullboard {
proxy_pass http://127.0.0.1:$BACKEND_PORT;
proxy_set_header Host \$host;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto \$scheme;
proxy_set_header X-Forwarded-Host \$host;
# CORS headers for Bull Board
add_header Access-Control-Allow-Origin * always;
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
add_header Access-Control-Allow-Headers "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization" always;
# Handle preflight requests
if (\$request_method = 'OPTIONS') {
return 204;
}
}
# API routes
# Bull Board proxy
location /bullboard {
proxy_pass http://127.0.0.1:$BACKEND_PORT;
proxy_set_header Host \$host;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto \$scheme;
proxy_set_header X-Forwarded-Host \$host;
# CORS headers for Bull Board
add_header Access-Control-Allow-Origin * always;
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
add_header Access-Control-Allow-Headers "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization" always;
# Handle preflight requests
if (\$request_method = 'OPTIONS') {
return 204;
}
}
location /api/ {
proxy_pass http://127.0.0.1:$BACKEND_PORT;
proxy_http_version 1.1;
@@ -1250,7 +1290,47 @@ server {
add_header X-XSS-Protection "1; mode=block";
}
# Bull Board proxy
location /bullboard {
proxy_pass http://127.0.0.1:$BACKEND_PORT;
proxy_set_header Host \$host;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto \$scheme;
proxy_set_header X-Forwarded-Host \$host;
# CORS headers for Bull Board
add_header Access-Control-Allow-Origin * always;
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
add_header Access-Control-Allow-Headers "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization" always;
# Handle preflight requests
if (\$request_method = 'OPTIONS') {
return 204;
}
}
# API proxy
# Bull Board proxy
location /bullboard {
proxy_pass http://127.0.0.1:$BACKEND_PORT;
proxy_set_header Host \$host;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto \$scheme;
proxy_set_header X-Forwarded-Host \$host;
# CORS headers for Bull Board
add_header Access-Control-Allow-Origin * always;
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
add_header Access-Control-Allow-Headers "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization" always;
# Handle preflight requests
if (\$request_method = 'OPTIONS') {
return 204;
}
}
location /api/ {
proxy_pass http://127.0.0.1:$BACKEND_PORT;
proxy_http_version 1.1;
@@ -1319,7 +1399,47 @@ server {
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
}
# Bull Board proxy
location /bullboard {
proxy_pass http://127.0.0.1:$BACKEND_PORT;
proxy_set_header Host \$host;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto \$scheme;
proxy_set_header X-Forwarded-Host \$host;
# CORS headers for Bull Board
add_header Access-Control-Allow-Origin * always;
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
add_header Access-Control-Allow-Headers "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization" always;
# Handle preflight requests
if (\$request_method = 'OPTIONS') {
return 204;
}
}
# API routes
# Bull Board proxy
location /bullboard {
proxy_pass http://127.0.0.1:$BACKEND_PORT;
proxy_set_header Host \$host;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto \$scheme;
proxy_set_header X-Forwarded-Host \$host;
# CORS headers for Bull Board
add_header Access-Control-Allow-Origin * always;
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
add_header Access-Control-Allow-Headers "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization" always;
# Handle preflight requests
if (\$request_method = 'OPTIONS') {
return 204;
}
}
location /api/ {
proxy_pass http://127.0.0.1:$BACKEND_PORT;
proxy_http_version 1.1;