diff --git a/.kiro/specs/admin-page-overhaul/.config.kiro b/.kiro/specs/admin-page-overhaul/.config.kiro new file mode 100644 index 0000000..448f681 --- /dev/null +++ b/.kiro/specs/admin-page-overhaul/.config.kiro @@ -0,0 +1 @@ +{"specId": "30e46443-e636-4df1-bb98-886f403b2e32", "workflowType": "requirements-first", "specType": "feature"} \ No newline at end of file diff --git a/.kiro/specs/admin-page-overhaul/design.md b/.kiro/specs/admin-page-overhaul/design.md new file mode 100644 index 0000000..4f9ef5a --- /dev/null +++ b/.kiro/specs/admin-page-overhaul/design.md @@ -0,0 +1,423 @@ +# Design Document: Admin Page Overhaul + +## Overview + +The Admin Page Overhaul replaces the current inline `UserManagement` modal rendering on the admin page with a full-page, themed admin panel. The new `AdminPage` component follows the same layout conventions as `CompliancePage`, `ExportsPage`, and `KnowledgeBasePage` — a top-level page component rendered in the main content area of `App.js` when `currentPage === 'admin'`. + +The page consolidates three admin functions into a single tabbed interface: + +1. **User Management** — themed table with inline add/edit forms, group badges, and active status toggles +2. **Audit Log** — paginated, filterable log table with action-type badges and date range filters +3. **System Info** — stat cards showing user counts, audit log totals, and recent activity + +All sections use the dark tactical intelligence theme defined in `DESIGN_SYSTEM.md` and `App.css` — `intel-card` containers, `intel-button` controls, `intel-input` form fields, `status-badge` action labels, and `stat-card` stat displays. + +### Design Decisions + +- **New component, not a wrapper.** The existing `UserManagement.js` and `AuditLog.js` are white-background modals with Tailwind utility classes. Wrapping them would create visual inconsistency. The `AdminPage` component builds themed versions of both panels from scratch, reusing the same backend API endpoints. +- **Existing modals preserved.** The `UserMenu` quick-access links ("Manage Users", "Audit Log") continue to open the existing modal components. This keeps the quick-access workflow intact while the admin page provides the full-featured experience. +- **No new backend endpoints.** All data comes from existing routes: `GET /api/users`, `POST/PATCH/DELETE /api/users/:id`, `GET /api/audit-logs`, `GET /api/audit-logs/actions`. +- **Inline styles + App.css classes.** Follows the project convention of defining style constants in the component file and referencing `App.css` classes (`intel-card`, `intel-button`, `data-row`, etc.) where available. + +## Architecture + +```mermaid +graph TD + A[App.js] -->|currentPage === 'admin' && isAdmin| B[AdminPage] + B --> C[Tab Navigation] + C -->|"User Management"| D[UserManagementPanel] + C -->|"Audit Log"| E[AuditLogPanel] + C -->|"System Info"| F[SystemInfoPanel] + + D -->|GET /api/users| G[Backend: users.js] + D -->|POST /api/users| G + D -->|PATCH /api/users/:id| G + D -->|DELETE /api/users/:id| G + + E -->|GET /api/audit-logs| H[Backend: auditLog.js] + E -->|GET /api/audit-logs/actions| H + + F -->|GET /api/users| G + F -->|GET /api/audit-logs?limit=10| H +``` + +### Component Hierarchy + +``` +AdminPage +├── PageHeader (title + accent glow) +├── TabNavigation (User Management | Audit Log | System Info) +├── UserManagementPanel +│ ├── AddUserButton / InlineForm +│ ├── UserTable +│ │ └── UserRow (group badge, status toggle, edit/delete actions) +│ ├── ErrorBanner +│ └── SuccessToast +├── AuditLogPanel +│ ├── FilterBar (username, action, entity type, start date, end date) +│ ├── LogTable +│ │ └── LogRow (timestamp, user, action badge, entity, details, IP) +│ ├── Pagination +│ ├── EmptyState +│ └── ErrorBanner +└── SystemInfoPanel + ├── StatCards (total users, active users, audit entries, recent logins) + └── RecentActivityList (10 most recent audit entries) +``` + +### Data Flow + +1. `App.js` renders `` when `currentPage === 'admin'` and `isAdmin()` returns true. Non-admin users are redirected to home. +2. `AdminPage` manages the active tab in local state (default: `'users'`). +3. Each panel fetches its own data on mount using `fetch()` with `credentials: 'include'`. +4. Mutations (create, update, delete user) trigger a re-fetch of the user list. Success/error feedback is shown inline. +5. Audit log panel manages its own pagination and filter state, re-fetching on filter apply or page change. +6. System info panel fetches user list and recent audit logs on mount, computing derived stats client-side. + +## Components and Interfaces + +### AdminPage (main component) + +```javascript +// frontend/src/components/pages/AdminPage.js +export default function AdminPage() { + // Props: none (reads auth context internally) + // State: + // activeTab: 'users' | 'audit' | 'system' + // Renders: PageHeader, TabNavigation, conditional panel +} +``` + +### TabNavigation + +```javascript +// Internal to AdminPage +// Props: +// activeTab: string +// onTabChange: (tab: string) => void +// Tabs: [ +// { id: 'users', label: 'User Management', icon: Shield }, +// { id: 'audit', label: 'Audit Log', icon: Clock }, +// { id: 'system', label: 'System Info', icon: Activity }, +// ] +``` + +Styling: monospace uppercase text, `--intel-accent` border and background on active tab, transparent with muted text on inactive tabs. Matches the tab pattern used in `CompliancePage` (team tabs). + +### UserManagementPanel + +```javascript +// Internal to AdminPage +// State: +// users: Array +// loading: boolean +// error: string | null +// showForm: boolean +// editingUser: User | null +// formData: { username, email, password, group } +// formError: string +// successMessage: string +// +// API calls: +// GET /api/users → fetch all users +// POST /api/users → create user +// PATCH /api/users/:id → update user (fields, group, is_active) +// DELETE /api/users/:id → delete user +// +// Group badge colors (themed): +// Admin: --intel-danger (#EF4444) +// Standard_User: --intel-accent (#0EA5E9) +// Leadership: --intel-warning (#F59E0B) +// Read_Only: --text-muted (#94A3B8) +``` + +### AuditLogPanel + +```javascript +// Internal to AdminPage +// State: +// logs: Array +// loading: boolean +// error: string | null +// pagination: { page, limit, total, totalPages } +// filters: { user, action, entityType, startDate, endDate } +// actions: string[] (populated from /api/audit-logs/actions) +// +// API calls: +// GET /api/audit-logs?page=&limit=25&user=&action=&entityType=&startDate=&endDate= +// GET /api/audit-logs/actions +// +// Action badge colors (themed): +// login/logout: --intel-success (#10B981) +// *_create: --intel-accent (#0EA5E9) +// *_update/*_edit: --intel-warning (#F59E0B) +// *_delete: --intel-danger (#EF4444) +// default: --text-muted (#94A3B8) +``` + +### SystemInfoPanel + +```javascript +// Internal to AdminPage +// State: +// users: Array +// recentLogs: Array +// loading: boolean +// errors: { users: string | null, logs: string | null } +// +// Derived stats: +// totalUsers: users.length +// activeUsers: users.filter(u => u.is_active).length +// recentLogins: users.filter(u => u.last_login && withinLast7Days(u.last_login)).length +// totalAuditEntries: fetched from audit-logs pagination.total +// +// API calls: +// GET /api/users +// GET /api/audit-logs?limit=10&page=1 +``` + +### Integration with App.js + +```javascript +// In App.js, replace: +// {currentPage === 'admin' && isAdmin() && ( +//
+// setCurrentPage('home')} /> +//
+// )} +// +// With: +// {currentPage === 'admin' && isAdmin() && } +// {currentPage === 'admin' && !isAdmin() && /* redirect to home */} +// +// Keep existing modal triggers: +// {showUserManagement && } +// {showAuditLog && } +``` + +## Data Models + +### User (from GET /api/users) + +```javascript +{ + id: number, + username: string, + email: string, + group: 'Admin' | 'Standard_User' | 'Leadership' | 'Read_Only', + is_active: 0 | 1, + created_at: string, // ISO datetime + last_login: string | null // ISO datetime +} +``` + +### AuditLogEntry (from GET /api/audit-logs) + +```javascript +{ + id: number, + user_id: number, + username: string, + action: string, // e.g. 'login', 'user_create', 'cve_delete' + entity_type: string, // e.g. 'auth', 'user', 'cve', 'document' + entity_id: string | null, + details: string | null, // JSON string + ip_address: string | null, + created_at: string // ISO datetime +} +``` + +### AuditLogPagination (from GET /api/audit-logs response) + +```javascript +{ + logs: AuditLogEntry[], + pagination: { + page: number, + limit: number, + total: number, + totalPages: number + } +} +``` + +### Tab Configuration + +```javascript +const TABS = [ + { id: 'users', label: 'User Management', icon: Shield }, + { id: 'audit', label: 'Audit Log', icon: Clock }, + { id: 'system', label: 'System Info', icon: Activity }, +]; +``` + +### Group Badge Theme Map + +```javascript +const GROUP_BADGE_THEMED = { + Admin: { bg: 'rgba(239,68,68,0.15)', border: '#EF4444', text: '#FCA5A5' }, + Standard_User: { bg: 'rgba(14,165,233,0.15)', border: '#0EA5E9', text: '#7DD3FC' }, + Leadership: { bg: 'rgba(245,158,11,0.15)', border: '#F59E0B', text: '#FCD34D' }, + Read_Only: { bg: 'rgba(148,163,184,0.15)', border: '#94A3B8', text: '#CBD5E1' }, +}; +``` + +### Action Badge Theme Map + +```javascript +const ACTION_BADGE_THEMED = { + login: { bg: 'rgba(16,185,129,0.15)', border: '#10B981', text: '#6EE7B7' }, + logout: { bg: 'rgba(148,163,184,0.15)', border: '#94A3B8', text: '#CBD5E1' }, + login_failed: { bg: 'rgba(239,68,68,0.15)', border: '#EF4444', text: '#FCA5A5' }, + user_create: { bg: 'rgba(14,165,233,0.15)', border: '#0EA5E9', text: '#7DD3FC' }, + user_update: { bg: 'rgba(245,158,11,0.15)', border: '#F59E0B', text: '#FCD34D' }, + user_delete: { bg: 'rgba(239,68,68,0.15)', border: '#EF4444', text: '#FCA5A5' }, + cve_create: { bg: 'rgba(14,165,233,0.15)', border: '#0EA5E9', text: '#7DD3FC' }, + cve_edit: { bg: 'rgba(245,158,11,0.15)', border: '#F59E0B', text: '#FCD34D' }, + cve_delete: { bg: 'rgba(239,68,68,0.15)', border: '#EF4444', text: '#FCA5A5' }, + document_upload: { bg: 'rgba(139,92,246,0.15)', border: '#8B5CF6', text: '#C4B5FD' }, + document_delete: { bg: 'rgba(239,68,68,0.15)', border: '#EF4444', text: '#FCA5A5' }, +}; +``` + +## Correctness Properties + +*A property is a characteristic or behavior that should hold true across all valid executions of a system — essentially, a formal statement about what the system should do. Properties serve as the bridge between human-readable specifications and machine-verifiable correctness guarantees.* + +### Property 1: Group badge color mapping is total and correct + +*For any* valid user group string (`Admin`, `Standard_User`, `Leadership`, `Read_Only`), the group badge styling function SHALL return a non-null object with `bg`, `border`, and `text` fields matching the themed color for that group. *For any* string that is not one of the four valid groups, the function SHALL return the default muted styling. + +**Validates: Requirements 3.3** + +### Property 2: Edit form population preserves user data + +*For any* user object with arbitrary `username`, `email`, and `group` values, populating the edit form from that user SHALL result in `formData.username === user.username`, `formData.email === user.email`, and `formData.group === user.group`, with `formData.password` set to an empty string. + +**Validates: Requirements 3.5** + +### Property 3: Self-modification prevention + +*For any* user list that contains the currently authenticated admin user, the admin user's own row SHALL have the group dropdown disabled and the active status toggle disabled. *For any* other user in the list, those controls SHALL be enabled. + +**Validates: Requirements 3.8** + +### Property 4: Action badge color mapping is total and correct + +*For any* known audit log action string (from the set of defined actions: `login`, `logout`, `login_failed`, `user_create`, `user_update`, `user_delete`, `cve_create`, `cve_edit`, `cve_delete`, `document_upload`, `document_delete`), the action badge styling function SHALL return the correct themed color object. *For any* unknown action string, the function SHALL return the default muted styling. + +**Validates: Requirements 4.4** + +### Property 5: Applying filters resets pagination to page 1 + +*For any* combination of filter values (username text, action type, entity type, start date, end date) and *for any* current page number, applying the filters SHALL result in a fetch call with `page=1`. + +**Validates: Requirements 4.7** + +### Property 6: Recent login count computation + +*For any* list of user objects with random `last_login` timestamps (including null values), the computed "recent logins" count SHALL equal the number of users whose `last_login` is non-null and falls within the last 7 days from the current time. + +**Validates: Requirements 5.1** + +### Property 7: Admin-only access control + +*For any* user object, the admin page content SHALL be rendered if and only if `user.group === 'Admin'`. When `user.group` is any value other than `'Admin'`, the system SHALL redirect to the home page. + +**Validates: Requirements 6.1, 6.2** + +## Error Handling + +### User Management Panel + +| Error Scenario | Handling | +|---|---| +| `GET /api/users` fails | Display error banner with `--intel-danger` styling. User table is hidden. Retry on next tab switch or manual refresh. | +| `POST /api/users` fails (validation) | Display `formError` message below the form in danger color. Form remains open for correction. | +| `POST /api/users` fails (409 conflict) | Display "Username or email already exists" in `formError`. | +| `PATCH /api/users/:id` fails | Display inline error. Revert optimistic UI changes if any. | +| `DELETE /api/users/:id` fails | Display alert with error message. User list unchanged. | +| Self-demotion attempt | Group dropdown disabled for current user. Backend returns 400 if bypassed. | +| Self-deactivation attempt | Toggle disabled for current user. Backend returns 400 if bypassed. | + +### Audit Log Panel + +| Error Scenario | Handling | +|---|---| +| `GET /api/audit-logs` fails | Display error banner with `--intel-danger` styling. Table hidden. | +| `GET /api/audit-logs/actions` fails | Action filter dropdown shows no options. Non-critical — silently ignored. | +| Invalid date range (start > end) | Client-side: no validation needed — backend handles gracefully by returning empty results. | +| Empty result set | Display "No audit log entries found" message in `--text-muted` color. | + +### System Info Panel + +| Error Scenario | Handling | +|---|---| +| `GET /api/users` fails | Affected stat cards (total users, active users, recent logins) show "Unable to load" fallback text. | +| `GET /api/audit-logs` fails | Audit entries stat card and recent activity list show "Unable to load" fallback. | +| Partial failure (one endpoint fails) | Only the affected cards show fallback. Successfully loaded cards display normally. | + +### Success Feedback + +- Create user: green success toast "User created successfully" auto-dismisses after 2 seconds. +- Update user: green success toast "User updated successfully" auto-dismisses after 2 seconds. +- Delete user: green success toast "User deleted" auto-dismisses after 2 seconds. +- Toggle active status: immediate UI update, no toast (inline visual feedback is sufficient). + +## Testing Strategy + +### Unit Tests (Example-Based) + +Unit tests cover specific rendering, interaction, and integration scenarios: + +**AdminPage structure:** +- Renders page header with "Admin Panel" title +- Defaults to User Management tab on mount +- Switches panels when tabs are clicked +- Only renders when user is admin (access control) + +**UserManagementPanel:** +- Renders user table with all required columns +- Displays themed group badges for each group type +- Shows inline form when "Add User" is clicked +- Populates form with user data when edit is clicked +- Shows confirmation dialog on delete +- Disables self-modification controls for current user +- Displays error banner on API failure +- Displays success toast on successful operations + +**AuditLogPanel:** +- Renders log table with all required columns +- Displays themed action badges +- Renders filter controls (username, action, entity type, dates) +- Fetches page 1 when filters are applied +- Navigates pages with pagination controls +- Shows empty state when no results +- Shows error banner on API failure + +**SystemInfoPanel:** +- Renders four stat cards with correct labels +- Computes derived stats correctly from mock data +- Shows recent activity list with up to 10 entries +- Shows fallback message when an API call fails + +### Property-Based Tests + +Property-based tests use [fast-check](https://github.com/dubzzz/fast-check) to verify universal properties across generated inputs. Each test runs a minimum of 100 iterations. + +| Property | Test Description | Tag | +|---|---|---| +| Property 1 | Generate random group strings (valid + invalid), verify badge function returns correct colors | Feature: admin-page-overhaul, Property 1: Group badge color mapping is total and correct | +| Property 2 | Generate random user objects, verify edit form population matches user fields exactly | Feature: admin-page-overhaul, Property 2: Edit form population preserves user data | +| Property 3 | Generate random user lists containing the current admin, verify self-edit controls are disabled | Feature: admin-page-overhaul, Property 3: Self-modification prevention | +| Property 4 | Generate random action strings (known + unknown), verify badge function returns correct colors | Feature: admin-page-overhaul, Property 4: Action badge color mapping is total and correct | +| Property 5 | Generate random filter states and current page numbers, verify fetch is called with page=1 | Feature: admin-page-overhaul, Property 5: Applying filters resets pagination to page 1 | +| Property 6 | Generate random user lists with random last_login timestamps, verify recent login count matches manual computation | Feature: admin-page-overhaul, Property 6: Recent login count computation | +| Property 7 | Generate random user objects with random groups, verify admin page renders iff group === 'Admin' | Feature: admin-page-overhaul, Property 7: Admin-only access control | + +### Test Configuration + +- **Library:** fast-check (JavaScript property-based testing) +- **Runner:** Jest (via react-scripts test) +- **Iterations:** Minimum 100 per property test (`fc.assert(property, { numRuns: 100 })`) +- **Tag format:** Comment at top of each property test referencing the design property diff --git a/.kiro/specs/admin-page-overhaul/requirements.md b/.kiro/specs/admin-page-overhaul/requirements.md new file mode 100644 index 0000000..2d61457 --- /dev/null +++ b/.kiro/specs/admin-page-overhaul/requirements.md @@ -0,0 +1,108 @@ +# Requirements Document + +## Introduction + +The STEAM Security Dashboard currently has an Admin page (`currentPage === 'admin'`) that renders the `UserManagement` modal component inline — the same modal triggered from the top-right `UserMenu`. The page does not follow the dashboard's dark "tactical intelligence" theme and provides no audit log viewing or other administrative capabilities. This feature overhauls the admin page into a dedicated, full-page admin panel that matches the design system and consolidates user management, audit log viewing, and system administration into a single cohesive interface accessible only to Admin-group users. + +## Glossary + +- **Admin_Page**: The full-page admin panel rendered when `currentPage === 'admin'`, replacing the current inline modal rendering +- **Dashboard**: The STEAM Security Dashboard application +- **Design_System**: The color palette, typography, component specs, and interaction patterns defined in `DESIGN_SYSTEM.md` and `App.css` +- **Audit_Log_Panel**: The section of the Admin_Page that displays paginated, filterable audit log entries +- **User_Management_Panel**: The section of the Admin_Page that displays the user list and provides create, edit, delete, and activate/deactivate operations +- **Admin_User**: A user whose `user_group` is `Admin` +- **Tab_Navigation**: The in-page navigation component that switches between Admin_Page sections (User Management, Audit Log, System Info) +- **System_Info_Panel**: The section of the Admin_Page that displays system metadata such as active user count, recent login activity, and database statistics + +## Requirements + +### Requirement 1: Admin Page Layout and Theme Compliance + +**User Story:** As an admin, I want the admin page to follow the same dark tactical intelligence theme as the rest of the dashboard, so that the experience is visually consistent. + +#### Acceptance Criteria + +1. THE Admin_Page SHALL use the Design_System color palette — `--intel-darkest` for the page background, `--intel-dark` and `--intel-medium` for card backgrounds, and `--intel-accent` for interactive elements +2. THE Admin_Page SHALL render as a full-page view within the main content area, matching the layout pattern used by other page components (CompliancePage, ExportsPage, KnowledgeBasePage) +3. THE Admin_Page SHALL display a page header with the title "Admin Panel" styled in monospace uppercase with the accent text glow defined in the Design_System +4. THE Admin_Page SHALL use `intel-card` styled containers for each content section, with the standard gradient backgrounds, border glow, and shadow depth defined in the Design_System +5. THE Admin_Page SHALL use `intel-button` styled controls for all interactive buttons, with primary, danger, and success variants as appropriate +6. THE Admin_Page SHALL use `intel-input` styled form fields for all text inputs, selects, and date pickers + +### Requirement 2: Tab-Based Section Navigation + +**User Story:** As an admin, I want to navigate between admin sections using tabs, so that I can quickly switch between user management, audit logs, and system information without leaving the page. + +#### Acceptance Criteria + +1. THE Admin_Page SHALL display a Tab_Navigation component with tabs for "User Management", "Audit Log", and "System Info" +2. WHEN an Admin_User clicks a tab, THE Tab_Navigation SHALL switch the visible content section to the selected tab and visually indicate the active tab using the `--intel-accent` color +3. THE Admin_Page SHALL default to the "User Management" tab when first loaded +4. THE Tab_Navigation SHALL use monospace uppercase text with letter spacing consistent with the Design_System label typography + +### Requirement 3: Themed User Management Panel + +**User Story:** As an admin, I want to manage users directly within the themed admin page instead of a white modal overlay, so that user management feels integrated into the dashboard. + +#### Acceptance Criteria + +1. THE User_Management_Panel SHALL display a table of all users with columns for username, email, group, active status, and last login +2. THE User_Management_Panel SHALL style the user table with dark theme rows using `data-row` hover effects and `--text-primary` / `--text-secondary` text colors from the Design_System +3. THE User_Management_Panel SHALL display group badges using severity-style badge coloring — Admin in danger color, Standard_User in accent color, Leadership in warning color, Read_Only in muted color +4. WHEN an Admin_User clicks "Add User", THE User_Management_Panel SHALL display an inline form styled with `intel-input` fields and `intel-button` controls +5. WHEN an Admin_User clicks the edit action on a user row, THE User_Management_Panel SHALL populate the inline form with that user's current data for editing +6. WHEN an Admin_User clicks the delete action on a user row, THE User_Management_Panel SHALL display a confirmation prompt before sending the delete request +7. WHEN an Admin_User toggles a user's active status, THE User_Management_Panel SHALL send a PATCH request and update the displayed status without a full page reload +8. THE User_Management_Panel SHALL prevent an Admin_User from changing their own group or deactivating their own account +9. IF a user management API request fails, THEN THE User_Management_Panel SHALL display an error message styled with the `--intel-danger` color + +### Requirement 4: Themed Audit Log Panel + +**User Story:** As an admin, I want to view audit logs in a themed, filterable table within the admin page, so that I can monitor system activity without opening a separate modal. + +#### Acceptance Criteria + +1. THE Audit_Log_Panel SHALL fetch and display paginated audit log entries from the `/api/audit-logs` endpoint +2. THE Audit_Log_Panel SHALL display columns for timestamp, username, action, entity type, entity ID, details, and IP address +3. THE Audit_Log_Panel SHALL style the log table with dark theme rows, monospace font for timestamps and IP addresses, and `data-row` hover effects +4. THE Audit_Log_Panel SHALL display action type badges using color-coded `status-badge` styling — login actions in success color, delete actions in danger color, create actions in accent color, update actions in warning color +5. THE Audit_Log_Panel SHALL provide filter controls for username (text search), action type (dropdown populated from `/api/audit-logs/actions`), entity type (dropdown), start date, and end date +6. THE Audit_Log_Panel SHALL style all filter controls using `intel-input` and `intel-button` components from the Design_System +7. WHEN an Admin_User applies filters, THE Audit_Log_Panel SHALL re-fetch audit logs from page 1 with the selected filter parameters +8. WHEN an Admin_User clicks a pagination control, THE Audit_Log_Panel SHALL fetch the requested page and display a page indicator showing current page, total pages, and total entry count +9. THE Audit_Log_Panel SHALL display a "No audit log entries found" message styled with `--text-muted` color when the query returns zero results +10. IF the audit log API request fails, THEN THE Audit_Log_Panel SHALL display an error message styled with the `--intel-danger` color + +### Requirement 5: System Info Panel + +**User Story:** As an admin, I want to see a summary of system health and usage statistics, so that I can quickly assess the state of the dashboard. + +#### Acceptance Criteria + +1. THE System_Info_Panel SHALL display stat cards showing: total user count, active user count, total audit log entries, and count of users who logged in within the last 7 days +2. THE System_Info_Panel SHALL style each stat card using the `stat-card` pattern from the Design_System with the accent-colored top bar and hover lift effect +3. THE System_Info_Panel SHALL display a "Recent Activity" section showing the 10 most recent audit log entries in a compact list format +4. WHEN the System_Info_Panel loads, THE System_Info_Panel SHALL fetch statistics from the existing `/api/users` and `/api/audit-logs` endpoints +5. IF any statistics API request fails, THEN THE System_Info_Panel SHALL display a fallback "Unable to load" message in the affected stat card + +### Requirement 6: Access Control + +**User Story:** As a non-admin user, I want to be prevented from accessing the admin page, so that sensitive administrative functions are protected. + +#### Acceptance Criteria + +1. THE Dashboard SHALL render the Admin_Page content only when the authenticated user belongs to the Admin group +2. WHEN a non-admin user navigates to the admin page, THE Dashboard SHALL redirect the user to the home page +3. THE NavDrawer SHALL continue to display the "Admin Panel" navigation item only for Admin-group users +4. THE UserMenu SHALL continue to provide "Manage Users" and "Audit Log" quick-access links for Admin-group users, opening the respective modals as before + +### Requirement 7: Loading and Error States + +**User Story:** As an admin, I want to see clear loading indicators and error messages, so that I know when data is being fetched and when something goes wrong. + +#### Acceptance Criteria + +1. WHILE data is being fetched for any Admin_Page section, THE Admin_Page SHALL display a loading spinner styled with the `loading-spinner` class and `--intel-accent` color +2. IF an API request returns an error, THEN THE Admin_Page SHALL display the error message in a container styled with `--intel-danger` border and text color +3. WHEN an Admin_User performs a successful create, update, or delete operation, THE Admin_Page SHALL display a brief success notification styled with `--intel-success` color diff --git a/.kiro/specs/admin-page-overhaul/tasks.md b/.kiro/specs/admin-page-overhaul/tasks.md new file mode 100644 index 0000000..c73c3b0 --- /dev/null +++ b/.kiro/specs/admin-page-overhaul/tasks.md @@ -0,0 +1,160 @@ +# Implementation Plan: Admin Page Overhaul + +## Overview + +Replace the current inline `UserManagement` modal rendering on the admin page with a full-page, themed `AdminPage` component. The new component lives at `frontend/src/components/pages/AdminPage.js` and provides three tabbed panels — User Management, Audit Log, and System Info — all styled with the dark tactical intelligence theme. No new backend endpoints are needed; the component reuses existing `/api/users` and `/api/audit-logs` routes. Existing modal components (`UserManagement`, `AuditLog`) are preserved for quick-access from `UserMenu`. + +## Tasks + +- [ ] 1. Create AdminPage component with page header and tab navigation + - [ ] 1.1 Create `frontend/src/components/pages/AdminPage.js` with the page shell + - Import React, useState, useAuth from AuthContext, and lucide-react icons (Shield, Clock, Activity) + - Define `API_BASE` constant matching project convention + - Define `TABS` array: `[{ id: 'users', label: 'User Management', icon: Shield }, { id: 'audit', label: 'Audit Log', icon: Clock }, { id: 'system', label: 'System Info', icon: Activity }]` + - Render page header with "Admin Panel" title in monospace uppercase with `--intel-accent` text glow + - Render tab navigation bar with monospace uppercase text, `--intel-accent` active styling, and muted inactive styling matching the CompliancePage team-tab pattern + - Manage `activeTab` state defaulting to `'users'` + - Conditionally render placeholder `
` for each panel based on `activeTab` + - _Requirements: 1.1, 1.2, 1.3, 2.1, 2.2, 2.3, 2.4_ + + - [ ] 1.2 Integrate AdminPage into App.js + - Import `AdminPage` from `./components/pages/AdminPage` + - Replace the existing `{currentPage === 'admin' && isAdmin() && (
setCurrentPage('home')} />
)}` block with `{currentPage === 'admin' && isAdmin() && }` + - Add non-admin redirect: `{currentPage === 'admin' && !isAdmin() && setCurrentPage('home')}` (or useEffect equivalent) + - Keep existing `{showUserManagement && }` and `{showAuditLog && }` modal triggers unchanged + - _Requirements: 1.2, 6.1, 6.2, 6.3, 6.4_ + +- [ ] 2. Implement UserManagementPanel + - [ ] 2.1 Build the themed user table and group badges + - Define `GROUP_BADGE_THEMED` map with themed colors: Admin → danger, Standard_User → accent, Leadership → warning, Read_Only → muted + - Fetch users from `GET /api/users` with `credentials: 'include'` on panel mount + - Render user table with columns: username, email, group, active status, last login + - Style table with dark theme rows using `data-row` hover effects and `--text-primary` / `--text-secondary` text colors + - Render group badges using the themed color map with severity-style badge coloring + - Display loading spinner (`loading-spinner` class, `--intel-accent` color) while fetching + - Display error banner with `--intel-danger` styling on fetch failure + - _Requirements: 3.1, 3.2, 3.3, 7.1, 7.2_ + + - [ ] 2.2 Implement inline add/edit form and CRUD operations + - Add "Add User" button styled with `intel-button` primary variant + - Show inline form with `intel-input` styled fields for username, email, password, and group dropdown + - On edit action: populate form with selected user's data (username, email, group; password blank) + - On form submit: POST (create) or PATCH (update) to `/api/users` or `/api/users/:id` + - On delete action: show confirmation prompt, then DELETE to `/api/users/:id` + - On active status toggle: PATCH to `/api/users/:id` with `is_active` toggled, update UI without full reload + - Prevent self-modification: disable group dropdown and active toggle for the current authenticated user's row + - Display form validation errors with `--intel-danger` color + - Display success toast with `--intel-success` color, auto-dismiss after 2 seconds + - _Requirements: 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 7.3_ + + - [ ]* 2.3 Write property test: Group badge color mapping is total and correct + - **Property 1: Group badge color mapping is total and correct** + - Install `fast-check` as a dev dependency in `frontend/` + - Create test file `frontend/src/components/pages/__tests__/AdminPage.property.test.js` + - Generate random strings including the four valid groups and arbitrary invalid strings + - Verify the badge function returns correct themed colors for valid groups and default muted styling for invalid groups + - Use `fc.assert(property, { numRuns: 100 })` + - **Validates: Requirements 3.3** + + - [ ]* 2.4 Write property test: Edit form population preserves user data + - **Property 2: Edit form population preserves user data** + - Generate random user objects with arbitrary username, email, and group values + - Verify that populating the edit form results in `formData.username === user.username`, `formData.email === user.email`, `formData.group === user.group`, and `formData.password === ''` + - Use `fc.assert(property, { numRuns: 100 })` + - **Validates: Requirements 3.5** + + - [ ]* 2.5 Write property test: Self-modification prevention + - **Property 3: Self-modification prevention** + - Generate random user lists that include a user matching the current admin's ID + - Verify the admin's own row has group dropdown disabled and active toggle disabled + - Verify all other users have those controls enabled + - Use `fc.assert(property, { numRuns: 100 })` + - **Validates: Requirements 3.8** + +- [ ] 3. Checkpoint — Verify user management panel + - Ensure all tests pass, ask the user if questions arise. + +- [ ] 4. Implement AuditLogPanel + - [ ] 4.1 Build the themed audit log table with action badges and filters + - Define `ACTION_BADGE_THEMED` map with themed colors: login/success → green, delete → danger, create → accent, update → warning, default → muted + - Fetch audit logs from `GET /api/audit-logs?page=1&limit=25` with `credentials: 'include'` on panel mount + - Fetch action types from `GET /api/audit-logs/actions` for the action filter dropdown + - Render log table with columns: timestamp, username, action, entity type, entity ID, details, IP address + - Style timestamps and IP addresses with monospace font + - Render action type badges using the themed color map + - Style table with dark theme rows and `data-row` hover effects + - Display loading spinner while fetching, error banner on failure + - Display "No audit log entries found" message with `--text-muted` color when results are empty + - _Requirements: 4.1, 4.2, 4.3, 4.4, 4.9, 4.10, 7.1, 7.2_ + + - [ ] 4.2 Implement filter controls and pagination + - Render filter bar with: username text input, action type dropdown, entity type dropdown, start date picker, end date picker + - Style all filter controls with `intel-input` and `intel-button` components + - On filter apply: re-fetch audit logs from page 1 with selected filter parameters + - Render pagination controls showing current page, total pages, and total entry count + - On page change: fetch the requested page + - _Requirements: 4.5, 4.6, 4.7, 4.8_ + + - [ ]* 4.3 Write property test: Action badge color mapping is total and correct + - **Property 4: Action badge color mapping is total and correct** + - Generate random action strings including all known actions and arbitrary unknown strings + - Verify the badge function returns correct themed colors for known actions and default muted styling for unknown actions + - Use `fc.assert(property, { numRuns: 100 })` + - **Validates: Requirements 4.4** + + - [ ]* 4.4 Write property test: Applying filters resets pagination to page 1 + - **Property 5: Applying filters resets pagination to page 1** + - Generate random filter combinations (username text, action type, entity type, start date, end date) and random current page numbers + - Verify that applying filters results in a fetch call with `page=1` + - Use `fc.assert(property, { numRuns: 100 })` + - **Validates: Requirements 4.7** + +- [ ] 5. Implement SystemInfoPanel + - [ ] 5.1 Build stat cards and recent activity list + - Fetch users from `GET /api/users` and recent audit logs from `GET /api/audit-logs?limit=10&page=1` on panel mount + - Compute derived stats: total users (`users.length`), active users (`users.filter(u => u.is_active)`), recent logins (users with `last_login` within last 7 days), total audit entries (from pagination.total) + - Render four stat cards using the `stat-card` pattern with accent-colored top bar and hover lift effect + - Render "Recent Activity" section showing the 10 most recent audit log entries in a compact list format + - Show "Unable to load" fallback in affected stat cards when individual API requests fail + - Display loading spinner while fetching + - _Requirements: 5.1, 5.2, 5.3, 5.4, 5.5, 7.1_ + + - [ ]* 5.2 Write property test: Recent login count computation + - **Property 6: Recent login count computation** + - Generate random user lists with random `last_login` timestamps (including null values) + - Verify the computed "recent logins" count equals the number of users whose `last_login` is non-null and falls within the last 7 days + - Use `fc.assert(property, { numRuns: 100 })` + - **Validates: Requirements 5.1** + +- [ ] 6. Checkpoint — Verify all panels and integration + - Ensure all tests pass, ask the user if questions arise. + +- [ ] 7. Access control and final wiring + - [ ] 7.1 Verify access control integration + - Confirm `AdminPage` reads auth context via `useAuth()` and only renders content for Admin-group users + - Confirm `App.js` redirects non-admin users to home when `currentPage === 'admin'` + - Confirm `NavDrawer` continues to show "Admin Panel" only for Admin-group users (no changes needed — verify existing behavior) + - Confirm `UserMenu` quick-access links ("Manage Users", "Audit Log") continue to open existing modal components (no changes needed — verify existing behavior) + - _Requirements: 6.1, 6.2, 6.3, 6.4_ + + - [ ]* 7.2 Write property test: Admin-only access control + - **Property 7: Admin-only access control** + - Generate random user objects with random group values + - Verify admin page content renders if and only if `user.group === 'Admin'` + - Verify non-Admin groups trigger redirect to home + - Use `fc.assert(property, { numRuns: 100 })` + - **Validates: Requirements 6.1, 6.2** + +- [ ] 8. Final checkpoint — Ensure all tests pass + - Ensure all tests pass, ask the user if questions arise. + +## Notes + +- Tasks marked with `*` are optional and can be skipped for faster MVP +- Each task references specific requirements for traceability +- Checkpoints ensure incremental validation +- Property tests validate universal correctness properties from the design document using fast-check +- Unit tests validate specific examples and edge cases +- Existing `UserManagement.js` and `AuditLog.js` modal components are not modified — they remain for UserMenu quick-access +- All styling follows the project convention of inline styles + App.css classes (no Tailwind in the new component) +- The `fast-check` library must be installed as a dev dependency before running property tests diff --git a/.kiro/specs/compliance-schema-drift-check/design.md b/.kiro/specs/compliance-schema-drift-check/design.md new file mode 100644 index 0000000..d0a0640 --- /dev/null +++ b/.kiro/specs/compliance-schema-drift-check/design.md @@ -0,0 +1,364 @@ +# Design Document: Compliance Schema Drift Check + +## Overview + +This feature adds schema drift detection to the compliance xlsx upload flow. When a user uploads a weekly NTS_AEO report, the backend extracts the xlsx structural schema (sheet names, column headers, metric values) and compares it against a shared parser configuration file. The comparison produces a categorised drift report with three severity levels: breaking (blocks upload), silent-miss (warns but allows proceeding), and cosmetic (informational). The frontend displays these findings in a new drift review phase inside the upload modal, inserted between the upload spinner and the existing diff preview. + +The parser configuration dicts (`METRIC_CATEGORIES`, `CORE_COLS`, `SKIP_SHEETS`) currently defined inline in `parse_compliance_xlsx.py` are extracted into a shared JSON file (`backend/scripts/compliance_config.json`) that both the Python parser and the Node.js drift checker read. This establishes a single source of truth for parser configuration. + +### Design Decisions + +1. **Shared JSON config over database storage**: The parser config is a developer-maintained mapping, not user data. A JSON file is version-controllable, diffable, and readable by both Python and Node.js without additional dependencies. + +2. **Python subprocess for schema extraction**: The existing `dump_xlsx_schema.py` already uses openpyxl to extract xlsx structure. We adapt this into a new `extract_xlsx_schema.py` script that the Node.js backend invokes as a subprocess, consistent with how `parse_compliance_xlsx.py` is already called. + +3. **Node.js drift comparison logic**: The drift comparison is pure object comparison (sets of strings) with no xlsx parsing. Implementing it in Node.js avoids a second Python subprocess call and keeps the logic co-located with the route handler. + +4. **Graceful degradation**: If the drift check fails, the upload flow proceeds normally with `drift: null` and a `drift_error` message. The drift check is additive and must never block the existing workflow. + +## Architecture + +```mermaid +sequenceDiagram + participant User + participant Modal as ComplianceUploadModal + participant API as POST /api/compliance/preview + participant Schema as extract_xlsx_schema.py + participant Drift as driftChecker (Node.js) + participant Config as compliance_config.json + participant Parser as parse_compliance_xlsx.py + + User->>Modal: Drops xlsx file + Modal->>API: POST /preview (multipart) + API->>Schema: spawn python3 extract_xlsx_schema.py + Schema-->>API: JSON { sheets: [...] } + API->>Config: fs.readFileSync(compliance_config.json) + API->>Drift: compareSchemaToDrift(schema, config) + Drift-->>API: { breaking: [...], silent_miss: [...], cosmetic: [...] } + API->>Parser: spawn python3 parse_compliance_xlsx.py + Parser->>Config: reads compliance_config.json + Parser-->>API: JSON { items, summary, ... } + API->>API: computeDiff(db, items) + API-->>Modal: { drift, diff, tempFile, ... } + alt drift has findings + Modal->>User: Show drift review phase + alt breaking findings exist + Modal->>User: Block "Continue to Preview" + else no breaking findings + User->>Modal: Click "Continue to Preview" + Modal->>User: Show diff preview + end + else no drift findings + Modal->>User: Show diff preview directly + end +``` + +### File Layout + +``` +backend/ + scripts/ + compliance_config.json # NEW — shared parser config (single source of truth) + extract_xlsx_schema.py # NEW — extracts xlsx structure as JSON + parse_compliance_xlsx.py # MODIFIED — reads config from JSON file + dump_xlsx_schema.py # UNCHANGED — standalone diagnostic tool + routes/ + compliance.js # MODIFIED — drift check in /preview, new driftChecker module + helpers/ + driftChecker.js # NEW — compareSchemaToDrift() function + +frontend/ + src/components/pages/ + ComplianceUploadModal.js # MODIFIED — new drift-review phase +``` + +## Components and Interfaces + +### 1. Shared Parser Configuration (`compliance_config.json`) + +```json +{ + "metric_categories": { + "2.3.4i": "Vulnerability Management", + "2.3.6i": "Vulnerability Management", + "5.2.4": "Access & MFA" + }, + "core_cols": [ + "Preferred - Hostname", + "GRANITE - IPv4_Address", + "GRANITE - Type", + "Team", + "Compliant", + "Source_Network", + "Vertical", + "GRANITE - Equip_Inst_ID", + "GRANITE - RESPONSIBLE_TEAM" + ], + "skip_sheets": ["Summary", "CMDB_9box", "Vulns", "Aging Dashboard"] +} +``` + +### 2. Schema Extractor (`extract_xlsx_schema.py`) + +**Input**: File path as CLI argument. + +**Output** (stdout JSON): +```json +{ + "sheets": [ + { + "name": "Summary", + "columns": ["Metric", "Non-Compliant", "..."], + "metric_values": ["2.3.4i", "5.2.4", "..."] + }, + { + "name": "2.3.4i", + "columns": ["Preferred - Hostname", "GRANITE - IPv4_Address", "..."] + } + ] +} +``` + +- Uses openpyxl in read-only mode. +- Extracts sheet names, first-row column headers per sheet, and unique metric values from the Summary sheet (header at row 4, data from row 5 onward). +- On error, returns `{ "error": "..." }` on stdout and exits with non-zero code. + +### 3. Drift Checker (`backend/helpers/driftChecker.js`) + +**Function**: `compareSchemaToDrift(schema, config) => DriftReport` + +**Parameters**: +- `schema` — object returned by `extract_xlsx_schema.py` +- `config` — object parsed from `compliance_config.json` + +**Returns** (`DriftReport`): +```javascript +{ + breaking: [ + { severity: 'breaking', message: 'Detail sheet "2.3.4i" is missing core column "Team"', value: 'Team', sheet: '2.3.4i' } + ], + silent_miss: [ + { severity: 'silent_miss', message: 'Unknown metric "9.1.2" in Summary — not in metric_categories', value: '9.1.2' } + ], + cosmetic: [ + { severity: 'cosmetic', message: 'New column "Extra_Field" in sheet "2.3.4i" — will be captured in extra_json', value: 'Extra_Field', sheet: '2.3.4i' } + ] +} +``` + +**Drift rules**: + +| Rule | Severity | Condition | +|---|---|---| +| Missing core column | `breaking` | A detail sheet (not in `skip_sheets`, present in xlsx) is missing a column from `core_cols` | +| Missing detail sheet | `breaking` | A sheet name in `metric_categories` (and not in `skip_sheets`) is absent from the xlsx | +| Unknown metric value | `silent_miss` | A metric value in the Summary sheet is not a key in `metric_categories` | +| Unknown sheet | `silent_miss` | An xlsx sheet is not in `skip_sheets` and not in `metric_categories` | +| New column in detail sheet | `cosmetic` | A detail sheet has columns not in `core_cols` | +| Stale metric category | `cosmetic` | A key in `metric_categories` does not appear in the Summary sheet's metric values | + +### 4. Preview Endpoint Changes (`POST /api/compliance/preview`) + +The existing `/preview` handler is modified to: + +1. After receiving the uploaded file, spawn `extract_xlsx_schema.py` to get the xlsx schema. +2. Read `compliance_config.json` from disk. +3. Call `compareSchemaToDrift(schema, config)` to produce the drift report. +4. Proceed with the existing `parseXlsx()` call and `computeDiff()`. +5. Include `drift` (the DriftReport object) and optionally `drift_error` (string) in the response. + +If the schema extraction or drift check throws, set `drift: null` and `drift_error: `, then continue with the normal flow. + +**Updated response shape**: +```json +{ + "drift": { + "breaking": [], + "silent_miss": [], + "cosmetic": [] + }, + "drift_error": null, + "diff": { "new_count": 5, "recurring_count": 120, "resolved_count": 3 }, + "tempFile": "/path/to/temp.json", + "filename": "NTS_AEO_2026_03_25.xlsx", + "report_date": "2026-03-25", + "total_items": 125 +} +``` + +### 5. Upload Modal Changes (`ComplianceUploadModal.js`) + +**New phase**: `drift-review` inserted between `uploading` and `preview`. + +**Phase flow**: +``` +idle → uploading → drift-review (if findings) → preview → committing → done + → preview (if no findings) +``` + +**Drift review UI**: +- Findings grouped by severity: breaking first, then silent-miss, then cosmetic. +- Each group has a header with severity label and count badge. +- Groups with more than 5 findings collapse with a "Show N more" toggle. +- Each finding shows the message text and the triggering value. +- Breaking findings: red text (`#EF4444`), red left-border accent. +- Silent-miss findings: amber text (`#F59E0B`), amber left-border accent. +- Cosmetic findings: muted text (`#94A3B8`), subtle left-border accent. +- "Cancel" button returns to idle. "Continue to Preview" button advances to diff preview. +- "Continue to Preview" is disabled when breaking findings exist, with a message explaining the block. +- When `drift` is `null` (drift check failed), skip drift-review and go straight to preview. + +## Data Models + +### DriftFinding + +```javascript +{ + severity: 'breaking' | 'silent_miss' | 'cosmetic', + message: string, // Human-readable description + value: string, // The specific column/sheet/metric that triggered the finding + sheet: string|null // Sheet name context (when applicable) +} +``` + +### DriftReport + +```javascript +{ + breaking: DriftFinding[], + silent_miss: DriftFinding[], + cosmetic: DriftFinding[] +} +``` + +### ParserConfig + +```javascript +{ + metric_categories: { [metricId: string]: string }, // metric ID → category name + core_cols: string[], // column names for main item fields + skip_sheets: string[] // sheet names excluded from parsing +} +``` + +### XlsxSchema (output of extract_xlsx_schema.py) + +```javascript +{ + sheets: [ + { + name: string, + columns: string[], + metric_values?: string[] // only present on Summary sheet + } + ] +} +``` + + +## Correctness Properties + +*A property is a characteristic or behavior that should hold true across all valid executions of a system — essentially, a formal statement about what the system should do. Properties serve as the bridge between human-readable specifications and machine-verifiable correctness guarantees.* + +### Property 1: Breaking drift completeness + +*For any* xlsx schema and parser config, the drift checker SHALL produce a breaking finding for every core column missing from every detail sheet, and for every detail sheet (present in `metric_categories` but not in `skip_sheets`) absent from the xlsx — and no other breaking findings. The set of breaking findings is exactly the union of missing-core-column findings and missing-detail-sheet findings. + +**Validates: Requirements 3.1, 3.2, 3.3** + +### Property 2: Silent-miss drift completeness + +*For any* xlsx schema and parser config, the drift checker SHALL produce a silent-miss finding for every metric value in the Summary sheet not present in `metric_categories`, and for every xlsx sheet not in `skip_sheets` and not in `metric_categories` — and no other silent-miss findings. The set of silent-miss findings is exactly the union of unknown-metric findings and unknown-sheet findings. + +**Validates: Requirements 4.1, 4.2, 4.3** + +### Property 3: Cosmetic drift completeness + +*For any* xlsx schema and parser config, the drift checker SHALL produce a cosmetic finding for every column in a detail sheet not present in `core_cols`, and for every key in `metric_categories` not present in the Summary sheet's metric values — and no other cosmetic findings. The set of cosmetic findings is exactly the union of new-column findings and stale-metric findings. + +**Validates: Requirements 5.1, 5.2, 5.3** + +### Property 4: Drift severity ordering + +*For any* drift report containing a mix of breaking, silent-miss, and cosmetic findings, the grouping function SHALL always return findings ordered by severity: all breaking findings first, then all silent-miss findings, then all cosmetic findings. + +**Validates: Requirements 8.1** + +## Error Handling + +### Python Script Failures + +| Failure | Handling | +|---|---| +| `extract_xlsx_schema.py` exits non-zero | Preview endpoint sets `drift: null`, `drift_error: `, continues with normal parse flow | +| `extract_xlsx_schema.py` returns invalid JSON | Same as above — caught in JSON.parse, treated as drift check failure | +| `compliance_config.json` missing or invalid (Node.js read) | Preview endpoint returns 500 with message "Configuration file could not be loaded" | +| `compliance_config.json` missing or invalid (Python parser read) | Parser exits non-zero, stderr describes the error, preview endpoint returns 500 with parse error | +| xlsx file cannot be opened by schema extractor | Schema extractor returns `{ "error": "..." }` on stdout, exits non-zero; drift check skipped gracefully | + +### Frontend Error States + +| Condition | Behavior | +|---|---| +| `drift` is `null` in preview response | Skip drift-review phase, proceed directly to diff preview | +| `drift_error` is present | Optionally display a subtle warning in the diff preview that drift check was skipped | +| Network error during upload | Existing error phase handling (unchanged) | + +### Config File Validation + +The Node.js config loader validates that: +- The file exists and is readable. +- The content parses as valid JSON. +- The parsed object contains `metric_categories` (object), `core_cols` (array), and `skip_sheets` (array). + +If any check fails, the loader throws with a descriptive message. The preview handler catches this and returns a 500 response. + +## Testing Strategy + +### Unit Tests + +**Drift checker (`driftChecker.js`)**: +- Breaking: missing core column produces finding with correct severity, message, value, and sheet. +- Breaking: missing detail sheet produces finding. +- Silent-miss: unknown metric value produces finding. +- Silent-miss: unknown sheet produces finding. +- Cosmetic: new column in detail sheet produces finding. +- Cosmetic: stale metric category produces finding. +- Empty schema (no sheets) produces appropriate findings. +- Config with empty metric_categories, core_cols, or skip_sheets. +- Schema and config that are perfectly aligned produce zero findings. + +**Config loader**: +- Valid config file loads correctly. +- Missing file throws descriptive error. +- Invalid JSON throws descriptive error. +- Config missing required keys throws descriptive error. + +**Frontend drift review component**: +- Drift review phase renders when findings exist. +- "Continue to Preview" button disabled when breaking findings present. +- "Continue to Preview" button enabled when no breaking findings. +- Groups collapse at 5+ findings with correct "Show N more" count. +- Cancel returns to idle phase. +- Skips drift review when drift is null or has no findings. + +### Property-Based Tests + +Property-based tests use `fast-check` (JavaScript) to verify the four correctness properties defined above. Each test generates random schema and config objects and verifies the drift checker output against the expected set-theoretic result. + +**Configuration**: +- Minimum 100 iterations per property test. +- Each test tagged with: **Feature: compliance-schema-drift-check, Property {N}: {title}** + +**Generators**: +- `arbitraryParserConfig`: generates random `metric_categories` (object with 0–20 string keys mapped to category strings), `core_cols` (array of 0–15 unique column name strings), `skip_sheets` (array of 0–5 unique sheet name strings). +- `arbitraryXlsxSchema`: generates random sheets array, each with a name, columns array, and optionally metric_values (for the Summary sheet). Sheet names, column names, and metric values drawn from a shared pool to ensure meaningful overlap with the config. + +### Integration Tests + +- Preview endpoint returns drift report alongside existing diff data. +- Preview endpoint returns 200 with breaking drift (does not error). +- Preview endpoint gracefully degrades when drift check fails (`drift: null`, `drift_error` present). +- Preview endpoint returns 500 when config file is missing. +- Python parser reads from `compliance_config.json` and produces same output as before. +- Commit endpoint is unchanged and does not reference drift. diff --git a/.kiro/specs/compliance-schema-drift-check/tasks.md b/.kiro/specs/compliance-schema-drift-check/tasks.md new file mode 100644 index 0000000..4ebe8ec --- /dev/null +++ b/.kiro/specs/compliance-schema-drift-check/tasks.md @@ -0,0 +1,154 @@ +# Implementation Plan: Compliance Schema Drift Check + +## Overview + +This plan implements schema drift detection in the compliance upload flow. The work proceeds in layers: first extract the shared config file, then build the Python schema extractor, then the Node.js drift checker, then wire it into the preview endpoint, and finally update the upload modal with the drift-review phase. Property-based tests validate the drift checker's correctness properties using fast-check. + +## Tasks + +- [x] 1. Create shared parser configuration file and update Python parser + - [x] 1.1 Create `backend/scripts/compliance_config.json` with `metric_categories`, `core_cols`, and `skip_sheets` + - Extract the exact values from the inline dicts `METRIC_CATEGORIES`, `CORE_COLS`, and `SKIP_SHEETS` in `parse_compliance_xlsx.py` + - `metric_categories` is an object mapping metric ID strings to category strings + - `core_cols` is an array of column name strings + - `skip_sheets` is an array of sheet name strings + - _Requirements: 1.1, 1.2_ + + - [x] 1.2 Modify `backend/scripts/parse_compliance_xlsx.py` to read config from JSON file + - Remove the inline `METRIC_CATEGORIES`, `CORE_COLS`, and `SKIP_SHEETS` definitions + - Load them from `compliance_config.json` (resolved relative to the script's directory) + - If the config file is missing or contains invalid JSON, print a descriptive error to stderr and exit with non-zero code + - Ensure `CORE_COLS` is converted to a set after loading from the JSON array + - _Requirements: 1.3, 1.4_ + + - [ ]* 1.3 Write unit tests for Python parser config loading + - Test that parser loads config correctly and produces same output as before + - Test that missing config file causes non-zero exit with descriptive stderr + - Test that invalid JSON in config file causes non-zero exit with descriptive stderr + - _Requirements: 1.3, 1.4_ + +- [x] 2. Create Python schema extractor script + - [x] 2.1 Create `backend/scripts/extract_xlsx_schema.py` + - Accept file path as CLI argument + - Use openpyxl in read-only mode to extract: sheet names, first-row column headers per sheet, and unique metric values from the Summary sheet (header at row 4, data from row 5 onward) + - Output JSON to stdout with shape `{ "sheets": [{ "name", "columns", "metric_values?" }] }` + - On error, return `{ "error": "..." }` on stdout and exit with non-zero code + - Reuse the approach from `dump_xlsx_schema.py` for Summary sheet metric extraction + - _Requirements: 2.1, 2.2, 2.3, 2.4_ + + - [ ]* 2.2 Write unit tests for schema extractor + - Test that valid xlsx produces correct schema JSON + - Test that missing file returns error JSON and non-zero exit + - Test that file with no sheets returns error JSON + - _Requirements: 2.1, 2.4_ + +- [x] 3. Implement Node.js drift checker module + - [x] 3.1 Create `backend/helpers/driftChecker.js` with `compareSchemaToDrift(schema, config)` function + - Implement breaking rules: missing core column in detail sheets, missing detail sheet (in `metric_categories` but not `skip_sheets` and absent from xlsx) + - Implement silent-miss rules: unknown metric value in Summary not in `metric_categories`, unknown sheet not in `skip_sheets` and not in `metric_categories` + - Implement cosmetic rules: new column in detail sheet not in `core_cols`, stale metric in `metric_categories` not in Summary metric values + - Each finding has shape `{ severity, message, value, sheet }` (sheet is null when not applicable) + - Return `{ breaking: [], silent_miss: [], cosmetic: [] }` + - Export `compareSchemaToDrift` and a `loadConfig(configPath)` function that reads and validates `compliance_config.json` + - Config loader validates: file exists, parses as JSON, contains `metric_categories` (object), `core_cols` (array), `skip_sheets` (array) + - _Requirements: 3.1, 3.2, 3.3, 4.1, 4.2, 4.3, 5.1, 5.2, 5.3, 1.5, 1.6_ + + - [ ] 3.2 Write property test: Breaking drift completeness (Property 1) + - **Property 1: Breaking drift completeness** + - For any generated schema and config, the set of breaking findings equals exactly the union of missing-core-column findings and missing-detail-sheet findings — no more, no fewer + - Use fast-check with arbitrary generators for schema and config objects + - Minimum 100 iterations + - **Validates: Requirements 3.1, 3.2, 3.3** + + - [ ]* 3.3 Write property test: Silent-miss drift completeness (Property 2) + - **Property 2: Silent-miss drift completeness** + - For any generated schema and config, the set of silent-miss findings equals exactly the union of unknown-metric findings and unknown-sheet findings + - Use fast-check with arbitrary generators for schema and config objects + - Minimum 100 iterations + - **Validates: Requirements 4.1, 4.2, 4.3** + + - [ ]* 3.4 Write property test: Cosmetic drift completeness (Property 3) + - **Property 3: Cosmetic drift completeness** + - For any generated schema and config, the set of cosmetic findings equals exactly the union of new-column findings and stale-metric findings + - Use fast-check with arbitrary generators for schema and config objects + - Minimum 100 iterations + - **Validates: Requirements 5.1, 5.2, 5.3** + + - [ ]* 3.5 Write property test: Drift severity ordering (Property 4) + - **Property 4: Drift severity ordering** + - For any drift report, the grouped output always returns all breaking findings first, then all silent-miss, then all cosmetic + - Use fast-check to generate mixed drift reports and verify ordering + - Minimum 100 iterations + - **Validates: Requirements 8.1** + + - [ ]* 3.6 Write unit tests for drift checker and config loader + - Test each drift rule individually with hand-crafted schema/config pairs + - Test config loader with valid file, missing file, invalid JSON, and missing required keys + - Test that perfectly aligned schema and config produce zero findings + - Test edge cases: empty metric_categories, empty core_cols, empty skip_sheets + - _Requirements: 3.1, 3.2, 3.3, 4.1, 4.2, 4.3, 5.1, 5.2, 5.3, 1.5, 1.6_ + +- [x] 4. Checkpoint — Verify backend modules + - Ensure all tests pass, ask the user if questions arise. + +- [x] 5. Integrate drift check into preview endpoint + - [x] 5.1 Modify `backend/routes/compliance.js` to add drift checking in `POST /preview` + - After receiving the uploaded file, spawn `extract_xlsx_schema.py` as a Python subprocess to get the xlsx schema + - Read `compliance_config.json` using the `loadConfig()` function from `driftChecker.js` + - Call `compareSchemaToDrift(schema, config)` to produce the drift report + - Proceed with the existing `parseXlsx()` call and `computeDiff()` + - Include `drift` (DriftReport object) and `drift_error` (string or null) in the response + - If schema extraction or drift check throws, set `drift: null` and `drift_error: `, then continue with normal flow + - If config file is missing or invalid, return 500 with descriptive message + - Preserve all existing response fields: `diff`, `tempFile`, `filename`, `report_date`, `total_items` + - _Requirements: 6.1, 6.2, 6.3, 6.4, 9.2_ + + - [ ]* 5.2 Write integration tests for preview endpoint drift behavior + - Test that preview response includes `drift` field alongside existing `diff` data + - Test that breaking drift still returns 200 (not an error) + - Test graceful degradation when drift check fails (`drift: null`, `drift_error` present) + - Test 500 response when config file is missing + - Test that commit endpoint is unchanged and does not reference drift + - _Requirements: 6.1, 6.2, 6.3, 6.4, 9.3_ + +- [x] 6. Update upload modal with drift-review phase + - [x] 6.1 Modify `frontend/src/components/pages/ComplianceUploadModal.js` to add drift-review phase + - Add `drift-review` phase between `uploading` and `preview` in the phase flow + - After upload response, check if `drift` is non-null and has findings — if so, enter `drift-review`; otherwise skip to `preview` + - When `drift` is `null` (drift check failed), skip drift-review and go straight to preview + - Display findings grouped by severity: breaking first, then silent-miss, then cosmetic + - Each severity group has a header with label and count badge + - Groups with more than 5 findings collapse with a "Show N more" toggle + - Each finding shows the message and the triggering value + - Breaking findings: red text (`#EF4444`), red left-border accent + - Silent-miss findings: amber text (`#F59E0B`), amber left-border accent + - Cosmetic findings: muted text (`#94A3B8`), subtle left-border accent + - "Cancel" button returns to idle phase; "Continue to Preview" button advances to diff preview + - "Continue to Preview" disabled when breaking findings exist, with a message explaining the block + - When no breaking findings but silent-miss exist, show warning message and enable "Continue to Preview" + - When only cosmetic findings, enable "Continue to Preview" without warning + - Follow dashboard dark theme and monospace typography from `DESIGN_SYSTEM.md` + - Preserve existing diff preview, commit flow, done, and error phases unchanged + - _Requirements: 7.1, 7.2, 7.3, 7.4, 7.5, 7.6, 7.7, 7.8, 8.1, 8.2, 8.3, 8.4, 8.5, 8.6, 9.1, 9.4_ + + - [ ]* 6.2 Write unit tests for upload modal drift-review phase + - Test drift-review phase renders when findings exist + - Test "Continue to Preview" button disabled when breaking findings present + - Test "Continue to Preview" button enabled when no breaking findings + - Test groups collapse at 5+ findings with correct "Show N more" count + - Test cancel returns to idle phase + - Test skips drift-review when drift is null or has no findings + - _Requirements: 7.1, 7.5, 7.6, 7.7, 7.8, 8.3_ + +- [x] 7. Final checkpoint — Ensure all tests pass + - Ensure all tests pass, ask the user if questions arise. + +## Notes + +- Tasks marked with `*` are optional and can be skipped for faster MVP +- Each task references specific requirements for traceability +- Checkpoints ensure incremental validation +- Property tests (3.2–3.5) validate the four correctness properties from the design using fast-check +- Unit tests validate specific examples and edge cases +- The Python parser modification (1.2) must produce identical output to the current inline-dict version — this is a refactor, not a behavior change +- The commit endpoint (`POST /api/compliance/commit`) is intentionally unchanged diff --git a/backend/cve_database.db.backupNVD b/backend/cve_database.db.backupNVD new file mode 100644 index 0000000..7d45c73 Binary files /dev/null and b/backend/cve_database.db.backupNVD differ diff --git a/backend/helpers/driftChecker.js b/backend/helpers/driftChecker.js new file mode 100644 index 0000000..427a1de --- /dev/null +++ b/backend/helpers/driftChecker.js @@ -0,0 +1,332 @@ +// Drift Checker — compares xlsx schema against parser config to detect structural drift +// Returns categorised findings: breaking, silent_miss, cosmetic + +const fs = require('fs'); +const path = require('path'); + +/** + * Load and validate the compliance parser configuration file. + * @param {string} configPath — absolute or relative path to compliance_config.json + * @returns {object} parsed config with metric_categories, core_cols, skip_sheets + * @throws {Error} descriptive error if file missing, invalid JSON, or missing required keys + */ +function loadConfig(configPath) { + let raw; + try { + raw = fs.readFileSync(configPath, 'utf8'); + } catch (err) { + if (err.code === 'ENOENT') { + throw new Error(`Configuration file not found: ${configPath}`); + } + throw new Error(`Failed to read configuration file: ${err.message}`); + } + + let config; + try { + config = JSON.parse(raw); + } catch (err) { + throw new Error(`Configuration file contains invalid JSON: ${err.message}`); + } + + if (!config.metric_categories || typeof config.metric_categories !== 'object' || Array.isArray(config.metric_categories)) { + throw new Error('Configuration file is missing required key "metric_categories" (must be an object)'); + } + if (!Array.isArray(config.core_cols)) { + throw new Error('Configuration file is missing required key "core_cols" (must be an array)'); + } + if (!Array.isArray(config.skip_sheets)) { + throw new Error('Configuration file is missing required key "skip_sheets" (must be an array)'); + } + + return config; +} + +/** + * Compare an xlsx schema against the parser config and produce a drift report. + * @param {object} schema — output of extract_xlsx_schema.py: { sheets: [{ name, columns, metric_values? }] } + * @param {object} config — parsed compliance_config.json: { metric_categories, core_cols, skip_sheets } + * @returns {{ breaking: Array, silent_miss: Array, cosmetic: Array }} + */ +function compareSchemaToDrift(schema, config) { + const breaking = []; + const silent_miss = []; + const cosmetic = []; + + const metricCategoryKeys = new Set(Object.keys(config.metric_categories)); + const coreCols = new Set(config.core_cols); + const skipSheets = new Set(config.skip_sheets); + + // Build lookup of xlsx sheet names and find the Summary sheet + const xlsxSheetNames = new Set(); + let summarySheet = null; + + for (const sheet of schema.sheets) { + xlsxSheetNames.add(sheet.name); + if (sheet.name === 'Summary') { + summarySheet = sheet; + } + } + + // Identify detail sheets: present in xlsx AND not in skip_sheets + const detailSheets = schema.sheets.filter(s => !skipSheets.has(s.name)); + + // Build set of metric values from the Summary sheet (used by multiple rules) + const summaryMetrics = new Set( + (summarySheet && Array.isArray(summarySheet.metric_values)) ? summarySheet.metric_values : [] + ); + + // --- Breaking rules --- + + // Missing core column: a detail sheet is missing a column from core_cols. + // Collect per-column stats first, then classify: if a column is missing from + // ALL detail sheets it's breaking. If missing from only some (e.g. 5.8.1 uses + // CMDB columns), it's cosmetic — the parser handles it via extra_json. + const coreColMissingMap = {}; // col -> [sheet names missing it] + for (const sheet of detailSheets) { + const sheetCols = new Set(sheet.columns || []); + for (const coreCol of config.core_cols) { + if (!sheetCols.has(coreCol)) { + if (!coreColMissingMap[coreCol]) coreColMissingMap[coreCol] = []; + coreColMissingMap[coreCol].push(sheet.name); + } + } + } + + for (const coreCol of Object.keys(coreColMissingMap)) { + const missingSheets = coreColMissingMap[coreCol]; + if (detailSheets.length > 0 && missingSheets.length >= detailSheets.length) { + // Missing from ALL detail sheets — genuinely breaking + breaking.push({ + severity: 'breaking', + message: `Core column "${coreCol}" is missing from all ${detailSheets.length} detail sheet(s)`, + value: coreCol, + sheet: null + }); + } else { + // Missing from some sheets — structural difference, not drift + cosmetic.push({ + severity: 'cosmetic', + message: `Core column "${coreCol}" is missing from ${missingSheets.length} of ${detailSheets.length} detail sheet(s): ${missingSheets.join(', ')}`, + value: coreCol, + sheet: null + }); + } + } + + // Missing detail sheet: a sheet in metric_categories (not in skip_sheets) is absent from xlsx. + // If the metric still appears in the Summary's metric_values, it's tracked but has zero + // violations this week — downgrade to cosmetic instead of breaking. + for (const metricKey of metricCategoryKeys) { + if (!skipSheets.has(metricKey) && !xlsxSheetNames.has(metricKey)) { + if (summaryMetrics.has(metricKey)) { + cosmetic.push({ + severity: 'cosmetic', + message: `Metric "${metricKey}" has no detail sheet this week — still tracked in Summary (zero violations)`, + value: metricKey, + sheet: null + }); + } else { + breaking.push({ + severity: 'breaking', + message: `Expected detail sheet "${metricKey}" (metric category) is missing from the workbook`, + value: metricKey, + sheet: null + }); + } + } + } + + // --- Silent-miss rules --- + + // Unknown metric value: a metric value in Summary is not a key in metric_categories + if (summarySheet && Array.isArray(summarySheet.metric_values)) { + for (const metricVal of summarySheet.metric_values) { + if (!metricCategoryKeys.has(metricVal)) { + silent_miss.push({ + severity: 'silent_miss', + message: `Unknown metric "${metricVal}" in Summary — not in metric_categories`, + value: metricVal, + sheet: 'Summary' + }); + } + } + } + + // Unknown sheet: an xlsx sheet not in skip_sheets and not in metric_categories + for (const sheet of schema.sheets) { + if (!skipSheets.has(sheet.name) && !metricCategoryKeys.has(sheet.name)) { + silent_miss.push({ + severity: 'silent_miss', + message: `Unknown sheet "${sheet.name}" — not in skip_sheets or metric_categories`, + value: sheet.name, + sheet: sheet.name + }); + } + } + + // --- Cosmetic rules --- + + // New column in detail sheet: a detail sheet has columns not in core_cols + for (const sheet of detailSheets) { + for (const col of (sheet.columns || [])) { + if (!coreCols.has(col)) { + cosmetic.push({ + severity: 'cosmetic', + message: `New column "${col}" in sheet "${sheet.name}" — will be captured in extra_json`, + value: col, + sheet: sheet.name + }); + } + } + } + + // Stale metric category: a key in metric_categories not in Summary metric values + for (const metricKey of metricCategoryKeys) { + if (!summaryMetrics.has(metricKey)) { + cosmetic.push({ + severity: 'cosmetic', + message: `Stale metric category "${metricKey}" — not found in Summary sheet metric values`, + value: metricKey, + sheet: null + }); + } + } + + return { breaking, silent_miss, cosmetic }; +} + +/** + * Reconcile the parser config to resolve breaking drift findings. + * + * Breaking — "missing detail sheet": + * A metric_categories key has no matching xlsx sheet. But if the metric + * still appears in the Summary sheet's metric_values, it's a legitimate + * tracked metric that simply doesn't have violations this week — keep it. + * Only remove metrics absent from BOTH the xlsx sheets AND the Summary. + * + * Breaking — "missing core column": + * A core_cols entry is absent from one or more detail sheets. Only remove + * if the column is missing from ALL detail sheets (some sheets like 5.8.1 + * have a completely different column structure and shouldn't cause removal). + * + * Silent-miss — "unknown metric": + * A metric value in the Summary is not in metric_categories. Add it as 'Other'. + * + * Silent-miss — "unknown sheet": + * Left as a warning. Auto-adding unknown sheets creates a reconcile loop. + * + * @param {string} configPath — path to compliance_config.json + * @param {object} driftReport — the drift report from compareSchemaToDrift() + * @param {object} [schema] — optional xlsx schema (with sheets[].name and Summary metric_values) + * @returns {{ changes: Array<{ action: string, key: string, value: string }>, config: object }} + */ +function reconcileConfig(configPath, driftReport, schema) { + const config = loadConfig(configPath); + const changes = []; + + // Build a set of metric values from the Summary sheet (if schema provided) + const summaryMetrics = new Set(); + if (schema && Array.isArray(schema.sheets)) { + const summarySheet = schema.sheets.find(function(s) { return s.name === 'Summary'; }); + if (summarySheet && Array.isArray(summarySheet.metric_values)) { + summarySheet.metric_values.forEach(function(v) { summaryMetrics.add(v); }); + } + } + + // Build a set of xlsx sheet names (if schema provided) + const xlsxSheetNames = new Set(); + if (schema && Array.isArray(schema.sheets)) { + schema.sheets.forEach(function(s) { xlsxSheetNames.add(s.name); }); + } + + // Count how many detail sheets exist in the xlsx (excluding skip_sheets) + const skipSheets = new Set(config.skip_sheets); + const detailSheetCount = schema + ? schema.sheets.filter(function(s) { return !skipSheets.has(s.name); }).length + : 0; + + // --- Resolve breaking findings --- + + for (const finding of (driftReport.breaking || [])) { + // Missing detail sheet: remove from metric_categories ONLY if the metric + // is also absent from the Summary's metric_values. If it's in the Summary, + // it's still a tracked metric — the sheet just has zero violations this week. + if (finding.message.includes('is missing from the workbook') && finding.value in config.metric_categories) { + if (summaryMetrics.has(finding.value)) { + // Metric is in the Summary — keep it, just note it's sheet-less this week + changes.push({ + action: 'kept', + key: 'metric_categories', + value: finding.value, + detail: `Kept metric "${finding.value}" — no detail sheet this week but still tracked in Summary` + }); + } else { + const oldCategory = config.metric_categories[finding.value]; + delete config.metric_categories[finding.value]; + changes.push({ + action: 'removed', + key: 'metric_categories', + value: finding.value, + detail: `Removed stale metric category "${finding.value}" (was "${oldCategory}") — absent from both workbook sheets and Summary` + }); + } + } + + // Missing core column: only remove if the column is missing from ALL detail sheets. + // Some sheets (e.g. 5.8.1 with CMDB columns) have a completely different structure + // and shouldn't cause removal of columns that exist in most other sheets. + if (finding.message.includes('is missing core column') && config.core_cols.includes(finding.value)) { + if (!changes.some(function(c) { return c.key === 'core_cols' && c.value === finding.value; })) { + const missingFromCount = (driftReport.breaking || []).filter( + function(f) { return f.message.includes('is missing core column') && f.value === finding.value; } + ).length; + + if (detailSheetCount > 0 && missingFromCount >= detailSheetCount) { + // Missing from ALL detail sheets — safe to remove + config.core_cols = config.core_cols.filter(function(c) { return c !== finding.value; }); + changes.push({ + action: 'removed', + key: 'core_cols', + value: finding.value, + detail: `Removed core column "${finding.value}" — missing from all ${detailSheetCount} detail sheet(s)` + }); + } else { + // Missing from some sheets but present in others — keep it + changes.push({ + action: 'kept', + key: 'core_cols', + value: finding.value, + detail: `Kept core column "${finding.value}" — missing from ${missingFromCount} of ${detailSheetCount} detail sheet(s)` + }); + } + } + } + } + + // --- Resolve silent-miss findings --- + + for (const finding of (driftReport.silent_miss || [])) { + // Unknown metric in Summary: add to metric_categories as 'Other' + if (finding.message.includes('not in metric_categories') && !(finding.value in config.metric_categories)) { + config.metric_categories[finding.value] = 'Other'; + changes.push({ + action: 'added', + key: 'metric_categories', + value: finding.value, + detail: `Added new metric "${finding.value}" to metric_categories as "Other"` + }); + } + + // Unknown sheet: left as a warning — auto-adding creates a reconcile loop. + } + + // Only write if there were actual config mutations (not just 'kept' entries) + const hasMutations = changes.some(function(c) { return c.action !== 'kept'; }); + if (hasMutations) { + fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n', 'utf8'); + } + + return { changes, config }; +} + +module.exports = { compareSchemaToDrift, loadConfig, reconcileConfig }; diff --git a/backend/routes/compliance.js b/backend/routes/compliance.js index c0535c3..d61de7a 100644 --- a/backend/routes/compliance.js +++ b/backend/routes/compliance.js @@ -2,25 +2,35 @@ // Handles xlsx upload/parse, non-compliant item history, and notes. // // Endpoints: -// POST /preview — parse xlsx, compute diff vs DB, return summary (no DB write) -// POST /commit — commit a previewed upload to DB -// GET /uploads — list all uploads -// GET /summary — metric health cards for a team (from latest upload) -// GET /items — non-compliant devices grouped by hostname (?team=X&status=active) -// GET /items/:hostname — detail panel: all metrics + notes + upload history for a device -// POST /notes — add a note to one or more (hostname, metric_id) pairs +// POST /preview — parse xlsx, run drift check, compute diff (no DB write) +// POST /reconcile-config — patch compliance_config.json to resolve drift findings +// POST /commit — commit a previewed upload to DB +// GET /uploads — list all uploads +// POST /rollback/:uploadId — roll back the most recent upload (Admin only) +// GET /summary — metric health cards for a team (from latest upload) +// GET /items — non-compliant devices grouped by hostname (?team=X&status=active) +// GET /items/:hostname — detail panel: all metrics + notes + upload history for a device +// POST /notes — add a note to one or more (hostname, metric_id) pairs // GET /notes/:hostname/:metricId — notes for a specific device+metric +// GET /trends — per-upload totals + per-team counts for time-series charts +// GET /mttr — mean time to resolution per team +// GET /top-recurring — chronic compliance gaps sorted by seen_count +// GET /category-trend — active counts per category per upload for stacked area chart const express = require('express'); const path = require('path'); const fs = require('fs'); const crypto = require('crypto'); const { spawn } = require('child_process'); +const { loadConfig, compareSchemaToDrift, reconcileConfig } = require('../helpers/driftChecker'); +const logAudit = require('../helpers/auditLog'); -const PARSER_SCRIPT = path.join(__dirname, '../scripts/parse_compliance_xlsx.py'); -const PYTHON_BIN = process.env.PYTHON_BIN || 'python3'; -const TEMP_DIR = path.join(process.cwd(), 'uploads', 'temp'); -const ALLOWED_TEAMS = new Set(['STEAM', 'ACCESS-ENG', 'ACCESS-OPS', 'INTELDEV']); +const PARSER_SCRIPT = path.join(__dirname, '../scripts/parse_compliance_xlsx.py'); +const SCHEMA_SCRIPT = path.join(__dirname, '../scripts/extract_xlsx_schema.py'); +const CONFIG_PATH = path.join(__dirname, '..', 'scripts', 'compliance_config.json'); +const PYTHON_BIN = process.env.PYTHON_BIN || 'python3'; +const TEMP_DIR = path.join(process.cwd(), 'uploads', 'temp'); +const ALLOWED_TEAMS = new Set(['STEAM', 'ACCESS-ENG', 'ACCESS-OPS', 'INTELDEV']); // --------------------------------------------------------------------------- // DB helpers @@ -63,6 +73,25 @@ function parseXlsx(filePath) { }); } +// --------------------------------------------------------------------------- +// Run Python schema extractor, return xlsx schema object +// --------------------------------------------------------------------------- +function extractXlsxSchema(filePath) { + return new Promise((resolve, reject) => { + const py = spawn(PYTHON_BIN, [SCHEMA_SCRIPT, filePath]); + let out = ''; + let err = ''; + py.stdout.on('data', d => { out += d; }); + py.stderr.on('data', d => { err += d; }); + py.on('close', code => { + if (code !== 0) return reject(new Error(err || `Schema extractor exited with code ${code}`)); + try { resolve(JSON.parse(out)); } + catch (e) { reject(new Error('Schema extractor returned invalid JSON')); } + }); + py.on('error', reject); + }); +} + // --------------------------------------------------------------------------- // Validate that a temp file path is safely within uploads/temp/ // --------------------------------------------------------------------------- @@ -228,6 +257,15 @@ function createComplianceRouter(db, upload, requireAuth, requireGroup) { // POST /preview // Parse the uploaded xlsx, compute diff, save parsed data to a temp JSON. // Returns diff counts + tempFile path for the commit step. + // + // Body: multipart/form-data with `file` field (xlsx) + // Response: { + // drift: { breaking: [], silent_miss: [], cosmetic: [] } | null, + // drift_error: string | null, + // diff: { new_count, recurring_count, resolved_count }, + // tempFile: string, filename: string, + // report_date: string, total_items: number + // } // ----------------------------------------------------------------------- router.post('/preview', requireGroup('Admin', 'Standard_User'), (req, res) => { upload.single('file')(req, res, async (uploadErr) => { @@ -243,6 +281,31 @@ function createComplianceRouter(db, upload, requireAuth, requireGroup) { } try { + // --- Drift check: load config, extract schema, compare --- + let drift = null; + let drift_error = null; + + let config; + try { + config = loadConfig(CONFIG_PATH); + } catch (configErr) { + fs.unlink(req.file.path, () => {}); + return res.status(500).json({ error: 'Configuration file could not be loaded: ' + configErr.message }); + } + + let xlsxSchema = null; + try { + xlsxSchema = await extractXlsxSchema(req.file.path); + if (xlsxSchema.error) { + throw new Error(xlsxSchema.error); + } + drift = compareSchemaToDrift(xlsxSchema, config); + } catch (driftErr) { + drift = null; + drift_error = driftErr.message || 'Drift check failed'; + } + + // --- Existing parse flow --- const parsed = await parseXlsx(req.file.path); if (parsed.error) { @@ -268,6 +331,9 @@ function createComplianceRouter(db, upload, requireAuth, requireGroup) { fs.unlink(req.file.path, () => {}); res.json({ + drift, + drift_error, + schema: xlsxSchema, diff: { new_count: diff.newCount, recurring_count: diff.recurringCount, @@ -287,10 +353,63 @@ function createComplianceRouter(db, upload, requireAuth, requireGroup) { }); }); + // ----------------------------------------------------------------------- + // POST /reconcile-config + // Admin-only. Patches compliance_config.json to resolve breaking and + // silent-miss drift findings, then re-runs the drift check and returns + // the updated report. Logs every change to the audit trail. + // + // Body: { drift: { breaking: [...], silent_miss: [...] } } + // Response: { changes: [{ action, key, value, detail }], message: string } + // ----------------------------------------------------------------------- + router.post('/reconcile-config', requireGroup('Admin'), async (req, res) => { + const { drift, schema } = req.body; + + if (!drift || typeof drift !== 'object') { + return res.status(400).json({ error: 'drift report is required in request body' }); + } + + const hasFindings = (drift.breaking && drift.breaking.length > 0) || + (drift.silent_miss && drift.silent_miss.length > 0); + if (!hasFindings) { + return res.status(400).json({ error: 'No breaking or silent-miss findings to reconcile' }); + } + + try { + const { changes } = reconcileConfig(CONFIG_PATH, drift, schema || null); + + if (changes.length === 0) { + return res.json({ changes: [], message: 'No changes needed' }); + } + + // Audit log each change + for (const change of changes) { + logAudit(db, { + userId: req.user.id, + username: req.user.username, + action: 'compliance_config_reconcile', + entityType: 'compliance_config', + entityId: change.value, + details: { action: change.action, key: change.key, detail: change.detail }, + ipAddress: req.ip, + }); + } + + res.json({ changes, message: `Reconciled ${changes.length} config change(s)` }); + + } catch (err) { + console.error('[Compliance] Reconcile config error:', err.message); + res.status(500).json({ error: 'Failed to reconcile config: ' + err.message }); + } + }); + // ----------------------------------------------------------------------- // POST /commit // Commit a previewed upload to the DB. - // Body: { tempFile, filename, report_date } + // + // Body: { tempFile: string, filename: string, report_date: string } + // Response: { upload: { id, filename, report_date, uploaded_at, + // new_count, resolved_count, recurring_count } } // ----------------------------------------------------------------------- router.post('/commit', requireGroup('Admin', 'Standard_User'), async (req, res) => { const { tempFile, filename, report_date } = req.body; @@ -341,6 +460,9 @@ function createComplianceRouter(db, upload, requireAuth, requireGroup) { // ----------------------------------------------------------------------- // GET /uploads // List all uploads, most recent first. + // + // Response: { uploads: [{ id, filename, report_date, uploaded_at, + // new_count, resolved_count, recurring_count }] } // ----------------------------------------------------------------------- router.get('/uploads', async (req, res) => { try { @@ -357,9 +479,133 @@ function createComplianceRouter(db, upload, requireAuth, requireGroup) { } }); + // ----------------------------------------------------------------------- + // POST /rollback/:uploadId + // Admin-only. Rolls back a specific upload. Only the most recent upload + // can be rolled back to avoid cascading data integrity issues. + // + // Params: uploadId — integer ID of the upload to roll back + // Response: { message: string, rolled_back: { upload_id, filename, + // report_date, items_deleted, items_reactivated } } + // + // Reversal logic: + // 1. Delete items first seen in this upload (new items) + // 2. Re-activate items resolved by this upload + // 3. Revert recurring items: decrement seen_count, point upload_id + // back to the previous upload + // 4. Delete the upload record + // ----------------------------------------------------------------------- + router.post('/rollback/:uploadId', requireGroup('Admin'), async (req, res) => { + const uploadId = parseInt(req.params.uploadId, 10); + if (isNaN(uploadId)) { + return res.status(400).json({ error: 'Invalid upload ID' }); + } + + try { + // Verify the upload exists + const upload = await dbGet(db, + `SELECT id, filename, report_date, new_count, resolved_count, recurring_count + FROM compliance_uploads WHERE id = ?`, + [uploadId] + ); + if (!upload) { + return res.status(404).json({ error: 'Upload not found' }); + } + + // Only allow rolling back the most recent upload + const latest = await dbGet(db, + `SELECT id FROM compliance_uploads ORDER BY id DESC LIMIT 1` + ); + if (latest.id !== uploadId) { + return res.status(400).json({ + error: 'Only the most recent upload can be rolled back', + latest_upload_id: latest.id + }); + } + + // Find the previous upload (to restore recurring items' upload_id) + const previousUpload = await dbGet(db, + `SELECT id FROM compliance_uploads WHERE id < ? ORDER BY id DESC LIMIT 1`, + [uploadId] + ); + + await dbRun(db, 'BEGIN TRANSACTION'); + + try { + // 1. Delete items that were NEW in this upload + const deleteNew = await dbRun(db, + `DELETE FROM compliance_items WHERE first_seen_upload_id = ? AND upload_id = ?`, + [uploadId, uploadId] + ); + + // 2. Re-activate items that were RESOLVED by this upload + const reactivate = await dbRun(db, + `UPDATE compliance_items + SET status = 'active', resolved_upload_id = NULL + WHERE resolved_upload_id = ?`, + [uploadId] + ); + + // 3. Revert RECURRING items: decrement seen_count, restore upload_id + if (previousUpload) { + await dbRun(db, + `UPDATE compliance_items + SET upload_id = ?, seen_count = MAX(seen_count - 1, 1) + WHERE upload_id = ? AND first_seen_upload_id != ?`, + [previousUpload.id, uploadId, uploadId] + ); + } + + // 4. Delete the upload record + await dbRun(db, `DELETE FROM compliance_uploads WHERE id = ?`, [uploadId]); + + await dbRun(db, 'COMMIT'); + + // Audit log + logAudit(db, { + userId: req.user.id, + username: req.user.username, + action: 'compliance_upload_rollback', + entityType: 'compliance_upload', + entityId: String(uploadId), + details: { + filename: upload.filename, + report_date: upload.report_date, + items_deleted: deleteNew.changes, + items_reactivated: reactivate.changes, + }, + ipAddress: req.ip, + }); + + res.json({ + message: `Rolled back upload "${upload.filename}"`, + rolled_back: { + upload_id: uploadId, + filename: upload.filename, + report_date: upload.report_date, + items_deleted: deleteNew.changes, + items_reactivated: reactivate.changes, + }, + }); + + } catch (err) { + await dbRun(db, 'ROLLBACK').catch(() => {}); + throw err; + } + + } catch (err) { + console.error('[Compliance] Rollback error:', err.message); + res.status(500).json({ error: 'Failed to rollback upload: ' + err.message }); + } + }); + // ----------------------------------------------------------------------- // GET /summary?team=STEAM // Return metric health rows for a team from the latest upload's summary_json. + // + // Query: team — optional, one of ALLOWED_TEAMS + // Response: { entries: [...], overall_scores: {}, upload: { id, + // report_date, uploaded_at } | null } // ----------------------------------------------------------------------- router.get('/summary', async (req, res) => { const team = req.query.team; @@ -403,6 +649,12 @@ function createComplianceRouter(db, upload, requireAuth, requireGroup) { // ----------------------------------------------------------------------- // GET /items?team=STEAM&status=active // Return non-compliant devices grouped by hostname. + // + // Query: team — required, one of ALLOWED_TEAMS + // status — optional, 'active' (default) or 'resolved' + // Response: { devices: [{ hostname, ip_address, device_type, team, + // status, failing_metrics, seen_count, first_seen, last_seen, + // resolved_on, has_notes }], team, status } // ----------------------------------------------------------------------- router.get('/items', async (req, res) => { const { team, status = 'active' } = req.query; @@ -448,6 +700,12 @@ function createComplianceRouter(db, upload, requireAuth, requireGroup) { // ----------------------------------------------------------------------- // GET /items/:hostname // Detail panel: all metric rows for this hostname + notes + upload history. + // + // Params: hostname — device hostname string + // Response: { hostname, ip_address, device_type, team, + // metrics: [{ metric_id, metric_desc, category, status, seen_count, + // extra, first_seen, last_seen, resolved_on, ... }], + // notes: [{ id, metric_id, note, group_id, created_at, created_by }] } // ----------------------------------------------------------------------- router.get('/items/:hostname', async (req, res) => { const hostname = req.params.hostname; @@ -519,7 +777,11 @@ function createComplianceRouter(db, upload, requireAuth, requireGroup) { // ----------------------------------------------------------------------- // POST /notes // Add a note to one or more (hostname, metric_id) pairs. - // Body: { hostname, metric_ids: [...], note } — or legacy { hostname, metric_id, note } + // + // Body: { hostname: string, metric_ids: string[], note: string } + // — or legacy: { hostname: string, metric_id: string, note: string } + // Response: { notes: [{ id, hostname, metric_id, note, group_id, + // created_at, created_by }] } // ----------------------------------------------------------------------- router.post('/notes', requireGroup('Admin', 'Standard_User'), async (req, res) => { const { hostname, metric_id, metric_ids, note } = req.body; @@ -602,6 +864,10 @@ function createComplianceRouter(db, upload, requireAuth, requireGroup) { // ----------------------------------------------------------------------- // GET /notes/:hostname/:metricId // Return all notes for a (hostname, metric_id) pair. + // + // Params: hostname — device hostname string + // metricId — metric identifier string + // Response: { notes: [{ id, note, created_at, created_by }] } // ----------------------------------------------------------------------- router.get('/notes/:hostname/:metricId', async (req, res) => { const { hostname, metricId } = req.params; @@ -629,6 +895,10 @@ function createComplianceRouter(db, upload, requireAuth, requireGroup) { // GET /trends // Per-upload active totals + per-team counts for time-series charts. // Returns rows ordered ascending by report_date. + // + // Response: { trends: [{ report_date, new_count, recurring_count, + // resolved_count, total_active, STEAM, ACCESS-ENG, ACCESS-OPS, + // INTELDEV }] } // ----------------------------------------------------------------------- router.get('/trends', async (req, res) => { try { @@ -681,6 +951,8 @@ function createComplianceRouter(db, upload, requireAuth, requireGroup) { // ----------------------------------------------------------------------- // GET /mttr // Mean time to resolution (calendar days) per team, for resolved items. + // + // Response: { mttr: [{ team, avg_days, resolved_count }] } // ----------------------------------------------------------------------- router.get('/mttr', async (req, res) => { try { @@ -709,6 +981,9 @@ function createComplianceRouter(db, upload, requireAuth, requireGroup) { // GET /top-recurring // Active findings grouped by team + metric_id, sorted by seen_count desc. // Identifies chronic compliance gaps that keep reappearing. + // + // Response: { items: [{ team, metric_id, metric_desc, seen_count, + // host_count }] } — limited to top 20 // ----------------------------------------------------------------------- router.get('/top-recurring', async (req, res) => { try { @@ -730,6 +1005,8 @@ function createComplianceRouter(db, upload, requireAuth, requireGroup) { // ----------------------------------------------------------------------- // GET /category-trend // Active item counts per category per upload, for stacked area chart. + // + // Response: { categoryTrend: [{ report_date, category, count }] } // ----------------------------------------------------------------------- router.get('/category-trend', async (req, res) => { try { diff --git a/backend/scripts/__pycache__/extract_xlsx_schema.cpython-312.pyc b/backend/scripts/__pycache__/extract_xlsx_schema.cpython-312.pyc new file mode 100644 index 0000000..5acef26 Binary files /dev/null and b/backend/scripts/__pycache__/extract_xlsx_schema.cpython-312.pyc differ diff --git a/backend/scripts/compliance_config.json b/backend/scripts/compliance_config.json new file mode 100644 index 0000000..368ce81 --- /dev/null +++ b/backend/scripts/compliance_config.json @@ -0,0 +1,44 @@ +{ + "metric_categories": { + "1.1.1": "Logging & Monitoring", + "1.1.3": "Logging & Monitoring", + "1.4.1": "Logging & Monitoring", + "2.3.4i": "Vulnerability Management", + "2.3.6i": "Vulnerability Management", + "2.3.8i": "Vulnerability Management", + "5.2.4": "Access & MFA", + "5.2.5": "Access & MFA", + "5.2.6": "Access & MFA", + "5.2.7": "Access & MFA", + "5.2.8": "Access & MFA", + "5.3.4": "Endpoint Protection", + "5.5.4i": "Vulnerability Management", + "5.5.5": "Decommissioned Assets", + "5.8.1": "Application Security", + "7.1.1": "Logging & Monitoring", + "7.1.4": "Logging & Monitoring", + "7.6.13": "Disaster Recovery", + "7.6.16": "Disaster Recovery", + "Missing_AppID": "Asset Data Quality", + "Missing_DF": "Asset Data Quality", + "Missing_OS": "Asset Data Quality", + "5.5.2": "Other" + }, + "core_cols": [ + "Preferred - Hostname", + "GRANITE - IPv4_Address", + "GRANITE - Type", + "Team", + "Compliant", + "Source_Network", + "Vertical", + "GRANITE - Equip_Inst_ID", + "GRANITE - RESPONSIBLE_TEAM" + ], + "skip_sheets": [ + "Summary", + "CMDB_9box", + "Vulns", + "Aging Dashboard" + ] +} diff --git a/backend/scripts/extract_xlsx_schema.py b/backend/scripts/extract_xlsx_schema.py new file mode 100644 index 0000000..83026ee --- /dev/null +++ b/backend/scripts/extract_xlsx_schema.py @@ -0,0 +1,91 @@ +#!/usr/bin/env python3 +""" +Extract the structural schema of a compliance xlsx file as JSON. +Usage: python3 extract_xlsx_schema.py + +Output: +{ + "sheets": [ + { + "name": "Summary", + "columns": ["Metric", "Non-Compliant", "..."], + "metric_values": ["2.3.4i", "5.2.4", "..."] + }, + { + "name": "2.3.4i", + "columns": ["Preferred - Hostname", "GRANITE - IPv4_Address", "..."] + } + ] +} + +- Uses openpyxl in read-only mode. +- Extracts sheet names, first-row column headers per sheet, and unique metric + values from the Summary sheet (header at row 4, data from row 5 onward). +- On error, returns { "error": "..." } on stdout and exits with non-zero code. + +Dependencies: openpyxl (already in requirements.txt) +""" +import sys +import json +from openpyxl import load_workbook + + +def main(): + if len(sys.argv) < 2: + print(json.dumps({"error": "No file path provided"})) + sys.exit(1) + + filepath = sys.argv[1] + + try: + wb = load_workbook(filepath, read_only=True, data_only=True) + except Exception as e: + print(json.dumps({"error": f"Cannot open file: {str(e)}"})) + sys.exit(1) + + if not wb.sheetnames: + print(json.dumps({"error": "Workbook contains no sheets"})) + wb.close() + sys.exit(1) + + sheets = [] + for sheet_name in wb.sheetnames: + ws = wb[sheet_name] + + # Extract first-row column headers + rows = list(ws.iter_rows(max_row=1, values_only=True)) + columns = [str(c).strip() for c in rows[0] if c is not None] if rows else [] + + entry = { + "name": sheet_name, + "columns": columns, + } + + # Extract metric values from the Summary sheet + # Summary has header at row 4, data from row 5 onward + if sheet_name == "Summary": + metric_values = [] + header_rows = list(ws.iter_rows(min_row=4, max_row=4, values_only=True)) + if header_rows: + summary_cols = [str(c).strip() if c else "" for c in header_rows[0]] + metric_idx = None + for i, col in enumerate(summary_cols): + if col == "Metric": + metric_idx = i + break + if metric_idx is not None: + for row in ws.iter_rows(min_row=5, values_only=True): + if row[metric_idx] is not None: + val = str(row[metric_idx]).strip() + if val and val != "Metric": + metric_values.append(val) + entry["metric_values"] = sorted(set(metric_values)) + + sheets.append(entry) + + wb.close() + print(json.dumps({"sheets": sheets})) + + +if __name__ == "__main__": + main() diff --git a/backend/scripts/parse_compliance_xlsx.py b/backend/scripts/parse_compliance_xlsx.py index a1c5949..16bd3b0 100644 --- a/backend/scripts/parse_compliance_xlsx.py +++ b/backend/scripts/parse_compliance_xlsx.py @@ -12,45 +12,35 @@ Output: } """ import sys +import os import json import re import pandas as pd from pathlib import Path -METRIC_CATEGORIES = { - '2.3.4i': 'Vulnerability Management', - '2.3.6i': 'Vulnerability Management', - '2.3.8i': 'Vulnerability Management', - '5.2.4': 'Access & MFA', - '5.2.5': 'Access & MFA', - '5.2.6': 'Access & MFA', - '5.3.4': 'Endpoint Protection', - '5.5.2': 'End-of-Life OS', - '5.5.4i': 'Vulnerability Management', - '5.5.5': 'Decommissioned Assets', - '5.8.1': 'Application Security', - '7.1.1': 'Logging & Monitoring', - '7.6.13': 'Disaster Recovery', - '7.6.16': 'Disaster Recovery', - '1.1.1': 'Logging & Monitoring', - '1.1.3': 'Logging & Monitoring', - '1.4.1': 'Logging & Monitoring', - '5.2.7': 'Access & MFA', - '5.2.8': 'Access & MFA', - '7.1.4': 'Logging & Monitoring', - 'Missing_AppID': 'Asset Data Quality', - 'Missing_DF': 'Asset Data Quality', - 'Missing_OS': 'Asset Data Quality', -} -# Columns that go into the main item fields — everything else becomes extra_json -CORE_COLS = { - 'Preferred - Hostname', 'GRANITE - IPv4_Address', 'GRANITE - Type', - 'Team', 'Compliant', 'Source_Network', 'Vertical', - 'GRANITE - Equip_Inst_ID', 'GRANITE - RESPONSIBLE_TEAM', -} +def load_config(): + """Load parser configuration from compliance_config.json.""" + script_dir = os.path.dirname(os.path.abspath(__file__)) + config_path = os.path.join(script_dir, 'compliance_config.json') -SKIP_SHEETS = {'Summary', 'CMDB_9box', 'Vulns', 'Aging Dashboard'} + try: + with open(config_path, 'r') as f: + config = json.load(f) + except FileNotFoundError: + print(f"Error: Configuration file not found: {config_path}", file=sys.stderr) + sys.exit(1) + except json.JSONDecodeError as e: + print(f"Error: Invalid JSON in configuration file {config_path}: {e}", file=sys.stderr) + sys.exit(1) + + return config + + +_config = load_config() +METRIC_CATEGORIES = _config['metric_categories'] +CORE_COLS = set(_config['core_cols']) +SKIP_SHEETS = set(_config['skip_sheets']) def safe_str(val): diff --git a/cve_database.db b/cve_database.db new file mode 100644 index 0000000..9240461 Binary files /dev/null and b/cve_database.db differ diff --git a/cve_database.db.backup b/cve_database.db.backup new file mode 100644 index 0000000..e69de29 diff --git a/database.db b/database.db new file mode 100644 index 0000000..e69de29 diff --git a/frontend/src/components/pages/CompliancePage.js b/frontend/src/components/pages/CompliancePage.js index d585b7b..7ec2d1d 100644 --- a/frontend/src/components/pages/CompliancePage.js +++ b/frontend/src/components/pages/CompliancePage.js @@ -1,5 +1,5 @@ import React, { useState, useEffect, useCallback } from 'react'; -import { Upload, MessageSquare, RefreshCw, AlertCircle, Loader } from 'lucide-react'; +import { Upload, MessageSquare, RefreshCw, AlertCircle, Loader, RotateCcw } from 'lucide-react'; import { useAuth } from '../../contexts/AuthContext'; import ComplianceUploadModal from './ComplianceUploadModal'; import ComplianceDetailPanel from './ComplianceDetailPanel'; @@ -143,7 +143,7 @@ function SeenBadge({ count }) { // Main Page // --------------------------------------------------------------------------- export default function CompliancePage({ onNavigate }) { - const { canWrite } = useAuth(); + const { canWrite, isAdmin } = useAuth(); const [activeTeam, setActiveTeam] = useState('STEAM'); const [activeTab, setActiveTab] = useState('active'); @@ -155,6 +155,9 @@ export default function CompliancePage({ onNavigate }) { const [error, setError] = useState(null); const [selectedHost, setSelectedHost] = useState(null); const [showUpload, setShowUpload] = useState(false); + const [rollbackConfirm, setRollbackConfirm] = useState(false); + const [rollbackLoading, setRollbackLoading] = useState(false); + const [rollbackResult, setRollbackResult] = useState(null); const fetchSummary = useCallback(async (team) => { try { @@ -198,6 +201,28 @@ export default function CompliancePage({ onNavigate }) { fetchDevices(activeTeam, activeTab); }; + const handleRollback = async () => { + if (!lastUpload) return; + setRollbackLoading(true); + try { + const res = await fetch(`${API_BASE}/compliance/rollback/${lastUpload.id}`, { + method: 'POST', + credentials: 'include', + }); + const data = await res.json(); + if (!res.ok) throw new Error(data.error || 'Rollback failed'); + setRollbackResult(data); + setRollbackConfirm(false); + refresh(); + // Auto-dismiss result after 4 seconds + setTimeout(() => setRollbackResult(null), 4000); + } catch (err) { + setRollbackResult({ error: err.message }); + } finally { + setRollbackLoading(false); + } + }; + // In-memory filters const filteredDevices = devices .filter(d => !metricFilter || d.failing_metrics.some(m => m.metric_id === metricFilter)) @@ -221,9 +246,30 @@ export default function CompliancePage({ onNavigate }) {
{lastUpload ? ( - - Last report: {lastUpload.report_date || lastUpload.uploaded_at?.slice(0, 10)} - + <> + + Last report: {lastUpload.report_date || lastUpload.uploaded_at?.slice(0, 10)} + + {isAdmin() && ( + + )} + ) : ( No reports uploaded )} @@ -439,6 +485,118 @@ export default function CompliancePage({ onNavigate }) { onUploadComplete={() => { setShowUpload(false); refresh(); }} /> )} + + {/* ── Rollback confirmation modal ──────────────────────────── */} + {rollbackConfirm && lastUpload && ( +
+
+
+ Rollback Upload +
+
+ This will reverse the most recent upload: +
+
+
File: {lastUpload.report_date || 'unknown date'}
+
+ New items will be deleted, resolved items will be reactivated, and the upload record will be removed. +
+
+
+ + +
+
+
+ )} + + {/* ── Rollback result toast ────────────────────────────────── */} + {rollbackResult && ( +
setRollbackResult(null)} + > + {rollbackResult.error ? ( +
+ + {rollbackResult.error} +
+ ) : ( + <> +
+ + {rollbackResult.message} +
+ {rollbackResult.rolled_back && ( +
+ {rollbackResult.rolled_back.items_deleted} items deleted, {rollbackResult.rolled_back.items_reactivated} reactivated +
+ )} + + )} +
+ )}
); } diff --git a/frontend/src/components/pages/ComplianceUploadModal.js b/frontend/src/components/pages/ComplianceUploadModal.js index 120c61f..dd56226 100644 --- a/frontend/src/components/pages/ComplianceUploadModal.js +++ b/frontend/src/components/pages/ComplianceUploadModal.js @@ -1,15 +1,122 @@ import React, { useState, useRef } from 'react'; -import { X, CheckCircle, AlertCircle, Loader, FileSpreadsheet } from 'lucide-react'; +import { X, CheckCircle, AlertCircle, Loader, FileSpreadsheet, ChevronDown, ChevronRight, ShieldAlert, AlertTriangle, Info, Wrench } from 'lucide-react'; +import { useAuth } from '../../contexts/AuthContext'; const API_BASE = process.env.REACT_APP_API_BASE || 'http://localhost:3001/api'; -// phase: idle → uploading → preview → committing → done | error +/* ── Drift Findings Group sub-component ─────────────────────────── */ +const SEVERITY_CONFIG = { + breaking: { label: 'Breaking', color: '#EF4444', Icon: ShieldAlert }, + silent_miss: { label: 'Silent-miss', color: '#F59E0B', Icon: AlertTriangle }, + cosmetic: { label: 'Cosmetic', color: '#94A3B8', Icon: Info }, +}; + +function DriftFindingsGroup({ severity, findings }) { + const [expanded, setExpanded] = useState(false); + const { label, color, Icon } = SEVERITY_CONFIG[severity]; + const COLLAPSE_THRESHOLD = 5; + const needsCollapse = findings.length > COLLAPSE_THRESHOLD; + const visibleFindings = needsCollapse && !expanded + ? findings.slice(0, COLLAPSE_THRESHOLD) + : findings; + const hiddenCount = findings.length - COLLAPSE_THRESHOLD; + + return ( +
+ {/* Group header */} +
+ + + {label} + + + {findings.length} + +
+ + {/* Findings list */} + {visibleFindings.map((f, i) => ( +
+
+ {f.message} +
+
+ {f.value} +
+
+ ))} + + {/* Show more / less toggle */} + {needsCollapse && ( + + )} +
+ ); +} + +// phase: idle → uploading → drift-review (if findings) → preview → committing → done | error export default function ComplianceUploadModal({ onClose, onUploadComplete }) { - const [phase, setPhase] = useState('idle'); - const [previewData, setPreviewData] = useState(null); - const [error, setError] = useState(null); - const [dragOver, setDragOver] = useState(false); - const fileInputRef = useRef(null); + const { isAdmin } = useAuth(); + const [phase, setPhase] = useState('idle'); + const [previewData, setPreviewData] = useState(null); + const [driftReport, setDriftReport] = useState(null); + const [reconcileChanges, setReconcileChanges] = useState(null); + const [reconciling, setReconciling] = useState(false); + const [error, setError] = useState(null); + const [dragOver, setDragOver] = useState(false); + const [lastFile, setLastFile] = useState(null); + const [lastSchema, setLastSchema] = useState(null); + const fileInputRef = useRef(null); + + /** Check whether a drift report has any findings */ + const hasDriftFindings = (drift) => { + if (!drift) return false; + return ( + (drift.breaking && drift.breaking.length > 0) || + (drift.silent_miss && drift.silent_miss.length > 0) || + (drift.cosmetic && drift.cosmetic.length > 0) + ); + }; const handleFile = async (file) => { if (!file) return; @@ -20,6 +127,9 @@ export default function ComplianceUploadModal({ onClose, onUploadComplete }) { setPhase('uploading'); setError(null); + setDriftReport(null); + setReconcileChanges(null); + setLastFile(file); try { const formData = new FormData(); @@ -37,7 +147,20 @@ export default function ComplianceUploadModal({ onClose, onUploadComplete }) { } setPreviewData(data); - setPhase('preview'); + + // Store schema for reconcile requests + if (data.schema) { + setLastSchema(data.schema); + } + + // Drift routing: if drift is non-null and has findings, enter drift-review + // If drift is null (failed) or has no findings, skip to preview + if (data.drift && hasDriftFindings(data.drift)) { + setDriftReport(data.drift); + setPhase('drift-review'); + } else { + setPhase('preview'); + } } catch (err) { setError(err.message); setPhase('error'); @@ -72,6 +195,70 @@ export default function ComplianceUploadModal({ onClose, onUploadComplete }) { } }; + /** Admin-only: reconcile config to fix breaking/silent-miss drift, then re-upload */ + const handleReconcile = async () => { + if (!driftReport || reconciling) return; + setReconciling(true); + setError(null); + + try { + // Step 1: Call reconcile endpoint + const reconcileRes = await fetch(`${API_BASE}/compliance/reconcile-config`, { + method: 'POST', + credentials: 'include', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ drift: driftReport, schema: lastSchema }), + }); + const reconcileData = await reconcileRes.json(); + + if (!reconcileRes.ok) throw new Error(reconcileData.error || 'Reconcile failed'); + + setReconcileChanges(reconcileData.changes); + + // Step 2: Re-upload the same file to get a fresh drift check + if (!lastFile) { + setReconciling(false); + return; + } + + setPhase('uploading'); + + const formData = new FormData(); + formData.append('file', lastFile); + + const previewRes = await fetch(`${API_BASE}/compliance/preview`, { + method: 'POST', + credentials: 'include', + body: formData, + }); + const previewData = await previewRes.json(); + + if (!previewRes.ok) { + throw new Error(previewData.error || 'Re-upload failed after reconcile'); + } + + setPreviewData(previewData); + setReconciling(false); + + // Update schema for any subsequent reconcile + if (previewData.schema) { + setLastSchema(previewData.schema); + } + + if (previewData.drift && hasDriftFindings(previewData.drift)) { + setDriftReport(previewData.drift); + setPhase('drift-review'); + } else { + setDriftReport(null); + setPhase('preview'); + } + } catch (err) { + setError(err.message); + setReconciling(false); + setPhase('error'); + } + }; + const TEAL = '#14B8A6'; return ( @@ -87,7 +274,10 @@ export default function ComplianceUploadModal({ onClose, onUploadComplete }) { border: `1px solid ${TEAL}40`, borderRadius: '0.75rem', boxShadow: `0 20px 60px rgba(0,0,0,0.7), 0 0 40px ${TEAL}15`, - width: '100%', maxWidth: '480px', + width: '100%', maxWidth: phase === 'drift-review' ? '560px' : '480px', + maxHeight: 'calc(100vh - 2rem)', + overflowY: 'auto', + transition: 'max-width 0.3s ease', padding: '2rem', }}> {/* Header */} @@ -148,6 +338,163 @@ export default function ComplianceUploadModal({ onClose, onUploadComplete }) {
)} + {/* DRIFT-REVIEW — schema drift findings */} + {phase === 'drift-review' && driftReport && ( + <> +
+ Schema Drift Review +
+ +
+ {driftReport.breaking && driftReport.breaking.length > 0 && ( + + )} + {driftReport.silent_miss && driftReport.silent_miss.length > 0 && ( + + )} + {driftReport.cosmetic && driftReport.cosmetic.length > 0 && ( + + )} +
+ + {/* Status message */} + {driftReport.breaking && driftReport.breaking.length > 0 && ( +
+ {isAdmin() + ? 'Upload blocked — use "Reconcile Config" to auto-fix the parser configuration, or update it manually.' + : 'Upload blocked — an admin must reconcile the parser configuration before this report can be uploaded.'} +
+ )} + {(!driftReport.breaking || driftReport.breaking.length === 0) && + driftReport.silent_miss && driftReport.silent_miss.length > 0 && ( +
+ Review warnings before proceeding. Data may be miscategorised or dropped. + {isAdmin() && ' Use "Reconcile Config" to auto-add unknown metrics and sheets.'} +
+ )} + + {/* Reconcile changes summary (shown after a successful reconcile) */} + {reconcileChanges && reconcileChanges.length > 0 && ( +
+
+ Config reconciled — {reconcileChanges.length} change(s) applied: +
+ {reconcileChanges.map((c, i) => ( +
+ {c.action === 'added' ? '+' : '−'} {c.detail} +
+ ))} +
Re-uploading file…
+
+ )} + + {/* Action buttons */} +
+ + {/* Admin reconcile button — shown when there are breaking or silent-miss findings */} + {isAdmin() && ((driftReport.breaking && driftReport.breaking.length > 0) || + (driftReport.silent_miss && driftReport.silent_miss.length > 0)) && ( + + )} + +
+ + )} + {/* PREVIEW — diff summary + confirm */} {phase === 'preview' && previewData && ( <> diff --git a/run_audit_tests.sh b/run_audit_tests.sh new file mode 100755 index 0000000..8891547 --- /dev/null +++ b/run_audit_tests.sh @@ -0,0 +1,1078 @@ +#!/bin/bash +# ============================================================================= +# Audit Logging Feature - Automated Test Script +# Covers test plan sections 1-7, 12-14 (backend + database) +# Sections 8-11 (frontend UI) require manual browser testing +# ============================================================================= +# +# Usage: +# ./run_audit_tests.sh [options] +# +# Options: +# --api-base URL Backend API base URL (default: http://localhost:3001/api) +# --db PATH Path to SQLite database file (default: backend/cve_database.db) +# --admin-pass PASS Admin password (default: admin123) +# --help Show this help message +# +# Prerequisites: +# - curl, jq, sqlite3 must be installed on this machine +# - Backend must be running with the audit feature branch deployed +# - Admin account "admin" must exist +# ============================================================================= + +set -euo pipefail + +# ── Defaults ────────────────────────────────────────────────────────────────── +API_BASE="http://localhost:3001/api" +DB_PATH="backend/cve_database.db" +ADMIN_PASS="admin123" + +# ── Parse arguments ────────────────────────────────────────────────────────── +while [[ $# -gt 0 ]]; do + case $1 in + --api-base) API_BASE="$2"; shift 2 ;; + --db) DB_PATH="$2"; shift 2 ;; + --admin-pass) ADMIN_PASS="$2"; shift 2 ;; + --help) + sed -n '2,/^# ====.*$/p' "$0" | sed 's/^# \?//' + exit 0 + ;; + *) echo "Unknown option: $1"; exit 1 ;; + esac +done + +# ── Colours & counters ─────────────────────────────────────────────────────── +GREEN='\033[0;32m' +RED='\033[0;31m' +YELLOW='\033[1;33m' +CYAN='\033[0;36m' +BOLD='\033[1m' +NC='\033[0m' + +PASS_COUNT=0 +FAIL_COUNT=0 +SKIP_COUNT=0 +TOTAL=0 + +TMPDIR_TEST=$(mktemp -d) +ADMIN_JAR="$TMPDIR_TEST/admin.cookies" +EDITOR_JAR="$TMPDIR_TEST/editor.cookies" +VIEWER_JAR="$TMPDIR_TEST/viewer.cookies" + +cleanup() { + rm -rf "$TMPDIR_TEST" +} +trap cleanup EXIT + +# ── Helpers ────────────────────────────────────────────────────────────────── + +pass() { + PASS_COUNT=$((PASS_COUNT + 1)) + TOTAL=$((TOTAL + 1)) + echo -e " ${GREEN}PASS${NC} $1" +} + +fail() { + FAIL_COUNT=$((FAIL_COUNT + 1)) + TOTAL=$((TOTAL + 1)) + echo -e " ${RED}FAIL${NC} $1" + if [[ -n "${2:-}" ]]; then + echo -e " ${RED}-> $2${NC}" + fi +} + +skip() { + SKIP_COUNT=$((SKIP_COUNT + 1)) + TOTAL=$((TOTAL + 1)) + echo -e " ${YELLOW}SKIP${NC} $1 -- $2" +} + +section() { + echo "" + echo -e "${CYAN}${BOLD}── $1 ──${NC}" +} + +sql() { + sqlite3 "$DB_PATH" "$1" +} + +# Login and store session cookie in a jar file +# Usage: login_as +# Returns: HTTP status code +login_as() { + local user="$1" pass="$2" jar="$3" + curl -s -o "$TMPDIR_TEST/login_resp.json" -w "%{http_code}" \ + -c "$jar" \ + -X POST "$API_BASE/auth/login" \ + -H "Content-Type: application/json" \ + -d "{\"username\":\"$user\",\"password\":\"$pass\"}" +} + +# Authenticated GET request +# Usage: api_get [extra_curl_args...] +api_get() { + local path="$1" jar="$2" + shift 2 + curl -s -b "$jar" "$@" "$API_BASE$path" +} + +# Authenticated POST request with JSON body +api_post() { + local path="$1" jar="$2" body="$3" + shift 3 + curl -s -b "$jar" -X POST "$API_BASE$path" \ + -H "Content-Type: application/json" \ + -d "$body" "$@" +} + +# Authenticated PATCH request with JSON body +api_patch() { + local path="$1" jar="$2" body="$3" + shift 3 + curl -s -b "$jar" -X PATCH "$API_BASE$path" \ + -H "Content-Type: application/json" \ + -d "$body" "$@" +} + +# Authenticated DELETE request +api_delete() { + local path="$1" jar="$2" + shift 2 + curl -s -b "$jar" -X DELETE "$API_BASE$path" "$@" +} + +# Get HTTP status code for an authenticated request +api_status() { + local method="$1" path="$2" jar="$3" + shift 3 + curl -s -o /dev/null -w "%{http_code}" -b "$jar" -X "$method" "$API_BASE$path" "$@" +} + +# Get the most recent audit log row matching a condition +latest_audit() { + local where="$1" + sql "SELECT id, user_id, username, action, entity_type, entity_id, details, ip_address FROM audit_logs WHERE $where ORDER BY id DESC LIMIT 1;" +} + +# Count audit rows matching a condition +count_audit() { + local where="$1" + sql "SELECT COUNT(*) FROM audit_logs WHERE $where;" +} + +# Record the current max audit log id so we can look at entries created after this point +mark_audit() { + AUDIT_MARK=$(sql "SELECT COALESCE(MAX(id),0) FROM audit_logs;") +} + +# Get audit rows created after the mark +audit_since() { + local where="${1:-1=1}" + sql "SELECT id, user_id, username, action, entity_type, entity_id, details, ip_address FROM audit_logs WHERE id > $AUDIT_MARK AND ($where) ORDER BY id DESC;" +} + +count_audit_since() { + local where="${1:-1=1}" + sql "SELECT COUNT(*) FROM audit_logs WHERE id > $AUDIT_MARK AND ($where);" +} + +# ============================================================================= +# PREFLIGHT CHECKS +# ============================================================================= +echo "" +echo -e "${BOLD}Audit Logging Feature - Automated Test Runner${NC}" +echo "==============================================" +echo "API Base : $API_BASE" +echo "DB Path : $DB_PATH" +echo "" + +PREFLIGHT_OK=true + +for cmd in curl jq sqlite3; do + if ! command -v "$cmd" &>/dev/null; then + echo -e "${RED}Missing dependency: $cmd${NC}" + PREFLIGHT_OK=false + fi +done + +if [[ ! -f "$DB_PATH" ]]; then + echo -e "${RED}Database file not found: $DB_PATH${NC}" + PREFLIGHT_OK=false +fi + +# Check backend is reachable +if ! curl -s --max-time 5 -o /dev/null "$API_BASE/../" 2>/dev/null; then + # Try the base URL directly + if ! curl -s --max-time 5 -o /dev/null "${API_BASE%/api}" 2>/dev/null; then + echo -e "${RED}Backend not reachable at $API_BASE${NC}" + PREFLIGHT_OK=false + fi +fi + +if [[ "$PREFLIGHT_OK" != "true" ]]; then + echo "" + echo "Fix the above issues and re-run." + exit 1 +fi + +echo -e "${GREEN}Preflight checks passed.${NC}" + +# ============================================================================= +# SECTION 1: Database & Schema +# ============================================================================= +section "1. Database & Schema" + +# 1.1 audit_logs table exists with correct columns +TABLE_SQL=$(sql "SELECT sql FROM sqlite_master WHERE name='audit_logs';") +if [[ -n "$TABLE_SQL" ]]; then + MISSING="" + for col in id user_id username action entity_type entity_id details ip_address created_at; do + if ! echo "$TABLE_SQL" | grep -qi "$col"; then + MISSING="$MISSING $col" + fi + done + if [[ -z "$MISSING" ]]; then + pass "1.1 audit_logs table exists with all columns" + else + fail "1.1 audit_logs table missing columns:$MISSING" + fi +else + fail "1.1 audit_logs table does not exist" "Table not found in sqlite_master" +fi + +# 1.2 Indexes created +INDEXES=$(sql "SELECT name FROM sqlite_master WHERE type='index' AND name LIKE 'idx_audit%' ORDER BY name;") +EXPECTED_INDEXES="idx_audit_action idx_audit_created_at idx_audit_entity_type idx_audit_user_id" +FOUND_INDEXES=$(echo "$INDEXES" | tr '\n' ' ' | xargs) +if [[ "$FOUND_INDEXES" == "$EXPECTED_INDEXES" ]]; then + pass "1.2 All four audit indexes exist" +else + fail "1.2 Audit indexes" "Expected: $EXPECTED_INDEXES | Found: $FOUND_INDEXES" +fi + +# 1.3 Migration idempotency - check that migrate script exists +if [[ -f "backend/migrate-audit-log.js" ]]; then + pass "1.3 Migration script exists (idempotency requires manual run)" +else + skip "1.3 Migration idempotency" "migrate-audit-log.js not found at expected path" +fi + +# 1.4 Migration creates backups - check script exists (actual backup test is manual) +if [[ -f "backend/migrate-audit-log.js" ]] && grep -q "backup" "backend/migrate-audit-log.js"; then + pass "1.4 Migration script contains backup logic" +else + skip "1.4 Migration backup" "Cannot verify without running migration" +fi + +# 1.5 Setup includes audit_logs +if [[ -f "backend/setup.js" ]] && grep -q "audit_logs" "backend/setup.js"; then + pass "1.5 setup.js references audit_logs table" +else + skip "1.5 Setup includes audit_logs" "setup.js not found or missing reference" +fi + +# ============================================================================= +# Login as admin for subsequent tests +# ============================================================================= +section "Setup: Authenticate test accounts" + +mark_audit + +ADMIN_STATUS=$(login_as "admin" "$ADMIN_PASS" "$ADMIN_JAR") +if [[ "$ADMIN_STATUS" != "200" ]]; then + echo -e "${RED}FATAL: Cannot log in as admin (HTTP $ADMIN_STATUS). Aborting.${NC}" + exit 1 +fi +echo -e " ${GREEN}OK${NC} Admin login successful" + +# Create editor1 and viewer1 if they don't exist +EDITOR_EXISTS=$(sql "SELECT COUNT(*) FROM users WHERE username='_test_editor1';") +if [[ "$EDITOR_EXISTS" == "0" ]]; then + api_post "/users" "$ADMIN_JAR" '{"username":"_test_editor1","email":"editor1@test.local","password":"editor123","role":"editor"}' > /dev/null + echo " Created test account: _test_editor1 (editor)" +fi + +VIEWER_EXISTS=$(sql "SELECT COUNT(*) FROM users WHERE username='_test_viewer1';") +if [[ "$VIEWER_EXISTS" == "0" ]]; then + api_post "/users" "$ADMIN_JAR" '{"username":"_test_viewer1","email":"viewer1@test.local","password":"viewer123","role":"viewer"}' > /dev/null + echo " Created test account: _test_viewer1 (viewer)" +fi + +EDITOR_STATUS=$(login_as "_test_editor1" "editor123" "$EDITOR_JAR") +if [[ "$EDITOR_STATUS" != "200" ]]; then + echo -e "${RED}FATAL: Cannot log in as _test_editor1 (HTTP $EDITOR_STATUS). Aborting.${NC}" + exit 1 +fi +echo -e " ${GREEN}OK${NC} Editor login successful" + +VIEWER_STATUS=$(login_as "_test_viewer1" "viewer123" "$VIEWER_JAR") +if [[ "$VIEWER_STATUS" != "200" ]]; then + echo -e "${RED}FATAL: Cannot log in as _test_viewer1 (HTTP $VIEWER_STATUS). Aborting.${NC}" + exit 1 +fi +echo -e " ${GREEN}OK${NC} Viewer login successful" + +# Small sleep to let fire-and-forget audit inserts complete +sleep 0.5 + +# ============================================================================= +# SECTION 2: Authentication Audit Logging +# ============================================================================= +section "2. Authentication Audit Logging" + +# 2.1 Successful login logged +ROW=$(latest_audit "action='login' AND username='admin'") +if [[ -n "$ROW" ]] && echo "$ROW" | grep -q "login"; then + # Check details contain role + DETAILS=$(echo "$ROW" | awk -F'|' '{print $7}') + if echo "$DETAILS" | jq -e '.role' &>/dev/null; then + pass "2.1 Successful login logged with role in details" + else + fail "2.1 Login logged but details missing role" "$DETAILS" + fi +else + fail "2.1 No login audit entry found for admin" +fi + +# 2.2 Failed login - wrong password +mark_audit +login_as "admin" "wrongpass" "$TMPDIR_TEST/throwaway.cookies" > /dev/null +sleep 0.3 +ROW=$(audit_since "action='login_failed' AND username='admin'") +if [[ -n "$ROW" ]]; then + DETAILS=$(echo "$ROW" | awk -F'|' '{print $7}') + if echo "$DETAILS" | grep -q "invalid_password"; then + pass "2.2 Failed login (wrong password) logged with reason" + else + fail "2.2 Failed login logged but reason missing" "$DETAILS" + fi +else + fail "2.2 No login_failed audit entry for wrong password" +fi + +# 2.3 Failed login - unknown user +mark_audit +login_as "nonexistent_user_xyz" "anypass" "$TMPDIR_TEST/throwaway.cookies" > /dev/null +sleep 0.3 +ROW=$(audit_since "action='login_failed' AND username='nonexistent_user_xyz'") +if [[ -n "$ROW" ]]; then + USER_ID_VAL=$(echo "$ROW" | awk -F'|' '{print $2}') + DETAILS=$(echo "$ROW" | awk -F'|' '{print $7}') + if [[ -z "$USER_ID_VAL" ]] && echo "$DETAILS" | grep -q "user_not_found"; then + pass "2.3 Failed login (unknown user) logged with null user_id" + else + fail "2.3 Unknown user login logged but data unexpected" "user_id=$USER_ID_VAL details=$DETAILS" + fi +else + fail "2.3 No login_failed audit entry for unknown user" +fi + +# 2.4 Failed login - disabled account +mark_audit +# Create a temp user, disable them, try to log in +api_post "/users" "$ADMIN_JAR" '{"username":"_test_disabled","email":"disabled@test.local","password":"test123","role":"viewer"}' > /dev/null +DISABLED_ID=$(sql "SELECT id FROM users WHERE username='_test_disabled';") +if [[ -n "$DISABLED_ID" ]]; then + api_patch "/users/$DISABLED_ID" "$ADMIN_JAR" '{"is_active":false}' > /dev/null + sleep 0.3 + mark_audit + login_as "_test_disabled" "test123" "$TMPDIR_TEST/throwaway.cookies" > /dev/null + sleep 0.3 + ROW=$(audit_since "action='login_failed' AND username='_test_disabled'") + if [[ -n "$ROW" ]]; then + DETAILS=$(echo "$ROW" | awk -F'|' '{print $7}') + if echo "$DETAILS" | grep -q "account_disabled"; then + pass "2.4 Failed login (disabled account) logged with reason" + else + fail "2.4 Disabled login logged but reason wrong" "$DETAILS" + fi + else + fail "2.4 No login_failed entry for disabled account" + fi + # Cleanup + api_delete "/users/$DISABLED_ID" "$ADMIN_JAR" > /dev/null +else + skip "2.4 Failed login - disabled account" "Could not create test user" +fi + +# 2.5 Logout logged +mark_audit +# Login fresh, then logout +login_as "admin" "$ADMIN_PASS" "$TMPDIR_TEST/logout_test.cookies" > /dev/null +sleep 0.2 +curl -s -b "$TMPDIR_TEST/logout_test.cookies" -X POST "$API_BASE/auth/logout" > /dev/null +sleep 0.3 +ROW=$(audit_since "action='logout' AND username='admin'") +if [[ -n "$ROW" ]]; then + pass "2.5 Logout logged" +else + fail "2.5 No logout audit entry found" +fi + +# 2.6 Fire-and-forget (tested more thoroughly in section 12) +skip "2.6 Login does not block on audit error" "Requires corrupting audit_logs table (see section 12)" + +# ============================================================================= +# SECTION 3: CVE Operation Audit Logging +# ============================================================================= +section "3. CVE Operation Audit Logging" + +TEST_CVE_ID="CVE-2025-AUDIT-$(date +%s)" + +# 3.1 CVE create logged +mark_audit +api_post "/cves" "$ADMIN_JAR" "{\"cve_id\":\"$TEST_CVE_ID\",\"vendor\":\"TestVendor\",\"severity\":\"Critical\",\"description\":\"Automated test CVE\",\"published_date\":\"2025-01-01\"}" > /dev/null +sleep 0.3 +ROW=$(audit_since "action='cve_create' AND entity_id='$TEST_CVE_ID'") +if [[ -n "$ROW" ]]; then + DETAILS=$(echo "$ROW" | awk -F'|' '{print $7}') + if echo "$DETAILS" | jq -e '.vendor' &>/dev/null && echo "$DETAILS" | jq -e '.severity' &>/dev/null; then + pass "3.1 CVE create logged with vendor and severity in details" + else + fail "3.1 CVE create logged but details incomplete" "$DETAILS" + fi +else + fail "3.1 No cve_create audit entry found" +fi + +# 3.2 CVE status update logged +mark_audit +STATUS_RESP=$(api_patch "/cves/$TEST_CVE_ID/status" "$ADMIN_JAR" '{"status":"Addressed"}') +sleep 0.3 +ROW=$(audit_since "action='cve_update_status' AND entity_id='$TEST_CVE_ID'") +if [[ -n "$ROW" ]]; then + DETAILS=$(echo "$ROW" | awk -F'|' '{print $7}') + if echo "$DETAILS" | grep -q "Addressed"; then + pass "3.2 CVE status update logged with status in details" + else + fail "3.2 CVE status update logged but status missing from details" "$DETAILS" + fi +else + # Check if the PATCH itself succeeded + if echo "$STATUS_RESP" | jq -e '.error' &>/dev/null 2>&1; then + fail "3.2 CVE status update" "PATCH failed: $(echo "$STATUS_RESP" | jq -r '.error')" + else + fail "3.2 No cve_update_status audit entry found" + fi +fi + +# 3.3 CVE status update bug fix (no SQL error with vendor reference) +STATUS_CODE=$(curl -s -o /dev/null -w "%{http_code}" -b "$ADMIN_JAR" -X PATCH "$API_BASE/cves/$TEST_CVE_ID/status" \ + -H "Content-Type: application/json" -d '{"status":"In Progress"}') +if [[ "$STATUS_CODE" == "200" ]]; then + pass "3.3 CVE status update completes without SQL error (vendor bug fixed)" +else + fail "3.3 CVE status update returned HTTP $STATUS_CODE" +fi + +# 3.4 Audit captures acting user +mark_audit +EDITOR_CVE_ID="CVE-2025-EDIT-$(date +%s)" +api_post "/cves" "$EDITOR_JAR" "{\"cve_id\":\"$EDITOR_CVE_ID\",\"vendor\":\"EditorVendor\",\"severity\":\"Low\",\"description\":\"Editor test CVE\",\"published_date\":\"2025-01-01\"}" > /dev/null +sleep 0.3 +ROW=$(audit_since "action='cve_create' AND entity_id='$EDITOR_CVE_ID'") +if [[ -n "$ROW" ]]; then + ACTOR=$(echo "$ROW" | awk -F'|' '{print $3}') + if [[ "$ACTOR" == "_test_editor1" ]]; then + pass "3.4 Audit captures acting user (_test_editor1)" + else + fail "3.4 Wrong acting user on CVE create" "Expected _test_editor1, got $ACTOR" + fi +else + fail "3.4 No cve_create audit entry for editor CVE" +fi + +# ============================================================================= +# SECTION 4: Document Operation Audit Logging +# ============================================================================= +section "4. Document Operation Audit Logging" + +# Create a small test file for upload +echo "test document content" > "$TMPDIR_TEST/test_advisory.txt" + +# 4.1 Document upload logged +mark_audit +UPLOAD_RESP=$(curl -s -b "$ADMIN_JAR" -X POST "$API_BASE/cves/$TEST_CVE_ID/documents" \ + -F "file=@$TMPDIR_TEST/test_advisory.txt" \ + -F "type=advisory" \ + -F "vendor=TestVendor" \ + -F "notes=Automated test upload") +sleep 0.3 +UPLOAD_DOC_ID=$(echo "$UPLOAD_RESP" | jq -r '.id // empty') +ROW=$(audit_since "action='document_upload' AND entity_id='$TEST_CVE_ID'") +if [[ -n "$ROW" ]]; then + pass "4.1 Document upload logged" +else + if [[ -z "$UPLOAD_DOC_ID" ]]; then + fail "4.1 Document upload" "Upload itself failed: $UPLOAD_RESP" + else + fail "4.1 No document_upload audit entry found" + fi +fi + +# 4.2 Document delete logged +if [[ -n "$UPLOAD_DOC_ID" ]]; then + mark_audit + api_delete "/documents/$UPLOAD_DOC_ID" "$ADMIN_JAR" > /dev/null + sleep 0.3 + ROW=$(audit_since "action='document_delete'") + if [[ -n "$ROW" ]]; then + pass "4.2 Document delete logged" + else + fail "4.2 No document_delete audit entry found" + fi +else + skip "4.2 Document delete logging" "No document ID from upload step" +fi + +# 4.3 Upload captures file metadata +mark_audit +UPLOAD_RESP2=$(curl -s -b "$ADMIN_JAR" -X POST "$API_BASE/cves/$TEST_CVE_ID/documents" \ + -F "file=@$TMPDIR_TEST/test_advisory.txt;filename=advisory.pdf" \ + -F "type=advisory" \ + -F "vendor=TestVendor" \ + -F "notes=metadata test") +sleep 0.3 +UPLOAD_DOC_ID2=$(echo "$UPLOAD_RESP2" | jq -r '.id // empty') +ROW=$(audit_since "action='document_upload' AND entity_id='$TEST_CVE_ID'") +if [[ -n "$ROW" ]]; then + DETAILS=$(echo "$ROW" | awk -F'|' '{print $7}') + HAS_VENDOR=$(echo "$DETAILS" | jq -e '.vendor' 2>/dev/null) + HAS_TYPE=$(echo "$DETAILS" | jq -e '.type' 2>/dev/null) + HAS_FILE=$(echo "$DETAILS" | jq -e '.filename' 2>/dev/null) + if [[ -n "$HAS_VENDOR" && -n "$HAS_TYPE" && -n "$HAS_FILE" ]]; then + pass "4.3 Upload details contain vendor, type, and filename" + else + fail "4.3 Upload details incomplete" "$DETAILS" + fi +else + fail "4.3 No document_upload audit entry for metadata test" +fi +# Cleanup doc +if [[ -n "$UPLOAD_DOC_ID2" ]]; then + api_delete "/documents/$UPLOAD_DOC_ID2" "$ADMIN_JAR" > /dev/null +fi + +# ============================================================================= +# SECTION 5: User Management Audit Logging +# ============================================================================= +section "5. User Management Audit Logging" + +# 5.1 User create logged +mark_audit +CREATE_RESP=$(api_post "/users" "$ADMIN_JAR" '{"username":"_test_audituser","email":"audituser@test.local","password":"pass123","role":"viewer"}') +TESTUSER_ID=$(echo "$CREATE_RESP" | jq -r '.user.id // empty') +sleep 0.3 +ROW=$(audit_since "action='user_create'") +if [[ -n "$ROW" ]]; then + DETAILS=$(echo "$ROW" | awk -F'|' '{print $7}') + if echo "$DETAILS" | grep -q "_test_audituser" && echo "$DETAILS" | grep -q "viewer"; then + pass "5.1 User create logged with username and role" + else + fail "5.1 User create logged but details incomplete" "$DETAILS" + fi +else + fail "5.1 No user_create audit entry found" +fi + +# 5.2 User role update logged +if [[ -n "$TESTUSER_ID" ]]; then + mark_audit + api_patch "/users/$TESTUSER_ID" "$ADMIN_JAR" '{"role":"editor"}' > /dev/null + sleep 0.3 + ROW=$(audit_since "action='user_update'") + if [[ -n "$ROW" ]]; then + DETAILS=$(echo "$ROW" | awk -F'|' '{print $7}') + if echo "$DETAILS" | grep -q '"role":"editor"'; then + pass "5.2 User role update logged" + else + fail "5.2 User update logged but role missing from details" "$DETAILS" + fi + else + fail "5.2 No user_update audit entry found" + fi +else + skip "5.2 User role update" "No test user ID" +fi + +# 5.3 User password change logged (password itself NOT logged) +if [[ -n "$TESTUSER_ID" ]]; then + mark_audit + api_patch "/users/$TESTUSER_ID" "$ADMIN_JAR" '{"password":"newpass456"}' > /dev/null + sleep 0.3 + ROW=$(audit_since "action='user_update'") + if [[ -n "$ROW" ]]; then + DETAILS=$(echo "$ROW" | awk -F'|' '{print $7}') + if echo "$DETAILS" | grep -q '"password_changed":true'; then + # Ensure actual password is NOT in details + if echo "$DETAILS" | grep -q "newpass456"; then + fail "5.3 Password change logged but PASSWORD IS IN DETAILS (security issue)" "$DETAILS" + else + pass "5.3 Password change logged with password_changed:true (password not exposed)" + fi + else + fail "5.3 Password change logged but password_changed flag missing" "$DETAILS" + fi + else + fail "5.3 No user_update audit entry for password change" + fi +else + skip "5.3 Password change logging" "No test user ID" +fi + +# 5.4 Multiple field update logged +if [[ -n "$TESTUSER_ID" ]]; then + mark_audit + api_patch "/users/$TESTUSER_ID" "$ADMIN_JAR" '{"username":"_test_audituser_renamed","role":"viewer"}' > /dev/null + sleep 0.3 + ROW=$(audit_since "action='user_update'") + if [[ -n "$ROW" ]]; then + DETAILS=$(echo "$ROW" | awk -F'|' '{print $7}') + HAS_USERNAME=$(echo "$DETAILS" | jq -e '.username' 2>/dev/null) + HAS_ROLE=$(echo "$DETAILS" | jq -e '.role' 2>/dev/null) + if [[ -n "$HAS_USERNAME" && -n "$HAS_ROLE" ]]; then + pass "5.4 Multiple field update logged with all changed fields" + else + fail "5.4 Multi-field update logged but fields missing" "$DETAILS" + fi + else + fail "5.4 No user_update audit entry for multi-field change" + fi + # Rename back for later tests + api_patch "/users/$TESTUSER_ID" "$ADMIN_JAR" '{"username":"_test_audituser"}' > /dev/null + sleep 0.2 +else + skip "5.4 Multiple field update" "No test user ID" +fi + +# 5.6 User deactivation logged (testing before 5.5 delete so user still exists) +if [[ -n "$TESTUSER_ID" ]]; then + mark_audit + api_patch "/users/$TESTUSER_ID" "$ADMIN_JAR" '{"is_active":false}' > /dev/null + sleep 0.3 + ROW=$(audit_since "action='user_update'") + if [[ -n "$ROW" ]]; then + DETAILS=$(echo "$ROW" | awk -F'|' '{print $7}') + if echo "$DETAILS" | grep -q '"is_active":false'; then + pass "5.6 User deactivation logged with is_active:false" + else + fail "5.6 Deactivation logged but is_active field missing" "$DETAILS" + fi + else + fail "5.6 No user_update audit entry for deactivation" + fi + # Re-activate for delete test + api_patch "/users/$TESTUSER_ID" "$ADMIN_JAR" '{"is_active":true}' > /dev/null + sleep 0.2 +else + skip "5.6 User deactivation" "No test user ID" +fi + +# 5.5 User delete logged +if [[ -n "$TESTUSER_ID" ]]; then + mark_audit + api_delete "/users/$TESTUSER_ID" "$ADMIN_JAR" > /dev/null + sleep 0.3 + ROW=$(audit_since "action='user_delete'") + if [[ -n "$ROW" ]]; then + DETAILS=$(echo "$ROW" | awk -F'|' '{print $7}') + if echo "$DETAILS" | grep -q "_test_audituser"; then + pass "5.5 User delete logged with deleted_username" + else + fail "5.5 User delete logged but username missing from details" "$DETAILS" + fi + else + fail "5.5 No user_delete audit entry found" + fi +else + skip "5.5 User delete" "No test user ID" +fi + +# 5.7 Self-delete prevented, no log +mark_audit +ADMIN_ID=$(sql "SELECT id FROM users WHERE username='admin';") +SELF_DEL_STATUS=$(curl -s -o /dev/null -w "%{http_code}" -b "$ADMIN_JAR" -X DELETE "$API_BASE/users/$ADMIN_ID") +sleep 0.3 +SELF_DEL_LOG=$(count_audit_since "action='user_delete' AND entity_id='$ADMIN_ID'") +if [[ "$SELF_DEL_STATUS" == "400" && "$SELF_DEL_LOG" == "0" ]]; then + pass "5.7 Self-delete prevented (400) with no audit entry" +elif [[ "$SELF_DEL_STATUS" != "400" ]]; then + fail "5.7 Self-delete returned HTTP $SELF_DEL_STATUS (expected 400)" +else + fail "5.7 Self-delete blocked but audit entry was still created" +fi + +# ============================================================================= +# SECTION 6: API Access Control +# ============================================================================= +section "6. API Access Control" + +# 6.1 Admin can query audit logs +RESP=$(api_get "/audit-logs" "$ADMIN_JAR") +if echo "$RESP" | jq -e '.logs' &>/dev/null && echo "$RESP" | jq -e '.pagination' &>/dev/null; then + pass "6.1 Admin can query audit logs (200 with logs + pagination)" +else + fail "6.1 Admin audit log query" "Response: $(echo "$RESP" | head -c 200)" +fi + +# 6.2 Editor denied audit logs +EDITOR_AL_STATUS=$(api_status "GET" "/audit-logs" "$EDITOR_JAR") +if [[ "$EDITOR_AL_STATUS" == "403" ]]; then + pass "6.2 Editor denied audit logs (403)" +else + fail "6.2 Editor audit log access returned HTTP $EDITOR_AL_STATUS (expected 403)" +fi + +# 6.3 Viewer denied audit logs +VIEWER_AL_STATUS=$(api_status "GET" "/audit-logs" "$VIEWER_JAR") +if [[ "$VIEWER_AL_STATUS" == "403" ]]; then + pass "6.3 Viewer denied audit logs (403)" +else + fail "6.3 Viewer audit log access returned HTTP $VIEWER_AL_STATUS (expected 403)" +fi + +# 6.4 Unauthenticated denied +UNAUTH_STATUS=$(curl -s -o /dev/null -w "%{http_code}" "$API_BASE/audit-logs") +if [[ "$UNAUTH_STATUS" == "401" ]]; then + pass "6.4 Unauthenticated denied audit logs (401)" +else + fail "6.4 Unauthenticated audit log access returned HTTP $UNAUTH_STATUS (expected 401)" +fi + +# 6.5 Admin can get actions list +ACTIONS_RESP=$(api_get "/audit-logs/actions" "$ADMIN_JAR") +if echo "$ACTIONS_RESP" | jq -e 'type == "array"' &>/dev/null; then + pass "6.5 Admin can get actions list (array returned)" +else + fail "6.5 Actions list" "Response: $(echo "$ACTIONS_RESP" | head -c 200)" +fi + +# 6.6 Non-admin denied actions list +EDITOR_ACTIONS_STATUS=$(api_status "GET" "/audit-logs/actions" "$EDITOR_JAR") +if [[ "$EDITOR_ACTIONS_STATUS" == "403" ]]; then + pass "6.6 Non-admin denied actions list (403)" +else + fail "6.6 Editor actions list returned HTTP $EDITOR_ACTIONS_STATUS (expected 403)" +fi + +# ============================================================================= +# SECTION 7: API Filtering & Pagination +# ============================================================================= +section "7. API Filtering & Pagination" + +# 7.1 Default pagination +RESP=$(api_get "/audit-logs" "$ADMIN_JAR") +PAGE=$(echo "$RESP" | jq -r '.pagination.page') +LIMIT=$(echo "$RESP" | jq -r '.pagination.limit') +LOG_COUNT=$(echo "$RESP" | jq '.logs | length') +TOTAL_COUNT=$(echo "$RESP" | jq -r '.pagination.total') +if [[ "$PAGE" == "1" && "$LIMIT" == "25" && "$LOG_COUNT" -le 25 ]]; then + pass "7.1 Default pagination (page=1, limit=25, logs<=$LIMIT)" +else + fail "7.1 Default pagination" "page=$PAGE limit=$LIMIT log_count=$LOG_COUNT" +fi + +# 7.2 Custom page size +RESP=$(api_get "/audit-logs?limit=5" "$ADMIN_JAR") +LOG_COUNT=$(echo "$RESP" | jq '.logs | length') +LIMIT=$(echo "$RESP" | jq -r '.pagination.limit') +if [[ "$LIMIT" == "5" && "$LOG_COUNT" -le 5 ]]; then + pass "7.2 Custom page size (limit=5)" +else + fail "7.2 Custom page size" "limit=$LIMIT log_count=$LOG_COUNT" +fi + +# 7.3 Page size capped at 100 +RESP=$(api_get "/audit-logs?limit=999" "$ADMIN_JAR") +LIMIT=$(echo "$RESP" | jq -r '.pagination.limit') +if [[ "$LIMIT" -le 100 ]]; then + pass "7.3 Page size capped at 100 (got limit=$LIMIT)" +else + fail "7.3 Page size cap" "limit=$LIMIT (expected <=100)" +fi + +# 7.4 Navigate to page 2 +RESP_P1=$(api_get "/audit-logs?limit=5&page=1" "$ADMIN_JAR") +RESP_P2=$(api_get "/audit-logs?limit=5&page=2" "$ADMIN_JAR") +P1_FIRST=$(echo "$RESP_P1" | jq -r '.logs[0].id // empty') +P2_FIRST=$(echo "$RESP_P2" | jq -r '.logs[0].id // empty') +P2_PAGE=$(echo "$RESP_P2" | jq -r '.pagination.page') +if [[ -n "$P2_FIRST" && "$P1_FIRST" != "$P2_FIRST" && "$P2_PAGE" == "2" ]]; then + pass "7.4 Page 2 returns different entries" +elif [[ -z "$P2_FIRST" ]]; then + skip "7.4 Navigate to page 2" "Not enough entries for 2 pages at limit=5" +else + fail "7.4 Page 2 entries same as page 1" +fi + +# 7.5 Filter by username +RESP=$(api_get "/audit-logs?user=admin" "$ADMIN_JAR") +NON_ADMIN=$(echo "$RESP" | jq '[.logs[] | select(.username != "admin" and (.username | test("admin") | not))] | length') +if [[ "$NON_ADMIN" == "0" ]]; then + pass "7.5 Filter by username=admin returns only admin entries" +else + fail "7.5 Username filter" "$NON_ADMIN non-admin entries returned" +fi + +# 7.6 Partial username match +RESP=$(api_get "/audit-logs?user=adm" "$ADMIN_JAR") +HAS_ADMIN=$(echo "$RESP" | jq '[.logs[] | select(.username == "admin")] | length') +if [[ "$HAS_ADMIN" -gt 0 ]]; then + pass "7.6 Partial username match (adm matches admin)" +else + fail "7.6 Partial username match found no admin entries" +fi + +# 7.7 Filter by action +RESP=$(api_get "/audit-logs?action=login" "$ADMIN_JAR") +NON_LOGIN=$(echo "$RESP" | jq '[.logs[] | select(.action != "login")] | length') +if [[ "$NON_LOGIN" == "0" ]]; then + pass "7.7 Filter by action=login returns only login entries" +else + fail "7.7 Action filter" "$NON_LOGIN non-login entries returned" +fi + +# 7.8 Filter by entity type +RESP=$(api_get "/audit-logs?entityType=auth" "$ADMIN_JAR") +NON_AUTH=$(echo "$RESP" | jq '[.logs[] | select(.entity_type != "auth")] | length') +if [[ "$NON_AUTH" == "0" ]]; then + pass "7.8 Filter by entityType=auth returns only auth entries" +else + fail "7.8 Entity type filter" "$NON_AUTH non-auth entries returned" +fi + +# 7.9 Filter by date range +TODAY=$(date +%Y-%m-%d) +RESP=$(api_get "/audit-logs?startDate=$TODAY&endDate=$TODAY" "$ADMIN_JAR") +LOG_COUNT=$(echo "$RESP" | jq '.logs | length') +if [[ "$LOG_COUNT" -gt 0 ]]; then + pass "7.9 Date range filter returns entries for today ($LOG_COUNT entries)" +else + fail "7.9 Date range filter returned 0 entries for today" +fi + +# 7.10 Combined filters +RESP=$(api_get "/audit-logs?user=admin&action=login&entityType=auth" "$ADMIN_JAR") +ALL_MATCH=$(echo "$RESP" | jq '[.logs[] | select(.action == "login" and .entity_type == "auth" and (.username | test("admin")))] | length') +TOTAL_RETURNED=$(echo "$RESP" | jq '.logs | length') +if [[ "$TOTAL_RETURNED" -gt 0 && "$ALL_MATCH" == "$TOTAL_RETURNED" ]]; then + pass "7.10 Combined filters return only matching entries ($TOTAL_RETURNED)" +elif [[ "$TOTAL_RETURNED" == "0" ]]; then + fail "7.10 Combined filters returned 0 entries" +else + fail "7.10 Combined filters" "$ALL_MATCH of $TOTAL_RETURNED matched all criteria" +fi + +# 7.11 Empty result set +RESP=$(api_get "/audit-logs?user=zzz_no_such_user_zzz" "$ADMIN_JAR") +LOG_COUNT=$(echo "$RESP" | jq '.logs | length') +TOTAL_VAL=$(echo "$RESP" | jq -r '.pagination.total') +if [[ "$LOG_COUNT" == "0" && "$TOTAL_VAL" == "0" ]]; then + pass "7.11 Empty result set returns logs:[] and total:0" +else + fail "7.11 Empty result set" "logs=$LOG_COUNT total=$TOTAL_VAL" +fi + +# 7.12 Ordering (newest first) +RESP=$(api_get "/audit-logs?limit=5" "$ADMIN_JAR") +FIRST_ID=$(echo "$RESP" | jq -r '.logs[0].id') +LAST_ID=$(echo "$RESP" | jq -r '.logs[-1].id') +if [[ "$FIRST_ID" -gt "$LAST_ID" ]]; then + pass "7.12 Entries ordered DESC (newest first: id $FIRST_ID > $LAST_ID)" +else + fail "7.12 Ordering" "First id=$FIRST_ID, last id=$LAST_ID (expected DESC)" +fi + +# ============================================================================= +# SECTION 12: Fire-and-Forget Behavior +# ============================================================================= +section "12. Fire-and-Forget Behavior" + +skip "12.1 Audit failure does not break login" "Requires temporarily corrupting audit_logs table" +skip "12.2 Audit failure does not break CVE create" "Requires temporarily corrupting audit_logs table" +skip "12.3 Response not delayed by audit" "Requires timing measurement under load" + +# ============================================================================= +# SECTION 13: Data Integrity +# ============================================================================= +section "13. Data Integrity" + +# 13.1 Audit survives user deletion +# Create user, perform action, delete user, check audit still has username +mark_audit +CREATE_RESP=$(api_post "/users" "$ADMIN_JAR" '{"username":"_test_ephemeral","email":"ephemeral@test.local","password":"pass123","role":"viewer"}') +EPH_ID=$(echo "$CREATE_RESP" | jq -r '.user.id // empty') +sleep 0.3 +if [[ -n "$EPH_ID" ]]; then + api_delete "/users/$EPH_ID" "$ADMIN_JAR" > /dev/null + sleep 0.3 + SURVIVING=$(sql "SELECT COUNT(*) FROM audit_logs WHERE details LIKE '%_test_ephemeral%';") + if [[ "$SURVIVING" -gt 0 ]]; then + pass "13.1 Audit entries survive user deletion (denormalized username)" + else + fail "13.1 No audit entries found for deleted user" + fi +else + skip "13.1 Audit survives user deletion" "Could not create ephemeral user" +fi + +# 13.2 Details stored as valid JSON +INVALID_JSON=$(sql "SELECT COUNT(*) FROM audit_logs WHERE details IS NOT NULL AND details != '' AND json_valid(details) = 0;") +if [[ "$INVALID_JSON" == "0" ]]; then + pass "13.2 All non-null details values are valid JSON" +else + fail "13.2 Found $INVALID_JSON rows with invalid JSON in details" +fi + +# 13.3 IP address captured +HAS_IP=$(sql "SELECT COUNT(*) FROM audit_logs WHERE ip_address IS NOT NULL AND ip_address != '';") +if [[ "$HAS_IP" -gt 0 ]]; then + pass "13.3 IP addresses captured ($HAS_IP entries with IP)" +else + fail "13.3 No audit entries have an IP address" +fi + +# 13.4 Timestamps auto-populated +NULL_TS=$(sql "SELECT COUNT(*) FROM audit_logs WHERE created_at IS NULL;") +if [[ "$NULL_TS" == "0" ]]; then + pass "13.4 All audit entries have non-null created_at" +else + fail "13.4 Found $NULL_TS entries with null created_at" +fi + +# 13.5 Null entity_id for auth actions +AUTH_WITH_ENTITY=$(sql "SELECT COUNT(*) FROM audit_logs WHERE entity_type='auth' AND entity_id IS NOT NULL;") +if [[ "$AUTH_WITH_ENTITY" == "0" ]]; then + pass "13.5 Auth entries have null entity_id" +else + fail "13.5 Found $AUTH_WITH_ENTITY auth entries with non-null entity_id" +fi + +# ============================================================================= +# SECTION 14: End-to-End Workflow +# ============================================================================= +section "14. End-to-End Workflow" + +# 14.1 Full user lifecycle +mark_audit +# Step 1: admin creates user +CREATE_RESP=$(api_post "/users" "$ADMIN_JAR" '{"username":"_test_lifecycle","email":"lifecycle@test.local","password":"life123","role":"viewer"}') +LIFE_ID=$(echo "$CREATE_RESP" | jq -r '.user.id // empty') +sleep 0.2 + +if [[ -n "$LIFE_ID" ]]; then + # Step 2: lifecycle user logs in + login_as "_test_lifecycle" "life123" "$TMPDIR_TEST/lifecycle.cookies" > /dev/null + sleep 0.2 + + # Step 3: lifecycle user creates a CVE + LIFE_CVE="CVE-2025-LIFE-$(date +%s)" + api_post "/cves" "$TMPDIR_TEST/lifecycle.cookies" "{\"cve_id\":\"$LIFE_CVE\",\"vendor\":\"LifeVendor\",\"severity\":\"Medium\",\"description\":\"Lifecycle test\",\"published_date\":\"2025-01-01\"}" > /dev/null + sleep 0.2 + + # Step 4: admin updates role + api_patch "/users/$LIFE_ID" "$ADMIN_JAR" '{"role":"editor"}' > /dev/null + sleep 0.2 + + # Step 5: admin deletes user + api_delete "/users/$LIFE_ID" "$ADMIN_JAR" > /dev/null + sleep 0.3 + + # Verify all actions logged + LIFECYCLE_ACTIONS=$(sql "SELECT action FROM audit_logs WHERE id > $AUDIT_MARK ORDER BY id;" | tr '\n' ',') + EXPECTED_ACTIONS="user_create,login,cve_create,user_update,user_delete," + + # Check each expected action is present in order + ALL_FOUND=true + for ACT in user_create login cve_create user_update user_delete; do + if ! echo "$LIFECYCLE_ACTIONS" | grep -q "$ACT"; then + ALL_FOUND=false + break + fi + done + + if [[ "$ALL_FOUND" == "true" ]]; then + pass "14.1 Full user lifecycle - all 5 actions logged" + else + fail "14.1 Full user lifecycle" "Expected: $EXPECTED_ACTIONS Got: $LIFECYCLE_ACTIONS" + fi + + # 14.2 Filter by lifecycle user's own actions + LIFE_OWN=$(sql "SELECT COUNT(*) FROM audit_logs WHERE id > $AUDIT_MARK AND username='_test_lifecycle';") + if [[ "$LIFE_OWN" -ge 2 ]]; then + pass "14.2 Lifecycle user's own actions found ($LIFE_OWN entries)" + else + fail "14.2 Expected at least 2 entries for _test_lifecycle, found $LIFE_OWN" + fi +else + skip "14.1 Full user lifecycle" "Could not create lifecycle user" + skip "14.2 Filter by lifecycle user" "Depends on 14.1" +fi + +# 14.3 Security audit trail - failed logins +mark_audit +for i in 1 2 3; do + login_as "admin" "badpass$i" "$TMPDIR_TEST/throwaway.cookies" > /dev/null +done +sleep 0.5 +FAIL_COUNT_CHECK=$(count_audit_since "action='login_failed' AND username='admin'") +if [[ "$FAIL_COUNT_CHECK" -ge 3 ]]; then + pass "14.3 Security audit trail - $FAIL_COUNT_CHECK failed login attempts recorded" +else + fail "14.3 Expected 3+ failed login attempts, found $FAIL_COUNT_CHECK" +fi + +# ============================================================================= +# CLEANUP +# ============================================================================= +section "Cleanup" + +# Remove test CVEs (direct SQL since there's no delete CVE API) +sql "DELETE FROM cves WHERE cve_id LIKE 'CVE-2025-AUDIT-%' OR cve_id LIKE 'CVE-2025-EDIT-%' OR cve_id LIKE 'CVE-2025-LIFE-%';" 2>/dev/null +echo " Removed test CVEs" + +# Remove test users (may already be deleted) +for u in _test_editor1 _test_viewer1 _test_disabled _test_audituser _test_ephemeral _test_lifecycle; do + UID_VAL=$(sql "SELECT id FROM users WHERE username='$u';" 2>/dev/null) + if [[ -n "$UID_VAL" ]]; then + sql "DELETE FROM sessions WHERE user_id=$UID_VAL;" 2>/dev/null + sql "DELETE FROM users WHERE id=$UID_VAL;" 2>/dev/null + fi +done +echo " Removed test users" + +# Remove test audit entries +sql "DELETE FROM audit_logs WHERE username LIKE '_test_%' OR entity_id LIKE 'CVE-2025-AUDIT-%' OR entity_id LIKE 'CVE-2025-EDIT-%' OR entity_id LIKE 'CVE-2025-LIFE-%' OR details LIKE '%_test_%';" 2>/dev/null +# Also clean up the failed login attempts for nonexistent user +sql "DELETE FROM audit_logs WHERE username='nonexistent_user_xyz';" 2>/dev/null +echo " Removed test audit entries" + +# ============================================================================= +# SUMMARY +# ============================================================================= +echo "" +echo "==============================================" +echo -e "${BOLD}TEST RESULTS${NC}" +echo "==============================================" +echo -e " ${GREEN}Passed: $PASS_COUNT${NC}" +echo -e " ${RED}Failed: $FAIL_COUNT${NC}" +echo -e " ${YELLOW}Skipped: $SKIP_COUNT${NC}" +echo " Total: $TOTAL" +echo "" + +# Note about manual tests +MANUAL_TESTS=34 +echo -e "${CYAN}Note: $MANUAL_TESTS tests in sections 8-11 (Frontend UI) require manual browser testing.${NC}" +echo " 8. Menu Access (5 tests) - Role-based visibility of Audit Log menu" +echo " 9. Modal Display (12 tests) - Table rendering, badges, formatting" +echo " 10. Frontend Filters (10 tests) - Filter dropdowns, reset, apply" +echo " 11. Pagination UI (7 tests) - Page navigation, boundary conditions" +echo "" + +if [[ "$FAIL_COUNT" -eq 0 ]]; then + echo -e "${GREEN}${BOLD}RESULT: ALL AUTOMATED TESTS PASSED${NC}" + exit 0 +else + echo -e "${RED}${BOLD}RESULT: $FAIL_COUNT TEST(S) FAILED${NC}" + exit 1 +fi diff --git a/swagger.json b/swagger.json new file mode 100644 index 0000000..3a3b2dd --- /dev/null +++ b/swagger.json @@ -0,0 +1,53228 @@ +{ + "swagger": "2.0", + "info": { + "title": "Ivanti Neurons API", + "description": "

RBAC 419 Error Codes

\n

The Ivanti Neurons platform supports a privilege-based permissions structure. When the requesting user doesn't have permission to access an endpoint, the API will return a 419 error code with a payload that looks like this:

\n
\n{\n   \"timestamp\": \"2021-03-30T16:47:30.648\",\n   \"status\": 419,\n   \"error\": \"InsufficientPrivileges\",\n   \"clientsMissingPrivileges\": [\n     656\n   ],\n   \"missingPrivilege\": \"Assessment Control\",\n   \"method\": \"PUT\",\n   \"path\": \"/api/v1/client/656/assessment/12\"\n}\n
\n

In the above example, the requesting user was denied access because they lacked the Assessment Control privilege. To overcome this, the requesting user needs to be assigned a role that grants the Assessment Control privilege. One way to do this is login to the platform UI and go to the IAM Roles page. Type in \"Assessment Control\" in the search input and select different roles on the left side panel. As you click through the various roles, look for ones that display a green checkmark for the Assessment Control card. Once you've found a suitable role, assign it yourself or have another user with User Role Disposition Control do it for you.

\n\n

If you don't want to assign one of the Ivanti Neurons provided roles to grant the Assessment Control privilege, you can create a custom role that only has the privileges needed. Note, if any role negates the Assessment Control privilege, you will need to un-assign that role regardless of any other roles that grant the privilege because negation always take precedence.

\n\n

Another option is to manually perform the action in the UI first. If your user doesn't have the necessary privileges, mouse over the button and a tooltip will display which roles need to be assigned (and unassigned in some cases because of negation). So for the above example, go to the Assessments page, select an assessment, and the Edit Assessment option should be disabled. Hover over it and the tooltip will show the pertinent roles.

\n\n

You can find more info here: Ivanti Neurons Risk-Based Solutions Knowledge Base - IAM

\n
\n\n

API Rate Limiting

\n In order to protect the security and stability of the platform for all users, the Ivanti Neurons platform rate limits requests. API requests will be limited to an average of three requests per second (there is some burst tolerance over short time periods). This will not affect the total number of requests. If the HTTP client exceeds the limit, our API gateway will return a 429 response code.\n\n We strongly advise wrapping all HTTP request in such a way to throttle each request with a wait/sleep function, or adding a retry mechanism as shown in the wrapper code example below.\n\n Python 3 Example\n\n
\n  import requests\n  from requests.adapters import HTTPAdapter\n  from urllib3 import Retry\n  def __requests_retry_session(max_retries=5, backoff_factor=0.5, status_forcelist=(429,)):\n      \"\"\"\n      Create a Requests session that uses automatic retries.\n      :param max_retries:         Maximum number of retries to attempt\n      :type  max_retries:         int\n      :param backoff_factor:      Backoff factor used to calculate time between retries.\n      :type  backoff_factor:      float\n      :param status_forcelist:    A tuple containing the response status codes that should trigger a retry.\n      :type  status_forcelist:    tuple\n      :return:    Requests Session\n      :rtype:     Requests Session Object\n      \"\"\"\n      session = requests.Session()\n      retry = Retry(\n         total=max_retries,\n         read=max_retries,\n         connect=max_retries,\n         backoff_factor=backoff_factor,\n         status_forcelist=status_forcelist,\n      )\n      adapter = HTTPAdapter(max_retries=retry)\n      session.mount('https://', adapter)\n      return session\n\n  
 header = {\n     \"content-type\": \"application/json\",\n     \"x-api-key\": \"INSERT KEY HERE\"\n  }
\n\n response = __requests_retry_session().get(\"https://platform.risksense.com/api/v1/client\", headers=header)
\n\n

Please contact Customer Success for information on platform rate limit thresholds and for any additional assistance during this transition.

\n
\n

Paginating Search Requests

\n

To paginate a request on a search endpoint, users should apply the parameter searchAfter in \ncombination with the parameter size. Users must employ this method for requests with more than \n10,000 results. For examples and additional documentation,\nrefer to the Knowledge Base article on \npagination of search requests.\n

\n
\nIvanti Neurons ™ API - The following API defines and documents the\nweb interface to the Ivanti Neurons ™ platform.\n

This page allows you to interact with the REAL LIVE Ivanti Neurons API. In\naddition to providing developer-oriented documentation for each endpoint,\nthe 'Try It Out' button will allow you to make an actual API request to\nIvanti Neurons without writing any code. Simply click the 'Try It Out' button, \nenter values for request parameters, then click the 'Execute' button.\n

\n

Note: The Ivanti Neurons ™ platform uses a CSRF token to validate\nuser requests after login. In order to have the platform use only the API\ntokens to validate requests, users will need to logout of their session, use\na different browser, or use the API via an incognito browser window.

\n

Ivanti Neurons ™ Website

\n", + "version": "1.0.0", + "termsOfService": "http://risksense.com/service-level-agreement/", + "contact": { + "name": "Ivanti Neurons Support", + "email": "support@risksense.com" + } + }, + "host": "platform4.risksense.com", + "schemes": [ + "https" + ], + "basePath": "/api/v1", + "securityDefinitions": { + "api_key": { + "type": "apiKey", + "name": "x-api-key", + "in": "header" + } + }, + "security": [ + { + "api_key": [] + } + ], + "tags": [ + { + "name": "UniqueFindingEOL", + "description": "As of May 7, 2021, we will deprecating the unique host and application finding endpoints. Do not rely on these endpoints going forward as they'll be removed without notice. Refer to the 'groupBy' endpoints that offer the same functionality to group by found-by-id (scanner plugin). Contact Customer Success for more info success@risksense.com." + } + ], + "paths": { + "/client/{clientId}/host/group-by": { + "get": { + "summary": "Get group by fields", + "tags": [ + "groupBy" + ], + "description": "Get group by fields for subject provided.\n", + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "description": "Allowed group by fields and metrics", + "type": "object", + "properties": { + "groupByFields": { + "description": "Allowed group by fields", + "type": "array", + "items": { + "description": "Group By Field with allowed metrics", + "type": "object", + "properties": { + "key": { + "description": "Group By Field Id that can be used in group by request", + "type": "string" + }, + "name": { + "description": "Display Value in UI", + "type": "string" + }, + "field": { + "type": "string" + }, + "isClickable": { + "description": "Whether this field allows click through", + "type": "boolean" + }, + "clickThroughSubject": { + "description": "page to which this field should navigate", + "type": "string" + }, + "format": { + "description": "Format of the field. Used for fields like date, RS3, VRR, Severity", + "type": "string" + }, + "defaultSort": { + "description": "Default sort order for this field", + "type": "string" + }, + "groupMetrics": { + "description": "Allowed metric fields for this group by field", + "type": "array", + "items": { + "description": "Allowed metric fields for a group by field", + "type": "object", + "properties": { + "key": { + "description": "Metric Field Id that can be used in group by request", + "type": "string" + }, + "name": { + "description": "Display Value in UI", + "type": "string" + }, + "isClickable": { + "description": "Whether this field allows click through", + "type": "boolean" + }, + "clickThroughSubject": { + "description": "page to which this field should navigate", + "type": "string" + }, + "format": { + "description": "Format of the field. Used for fields like date, RS3, VRR, Severity", + "type": "string" + }, + "isDefault": { + "description": "Whether this field is default is part of default columns", + "type": "boolean" + }, + "sortable": { + "description": "Whether this field is sortable", + "type": "boolean" + }, + "defaultSort": { + "description": "Default sort order for this field", + "type": "string" + }, + "order": { + "description": "Default order for this field", + "type": "number" + } + } + } + } + } + } + }, + "groupByColumns": { + "description": "Allowed metric fields for a group by field", + "type": "array", + "items": { + "description": "Allowed metric fields for a group by field", + "type": "object", + "properties": { + "key": { + "description": "Metric Field Id that can be used in group by request", + "type": "string" + }, + "name": { + "description": "Display Value in UI", + "type": "string" + }, + "isClickable": { + "description": "Whether this field allows click through", + "type": "boolean" + }, + "clickThroughSubject": { + "description": "page to which this field should navigate", + "type": "string" + }, + "format": { + "description": "Format of the field. Used for fields like date, RS3, VRR, Severity", + "type": "string" + }, + "isDefault": { + "description": "Whether this field is default is part of default columns", + "type": "boolean" + }, + "sortable": { + "description": "Whether this field is sortable", + "type": "boolean" + }, + "defaultSort": { + "description": "Default sort order for this field", + "type": "string" + }, + "order": { + "description": "Default order for this field", + "type": "number" + } + } + } + } + }, + "example": { + "groupByFields": [ + { + "key": "Host RS3 Group", + "name": "RS3", + "field": "rs3_group", + "description": null, + "clickThroughSubject": "host", + "format": "RS3", + "defaultSort": "ASC", + "isClickable": false, + "groupMetrics": [ + { + "key": "Host Count", + "name": "Hosts", + "description": null, + "clickThroughSubject": "host", + "format": "NONE", + "isDefault": true, + "sortable": true, + "defaultSort": null, + "isClickable": true, + "order": 1 + } + ] + } + ], + "groupByColumns": [ + { + "key": "Host Count", + "name": "Hosts", + "description": null, + "clickThroughSubject": "host", + "format": "NONE", + "isDefault": true, + "sortable": true, + "defaultSort": null, + "isClickable": true, + "order": 1 + } + ] + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + }, + "post": { + "summary": "Group by on host", + "tags": [ + "groupBy" + ], + "description": "Group by on host\n", + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "key", + "metricFields", + "filters", + "sortOrder" + ], + "properties": { + "key": { + "description": "The field to group by", + "type": "string" + }, + "metricFields": { + "description": "The fields to aggregate in the response data", + "type": "array", + "items": { + "type": "string" + } + }, + "filters": { + "description": "Array of filter values", + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + }, + "sortOrder": { + "description": "Field and direction to sort the response data on", + "type": "array", + "items": { + "type": "object", + "properties": { + "field": { + "type": "string" + }, + "direction": { + "type": "string", + "enum": [ + "ASC", + "DESC" + ] + } + } + } + } + }, + "example": { + "key": "Host RS3 Group", + "metricFields": [ + "Host Asset Criticality 3", + "Host Asset Criticality 4", + "Host Asset Criticality 5", + "Host Count", + "Host RS3 Critical Risk", + "Host RS3 High Risk", + "Host RS3 Medium Risk" + ], + "filters": [ + { + "field": "assessment_labels", + "exclusive": true, + "operator": "IN", + "value": "exampleAssessment," + } + ], + "sortOrder": [ + { + "field": "Host RS3 Group", + "direction": "ASC" + } + ] + } + } + } + ], + "responses": { + "200": { + "description": "The response for group by foundById.", + "schema": { + "type": "object", + "properties": { + "data": { + "description": "All of the response properties are dynamic and based on the specified request fields", + "type": "array", + "items": { + "type": "object" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/hostFinding/group-by": { + "get": { + "summary": "Get group by fields", + "tags": [ + "groupBy" + ], + "description": "Get group by fields for subject provided.\n", + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "description": "Allowed group by fields and metrics", + "type": "object", + "properties": { + "groupByFields": { + "description": "Allowed group by fields", + "type": "array", + "items": { + "description": "Group By Field with allowed metrics", + "type": "object", + "properties": { + "key": { + "description": "Group By Field Id that can be used in group by request", + "type": "string" + }, + "name": { + "description": "Display Value in UI", + "type": "string" + }, + "field": { + "type": "string" + }, + "isClickable": { + "description": "Whether this field allows click through", + "type": "boolean" + }, + "clickThroughSubject": { + "description": "page to which this field should navigate", + "type": "string" + }, + "format": { + "description": "Format of the field. Used for fields like date, RS3, VRR, Severity", + "type": "string" + }, + "defaultSort": { + "description": "Default sort order for this field", + "type": "string" + }, + "groupMetrics": { + "description": "Allowed metric fields for this group by field", + "type": "array", + "items": { + "description": "Allowed metric fields for a group by field", + "type": "object", + "properties": { + "key": { + "description": "Metric Field Id that can be used in group by request", + "type": "string" + }, + "name": { + "description": "Display Value in UI", + "type": "string" + }, + "isClickable": { + "description": "Whether this field allows click through", + "type": "boolean" + }, + "clickThroughSubject": { + "description": "page to which this field should navigate", + "type": "string" + }, + "format": { + "description": "Format of the field. Used for fields like date, RS3, VRR, Severity", + "type": "string" + }, + "isDefault": { + "description": "Whether this field is default is part of default columns", + "type": "boolean" + }, + "sortable": { + "description": "Whether this field is sortable", + "type": "boolean" + }, + "defaultSort": { + "description": "Default sort order for this field", + "type": "string" + }, + "order": { + "description": "Default order for this field", + "type": "number" + } + } + } + } + } + } + }, + "groupByColumns": { + "description": "Allowed metric fields for a group by field", + "type": "array", + "items": { + "description": "Allowed metric fields for a group by field", + "type": "object", + "properties": { + "key": { + "description": "Metric Field Id that can be used in group by request", + "type": "string" + }, + "name": { + "description": "Display Value in UI", + "type": "string" + }, + "isClickable": { + "description": "Whether this field allows click through", + "type": "boolean" + }, + "clickThroughSubject": { + "description": "page to which this field should navigate", + "type": "string" + }, + "format": { + "description": "Format of the field. Used for fields like date, RS3, VRR, Severity", + "type": "string" + }, + "isDefault": { + "description": "Whether this field is default is part of default columns", + "type": "boolean" + }, + "sortable": { + "description": "Whether this field is sortable", + "type": "boolean" + }, + "defaultSort": { + "description": "Default sort order for this field", + "type": "string" + }, + "order": { + "description": "Default order for this field", + "type": "number" + } + } + } + } + }, + "example": { + "groupByFields": [ + { + "key": "Host Finding Scanner Plugin", + "name": "Scanner Plugin", + "field": "found_by_id", + "description": null, + "clickThroughSubject": "hostFinding", + "format": "NONE", + "defaultSort": "ASC", + "isClickable": false, + "groupMetrics": [ + { + "key": "Host Finding Hosts Count", + "name": "Hosts", + "description": null, + "clickThroughSubject": "host", + "format": "NONE", + "isDefault": true, + "sortable": true, + "defaultSort": null, + "isClickable": true, + "order": 1 + } + ] + } + ], + "groupByColumns": [ + { + "key": "Host Finding Hosts Count", + "name": "Hosts", + "description": null, + "clickThroughSubject": "host", + "format": "NONE", + "isDefault": true, + "sortable": true, + "defaultSort": null, + "isClickable": true, + "order": 1 + } + ] + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + }, + "post": { + "summary": "Group by foundById (scanner plugin) on host finding", + "tags": [ + "groupBy" + ], + "description": "Group by foundById (scanner plugin) on host finding. This replaces the deprecated unique findings endpoints.\n", + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "key", + "metricFields", + "filters", + "sortOrder" + ], + "properties": { + "key": { + "description": "The field to group by", + "type": "string" + }, + "metricFields": { + "description": "The fields to aggregate in the response data", + "type": "array", + "items": { + "type": "string" + } + }, + "filters": { + "description": "Array of filter values", + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + }, + "sortOrder": { + "description": "Field and direction to sort the response data on", + "type": "array", + "items": { + "type": "object", + "properties": { + "field": { + "type": "string" + }, + "direction": { + "type": "string", + "enum": [ + "ASC", + "DESC" + ] + } + } + } + } + }, + "example": { + "key": "Host Finding Scanner Plugin", + "metricFields": [ + "Host Finding Title", + "Host Finding Scanner Name", + "Host Finding Hosts Count", + "Host Finding Open Count", + "Host Finding Closed Count", + "Host Finding With Threat Count", + "Host Finding Threat Count", + "Host Finding Fixes Count", + "Host Finding VRR Critical Count", + "Host Finding VRR High Count", + "Host Finding VRR Medium Count", + "Host Finding VRR Low Count", + "Host Finding VRR Info Count", + "Host Finding CVE Count" + ], + "filters": [ + { + "field": "assessment_labels", + "exclusive": true, + "operator": "IN", + "value": "exampleAssessment," + } + ], + "sortOrder": [ + { + "field": "Host Finding Scanner Plugin", + "direction": "ASC" + } + ] + } + } + } + ], + "responses": { + "200": { + "description": "The response for group by foundById.", + "schema": { + "type": "object", + "properties": { + "data": { + "description": "All of the response properties are dynamic and based on the specified request fields", + "type": "array", + "items": { + "type": "object" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/application/group-by": { + "get": { + "summary": "Get group by fields", + "tags": [ + "groupBy" + ], + "description": "Get group by fields for subject provided.\n", + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "description": "Allowed group by fields and metrics", + "type": "object", + "properties": { + "groupByFields": { + "description": "Allowed group by fields", + "type": "array", + "items": { + "description": "Group By Field with allowed metrics", + "type": "object", + "properties": { + "key": { + "description": "Group By Field Id that can be used in group by request", + "type": "string" + }, + "name": { + "description": "Display Value in UI", + "type": "string" + }, + "field": { + "type": "string" + }, + "isClickable": { + "description": "Whether this field allows click through", + "type": "boolean" + }, + "clickThroughSubject": { + "description": "page to which this field should navigate", + "type": "string" + }, + "format": { + "description": "Format of the field. Used for fields like date, RS3, VRR, Severity", + "type": "string" + }, + "defaultSort": { + "description": "Default sort order for this field", + "type": "string" + }, + "groupMetrics": { + "description": "Allowed metric fields for this group by field", + "type": "array", + "items": { + "description": "Allowed metric fields for a group by field", + "type": "object", + "properties": { + "key": { + "description": "Metric Field Id that can be used in group by request", + "type": "string" + }, + "name": { + "description": "Display Value in UI", + "type": "string" + }, + "isClickable": { + "description": "Whether this field allows click through", + "type": "boolean" + }, + "clickThroughSubject": { + "description": "page to which this field should navigate", + "type": "string" + }, + "format": { + "description": "Format of the field. Used for fields like date, RS3, VRR, Severity", + "type": "string" + }, + "isDefault": { + "description": "Whether this field is default is part of default columns", + "type": "boolean" + }, + "sortable": { + "description": "Whether this field is sortable", + "type": "boolean" + }, + "defaultSort": { + "description": "Default sort order for this field", + "type": "string" + }, + "order": { + "description": "Default order for this field", + "type": "number" + } + } + } + } + } + } + }, + "groupByColumns": { + "description": "Allowed metric fields for a group by field", + "type": "array", + "items": { + "description": "Allowed metric fields for a group by field", + "type": "object", + "properties": { + "key": { + "description": "Metric Field Id that can be used in group by request", + "type": "string" + }, + "name": { + "description": "Display Value in UI", + "type": "string" + }, + "isClickable": { + "description": "Whether this field allows click through", + "type": "boolean" + }, + "clickThroughSubject": { + "description": "page to which this field should navigate", + "type": "string" + }, + "format": { + "description": "Format of the field. Used for fields like date, RS3, VRR, Severity", + "type": "string" + }, + "isDefault": { + "description": "Whether this field is default is part of default columns", + "type": "boolean" + }, + "sortable": { + "description": "Whether this field is sortable", + "type": "boolean" + }, + "defaultSort": { + "description": "Default sort order for this field", + "type": "string" + }, + "order": { + "description": "Default order for this field", + "type": "number" + } + } + } + } + }, + "example": { + "groupByFields": [ + { + "key": "Application RS3 Group", + "name": "RS3", + "field": "rs3_group", + "description": null, + "clickThroughSubject": "application", + "format": "RS3", + "defaultSort": "ASC", + "isClickable": false, + "groupMetrics": [ + { + "key": "Application Count", + "name": "Applications", + "description": null, + "clickThroughSubject": "application", + "format": "NONE", + "isDefault": true, + "sortable": true, + "defaultSort": null, + "isClickable": true, + "order": 1 + } + ] + } + ], + "groupByColumns": [ + { + "key": "Application Count", + "name": "Applications", + "description": null, + "clickThroughSubject": "application", + "format": "NONE", + "isDefault": true, + "sortable": true, + "defaultSort": null, + "isClickable": true, + "order": 1 + } + ] + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + }, + "post": { + "summary": "Group by on application", + "tags": [ + "groupBy" + ], + "description": "Group by on application\n", + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "key", + "metricFields", + "filters", + "sortOrder" + ], + "properties": { + "key": { + "description": "The field to group by", + "type": "string" + }, + "metricFields": { + "description": "The fields to aggregate in the response data", + "type": "array", + "items": { + "type": "string" + } + }, + "filters": { + "description": "Array of filter values", + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + }, + "sortOrder": { + "description": "Field and direction to sort the response data on", + "type": "array", + "items": { + "type": "object", + "properties": { + "field": { + "type": "string" + }, + "direction": { + "type": "string", + "enum": [ + "ASC", + "DESC" + ] + } + } + } + } + }, + "example": { + "key": "Application RS3 Group", + "metricFields": [ + "Application Asset Criticality 3", + "Application Asset Criticality 4", + "Application Asset Criticality 5", + "Application Count", + "Application RS3 Critical Risk", + "Application RS3 High Risk", + "Application RS3 Medium Risk" + ], + "filters": [ + { + "field": "assessment_labels", + "exclusive": true, + "operator": "IN", + "value": "exampleAssessment," + } + ], + "sortOrder": [ + { + "field": "Application RS3 Group", + "direction": "ASC" + } + ] + } + } + } + ], + "responses": { + "200": { + "description": "The response for group by foundById.", + "schema": { + "type": "object", + "properties": { + "data": { + "description": "All of the response properties are dynamic and based on the specified request fields", + "type": "array", + "items": { + "type": "object" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/applicationFinding/group-by": { + "get": { + "summary": "Get group by fields", + "tags": [ + "groupBy" + ], + "description": "Get group by fields for subject provided.\n", + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "description": "Allowed group by fields and metrics", + "type": "object", + "properties": { + "groupByFields": { + "description": "Allowed group by fields", + "type": "array", + "items": { + "description": "Group By Field with allowed metrics", + "type": "object", + "properties": { + "key": { + "description": "Group By Field Id that can be used in group by request", + "type": "string" + }, + "name": { + "description": "Display Value in UI", + "type": "string" + }, + "field": { + "type": "string" + }, + "isClickable": { + "description": "Whether this field allows click through", + "type": "boolean" + }, + "clickThroughSubject": { + "description": "page to which this field should navigate", + "type": "string" + }, + "format": { + "description": "Format of the field. Used for fields like date, RS3, VRR, Severity", + "type": "string" + }, + "defaultSort": { + "description": "Default sort order for this field", + "type": "string" + }, + "groupMetrics": { + "description": "Allowed metric fields for this group by field", + "type": "array", + "items": { + "description": "Allowed metric fields for a group by field", + "type": "object", + "properties": { + "key": { + "description": "Metric Field Id that can be used in group by request", + "type": "string" + }, + "name": { + "description": "Display Value in UI", + "type": "string" + }, + "isClickable": { + "description": "Whether this field allows click through", + "type": "boolean" + }, + "clickThroughSubject": { + "description": "page to which this field should navigate", + "type": "string" + }, + "format": { + "description": "Format of the field. Used for fields like date, RS3, VRR, Severity", + "type": "string" + }, + "isDefault": { + "description": "Whether this field is default is part of default columns", + "type": "boolean" + }, + "sortable": { + "description": "Whether this field is sortable", + "type": "boolean" + }, + "defaultSort": { + "description": "Default sort order for this field", + "type": "string" + }, + "order": { + "description": "Default order for this field", + "type": "number" + } + } + } + } + } + } + }, + "groupByColumns": { + "description": "Allowed metric fields for a group by field", + "type": "array", + "items": { + "description": "Allowed metric fields for a group by field", + "type": "object", + "properties": { + "key": { + "description": "Metric Field Id that can be used in group by request", + "type": "string" + }, + "name": { + "description": "Display Value in UI", + "type": "string" + }, + "isClickable": { + "description": "Whether this field allows click through", + "type": "boolean" + }, + "clickThroughSubject": { + "description": "page to which this field should navigate", + "type": "string" + }, + "format": { + "description": "Format of the field. Used for fields like date, RS3, VRR, Severity", + "type": "string" + }, + "isDefault": { + "description": "Whether this field is default is part of default columns", + "type": "boolean" + }, + "sortable": { + "description": "Whether this field is sortable", + "type": "boolean" + }, + "defaultSort": { + "description": "Default sort order for this field", + "type": "string" + }, + "order": { + "description": "Default order for this field", + "type": "number" + } + } + } + } + }, + "example": { + "groupByFields": [ + { + "key": "App Finding Scanner Plugin", + "name": "Scanner Plugin", + "field": "foundById", + "description": null, + "clickThroughSubject": "applicationFinding", + "format": "NONE", + "defaultSort": "ASC", + "isClickable": false, + "groupMetrics": [ + { + "key": "App Finding Hosts Count", + "name": "Apps", + "description": null, + "clickThroughSubject": "application", + "format": "NONE", + "isDefault": true, + "sortable": true, + "defaultSort": null, + "isClickable": true, + "order": 1 + } + ] + } + ], + "groupByColumns": [ + { + "key": "App Finding Hosts Count", + "name": "Apps", + "description": null, + "clickThroughSubject": "application", + "format": "NONE", + "isDefault": true, + "sortable": true, + "defaultSort": null, + "isClickable": true, + "order": 1 + } + ] + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + }, + "post": { + "summary": "Group by foundById (scanner plugin) on application finding", + "tags": [ + "groupBy" + ], + "description": "Group by foundById (scanner plugin) on application finding. This replaces the deprecated unique findings endpoints.\n", + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "key", + "metricFields", + "filters", + "sortOrder" + ], + "properties": { + "key": { + "description": "The field to group by", + "type": "string" + }, + "metricFields": { + "description": "The fields to aggregate in the response data", + "type": "array", + "items": { + "type": "string" + } + }, + "filters": { + "description": "Array of filter values", + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + }, + "sortOrder": { + "description": "Field and direction to sort the response data on", + "type": "array", + "items": { + "type": "object", + "properties": { + "field": { + "type": "string" + }, + "direction": { + "type": "string", + "enum": [ + "ASC", + "DESC" + ] + } + } + } + } + }, + "example": { + "key": "App Finding Scanner Plugin", + "metricFields": [ + "App Finding Title", + "App Finding Scanner Name", + "App Finding Apps Count", + "App Finding Open Count", + "App Finding Closed Count", + "App Finding VRR Critical Count", + "App Finding VRR High Count", + "App Finding VRR Medium Count", + "App Finding VRR Low Count", + "App Finding VRR Info Count" + ], + "filters": [ + { + "field": "assessment_labels", + "exclusive": true, + "operator": "IN", + "value": "exampleAssessment," + } + ], + "sortOrder": [ + { + "field": "App Finding Scanner Plugin", + "direction": "ASC" + } + ] + } + } + } + ], + "responses": { + "200": { + "description": "The response for group by foundById.", + "schema": { + "type": "object", + "properties": { + "data": { + "description": "All of the response properties are dynamic and based on the specified request fields", + "type": "array", + "items": { + "type": "object" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client": { + "get": { + "summary": "List clients", + "tags": [ + "client" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "size", + "in": "query", + "description": "Size of the page requested", + "required": false, + "type": "integer" + }, + { + "name": "page", + "in": "query", + "description": "Page number being requested (first page: 0)", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "_embedded", + "page" + ], + "properties": { + "_embedded": { + "type": "object", + "required": [ + "clients" + ], + "properties": { + "clients": { + "type": "array", + "items": { + "allOf": [ + { + "type": "object", + "required": [ + "id" + ], + "properties": { + "id": { + "type": "integer" + } + }, + "example": { + "id": 12 + } + } + ], + "properties": { + "uuid": { + "type": "string" + }, + "name": { + "type": "string" + }, + "rs3": { + "type": "number", + "format": "double" + }, + "contact": { + "type": "object", + "properties": { + "address": { + "type": "string" + }, + "address2": { + "type": "string" + }, + "city": { + "type": "string" + }, + "state": { + "type": "string" + }, + "zip": { + "type": "string", + "pattern": "\\d{5}" + } + } + }, + "expirationDate": { + "type": "string", + "format": "date" + }, + "notes": { + "type": "string" + }, + "description": { + "type": "string" + }, + "industry": { + "type": "string", + "enum": [ + "General", + "Education", + "Energy/Utility", + "Entertainment", + "Finance", + "Gaming", + "Goverment", + "Healthcare", + "Retail" + ] + }, + "disabled": { + "type": "boolean" + }, + "demoClient": { + "type": "boolean" + }, + "accountManagerId": { + "type": "number" + }, + "clientCustomField1": { + "type": "string" + }, + "clientCustomField2": { + "type": "string" + } + }, + "example": { + "uuid": "123e4567-e89b-12d3-a456-556642440000", + "name": "sample client", + "rs3": 432, + "contact": { + "address": "4200 Osuna Rd NE", + "address2": "Suite 300", + "city": "Albuquerque", + "state": "NM", + "zip": 87113 + }, + "expirationDate": "2018-02-26", + "notes": "some notes", + "description": "some text", + "industry": "General", + "disabled": false, + "demoClient": true, + "accountManagerId": 2, + "clientCustomField1": "some text 1", + "clientCustomField2": "some text 2" + } + } + } + } + }, + "page": { + "type": "object", + "required": [ + "size", + "totalElements", + "totalPages", + "number" + ], + "properties": { + "size": { + "type": "integer" + }, + "totalElements": { + "type": "integer" + }, + "totalPages": { + "type": "integer" + }, + "number": { + "type": "integer" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + } + } + } + }, + "/client/{clientId}": { + "get": { + "summary": "Get details about a client", + "tags": [ + "client" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "allOf": [ + { + "type": "object", + "required": [ + "id" + ], + "properties": { + "id": { + "type": "integer" + } + }, + "example": { + "id": 12 + } + } + ], + "properties": { + "uuid": { + "type": "string" + }, + "name": { + "type": "string" + }, + "rs3": { + "type": "number", + "format": "double" + }, + "contact": { + "type": "object", + "properties": { + "address": { + "type": "string" + }, + "address2": { + "type": "string" + }, + "city": { + "type": "string" + }, + "state": { + "type": "string" + }, + "zip": { + "type": "string", + "pattern": "\\d{5}" + } + } + }, + "expirationDate": { + "type": "string", + "format": "date" + }, + "notes": { + "type": "string" + }, + "description": { + "type": "string" + }, + "industry": { + "type": "string", + "enum": [ + "General", + "Education", + "Energy/Utility", + "Entertainment", + "Finance", + "Gaming", + "Goverment", + "Healthcare", + "Retail" + ] + }, + "disabled": { + "type": "boolean" + }, + "demoClient": { + "type": "boolean" + }, + "accountManagerId": { + "type": "number" + }, + "clientCustomField1": { + "type": "string" + }, + "clientCustomField2": { + "type": "string" + } + }, + "example": { + "uuid": "123e4567-e89b-12d3-a456-556642440000", + "name": "sample client", + "rs3": 432, + "contact": { + "address": "4200 Osuna Rd NE", + "address2": "Suite 300", + "city": "Albuquerque", + "state": "NM", + "zip": 87113 + }, + "expirationDate": "2018-02-26", + "notes": "some notes", + "description": "some text", + "industry": "General", + "disabled": false, + "demoClient": true, + "accountManagerId": 2, + "clientCustomField1": "some text 1", + "clientCustomField2": "some text 2" + } + } + }, + "401": { + "description": "Unauthorized" + } + } + } + }, + "/search/systemFilter": { + "get": { + "summary": "search system filters", + "tags": [ + "filter" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "array", + "items": { + "type": "object", + "required": [ + "uuid", + "name" + ], + "properties": { + "uuid": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "weight": { + "type": "integer" + }, + "dateUntilNewBadgeShown": { + "type": "string", + "format": "date" + }, + "widgets": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "FILTER_OVERVIEW" + ] + } + }, + "subjectFilters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "subject", + "filterRequest" + ], + "properties": { + "subject": { + "type": "string" + }, + "filterRequest": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "sort" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + }, + "projection": { + "type": "string" + }, + "sort": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "direction" + ], + "properties": { + "field": { + "type": "string" + }, + "direction": { + "type": "string", + "enum": [ + "ASC", + "DESC" + ] + } + } + } + }, + "page": { + "type": "integer" + }, + "size": { + "type": "integer" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "projection": "basic", + "sort": [ + { + "field": "id", + "direction": "ASC" + } + ], + "page": 0, + "size": 20 + } + } + }, + "example": { + "subject": "hostFinding", + "filterRequest": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "projection": "basic", + "sort": [ + { + "field": "id", + "direction": "ASC" + } + ], + "page": 0, + "size": 20 + } + } + } + }, + "created": { + "type": "string" + }, + "updated": { + "type": "string" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + } + } + } + }, + "/client/{clientId}/assessment": { + "post": { + "summary": "Create new assessment", + "tags": [ + "assessment" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "allOf": [ + { + "type": "object", + "required": [ + "name", + "startDate", + "notes" + ], + "properties": { + "name": { + "type": "string" + }, + "startDate": { + "type": "string", + "format": "date" + }, + "notes": { + "type": "string" + }, + "startTime": { + "type": "string" + } + }, + "example": { + "name": "Q2", + "startDate": "2018-04-01", + "notes": "", + "startTime": "14:51" + } + } + ], + "type": "object" + } + } + ], + "responses": { + "201": { + "description": "Success", + "schema": { + "allOf": [ + { + "type": "object", + "required": [ + "id" + ], + "properties": { + "id": { + "type": "integer" + } + }, + "example": { + "id": 12 + } + }, + { + "allOf": [ + { + "type": "object", + "required": [ + "name", + "startDate", + "notes" + ], + "properties": { + "name": { + "type": "string" + }, + "startDate": { + "type": "string", + "format": "date" + }, + "notes": { + "type": "string" + }, + "startTime": { + "type": "string" + } + }, + "example": { + "name": "Q2", + "startDate": "2018-04-01", + "notes": "", + "startTime": "14:51" + } + } + ], + "type": "object" + }, + { + "type": "object", + "required": [ + "clientId" + ], + "properties": { + "clientId": { + "type": "integer", + "description": "client identifier" + } + } + } + ], + "example": { + "id": 12, + "name": "Q2", + "startDate": "2018-04-01", + "notes": "", + "clientId": 5 + } + } + }, + "400": { + "description": "User Error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/assessment/{assessmentId}": { + "put": { + "summary": "Update an assessment", + "description": "

Replaces all fields in the assessment with the new values

\n", + "tags": [ + "assessment" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "assessmentId", + "description": "

Id of an assessment

\n

'search/assessment/find' returns available assessments

\n", + "in": "path", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "name", + "startDate", + "notes" + ], + "properties": { + "name": { + "type": "string" + }, + "startDate": { + "type": "string", + "format": "date" + }, + "notes": { + "type": "string" + }, + "startTime": { + "type": "string" + } + }, + "example": { + "name": "Q2", + "startDate": "2018-04-01", + "notes": "", + "startTime": "14:51" + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "allOf": [ + { + "type": "object", + "required": [ + "id" + ], + "properties": { + "id": { + "type": "integer" + } + }, + "example": { + "id": 12 + } + }, + { + "allOf": [ + { + "type": "object", + "required": [ + "name", + "startDate", + "notes" + ], + "properties": { + "name": { + "type": "string" + }, + "startDate": { + "type": "string", + "format": "date" + }, + "notes": { + "type": "string" + }, + "startTime": { + "type": "string" + } + }, + "example": { + "name": "Q2", + "startDate": "2018-04-01", + "notes": "", + "startTime": "14:51" + } + } + ], + "type": "object" + }, + { + "type": "object", + "required": [ + "clientId" + ], + "properties": { + "clientId": { + "type": "integer", + "description": "client identifier" + } + } + } + ], + "example": { + "id": 12, + "name": "Q2", + "startDate": "2018-04-01", + "notes": "", + "clientId": 5 + } + } + }, + "400": { + "description": "User Error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + }, + "delete": { + "summary": "Delete an assessment", + "tags": [ + "assessment" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "assessmentId", + "description": "

Id of an assessment

\n

'search/assessment/find' returns available assessments

\n", + "in": "path", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Job Created", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/assessment/model": { + "get": { + "summary": "List projections and their models", + "description": "List projections and their models that can be requested from the search endpoint.\n", + "tags": [ + "assessment" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "object", + "properties": { + "projections": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "fields": { + "type": "array", + "items": { + "type": "object", + "properties": { + "field": { + "type": "string" + }, + "type": { + "type": "string" + }, + "nested": { + "type": "array", + "items": { + "type": "object", + "description": "Same as ProjectionField" + } + } + } + } + } + } + } + } + }, + "example": { + "projections": [ + { + "name": "basic", + "fields": [ + { + "field": "id", + "type": "integer" + }, + { + "field": "name", + "type": "string" + } + ] + } + ] + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/assessment/filter": { + "get": { + "summary": "List fields that can be filtered by in the search endpoint", + "tags": [ + "assessment" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "array", + "items": { + "required": [ + "name", + "uid", + "operators", + "type", + "description" + ], + "properties": { + "name": { + "type": "string" + }, + "uid": { + "type": "string", + "description": "uid used to indentify fields in suggest and search requests" + }, + "operators": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + } + }, + "datatype": { + "type": "string" + }, + "description": { + "type": "string" + } + } + }, + "example": [ + { + "name": "id", + "uid": "id", + "operator": [ + "EXACT", + "IN" + ], + "type": "integer", + "description": "The id" + } + ] + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/assessment/suggest": { + "post": { + "summary": "Suggest values for filter fields", + "tags": [ + "assessment" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "filter" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + }, + "description": "Filters to used to narrow down the the result set\n" + }, + "filter": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + }, + "description": "Filter for which to suggest values for. The filter value will be\ntreated as a wildcard.\n" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": true, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "filter": { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "" + } + } + } + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key", + "count" + ], + "properties": { + "key": { + "type": "string", + "description": "Value for the field the suggestion was requested for." + }, + "count": { + "type": "integer", + "format": "int64" + } + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/assessment/search": { + "post": { + "summary": "Search for assessments", + "tags": [ + "assessment" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "sort" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + }, + "projection": { + "type": "string" + }, + "sort": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "direction" + ], + "properties": { + "field": { + "type": "string" + }, + "direction": { + "type": "string", + "enum": [ + "ASC", + "DESC" + ] + } + } + } + }, + "page": { + "type": "integer" + }, + "size": { + "type": "integer" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "projection": "basic", + "sort": [ + { + "field": "id", + "direction": "ASC" + } + ], + "page": 0, + "size": 20 + } + } + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "object", + "required": [ + "_embedded", + "page" + ], + "properties": { + "_embedded": { + "type": "object", + "required": [ + "strings" + ], + "properties": { + "strings": { + "type": "array", + "items": { + "type": "object", + "description": "

The response structure is subject dependent. Subject structure\ncan be found via the subject endpoint.

\n" + } + } + } + }, + "page": { + "type": "object", + "required": [ + "size", + "totalElements", + "totalPages", + "number" + ], + "properties": { + "size": { + "type": "integer" + }, + "totalElements": { + "type": "integer" + }, + "totalPages": { + "type": "integer" + }, + "number": { + "type": "integer" + } + } + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "id", + "errorRefId", + "code", + "cause" + ], + "properties": { + "id": { + "type": "string", + "description": "Entity id which failed to be retrieved" + }, + "errorRefId": { + "type": "string", + "description": "A unique identifier for the error" + }, + "code": { + "type": "integer", + "description": "http status code of the error" + }, + "cause": { + "type": "string", + "description": "http status code message" + } + } + } + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/assessment/{assessmentId}/status": { + "post": { + "summary": "Update status of assessment", + "tags": [ + "assessment" + ], + "consumes": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "assessmentId", + "description": "

Id of an assessment

\n

'search/assessment/find' returns available assessments

\n", + "in": "path", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "status" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "LOCKED", + "UNLOCKED" + ] + } + } + } + } + ], + "responses": { + "200": { + "description": "Success" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/assessment/{assessmentId}/history": { + "get": { + "summary": "History of assessment", + "tags": [ + "assessment" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "assessmentId", + "description": "

Id of an assessment

\n

'search/assessment/find' returns available assessments

\n", + "in": "path", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "action": { + "type": "string" + }, + "title": { + "type": "string" + }, + "userId": { + "type": "string" + }, + "userName": { + "type": "string" + }, + "date": { + "type": "string", + "format": "date-time" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/assessment/{assessmentId}/attachment": { + "get": { + "summary": "List the attachments", + "tags": [ + "assessment" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "assessmentId", + "description": "

Id of an assessment

\n

'search/assessment/find' returns available assessments

\n", + "in": "path", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "array", + "items": { + "type": "object", + "required": [ + "filename", + "uuid", + "contentType", + "contentLength" + ], + "properties": { + "filename": { + "type": "string" + }, + "uuid": { + "type": "string" + }, + "contentType": { + "type": "string" + }, + "contentLength": { + "type": "integer" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + }, + "post": { + "summary": "Upload 1 or more attachment files", + "tags": [ + "assessment" + ], + "consumes": [ + "multipart/form-data" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "assessmentId", + "description": "

Id of an assessment

\n

'search/assessment/find' returns available assessments

\n", + "in": "path", + "required": true, + "type": "integer" + }, + { + "in": "formData", + "name": "attachments", + "type": "file", + "required": true, + "description": "An attachment file" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "array", + "items": { + "type": "object", + "required": [ + "filename", + "uuid", + "contentType", + "contentLength" + ], + "properties": { + "filename": { + "type": "string" + }, + "uuid": { + "type": "string" + }, + "contentType": { + "type": "string" + }, + "contentLength": { + "type": "integer" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/assessment/{assessmentId}/attachment/{attachmentUUID}": { + "get": { + "summary": "Fetch attachment by UUID", + "tags": [ + "assessment" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "assessmentId", + "description": "

Id of an assessment

\n

'search/assessment/find' returns available assessments

\n", + "in": "path", + "required": true, + "type": "integer" + }, + { + "name": "attachmentUUID", + "description": "The attachment UUID, given when the attachments were uploaded\n", + "in": "path", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "description": "Ok" + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + }, + "406": { + "description": "MIME Mismatch\nTry changing from application/octet-stream to application/json, or vice-versa." + } + } + }, + "delete": { + "summary": "Remove an attachment", + "tags": [ + "assessment" + ], + "consumes": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "assessmentId", + "description": "

Id of an assessment

\n

'search/assessment/find' returns available assessments

\n", + "in": "path", + "required": true, + "type": "integer" + }, + { + "name": "attachmentUUID", + "description": "The attachment UUID, given when the attachments were uploaded\n", + "in": "path", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "description": "List of attachment UUIDs that were deleted successfully\n", + "type": "array", + "items": { + "type": "string" + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/assessment/{assessmentId}/attachment/{attachmentUUID}/meta": { + "get": { + "summary": "Fetch attachment metadata", + "tags": [ + "assessment" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "assessmentId", + "description": "

Id of an assessment

\n

'search/assessment/find' returns available assessments

\n", + "in": "path", + "required": true, + "type": "integer" + }, + { + "name": "attachmentUUID", + "description": "The attachment UUID, given when the attachments were uploaded\n", + "in": "path", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "filename", + "uuid", + "contentType", + "contentLength" + ], + "properties": { + "filename": { + "type": "string" + }, + "uuid": { + "type": "string" + }, + "contentType": { + "type": "string" + }, + "contentLength": { + "type": "integer" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/network": { + "get": { + "summary": "Retrieve a paginated list of networks for the specified client.", + "tags": [ + "network" + ], + "description": "Use search endpoint:/client/{clientId}/network/search\n", + "deprecated": true, + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "size", + "in": "query", + "description": "Size of the page requested", + "required": false, + "type": "integer" + }, + { + "name": "page", + "in": "query", + "description": "Page number being requested (first page: 0)", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "_embedded", + "page" + ], + "properties": { + "_embedded": { + "type": "object", + "required": [ + "networks" + ], + "properties": { + "networks": { + "type": "array", + "items": { + "type": "object", + "required": [ + "id", + "name", + "type" + ], + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string", + "pattern": "[a-zA-Z0-9'_\\-]+" + }, + "type": { + "type": "string", + "enum": [ + "IP", + "HOSTNAME", + "MIXED" + ] + } + } + } + } + } + }, + "page": { + "type": "object", + "required": [ + "size", + "totalElements", + "totalPages", + "number" + ], + "properties": { + "size": { + "type": "integer" + }, + "totalElements": { + "type": "integer" + }, + "totalPages": { + "type": "integer" + }, + "number": { + "type": "integer" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + }, + "post": { + "summary": "Create a new network for the specified client.", + "tags": [ + "network" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "name", + "type" + ], + "properties": { + "name": { + "type": "string", + "pattern": "[a-zA-Z0-9'_\\-]+" + }, + "type": { + "type": "string", + "enum": [ + "MIXED" + ] + } + } + } + } + ], + "responses": { + "201": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "id", + "name", + "type" + ], + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string", + "pattern": "[a-zA-Z0-9'_\\-]+" + }, + "type": { + "type": "string", + "enum": [ + "IP", + "HOSTNAME", + "MIXED" + ] + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/network/{networkId}": { + "get": { + "summary": "Retrieve details about a single network.", + "tags": [ + "network" + ], + "description": "Use search endpoint: /client/{clientId}/network/search\n", + "deprecated": true, + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "networkId", + "description": "Identifier for a network associated with the client (This parameter can be obtained via the GET method on '/network')\n", + "in": "path", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "id", + "name", + "type" + ], + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string", + "pattern": "[a-zA-Z0-9'_\\-]+" + }, + "type": { + "type": "string", + "enum": [ + "IP", + "HOSTNAME", + "MIXED" + ] + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + }, + "put": { + "summary": "Update a network for the specified client.", + "tags": [ + "network" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "networkId", + "description": "Identifier for a network associated with the client (This parameter can be obtained via the GET method on '/network')\n", + "in": "path", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "allOf": [ + { + "type": "object", + "required": [ + "id" + ], + "properties": { + "id": { + "type": "integer" + } + }, + "example": { + "id": 12 + } + }, + { + "type": "object", + "required": [ + "name", + "type" + ], + "properties": { + "name": { + "type": "string", + "pattern": "[a-zA-Z0-9'_\\-]+" + }, + "type": { + "type": "string", + "enum": [ + "IP", + "HOSTNAME", + "MIXED" + ] + } + } + } + ] + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "id", + "name", + "type" + ], + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string", + "pattern": "[a-zA-Z0-9'_\\-]+" + }, + "type": { + "type": "string", + "enum": [ + "IP", + "HOSTNAME", + "MIXED" + ] + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + }, + "delete": { + "summary": "Delete a network", + "tags": [ + "network" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "networkId", + "description": "Identifier for a network associated with the client (This parameter can be obtained via the GET method on '/network')\n", + "in": "path", + "required": true, + "type": "integer" + } + ], + "responses": { + "204": { + "description": "Request was processed without errors" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/network/model": { + "get": { + "summary": "List projections and their models", + "description": "List projections and their models that can be requested from the search endpoint.\n", + "tags": [ + "network" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "object", + "properties": { + "projections": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "fields": { + "type": "array", + "items": { + "type": "object", + "properties": { + "field": { + "type": "string" + }, + "type": { + "type": "string" + }, + "nested": { + "type": "array", + "items": { + "type": "object", + "description": "Same as ProjectionField" + } + } + } + } + } + } + } + } + }, + "example": { + "projections": [ + { + "name": "basic", + "fields": [ + { + "field": "id", + "type": "integer" + }, + { + "field": "name", + "type": "string" + } + ] + } + ] + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/network/filter": { + "get": { + "summary": "List fields that can be filtered by in the search endpoint", + "tags": [ + "network" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "array", + "items": { + "required": [ + "name", + "uid", + "operators", + "type", + "description" + ], + "properties": { + "name": { + "type": "string" + }, + "uid": { + "type": "string", + "description": "uid used to indentify fields in suggest and search requests" + }, + "operators": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + } + }, + "datatype": { + "type": "string" + }, + "description": { + "type": "string" + } + } + }, + "example": [ + { + "name": "id", + "uid": "id", + "operator": [ + "EXACT", + "IN" + ], + "type": "integer", + "description": "The id" + } + ] + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/network/suggest": { + "post": { + "summary": "Suggest values for filter fields", + "tags": [ + "network" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "filter" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + }, + "description": "Filters to used to narrow down the the result set\n" + }, + "filter": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + }, + "description": "Filter for which to suggest values for. The filter value will be\ntreated as a wildcard.\n" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": true, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "filter": { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "" + } + } + } + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key", + "count" + ], + "properties": { + "key": { + "type": "string", + "description": "Value for the field the suggestion was requested for." + }, + "count": { + "type": "integer", + "format": "int64" + } + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/network/search": { + "post": { + "summary": "Search for networks", + "tags": [ + "network" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "sort" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + }, + "projection": { + "type": "string" + }, + "sort": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "direction" + ], + "properties": { + "field": { + "type": "string" + }, + "direction": { + "type": "string", + "enum": [ + "ASC", + "DESC" + ] + } + } + } + }, + "page": { + "type": "integer" + }, + "size": { + "type": "integer" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "projection": "basic", + "sort": [ + { + "field": "id", + "direction": "ASC" + } + ], + "page": 0, + "size": 20 + } + } + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "object", + "required": [ + "_embedded", + "page" + ], + "properties": { + "_embedded": { + "type": "object", + "required": [ + "strings" + ], + "properties": { + "strings": { + "type": "array", + "items": { + "type": "object", + "description": "

The response structure is subject dependent. Subject structure\ncan be found via the subject endpoint.

\n" + } + } + } + }, + "page": { + "type": "object", + "required": [ + "size", + "totalElements", + "totalPages", + "number" + ], + "properties": { + "size": { + "type": "integer" + }, + "totalElements": { + "type": "integer" + }, + "totalPages": { + "type": "integer" + }, + "number": { + "type": "integer" + } + } + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "id", + "errorRefId", + "code", + "cause" + ], + "properties": { + "id": { + "type": "string", + "description": "Entity id which failed to be retrieved" + }, + "errorRefId": { + "type": "string", + "description": "A unique identifier for the error" + }, + "code": { + "type": "integer", + "description": "http status code of the error" + }, + "cause": { + "type": "string", + "description": "http status code message" + } + } + } + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/group": { + "post": { + "summary": "Create new group on client", + "description": "

Warning:

  • The assetCriticality field is deprecated and its value sent in the request will have no significance.
  • \n
  • To support backward compatibility the response will have assetCriticality value defaulted to 1

\n", + "tags": [ + "group" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string" + }, + "assetCriticality": { + "type": "integer" + } + }, + "example": { + "name": "Example Group" + } + } + } + ], + "responses": { + "201": { + "description": "Success", + "schema": { + "allOf": [ + { + "type": "object", + "required": [ + "id" + ], + "properties": { + "id": { + "type": "integer" + } + }, + "example": { + "id": 12 + } + }, + { + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string" + }, + "assetCriticality": { + "type": "integer" + } + }, + "example": { + "name": "Example Group" + } + }, + { + "type": "object", + "required": [ + "clientId" + ], + "properties": { + "clientId": { + "type": "integer", + "description": "client identifier" + } + } + } + ], + "example": { + "id": 12, + "name": "Example Group", + "assetCriticality": 1, + "clientId": 5 + } + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "409": { + "description": "Conflict" + } + } + } + }, + "/client/{clientId}/group/{groupId}": { + "put": { + "summary": "Update single group on client", + "description": "

Warning:

  • The assetCriticality field is deprecated and its value sent in the request will have no significance.
  • \n

\n", + "tags": [ + "group" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "groupId", + "in": "path", + "description": "Id of group", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string" + }, + "assetCriticality": { + "type": "integer" + } + }, + "example": { + "name": "Example Group" + } + } + } + ], + "responses": { + "201": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "409": { + "description": "Conflict" + } + } + } + }, + "/client/{clientId}/group/model": { + "get": { + "summary": "List projections and their models", + "description": "List projections and their models that can be requested from the search endpoint.\n", + "tags": [ + "group" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "object", + "properties": { + "projections": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "fields": { + "type": "array", + "items": { + "type": "object", + "properties": { + "field": { + "type": "string" + }, + "type": { + "type": "string" + }, + "nested": { + "type": "array", + "items": { + "type": "object", + "description": "Same as ProjectionField" + } + } + } + } + } + } + } + } + }, + "example": { + "projections": [ + { + "name": "basic", + "fields": [ + { + "field": "id", + "type": "integer" + }, + { + "field": "name", + "type": "string" + } + ] + } + ] + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/group/filter": { + "get": { + "summary": "List fields that can be filtered by in the search endpoint", + "tags": [ + "group" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "array", + "items": { + "required": [ + "name", + "uid", + "operators", + "type", + "description" + ], + "properties": { + "name": { + "type": "string" + }, + "uid": { + "type": "string", + "description": "uid used to indentify fields in suggest and search requests" + }, + "operators": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + } + }, + "datatype": { + "type": "string" + }, + "description": { + "type": "string" + } + } + }, + "example": [ + { + "name": "id", + "uid": "id", + "operator": [ + "EXACT", + "IN" + ], + "type": "integer", + "description": "The id" + } + ] + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/group/suggest": { + "post": { + "summary": "Suggest values for filter fields", + "tags": [ + "group" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "filter" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + }, + "description": "Filters to used to narrow down the the result set\n" + }, + "filter": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + }, + "description": "Filter for which to suggest values for. The filter value will be\ntreated as a wildcard.\n" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": true, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "filter": { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "" + } + } + } + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key", + "count" + ], + "properties": { + "key": { + "type": "string", + "description": "Value for the field the suggestion was requested for." + }, + "count": { + "type": "integer", + "format": "int64" + } + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/group/search": { + "post": { + "summary": "Search for groups", + "description": "

Warning:

  • The criticality field is deprecated and its value in the response is defaulted to 1
  • \n
  • Database count fields are deprecated
  • \n
  • Unique Finding count fields are deprecated
  • \n
  • Data refresh field is deprecated
  • \n

\n", + "tags": [ + "group" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "sort" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + }, + "projection": { + "type": "string" + }, + "sort": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "direction" + ], + "properties": { + "field": { + "type": "string" + }, + "direction": { + "type": "string", + "enum": [ + "ASC", + "DESC" + ] + } + } + } + }, + "page": { + "type": "integer" + }, + "size": { + "type": "integer" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "projection": "basic", + "sort": [ + { + "field": "id", + "direction": "ASC" + } + ], + "page": 0, + "size": 20 + } + } + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "object", + "required": [ + "_embedded", + "page" + ], + "properties": { + "_embedded": { + "type": "object", + "required": [ + "strings" + ], + "properties": { + "strings": { + "type": "array", + "items": { + "type": "object", + "description": "

The response structure is subject dependent. Subject structure\ncan be found via the subject endpoint.

\n" + } + } + } + }, + "page": { + "type": "object", + "required": [ + "size", + "totalElements", + "totalPages", + "number" + ], + "properties": { + "size": { + "type": "integer" + }, + "totalElements": { + "type": "integer" + }, + "totalPages": { + "type": "integer" + }, + "number": { + "type": "integer" + } + } + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "id", + "errorRefId", + "code", + "cause" + ], + "properties": { + "id": { + "type": "string", + "description": "Entity id which failed to be retrieved" + }, + "errorRefId": { + "type": "string", + "description": "A unique identifier for the error" + }, + "code": { + "type": "integer", + "description": "http status code of the error" + }, + "cause": { + "type": "string", + "description": "http status code message" + } + } + } + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/group/assign": { + "post": { + "summary": "Assign group(s)", + "tags": [ + "group" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filters", + "userIds" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + }, + "userIds": { + "description": "Collection of user Ids to assign/unassign findings to/from.", + "type": "array", + "items": { + "type": "integer" + } + } + } + } + } + ], + "responses": { + "200": { + "description": "Job Created", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/group/unassign": { + "post": { + "summary": "Unassign group(s)", + "tags": [ + "group" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filters", + "userIds" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + }, + "userIds": { + "description": "Collection of user Ids to assign/unassign findings to/from.", + "type": "array", + "items": { + "type": "integer" + } + } + } + } + } + ], + "responses": { + "200": { + "description": "Job Created", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/group/delete": { + "post": { + "summary": "Delete groups that match the given filter", + "tags": [ + "group" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filterRequest" + ], + "properties": { + "filterRequest": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "sort" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + }, + "projection": { + "type": "string" + }, + "sort": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "direction" + ], + "properties": { + "field": { + "type": "string" + }, + "direction": { + "type": "string", + "enum": [ + "ASC", + "DESC" + ] + } + } + } + }, + "page": { + "type": "integer" + }, + "size": { + "type": "integer" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "projection": "basic", + "sort": [ + { + "field": "id", + "direction": "ASC" + } + ], + "page": 0, + "size": 20 + } + } + }, + "example": { + "filterRequest": { + "filters": [ + { + "field": "name", + "exclusive": false, + "operator": "EXACT", + "value": "Example Group" + } + ] + } + } + } + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "object", + "properties": { + "projections": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "fields": { + "type": "array", + "items": { + "type": "object", + "properties": { + "field": { + "type": "string" + }, + "type": { + "type": "string" + }, + "nested": { + "type": "array", + "items": { + "type": "object", + "description": "Same as ProjectionField" + } + } + } + } + } + } + } + } + }, + "example": { + "projections": [ + { + "name": "basic", + "fields": [ + { + "field": "id", + "type": "integer" + }, + { + "field": "name", + "type": "string" + } + ] + } + ] + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/group/export": { + "post": { + "summary": "Initiate export job", + "description": "

\n

\n

\nEndpoint for initiating an export job against the\ndata outlined in the given FilterRequest.\nThe Group Export Template API (/client/{clientId}/group/export/template) lists the fields that can be exported. The exportableFields section of the request body can be used to choose the fields that needs to be exported.\n

\n", + "tags": [ + "group" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filterRequest", + "fileType", + "noOfRows", + "fileName", + "exportableFields" + ], + "properties": { + "filterRequest": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + } + }, + "fileType": { + "description": "Type of file to be exported into", + "type": "string", + "enum": [ + "JSON", + "CSV" + ] + }, + "noOfRows": { + "description": "Number of rows to be exported by default", + "type": "integer" + }, + "fileName": { + "description": "Name of the exported file", + "type": "string" + }, + "exportableFields": { + "description": "Fields included for Export", + "type": "array", + "items": { + "type": "object", + "required": [ + "heading", + "fields" + ], + "properties": { + "heading": { + "description": "Used to set fields(asset_options/finding_options/group_options/tag_options/user_options)", + "type": "string" + }, + "fields": { + "description": "Fields which are available in exported file", + "type": "array", + "items": { + "type": "object", + "required": [ + "identifierField", + "fieldOrder", + "selected", + "sortable", + "sortOrder", + "sortType" + ], + "properties": { + "identifierField": { + "description": "Internal field which we use to identify the export field", + "type": "string" + }, + "sortable": { + "description": "Is Field Sortable", + "type": "boolean" + }, + "fieldOrder": { + "description": "Order of the export field", + "type": "integer" + }, + "selected": { + "description": "Is Field Selected", + "type": "boolean" + }, + "sortOrder": { + "description": "Sort order of the exportable fields", + "type": "integer" + }, + "sortType": { + "description": "Sort type of the exportable fields - asc/desc", + "type": "string" + } + } + } + } + } + } + } + }, + "example": { + "filterRequest": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + }, + "fileName": "TestGroupExport", + "fileType": "CSV", + "noOfRows": 5000, + "exportableFields": [ + { + "heading": "group_options", + "fields": [ + { + "identifierField": "name", + "fieldOrder": 1, + "selected": false, + "sortable": false, + "sortOrder": 0, + "sortType": "ASC" + } + ] + } + ] + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/group/export/template": { + "get": { + "summary": "List out all fields that are part of configurable export.", + "tags": [ + "group" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "object", + "required": [ + "id", + "clientId", + "userId", + "name", + "description", + "shared", + "isDefault", + "subject", + "exportableFields" + ], + "properties": { + "id": { + "description": "The id", + "type": "integer" + }, + "clientId": { + "description": "Client id", + "type": "integer" + }, + "userId": { + "description": "User id", + "type": "integer" + }, + "name": { + "description": "Template name", + "type": "string" + }, + "description": { + "description": "Template description", + "type": "string" + }, + "shared": { + "description": "Describes whether this template shared or not", + "type": "boolean" + }, + "isDefault": { + "description": "Describes whether this template is default or not", + "type": "boolean" + }, + "subject": { + "description": "For which asset to fetch fileds", + "type": "string" + }, + "exportableFields": { + "description": "List of fileds", + "type": "array", + "items": { + "type": "object", + "required": [ + "heading", + "fields" + ], + "properties": { + "heading": { + "description": "Used to set fields(asset_options/finding_options/group_options/tag_options/user_options)", + "type": "string" + }, + "fields": { + "description": "Fields which are available in exported file", + "type": "array", + "items": { + "type": "object", + "required": [ + "identifierField", + "fieldOrder", + "selected", + "sortable", + "sortOrder", + "sortType" + ], + "properties": { + "identifierField": { + "description": "Internal field which we use to identify the export field", + "type": "string" + }, + "sortable": { + "description": "Is Field Sortable", + "type": "boolean" + }, + "fieldOrder": { + "description": "Order of the export field", + "type": "integer" + }, + "selected": { + "description": "Is Field Selected", + "type": "boolean" + }, + "sortOrder": { + "description": "Sort order of the exportable fields", + "type": "integer" + }, + "sortType": { + "description": "Sort type of the exportable fields - asc/desc", + "type": "string" + } + } + } + } + } + } + } + }, + "example": { + "id": 0, + "clientId": 1, + "userId": 1, + "name": "Group-Export-Template-Name", + "description": "Group-Export-Template-Description", + "shared": false, + "isDefault": false, + "subject": "tag", + "exportableFields": [ + { + "heading": "group_options", + "fields": [ + { + "identifierField": "name", + "displayText": "Name", + "sortable": false, + "fieldOrder": 1, + "selected": false, + "sortOrder": 0, + "sortType": "ASC" + } + ] + } + ] + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/tag": { + "post": { + "summary": "Create new tag on client", + "tags": [ + "tag" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "fields" + ], + "properties": { + "fields": { + "type": "array", + "items": { + "type": "object", + "required": [ + "uid", + "value" + ], + "properties": { + "uid": { + "description": "Unique identifier of the tag value", + "type": "string" + }, + "value": { + "description": "Value assigned to the uid", + "type": "string" + } + } + } + } + }, + "example": { + "fields": [ + { + "uid": "TAG_TYPE", + "value": "CUSTOM" + }, + { + "uid": "NAME", + "value": "MyTag" + }, + { + "uid": "DESCRIPTION", + "value": "Just for me" + }, + { + "uid": "OWNER", + "value": "1" + }, + { + "uid": "COLOR", + "value": "#648d9f" + }, + { + "uid": "LOCKED", + "value": false + }, + { + "uid": "PROPAGATE_TO_ALL_FINDINGS", + "value": true + } + ] + } + } + } + ], + "responses": { + "201": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "id", + "tag" + ], + "properties": { + "id": { + "description": "ID of the tag", + "type": "integer" + }, + "tag": { + "type": "object", + "required": [ + "uid", + "value", + "legacyLink" + ], + "properties": { + "uid": { + "description": "Unique identifier of the tag value", + "type": "string" + }, + "value": { + "description": "

The value assigned to the uid, unique to the parent tag. The value is dependent on the\nuid field type.

\n
    \n
  • USER_LIST: List[String]
  • \n
  • ALL OTHER TYPES: String
  • \n
\n", + "type": "object" + }, + "legacyLink": { + "description": "Internal serialized link to different pages in the UI", + "type": "string" + } + } + } + } + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "409": { + "description": "Conflict" + } + } + }, + "delete": { + "summary": "Bulk Delete Tags", + "tags": [ + "tag" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filterRequest" + ], + "properties": { + "filterRequest": { + "description": "Filter for job requests", + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + } + }, + "forceDeleteTicket": { + "type": "boolean" + } + }, + "example": { + "filterRequest": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + }, + "forceDeleteTicket": true + } + } + } + ], + "responses": { + "200": { + "description": "Job Created", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/tag/{tagId}": { + "put": { + "summary": "Update a tag", + "tags": [ + "tag" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "tagId", + "description": "Id of the tag", + "in": "path", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "fields" + ], + "properties": { + "fields": { + "type": "array", + "items": { + "type": "object", + "required": [ + "uid", + "value" + ], + "properties": { + "uid": { + "description": "Unique identifier of the tag value", + "type": "string" + }, + "value": { + "description": "Value assigned to the uid", + "type": "string" + } + } + } + } + }, + "example": { + "fields": [ + { + "uid": "TAG_TYPE", + "value": "CUSTOM" + }, + { + "uid": "NAME", + "value": "MyTag" + }, + { + "uid": "DESCRIPTION", + "value": "Just for me" + }, + { + "uid": "OWNER", + "value": "1" + }, + { + "uid": "COLOR", + "value": "#648d9f" + }, + { + "uid": "LOCKED", + "value": false + }, + { + "uid": "PROPAGATE_TO_ALL_FINDINGS", + "value": true + } + ] + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "id", + "tag" + ], + "properties": { + "id": { + "description": "ID of the tag", + "type": "integer" + }, + "tag": { + "type": "object", + "required": [ + "uid", + "value", + "legacyLink" + ], + "properties": { + "uid": { + "description": "Unique identifier of the tag value", + "type": "string" + }, + "value": { + "description": "

The value assigned to the uid, unique to the parent tag. The value is dependent on the\nuid field type.

\n
    \n
  • USER_LIST: List[String]
  • \n
  • ALL OTHER TYPES: String
  • \n
\n", + "type": "object" + }, + "legacyLink": { + "description": "Internal serialized link to different pages in the UI", + "type": "string" + } + } + } + } + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + }, + "409": { + "description": "Conflict" + } + } + }, + "delete": { + "summary": "Delete a tag", + "tags": [ + "tag" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "tagId", + "description": "Id of the tag", + "in": "path", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": false, + "schema": { + "type": "object", + "properties": { + "forceDeleteTicket": { + "type": "boolean", + "description": "Force delete the associated ticket or not." + } + } + } + } + ], + "responses": { + "204": { + "description": "Request was processed without errors" + }, + "401": { + "description": "Unauthorized" + } + } + } + }, + "/client/{clientId}/tag/{tagId}/history": { + "get": { + "summary": "Retrieve a paginated list of histories of a tag for the specified client", + "tags": [ + "tag" + ], + "description": "produces:\n- application/json\n", + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "tagId", + "description": "Id of the tag", + "in": "path", + "required": true, + "type": "integer" + }, + { + "name": "size", + "in": "query", + "description": "Size of the page requested", + "required": false, + "type": "integer" + }, + { + "name": "page", + "in": "query", + "description": "Page number being requested (first page: 0)", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "_embedded", + "page" + ], + "properties": { + "_embedded": { + "type": "object", + "required": [ + "tagHistories" + ], + "properties": { + "tagHistories": { + "type": "array", + "items": { + "type": "object", + "required": [ + "tagId", + "log", + "created" + ], + "properties": { + "tagId": { + "type": "integer" + }, + "log": { + "type": "string", + "pattern": "[a-zA-Z0-9'_\\-]+" + }, + "created": { + "type": "string", + "format": "date-time" + } + } + } + } + } + }, + "page": { + "type": "object", + "required": [ + "size", + "totalElements", + "totalPages", + "number" + ], + "properties": { + "size": { + "type": "integer" + }, + "totalElements": { + "type": "integer" + }, + "totalPages": { + "type": "integer" + }, + "number": { + "type": "integer" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/tag/model": { + "get": { + "summary": "List projections and their models", + "description": "List projections and their models that can be requested from the search endpoint.\n", + "tags": [ + "tag" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "object", + "properties": { + "projections": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "fields": { + "type": "array", + "items": { + "type": "object", + "properties": { + "field": { + "type": "string" + }, + "type": { + "type": "string" + }, + "nested": { + "type": "array", + "items": { + "type": "object", + "description": "Same as ProjectionField" + } + } + } + } + } + } + } + } + }, + "example": { + "projections": [ + { + "name": "basic", + "fields": [ + { + "field": "id", + "type": "integer" + }, + { + "field": "name", + "type": "string" + } + ] + } + ] + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/tag/filter": { + "get": { + "summary": "List fields that can be filtered by in the search endpoint", + "tags": [ + "tag" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "array", + "items": { + "required": [ + "name", + "uid", + "operators", + "type", + "description" + ], + "properties": { + "name": { + "type": "string" + }, + "uid": { + "type": "string", + "description": "uid used to indentify fields in suggest and search requests" + }, + "operators": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + } + }, + "datatype": { + "type": "string" + }, + "description": { + "type": "string" + } + } + }, + "example": [ + { + "name": "id", + "uid": "id", + "operator": [ + "EXACT", + "IN" + ], + "type": "integer", + "description": "The id" + } + ] + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/tag/suggest": { + "post": { + "summary": "Suggest values for filter fields", + "tags": [ + "tag" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "filter" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + }, + "description": "Filters to used to narrow down the the result set\n" + }, + "filter": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + }, + "description": "Filter for which to suggest values for. The filter value will be\ntreated as a wildcard.\n" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": true, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "filter": { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "" + } + } + } + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key", + "count" + ], + "properties": { + "key": { + "type": "string", + "description": "Value for the field the suggestion was requested for." + }, + "count": { + "type": "integer", + "format": "int64" + } + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/tag/search": { + "post": { + "summary": "Search for tags", + "tags": [ + "tag" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "sort" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + }, + "projection": { + "type": "string" + }, + "sort": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "direction" + ], + "properties": { + "field": { + "type": "string" + }, + "direction": { + "type": "string", + "enum": [ + "ASC", + "DESC" + ] + } + } + } + }, + "page": { + "type": "integer" + }, + "size": { + "type": "integer" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "projection": "basic", + "sort": [ + { + "field": "id", + "direction": "ASC" + } + ], + "page": 0, + "size": 20 + } + } + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "object", + "required": [ + "_embedded", + "page" + ], + "properties": { + "_embedded": { + "type": "object", + "required": [ + "strings" + ], + "properties": { + "strings": { + "type": "array", + "items": { + "type": "object", + "description": "

The response structure is subject dependent. Subject structure\ncan be found via the subject endpoint.

\n" + } + } + } + }, + "page": { + "type": "object", + "required": [ + "size", + "totalElements", + "totalPages", + "number" + ], + "properties": { + "size": { + "type": "integer" + }, + "totalElements": { + "type": "integer" + }, + "totalPages": { + "type": "integer" + }, + "number": { + "type": "integer" + } + } + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "id", + "errorRefId", + "code", + "cause" + ], + "properties": { + "id": { + "type": "string", + "description": "Entity id which failed to be retrieved" + }, + "errorRefId": { + "type": "string", + "description": "A unique identifier for the error" + }, + "code": { + "type": "integer", + "description": "http status code of the error" + }, + "cause": { + "type": "string", + "description": "http status code message" + } + } + } + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/tag/export": { + "post": { + "summary": "Initiate export job", + "description": "

\n

\n

\nEndpoint for initiating an export job against the\ndata outlined in the given FilterRequest.\nThe Tag Export Template API (/client/{clientId}/tag/export/template) lists the fields that can be exported. The exportableFields section of the request body can be used to choose the fields that needs to be exported.\n

\n", + "tags": [ + "tag" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filterRequest", + "fileType", + "noOfRows", + "fileName", + "exportableFields" + ], + "properties": { + "filterRequest": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + } + }, + "fileType": { + "description": "Type of file to be exported into", + "type": "string", + "enum": [ + "JSON", + "CSV" + ] + }, + "noOfRows": { + "description": "Number of rows to be exported by default", + "type": "integer" + }, + "fileName": { + "description": "Name of the exported file", + "type": "string" + }, + "exportableFields": { + "description": "Fields included for Export", + "type": "array", + "items": { + "type": "object", + "required": [ + "heading", + "fields" + ], + "properties": { + "heading": { + "description": "Used to set fields(asset_options/finding_options/group_options/tag_options/user_options)", + "type": "string" + }, + "fields": { + "description": "Fields which are available in exported file", + "type": "array", + "items": { + "type": "object", + "required": [ + "identifierField", + "fieldOrder", + "selected", + "sortable", + "sortOrder", + "sortType" + ], + "properties": { + "identifierField": { + "description": "Internal field which we use to identify the export field", + "type": "string" + }, + "sortable": { + "description": "Is Field Sortable", + "type": "boolean" + }, + "fieldOrder": { + "description": "Order of the export field", + "type": "integer" + }, + "selected": { + "description": "Is Field Selected", + "type": "boolean" + }, + "sortOrder": { + "description": "Sort order of the exportable fields", + "type": "integer" + }, + "sortType": { + "description": "Sort type of the exportable fields - asc/desc", + "type": "string" + } + } + } + } + } + } + } + }, + "example": { + "filterRequest": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + }, + "fileName": "TestTagExport", + "fileType": "CSV", + "noOfRows": 5000, + "exportableFields": [ + { + "heading": "tag_options", + "fields": [ + { + "identifierField": "name", + "fieldOrder": 1, + "selected": "flase", + "sortable": false, + "sortOrder": 0, + "sortType": "ASC" + } + ] + } + ] + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/tag/export/template": { + "get": { + "summary": "List out all fields that are part of configurable export.", + "tags": [ + "tag" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "object", + "required": [ + "id", + "clientId", + "userId", + "name", + "description", + "shared", + "isDefault", + "subject", + "exportableFields" + ], + "properties": { + "id": { + "description": "The id", + "type": "integer" + }, + "clientId": { + "description": "Client id", + "type": "integer" + }, + "userId": { + "description": "User id", + "type": "integer" + }, + "name": { + "description": "Template name", + "type": "string" + }, + "description": { + "description": "Template description", + "type": "string" + }, + "shared": { + "description": "Describes whether this template shared or not", + "type": "boolean" + }, + "isDefault": { + "description": "Describes whether this template is default or not", + "type": "boolean" + }, + "subject": { + "description": "For which asset to fetch fileds", + "type": "string" + }, + "exportableFields": { + "description": "List of fileds", + "type": "array", + "items": { + "type": "object", + "required": [ + "heading", + "fields" + ], + "properties": { + "heading": { + "description": "Used to set fields(asset_options/finding_options/group_options/tag_options/user_options)", + "type": "string" + }, + "fields": { + "description": "Fields which are available in exported file", + "type": "array", + "items": { + "type": "object", + "required": [ + "identifierField", + "fieldOrder", + "selected", + "sortable", + "sortOrder", + "sortType" + ], + "properties": { + "identifierField": { + "description": "Internal field which we use to identify the export field", + "type": "string" + }, + "sortable": { + "description": "Is Field Sortable", + "type": "boolean" + }, + "fieldOrder": { + "description": "Order of the export field", + "type": "integer" + }, + "selected": { + "description": "Is Field Selected", + "type": "boolean" + }, + "sortOrder": { + "description": "Sort order of the exportable fields", + "type": "integer" + }, + "sortType": { + "description": "Sort type of the exportable fields - asc/desc", + "type": "string" + } + } + } + } + } + } + } + }, + "example": { + "id": 0, + "clientId": 1, + "userId": 1, + "name": "Tag-Export-Template-Name", + "description": "Tag-Export-Template-Description", + "shared": false, + "isDefault": false, + "subject": "tag", + "exportableFields": [ + { + "heading": "tag_options", + "fields": [ + { + "identifierField": "name", + "displayText": "Name", + "sortable": false, + "fieldOrder": 1, + "selected": false, + "sortOrder": 0, + "sortType": "ASC" + } + ] + } + ] + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/tag/{tagId}/attachment": { + "post": { + "summary": "Upload 1 or more attachment files for a tag", + "description": "Only the owner of the specified tag can upload files to it\n", + "tags": [ + "attachment" + ], + "consumes": [ + "multipart/form-data" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "tagId", + "description": "tag id\n", + "in": "path", + "required": true, + "type": "integer" + }, + { + "in": "formData", + "name": "attachments", + "type": "file", + "required": true, + "description": "An attachment file" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "array", + "items": { + "type": "object", + "required": [ + "filename", + "uuid", + "contentType", + "contentLength" + ], + "properties": { + "filename": { + "type": "string" + }, + "uuid": { + "type": "string" + }, + "contentType": { + "type": "string" + }, + "contentLength": { + "type": "integer" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Not Found" + } + } + }, + "get": { + "summary": "List out the attachments on the given tag", + "description": "Depenedent upon whether the caller has access to the tag\n", + "tags": [ + "attachment" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "tagId", + "description": "tag id\n", + "in": "path", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "array", + "items": { + "type": "object", + "required": [ + "filename", + "uuid", + "contentType", + "contentLength" + ], + "properties": { + "filename": { + "type": "string" + }, + "uuid": { + "type": "string" + }, + "contentType": { + "type": "string" + }, + "contentLength": { + "type": "integer" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/tag/{tagId}/attachment/{attachmentUUID}": { + "get": { + "summary": "Fetch tag attachment by UUID", + "description": "Depenedent upon whether the caller has access to the tag\n", + "tags": [ + "attachment" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "tagId", + "description": "tag id\n", + "in": "path", + "required": true, + "type": "integer" + }, + { + "name": "attachmentUUID", + "description": "The attachment UUID, given when the attachments were uploaded\n", + "in": "path", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "description": "Ok" + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + }, + "406": { + "description": "MIME Mismatch\nTry changing from application/octet-stream to application/json, or vice-versa." + } + } + }, + "delete": { + "summary": "Remove an attachment file for a tag", + "description": "Only the owner of the specified tag can removes attached files\n", + "tags": [ + "attachment" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "tagId", + "description": "tag id\n", + "in": "path", + "required": true, + "type": "integer" + }, + { + "name": "attachmentUUID", + "description": "The attachment UUID, given when the attachments were uploaded\n", + "in": "path", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "description": "List of attachment UUIDs that were deleted successfully\n", + "type": "array", + "items": { + "type": "string" + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/tag/{tagId}/attachment/{attachmentUUID}/meta": { + "get": { + "summary": "Fetch tag attachment metadata", + "description": "Depenedent upon whether the caller has access to the tag\n", + "tags": [ + "attachment" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "tagId", + "description": "tag id\n", + "in": "path", + "required": true, + "type": "integer" + }, + { + "name": "attachmentUUID", + "description": "The attachment UUID, given when the attachments were uploaded\n", + "in": "path", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "filename", + "uuid", + "contentType", + "contentLength" + ], + "properties": { + "filename": { + "type": "string" + }, + "uuid": { + "type": "string" + }, + "contentType": { + "type": "string" + }, + "contentLength": { + "type": "integer" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/search/{subject}/filter": { + "get": { + "summary": "List saved and shared filters", + "tags": [ + "filter" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "subject", + "description": "

Subject to search against. Supported subject are available\nthrough the GET method on /subjects
\nExample: \"hostFinding\"

\n", + "in": "path", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "description": { + "description": "description of the filter", + "type": "string" + }, + "filters": { + "description": "Array of filter values", + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "description": "Field to filter on", + "type": "string" + }, + "exclusive": { + "description": "True if \"is not\" false means \"is\"", + "type": "boolean" + }, + "operator": { + "description": "The operator to filter with", + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "description": "Value to filter on", + "type": "string" + } + } + } + }, + "id": { + "description": "ID of filter", + "type": "number" + }, + "name": { + "description": "name of the filter", + "type": "string" + }, + "shared": { + "description": "True if this filter is shared with all users on the client", + "type": "boolean" + }, + "standard": { + "description": "If true, will be shown to all platform users", + "type": "boolean" + }, + "system": { + "description": "True if this filter is to be set as a system filter", + "type": "boolean" + }, + "dateUntilNewBadgeShown": { + "description": "a future date to be set which adds up to the count shown as a badge in the frontend", + "format": "date", + "type": "string" + }, + "weight": { + "description": "weight ranges from 0 - 999 (used by the frontend)", + "type": "number" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + } + } + }, + "post": { + "summary": "Create a new saved filter", + "tags": [ + "filter" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "subject", + "description": "

Subject to search against. Supported subject are available\nthrough the GET method on /subjects
\nExample: \"hostFinding\"

\n", + "in": "path", + "required": true, + "type": "string" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "description", + "filters", + "name", + "shared", + "standard" + ], + "properties": { + "description": { + "description": "description of the saved/shared filter", + "type": "string" + }, + "filters": { + "description": "Array of filter values", + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "description": "Field to filter on", + "type": "string" + }, + "exclusive": { + "description": "True if \"is not\" false means \"is\"", + "type": "boolean" + }, + "operator": { + "description": "The operator to filter with", + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "description": "Value to filter on", + "type": "string" + } + } + } + }, + "name": { + "description": "name of the saved/shared filter", + "type": "string" + }, + "shared": { + "description": "True if this filter is shared with all users on the client", + "type": "boolean" + }, + "standard": { + "description": "If true, will be shown to all platform users", + "type": "boolean" + } + } + } + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "type": "object", + "properties": { + "description": { + "description": "description of the filter", + "type": "string" + }, + "filters": { + "description": "Array of filter values", + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "description": "Field to filter on", + "type": "string" + }, + "exclusive": { + "description": "True if \"is not\" false means \"is\"", + "type": "boolean" + }, + "operator": { + "description": "The operator to filter with", + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "description": "Value to filter on", + "type": "string" + } + } + } + }, + "id": { + "description": "ID of filter", + "type": "number" + }, + "name": { + "description": "name of the filter", + "type": "string" + }, + "shared": { + "description": "True if this filter is shared with all users on the client", + "type": "boolean" + }, + "standard": { + "description": "If true, will be shown to all platform users", + "type": "boolean" + }, + "system": { + "description": "True if this filter is to be set as a system filter", + "type": "boolean" + }, + "dateUntilNewBadgeShown": { + "description": "a future date to be set which adds up to the count shown as a badge in the frontend", + "format": "date", + "type": "string" + }, + "weight": { + "description": "weight ranges from 0 - 999 (used by the frontend)", + "type": "number" + } + } + } + }, + "401": { + "description": "Unauthorized" + } + } + } + }, + "/client/{clientId}/search/{subject}/filter/{filterId}": { + "get": { + "summary": "Retrieve specific filter", + "tags": [ + "filter" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "subject", + "description": "

Subject to search against. Supported subject are available\nthrough the GET method on /subjects
\nExample: \"hostFinding\"

\n", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "filterId", + "description": "Id of the filter", + "in": "path", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "properties": { + "description": { + "description": "description of the filter", + "type": "string" + }, + "filters": { + "description": "Array of filter values", + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "description": "Field to filter on", + "type": "string" + }, + "exclusive": { + "description": "True if \"is not\" false means \"is\"", + "type": "boolean" + }, + "operator": { + "description": "The operator to filter with", + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "description": "Value to filter on", + "type": "string" + } + } + } + }, + "id": { + "description": "ID of filter", + "type": "number" + }, + "name": { + "description": "name of the filter", + "type": "string" + }, + "shared": { + "description": "True if this filter is shared with all users on the client", + "type": "boolean" + }, + "standard": { + "description": "If true, will be shown to all platform users", + "type": "boolean" + }, + "system": { + "description": "True if this filter is to be set as a system filter", + "type": "boolean" + }, + "dateUntilNewBadgeShown": { + "description": "a future date to be set which adds up to the count shown as a badge in the frontend", + "format": "date", + "type": "string" + }, + "weight": { + "description": "weight ranges from 0 - 999 (used by the frontend)", + "type": "number" + } + } + } + }, + "401": { + "description": "Unauthorized" + } + } + }, + "put": { + "summary": "Update specific filter", + "tags": [ + "filter" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "subject", + "description": "

Subject to search against. Supported subject are available\nthrough the GET method on /subjects
\nExample: \"hostFinding\"

\n", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "filterId", + "description": "Id of the filter", + "in": "path", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "description": { + "description": "description of the saved/shared filter", + "type": "string" + }, + "filters": { + "description": "Array of filter values", + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "description": "Field to filter on", + "type": "string" + }, + "exclusive": { + "description": "True if \"is not\" false means \"is\"", + "type": "boolean" + }, + "operator": { + "description": "The operator to filter with", + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "description": "Value to filter on", + "type": "string" + } + } + } + }, + "name": { + "description": "name of the saved/shared filter", + "type": "string" + }, + "shared": { + "description": "True if this filter is shared with all users on the client", + "type": "boolean" + }, + "standard": { + "description": "If true, will be shown to all platform users", + "type": "boolean" + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "properties": { + "description": { + "description": "description of the filter", + "type": "string" + }, + "filters": { + "description": "Array of filter values", + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "description": "Field to filter on", + "type": "string" + }, + "exclusive": { + "description": "True if \"is not\" false means \"is\"", + "type": "boolean" + }, + "operator": { + "description": "The operator to filter with", + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "description": "Value to filter on", + "type": "string" + } + } + } + }, + "id": { + "description": "ID of filter", + "type": "number" + }, + "name": { + "description": "name of the filter", + "type": "string" + }, + "shared": { + "description": "True if this filter is shared with all users on the client", + "type": "boolean" + }, + "standard": { + "description": "If true, will be shown to all platform users", + "type": "boolean" + }, + "system": { + "description": "True if this filter is to be set as a system filter", + "type": "boolean" + }, + "dateUntilNewBadgeShown": { + "description": "a future date to be set which adds up to the count shown as a badge in the frontend", + "format": "date", + "type": "string" + }, + "weight": { + "description": "weight ranges from 0 - 999 (used by the frontend)", + "type": "number" + } + } + } + }, + "401": { + "description": "Unauthorized" + } + } + }, + "delete": { + "summary": "Delete specific filter", + "tags": [ + "filter" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "subject", + "description": "

Subject to search against. Supported subject are available\nthrough the GET method on /subjects
\nExample: \"hostFinding\"

\n", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "filterId", + "description": "Id of the filter", + "in": "path", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Deleted" + }, + "401": { + "description": "Unauthorized" + } + } + } + }, + "/search/{subject}/filter": { + "get": { + "summary": "List system filters", + "tags": [ + "filter" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "subject", + "description": "

Subject to search against. Supported subject are available\nthrough the GET method on /subjects
\nExample: \"hostFinding\"

\n", + "in": "path", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "description": { + "description": "description of the filter", + "type": "string" + }, + "filters": { + "description": "Array of filter values", + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "description": "Field to filter on", + "type": "string" + }, + "exclusive": { + "description": "True if \"is not\" false means \"is\"", + "type": "boolean" + }, + "operator": { + "description": "The operator to filter with", + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "description": "Value to filter on", + "type": "string" + } + } + } + }, + "id": { + "description": "ID of filter", + "type": "number" + }, + "name": { + "description": "name of the filter", + "type": "string" + }, + "shared": { + "description": "True if this filter is shared with all users on the client", + "type": "boolean" + }, + "standard": { + "description": "If true, will be shown to all platform users", + "type": "boolean" + }, + "system": { + "description": "True if this filter is to be set as a system filter", + "type": "boolean" + }, + "dateUntilNewBadgeShown": { + "description": "a future date to be set which adds up to the count shown as a badge in the frontend", + "format": "date", + "type": "string" + }, + "weight": { + "description": "weight ranges from 0 - 999 (used by the frontend)", + "type": "number" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + } + } + } + }, + "/search/{subject}/filter/{filterId}": { + "get": { + "summary": "Retrieve specific system filter", + "tags": [ + "filter" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "subject", + "description": "

Subject to search against. Supported subject are available\nthrough the GET method on /subjects
\nExample: \"hostFinding\"

\n", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "filterId", + "description": "Id of the filter", + "in": "path", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "properties": { + "description": { + "description": "description of the filter", + "type": "string" + }, + "filters": { + "description": "Array of filter values", + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "description": "Field to filter on", + "type": "string" + }, + "exclusive": { + "description": "True if \"is not\" false means \"is\"", + "type": "boolean" + }, + "operator": { + "description": "The operator to filter with", + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "description": "Value to filter on", + "type": "string" + } + } + } + }, + "id": { + "description": "ID of filter", + "type": "number" + }, + "name": { + "description": "name of the filter", + "type": "string" + }, + "shared": { + "description": "True if this filter is shared with all users on the client", + "type": "boolean" + }, + "standard": { + "description": "If true, will be shown to all platform users", + "type": "boolean" + }, + "system": { + "description": "True if this filter is to be set as a system filter", + "type": "boolean" + }, + "dateUntilNewBadgeShown": { + "description": "a future date to be set which adds up to the count shown as a badge in the frontend", + "format": "date", + "type": "string" + }, + "weight": { + "description": "weight ranges from 0 - 999 (used by the frontend)", + "type": "number" + } + } + } + }, + "401": { + "description": "Unauthorized" + } + } + } + }, + "/client/{clientId}/upload": { + "get": { + "summary": "List uploads in a client", + "tags": [ + "upload" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "assessmentId", + "description": "Id of Assessment (This parameter can be obtained via the POST method on\n'/client/{clientId}/assessment/search')\n", + "in": "query", + "required": false, + "type": "integer" + }, + { + "name": "size", + "in": "query", + "description": "Size of the page requested", + "required": false, + "type": "integer" + }, + { + "name": "page", + "in": "query", + "description": "Page number being requested (first page: 0)", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "_embedded", + "page" + ], + "properties": { + "_embedded": { + "type": "object", + "required": [ + "uploads" + ], + "properties": { + "uploads": { + "type": "array", + "items": { + "allOf": [ + { + "type": "object", + "required": [ + "id" + ], + "properties": { + "id": { + "type": "integer" + } + }, + "example": { + "id": 12 + } + }, + { + "allOf": [ + { + "type": "object", + "required": [ + "assessmentId", + "networkId" + ], + "properties": { + "assessmentId": { + "type": "integer" + }, + "networkId": { + "type": "integer" + } + } + }, + { + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string" + } + } + } + ] + }, + { + "type": "object", + "required": [ + "state", + "userId" + ], + "properties": { + "userId": { + "type": "integer" + }, + "state": { + "type": "string", + "enum": [ + "Pending", + "FingerPrinting", + "Processing", + "Success", + "PartialSuccess", + "Failure" + ] + }, + "connectorId": { + "type": "integer", + "description": "Id of the connector if the upload has been automatically created by a connector. Otherwise, null." + } + } + } + ] + } + } + } + }, + "page": { + "type": "object", + "required": [ + "size", + "totalElements", + "totalPages", + "number" + ], + "properties": { + "size": { + "type": "integer" + }, + "totalElements": { + "type": "integer" + }, + "totalPages": { + "type": "integer" + }, + "number": { + "type": "integer" + } + } + } + } + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + }, + "post": { + "summary": "Create new upload", + "tags": [ + "upload" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "allOf": [ + { + "type": "object", + "required": [ + "assessmentId", + "networkId" + ], + "properties": { + "assessmentId": { + "type": "integer" + }, + "networkId": { + "type": "integer" + } + } + }, + { + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string" + } + } + } + ] + } + } + ], + "responses": { + "201": { + "description": "Success", + "schema": { + "allOf": [ + { + "type": "object", + "required": [ + "id" + ], + "properties": { + "id": { + "type": "integer" + } + }, + "example": { + "id": 12 + } + }, + { + "allOf": [ + { + "type": "object", + "required": [ + "assessmentId", + "networkId" + ], + "properties": { + "assessmentId": { + "type": "integer" + }, + "networkId": { + "type": "integer" + } + } + }, + { + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string" + } + } + } + ] + }, + { + "type": "object", + "required": [ + "state", + "userId" + ], + "properties": { + "userId": { + "type": "integer" + }, + "state": { + "type": "string", + "enum": [ + "Pending", + "FingerPrinting", + "Processing", + "Success", + "PartialSuccess", + "Failure" + ] + }, + "connectorId": { + "type": "integer", + "description": "Id of the connector if the upload has been automatically created by a connector. Otherwise, null." + } + } + } + ] + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/upload/{uploadId}": { + "get": { + "summary": "State of an upload", + "tags": [ + "upload" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "uploadId", + "description": "Id of upload (This parameter can be obtained via the GET method on\n'/client/{clientId}/upload')\n", + "in": "path", + "required": true, + "type": "integer" + } + ], + "produces": [ + "application/json" + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "allOf": [ + { + "type": "object", + "required": [ + "id" + ], + "properties": { + "id": { + "type": "integer" + } + }, + "example": { + "id": 12 + } + }, + { + "allOf": [ + { + "type": "object", + "required": [ + "assessmentId", + "networkId" + ], + "properties": { + "assessmentId": { + "type": "integer" + }, + "networkId": { + "type": "integer" + } + } + }, + { + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string" + } + } + } + ] + }, + { + "type": "object", + "required": [ + "state", + "userId" + ], + "properties": { + "userId": { + "type": "integer" + }, + "state": { + "type": "string", + "enum": [ + "Pending", + "FingerPrinting", + "Processing", + "Success", + "PartialSuccess", + "Failure" + ] + }, + "connectorId": { + "type": "integer", + "description": "Id of the connector if the upload has been automatically created by a connector. Otherwise, null." + } + } + } + ] + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + }, + "put": { + "summary": "Update an upload", + "description": "Only available before an upload started processing\n", + "tags": [ + "upload" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "uploadId", + "description": "Id of upload (This parameter can be obtained via the GET method on\n'/client/{clientId}/upload')\n", + "in": "path", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "allOf": [ + { + "type": "object", + "required": [ + "assessmentId", + "networkId" + ], + "properties": { + "assessmentId": { + "type": "integer" + }, + "networkId": { + "type": "integer" + } + } + }, + { + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string" + } + } + } + ] + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "allOf": [ + { + "type": "object", + "required": [ + "id" + ], + "properties": { + "id": { + "type": "integer" + } + }, + "example": { + "id": 12 + } + }, + { + "allOf": [ + { + "type": "object", + "required": [ + "assessmentId", + "networkId" + ], + "properties": { + "assessmentId": { + "type": "integer" + }, + "networkId": { + "type": "integer" + } + } + }, + { + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string" + } + } + } + ] + }, + { + "type": "object", + "required": [ + "state", + "userId" + ], + "properties": { + "userId": { + "type": "integer" + }, + "state": { + "type": "string", + "enum": [ + "Pending", + "FingerPrinting", + "Processing", + "Success", + "PartialSuccess", + "Failure" + ] + }, + "connectorId": { + "type": "integer", + "description": "Id of the connector if the upload has been automatically created by a connector. Otherwise, null." + } + } + } + ] + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + }, + "delete": { + "summary": "Delete an upload", + "description": "Only available while the upload is not processing (before start and\nafter files are done processing)\n", + "tags": [ + "upload" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "uploadId", + "description": "Id of upload (This parameter can be obtained via the GET method on\n'/client/{clientId}/upload')\n", + "in": "path", + "required": true, + "type": "integer" + } + ], + "responses": { + "204": { + "description": "Success" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/upload/{uploadId}/file": { + "get": { + "summary": "List files in an upload", + "tags": [ + "upload" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "uploadId", + "description": "Id of upload (This parameter can be obtained via the GET method on\n'/client/{clientId}/upload')\n", + "in": "path", + "required": true, + "type": "integer" + }, + { + "name": "size", + "in": "query", + "description": "Size of the page requested", + "required": false, + "type": "integer" + }, + { + "name": "page", + "in": "query", + "description": "Page number being requested (first page: 0)", + "required": false, + "type": "integer" + } + ], + "produces": [ + "application/json" + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "_embedded", + "page" + ], + "properties": { + "_embedded": { + "type": "object", + "required": [ + "files" + ], + "properties": { + "files": { + "type": "array", + "items": { + "allOf": [ + { + "type": "object", + "required": [ + "id" + ], + "properties": { + "id": { + "type": "integer" + } + }, + "example": { + "id": 12 + } + }, + { + "properties": { + "networkId": { + "type": "integer" + }, + "applicationId": { + "type": "integer" + } + } + }, + { + "type": "object", + "properties": { + "state": { + "type": "string" + }, + "scannerName": { + "type": "string" + }, + "scannerUuid": { + "type": "string" + } + } + } + ], + "example": { + "id": 53606, + "scannerName": "Nexpose", + "scannerUuid": "NEXPOSE", + "assessmentId": 8070, + "networkId": 15, + "applicationId": null, + "state": "PROCESSED" + } + } + } + } + }, + "page": { + "type": "object", + "required": [ + "size", + "totalElements", + "totalPages", + "number" + ], + "properties": { + "size": { + "type": "integer" + }, + "totalElements": { + "type": "integer" + }, + "totalPages": { + "type": "integer" + }, + "number": { + "type": "integer" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + }, + "post": { + "summary": "Add a file to an upload", + "description": "Only available before an upload started processing\n", + "tags": [ + "upload" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "uploadId", + "description": "Id of upload (This parameter can be obtained via the GET method on\n'/client/{clientId}/upload')\n", + "in": "path", + "required": true, + "type": "integer" + }, + { + "in": "formData", + "name": "scanFile", + "type": "file", + "required": true, + "description": "A scan file" + } + ], + "consumes": [ + "multipart/form-data" + ], + "produces": [ + "application/json" + ], + "responses": { + "201": { + "description": "Success", + "schema": { + "type": "array", + "items": { + "allOf": [ + { + "type": "object", + "required": [ + "id" + ], + "properties": { + "id": { + "type": "integer" + } + }, + "example": { + "id": 12 + } + }, + { + "properties": { + "networkId": { + "type": "integer" + }, + "applicationId": { + "type": "integer" + } + } + }, + { + "type": "object", + "properties": { + "state": { + "type": "string" + }, + "scannerName": { + "type": "string" + }, + "scannerUuid": { + "type": "string" + } + } + } + ], + "example": { + "id": 53606, + "scannerName": "Nexpose", + "scannerUuid": "NEXPOSE", + "assessmentId": 8070, + "networkId": 15, + "applicationId": null, + "state": "PROCESSED" + } + } + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + }, + "409": { + "description": "Conflict" + } + } + } + }, + "/client/{clientId}/upload/{uploadId}/file/{fileId}": { + "put": { + "summary": "Configure an upload file", + "description": "Only available before an upload started processing\nOnly fields that are present and not null will be updated\nAssessment field is deprecated and only updated at upload level\n", + "tags": [ + "upload" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "uploadId", + "description": "Id of upload (This parameter can be obtained via the GET method on\n'/client/{clientId}/upload')\n", + "in": "path", + "required": true, + "type": "integer" + }, + { + "name": "fileId", + "description": "Id of upload file (This parameter can be obtained via the GET method on\n'/client/{clientId}/upload/{uploadId}/file')\n", + "in": "path", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "properties": { + "networkId": { + "type": "integer" + }, + "applicationId": { + "type": "integer" + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "allOf": [ + { + "type": "object", + "required": [ + "id" + ], + "properties": { + "id": { + "type": "integer" + } + }, + "example": { + "id": 12 + } + }, + { + "properties": { + "networkId": { + "type": "integer" + }, + "applicationId": { + "type": "integer" + } + } + }, + { + "type": "object", + "properties": { + "state": { + "type": "string" + }, + "scannerName": { + "type": "string" + }, + "scannerUuid": { + "type": "string" + } + } + } + ], + "example": { + "id": 53606, + "scannerName": "Nexpose", + "scannerUuid": "NEXPOSE", + "assessmentId": 8070, + "networkId": 15, + "applicationId": null, + "state": "PROCESSED" + } + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + }, + "delete": { + "summary": "Remove file from upload", + "description": "Only available before an upload started processing\n", + "tags": [ + "upload" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "uploadId", + "description": "Id of upload (This parameter can be obtained via the GET method on\n'/client/{clientId}/upload')\n", + "in": "path", + "required": true, + "type": "integer" + }, + { + "name": "fileId", + "description": "Id of upload file (This parameter can be obtained via the GET method on\n'/client/{clientId}/upload/{uploadId}/file')\n", + "in": "path", + "required": true, + "type": "integer" + } + ], + "responses": { + "204": { + "description": "Success" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/upload/{uploadId}/file/download": { + "get": { + "summary": "Download all upload files in the Upload", + "description": "Only available for files that are uploaded by using this API. Files\nuploaded via UI/connectors are not supported right now.\n", + "tags": [ + "upload" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "uploadId", + "description": "Id of upload (This parameter can be obtained via the GET method on\n'/client/{clientId}/upload')\n", + "in": "path", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "description": "Ok" + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + }, + "406": { + "description": "MIME Mismatch\nTry changing from application/octet-stream to application/json, or vice-versa." + } + } + } + }, + "/client/{clientId}/upload/{uploadId}/file/{fileUUID}": { + "get": { + "summary": "Fetch an upload file by UUID", + "description": "Only available for files that are uploaded by using this API. Files\nuploaded by Risksense UI are not supported right now.\n", + "tags": [ + "upload" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "uploadId", + "description": "Id of upload (This parameter can be obtained via the GET method on\n'/client/{clientId}/upload')\n", + "in": "path", + "required": true, + "type": "integer" + }, + { + "name": "fileUUID", + "description": "UUID of the upload file (This parameter can be obtained via the GET method on\n'/client/{clientId}/upload/{uploadId}/file')\n", + "in": "path", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "description": "Ok" + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + }, + "406": { + "description": "MIME Mismatch\nTry changing from application/octet-stream to application/json, or vice-versa." + } + } + } + }, + "/client/{clientId}/upload/{uploadId}/start": { + "post": { + "summary": "Start processing an upload", + "tags": [ + "upload" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "uploadId", + "description": "Id of upload (This parameter can be obtained via the GET method on\n'/client/{clientId}/upload')\n", + "in": "path", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": false, + "schema": { + "properties": { + "autoUrba": { + "type": "boolean", + "description": "Set this to true to automatically update remediation by assessment for the applicable network" + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "allOf": [ + { + "type": "object", + "required": [ + "id" + ], + "properties": { + "id": { + "type": "integer" + } + }, + "example": { + "id": 12 + } + }, + { + "allOf": [ + { + "type": "object", + "required": [ + "assessmentId", + "networkId" + ], + "properties": { + "assessmentId": { + "type": "integer" + }, + "networkId": { + "type": "integer" + } + } + }, + { + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string" + } + } + } + ] + }, + { + "type": "object", + "required": [ + "state", + "userId" + ], + "properties": { + "userId": { + "type": "integer" + }, + "state": { + "type": "string", + "enum": [ + "Pending", + "FingerPrinting", + "Processing", + "Success", + "PartialSuccess", + "Failure" + ] + }, + "connectorId": { + "type": "integer", + "description": "Id of the connector if the upload has been automatically created by a connector. Otherwise, null." + } + } + } + ] + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/connector": { + "get": { + "summary": "Paginate connectors in client", + "tags": [ + "connector" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "size", + "in": "query", + "description": "Size of the page requested", + "required": false, + "type": "integer" + }, + { + "name": "page", + "in": "query", + "description": "Page number being requested (first page: 0)", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "_embedded", + "page" + ], + "properties": { + "_embedded": { + "type": "object", + "properties": { + "connectors": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "number" + }, + "type": { + "type": "string", + "enum": [ + "CENZIC_HAILSTORM", + "NESSUS", + "NEXPOSE", + "QUALYS_ASSET", + "QUALYS_VULNERABILITY", + "SECURE_SPHERE_115", + "TENABLE_SECURITY_CENTER" + ] + }, + "name": { + "type": "string" + }, + "connection": { + "type": "object", + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "format": "uri" + }, + "sslCertificates": { + "type": "string", + "format": "base64", + "description": "

\nThis field is a Base64-encoded SSL Certficate bundle. The certficates can be\nexported from your browser as a text file.\n

\n

NOTE: The Base64-encoded SSL Certificate bundle cannot contain line-endings as it must\nbe encoded as a JSON string field.

\n

\nIf you have access to the GNU commandline tools, you can retrieve the ssl certificates:\n

 prompt> openssl s_client -connect platform.risksense.com:443 -showcerts 
\nyou can base64 encode the certificates using the following command:\n
 prompt> cat certs.txt | base64 -w0 
\nin a single command you can retrieve, parse, and encode the certificates:\n
 prompt> echo | openssl s_client -connect platform.risksense.com:443 -showcerts | awk '/^-----BEGIN CERT/,/^-----END CERT/' | base64 -w0 
\n

\n" + } + } + }, + "schedule": { + "type": "object", + "required": [ + "type", + "enabled", + "hourOfDay" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "DAILY", + "WEEKLY", + "MONTHLY" + ] + }, + "enabled": { + "type": "boolean" + }, + "hourOfDay": { + "type": "integer", + "description": "0 - 23 (Required for Daily, Weekly, Monthly)" + }, + "dayOfWeek": { + "type": "integer", + "description": "1 - 7 (Required for Weekly)" + }, + "dayOfMonth": { + "type": "integer", + "description": "1 - 31 (Required for Monthly)" + } + } + }, + "networkId": { + "type": "number" + }, + "attributes": { + "type": "object", + "description": "

Structure is dependent on the type field. Unless listed here\nAttributes_UsernameAndPassword is expected. The referenced structures\ncan be found at the bottom of this document.

\n
    \n
  • CENZIC_HAILSTORM: Attributes_Cenzic_Hailstorm
  • \n
  • JIRA: Attributes_UsernameAndPassword
  • \n
  • NESSUS: Attributes_Nessus
  • \n
  • NEXPOSE: Attributes_Nexpose
  • \n
  • REMEDY76: Attributes_Remedy
  • \n
  • REMEDY9: Attributes_Remedy
  • \n
  • SERVICE_NOW: Attributes_UsernameAndPassword
  • \n
  • SNOW_SERVICE_REQUEST: Attributes_UsernameAndPassword
  • \n
  • WHITEHAT: Attributes_WhiteHat
  • \n
\n" + }, + "autoUrba": { + "type": "boolean" + }, + "isTagRemovalEnabled": { + "type": "boolean" + }, + "isTicketingConnector": { + "type": "boolean" + }, + "urbaConfidenceLevel": { + "type": "integer" + } + }, + "example": { + "id": 123, + "type": "SERVICE_NOW", + "name": "service_now_test", + "connection": { + "url": "https://ven01446.service-now.com" + }, + "schedule": { + "type": "DAILY", + "hourOfDay": 0 + }, + "networkId": -1, + "attributes": { + "username": "username", + "password": "password" + }, + "autoUrba": true, + "isTagRemovalEnabled": false, + "isTicketingConnector": true, + "urbaConfidenceLevel": 1 + } + } + } + } + }, + "page": { + "type": "object", + "required": [ + "size", + "totalElements", + "totalPages", + "number" + ], + "properties": { + "size": { + "type": "integer" + }, + "totalElements": { + "type": "integer" + }, + "totalPages": { + "type": "integer" + }, + "number": { + "type": "integer" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + } + } + }, + "post": { + "summary": "Create new connector on client", + "tags": [ + "connector" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "type", + "name", + "connection", + "schedule", + "networkId", + "attributes" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "CENZIC_HAILSTORM", + "NESSUS", + "NEXPOSE", + "QUALYS_ASSET", + "QUALYS_VULNERABILITY", + "SECURE_SPHERE_115", + "TENABLE_SECURITY_CENTER" + ] + }, + "name": { + "type": "string" + }, + "connection": { + "type": "object", + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "format": "uri" + }, + "sslCertificates": { + "type": "string", + "format": "base64", + "description": "

\nThis field is a Base64-encoded SSL Certficate bundle. The certficates can be\nexported from your browser as a text file.\n

\n

NOTE: The Base64-encoded SSL Certificate bundle cannot contain line-endings as it must\nbe encoded as a JSON string field.

\n

\nIf you have access to the GNU commandline tools, you can retrieve the ssl certificates:\n

 prompt> openssl s_client -connect platform.risksense.com:443 -showcerts 
\nyou can base64 encode the certificates using the following command:\n
 prompt> cat certs.txt | base64 -w0 
\nin a single command you can retrieve, parse, and encode the certificates:\n
 prompt> echo | openssl s_client -connect platform.risksense.com:443 -showcerts | awk '/^-----BEGIN CERT/,/^-----END CERT/' | base64 -w0 
\n

\n" + } + } + }, + "schedule": { + "type": "object", + "required": [ + "type", + "enabled", + "hourOfDay" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "DAILY", + "WEEKLY", + "MONTHLY" + ] + }, + "enabled": { + "type": "boolean" + }, + "hourOfDay": { + "type": "integer", + "description": "0 - 23 (Required for Daily, Weekly, Monthly)" + }, + "dayOfWeek": { + "type": "integer", + "description": "1 - 7 (Required for Weekly)" + }, + "dayOfMonth": { + "type": "integer", + "description": "1 - 31 (Required for Monthly)" + } + } + }, + "networkId": { + "type": "integer" + }, + "attributes": { + "type": "object", + "description": "

Structure is dependent on the type field. Unless listed here\nAttributes_UsernameAndPassword is expected. The referenced structures\ncan be found at the bottom of this document.

\n
    \n
  • CENZIC_HAILSTORM: Attributes_Cenzic_Hailstorm
  • \n
  • JIRA: Attributes_UsernameAndPassword
  • \n
  • NESSUS: Attributes_Nessus
  • \n
  • NEXPOSE: Attributes_Nexpose
  • \n
  • REMEDY76: Attributes_Remedy
  • \n
  • REMEDY9: Attributes_Remedy
  • \n
  • SERVICE_NOW: Attributes_UsernameAndPassword
  • \n
  • SNOW_SERVICE_REQUEST: Attributes_UsernameAndPassword
  • \n
  • WHITEHAT: Attributes_WhiteHat
  • \n
\n" + }, + "connectorField": { + "type": "object", + "description": "

Structure is dependent on the type field. This parameter is optional for all the connector types\n except the ones listed below. The referenced structures can be found at the bottom of this document.

\n
    \n
  • JIRA: ConnectorField_Jira
  • \n
  • SERVICE_NOW: ConnectorField_ServiceNow
  • \n
  • SNOW_SERVICE_REQUEST: ConnectorField_SnowServiceRequest
  • \n
  • GENERIC_SNOW: ConnectorField_GenericSnow
  • \n
\n" + }, + "autoUrba": { + "type": "boolean" + }, + "urbaConfidenceLevel": { + "type": "integer" + } + }, + "example": { + "type": "QUALYS_VULNERABILITY", + "name": "QV", + "connection": { + "url": "https://qualysguard.qg2.apps.qualys.com/" + }, + "schedule": { + "type": "DAILY", + "hourOfDay": 0 + }, + "networkId": -1, + "attributes": { + "username": "username", + "password": "password" + }, + "autoUrba": true, + "urbaConfidenceLevel": 1 + } + } + } + ], + "responses": { + "201": { + "description": "Success", + "schema": { + "type": "object", + "properties": { + "id": { + "type": "number" + }, + "type": { + "type": "string", + "enum": [ + "CENZIC_HAILSTORM", + "NESSUS", + "NEXPOSE", + "QUALYS_ASSET", + "QUALYS_VULNERABILITY", + "SECURE_SPHERE_115", + "TENABLE_SECURITY_CENTER" + ] + }, + "name": { + "type": "string" + }, + "connection": { + "type": "object", + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "format": "uri" + }, + "sslCertificates": { + "type": "string", + "format": "base64", + "description": "

\nThis field is a Base64-encoded SSL Certficate bundle. The certficates can be\nexported from your browser as a text file.\n

\n

NOTE: The Base64-encoded SSL Certificate bundle cannot contain line-endings as it must\nbe encoded as a JSON string field.

\n

\nIf you have access to the GNU commandline tools, you can retrieve the ssl certificates:\n

 prompt> openssl s_client -connect platform.risksense.com:443 -showcerts 
\nyou can base64 encode the certificates using the following command:\n
 prompt> cat certs.txt | base64 -w0 
\nin a single command you can retrieve, parse, and encode the certificates:\n
 prompt> echo | openssl s_client -connect platform.risksense.com:443 -showcerts | awk '/^-----BEGIN CERT/,/^-----END CERT/' | base64 -w0 
\n

\n" + } + } + }, + "schedule": { + "type": "object", + "required": [ + "type", + "enabled", + "hourOfDay" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "DAILY", + "WEEKLY", + "MONTHLY" + ] + }, + "enabled": { + "type": "boolean" + }, + "hourOfDay": { + "type": "integer", + "description": "0 - 23 (Required for Daily, Weekly, Monthly)" + }, + "dayOfWeek": { + "type": "integer", + "description": "1 - 7 (Required for Weekly)" + }, + "dayOfMonth": { + "type": "integer", + "description": "1 - 31 (Required for Monthly)" + } + } + }, + "networkId": { + "type": "number" + }, + "attributes": { + "type": "object", + "description": "

Structure is dependent on the type field. Unless listed here\nAttributes_UsernameAndPassword is expected. The referenced structures\ncan be found at the bottom of this document.

\n
    \n
  • CENZIC_HAILSTORM: Attributes_Cenzic_Hailstorm
  • \n
  • JIRA: Attributes_UsernameAndPassword
  • \n
  • NESSUS: Attributes_Nessus
  • \n
  • NEXPOSE: Attributes_Nexpose
  • \n
  • REMEDY76: Attributes_Remedy
  • \n
  • REMEDY9: Attributes_Remedy
  • \n
  • SERVICE_NOW: Attributes_UsernameAndPassword
  • \n
  • SNOW_SERVICE_REQUEST: Attributes_UsernameAndPassword
  • \n
  • WHITEHAT: Attributes_WhiteHat
  • \n
\n" + }, + "autoUrba": { + "type": "boolean" + }, + "isTagRemovalEnabled": { + "type": "boolean" + }, + "isTicketingConnector": { + "type": "boolean" + }, + "urbaConfidenceLevel": { + "type": "integer" + } + }, + "example": { + "id": 123, + "type": "SERVICE_NOW", + "name": "service_now_test", + "connection": { + "url": "https://ven01446.service-now.com" + }, + "schedule": { + "type": "DAILY", + "hourOfDay": 0 + }, + "networkId": -1, + "attributes": { + "username": "username", + "password": "password" + }, + "autoUrba": true, + "isTagRemovalEnabled": false, + "isTicketingConnector": true, + "urbaConfidenceLevel": 1 + } + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + } + } + } + }, + "/client/{clientId}/connector/{connectorId}": { + "get": { + "summary": "One connector", + "tags": [ + "connector" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "connectorId", + "description": "Id of connector (This parameter can be obtained via the GET\nmethod on '/client/{clientId}/connector')\n", + "in": "path", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "properties": { + "id": { + "type": "number" + }, + "type": { + "type": "string", + "enum": [ + "CENZIC_HAILSTORM", + "NESSUS", + "NEXPOSE", + "QUALYS_ASSET", + "QUALYS_VULNERABILITY", + "SECURE_SPHERE_115", + "TENABLE_SECURITY_CENTER" + ] + }, + "name": { + "type": "string" + }, + "connection": { + "type": "object", + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "format": "uri" + }, + "sslCertificates": { + "type": "string", + "format": "base64", + "description": "

\nThis field is a Base64-encoded SSL Certficate bundle. The certficates can be\nexported from your browser as a text file.\n

\n

NOTE: The Base64-encoded SSL Certificate bundle cannot contain line-endings as it must\nbe encoded as a JSON string field.

\n

\nIf you have access to the GNU commandline tools, you can retrieve the ssl certificates:\n

 prompt> openssl s_client -connect platform.risksense.com:443 -showcerts 
\nyou can base64 encode the certificates using the following command:\n
 prompt> cat certs.txt | base64 -w0 
\nin a single command you can retrieve, parse, and encode the certificates:\n
 prompt> echo | openssl s_client -connect platform.risksense.com:443 -showcerts | awk '/^-----BEGIN CERT/,/^-----END CERT/' | base64 -w0 
\n

\n" + } + } + }, + "schedule": { + "type": "object", + "required": [ + "type", + "enabled", + "hourOfDay" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "DAILY", + "WEEKLY", + "MONTHLY" + ] + }, + "enabled": { + "type": "boolean" + }, + "hourOfDay": { + "type": "integer", + "description": "0 - 23 (Required for Daily, Weekly, Monthly)" + }, + "dayOfWeek": { + "type": "integer", + "description": "1 - 7 (Required for Weekly)" + }, + "dayOfMonth": { + "type": "integer", + "description": "1 - 31 (Required for Monthly)" + } + } + }, + "networkId": { + "type": "number" + }, + "attributes": { + "type": "object", + "description": "

Structure is dependent on the type field. Unless listed here\nAttributes_UsernameAndPassword is expected. The referenced structures\ncan be found at the bottom of this document.

\n
    \n
  • CENZIC_HAILSTORM: Attributes_Cenzic_Hailstorm
  • \n
  • JIRA: Attributes_UsernameAndPassword
  • \n
  • NESSUS: Attributes_Nessus
  • \n
  • NEXPOSE: Attributes_Nexpose
  • \n
  • REMEDY76: Attributes_Remedy
  • \n
  • REMEDY9: Attributes_Remedy
  • \n
  • SERVICE_NOW: Attributes_UsernameAndPassword
  • \n
  • SNOW_SERVICE_REQUEST: Attributes_UsernameAndPassword
  • \n
  • WHITEHAT: Attributes_WhiteHat
  • \n
\n" + }, + "autoUrba": { + "type": "boolean" + }, + "isTagRemovalEnabled": { + "type": "boolean" + }, + "isTicketingConnector": { + "type": "boolean" + }, + "urbaConfidenceLevel": { + "type": "integer" + } + }, + "example": { + "id": 123, + "type": "SERVICE_NOW", + "name": "service_now_test", + "connection": { + "url": "https://ven01446.service-now.com" + }, + "schedule": { + "type": "DAILY", + "hourOfDay": 0 + }, + "networkId": -1, + "attributes": { + "username": "username", + "password": "password" + }, + "autoUrba": true, + "isTagRemovalEnabled": false, + "isTicketingConnector": true, + "urbaConfidenceLevel": 1 + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + }, + "put": { + "summary": "Update a connector", + "tags": [ + "connector" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "connectorId", + "description": "Id of connector (This parameter can be obtained via the GET\nmethod on '/client/{clientId}/connector')\n", + "in": "path", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "type", + "name", + "connection", + "schedule", + "networkId", + "attributes" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "CENZIC_HAILSTORM", + "NESSUS", + "NEXPOSE", + "QUALYS_ASSET", + "QUALYS_VULNERABILITY", + "SECURE_SPHERE_115", + "TENABLE_SECURITY_CENTER" + ] + }, + "name": { + "type": "string" + }, + "connection": { + "type": "object", + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "format": "uri" + }, + "sslCertificates": { + "type": "string", + "format": "base64", + "description": "

\nThis field is a Base64-encoded SSL Certficate bundle. The certficates can be\nexported from your browser as a text file.\n

\n

NOTE: The Base64-encoded SSL Certificate bundle cannot contain line-endings as it must\nbe encoded as a JSON string field.

\n

\nIf you have access to the GNU commandline tools, you can retrieve the ssl certificates:\n

 prompt> openssl s_client -connect platform.risksense.com:443 -showcerts 
\nyou can base64 encode the certificates using the following command:\n
 prompt> cat certs.txt | base64 -w0 
\nin a single command you can retrieve, parse, and encode the certificates:\n
 prompt> echo | openssl s_client -connect platform.risksense.com:443 -showcerts | awk '/^-----BEGIN CERT/,/^-----END CERT/' | base64 -w0 
\n

\n" + } + } + }, + "schedule": { + "type": "object", + "required": [ + "type", + "enabled", + "hourOfDay" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "DAILY", + "WEEKLY", + "MONTHLY" + ] + }, + "enabled": { + "type": "boolean" + }, + "hourOfDay": { + "type": "integer", + "description": "0 - 23 (Required for Daily, Weekly, Monthly)" + }, + "dayOfWeek": { + "type": "integer", + "description": "1 - 7 (Required for Weekly)" + }, + "dayOfMonth": { + "type": "integer", + "description": "1 - 31 (Required for Monthly)" + } + } + }, + "networkId": { + "type": "integer" + }, + "attributes": { + "type": "object", + "description": "

Structure is dependent on the type field. Unless listed here\nAttributes_UsernameAndPassword is expected. The referenced structures\ncan be found at the bottom of this document.

\n
    \n
  • CENZIC_HAILSTORM: Attributes_Cenzic_Hailstorm
  • \n
  • JIRA: Attributes_UsernameAndPassword
  • \n
  • NESSUS: Attributes_Nessus
  • \n
  • NEXPOSE: Attributes_Nexpose
  • \n
  • REMEDY76: Attributes_Remedy
  • \n
  • REMEDY9: Attributes_Remedy
  • \n
  • SERVICE_NOW: Attributes_UsernameAndPassword
  • \n
  • SNOW_SERVICE_REQUEST: Attributes_UsernameAndPassword
  • \n
  • WHITEHAT: Attributes_WhiteHat
  • \n
\n" + }, + "connectorField": { + "type": "object", + "description": "

Structure is dependent on the type field. This parameter is optional for all the connector types\n except the ones listed below. The referenced structures can be found at the bottom of this document.

\n
    \n
  • JIRA: ConnectorField_Jira
  • \n
  • SERVICE_NOW: ConnectorField_ServiceNow
  • \n
  • SNOW_SERVICE_REQUEST: ConnectorField_SnowServiceRequest
  • \n
  • GENERIC_SNOW: ConnectorField_GenericSnow
  • \n
\n" + }, + "autoUrba": { + "type": "boolean" + }, + "urbaConfidenceLevel": { + "type": "integer" + } + }, + "example": { + "type": "QUALYS_VULNERABILITY", + "name": "QV", + "connection": { + "url": "https://qualysguard.qg2.apps.qualys.com/" + }, + "schedule": { + "type": "DAILY", + "hourOfDay": 0 + }, + "networkId": -1, + "attributes": { + "username": "username", + "password": "password" + }, + "autoUrba": true, + "urbaConfidenceLevel": 1 + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "properties": { + "id": { + "type": "number" + }, + "type": { + "type": "string", + "enum": [ + "CENZIC_HAILSTORM", + "NESSUS", + "NEXPOSE", + "QUALYS_ASSET", + "QUALYS_VULNERABILITY", + "SECURE_SPHERE_115", + "TENABLE_SECURITY_CENTER" + ] + }, + "name": { + "type": "string" + }, + "connection": { + "type": "object", + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "format": "uri" + }, + "sslCertificates": { + "type": "string", + "format": "base64", + "description": "

\nThis field is a Base64-encoded SSL Certficate bundle. The certficates can be\nexported from your browser as a text file.\n

\n

NOTE: The Base64-encoded SSL Certificate bundle cannot contain line-endings as it must\nbe encoded as a JSON string field.

\n

\nIf you have access to the GNU commandline tools, you can retrieve the ssl certificates:\n

 prompt> openssl s_client -connect platform.risksense.com:443 -showcerts 
\nyou can base64 encode the certificates using the following command:\n
 prompt> cat certs.txt | base64 -w0 
\nin a single command you can retrieve, parse, and encode the certificates:\n
 prompt> echo | openssl s_client -connect platform.risksense.com:443 -showcerts | awk '/^-----BEGIN CERT/,/^-----END CERT/' | base64 -w0 
\n

\n" + } + } + }, + "schedule": { + "type": "object", + "required": [ + "type", + "enabled", + "hourOfDay" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "DAILY", + "WEEKLY", + "MONTHLY" + ] + }, + "enabled": { + "type": "boolean" + }, + "hourOfDay": { + "type": "integer", + "description": "0 - 23 (Required for Daily, Weekly, Monthly)" + }, + "dayOfWeek": { + "type": "integer", + "description": "1 - 7 (Required for Weekly)" + }, + "dayOfMonth": { + "type": "integer", + "description": "1 - 31 (Required for Monthly)" + } + } + }, + "networkId": { + "type": "number" + }, + "attributes": { + "type": "object", + "description": "

Structure is dependent on the type field. Unless listed here\nAttributes_UsernameAndPassword is expected. The referenced structures\ncan be found at the bottom of this document.

\n
    \n
  • CENZIC_HAILSTORM: Attributes_Cenzic_Hailstorm
  • \n
  • JIRA: Attributes_UsernameAndPassword
  • \n
  • NESSUS: Attributes_Nessus
  • \n
  • NEXPOSE: Attributes_Nexpose
  • \n
  • REMEDY76: Attributes_Remedy
  • \n
  • REMEDY9: Attributes_Remedy
  • \n
  • SERVICE_NOW: Attributes_UsernameAndPassword
  • \n
  • SNOW_SERVICE_REQUEST: Attributes_UsernameAndPassword
  • \n
  • WHITEHAT: Attributes_WhiteHat
  • \n
\n" + }, + "autoUrba": { + "type": "boolean" + }, + "isTagRemovalEnabled": { + "type": "boolean" + }, + "isTicketingConnector": { + "type": "boolean" + }, + "urbaConfidenceLevel": { + "type": "integer" + } + }, + "example": { + "id": 123, + "type": "SERVICE_NOW", + "name": "service_now_test", + "connection": { + "url": "https://ven01446.service-now.com" + }, + "schedule": { + "type": "DAILY", + "hourOfDay": 0 + }, + "networkId": -1, + "attributes": { + "username": "username", + "password": "password" + }, + "autoUrba": true, + "isTagRemovalEnabled": false, + "isTicketingConnector": true, + "urbaConfidenceLevel": 1 + } + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + }, + "delete": { + "summary": "Delete a connector", + "tags": [ + "connector" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "connectorId", + "description": "Id of connector (This parameter can be obtained via the GET\nmethod on '/client/{clientId}/connector')\n", + "in": "path", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": false, + "schema": { + "type": "object", + "properties": { + "deleteTag": { + "type": "boolean", + "description": "Force delete the associated tag or not." + } + } + } + } + ], + "responses": { + "204": { + "description": "Request was processed without errors" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/connector/{connectorId}/job": { + "get": { + "summary": "Paginate connector jobs", + "description": "

Description: Paginate connector jobs.\nIf the connector is enabled a pending job is added to the first\npage exceeding the requested page size by one. The meta data in\nthe page field will reflect the correct page size.

\n", + "tags": [ + "connector" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "connectorId", + "description": "Id of connector (This parameter can be obtained via the GET\nmethod on '/client/{clientId}/connector')\n", + "in": "path", + "required": true, + "type": "integer" + }, + { + "name": "size", + "in": "query", + "description": "Size of the page requested", + "required": false, + "type": "integer" + }, + { + "name": "page", + "in": "query", + "description": "Page number being requested (first page: 0)", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "properties": { + "_embedded": { + "type": "object", + "required": [ + "connectorJobs" + ], + "properties": { + "connectorJobs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "description": "Not present for pending jobs" + }, + "startTime": { + "type": "string", + "format": "date-time" + }, + "state": { + "type": "string", + "enum": [ + "Pending", + "Processing", + "Success", + "PartialSuccess", + "Failure" + ] + } + } + } + } + } + }, + "page": { + "type": "object", + "required": [ + "size", + "totalElements", + "totalPages", + "number" + ], + "properties": { + "size": { + "type": "integer" + }, + "totalElements": { + "type": "integer" + }, + "totalPages": { + "type": "integer" + }, + "number": { + "type": "integer" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/connector/{connectorId}/log": { + "get": { + "summary": "Paginate connector logs", + "description": "

Description: Paginate connector Log.

\n", + "tags": [ + "connector" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "connectorId", + "description": "Id of connector (This parameter can be obtained via the GET\nmethod on '/client/{clientId}/connector')\n", + "in": "path", + "required": true, + "type": "integer" + }, + { + "name": "size", + "in": "query", + "description": "Size of the page requested", + "required": false, + "type": "integer" + }, + { + "name": "page", + "in": "query", + "description": "Page number being requested (first page: 0)", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "properties": { + "_embedded": { + "type": "object", + "required": [ + "connectorLogModels" + ], + "properties": { + "connectorLogModels": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "description": "Connector log id" + }, + "message": { + "type": "string" + }, + "state": { + "type": "string", + "enum": [ + "OK", + "ERROR" + ] + }, + "internalMessage": { + "type": "string" + }, + "isAdditionalDetailAvailable": { + "type": "boolean" + }, + "logFileCount": { + "type": "integer" + }, + "timeAdded": { + "type": "string", + "format": "date-time" + } + } + } + } + } + }, + "page": { + "type": "object", + "required": [ + "size", + "totalElements", + "totalPages", + "number" + ], + "properties": { + "size": { + "type": "integer" + }, + "totalElements": { + "type": "integer" + }, + "totalPages": { + "type": "integer" + }, + "number": { + "type": "integer" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/connector/{connectorId}/schedule": { + "put": { + "summary": "Update a connector schedule", + "tags": [ + "connector" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "connectorId", + "description": "Id of connector (This parameter can be obtained via the GET\nmethod on '/client/{clientId}/connector')\n", + "in": "path", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "type", + "enabled", + "hourOfDay" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "DAILY", + "WEEKLY", + "MONTHLY" + ] + }, + "enabled": { + "type": "boolean" + }, + "hourOfDay": { + "type": "integer", + "description": "0 - 23 (Required for Daily, Weekly, Monthly)" + }, + "dayOfWeek": { + "type": "integer", + "description": "1 - 7 (Required for Weekly)" + }, + "dayOfMonth": { + "type": "integer", + "description": "1 - 31 (Required for Monthly)" + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "properties": { + "id": { + "type": "number" + }, + "type": { + "type": "string", + "enum": [ + "CENZIC_HAILSTORM", + "NESSUS", + "NEXPOSE", + "QUALYS_ASSET", + "QUALYS_VULNERABILITY", + "SECURE_SPHERE_115", + "TENABLE_SECURITY_CENTER" + ] + }, + "name": { + "type": "string" + }, + "connection": { + "type": "object", + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "format": "uri" + }, + "sslCertificates": { + "type": "string", + "format": "base64", + "description": "

\nThis field is a Base64-encoded SSL Certficate bundle. The certficates can be\nexported from your browser as a text file.\n

\n

NOTE: The Base64-encoded SSL Certificate bundle cannot contain line-endings as it must\nbe encoded as a JSON string field.

\n

\nIf you have access to the GNU commandline tools, you can retrieve the ssl certificates:\n

 prompt> openssl s_client -connect platform.risksense.com:443 -showcerts 
\nyou can base64 encode the certificates using the following command:\n
 prompt> cat certs.txt | base64 -w0 
\nin a single command you can retrieve, parse, and encode the certificates:\n
 prompt> echo | openssl s_client -connect platform.risksense.com:443 -showcerts | awk '/^-----BEGIN CERT/,/^-----END CERT/' | base64 -w0 
\n

\n" + } + } + }, + "schedule": { + "type": "object", + "required": [ + "type", + "enabled", + "hourOfDay" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "DAILY", + "WEEKLY", + "MONTHLY" + ] + }, + "enabled": { + "type": "boolean" + }, + "hourOfDay": { + "type": "integer", + "description": "0 - 23 (Required for Daily, Weekly, Monthly)" + }, + "dayOfWeek": { + "type": "integer", + "description": "1 - 7 (Required for Weekly)" + }, + "dayOfMonth": { + "type": "integer", + "description": "1 - 31 (Required for Monthly)" + } + } + }, + "networkId": { + "type": "number" + }, + "attributes": { + "type": "object", + "description": "

Structure is dependent on the type field. Unless listed here\nAttributes_UsernameAndPassword is expected. The referenced structures\ncan be found at the bottom of this document.

\n
    \n
  • CENZIC_HAILSTORM: Attributes_Cenzic_Hailstorm
  • \n
  • JIRA: Attributes_UsernameAndPassword
  • \n
  • NESSUS: Attributes_Nessus
  • \n
  • NEXPOSE: Attributes_Nexpose
  • \n
  • REMEDY76: Attributes_Remedy
  • \n
  • REMEDY9: Attributes_Remedy
  • \n
  • SERVICE_NOW: Attributes_UsernameAndPassword
  • \n
  • SNOW_SERVICE_REQUEST: Attributes_UsernameAndPassword
  • \n
  • WHITEHAT: Attributes_WhiteHat
  • \n
\n" + }, + "autoUrba": { + "type": "boolean" + }, + "isTagRemovalEnabled": { + "type": "boolean" + }, + "isTicketingConnector": { + "type": "boolean" + }, + "urbaConfidenceLevel": { + "type": "integer" + } + }, + "example": { + "id": 123, + "type": "SERVICE_NOW", + "name": "service_now_test", + "connection": { + "url": "https://ven01446.service-now.com" + }, + "schedule": { + "type": "DAILY", + "hourOfDay": 0 + }, + "networkId": -1, + "attributes": { + "username": "username", + "password": "password" + }, + "autoUrba": true, + "isTagRemovalEnabled": false, + "isTicketingConnector": true, + "urbaConfidenceLevel": 1 + } + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/connector/{connectorId}/field": { + "put": { + "summary": "Save the connector templates, description fields, default connector fields", + "description": "

Description: Save connector information.\nOnce the connector is created, this api is used to store all the connector\nrelated information that has been configured while creating/editing a connector.\n", + "tags": [ + "connector" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "connectorId", + "description": "Id of connector (This parameter can be obtained via the GET\nmethod on '/client/{clientId}/connector')\n", + "in": "path", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "type", + "defaultTemplateId", + "templates", + "descriptionFields", + "defaultSupportedFieldValues", + "catalog", + "category", + "catalogItem", + "dynamicFields", + "tagSyncField", + "connectorSettings" + ], + "properties": { + "type": { + "type": "string", + "description": "Connector Type.\nCurrent supports only two types of connector. They are\n1. SERVICE_NOW - Service Now Incident.\n2. SNOW_SERVICE_REQUEST - Service Now Service Request.\n" + }, + "defaultTemplateId": { + "type": "string", + "description": "Optional default template Id. This is a SERVICE_NOW ONLY field." + }, + "templates": { + "type": "array", + "items": { + "type": "object", + "description": "SERVICE_NOW field only.", + "required": [ + "id", + "name", + "locked" + ], + "properties": { + "id": { + "type": "string", + "description": "Template Id" + }, + "name": { + "type": "string", + "description": "Template name" + }, + "locked": { + "type": "boolean", + "description": "The selected template is locked or not. Locked implies that you\nwill not be able to edit those fields and unlocked implies that\nyou can edit the fields which are supported by Ivanti Neurons.\n" + } + } + } + }, + "descriptionFields": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key", + "enabled" + ], + "properties": { + "key": { + "type": "string", + "description": "Description field key" + }, + "enabled": { + "type": "boolean", + "description": "True when description field key is enabled else False" + } + } + } + }, + "defaultSupportedFieldValues": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key", + "value" + ], + "properties": { + "key": { + "type": "string", + "description": "Supported template field key" + }, + "value": { + "type": "string", + "description": "Supported template field value" + } + } + } + }, + "catalog": { + "type": "string", + "description": "Catalog type. SNOW_SERVICE_REQUEST field only." + }, + "category": { + "type": "string", + "description": "Category type. SNOW_SERVICE_REQUEST field only." + }, + "catalogItem": { + "type": "string", + "description": "Catalog Item type. SNOW_SERVICE_REQUEST field only." + }, + "dynamicFields": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key", + "value" + ], + "properties": { + "key": { + "type": "string", + "description": "Field key" + }, + "value": { + "type": "string", + "description": "Field value" + }, + "displayValue": { + "type": "string", + "description": "Label of the value." + } + } + } + }, + "tagSyncField": { + "type": "string", + "description": "Value of Tag Name Sync Field. This field is populated with the tag name while creating tickets." + }, + "connectorSettings": { + "type": "object", + "required": [ + "initialState", + "enabledTagRemoval", + "closeTicketOnFindingsCloseEnabled", + "closedStateKey", + "closedStateLabel" + ], + "properties": { + "initialState": { + "type": "string", + "description": "Initial state of the ticket which is used to create a ticket using this connector." + }, + "enabledTagRemoval": { + "type": "boolean", + "description": "True if the user allows the deletion of tags associated with this connector, otherwise false." + }, + "closeTicketOnFindingsCloseEnabled": { + "type": "boolean", + "description": "True if enable changing the ticket state to the set state when all the associated findings reach to the close state.\n" + }, + "closedStateKey": { + "type": "string", + "description": "the close state value of the status." + }, + "closedStateLabel": { + "type": "string", + "description": "the close state label of the status." + } + } + } + } + } + } + ], + "responses": { + "204": { + "description": "Save request was processed without errors" + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/connector/{connectorId}/template/{templateId}/field": { + "get": { + "summary": "Return list of fields which are associated with this templateId for connectorId", + "description": "

This returns list of template fields which may or may not be supported by the platform

\n", + "tags": [ + "ticket" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "connectorId", + "description": "Id of connector (This parameter can be obtained via the GET\nmethod on '/client/{clientId}/connector')\n", + "in": "path", + "required": true, + "type": "integer" + }, + { + "name": "templateId", + "description": "Id of template (This parameter can be obtained via the GET\nmethod on '/client/{clientId}/connector/{connectorId}/template')\n", + "in": "path", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "fields" + ], + "properties": { + "fields": { + "type": "array", + "items": { + "type": "object", + "required": [ + "type", + "locked", + "defaultValue", + "key", + "label", + "isSupported", + "descriptionText", + "selectOptions" + ], + "properties": { + "type": { + "type": "string", + "description": "

This is the DisplayType of the field.Some of the examples are

\n
    \n
  • textArea: Used for Text area
  • \n
  • valueDropdown: Used for Dropdown
  • \n
\n

This is not available if isSupported is false

\n" + }, + "locked": { + "type": "boolean", + "description": "If this is true that means user cannot modify the field and\nIf this is false that means user can modify this field that to if\nisSupported is true.\n

This is not available if isSupported is false

\n" + }, + "defaultValue": { + "type": "string", + "description": "This is the default value for the field. It is obtained from the template from the\nconnector and if it is not available in template then it is either retrieved from the\ndefault fields value from database that to if isSupported is true.\n" + }, + "key": { + "type": "string", + "description": "This is the key of the field.This is empty if and only if isSupported is false.\n" + }, + "label": { + "type": "string", + "description": "This is the label of the field which is used for the display.\n" + }, + "isSupported": { + "type": "boolean", + "description": "This is true if the platform support(Editing/Modifying) the field.\n" + }, + "descriptionText": { + "type": "string", + "description": "This is the additional description provided to the user regarding the field.\n" + }, + "selectOptions": { + "description": "This is only available if the type is valueDropdown\n", + "type": "array", + "items": { + "type": "object", + "required": [ + "label", + "value" + ], + "properties": { + "label": { + "type": "string", + "description": "Label of field which is used to display." + }, + "value": { + "type": "string", + "description": "Value of the dropdown and this can be human readable or may not be human readable." + } + } + } + } + } + } + } + } + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/connector/populate": { + "post": { + "summary": "Retrieve list of connector templates and configurable fields options which are used to create connector or update existing connector.", + "description": "

Description: Populate Fields.\n

Will populate list of Connector templates, Ivanti Neurons supported configurable template fields and description for Service Now incident request.

\n

Or populate list of Service Now service request Catalogs associated with current selected catalog and Ivanti Neurons supported configurable fields.

\n", + "tags": [ + "connector" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "type", + "username", + "password", + "url" + ], + "properties": { + "type": { + "type": "string", + "description": "Service now request type. Provide 'SERVICE_NOW' for incident request or 'SNOW_SERVICE_REQUEST' for service request." + }, + "username": { + "type": "string", + "description": "Username of the connector account." + }, + "password": { + "type": "string", + "description": "Password of the connector account. It is optional when connectorId is provided." + }, + "url": { + "type": "string", + "description": "URL of the connector framework." + }, + "connectorId": { + "type": "integer", + "description": "Id of the connector that will be edited.\nIf the connector Id is provided then password is not required. If the connector Id is not\nprovided, then you should provide all the required fields compulsory.\n" + }, + "ssl": { + "type": "string", + "format": "base64", + "description": "

\nThis field is a Base64-encoded SSL Certficate bundle. The certficates can be\nexported from your browser as a text file.\n

\n

NOTE: The Base64-encoded SSL Certificate bundle cannot contain line-endings as it must\nbe encoded as a JSON string field.

\n

\nIf you have access to the GNU commandline tools, you can retrieve the ssl certificates:\n

 prompt> openssl s_client -connect platform.risksense.com:443 -showcerts 
\nyou can base64 encode the certificates using the following command:\n
 prompt> cat certs.txt | base64 -w0 
\nin a single command you can retrieve, parse, and encode the certificates:\n
 prompt> echo | openssl s_client -connect platform.risksense.com:443 -showcerts | awk '/^-----BEGIN CERT/,/^-----END CERT/' | base64 -w0 
\n

\n" + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "description": "

Structure is dependent on the type field. The referenced structures can be found at the bottom of this document.

\n
    \n
  • SERVICE_NOW: ConnectorPopulate_ServiceNow
  • \n
  • JIRA: ConnectorPopulate_Jira
  • \n
  • SNOW_SERVICE_REQUEST: ConnectorPopulate_SnowServiceRequest
  • \n
  • GENERIC_SNOW: ConnectorPopulate_GenericSnow
  • \n
\n" + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/connector/{connectorId}/template": { + "get": { + "summary": "List of templates that are selected while creating the connector", + "description": "

Description: List of templates.\nThis contains the list of templates which are selected while creating the connector\nThe List should start with None template which is used to create ticket without template\n

Supported Connector Types: SERVICE_NOW.

\n", + "tags": [ + "ticket" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "connectorId", + "description": "Id of connector (This parameter can be obtained via the GET\nmethod on '/client/{clientId}/connector')\n", + "in": "path", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "templates" + ], + "properties": { + "templates": { + "type": "array", + "items": { + "type": "object", + "required": [ + "id", + "label", + "tableName", + "isDefault" + ], + "properties": { + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "tableName": { + "type": "string", + "description": "The Table name that the template belongs to." + }, + "isDefault": { + "type": "boolean", + "description": "Should only be true for one of the templates in the list." + } + } + } + } + } + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/connector/populate/catalog/{catalogId}/category": { + "post": { + "summary": "Retrieve list of Category from Service Now.", + "description": "

Description: Retrieve list of Service request category within given catalog.\n

Supported Connector Types: SNOW_SERVICE_REQUEST.

\n", + "tags": [ + "connector" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "catalogId", + "in": "path", + "description": "Id of Catalog (This parameter can be obtained via the POST\nmethod on '/client/{clientId}/connector/populate with SNOW_SERVICE_REQUEST as the type')\n", + "required": true, + "type": "string" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "type", + "username", + "password", + "url" + ], + "properties": { + "type": { + "type": "string", + "description": "Service now request type. Provide 'SERVICE_NOW' for incident request or 'SNOW_SERVICE_REQUEST' for service request." + }, + "username": { + "type": "string", + "description": "Username of the connector account." + }, + "password": { + "type": "string", + "description": "Password of the connector account. It is optional when connectorId is provided." + }, + "url": { + "type": "string", + "description": "URL of the connector framework." + }, + "connectorId": { + "type": "integer", + "description": "Id of the connector that will be edited.\nIf the connector Id is provided then password is not required. If the connector Id is not\nprovided, then you should provide all the required fields compulsory.\n" + }, + "ssl": { + "type": "string", + "format": "base64", + "description": "

\nThis field is a Base64-encoded SSL Certficate bundle. The certficates can be\nexported from your browser as a text file.\n

\n

NOTE: The Base64-encoded SSL Certificate bundle cannot contain line-endings as it must\nbe encoded as a JSON string field.

\n

\nIf you have access to the GNU commandline tools, you can retrieve the ssl certificates:\n

 prompt> openssl s_client -connect platform.risksense.com:443 -showcerts 
\nyou can base64 encode the certificates using the following command:\n
 prompt> cat certs.txt | base64 -w0 
\nin a single command you can retrieve, parse, and encode the certificates:\n
 prompt> echo | openssl s_client -connect platform.risksense.com:443 -showcerts | awk '/^-----BEGIN CERT/,/^-----END CERT/' | base64 -w0 
\n

\n" + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "currentSelectedCategory", + "categories" + ], + "properties": { + "currentSelectedCategory": { + "type": "string" + }, + "categories": { + "type": "array", + "items": { + "type": "object", + "required": [ + "displayValue", + "value" + ], + "properties": { + "displayValue": { + "type": "string", + "description": "Label of the Field." + }, + "value": { + "type": "string", + "description": "Id of the Field." + } + } + } + } + } + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/connector/populate/catalog/{catalogId}/category/{categoryId}/item": { + "post": { + "summary": "Retrieve list of Catalog items associated with the catalog and category", + "description": "

Description: Get catalog items under the given catalog and category from Service Now.\n

Supported Connector Types: SNOW_SERVICE_REQUEST.

\n", + "tags": [ + "connector" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "catalogId", + "in": "path", + "description": "Id of Catalog (This parameter can be obtained via the POST\nmethod on '/client/{clientId}/connector/populate with SNOW_SERVICE_REQUEST as the type')\n", + "required": true, + "type": "string" + }, + { + "name": "categoryId", + "description": "Id of the category (This parameter can be obtained via the POST\nmethod on '/client/{clientId}/connector/populate/catalog/{catalogId}/category'\n", + "in": "path", + "required": true, + "type": "string" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "type", + "username", + "password", + "url" + ], + "properties": { + "type": { + "type": "string", + "description": "Service now request type. Provide 'SERVICE_NOW' for incident request or 'SNOW_SERVICE_REQUEST' for service request." + }, + "username": { + "type": "string", + "description": "Username of the connector account." + }, + "password": { + "type": "string", + "description": "Password of the connector account. It is optional when connectorId is provided." + }, + "url": { + "type": "string", + "description": "URL of the connector framework." + }, + "connectorId": { + "type": "integer", + "description": "Id of the connector that will be edited.\nIf the connector Id is provided then password is not required. If the connector Id is not\nprovided, then you should provide all the required fields compulsory.\n" + }, + "ssl": { + "type": "string", + "format": "base64", + "description": "

\nThis field is a Base64-encoded SSL Certficate bundle. The certficates can be\nexported from your browser as a text file.\n

\n

NOTE: The Base64-encoded SSL Certificate bundle cannot contain line-endings as it must\nbe encoded as a JSON string field.

\n

\nIf you have access to the GNU commandline tools, you can retrieve the ssl certificates:\n

 prompt> openssl s_client -connect platform.risksense.com:443 -showcerts 
\nyou can base64 encode the certificates using the following command:\n
 prompt> cat certs.txt | base64 -w0 
\nin a single command you can retrieve, parse, and encode the certificates:\n
 prompt> echo | openssl s_client -connect platform.risksense.com:443 -showcerts | awk '/^-----BEGIN CERT/,/^-----END CERT/' | base64 -w0 
\n

\n" + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "currentlySelectedCatalogItem", + "catalogItems" + ], + "properties": { + "currentlySelectedCatalogItem": { + "type": "string", + "description": "Selected catalog item system id" + }, + "catalogItems": { + "type": "array", + "items": { + "type": "object", + "required": [ + "displayValue", + "value" + ], + "properties": { + "displayValue": { + "type": "string", + "description": "Label of the Field." + }, + "value": { + "type": "string", + "description": "Id of the Field." + } + } + } + } + } + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/connector/populate/catalog/{catalogId}/category/{categoryId}/item/{catalogItemId}": { + "post": { + "summary": "Retrieve variables of catalog item, saved tag sync field and its options and connector settings", + "description": "

Description: Get catalog item variables for a given catalog item from Service Now.\n Also get list of tag sync field and saved tag sync field. This tagSyncField is the field\n which is used to store the tag name in servicenow.\n Connector Settings which contains the initialState, close Ticket on finding close and close finding on ticket close.\n This information is used to sync the servicenow and do necessary actions.

\n

Supported Connector Types: SNOW_SERVICE_REQUEST.

\n", + "tags": [ + "connector" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "catalogId", + "in": "path", + "description": "Id of Catalog (This parameter can be obtained via the POST\nmethod on '/client/{clientId}/connector/populate with SNOW_SERVICE_REQUEST as the type')\n", + "required": true, + "type": "string" + }, + { + "name": "categoryId", + "description": "Id of the category (This parameter can be obtained via the POST\nmethod on '/client/{clientId}/connector/populate/catalog/{catalogId}/category'\n", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "catalogItemId", + "in": "path", + "description": "Id of Catalog Item(This parameter can be obtained via the POST\nmethod on '/client/{clientId}/connector/populate/catalog/{catalogId}/category/{CategoryId}/item with SNOW_SERVICE_REQUEST as the type')\n", + "required": true, + "type": "string" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "type", + "username", + "password", + "url" + ], + "properties": { + "type": { + "type": "string", + "description": "Service now request type. Provide 'SERVICE_NOW' for incident request or 'SNOW_SERVICE_REQUEST' for service request." + }, + "username": { + "type": "string", + "description": "Username of the connector account." + }, + "password": { + "type": "string", + "description": "Password of the connector account. It is optional when connectorId is provided." + }, + "url": { + "type": "string", + "description": "URL of the connector framework." + }, + "connectorId": { + "type": "integer", + "description": "Id of the connector that will be edited.\nIf the connector Id is provided then password is not required. If the connector Id is not\nprovided, then you should provide all the required fields compulsory.\n" + }, + "ssl": { + "type": "string", + "format": "base64", + "description": "

\nThis field is a Base64-encoded SSL Certficate bundle. The certficates can be\nexported from your browser as a text file.\n

\n

NOTE: The Base64-encoded SSL Certificate bundle cannot contain line-endings as it must\nbe encoded as a JSON string field.

\n

\nIf you have access to the GNU commandline tools, you can retrieve the ssl certificates:\n

 prompt> openssl s_client -connect platform.risksense.com:443 -showcerts 
\nyou can base64 encode the certificates using the following command:\n
 prompt> cat certs.txt | base64 -w0 
\nin a single command you can retrieve, parse, and encode the certificates:\n
 prompt> echo | openssl s_client -connect platform.risksense.com:443 -showcerts | awk '/^-----BEGIN CERT/,/^-----END CERT/' | base64 -w0 
\n

\n" + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "fields", + "tagSyncField", + "tagSyncFieldOptions", + "templates", + "connectorSettings" + ], + "properties": { + "fields": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key", + "label", + "type", + "value", + "required", + "locked", + "isSupported", + "selectOptions", + "fields", + "queryParameters", + "dependentKey" + ], + "properties": { + "key": { + "type": "string", + "description": "Key of the field." + }, + "label": { + "type": "string", + "description": "Label of field." + }, + "type": { + "type": "string", + "description": "

Type of Field used to display.The types are

\n
    \n
  • boolean: Used for CheckBox field
  • \n
  • date: Used for Date field
  • \n
  • multiSelect: Used for the multiselect dropdown field
  • \n
  • number: Used for Number field
  • \n
  • radio: Used for Radio button field
  • \n
  • referenceDropdown: Used for the dropdown view where dropdown options are fetched dynamically.
  • \n
  • referenceMultiSelect: Used for the multiselect dropdown view where dropdown options are fetched dynamically.
  • \n
  • section: Used for Section field. This field only supported in SNOW_SERVICE_REQUEST connector type.
  • \n
  • string: Used for single line text field
  • \n
  • textArea: Used for TextArea field
  • \n
  • valueDropdown: Used for the dropdown field
  • \n
\n" + }, + "value": { + "type": "string", + "description": "Value of the field which was set when creating the connector otherwise empty string.\n" + }, + "required": { + "type": "boolean", + "description": "This variable shows whether this field is required or not. If it is required, it cannot be sumbitted as empty.\n" + }, + "locked": { + "type": "boolean", + "description": "True if the field value is not allowed to edit, otherwise false.\n" + }, + "isSupported": { + "type": "boolean", + "description": "True for all supported fields." + }, + "selectOptions": { + "type": "array", + "items": { + "type": "object", + "required": [ + "displayValue", + "value", + "isCurrentlySelected" + ], + "properties": { + "displayValue": { + "type": "string", + "description": "Label of the Field." + }, + "value": { + "type": "string", + "description": "Id of the Field." + }, + "isCurrentlySelected": { + "type": "boolean", + "description": "True if previously selected this option otherwise false.\nAvailable only if the type is 'referenceMultiSelect' or 'multiSelect'.\n" + } + } + } + }, + "fields": { + "type": "array", + "items": {}, + "description": "Available if the type is 'section'. This is same as parent field.\n" + }, + "queryParameters": { + "description": "Available only if the type is 'referenceDropdown' or 'referenceMultiSelect'", + "type": "object", + "required": [ + "table", + "filter", + "fieldName" + ], + "properties": { + "table": { + "type": "string", + "description": "Table name from which dropdown options are fetched. This is a 'SNOW_SERVICE_REQUEST' and 'SERVICE_NOW' request field." + }, + "filter": { + "type": "string", + "description": "Table filter to filter the records. This is a 'SNOW_SERVICE_REQUEST' and 'SERVICE_NOW' request field." + }, + "fieldName": { + "type": "string", + "description": "Field Name for which dropdown options are fetched. This is a 'JIRA' request field." + } + } + }, + "dependentKey": { + "type": "string", + "description": "Key of dependent field. Dropdown options for this field is dependent on value of this\nfield to which this key belongs. Available only if the type is 'referenceDropdown'\n" + } + } + } + }, + "tagSyncField": { + "type": "string", + "description": "Value of Tag Sync Field which was set when creating the connector otherwise empty string.\n" + }, + "tagSyncFieldOptions": { + "type": "array", + "items": { + "type": "object", + "required": [ + "displayValue", + "value" + ], + "properties": { + "displayValue": { + "type": "string", + "description": "Label of the Field." + }, + "value": { + "type": "string", + "description": "Id of the Field." + } + } + } + }, + "connectorSettings": { + "type": "object", + "required": [ + "initialState", + "statusOptions", + "closeTicketOnFindingsCloseEnabled", + "closedStateKey" + ], + "properties": { + "initialState": { + "type": "string", + "description": "Initial state of the ticket which is used to create a ticket using this connector." + }, + "statusOptions": { + "type": "array", + "items": { + "type": "object", + "required": [ + "displayValue", + "value" + ], + "properties": { + "displayValue": { + "type": "string", + "description": "Label of the Field." + }, + "value": { + "type": "string", + "description": "Id of the Field." + } + } + } + }, + "closeTicketOnFindingsClose": { + "type": "boolean", + "description": "True if enable changing the ticket state to the set state when all the associated findings reach the close state.\n" + }, + "closedStateKey": { + "type": "string", + "description": "the close state value of the status." + } + } + } + } + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/connector/{connectorId}/catalogItemField": { + "get": { + "summary": "Get list of catalog item fields associated with the connector.", + "description": "Supported Connector Types: SNOW_SERVICE_REQUEST\n", + "tags": [ + "ticket" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "connectorId", + "description": "Id of connector (This parameter can be obtained via the GET\nmethod on '/client/{clientId}/connector')\n", + "in": "path", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "fields", + "tagSyncField" + ], + "properties": { + "fields": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key", + "label", + "type", + "value", + "required", + "locked", + "isSupported", + "selectOptions", + "fields", + "queryParameters", + "dependentKey" + ], + "properties": { + "key": { + "type": "string", + "description": "Key of the field." + }, + "label": { + "type": "string", + "description": "Label of field." + }, + "type": { + "type": "string", + "description": "

Type of Field used to display.The types are

\n
    \n
  • boolean: Used for CheckBox field
  • \n
  • date: Used for Date field
  • \n
  • multiSelect: Used for the multiselect dropdown field
  • \n
  • number: Used for Number field
  • \n
  • radio: Used for Radio button field
  • \n
  • referenceDropdown: Used for the dropdown view where dropdown options are fetched dynamically.
  • \n
  • referenceMultiSelect: Used for the multiselect dropdown view where dropdown options are fetched dynamically.
  • \n
  • section: Used for Section field. This field only supported in SNOW_SERVICE_REQUEST connector type.
  • \n
  • string: Used for single line text field
  • \n
  • textArea: Used for TextArea field
  • \n
  • valueDropdown: Used for the dropdown field
  • \n
\n" + }, + "value": { + "type": "string", + "description": "Value of the field which was set when creating the connector otherwise empty string.\n" + }, + "required": { + "type": "boolean", + "description": "This variable shows whether this field is required or not. If it is required, it cannot be sumbitted as empty.\n" + }, + "locked": { + "type": "boolean", + "description": "True if the field value is not allowed to edit, otherwise false.\n" + }, + "isSupported": { + "type": "boolean", + "description": "True for all supported fields." + }, + "selectOptions": { + "type": "array", + "items": { + "type": "object", + "required": [ + "displayValue", + "value", + "isCurrentlySelected" + ], + "properties": { + "displayValue": { + "type": "string", + "description": "Label of the Field." + }, + "value": { + "type": "string", + "description": "Id of the Field." + }, + "isCurrentlySelected": { + "type": "boolean", + "description": "True if previously selected this option otherwise false.\nAvailable only if the type is 'referenceMultiSelect' or 'multiSelect'.\n" + } + } + } + }, + "fields": { + "type": "array", + "items": {}, + "description": "Available if the type is 'section'. This is same as parent field.\n" + }, + "queryParameters": { + "description": "Available only if the type is 'referenceDropdown' or 'referenceMultiSelect'", + "type": "object", + "required": [ + "table", + "filter", + "fieldName" + ], + "properties": { + "table": { + "type": "string", + "description": "Table name from which dropdown options are fetched. This is a 'SNOW_SERVICE_REQUEST' and 'SERVICE_NOW' request field." + }, + "filter": { + "type": "string", + "description": "Table filter to filter the records. This is a 'SNOW_SERVICE_REQUEST' and 'SERVICE_NOW' request field." + }, + "fieldName": { + "type": "string", + "description": "Field Name for which dropdown options are fetched. This is a 'JIRA' request field." + } + } + }, + "dependentKey": { + "type": "string", + "description": "Key of dependent field. Dropdown options for this field is dependent on value of this\nfield to which this key belongs. Available only if the type is 'referenceDropdown'\n" + } + } + } + }, + "tagSyncField": { + "type": "string", + "description": "Value of Tag Sync Field which was set when creating the connector otherwise empty string.\n" + } + } + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/connector/field/option": { + "post": { + "summary": "Retrieve dropdown options for the field", + "description": "

Description: Get the dropdown options for the field from servicenow from given table using the filter and search string.

\n

Supported Connector Types: JIRA, SNOW_SERVICE_REQUEST, SERVICE_NOW

\n", + "tags": [ + "connector" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "type", + "connectorCredentials", + "connectorId", + "queryParameters", + "query", + "key" + ], + "properties": { + "type": { + "type": "string", + "description": "Connector type." + }, + "connectorCredentials": { + "type": "object", + "required": [ + "username", + "password", + "url", + "ssl" + ], + "properties": { + "username": { + "type": "string", + "description": "Username of the connector account." + }, + "password": { + "type": "string", + "description": "Password of the connector account." + }, + "url": { + "type": "string", + "description": "URL of the connector framework." + }, + "ssl": { + "type": "string", + "format": "base64", + "description": "

\nThis field is a Base64-encoded SSL Certficate bundle. The certficates can be\nexported from your browser as a text file.\n

\n

NOTE: The Base64-encoded SSL Certificate bundle cannot contain line-endings as it must\nbe encoded as a JSON string field.

\n

\nIf you have access to the GNU commandline tools, you can retrieve the ssl certificates:\n

 prompt> openssl s_client -connect platform.risksense.com:443 -showcerts 
\nyou can base64 encode the certificates using the following command:\n
 prompt> cat certs.txt | base64 -w0 
\nin a single command you can retrieve, parse, and encode the certificates:\n
 prompt> echo | openssl s_client -connect platform.risksense.com:443 -showcerts | awk '/^-----BEGIN CERT/,/^-----END CERT/' | base64 -w0 
\n

\n" + } + } + }, + "connectorId": { + "type": "integer", + "description": "Id of the connector.\nIf the connector Id is provided then connectorCredentials is not required. If the connector Id is not\nprovided, then you should provide connectorCredentials compulsory.\n" + }, + "queryParameters": { + "type": "object", + "required": [ + "table", + "filter", + "fieldName" + ], + "properties": { + "table": { + "type": "string", + "description": "Table name from which dropdown options are fetched. This is a 'SNOW_SERVICE_REQUEST' and 'SERVICE_NOW' request field." + }, + "filter": { + "type": "string", + "description": "Table filter to filter the records. This is a 'SNOW_SERVICE_REQUEST' and 'SERVICE_NOW' request field." + }, + "fieldName": { + "type": "string", + "description": "Field Name for which dropdown options are fetched. This is a 'JIRA' request field." + } + } + }, + "query": { + "type": "string", + "description": "Search string to filter the records." + }, + "key": { + "type": "string", + "description": "Key of the field to which dropdown options are fetched." + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "key", + "selectOptions" + ], + "properties": { + "key": { + "type": "string", + "description": "Key of the field to which dropdown options are fetched." + }, + "selectOptions": { + "type": "array", + "description": "Options for the dropdown.", + "items": { + "type": "object", + "required": [ + "label", + "value" + ], + "properties": { + "label": { + "type": "string", + "description": "Label of field which is used to display." + }, + "value": { + "type": "string", + "description": "Value of the dropdown and this can be human readable or may not be human readable." + } + } + } + } + } + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/connector/{connectorId}/run": { + "get": { + "summary": "Run connector on demand", + "tags": [ + "connector" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "connectorId", + "description": "Id of connector (This parameter can be obtained via the GET\nmethod on '/client/{clientId}/connector')\n", + "in": "path", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "description": "Not present for pending jobs" + }, + "startTime": { + "type": "string", + "format": "date-time" + }, + "state": { + "type": "string", + "enum": [ + "Pending", + "Processing", + "Success", + "PartialSuccess", + "Failure" + ] + } + } + } + }, + "401": { + "description": "Unauthorized" + } + } + } + }, + "/client/{clientId}/connector/populate/project/{projectId}/issueType": { + "post": { + "summary": "Retrieve list of issue types from Jira under a given project.", + "description": "

Description: Retrieve list of issue types within given project.

\n

Supported Connector Types: JIRA

\n", + "tags": [ + "connector" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "projectId", + "description": "Key of the project (This parameter can be obtained via the POST\nmethod on '/client/{clientId}/connector/populate')\n", + "in": "path", + "required": true, + "type": "string" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "type", + "username", + "password", + "url" + ], + "properties": { + "type": { + "type": "string", + "description": "Service now request type. Provide 'SERVICE_NOW' for incident request or 'SNOW_SERVICE_REQUEST' for service request." + }, + "username": { + "type": "string", + "description": "Username of the connector account." + }, + "password": { + "type": "string", + "description": "Password of the connector account. It is optional when connectorId is provided." + }, + "url": { + "type": "string", + "description": "URL of the connector framework." + }, + "connectorId": { + "type": "integer", + "description": "Id of the connector that will be edited.\nIf the connector Id is provided then password is not required. If the connector Id is not\nprovided, then you should provide all the required fields compulsory.\n" + }, + "ssl": { + "type": "string", + "format": "base64", + "description": "

\nThis field is a Base64-encoded SSL Certficate bundle. The certficates can be\nexported from your browser as a text file.\n

\n

NOTE: The Base64-encoded SSL Certificate bundle cannot contain line-endings as it must\nbe encoded as a JSON string field.

\n

\nIf you have access to the GNU commandline tools, you can retrieve the ssl certificates:\n

 prompt> openssl s_client -connect platform.risksense.com:443 -showcerts 
\nyou can base64 encode the certificates using the following command:\n
 prompt> cat certs.txt | base64 -w0 
\nin a single command you can retrieve, parse, and encode the certificates:\n
 prompt> echo | openssl s_client -connect platform.risksense.com:443 -showcerts | awk '/^-----BEGIN CERT/,/^-----END CERT/' | base64 -w0 
\n

\n" + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "currentlySelectedIssueType", + "issueTypes" + ], + "properties": { + "currentlySelectedIssueType": { + "type": "string", + "description": "Current selected issue type." + }, + "issueTypes": { + "type": "array", + "items": { + "type": "object", + "required": [ + "displayValue", + "value" + ], + "properties": { + "displayValue": { + "type": "string", + "description": "Label of the Field." + }, + "value": { + "type": "string", + "description": "Id of the Field." + } + } + } + } + } + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/connector/populate/project/{projectId}/issueType/{issueTypeId}": { + "post": { + "summary": "Retrieve list of supported and unsupported fields and connectorsettings.", + "description": "

Description: Retrieve list of supported and unsupported fields and connectorsettings.

\n

Supported Connector Types: JIRA

\n", + "tags": [ + "connector" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "projectId", + "description": "Key of the project (This parameter can be obtained via the POST\nmethod on '/client/{clientId}/connector/populate')\n", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "issueTypeId", + "description": "Id of the issueType (This parameter can be obtained via the POST\nmethod on '/client/{clientId}/connector/populate/project/{projectId}/issueType')\n", + "in": "path", + "required": true, + "type": "string" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "type", + "username", + "password", + "url" + ], + "properties": { + "type": { + "type": "string", + "description": "Service now request type. Provide 'SERVICE_NOW' for incident request or 'SNOW_SERVICE_REQUEST' for service request." + }, + "username": { + "type": "string", + "description": "Username of the connector account." + }, + "password": { + "type": "string", + "description": "Password of the connector account. It is optional when connectorId is provided." + }, + "url": { + "type": "string", + "description": "URL of the connector framework." + }, + "connectorId": { + "type": "integer", + "description": "Id of the connector that will be edited.\nIf the connector Id is provided then password is not required. If the connector Id is not\nprovided, then you should provide all the required fields compulsory.\n" + }, + "ssl": { + "type": "string", + "format": "base64", + "description": "

\nThis field is a Base64-encoded SSL Certficate bundle. The certficates can be\nexported from your browser as a text file.\n

\n

NOTE: The Base64-encoded SSL Certificate bundle cannot contain line-endings as it must\nbe encoded as a JSON string field.

\n

\nIf you have access to the GNU commandline tools, you can retrieve the ssl certificates:\n

 prompt> openssl s_client -connect platform.risksense.com:443 -showcerts 
\nyou can base64 encode the certificates using the following command:\n
 prompt> cat certs.txt | base64 -w0 
\nin a single command you can retrieve, parse, and encode the certificates:\n
 prompt> echo | openssl s_client -connect platform.risksense.com:443 -showcerts | awk '/^-----BEGIN CERT/,/^-----END CERT/' | base64 -w0 
\n

\n" + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "connectorSettings", + "fields", + "lockedFields", + "tagSyncField", + "tagSyncFieldOptions", + "unSupportedFields" + ], + "properties": { + "connectorSettings": { + "type": "object", + "required": [ + "initialState", + "statusOptions", + "closeTicketOnFindingsCloseEnabled", + "closedStateKey" + ], + "properties": { + "initialState": { + "type": "string", + "description": "Initial state of the ticket which is used to create a ticket using this connector." + }, + "statusOptions": { + "type": "array", + "items": { + "type": "object", + "required": [ + "displayValue", + "value" + ], + "properties": { + "displayValue": { + "type": "string", + "description": "Label of the Field." + }, + "value": { + "type": "string", + "description": "Id of the Field." + } + } + } + }, + "closeTicketOnFindingsClose": { + "type": "boolean", + "description": "True if enable changing the ticket state to the set state when all the associated findings reach the close state.\n" + }, + "closedStateKey": { + "type": "string", + "description": "the close state value of the status." + } + } + }, + "fields": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key", + "label", + "type", + "value", + "required", + "locked", + "isSupported", + "selectOptions", + "fields", + "queryParameters", + "dependentKey" + ], + "properties": { + "key": { + "type": "string", + "description": "Key of the field." + }, + "label": { + "type": "string", + "description": "Label of field." + }, + "type": { + "type": "string", + "description": "

Type of Field used to display.The types are

\n
    \n
  • boolean: Used for CheckBox field
  • \n
  • date: Used for Date field
  • \n
  • multiSelect: Used for the multiselect dropdown field
  • \n
  • number: Used for Number field
  • \n
  • radio: Used for Radio button field
  • \n
  • referenceDropdown: Used for the dropdown view where dropdown options are fetched dynamically.
  • \n
  • referenceMultiSelect: Used for the multiselect dropdown view where dropdown options are fetched dynamically.
  • \n
  • section: Used for Section field. This field only supported in SNOW_SERVICE_REQUEST connector type.
  • \n
  • string: Used for single line text field
  • \n
  • textArea: Used for TextArea field
  • \n
  • valueDropdown: Used for the dropdown field
  • \n
\n" + }, + "value": { + "type": "string", + "description": "Value of the field which was set when creating the connector otherwise empty string.\n" + }, + "required": { + "type": "boolean", + "description": "This variable shows whether this field is required or not. If it is required, it cannot be sumbitted as empty.\n" + }, + "locked": { + "type": "boolean", + "description": "True if the field value is not allowed to edit, otherwise false.\n" + }, + "isSupported": { + "type": "boolean", + "description": "True for all supported fields." + }, + "selectOptions": { + "type": "array", + "items": { + "type": "object", + "required": [ + "displayValue", + "value", + "isCurrentlySelected" + ], + "properties": { + "displayValue": { + "type": "string", + "description": "Label of the Field." + }, + "value": { + "type": "string", + "description": "Id of the Field." + }, + "isCurrentlySelected": { + "type": "boolean", + "description": "True if previously selected this option otherwise false.\nAvailable only if the type is 'referenceMultiSelect' or 'multiSelect'.\n" + } + } + } + }, + "fields": { + "type": "array", + "items": {}, + "description": "Available if the type is 'section'. This is same as parent field.\n" + }, + "queryParameters": { + "description": "Available only if the type is 'referenceDropdown' or 'referenceMultiSelect'", + "type": "object", + "required": [ + "table", + "filter", + "fieldName" + ], + "properties": { + "table": { + "type": "string", + "description": "Table name from which dropdown options are fetched. This is a 'SNOW_SERVICE_REQUEST' and 'SERVICE_NOW' request field." + }, + "filter": { + "type": "string", + "description": "Table filter to filter the records. This is a 'SNOW_SERVICE_REQUEST' and 'SERVICE_NOW' request field." + }, + "fieldName": { + "type": "string", + "description": "Field Name for which dropdown options are fetched. This is a 'JIRA' request field." + } + } + }, + "dependentKey": { + "type": "string", + "description": "Key of dependent field. Dropdown options for this field is dependent on value of this\nfield to which this key belongs. Available only if the type is 'referenceDropdown'\n" + } + } + } + }, + "lockedFields": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key", + "label", + "isCurrentlySelected" + ], + "properties": { + "key": { + "type": "string", + "description": "Key of the option." + }, + "label": { + "type": "string", + "description": "Label of the option which is used to display." + }, + "isCurrentlySelected": { + "type": "boolean", + "description": "True if previously selected this option otherwise false. \n" + } + } + } + }, + "tagSyncField": { + "type": "string", + "description": "Value of Tag Name Sync Field. This field is populated with the tag name while creating tickets." + }, + "tagSyncFieldOptions": { + "type": "array", + "items": { + "type": "object", + "required": [ + "displayValue", + "value" + ], + "properties": { + "displayValue": { + "type": "string", + "description": "Label of the Field." + }, + "value": { + "type": "string", + "description": "Id of the Field." + } + } + } + }, + "unSupportedFields": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key", + "label", + "value", + "isSupported" + ], + "properties": { + "key": { + "type": "string", + "description": "Key of the field." + }, + "label": { + "type": "string", + "description": "Label of field." + }, + "value": { + "type": "string", + "description": "Value of the field which was set when creating the connector otherwise empty string.\n" + }, + "isSupported": { + "type": "boolean", + "description": "false for all unsupported Fields." + } + } + } + } + } + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/connector/{connectorId}/issueTypeField": { + "get": { + "summary": "Get list of issue type fields associated with the connector.", + "description": "Supported Connector Types: JIRA\n", + "tags": [ + "ticket" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "connectorId", + "description": "Id of connector (This parameter can be obtained via the GET\nmethod on '/client/{clientId}/connector')\n", + "in": "path", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "fields", + "unSupportedFields", + "tagSyncField", + "project", + "issueType" + ], + "properties": { + "fields": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key", + "label", + "type", + "value", + "required", + "locked", + "isSupported", + "selectOptions", + "fields", + "queryParameters", + "dependentKey" + ], + "properties": { + "key": { + "type": "string", + "description": "Key of the field." + }, + "label": { + "type": "string", + "description": "Label of field." + }, + "type": { + "type": "string", + "description": "

Type of Field used to display.The types are

\n
    \n
  • boolean: Used for CheckBox field
  • \n
  • date: Used for Date field
  • \n
  • multiSelect: Used for the multiselect dropdown field
  • \n
  • number: Used for Number field
  • \n
  • radio: Used for Radio button field
  • \n
  • referenceDropdown: Used for the dropdown view where dropdown options are fetched dynamically.
  • \n
  • referenceMultiSelect: Used for the multiselect dropdown view where dropdown options are fetched dynamically.
  • \n
  • section: Used for Section field. This field only supported in SNOW_SERVICE_REQUEST connector type.
  • \n
  • string: Used for single line text field
  • \n
  • textArea: Used for TextArea field
  • \n
  • valueDropdown: Used for the dropdown field
  • \n
\n" + }, + "value": { + "type": "string", + "description": "Value of the field which was set when creating the connector otherwise empty string.\n" + }, + "required": { + "type": "boolean", + "description": "This variable shows whether this field is required or not. If it is required, it cannot be sumbitted as empty.\n" + }, + "locked": { + "type": "boolean", + "description": "True if the field value is not allowed to edit, otherwise false.\n" + }, + "isSupported": { + "type": "boolean", + "description": "True for all supported fields." + }, + "selectOptions": { + "type": "array", + "items": { + "type": "object", + "required": [ + "displayValue", + "value", + "isCurrentlySelected" + ], + "properties": { + "displayValue": { + "type": "string", + "description": "Label of the Field." + }, + "value": { + "type": "string", + "description": "Id of the Field." + }, + "isCurrentlySelected": { + "type": "boolean", + "description": "True if previously selected this option otherwise false.\nAvailable only if the type is 'referenceMultiSelect' or 'multiSelect'.\n" + } + } + } + }, + "fields": { + "type": "array", + "items": {}, + "description": "Available if the type is 'section'. This is same as parent field.\n" + }, + "queryParameters": { + "description": "Available only if the type is 'referenceDropdown' or 'referenceMultiSelect'", + "type": "object", + "required": [ + "table", + "filter", + "fieldName" + ], + "properties": { + "table": { + "type": "string", + "description": "Table name from which dropdown options are fetched. This is a 'SNOW_SERVICE_REQUEST' and 'SERVICE_NOW' request field." + }, + "filter": { + "type": "string", + "description": "Table filter to filter the records. This is a 'SNOW_SERVICE_REQUEST' and 'SERVICE_NOW' request field." + }, + "fieldName": { + "type": "string", + "description": "Field Name for which dropdown options are fetched. This is a 'JIRA' request field." + } + } + }, + "dependentKey": { + "type": "string", + "description": "Key of dependent field. Dropdown options for this field is dependent on value of this\nfield to which this key belongs. Available only if the type is 'referenceDropdown'\n" + } + } + } + }, + "unSupportedFields": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key", + "label", + "value", + "isSupported" + ], + "properties": { + "key": { + "type": "string", + "description": "Key of the field." + }, + "label": { + "type": "string", + "description": "Label of field." + }, + "value": { + "type": "string", + "description": "Value of the field which was set when creating the connector otherwise empty string.\n" + }, + "isSupported": { + "type": "boolean", + "description": "false for all unsupported Fields." + } + } + } + }, + "tagSyncField": { + "type": "string", + "description": "Value of Tag Sync Field which was set when creating the connector otherwise empty string.\n" + }, + "project": { + "type": "string", + "description": "Project Name." + }, + "issueType": { + "type": "string", + "description": "Issue Type Name." + } + } + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/connector/cmdb/field/editForm/populate": { + "post": { + "summary": "Get list of CMDB fields and connector mappings to each field for editing.", + "tags": [ + "connector" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "description": "Filter for job requests", + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "fields", + "fieldProperties" + ], + "properties": { + "fields": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key", + "label", + "isCurrentlySelected" + ], + "properties": { + "key": { + "type": "string", + "description": "Key of the option." + }, + "label": { + "type": "string", + "description": "Label of the option which is used to display." + }, + "isCurrentlySelected": { + "type": "boolean", + "description": "True if previously selected this option otherwise false. \n" + } + } + } + }, + "fieldProperties": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key", + "value", + "label", + "connectorMapping" + ], + "properties": { + "key": { + "type": "string", + "description": "CMDB field key." + }, + "value": { + "type": "string", + "description": "Value of the field." + }, + "label": { + "type": "string", + "description": "Label of the CMDB field." + }, + "connectorMapping": { + "type": "array", + "description": "Mapping of connector to asset count for this CMDB field.", + "items": { + "type": "object", + "required": [ + "name", + "assetCount" + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the connector" + }, + "assetCount": { + "type": "integer", + "description": "Total number of asset's CMDB field mapped to this connector" + } + } + } + } + } + } + } + } + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/connector/cmdb/field/lockForm/populate": { + "post": { + "summary": "Get list of CMDB fields and connector mappings to each field for locking.", + "tags": [ + "connector" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "description": "Filter for job requests", + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "fields", + "fieldProperties", + "connectors" + ], + "properties": { + "fields": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key", + "label", + "isCurrentlySelected" + ], + "properties": { + "key": { + "type": "string", + "description": "Key of the option." + }, + "label": { + "type": "string", + "description": "Label of the option which is used to display." + }, + "isCurrentlySelected": { + "type": "boolean", + "description": "True if previously selected this option otherwise false. \n" + } + } + } + }, + "fieldProperties": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key", + "value", + "label", + "connectorMapping" + ], + "properties": { + "key": { + "type": "string", + "description": "CMDB field key." + }, + "value": { + "type": "string", + "description": "Value of the field." + }, + "label": { + "type": "string", + "description": "Label of the CMDB field." + }, + "connectorMapping": { + "type": "array", + "description": "Mapping of connector to asset count for this CMDB field.", + "items": { + "type": "object", + "required": [ + "name", + "assetCount" + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the connector" + }, + "assetCount": { + "type": "integer", + "description": "Total number of asset's CMDB field mapped to this connector" + } + } + } + } + } + } + }, + "connectors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "displayValue", + "value" + ], + "properties": { + "displayValue": { + "type": "string", + "description": "Label of the Field." + }, + "value": { + "type": "integer", + "description": "Id of the Field." + } + } + } + } + } + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/connector/cmdb/customField/label": { + "get": { + "summary": "List of CMDB custom fields.", + "tags": [ + "connector" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key", + "label", + "type", + "value", + "required", + "locked", + "isSupported" + ], + "properties": { + "key": { + "type": "string", + "description": "Key of the field." + }, + "label": { + "type": "string", + "description": "Label of field." + }, + "type": { + "type": "string" + }, + "value": { + "type": "string", + "description": "Value of the field which was set when creating the connector otherwise empty string.\n" + }, + "required": { + "type": "boolean", + "description": "This variable shows whether this field is required or not. If it is required, it cannot be submitted as empty.\n" + }, + "locked": { + "type": "boolean", + "description": "True if the field value is not allowed to edit, otherwise false.\n" + }, + "isSupported": { + "type": "boolean", + "description": "True for all supported fields." + } + } + } + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + }, + "post": { + "summary": "Save CMDB custom field label.", + "tags": [ + "connector" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "object", + "required": [ + "value", + "key" + ], + "properties": { + "value": { + "type": "string", + "description": "value of the Field." + }, + "key": { + "type": "string", + "description": "key of the Field." + } + } + } + } + } + ], + "responses": { + "204": { + "description": "Success", + "schema": { + "description": "Save request was processed without errors" + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/{subject}/{assetId}/cmdb/multipleFound": { + "get": { + "summary": "Get the list of assets that have multiple matches.", + "description": "In case if Service Now CMDB has more than one match for an asset then the full list of duplicates can be seen through this", + "tags": [ + "connector" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "subject", + "description": "

Subject to search against. Supported subject are available\nthrough the GET method on /subjects
\nExample: \"hostFinding\"

\n", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "assetId", + "description": "Id of the asset that needs to be created (This parameter can be obtained via the GET method on '/{subject}/{assetId}')", + "in": "path", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "connectorId", + "sysIdFieldInfo" + ], + "properties": { + "connectorId": { + "type": "integer", + "description": "Id of the connector used" + }, + "sysIdFieldInfo": { + "type": "array", + "items": { + "type": "object", + "required": [ + "sysId", + "className" + ], + "properties": { + "sysId": { + "type": "string", + "description": "Unique id for the configuration item at the Service Now end" + }, + "className": { + "type": "string", + "description": "Name of the class associated at the Service Now end" + } + } + } + } + }, + "example": { + "connectorId": 111, + "sysIdFieldInfo": { + "sysId": "duu3434uuew", + "className": "cmdb_ci" + } + } + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/{subject}/{assetId}/connector/{connectorId}/cmdb/mergeMultipleFound": { + "post": { + "summary": "Get the list of assets that have multiple matches.", + "description": "In case if Service Now CMDB has more than one match for an asset then the full list of duplicates can be seen through this", + "tags": [ + "connector" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "subject", + "description": "

Subject to search against. Supported subject are available\nthrough the GET method on /subjects
\nExample: \"hostFinding\"

\n", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "assetId", + "description": "Id of the asset that needs to be created (This parameter can be obtained via the GET method on '/{subject}/{assetId}')", + "in": "path", + "required": true, + "type": "integer" + }, + { + "name": "connectorId", + "description": "Id of connector (This parameter can be obtained via the GET\nmethod on '/client/{clientId}/connector')\n", + "in": "path", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "hostId", + "uniqueId", + "table" + ], + "properties": { + "hostId": { + "type": "integer", + "description": "Unique id of the host that needs to be merged" + }, + "uniqueId": { + "type": "string", + "description": "Unique id for the configuration item at the Service Now end" + }, + "table": { + "type": "string", + "description": "Name of the class associated at the Service Now end" + } + }, + "example": { + "hostId": 20, + "sysId": "a1b345", + "table": "cmdb_ci" + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "id", + "clientId", + "jobTypeId", + "jobPriorityId", + "jobStateId", + "workerInstanceId", + "userId", + "isDrainstopExempt", + "startTime", + "endTime", + "filterStartTime", + "created", + "updated", + "retryDateTime", + "isClientExclusiveLock" + ], + "properties": { + "id": { + "type": "integer" + }, + "clientId": { + "type": "integer" + }, + "jobTypeId": { + "type": "integer" + }, + "jobPriorityId": { + "type": "integer" + }, + "jobStateId": { + "type": "integer" + }, + "workerInstanceId": { + "type": "integer" + }, + "userId": { + "type": "integer" + }, + "isDrainstopExempt": { + "type": "boolean" + }, + "startTime": { + "type": "string", + "format": "date-time" + }, + "endTime": { + "type": "string", + "format": "date-time" + }, + "filterStartTime": { + "type": "string", + "format": "date-time" + }, + "created": { + "type": "string", + "format": "date-time" + }, + "updated": { + "type": "string", + "format": "date-time" + }, + "retryDateTime": { + "type": "string", + "format": "date-time" + }, + "isClientExclusiveLock": { + "type": "boolean" + } + } + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/{subject}/{assetId}/connector/{connectorId}/cmdb/createAsset": { + "get": { + "summary": "Create asset at the Service Now CMDB end.", + "description": "Assets not found at the Service Now CMDB will be created in the extended table\n", + "tags": [ + "connector" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "subject", + "description": "

Subject to search against. Supported subject are available\nthrough the GET method on /subjects
\nExample: \"hostFinding\"

\n", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "assetId", + "description": "Id of the asset that needs to be created (This parameter can be obtained via the GET method on '/{subject}/{assetId}')", + "in": "path", + "required": true, + "type": "integer" + }, + { + "name": "connectorId", + "description": "Id of connector (This parameter can be obtained via the GET\nmethod on '/client/{clientId}/connector')\n", + "in": "path", + "required": true, + "type": "integer" + } + ], + "responses": { + "202": { + "description": "Accepted", + "schema": { + "type": "object", + "required": [ + "connectorId", + "sysId" + ], + "properties": { + "connectorId": { + "type": "integer" + }, + "sysId": { + "type": "string", + "description": "Unique Id of the configuration item maintained at the CMDB end" + } + } + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/{subject}/{assetId}/connector/{connectorId}/cmdb/syncSingleAsset": { + "get": { + "summary": "Realign a record that has failed to sync.", + "description": "Assets no longer syncing can be manually realigned based on the current status at Service Now\n", + "tags": [ + "connector" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "subject", + "description": "

Subject to search against. Supported subject are available\nthrough the GET method on /subjects
\nExample: \"hostFinding\"

\n", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "assetId", + "description": "Id of the asset that needs to be created (This parameter can be obtained via the GET method on '/{subject}/{assetId}')", + "in": "path", + "required": true, + "type": "integer" + }, + { + "name": "connectorId", + "description": "Id of connector (This parameter can be obtained via the GET\nmethod on '/client/{clientId}/connector')\n", + "in": "path", + "required": true, + "type": "integer" + } + ], + "responses": { + "202": { + "description": "Accepted", + "schema": { + "type": "object", + "required": [ + "assetId", + "CmdbUniqueIdStatus" + ], + "properties": { + "assetId": { + "type": "integer" + }, + "CmdbUniqueIdStatus": { + "type": "string", + "enum": [ + "SYNCED", + "NOT_FOUND", + "MULTIPLE_FOUND", + "RECORD_NO_LONGER_FOUND", + "NOT_APPLICABLE" + ] + } + } + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/connector/{connectorId}/ticket": { + "get": { + "summary": "Get list of fields associated with the connector.", + "description": "Supported Connector Types: GENERIC_SNOW\n", + "tags": [ + "ticket" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "connectorId", + "description": "Id of connector (This parameter can be obtained via the GET\nmethod on '/client/{clientId}/connector')\n", + "in": "path", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key", + "label", + "type", + "value", + "required", + "locked", + "isSupported", + "selectOptions", + "fields", + "queryParameters", + "dependentKey" + ], + "properties": { + "key": { + "type": "string", + "description": "Key of the field." + }, + "label": { + "type": "string", + "description": "Label of field." + }, + "type": { + "type": "string", + "description": "

Type of Field used to display.The types are

\n
    \n
  • boolean: Used for CheckBox field
  • \n
  • date: Used for Date field
  • \n
  • multiSelect: Used for the multiselect dropdown field
  • \n
  • number: Used for Number field
  • \n
  • radio: Used for Radio button field
  • \n
  • referenceDropdown: Used for the dropdown view where dropdown options are fetched dynamically.
  • \n
  • referenceMultiSelect: Used for the multiselect dropdown view where dropdown options are fetched dynamically.
  • \n
  • section: Used for Section field. This field only supported in SNOW_SERVICE_REQUEST connector type.
  • \n
  • string: Used for single line text field
  • \n
  • textArea: Used for TextArea field
  • \n
  • valueDropdown: Used for the dropdown field
  • \n
\n" + }, + "value": { + "type": "string", + "description": "Value of the field which was set when creating the connector otherwise empty string.\n" + }, + "required": { + "type": "boolean", + "description": "This variable shows whether this field is required or not. If it is required, it cannot be sumbitted as empty.\n" + }, + "locked": { + "type": "boolean", + "description": "True if the field value is not allowed to edit, otherwise false.\n" + }, + "isSupported": { + "type": "boolean", + "description": "True for all supported fields." + }, + "selectOptions": { + "type": "array", + "items": { + "type": "object", + "required": [ + "displayValue", + "value", + "isCurrentlySelected" + ], + "properties": { + "displayValue": { + "type": "string", + "description": "Label of the Field." + }, + "value": { + "type": "string", + "description": "Id of the Field." + }, + "isCurrentlySelected": { + "type": "boolean", + "description": "True if previously selected this option otherwise false.\nAvailable only if the type is 'referenceMultiSelect' or 'multiSelect'.\n" + } + } + } + }, + "fields": { + "type": "array", + "items": {}, + "description": "Available if the type is 'section'. This is same as parent field.\n" + }, + "queryParameters": { + "description": "Available only if the type is 'referenceDropdown' or 'referenceMultiSelect'", + "type": "object", + "required": [ + "table", + "filter", + "fieldName" + ], + "properties": { + "table": { + "type": "string", + "description": "Table name from which dropdown options are fetched. This is a 'SNOW_SERVICE_REQUEST' and 'SERVICE_NOW' request field." + }, + "filter": { + "type": "string", + "description": "Table filter to filter the records. This is a 'SNOW_SERVICE_REQUEST' and 'SERVICE_NOW' request field." + }, + "fieldName": { + "type": "string", + "description": "Field Name for which dropdown options are fetched. This is a 'JIRA' request field." + } + } + }, + "dependentKey": { + "type": "string", + "description": "Key of dependent field. Dropdown options for this field is dependent on value of this\nfield to which this key belongs. Available only if the type is 'referenceDropdown'\n" + } + } + } + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/host": { + "post": { + "summary": "Create a new host", + "tags": [ + "host" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "groupId", + "groupIds", + "assessmentId", + "networkId", + "ipAddress", + "subnet", + "hostName", + "discoveredDate" + ], + "properties": { + "groupId": { + "description": "Either Group Id or Group Ids is mandatory", + "type": "integer" + }, + "groupIds": { + "description": "Either Group Id or Group Ids is mandatory", + "type": "array", + "items": { + "type": "integer" + } + }, + "assessmentId": { + "type": "integer" + }, + "networkId": { + "type": "integer" + }, + "ipAddress": { + "type": "string" + }, + "subnet": { + "type": "string" + }, + "hostName": { + "type": "string" + }, + "discoveredDate": { + "type": "string" + }, + "scannerFirstDiscoveredOn": { + "type": "string" + }, + "scannerLastDiscoveredOn": { + "type": "string" + }, + "services": { + "type": "array", + "items": { + "type": "object", + "required": [ + "portNumber", + "name" + ], + "properties": { + "portNumber": { + "type": "integer" + }, + "name": { + "type": "string" + } + } + } + }, + "criticality": { + "type": "integer" + }, + "operatingSystemScanner": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "family": { + "type": "string" + }, + "class": { + "type": "string" + }, + "vendor": { + "type": "string" + }, + "product": { + "type": "string" + }, + "certainty": { + "type": "number" + } + } + }, + "createCmdb": { + "type": "object", + "description": "cmdb field key to value.\n" + }, + "lockCmdb": { + "type": "object", + "description": "cmdb field key to connectorId. If connectorId is -1, the field is locked to API/UI and\nany further updates to this field, can only be done by API/UI.\n" + } + }, + "example": { + "groupId": 1, + "groupIds": [ + 101, + 102, + 103 + ], + "assessmentId": 1, + "networkId": 3, + "ipAddress": "10.1.1.1", + "subnet": "10.1.1", + "hostName": "www.hostname.com", + "discoveredDate": "2018-06-18T00:00:00", + "scannerFirstDiscoveredOn": "2018-06-18T00:00:00", + "scannerLastDiscoveredOn": "2019-07-18T00:00:00", + "services": [ + { + "portNumber": 8080, + "name": "http" + }, + { + "portNumber": 22, + "name": "ssh" + } + ], + "criticality": 1, + "operatingSystemScanner": { + "name": "Linux Kernel 3.2.0-67-generic on Ubuntu 12.04", + "family": "Linux", + "class": "general-purpose", + "vendor": "Ubuntu", + "product": "Linux Kernel 3.2.0-67-generic on Ubuntu 12.04", + "certainty": 2 + }, + "createCmdb": { + "busines_criticality": 1, + "manufacturer": "Dell", + "model_id": "XPS-15", + "mac_address": "AA-00-04-00-XX-YY", + "location": "Albuquerque", + "managed_by": "manager", + "owned_by": "owner", + "supported_by": "supporter", + "support_group": "supportGrp", + "sys_id": "123e4567-e89b-12d3-a456-556642440000", + "os": "Windows 10", + "sys_updated_on": "2018-07-23", + "asset_tag": "asset tag", + "cf_1": "custom tag", + "ferpa": "true", + "hipaa": "true", + "pci": "false" + }, + "lockCmdb": { + "os": -1, + "manufacturer": 85 + } + } + } + } + ], + "responses": { + "201": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "409": { + "description": "Conflict" + } + } + } + }, + "/client/{clientId}/host/model": { + "get": { + "summary": "List projections and their models", + "description": "List projections and their models that can be requested from the search endpoint.\n", + "tags": [ + "host" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "object", + "properties": { + "projections": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "fields": { + "type": "array", + "items": { + "type": "object", + "properties": { + "field": { + "type": "string" + }, + "type": { + "type": "string" + }, + "nested": { + "type": "array", + "items": { + "type": "object", + "description": "Same as ProjectionField" + } + } + } + } + } + } + } + } + }, + "example": { + "projections": [ + { + "name": "basic", + "fields": [ + { + "field": "id", + "type": "integer" + }, + { + "field": "name", + "type": "string" + } + ] + } + ] + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/host/filter": { + "get": { + "summary": "List fields that can be filtered by in the search endpoint", + "tags": [ + "host" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "array", + "items": { + "required": [ + "name", + "uid", + "operators", + "type", + "description" + ], + "properties": { + "name": { + "type": "string" + }, + "uid": { + "type": "string", + "description": "uid used to indentify fields in suggest and search requests" + }, + "operators": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + } + }, + "datatype": { + "type": "string" + }, + "description": { + "type": "string" + } + } + }, + "example": [ + { + "name": "id", + "uid": "id", + "operator": [ + "EXACT", + "IN" + ], + "type": "integer", + "description": "The id" + } + ] + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/host/suggest": { + "post": { + "summary": "Suggest values for filter fields", + "tags": [ + "host" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "filter" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + }, + "description": "Filters to used to narrow down the the result set\n" + }, + "filter": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + }, + "description": "Filter for which to suggest values for. The filter value will be\ntreated as a wildcard.\n" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": true, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "filter": { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "" + } + } + } + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key", + "count" + ], + "properties": { + "key": { + "type": "string", + "description": "Value for the field the suggestion was requested for." + }, + "count": { + "type": "integer", + "format": "int64" + } + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/host/search": { + "post": { + "summary": "Search for hosts", + "tags": [ + "host" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "sort" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + }, + "projection": { + "type": "string" + }, + "sort": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "direction" + ], + "properties": { + "field": { + "type": "string" + }, + "direction": { + "type": "string", + "enum": [ + "ASC", + "DESC" + ] + } + } + } + }, + "page": { + "type": "integer" + }, + "size": { + "type": "integer" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "projection": "basic", + "sort": [ + { + "field": "id", + "direction": "ASC" + } + ], + "page": 0, + "size": 20 + } + } + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "object", + "required": [ + "_embedded", + "page" + ], + "properties": { + "_embedded": { + "type": "object", + "required": [ + "strings" + ], + "properties": { + "strings": { + "type": "array", + "items": { + "type": "object", + "description": "

The response structure is subject dependent. Subject structure\ncan be found via the subject endpoint.

\n" + } + } + } + }, + "page": { + "type": "object", + "required": [ + "size", + "totalElements", + "totalPages", + "number" + ], + "properties": { + "size": { + "type": "integer" + }, + "totalElements": { + "type": "integer" + }, + "totalPages": { + "type": "integer" + }, + "number": { + "type": "integer" + } + } + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "id", + "errorRefId", + "code", + "cause" + ], + "properties": { + "id": { + "type": "string", + "description": "Entity id which failed to be retrieved" + }, + "errorRefId": { + "type": "string", + "description": "A unique identifier for the error" + }, + "code": { + "type": "integer", + "description": "http status code of the error" + }, + "cause": { + "type": "string", + "description": "http status code message" + } + } + } + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/host/trend": { + "post": { + "summary": "Search for trend information of hosts", + "tags": [ + "host" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "assetIds" + ], + "properties": { + "assetIds": { + "description": "Asset ids for which trend has to be calculated", + "type": "array", + "items": { + "type": "integer" + } + }, + "includeWeeklyTrend": { + "description": "Include weekly trend for assets", + "type": "boolean", + "default": true + }, + "includeMonthlyTrend": { + "description": "Include monthly trend for assets", + "type": "boolean", + "default": true + }, + "fields": { + "description": "fields for which we need to fetch trend information", + "type": "array", + "items": { + "type": "string", + "enum": [ + "open", + "closed", + "open_weaponized", + "closed_weaponized", + "open_vrr_critical", + "open_vrr_high", + "open_vrr_medium", + "open_vrr_low", + "open_vrr_info", + "open_severity_critical", + "open_severity_high", + "open_severity_medium", + "open_severity_low", + "open_severity_info", + "open_weaponized_vrr_critical", + "open_weaponized_vrr_high", + "open_weaponized_vrr_medium", + "open_weaponized_vrr_low", + "open_weaponized_vrr_info", + "open_weaponized_severity_critical", + "open_weaponized_severity_high", + "open_weaponized_severity_medium", + "open_weaponized_severity_low", + "open_weaponized_severity_info", + "closed_vrr_critical", + "closed_vrr_high", + "closed_vrr_medium", + "closed_vrr_low", + "closed_vrr_info", + "closed_severity_critical", + "closed_severity_high", + "closed_severity_medium", + "closed_severity_low", + "closed_severity_info", + "closed_weaponized_vrr_critical", + "closed_weaponized_vrr_high", + "closed_weaponized_vrr_medium", + "closed_weaponized_vrr_low", + "closed_weaponized_vrr_info", + "closed_weaponized_severity_critical", + "closed_weaponized_severity_high", + "closed_weaponized_severity_medium", + "closed_weaponized_severity_low", + "closed_weaponized_severity_info" + ] + } + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object" + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/search/host/dynamic-columns": { + "get": { + "summary": "Get Dynamic Columns", + "tags": [ + "host" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "array", + "items": { + "properties": { + "esParent": { + "type": "string" + }, + "rsName": { + "type": "string" + }, + "esName": { + "type": "string" + }, + "esFieldType": { + "type": "string" + }, + "subject": { + "type": "string" + }, + "scannerUuid": { + "type": "array" + } + } + }, + "example": [ + { + "esParent": "additionalDetails" + }, + { + "rsName": "Tenable UUID" + }, + { + "esName": "tenable_uuid" + }, + { + "esFieldType": "STRING" + }, + { + "subject": "host" + }, + { + "scannerUuid": "Nessus" + } + ] + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/host/update": { + "post": { + "summary": "Update hosts", + "tags": [ + "host" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filterRequest" + ], + "properties": { + "filterRequest": { + "description": "Filter for job requests", + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + } + }, + "criticality": { + "type": "integer", + "description": "1 - 5" + }, + "isExternal": { + "type": "boolean" + }, + "editCmdb": { + "type": "object", + "description": "cmdb field key to value.The cmdb fields keys can be obtained via the POST\nmethod on '/client/{clientId}/connector/cmdb/field/editForm/populate'\n" + }, + "lockCmdb": { + "type": "object", + "description": "cmdb field key to connectorId. If connectorId is -1, the field is locked to API/UI and\nany further updates to this field, can only be done by API/UI. The cmdb field keys and connector Id can be obtained via the POST\nmethod on '/client/{clientId}/connector/cmdb/field/lockForm/populate'\n" + }, + "metricsOverrideType": { + "type": "string", + "enum": [ + "OVERRIDE", + "RESET" + ] + } + }, + "example": { + "filterRequest": { + "filters": [ + { + "field": "ipAddress", + "exclusive": false, + "operator": "EXACT", + "value": "10.0.97.1" + } + ] + }, + "criticality": 2, + "isExternal": true, + "editCmdb": { + "os": "MAC OS", + "manufacturer": "Apple" + }, + "lockCmdb": { + "os": -1, + "manufacturer": 85 + }, + "metricsOverrideType": "OVERRIDE" + } + } + } + ], + "responses": { + "200": { + "description": "Job Created", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/host/tag": { + "post": { + "summary": "Add or remove tag", + "tags": [ + "host" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filterRequest", + "tagId", + "isRemove" + ], + "properties": { + "filterRequest": { + "description": "Filter for job requests", + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + } + }, + "tagId": { + "description": "Tag being used in tagging/untagging", + "type": "integer" + }, + "isRemove": { + "description": "True if the tag is being removed, false otherwise.", + "type": "boolean" + }, + "publishTicketStats": { + "description": "To publish ticket description fields to the ticket which is associated with the tag.", + "type": "boolean" + } + }, + "example": { + "tagId": 1, + "isRemove": false, + "filterRequest": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "EXACT", + "value": 1 + } + ] + } + } + } + } + ], + "responses": { + "200": { + "description": "Job Created", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/host/delete": { + "post": { + "summary": "Delete entities based on filters", + "tags": [ + "host" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filterRequest" + ], + "properties": { + "filterRequest": { + "description": "Filter for job requests", + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + } + } + }, + "example": { + "filterRequest": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "EXACT", + "value": "1" + } + ] + } + } + } + } + ], + "responses": { + "200": { + "description": "Job Created", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/host/{identifier}": { + "get": { + "summary": "Paginate hosts in client that match the identifier", + "tags": [ + "asset" + ], + "description": "Use search endpoint: '/client/{clientId}/host/search' instead", + "deprecated": true, + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "identifier", + "description": "address/hostname (depending on the associated network type) of the host", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "size", + "in": "query", + "description": "Size of the page requested", + "required": false, + "type": "integer" + }, + { + "name": "page", + "in": "query", + "description": "Page number being requested (first page: 0)", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "_embedded", + "page" + ], + "properties": { + "_embedded": { + "type": "object", + "required": [ + "hosts" + ], + "properties": { + "hosts": { + "type": "array", + "items": { + "allOf": [ + { + "type": "object", + "required": [ + "id", + "rs3", + "criticallity", + "tags", + "networkId", + "openFindingCounts", + "lastScanTime", + "scanners" + ], + "properties": { + "id": { + "type": "integer" + }, + "rs3": { + "type": "integer", + "minimum": 300, + "maximum": 850 + }, + "criticallity": { + "type": "integer", + "minimum": 1, + "maximum": 5 + }, + "tags": { + "type": "array", + "items": { + "type": "object", + "required": [ + "name", + "description", + "category" + ], + "properties": { + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "category": { + "type": "string", + "enum": [ + "COMPLIANCE", + "LOCATION", + "CUSTOM", + "REMEDIATION", + "PEOPLE" + ] + } + } + } + }, + "networkId": { + "type": "integer" + }, + "openFindingCounts": { + "type": "object", + "description": "Counts of open finding by severity", + "properties": { + "critical": { + "type": "integer" + }, + "high": { + "type": "integer" + }, + "medium": { + "type": "integer" + }, + "low": { + "type": "integer" + }, + "info": { + "type": "integer" + } + } + }, + "lastScanTime": { + "type": "string", + "format": "date-time" + }, + "scanners": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + { + "type": "object", + "required": [ + "hostname", + "ipAddress", + "ports", + "osName", + "osFamily", + "osClass", + "osVendor", + "external" + ], + "properties": { + "hostname": { + "type": "string" + }, + "ipAddress": { + "type": "string" + }, + "ports": { + "type": "array", + "items": { + "type": "integer" + } + }, + "osName": { + "type": "string" + }, + "osFamily": { + "type": "string" + }, + "osClass": { + "type": "string" + }, + "osVendor": { + "type": "string" + }, + "external": { + "type": "boolean" + } + } + } + ] + } + } + } + }, + "page": { + "type": "object", + "required": [ + "size", + "totalElements", + "totalPages", + "number" + ], + "properties": { + "size": { + "type": "integer" + }, + "totalElements": { + "type": "integer" + }, + "totalPages": { + "type": "integer" + }, + "number": { + "type": "integer" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/host/{identifier}/network/{networkId}": { + "get": { + "summary": "List hosts in client from network", + "tags": [ + "asset" + ], + "deprecated": true, + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "identifier", + "description": "address/hostname (depending on the associated network type) of the host", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "networkId", + "description": "Identifier for a network associated with the client (This parameter can be obtained via the GET method on '/network')\n", + "in": "path", + "required": true, + "type": "integer" + }, + { + "name": "size", + "in": "query", + "description": "Size of the page requested", + "required": false, + "type": "integer" + }, + { + "name": "page", + "in": "query", + "description": "Page number being requested (first page: 0)", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "_embedded", + "page" + ], + "properties": { + "_embedded": { + "type": "object", + "required": [ + "hosts" + ], + "properties": { + "hosts": { + "type": "array", + "items": { + "allOf": [ + { + "type": "object", + "required": [ + "id", + "rs3", + "criticallity", + "tags", + "networkId", + "openFindingCounts", + "lastScanTime", + "scanners" + ], + "properties": { + "id": { + "type": "integer" + }, + "rs3": { + "type": "integer", + "minimum": 300, + "maximum": 850 + }, + "criticallity": { + "type": "integer", + "minimum": 1, + "maximum": 5 + }, + "tags": { + "type": "array", + "items": { + "type": "object", + "required": [ + "name", + "description", + "category" + ], + "properties": { + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "category": { + "type": "string", + "enum": [ + "COMPLIANCE", + "LOCATION", + "CUSTOM", + "REMEDIATION", + "PEOPLE" + ] + } + } + } + }, + "networkId": { + "type": "integer" + }, + "openFindingCounts": { + "type": "object", + "description": "Counts of open finding by severity", + "properties": { + "critical": { + "type": "integer" + }, + "high": { + "type": "integer" + }, + "medium": { + "type": "integer" + }, + "low": { + "type": "integer" + }, + "info": { + "type": "integer" + } + } + }, + "lastScanTime": { + "type": "string", + "format": "date-time" + }, + "scanners": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + { + "type": "object", + "required": [ + "hostname", + "ipAddress", + "ports", + "osName", + "osFamily", + "osClass", + "osVendor", + "external" + ], + "properties": { + "hostname": { + "type": "string" + }, + "ipAddress": { + "type": "string" + }, + "ports": { + "type": "array", + "items": { + "type": "integer" + } + }, + "osName": { + "type": "string" + }, + "osFamily": { + "type": "string" + }, + "osClass": { + "type": "string" + }, + "osVendor": { + "type": "string" + }, + "external": { + "type": "boolean" + } + } + } + ] + } + } + } + }, + "page": { + "type": "object", + "required": [ + "size", + "totalElements", + "totalPages", + "number" + ], + "properties": { + "size": { + "type": "integer" + }, + "totalElements": { + "type": "integer" + }, + "totalPages": { + "type": "integer" + }, + "number": { + "type": "integer" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/host/export/template": { + "get": { + "summary": "List out all fields that are part of configurable export.", + "tags": [ + "host" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "object", + "required": [ + "id", + "clientId", + "userId", + "name", + "description", + "shared", + "isDefault", + "subject", + "exportableFields" + ], + "properties": { + "id": { + "description": "The id", + "type": "integer" + }, + "clientId": { + "description": "Client id", + "type": "integer" + }, + "userId": { + "description": "User id", + "type": "integer" + }, + "name": { + "description": "Template name", + "type": "string" + }, + "description": { + "description": "Template description", + "type": "string" + }, + "shared": { + "description": "Describes whether this template shared or not", + "type": "boolean" + }, + "isDefault": { + "description": "Describes whether this template is default or not", + "type": "boolean" + }, + "subject": { + "description": "For which asset to fetch fileds", + "type": "string" + }, + "exportableFields": { + "description": "List of fileds", + "type": "array", + "items": { + "type": "object", + "required": [ + "heading", + "fields" + ], + "properties": { + "heading": { + "description": "Used to set fields(asset_options/finding_options/group_options/tag_options/user_options)", + "type": "string" + }, + "fields": { + "description": "Fields which are available in exported file", + "type": "array", + "items": { + "type": "object", + "required": [ + "identifierField", + "fieldOrder", + "selected", + "sortable", + "sortOrder", + "sortType" + ], + "properties": { + "identifierField": { + "description": "Internal field which we use to identify the export field", + "type": "string" + }, + "sortable": { + "description": "Is Field Sortable", + "type": "boolean" + }, + "fieldOrder": { + "description": "Order of the export field", + "type": "integer" + }, + "selected": { + "description": "Is Field Selected", + "type": "boolean" + }, + "sortOrder": { + "description": "Sort order of the exportable fields", + "type": "integer" + }, + "sortType": { + "description": "Sort type of the exportable fields - asc/desc", + "type": "string" + } + } + } + } + } + } + } + }, + "example": { + "id": 0, + "clientId": 1, + "userId": 1, + "name": "Export-Template-Name", + "description": "Export-Template-Description", + "shared": false, + "isDefault": false, + "subject": "tag", + "exportableFields": [ + { + "heading": "asset_options", + "fields": [ + { + "identifierField": "name", + "displayText": "Name", + "sortable": false, + "fieldOrder": 1, + "selected": false, + "sortOrder": 0, + "sortType": "ASC" + } + ] + } + ] + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/host/export": { + "post": { + "summary": "Initiate export job", + "description": "

\n

\n

\nEndpoint for initiating an export job against the\ndata outlined in the given FilterRequest.\nThe Host Export Template API (/client/{clientId}/host/export/template) lists the fields that can be exported. The exportableFields section of the request body can be used to choose the fields that needs to be exported.\n

\n", + "tags": [ + "host" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filterRequest", + "fileType", + "noOfRows", + "fileName", + "exportableFields" + ], + "properties": { + "filterRequest": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + } + }, + "fileType": { + "description": "Type of file to be exported into", + "type": "string", + "enum": [ + "JSON", + "CSV" + ] + }, + "noOfRows": { + "description": "Number of rows to be exported by default", + "type": "integer" + }, + "fileName": { + "description": "Name of the exported file", + "type": "string" + }, + "exportableFields": { + "description": "Fields included for Export", + "type": "array", + "items": { + "type": "object", + "required": [ + "heading", + "fields" + ], + "properties": { + "heading": { + "description": "Used to set fields(asset_options/finding_options/group_options/tag_options/user_options)", + "type": "string" + }, + "fields": { + "description": "Fields which are available in exported file", + "type": "array", + "items": { + "type": "object", + "required": [ + "identifierField", + "fieldOrder", + "selected", + "sortable", + "sortOrder", + "sortType" + ], + "properties": { + "identifierField": { + "description": "Internal field which we use to identify the export field", + "type": "string" + }, + "sortable": { + "description": "Is Field Sortable", + "type": "boolean" + }, + "fieldOrder": { + "description": "Order of the export field", + "type": "integer" + }, + "selected": { + "description": "Is Field Selected", + "type": "boolean" + }, + "sortOrder": { + "description": "Sort order of the exportable fields", + "type": "integer" + }, + "sortType": { + "description": "Sort type of the exportable fields - asc/desc", + "type": "string" + } + } + } + } + } + } + } + }, + "example": { + "filterRequest": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + }, + "fileName": "TestAssetExport", + "fileType": "CSV", + "noOfRows": 5000, + "exportableFields": [ + { + "heading": "asset_options", + "fields": [ + { + "identifierField": "name", + "fieldOrder": 1, + "selected": false, + "sortable": false, + "sortOrder": 0, + "sortType": "ASC" + } + ] + } + ] + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/host/group/move": { + "post": { + "deprecated": true, + "summary": "Deprecated because of multi-group asset support. Please use the /client/{clientId}/{subject}/add-group and /client/{clientId}/{subject}/remove-group endpoints.", + "description": "

\nEndpoint for initiating a group move job against the\ndata outlined in the given FilterRequest\n

\n", + "tags": [ + "host" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filterRequest", + "targetGroupId" + ], + "properties": { + "filterRequest": { + "description": "Filter for job requests", + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + } + }, + "targetGroupId": { + "description": "The group to move the assets to", + "type": "integer" + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/host/network/move": { + "post": { + "summary": "Move to different network based on filters", + "description": "

\nEndpoint for initiating a network move job against the\ndata outlined in the given FilterRequest\n

\n", + "tags": [ + "host" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filterRequest", + "targetNetworkId", + "isForceMerge" + ], + "properties": { + "filterRequest": { + "description": "Filter for job requests", + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + } + }, + "targetNetworkId": { + "type": "integer" + }, + "isForceMerge": { + "type": "boolean" + } + }, + "example": { + "filterRequest": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "EXACT", + "value": "1" + } + ] + }, + "targetNetworkId": 2, + "isForceMerge": false + } + } + } + ], + "responses": { + "200": { + "description": "Job Created", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/host/update-remediation-by-assessment": { + "post": { + "summary": "Remediate findings by assessment", + "description": "

\n

\n

\nEndpoint for updating findings' remediation workflow for the hosts retrieved\n from the filerRequest by the most recent assessment\n

\n", + "tags": [ + "host" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filterRequest" + ], + "properties": { + "filterRequest": { + "description": "Filter for job requests", + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + } + } + }, + "example": { + "filterRequest": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/host/note": { + "post": { + "summary": "Add a note to hosts", + "description": "

\n

\n

\nEndpoint for initiating a note creation job against the\ndata outlined in the given FilterRequest\n

\n", + "tags": [ + "host" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filterRequest", + "note" + ], + "properties": { + "filterRequest": { + "description": "Filter for job requests", + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + } + }, + "note": { + "description": "The note you are adding to the entity", + "type": "string" + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/host/add-group": { + "post": { + "summary": "Add assets to group", + "tags": [ + "host" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filterRequest", + "targetGroupIds" + ], + "properties": { + "filterRequest": { + "description": "Filter for job requests", + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + } + }, + "targetGroupIds": { + "description": "List of groupIds where assets to be added or removed.", + "type": "array", + "items": { + "type": "integer" + } + } + } + } + } + ], + "responses": { + "200": { + "description": "Job Created", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/host/remove-group": { + "post": { + "summary": "Remove assets from group", + "tags": [ + "host" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filterRequest", + "targetGroupIds" + ], + "properties": { + "filterRequest": { + "description": "Filter for job requests", + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + } + }, + "targetGroupIds": { + "description": "List of groupIds where assets to be added or removed.", + "type": "array", + "items": { + "type": "integer" + } + } + } + } + } + ], + "responses": { + "200": { + "description": "Job Created", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/host/apiExport": { + "post": { + "summary": "Initiate paginated export", + "description": "

\n

\n

\nEndpoint to fetch the paginated export response against the\ndata outlined in the given FilterRequest.\nThe exportableFields section of the request body can be used to choose the fields that needs to be exported.\n

\n", + "tags": [ + "host" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "searchAfter", + "description": "Pagination parameter to retrieve result after the given value, get the value from the field 'searchAfter' in the response", + "type": "integer", + "in": "query", + "required": false + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filterRequest", + "exportableFields" + ], + "properties": { + "filterRequest": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + } + }, + "noOfRows": { + "description": "Number of rows to be exported by default. It is optional", + "type": "integer" + }, + "exportableFields": { + "description": "Fields included for api export", + "type": "array", + "items": { + "type": "object", + "required": [ + "heading", + "fields" + ], + "properties": { + "heading": { + "description": "Used to set fields(asset_options/finding_options)", + "type": "string" + }, + "fields": { + "description": "Fields which are available in response", + "type": "array", + "items": { + "type": "object", + "required": [ + "identifierField", + "selected" + ], + "properties": { + "identifierField": { + "description": "Internal field which we use to identify the export field", + "type": "string" + }, + "selected": { + "description": "Is Field Selected", + "type": "boolean" + } + } + } + } + } + } + } + }, + "example": { + "filterRequest": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + }, + "noOfRows": 250, + "exportableFields": [ + { + "heading": "asset_options", + "fields": [ + { + "identifierField": "name", + "selected": true + } + ] + }, + { + "heading": "finding_options", + "fields": [ + { + "identifierField": "host", + "selected": true + } + ] + } + ] + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "type": "object" + } + }, + "searchAfter": { + "type": "string", + "description": "Paginated value to retrieve the next result" + }, + "totalCount": { + "type": "string", + "description": "Total findings/assets count" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/hostFinding": { + "post": { + "summary": "Create a new host finding on client", + "tags": [ + "hostFinding" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "hostId", + "assessmentId", + "severity", + "sourceId", + "scannerUuid", + "title", + "type", + "description", + "solution", + "isSelectedAll", + "filterRequest" + ], + "properties": { + "hostId": { + "type": "array", + "items": { + "type": "integer" + } + }, + "assessmentId": { + "type": "integer" + }, + "severity": { + "type": "number" + }, + "sourceId": { + "type": "string" + }, + "scannerUuid": { + "type": "string" + }, + "title": { + "type": "string" + }, + "type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "output": { + "type": "string" + }, + "solution": { + "type": "string" + }, + "synopsis": { + "type": "string" + }, + "service": { + "type": "object", + "required": [ + "portNumber", + "name" + ], + "properties": { + "portNumber": { + "type": "integer" + }, + "name": { + "type": "string" + } + } + }, + "cveId": { + "type": "string", + "description": "Deprecated cve id or comma/whitespace delimited cve ids. Please use cveIds instead." + }, + "cveIds": { + "type": "array", + "items": { + "type": "string" + } + }, + "isSelectedAll": { + "type": "boolean" + }, + "filterRequest": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "sort" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + }, + "projection": { + "type": "string" + }, + "sort": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "direction" + ], + "properties": { + "field": { + "type": "string" + }, + "direction": { + "type": "string", + "enum": [ + "ASC", + "DESC" + ] + } + } + } + }, + "page": { + "type": "integer" + }, + "size": { + "type": "integer" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "projection": "basic", + "sort": [ + { + "field": "id", + "direction": "ASC" + } + ], + "page": 0, + "size": 20 + } + }, + "scannerFirstDiscoveredOn": { + "type": "string" + }, + "scannerLastDiscoveredOn": { + "type": "string" + } + }, + "example": { + "hostId": [ + 1, + 2, + 3 + ], + "assessmentId": 1, + "severity": 5, + "sourceId": "PUBLIC-KEY-PINNING-EXTENSIONS-FOR-HTTP-STRICT", + "scannerUuid": "RISKSENSE", + "title": "Multi host finding", + "type": "SERVICE", + "description": "Some description", + "output": "Some output", + "solution": "Some solution", + "synopsis": "This field is deprecated now", + "service": { + "portNumber": 8080, + "name": "http" + }, + "cveId": "CVE-1234-0001, CVE-1234-0002", + "cveIds": [ + "CVE-1234-0001", + "CVE-1234-0002" + ], + "isSelectedAll": false, + "filterRequest": { + "filters": [ + { + "field": "vulnId", + "exclusive": false, + "operator": "IN", + "value": "CVE-123" + } + ] + }, + "scannerFirstDiscoveredOn": "2023-01-30", + "scannerLastDiscoveredOn": "2023-02-27" + } + } + } + ], + "responses": { + "201": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "409": { + "description": "Conflict" + } + } + } + }, + "/client/{clientId}/hostFinding/{hostFindingId}": { + "put": { + "summary": "Update a manual host finding on client", + "tags": [ + "hostFinding" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "hostFindingId", + "description": "Id of host finding (This parameter can be obtained via the POST\nmethod on '/client/{clientId}/search/hostFinding/find')\n", + "in": "path", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "solution": { + "type": "string" + }, + "synopsis": { + "type": "string" + } + } + } + } + ], + "responses": { + "201": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/hostFinding/model": { + "get": { + "summary": "List projections and their models", + "description": "List projections and their models that can be requested from the search endpoint.\n", + "tags": [ + "hostFinding" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "object", + "properties": { + "projections": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "fields": { + "type": "array", + "items": { + "type": "object", + "properties": { + "field": { + "type": "string" + }, + "type": { + "type": "string" + }, + "nested": { + "type": "array", + "items": { + "type": "object", + "description": "Same as ProjectionField" + } + } + } + } + } + } + } + } + }, + "example": { + "projections": [ + { + "name": "basic", + "fields": [ + { + "field": "id", + "type": "integer" + }, + { + "field": "name", + "type": "string" + } + ] + } + ] + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/hostFinding/filter": { + "get": { + "summary": "List fields that can be filtered by in the search endpoint", + "tags": [ + "hostFinding" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "array", + "items": { + "required": [ + "name", + "uid", + "operators", + "type", + "description" + ], + "properties": { + "name": { + "type": "string" + }, + "uid": { + "type": "string", + "description": "uid used to indentify fields in suggest and search requests" + }, + "operators": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + } + }, + "datatype": { + "type": "string" + }, + "description": { + "type": "string" + } + } + }, + "example": [ + { + "name": "id", + "uid": "id", + "operator": [ + "EXACT", + "IN" + ], + "type": "integer", + "description": "The id" + } + ] + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/hostFinding/suggest": { + "post": { + "summary": "Suggest values for filter fields", + "tags": [ + "hostFinding" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "filter" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + }, + "description": "Filters to used to narrow down the the result set\n" + }, + "filter": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + }, + "description": "Filter for which to suggest values for. The filter value will be\ntreated as a wildcard.\n" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": true, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "filter": { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "" + } + } + } + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key", + "count" + ], + "properties": { + "key": { + "type": "string", + "description": "Value for the field the suggestion was requested for." + }, + "count": { + "type": "integer", + "format": "int64" + } + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/hostFinding/search": { + "post": { + "summary": "Search for hosts findings", + "description": "As of June 11, 2021, we will be deprecating parserUploadFileData attribute from the detail projection of this endpoint. If you are using this attribute you can contact support for more information at support@risksense.com.", + "tags": [ + "hostFinding" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "sort" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + }, + "projection": { + "type": "string" + }, + "sort": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "direction" + ], + "properties": { + "field": { + "type": "string" + }, + "direction": { + "type": "string", + "enum": [ + "ASC", + "DESC" + ] + } + } + } + }, + "page": { + "type": "integer" + }, + "size": { + "type": "integer" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "projection": "basic", + "sort": [ + { + "field": "id", + "direction": "ASC" + } + ], + "page": 0, + "size": 20 + } + } + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "object", + "required": [ + "_embedded", + "page" + ], + "properties": { + "_embedded": { + "type": "object", + "required": [ + "strings" + ], + "properties": { + "strings": { + "type": "array", + "items": { + "type": "object", + "description": "

The response structure is subject dependent. Subject structure\ncan be found via the subject endpoint.

\n" + } + } + } + }, + "page": { + "type": "object", + "required": [ + "size", + "totalElements", + "totalPages", + "number" + ], + "properties": { + "size": { + "type": "integer" + }, + "totalElements": { + "type": "integer" + }, + "totalPages": { + "type": "integer" + }, + "number": { + "type": "integer" + } + } + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "id", + "errorRefId", + "code", + "cause" + ], + "properties": { + "id": { + "type": "string", + "description": "Entity id which failed to be retrieved" + }, + "errorRefId": { + "type": "string", + "description": "A unique identifier for the error" + }, + "code": { + "type": "integer", + "description": "http status code of the error" + }, + "cause": { + "type": "string", + "description": "http status code message" + } + } + } + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/search/hostFinding/dynamic-columns": { + "get": { + "summary": "Get Dynamic Columns", + "tags": [ + "host" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "array", + "items": { + "properties": { + "esParent": { + "type": "string" + }, + "rsName": { + "type": "string" + }, + "esName": { + "type": "string" + }, + "esFieldType": { + "type": "string" + }, + "subject": { + "type": "string" + }, + "scannerUuid": { + "type": "array" + } + } + }, + "example": [ + { + "esParent": "additionalDetails" + }, + { + "rsName": "Tenable UUID" + }, + { + "esName": "tenable_uuid" + }, + { + "esFieldType": "STRING" + }, + { + "subject": "host" + }, + { + "scannerUuid": "Nessus" + } + ] + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/hostFinding/tag": { + "post": { + "summary": "Add or remove tag", + "tags": [ + "hostFinding" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filterRequest", + "tagId", + "isRemove" + ], + "properties": { + "filterRequest": { + "description": "Filter for job requests", + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + } + }, + "tagId": { + "description": "Tag being used in tagging/untagging", + "type": "integer" + }, + "isRemove": { + "description": "True if the tag is being removed, false otherwise.", + "type": "boolean" + }, + "publishTicketStats": { + "description": "To publish ticket description fields to the ticket which is associated with the tag.", + "type": "boolean" + } + }, + "example": { + "tagId": 1, + "isRemove": false, + "filterRequest": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "EXACT", + "value": 1 + } + ] + } + } + } + } + ], + "responses": { + "200": { + "description": "Job Created", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/hostFinding/assign": { + "post": { + "summary": "Assign host finding(s)", + "tags": [ + "hostFinding" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filters", + "userIds" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + }, + "userIds": { + "description": "Collection of user Ids to assign/unassign findings to/from.", + "type": "array", + "items": { + "type": "integer" + } + } + } + } + } + ], + "responses": { + "200": { + "description": "Job Created", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/hostFinding/unassign": { + "post": { + "summary": "Unassign host finding(s)", + "tags": [ + "hostFinding" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filters", + "userIds" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + }, + "userIds": { + "description": "Collection of user Ids to assign/unassign findings to/from.", + "type": "array", + "items": { + "type": "integer" + } + } + } + } + } + ], + "responses": { + "200": { + "description": "Job Created", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/hostFinding/self-assign": { + "post": { + "summary": "Self assign host finding(s)", + "tags": [ + "hostFinding" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + } + } + } + ], + "responses": { + "200": { + "description": "Job Created", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/hostFinding/self-unassign": { + "post": { + "summary": "Self unassign host finding(s)", + "tags": [ + "hostFinding" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + } + } + } + ], + "responses": { + "200": { + "description": "Job Created", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/hostFinding/export/template": { + "get": { + "summary": "List out all fields that are part of configurable export.", + "tags": [ + "hostFinding" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "object", + "required": [ + "id", + "clientId", + "userId", + "name", + "description", + "shared", + "isDefault", + "subject", + "exportableFields" + ], + "properties": { + "id": { + "description": "The id", + "type": "integer" + }, + "clientId": { + "description": "Client id", + "type": "integer" + }, + "userId": { + "description": "User id", + "type": "integer" + }, + "name": { + "description": "Template name", + "type": "string" + }, + "description": { + "description": "Template description", + "type": "string" + }, + "shared": { + "description": "Describes whether this template shared or not", + "type": "boolean" + }, + "isDefault": { + "description": "Describes whether this template is default or not", + "type": "boolean" + }, + "subject": { + "description": "For which asset to fetch fileds", + "type": "string" + }, + "exportableFields": { + "description": "List of fileds", + "type": "array", + "items": { + "type": "object", + "required": [ + "heading", + "fields" + ], + "properties": { + "heading": { + "description": "Used to set fields(asset_options/finding_options/group_options/tag_options/user_options)", + "type": "string" + }, + "fields": { + "description": "Fields which are available in exported file", + "type": "array", + "items": { + "type": "object", + "required": [ + "identifierField", + "fieldOrder", + "selected", + "sortable", + "sortOrder", + "sortType" + ], + "properties": { + "identifierField": { + "description": "Internal field which we use to identify the export field", + "type": "string" + }, + "sortable": { + "description": "Is Field Sortable", + "type": "boolean" + }, + "fieldOrder": { + "description": "Order of the export field", + "type": "integer" + }, + "selected": { + "description": "Is Field Selected", + "type": "boolean" + }, + "sortOrder": { + "description": "Sort order of the exportable fields", + "type": "integer" + }, + "sortType": { + "description": "Sort type of the exportable fields - asc/desc", + "type": "string" + } + } + } + } + } + } + } + }, + "example": { + "id": 0, + "clientId": 1, + "userId": 1, + "name": "Export-Template-Name", + "description": "Export-Template-Description", + "shared": false, + "isDefault": false, + "subject": "tag", + "exportableFields": [ + { + "heading": "asset_options", + "fields": [ + { + "identifierField": "name", + "displayText": "Name", + "sortable": false, + "fieldOrder": 1, + "selected": false, + "sortOrder": 0, + "sortType": "ASC" + } + ] + }, + { + "heading": "finding_options", + "fields": [ + { + "identifierField": "description", + "displayText": "Description", + "sortable": false, + "fieldOrder": 1, + "selected": false, + "sortOrder": 0, + "sortType": "ASC" + } + ] + } + ] + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/hostFinding/export": { + "post": { + "summary": "Initiate export job", + "description": "

\n

\n

\nEndpoint for initiating an export job against the\ndata outlined in the given FilterRequest.\nThe Host Finding Export Template API (/client/{clientId}/hostFinding/export/template) lists the fields that can be exported. The exportableFields section of the request body can be used to choose the fields that needs to be exported.\n

\n", + "tags": [ + "hostFinding" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filterRequest", + "fileType", + "noOfRows", + "fileName", + "exportableFields" + ], + "properties": { + "filterRequest": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + } + }, + "fileType": { + "description": "Type of file to be exported into", + "type": "string", + "enum": [ + "JSON", + "CSV" + ] + }, + "noOfRows": { + "description": "Number of rows to be exported by default", + "type": "integer" + }, + "fileName": { + "description": "Name of the exported file", + "type": "string" + }, + "exportableFields": { + "description": "Fields included for Export", + "type": "array", + "items": { + "type": "object", + "required": [ + "heading", + "fields" + ], + "properties": { + "heading": { + "description": "Used to set fields(asset_options/finding_options/group_options/tag_options/user_options)", + "type": "string" + }, + "fields": { + "description": "Fields which are available in exported file", + "type": "array", + "items": { + "type": "object", + "required": [ + "identifierField", + "fieldOrder", + "selected", + "sortable", + "sortOrder", + "sortType" + ], + "properties": { + "identifierField": { + "description": "Internal field which we use to identify the export field", + "type": "string" + }, + "sortable": { + "description": "Is Field Sortable", + "type": "boolean" + }, + "fieldOrder": { + "description": "Order of the export field", + "type": "integer" + }, + "selected": { + "description": "Is Field Selected", + "type": "boolean" + }, + "sortOrder": { + "description": "Sort order of the exportable fields", + "type": "integer" + }, + "sortType": { + "description": "Sort type of the exportable fields - asc/desc", + "type": "string" + } + } + } + } + } + } + } + }, + "example": { + "filterRequest": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + }, + "fileName": "TestFindingsExport", + "fileType": "CSV", + "noOfRows": 5000, + "exportableFields": [ + { + "heading": "asset_options", + "fields": [ + { + "identifierField": "name", + "fieldOrder": 1, + "selected": false, + "sortable": false, + "sortOrder": 0, + "sortType": "ASC" + } + ] + }, + { + "heading": "finding_options", + "fields": [ + { + "identifierField": "host", + "fieldOrder": 1, + "selected": false, + "sortable": false, + "sortOrder": 0, + "sortType": "ASC" + } + ] + } + ] + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/hostFinding/update-due-date": { + "post": { + "summary": "Bulk update due dates", + "description": "

\n

\n

\nEndpoint for initializing a due date update job against the\ndata outlined in the given FilterRequest\n

\n", + "tags": [ + "hostFinding" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filterRequest" + ], + "properties": { + "filterRequest": { + "description": "Filter for job requests", + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + } + }, + "dueDate": { + "type": "string", + "format": "date" + } + }, + "example": { + "filterRequest": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + }, + "dueDate": "2019-12-30" + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/hostFinding/delete": { + "post": { + "summary": "Delete entities based on filters", + "tags": [ + "hostFinding" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filterRequest" + ], + "properties": { + "filterRequest": { + "description": "Filter for job requests", + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + } + } + }, + "example": { + "filterRequest": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "EXACT", + "value": "1" + } + ] + } + } + } + } + ], + "responses": { + "200": { + "description": "Job Created", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/hostFinding/{hostFindingId}/assessment/delete": { + "post": { + "summary": "Delete manage observations", + "tags": [ + "hostFinding" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "hostFindingId", + "description": "Id of host finding (This parameter can be obtained via the POST\nmethod on '/client/{clientId}/search/hostFinding/find')\n", + "in": "path", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "assessmentIds" + ], + "properties": { + "assessmentIds": { + "type": "array", + "items": { + "type": "integer" + } + } + }, + "example": "assessmentIds:[1, 2]" + } + } + ], + "responses": { + "200": { + "description": "Job Created", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/hostFinding/note": { + "post": { + "summary": "Add a note to host findings", + "description": "

\n

\n

\nEndpoint for initiating a note creation job against the\ndata outlined in the given FilterRequest\n

\n", + "tags": [ + "hostFinding" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filterRequest", + "note" + ], + "properties": { + "filterRequest": { + "description": "Filter for job requests", + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + } + }, + "note": { + "description": "The note you are adding to the entity", + "type": "string" + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/hostFinding/apiExport": { + "post": { + "summary": "Initiate paginated export", + "description": "

\n

\n

\nEndpoint to fetch the paginated export response against the\ndata outlined in the given FilterRequest.\nThe exportableFields section of the request body can be used to choose the fields that needs to be exported.\n

\n", + "tags": [ + "hostFinding" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "searchAfter", + "description": "Pagination parameter to retrieve result after the given value, get the value from the field 'searchAfter' in the response", + "type": "integer", + "in": "query", + "required": false + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filterRequest", + "exportableFields" + ], + "properties": { + "filterRequest": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + } + }, + "noOfRows": { + "description": "Number of rows to be exported by default. It is optional", + "type": "integer" + }, + "exportableFields": { + "description": "Fields included for api export", + "type": "array", + "items": { + "type": "object", + "required": [ + "heading", + "fields" + ], + "properties": { + "heading": { + "description": "Used to set fields(asset_options/finding_options)", + "type": "string" + }, + "fields": { + "description": "Fields which are available in response", + "type": "array", + "items": { + "type": "object", + "required": [ + "identifierField", + "selected" + ], + "properties": { + "identifierField": { + "description": "Internal field which we use to identify the export field", + "type": "string" + }, + "selected": { + "description": "Is Field Selected", + "type": "boolean" + } + } + } + } + } + } + } + }, + "example": { + "filterRequest": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + }, + "noOfRows": 250, + "exportableFields": [ + { + "heading": "asset_options", + "fields": [ + { + "identifierField": "name", + "selected": true + } + ] + }, + { + "heading": "finding_options", + "fields": [ + { + "identifierField": "host", + "selected": true + } + ] + } + ] + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "type": "object" + } + }, + "searchAfter": { + "type": "string", + "description": "Paginated value to retrieve the next result" + }, + "totalCount": { + "type": "string", + "description": "Total findings/assets count" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/uniqueHostFinding/model": { + "get": { + "deprecated": true, + "summary": "List projections and their models", + "description": "List projections and their models that can be requested from the search endpoint.\n", + "tags": [ + "UniqueFindingEOL" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "object", + "properties": { + "projections": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "fields": { + "type": "array", + "items": { + "type": "object", + "properties": { + "field": { + "type": "string" + }, + "type": { + "type": "string" + }, + "nested": { + "type": "array", + "items": { + "type": "object", + "description": "Same as ProjectionField" + } + } + } + } + } + } + } + } + }, + "example": { + "projections": [ + { + "name": "basic", + "fields": [ + { + "field": "id", + "type": "integer" + }, + { + "field": "name", + "type": "string" + } + ] + } + ] + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/uniqueHostFinding/filter": { + "get": { + "deprecated": true, + "summary": "List fields that can be filtered by in the search endpoint", + "tags": [ + "UniqueFindingEOL" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "array", + "items": { + "required": [ + "name", + "uid", + "operators", + "type", + "description" + ], + "properties": { + "name": { + "type": "string" + }, + "uid": { + "type": "string", + "description": "uid used to indentify fields in suggest and search requests" + }, + "operators": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + } + }, + "datatype": { + "type": "string" + }, + "description": { + "type": "string" + } + } + }, + "example": [ + { + "name": "id", + "uid": "id", + "operator": [ + "EXACT", + "IN" + ], + "type": "integer", + "description": "The id" + } + ] + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/uniqueHostFinding/suggest": { + "post": { + "deprecated": true, + "summary": "Suggest values for filter fields", + "tags": [ + "UniqueFindingEOL" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "filter" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + }, + "description": "Filters to used to narrow down the the result set\n" + }, + "filter": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + }, + "description": "Filter for which to suggest values for. The filter value will be\ntreated as a wildcard.\n" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": true, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "filter": { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "" + } + } + } + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key", + "count" + ], + "properties": { + "key": { + "type": "string", + "description": "Value for the field the suggestion was requested for." + }, + "count": { + "type": "integer", + "format": "int64" + } + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/uniqueHostFinding/search": { + "post": { + "deprecated": true, + "summary": "Search for host unique findings", + "tags": [ + "UniqueFindingEOL" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "sort" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + }, + "projection": { + "type": "string" + }, + "sort": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "direction" + ], + "properties": { + "field": { + "type": "string" + }, + "direction": { + "type": "string", + "enum": [ + "ASC", + "DESC" + ] + } + } + } + }, + "page": { + "type": "integer" + }, + "size": { + "type": "integer" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "projection": "basic", + "sort": [ + { + "field": "id", + "direction": "ASC" + } + ], + "page": 0, + "size": 20 + } + } + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "object", + "required": [ + "_embedded", + "page" + ], + "properties": { + "_embedded": { + "type": "object", + "required": [ + "strings" + ], + "properties": { + "strings": { + "type": "array", + "items": { + "type": "object", + "description": "

The response structure is subject dependent. Subject structure\ncan be found via the subject endpoint.

\n" + } + } + } + }, + "page": { + "type": "object", + "required": [ + "size", + "totalElements", + "totalPages", + "number" + ], + "properties": { + "size": { + "type": "integer" + }, + "totalElements": { + "type": "integer" + }, + "totalPages": { + "type": "integer" + }, + "number": { + "type": "integer" + } + } + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "id", + "errorRefId", + "code", + "cause" + ], + "properties": { + "id": { + "type": "string", + "description": "Entity id which failed to be retrieved" + }, + "errorRefId": { + "type": "string", + "description": "A unique identifier for the error" + }, + "code": { + "type": "integer", + "description": "http status code of the error" + }, + "cause": { + "type": "string", + "description": "http status code message" + } + } + } + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/uniqueHostFinding/export": { + "post": { + "deprecated": true, + "summary": "Initiate export job", + "description": "

\n

\n

\nEndpoint for initiating an export job against the\ndata outlined in the given FilterRequest\n

\n", + "tags": [ + "UniqueFindingEOL" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filterRequest", + "fileType", + "comment", + "fileName" + ], + "properties": { + "filterRequest": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + } + }, + "fileType": { + "description": "Type of file to be exported into", + "type": "string", + "enum": [ + "XML", + "XLSX", + "CSV" + ] + }, + "comment": { + "description": "Addition description for the exported file", + "type": "string" + }, + "fileName": { + "description": "Name of the exported file", + "type": "string" + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/application": { + "post": { + "summary": "Create new web application on client", + "tags": [ + "application" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "name", + "url", + "groupId", + "groupIds", + "networkId" + ], + "properties": { + "name": { + "type": "string" + }, + "url": { + "type": "string" + }, + "groupId": { + "description": "Either Group Id or Group Ids is mandatory", + "type": "integer" + }, + "groupIds": { + "description": "Either Group Id or Group Ids is mandatory", + "type": "array", + "items": { + "type": "integer" + } + }, + "hostId": { + "type": "integer" + }, + "networkId": { + "type": "integer" + }, + "ports": { + "type": "array", + "items": { + "type": "integer" + } + }, + "manufacturedBy": { + "type": "string" + }, + "model": { + "type": "string" + }, + "macAddress": { + "type": "string" + }, + "location": { + "type": "string" + }, + "managedBy": { + "type": "string" + }, + "ownedBy": { + "type": "string" + }, + "supportedBy": { + "type": "string" + }, + "supportGroup": { + "type": "string" + }, + "sysId": { + "type": "string" + }, + "operatingSystem": { + "type": "string" + }, + "lastScanDate": { + "type": "string", + "format": "date" + }, + "ferpaComplianceAsset": { + "type": "boolean" + }, + "hipaaComplianceAsset": { + "type": "boolean" + }, + "pciComplianceAsset": { + "type": "boolean" + }, + "criticality": { + "type": "integer" + }, + "externality": { + "type": "boolean" + } + }, + "example": { + "name": "Example Application", + "url": "www.example.com", + "groupId": 3, + "groupIds": [ + 101, + 102, + 103 + ], + "networkId": 1, + "hostId": 1, + "ports": [ + 80, + 443 + ], + "manufacturedBy": "Dell", + "model": "XPS-15", + "macAddress": "AA-00-04-00-XX-YY", + "location": "Albuquerque", + "managedBy": "manager", + "ownedBy": "owner", + "supportedBy": "supporter", + "supportGroup": "supportGrp", + "sysId": "123e4567-e89b-12d3-a456-556642440000", + "operatingSystem": "Windows 10", + "lastScanDate": "2018-07-23", + "ferpaComplianceAsset": "true", + "hipaaComplianceAsset": "true", + "pciComplianceAsset": "false", + "criticality": 1, + "externality": "true" + } + } + } + ], + "responses": { + "201": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + } + } + } + }, + "/client/{clientId}/application/model": { + "get": { + "summary": "List projections and their models", + "description": "List projections and their models that can be requested from the search endpoint.\n", + "tags": [ + "application" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "object", + "properties": { + "projections": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "fields": { + "type": "array", + "items": { + "type": "object", + "properties": { + "field": { + "type": "string" + }, + "type": { + "type": "string" + }, + "nested": { + "type": "array", + "items": { + "type": "object", + "description": "Same as ProjectionField" + } + } + } + } + } + } + } + } + }, + "example": { + "projections": [ + { + "name": "basic", + "fields": [ + { + "field": "id", + "type": "integer" + }, + { + "field": "name", + "type": "string" + } + ] + } + ] + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/application/filter": { + "get": { + "summary": "List fields that can be filtered by in the search endpoint", + "tags": [ + "application" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "array", + "items": { + "required": [ + "name", + "uid", + "operators", + "type", + "description" + ], + "properties": { + "name": { + "type": "string" + }, + "uid": { + "type": "string", + "description": "uid used to indentify fields in suggest and search requests" + }, + "operators": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + } + }, + "datatype": { + "type": "string" + }, + "description": { + "type": "string" + } + } + }, + "example": [ + { + "name": "id", + "uid": "id", + "operator": [ + "EXACT", + "IN" + ], + "type": "integer", + "description": "The id" + } + ] + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/application/suggest": { + "post": { + "summary": "Suggest values for filter fields", + "tags": [ + "application" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "filter" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + }, + "description": "Filters to used to narrow down the the result set\n" + }, + "filter": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + }, + "description": "Filter for which to suggest values for. The filter value will be\ntreated as a wildcard.\n" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": true, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "filter": { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "" + } + } + } + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key", + "count" + ], + "properties": { + "key": { + "type": "string", + "description": "Value for the field the suggestion was requested for." + }, + "count": { + "type": "integer", + "format": "int64" + } + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/application/search": { + "post": { + "summary": "Search for applications", + "tags": [ + "application" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "sort" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + }, + "projection": { + "type": "string" + }, + "sort": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "direction" + ], + "properties": { + "field": { + "type": "string" + }, + "direction": { + "type": "string", + "enum": [ + "ASC", + "DESC" + ] + } + } + } + }, + "page": { + "type": "integer" + }, + "size": { + "type": "integer" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "projection": "basic", + "sort": [ + { + "field": "id", + "direction": "ASC" + } + ], + "page": 0, + "size": 20 + } + } + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "object", + "required": [ + "_embedded", + "page" + ], + "properties": { + "_embedded": { + "type": "object", + "required": [ + "strings" + ], + "properties": { + "strings": { + "type": "array", + "items": { + "type": "object", + "description": "

The response structure is subject dependent. Subject structure\ncan be found via the subject endpoint.

\n" + } + } + } + }, + "page": { + "type": "object", + "required": [ + "size", + "totalElements", + "totalPages", + "number" + ], + "properties": { + "size": { + "type": "integer" + }, + "totalElements": { + "type": "integer" + }, + "totalPages": { + "type": "integer" + }, + "number": { + "type": "integer" + } + } + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "id", + "errorRefId", + "code", + "cause" + ], + "properties": { + "id": { + "type": "string", + "description": "Entity id which failed to be retrieved" + }, + "errorRefId": { + "type": "string", + "description": "A unique identifier for the error" + }, + "code": { + "type": "integer", + "description": "http status code of the error" + }, + "cause": { + "type": "string", + "description": "http status code message" + } + } + } + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/search/application/dynamic-columns": { + "get": { + "summary": "Get Dynamic Columns", + "tags": [ + "host" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "array", + "items": { + "properties": { + "esParent": { + "type": "string" + }, + "rsName": { + "type": "string" + }, + "esName": { + "type": "string" + }, + "esFieldType": { + "type": "string" + }, + "subject": { + "type": "string" + }, + "scannerUuid": { + "type": "array" + } + } + }, + "example": [ + { + "esParent": "additionalDetails" + }, + { + "rsName": "Tenable UUID" + }, + { + "esName": "tenable_uuid" + }, + { + "esFieldType": "STRING" + }, + { + "subject": "host" + }, + { + "scannerUuid": "Nessus" + } + ] + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/application/tag": { + "post": { + "summary": "Add or remove tag", + "tags": [ + "application" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filterRequest", + "tagId", + "isRemove" + ], + "properties": { + "filterRequest": { + "description": "Filter for job requests", + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + } + }, + "tagId": { + "description": "Tag being used in tagging/untagging", + "type": "integer" + }, + "isRemove": { + "description": "True if the tag is being removed, false otherwise.", + "type": "boolean" + }, + "publishTicketStats": { + "description": "To publish ticket description fields to the ticket which is associated with the tag.", + "type": "boolean" + } + }, + "example": { + "tagId": 1, + "isRemove": false, + "filterRequest": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "EXACT", + "value": 1 + } + ] + } + } + } + } + ], + "responses": { + "200": { + "description": "Job Created", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/application/delete": { + "post": { + "summary": "Delete entities based on filters", + "tags": [ + "application" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filterRequest" + ], + "properties": { + "filterRequest": { + "description": "Filter for job requests", + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + } + } + }, + "example": { + "filterRequest": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "EXACT", + "value": "1" + } + ] + } + } + } + } + ], + "responses": { + "200": { + "description": "Job Created", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/application/update": { + "post": { + "summary": "Update application", + "tags": [ + "application" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filterRequest" + ], + "properties": { + "filterRequest": { + "description": "Filter for job requests", + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + } + }, + "name": { + "type": "string" + }, + "url": { + "type": "string" + }, + "ports": { + "type": "array", + "items": { + "type": "integer" + } + }, + "hostId": { + "type": "integer" + }, + "criticality": { + "type": "integer" + }, + "isExternal": { + "type": "boolean" + }, + "metricsOverrideType": { + "type": "string", + "enum": [ + "OVERRIDE", + "RESET" + ] + } + }, + "example": { + "filterRequest": { + "filters": [ + { + "field": "name", + "exclusive": false, + "operator": "EXACT", + "value": "Old App Name" + } + ] + }, + "name": "New App Name", + "url": "10.1.2.3/customwebapp", + "hostId": 1, + "ports": [ + 8080, + 8081 + ] + } + } + } + ], + "responses": { + "200": { + "description": "Job Created", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/application/export/template": { + "get": { + "summary": "List out all fields that are part of configurable export.", + "tags": [ + "application" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "object", + "required": [ + "id", + "clientId", + "userId", + "name", + "description", + "shared", + "isDefault", + "subject", + "exportableFields" + ], + "properties": { + "id": { + "description": "The id", + "type": "integer" + }, + "clientId": { + "description": "Client id", + "type": "integer" + }, + "userId": { + "description": "User id", + "type": "integer" + }, + "name": { + "description": "Template name", + "type": "string" + }, + "description": { + "description": "Template description", + "type": "string" + }, + "shared": { + "description": "Describes whether this template shared or not", + "type": "boolean" + }, + "isDefault": { + "description": "Describes whether this template is default or not", + "type": "boolean" + }, + "subject": { + "description": "For which asset to fetch fileds", + "type": "string" + }, + "exportableFields": { + "description": "List of fileds", + "type": "array", + "items": { + "type": "object", + "required": [ + "heading", + "fields" + ], + "properties": { + "heading": { + "description": "Used to set fields(asset_options/finding_options/group_options/tag_options/user_options)", + "type": "string" + }, + "fields": { + "description": "Fields which are available in exported file", + "type": "array", + "items": { + "type": "object", + "required": [ + "identifierField", + "fieldOrder", + "selected", + "sortable", + "sortOrder", + "sortType" + ], + "properties": { + "identifierField": { + "description": "Internal field which we use to identify the export field", + "type": "string" + }, + "sortable": { + "description": "Is Field Sortable", + "type": "boolean" + }, + "fieldOrder": { + "description": "Order of the export field", + "type": "integer" + }, + "selected": { + "description": "Is Field Selected", + "type": "boolean" + }, + "sortOrder": { + "description": "Sort order of the exportable fields", + "type": "integer" + }, + "sortType": { + "description": "Sort type of the exportable fields - asc/desc", + "type": "string" + } + } + } + } + } + } + } + }, + "example": { + "id": 0, + "clientId": 1, + "userId": 1, + "name": "Export-Template-Name", + "description": "Export-Template-Description", + "shared": false, + "isDefault": false, + "subject": "tag", + "exportableFields": [ + { + "heading": "asset_options", + "fields": [ + { + "identifierField": "name", + "displayText": "Name", + "sortable": false, + "fieldOrder": 1, + "selected": false, + "sortOrder": 0, + "sortType": "ASC" + } + ] + } + ] + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/application/export": { + "post": { + "summary": "Initiate export job", + "description": "

\nEndpoint for initiating an export job against the\ndata outlined in the given FilterRequest.\nThe Application Export Template API (/client/{clientId}/application/export/template) lists the fields that can be exported. The exportableFields section of the request body can be used to choose the fields that needs to be exported. \n

\n", + "tags": [ + "application" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filterRequest", + "fileType", + "noOfRows", + "fileName", + "exportableFields" + ], + "properties": { + "filterRequest": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + } + }, + "fileType": { + "description": "Type of file to be exported into", + "type": "string", + "enum": [ + "JSON", + "CSV" + ] + }, + "noOfRows": { + "description": "Number of rows to be exported by default", + "type": "integer" + }, + "fileName": { + "description": "Name of the exported file", + "type": "string" + }, + "exportableFields": { + "description": "Fields included for Export", + "type": "array", + "items": { + "type": "object", + "required": [ + "heading", + "fields" + ], + "properties": { + "heading": { + "description": "Used to set fields(asset_options/finding_options/group_options/tag_options/user_options)", + "type": "string" + }, + "fields": { + "description": "Fields which are available in exported file", + "type": "array", + "items": { + "type": "object", + "required": [ + "identifierField", + "fieldOrder", + "selected", + "sortable", + "sortOrder", + "sortType" + ], + "properties": { + "identifierField": { + "description": "Internal field which we use to identify the export field", + "type": "string" + }, + "sortable": { + "description": "Is Field Sortable", + "type": "boolean" + }, + "fieldOrder": { + "description": "Order of the export field", + "type": "integer" + }, + "selected": { + "description": "Is Field Selected", + "type": "boolean" + }, + "sortOrder": { + "description": "Sort order of the exportable fields", + "type": "integer" + }, + "sortType": { + "description": "Sort type of the exportable fields - asc/desc", + "type": "string" + } + } + } + } + } + } + } + }, + "example": { + "filterRequest": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + }, + "fileName": "TestAssetExport", + "fileType": "CSV", + "noOfRows": 5000, + "exportableFields": [ + { + "heading": "asset_options", + "fields": [ + { + "identifierField": "name", + "fieldOrder": 1, + "selected": false, + "sortable": false, + "sortOrder": 0, + "sortType": "ASC" + } + ] + } + ] + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/application/group/move": { + "post": { + "deprecated": true, + "summary": "Deprecated because of multi-group asset support. Please use the /client/{clientId}/{subject}/add-group and /client/{clientId}/{subject}/remove-group endpoints.", + "description": "

\nEndpoint for initiating a group move job against the\ndata outlined in the given FilterRequest\n

\n", + "tags": [ + "application" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filterRequest", + "targetGroupId" + ], + "properties": { + "filterRequest": { + "description": "Filter for job requests", + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + } + }, + "targetGroupId": { + "description": "The group to move the assets to", + "type": "integer" + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/application/network/move": { + "post": { + "summary": "Move to different network based on filters", + "description": "

\nEndpoint for initiating a network move job against the\ndata outlined in the given FilterRequest\n

\n", + "tags": [ + "application" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filterRequest", + "targetNetworkId", + "isForceMerge" + ], + "properties": { + "filterRequest": { + "description": "Filter for job requests", + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + } + }, + "targetNetworkId": { + "type": "integer" + }, + "isForceMerge": { + "type": "boolean" + } + }, + "example": { + "filterRequest": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "EXACT", + "value": "1" + } + ] + }, + "targetNetworkId": 2, + "isForceMerge": false + } + } + } + ], + "responses": { + "200": { + "description": "Job Created", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/application/update-remediation-by-assessment": { + "post": { + "summary": "Remediate findings by assessment", + "description": "

\nEndpoint for updating findings' remediation workflow for the Applications retrieved\n from the filterRequest by the most recent assessment\n

\n", + "tags": [ + "application" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filterRequest" + ], + "properties": { + "filterRequest": { + "description": "Filter for job requests", + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + } + } + }, + "example": { + "filterRequest": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/application/note": { + "post": { + "summary": "Add a note to applications", + "description": "

\nEndpoint for initiating a note creation job against the\ndata outlined in the given FilterRequest\n

\n", + "tags": [ + "application" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filterRequest", + "note" + ], + "properties": { + "filterRequest": { + "description": "Filter for job requests", + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + } + }, + "note": { + "description": "The note you are adding to the entity", + "type": "string" + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/application/add-group": { + "post": { + "summary": "Add assets to group", + "tags": [ + "application" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filterRequest", + "targetGroupIds" + ], + "properties": { + "filterRequest": { + "description": "Filter for job requests", + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + } + }, + "targetGroupIds": { + "description": "List of groupIds where assets to be added or removed.", + "type": "array", + "items": { + "type": "integer" + } + } + } + } + } + ], + "responses": { + "200": { + "description": "Job Created", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/application/remove-group": { + "post": { + "summary": "Remove assets from group", + "tags": [ + "application" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filterRequest", + "targetGroupIds" + ], + "properties": { + "filterRequest": { + "description": "Filter for job requests", + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + } + }, + "targetGroupIds": { + "description": "List of groupIds where assets to be added or removed.", + "type": "array", + "items": { + "type": "integer" + } + } + } + } + } + ], + "responses": { + "200": { + "description": "Job Created", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/application/apiExport": { + "post": { + "summary": "Initiate paginated export", + "description": "

\n

\n

\nEndpoint to fetch the paginated export response against the\ndata outlined in the given FilterRequest.\nThe exportableFields section of the request body can be used to choose the fields that needs to be exported.\n

\n", + "tags": [ + "application" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "searchAfter", + "description": "Pagination parameter to retrieve result after the given value, get the value from the field 'searchAfter' in the response", + "type": "integer", + "in": "query", + "required": false + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filterRequest", + "exportableFields" + ], + "properties": { + "filterRequest": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + } + }, + "noOfRows": { + "description": "Number of rows to be exported by default. It is optional", + "type": "integer" + }, + "exportableFields": { + "description": "Fields included for api export", + "type": "array", + "items": { + "type": "object", + "required": [ + "heading", + "fields" + ], + "properties": { + "heading": { + "description": "Used to set fields(asset_options/finding_options)", + "type": "string" + }, + "fields": { + "description": "Fields which are available in response", + "type": "array", + "items": { + "type": "object", + "required": [ + "identifierField", + "selected" + ], + "properties": { + "identifierField": { + "description": "Internal field which we use to identify the export field", + "type": "string" + }, + "selected": { + "description": "Is Field Selected", + "type": "boolean" + } + } + } + } + } + } + } + }, + "example": { + "filterRequest": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + }, + "noOfRows": 250, + "exportableFields": [ + { + "heading": "asset_options", + "fields": [ + { + "identifierField": "name", + "selected": true + } + ] + }, + { + "heading": "finding_options", + "fields": [ + { + "identifierField": "host", + "selected": true + } + ] + } + ] + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "type": "object" + } + }, + "searchAfter": { + "type": "string", + "description": "Paginated value to retrieve the next result" + }, + "totalCount": { + "type": "string", + "description": "Total findings/assets count" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/applicationFinding": { + "post": { + "summary": "Create new application finding on client", + "tags": [ + "applicationFinding" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "applicationIds", + "assessmentId", + "oneOf", + "severity", + "sourceId", + "scannerUuid", + "title", + "description", + "solution", + "isSelectedAll", + "filterRequest" + ], + "properties": { + "applicationIds": { + "type": "array", + "items": { + "type": "integer" + } + }, + "assessmentId": { + "type": "integer" + }, + "oneOf": { + "type": "object", + "properties": { + "applicationUrlId": { + "type": "integer" + }, + "applicationUrl": { + "type": "string" + } + } + }, + "severity": { + "type": "integer" + }, + "sourceId": { + "type": "string" + }, + "scannerUuid": { + "type": "string" + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "solution": { + "type": "string" + }, + "synopsis": { + "type": "string" + }, + "cweId": { + "type": "integer" + }, + "cweIds": { + "type": "array", + "items": { + "type": "integer" + } + }, + "isSelectedAll": { + "type": "boolean" + }, + "filterRequest": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "sort" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + }, + "projection": { + "type": "string" + }, + "sort": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "direction" + ], + "properties": { + "field": { + "type": "string" + }, + "direction": { + "type": "string", + "enum": [ + "ASC", + "DESC" + ] + } + } + } + }, + "page": { + "type": "integer" + }, + "size": { + "type": "integer" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "projection": "basic", + "sort": [ + { + "field": "id", + "direction": "ASC" + } + ], + "page": 0, + "size": 20 + } + }, + "requestMethod": { + "type": "string" + }, + "requestUrl": { + "type": "string" + }, + "isRequestResponseBase64Encoded": { + "type": "boolean" + }, + "request": { + "type": "string" + }, + "response": { + "type": "string" + }, + "output": { + "type": "string" + }, + "parameter": { + "type": "string" + }, + "payload": { + "type": "string" + }, + "scannerFirstDiscoveredOn": { + "type": "string" + }, + "scannerLastDiscoveredOn": { + "type": "string" + } + }, + "example": { + "applicationIds": [ + 1 + ], + "assessmentId": 1, + "applicationUrl": "www.example.com", + "severity": 1, + "scannerUuid": "RISKSENSE", + "sourceId": "1234567", + "title": "Example Application Finding Title", + "description": "Example description", + "solution": "Some solution", + "output": "Some output", + "synopsis": "Some synopsis", + "notes": "Some notes", + "cweId": 1, + "cweIds": [ + 2, + 3 + ], + "requestMethod": "POST", + "requestUrl": "http://someurl.com", + "isRequestResponseBase64Encoded": false, + "request": "Some request", + "response": "Some response", + "parameter": "Some parameter", + "payload": "Some payload", + "isSelectedAll": false, + "filterRequest": { + "filters": [ + { + "field": "vulnId", + "exclusive": false, + "operator": "IN", + "value": "CVE-123" + } + ] + }, + "scannerFirstDiscoveredOn": "2023-01-30", + "scannerLastDiscoveredOn": "2023-02-27" + } + } + } + ], + "responses": { + "201": { + "description": "Job Created", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + } + } + } + }, + "/client/{clientId}/applicationFinding/{applicationFindingId}": { + "put": { + "summary": "Update a manual application finding on client", + "tags": [ + "applicationFinding" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "applicationFindingId", + "description": "Id of the application finding (This parameter can be obtained via the POST\nmethod on '/client/{clientId}/search/applicationFinding/find')\n", + "in": "path", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "url": { + "type": "string" + }, + "description": { + "type": "string" + }, + "solution": { + "type": "string" + }, + "synopsis": { + "type": "string" + }, + "notes": { + "type": "string" + }, + "request": { + "type": "string" + }, + "response": { + "type": "string" + }, + "parameter": { + "type": "string" + }, + "payload": { + "type": "string" + }, + "vulnRequestId": { + "type": "integer" + } + }, + "example": { + "applicationId": 1, + "assessmentId": 1, + "applicationUrl": "www.example.com", + "severity": 1, + "sourceId": 145, + "title": "Example Application Finding Title", + "description": "Example description", + "solution": "Some solution", + "synopsis": "Some synopsis", + "notes": "Some notes", + "cweId": 1, + "request": "Some request", + "response": "Some response", + "parameter": "Some parameter", + "payload": "Some payload", + "vulnRequestId": 4 + } + } + } + ], + "responses": { + "201": { + "description": "Job Created", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/applicationFinding/model": { + "get": { + "summary": "List projections and their models", + "description": "List projections and their models that can be requested from the search endpoint.\n", + "tags": [ + "applicationFinding" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "object", + "properties": { + "projections": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "fields": { + "type": "array", + "items": { + "type": "object", + "properties": { + "field": { + "type": "string" + }, + "type": { + "type": "string" + }, + "nested": { + "type": "array", + "items": { + "type": "object", + "description": "Same as ProjectionField" + } + } + } + } + } + } + } + } + }, + "example": { + "projections": [ + { + "name": "basic", + "fields": [ + { + "field": "id", + "type": "integer" + }, + { + "field": "name", + "type": "string" + } + ] + } + ] + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/applicationFinding/filter": { + "get": { + "summary": "List fields that can be filtered by in the search endpoint", + "tags": [ + "applicationFinding" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "array", + "items": { + "required": [ + "name", + "uid", + "operators", + "type", + "description" + ], + "properties": { + "name": { + "type": "string" + }, + "uid": { + "type": "string", + "description": "uid used to indentify fields in suggest and search requests" + }, + "operators": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + } + }, + "datatype": { + "type": "string" + }, + "description": { + "type": "string" + } + } + }, + "example": [ + { + "name": "id", + "uid": "id", + "operator": [ + "EXACT", + "IN" + ], + "type": "integer", + "description": "The id" + } + ] + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/applicationFinding/suggest": { + "post": { + "summary": "Suggest values for filter fields", + "tags": [ + "applicationFinding" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "filter" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + }, + "description": "Filters to used to narrow down the the result set\n" + }, + "filter": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + }, + "description": "Filter for which to suggest values for. The filter value will be\ntreated as a wildcard.\n" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": true, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "filter": { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "" + } + } + } + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key", + "count" + ], + "properties": { + "key": { + "type": "string", + "description": "Value for the field the suggestion was requested for." + }, + "count": { + "type": "integer", + "format": "int64" + } + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/applicationFinding/search": { + "post": { + "summary": "Search for application findings", + "tags": [ + "applicationFinding" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "sort" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + }, + "projection": { + "type": "string" + }, + "sort": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "direction" + ], + "properties": { + "field": { + "type": "string" + }, + "direction": { + "type": "string", + "enum": [ + "ASC", + "DESC" + ] + } + } + } + }, + "page": { + "type": "integer" + }, + "size": { + "type": "integer" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "projection": "basic", + "sort": [ + { + "field": "id", + "direction": "ASC" + } + ], + "page": 0, + "size": 20 + } + } + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "object", + "required": [ + "_embedded", + "page" + ], + "properties": { + "_embedded": { + "type": "object", + "required": [ + "strings" + ], + "properties": { + "strings": { + "type": "array", + "items": { + "type": "object", + "description": "

The response structure is subject dependent. Subject structure\ncan be found via the subject endpoint.

\n" + } + } + } + }, + "page": { + "type": "object", + "required": [ + "size", + "totalElements", + "totalPages", + "number" + ], + "properties": { + "size": { + "type": "integer" + }, + "totalElements": { + "type": "integer" + }, + "totalPages": { + "type": "integer" + }, + "number": { + "type": "integer" + } + } + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "id", + "errorRefId", + "code", + "cause" + ], + "properties": { + "id": { + "type": "string", + "description": "Entity id which failed to be retrieved" + }, + "errorRefId": { + "type": "string", + "description": "A unique identifier for the error" + }, + "code": { + "type": "integer", + "description": "http status code of the error" + }, + "cause": { + "type": "string", + "description": "http status code message" + } + } + } + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/search/applicationFinding/dynamic-columns": { + "get": { + "summary": "Get Dynamic Columns", + "tags": [ + "host" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "array", + "items": { + "properties": { + "esParent": { + "type": "string" + }, + "rsName": { + "type": "string" + }, + "esName": { + "type": "string" + }, + "esFieldType": { + "type": "string" + }, + "subject": { + "type": "string" + }, + "scannerUuid": { + "type": "array" + } + } + }, + "example": [ + { + "esParent": "additionalDetails" + }, + { + "rsName": "Tenable UUID" + }, + { + "esName": "tenable_uuid" + }, + { + "esFieldType": "STRING" + }, + { + "subject": "host" + }, + { + "scannerUuid": "Nessus" + } + ] + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/applicationFinding/tag": { + "post": { + "summary": "Add or remove tag", + "tags": [ + "applicationFinding" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filterRequest", + "tagId", + "isRemove" + ], + "properties": { + "filterRequest": { + "description": "Filter for job requests", + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + } + }, + "tagId": { + "description": "Tag being used in tagging/untagging", + "type": "integer" + }, + "isRemove": { + "description": "True if the tag is being removed, false otherwise.", + "type": "boolean" + }, + "publishTicketStats": { + "description": "To publish ticket description fields to the ticket which is associated with the tag.", + "type": "boolean" + } + }, + "example": { + "tagId": 1, + "isRemove": false, + "filterRequest": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "EXACT", + "value": 1 + } + ] + } + } + } + } + ], + "responses": { + "200": { + "description": "Job Created", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/applicationFinding/assign": { + "post": { + "summary": "Assign application finding(s)", + "tags": [ + "applicationFinding" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filters", + "userIds" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + }, + "userIds": { + "description": "Collection of user Ids to assign/unassign findings to/from.", + "type": "array", + "items": { + "type": "integer" + } + } + } + } + } + ], + "responses": { + "200": { + "description": "Job Created", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/applicationFinding/unassign": { + "post": { + "summary": "Unassign application finding(s)", + "tags": [ + "applicationFinding" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filters", + "userIds" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + }, + "userIds": { + "description": "Collection of user Ids to assign/unassign findings to/from.", + "type": "array", + "items": { + "type": "integer" + } + } + } + } + } + ], + "responses": { + "200": { + "description": "Job Created", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/applicationFinding/self-assign": { + "post": { + "summary": "Self assign application finding(s)", + "tags": [ + "applicationFinding" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + } + } + } + ], + "responses": { + "200": { + "description": "Job Created", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/applicationFinding/self-unassign": { + "post": { + "summary": "Self unassign application finding(s)", + "tags": [ + "applicationFinding" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + } + } + } + ], + "responses": { + "200": { + "description": "Job Created", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/applicationFinding/export/template": { + "get": { + "summary": "List out all fields that are part of configurable export.", + "tags": [ + "applicationFinding" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "object", + "required": [ + "id", + "clientId", + "userId", + "name", + "description", + "shared", + "isDefault", + "subject", + "exportableFields" + ], + "properties": { + "id": { + "description": "The id", + "type": "integer" + }, + "clientId": { + "description": "Client id", + "type": "integer" + }, + "userId": { + "description": "User id", + "type": "integer" + }, + "name": { + "description": "Template name", + "type": "string" + }, + "description": { + "description": "Template description", + "type": "string" + }, + "shared": { + "description": "Describes whether this template shared or not", + "type": "boolean" + }, + "isDefault": { + "description": "Describes whether this template is default or not", + "type": "boolean" + }, + "subject": { + "description": "For which asset to fetch fileds", + "type": "string" + }, + "exportableFields": { + "description": "List of fileds", + "type": "array", + "items": { + "type": "object", + "required": [ + "heading", + "fields" + ], + "properties": { + "heading": { + "description": "Used to set fields(asset_options/finding_options/group_options/tag_options/user_options)", + "type": "string" + }, + "fields": { + "description": "Fields which are available in exported file", + "type": "array", + "items": { + "type": "object", + "required": [ + "identifierField", + "fieldOrder", + "selected", + "sortable", + "sortOrder", + "sortType" + ], + "properties": { + "identifierField": { + "description": "Internal field which we use to identify the export field", + "type": "string" + }, + "sortable": { + "description": "Is Field Sortable", + "type": "boolean" + }, + "fieldOrder": { + "description": "Order of the export field", + "type": "integer" + }, + "selected": { + "description": "Is Field Selected", + "type": "boolean" + }, + "sortOrder": { + "description": "Sort order of the exportable fields", + "type": "integer" + }, + "sortType": { + "description": "Sort type of the exportable fields - asc/desc", + "type": "string" + } + } + } + } + } + } + } + }, + "example": { + "id": 0, + "clientId": 1, + "userId": 1, + "name": "Export-Template-Name", + "description": "Export-Template-Description", + "shared": false, + "isDefault": false, + "subject": "tag", + "exportableFields": [ + { + "heading": "asset_options", + "fields": [ + { + "identifierField": "name", + "displayText": "Name", + "sortable": false, + "fieldOrder": 1, + "selected": false, + "sortOrder": 0, + "sortType": "ASC" + } + ] + }, + { + "heading": "finding_options", + "fields": [ + { + "identifierField": "description", + "displayText": "Description", + "sortable": false, + "fieldOrder": 1, + "selected": false, + "sortOrder": 0, + "sortType": "ASC" + } + ] + } + ] + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/applicationFinding/export": { + "post": { + "summary": "Initiate export job", + "description": "

\nEndpoint for initiating an export job against the\ndata outlined in the given FilterRequest.\nThe Application Finding Export Template API (/client/{clientId}/applicationFinding/export/template) lists the fields that can be exported. The exportableFields section of the request body can be used to choose the fields that needs to be exported.\n

\n", + "tags": [ + "applicationFinding" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filterRequest", + "fileType", + "noOfRows", + "fileName", + "exportableFields" + ], + "properties": { + "filterRequest": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + } + }, + "fileType": { + "description": "Type of file to be exported into", + "type": "string", + "enum": [ + "JSON", + "CSV" + ] + }, + "noOfRows": { + "description": "Number of rows to be exported by default", + "type": "integer" + }, + "fileName": { + "description": "Name of the exported file", + "type": "string" + }, + "exportableFields": { + "description": "Fields included for Export", + "type": "array", + "items": { + "type": "object", + "required": [ + "heading", + "fields" + ], + "properties": { + "heading": { + "description": "Used to set fields(asset_options/finding_options/group_options/tag_options/user_options)", + "type": "string" + }, + "fields": { + "description": "Fields which are available in exported file", + "type": "array", + "items": { + "type": "object", + "required": [ + "identifierField", + "fieldOrder", + "selected", + "sortable", + "sortOrder", + "sortType" + ], + "properties": { + "identifierField": { + "description": "Internal field which we use to identify the export field", + "type": "string" + }, + "sortable": { + "description": "Is Field Sortable", + "type": "boolean" + }, + "fieldOrder": { + "description": "Order of the export field", + "type": "integer" + }, + "selected": { + "description": "Is Field Selected", + "type": "boolean" + }, + "sortOrder": { + "description": "Sort order of the exportable fields", + "type": "integer" + }, + "sortType": { + "description": "Sort type of the exportable fields - asc/desc", + "type": "string" + } + } + } + } + } + } + } + }, + "example": { + "filterRequest": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + }, + "fileName": "TestFindingsExport", + "fileType": "CSV", + "noOfRows": 5000, + "exportableFields": [ + { + "heading": "asset_options", + "fields": [ + { + "identifierField": "name", + "fieldOrder": 1, + "selected": false, + "sortable": false, + "sortOrder": 0, + "sortType": "ASC" + } + ] + }, + { + "heading": "finding_options", + "fields": [ + { + "identifierField": "host", + "fieldOrder": 1, + "selected": false, + "sortable": false, + "sortOrder": 0, + "sortType": "ASC" + } + ] + } + ] + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/applicationFinding/update-due-date": { + "post": { + "summary": "Bulk update due dates", + "description": "

\nEndpoint for initializing a due date update job against the\ndata outlined in the given FilterRequest\n

\n", + "tags": [ + "applicationFinding" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filterRequest" + ], + "properties": { + "filterRequest": { + "description": "Filter for job requests", + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + } + }, + "dueDate": { + "type": "string", + "format": "date" + } + }, + "example": { + "filterRequest": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + }, + "dueDate": "2019-12-30" + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/applicationFinding/delete": { + "post": { + "summary": "Delete entities based on filters", + "tags": [ + "applicationFinding" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filterRequest" + ], + "properties": { + "filterRequest": { + "description": "Filter for job requests", + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + } + } + }, + "example": { + "filterRequest": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "EXACT", + "value": "1" + } + ] + } + } + } + } + ], + "responses": { + "200": { + "description": "Job Created", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/applicationFinding/note": { + "post": { + "summary": "Add a note to application findings", + "description": "

\nEndpoint for initiating a note creation job against the\ndata outlined in the given FilterRequest\n

\n", + "tags": [ + "applicationFinding" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filterRequest", + "note" + ], + "properties": { + "filterRequest": { + "description": "Filter for job requests", + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + } + }, + "note": { + "description": "The note you are adding to the entity", + "type": "string" + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/applicationFinding/apiExport": { + "post": { + "summary": "Initiate paginated export", + "description": "

\n

\n

\nEndpoint to fetch the paginated export response against the\ndata outlined in the given FilterRequest.\nThe exportableFields section of the request body can be used to choose the fields that needs to be exported.\n

\n", + "tags": [ + "applicationFinding" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "searchAfter", + "description": "Pagination parameter to retrieve result after the given value, get the value from the field 'searchAfter' in the response", + "type": "integer", + "in": "query", + "required": false + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filterRequest", + "exportableFields" + ], + "properties": { + "filterRequest": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + } + }, + "noOfRows": { + "description": "Number of rows to be exported by default. It is optional", + "type": "integer" + }, + "exportableFields": { + "description": "Fields included for api export", + "type": "array", + "items": { + "type": "object", + "required": [ + "heading", + "fields" + ], + "properties": { + "heading": { + "description": "Used to set fields(asset_options/finding_options)", + "type": "string" + }, + "fields": { + "description": "Fields which are available in response", + "type": "array", + "items": { + "type": "object", + "required": [ + "identifierField", + "selected" + ], + "properties": { + "identifierField": { + "description": "Internal field which we use to identify the export field", + "type": "string" + }, + "selected": { + "description": "Is Field Selected", + "type": "boolean" + } + } + } + } + } + } + } + }, + "example": { + "filterRequest": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + }, + "noOfRows": 250, + "exportableFields": [ + { + "heading": "asset_options", + "fields": [ + { + "identifierField": "name", + "selected": true + } + ] + }, + { + "heading": "finding_options", + "fields": [ + { + "identifierField": "host", + "selected": true + } + ] + } + ] + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "type": "object" + } + }, + "searchAfter": { + "type": "string", + "description": "Paginated value to retrieve the next result" + }, + "totalCount": { + "type": "string", + "description": "Total findings/assets count" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/uniqueApplicationFinding/model": { + "get": { + "deprecated": true, + "summary": "List projections and their models", + "description": "List projections and their models that can be requested from the search endpoint.\n", + "tags": [ + "UniqueFindingEOL" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "object", + "properties": { + "projections": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "fields": { + "type": "array", + "items": { + "type": "object", + "properties": { + "field": { + "type": "string" + }, + "type": { + "type": "string" + }, + "nested": { + "type": "array", + "items": { + "type": "object", + "description": "Same as ProjectionField" + } + } + } + } + } + } + } + } + }, + "example": { + "projections": [ + { + "name": "basic", + "fields": [ + { + "field": "id", + "type": "integer" + }, + { + "field": "name", + "type": "string" + } + ] + } + ] + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/uniqueApplicationFinding/filter": { + "get": { + "deprecated": true, + "summary": "List fields that can be filtered by in the search endpoint", + "tags": [ + "UniqueFindingEOL" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "array", + "items": { + "required": [ + "name", + "uid", + "operators", + "type", + "description" + ], + "properties": { + "name": { + "type": "string" + }, + "uid": { + "type": "string", + "description": "uid used to indentify fields in suggest and search requests" + }, + "operators": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + } + }, + "datatype": { + "type": "string" + }, + "description": { + "type": "string" + } + } + }, + "example": [ + { + "name": "id", + "uid": "id", + "operator": [ + "EXACT", + "IN" + ], + "type": "integer", + "description": "The id" + } + ] + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/uniqueApplicationFinding/suggest": { + "post": { + "deprecated": true, + "summary": "Suggest values for filter fields", + "tags": [ + "UniqueFindingEOL" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "filter" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + }, + "description": "Filters to used to narrow down the the result set\n" + }, + "filter": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + }, + "description": "Filter for which to suggest values for. The filter value will be\ntreated as a wildcard.\n" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": true, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "filter": { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "" + } + } + } + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key", + "count" + ], + "properties": { + "key": { + "type": "string", + "description": "Value for the field the suggestion was requested for." + }, + "count": { + "type": "integer", + "format": "int64" + } + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/uniqueApplicationFinding/search": { + "post": { + "deprecated": true, + "summary": "Search for application unique findings", + "tags": [ + "UniqueFindingEOL" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "sort" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + }, + "projection": { + "type": "string" + }, + "sort": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "direction" + ], + "properties": { + "field": { + "type": "string" + }, + "direction": { + "type": "string", + "enum": [ + "ASC", + "DESC" + ] + } + } + } + }, + "page": { + "type": "integer" + }, + "size": { + "type": "integer" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "projection": "basic", + "sort": [ + { + "field": "id", + "direction": "ASC" + } + ], + "page": 0, + "size": 20 + } + } + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "object", + "required": [ + "_embedded", + "page" + ], + "properties": { + "_embedded": { + "type": "object", + "required": [ + "strings" + ], + "properties": { + "strings": { + "type": "array", + "items": { + "type": "object", + "description": "

The response structure is subject dependent. Subject structure\ncan be found via the subject endpoint.

\n" + } + } + } + }, + "page": { + "type": "object", + "required": [ + "size", + "totalElements", + "totalPages", + "number" + ], + "properties": { + "size": { + "type": "integer" + }, + "totalElements": { + "type": "integer" + }, + "totalPages": { + "type": "integer" + }, + "number": { + "type": "integer" + } + } + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "id", + "errorRefId", + "code", + "cause" + ], + "properties": { + "id": { + "type": "string", + "description": "Entity id which failed to be retrieved" + }, + "errorRefId": { + "type": "string", + "description": "A unique identifier for the error" + }, + "code": { + "type": "integer", + "description": "http status code of the error" + }, + "cause": { + "type": "string", + "description": "http status code message" + } + } + } + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/uniqueApplicationFinding/export": { + "post": { + "deprecated": true, + "summary": "Initiate export job", + "description": "

\nEndpoint for initiating an export job against the\ndata outlined in the given FilterRequest\n

\n", + "tags": [ + "UniqueFindingEOL" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filterRequest", + "fileType", + "comment", + "fileName" + ], + "properties": { + "filterRequest": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + } + }, + "fileType": { + "description": "Type of file to be exported into", + "type": "string", + "enum": [ + "XML", + "XLSX", + "CSV" + ] + }, + "comment": { + "description": "Addition description for the exported file", + "type": "string" + }, + "fileName": { + "description": "Name of the exported file", + "type": "string" + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/user": { + "get": { + "summary": "Get information about a user for listview use", + "tags": [ + "user" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "userId", + "description": "Optional Id of the user. If not provided, the user's id that is making this request will be used", + "in": "query", + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "firstName", + "lastName", + "userName" + ], + "properties": { + "firstName": { + "type": "string", + "description": "The first name of the requesting user" + }, + "lastName": { + "type": "string", + "description": "The last name of the requesting user" + }, + "userName": { + "type": "string", + "description": "The username of the requesting user" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/user/profile": { + "get": { + "summary": "Get information about the requesting user including the current client ID", + "tags": [ + "user" + ], + "produces": [ + "application/json" + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "rbacRolesToClient", + "clientId", + "clientName", + "firstName", + "lastName", + "multiClientUser", + "readOnly", + "role", + "uploadEnabled", + "userId", + "userName", + "privilegesByClient", + "whitelistByClient" + ], + "properties": { + "rbacRolesToClient": { + "type": "array", + "description": "The list of accessible clients with roles for the requesting multi-client user", + "items": { + "type": "object", + "required": [ + "id", + "name", + "roles" + ], + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "roles": { + "type": "array", + "description": "Array of roles.", + "items": { + "type": "string" + } + } + } + } + }, + "clientId": { + "type": "integer", + "description": "The ID of the client which can be used for other endpoints" + }, + "clientName": { + "type": "string", + "description": "The name of the client that corresponds to the clientId property" + }, + "firstName": { + "type": "string", + "description": "The first name of the requesting user" + }, + "lastName": { + "type": "string", + "description": "The last name of the requesting user" + }, + "email": { + "type": "string", + "description": "The registered email address of the requesting user" + }, + "isReceiveEmails": { + "type": "boolean", + "description": "Global email notification enable/disable" + }, + "multiClientUser": { + "type": "boolean", + "description": "Indicates if the user has access to multiple clients" + }, + "readOnly": { + "type": "boolean", + "description": "Indicates if the client is in read-only mode" + }, + "role": { + "type": "string", + "description": "The permission role of the requesting user" + }, + "uploadEnabled": { + "type": "boolean", + "description": "Provides group-manager users the ability to upload scan files" + }, + "userId": { + "type": "integer", + "description": "The ID of the requesting user" + }, + "userUuid": { + "type": "string", + "description": "Globally unique ID. Used for create and edit endpoints." + }, + "userName": { + "type": "string", + "description": "The username of the requesting user" + }, + "privilegesByClient": { + "type": "object", + "description": "The list of privileges a user has from all clients and roles.", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "whitelistByClient": { + "type": "object", + "description": "For each client whether it is whitelisted.", + "additionalProperties": { + "type": "boolean" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + } + } + } + }, + "/clients/user/{userId}/tokenAllowed": { + "post": { + "summary": "Change whether or not a user can use tokens", + "tags": [ + "user" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientIds", + "in": "query", + "description": "Ids of clients (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "array", + "items": { + "type": "integer" + } + }, + { + "name": "userId", + "description": "Id of the user to update", + "in": "path", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "allowed" + ], + "properties": { + "allowed": { + "type": "boolean" + } + } + } + } + ], + "responses": { + "204": { + "description": "Success" + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/user": { + "post": { + "summary": "Create a user", + "tags": [ + "user" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "username", + "firstName", + "lastName", + "email", + "readOnly", + "groupIds" + ], + "properties": { + "username": { + "type": "string" + }, + "firstName": { + "type": "string" + }, + "lastName": { + "type": "string" + }, + "email": { + "type": "string" + }, + "readOnly": { + "type": "boolean" + }, + "groupIds": { + "type": "array", + "description": "Array of group IDs, can be empty.", + "items": { + "type": "integer" + } + }, + "useSamlAuthentication": { + "type": "boolean" + }, + "samlAttribute1": { + "description": "SAML attribute 1 should always be an email address", + "type": "string" + }, + "samlAttribute2": { + "description": "SAML attribute 2 can be anything but tends to be username", + "type": "string" + }, + "expirationDate": { + "type": "string", + "format": "date-time" + } + } + } + } + ], + "responses": { + "201": { + "description": "Success" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/user/{userUUID}": { + "put": { + "summary": "Update a user. Please note you cannot modify username, email of another user for security reasons. Please contact support if you need assistance.", + "tags": [ + "user" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "userUUID", + "description": "UUID of the User\n", + "in": "path", + "required": true, + "type": "string" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "username": { + "description": "This field is only available for managers.", + "type": "string" + }, + "firstName": { + "type": "string" + }, + "lastName": { + "type": "string" + }, + "email": { + "type": "string" + }, + "readOnly": { + "description": "This field is only available for managers.", + "type": "boolean" + }, + "useSamlAuthentication": { + "description": "This field is only available for managers.", + "type": "boolean" + }, + "samlAttribute1": { + "description": "SAML attribute 1 should always be an email address", + "type": "string" + }, + "samlAttribute2": { + "description": "SAML attribute 2 can be anything but tends to be username", + "type": "string" + }, + "expirationDate": { + "description": "This field is only available for managers.", + "type": "string", + "format": "date" + }, + "twoFactorType": { + "type": "string", + "enum": [ + "EMAIL", + "GOOGLE" + ] + } + } + } + } + ], + "responses": { + "200": { + "description": "Success" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Not Found" + } + } + }, + "delete": { + "summary": "Remove user from client", + "tags": [ + "user" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "userUUID", + "description": "UUID of the User\n", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "delay", + "description": "Delay at which to start the user remove job in seconds. Default is 12 hours.", + "in": "query", + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Job Created", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/user/{userUUID}/role": { + "put": { + "summary": "Update users role", + "tags": [ + "user" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "userUUID", + "description": "UUID of the User\n", + "in": "path", + "required": true, + "type": "string" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "roles": { + "type": "array", + "items": { + "type": "object", + "properties": { + "role": { + "type": "string" + }, + "expirationDate": { + "type": "string", + "format": "date" + } + } + } + } + }, + "example": { + "roles": [ + { + "role": "BasicUser", + "expirationDate": null + }, + { + "role": "SecurityAnalyst", + "expirationDate": "2020-12-31" + } + ] + } + } + } + ], + "responses": { + "200": { + "description": "Job Created", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/user/{userUUID}/iam": { + "get": { + "summary": "User IAM information on a client", + "tags": [ + "user" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "userUUID", + "description": "UUID of the User\n", + "in": "path", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "properties": { + "roles": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "id": { + "type": "string" + } + } + } + }, + "privileges": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "id": { + "type": "string" + }, + "active": { + "description": "After the evaluating all roles this privilege is active", + "type": "string" + }, + "userSupportingRoles": { + "description": "Roles the user has that give them the privilege", + "type": "array", + "items": { + "type": "string" + } + }, + "userNegatingRoles": { + "description": "Roles the user has that prevents them from having the privilege", + "type": "array", + "items": { + "type": "string" + } + }, + "allSupportingRoles": { + "description": "Roles on the client that would give the user the privilege", + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/user/sendWelcomeEmail": { + "post": { + "summary": "Send welcome emails to users", + "tags": [ + "user" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filterRequest" + ], + "properties": { + "filterRequest": { + "description": "Filter for job requests", + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + } + } + }, + "example": { + "filterRequest": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2" + } + ] + } + } + } + } + ], + "responses": { + "200": { + "description": "Success" + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/user/importUsersCsv": { + "post": { + "summary": "Import users via CSV.", + "tags": [ + "user" + ], + "consumes": [ + "multipart/form-data" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "formData", + "name": "csvUsers", + "type": "file", + "required": true, + "description": "The CSV file representing users to create. The schema is as follows and must be included as the first line header of the file:\nUsername, First Name, Last Name, Email Address, Role Level (Disabled | Technician | User | Group Manager | Manager), Group Access (All | None), Use SAML? (Yes | No), SAML Username, SAML" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/user/export/template": { + "get": { + "summary": "List out all fields that are part of configurable export.", + "tags": [ + "user" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "object", + "required": [ + "id", + "clientId", + "userId", + "name", + "description", + "shared", + "isDefault", + "subject", + "exportableFields" + ], + "properties": { + "id": { + "description": "The id", + "type": "integer" + }, + "clientId": { + "description": "Client id", + "type": "integer" + }, + "userId": { + "description": "User id", + "type": "integer" + }, + "name": { + "description": "Template name", + "type": "string" + }, + "description": { + "description": "Template description", + "type": "string" + }, + "shared": { + "description": "Describes whether this template shared or not", + "type": "boolean" + }, + "isDefault": { + "description": "Describes whether this template is default or not", + "type": "boolean" + }, + "subject": { + "description": "For which asset to fetch fileds", + "type": "string" + }, + "exportableFields": { + "description": "List of fileds", + "type": "array", + "items": { + "type": "object", + "required": [ + "heading", + "fields" + ], + "properties": { + "heading": { + "description": "Used to set fields(asset_options/finding_options/group_options/tag_options/user_options)", + "type": "string" + }, + "fields": { + "description": "Fields which are available in exported file", + "type": "array", + "items": { + "type": "object", + "required": [ + "identifierField", + "fieldOrder", + "selected", + "sortable", + "sortOrder", + "sortType" + ], + "properties": { + "identifierField": { + "description": "Internal field which we use to identify the export field", + "type": "string" + }, + "sortable": { + "description": "Is Field Sortable", + "type": "boolean" + }, + "fieldOrder": { + "description": "Order of the export field", + "type": "integer" + }, + "selected": { + "description": "Is Field Selected", + "type": "boolean" + }, + "sortOrder": { + "description": "Sort order of the exportable fields", + "type": "integer" + }, + "sortType": { + "description": "Sort type of the exportable fields - asc/desc", + "type": "string" + } + } + } + } + } + } + } + }, + "example": { + "id": 0, + "clientId": 1, + "userId": 1, + "name": "User-Export-Template-Name", + "description": "User-Export-Template-Description", + "shared": false, + "isDefault": false, + "subject": "tag", + "exportableFields": [ + { + "heading": "user_options", + "fields": [ + { + "identifierField": "name", + "displayText": "Name", + "sortable": false, + "fieldOrder": 1, + "selected": false, + "sortOrder": 0, + "sortType": "ASC" + } + ] + } + ] + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/user/export": { + "post": { + "summary": "Initiate export job", + "description": "

\n

\n

\nEndpoint for initiating an export job against the\ndata outlined in the given FilterRequest.\nThe User Export Template API (/client/{clientId}/user/export/template) lists the fields that can be exported. The exportableFields section of the request body can be used to choose the fields that needs to be exported.\n

\n", + "tags": [ + "user" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filterRequest", + "fileType", + "noOfRows", + "fileName", + "exportableFields" + ], + "properties": { + "filterRequest": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + } + }, + "fileType": { + "description": "Type of file to be exported into", + "type": "string", + "enum": [ + "JSON", + "CSV" + ] + }, + "noOfRows": { + "description": "Number of rows to be exported by default", + "type": "integer" + }, + "fileName": { + "description": "Name of the exported file", + "type": "string" + }, + "exportableFields": { + "description": "Fields included for Export", + "type": "array", + "items": { + "type": "object", + "required": [ + "heading", + "fields" + ], + "properties": { + "heading": { + "description": "Used to set fields(asset_options/finding_options/group_options/tag_options/user_options)", + "type": "string" + }, + "fields": { + "description": "Fields which are available in exported file", + "type": "array", + "items": { + "type": "object", + "required": [ + "identifierField", + "fieldOrder", + "selected", + "sortable", + "sortOrder", + "sortType" + ], + "properties": { + "identifierField": { + "description": "Internal field which we use to identify the export field", + "type": "string" + }, + "sortable": { + "description": "Is Field Sortable", + "type": "boolean" + }, + "fieldOrder": { + "description": "Order of the export field", + "type": "integer" + }, + "selected": { + "description": "Is Field Selected", + "type": "boolean" + }, + "sortOrder": { + "description": "Sort order of the exportable fields", + "type": "integer" + }, + "sortType": { + "description": "Sort type of the exportable fields - asc/desc", + "type": "string" + } + } + } + } + } + } + } + }, + "example": { + "filterRequest": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + }, + "fileName": "TestUserExport", + "fileType": "CSV", + "noOfRows": 5000, + "exportableFields": [ + { + "heading": "user_options", + "fields": [ + { + "identifierField": "name", + "fieldOrder": 1, + "selected": false, + "sortable": false, + "sortOrder": 0, + "sortType": "ASC" + } + ] + } + ] + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/user/model": { + "get": { + "summary": "List projections and their models", + "description": "List projections and their models that can be requested from the search endpoint.\n", + "tags": [ + "user" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "object", + "properties": { + "projections": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "fields": { + "type": "array", + "items": { + "type": "object", + "properties": { + "field": { + "type": "string" + }, + "type": { + "type": "string" + }, + "nested": { + "type": "array", + "items": { + "type": "object", + "description": "Same as ProjectionField" + } + } + } + } + } + } + } + } + }, + "example": { + "projections": [ + { + "name": "basic", + "fields": [ + { + "field": "id", + "type": "integer" + }, + { + "field": "name", + "type": "string" + } + ] + } + ] + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/user/filter": { + "get": { + "summary": "List fields that can be filtered by in the search endpoint", + "tags": [ + "user" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "array", + "items": { + "required": [ + "name", + "uid", + "operators", + "type", + "description" + ], + "properties": { + "name": { + "type": "string" + }, + "uid": { + "type": "string", + "description": "uid used to indentify fields in suggest and search requests" + }, + "operators": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + } + }, + "datatype": { + "type": "string" + }, + "description": { + "type": "string" + } + } + }, + "example": [ + { + "name": "id", + "uid": "id", + "operator": [ + "EXACT", + "IN" + ], + "type": "integer", + "description": "The id" + } + ] + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/user/suggest": { + "post": { + "summary": "Suggest values for filter fields", + "tags": [ + "user" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "filter" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + }, + "description": "Filters to used to narrow down the the result set\n" + }, + "filter": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + }, + "description": "Filter for which to suggest values for. The filter value will be\ntreated as a wildcard.\n" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": true, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "filter": { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "" + } + } + } + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key", + "count" + ], + "properties": { + "key": { + "type": "string", + "description": "Value for the field the suggestion was requested for." + }, + "count": { + "type": "integer", + "format": "int64" + } + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/user/search": { + "post": { + "summary": "Search for users", + "tags": [ + "user" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "sort" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + }, + "projection": { + "type": "string" + }, + "sort": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "direction" + ], + "properties": { + "field": { + "type": "string" + }, + "direction": { + "type": "string", + "enum": [ + "ASC", + "DESC" + ] + } + } + } + }, + "page": { + "type": "integer" + }, + "size": { + "type": "integer" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "projection": "basic", + "sort": [ + { + "field": "id", + "direction": "ASC" + } + ], + "page": 0, + "size": 20 + } + } + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "object", + "required": [ + "_embedded", + "page" + ], + "properties": { + "_embedded": { + "type": "object", + "required": [ + "strings" + ], + "properties": { + "strings": { + "type": "array", + "items": { + "type": "object", + "description": "

The response structure is subject dependent. Subject structure\ncan be found via the subject endpoint.

\n" + } + } + } + }, + "page": { + "type": "object", + "required": [ + "size", + "totalElements", + "totalPages", + "number" + ], + "properties": { + "size": { + "type": "integer" + }, + "totalElements": { + "type": "integer" + }, + "totalPages": { + "type": "integer" + }, + "number": { + "type": "integer" + } + } + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "id", + "errorRefId", + "code", + "cause" + ], + "properties": { + "id": { + "type": "string", + "description": "Entity id which failed to be retrieved" + }, + "errorRefId": { + "type": "string", + "description": "A unique identifier for the error" + }, + "code": { + "type": "integer", + "description": "http status code of the error" + }, + "cause": { + "type": "string", + "description": "http status code message" + } + } + } + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/user/assign-group": { + "post": { + "summary": "Assign users to group", + "tags": [ + "user" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filterRequest", + "targetGroupIds" + ], + "properties": { + "filterRequest": { + "description": "Filter for job requests", + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + } + }, + "targetGroupIds": { + "description": "List of groupIds where users to be assigned or unassigned.", + "type": "array", + "items": { + "type": "integer" + } + } + } + } + } + ], + "responses": { + "200": { + "description": "Success" + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/user/unassign-group": { + "post": { + "summary": "Unassign users from group", + "tags": [ + "user" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filterRequest", + "targetGroupIds" + ], + "properties": { + "filterRequest": { + "description": "Filter for job requests", + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + } + }, + "targetGroupIds": { + "description": "List of groupIds where users to be assigned or unassigned.", + "type": "array", + "items": { + "type": "integer" + } + } + } + } + } + ], + "responses": { + "200": { + "description": "Success" + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/user/privilege": { + "post": { + "summary": "List all users with certain privileges on the client", + "tags": [ + "user" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "privilegeIds", + "workflowType" + ], + "properties": { + "privilegeIds": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of privilege ids to fetch user for" + }, + "workflowType": { + "type": "string" + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "array", + "items": { + "type": "object", + "required": [ + "id", + "clientId", + "firstName", + "lastName", + "username" + ], + "properties": { + "id": { + "type": "integer" + }, + "clientId": { + "type": "integer" + }, + "firstName": { + "type": "string" + }, + "lastName": { + "type": "string" + }, + "username": { + "type": "string" + } + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/ticket/{tagId}": { + "post": { + "summary": "Create a new ticket", + "tags": [ + "ticket" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "tagId", + "description": "Id of the tag", + "in": "path", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "description": "

Structure is dependent on the type field. The referenced structures can be found at the bottom of this document.

\n
    \n
  • SERVICE_NOW: CreateTicketRequest_ServiceNow_Incident
  • \n
  • SNOW_SERVICE_REQUEST: CreateTicketRequest_ServiceNow_ServiceRequest
  • \n
  • JIRA: CreateTicketRequest_Jira
  • \n
  • GENERIC_SNOW: CreateTicketRequest_ServiceNow_Generic
  • \n
\n" + } + } + ], + "responses": { + "201": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "uuid", + "id", + "tagId", + "link", + "status" + ], + "properties": { + "uuid": { + "type": "string" + }, + "id": { + "type": "string" + }, + "tagId": { + "type": "integer" + }, + "link": { + "type": "string" + }, + "status": { + "type": "string" + } + } + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + } + } + } + }, + "/client/{clientId}/ticket/{ticketId}": { + "get": { + "summary": "Get information about a specific ticket", + "tags": [ + "ticket" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "ticketId", + "description": "Id of the ticket", + "in": "path", + "required": true, + "type": "integer" + } + ], + "responses": { + "201": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "uuid", + "id", + "tagId", + "link", + "status" + ], + "properties": { + "uuid": { + "type": "string" + }, + "id": { + "type": "string" + }, + "tagId": { + "type": "integer" + }, + "link": { + "type": "string" + }, + "status": { + "type": "string" + } + } + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + } + } + } + }, + "/client/{clientId}/ticket/{ticketUuid}": { + "delete": { + "summary": "Delete a ticket", + "tags": [ + "ticket" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "ticketUuid", + "description": "Uuid of the ticket (This parameter can be obtained via the GET method on '/ticket')", + "in": "path", + "required": true, + "type": "string" + } + ], + "responses": { + "204": { + "description": "Request was processed without errors" + }, + "401": { + "description": "Unauthorized" + } + } + } + }, + "/client/{clientId}/export/{exportId}/status": { + "get": { + "summary": "Check status of an export job", + "description": "

\n

\n

\nCheck status of an export job\n

\n", + "tags": [ + "export" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "exportId", + "in": "path", + "description": "The export id", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Successfully fetched the export status", + "schema": { + "properties": { + "id": { + "type": "integer", + "description": "The export id" + }, + "filename": { + "type": "string", + "description": "Name of the file created by this export" + }, + "status": { + "type": "string", + "description": "Status of the export" + }, + "history": { + "type": "array", + "items": { + "properties": { + "state": { + "type": "string" + }, + "message": { + "type": "string" + }, + "time": { + "type": "string" + } + } + } + }, + "fileId": { + "type": "integer" + }, + "progress": { + "type": "integer" + }, + "total": { + "type": "integer" + }, + "timeCreated": { + "type": "string" + }, + "timeExpired": { + "type": "string" + } + }, + "example": { + "id": 3, + "filename": "host.csv", + "status": "COMPLETE" + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Unable to find the export id" + } + } + } + }, + "/client/{clientId}/export/{exportId}": { + "get": { + "summary": "Download a file created by an export job", + "description": "

\n

\n

\nDownload the file created by an export job\n

\n", + "tags": [ + "export" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "exportId", + "in": "path", + "description": "The export id", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Successfully fetched the export file", + "schema": { + "type": "file" + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Unable to find the export id" + }, + "500": { + "description": "Error occurred when connecting to the file service" + } + } + }, + "delete": { + "summary": "Delete files related to export", + "tags": [ + "export" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "exportId", + "in": "path", + "description": "The export id", + "required": true, + "type": "integer" + } + ], + "responses": { + "204": { + "description": "Request was processed without errors" + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Error occurred when connecting to the file service" + } + } + } + }, + "/client/{clientId}/export/rs-sbom": { + "get": { + "summary": "Download RS SBOM Report.", + "tags": [ + "export" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Successfully fetched the RS SBOM Report" + } + } + } + }, + "/client/{clientId}/rs3/aggregate": { + "post": { + "summary": "Aggregate Host/App and calculate overall RS3", + "tags": [ + "rs3" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "applyMeCheck", + "description": "Apply Manual Exploit Check for client RS3 with default as true", + "in": "query", + "required": true, + "type": "boolean", + "default": true + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "sort" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + }, + "projection": { + "type": "string" + }, + "sort": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "direction" + ], + "properties": { + "field": { + "type": "string" + }, + "direction": { + "type": "string", + "enum": [ + "ASC", + "DESC" + ] + } + } + } + }, + "page": { + "type": "integer" + }, + "size": { + "type": "integer" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "projection": "basic", + "sort": [ + { + "field": "id", + "direction": "ASC" + } + ], + "page": 0, + "size": 20 + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "properties": { + "hostRs3": { + "type": "object", + "properties": { + "rs3": { + "type": "integer" + }, + "riskAcceptedRS3": { + "type": "integer" + }, + "hosts": { + "type": "integer" + }, + "critical": { + "type": "integer" + }, + "high": { + "type": "integer" + }, + "medium": { + "type": "integer" + }, + "low": { + "type": "integer" + }, + "info": { + "type": "integer" + } + } + }, + "appRs3": { + "type": "object", + "properties": { + "rs3": { + "type": "integer" + }, + "riskAcceptedRS3": { + "type": "integer" + }, + "hosts": { + "type": "integer" + }, + "critical": { + "type": "integer" + }, + "high": { + "type": "integer" + }, + "medium": { + "type": "integer" + }, + "low": { + "type": "integer" + }, + "info": { + "type": "integer" + } + } + }, + "clientRs3": { + "type": "object", + "properties": { + "rs3": { + "type": "integer" + }, + "riskAcceptedRS3": { + "type": "integer" + }, + "hosts": { + "type": "integer" + }, + "critical": { + "type": "integer" + }, + "high": { + "type": "integer" + }, + "medium": { + "type": "integer" + }, + "low": { + "type": "integer" + }, + "info": { + "type": "integer" + } + } + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/rs3History/aggregate": { + "post": { + "summary": "Aggregate client RS3 and risk accepted RS3 value over time", + "tags": [ + "rs3" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "startDate", + "endDate", + "filters" + ], + "properties": { + "startDate": { + "description": "The starting date of the range of which trend data will be fetched from", + "type": "string", + "format": "date" + }, + "endDate": { + "description": "The ending date of the range of which trend data will be fetched from", + "type": "string", + "format": "date" + }, + "filters": { + "description": "Array of filter values to filter on client host rs3 history", + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "description": "Field to filter on", + "type": "string" + }, + "exclusive": { + "description": "True if \"is not\" false means \"is\"", + "type": "boolean" + }, + "operator": { + "description": "The operator to filter with", + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "description": "Value to filter on", + "type": "string" + } + } + } + } + }, + "example": { + "startDate": "2018-07-12", + "endDate": "2019-07-12", + "filters": [ + { + "field": "groupIds", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "date": { + "type": "string", + "format": "date" + }, + "client": { + "description": "Client level RS3 information and counts", + "type": "object", + "properties": { + "rs3": { + "type": "integer" + }, + "riskAcceptedRs3": { + "type": "integer" + }, + "actualRs3": { + "type": "integer" + }, + "actualRiskAcceptedRs3": { + "type": "integer" + }, + "totalWeight": { + "type": "integer" + }, + "assetCount": { + "type": "integer" + }, + "findingCount": { + "type": "integer" + }, + "criticalCount": { + "type": "integer" + }, + "highCount": { + "type": "integer" + }, + "mediumCount": { + "type": "integer" + }, + "lowCount": { + "type": "integer" + }, + "infoCount": { + "type": "integer" + }, + "manualExploitCount": { + "type": "integer" + } + } + }, + "host": { + "description": "Host level RS3 information and counts", + "type": "object", + "properties": { + "rs3": { + "type": "integer" + }, + "riskAcceptedRs3": { + "type": "integer" + }, + "actualRs3": { + "type": "integer" + }, + "actualRiskAcceptedRs3": { + "type": "integer" + }, + "totalWeight": { + "type": "integer" + }, + "assetCount": { + "type": "integer" + }, + "findingCount": { + "type": "integer" + }, + "criticalCount": { + "type": "integer" + }, + "highCount": { + "type": "integer" + }, + "mediumCount": { + "type": "integer" + }, + "lowCount": { + "type": "integer" + }, + "infoCount": { + "type": "integer" + }, + "manualExploitCount": { + "type": "integer" + } + } + }, + "app": { + "description": "App level RS3 information and counts", + "type": "object", + "properties": { + "rs3": { + "type": "integer" + }, + "riskAcceptedRs3": { + "type": "integer" + }, + "actualRs3": { + "type": "integer" + }, + "actualRiskAcceptedRs3": { + "type": "integer" + }, + "totalWeight": { + "type": "integer" + }, + "assetCount": { + "type": "integer" + }, + "findingCount": { + "type": "integer" + }, + "criticalCount": { + "type": "integer" + }, + "highCount": { + "type": "integer" + }, + "mediumCount": { + "type": "integer" + }, + "lowCount": { + "type": "integer" + }, + "infoCount": { + "type": "integer" + }, + "manualExploitCount": { + "type": "integer" + } + } + } + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/simulate/rs3": { + "post": { + "summary": "Simulates the rs3 score of a particular asset(Host and application)", + "tags": [ + "rs3" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "description": "Request containing the necessary parameters to simulate the rs3 score of an asset", + "type": "object", + "required": [ + "findingCount", + "assetType", + "assetCriticality", + "assetCategory" + ], + "properties": { + "vrrCriticalMax": { + "type": "number" + }, + "vrrHighMax": { + "type": "number" + }, + "vrrMediumMax": { + "type": "number" + }, + "vrrLowMax": { + "type": "number" + }, + "findingCount": { + "type": "integer" + }, + "assetType": { + "type": "string" + }, + "assetCriticality": { + "type": "integer" + }, + "assetCategory": { + "type": "string" + } + }, + "example": { + "vrrCriticalMax": 9.1, + "vrrHighMax": 7.1, + "vrrMediumMax": 5.1, + "vrrLowMax": 2.1, + "findingCount": 4, + "assetType": "External", + "assetCriticality": 3, + "assetCategory": "Host" + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "description": "Simulated Rs3 score", + "type": "object", + "properties": { + "rs3": { + "type": "number" + } + }, + "example": { + "rs3": 504 + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/playbook/supported-inputs": { + "get": { + "summary": "Get supported playbook inputs", + "tags": [ + "playbook" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "HOST", + "HOST_FINDING", + "APPLICATION", + "APPLICATION_FINDING" + ] + } + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + } + } + } + }, + "/client/{clientId}/playbook/supported-actions": { + "get": { + "summary": "Get supported playbook action types", + "tags": [ + "playbook" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "GROUP_MOVE", + "SEVERITY_CHANGE" + ] + } + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + } + } + } + }, + "/client/{clientId}/playbook/supported-frequencies": { + "get": { + "summary": "Get supported playbook frequencies", + "tags": [ + "playbook" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "DAILY", + "WEEKLY", + "MONTHLY" + ] + } + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + } + } + } + }, + "/client/{clientId}/playbook/supported-outputs": { + "get": { + "summary": "Get supported playbook outputs", + "tags": [ + "playbook" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "EMAIL", + "NO_OUTPUT", + "WEBHOOK" + ] + } + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + } + } + } + }, + "/client/{clientId}/playbook/subject-supported-actions": { + "get": { + "summary": "Get the mapping of subject to the subject's list of actions that it can use", + "tags": [ + "playbook" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "401": { + "description": "Unauthorized" + } + } + } + }, + "/client/{clientId}/playbook/fetch": { + "get": { + "summary": "Fetch all playbooks for a client", + "tags": [ + "playbook" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "size", + "in": "query", + "description": "Size of the page requested", + "required": false, + "type": "integer" + }, + { + "name": "page", + "in": "query", + "description": "Page number being requested (first page: 0)", + "required": false, + "type": "integer" + }, + { + "name": "sort", + "in": "query", + "description": "field to sort by and direction", + "required": false, + "type": "string" + }, + { + "name": "sText", + "in": "query", + "description": "search string to apply", + "required": false, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "content", + "last", + "totalElements", + "totalPages", + "sort", + "numberOfElements", + "first", + "size", + "number" + ], + "properties": { + "content": { + "type": "array", + "items": { + "type": "object", + "required": [ + "uuid", + "name", + "description", + "frequency", + "status", + "created", + "updated", + "ruleCount" + ], + "properties": { + "uuid": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "dayOfMonth": { + "type": "integer" + }, + "dayOfWeek": { + "type": "integer" + }, + "hourOfDay": { + "type": "integer" + }, + "ownerUserId": { + "type": "integer" + }, + "nextRunDatetime": { + "type": "string", + "format": "date-time" + }, + "lastRunStartDatetime": { + "type": "string", + "format": "date-time" + }, + "lastRunEndDatetime": { + "type": "string", + "format": "date-time" + }, + "lastRunStatus": { + "type": "string" + }, + "created": { + "type": "string", + "format": "date-time" + }, + "updated": { + "type": "string", + "format": "date-time" + }, + "status": { + "type": "string" + }, + "frequency": { + "type": "string" + }, + "ruleCount": { + "type": "integer" + } + } + } + }, + "last": { + "type": "boolean" + }, + "totalElements": { + "type": "integer" + }, + "totalPages": { + "type": "integer" + }, + "sort": { + "type": "string" + }, + "numberOfElements": { + "type": "integer" + }, + "first": { + "type": "boolean" + }, + "size": { + "type": "integer" + }, + "number": { + "type": "integer" + } + } + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + } + } + } + }, + "/client/{clientId}/playbook/fetch/{playbookUuid}": { + "get": { + "summary": "Fetch a specified playbook", + "tags": [ + "playbook" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "playbookUuid", + "in": "path", + "description": "UUID of a playbook\n", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "uuid", + "name", + "description", + "frequency", + "status", + "created", + "updated", + "ruleCount" + ], + "properties": { + "uuid": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "dayOfMonth": { + "type": "integer" + }, + "dayOfWeek": { + "type": "integer" + }, + "hourOfDay": { + "type": "integer" + }, + "ownerUserId": { + "type": "integer" + }, + "nextRunDatetime": { + "type": "string", + "format": "date-time" + }, + "lastRunStartDatetime": { + "type": "string", + "format": "date-time" + }, + "lastRunEndDatetime": { + "type": "string", + "format": "date-time" + }, + "lastRunStatus": { + "type": "string" + }, + "created": { + "type": "string", + "format": "date-time" + }, + "updated": { + "type": "string", + "format": "date-time" + }, + "status": { + "type": "string" + }, + "frequency": { + "type": "string" + }, + "ruleCount": { + "type": "integer" + } + } + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + } + } + } + }, + "/client/{clientId}/playbook/{playbookUuid}/rules": { + "get": { + "summary": "Fetch all playbook rules for a playbook", + "tags": [ + "playbook" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "playbookUuid", + "in": "path", + "description": "UUID of a playbook\n", + "required": true, + "type": "string" + }, + { + "name": "size", + "in": "query", + "description": "Size of the page requested", + "required": false, + "type": "integer" + }, + { + "name": "page", + "in": "query", + "description": "Page number being requested (first page: 0)", + "required": false, + "type": "integer" + }, + { + "name": "sort", + "in": "query", + "description": "field to sort by and direction", + "required": false, + "type": "string" + }, + { + "name": "sText", + "in": "query", + "description": "search string to apply", + "required": false, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "content", + "last", + "totalElements", + "totalPages", + "sort", + "numberOfElements", + "first", + "size", + "number" + ], + "properties": { + "content": { + "type": "array", + "items": { + "type": "object", + "required": [ + "uuid", + "name", + "description", + "priority", + "input", + "filter", + "actionId", + "detailInfo", + "actionConfig", + "outputConfig" + ], + "properties": { + "uuid": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "priority": { + "type": "integer" + }, + "input": { + "type": "string" + }, + "filter": { + "type": "string" + }, + "actionId": { + "type": "string" + }, + "actionName": { + "type": "string" + }, + "actionConfig": { + "type": "string" + }, + "detailInfo": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "outputConfig": { + "type": "string" + }, + "files": { + "type": "array" + } + } + } + }, + "last": { + "type": "boolean" + }, + "totalElements": { + "type": "integer" + }, + "totalPages": { + "type": "integer" + }, + "sort": { + "type": "string" + }, + "numberOfElements": { + "type": "integer" + }, + "first": { + "type": "boolean" + }, + "size": { + "type": "integer" + }, + "number": { + "type": "integer" + } + } + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + } + } + }, + "post": { + "summary": "Save a rule(s) for an already existing playbook", + "tags": [ + "playbook" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "playbookUuid", + "in": "path", + "description": "UUID of a playbook\n", + "required": true, + "type": "string" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "rules" + ], + "properties": { + "rules": { + "type": "array", + "items": { + "type": "object", + "required": [ + "name", + "description", + "input", + "actionType", + "action", + "outputType", + "output" + ], + "properties": { + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "input": { + "type": "string", + "enum": [ + "HOST", + "HOST_FINDING", + "APPLICATION", + "APPLICATION_FINDING" + ] + }, + "actionType": { + "type": "string", + "enum": [ + "GROUP_MOVE", + "SEVERITY_CHANGE" + ] + }, + "action": { + "type": "object", + "description": "

Structure is dependent on the action type field.\nThe referenced structures can be found at the bottom of this document.

\n
    \n
  • ASSIGNMENT: PlaybookActionConfig_AssignUnassign
  • \n
  • UNASSIGNMENT: PlaybookActionConfig_AssignUnassign
  • \n
  • DUE_DATE_EXPLICIT: PlaybookActionConfig_Due_Date_EXPLICIT
  • \n
  • DUE_DATE_OFFSET: PlaybookActionConfig_Due_Date_OFFSET
  • \n
  • DUE_DATE_REMOVE: PlaybookActionConfig_Due_Date_REMOVE
  • \n
  • SEVERITY_CHANGE: PlaybookActionConfig_Severity_Change
  • \n
  • TAG_APPLY: PlaybookActionConfig_TagApplyUnapply
  • \n
  • TAG_UNAPPLY: PlaybookActionConfig_TagApplyUnapply
  • \n
  • ADD_TO_GROUP: PlaybookActionConfig_AddToGroup
  • \n
  • REMOVE_FROM_GROUP: PlaybookActionConfig_RemoveFromGroup
  • \n
  • UPDATE_BUSINESS_CRITICALITY: PlaybookActionConfig_AssetUpdate
  • \n
  • UPDATE_IP_ADDRESS_TYPE: PlaybookActionConfig_AssetUpdate
  • \n
  • REMEDIATION_SLA: PlaybookActionConfig_AssetUpdate
  • \n
\n" + }, + "outputType": { + "type": "string", + "enum": [ + "EMAIL", + "NO_OUTPUT", + "WEBHOOK" + ] + }, + "output": { + "type": "object", + "description": "

Structure is dependent on the output type field.\nThe referenced structures can be found at the bottom of this document.

\n
    \n
  • EMAIL: PlaybookOutputConfig_Email
  • \n
\n" + } + }, + "example": { + "name": "Example Rule", + "description": "This rule will add hosts with IDs 1, 2, 3 to the group with ID 42", + "input": "HOST", + "actionType": "ADD_TO_GROUP", + "action": { + "targetGroupIds": [ + 42 + ], + "filterRequest": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3" + } + ] + } + }, + "outputType": "EMAIL", + "output": { + "targetUsernames": [ + "firstLastUsername" + ], + "subject": "New set of hosts moved to group alpha", + "message": "Here to inform you the group move completed.", + "includeOperationalSummary": true + } + } + } + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "description": "An array of all rules associated with the given playbook after inserting the new rules.", + "type": "array", + "items": { + "type": "object", + "required": [ + "uuid", + "name", + "description", + "priority", + "input", + "filter", + "actionId", + "detailInfo", + "actionConfig", + "outputConfig" + ], + "properties": { + "uuid": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "priority": { + "type": "integer" + }, + "input": { + "type": "string" + }, + "filter": { + "type": "string" + }, + "actionId": { + "type": "string" + }, + "actionName": { + "type": "string" + }, + "actionConfig": { + "type": "string" + }, + "detailInfo": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "outputConfig": { + "type": "string" + }, + "files": { + "type": "array" + } + } + } + } + }, + "400": { + "description": "User error", + "schema": { + "description": "Bad Request" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "description": "Unauthorized" + } + }, + "404": { + "description": "Not Found", + "schema": { + "description": "Not Found" + } + } + } + } + }, + "/client/{clientId}/playbook": { + "post": { + "summary": "Create a playbook without any rules", + "tags": [ + "playbook" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "name", + "description", + "schedule" + ], + "properties": { + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "schedule": { + "type": "object", + "required": [ + "type", + "hourOfDay" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "DAILY", + "WEEKLY", + "MONTHLY" + ] + }, + "hourOfDay": { + "type": "integer", + "description": "0 - 23 (Required for Daily, Weekly, Monthly)" + }, + "dayOfWeek": { + "type": "integer", + "description": "1 - 7 (Required for Weekly)" + }, + "dayOfMonth": { + "type": "integer", + "description": "1 - 31 (Required for Monthly)" + } + } + }, + "type": { + "type": "string" + }, + "ownerUserId": { + "type": "integer" + } + }, + "example": { + "name": "Move hosts", + "description": "All client hosts should automatically migrate to group Alpha", + "schedule": { + "type": "DAILY", + "hourOfDay": 8 + }, + "type": "User", + "ownerUserId": 123 + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "uuid", + "name", + "description", + "frequency", + "status", + "created", + "updated", + "ruleCount" + ], + "properties": { + "uuid": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "dayOfMonth": { + "type": "integer" + }, + "dayOfWeek": { + "type": "integer" + }, + "hourOfDay": { + "type": "integer" + }, + "ownerUserId": { + "type": "integer" + }, + "nextRunDatetime": { + "type": "string", + "format": "date-time" + }, + "lastRunStartDatetime": { + "type": "string", + "format": "date-time" + }, + "lastRunEndDatetime": { + "type": "string", + "format": "date-time" + }, + "lastRunStatus": { + "type": "string" + }, + "created": { + "type": "string", + "format": "date-time" + }, + "updated": { + "type": "string", + "format": "date-time" + }, + "status": { + "type": "string" + }, + "frequency": { + "type": "string" + }, + "ruleCount": { + "type": "integer" + } + } + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + } + } + } + }, + "/client/{clientId}/playbook/{playbookUuid}": { + "put": { + "summary": "Update a playbook", + "tags": [ + "playbook" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "playbookUuid", + "in": "path", + "description": "UUID of a playbook\n", + "required": true, + "type": "string" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "name", + "description", + "schedule" + ], + "properties": { + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "schedule": { + "type": "object", + "required": [ + "type", + "hourOfDay" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "DAILY", + "WEEKLY", + "MONTHLY" + ] + }, + "hourOfDay": { + "type": "integer", + "description": "0 - 23 (Required for Daily, Weekly, Monthly)" + }, + "dayOfWeek": { + "type": "integer", + "description": "1 - 7 (Required for Weekly)" + }, + "dayOfMonth": { + "type": "integer", + "description": "1 - 31 (Required for Monthly)" + } + } + }, + "type": { + "type": "string" + }, + "ownerUserId": { + "type": "integer" + } + }, + "example": { + "name": "Move hosts", + "description": "All client hosts should automatically migrate to group Alpha", + "schedule": { + "type": "DAILY", + "hourOfDay": 8 + }, + "type": "User", + "ownerUserId": 123 + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "uuid", + "name", + "description", + "frequency", + "status", + "created", + "updated", + "ruleCount" + ], + "properties": { + "uuid": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "dayOfMonth": { + "type": "integer" + }, + "dayOfWeek": { + "type": "integer" + }, + "hourOfDay": { + "type": "integer" + }, + "ownerUserId": { + "type": "integer" + }, + "nextRunDatetime": { + "type": "string", + "format": "date-time" + }, + "lastRunStartDatetime": { + "type": "string", + "format": "date-time" + }, + "lastRunEndDatetime": { + "type": "string", + "format": "date-time" + }, + "lastRunStatus": { + "type": "string" + }, + "created": { + "type": "string", + "format": "date-time" + }, + "updated": { + "type": "string", + "format": "date-time" + }, + "status": { + "type": "string" + }, + "frequency": { + "type": "string" + }, + "ruleCount": { + "type": "integer" + } + } + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + } + } + }, + "delete": { + "summary": "Delete a playbook", + "tags": [ + "playbook" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "playbookUuid", + "in": "path", + "description": "UUID of a playbook\n", + "required": true, + "type": "string" + } + ], + "responses": { + "204": { + "description": "Request was processed without errors" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + }, + "get": { + "summary": "Fetch playbook details", + "tags": [ + "playbook" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "playbookUuid", + "in": "path", + "description": "UUID of a playbook\n", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "properties": { + "uuid": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "schedule": { + "type": "object", + "required": [ + "type", + "enabled", + "hourOfDay" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "DAILY", + "WEEKLY", + "MONTHLY" + ] + }, + "enabled": { + "type": "boolean" + }, + "hourOfDay": { + "type": "integer", + "description": "0 - 23 (Required for Daily, Weekly, Monthly)" + }, + "dayOfWeek": { + "type": "integer", + "description": "1 - 7 (Required for Weekly)" + }, + "dayOfMonth": { + "type": "integer", + "description": "1 - 31 (Required for Monthly)" + } + } + }, + "lastStatusUpdatedDatetime": { + "type": "string", + "format": "date-time" + }, + "activatedDatetime": { + "type": "string", + "format": "date-time" + }, + "nextRunDatetime": { + "type": "string", + "format": "date-time" + }, + "creator": { + "type": "string" + }, + "lastModifiedBy": { + "type": "string" + }, + "created": { + "type": "string", + "format": "date-time" + }, + "updated": { + "type": "string", + "format": "date-time" + }, + "status": { + "type": "string" + }, + "lastRunStartTime": { + "type": "string", + "format": "date-time" + }, + "lastRunEndTime": { + "type": "string", + "format": "date-time" + }, + "lastRunSuccess": { + "type": "boolean" + }, + "timeDeferredMs": { + "type": "integer" + }, + "ruleCount": { + "type": "integer" + }, + "totalRuns": { + "type": "integer" + }, + "totalPassed": { + "type": "integer" + }, + "totalFailed": { + "type": "integer" + }, + "averageRunTimeSeconds": { + "type": "integer" + }, + "lastRunRuleExecutions": { + "type": "array", + "items": { + "type": "object", + "properties": { + "ruleName": { + "type": "string" + }, + "ruleUuid": { + "type": "string" + }, + "jobSummary": { + "type": "object", + "properties": { + "job": { + "type": "string" + }, + "timeQueuedMs": { + "type": "integer" + }, + "startTime": { + "type": "string", + "format": "date-time" + }, + "completionTime": { + "type": "string", + "format": "date-time" + }, + "succeeded": { + "type": "boolean" + }, + "targetedActions": { + "type": "integer" + }, + "targetedActionsPassed": { + "type": "integer" + }, + "targetedActionsFailed": { + "type": "integer" + } + } + } + } + } + } + } + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + } + } + } + }, + "/client/{clientId}/playbook/{playbookUuid}/rule": { + "post": { + "summary": "Save a rule for an already existing playbook", + "description": "

If you would like to upload a file associated with your rule, then use the other rule save endpoint:\n \"/client/{clientId}/playbook/{playbookUuid}/rule/with-files\"\n

\n", + "tags": [ + "playbook" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "playbookUuid", + "in": "path", + "description": "UUID of a playbook\n", + "required": true, + "type": "string" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "name", + "description", + "input", + "actionType", + "action", + "outputType", + "output" + ], + "properties": { + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "input": { + "type": "string", + "enum": [ + "HOST", + "HOST_FINDING", + "APPLICATION", + "APPLICATION_FINDING" + ] + }, + "actionType": { + "type": "string", + "enum": [ + "GROUP_MOVE", + "SEVERITY_CHANGE" + ] + }, + "action": { + "type": "object", + "description": "

Structure is dependent on the action type field.\nThe referenced structures can be found at the bottom of this document.

\n
    \n
  • ASSIGNMENT: PlaybookActionConfig_AssignUnassign
  • \n
  • UNASSIGNMENT: PlaybookActionConfig_AssignUnassign
  • \n
  • DUE_DATE_EXPLICIT: PlaybookActionConfig_Due_Date_EXPLICIT
  • \n
  • DUE_DATE_OFFSET: PlaybookActionConfig_Due_Date_OFFSET
  • \n
  • DUE_DATE_REMOVE: PlaybookActionConfig_Due_Date_REMOVE
  • \n
  • SEVERITY_CHANGE: PlaybookActionConfig_Severity_Change
  • \n
  • TAG_APPLY: PlaybookActionConfig_TagApplyUnapply
  • \n
  • TAG_UNAPPLY: PlaybookActionConfig_TagApplyUnapply
  • \n
  • ADD_TO_GROUP: PlaybookActionConfig_AddToGroup
  • \n
  • REMOVE_FROM_GROUP: PlaybookActionConfig_RemoveFromGroup
  • \n
  • UPDATE_BUSINESS_CRITICALITY: PlaybookActionConfig_AssetUpdate
  • \n
  • UPDATE_IP_ADDRESS_TYPE: PlaybookActionConfig_AssetUpdate
  • \n
  • REMEDIATION_SLA: PlaybookActionConfig_AssetUpdate
  • \n
\n" + }, + "outputType": { + "type": "string", + "enum": [ + "EMAIL", + "NO_OUTPUT", + "WEBHOOK" + ] + }, + "output": { + "type": "object", + "description": "

Structure is dependent on the output type field.\nThe referenced structures can be found at the bottom of this document.

\n
    \n
  • EMAIL: PlaybookOutputConfig_Email
  • \n
\n" + } + }, + "example": { + "name": "Example Rule", + "description": "This rule will add hosts with IDs 1, 2, 3 to the group with ID 42", + "input": "HOST", + "actionType": "ADD_TO_GROUP", + "action": { + "targetGroupIds": [ + 42 + ], + "filterRequest": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3" + } + ] + } + }, + "outputType": "EMAIL", + "output": { + "targetUsernames": [ + "firstLastUsername" + ], + "subject": "New set of hosts moved to group alpha", + "message": "Here to inform you the group move completed.", + "includeOperationalSummary": true + } + } + } + } + ], + "responses": { + "204": { + "description": "Success" + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/playbook/{playbookUuid}/rule/with-files": { + "post": { + "summary": "Save a rule for an already existing playbook with files", + "description": "

The rule must be serialize as a string and sent in a form field. An example of a deserialized rule\nstructure is at the bottom of this document under \"PlaybookRuleDeserialized\".

\n", + "tags": [ + "playbook" + ], + "consumes": [ + "multipart/form-data" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "playbookUuid", + "in": "path", + "description": "UUID of a playbook\n", + "required": true, + "type": "string" + }, + { + "in": "formData", + "name": "files", + "type": "file", + "required": false, + "description": "The file associated with this rule, may not always be applicable" + }, + { + "in": "formData", + "name": "serializedPlaybookRule", + "type": "string", + "required": true, + "description": "The stringified playbook rule JSON" + } + ], + "responses": { + "204": { + "description": "Success" + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/playbook/{playbookUuid}/rule-reorder": { + "put": { + "summary": "Reorder playbook rules for an already existing playbook", + "tags": [ + "playbook" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "playbookUuid", + "in": "path", + "description": "UUID of a playbook\n", + "required": true, + "type": "string" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "ruleUuids" + ], + "properties": { + "ruleUuids": { + "type": "array", + "items": { + "type": "string", + "description": "Rule UUID" + } + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "description": "An array of all rules associated with the given playbook after inserting the new rules.", + "type": "array", + "items": { + "type": "object", + "required": [ + "uuid", + "name", + "description", + "priority", + "input", + "filter", + "actionId", + "detailInfo", + "actionConfig", + "outputConfig" + ], + "properties": { + "uuid": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "priority": { + "type": "integer" + }, + "input": { + "type": "string" + }, + "filter": { + "type": "string" + }, + "actionId": { + "type": "string" + }, + "actionName": { + "type": "string" + }, + "actionConfig": { + "type": "string" + }, + "detailInfo": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "outputConfig": { + "type": "string" + }, + "files": { + "type": "array" + } + } + } + } + }, + "400": { + "description": "User error", + "schema": { + "description": "Bad Request" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "description": "Unauthorized" + } + }, + "404": { + "description": "Not Found", + "schema": { + "description": "Not Found" + } + } + } + } + }, + "/client/{clientId}/playbook/rule/{playbookRuleUuid}": { + "put": { + "summary": "Update a playbook rule", + "tags": [ + "playbook" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "playbookRuleUuid", + "in": "path", + "description": "UUID of a rule\n", + "required": true, + "type": "string" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "name", + "description", + "input", + "actionType", + "action", + "outputType", + "output" + ], + "properties": { + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "input": { + "type": "string", + "enum": [ + "HOST", + "HOST_FINDING", + "APPLICATION", + "APPLICATION_FINDING" + ] + }, + "actionType": { + "type": "string", + "enum": [ + "GROUP_MOVE", + "SEVERITY_CHANGE" + ] + }, + "action": { + "type": "object", + "description": "

Structure is dependent on the action type field.\nThe referenced structures can be found at the bottom of this document.

\n
    \n
  • ASSIGNMENT: PlaybookActionConfig_AssignUnassign
  • \n
  • UNASSIGNMENT: PlaybookActionConfig_AssignUnassign
  • \n
  • DUE_DATE_EXPLICIT: PlaybookActionConfig_Due_Date_EXPLICIT
  • \n
  • DUE_DATE_OFFSET: PlaybookActionConfig_Due_Date_OFFSET
  • \n
  • DUE_DATE_REMOVE: PlaybookActionConfig_Due_Date_REMOVE
  • \n
  • SEVERITY_CHANGE: PlaybookActionConfig_Severity_Change
  • \n
  • TAG_APPLY: PlaybookActionConfig_TagApplyUnapply
  • \n
  • TAG_UNAPPLY: PlaybookActionConfig_TagApplyUnapply
  • \n
  • ADD_TO_GROUP: PlaybookActionConfig_AddToGroup
  • \n
  • REMOVE_FROM_GROUP: PlaybookActionConfig_RemoveFromGroup
  • \n
  • UPDATE_BUSINESS_CRITICALITY: PlaybookActionConfig_AssetUpdate
  • \n
  • UPDATE_IP_ADDRESS_TYPE: PlaybookActionConfig_AssetUpdate
  • \n
  • REMEDIATION_SLA: PlaybookActionConfig_AssetUpdate
  • \n
\n" + }, + "outputType": { + "type": "string", + "enum": [ + "EMAIL", + "NO_OUTPUT", + "WEBHOOK" + ] + }, + "output": { + "type": "object", + "description": "

Structure is dependent on the output type field.\nThe referenced structures can be found at the bottom of this document.

\n
    \n
  • EMAIL: PlaybookOutputConfig_Email
  • \n
\n" + } + }, + "example": { + "name": "Example Rule", + "description": "This rule will add hosts with IDs 1, 2, 3 to the group with ID 42", + "input": "HOST", + "actionType": "ADD_TO_GROUP", + "action": { + "targetGroupIds": [ + 42 + ], + "filterRequest": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3" + } + ] + } + }, + "outputType": "EMAIL", + "output": { + "targetUsernames": [ + "firstLastUsername" + ], + "subject": "New set of hosts moved to group alpha", + "message": "Here to inform you the group move completed.", + "includeOperationalSummary": true + } + } + } + } + ], + "responses": { + "200": { + "description": "Request was processed without errors" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + }, + "delete": { + "summary": "Delete a playbook rule", + "tags": [ + "playbook" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "playbookRuleUuid", + "in": "path", + "description": "UUID of a rule\n", + "required": true, + "type": "string" + } + ], + "responses": { + "204": { + "description": "Request was processed without errors" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + }, + "get": { + "summary": "Fetch a specified playbook rule", + "tags": [ + "playbook" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "playbookRuleUuid", + "in": "path", + "description": "UUID of a rule\n", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "uuid", + "name", + "description", + "priority", + "input", + "filter", + "actionId", + "detailInfo", + "actionConfig", + "outputConfig" + ], + "properties": { + "uuid": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "priority": { + "type": "integer" + }, + "input": { + "type": "string" + }, + "filter": { + "type": "string" + }, + "actionId": { + "type": "string" + }, + "actionName": { + "type": "string" + }, + "actionConfig": { + "type": "string" + }, + "detailInfo": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "outputConfig": { + "type": "string" + }, + "files": { + "type": "array" + } + } + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + } + } + } + }, + "/client/{clientId}/playbook/rule/{playbookRuleUuid}/file/{fileUuid}": { + "delete": { + "summary": "delete a file from a playbook rule", + "tags": [ + "playbook" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "playbookRuleUuid", + "in": "path", + "description": "UUID of a rule\n", + "required": true, + "type": "string" + }, + { + "name": "fileUuid", + "in": "path", + "description": "UUID of a rule file\n", + "required": true, + "type": "string" + } + ], + "responses": { + "204": { + "description": "Request was processed without errors" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + }, + "get": { + "summary": "Download an attachment", + "tags": [ + "playbook" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "playbookRuleUuid", + "in": "path", + "description": "UUID of a rule\n", + "required": true, + "type": "string" + }, + { + "name": "fileUuid", + "in": "path", + "description": "UUID of a rule file\n", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "description": "Ok" + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/playbook/rule/{playbookRuleUuid}/file": { + "post": { + "summary": "Attach files to a playbook rule", + "tags": [ + "playbook" + ], + "consumes": [ + "multipart/form-data" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "playbookRuleUuid", + "in": "path", + "description": "UUID of a rule\n", + "required": true, + "type": "string" + }, + { + "in": "formData", + "name": "files", + "type": "file", + "required": false, + "description": "The file(s) to associate with this rule" + } + ], + "responses": { + "204": { + "description": "Success" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/playbook/toggle-enabled": { + "put": { + "summary": "Enable/disable a set of playbooks", + "tags": [ + "playbook" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "playbookUuids", + "enabled" + ], + "properties": { + "playbookUuids": { + "type": "array", + "items": { + "type": "string" + } + }, + "enabled": { + "type": "boolean" + } + }, + "example": { + "playbookUuids": [ + "11e9a804-8b43-3b13-9d62-0242c0a88007", + "c269a9c4-a804-11e9-a2a3-2a2ae2dbcce4", + "2021e64b-69a3-46b8-85ee-32004af00619" + ], + "enabled": false + } + } + } + ], + "responses": { + "200": { + "description": "Success" + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + } + } + } + }, + "/client/{clientId}/playbook/{playbookUuid}/run": { + "get": { + "summary": "Manually start a playbook and its associated rules", + "tags": [ + "playbook" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "playbookUuid", + "in": "path", + "description": "UUID of a playbook\n", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "uuid", + "name", + "description", + "frequency", + "status", + "created", + "updated", + "ruleCount" + ], + "properties": { + "uuid": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "dayOfMonth": { + "type": "integer" + }, + "dayOfWeek": { + "type": "integer" + }, + "hourOfDay": { + "type": "integer" + }, + "ownerUserId": { + "type": "integer" + }, + "nextRunDatetime": { + "type": "string", + "format": "date-time" + }, + "lastRunStartDatetime": { + "type": "string", + "format": "date-time" + }, + "lastRunEndDatetime": { + "type": "string", + "format": "date-time" + }, + "lastRunStatus": { + "type": "string" + }, + "created": { + "type": "string", + "format": "date-time" + }, + "updated": { + "type": "string", + "format": "date-time" + }, + "status": { + "type": "string" + }, + "frequency": { + "type": "string" + }, + "ruleCount": { + "type": "integer" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/sla": { + "post": { + "summary": "Create a sla without any rules", + "tags": [ + "sla" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "name", + "description", + "schedule", + "type" + ], + "properties": { + "name": { + "type": "string", + "description": "Name should be 'Remediation SLAs'", + "enum": [ + "Remediation SLAs" + ] + }, + "description": { + "type": "string" + }, + "schedule": { + "type": "object", + "required": [ + "type", + "hourOfDay" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "DAILY", + "WEEKLY", + "MONTHLY" + ] + }, + "hourOfDay": { + "type": "integer", + "description": "0 - 23 (Required for Daily, Weekly, Monthly)" + }, + "dayOfWeek": { + "type": "integer", + "description": "1 - 7 (Required for Weekly)" + }, + "dayOfMonth": { + "type": "integer", + "description": "1 - 31 (Required for Monthly)" + } + }, + "description": "The set schedule has no bearing on when SLA runs as it instead is trigger based." + }, + "type": { + "type": "string" + } + }, + "example": { + "name": "Remediation SLAs", + "description": "Remediation SLA for default and group specific SLA rules.", + "schedule": { + "type": "DAILY", + "hourOfDay": 8 + }, + "type": "System" + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "uuid", + "name", + "description", + "frequency", + "status", + "created", + "updated", + "ruleCount" + ], + "properties": { + "uuid": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "dayOfMonth": { + "type": "integer" + }, + "dayOfWeek": { + "type": "integer" + }, + "hourOfDay": { + "type": "integer" + }, + "ownerUserId": { + "type": "integer" + }, + "nextRunDatetime": { + "type": "string", + "format": "date-time" + }, + "lastRunStartDatetime": { + "type": "string", + "format": "date-time" + }, + "lastRunEndDatetime": { + "type": "string", + "format": "date-time" + }, + "lastRunStatus": { + "type": "string" + }, + "created": { + "type": "string", + "format": "date-time" + }, + "updated": { + "type": "string", + "format": "date-time" + }, + "status": { + "type": "string" + }, + "frequency": { + "type": "string" + }, + "ruleCount": { + "type": "integer" + } + } + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + } + } + } + }, + "/client/{clientId}/sla/fetch": { + "get": { + "summary": "Fetch all SLAs for a client", + "tags": [ + "sla" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "size", + "in": "query", + "description": "Size of the page requested", + "required": false, + "type": "integer" + }, + { + "name": "page", + "in": "query", + "description": "Page number being requested (first page: 0)", + "required": false, + "type": "integer" + }, + { + "name": "sort", + "in": "query", + "description": "field to sort by and direction", + "required": false, + "type": "string" + }, + { + "name": "sText", + "in": "query", + "description": "search string to apply", + "required": false, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "content", + "last", + "totalElements", + "totalPages", + "sort", + "numberOfElements", + "first", + "size", + "number" + ], + "properties": { + "content": { + "type": "array", + "items": { + "type": "object", + "required": [ + "uuid", + "name", + "description", + "frequency", + "status", + "created", + "updated", + "ruleCount" + ], + "properties": { + "uuid": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "dayOfMonth": { + "type": "integer" + }, + "dayOfWeek": { + "type": "integer" + }, + "hourOfDay": { + "type": "integer" + }, + "ownerUserId": { + "type": "integer" + }, + "nextRunDatetime": { + "type": "string", + "format": "date-time" + }, + "lastRunStartDatetime": { + "type": "string", + "format": "date-time" + }, + "lastRunEndDatetime": { + "type": "string", + "format": "date-time" + }, + "lastRunStatus": { + "type": "string" + }, + "created": { + "type": "string", + "format": "date-time" + }, + "updated": { + "type": "string", + "format": "date-time" + }, + "status": { + "type": "string" + }, + "frequency": { + "type": "string" + }, + "ruleCount": { + "type": "integer" + } + } + } + }, + "last": { + "type": "boolean" + }, + "totalElements": { + "type": "integer" + }, + "totalPages": { + "type": "integer" + }, + "sort": { + "type": "string" + }, + "numberOfElements": { + "type": "integer" + }, + "first": { + "type": "boolean" + }, + "size": { + "type": "integer" + }, + "number": { + "type": "integer" + } + } + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + } + } + } + }, + "/client/{clientId}/sla/fetch/{playbookUuid}": { + "get": { + "summary": "Fetch a specified SLA", + "tags": [ + "sla" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "playbookUuid", + "in": "path", + "description": "UUID of a playbook\n", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "uuid", + "name", + "description", + "frequency", + "status", + "created", + "updated", + "ruleCount" + ], + "properties": { + "uuid": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "dayOfMonth": { + "type": "integer" + }, + "dayOfWeek": { + "type": "integer" + }, + "hourOfDay": { + "type": "integer" + }, + "ownerUserId": { + "type": "integer" + }, + "nextRunDatetime": { + "type": "string", + "format": "date-time" + }, + "lastRunStartDatetime": { + "type": "string", + "format": "date-time" + }, + "lastRunEndDatetime": { + "type": "string", + "format": "date-time" + }, + "lastRunStatus": { + "type": "string" + }, + "created": { + "type": "string", + "format": "date-time" + }, + "updated": { + "type": "string", + "format": "date-time" + }, + "status": { + "type": "string" + }, + "frequency": { + "type": "string" + }, + "ruleCount": { + "type": "integer" + } + } + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + } + } + } + }, + "/client/{clientId}/sla/{playbookUuid}": { + "put": { + "summary": "Update a sla", + "tags": [ + "sla" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "playbookUuid", + "in": "path", + "description": "UUID of a playbook\n", + "required": true, + "type": "string" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "name", + "description", + "schedule", + "type" + ], + "properties": { + "name": { + "type": "string", + "description": "Name should be 'Remediation SLAs'", + "enum": [ + "Remediation SLAs" + ] + }, + "description": { + "type": "string" + }, + "schedule": { + "type": "object", + "required": [ + "type", + "hourOfDay" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "DAILY", + "WEEKLY", + "MONTHLY" + ] + }, + "hourOfDay": { + "type": "integer", + "description": "0 - 23 (Required for Daily, Weekly, Monthly)" + }, + "dayOfWeek": { + "type": "integer", + "description": "1 - 7 (Required for Weekly)" + }, + "dayOfMonth": { + "type": "integer", + "description": "1 - 31 (Required for Monthly)" + } + }, + "description": "The set schedule has no bearing on when SLA runs as it instead is trigger based." + }, + "type": { + "type": "string" + } + }, + "example": { + "name": "Remediation SLAs", + "description": "Remediation SLA for default and group specific SLA rules.", + "schedule": { + "type": "DAILY", + "hourOfDay": 8 + }, + "type": "System" + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "uuid", + "name", + "description", + "frequency", + "status", + "created", + "updated", + "ruleCount" + ], + "properties": { + "uuid": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "dayOfMonth": { + "type": "integer" + }, + "dayOfWeek": { + "type": "integer" + }, + "hourOfDay": { + "type": "integer" + }, + "ownerUserId": { + "type": "integer" + }, + "nextRunDatetime": { + "type": "string", + "format": "date-time" + }, + "lastRunStartDatetime": { + "type": "string", + "format": "date-time" + }, + "lastRunEndDatetime": { + "type": "string", + "format": "date-time" + }, + "lastRunStatus": { + "type": "string" + }, + "created": { + "type": "string", + "format": "date-time" + }, + "updated": { + "type": "string", + "format": "date-time" + }, + "status": { + "type": "string" + }, + "frequency": { + "type": "string" + }, + "ruleCount": { + "type": "integer" + } + } + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + } + } + }, + "delete": { + "summary": "Delete a sla", + "tags": [ + "sla" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "playbookUuid", + "in": "path", + "description": "UUID of a playbook\n", + "required": true, + "type": "string" + } + ], + "responses": { + "204": { + "description": "Request was processed without errors" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + }, + "get": { + "summary": "Fetch sla details", + "tags": [ + "sla" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "playbookUuid", + "in": "path", + "description": "UUID of a playbook\n", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "properties": { + "uuid": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "schedule": { + "type": "object", + "required": [ + "type", + "enabled", + "hourOfDay" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "DAILY", + "WEEKLY", + "MONTHLY" + ] + }, + "enabled": { + "type": "boolean" + }, + "hourOfDay": { + "type": "integer", + "description": "0 - 23 (Required for Daily, Weekly, Monthly)" + }, + "dayOfWeek": { + "type": "integer", + "description": "1 - 7 (Required for Weekly)" + }, + "dayOfMonth": { + "type": "integer", + "description": "1 - 31 (Required for Monthly)" + } + } + }, + "lastStatusUpdatedDatetime": { + "type": "string", + "format": "date-time" + }, + "activatedDatetime": { + "type": "string", + "format": "date-time" + }, + "nextRunDatetime": { + "type": "string", + "format": "date-time" + }, + "creator": { + "type": "string" + }, + "lastModifiedBy": { + "type": "string" + }, + "created": { + "type": "string", + "format": "date-time" + }, + "updated": { + "type": "string", + "format": "date-time" + }, + "status": { + "type": "string" + }, + "lastRunStartTime": { + "type": "string", + "format": "date-time" + }, + "lastRunEndTime": { + "type": "string", + "format": "date-time" + }, + "lastRunSuccess": { + "type": "boolean" + }, + "timeDeferredMs": { + "type": "integer" + }, + "ruleCount": { + "type": "integer" + }, + "totalRuns": { + "type": "integer" + }, + "totalPassed": { + "type": "integer" + }, + "totalFailed": { + "type": "integer" + }, + "averageRunTimeSeconds": { + "type": "integer" + }, + "lastRunRuleExecutions": { + "type": "array", + "items": { + "type": "object", + "properties": { + "ruleName": { + "type": "string" + }, + "ruleUuid": { + "type": "string" + }, + "jobSummary": { + "type": "object", + "properties": { + "job": { + "type": "string" + }, + "timeQueuedMs": { + "type": "integer" + }, + "startTime": { + "type": "string", + "format": "date-time" + }, + "completionTime": { + "type": "string", + "format": "date-time" + }, + "succeeded": { + "type": "boolean" + }, + "targetedActions": { + "type": "integer" + }, + "targetedActionsPassed": { + "type": "integer" + }, + "targetedActionsFailed": { + "type": "integer" + } + } + } + } + } + } + } + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + } + } + } + }, + "/client/{clientId}/sla/{playbookUuid}/rule": { + "post": { + "summary": "Save a rule for an already existing sla", + "tags": [ + "sla" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "playbookUuid", + "in": "path", + "description": "UUID of a playbook\n", + "required": true, + "type": "string" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "name", + "description", + "input", + "actionType", + "action", + "outputType", + "output" + ], + "properties": { + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "input": { + "type": "object", + "enum": [ + "DISCOVERED_DATE", + "INGESTION_DATE" + ] + }, + "actionType": { + "type": "string", + "enum": [ + "REMEDIATION_SLA" + ] + }, + "action": { + "type": "object", + "required": [ + "isDefaultSLA", + "targetGroupIds", + "timeReference", + "serviceLevelAgreementMatrix", + "slaMatrixProfileType", + "offsetBasis", + "affectOnlyNewFindings", + "updateSLAIfVRRUpdates" + ], + "properties": { + "isDefaultSLA": { + "type": "boolean" + }, + "targetGroupIds": { + "type": "array", + "items": { + "type": "integer" + }, + "description": "

If `isDefaultSLA` = true leave this empty.

\n" + }, + "timeReference": { + "type": "string", + "enum": [ + "DISCOVERED_DATE", + "INGESTION_DATE", + "ASSIGNED_ON" + ] + }, + "serviceLevelAgreementMatrix": { + "type": "object", + "additionalProperties": { + "type": "object", + "properties": { + "criticality": { + "type": "string", + "description": "A number between 1 and 5" + }, + "chmliOffset": { + "type": "array", + "items": { + "type": "integer" + }, + "description": "An array of 5 numbers mapping to the desired offset for findings that are in CHMLI buckets; array order corresponds to CHMLI left to right." + } + } + } + }, + "slaMatrixProfileType": { + "type": "string", + "enum": [ + "STANDARD", + "ACCELERATED", + "AGGRESSIVE", + "CUSTOM" + ] + }, + "offsetBasis": { + "type": "string", + "enum": [ + "SEVERITY", + "VRR" + ] + }, + "affectOnlyNewFindings": { + "type": "boolean" + }, + "updateSLAIfVRRUpdates": { + "type": "boolean" + } + } + }, + "outputType": { + "type": "string", + "enum": [ + "EMAIL", + "NO_OUTPUT" + ] + }, + "output": { + "type": "object", + "description": "

Structure is dependent on the output type field.\nThe referenced structures can be found at the bottom of this document.

\n
    \n
  • EMAIL: PlaybookOutputConfig_Email
  • \n
\n" + } + }, + "example": { + "name": "Group Specific SLA One", + "description": "This group specific SLA will cover a subset of group(s).", + "input": "HOST_FINDING", + "actionType": "REMEDIATION_SLA", + "action": { + "isDefaultSLA": false, + "targetGroupIds": [ + 1, + 2, + 3 + ], + "timeReference": "INGESTION_DATE", + "serviceLevelAgreementMatrix": { + "1": [ + 15, + 15, + 45, + 45, + 0 + ], + "2": [ + 10, + 22, + 45, + 45, + 0 + ], + "3": [ + 14, + 15, + 30, + 45, + 0 + ], + "4": [ + 3, + 10, + 45, + 45, + 0 + ], + "5": [ + 3, + 14, + 15, + 45, + 0 + ] + }, + "slaMatrixProfileType": "CUSTOM", + "offsetBasis": "VRR", + "affectOnlyNewFindings": true, + "updateSLAIfVRRUpdates": true + }, + "outputType": "EMAIL", + "output": { + "targetUsernames": [ + "firstLastUsername" + ], + "subject": "New set of hosts moved to group alpha", + "message": "Here to inform you the group move completed.", + "includeOperationalSummary": true + } + } + } + } + ], + "responses": { + "204": { + "description": "Success" + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/sla/rule/{playbookRulePairingUuid}": { + "put": { + "summary": "Update a sla rule", + "tags": [ + "sla" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "playbookRulePairingUuid", + "in": "path", + "description": "Pairing UUID for host/application finding rule pair\n", + "required": true, + "type": "string" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "name", + "description", + "input", + "actionType", + "action", + "outputType", + "output" + ], + "properties": { + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "input": { + "type": "object", + "enum": [ + "DISCOVERED_DATE", + "INGESTION_DATE" + ] + }, + "actionType": { + "type": "string", + "enum": [ + "REMEDIATION_SLA" + ] + }, + "action": { + "type": "object", + "required": [ + "isDefaultSLA", + "targetGroupIds", + "timeReference", + "serviceLevelAgreementMatrix", + "slaMatrixProfileType", + "offsetBasis", + "affectOnlyNewFindings", + "updateSLAIfVRRUpdates" + ], + "properties": { + "isDefaultSLA": { + "type": "boolean" + }, + "targetGroupIds": { + "type": "array", + "items": { + "type": "integer" + }, + "description": "

If `isDefaultSLA` = true leave this empty.

\n" + }, + "timeReference": { + "type": "string", + "enum": [ + "DISCOVERED_DATE", + "INGESTION_DATE", + "ASSIGNED_ON" + ] + }, + "serviceLevelAgreementMatrix": { + "type": "object", + "additionalProperties": { + "type": "object", + "properties": { + "criticality": { + "type": "string", + "description": "A number between 1 and 5" + }, + "chmliOffset": { + "type": "array", + "items": { + "type": "integer" + }, + "description": "An array of 5 numbers mapping to the desired offset for findings that are in CHMLI buckets; array order corresponds to CHMLI left to right." + } + } + } + }, + "slaMatrixProfileType": { + "type": "string", + "enum": [ + "STANDARD", + "ACCELERATED", + "AGGRESSIVE", + "CUSTOM" + ] + }, + "offsetBasis": { + "type": "string", + "enum": [ + "SEVERITY", + "VRR" + ] + }, + "affectOnlyNewFindings": { + "type": "boolean" + }, + "updateSLAIfVRRUpdates": { + "type": "boolean" + } + } + }, + "outputType": { + "type": "string", + "enum": [ + "EMAIL", + "NO_OUTPUT" + ] + }, + "output": { + "type": "object", + "description": "

Structure is dependent on the output type field.\nThe referenced structures can be found at the bottom of this document.

\n
    \n
  • EMAIL: PlaybookOutputConfig_Email
  • \n
\n" + } + }, + "example": { + "name": "Group Specific SLA One", + "description": "This group specific SLA will cover a subset of group(s).", + "input": "HOST_FINDING", + "actionType": "REMEDIATION_SLA", + "action": { + "isDefaultSLA": false, + "targetGroupIds": [ + 1, + 2, + 3 + ], + "timeReference": "INGESTION_DATE", + "serviceLevelAgreementMatrix": { + "1": [ + 15, + 15, + 45, + 45, + 0 + ], + "2": [ + 10, + 22, + 45, + 45, + 0 + ], + "3": [ + 14, + 15, + 30, + 45, + 0 + ], + "4": [ + 3, + 10, + 45, + 45, + 0 + ], + "5": [ + 3, + 14, + 15, + 45, + 0 + ] + }, + "slaMatrixProfileType": "CUSTOM", + "offsetBasis": "VRR", + "affectOnlyNewFindings": true, + "updateSLAIfVRRUpdates": true + }, + "outputType": "EMAIL", + "output": { + "targetUsernames": [ + "firstLastUsername" + ], + "subject": "New set of hosts moved to group alpha", + "message": "Here to inform you the group move completed.", + "includeOperationalSummary": true + } + } + } + } + ], + "responses": { + "200": { + "description": "Request was processed without errors" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + }, + "delete": { + "summary": "Delete a sla rule. (Cannot delete the default SLA rule)", + "tags": [ + "sla" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "playbookRulePairingUuid", + "in": "path", + "description": "Pairing UUID for host/application finding rule pair\n", + "required": true, + "type": "string" + } + ], + "responses": { + "204": { + "description": "Request was processed without errors" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + }, + "get": { + "summary": "Fetch a specified sla rule", + "tags": [ + "sla" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "playbookRulePairingUuid", + "in": "path", + "description": "Pairing UUID for host/application finding rule pair\n", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "uuid", + "name", + "description", + "priority", + "input", + "filter", + "actionId", + "detailInfo", + "actionConfig", + "outputConfig" + ], + "properties": { + "uuid": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "priority": { + "type": "integer" + }, + "input": { + "type": "string" + }, + "filter": { + "type": "string" + }, + "actionId": { + "type": "string" + }, + "actionName": { + "type": "string" + }, + "actionConfig": { + "type": "string" + }, + "detailInfo": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "outputConfig": { + "type": "string" + }, + "files": { + "type": "array", + "items": { + "type": "string" + } + }, + "rulePairingUuid": { + "type": "string" + } + } + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + } + } + } + }, + "/client/{clientId}/sla/{playbookUuid}/rules": { + "get": { + "summary": "Fetch all rules for an sla", + "tags": [ + "sla" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "playbookUuid", + "in": "path", + "description": "UUID of a playbook\n", + "required": true, + "type": "string" + }, + { + "name": "size", + "in": "query", + "description": "Size of the page requested", + "required": false, + "type": "integer" + }, + { + "name": "page", + "in": "query", + "description": "Page number being requested (first page: 0)", + "required": false, + "type": "integer" + }, + { + "name": "sort", + "in": "query", + "description": "field to sort by and direction", + "required": false, + "type": "string" + }, + { + "name": "sText", + "in": "query", + "description": "search string to apply", + "required": false, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "content", + "last", + "totalElements", + "totalPages", + "sort", + "numberOfElements", + "first", + "size", + "number" + ], + "properties": { + "content": { + "type": "array", + "items": { + "type": "object", + "required": [ + "uuid", + "name", + "description", + "priority", + "input", + "filter", + "actionId", + "detailInfo", + "actionConfig", + "outputConfig" + ], + "properties": { + "uuid": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "priority": { + "type": "integer" + }, + "input": { + "type": "string" + }, + "filter": { + "type": "string" + }, + "actionId": { + "type": "string" + }, + "actionName": { + "type": "string" + }, + "actionConfig": { + "type": "string" + }, + "detailInfo": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "outputConfig": { + "type": "string" + }, + "files": { + "type": "array", + "items": { + "type": "string" + } + }, + "rulePairingUuid": { + "type": "string" + } + } + } + }, + "last": { + "type": "boolean" + }, + "totalElements": { + "type": "integer" + }, + "totalPages": { + "type": "integer" + }, + "sort": { + "type": "string" + }, + "numberOfElements": { + "type": "integer" + }, + "first": { + "type": "boolean" + }, + "size": { + "type": "integer" + }, + "number": { + "type": "integer" + } + } + } + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + } + } + } + }, + "/client/{clientId}/sla/toggle-enabled": { + "put": { + "summary": "Enable/disable a set of slas", + "tags": [ + "sla" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "playbookUuids", + "enabled" + ], + "properties": { + "playbookUuids": { + "type": "array", + "items": { + "type": "string" + } + }, + "enabled": { + "type": "boolean" + } + }, + "example": { + "playbookUuids": [ + "11e9a804-8b43-3b13-9d62-0242c0a88007", + "c269a9c4-a804-11e9-a2a3-2a2ae2dbcce4", + "2021e64b-69a3-46b8-85ee-32004af00619" + ], + "enabled": false + } + } + } + ], + "responses": { + "200": { + "description": "Success" + }, + "400": { + "description": "User error", + "schema": { + "type": "object", + "required": [ + "status", + "path", + "errors" + ], + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "path": { + "type": "string", + "description": "request path" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "code" + ], + "properties": { + "field": { + "type": "string", + "description": "name / path of offending field" + }, + "code": { + "type": "string", + "description": "short (usually one word) description of what is wrong with a field e.g. notFound, duplicate, length, pattern" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + } + } + } + }, + "/client/{clientId}/sla/{playbookUuid}/run": { + "get": { + "summary": "Manually start a sla and its associated rules", + "tags": [ + "sla" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "playbookUuid", + "in": "path", + "description": "UUID of a playbook\n", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "uuid", + "name", + "description", + "frequency", + "status", + "created", + "updated", + "ruleCount" + ], + "properties": { + "uuid": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "dayOfMonth": { + "type": "integer" + }, + "dayOfWeek": { + "type": "integer" + }, + "hourOfDay": { + "type": "integer" + }, + "ownerUserId": { + "type": "integer" + }, + "nextRunDatetime": { + "type": "string", + "format": "date-time" + }, + "lastRunStartDatetime": { + "type": "string", + "format": "date-time" + }, + "lastRunEndDatetime": { + "type": "string", + "format": "date-time" + }, + "lastRunStatus": { + "type": "string" + }, + "created": { + "type": "string", + "format": "date-time" + }, + "updated": { + "type": "string", + "format": "date-time" + }, + "status": { + "type": "string" + }, + "frequency": { + "type": "string" + }, + "ruleCount": { + "type": "integer" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/sla/{playbookUuid}/rule-reorder": { + "put": { + "summary": "Reorder sla rule pairs for an already existing playbook", + "tags": [ + "sla" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "playbookUuid", + "in": "path", + "description": "UUID of a playbook\n", + "required": true, + "type": "string" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "ruleUuids" + ], + "properties": { + "ruleUuids": { + "type": "array", + "items": { + "type": "string", + "description": "Rule Pairing UUID" + } + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "description": "An array of all rules associated with the given playbook after inserting the new rules.", + "type": "array", + "items": { + "type": "object", + "required": [ + "uuid", + "name", + "description", + "priority", + "input", + "filter", + "actionId", + "detailInfo", + "actionConfig", + "outputConfig" + ], + "properties": { + "uuid": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "priority": { + "type": "integer" + }, + "input": { + "type": "string" + }, + "filter": { + "type": "string" + }, + "actionId": { + "type": "string" + }, + "actionName": { + "type": "string" + }, + "actionConfig": { + "type": "string" + }, + "detailInfo": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "outputConfig": { + "type": "string" + }, + "files": { + "type": "array", + "items": { + "type": "string" + } + }, + "rulePairingUuid": { + "type": "string" + } + } + } + } + }, + "400": { + "description": "User error", + "schema": { + "description": "Bad Request" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "description": "Unauthorized" + } + }, + "404": { + "description": "Not Found", + "schema": { + "description": "Not Found" + } + } + } + } + }, + "/client/{clientId}/workflowBatch/model": { + "get": { + "summary": "List projections and their models", + "description": "List projections and their models that can be requested from the search endpoint.\n", + "tags": [ + "workflowBatch" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "object", + "properties": { + "projections": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "fields": { + "type": "array", + "items": { + "type": "object", + "properties": { + "field": { + "type": "string" + }, + "type": { + "type": "string" + }, + "nested": { + "type": "array", + "items": { + "type": "object", + "description": "Same as ProjectionField" + } + } + } + } + } + } + } + } + }, + "example": { + "projections": [ + { + "name": "basic", + "fields": [ + { + "field": "id", + "type": "integer" + }, + { + "field": "name", + "type": "string" + } + ] + } + ] + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/workflowBatch/filter": { + "get": { + "summary": "List fields that can be filtered by in the search endpoint", + "tags": [ + "workflowBatch" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "array", + "items": { + "required": [ + "name", + "uid", + "operators", + "type", + "description" + ], + "properties": { + "name": { + "type": "string" + }, + "uid": { + "type": "string", + "description": "uid used to indentify fields in suggest and search requests" + }, + "operators": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + } + }, + "datatype": { + "type": "string" + }, + "description": { + "type": "string" + } + } + }, + "example": [ + { + "name": "id", + "uid": "id", + "operator": [ + "EXACT", + "IN" + ], + "type": "integer", + "description": "The id" + } + ] + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/workflowBatch/suggest": { + "post": { + "summary": "Suggest values for filter fields", + "tags": [ + "workflowBatch" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "filter" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + }, + "description": "Filters to used to narrow down the the result set\n" + }, + "filter": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + }, + "description": "Filter for which to suggest values for. The filter value will be\ntreated as a wildcard.\n" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": true, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "filter": { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "" + } + } + } + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key", + "count" + ], + "properties": { + "key": { + "type": "string", + "description": "Value for the field the suggestion was requested for." + }, + "count": { + "type": "integer", + "format": "int64" + } + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/workflowBatch/search": { + "post": { + "summary": "Search for workflow batches", + "tags": [ + "workflowBatch" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "sort" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + }, + "projection": { + "type": "string" + }, + "sort": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "direction" + ], + "properties": { + "field": { + "type": "string" + }, + "direction": { + "type": "string", + "enum": [ + "ASC", + "DESC" + ] + } + } + } + }, + "page": { + "type": "integer" + }, + "size": { + "type": "integer" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "projection": "basic", + "sort": [ + { + "field": "id", + "direction": "ASC" + } + ], + "page": 0, + "size": 20 + } + } + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "object", + "required": [ + "_embedded", + "page" + ], + "properties": { + "_embedded": { + "type": "object", + "required": [ + "strings" + ], + "properties": { + "strings": { + "type": "array", + "items": { + "type": "object", + "description": "

The response structure is subject dependent. Subject structure\ncan be found via the subject endpoint.

\n" + } + } + } + }, + "page": { + "type": "object", + "required": [ + "size", + "totalElements", + "totalPages", + "number" + ], + "properties": { + "size": { + "type": "integer" + }, + "totalElements": { + "type": "integer" + }, + "totalPages": { + "type": "integer" + }, + "number": { + "type": "integer" + } + } + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "id", + "errorRefId", + "code", + "cause" + ], + "properties": { + "id": { + "type": "string", + "description": "Entity id which failed to be retrieved" + }, + "errorRefId": { + "type": "string", + "description": "A unique identifier for the error" + }, + "code": { + "type": "integer", + "description": "http status code of the error" + }, + "cause": { + "type": "string", + "description": "http status code message" + } + } + } + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/workflowBatch/acceptance/request": { + "post": { + "summary": "Initiate workflow batch acceptance request", + "description": "

\n

\n

\nEndpoint for creating a workflow batch acceptance request job against the\ndata outlined in the given SubjectFilterRequest\n

\n", + "tags": [ + "workflowBatch" + ], + "consumes": [ + "multipart/form-data" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "formData", + "name": "files", + "type": "file", + "required": false, + "description": "The file associated with this request" + }, + { + "in": "formData", + "name": "name", + "type": "string", + "required": true, + "description": "The workflow batch request name (i.e., custom name)" + }, + { + "in": "formData", + "name": "title", + "type": "string", + "required": false, + "description": "Deprecated, the workflow batch request title, please use 'name' field instead." + }, + { + "in": "formData", + "name": "overrideControl", + "type": "string", + "required": true, + "description": "The workflow batch scope type (NONE, AUTHORIZED, AUTOMATED). Scope type is used to specify if a batch can have its scope changed after approval." + }, + { + "in": "formData", + "name": "subjectFilterRequest", + "type": "string", + "required": true, + "description": "The stringified subject filter request" + }, + { + "in": "formData", + "name": "expirationDate", + "type": "string", + "required": true, + "description": "The expiration date in ISO-8601 format" + }, + { + "in": "formData", + "name": "description", + "type": "string", + "required": true, + "description": "the description of the request" + }, + { + "in": "formData", + "name": "reason", + "type": "string", + "required": true, + "description": "the reason of the request" + }, + { + "in": "formData", + "name": "compensatingControls", + "type": "string", + "required": true, + "description": "the compensating controls" + }, + { + "in": "formData", + "name": "isEmptyWorkflow", + "type": "boolean", + "required": true, + "description": "create this workflow batch without any finding or not" + }, + { + "in": "formData", + "name": "isAutomated", + "type": "boolean", + "required": false, + "description": "Flag for automated workflow" + }, + { + "in": "formData", + "name": "automationStopDate", + "type": "string", + "required": false, + "description": "The automation stop date in ISO-8601 format for automated workflow" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/workflowBatch/falsePositive/request": { + "post": { + "summary": "Initiate workflow batch false positive request", + "description": "

\n

\n

\nEndpoint for creating a workflow batch false positive request job against the\ndata outlined in the given SubjectFilterRequest\n

\n", + "tags": [ + "workflowBatch" + ], + "consumes": [ + "multipart/form-data" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "formData", + "name": "files", + "type": "file", + "required": false, + "description": "The file associated with this request" + }, + { + "in": "formData", + "name": "name", + "type": "string", + "required": true, + "description": "The workflow batch request name (i.e., custom name)" + }, + { + "in": "formData", + "name": "title", + "type": "string", + "required": false, + "description": "Deprecated, the workflow batch request title, please use 'name' field instead." + }, + { + "in": "formData", + "name": "overrideControl", + "type": "string", + "required": true, + "description": "The workflow batch scope type (NONE, AUTHORIZED, AUTOMATED). Scope type is used to specify if a batch can have its scope changed after approval." + }, + { + "in": "formData", + "name": "subjectFilterRequest", + "type": "string", + "required": true, + "description": "The stringified subject filter request" + }, + { + "in": "formData", + "name": "expirationDate", + "type": "string", + "required": true, + "description": "The expiration date in ISO-8601 format" + }, + { + "in": "formData", + "name": "description", + "type": "string", + "required": true, + "description": "the description of the request" + }, + { + "in": "formData", + "name": "reason", + "type": "string", + "required": true, + "description": "the reason of the request" + }, + { + "in": "formData", + "name": "isEmptyWorkflow", + "type": "boolean", + "required": true, + "description": "create this workflow batch without any finding or not" + }, + { + "in": "formData", + "name": "isAutomated", + "type": "boolean", + "required": false, + "description": "Flag for automated workflow" + }, + { + "in": "formData", + "name": "automationStopDate", + "type": "string", + "required": false, + "description": "The automation stop date in ISO-8601 format for automated workflow" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/workflowBatch/remediation/request": { + "post": { + "summary": "Initiate workflow batch remediation request", + "description": "

\n

\n

\nEndpoint for creating a workflow batch remediation request job against the\ndata outlined in the given SubjectFilterRequest\n

\n", + "tags": [ + "workflowBatch" + ], + "consumes": [ + "multipart/form-data" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "formData", + "name": "files", + "type": "file", + "required": false, + "description": "The file associated with this request" + }, + { + "in": "formData", + "name": "name", + "type": "string", + "required": true, + "description": "The workflow batch request name (i.e., custom name)" + }, + { + "in": "formData", + "name": "title", + "type": "string", + "required": false, + "description": "Deprecated, the workflow batch request title, please use 'name' field instead." + }, + { + "in": "formData", + "name": "overrideControl", + "type": "string", + "required": true, + "description": "The workflow batch scope type (NONE, AUTHORIZED). Scope type is used to specify if a batch can have its scope changed after approval." + }, + { + "in": "formData", + "name": "subjectFilterRequest", + "type": "string", + "required": true, + "description": "The stringified subject filter request" + }, + { + "in": "formData", + "name": "expirationDate", + "type": "string", + "required": false, + "description": "The expiration date in ISO-8601 format" + }, + { + "in": "formData", + "name": "description", + "type": "string", + "required": true, + "description": "the description of the request" + }, + { + "in": "formData", + "name": "reason", + "type": "string", + "required": true, + "description": "the reason of the request" + }, + { + "in": "formData", + "name": "isEmptyWorkflow", + "type": "boolean", + "required": true, + "description": "create this workflow batch without any finding or not" + }, + { + "in": "formData", + "name": "isAutomated", + "type": "boolean", + "required": false, + "description": "Flag for automated workflow" + }, + { + "in": "formData", + "name": "automationStopDate", + "type": "string", + "required": false, + "description": "The automation stop date in ISO-8601 format for automated workflow" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/workflowBatch/severityChange/request": { + "post": { + "summary": "Initiate workflow batch severity change request", + "description": "

\n

\n

\nEndpoint for creating a workflow batch severity change request job against the\ndata outlined in the given SubjectFilterRequest\n

\n", + "tags": [ + "workflowBatch" + ], + "consumes": [ + "multipart/form-data" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "formData", + "name": "files", + "type": "file", + "required": false, + "description": "The file associated with this request" + }, + { + "in": "formData", + "name": "name", + "type": "string", + "required": true, + "description": "The workflow batch request name (i.e., custom name)" + }, + { + "in": "formData", + "name": "title", + "type": "string", + "required": false, + "description": "Deprecated, the workflow batch request title, please use 'name' field instead." + }, + { + "in": "formData", + "name": "overrideControl", + "type": "string", + "required": true, + "description": "The workflow batch scope type (NONE, AUTHORIZED, AUTOMATED). Scope type is used to specify if a batch can have its scope changed after approval." + }, + { + "in": "formData", + "name": "subjectFilterRequest", + "type": "string", + "required": true, + "description": "The stringified subject filter request" + }, + { + "in": "formData", + "name": "expirationDate", + "type": "string", + "required": true, + "description": "The expiration date in ISO-8601 format" + }, + { + "in": "formData", + "name": "description", + "type": "string", + "required": true, + "description": "the description of the request" + }, + { + "in": "formData", + "name": "reason", + "type": "string", + "required": true, + "description": "the reason of the request" + }, + { + "in": "formData", + "name": "severity", + "type": "string", + "required": true, + "description": "the severity to request" + }, + { + "in": "formData", + "name": "isEmptyWorkflow", + "type": "boolean", + "required": true, + "description": "create this workflow batch without any finding or not" + }, + { + "in": "formData", + "name": "isAutomated", + "type": "boolean", + "required": false, + "description": "Flag for automated workflow" + }, + { + "in": "formData", + "name": "automationStopDate", + "type": "string", + "required": false, + "description": "The automation stop date in ISO-8601 format for automated workflow" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/workflowBatch/{workflowType}/approve": { + "post": { + "summary": "Accept workflow batch request", + "description": "

\nEndpoint for accepting a workflow batch request job against the\ndata outlined in the given FilterRequest\n

\n", + "tags": [ + "workflowBatch" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "workflowType", + "in": "path", + "description": "the type of workflow\n", + "required": true, + "type": "string", + "enum": [ + "acceptance", + "falsePositive", + "severityChange", + "remediation" + ] + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "workflowBatchUuid", + "overrideExpirationDate" + ], + "properties": { + "workflowBatchUuid": { + "description": "The UUID for the workflow batch to be accepted.", + "type": "string" + }, + "expirationDate": { + "description": "The proposed expiration date of the acceptance", + "type": "string" + }, + "overrideExpirationDate": { + "description": "True/False if new expiration date overrides the previously recommended date", + "type": "boolean" + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/workflowBatch/{workflowType}/rework": { + "post": { + "summary": "Rework worflow request", + "description": "

\nEndpoint for creating a workflow batch rework request job against the\ndata outlined in the given FilterRequest\n

\n", + "tags": [ + "workflowBatch" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "workflowType", + "in": "path", + "description": "the type of workflow\n", + "required": true, + "type": "string", + "enum": [ + "acceptance", + "falsePositive", + "severityChange", + "remediation" + ] + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "workflowBatchUuid", + "description" + ], + "properties": { + "workflowBatchUuid": { + "description": "The UUID for the workflow batch to be accepted.", + "type": "string" + }, + "description": { + "type": "string" + } + } + } + } + ], + "responses": { + "201": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/workflowBatch/{workflowType}/reject": { + "post": { + "summary": "Request to reject workflow batch", + "description": "

\nEndpoint for creating a workflow batch reject job against the data outlined in the given FilterRequest.\n

\n", + "tags": [ + "workflowBatch" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "workflowType", + "in": "path", + "description": "the type of workflow\n", + "required": true, + "type": "string", + "enum": [ + "acceptance", + "falsePositive", + "severityChange", + "remediation" + ] + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "workflowBatchUuid", + "description" + ], + "properties": { + "workflowBatchUuid": { + "description": "The UUID for the workflow batch to be accepted.", + "type": "string" + }, + "description": { + "type": "string" + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/workflowBatch/{workflowType}/update": { + "post": { + "summary": "Update workflow batch property", + "description": "

\n

\n

\nUpdate a Reworked or Requested workflow batch name, description, expiration date and severity using its UUID.\n

\n", + "tags": [ + "workflowBatch" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "workflowType", + "in": "path", + "description": "the type of workflow\n", + "required": true, + "type": "string", + "enum": [ + "acceptance", + "falsePositive", + "severityChange", + "remediation" + ] + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "workflowBatchUuid" + ], + "properties": { + "workflowBatchUuid": { + "type": "string" + }, + "expirationDate": { + "type": "string", + "format": "date" + }, + "description": { + "type": "string" + }, + "name": { + "type": "string" + }, + "severity": { + "type": "number", + "format": "double" + }, + "overrideControl": { + "type": "string", + "enum": [ + "NONE", + "AUTHORIZED" + ] + }, + "compensatingControl": { + "type": "string" + }, + "reason": { + "type": "string" + }, + "automationStopDate": { + "type": "string", + "format": "date" + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "properties": { + "workflowBatchUuid": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "expiration": { + "type": "string", + "format": "date" + }, + "severity": { + "type": "number", + "format": "double" + }, + "reason": { + "type": "string" + }, + "overrideControl": { + "type": "string" + }, + "compensatingControl": { + "type": "integer" + }, + "automationStopDate": { + "type": "string", + "format": "date" + } + }, + "example": { + "workflowBatchUuid": "43a60702-89b5-11ea-bc61-0242ac17000b", + "name": "Updated workflow name", + "description": "Updated workflow description", + "expiration": "2020-08-01", + "severity": 9.9, + "reason": "Updated reason", + "overrideControl": "AUTHORIZED", + "compensatingControl": 1, + "automationStopDate": "2020-08-01" + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/workflowBatch/{workflowType}/{workflowBatchUuid}/map": { + "post": { + "summary": "Map findings to the workflow batch", + "description": "

\nEndpoint for adding one or more findings to a workflow batch with the given subject filter request.\n

\n", + "tags": [ + "workflowBatch" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "workflowType", + "in": "path", + "description": "the type of workflow\n", + "required": true, + "type": "string", + "enum": [ + "acceptance", + "falsePositive", + "severityChange", + "remediation" + ] + }, + { + "name": "workflowBatchUuid", + "in": "path", + "description": "UUID of workflow batch\n", + "required": true, + "type": "string" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "subject", + "filterRequest" + ], + "properties": { + "subject": { + "type": "string" + }, + "filterRequest": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "sort" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + }, + "projection": { + "type": "string" + }, + "sort": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "direction" + ], + "properties": { + "field": { + "type": "string" + }, + "direction": { + "type": "string", + "enum": [ + "ASC", + "DESC" + ] + } + } + } + }, + "page": { + "type": "integer" + }, + "size": { + "type": "integer" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "projection": "basic", + "sort": [ + { + "field": "id", + "direction": "ASC" + } + ], + "page": 0, + "size": 20 + } + } + }, + "example": { + "subject": "hostFinding", + "filterRequest": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "projection": "basic", + "sort": [ + { + "field": "id", + "direction": "ASC" + } + ], + "page": 0, + "size": 20 + } + } + } + } + ], + "responses": { + "200": { + "description": "Success" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/workflowBatch/{workflowType}/{workflowBatchUuid}/unmap": { + "post": { + "summary": "Remove findings from the workflow batch", + "description": "

\nEndpoint for removing one or more findings from a workflow batch with the given subject filter request.\n

\n", + "tags": [ + "workflowBatch" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "workflowType", + "in": "path", + "description": "the type of workflow\n", + "required": true, + "type": "string", + "enum": [ + "acceptance", + "falsePositive", + "severityChange", + "remediation" + ] + }, + { + "name": "workflowBatchUuid", + "in": "path", + "description": "UUID of workflow batch\n", + "required": true, + "type": "string" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "subject", + "filterRequest" + ], + "properties": { + "subject": { + "type": "string" + }, + "filterRequest": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "sort" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + }, + "projection": { + "type": "string" + }, + "sort": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "direction" + ], + "properties": { + "field": { + "type": "string" + }, + "direction": { + "type": "string", + "enum": [ + "ASC", + "DESC" + ] + } + } + } + }, + "page": { + "type": "integer" + }, + "size": { + "type": "integer" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "projection": "basic", + "sort": [ + { + "field": "id", + "direction": "ASC" + } + ], + "page": 0, + "size": 20 + } + } + }, + "example": { + "subject": "hostFinding", + "filterRequest": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "projection": "basic", + "sort": [ + { + "field": "id", + "direction": "ASC" + } + ], + "page": 0, + "size": 20 + } + } + } + } + ], + "responses": { + "200": { + "description": "Success" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/{subject}/download/{workflowType}/{workflowCategory}/{fileUuid}": { + "get": { + "summary": "Download an attachment associated w/ a workflow batch", + "tags": [ + "workflowBatch" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "subject", + "description": "

Subject to download against. Only supports \"hostFinding\" and \"applicationFinding\"
\n", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "workflowType", + "in": "path", + "description": "the type of workflow\n", + "required": true, + "type": "string", + "enum": [ + "acceptance", + "falsePositive", + "severityChange", + "remediation" + ] + }, + { + "name": "workflowCategory", + "description": "

Workflow category to download against. Only supports \"CHANGE_REQUEST\" and \"CLOSE_REQUEST\"
\n", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "fileUuid", + "in": "path", + "description": "UUID of file attached to workflow batch\n", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "description": "Ok" + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + }, + "406": { + "description": "MIME Mismatch\nTry changing from application/octet-stream to application/json, or vice-versa." + } + } + } + }, + "/client/{clientId}/{subject}/{workflowType}/{WorkflowBatchUUID}/attachments": { + "get": { + "summary": "List attachments associated w/ a workflow batch", + "tags": [ + "workflowBatch" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "subject", + "description": "

Subject to download against. Only supports \"hostFinding\" and \"applicationFinding\"
\n", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "workflowType", + "in": "path", + "description": "the type of workflow\n", + "required": true, + "type": "string", + "enum": [ + "acceptance", + "falsePositive", + "severityChange", + "remediation" + ] + }, + { + "name": "WorkflowBatchUUID", + "in": "path", + "description": "UUID of workflow batch\n", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "description": "Ok" + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + }, + "406": { + "description": "MIME Mismatch\nTry changing from application/octet-stream to application/json, or vice-versa." + } + } + } + }, + "/client/{clientId}/workflowBatch/{workflowType}/{workflowBatchUuid}/attach": { + "post": { + "summary": "Attach the files to workflow", + "description": "

\nAttach the files to workflow and update the workflow model.\n

\n", + "tags": [ + "workflowBatch" + ], + "consumes": [ + "multipart/form-data" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "workflowType", + "in": "path", + "description": "the type of workflow\n", + "required": true, + "type": "string", + "enum": [ + "acceptance", + "falsePositive", + "severityChange", + "remediation" + ] + }, + { + "name": "workflowBatchUuid", + "in": "path", + "description": "UUID of workflow batch\n", + "required": true, + "type": "string" + }, + { + "in": "formData", + "name": "subject", + "type": "string", + "required": true, + "description": "Finding subject of the workflow" + }, + { + "in": "formData", + "name": "files", + "type": "file", + "required": true, + "description": "An attachment file" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "uuid": { + "type": "string" + }, + "filename": { + "type": "string" + } + }, + "example": { + "uuid": "43a60702-89b5-11ea-bc61-0242ac17000b", + "filename": "testworkflow.txt" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/workflowBatch/{workflowType}/{workflowBatchUuid}/detach": { + "delete": { + "summary": "Detach the files from workflow", + "description": "

\nDetach the files from workflow and update the workflow model.\n

\n", + "tags": [ + "workflowBatch" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "workflowType", + "in": "path", + "description": "the type of workflow\n", + "required": true, + "type": "string", + "enum": [ + "acceptance", + "falsePositive", + "severityChange", + "remediation" + ] + }, + { + "name": "workflowBatchUuid", + "in": "path", + "description": "UUID of workflow batch\n", + "required": true, + "type": "string" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "attachmentUuid", + "subject" + ], + "properties": { + "attachmentUuid": { + "description": "The UUID of the file that attached with workflow.", + "type": "array", + "items": { + "type": "string", + "description": "File uuid to detach." + }, + "example": [ + "43a60702-89b5-11ea-bc61-0242ac17000b", + "fba68af8-55fb-4ea7-80a6-73c18e82214c" + ] + }, + "subject": { + "description": "The finding subject that workflow associated.", + "type": "string", + "example": "hostFinding" + } + } + } + } + ], + "responses": { + "204": { + "description": "Success" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/vulnerability/model": { + "get": { + "summary": "List projections and their models", + "description": "List projections and their models that can be requested from the search endpoint.\n", + "tags": [ + "vulnerability" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "object", + "properties": { + "projections": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "fields": { + "type": "array", + "items": { + "type": "object", + "properties": { + "field": { + "type": "string" + }, + "type": { + "type": "string" + }, + "nested": { + "type": "array", + "items": { + "type": "object", + "description": "Same as ProjectionField" + } + } + } + } + } + } + } + } + }, + "example": { + "projections": [ + { + "name": "basic", + "fields": [ + { + "field": "id", + "type": "integer" + }, + { + "field": "name", + "type": "string" + } + ] + } + ] + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/vulnerability/filter": { + "get": { + "summary": "List fields that can be filtered by in the search endpoint", + "tags": [ + "vulnerability" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "array", + "items": { + "required": [ + "name", + "uid", + "operators", + "type", + "description" + ], + "properties": { + "name": { + "type": "string" + }, + "uid": { + "type": "string", + "description": "uid used to indentify fields in suggest and search requests" + }, + "operators": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + } + }, + "datatype": { + "type": "string" + }, + "description": { + "type": "string" + } + } + }, + "example": [ + { + "name": "id", + "uid": "id", + "operator": [ + "EXACT", + "IN" + ], + "type": "integer", + "description": "The id" + } + ] + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/vulnerability/suggest": { + "post": { + "summary": "Suggest values for filter fields", + "tags": [ + "vulnerability" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "filter" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + }, + "description": "Filters to used to narrow down the the result set\n" + }, + "filter": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + }, + "description": "Filter for which to suggest values for. The filter value will be\ntreated as a wildcard.\n" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": true, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "filter": { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "" + } + } + } + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key", + "count" + ], + "properties": { + "key": { + "type": "string", + "description": "Value for the field the suggestion was requested for." + }, + "count": { + "type": "integer", + "format": "int64" + } + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/vulnerability/search": { + "post": { + "summary": "Search for vulnerability", + "tags": [ + "vulnerability" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "sort" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + }, + "projection": { + "type": "string" + }, + "sort": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "direction" + ], + "properties": { + "field": { + "type": "string" + }, + "direction": { + "type": "string", + "enum": [ + "ASC", + "DESC" + ] + } + } + } + }, + "page": { + "type": "integer" + }, + "size": { + "type": "integer" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "projection": "basic", + "sort": [ + { + "field": "id", + "direction": "ASC" + } + ], + "page": 0, + "size": 20 + } + } + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "object", + "required": [ + "_embedded", + "page" + ], + "properties": { + "_embedded": { + "type": "object", + "required": [ + "strings" + ], + "properties": { + "strings": { + "type": "array", + "items": { + "type": "object", + "description": "

The response structure is subject dependent. Subject structure\ncan be found via the subject endpoint.

\n" + } + } + } + }, + "page": { + "type": "object", + "required": [ + "size", + "totalElements", + "totalPages", + "number" + ], + "properties": { + "size": { + "type": "integer" + }, + "totalElements": { + "type": "integer" + }, + "totalPages": { + "type": "integer" + }, + "number": { + "type": "integer" + } + } + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "id", + "errorRefId", + "code", + "cause" + ], + "properties": { + "id": { + "type": "string", + "description": "Entity id which failed to be retrieved" + }, + "errorRefId": { + "type": "string", + "description": "A unique identifier for the error" + }, + "code": { + "type": "integer", + "description": "http status code of the error" + }, + "cause": { + "type": "string", + "description": "http status code message" + } + } + } + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/vulnerability/export/template": { + "get": { + "summary": "List out all fields that are part of configurable export.", + "tags": [ + "vulnerability" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "object", + "required": [ + "id", + "clientId", + "userId", + "name", + "description", + "shared", + "isDefault", + "subject", + "exportableFields" + ], + "properties": { + "id": { + "description": "The id", + "type": "integer" + }, + "clientId": { + "description": "Client id", + "type": "integer" + }, + "userId": { + "description": "User id", + "type": "integer" + }, + "name": { + "description": "Template name", + "type": "string" + }, + "description": { + "description": "Template description", + "type": "string" + }, + "shared": { + "description": "Describes whether this template shared or not", + "type": "boolean" + }, + "isDefault": { + "description": "Describes whether this template is default or not", + "type": "boolean" + }, + "subject": { + "description": "For which asset to fetch fileds", + "type": "string" + }, + "exportableFields": { + "description": "List of fileds", + "type": "array", + "items": { + "type": "object", + "required": [ + "heading", + "fields" + ], + "properties": { + "heading": { + "description": "Used to set fields(asset_options/finding_options/group_options/tag_options/user_options)", + "type": "string" + }, + "fields": { + "description": "Fields which are available in exported file", + "type": "array", + "items": { + "type": "object", + "required": [ + "identifierField", + "fieldOrder", + "selected", + "sortable", + "sortOrder", + "sortType" + ], + "properties": { + "identifierField": { + "description": "Internal field which we use to identify the export field", + "type": "string" + }, + "sortable": { + "description": "Is Field Sortable", + "type": "boolean" + }, + "fieldOrder": { + "description": "Order of the export field", + "type": "integer" + }, + "selected": { + "description": "Is Field Selected", + "type": "boolean" + }, + "sortOrder": { + "description": "Sort order of the exportable fields", + "type": "integer" + }, + "sortType": { + "description": "Sort type of the exportable fields - asc/desc", + "type": "string" + } + } + } + } + } + } + } + }, + "example": { + "id": 0, + "clientId": 1, + "userId": 1, + "name": "Export-Template-Name", + "description": "Export-Template-Description", + "shared": false, + "isDefault": false, + "subject": "vulnerability", + "exportableFields": [ + { + "heading": "vulnerability_options", + "fields": [ + { + "identifierField": "name", + "displayText": "Name", + "sortable": false, + "fieldOrder": 1, + "selected": false, + "sortOrder": 0, + "sortType": "ASC" + } + ] + } + ] + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/vulnerability/export": { + "post": { + "summary": "Initiate export job", + "description": "

\nEndpoint for initiating an export job against the\ndata outlined in the given FilterRequest.\nThe Application Export Template API (/client/{clientId}/vulnerability/export/template) lists the fields that can be exported. The exportableFields section of the request body can be used to choose the fields that needs to be exported.\n

\n", + "tags": [ + "vulnerability" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filterRequest", + "fileType", + "noOfRows", + "fileName", + "exportableFields" + ], + "properties": { + "filterRequest": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + }, + "example": { + "filters": [ + { + "field": "vulnId", + "exclusive": false, + "operator": "IN", + "value": "CVE-123" + } + ] + } + }, + "fileType": { + "description": "Type of file to be exported into", + "type": "string", + "enum": [ + "JSON", + "CSV" + ] + }, + "noOfRows": { + "description": "Number of rows to be exported by default", + "type": "integer" + }, + "fileName": { + "description": "Name of the exported file", + "type": "string" + }, + "exportableFields": { + "description": "Fields included for Export", + "type": "array", + "items": { + "type": "object", + "required": [ + "heading", + "fields" + ], + "properties": { + "heading": { + "description": "Used to set fields(asset_options/finding_options/group_options/tag_options/user_options)", + "type": "string" + }, + "fields": { + "description": "Fields which are available in exported file", + "type": "array", + "items": { + "type": "object", + "required": [ + "identifierField", + "fieldOrder", + "selected", + "sortable", + "sortOrder", + "sortType" + ], + "properties": { + "identifierField": { + "description": "Internal field which we use to identify the export field", + "type": "string" + }, + "sortable": { + "description": "Is Field Sortable", + "type": "boolean" + }, + "fieldOrder": { + "description": "Order of the export field", + "type": "integer" + }, + "selected": { + "description": "Is Field Selected", + "type": "boolean" + }, + "sortOrder": { + "description": "Sort order of the exportable fields", + "type": "integer" + }, + "sortType": { + "description": "Sort type of the exportable fields - asc/desc", + "type": "string" + } + } + } + } + } + } + } + }, + "example": { + "filterRequest": { + "filters": [ + { + "field": "vulnId", + "exclusive": false, + "operator": "IN", + "value": "CVE-123" + } + ] + }, + "fileName": "TestVulnerabilityExport", + "fileType": "CSV", + "noOfRows": 5000, + "exportableFields": [ + { + "heading": "vulnerability_options", + "fields": [ + { + "identifierField": "name", + "fieldOrder": 1, + "selected": false, + "sortable": false, + "sortOrder": 0, + "sortType": "ASC" + } + ] + } + ] + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/weakness/model": { + "get": { + "summary": "List projections and their models", + "description": "List projections and their models that can be requested from the search endpoint.\n", + "tags": [ + "weakness" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "object", + "properties": { + "projections": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "fields": { + "type": "array", + "items": { + "type": "object", + "properties": { + "field": { + "type": "string" + }, + "type": { + "type": "string" + }, + "nested": { + "type": "array", + "items": { + "type": "object", + "description": "Same as ProjectionField" + } + } + } + } + } + } + } + } + }, + "example": { + "projections": [ + { + "name": "basic", + "fields": [ + { + "field": "id", + "type": "integer" + }, + { + "field": "name", + "type": "string" + } + ] + } + ] + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/weakness/filter": { + "get": { + "summary": "List fields that can be filtered by in the search endpoint", + "tags": [ + "weakness" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "array", + "items": { + "required": [ + "name", + "uid", + "operators", + "type", + "description" + ], + "properties": { + "name": { + "type": "string" + }, + "uid": { + "type": "string", + "description": "uid used to indentify fields in suggest and search requests" + }, + "operators": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + } + }, + "datatype": { + "type": "string" + }, + "description": { + "type": "string" + } + } + }, + "example": [ + { + "name": "id", + "uid": "id", + "operator": [ + "EXACT", + "IN" + ], + "type": "integer", + "description": "The id" + } + ] + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/weakness/suggest": { + "post": { + "summary": "Suggest values for filter fields", + "tags": [ + "weakness" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "filter" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + }, + "description": "Filters to used to narrow down the the result set\n" + }, + "filter": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + }, + "description": "Filter for which to suggest values for. The filter value will be\ntreated as a wildcard.\n" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": true, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "filter": { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "" + } + } + } + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key", + "count" + ], + "properties": { + "key": { + "type": "string", + "description": "Value for the field the suggestion was requested for." + }, + "count": { + "type": "integer", + "format": "int64" + } + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/weakness/search": { + "post": { + "summary": "Search for weakness", + "tags": [ + "weakness" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "sort" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + }, + "projection": { + "type": "string" + }, + "sort": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "direction" + ], + "properties": { + "field": { + "type": "string" + }, + "direction": { + "type": "string", + "enum": [ + "ASC", + "DESC" + ] + } + } + } + }, + "page": { + "type": "integer" + }, + "size": { + "type": "integer" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "projection": "basic", + "sort": [ + { + "field": "id", + "direction": "ASC" + } + ], + "page": 0, + "size": 20 + } + } + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "object", + "required": [ + "_embedded", + "page" + ], + "properties": { + "_embedded": { + "type": "object", + "required": [ + "strings" + ], + "properties": { + "strings": { + "type": "array", + "items": { + "type": "object", + "description": "

The response structure is subject dependent. Subject structure\ncan be found via the subject endpoint.

\n" + } + } + } + }, + "page": { + "type": "object", + "required": [ + "size", + "totalElements", + "totalPages", + "number" + ], + "properties": { + "size": { + "type": "integer" + }, + "totalElements": { + "type": "integer" + }, + "totalPages": { + "type": "integer" + }, + "number": { + "type": "integer" + } + } + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "id", + "errorRefId", + "code", + "cause" + ], + "properties": { + "id": { + "type": "string", + "description": "Entity id which failed to be retrieved" + }, + "errorRefId": { + "type": "string", + "description": "A unique identifier for the error" + }, + "code": { + "type": "integer", + "description": "http status code of the error" + }, + "cause": { + "type": "string", + "description": "http status code message" + } + } + } + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/weakness/export/template": { + "get": { + "summary": "List out all fields that are part of configurable export.", + "tags": [ + "weakness" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "object", + "required": [ + "id", + "clientId", + "userId", + "name", + "description", + "shared", + "isDefault", + "subject", + "exportableFields" + ], + "properties": { + "id": { + "description": "The id", + "type": "integer" + }, + "clientId": { + "description": "Client id", + "type": "integer" + }, + "userId": { + "description": "User id", + "type": "integer" + }, + "name": { + "description": "Template name", + "type": "string" + }, + "description": { + "description": "Template description", + "type": "string" + }, + "shared": { + "description": "Describes whether this template shared or not", + "type": "boolean" + }, + "isDefault": { + "description": "Describes whether this template is default or not", + "type": "boolean" + }, + "subject": { + "description": "For which asset to fetch fileds", + "type": "string" + }, + "exportableFields": { + "description": "List of fileds", + "type": "array", + "items": { + "type": "object", + "required": [ + "heading", + "fields" + ], + "properties": { + "heading": { + "description": "Used to set fields(asset_options/finding_options/group_options/tag_options/user_options)", + "type": "string" + }, + "fields": { + "description": "Fields which are available in exported file", + "type": "array", + "items": { + "type": "object", + "required": [ + "identifierField", + "fieldOrder", + "selected", + "sortable", + "sortOrder", + "sortType" + ], + "properties": { + "identifierField": { + "description": "Internal field which we use to identify the export field", + "type": "string" + }, + "sortable": { + "description": "Is Field Sortable", + "type": "boolean" + }, + "fieldOrder": { + "description": "Order of the export field", + "type": "integer" + }, + "selected": { + "description": "Is Field Selected", + "type": "boolean" + }, + "sortOrder": { + "description": "Sort order of the exportable fields", + "type": "integer" + }, + "sortType": { + "description": "Sort type of the exportable fields - asc/desc", + "type": "string" + } + } + } + } + } + } + } + }, + "example": { + "id": 0, + "clientId": 1, + "userId": 1, + "name": "Export-Template-Name", + "description": "Export-Template-Description", + "shared": false, + "isDefault": false, + "subject": "weakness", + "exportableFields": [ + { + "heading": "weakness_options", + "fields": [ + { + "identifierField": "name", + "displayText": "Name", + "sortable": false, + "fieldOrder": 1, + "selected": false, + "sortOrder": 0, + "sortType": "ASC" + } + ] + } + ] + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/weakness/export": { + "post": { + "summary": "Initiate export job", + "description": "

\nEndpoint for initiating an export job against the\ndata outlined in the given FilterRequest.\nThe Application Export Template API (/client/{clientId}/weakness/export/template) lists the fields that can be exported. The exportableFields section of the request body can be used to choose the fields that needs to be exported.\n

\n", + "tags": [ + "weakness" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "filterRequest", + "fileType", + "noOfRows", + "fileName", + "exportableFields" + ], + "properties": { + "filterRequest": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + }, + "example": { + "filters": [ + { + "field": "vulnId", + "exclusive": false, + "operator": "IN", + "value": "CWE-123" + } + ] + } + }, + "fileType": { + "description": "Type of file to be exported into", + "type": "string", + "enum": [ + "JSON", + "CSV" + ] + }, + "noOfRows": { + "description": "Number of rows to be exported by default", + "type": "integer" + }, + "fileName": { + "description": "Name of the exported file", + "type": "string" + }, + "exportableFields": { + "description": "Fields included for Export", + "type": "array", + "items": { + "type": "object", + "required": [ + "heading", + "fields" + ], + "properties": { + "heading": { + "description": "Used to set fields(asset_options/finding_options/group_options/tag_options/user_options)", + "type": "string" + }, + "fields": { + "description": "Fields which are available in exported file", + "type": "array", + "items": { + "type": "object", + "required": [ + "identifierField", + "fieldOrder", + "selected", + "sortable", + "sortOrder", + "sortType" + ], + "properties": { + "identifierField": { + "description": "Internal field which we use to identify the export field", + "type": "string" + }, + "sortable": { + "description": "Is Field Sortable", + "type": "boolean" + }, + "fieldOrder": { + "description": "Order of the export field", + "type": "integer" + }, + "selected": { + "description": "Is Field Selected", + "type": "boolean" + }, + "sortOrder": { + "description": "Sort order of the exportable fields", + "type": "integer" + }, + "sortType": { + "description": "Sort type of the exportable fields - asc/desc", + "type": "string" + } + } + } + } + } + } + } + }, + "example": { + "filterRequest": { + "filters": [ + { + "field": "vulnId", + "exclusive": false, + "operator": "IN", + "value": "CWE-123" + } + ] + }, + "fileName": "TestWeaknessExport", + "fileType": "CSV", + "noOfRows": 5000, + "exportableFields": [ + { + "heading": "weakness_options", + "fields": [ + { + "identifierField": "name", + "fieldOrder": 1, + "selected": false, + "sortable": false, + "sortOrder": 0, + "sortType": "ASC" + } + ] + } + ] + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/quick-filters": { + "post": { + "summary": "List fields that can be filtered by in the search endpoint", + "tags": [ + "quickFilter" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "subject", + "filterRequest" + ], + "properties": { + "subject": { + "type": "string" + }, + "filterRequest": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "sort" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + }, + "projection": { + "type": "string" + }, + "sort": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "direction" + ], + "properties": { + "field": { + "type": "string" + }, + "direction": { + "type": "string", + "enum": [ + "ASC", + "DESC" + ] + } + } + } + }, + "page": { + "type": "integer" + }, + "size": { + "type": "integer" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "projection": "basic", + "sort": [ + { + "field": "id", + "direction": "ASC" + } + ], + "page": 0, + "size": 20 + } + } + }, + "example": { + "subject": "vulnerability", + "filterRequest": { + "filters": [ + { + "field": "vulnId", + "exclusive": false, + "operator": "IN", + "value": "CVE-123, CVE-234" + } + ] + } + } + } + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "object", + "required": [ + "uid", + "name", + "inputType", + "value", + "subCategory", + "filterField", + "filterValue", + "implicitFilters" + ], + "properties": { + "uid": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "inputType": { + "description": "Input type", + "type": "string", + "enum": [ + "RANGE", + "MULTISELECT", + "NONE" + ] + }, + "value": { + "type": "array", + "items": { + "type": "string" + } + }, + "subCategory": { + "type": "array", + "items": { + "type": "object", + "required": [ + "uid", + "name", + "inputType", + "value", + "subCategory", + "filterField", + "filterValue", + "implicitFilters" + ], + "properties": { + "uid": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "inputType": { + "type": "string", + "enum": [ + "RANGE", + "MULTISELECT", + "NONE" + ] + }, + "value": { + "type": "array", + "items": { + "type": "string" + } + }, + "subCategory": { + "type": "array", + "items": { + "type": "object" + } + }, + "filterField": { + "type": "string" + }, + "filterValue": { + "type": "string" + }, + "implicitFilters": { + "type": "array", + "items": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "sort" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + }, + "projection": { + "type": "string" + }, + "sort": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "direction" + ], + "properties": { + "field": { + "type": "string" + }, + "direction": { + "type": "string", + "enum": [ + "ASC", + "DESC" + ] + } + } + } + }, + "page": { + "type": "integer" + }, + "size": { + "type": "integer" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "projection": "basic", + "sort": [ + { + "field": "id", + "direction": "ASC" + } + ], + "page": 0, + "size": 20 + } + } + } + } + } + }, + "filterField": { + "description": "Filter field", + "type": "string" + }, + "filterValue": { + "type": "string" + }, + "implicitFilters": { + "type": "array", + "items": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "sort" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + }, + "projection": { + "type": "string" + }, + "sort": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "direction" + ], + "properties": { + "field": { + "type": "string" + }, + "direction": { + "type": "string", + "enum": [ + "ASC", + "DESC" + ] + } + } + } + }, + "page": { + "type": "integer" + }, + "size": { + "type": "integer" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "projection": "basic", + "sort": [ + { + "field": "id", + "direction": "ASC" + } + ], + "page": 0, + "size": 20 + } + } + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/rsNotifications/rules": { + "get": { + "summary": "List all templates for a user", + "tags": [ + "rsnotifications" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object" + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + }, + "put": { + "summary": "Subscribe notifications", + "tags": [ + "rsnotifications" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "rules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "notificationTypeId": { + "type": "integer" + }, + "subject": { + "type": "string" + }, + "subscribe": { + "type": "boolean" + }, + "operators": { + "type": "array", + "items": { + "type": "object", + "properties": { + "operator": { + "type": "string", + "enum": [ + "LESSER_THAN", + "GREATER_THAN", + "INCREASED_BY", + "DECREASED_BY", + "EMPTY" + ] + }, + "operand": { + "type": "integer" + } + } + } + }, + "frequency": { + "type": "array", + "items": { + "type": "object", + "properties": { + "frequency": { + "type": "string", + "enum": [ + "IMMEDIATE", + "DAILY", + "WEEKLY" + ] + } + } + } + }, + "whiteListed": { + "type": "array", + "items": { + "type": "integer" + } + }, + "blackListed": { + "type": "array", + "items": { + "type": "integer" + } + }, + "deliveryChannelId": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + } + } + } + ], + "responses": { + "200": { + "description": "Ok" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/rsNotifications/mark-as-read": { + "put": { + "summary": "Mark as read/unread notifications", + "tags": [ + "rsnotifications" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "notificationIds": { + "type": "array", + "items": { + "type": "integer" + } + }, + "markAsRead": { + "type": "boolean" + } + } + } + } + ], + "responses": { + "200": { + "description": "Ok" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/rsNotifications/channel": { + "post": { + "summary": "Create delivery channel", + "tags": [ + "rsnotifications" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "channelName": { + "type": "string" + }, + "channelType": { + "type": "string" + }, + "webhookContentType": { + "type": "string" + }, + "addressDetails": { + "type": "array", + "items": { + "type": "object", + "properties": { + "address": { + "type": "string" + }, + "verification_code": { + "type": "string" + } + } + } + } + } + } + } + ], + "responses": { + "200": { + "description": "Ok" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + }, + "put": { + "summary": "Edit delivery channel", + "tags": [ + "rsnotifications" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "channelName": { + "type": "string" + }, + "channelType": { + "type": "string" + }, + "webhookContentType": { + "type": "string" + }, + "disabled": { + "type": "boolean" + }, + "shared": { + "type": "boolean" + }, + "addressDetails": { + "type": "array", + "items": { + "type": "object", + "properties": { + "address": { + "type": "string" + }, + "verification_code": { + "type": "string" + } + } + } + } + } + } + } + ], + "responses": { + "200": { + "description": "Ok" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + }, + "delete": { + "summary": "Delete delivery channel", + "tags": [ + "rsnotifications" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "channelIds": { + "type": "array", + "items": { + "type": "integer" + } + } + } + } + } + ], + "responses": { + "200": { + "description": "Ok" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/rsNotifications/channel/{order}": { + "get": { + "summary": "List all channel for a user", + "tags": [ + "rsnotifications" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "order", + "in": "path", + "required": true, + "type": "string", + "enum": [ + "ASC", + "DESC" + ] + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object" + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/rsNotifications/sendverificationcode": { + "post": { + "summary": "Get verification code", + "tags": [ + "rsnotifications" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "channelName": { + "type": "string" + }, + "channelDetails": { + "type": "array", + "items": { + "type": "object", + "properties": { + "channelAddress": { + "type": "string" + }, + "channelType": { + "type": "string" + } + } + } + } + } + } + } + ], + "responses": { + "200": { + "description": "Ok" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/rsNotifications/model": { + "get": { + "summary": "List projections and their models", + "description": "List projections and their models that can be requested from the search endpoint.\n", + "tags": [ + "rsnotifications" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "object", + "properties": { + "projections": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "fields": { + "type": "array", + "items": { + "type": "object", + "properties": { + "field": { + "type": "string" + }, + "type": { + "type": "string" + }, + "nested": { + "type": "array", + "items": { + "type": "object", + "description": "Same as ProjectionField" + } + } + } + } + } + } + } + } + }, + "example": { + "projections": [ + { + "name": "basic", + "fields": [ + { + "field": "id", + "type": "integer" + }, + { + "field": "name", + "type": "string" + } + ] + } + ] + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/rsNotifications/filter": { + "get": { + "summary": "List fields that can be filtered by in the search endpoint", + "tags": [ + "rsnotifications" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "array", + "items": { + "required": [ + "name", + "uid", + "operators", + "type", + "description" + ], + "properties": { + "name": { + "type": "string" + }, + "uid": { + "type": "string", + "description": "uid used to indentify fields in suggest and search requests" + }, + "operators": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + } + }, + "datatype": { + "type": "string" + }, + "description": { + "type": "string" + } + } + }, + "example": [ + { + "name": "id", + "uid": "id", + "operator": [ + "EXACT", + "IN" + ], + "type": "integer", + "description": "The id" + } + ] + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/rsNotifications/search": { + "post": { + "summary": "Search for Notifications", + "tags": [ + "rsnotifications" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "sort" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + }, + "projection": { + "type": "string" + }, + "sort": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "direction" + ], + "properties": { + "field": { + "type": "string" + }, + "direction": { + "type": "string", + "enum": [ + "ASC", + "DESC" + ] + } + } + } + }, + "page": { + "type": "integer" + }, + "size": { + "type": "integer" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "projection": "basic", + "sort": [ + { + "field": "id", + "direction": "ASC" + } + ], + "page": 0, + "size": 20 + } + } + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "object", + "required": [ + "_embedded", + "page" + ], + "properties": { + "_embedded": { + "type": "object", + "required": [ + "strings" + ], + "properties": { + "strings": { + "type": "array", + "items": { + "type": "object", + "description": "

The response structure is subject dependent. Subject structure\ncan be found via the subject endpoint.

\n" + } + } + } + }, + "page": { + "type": "object", + "required": [ + "size", + "totalElements", + "totalPages", + "number" + ], + "properties": { + "size": { + "type": "integer" + }, + "totalElements": { + "type": "integer" + }, + "totalPages": { + "type": "integer" + }, + "number": { + "type": "integer" + } + } + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "id", + "errorRefId", + "code", + "cause" + ], + "properties": { + "id": { + "type": "string", + "description": "Entity id which failed to be retrieved" + }, + "errorRefId": { + "type": "string", + "description": "A unique identifier for the error" + }, + "code": { + "type": "integer", + "description": "http status code of the error" + }, + "cause": { + "type": "string", + "description": "http status code message" + } + } + } + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/rsNotifications/quick-filters/count": { + "post": { + "summary": "List fields that can be filtered by in the search endpoint", + "tags": [ + "rsnotifications" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "subject", + "filterRequest" + ], + "properties": { + "subject": { + "type": "string" + }, + "filterRequest": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "sort" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + }, + "projection": { + "type": "string" + }, + "sort": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "direction" + ], + "properties": { + "field": { + "type": "string" + }, + "direction": { + "type": "string", + "enum": [ + "ASC", + "DESC" + ] + } + } + } + }, + "page": { + "type": "integer" + }, + "size": { + "type": "integer" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "projection": "basic", + "sort": [ + { + "field": "id", + "direction": "ASC" + } + ], + "page": 0, + "size": 20 + } + } + }, + "example": { + "subject": "rsNotifications", + "filterRequest": { + "filters": [ + { + "field": "subject", + "exclusive": false, + "operator": "IN", + "value": "groups" + } + ] + } + } + } + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "object", + "required": [ + "uid", + "name", + "inputType", + "value", + "subCategory", + "filterField", + "filterValue", + "implicitFilters" + ], + "properties": { + "uid": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "inputType": { + "description": "Input type", + "type": "string", + "enum": [ + "RANGE", + "MULTISELECT", + "NONE" + ] + }, + "value": { + "type": "array", + "items": { + "type": "string" + } + }, + "subCategory": { + "type": "array", + "items": { + "type": "object", + "required": [ + "uid", + "name", + "inputType", + "value", + "subCategory", + "filterField", + "filterValue", + "implicitFilters" + ], + "properties": { + "uid": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "inputType": { + "type": "string", + "enum": [ + "RANGE", + "MULTISELECT", + "NONE" + ] + }, + "value": { + "type": "array", + "items": { + "type": "string" + } + }, + "subCategory": { + "type": "array", + "items": { + "type": "object" + } + }, + "filterField": { + "type": "string" + }, + "filterValue": { + "type": "string" + }, + "implicitFilters": { + "type": "array", + "items": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "sort" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + }, + "projection": { + "type": "string" + }, + "sort": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "direction" + ], + "properties": { + "field": { + "type": "string" + }, + "direction": { + "type": "string", + "enum": [ + "ASC", + "DESC" + ] + } + } + } + }, + "page": { + "type": "integer" + }, + "size": { + "type": "integer" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "projection": "basic", + "sort": [ + { + "field": "id", + "direction": "ASC" + } + ], + "page": 0, + "size": 20 + } + } + } + } + } + }, + "filterField": { + "description": "Filter field", + "type": "string" + }, + "filterValue": { + "type": "string" + }, + "implicitFilters": { + "type": "array", + "items": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "sort" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + }, + "projection": { + "type": "string" + }, + "sort": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "direction" + ], + "properties": { + "field": { + "type": "string" + }, + "direction": { + "type": "string", + "enum": [ + "ASC", + "DESC" + ] + } + } + } + }, + "page": { + "type": "integer" + }, + "size": { + "type": "integer" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "projection": "basic", + "sort": [ + { + "field": "id", + "direction": "ASC" + } + ], + "page": 0, + "size": 20 + } + } + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/rsNotifications/channel/admin": { + "put": { + "summary": "Edit delivery channel", + "tags": [ + "rsnotifications" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "channelName": { + "type": "string" + }, + "channelType": { + "type": "string" + }, + "webhookContentType": { + "type": "string" + }, + "disabled": { + "type": "boolean" + }, + "shared": { + "type": "boolean" + }, + "addressDetails": { + "type": "array", + "items": { + "type": "object", + "properties": { + "address": { + "type": "string" + }, + "verification_code": { + "type": "string" + } + } + } + } + } + } + } + ], + "responses": { + "200": { + "description": "Ok" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/rsNotifications/channel/admin/{order}": { + "get": { + "summary": "List all channel for admin user", + "tags": [ + "rsnotifications" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "order", + "in": "path", + "required": true, + "type": "string", + "enum": [ + "ASC", + "DESC" + ] + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object" + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/rsNotifications/detail": { + "get": { + "summary": "Fetch detail pane details", + "description": "Fetch detail pane details of notifications from defined template.\n", + "tags": [ + "rsnotifications" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "notification_id", + "description": "Id of the notification\n", + "in": "query", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "array", + "items": { + "type": "object", + "required": [ + "label", + "value", + "style" + ], + "properties": { + "label": { + "type": "string" + }, + "value": { + "type": "string" + }, + "style": { + "type": "string" + } + }, + "example": { + "label": "Event Title", + "value": "Notification triggered", + "style": "background: #39b54a;" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/rsNotifications/delivery-channel-template": { + "get": { + "summary": "List supported delivery channels", + "description": "List delivery channels with required attributes.\n", + "tags": [ + "rsnotifications" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "array", + "items": { + "type": "object", + "required": [ + "type", + "label", + "attributes" + ], + "properties": { + "type": { + "type": "string" + }, + "label": { + "type": "string" + }, + "attributes": { + "type": "array", + "items": { + "type": "object", + "required": [ + "label", + "key", + "type" + ], + "properties": { + "label": { + "type": "string" + }, + "key": { + "type": "string" + }, + "type": { + "type": "string" + } + } + } + } + }, + "example": { + "type": "EMAIL", + "label": "Email", + "attributes": [ + { + "label": "Channel name", + "key": "channelName", + "type": "TEXT" + }, + { + "label": "Email", + "key": "address", + "type": "TEXT" + } + ] + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/{historyType}/history": { + "post": { + "summary": "Get finding history by finding id", + "description": "Get host finding or application finding history.\n", + "tags": [ + "findingHistory" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "historyType", + "description": "

Subject to fetch the history. Supported types are hostFinding and applicationFinding
\n", + "in": "path", + "required": true, + "type": "string" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "vulnIds" + ], + "properties": { + "vulnIds": { + "type": "array", + "items": { + "type": "integer" + } + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "array", + "items": { + "type": "object", + "required": [ + "findingId", + "findingType", + "date", + "firstName", + "lastName", + "user_id", + "descriptionType", + "file_id", + "description", + "username" + ], + "properties": { + "findingId": { + "type": "integer" + }, + "findingType": { + "type": "string", + "enum": [ + "NETWORK", + "URL" + ] + }, + "date": { + "type": "string", + "format": "date" + }, + "fistName": { + "type": "string" + }, + "lastName": { + "type": "string" + }, + "user_id": { + "type": "integer" + }, + "descriptionType": { + "type": "string" + }, + "file_id": { + "type": "integer" + }, + "description": { + "type": "string" + }, + "username": { + "type": "string" + } + }, + "example": { + "findingId": 123, + "findingType": "NETWORK", + "date": "2020-05-20 00:00:00", + "firstName": "Risk Pen", + "lastName": "Dave", + "user_id": 4298, + "descriptionType": "Info", + "file_id": 1982, + "description": "Tag tag32 is applied.", + "username": "risk_pen" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/custom-attributes/group": { + "get": { + "summary": "Get Custom Attributes", + "tags": [ + "CustomAttributes" + ], + "description": "List Custom Attributes\n", + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "attributeId": { + "type": "string", + "example": "1_customAttr_1" + }, + "clientId": { + "type": "integer" + }, + "subject": { + "type": "string" + }, + "label": { + "type": "string" + }, + "attributeType": { + "type": "string" + }, + "format": { + "type": "string" + }, + "propagateToAsset": { + "type": "boolean" + }, + "propagateToFinding": { + "type": "boolean" + }, + "filterable": { + "type": "boolean" + }, + "listViewEnabled": { + "type": "boolean" + }, + "exportable": { + "type": "boolean" + }, + "sortable": { + "type": "boolean" + }, + "groupByEnabled": { + "type": "boolean" + }, + "createdBy": { + "type": "integer" + }, + "createdOn": { + "type": "string", + "format": "date-time" + }, + "updatedBy": { + "type": "integer" + }, + "updatedOn": { + "type": "string", + "format": "date-time" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + }, + "post": { + "summary": "Create Custom Attributes", + "tags": [ + "CustomAttributes" + ], + "description": "Create Custom Attributes\n", + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "label", + "attributeType" + ], + "properties": { + "label": { + "description": "Label of custom attribute", + "type": "string", + "example": "Custom Attribute 1" + }, + "attributeType": { + "description": "Data type of custom attribute", + "type": "string", + "enum": [ + "STRING", + "URL", + "DATE", + "BOOLEAN", + "INTEGER", + "FLOAT", + "TEXT", + "LIST_STRING", + "LIST_URL", + "LIST_BOOLEAN", + "LIST_INTEGER", + "LIST_FLOAT" + ] + }, + "format": { + "description": "Format of date custom attribute. Required for creating date datatype", + "type": "string", + "default": null + }, + "propagateToAsset": { + "description": "Should this attribute be propagated to asset. Applicable for group custom attributes only", + "type": "boolean", + "default": false + }, + "propagateToFinding": { + "description": "Should this attribute be propagated to finding. Applicable for both group and asset custom attributes", + "type": "boolean", + "default": false + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "properties": { + "attributeId": { + "type": "string", + "example": "1_customAttr_1" + }, + "clientId": { + "type": "integer" + }, + "subject": { + "type": "string" + }, + "label": { + "type": "string" + }, + "attributeType": { + "type": "string" + }, + "format": { + "type": "string" + }, + "propagateToAsset": { + "type": "boolean" + }, + "propagateToFinding": { + "type": "boolean" + }, + "filterable": { + "type": "boolean" + }, + "listViewEnabled": { + "type": "boolean" + }, + "exportable": { + "type": "boolean" + }, + "sortable": { + "type": "boolean" + }, + "groupByEnabled": { + "type": "boolean" + }, + "createdBy": { + "type": "integer" + }, + "createdOn": { + "type": "string", + "format": "date-time" + }, + "updatedBy": { + "type": "integer" + }, + "updatedOn": { + "type": "string", + "format": "date-time" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/custom-attributes/group/{attributeId}": { + "put": { + "summary": "Update Custom Attributes", + "tags": [ + "CustomAttributes" + ], + "description": "Create Custom Attributes\n", + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "attributeId", + "in": "path", + "description": "Id of Custom Attribute\n", + "required": true, + "type": "string" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "label" + ], + "properties": { + "label": { + "description": "Label of custom attribute", + "type": "string", + "example": "New Label" + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "properties": { + "attributeId": { + "type": "string", + "example": "1_customAttr_1" + }, + "clientId": { + "type": "integer" + }, + "subject": { + "type": "string" + }, + "label": { + "type": "string" + }, + "attributeType": { + "type": "string" + }, + "format": { + "type": "string" + }, + "propagateToAsset": { + "type": "boolean" + }, + "propagateToFinding": { + "type": "boolean" + }, + "filterable": { + "type": "boolean" + }, + "listViewEnabled": { + "type": "boolean" + }, + "exportable": { + "type": "boolean" + }, + "sortable": { + "type": "boolean" + }, + "groupByEnabled": { + "type": "boolean" + }, + "createdBy": { + "type": "integer" + }, + "createdOn": { + "type": "string", + "format": "date-time" + }, + "updatedBy": { + "type": "integer" + }, + "updatedOn": { + "type": "string", + "format": "date-time" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/job/group/bulk-update-cust-attrs": { + "post": { + "summary": "Create job to update Custom Attributes", + "tags": [ + "CustomAttributes" + ], + "description": "Create job to update Custom Attributes\n", + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "sources": { + "type": "array", + "items": { + "type": "object", + "properties": { + "filterRequest": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "sort" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + }, + "projection": { + "type": "string" + }, + "sort": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "direction" + ], + "properties": { + "field": { + "type": "string" + }, + "direction": { + "type": "string", + "enum": [ + "ASC", + "DESC" + ] + } + } + } + }, + "page": { + "type": "integer" + }, + "size": { + "type": "integer" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "projection": "basic", + "sort": [ + { + "field": "id", + "direction": "ASC" + } + ], + "page": 0, + "size": 20 + } + }, + "updateAttributes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "attributeId": { + "type": "string" + }, + "oneOf": { + "type": "object", + "properties": { + "attributeValue": { + "type": "string" + }, + "attributeValues": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "example": [ + { + "attributeId": "1_customAttr_1", + "attributeValue": "Text Data" + }, + { + "attributeId": "1_customAttr_2", + "attributeValues": [ + "Data1", + "Data2" + ] + } + ] + } + }, + "deleteAttributes": { + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "1_customAttr_3", + "1_customAttr_4" + ] + } + } + } + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "array", + "items": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/custom-attributes/group/get-job-stats": { + "get": { + "summary": "Get Custom Attributes Update Job Stats", + "tags": [ + "CustomAttributes" + ], + "description": "Get the status of the ongoing and completed custom attributes jobs\n", + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "jobId": { + "type": "integer" + }, + "jobType": { + "type": "string" + }, + "createdUserFullName": { + "type": "string" + }, + "timeCreated": { + "type": "string" + }, + "subject": { + "type": "string" + }, + "attributes": { + "type": "array", + "items": { + "type": "string" + } + }, + "impact": { + "type": "object", + "properties": { + "hosts": { + "type": "integer" + }, + "hostFindings": { + "type": "integer" + }, + "application": { + "type": "integer" + }, + "applicationFinding": { + "type": "integer" + }, + "groups": { + "type": "integer" + } + } + }, + "progressPercentage": { + "type": "integer" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/custom-attributes/host": { + "get": { + "summary": "Get Custom Attributes", + "tags": [ + "CustomAttributes" + ], + "description": "List Custom Attributes\n", + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "attributeId": { + "type": "string", + "example": "1_customAttr_1" + }, + "clientId": { + "type": "integer" + }, + "subject": { + "type": "string" + }, + "label": { + "type": "string" + }, + "attributeType": { + "type": "string" + }, + "format": { + "type": "string" + }, + "propagateToAsset": { + "type": "boolean" + }, + "propagateToFinding": { + "type": "boolean" + }, + "filterable": { + "type": "boolean" + }, + "listViewEnabled": { + "type": "boolean" + }, + "exportable": { + "type": "boolean" + }, + "sortable": { + "type": "boolean" + }, + "groupByEnabled": { + "type": "boolean" + }, + "createdBy": { + "type": "integer" + }, + "createdOn": { + "type": "string", + "format": "date-time" + }, + "updatedBy": { + "type": "integer" + }, + "updatedOn": { + "type": "string", + "format": "date-time" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + }, + "post": { + "summary": "Create Custom Attributes", + "tags": [ + "CustomAttributes" + ], + "description": "Create Custom Attributes\n", + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "label", + "attributeType" + ], + "properties": { + "label": { + "description": "Label of custom attribute", + "type": "string", + "example": "Custom Attribute 1" + }, + "attributeType": { + "description": "Data type of custom attribute", + "type": "string", + "enum": [ + "STRING", + "URL", + "DATE", + "BOOLEAN", + "INTEGER", + "FLOAT", + "TEXT", + "LIST_STRING", + "LIST_URL", + "LIST_BOOLEAN", + "LIST_INTEGER", + "LIST_FLOAT" + ] + }, + "format": { + "description": "Format of date custom attribute. Required for creating date datatype", + "type": "string", + "default": null + }, + "propagateToAsset": { + "description": "Should this attribute be propagated to asset. Applicable for group custom attributes only", + "type": "boolean", + "default": false + }, + "propagateToFinding": { + "description": "Should this attribute be propagated to finding. Applicable for both group and asset custom attributes", + "type": "boolean", + "default": false + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "properties": { + "attributeId": { + "type": "string", + "example": "1_customAttr_1" + }, + "clientId": { + "type": "integer" + }, + "subject": { + "type": "string" + }, + "label": { + "type": "string" + }, + "attributeType": { + "type": "string" + }, + "format": { + "type": "string" + }, + "propagateToAsset": { + "type": "boolean" + }, + "propagateToFinding": { + "type": "boolean" + }, + "filterable": { + "type": "boolean" + }, + "listViewEnabled": { + "type": "boolean" + }, + "exportable": { + "type": "boolean" + }, + "sortable": { + "type": "boolean" + }, + "groupByEnabled": { + "type": "boolean" + }, + "createdBy": { + "type": "integer" + }, + "createdOn": { + "type": "string", + "format": "date-time" + }, + "updatedBy": { + "type": "integer" + }, + "updatedOn": { + "type": "string", + "format": "date-time" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/custom-attributes/host/{attributeId}": { + "put": { + "summary": "Update Custom Attributes", + "tags": [ + "CustomAttributes" + ], + "description": "Create Custom Attributes\n", + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "attributeId", + "in": "path", + "description": "Id of Custom Attribute\n", + "required": true, + "type": "string" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "label" + ], + "properties": { + "label": { + "description": "Label of custom attribute", + "type": "string", + "example": "New Label" + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "properties": { + "attributeId": { + "type": "string", + "example": "1_customAttr_1" + }, + "clientId": { + "type": "integer" + }, + "subject": { + "type": "string" + }, + "label": { + "type": "string" + }, + "attributeType": { + "type": "string" + }, + "format": { + "type": "string" + }, + "propagateToAsset": { + "type": "boolean" + }, + "propagateToFinding": { + "type": "boolean" + }, + "filterable": { + "type": "boolean" + }, + "listViewEnabled": { + "type": "boolean" + }, + "exportable": { + "type": "boolean" + }, + "sortable": { + "type": "boolean" + }, + "groupByEnabled": { + "type": "boolean" + }, + "createdBy": { + "type": "integer" + }, + "createdOn": { + "type": "string", + "format": "date-time" + }, + "updatedBy": { + "type": "integer" + }, + "updatedOn": { + "type": "string", + "format": "date-time" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/job/host/bulk-update-cust-attrs": { + "post": { + "summary": "Create job to update Custom Attributes", + "tags": [ + "CustomAttributes" + ], + "description": "Create job to update Custom Attributes\n", + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "sources": { + "type": "array", + "items": { + "type": "object", + "properties": { + "filterRequest": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "sort" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + }, + "projection": { + "type": "string" + }, + "sort": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "direction" + ], + "properties": { + "field": { + "type": "string" + }, + "direction": { + "type": "string", + "enum": [ + "ASC", + "DESC" + ] + } + } + } + }, + "page": { + "type": "integer" + }, + "size": { + "type": "integer" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "projection": "basic", + "sort": [ + { + "field": "id", + "direction": "ASC" + } + ], + "page": 0, + "size": 20 + } + }, + "updateAttributes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "attributeId": { + "type": "string" + }, + "oneOf": { + "type": "object", + "properties": { + "attributeValue": { + "type": "string" + }, + "attributeValues": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "example": [ + { + "attributeId": "1_customAttr_1", + "attributeValue": "Text Data" + }, + { + "attributeId": "1_customAttr_2", + "attributeValues": [ + "Data1", + "Data2" + ] + } + ] + } + }, + "deleteAttributes": { + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "1_customAttr_3", + "1_customAttr_4" + ] + } + } + } + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "array", + "items": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/custom-attributes/host/get-job-stats": { + "get": { + "summary": "Get Custom Attributes Update Job Stats", + "tags": [ + "CustomAttributes" + ], + "description": "Get the status of the ongoing and completed custom attributes jobs\n", + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "jobId": { + "type": "integer" + }, + "jobType": { + "type": "string" + }, + "createdUserFullName": { + "type": "string" + }, + "timeCreated": { + "type": "string" + }, + "subject": { + "type": "string" + }, + "attributes": { + "type": "array", + "items": { + "type": "string" + } + }, + "impact": { + "type": "object", + "properties": { + "hosts": { + "type": "integer" + }, + "hostFindings": { + "type": "integer" + }, + "application": { + "type": "integer" + }, + "applicationFinding": { + "type": "integer" + }, + "groups": { + "type": "integer" + } + } + }, + "progressPercentage": { + "type": "integer" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/custom-attributes/hostFinding": { + "get": { + "summary": "Get Custom Attributes", + "tags": [ + "CustomAttributes" + ], + "description": "List Custom Attributes\n", + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "attributeId": { + "type": "string", + "example": "1_customAttr_1" + }, + "clientId": { + "type": "integer" + }, + "subject": { + "type": "string" + }, + "label": { + "type": "string" + }, + "attributeType": { + "type": "string" + }, + "format": { + "type": "string" + }, + "propagateToAsset": { + "type": "boolean" + }, + "propagateToFinding": { + "type": "boolean" + }, + "filterable": { + "type": "boolean" + }, + "listViewEnabled": { + "type": "boolean" + }, + "exportable": { + "type": "boolean" + }, + "sortable": { + "type": "boolean" + }, + "groupByEnabled": { + "type": "boolean" + }, + "createdBy": { + "type": "integer" + }, + "createdOn": { + "type": "string", + "format": "date-time" + }, + "updatedBy": { + "type": "integer" + }, + "updatedOn": { + "type": "string", + "format": "date-time" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + }, + "post": { + "summary": "Create Custom Attributes", + "tags": [ + "CustomAttributes" + ], + "description": "Create Custom Attributes\n", + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "label", + "attributeType" + ], + "properties": { + "label": { + "description": "Label of custom attribute", + "type": "string", + "example": "Custom Attribute 1" + }, + "attributeType": { + "description": "Data type of custom attribute", + "type": "string", + "enum": [ + "STRING", + "URL", + "DATE", + "BOOLEAN", + "INTEGER", + "FLOAT", + "TEXT", + "LIST_STRING", + "LIST_URL", + "LIST_BOOLEAN", + "LIST_INTEGER", + "LIST_FLOAT" + ] + }, + "format": { + "description": "Format of date custom attribute. Required for creating date datatype", + "type": "string", + "default": null + }, + "propagateToAsset": { + "description": "Should this attribute be propagated to asset. Applicable for group custom attributes only", + "type": "boolean", + "default": false + }, + "propagateToFinding": { + "description": "Should this attribute be propagated to finding. Applicable for both group and asset custom attributes", + "type": "boolean", + "default": false + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "properties": { + "attributeId": { + "type": "string", + "example": "1_customAttr_1" + }, + "clientId": { + "type": "integer" + }, + "subject": { + "type": "string" + }, + "label": { + "type": "string" + }, + "attributeType": { + "type": "string" + }, + "format": { + "type": "string" + }, + "propagateToAsset": { + "type": "boolean" + }, + "propagateToFinding": { + "type": "boolean" + }, + "filterable": { + "type": "boolean" + }, + "listViewEnabled": { + "type": "boolean" + }, + "exportable": { + "type": "boolean" + }, + "sortable": { + "type": "boolean" + }, + "groupByEnabled": { + "type": "boolean" + }, + "createdBy": { + "type": "integer" + }, + "createdOn": { + "type": "string", + "format": "date-time" + }, + "updatedBy": { + "type": "integer" + }, + "updatedOn": { + "type": "string", + "format": "date-time" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/custom-attributes/hostFinding/{attributeId}": { + "put": { + "summary": "Update Custom Attributes", + "tags": [ + "CustomAttributes" + ], + "description": "Create Custom Attributes\n", + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "attributeId", + "in": "path", + "description": "Id of Custom Attribute\n", + "required": true, + "type": "string" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "label" + ], + "properties": { + "label": { + "description": "Label of custom attribute", + "type": "string", + "example": "New Label" + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "properties": { + "attributeId": { + "type": "string", + "example": "1_customAttr_1" + }, + "clientId": { + "type": "integer" + }, + "subject": { + "type": "string" + }, + "label": { + "type": "string" + }, + "attributeType": { + "type": "string" + }, + "format": { + "type": "string" + }, + "propagateToAsset": { + "type": "boolean" + }, + "propagateToFinding": { + "type": "boolean" + }, + "filterable": { + "type": "boolean" + }, + "listViewEnabled": { + "type": "boolean" + }, + "exportable": { + "type": "boolean" + }, + "sortable": { + "type": "boolean" + }, + "groupByEnabled": { + "type": "boolean" + }, + "createdBy": { + "type": "integer" + }, + "createdOn": { + "type": "string", + "format": "date-time" + }, + "updatedBy": { + "type": "integer" + }, + "updatedOn": { + "type": "string", + "format": "date-time" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/job/hostFinding/bulk-update-cust-attrs": { + "post": { + "summary": "Create job to update Custom Attributes", + "tags": [ + "CustomAttributes" + ], + "description": "Create job to update Custom Attributes\n", + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "sources": { + "type": "array", + "items": { + "type": "object", + "properties": { + "filterRequest": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "sort" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + }, + "projection": { + "type": "string" + }, + "sort": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "direction" + ], + "properties": { + "field": { + "type": "string" + }, + "direction": { + "type": "string", + "enum": [ + "ASC", + "DESC" + ] + } + } + } + }, + "page": { + "type": "integer" + }, + "size": { + "type": "integer" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "projection": "basic", + "sort": [ + { + "field": "id", + "direction": "ASC" + } + ], + "page": 0, + "size": 20 + } + }, + "updateAttributes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "attributeId": { + "type": "string" + }, + "oneOf": { + "type": "object", + "properties": { + "attributeValue": { + "type": "string" + }, + "attributeValues": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "example": [ + { + "attributeId": "1_customAttr_1", + "attributeValue": "Text Data" + }, + { + "attributeId": "1_customAttr_2", + "attributeValues": [ + "Data1", + "Data2" + ] + } + ] + } + }, + "deleteAttributes": { + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "1_customAttr_3", + "1_customAttr_4" + ] + } + } + } + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "array", + "items": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/custom-attributes/hostFinding/get-job-stats": { + "get": { + "summary": "Get Custom Attributes Update Job Stats", + "tags": [ + "CustomAttributes" + ], + "description": "Get the status of the ongoing and completed custom attributes jobs\n", + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "jobId": { + "type": "integer" + }, + "jobType": { + "type": "string" + }, + "createdUserFullName": { + "type": "string" + }, + "timeCreated": { + "type": "string" + }, + "subject": { + "type": "string" + }, + "attributes": { + "type": "array", + "items": { + "type": "string" + } + }, + "impact": { + "type": "object", + "properties": { + "hosts": { + "type": "integer" + }, + "hostFindings": { + "type": "integer" + }, + "application": { + "type": "integer" + }, + "applicationFinding": { + "type": "integer" + }, + "groups": { + "type": "integer" + } + } + }, + "progressPercentage": { + "type": "integer" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/custom-attributes/application": { + "get": { + "summary": "Get Custom Attributes", + "tags": [ + "CustomAttributes" + ], + "description": "List Custom Attributes\n", + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "attributeId": { + "type": "string", + "example": "1_customAttr_1" + }, + "clientId": { + "type": "integer" + }, + "subject": { + "type": "string" + }, + "label": { + "type": "string" + }, + "attributeType": { + "type": "string" + }, + "format": { + "type": "string" + }, + "propagateToAsset": { + "type": "boolean" + }, + "propagateToFinding": { + "type": "boolean" + }, + "filterable": { + "type": "boolean" + }, + "listViewEnabled": { + "type": "boolean" + }, + "exportable": { + "type": "boolean" + }, + "sortable": { + "type": "boolean" + }, + "groupByEnabled": { + "type": "boolean" + }, + "createdBy": { + "type": "integer" + }, + "createdOn": { + "type": "string", + "format": "date-time" + }, + "updatedBy": { + "type": "integer" + }, + "updatedOn": { + "type": "string", + "format": "date-time" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + }, + "post": { + "summary": "Create Custom Attributes", + "tags": [ + "CustomAttributes" + ], + "description": "Create Custom Attributes\n", + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "label", + "attributeType" + ], + "properties": { + "label": { + "description": "Label of custom attribute", + "type": "string", + "example": "Custom Attribute 1" + }, + "attributeType": { + "description": "Data type of custom attribute", + "type": "string", + "enum": [ + "STRING", + "URL", + "DATE", + "BOOLEAN", + "INTEGER", + "FLOAT", + "TEXT", + "LIST_STRING", + "LIST_URL", + "LIST_BOOLEAN", + "LIST_INTEGER", + "LIST_FLOAT" + ] + }, + "format": { + "description": "Format of date custom attribute. Required for creating date datatype", + "type": "string", + "default": null + }, + "propagateToAsset": { + "description": "Should this attribute be propagated to asset. Applicable for group custom attributes only", + "type": "boolean", + "default": false + }, + "propagateToFinding": { + "description": "Should this attribute be propagated to finding. Applicable for both group and asset custom attributes", + "type": "boolean", + "default": false + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "properties": { + "attributeId": { + "type": "string", + "example": "1_customAttr_1" + }, + "clientId": { + "type": "integer" + }, + "subject": { + "type": "string" + }, + "label": { + "type": "string" + }, + "attributeType": { + "type": "string" + }, + "format": { + "type": "string" + }, + "propagateToAsset": { + "type": "boolean" + }, + "propagateToFinding": { + "type": "boolean" + }, + "filterable": { + "type": "boolean" + }, + "listViewEnabled": { + "type": "boolean" + }, + "exportable": { + "type": "boolean" + }, + "sortable": { + "type": "boolean" + }, + "groupByEnabled": { + "type": "boolean" + }, + "createdBy": { + "type": "integer" + }, + "createdOn": { + "type": "string", + "format": "date-time" + }, + "updatedBy": { + "type": "integer" + }, + "updatedOn": { + "type": "string", + "format": "date-time" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/custom-attributes/application/{attributeId}": { + "put": { + "summary": "Update Custom Attributes", + "tags": [ + "CustomAttributes" + ], + "description": "Create Custom Attributes\n", + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "attributeId", + "in": "path", + "description": "Id of Custom Attribute\n", + "required": true, + "type": "string" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "label" + ], + "properties": { + "label": { + "description": "Label of custom attribute", + "type": "string", + "example": "New Label" + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "properties": { + "attributeId": { + "type": "string", + "example": "1_customAttr_1" + }, + "clientId": { + "type": "integer" + }, + "subject": { + "type": "string" + }, + "label": { + "type": "string" + }, + "attributeType": { + "type": "string" + }, + "format": { + "type": "string" + }, + "propagateToAsset": { + "type": "boolean" + }, + "propagateToFinding": { + "type": "boolean" + }, + "filterable": { + "type": "boolean" + }, + "listViewEnabled": { + "type": "boolean" + }, + "exportable": { + "type": "boolean" + }, + "sortable": { + "type": "boolean" + }, + "groupByEnabled": { + "type": "boolean" + }, + "createdBy": { + "type": "integer" + }, + "createdOn": { + "type": "string", + "format": "date-time" + }, + "updatedBy": { + "type": "integer" + }, + "updatedOn": { + "type": "string", + "format": "date-time" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/job/application/bulk-update-cust-attrs": { + "post": { + "summary": "Create job to update Custom Attributes", + "tags": [ + "CustomAttributes" + ], + "description": "Create job to update Custom Attributes\n", + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "sources": { + "type": "array", + "items": { + "type": "object", + "properties": { + "filterRequest": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "sort" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + }, + "projection": { + "type": "string" + }, + "sort": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "direction" + ], + "properties": { + "field": { + "type": "string" + }, + "direction": { + "type": "string", + "enum": [ + "ASC", + "DESC" + ] + } + } + } + }, + "page": { + "type": "integer" + }, + "size": { + "type": "integer" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "projection": "basic", + "sort": [ + { + "field": "id", + "direction": "ASC" + } + ], + "page": 0, + "size": 20 + } + }, + "updateAttributes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "attributeId": { + "type": "string" + }, + "oneOf": { + "type": "object", + "properties": { + "attributeValue": { + "type": "string" + }, + "attributeValues": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "example": [ + { + "attributeId": "1_customAttr_1", + "attributeValue": "Text Data" + }, + { + "attributeId": "1_customAttr_2", + "attributeValues": [ + "Data1", + "Data2" + ] + } + ] + } + }, + "deleteAttributes": { + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "1_customAttr_3", + "1_customAttr_4" + ] + } + } + } + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "array", + "items": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/custom-attributes/application/get-job-stats": { + "get": { + "summary": "Get Custom Attributes Update Job Stats", + "tags": [ + "CustomAttributes" + ], + "description": "Get the status of the ongoing and completed custom attributes jobs\n", + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "jobId": { + "type": "integer" + }, + "jobType": { + "type": "string" + }, + "createdUserFullName": { + "type": "string" + }, + "timeCreated": { + "type": "string" + }, + "subject": { + "type": "string" + }, + "attributes": { + "type": "array", + "items": { + "type": "string" + } + }, + "impact": { + "type": "object", + "properties": { + "hosts": { + "type": "integer" + }, + "hostFindings": { + "type": "integer" + }, + "application": { + "type": "integer" + }, + "applicationFinding": { + "type": "integer" + }, + "groups": { + "type": "integer" + } + } + }, + "progressPercentage": { + "type": "integer" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/custom-attributes/applicationFinding": { + "get": { + "summary": "Get Custom Attributes", + "tags": [ + "CustomAttributes" + ], + "description": "List Custom Attributes\n", + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "attributeId": { + "type": "string", + "example": "1_customAttr_1" + }, + "clientId": { + "type": "integer" + }, + "subject": { + "type": "string" + }, + "label": { + "type": "string" + }, + "attributeType": { + "type": "string" + }, + "format": { + "type": "string" + }, + "propagateToAsset": { + "type": "boolean" + }, + "propagateToFinding": { + "type": "boolean" + }, + "filterable": { + "type": "boolean" + }, + "listViewEnabled": { + "type": "boolean" + }, + "exportable": { + "type": "boolean" + }, + "sortable": { + "type": "boolean" + }, + "groupByEnabled": { + "type": "boolean" + }, + "createdBy": { + "type": "integer" + }, + "createdOn": { + "type": "string", + "format": "date-time" + }, + "updatedBy": { + "type": "integer" + }, + "updatedOn": { + "type": "string", + "format": "date-time" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + }, + "post": { + "summary": "Create Custom Attributes", + "tags": [ + "CustomAttributes" + ], + "description": "Create Custom Attributes\n", + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "label", + "attributeType" + ], + "properties": { + "label": { + "description": "Label of custom attribute", + "type": "string", + "example": "Custom Attribute 1" + }, + "attributeType": { + "description": "Data type of custom attribute", + "type": "string", + "enum": [ + "STRING", + "URL", + "DATE", + "BOOLEAN", + "INTEGER", + "FLOAT", + "TEXT", + "LIST_STRING", + "LIST_URL", + "LIST_BOOLEAN", + "LIST_INTEGER", + "LIST_FLOAT" + ] + }, + "format": { + "description": "Format of date custom attribute. Required for creating date datatype", + "type": "string", + "default": null + }, + "propagateToAsset": { + "description": "Should this attribute be propagated to asset. Applicable for group custom attributes only", + "type": "boolean", + "default": false + }, + "propagateToFinding": { + "description": "Should this attribute be propagated to finding. Applicable for both group and asset custom attributes", + "type": "boolean", + "default": false + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "properties": { + "attributeId": { + "type": "string", + "example": "1_customAttr_1" + }, + "clientId": { + "type": "integer" + }, + "subject": { + "type": "string" + }, + "label": { + "type": "string" + }, + "attributeType": { + "type": "string" + }, + "format": { + "type": "string" + }, + "propagateToAsset": { + "type": "boolean" + }, + "propagateToFinding": { + "type": "boolean" + }, + "filterable": { + "type": "boolean" + }, + "listViewEnabled": { + "type": "boolean" + }, + "exportable": { + "type": "boolean" + }, + "sortable": { + "type": "boolean" + }, + "groupByEnabled": { + "type": "boolean" + }, + "createdBy": { + "type": "integer" + }, + "createdOn": { + "type": "string", + "format": "date-time" + }, + "updatedBy": { + "type": "integer" + }, + "updatedOn": { + "type": "string", + "format": "date-time" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/custom-attributes/applicationFinding/{attributeId}": { + "put": { + "summary": "Update Custom Attributes", + "tags": [ + "CustomAttributes" + ], + "description": "Create Custom Attributes\n", + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "attributeId", + "in": "path", + "description": "Id of Custom Attribute\n", + "required": true, + "type": "string" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "required": [ + "label" + ], + "properties": { + "label": { + "description": "Label of custom attribute", + "type": "string", + "example": "New Label" + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "properties": { + "attributeId": { + "type": "string", + "example": "1_customAttr_1" + }, + "clientId": { + "type": "integer" + }, + "subject": { + "type": "string" + }, + "label": { + "type": "string" + }, + "attributeType": { + "type": "string" + }, + "format": { + "type": "string" + }, + "propagateToAsset": { + "type": "boolean" + }, + "propagateToFinding": { + "type": "boolean" + }, + "filterable": { + "type": "boolean" + }, + "listViewEnabled": { + "type": "boolean" + }, + "exportable": { + "type": "boolean" + }, + "sortable": { + "type": "boolean" + }, + "groupByEnabled": { + "type": "boolean" + }, + "createdBy": { + "type": "integer" + }, + "createdOn": { + "type": "string", + "format": "date-time" + }, + "updatedBy": { + "type": "integer" + }, + "updatedOn": { + "type": "string", + "format": "date-time" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/job/applicationFinding/bulk-update-cust-attrs": { + "post": { + "summary": "Create job to update Custom Attributes", + "tags": [ + "CustomAttributes" + ], + "description": "Create job to update Custom Attributes\n", + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "sources": { + "type": "array", + "items": { + "type": "object", + "properties": { + "filterRequest": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "sort" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + }, + "projection": { + "type": "string" + }, + "sort": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "direction" + ], + "properties": { + "field": { + "type": "string" + }, + "direction": { + "type": "string", + "enum": [ + "ASC", + "DESC" + ] + } + } + } + }, + "page": { + "type": "integer" + }, + "size": { + "type": "integer" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "projection": "basic", + "sort": [ + { + "field": "id", + "direction": "ASC" + } + ], + "page": 0, + "size": 20 + } + }, + "updateAttributes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "attributeId": { + "type": "string" + }, + "oneOf": { + "type": "object", + "properties": { + "attributeValue": { + "type": "string" + }, + "attributeValues": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "example": [ + { + "attributeId": "1_customAttr_1", + "attributeValue": "Text Data" + }, + { + "attributeId": "1_customAttr_2", + "attributeValues": [ + "Data1", + "Data2" + ] + } + ] + } + }, + "deleteAttributes": { + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "1_customAttr_3", + "1_customAttr_4" + ] + } + } + } + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "array", + "items": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/custom-attributes/applicationFinding/get-job-stats": { + "get": { + "summary": "Get Custom Attributes Update Job Stats", + "tags": [ + "CustomAttributes" + ], + "description": "Get the status of the ongoing and completed custom attributes jobs\n", + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "jobId": { + "type": "integer" + }, + "jobType": { + "type": "string" + }, + "createdUserFullName": { + "type": "string" + }, + "timeCreated": { + "type": "string" + }, + "subject": { + "type": "string" + }, + "attributes": { + "type": "array", + "items": { + "type": "string" + } + }, + "impact": { + "type": "object", + "properties": { + "hosts": { + "type": "integer" + }, + "hostFindings": { + "type": "integer" + }, + "application": { + "type": "integer" + }, + "applicationFinding": { + "type": "integer" + }, + "groups": { + "type": "integer" + } + } + }, + "progressPercentage": { + "type": "integer" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/hostFindingArticle/restricted": { + "post": { + "summary": "Create Finding Article", + "description": "Create Finding Article", + "tags": [ + "Finding Article" + ], + "consumes": [ + "multipart/form-data" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "accessLevel", + "in": "formData", + "type": "string", + "enum": [ + "RESTRICTED", + "UNRESTRICTED" + ], + "required": true + }, + { + "name": "title", + "in": "formData", + "type": "string", + "required": true + }, + { + "name": "pii", + "in": "formData", + "type": "string", + "enum": [ + "None", + "Unknown", + "Direct", + "Indirect" + ], + "required": true + }, + { + "name": "proofOfExploitation", + "in": "formData", + "type": "string", + "enum": [ + "NO", + "YES", + "YES_WITH_RS3_IMPACT" + ], + "required": true + }, + { + "name": "description", + "in": "formData", + "type": "string", + "required": false + }, + { + "name": "attachments", + "in": "formData", + "description": "List of attachments for article(Multiple attachments not supported in swagger)", + "required": false, + "type": "file" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "properties": { + "id": { + "type": "number" + }, + "uuid": { + "type": "string", + "format": "uuid" + }, + "accessLevel": { + "type": "string", + "enum": [ + "RESTRICTED", + "UNRESTRICTED" + ] + }, + "findingType": { + "type": "string", + "enum": [ + "NETWORK", + "APPLICATION" + ] + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "pii": { + "type": "string", + "enum": [ + "None", + "Unknown", + "Direct", + "Indirect" + ] + }, + "proofOfExploitation": { + "type": "string", + "enum": [ + "NO", + "YES", + "YES_WITH_RS3_IMPACT" + ] + }, + "attachments": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "number" + }, + "uuid": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "fileType": { + "type": "string" + }, + "size": { + "type": "number" + }, + "downloadLink": { + "type": "string" + } + } + } + }, + "createdBy": { + "type": "string" + }, + "createdById": { + "type": "number" + }, + "createdOn": { + "type": "string", + "format": "date-time" + }, + "updatedBy": { + "type": "string" + }, + "updatedById": { + "type": "number" + }, + "updatedOn": { + "type": "string", + "format": "date-time" + } + } + } + } + } + } + }, + "/client/{clientId}/hostFindingArticle/{articleId}/restricted": { + "put": { + "summary": "Update Finding Article", + "description": "Update Finding Article", + "tags": [ + "Finding Article" + ], + "consumes": [ + "multipart/form-data" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "articleId", + "in": "path", + "description": "Id/UUID of Finding Article\n", + "required": true, + "type": "string" + }, + { + "name": "accessLevel", + "in": "formData", + "type": "string", + "enum": [ + "RESTRICTED", + "UNRESTRICTED" + ], + "required": true + }, + { + "name": "title", + "in": "formData", + "type": "string", + "required": false + }, + { + "name": "pii", + "in": "formData", + "type": "string", + "enum": [ + "None", + "Unknown", + "Direct", + "Indirect" + ], + "required": false + }, + { + "name": "proofOfExploitation", + "in": "formData", + "type": "string", + "enum": [ + "NO", + "YES", + "YES_WITH_RS3_IMPACT" + ], + "required": false + }, + { + "name": "description", + "in": "formData", + "type": "string", + "required": false + }, + { + "name": "attachments", + "in": "formData", + "description": "List of attachments for article(Multiple attachments not supported in swagger)", + "required": false, + "type": "file" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "properties": { + "id": { + "type": "number" + }, + "uuid": { + "type": "string", + "format": "uuid" + }, + "accessLevel": { + "type": "string", + "enum": [ + "RESTRICTED", + "UNRESTRICTED" + ] + }, + "findingType": { + "type": "string", + "enum": [ + "NETWORK", + "APPLICATION" + ] + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "pii": { + "type": "string", + "enum": [ + "None", + "Unknown", + "Direct", + "Indirect" + ] + }, + "proofOfExploitation": { + "type": "string", + "enum": [ + "NO", + "YES", + "YES_WITH_RS3_IMPACT" + ] + }, + "attachments": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "number" + }, + "uuid": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "fileType": { + "type": "string" + }, + "size": { + "type": "number" + }, + "downloadLink": { + "type": "string" + } + } + } + }, + "createdBy": { + "type": "string" + }, + "createdById": { + "type": "number" + }, + "createdOn": { + "type": "string", + "format": "date-time" + }, + "updatedBy": { + "type": "string" + }, + "updatedById": { + "type": "number" + }, + "updatedOn": { + "type": "string", + "format": "date-time" + } + } + } + } + } + }, + "get": { + "summary": "Get Finding Article", + "description": "Get Finding Article", + "tags": [ + "Finding Article" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "articleId", + "in": "path", + "description": "Id/UUID of Finding Article\n", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "properties": { + "id": { + "type": "number" + }, + "uuid": { + "type": "string", + "format": "uuid" + }, + "accessLevel": { + "type": "string", + "enum": [ + "RESTRICTED", + "UNRESTRICTED" + ] + }, + "findingType": { + "type": "string", + "enum": [ + "NETWORK", + "APPLICATION" + ] + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "pii": { + "type": "string", + "enum": [ + "None", + "Unknown", + "Direct", + "Indirect" + ] + }, + "proofOfExploitation": { + "type": "string", + "enum": [ + "NO", + "YES", + "YES_WITH_RS3_IMPACT" + ] + }, + "attachments": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "number" + }, + "uuid": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "fileType": { + "type": "string" + }, + "size": { + "type": "number" + }, + "downloadLink": { + "type": "string" + } + } + } + }, + "createdBy": { + "type": "string" + }, + "createdById": { + "type": "number" + }, + "createdOn": { + "type": "string", + "format": "date-time" + }, + "updatedBy": { + "type": "string" + }, + "updatedById": { + "type": "number" + }, + "updatedOn": { + "type": "string", + "format": "date-time" + } + } + } + } + } + }, + "delete": { + "summary": "Delete Finding Article", + "description": "Delete Finding Article", + "tags": [ + "Finding Article" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "articleId", + "in": "path", + "description": "Id/UUID of Finding Article\n", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + } + } + } + }, + "/client/{clientId}/hostFindingArticle/{articleId}/attachment/restricted": { + "get": { + "summary": "Get list of Finding Article attachments", + "description": "Get list of Finding Article attachments", + "tags": [ + "Finding Article" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "articleId", + "in": "path", + "description": "Id/UUID of Finding Article\n", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "number" + }, + "uuid": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "fileType": { + "type": "string" + }, + "size": { + "type": "number" + }, + "downloadLink": { + "type": "string" + } + } + } + } + } + } + }, + "post": { + "summary": "Add Finding Article Attachments", + "description": "Add Finding Article Attachments", + "tags": [ + "Finding Article" + ], + "consumes": [ + "multipart/form-data" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "articleId", + "in": "path", + "description": "Id/UUID of Finding Article\n", + "required": true, + "type": "string" + }, + { + "name": "attachments", + "in": "formData", + "description": "List of attachments for article(Multiple attachments not supported in swagger)", + "required": false, + "type": "file" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "number" + }, + "uuid": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "fileType": { + "type": "string" + }, + "size": { + "type": "number" + }, + "downloadLink": { + "type": "string" + } + } + } + } + } + } + } + }, + "/client/{clientId}/hostFindingArticle/{articleId}/attachment/{attachmentId}/restricted": { + "get": { + "summary": "Download Finding Article attachment", + "description": "Download Finding Article attachment", + "tags": [ + "Finding Article" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "articleId", + "in": "path", + "description": "Id/UUID of Finding Article\n", + "required": true, + "type": "string" + }, + { + "name": "attachmentId", + "in": "path", + "description": "Id/UUID of Finding Article Attachment\n", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Success" + } + } + }, + "delete": { + "summary": "Delete Finding Article", + "description": "Delete Finding Article", + "tags": [ + "Finding Article" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "articleId", + "in": "path", + "description": "Id/UUID of Finding Article\n", + "required": true, + "type": "string" + }, + { + "name": "attachmentId", + "in": "path", + "description": "Id/UUID of Finding Article Attachment\n", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + } + } + } + }, + "/client/{clientId}/hostFindingArticle/{articleId}/map/restricted": { + "post": { + "summary": "Map/Umap Finding Article to findings", + "description": "Map/Umap Finding Article to findings", + "tags": [ + "Finding Article" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "articleId", + "in": "path", + "description": "Id/UUID of Finding Article\n", + "required": true, + "type": "string" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "isRemove": { + "type": "boolean" + }, + "filterRequest": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "sort" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + }, + "projection": { + "type": "string" + }, + "sort": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "direction" + ], + "properties": { + "field": { + "type": "string" + }, + "direction": { + "type": "string", + "enum": [ + "ASC", + "DESC" + ] + } + } + } + }, + "page": { + "type": "integer" + }, + "size": { + "type": "integer" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "projection": "basic", + "sort": [ + { + "field": "id", + "direction": "ASC" + } + ], + "page": 0, + "size": 20 + } + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + } + } + } + }, + "/client/{clientId}/hostFindingArticle": { + "post": { + "summary": "Create Finding Article", + "description": "Create Finding Article", + "tags": [ + "Finding Article" + ], + "consumes": [ + "multipart/form-data" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "title", + "in": "formData", + "type": "string", + "required": true + }, + { + "name": "pii", + "in": "formData", + "type": "string", + "enum": [ + "None", + "Unknown", + "Direct", + "Indirect" + ], + "required": true + }, + { + "name": "proofOfExploitation", + "in": "formData", + "type": "string", + "enum": [ + "NO", + "YES", + "YES_WITH_RS3_IMPACT" + ], + "required": true + }, + { + "name": "description", + "in": "formData", + "type": "string", + "required": false + }, + { + "name": "attachments", + "in": "formData", + "description": "List of attachments for article(Multiple attachments not supported in swagger)", + "required": false, + "type": "file" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "properties": { + "id": { + "type": "number" + }, + "uuid": { + "type": "string", + "format": "uuid" + }, + "accessLevel": { + "type": "string", + "enum": [ + "RESTRICTED", + "UNRESTRICTED" + ] + }, + "findingType": { + "type": "string", + "enum": [ + "NETWORK", + "APPLICATION" + ] + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "pii": { + "type": "string", + "enum": [ + "None", + "Unknown", + "Direct", + "Indirect" + ] + }, + "proofOfExploitation": { + "type": "string", + "enum": [ + "NO", + "YES", + "YES_WITH_RS3_IMPACT" + ] + }, + "attachments": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "number" + }, + "uuid": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "fileType": { + "type": "string" + }, + "size": { + "type": "number" + }, + "downloadLink": { + "type": "string" + } + } + } + }, + "createdBy": { + "type": "string" + }, + "createdById": { + "type": "number" + }, + "createdOn": { + "type": "string", + "format": "date-time" + }, + "updatedBy": { + "type": "string" + }, + "updatedById": { + "type": "number" + }, + "updatedOn": { + "type": "string", + "format": "date-time" + } + } + } + } + } + } + }, + "/client/{clientId}/hostFindingArticle/{articleId}": { + "put": { + "summary": "Update Finding Article", + "description": "Update Finding Article", + "tags": [ + "Finding Article" + ], + "consumes": [ + "multipart/form-data" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "articleId", + "in": "path", + "description": "Id/UUID of Finding Article\n", + "required": true, + "type": "string" + }, + { + "name": "title", + "in": "formData", + "type": "string", + "required": false + }, + { + "name": "pii", + "in": "formData", + "type": "string", + "enum": [ + "None", + "Unknown", + "Direct", + "Indirect" + ], + "required": false + }, + { + "name": "proofOfExploitation", + "in": "formData", + "type": "string", + "enum": [ + "NO", + "YES", + "YES_WITH_RS3_IMPACT" + ], + "required": false + }, + { + "name": "description", + "in": "formData", + "type": "string", + "required": false + }, + { + "name": "attachments", + "in": "formData", + "description": "List of attachments for article(Multiple attachments not supported in swagger)", + "required": false, + "type": "file" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "properties": { + "id": { + "type": "number" + }, + "uuid": { + "type": "string", + "format": "uuid" + }, + "accessLevel": { + "type": "string", + "enum": [ + "RESTRICTED", + "UNRESTRICTED" + ] + }, + "findingType": { + "type": "string", + "enum": [ + "NETWORK", + "APPLICATION" + ] + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "pii": { + "type": "string", + "enum": [ + "None", + "Unknown", + "Direct", + "Indirect" + ] + }, + "proofOfExploitation": { + "type": "string", + "enum": [ + "NO", + "YES", + "YES_WITH_RS3_IMPACT" + ] + }, + "attachments": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "number" + }, + "uuid": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "fileType": { + "type": "string" + }, + "size": { + "type": "number" + }, + "downloadLink": { + "type": "string" + } + } + } + }, + "createdBy": { + "type": "string" + }, + "createdById": { + "type": "number" + }, + "createdOn": { + "type": "string", + "format": "date-time" + }, + "updatedBy": { + "type": "string" + }, + "updatedById": { + "type": "number" + }, + "updatedOn": { + "type": "string", + "format": "date-time" + } + } + } + } + } + }, + "get": { + "summary": "Get Finding Article", + "description": "Get Finding Article", + "tags": [ + "Finding Article" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "articleId", + "in": "path", + "description": "Id/UUID of Finding Article\n", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "properties": { + "id": { + "type": "number" + }, + "uuid": { + "type": "string", + "format": "uuid" + }, + "accessLevel": { + "type": "string", + "enum": [ + "RESTRICTED", + "UNRESTRICTED" + ] + }, + "findingType": { + "type": "string", + "enum": [ + "NETWORK", + "APPLICATION" + ] + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "pii": { + "type": "string", + "enum": [ + "None", + "Unknown", + "Direct", + "Indirect" + ] + }, + "proofOfExploitation": { + "type": "string", + "enum": [ + "NO", + "YES", + "YES_WITH_RS3_IMPACT" + ] + }, + "attachments": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "number" + }, + "uuid": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "fileType": { + "type": "string" + }, + "size": { + "type": "number" + }, + "downloadLink": { + "type": "string" + } + } + } + }, + "createdBy": { + "type": "string" + }, + "createdById": { + "type": "number" + }, + "createdOn": { + "type": "string", + "format": "date-time" + }, + "updatedBy": { + "type": "string" + }, + "updatedById": { + "type": "number" + }, + "updatedOn": { + "type": "string", + "format": "date-time" + } + } + } + } + } + }, + "delete": { + "summary": "Delete Finding Article", + "description": "Delete Finding Article", + "tags": [ + "Finding Article" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "articleId", + "in": "path", + "description": "Id/UUID of Finding Article\n", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + } + } + } + }, + "/client/{clientId}/hostFindingArticle/{articleId}/attachment": { + "get": { + "summary": "Get list of Finding Article attachments", + "description": "Get list of Finding Article attachments", + "tags": [ + "Finding Article" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "articleId", + "in": "path", + "description": "Id/UUID of Finding Article\n", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "number" + }, + "uuid": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "fileType": { + "type": "string" + }, + "size": { + "type": "number" + }, + "downloadLink": { + "type": "string" + } + } + } + } + } + } + }, + "post": { + "summary": "Add Finding Article Attachments", + "description": "Add Finding Article Attachments", + "tags": [ + "Finding Article" + ], + "consumes": [ + "multipart/form-data" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "articleId", + "in": "path", + "description": "Id/UUID of Finding Article\n", + "required": true, + "type": "string" + }, + { + "name": "attachments", + "in": "formData", + "description": "List of attachments for article(Multiple attachments not supported in swagger)", + "required": false, + "type": "file" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "number" + }, + "uuid": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "fileType": { + "type": "string" + }, + "size": { + "type": "number" + }, + "downloadLink": { + "type": "string" + } + } + } + } + } + } + } + }, + "/client/{clientId}/hostFindingArticle/{articleId}/attachment/{attachmentId}": { + "get": { + "summary": "Download Finding Article attachment", + "description": "Download Finding Article attachment", + "tags": [ + "Finding Article" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "articleId", + "in": "path", + "description": "Id/UUID of Finding Article\n", + "required": true, + "type": "string" + }, + { + "name": "attachmentId", + "in": "path", + "description": "Id/UUID of Finding Article Attachment\n", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Success" + } + } + }, + "delete": { + "summary": "Delete Finding Article", + "description": "Delete Finding Article", + "tags": [ + "Finding Article" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "articleId", + "in": "path", + "description": "Id/UUID of Finding Article\n", + "required": true, + "type": "string" + }, + { + "name": "attachmentId", + "in": "path", + "description": "Id/UUID of Finding Article Attachment\n", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + } + } + } + }, + "/client/{clientId}/hostFindingArticle/{articleId}/map": { + "post": { + "summary": "Map/Umap Finding Article to findings", + "description": "Map/Umap Finding Article to findings", + "tags": [ + "Finding Article" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "articleId", + "in": "path", + "description": "Id/UUID of Finding Article\n", + "required": true, + "type": "string" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "isRemove": { + "type": "boolean" + }, + "filterRequest": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "sort" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + }, + "projection": { + "type": "string" + }, + "sort": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "direction" + ], + "properties": { + "field": { + "type": "string" + }, + "direction": { + "type": "string", + "enum": [ + "ASC", + "DESC" + ] + } + } + } + }, + "page": { + "type": "integer" + }, + "size": { + "type": "integer" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "projection": "basic", + "sort": [ + { + "field": "id", + "direction": "ASC" + } + ], + "page": 0, + "size": 20 + } + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + } + } + } + }, + "/client/{clientId}/hostFindingArticle/model": { + "get": { + "summary": "List projections and their models", + "description": "List projections and their models that can be requested from the search endpoint.\n", + "tags": [ + "Finding Article" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "object", + "properties": { + "projections": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "fields": { + "type": "array", + "items": { + "type": "object", + "properties": { + "field": { + "type": "string" + }, + "type": { + "type": "string" + }, + "nested": { + "type": "array", + "items": { + "type": "object", + "description": "Same as ProjectionField" + } + } + } + } + } + } + } + } + }, + "example": { + "projections": [ + { + "name": "basic", + "fields": [ + { + "field": "id", + "type": "integer" + }, + { + "field": "name", + "type": "string" + } + ] + } + ] + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/hostFindingArticle/filter": { + "get": { + "summary": "List fields that can be filtered by in the search endpoint", + "tags": [ + "Finding Article" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "array", + "items": { + "required": [ + "name", + "uid", + "operators", + "type", + "description" + ], + "properties": { + "name": { + "type": "string" + }, + "uid": { + "type": "string", + "description": "uid used to indentify fields in suggest and search requests" + }, + "operators": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + } + }, + "datatype": { + "type": "string" + }, + "description": { + "type": "string" + } + } + }, + "example": [ + { + "name": "id", + "uid": "id", + "operator": [ + "EXACT", + "IN" + ], + "type": "integer", + "description": "The id" + } + ] + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/hostFindingArticle/suggest": { + "post": { + "summary": "Suggest values for filter fields", + "tags": [ + "Finding Article" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "filter" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + }, + "description": "Filters to used to narrow down the the result set\n" + }, + "filter": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + }, + "description": "Filter for which to suggest values for. The filter value will be\ntreated as a wildcard.\n" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": true, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "filter": { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "" + } + } + } + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key", + "count" + ], + "properties": { + "key": { + "type": "string", + "description": "Value for the field the suggestion was requested for." + }, + "count": { + "type": "integer", + "format": "int64" + } + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/hostFindingArticle/search": { + "post": { + "summary": "Search for Finding Article", + "tags": [ + "Finding Article" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "sort" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + }, + "projection": { + "type": "string" + }, + "sort": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "direction" + ], + "properties": { + "field": { + "type": "string" + }, + "direction": { + "type": "string", + "enum": [ + "ASC", + "DESC" + ] + } + } + } + }, + "page": { + "type": "integer" + }, + "size": { + "type": "integer" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "projection": "basic", + "sort": [ + { + "field": "id", + "direction": "ASC" + } + ], + "page": 0, + "size": 20 + } + } + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "object", + "required": [ + "_embedded", + "page" + ], + "properties": { + "_embedded": { + "type": "object", + "required": [ + "strings" + ], + "properties": { + "strings": { + "type": "array", + "items": { + "type": "object", + "description": "

The response structure is subject dependent. Subject structure\ncan be found via the subject endpoint.

\n" + } + } + } + }, + "page": { + "type": "object", + "required": [ + "size", + "totalElements", + "totalPages", + "number" + ], + "properties": { + "size": { + "type": "integer" + }, + "totalElements": { + "type": "integer" + }, + "totalPages": { + "type": "integer" + }, + "number": { + "type": "integer" + } + } + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "id", + "errorRefId", + "code", + "cause" + ], + "properties": { + "id": { + "type": "string", + "description": "Entity id which failed to be retrieved" + }, + "errorRefId": { + "type": "string", + "description": "A unique identifier for the error" + }, + "code": { + "type": "integer", + "description": "http status code of the error" + }, + "cause": { + "type": "string", + "description": "http status code message" + } + } + } + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/hostFindingArticle/{articleId}/history": { + "get": { + "summary": "Get Finding Article History", + "description": "Get Finding Article History", + "tags": [ + "Finding Article" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "articleId", + "in": "path", + "description": "Id/UUID of Finding Article\n", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "action": { + "type": "string" + }, + "title": { + "type": "string" + }, + "userId": { + "type": "number" + }, + "userName": { + "type": "string" + }, + "date": { + "type": "string", + "format": "date-time" + } + } + } + } + } + } + } + }, + "/client/{clientId}/applicationFindingArticle/restricted": { + "post": { + "summary": "Create Finding Article", + "description": "Create Finding Article", + "tags": [ + "Finding Article" + ], + "consumes": [ + "multipart/form-data" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "accessLevel", + "in": "formData", + "type": "string", + "enum": [ + "RESTRICTED", + "UNRESTRICTED" + ], + "required": true + }, + { + "name": "title", + "in": "formData", + "type": "string", + "required": true + }, + { + "name": "pii", + "in": "formData", + "type": "string", + "enum": [ + "None", + "Unknown", + "Direct", + "Indirect" + ], + "required": true + }, + { + "name": "proofOfExploitation", + "in": "formData", + "type": "string", + "enum": [ + "NO", + "YES", + "YES_WITH_RS3_IMPACT" + ], + "required": true + }, + { + "name": "description", + "in": "formData", + "type": "string", + "required": false + }, + { + "name": "attachments", + "in": "formData", + "description": "List of attachments for article(Multiple attachments not supported in swagger)", + "required": false, + "type": "file" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "properties": { + "id": { + "type": "number" + }, + "uuid": { + "type": "string", + "format": "uuid" + }, + "accessLevel": { + "type": "string", + "enum": [ + "RESTRICTED", + "UNRESTRICTED" + ] + }, + "findingType": { + "type": "string", + "enum": [ + "NETWORK", + "APPLICATION" + ] + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "pii": { + "type": "string", + "enum": [ + "None", + "Unknown", + "Direct", + "Indirect" + ] + }, + "proofOfExploitation": { + "type": "string", + "enum": [ + "NO", + "YES", + "YES_WITH_RS3_IMPACT" + ] + }, + "attachments": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "number" + }, + "uuid": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "fileType": { + "type": "string" + }, + "size": { + "type": "number" + }, + "downloadLink": { + "type": "string" + } + } + } + }, + "createdBy": { + "type": "string" + }, + "createdById": { + "type": "number" + }, + "createdOn": { + "type": "string", + "format": "date-time" + }, + "updatedBy": { + "type": "string" + }, + "updatedById": { + "type": "number" + }, + "updatedOn": { + "type": "string", + "format": "date-time" + } + } + } + } + } + } + }, + "/client/{clientId}/applicationFindingArticle/{articleId}/restricted": { + "put": { + "summary": "Update Finding Article", + "description": "Update Finding Article", + "tags": [ + "Finding Article" + ], + "consumes": [ + "multipart/form-data" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "articleId", + "in": "path", + "description": "Id/UUID of Finding Article\n", + "required": true, + "type": "string" + }, + { + "name": "accessLevel", + "in": "formData", + "type": "string", + "enum": [ + "RESTRICTED", + "UNRESTRICTED" + ], + "required": true + }, + { + "name": "title", + "in": "formData", + "type": "string", + "required": false + }, + { + "name": "pii", + "in": "formData", + "type": "string", + "enum": [ + "None", + "Unknown", + "Direct", + "Indirect" + ], + "required": false + }, + { + "name": "proofOfExploitation", + "in": "formData", + "type": "string", + "enum": [ + "NO", + "YES", + "YES_WITH_RS3_IMPACT" + ], + "required": false + }, + { + "name": "description", + "in": "formData", + "type": "string", + "required": false + }, + { + "name": "attachments", + "in": "formData", + "description": "List of attachments for article(Multiple attachments not supported in swagger)", + "required": false, + "type": "file" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "properties": { + "id": { + "type": "number" + }, + "uuid": { + "type": "string", + "format": "uuid" + }, + "accessLevel": { + "type": "string", + "enum": [ + "RESTRICTED", + "UNRESTRICTED" + ] + }, + "findingType": { + "type": "string", + "enum": [ + "NETWORK", + "APPLICATION" + ] + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "pii": { + "type": "string", + "enum": [ + "None", + "Unknown", + "Direct", + "Indirect" + ] + }, + "proofOfExploitation": { + "type": "string", + "enum": [ + "NO", + "YES", + "YES_WITH_RS3_IMPACT" + ] + }, + "attachments": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "number" + }, + "uuid": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "fileType": { + "type": "string" + }, + "size": { + "type": "number" + }, + "downloadLink": { + "type": "string" + } + } + } + }, + "createdBy": { + "type": "string" + }, + "createdById": { + "type": "number" + }, + "createdOn": { + "type": "string", + "format": "date-time" + }, + "updatedBy": { + "type": "string" + }, + "updatedById": { + "type": "number" + }, + "updatedOn": { + "type": "string", + "format": "date-time" + } + } + } + } + } + }, + "get": { + "summary": "Get Finding Article", + "description": "Get Finding Article", + "tags": [ + "Finding Article" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "articleId", + "in": "path", + "description": "Id/UUID of Finding Article\n", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "properties": { + "id": { + "type": "number" + }, + "uuid": { + "type": "string", + "format": "uuid" + }, + "accessLevel": { + "type": "string", + "enum": [ + "RESTRICTED", + "UNRESTRICTED" + ] + }, + "findingType": { + "type": "string", + "enum": [ + "NETWORK", + "APPLICATION" + ] + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "pii": { + "type": "string", + "enum": [ + "None", + "Unknown", + "Direct", + "Indirect" + ] + }, + "proofOfExploitation": { + "type": "string", + "enum": [ + "NO", + "YES", + "YES_WITH_RS3_IMPACT" + ] + }, + "attachments": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "number" + }, + "uuid": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "fileType": { + "type": "string" + }, + "size": { + "type": "number" + }, + "downloadLink": { + "type": "string" + } + } + } + }, + "createdBy": { + "type": "string" + }, + "createdById": { + "type": "number" + }, + "createdOn": { + "type": "string", + "format": "date-time" + }, + "updatedBy": { + "type": "string" + }, + "updatedById": { + "type": "number" + }, + "updatedOn": { + "type": "string", + "format": "date-time" + } + } + } + } + } + }, + "delete": { + "summary": "Delete Finding Article", + "description": "Delete Finding Article", + "tags": [ + "Finding Article" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "articleId", + "in": "path", + "description": "Id/UUID of Finding Article\n", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + } + } + } + }, + "/client/{clientId}/applicationFindingArticle/{articleId}/attachment/restricted": { + "get": { + "summary": "Get list of Finding Article attachments", + "description": "Get list of Finding Article attachments", + "tags": [ + "Finding Article" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "articleId", + "in": "path", + "description": "Id/UUID of Finding Article\n", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "number" + }, + "uuid": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "fileType": { + "type": "string" + }, + "size": { + "type": "number" + }, + "downloadLink": { + "type": "string" + } + } + } + } + } + } + }, + "post": { + "summary": "Add Finding Article Attachments", + "description": "Add Finding Article Attachments", + "tags": [ + "Finding Article" + ], + "consumes": [ + "multipart/form-data" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "articleId", + "in": "path", + "description": "Id/UUID of Finding Article\n", + "required": true, + "type": "string" + }, + { + "name": "attachments", + "in": "formData", + "description": "List of attachments for article(Multiple attachments not supported in swagger)", + "required": false, + "type": "file" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "number" + }, + "uuid": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "fileType": { + "type": "string" + }, + "size": { + "type": "number" + }, + "downloadLink": { + "type": "string" + } + } + } + } + } + } + } + }, + "/client/{clientId}/applicationFindingArticle/{articleId}/attachment/{attachmentId}/restricted": { + "get": { + "summary": "Download Finding Article attachment", + "description": "Download Finding Article attachment", + "tags": [ + "Finding Article" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "articleId", + "in": "path", + "description": "Id/UUID of Finding Article\n", + "required": true, + "type": "string" + }, + { + "name": "attachmentId", + "in": "path", + "description": "Id/UUID of Finding Article Attachment\n", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Success" + } + } + }, + "delete": { + "summary": "Delete Finding Article", + "description": "Delete Finding Article", + "tags": [ + "Finding Article" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "articleId", + "in": "path", + "description": "Id/UUID of Finding Article\n", + "required": true, + "type": "string" + }, + { + "name": "attachmentId", + "in": "path", + "description": "Id/UUID of Finding Article Attachment\n", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + } + } + } + }, + "/client/{clientId}/applicationFindingArticle/{articleId}/map/restricted": { + "post": { + "summary": "Map/Umap Finding Article to findings", + "description": "Map/Umap Finding Article to findings", + "tags": [ + "Finding Article" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "articleId", + "in": "path", + "description": "Id/UUID of Finding Article\n", + "required": true, + "type": "string" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "isRemove": { + "type": "boolean" + }, + "filterRequest": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "sort" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + }, + "projection": { + "type": "string" + }, + "sort": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "direction" + ], + "properties": { + "field": { + "type": "string" + }, + "direction": { + "type": "string", + "enum": [ + "ASC", + "DESC" + ] + } + } + } + }, + "page": { + "type": "integer" + }, + "size": { + "type": "integer" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "projection": "basic", + "sort": [ + { + "field": "id", + "direction": "ASC" + } + ], + "page": 0, + "size": 20 + } + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + } + } + } + }, + "/client/{clientId}/applicationFindingArticle": { + "post": { + "summary": "Create Finding Article", + "description": "Create Finding Article", + "tags": [ + "Finding Article" + ], + "consumes": [ + "multipart/form-data" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "title", + "in": "formData", + "type": "string", + "required": true + }, + { + "name": "pii", + "in": "formData", + "type": "string", + "enum": [ + "None", + "Unknown", + "Direct", + "Indirect" + ], + "required": true + }, + { + "name": "proofOfExploitation", + "in": "formData", + "type": "string", + "enum": [ + "NO", + "YES", + "YES_WITH_RS3_IMPACT" + ], + "required": true + }, + { + "name": "description", + "in": "formData", + "type": "string", + "required": false + }, + { + "name": "attachments", + "in": "formData", + "description": "List of attachments for article(Multiple attachments not supported in swagger)", + "required": false, + "type": "file" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "properties": { + "id": { + "type": "number" + }, + "uuid": { + "type": "string", + "format": "uuid" + }, + "accessLevel": { + "type": "string", + "enum": [ + "RESTRICTED", + "UNRESTRICTED" + ] + }, + "findingType": { + "type": "string", + "enum": [ + "NETWORK", + "APPLICATION" + ] + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "pii": { + "type": "string", + "enum": [ + "None", + "Unknown", + "Direct", + "Indirect" + ] + }, + "proofOfExploitation": { + "type": "string", + "enum": [ + "NO", + "YES", + "YES_WITH_RS3_IMPACT" + ] + }, + "attachments": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "number" + }, + "uuid": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "fileType": { + "type": "string" + }, + "size": { + "type": "number" + }, + "downloadLink": { + "type": "string" + } + } + } + }, + "createdBy": { + "type": "string" + }, + "createdById": { + "type": "number" + }, + "createdOn": { + "type": "string", + "format": "date-time" + }, + "updatedBy": { + "type": "string" + }, + "updatedById": { + "type": "number" + }, + "updatedOn": { + "type": "string", + "format": "date-time" + } + } + } + } + } + } + }, + "/client/{clientId}/applicationFindingArticle/{articleId}": { + "put": { + "summary": "Update Finding Article", + "description": "Update Finding Article", + "tags": [ + "Finding Article" + ], + "consumes": [ + "multipart/form-data" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "articleId", + "in": "path", + "description": "Id/UUID of Finding Article\n", + "required": true, + "type": "string" + }, + { + "name": "title", + "in": "formData", + "type": "string", + "required": false + }, + { + "name": "pii", + "in": "formData", + "type": "string", + "enum": [ + "None", + "Unknown", + "Direct", + "Indirect" + ], + "required": false + }, + { + "name": "proofOfExploitation", + "in": "formData", + "type": "string", + "enum": [ + "NO", + "YES", + "YES_WITH_RS3_IMPACT" + ], + "required": false + }, + { + "name": "description", + "in": "formData", + "type": "string", + "required": false + }, + { + "name": "attachments", + "in": "formData", + "description": "List of attachments for article(Multiple attachments not supported in swagger)", + "required": false, + "type": "file" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "properties": { + "id": { + "type": "number" + }, + "uuid": { + "type": "string", + "format": "uuid" + }, + "accessLevel": { + "type": "string", + "enum": [ + "RESTRICTED", + "UNRESTRICTED" + ] + }, + "findingType": { + "type": "string", + "enum": [ + "NETWORK", + "APPLICATION" + ] + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "pii": { + "type": "string", + "enum": [ + "None", + "Unknown", + "Direct", + "Indirect" + ] + }, + "proofOfExploitation": { + "type": "string", + "enum": [ + "NO", + "YES", + "YES_WITH_RS3_IMPACT" + ] + }, + "attachments": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "number" + }, + "uuid": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "fileType": { + "type": "string" + }, + "size": { + "type": "number" + }, + "downloadLink": { + "type": "string" + } + } + } + }, + "createdBy": { + "type": "string" + }, + "createdById": { + "type": "number" + }, + "createdOn": { + "type": "string", + "format": "date-time" + }, + "updatedBy": { + "type": "string" + }, + "updatedById": { + "type": "number" + }, + "updatedOn": { + "type": "string", + "format": "date-time" + } + } + } + } + } + }, + "get": { + "summary": "Get Finding Article", + "description": "Get Finding Article", + "tags": [ + "Finding Article" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "articleId", + "in": "path", + "description": "Id/UUID of Finding Article\n", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "properties": { + "id": { + "type": "number" + }, + "uuid": { + "type": "string", + "format": "uuid" + }, + "accessLevel": { + "type": "string", + "enum": [ + "RESTRICTED", + "UNRESTRICTED" + ] + }, + "findingType": { + "type": "string", + "enum": [ + "NETWORK", + "APPLICATION" + ] + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "pii": { + "type": "string", + "enum": [ + "None", + "Unknown", + "Direct", + "Indirect" + ] + }, + "proofOfExploitation": { + "type": "string", + "enum": [ + "NO", + "YES", + "YES_WITH_RS3_IMPACT" + ] + }, + "attachments": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "number" + }, + "uuid": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "fileType": { + "type": "string" + }, + "size": { + "type": "number" + }, + "downloadLink": { + "type": "string" + } + } + } + }, + "createdBy": { + "type": "string" + }, + "createdById": { + "type": "number" + }, + "createdOn": { + "type": "string", + "format": "date-time" + }, + "updatedBy": { + "type": "string" + }, + "updatedById": { + "type": "number" + }, + "updatedOn": { + "type": "string", + "format": "date-time" + } + } + } + } + } + }, + "delete": { + "summary": "Delete Finding Article", + "description": "Delete Finding Article", + "tags": [ + "Finding Article" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "articleId", + "in": "path", + "description": "Id/UUID of Finding Article\n", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + } + } + } + }, + "/client/{clientId}/applicationFindingArticle/{articleId}/attachment": { + "get": { + "summary": "Get list of Finding Article attachments", + "description": "Get list of Finding Article attachments", + "tags": [ + "Finding Article" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "articleId", + "in": "path", + "description": "Id/UUID of Finding Article\n", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "number" + }, + "uuid": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "fileType": { + "type": "string" + }, + "size": { + "type": "number" + }, + "downloadLink": { + "type": "string" + } + } + } + } + } + } + }, + "post": { + "summary": "Add Finding Article Attachments", + "description": "Add Finding Article Attachments", + "tags": [ + "Finding Article" + ], + "consumes": [ + "multipart/form-data" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "articleId", + "in": "path", + "description": "Id/UUID of Finding Article\n", + "required": true, + "type": "string" + }, + { + "name": "attachments", + "in": "formData", + "description": "List of attachments for article(Multiple attachments not supported in swagger)", + "required": false, + "type": "file" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "number" + }, + "uuid": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "fileType": { + "type": "string" + }, + "size": { + "type": "number" + }, + "downloadLink": { + "type": "string" + } + } + } + } + } + } + } + }, + "/client/{clientId}/applicationFindingArticle/{articleId}/attachment/{attachmentId}": { + "get": { + "summary": "Download Finding Article attachment", + "description": "Download Finding Article attachment", + "tags": [ + "Finding Article" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "articleId", + "in": "path", + "description": "Id/UUID of Finding Article\n", + "required": true, + "type": "string" + }, + { + "name": "attachmentId", + "in": "path", + "description": "Id/UUID of Finding Article Attachment\n", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Success" + } + } + }, + "delete": { + "summary": "Delete Finding Article", + "description": "Delete Finding Article", + "tags": [ + "Finding Article" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "articleId", + "in": "path", + "description": "Id/UUID of Finding Article\n", + "required": true, + "type": "string" + }, + { + "name": "attachmentId", + "in": "path", + "description": "Id/UUID of Finding Article Attachment\n", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + } + } + } + }, + "/client/{clientId}/applicationFindingArticle/{articleId}/map": { + "post": { + "summary": "Map/Umap Finding Article to findings", + "description": "Map/Umap Finding Article to findings", + "tags": [ + "Finding Article" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "articleId", + "in": "path", + "description": "Id/UUID of Finding Article\n", + "required": true, + "type": "string" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "isRemove": { + "type": "boolean" + }, + "filterRequest": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "sort" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + }, + "projection": { + "type": "string" + }, + "sort": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "direction" + ], + "properties": { + "field": { + "type": "string" + }, + "direction": { + "type": "string", + "enum": [ + "ASC", + "DESC" + ] + } + } + } + }, + "page": { + "type": "integer" + }, + "size": { + "type": "integer" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "projection": "basic", + "sort": [ + { + "field": "id", + "direction": "ASC" + } + ], + "page": 0, + "size": 20 + } + } + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "required": [ + "id", + "created" + ], + "properties": { + "id": { + "type": "integer", + "description": "Id of the created job" + }, + "created": { + "type": "string", + "description": "Datetime the job was created in the database", + "format": "date-time" + } + } + } + } + } + } + }, + "/client/{clientId}/applicationFindingArticle/model": { + "get": { + "summary": "List projections and their models", + "description": "List projections and their models that can be requested from the search endpoint.\n", + "tags": [ + "Finding Article" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "object", + "properties": { + "projections": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "fields": { + "type": "array", + "items": { + "type": "object", + "properties": { + "field": { + "type": "string" + }, + "type": { + "type": "string" + }, + "nested": { + "type": "array", + "items": { + "type": "object", + "description": "Same as ProjectionField" + } + } + } + } + } + } + } + } + }, + "example": { + "projections": [ + { + "name": "basic", + "fields": [ + { + "field": "id", + "type": "integer" + }, + { + "field": "name", + "type": "string" + } + ] + } + ] + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/applicationFindingArticle/filter": { + "get": { + "summary": "List fields that can be filtered by in the search endpoint", + "tags": [ + "Finding Article" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "array", + "items": { + "required": [ + "name", + "uid", + "operators", + "type", + "description" + ], + "properties": { + "name": { + "type": "string" + }, + "uid": { + "type": "string", + "description": "uid used to indentify fields in suggest and search requests" + }, + "operators": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + } + }, + "datatype": { + "type": "string" + }, + "description": { + "type": "string" + } + } + }, + "example": [ + { + "name": "id", + "uid": "id", + "operator": [ + "EXACT", + "IN" + ], + "type": "integer", + "description": "The id" + } + ] + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/applicationFindingArticle/suggest": { + "post": { + "summary": "Suggest values for filter fields", + "tags": [ + "Finding Article" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "filter" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + }, + "description": "Filters to used to narrow down the the result set\n" + }, + "filter": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + }, + "description": "Filter for which to suggest values for. The filter value will be\ntreated as a wildcard.\n" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": true, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "filter": { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "" + } + } + } + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key", + "count" + ], + "properties": { + "key": { + "type": "string", + "description": "Value for the field the suggestion was requested for." + }, + "count": { + "type": "integer", + "format": "int64" + } + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/applicationFindingArticle/search": { + "post": { + "summary": "Search for Finding Article", + "tags": [ + "Finding Article" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "sort" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + }, + "projection": { + "type": "string" + }, + "sort": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "direction" + ], + "properties": { + "field": { + "type": "string" + }, + "direction": { + "type": "string", + "enum": [ + "ASC", + "DESC" + ] + } + } + } + }, + "page": { + "type": "integer" + }, + "size": { + "type": "integer" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "projection": "basic", + "sort": [ + { + "field": "id", + "direction": "ASC" + } + ], + "page": 0, + "size": 20 + } + } + } + ], + "responses": { + "200": { + "description": "Ok", + "schema": { + "type": "object", + "required": [ + "_embedded", + "page" + ], + "properties": { + "_embedded": { + "type": "object", + "required": [ + "strings" + ], + "properties": { + "strings": { + "type": "array", + "items": { + "type": "object", + "description": "

The response structure is subject dependent. Subject structure\ncan be found via the subject endpoint.

\n" + } + } + } + }, + "page": { + "type": "object", + "required": [ + "size", + "totalElements", + "totalPages", + "number" + ], + "properties": { + "size": { + "type": "integer" + }, + "totalElements": { + "type": "integer" + }, + "totalPages": { + "type": "integer" + }, + "number": { + "type": "integer" + } + } + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "required": [ + "id", + "errorRefId", + "code", + "cause" + ], + "properties": { + "id": { + "type": "string", + "description": "Entity id which failed to be retrieved" + }, + "errorRefId": { + "type": "string", + "description": "A unique identifier for the error" + }, + "code": { + "type": "integer", + "description": "http status code of the error" + }, + "cause": { + "type": "string", + "description": "http status code message" + } + } + } + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/client/{clientId}/applicationFindingArticle/{articleId}/history": { + "get": { + "summary": "Get Finding Article History", + "description": "Get Finding Article History", + "tags": [ + "Finding Article" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Id of client (This parameter can be obtained via the GET method on '/client')\n", + "required": true, + "type": "integer" + }, + { + "name": "articleId", + "in": "path", + "description": "Id/UUID of Finding Article\n", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "action": { + "type": "string" + }, + "title": { + "type": "string" + }, + "userId": { + "type": "number" + }, + "userName": { + "type": "string" + }, + "date": { + "type": "string", + "format": "date-time" + } + } + } + } + } + } + } + } + }, + "definitions": { + "Attributes_UsernameAndPassword": { + "type": "object", + "required": [ + "username", + "password" + ], + "properties": { + "username": { + "type": "string" + }, + "password": { + "type": "string" + } + } + }, + "Attributes_Nessus": { + "type": "object", + "required": [ + "accessKey", + "secretKey" + ], + "properties": { + "accessKey": { + "type": "string" + }, + "secretKey": { + "type": "string" + } + } + }, + "Attributes_Nexpose": { + "type": "object", + "required": [ + "username", + "password", + "filterValues" + ], + "properties": { + "username": { + "type": "string" + }, + "password": { + "type": "string" + }, + "filterValues": { + "description": "Obtaining a list of filterValues can be obtained using\nthe Nexpose API. See the Nexpose API documentation here:\nhttps://www.rapid7.com/docs/download/Nexpose_API_guide.pdf\n", + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "filterType": { + "type": "string", + "enum": [ + "ASSET_GROUP", + "SITE_ID", + "TAG" + ] + } + } + } + } + } + }, + "Attributes_Cenzic_Hailstorm": { + "type": "object", + "required": [ + "client", + "customerId", + "applications" + ], + "properties": { + "client": { + "type": "string" + }, + "customerId": { + "type": "string" + }, + "applications": { + "type": "array", + "description": "Array of application names", + "items": { + "type": "string" + } + } + } + }, + "Attributes_Remedy": { + "type": "object", + "required": [ + "username", + "password", + "requestingUserFirstName", + "requestingUserLastName", + "impact", + "urgency", + "reportedSource", + "serviceType", + "initialStatus", + "remediatedStatus", + "assignedGroup", + "assignee" + ], + "properties": { + "username": { + "type": "string" + }, + "password": { + "type": "string" + }, + "requestingUserFirstName": { + "type": "string" + }, + "requestingUserLastName": { + "type": "string" + }, + "impact": { + "type": "string" + }, + "urgency": { + "type": "string" + }, + "reportedSource": { + "type": "string" + }, + "serviceType": { + "type": "string" + }, + "initialStatus": { + "type": "string" + }, + "remediatedStatus": { + "type": "string" + }, + "assignedGroup": { + "type": "string" + }, + "assignee": { + "type": "string" + } + } + }, + "Attributes_ServiceNow": { + "type": "object", + "required": [ + "username", + "password", + "assignmentGroup", + "assignTo", + "caller", + "category", + "subcategory", + "remediatedState", + "initialState", + "impact", + "priority", + "urgency" + ], + "properties": { + "username": { + "type": "string" + }, + "password": { + "type": "string" + }, + "assignmentGroup": { + "type": "string", + "description": "Reference identifier of assignment group" + }, + "assignTo": { + "type": "string", + "description": "Reference identifier of assignTo" + }, + "caller": { + "type": "string", + "description": "Reference identifier of caller" + }, + "category": { + "type": "string" + }, + "subcategory": { + "type": "string" + }, + "remediatedState": { + "type": "integer", + "description": "Reference identifier of remediated state" + }, + "initialState": { + "type": "integer", + "description": "Reference identifier of initial state" + }, + "impact": { + "type": "integer", + "description": "Reference identifier of impact" + }, + "priority": { + "type": "integer", + "description": "Reference identifier of priority" + }, + "urgency": { + "type": "integer", + "description": "Reference identifier of urgency" + } + } + }, + "Attributes_WhiteHat": { + "type": "object", + "required": [ + "apiKey" + ], + "properties": { + "apiKey": { + "type": "string" + } + } + }, + "ConnectorField_Jira": { + "type": "object", + "required": [ + "type", + "connectorSettings", + "descriptionFields", + "dynamicFields", + "issueType", + "lockedFields", + "project", + "tagSyncField" + ], + "properties": { + "type": { + "type": "string", + "description": "should be 'JIRA'\n" + }, + "connectorSettings": { + "type": "object", + "required": [ + "initialState", + "enabledTagRemoval", + "closeTicketOnFindingsCloseEnabled", + "closedStateKey", + "closedStateLabel" + ], + "properties": { + "initialState": { + "type": "string", + "description": "Initial state of the ticket which is used to create a ticket using this connector." + }, + "enabledTagRemoval": { + "type": "boolean", + "description": "True if the user allows the deletion of tags associated with this connector, otherwise false." + }, + "closeTicketOnFindingsCloseEnabled": { + "type": "boolean", + "description": "True if enable changing the ticket state to the set state when all the associated findings reach to the close state.\n" + }, + "closedStateKey": { + "type": "string", + "description": "the close state value of the status." + }, + "closedStateLabel": { + "type": "string", + "description": "the close state label of the status." + } + } + }, + "descriptionFields": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key", + "enabled" + ], + "properties": { + "key": { + "type": "string", + "description": "Description field key" + }, + "enabled": { + "type": "boolean", + "description": "True when description field key is enabled else False" + } + } + } + }, + "dynamicFields": { + "type": "object", + "required": [ + "key", + "value" + ], + "properties": { + "key": { + "type": "string", + "description": "Field key" + }, + "value": { + "type": "string", + "description": "Field value" + }, + "displayValue": { + "type": "string", + "description": "Label of the value." + } + } + }, + "issueType": { + "type": "object", + "required": [ + "displayValue", + "value" + ], + "properties": { + "displayValue": { + "type": "string", + "description": "Label of the Field." + }, + "value": { + "type": "string", + "description": "Id of the Field." + } + }, + "description": "Selected issue type." + }, + "lockedFields": { + "type": "array", + "items": { + "type": "string", + "description": "Key of the field." + } + }, + "project": { + "type": "object", + "required": [ + "displayValue", + "value" + ], + "properties": { + "displayValue": { + "type": "string", + "description": "Label of the Field." + }, + "value": { + "type": "string", + "description": "Id of the Field." + } + }, + "description": "selected project." + }, + "tagSyncField": { + "type": "string", + "description": "Value of Tag Name Sync Field. This field is populated with the tag name while creating tickets." + } + } + }, + "ConnectorField_ServiceNow": { + "type": "object", + "required": [ + "type", + "defaultTemplateId", + "templates", + "descriptionFields", + "defaultSupportedFieldValues", + "tagSyncField", + "connectorSettings" + ], + "properties": { + "type": { + "type": "string", + "description": "Should be 'SERVICE_NOW'.\n" + }, + "defaultTemplateId": { + "type": "string", + "description": "Optional default template Id." + }, + "templates": { + "type": "array", + "items": { + "type": "object", + "description": "SERVICE_NOW field only.", + "required": [ + "id", + "name", + "locked" + ], + "properties": { + "id": { + "type": "string", + "description": "Template Id" + }, + "name": { + "type": "string", + "description": "Template name" + }, + "locked": { + "type": "boolean", + "description": "The selected template is locked or not. Locked implies that you\nwill not be able to edit those fields and unlocked implies that\nyou can edit the fields which are supported by Ivanti Neurons.\n" + } + } + } + }, + "descriptionFields": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key", + "enabled" + ], + "properties": { + "key": { + "type": "string", + "description": "Description field key" + }, + "enabled": { + "type": "boolean", + "description": "True when description field key is enabled else False" + } + } + } + }, + "defaultSupportedFieldValues": { + "type": "object", + "required": [ + "key", + "value" + ], + "properties": { + "key": { + "type": "string", + "description": "Field key" + }, + "value": { + "type": "string", + "description": "Field value" + }, + "displayValue": { + "type": "string", + "description": "Label of the value." + } + } + }, + "tagSyncField": { + "type": "string", + "description": "Value of Tag Name Sync Field. This field is populated with the tag name while creating tickets." + }, + "connectorSettings": { + "type": "object", + "required": [ + "initialState", + "enabledTagRemoval", + "closeTicketOnFindingsCloseEnabled", + "closedStateKey", + "closedStateLabel" + ], + "properties": { + "initialState": { + "type": "string", + "description": "Initial state of the ticket which is used to create a ticket using this connector." + }, + "enabledTagRemoval": { + "type": "boolean", + "description": "True if the user allows the deletion of tags associated with this connector, otherwise false." + }, + "closeTicketOnFindingsCloseEnabled": { + "type": "boolean", + "description": "True if enable changing the ticket state to the set state when all the associated findings reach to the close state.\n" + }, + "closedStateKey": { + "type": "string", + "description": "the close state value of the status." + }, + "closedStateLabel": { + "type": "string", + "description": "the close state label of the status." + } + } + }, + "selectedOptionalFields": { + "type": "array", + "description": "Optional fields that are rendered in create ticket form apart from required fields.\n", + "items": { + "type": "string", + "description": "field key." + } + } + } + }, + "ConnectorField_SnowServiceRequest": { + "type": "object", + "required": [ + "type", + "catalog", + "category", + "catalogItem", + "descriptionFields", + "defaultSupportedFieldValues", + "dynamicFields", + "tagSyncField", + "connectorSettings" + ], + "properties": { + "type": { + "type": "string", + "description": "Should be 'SNOW_SERVICE_REQUEST'.\n" + }, + "catalog": { + "type": "string", + "description": "Catalog type." + }, + "category": { + "type": "string", + "description": "Category type." + }, + "catalogItem": { + "type": "string", + "description": "Catalog Item type." + }, + "descriptionFields": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key", + "enabled" + ], + "properties": { + "key": { + "type": "string", + "description": "Description field key" + }, + "enabled": { + "type": "boolean", + "description": "True when description field key is enabled else False" + } + } + } + }, + "defaultSupportedFieldValues": { + "type": "object", + "required": [ + "key", + "value" + ], + "properties": { + "key": { + "type": "string", + "description": "Field key" + }, + "value": { + "type": "string", + "description": "Field value" + }, + "displayValue": { + "type": "string", + "description": "Label of the value." + } + } + }, + "dynamicFields": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key", + "value" + ], + "properties": { + "key": { + "type": "string", + "description": "Field key" + }, + "value": { + "type": "string", + "description": "Field value" + }, + "displayValue": { + "type": "string", + "description": "Label of the value." + } + } + } + }, + "tagSyncField": { + "type": "string", + "description": "Value of Tag Name Sync Field. This field is populated with the tag name while creating tickets." + }, + "connectorSettings": { + "type": "object", + "required": [ + "initialState", + "enabledTagRemoval", + "closeTicketOnFindingsCloseEnabled", + "closedStateKey", + "closedStateLabel" + ], + "properties": { + "initialState": { + "type": "string", + "description": "Initial state of the ticket which is used to create a ticket using this connector." + }, + "enabledTagRemoval": { + "type": "boolean", + "description": "True if the user allows the deletion of tags associated with this connector, otherwise false." + }, + "closeTicketOnFindingsCloseEnabled": { + "type": "boolean", + "description": "True if enable changing the ticket state to the set state when all the associated findings reach to the close state.\n" + }, + "closedStateKey": { + "type": "string", + "description": "the close state value of the status." + }, + "closedStateLabel": { + "type": "string", + "description": "the close state label of the status." + } + } + } + } + }, + "ConnectorField_GenericSnow": { + "type": "object", + "required": [ + "type", + "tableName", + "statusField", + "enabledTagRemoval", + "descriptionFieldToTableFields", + "tableFields" + ], + "properties": { + "type": { + "type": "string", + "description": "Should be 'GENERIC_SNOW'.\n" + }, + "tableName": { + "type": "string", + "description": "Name of the servicenow table in which ticket needs to be created." + }, + "statusField": { + "type": "string", + "description": "Status field to track status of the ticket." + }, + "enabledTagRemoval": { + "type": "boolean", + "description": "True if the user allows the deletion of tags associated with this connector, otherwise false." + }, + "descriptionFieldToTableFields": { + "type": "array", + "items": { + "type": "object", + "required": [ + "descriptionField", + "tableField" + ], + "properties": { + "descriptionField": { + "type": "string", + "description": "Tag description field key." + }, + "tableField": { + "type": "string", + "description": "Table field key in servicenow to which the description field value needs to be populate." + } + } + } + }, + "tableFields": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key", + "value" + ], + "properties": { + "key": { + "type": "string", + "description": "Table field key in servicenow." + }, + "value": { + "type": "string", + "description": "Table field value." + } + } + } + } + } + }, + "ConnectorPopulate_ServiceNow": { + "type": "object", + "required": [ + "templates", + "supportedFields", + "supportedDescriptionFields", + "enabledTagRemoval", + "tagSyncField", + "tagSyncFieldOptions", + "connectorSettings", + "selectedOptionalFields", + "unSupportedFields" + ], + "properties": { + "templates": { + "type": "array", + "items": { + "type": "object", + "required": [ + "sysId", + "name", + "tableName", + "isDefault", + "isLocked", + "isCurrentlySelected", + "fields" + ], + "properties": { + "sysId": { + "type": "string", + "description": "This is the id of the template" + }, + "name": { + "type": "string", + "description": "This is the name of the template" + }, + "tableName": { + "type": "string", + "description": "This is the table name of the template" + }, + "isDefault": { + "type": "boolean", + "description": "In case of editing the connector,this is true only if it is a default template and it is true for only one of the template.\nIn case of creating the connector, this is always false.\n" + }, + "isLocked": { + "type": "boolean", + "description": "In case of editing the connector,this is true only if user is not allowed to change the template fields.\nIn case of creating the connector, this is always false.\n" + }, + "isCurrentlySelected": { + "type": "boolean", + "description": "True if user has selected this template while creating the connector otherwise False.\n" + }, + "fields": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key", + "label", + "value" + ], + "properties": { + "key": { + "type": "string", + "description": "This is empty string if this field is not supported by the risksense or\nthis is the key of the supportedfields for this type of connector.\n" + }, + "label": { + "type": "string", + "description": "This is the label of field which is used to display.\n" + }, + "value": { + "type": "string", + "description": "This is the value of the field. Even it is integer, boolean they has to passed as string.\n" + } + } + } + } + } + }, + "description": "Connector template." + }, + "supportedFields": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key", + "label", + "type", + "value", + "required", + "locked", + "isSupported", + "selectOptions", + "fields", + "queryParameters", + "dependentKey" + ], + "properties": { + "key": { + "type": "string", + "description": "Key of the field." + }, + "label": { + "type": "string", + "description": "Label of field." + }, + "type": { + "type": "string", + "description": "

Type of Field used to display.The types are

\n
    \n
  • boolean: Used for CheckBox field
  • \n
  • date: Used for Date field
  • \n
  • multiSelect: Used for the multiselect dropdown field
  • \n
  • number: Used for Number field
  • \n
  • radio: Used for Radio button field
  • \n
  • referenceDropdown: Used for the dropdown view where dropdown options are fetched dynamically.
  • \n
  • referenceMultiSelect: Used for the multiselect dropdown view where dropdown options are fetched dynamically.
  • \n
  • section: Used for Section field. This field only supported in SNOW_SERVICE_REQUEST connector type.
  • \n
  • string: Used for single line text field
  • \n
  • textArea: Used for TextArea field
  • \n
  • valueDropdown: Used for the dropdown field
  • \n
\n" + }, + "value": { + "type": "string", + "description": "Value of the field which was set when creating the connector otherwise empty string.\n" + }, + "required": { + "type": "boolean", + "description": "This variable shows whether this field is required or not. If it is required, it cannot be sumbitted as empty.\n" + }, + "locked": { + "type": "boolean", + "description": "True if the field value is not allowed to edit, otherwise false.\n" + }, + "isSupported": { + "type": "boolean", + "description": "True for all supported fields." + }, + "selectOptions": { + "type": "array", + "items": { + "type": "object", + "required": [ + "displayValue", + "value", + "isCurrentlySelected" + ], + "properties": { + "displayValue": { + "type": "string", + "description": "Label of the Field." + }, + "value": { + "type": "string", + "description": "Id of the Field." + }, + "isCurrentlySelected": { + "type": "boolean", + "description": "True if previously selected this option otherwise false.\nAvailable only if the type is 'referenceMultiSelect' or 'multiSelect'.\n" + } + } + } + }, + "fields": { + "type": "array", + "items": {}, + "description": "Available if the type is 'section'. This is same as parent field.\n" + }, + "queryParameters": { + "description": "Available only if the type is 'referenceDropdown' or 'referenceMultiSelect'", + "type": "object", + "required": [ + "table", + "filter", + "fieldName" + ], + "properties": { + "table": { + "type": "string", + "description": "Table name from which dropdown options are fetched. This is a 'SNOW_SERVICE_REQUEST' and 'SERVICE_NOW' request field." + }, + "filter": { + "type": "string", + "description": "Table filter to filter the records. This is a 'SNOW_SERVICE_REQUEST' and 'SERVICE_NOW' request field." + }, + "fieldName": { + "type": "string", + "description": "Field Name for which dropdown options are fetched. This is a 'JIRA' request field." + } + } + }, + "dependentKey": { + "type": "string", + "description": "Key of dependent field. Dropdown options for this field is dependent on value of this\nfield to which this key belongs. Available only if the type is 'referenceDropdown'\n" + } + } + }, + "description": "List of fields." + }, + "supportedDescriptionFields": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key", + "label", + "isCurrentlySelected" + ], + "properties": { + "key": { + "type": "string", + "description": "Key of the SupportedDescriptionField." + }, + "label": { + "type": "string", + "description": "Label of field which is used to display." + }, + "isCurrentlySelected": { + "type": "boolean", + "description": "True if user has selected this Description Field while creating the connector otherwise false.\n" + } + } + } + }, + "enabledTagRemoval": { + "type": "boolean", + "description": "Allow tag to be removed or not." + }, + "tagSyncField": { + "type": "string", + "description": "Value of Tag Sync Field which was set when creating the connector otherwise empty string.\n" + }, + "tagSyncFieldOptions": { + "type": "array", + "items": { + "type": "object", + "required": [ + "displayValue", + "value" + ], + "properties": { + "displayValue": { + "type": "string", + "description": "Label of the Field." + }, + "value": { + "type": "string", + "description": "Id of the Field." + } + } + } + }, + "connectorSettings": { + "type": "object", + "required": [ + "initialState", + "statusOptions", + "closeTicketOnFindingsCloseEnabled", + "closedStateKey" + ], + "properties": { + "initialState": { + "type": "string", + "description": "Initial state of the ticket which is used to create a ticket using this connector." + }, + "statusOptions": { + "type": "array", + "items": { + "type": "object", + "required": [ + "displayValue", + "value" + ], + "properties": { + "displayValue": { + "type": "string", + "description": "Label of the Field." + }, + "value": { + "type": "string", + "description": "Id of the Field." + } + } + } + }, + "closeTicketOnFindingsClose": { + "type": "boolean", + "description": "True if enable changing the ticket state to the set state when all the associated findings reach the close state.\n" + }, + "closedStateKey": { + "type": "string", + "description": "the close state value of the status." + } + } + }, + "selectedOptionalFields": { + "type": "array", + "description": "Optional fields that are rendered in create ticket form apart from required fields.\n", + "items": { + "type": "string", + "description": "Field key." + } + }, + "unSupportedFields": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key", + "label", + "value", + "isSupported" + ], + "properties": { + "key": { + "type": "string", + "description": "Key of the field." + }, + "label": { + "type": "string", + "description": "Label of field." + }, + "value": { + "type": "string", + "description": "Value of the field which was set when creating the connector otherwise empty string.\n" + }, + "isSupported": { + "type": "boolean", + "description": "false for all unsupported Fields." + } + } + } + } + } + }, + "ConnectorPopulate_SnowServiceRequest": { + "type": "object", + "required": [ + "currentlySelectedCatalog", + "catalogs", + "supportedDescriptionFields", + "supportedFields", + "enabledTagRemoval" + ], + "properties": { + "currentlySelectedCatalog": { + "type": "string", + "description": "Current selected catalog system id." + }, + "catalogs": { + "type": "array", + "items": { + "type": "object", + "required": [ + "displayValue", + "value" + ], + "properties": { + "displayValue": { + "type": "string", + "description": "Label of the Field." + }, + "value": { + "type": "string", + "description": "Id of the Field." + } + } + }, + "description": "Catalogs on Service Now." + }, + "supportedDescriptionFields": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key", + "label", + "isCurrentlySelected" + ], + "properties": { + "key": { + "type": "string", + "description": "Key of the SupportedDescriptionField." + }, + "label": { + "type": "string", + "description": "Label of field which is used to display." + }, + "isCurrentlySelected": { + "type": "boolean", + "description": "True if user has selected this Description Field while creating the connector otherwise false.\n" + } + } + } + }, + "supportedFields": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key", + "label", + "type", + "value", + "required", + "locked", + "isSupported", + "selectOptions", + "fields", + "queryParameters", + "dependentKey" + ], + "properties": { + "key": { + "type": "string", + "description": "Key of the field." + }, + "label": { + "type": "string", + "description": "Label of field." + }, + "type": { + "type": "string", + "description": "

Type of Field used to display.The types are

\n
    \n
  • boolean: Used for CheckBox field
  • \n
  • date: Used for Date field
  • \n
  • multiSelect: Used for the multiselect dropdown field
  • \n
  • number: Used for Number field
  • \n
  • radio: Used for Radio button field
  • \n
  • referenceDropdown: Used for the dropdown view where dropdown options are fetched dynamically.
  • \n
  • referenceMultiSelect: Used for the multiselect dropdown view where dropdown options are fetched dynamically.
  • \n
  • section: Used for Section field. This field only supported in SNOW_SERVICE_REQUEST connector type.
  • \n
  • string: Used for single line text field
  • \n
  • textArea: Used for TextArea field
  • \n
  • valueDropdown: Used for the dropdown field
  • \n
\n" + }, + "value": { + "type": "string", + "description": "Value of the field which was set when creating the connector otherwise empty string.\n" + }, + "required": { + "type": "boolean", + "description": "This variable shows whether this field is required or not. If it is required, it cannot be sumbitted as empty.\n" + }, + "locked": { + "type": "boolean", + "description": "True if the field value is not allowed to edit, otherwise false.\n" + }, + "isSupported": { + "type": "boolean", + "description": "True for all supported fields." + }, + "selectOptions": { + "type": "array", + "items": { + "type": "object", + "required": [ + "displayValue", + "value", + "isCurrentlySelected" + ], + "properties": { + "displayValue": { + "type": "string", + "description": "Label of the Field." + }, + "value": { + "type": "string", + "description": "Id of the Field." + }, + "isCurrentlySelected": { + "type": "boolean", + "description": "True if previously selected this option otherwise false.\nAvailable only if the type is 'referenceMultiSelect' or 'multiSelect'.\n" + } + } + } + }, + "fields": { + "type": "array", + "items": {}, + "description": "Available if the type is 'section'. This is same as parent field.\n" + }, + "queryParameters": { + "description": "Available only if the type is 'referenceDropdown' or 'referenceMultiSelect'", + "type": "object", + "required": [ + "table", + "filter", + "fieldName" + ], + "properties": { + "table": { + "type": "string", + "description": "Table name from which dropdown options are fetched. This is a 'SNOW_SERVICE_REQUEST' and 'SERVICE_NOW' request field." + }, + "filter": { + "type": "string", + "description": "Table filter to filter the records. This is a 'SNOW_SERVICE_REQUEST' and 'SERVICE_NOW' request field." + }, + "fieldName": { + "type": "string", + "description": "Field Name for which dropdown options are fetched. This is a 'JIRA' request field." + } + } + }, + "dependentKey": { + "type": "string", + "description": "Key of dependent field. Dropdown options for this field is dependent on value of this\nfield to which this key belongs. Available only if the type is 'referenceDropdown'\n" + } + } + } + }, + "enabledTagRemoval": { + "type": "boolean", + "description": "Allow tag to be removed or not." + } + } + }, + "ConnectorPopulate_Jira": { + "type": "object", + "required": [ + "currentlySelectedProject", + "projects", + "supportedDescriptionFields", + "enabledTagRemoval" + ], + "properties": { + "currentlySelectedProject": { + "type": "string", + "description": "Current selected project key." + }, + "projects": { + "type": "array", + "items": { + "type": "object", + "required": [ + "displayValue", + "value" + ], + "properties": { + "displayValue": { + "type": "string", + "description": "Label of the Field." + }, + "value": { + "type": "string", + "description": "Id of the Field." + } + } + }, + "description": "Projects on Jira." + }, + "supportedDescriptionFields": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key", + "label", + "isCurrentlySelected" + ], + "properties": { + "key": { + "type": "string", + "description": "Key of the SupportedDescriptionField." + }, + "label": { + "type": "string", + "description": "Label of field which is used to display." + }, + "isCurrentlySelected": { + "type": "boolean", + "description": "True if user has selected this Description Field while creating the connector otherwise false.\n" + } + } + } + }, + "enabledTagRemoval": { + "type": "boolean", + "description": "Allow tag to be removed or not." + } + } + }, + "ConnectorPopulate_GenericSnow": { + "type": "object", + "required": [ + "tableName", + "statusField", + "enabledTagRemoval", + "descriptionFieldToTableFields", + "tableFields", + "descriptionFieldDropDownOptions" + ], + "properties": { + "tableName": { + "type": "string", + "description": "Name of the servicenow table in which ticket needs to be created." + }, + "statusField": { + "type": "string", + "description": "Status field to track status of the ticket." + }, + "enabledTagRemoval": { + "type": "boolean", + "description": "True if the user allows the deletion of tags associated with this connector, otherwise false." + }, + "descriptionFieldToTableFields": { + "type": "array", + "items": { + "type": "object", + "required": [ + "descriptionField", + "tableField" + ], + "properties": { + "descriptionField": { + "type": "string", + "description": "Tag description field key." + }, + "tableField": { + "type": "string", + "description": "Table field key in servicenow to which the description field value needs to be populate." + } + } + } + }, + "tableFields": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key", + "value" + ], + "properties": { + "key": { + "type": "string", + "description": "Table field key in servicenow." + }, + "value": { + "type": "string", + "description": "Table field value." + } + } + } + }, + "descriptionFieldDropDownOptions": { + "type": "array", + "items": { + "type": "object", + "required": [ + "displayValue", + "value" + ], + "properties": { + "displayValue": { + "type": "string", + "description": "Label of the Field." + }, + "value": { + "type": "string", + "description": "Id of the Field." + } + } + } + } + } + }, + "CreateTicketRequest_ServiceNow_Incident": { + "type": "object", + "required": [ + "connectorId", + "type", + "templateId", + "fields" + ], + "properties": { + "connectorId": { + "type": "integer", + "description": "Id of the connector." + }, + "type": { + "type": "string", + "description": "Should be 'SERVICE_NOW'.\n" + }, + "templateId": { + "type": "string", + "description": "This can be either \"None\" or can be one of the templateId's which are linked with this connector.\n" + }, + "fields": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key", + "value" + ], + "properties": { + "key": { + "type": "string", + "description": "Field key" + }, + "value": { + "type": "string", + "description": "Field value" + }, + "displayValue": { + "type": "string", + "description": "Label of the value" + } + } + } + } + } + }, + "CreateTicketRequest_ServiceNow_ServiceRequest": { + "type": "object", + "required": [ + "connectorId", + "type", + "dynamicFields" + ], + "properties": { + "connectorId": { + "type": "integer", + "description": "Id of the connector." + }, + "type": { + "type": "string", + "description": "Should be 'SNOW_SERVICE_REQUEST'.\n" + }, + "dynamicFields": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key", + "value" + ], + "properties": { + "key": { + "type": "string", + "description": "Field key" + }, + "value": { + "type": "string", + "description": "Field value" + }, + "displayValue": { + "type": "string", + "description": "Label of the value" + } + } + } + } + } + }, + "CreateTicketRequest_Jira": { + "type": "object", + "required": [ + "connectorId", + "type", + "dynamicFields" + ], + "properties": { + "connectorId": { + "type": "integer", + "description": "Id of the connector." + }, + "type": { + "type": "string", + "description": "Should be 'JIRA'.\n" + }, + "dynamicFields": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key", + "value" + ], + "properties": { + "key": { + "type": "string", + "description": "Field key" + }, + "value": { + "type": "string", + "description": "Field value" + }, + "displayValue": { + "type": "string", + "description": "Label of the value" + } + } + } + } + } + }, + "CreateTicketRequest_ServiceNow_Generic": { + "type": "object", + "required": [ + "connectorId", + "type", + "fields" + ], + "properties": { + "connectorId": { + "type": "integer", + "description": "Id of the connector." + }, + "type": { + "type": "string", + "description": "Should be 'GENERIC_SNOW'.\n" + }, + "fields": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key", + "value" + ], + "properties": { + "key": { + "type": "string", + "description": "Field key" + }, + "value": { + "type": "string", + "description": "Field value" + }, + "displayValue": { + "type": "string", + "description": "Label of the value" + } + } + } + } + } + }, + "PlaybookRuleDeserialized": { + "type": "object", + "required": [ + "name", + "description", + "input", + "actionType", + "action", + "outputType", + "output" + ], + "properties": { + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "input": { + "type": "string", + "enum": [ + "HOST", + "HOST_FINDING", + "APPLICATION", + "APPLICATION_FINDING" + ] + }, + "actionType": { + "type": "string", + "enum": [ + "GROUP_MOVE", + "SEVERITY_CHANGE" + ] + }, + "action": { + "type": "object", + "description": "

Structure is dependent on the action type field.\nThe referenced structures can be found at the bottom of this document.

\n
    \n
  • ASSIGNMENT: PlaybookActionConfig_AssignUnassign
  • \n
  • UNASSIGNMENT: PlaybookActionConfig_AssignUnassign
  • \n
  • DUE_DATE_EXPLICIT: PlaybookActionConfig_Due_Date_EXPLICIT
  • \n
  • DUE_DATE_OFFSET: PlaybookActionConfig_Due_Date_OFFSET
  • \n
  • DUE_DATE_REMOVE: PlaybookActionConfig_Due_Date_REMOVE
  • \n
  • SEVERITY_CHANGE: PlaybookActionConfig_Severity_Change
  • \n
  • TAG_APPLY: PlaybookActionConfig_TagApplyUnapply
  • \n
  • TAG_UNAPPLY: PlaybookActionConfig_TagApplyUnapply
  • \n
  • ADD_TO_GROUP: PlaybookActionConfig_AddToGroup
  • \n
  • REMOVE_FROM_GROUP: PlaybookActionConfig_RemoveFromGroup
  • \n
  • UPDATE_BUSINESS_CRITICALITY: PlaybookActionConfig_AssetUpdate
  • \n
  • UPDATE_IP_ADDRESS_TYPE: PlaybookActionConfig_AssetUpdate
  • \n
  • REMEDIATION_SLA: PlaybookActionConfig_AssetUpdate
  • \n
\n" + }, + "outputType": { + "type": "string", + "enum": [ + "EMAIL", + "NO_OUTPUT", + "WEBHOOK" + ] + }, + "output": { + "type": "object", + "description": "

Structure is dependent on the output type field.\nThe referenced structures can be found at the bottom of this document.

\n
    \n
  • EMAIL: PlaybookOutputConfig_Email
  • \n
\n" + } + }, + "example": { + "name": "Example Rule", + "description": "This rule will add hosts with IDs 1, 2, 3 to the group with ID 42", + "input": "HOST", + "actionType": "ADD_TO_GROUP", + "action": { + "targetGroupIds": [ + 42 + ], + "filterRequest": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3" + } + ] + } + }, + "outputType": "EMAIL", + "output": { + "targetUsernames": [ + "firstLastUsername" + ], + "subject": "New set of hosts moved to group alpha", + "message": "Here to inform you the group move completed.", + "includeOperationalSummary": true + } + } + }, + "PlaybookActionConfig_AssignUnassign": { + "type": "object", + "required": [ + "filterRequest", + "userIds" + ], + "properties": { + "filterRequest": { + "description": "Filter for finding assignment and unassignment job requests", + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "orWithPrevious", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values" + }, + "exclusive": { + "type": "boolean" + }, + "orWithPrevious": { + "description": "This optional field can be used to provide OR functionality for filters.", + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values" + } + } + } + } + } + }, + "userIds": { + "description": "Collection of user Ids to assign/unassign findings to/from.", + "type": "array", + "items": { + "type": "integer" + } + } + } + }, + "PlaybookActionConfig_Due_Date_Explicit": { + "type": "object", + "required": [ + "dueDate", + "filterRequest" + ], + "properties": { + "dueDate": { + "type": "string" + }, + "filterRequest": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "sort" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + }, + "projection": { + "type": "string" + }, + "sort": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "direction" + ], + "properties": { + "field": { + "type": "string" + }, + "direction": { + "type": "string", + "enum": [ + "ASC", + "DESC" + ] + } + } + } + }, + "page": { + "type": "integer" + }, + "size": { + "type": "integer" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "projection": "basic", + "sort": [ + { + "field": "id", + "direction": "ASC" + } + ], + "page": 0, + "size": 20 + } + } + } + }, + "PlaybookActionConfig_Due_Date_Offset": { + "type": "object", + "required": [ + "offset", + "filterRequest" + ], + "properties": { + "offset": { + "type": "integer", + "description": "Offset is days\n" + }, + "filterRequest": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "sort" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + }, + "projection": { + "type": "string" + }, + "sort": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "direction" + ], + "properties": { + "field": { + "type": "string" + }, + "direction": { + "type": "string", + "enum": [ + "ASC", + "DESC" + ] + } + } + } + }, + "page": { + "type": "integer" + }, + "size": { + "type": "integer" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "projection": "basic", + "sort": [ + { + "field": "id", + "direction": "ASC" + } + ], + "page": 0, + "size": 20 + } + } + } + }, + "PlaybookActionConfig_Due_Date_Remove": { + "type": "object", + "required": [ + "filterRequest" + ], + "properties": { + "filterRequest": { + "description": "A series of filters that make up a complete filter to be used in a request", + "type": "object", + "required": [ + "filters", + "sort" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + }, + "projection": { + "type": "string" + }, + "sort": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "direction" + ], + "properties": { + "field": { + "type": "string" + }, + "direction": { + "type": "string", + "enum": [ + "ASC", + "DESC" + ] + } + } + } + }, + "page": { + "type": "integer" + }, + "size": { + "type": "integer" + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ], + "projection": "basic", + "sort": [ + { + "field": "id", + "direction": "ASC" + } + ], + "page": 0, + "size": 20 + } + } + } + }, + "PlaybookActionConfig_Severity_Change": { + "type": "object", + "required": [ + "filterRequest", + "description", + "reason", + "severity" + ], + "properties": { + "filterRequest": { + "description": "Filter for job requests", + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + } + }, + "expireAfterDays": { + "type": "integer" + }, + "description": { + "type": "string" + }, + "reason": { + "type": "string" + }, + "severity": { + "type": "string" + } + }, + "example": { + "filterRequest": { + "filters": [ + { + "field": "has_malware", + "exclusive": false, + "operator": "EXACT", + "value": true + } + ] + }, + "description": "Findings with Malware are more severe.", + "reason": "Severity should reflect malware accordingly.", + "severity": "9.1" + } + }, + "PlaybookActionConfig_TagApplyUnapply": { + "type": "object", + "required": [ + "filterRequest", + "tagId", + "isRemove" + ], + "properties": { + "filterRequest": { + "description": "Filter for job requests", + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + } + }, + "tagId": { + "description": "Tag being used in tagging/untagging", + "type": "integer" + }, + "isRemove": { + "description": "True if the tag is being removed, false otherwise.", + "type": "boolean" + }, + "publishTicketStats": { + "description": "To publish ticket description fields to the ticket which is associated with the tag.", + "type": "boolean" + } + }, + "example": { + "tagId": 1, + "isRemove": false, + "filterRequest": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "EXACT", + "value": 1 + } + ] + } + } + }, + "PlaybookActionConfig_AddToGroup": { + "type": "object", + "required": [ + "filterRequest", + "targetGroupIds" + ], + "properties": { + "filterRequest": { + "description": "Filter for job requests", + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + } + }, + "targetGroupIds": { + "description": "List of groupIds where assets to be added or removed.", + "type": "array", + "items": { + "type": "integer" + } + } + } + }, + "PlaybookActionConfig_RemoveFromGroup": { + "type": "object", + "required": [ + "filterRequest", + "targetGroupIds" + ], + "properties": { + "filterRequest": { + "description": "Filter for job requests", + "type": "object", + "required": [ + "filters" + ], + "properties": { + "filters": { + "type": "array", + "items": { + "type": "object", + "required": [ + "field", + "exclusive", + "operator", + "value" + ], + "properties": { + "field": { + "type": "string", + "description": "See filter endpoint for possible values\n" + }, + "exclusive": { + "type": "boolean" + }, + "operator": { + "type": "string", + "enum": [ + "EXACT", + "IN", + "LIKE", + "WILDCARD", + "RANGE", + "CIDR" + ] + }, + "value": { + "type": "string", + "description": "See suggest endpoint for possible values\n" + } + } + } + } + }, + "example": { + "filters": [ + { + "field": "id", + "exclusive": false, + "operator": "IN", + "value": "1,2,3,4" + } + ] + } + }, + "targetGroupIds": { + "description": "List of groupIds where assets to be added or removed.", + "type": "array", + "items": { + "type": "integer" + } + } + } + }, + "PlaybookOutputConfig_Email": { + "type": "object", + "required": [ + "targetUsernames", + "subject", + "message", + "includeOperationalSummary" + ], + "properties": { + "targetUsernames": { + "type": "array", + "items": { + "type": "string" + } + }, + "subject": { + "type": "string" + }, + "message": { + "type": "string" + }, + "includeOperationalSummary": { + "type": "boolean" + } + } + }, + "PlaybookOutputConfig_No_Output": { + "type": "object" + } + } +}