Add Atlas InfoSec action plans integration
Integrate Atlas InfoSec API to manage compliance action plans directly from
the ReportingPage. Users can view, create, and update action plans for host
findings without switching to the Atlas web tool.
Backend:
- Add atlasApi.js helper with Basic Auth, TLS skip, GET/PUT/PATCH/POST
- Add atlas_action_plans_cache migration for SQLite cache table
- Add atlas.js router with sync, status, and proxy CRUD endpoints
- Mount Atlas router at /api/atlas in server.js
- Extract hostId from Ivanti host findings during sync
Frontend:
- Add AtlasBadge component (amber=needs plan, green=has plan)
- Add AtlasSlideOutPanel with plan list, create form, edit capability
- Separate active plans from inactive history in collapsible section
- Custom dark-themed plan type dropdown
- Optimistic local state shows pending plans immediately after creation
- Atlas sync button on ReportingPage toolbar
- Prepopulate finding ID in create form from clicked row
Environment:
- Add ATLAS_API_URL, ATLAS_API_USER, ATLAS_API_PASS, ATLAS_SKIP_TLS to .env.example
2026-04-23 21:52:53 +00:00
|
|
|
// Atlas InfoSec Action Plans Routes
|
2026-05-06 11:44:17 -06:00
|
|
|
// Proxies CRUD operations to the Atlas API and maintains a local cache
|
Add Atlas InfoSec action plans integration
Integrate Atlas InfoSec API to manage compliance action plans directly from
the ReportingPage. Users can view, create, and update action plans for host
findings without switching to the Atlas web tool.
Backend:
- Add atlasApi.js helper with Basic Auth, TLS skip, GET/PUT/PATCH/POST
- Add atlas_action_plans_cache migration for SQLite cache table
- Add atlas.js router with sync, status, and proxy CRUD endpoints
- Mount Atlas router at /api/atlas in server.js
- Extract hostId from Ivanti host findings during sync
Frontend:
- Add AtlasBadge component (amber=needs plan, green=has plan)
- Add AtlasSlideOutPanel with plan list, create form, edit capability
- Separate active plans from inactive history in collapsible section
- Custom dark-themed plan type dropdown
- Optimistic local state shows pending plans immediately after creation
- Atlas sync button on ReportingPage toolbar
- Prepopulate finding ID in create form from clicked row
Environment:
- Add ATLAS_API_URL, ATLAS_API_USER, ATLAS_API_PASS, ATLAS_SKIP_TLS to .env.example
2026-04-23 21:52:53 +00:00
|
|
|
// for fast badge rendering on the ReportingPage.
|
|
|
|
|
|
|
|
|
|
const express = require('express');
|
2026-05-06 11:44:17 -06:00
|
|
|
const pool = require('../db');
|
|
|
|
|
const { requireAuth, requireGroup } = require('../middleware/auth');
|
Add Atlas InfoSec action plans integration
Integrate Atlas InfoSec API to manage compliance action plans directly from
the ReportingPage. Users can view, create, and update action plans for host
findings without switching to the Atlas web tool.
Backend:
- Add atlasApi.js helper with Basic Auth, TLS skip, GET/PUT/PATCH/POST
- Add atlas_action_plans_cache migration for SQLite cache table
- Add atlas.js router with sync, status, and proxy CRUD endpoints
- Mount Atlas router at /api/atlas in server.js
- Extract hostId from Ivanti host findings during sync
Frontend:
- Add AtlasBadge component (amber=needs plan, green=has plan)
- Add AtlasSlideOutPanel with plan list, create form, edit capability
- Separate active plans from inactive history in collapsible section
- Custom dark-themed plan type dropdown
- Optimistic local state shows pending plans immediately after creation
- Atlas sync button on ReportingPage toolbar
- Prepopulate finding ID in create form from clicked row
Environment:
- Add ATLAS_API_URL, ATLAS_API_USER, ATLAS_API_PASS, ATLAS_SKIP_TLS to .env.example
2026-04-23 21:52:53 +00:00
|
|
|
const logAudit = require('../helpers/auditLog');
|
|
|
|
|
const { isConfigured, atlasGet, atlasPut, atlasPatch, atlasPost } = require('../helpers/atlasApi');
|
|
|
|
|
|
2026-05-05 11:04:53 -06:00
|
|
|
const fs = require('fs');
|
|
|
|
|
const path = require('path');
|
|
|
|
|
|
Add Atlas InfoSec action plans integration
Integrate Atlas InfoSec API to manage compliance action plans directly from
the ReportingPage. Users can view, create, and update action plans for host
findings without switching to the Atlas web tool.
Backend:
- Add atlasApi.js helper with Basic Auth, TLS skip, GET/PUT/PATCH/POST
- Add atlas_action_plans_cache migration for SQLite cache table
- Add atlas.js router with sync, status, and proxy CRUD endpoints
- Mount Atlas router at /api/atlas in server.js
- Extract hostId from Ivanti host findings during sync
Frontend:
- Add AtlasBadge component (amber=needs plan, green=has plan)
- Add AtlasSlideOutPanel with plan list, create form, edit capability
- Separate active plans from inactive history in collapsible section
- Custom dark-themed plan type dropdown
- Optimistic local state shows pending plans immediately after creation
- Atlas sync button on ReportingPage toolbar
- Prepopulate finding ID in create form from clicked row
Environment:
- Add ATLAS_API_URL, ATLAS_API_USER, ATLAS_API_PASS, ATLAS_SKIP_TLS to .env.example
2026-04-23 21:52:53 +00:00
|
|
|
const VALID_PLAN_TYPES = ['decommission', 'remediation', 'false_positive', 'risk_acceptance', 'scan_exclusion'];
|
|
|
|
|
const DATE_PATTERN = /^\d{4}-\d{2}-\d{2}$/;
|
|
|
|
|
|
2026-05-06 11:44:17 -06:00
|
|
|
// Diagnostic log helper
|
2026-05-05 11:04:53 -06:00
|
|
|
function syncLog(msg) {
|
|
|
|
|
const line = `${new Date().toISOString()} ${msg}\n`;
|
|
|
|
|
try { fs.appendFileSync(path.join(__dirname, '..', 'atlas-sync-debug.log'), line); } catch (_) { /* ignore */ }
|
|
|
|
|
console.log(msg);
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-24 17:30:06 +00:00
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
// Pure aggregation function — exported for testability
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
function aggregateAtlasMetrics(rows) {
|
|
|
|
|
const result = {
|
|
|
|
|
totalHosts: rows.length,
|
|
|
|
|
hostsWithPlans: 0,
|
|
|
|
|
hostsWithoutPlans: 0,
|
|
|
|
|
plansByType: {},
|
|
|
|
|
plansByStatus: {},
|
|
|
|
|
totalPlans: 0
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
for (const row of rows) {
|
2026-05-06 11:44:17 -06:00
|
|
|
if (row.has_action_plan === true || row.has_action_plan === 1) {
|
2026-04-24 17:30:06 +00:00
|
|
|
result.hostsWithPlans++;
|
|
|
|
|
} else {
|
|
|
|
|
result.hostsWithoutPlans++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let plans;
|
|
|
|
|
try {
|
|
|
|
|
plans = JSON.parse(row.plans_json);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!Array.isArray(plans)) continue;
|
|
|
|
|
|
|
|
|
|
for (const plan of plans) {
|
|
|
|
|
result.totalPlans++;
|
|
|
|
|
if (plan.plan_type) {
|
|
|
|
|
result.plansByType[plan.plan_type] = (result.plansByType[plan.plan_type] || 0) + 1;
|
|
|
|
|
}
|
|
|
|
|
if (plan.status) {
|
|
|
|
|
result.plansByStatus[plan.status] = (result.plansByStatus[plan.status] || 0) + 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
Add Atlas InfoSec action plans integration
Integrate Atlas InfoSec API to manage compliance action plans directly from
the ReportingPage. Users can view, create, and update action plans for host
findings without switching to the Atlas web tool.
Backend:
- Add atlasApi.js helper with Basic Auth, TLS skip, GET/PUT/PATCH/POST
- Add atlas_action_plans_cache migration for SQLite cache table
- Add atlas.js router with sync, status, and proxy CRUD endpoints
- Mount Atlas router at /api/atlas in server.js
- Extract hostId from Ivanti host findings during sync
Frontend:
- Add AtlasBadge component (amber=needs plan, green=has plan)
- Add AtlasSlideOutPanel with plan list, create form, edit capability
- Separate active plans from inactive history in collapsible section
- Custom dark-themed plan type dropdown
- Optimistic local state shows pending plans immediately after creation
- Atlas sync button on ReportingPage toolbar
- Prepopulate finding ID in create form from clicked row
Environment:
- Add ATLAS_API_URL, ATLAS_API_USER, ATLAS_API_PASS, ATLAS_SKIP_TLS to .env.example
2026-04-23 21:52:53 +00:00
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
// Router factory
|
|
|
|
|
// ---------------------------------------------------------------------------
|
2026-05-06 11:44:17 -06:00
|
|
|
function createAtlasRouter() {
|
Add Atlas InfoSec action plans integration
Integrate Atlas InfoSec API to manage compliance action plans directly from
the ReportingPage. Users can view, create, and update action plans for host
findings without switching to the Atlas web tool.
Backend:
- Add atlasApi.js helper with Basic Auth, TLS skip, GET/PUT/PATCH/POST
- Add atlas_action_plans_cache migration for SQLite cache table
- Add atlas.js router with sync, status, and proxy CRUD endpoints
- Mount Atlas router at /api/atlas in server.js
- Extract hostId from Ivanti host findings during sync
Frontend:
- Add AtlasBadge component (amber=needs plan, green=has plan)
- Add AtlasSlideOutPanel with plan list, create form, edit capability
- Separate active plans from inactive history in collapsible section
- Custom dark-themed plan type dropdown
- Optimistic local state shows pending plans immediately after creation
- Atlas sync button on ReportingPage toolbar
- Prepopulate finding ID in create form from clicked row
Environment:
- Add ATLAS_API_URL, ATLAS_API_USER, ATLAS_API_PASS, ATLAS_SKIP_TLS to .env.example
2026-04-23 21:52:53 +00:00
|
|
|
const router = express.Router();
|
|
|
|
|
|
2026-04-24 17:30:06 +00:00
|
|
|
// GET /metrics
|
2026-05-06 11:44:17 -06:00
|
|
|
router.get('/metrics', requireAuth(), async (req, res) => {
|
2026-04-24 17:30:06 +00:00
|
|
|
if (!isConfigured) {
|
|
|
|
|
return res.status(503).json({ error: 'Atlas API is not configured. Check ATLAS_API_URL, ATLAS_API_USER, and ATLAS_API_PASS environment variables.' });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
2026-05-06 11:44:17 -06:00
|
|
|
const { rows } = await pool.query(
|
2026-04-24 17:30:06 +00:00
|
|
|
`SELECT has_action_plan, plans_json FROM atlas_action_plans_cache`
|
|
|
|
|
);
|
|
|
|
|
const metrics = aggregateAtlasMetrics(rows);
|
|
|
|
|
res.json(metrics);
|
|
|
|
|
} catch (err) {
|
|
|
|
|
console.error('[Atlas] Error fetching metrics:', err.message);
|
|
|
|
|
res.status(500).json({ error: 'Failed to fetch Atlas metrics.' });
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
Add Atlas InfoSec action plans integration
Integrate Atlas InfoSec API to manage compliance action plans directly from
the ReportingPage. Users can view, create, and update action plans for host
findings without switching to the Atlas web tool.
Backend:
- Add atlasApi.js helper with Basic Auth, TLS skip, GET/PUT/PATCH/POST
- Add atlas_action_plans_cache migration for SQLite cache table
- Add atlas.js router with sync, status, and proxy CRUD endpoints
- Mount Atlas router at /api/atlas in server.js
- Extract hostId from Ivanti host findings during sync
Frontend:
- Add AtlasBadge component (amber=needs plan, green=has plan)
- Add AtlasSlideOutPanel with plan list, create form, edit capability
- Separate active plans from inactive history in collapsible section
- Custom dark-themed plan type dropdown
- Optimistic local state shows pending plans immediately after creation
- Atlas sync button on ReportingPage toolbar
- Prepopulate finding ID in create form from clicked row
Environment:
- Add ATLAS_API_URL, ATLAS_API_USER, ATLAS_API_PASS, ATLAS_SKIP_TLS to .env.example
2026-04-23 21:52:53 +00:00
|
|
|
// GET /status
|
2026-05-06 11:44:17 -06:00
|
|
|
router.get('/status', requireAuth(), async (req, res) => {
|
Add Atlas InfoSec action plans integration
Integrate Atlas InfoSec API to manage compliance action plans directly from
the ReportingPage. Users can view, create, and update action plans for host
findings without switching to the Atlas web tool.
Backend:
- Add atlasApi.js helper with Basic Auth, TLS skip, GET/PUT/PATCH/POST
- Add atlas_action_plans_cache migration for SQLite cache table
- Add atlas.js router with sync, status, and proxy CRUD endpoints
- Mount Atlas router at /api/atlas in server.js
- Extract hostId from Ivanti host findings during sync
Frontend:
- Add AtlasBadge component (amber=needs plan, green=has plan)
- Add AtlasSlideOutPanel with plan list, create form, edit capability
- Separate active plans from inactive history in collapsible section
- Custom dark-themed plan type dropdown
- Optimistic local state shows pending plans immediately after creation
- Atlas sync button on ReportingPage toolbar
- Prepopulate finding ID in create form from clicked row
Environment:
- Add ATLAS_API_URL, ATLAS_API_USER, ATLAS_API_PASS, ATLAS_SKIP_TLS to .env.example
2026-04-23 21:52:53 +00:00
|
|
|
if (!isConfigured) {
|
|
|
|
|
return res.status(503).json({ error: 'Atlas API is not configured. Check ATLAS_API_URL, ATLAS_API_USER, and ATLAS_API_PASS environment variables.' });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
2026-05-06 11:44:17 -06:00
|
|
|
const { rows } = await pool.query(
|
2026-05-05 11:04:53 -06:00
|
|
|
`SELECT host_id, has_action_plan, plan_count, plans_json, synced_at FROM atlas_action_plans_cache`
|
Add Atlas InfoSec action plans integration
Integrate Atlas InfoSec API to manage compliance action plans directly from
the ReportingPage. Users can view, create, and update action plans for host
findings without switching to the Atlas web tool.
Backend:
- Add atlasApi.js helper with Basic Auth, TLS skip, GET/PUT/PATCH/POST
- Add atlas_action_plans_cache migration for SQLite cache table
- Add atlas.js router with sync, status, and proxy CRUD endpoints
- Mount Atlas router at /api/atlas in server.js
- Extract hostId from Ivanti host findings during sync
Frontend:
- Add AtlasBadge component (amber=needs plan, green=has plan)
- Add AtlasSlideOutPanel with plan list, create form, edit capability
- Separate active plans from inactive history in collapsible section
- Custom dark-themed plan type dropdown
- Optimistic local state shows pending plans immediately after creation
- Atlas sync button on ReportingPage toolbar
- Prepopulate finding ID in create form from clicked row
Environment:
- Add ATLAS_API_URL, ATLAS_API_USER, ATLAS_API_PASS, ATLAS_SKIP_TLS to .env.example
2026-04-23 21:52:53 +00:00
|
|
|
);
|
|
|
|
|
res.json(rows);
|
|
|
|
|
} catch (err) {
|
|
|
|
|
console.error('[Atlas] Error fetching status:', err.message);
|
|
|
|
|
res.status(500).json({ error: 'Failed to fetch Atlas status.' });
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// POST /sync
|
2026-05-06 11:44:17 -06:00
|
|
|
router.post('/sync', requireAuth(), requireGroup('Admin', 'Standard_User'), async (req, res) => {
|
Add Atlas InfoSec action plans integration
Integrate Atlas InfoSec API to manage compliance action plans directly from
the ReportingPage. Users can view, create, and update action plans for host
findings without switching to the Atlas web tool.
Backend:
- Add atlasApi.js helper with Basic Auth, TLS skip, GET/PUT/PATCH/POST
- Add atlas_action_plans_cache migration for SQLite cache table
- Add atlas.js router with sync, status, and proxy CRUD endpoints
- Mount Atlas router at /api/atlas in server.js
- Extract hostId from Ivanti host findings during sync
Frontend:
- Add AtlasBadge component (amber=needs plan, green=has plan)
- Add AtlasSlideOutPanel with plan list, create form, edit capability
- Separate active plans from inactive history in collapsible section
- Custom dark-themed plan type dropdown
- Optimistic local state shows pending plans immediately after creation
- Atlas sync button on ReportingPage toolbar
- Prepopulate finding ID in create form from clicked row
Environment:
- Add ATLAS_API_URL, ATLAS_API_USER, ATLAS_API_PASS, ATLAS_SKIP_TLS to .env.example
2026-04-23 21:52:53 +00:00
|
|
|
if (!isConfigured) {
|
|
|
|
|
return res.status(503).json({ error: 'Atlas API is not configured. Check ATLAS_API_URL, ATLAS_API_USER, and ATLAS_API_PASS environment variables.' });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
2026-05-06 11:44:17 -06:00
|
|
|
// Read Ivanti findings and extract unique non-null hostIds
|
|
|
|
|
const { rows: findingsRows } = await pool.query(
|
|
|
|
|
`SELECT DISTINCT host_id FROM ivanti_findings WHERE host_id IS NOT NULL AND host_id > 0`
|
|
|
|
|
);
|
|
|
|
|
const hostIds = findingsRows.map(r => r.host_id);
|
Add Atlas InfoSec action plans integration
Integrate Atlas InfoSec API to manage compliance action plans directly from
the ReportingPage. Users can view, create, and update action plans for host
findings without switching to the Atlas web tool.
Backend:
- Add atlasApi.js helper with Basic Auth, TLS skip, GET/PUT/PATCH/POST
- Add atlas_action_plans_cache migration for SQLite cache table
- Add atlas.js router with sync, status, and proxy CRUD endpoints
- Mount Atlas router at /api/atlas in server.js
- Extract hostId from Ivanti host findings during sync
Frontend:
- Add AtlasBadge component (amber=needs plan, green=has plan)
- Add AtlasSlideOutPanel with plan list, create form, edit capability
- Separate active plans from inactive history in collapsible section
- Custom dark-themed plan type dropdown
- Optimistic local state shows pending plans immediately after creation
- Atlas sync button on ReportingPage toolbar
- Prepopulate finding ID in create form from clicked row
Environment:
- Add ATLAS_API_URL, ATLAS_API_USER, ATLAS_API_PASS, ATLAS_SKIP_TLS to .env.example
2026-04-23 21:52:53 +00:00
|
|
|
|
|
|
|
|
if (hostIds.length === 0) {
|
|
|
|
|
return res.json({ synced: 0, withPlans: 0, failed: 0 });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let synced = 0;
|
|
|
|
|
let withPlans = 0;
|
|
|
|
|
let failed = 0;
|
|
|
|
|
const BATCH_SIZE = 5;
|
|
|
|
|
|
|
|
|
|
for (let i = 0; i < hostIds.length; i += BATCH_SIZE) {
|
|
|
|
|
const batch = hostIds.slice(i, i + BATCH_SIZE);
|
|
|
|
|
const results = await Promise.allSettled(
|
|
|
|
|
batch.map(async (hostId) => {
|
|
|
|
|
const result = await atlasGet('/hosts/' + hostId + '/action-plans');
|
|
|
|
|
return { hostId, result };
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
for (const settled of results) {
|
|
|
|
|
if (settled.status === 'rejected') {
|
|
|
|
|
failed++;
|
|
|
|
|
console.warn('[Atlas Sync] Request failed for host:', settled.reason?.message || settled.reason);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const { hostId, result } = settled.value;
|
|
|
|
|
|
|
|
|
|
if (result.status >= 200 && result.status < 300) {
|
|
|
|
|
let allPlans = [];
|
|
|
|
|
let activePlans = [];
|
|
|
|
|
try {
|
|
|
|
|
const parsed = JSON.parse(result.body);
|
|
|
|
|
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
|
|
|
|
|
activePlans = Array.isArray(parsed.active) ? parsed.active : [];
|
|
|
|
|
const inactive = Array.isArray(parsed.inactive) ? parsed.inactive : [];
|
|
|
|
|
allPlans = [...activePlans, ...inactive];
|
|
|
|
|
} else if (Array.isArray(parsed)) {
|
|
|
|
|
allPlans = parsed;
|
|
|
|
|
activePlans = parsed;
|
|
|
|
|
}
|
|
|
|
|
} catch (e) {
|
|
|
|
|
allPlans = [];
|
|
|
|
|
activePlans = [];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const planCount = activePlans.length;
|
2026-05-06 11:44:17 -06:00
|
|
|
const hasActionPlan = planCount > 0;
|
2026-05-05 11:04:53 -06:00
|
|
|
|
Add Atlas InfoSec action plans integration
Integrate Atlas InfoSec API to manage compliance action plans directly from
the ReportingPage. Users can view, create, and update action plans for host
findings without switching to the Atlas web tool.
Backend:
- Add atlasApi.js helper with Basic Auth, TLS skip, GET/PUT/PATCH/POST
- Add atlas_action_plans_cache migration for SQLite cache table
- Add atlas.js router with sync, status, and proxy CRUD endpoints
- Mount Atlas router at /api/atlas in server.js
- Extract hostId from Ivanti host findings during sync
Frontend:
- Add AtlasBadge component (amber=needs plan, green=has plan)
- Add AtlasSlideOutPanel with plan list, create form, edit capability
- Separate active plans from inactive history in collapsible section
- Custom dark-themed plan type dropdown
- Optimistic local state shows pending plans immediately after creation
- Atlas sync button on ReportingPage toolbar
- Prepopulate finding ID in create form from clicked row
Environment:
- Add ATLAS_API_URL, ATLAS_API_USER, ATLAS_API_PASS, ATLAS_SKIP_TLS to .env.example
2026-04-23 21:52:53 +00:00
|
|
|
try {
|
2026-05-06 11:44:17 -06:00
|
|
|
if (!hasActionPlan) {
|
|
|
|
|
const { rows: existingRows } = await pool.query(
|
|
|
|
|
`SELECT has_action_plan, plans_json, synced_at FROM atlas_action_plans_cache WHERE host_id = $1`,
|
2026-05-05 11:04:53 -06:00
|
|
|
[hostId]
|
|
|
|
|
);
|
2026-05-06 11:44:17 -06:00
|
|
|
const existing = existingRows[0];
|
|
|
|
|
if (existing && existing.has_action_plan === true) {
|
2026-05-05 11:04:53 -06:00
|
|
|
let existingPlans = [];
|
|
|
|
|
try { existingPlans = JSON.parse(existing.plans_json || '[]'); } catch (_) {}
|
|
|
|
|
const hasBulkStub = existingPlans.some(p => p.source === 'bulk-create');
|
|
|
|
|
if (hasBulkStub) {
|
2026-05-06 11:44:17 -06:00
|
|
|
const ageMs = Date.now() - new Date(existing.synced_at).getTime();
|
2026-05-05 11:04:53 -06:00
|
|
|
const TEN_MINUTES = 10 * 60 * 1000;
|
|
|
|
|
if (ageMs < TEN_MINUTES) {
|
|
|
|
|
synced++;
|
|
|
|
|
withPlans++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-06 11:44:17 -06:00
|
|
|
await pool.query(
|
Add Atlas InfoSec action plans integration
Integrate Atlas InfoSec API to manage compliance action plans directly from
the ReportingPage. Users can view, create, and update action plans for host
findings without switching to the Atlas web tool.
Backend:
- Add atlasApi.js helper with Basic Auth, TLS skip, GET/PUT/PATCH/POST
- Add atlas_action_plans_cache migration for SQLite cache table
- Add atlas.js router with sync, status, and proxy CRUD endpoints
- Mount Atlas router at /api/atlas in server.js
- Extract hostId from Ivanti host findings during sync
Frontend:
- Add AtlasBadge component (amber=needs plan, green=has plan)
- Add AtlasSlideOutPanel with plan list, create form, edit capability
- Separate active plans from inactive history in collapsible section
- Custom dark-themed plan type dropdown
- Optimistic local state shows pending plans immediately after creation
- Atlas sync button on ReportingPage toolbar
- Prepopulate finding ID in create form from clicked row
Environment:
- Add ATLAS_API_URL, ATLAS_API_USER, ATLAS_API_PASS, ATLAS_SKIP_TLS to .env.example
2026-04-23 21:52:53 +00:00
|
|
|
`INSERT INTO atlas_action_plans_cache (host_id, has_action_plan, plan_count, plans_json, synced_at)
|
2026-05-06 11:44:17 -06:00
|
|
|
VALUES ($1, $2, $3, $4, NOW())
|
Add Atlas InfoSec action plans integration
Integrate Atlas InfoSec API to manage compliance action plans directly from
the ReportingPage. Users can view, create, and update action plans for host
findings without switching to the Atlas web tool.
Backend:
- Add atlasApi.js helper with Basic Auth, TLS skip, GET/PUT/PATCH/POST
- Add atlas_action_plans_cache migration for SQLite cache table
- Add atlas.js router with sync, status, and proxy CRUD endpoints
- Mount Atlas router at /api/atlas in server.js
- Extract hostId from Ivanti host findings during sync
Frontend:
- Add AtlasBadge component (amber=needs plan, green=has plan)
- Add AtlasSlideOutPanel with plan list, create form, edit capability
- Separate active plans from inactive history in collapsible section
- Custom dark-themed plan type dropdown
- Optimistic local state shows pending plans immediately after creation
- Atlas sync button on ReportingPage toolbar
- Prepopulate finding ID in create form from clicked row
Environment:
- Add ATLAS_API_URL, ATLAS_API_USER, ATLAS_API_PASS, ATLAS_SKIP_TLS to .env.example
2026-04-23 21:52:53 +00:00
|
|
|
ON CONFLICT(host_id) DO UPDATE SET
|
2026-05-06 11:44:17 -06:00
|
|
|
has_action_plan = EXCLUDED.has_action_plan,
|
|
|
|
|
plan_count = EXCLUDED.plan_count,
|
|
|
|
|
plans_json = EXCLUDED.plans_json,
|
|
|
|
|
synced_at = EXCLUDED.synced_at`,
|
Add Atlas InfoSec action plans integration
Integrate Atlas InfoSec API to manage compliance action plans directly from
the ReportingPage. Users can view, create, and update action plans for host
findings without switching to the Atlas web tool.
Backend:
- Add atlasApi.js helper with Basic Auth, TLS skip, GET/PUT/PATCH/POST
- Add atlas_action_plans_cache migration for SQLite cache table
- Add atlas.js router with sync, status, and proxy CRUD endpoints
- Mount Atlas router at /api/atlas in server.js
- Extract hostId from Ivanti host findings during sync
Frontend:
- Add AtlasBadge component (amber=needs plan, green=has plan)
- Add AtlasSlideOutPanel with plan list, create form, edit capability
- Separate active plans from inactive history in collapsible section
- Custom dark-themed plan type dropdown
- Optimistic local state shows pending plans immediately after creation
- Atlas sync button on ReportingPage toolbar
- Prepopulate finding ID in create form from clicked row
Environment:
- Add ATLAS_API_URL, ATLAS_API_USER, ATLAS_API_PASS, ATLAS_SKIP_TLS to .env.example
2026-04-23 21:52:53 +00:00
|
|
|
[hostId, hasActionPlan, planCount, JSON.stringify(allPlans)]
|
|
|
|
|
);
|
|
|
|
|
} catch (dbErr) {
|
|
|
|
|
console.error('[Atlas Sync] DB upsert failed for host', hostId, ':', dbErr.message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
synced++;
|
|
|
|
|
if (hasActionPlan) withPlans++;
|
|
|
|
|
} else {
|
|
|
|
|
failed++;
|
2026-05-06 11:44:17 -06:00
|
|
|
console.warn(`[Atlas Sync] Non-2xx response for host ${hostId}: status ${result.status}`);
|
Add Atlas InfoSec action plans integration
Integrate Atlas InfoSec API to manage compliance action plans directly from
the ReportingPage. Users can view, create, and update action plans for host
findings without switching to the Atlas web tool.
Backend:
- Add atlasApi.js helper with Basic Auth, TLS skip, GET/PUT/PATCH/POST
- Add atlas_action_plans_cache migration for SQLite cache table
- Add atlas.js router with sync, status, and proxy CRUD endpoints
- Mount Atlas router at /api/atlas in server.js
- Extract hostId from Ivanti host findings during sync
Frontend:
- Add AtlasBadge component (amber=needs plan, green=has plan)
- Add AtlasSlideOutPanel with plan list, create form, edit capability
- Separate active plans from inactive history in collapsible section
- Custom dark-themed plan type dropdown
- Optimistic local state shows pending plans immediately after creation
- Atlas sync button on ReportingPage toolbar
- Prepopulate finding ID in create form from clicked row
Environment:
- Add ATLAS_API_URL, ATLAS_API_USER, ATLAS_API_PASS, ATLAS_SKIP_TLS to .env.example
2026-04-23 21:52:53 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-06 11:44:17 -06:00
|
|
|
logAudit({
|
Add Atlas InfoSec action plans integration
Integrate Atlas InfoSec API to manage compliance action plans directly from
the ReportingPage. Users can view, create, and update action plans for host
findings without switching to the Atlas web tool.
Backend:
- Add atlasApi.js helper with Basic Auth, TLS skip, GET/PUT/PATCH/POST
- Add atlas_action_plans_cache migration for SQLite cache table
- Add atlas.js router with sync, status, and proxy CRUD endpoints
- Mount Atlas router at /api/atlas in server.js
- Extract hostId from Ivanti host findings during sync
Frontend:
- Add AtlasBadge component (amber=needs plan, green=has plan)
- Add AtlasSlideOutPanel with plan list, create form, edit capability
- Separate active plans from inactive history in collapsible section
- Custom dark-themed plan type dropdown
- Optimistic local state shows pending plans immediately after creation
- Atlas sync button on ReportingPage toolbar
- Prepopulate finding ID in create form from clicked row
Environment:
- Add ATLAS_API_URL, ATLAS_API_USER, ATLAS_API_PASS, ATLAS_SKIP_TLS to .env.example
2026-04-23 21:52:53 +00:00
|
|
|
userId: req.user.id,
|
|
|
|
|
username: req.user.username,
|
|
|
|
|
action: 'ATLAS_SYNC',
|
|
|
|
|
entityType: 'atlas_action_plans',
|
|
|
|
|
entityId: null,
|
|
|
|
|
details: { synced, withPlans, failed, totalHosts: hostIds.length },
|
|
|
|
|
ipAddress: req.ip
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
res.json({ synced, withPlans, failed });
|
|
|
|
|
} catch (err) {
|
|
|
|
|
console.error('[Atlas Sync] Unexpected error:', err.message);
|
|
|
|
|
res.status(500).json({ error: 'Atlas sync failed: ' + err.message });
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// GET /hosts/:hostId/action-plans
|
2026-05-06 11:44:17 -06:00
|
|
|
router.get('/hosts/:hostId/action-plans', requireAuth(), async (req, res) => {
|
Add Atlas InfoSec action plans integration
Integrate Atlas InfoSec API to manage compliance action plans directly from
the ReportingPage. Users can view, create, and update action plans for host
findings without switching to the Atlas web tool.
Backend:
- Add atlasApi.js helper with Basic Auth, TLS skip, GET/PUT/PATCH/POST
- Add atlas_action_plans_cache migration for SQLite cache table
- Add atlas.js router with sync, status, and proxy CRUD endpoints
- Mount Atlas router at /api/atlas in server.js
- Extract hostId from Ivanti host findings during sync
Frontend:
- Add AtlasBadge component (amber=needs plan, green=has plan)
- Add AtlasSlideOutPanel with plan list, create form, edit capability
- Separate active plans from inactive history in collapsible section
- Custom dark-themed plan type dropdown
- Optimistic local state shows pending plans immediately after creation
- Atlas sync button on ReportingPage toolbar
- Prepopulate finding ID in create form from clicked row
Environment:
- Add ATLAS_API_URL, ATLAS_API_USER, ATLAS_API_PASS, ATLAS_SKIP_TLS to .env.example
2026-04-23 21:52:53 +00:00
|
|
|
if (!isConfigured) {
|
|
|
|
|
return res.status(503).json({ error: 'Atlas API is not configured. Check ATLAS_API_URL, ATLAS_API_USER, and ATLAS_API_PASS environment variables.' });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const hostId = parseInt(req.params.hostId, 10);
|
|
|
|
|
if (!Number.isInteger(hostId) || hostId <= 0) {
|
|
|
|
|
return res.status(400).json({ error: 'hostId must be a positive integer' });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const result = await atlasGet('/hosts/' + hostId + '/action-plans');
|
|
|
|
|
if (result.status >= 200 && result.status < 300) {
|
|
|
|
|
let body;
|
2026-05-06 11:44:17 -06:00
|
|
|
try { body = JSON.parse(result.body); } catch (e) { body = result.body; }
|
Add Atlas InfoSec action plans integration
Integrate Atlas InfoSec API to manage compliance action plans directly from
the ReportingPage. Users can view, create, and update action plans for host
findings without switching to the Atlas web tool.
Backend:
- Add atlasApi.js helper with Basic Auth, TLS skip, GET/PUT/PATCH/POST
- Add atlas_action_plans_cache migration for SQLite cache table
- Add atlas.js router with sync, status, and proxy CRUD endpoints
- Mount Atlas router at /api/atlas in server.js
- Extract hostId from Ivanti host findings during sync
Frontend:
- Add AtlasBadge component (amber=needs plan, green=has plan)
- Add AtlasSlideOutPanel with plan list, create form, edit capability
- Separate active plans from inactive history in collapsible section
- Custom dark-themed plan type dropdown
- Optimistic local state shows pending plans immediately after creation
- Atlas sync button on ReportingPage toolbar
- Prepopulate finding ID in create form from clicked row
Environment:
- Add ATLAS_API_URL, ATLAS_API_USER, ATLAS_API_PASS, ATLAS_SKIP_TLS to .env.example
2026-04-23 21:52:53 +00:00
|
|
|
res.status(result.status).json(body);
|
|
|
|
|
} else {
|
|
|
|
|
let errorBody;
|
2026-05-06 11:44:17 -06:00
|
|
|
try { errorBody = JSON.parse(result.body); } catch (e) { errorBody = { error: result.body }; }
|
Add Atlas InfoSec action plans integration
Integrate Atlas InfoSec API to manage compliance action plans directly from
the ReportingPage. Users can view, create, and update action plans for host
findings without switching to the Atlas web tool.
Backend:
- Add atlasApi.js helper with Basic Auth, TLS skip, GET/PUT/PATCH/POST
- Add atlas_action_plans_cache migration for SQLite cache table
- Add atlas.js router with sync, status, and proxy CRUD endpoints
- Mount Atlas router at /api/atlas in server.js
- Extract hostId from Ivanti host findings during sync
Frontend:
- Add AtlasBadge component (amber=needs plan, green=has plan)
- Add AtlasSlideOutPanel with plan list, create form, edit capability
- Separate active plans from inactive history in collapsible section
- Custom dark-themed plan type dropdown
- Optimistic local state shows pending plans immediately after creation
- Atlas sync button on ReportingPage toolbar
- Prepopulate finding ID in create form from clicked row
Environment:
- Add ATLAS_API_URL, ATLAS_API_USER, ATLAS_API_PASS, ATLAS_SKIP_TLS to .env.example
2026-04-23 21:52:53 +00:00
|
|
|
res.status(result.status).json(errorBody);
|
|
|
|
|
}
|
|
|
|
|
} catch (err) {
|
|
|
|
|
console.error('[Atlas] GET action-plans failed for host', hostId, ':', err.message);
|
|
|
|
|
res.status(502).json({ error: 'Failed to reach Atlas API: ' + err.message });
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// PUT /hosts/:hostId/action-plans
|
2026-05-06 11:44:17 -06:00
|
|
|
router.put('/hosts/:hostId/action-plans', requireAuth(), requireGroup('Admin', 'Standard_User'), async (req, res) => {
|
Add Atlas InfoSec action plans integration
Integrate Atlas InfoSec API to manage compliance action plans directly from
the ReportingPage. Users can view, create, and update action plans for host
findings without switching to the Atlas web tool.
Backend:
- Add atlasApi.js helper with Basic Auth, TLS skip, GET/PUT/PATCH/POST
- Add atlas_action_plans_cache migration for SQLite cache table
- Add atlas.js router with sync, status, and proxy CRUD endpoints
- Mount Atlas router at /api/atlas in server.js
- Extract hostId from Ivanti host findings during sync
Frontend:
- Add AtlasBadge component (amber=needs plan, green=has plan)
- Add AtlasSlideOutPanel with plan list, create form, edit capability
- Separate active plans from inactive history in collapsible section
- Custom dark-themed plan type dropdown
- Optimistic local state shows pending plans immediately after creation
- Atlas sync button on ReportingPage toolbar
- Prepopulate finding ID in create form from clicked row
Environment:
- Add ATLAS_API_URL, ATLAS_API_USER, ATLAS_API_PASS, ATLAS_SKIP_TLS to .env.example
2026-04-23 21:52:53 +00:00
|
|
|
if (!isConfigured) {
|
|
|
|
|
return res.status(503).json({ error: 'Atlas API is not configured. Check ATLAS_API_URL, ATLAS_API_USER, and ATLAS_API_PASS environment variables.' });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const hostId = parseInt(req.params.hostId, 10);
|
|
|
|
|
if (!Number.isInteger(hostId) || hostId <= 0) {
|
|
|
|
|
return res.status(400).json({ error: 'hostId must be a positive integer' });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const { plan_type, commit_date } = req.body || {};
|
|
|
|
|
if (!plan_type || !VALID_PLAN_TYPES.includes(plan_type)) {
|
|
|
|
|
return res.status(400).json({ error: 'plan_type must be one of: ' + VALID_PLAN_TYPES.join(', ') });
|
|
|
|
|
}
|
|
|
|
|
if (!commit_date || !DATE_PATTERN.test(commit_date)) {
|
|
|
|
|
return res.status(400).json({ error: 'commit_date must be a valid YYYY-MM-DD date string' });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const result = await atlasPut('/hosts/' + hostId + '/action-plans', req.body);
|
|
|
|
|
|
2026-05-06 11:44:17 -06:00
|
|
|
logAudit({
|
Add Atlas InfoSec action plans integration
Integrate Atlas InfoSec API to manage compliance action plans directly from
the ReportingPage. Users can view, create, and update action plans for host
findings without switching to the Atlas web tool.
Backend:
- Add atlasApi.js helper with Basic Auth, TLS skip, GET/PUT/PATCH/POST
- Add atlas_action_plans_cache migration for SQLite cache table
- Add atlas.js router with sync, status, and proxy CRUD endpoints
- Mount Atlas router at /api/atlas in server.js
- Extract hostId from Ivanti host findings during sync
Frontend:
- Add AtlasBadge component (amber=needs plan, green=has plan)
- Add AtlasSlideOutPanel with plan list, create form, edit capability
- Separate active plans from inactive history in collapsible section
- Custom dark-themed plan type dropdown
- Optimistic local state shows pending plans immediately after creation
- Atlas sync button on ReportingPage toolbar
- Prepopulate finding ID in create form from clicked row
Environment:
- Add ATLAS_API_URL, ATLAS_API_USER, ATLAS_API_PASS, ATLAS_SKIP_TLS to .env.example
2026-04-23 21:52:53 +00:00
|
|
|
userId: req.user.id,
|
|
|
|
|
username: req.user.username,
|
|
|
|
|
action: 'ATLAS_CREATE_PLAN',
|
|
|
|
|
entityType: 'atlas_action_plan',
|
|
|
|
|
entityId: String(hostId),
|
|
|
|
|
details: { hostId, plan_type, commit_date },
|
|
|
|
|
ipAddress: req.ip
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (result.status >= 200 && result.status < 300) {
|
|
|
|
|
let body;
|
2026-05-06 11:44:17 -06:00
|
|
|
try { body = JSON.parse(result.body); } catch (e) { body = result.body; }
|
Add Atlas InfoSec action plans integration
Integrate Atlas InfoSec API to manage compliance action plans directly from
the ReportingPage. Users can view, create, and update action plans for host
findings without switching to the Atlas web tool.
Backend:
- Add atlasApi.js helper with Basic Auth, TLS skip, GET/PUT/PATCH/POST
- Add atlas_action_plans_cache migration for SQLite cache table
- Add atlas.js router with sync, status, and proxy CRUD endpoints
- Mount Atlas router at /api/atlas in server.js
- Extract hostId from Ivanti host findings during sync
Frontend:
- Add AtlasBadge component (amber=needs plan, green=has plan)
- Add AtlasSlideOutPanel with plan list, create form, edit capability
- Separate active plans from inactive history in collapsible section
- Custom dark-themed plan type dropdown
- Optimistic local state shows pending plans immediately after creation
- Atlas sync button on ReportingPage toolbar
- Prepopulate finding ID in create form from clicked row
Environment:
- Add ATLAS_API_URL, ATLAS_API_USER, ATLAS_API_PASS, ATLAS_SKIP_TLS to .env.example
2026-04-23 21:52:53 +00:00
|
|
|
res.status(result.status).json(body);
|
|
|
|
|
} else {
|
|
|
|
|
let errorBody;
|
2026-05-06 11:44:17 -06:00
|
|
|
try { errorBody = JSON.parse(result.body); } catch (e) { errorBody = { error: result.body }; }
|
Add Atlas InfoSec action plans integration
Integrate Atlas InfoSec API to manage compliance action plans directly from
the ReportingPage. Users can view, create, and update action plans for host
findings without switching to the Atlas web tool.
Backend:
- Add atlasApi.js helper with Basic Auth, TLS skip, GET/PUT/PATCH/POST
- Add atlas_action_plans_cache migration for SQLite cache table
- Add atlas.js router with sync, status, and proxy CRUD endpoints
- Mount Atlas router at /api/atlas in server.js
- Extract hostId from Ivanti host findings during sync
Frontend:
- Add AtlasBadge component (amber=needs plan, green=has plan)
- Add AtlasSlideOutPanel with plan list, create form, edit capability
- Separate active plans from inactive history in collapsible section
- Custom dark-themed plan type dropdown
- Optimistic local state shows pending plans immediately after creation
- Atlas sync button on ReportingPage toolbar
- Prepopulate finding ID in create form from clicked row
Environment:
- Add ATLAS_API_URL, ATLAS_API_USER, ATLAS_API_PASS, ATLAS_SKIP_TLS to .env.example
2026-04-23 21:52:53 +00:00
|
|
|
res.status(result.status).json(errorBody);
|
|
|
|
|
}
|
|
|
|
|
} catch (err) {
|
|
|
|
|
console.error('[Atlas] PUT action-plans failed for host', hostId, ':', err.message);
|
|
|
|
|
res.status(502).json({ error: 'Failed to reach Atlas API: ' + err.message });
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// PATCH /hosts/:hostId/action-plans
|
2026-05-06 11:44:17 -06:00
|
|
|
router.patch('/hosts/:hostId/action-plans', requireAuth(), requireGroup('Admin', 'Standard_User'), async (req, res) => {
|
Add Atlas InfoSec action plans integration
Integrate Atlas InfoSec API to manage compliance action plans directly from
the ReportingPage. Users can view, create, and update action plans for host
findings without switching to the Atlas web tool.
Backend:
- Add atlasApi.js helper with Basic Auth, TLS skip, GET/PUT/PATCH/POST
- Add atlas_action_plans_cache migration for SQLite cache table
- Add atlas.js router with sync, status, and proxy CRUD endpoints
- Mount Atlas router at /api/atlas in server.js
- Extract hostId from Ivanti host findings during sync
Frontend:
- Add AtlasBadge component (amber=needs plan, green=has plan)
- Add AtlasSlideOutPanel with plan list, create form, edit capability
- Separate active plans from inactive history in collapsible section
- Custom dark-themed plan type dropdown
- Optimistic local state shows pending plans immediately after creation
- Atlas sync button on ReportingPage toolbar
- Prepopulate finding ID in create form from clicked row
Environment:
- Add ATLAS_API_URL, ATLAS_API_USER, ATLAS_API_PASS, ATLAS_SKIP_TLS to .env.example
2026-04-23 21:52:53 +00:00
|
|
|
if (!isConfigured) {
|
|
|
|
|
return res.status(503).json({ error: 'Atlas API is not configured. Check ATLAS_API_URL, ATLAS_API_USER, and ATLAS_API_PASS environment variables.' });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const hostId = parseInt(req.params.hostId, 10);
|
|
|
|
|
if (!Number.isInteger(hostId) || hostId <= 0) {
|
|
|
|
|
return res.status(400).json({ error: 'hostId must be a positive integer' });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const { action_plan_id, updates } = req.body || {};
|
|
|
|
|
if (!action_plan_id || typeof action_plan_id !== 'string' || action_plan_id.trim() === '') {
|
|
|
|
|
return res.status(400).json({ error: 'action_plan_id is required and must be a non-empty string' });
|
|
|
|
|
}
|
|
|
|
|
if (!updates || typeof updates !== 'object' || Array.isArray(updates)) {
|
|
|
|
|
return res.status(400).json({ error: 'updates is required and must be an object' });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const result = await atlasPatch('/hosts/' + hostId + '/action-plans', req.body);
|
|
|
|
|
|
2026-05-06 11:44:17 -06:00
|
|
|
logAudit({
|
Add Atlas InfoSec action plans integration
Integrate Atlas InfoSec API to manage compliance action plans directly from
the ReportingPage. Users can view, create, and update action plans for host
findings without switching to the Atlas web tool.
Backend:
- Add atlasApi.js helper with Basic Auth, TLS skip, GET/PUT/PATCH/POST
- Add atlas_action_plans_cache migration for SQLite cache table
- Add atlas.js router with sync, status, and proxy CRUD endpoints
- Mount Atlas router at /api/atlas in server.js
- Extract hostId from Ivanti host findings during sync
Frontend:
- Add AtlasBadge component (amber=needs plan, green=has plan)
- Add AtlasSlideOutPanel with plan list, create form, edit capability
- Separate active plans from inactive history in collapsible section
- Custom dark-themed plan type dropdown
- Optimistic local state shows pending plans immediately after creation
- Atlas sync button on ReportingPage toolbar
- Prepopulate finding ID in create form from clicked row
Environment:
- Add ATLAS_API_URL, ATLAS_API_USER, ATLAS_API_PASS, ATLAS_SKIP_TLS to .env.example
2026-04-23 21:52:53 +00:00
|
|
|
userId: req.user.id,
|
|
|
|
|
username: req.user.username,
|
|
|
|
|
action: 'ATLAS_UPDATE_PLAN',
|
|
|
|
|
entityType: 'atlas_action_plan',
|
|
|
|
|
entityId: String(hostId),
|
|
|
|
|
details: { hostId, action_plan_id },
|
|
|
|
|
ipAddress: req.ip
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (result.status >= 200 && result.status < 300) {
|
|
|
|
|
let body;
|
2026-05-06 11:44:17 -06:00
|
|
|
try { body = JSON.parse(result.body); } catch (e) { body = result.body; }
|
Add Atlas InfoSec action plans integration
Integrate Atlas InfoSec API to manage compliance action plans directly from
the ReportingPage. Users can view, create, and update action plans for host
findings without switching to the Atlas web tool.
Backend:
- Add atlasApi.js helper with Basic Auth, TLS skip, GET/PUT/PATCH/POST
- Add atlas_action_plans_cache migration for SQLite cache table
- Add atlas.js router with sync, status, and proxy CRUD endpoints
- Mount Atlas router at /api/atlas in server.js
- Extract hostId from Ivanti host findings during sync
Frontend:
- Add AtlasBadge component (amber=needs plan, green=has plan)
- Add AtlasSlideOutPanel with plan list, create form, edit capability
- Separate active plans from inactive history in collapsible section
- Custom dark-themed plan type dropdown
- Optimistic local state shows pending plans immediately after creation
- Atlas sync button on ReportingPage toolbar
- Prepopulate finding ID in create form from clicked row
Environment:
- Add ATLAS_API_URL, ATLAS_API_USER, ATLAS_API_PASS, ATLAS_SKIP_TLS to .env.example
2026-04-23 21:52:53 +00:00
|
|
|
res.status(result.status).json(body);
|
|
|
|
|
} else {
|
|
|
|
|
let errorBody;
|
2026-05-06 11:44:17 -06:00
|
|
|
try { errorBody = JSON.parse(result.body); } catch (e) { errorBody = { error: result.body }; }
|
Add Atlas InfoSec action plans integration
Integrate Atlas InfoSec API to manage compliance action plans directly from
the ReportingPage. Users can view, create, and update action plans for host
findings without switching to the Atlas web tool.
Backend:
- Add atlasApi.js helper with Basic Auth, TLS skip, GET/PUT/PATCH/POST
- Add atlas_action_plans_cache migration for SQLite cache table
- Add atlas.js router with sync, status, and proxy CRUD endpoints
- Mount Atlas router at /api/atlas in server.js
- Extract hostId from Ivanti host findings during sync
Frontend:
- Add AtlasBadge component (amber=needs plan, green=has plan)
- Add AtlasSlideOutPanel with plan list, create form, edit capability
- Separate active plans from inactive history in collapsible section
- Custom dark-themed plan type dropdown
- Optimistic local state shows pending plans immediately after creation
- Atlas sync button on ReportingPage toolbar
- Prepopulate finding ID in create form from clicked row
Environment:
- Add ATLAS_API_URL, ATLAS_API_USER, ATLAS_API_PASS, ATLAS_SKIP_TLS to .env.example
2026-04-23 21:52:53 +00:00
|
|
|
res.status(result.status).json(errorBody);
|
|
|
|
|
}
|
|
|
|
|
} catch (err) {
|
|
|
|
|
console.error('[Atlas] PATCH action-plans failed for host', hostId, ':', err.message);
|
|
|
|
|
res.status(502).json({ error: 'Failed to reach Atlas API: ' + err.message });
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// POST /hosts/bulk-action-plans
|
2026-05-06 11:44:17 -06:00
|
|
|
router.post('/hosts/bulk-action-plans', requireAuth(), requireGroup('Admin', 'Standard_User'), async (req, res) => {
|
Add Atlas InfoSec action plans integration
Integrate Atlas InfoSec API to manage compliance action plans directly from
the ReportingPage. Users can view, create, and update action plans for host
findings without switching to the Atlas web tool.
Backend:
- Add atlasApi.js helper with Basic Auth, TLS skip, GET/PUT/PATCH/POST
- Add atlas_action_plans_cache migration for SQLite cache table
- Add atlas.js router with sync, status, and proxy CRUD endpoints
- Mount Atlas router at /api/atlas in server.js
- Extract hostId from Ivanti host findings during sync
Frontend:
- Add AtlasBadge component (amber=needs plan, green=has plan)
- Add AtlasSlideOutPanel with plan list, create form, edit capability
- Separate active plans from inactive history in collapsible section
- Custom dark-themed plan type dropdown
- Optimistic local state shows pending plans immediately after creation
- Atlas sync button on ReportingPage toolbar
- Prepopulate finding ID in create form from clicked row
Environment:
- Add ATLAS_API_URL, ATLAS_API_USER, ATLAS_API_PASS, ATLAS_SKIP_TLS to .env.example
2026-04-23 21:52:53 +00:00
|
|
|
if (!isConfigured) {
|
|
|
|
|
return res.status(503).json({ error: 'Atlas API is not configured. Check ATLAS_API_URL, ATLAS_API_USER, and ATLAS_API_PASS environment variables.' });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const { host_ids, plan_type, commit_date } = req.body || {};
|
|
|
|
|
if (!Array.isArray(host_ids) || host_ids.length === 0) {
|
|
|
|
|
return res.status(400).json({ error: 'host_ids must be a non-empty array of positive integers' });
|
|
|
|
|
}
|
|
|
|
|
for (const id of host_ids) {
|
|
|
|
|
if (!Number.isInteger(id) || id <= 0) {
|
|
|
|
|
return res.status(400).json({ error: 'host_ids must be a non-empty array of positive integers' });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!plan_type || !VALID_PLAN_TYPES.includes(plan_type)) {
|
|
|
|
|
return res.status(400).json({ error: 'plan_type must be one of: ' + VALID_PLAN_TYPES.join(', ') });
|
|
|
|
|
}
|
|
|
|
|
if (!commit_date || !DATE_PATTERN.test(commit_date)) {
|
|
|
|
|
return res.status(400).json({ error: 'commit_date must be a valid YYYY-MM-DD date string' });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const result = await atlasPost('/hosts/create-bulk-action-plans', req.body);
|
|
|
|
|
|
|
|
|
|
if (result.status >= 200 && result.status < 300) {
|
|
|
|
|
let body;
|
2026-05-06 11:44:17 -06:00
|
|
|
try { body = JSON.parse(result.body); } catch (e) { body = result.body; }
|
2026-05-05 11:04:53 -06:00
|
|
|
|
2026-05-06 11:44:17 -06:00
|
|
|
// Optimistically update local cache
|
2026-05-05 11:04:53 -06:00
|
|
|
for (const hid of host_ids) {
|
|
|
|
|
try {
|
2026-05-06 11:44:17 -06:00
|
|
|
const { rows: existingRows } = await pool.query(
|
|
|
|
|
`SELECT plan_count, plans_json FROM atlas_action_plans_cache WHERE host_id = $1`,
|
2026-05-05 11:04:53 -06:00
|
|
|
[hid]
|
|
|
|
|
);
|
2026-05-06 11:44:17 -06:00
|
|
|
const existing = existingRows[0];
|
2026-05-05 11:04:53 -06:00
|
|
|
|
|
|
|
|
let existingPlans = [];
|
|
|
|
|
if (existing && existing.plans_json) {
|
2026-05-06 11:44:17 -06:00
|
|
|
try { existingPlans = JSON.parse(existing.plans_json); } catch (_) {}
|
2026-05-05 11:04:53 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const stubPlan = { plan_type, commit_date, source: 'bulk-create', created_at: new Date().toISOString() };
|
|
|
|
|
const updatedPlans = [...existingPlans, stubPlan];
|
|
|
|
|
const newCount = updatedPlans.length;
|
|
|
|
|
|
2026-05-06 11:44:17 -06:00
|
|
|
await pool.query(
|
2026-05-05 11:04:53 -06:00
|
|
|
`INSERT INTO atlas_action_plans_cache (host_id, has_action_plan, plan_count, plans_json, synced_at)
|
2026-05-06 11:44:17 -06:00
|
|
|
VALUES ($1, true, $2, $3, NOW())
|
2026-05-05 11:04:53 -06:00
|
|
|
ON CONFLICT(host_id) DO UPDATE SET
|
2026-05-06 11:44:17 -06:00
|
|
|
has_action_plan = true,
|
|
|
|
|
plan_count = EXCLUDED.plan_count,
|
|
|
|
|
plans_json = EXCLUDED.plans_json,
|
|
|
|
|
synced_at = EXCLUDED.synced_at`,
|
2026-05-05 11:04:53 -06:00
|
|
|
[hid, newCount, JSON.stringify(updatedPlans)]
|
|
|
|
|
);
|
|
|
|
|
} catch (cacheErr) {
|
|
|
|
|
console.error('[Atlas] Cache update failed for host', hid, ':', cacheErr.message);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-06 11:44:17 -06:00
|
|
|
logAudit({
|
2026-05-05 11:04:53 -06:00
|
|
|
userId: req.user.id,
|
|
|
|
|
username: req.user.username,
|
|
|
|
|
action: 'ATLAS_BULK_CREATE_PLANS',
|
|
|
|
|
entityType: 'atlas_action_plan',
|
|
|
|
|
entityId: null,
|
|
|
|
|
details: { host_ids, plan_type, commit_date, count: host_ids.length },
|
|
|
|
|
ipAddress: req.ip
|
|
|
|
|
});
|
|
|
|
|
|
Add Atlas InfoSec action plans integration
Integrate Atlas InfoSec API to manage compliance action plans directly from
the ReportingPage. Users can view, create, and update action plans for host
findings without switching to the Atlas web tool.
Backend:
- Add atlasApi.js helper with Basic Auth, TLS skip, GET/PUT/PATCH/POST
- Add atlas_action_plans_cache migration for SQLite cache table
- Add atlas.js router with sync, status, and proxy CRUD endpoints
- Mount Atlas router at /api/atlas in server.js
- Extract hostId from Ivanti host findings during sync
Frontend:
- Add AtlasBadge component (amber=needs plan, green=has plan)
- Add AtlasSlideOutPanel with plan list, create form, edit capability
- Separate active plans from inactive history in collapsible section
- Custom dark-themed plan type dropdown
- Optimistic local state shows pending plans immediately after creation
- Atlas sync button on ReportingPage toolbar
- Prepopulate finding ID in create form from clicked row
Environment:
- Add ATLAS_API_URL, ATLAS_API_USER, ATLAS_API_PASS, ATLAS_SKIP_TLS to .env.example
2026-04-23 21:52:53 +00:00
|
|
|
res.status(result.status).json(body);
|
|
|
|
|
} else {
|
|
|
|
|
let errorBody;
|
2026-05-06 11:44:17 -06:00
|
|
|
try { errorBody = JSON.parse(result.body); } catch (e) { errorBody = { error: result.body }; }
|
Add Atlas InfoSec action plans integration
Integrate Atlas InfoSec API to manage compliance action plans directly from
the ReportingPage. Users can view, create, and update action plans for host
findings without switching to the Atlas web tool.
Backend:
- Add atlasApi.js helper with Basic Auth, TLS skip, GET/PUT/PATCH/POST
- Add atlas_action_plans_cache migration for SQLite cache table
- Add atlas.js router with sync, status, and proxy CRUD endpoints
- Mount Atlas router at /api/atlas in server.js
- Extract hostId from Ivanti host findings during sync
Frontend:
- Add AtlasBadge component (amber=needs plan, green=has plan)
- Add AtlasSlideOutPanel with plan list, create form, edit capability
- Separate active plans from inactive history in collapsible section
- Custom dark-themed plan type dropdown
- Optimistic local state shows pending plans immediately after creation
- Atlas sync button on ReportingPage toolbar
- Prepopulate finding ID in create form from clicked row
Environment:
- Add ATLAS_API_URL, ATLAS_API_USER, ATLAS_API_PASS, ATLAS_SKIP_TLS to .env.example
2026-04-23 21:52:53 +00:00
|
|
|
res.status(result.status).json(errorBody);
|
|
|
|
|
}
|
|
|
|
|
} catch (err) {
|
|
|
|
|
console.error('[Atlas] POST bulk-action-plans failed:', err.message);
|
|
|
|
|
res.status(502).json({ error: 'Failed to reach Atlas API: ' + err.message });
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2026-04-24 22:07:55 +00:00
|
|
|
// POST /hosts/vulnerabilities
|
2026-05-06 11:44:17 -06:00
|
|
|
router.post('/hosts/vulnerabilities', requireAuth(), async (req, res) => {
|
2026-04-24 22:07:55 +00:00
|
|
|
if (!isConfigured) {
|
|
|
|
|
return res.status(503).json({ error: 'Atlas API is not configured. Check ATLAS_API_URL, ATLAS_API_USER, and ATLAS_API_PASS environment variables.' });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const { host_ids } = req.body || {};
|
|
|
|
|
if (!Array.isArray(host_ids) || host_ids.length === 0) {
|
|
|
|
|
return res.status(400).json({ error: 'host_ids must be a non-empty array of positive integers' });
|
|
|
|
|
}
|
|
|
|
|
for (const id of host_ids) {
|
|
|
|
|
if (!Number.isInteger(id) || id <= 0) {
|
|
|
|
|
return res.status(400).json({ error: 'host_ids must be a non-empty array of positive integers' });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const result = await atlasPost('/ivanti-vulnerabilities-by-host', { host_ids }, { timeout: 30000 });
|
|
|
|
|
|
|
|
|
|
if (result.status >= 200 && result.status < 300) {
|
|
|
|
|
let body;
|
2026-05-06 11:44:17 -06:00
|
|
|
try { body = JSON.parse(result.body); } catch (e) { body = result.body; }
|
2026-04-24 22:07:55 +00:00
|
|
|
res.status(result.status).json(body);
|
|
|
|
|
} else {
|
|
|
|
|
let errorBody;
|
2026-05-06 11:44:17 -06:00
|
|
|
try { errorBody = JSON.parse(result.body); } catch (e) { errorBody = { error: result.body }; }
|
2026-04-24 22:07:55 +00:00
|
|
|
res.status(result.status).json(errorBody);
|
|
|
|
|
}
|
|
|
|
|
} catch (err) {
|
|
|
|
|
console.error('[Atlas] POST hosts/vulnerabilities failed:', err.message);
|
|
|
|
|
res.status(502).json({ error: 'Failed to reach Atlas API: ' + err.message });
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
Add Atlas InfoSec action plans integration
Integrate Atlas InfoSec API to manage compliance action plans directly from
the ReportingPage. Users can view, create, and update action plans for host
findings without switching to the Atlas web tool.
Backend:
- Add atlasApi.js helper with Basic Auth, TLS skip, GET/PUT/PATCH/POST
- Add atlas_action_plans_cache migration for SQLite cache table
- Add atlas.js router with sync, status, and proxy CRUD endpoints
- Mount Atlas router at /api/atlas in server.js
- Extract hostId from Ivanti host findings during sync
Frontend:
- Add AtlasBadge component (amber=needs plan, green=has plan)
- Add AtlasSlideOutPanel with plan list, create form, edit capability
- Separate active plans from inactive history in collapsible section
- Custom dark-themed plan type dropdown
- Optimistic local state shows pending plans immediately after creation
- Atlas sync button on ReportingPage toolbar
- Prepopulate finding ID in create form from clicked row
Environment:
- Add ATLAS_API_URL, ATLAS_API_USER, ATLAS_API_PASS, ATLAS_SKIP_TLS to .env.example
2026-04-23 21:52:53 +00:00
|
|
|
return router;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
module.exports = createAtlasRouter;
|
2026-04-24 17:30:06 +00:00
|
|
|
module.exports.aggregateAtlasMetrics = aggregateAtlasMetrics;
|