Help & Documentation
What is Octotor?
IT information lives scattered across independent systems — Active Directory, Microsoft 365, network equipment, and the machines themselves — making it hard to get a quick read or run a deep investigation in one place. Octotor solves both: it gathers information from any script-capable system and presents it through a single, friendly web interface. And it doesn't just collect — it acts: scripts run directly on remote computers, switches, and firewalls, manually, on a schedule, or automatically when an alert fires.
Octotor is agentless: built on industry-standard protocols — WinRM, SSH, and SNMP — it talks to almost any system straight out of the box, with nothing to install on the target. Deployment is fast and simple.
See everything in one place
Every asset — person, computer, switch, firewall, cloud account — has one page holding everything Octotor knows about it: identity, attributes, linked accounts, relationships, history. For the help desk this turns support into a one-glance operation: the moment a call comes in, the caller's full picture is already on screen, and the technician can act immediately — running pre-built toolkit scripts in real time with a single click.
Act on what you see
Select one or several assets, pick a script, and run it instantly — without ever seeing the target's credentials, which stay securely stored in Octotor. The Scheduler runs the same scripts on a clock — a routine AD sync to keep the inventory current, an SNMP query to check switch port status — or triggered by a detected condition instead of time, driving automatic remediation (for example, resetting a VPN tunnel the moment a connection loss is detected).
Know the moment something changes
Alerts fire on a wide range of conditions — an asset going offline or coming back, an attribute crossing a threshold (like low disk space), a system event, a locked account, a failed logon, and more — delivered by email, Telegram, or webhook. An alert can also trigger a remedy: a script that runs on the asset that fired it (or any other asset), so routine problems are handled before anyone files a ticket. See Alert Center.
The right command on the right machine
Before executing actions, Octotor's Identity Verification confirms the target on the other end is genuinely the one you intended — not a stale record, a reassigned IP, or a renamed machine. And permissions run through every layer: which group a user belongs to, which toolkit scripts they may run, which customers they can view or manage, whether their rights are read-only or read-write, and whether sensitive actions require an extra per-action password before anything executes. See Permissions and Security.
Everything on the record
Every action taken through Octotor — and every piece of information it collects — is tracked. Whether a script ran manually, on schedule, or as an alert-triggered remedy; whether a setting changed or a user signed in — nothing goes unrecorded. The Investigate page is the single timeline where you can reconstruct what changed, who or what triggered it, when, and what the outcome was.
AI, your way
Octotor's toolkit is built to expand: with AI assistance, you can write tailor-made PowerShell or shell scripts for exactly what you need and save them to the Toolkit for manual or scheduled use. Operators can also work in plain language through the AI assistant — ask "which servers haven't rebooted in over 30 days?" or say "restart the DNS service on DC01". You choose where the AI runs: a fully local model, entirely offline and air-gapped — no data ever leaves your network — or an external cloud provider for the full power of the latest large language models. Either way, it's your call, and Octotor adapts.
How it fits together
Page Overview
| Page | Purpose | Who can access |
|---|---|---|
| Dashboard | The Customer Overview: every customer's state at a glance, and one customer's topics in full | Admin, Operator, Viewer |
| Assets | Manage devices, people, accounts, attributes, relationships | Admin, Operator, Viewer (read-only) |
| Run | Execute scripts and protocols on assets in real time | Admin, Operator |
| Toolkit | Manage the script library | Admin |
| Scheduler | Recurring and condition-triggered tasks | Admin |
| Investigate | Unified events timeline with AI queries | Admin, Operator (if group allows) |
| Alerts | Live alert center — acknowledge, resolve, investigate | Admin, Operator, Viewer (if group allows) |
| Alerts Admin | Alert rules, notification channels, maintenance windows | Admin |
| Goose | AI agent chat — run scripts, investigate, manage via natural language | Admin, Operator (if group includes 'goose') |
| Services | Background service status and health | Admin |
| Settings | System configuration, users, groups, credentials, tokens, AI | Admin only |
Notifications (Toast System)
Octotor uses non-blocking toast notifications for feedback on every user action. Toasts appear briefly in the top-right corner and never block the UI the way classic pop-up dialogs do. All frontend feedback uses this system — there are no native pop-up dialogs in the app.
| Color | Meaning | Default duration |
|---|---|---|
| Green (success) | Action completed — a record was saved, a job started, a password was changed | 4 seconds |
| Green — persistent | Security-critical confirmation (master action password saved / changed / removed; VACUUM or maintenance results with row counts) | Until you click it |
| Red (error) | Action failed — form preserved so you can retry | 4 seconds |
| Amber (warn) | Validation problem — fill required fields, check format | 4 seconds |
| Blue (info) | Informational update | 4 seconds |
Click a toast to dismiss it immediately. Persistent toasts (security-critical confirmations and VACUUM/prune result counts) will remain on screen until you click — this is intentional so you can read important numbers or confirmations without them flashing away.
Content Security Policy (CSP)
Octotor ships with a hardened CSP that disallows inline scripts and disallows eval() / runtime JS compilation. If you see console messages like "Refused to execute inline script" in the browser devtools, that is expected — the browser is enforcing the policy. This significantly reduces the reflected-XSS-to-RCE attack surface; it does not affect normal use of any page. If a feature appears to misbehave after a Chrome/Firefox update, open devtools > Console and send the full CSP error text when reporting.
Dashboard — the Customer Overview
The Dashboard is the landing page. It shows every customer's state at a glance, and one click opens a customer's own page with every topic in full. The page reloads its data on its own (every 60 seconds by default; the interval is a setting under Settings → Dashboard).
Two views
- All customers — the state summary (how many customers need action, are to watch, are OK, have no data), ten counters (Customers, Servers, Computers, People, Switches, Firewalls, Backup servers, AD domains, M365 tenants, Open alerts), the Needs action now panel with every open item across all the customers you can see, and one card per customer. Sort the cards Worst first or By name (your choice is remembered for your login) and narrow them with the search box.
- One customer — click Open customer on a card. The page shows the customer's state and how long it has been that way, the Daily Status strip (the worst state each day for the last seven days — right after an upgrade the strip starts empty, because the history it draws from begins at that moment; it fills in one square a day and is complete after a week), the nine counters, the Needs action now panel for this customer (open items, acknowledged items, items to watch), the health topics, the inventory tiles, the operations tiles, the providers that are not configured, and the customer's recent events. The address of this page (
/index.html?customer=…) can be shared. Every tile's links open the Assets, Alerts or Investigate page already filtered to this customer and topic (for example the Servers tile's Servers → opens the Assets page showing only this customer's servers).
Which view opens first is the Landing view setting: automatic (one customer with assets opens that customer's page, several open the all-customers page), always all customers, or always one chosen customer. The other view is always one click away.
The three states
- Needs action (red) — at least one item needs action: an offline server, a failed backup job, a disk under 5 % free, an offline switch or firewall, an account list that could not be read, every scheduled task failing, or more than 75 % of the customer's computers offline at once.
- Watch (yellow) — something is wrong but nothing needs action: a warning alert, a backup job with warnings, a disk under 10 % free, a port below its speed, an account list that is out of date, some tasks failing, 65–75 % of the computers offline.
- OK (green) — nothing is wrong.
- No data (grey) — every collector for the customer is silent, or nothing is set up yet.
The thresholds behind the colours are set under Settings → Dashboard. They colour tiles only; to be notified, use an alert rule. Every tile says what it measured, of how many, and the real date and time of its data; a tile whose data is older than expected says so on its last line.
How to read a customer
Every customer is described the same way, on its card and on its own page:
- The state, and how long it has held — the coloured word beside the customer's name (Needs action, Watch, OK, No data) with a line such as Needs action for 7 h, counted from the moment the oldest item behind that state opened.
- The two counts — how many items need action and how many are to watch. An acknowledged item is counted on its own and is not in the needs-action count.
- Seven squares — one per day for the last seven days, oldest on the left and today on the right. Each square holds the worst state that customer reached that day, and pointing at a square names the worst item recorded that day (for example Sat 27: Needs action — the last Active Directory account-list read failed), so a red square over a green headline is a problem that came and went earlier that day. A run of red squares shows a problem that has been standing for days. Each tile carries the same seven squares for its own topic.
- The counters — ten on the all-customers page (Customers, Servers, Computers, People, Switches, Firewalls, Backup servers, AD domains, M365 tenants, Open alerts) and the same set without Customers on a single customer's page. Each shows a total with a short note under it, for example 3 offline in red or 42 online; a counter for something the customer does not use reads not set up.
A tile is one topic for one customer, and every tile is laid out the same way:
- Title band — the topic's name with its state dot, the pin, and on a custom tile an Edit link.
- Headline — the short answer, for example 2 of 6 offline.
- Detail — one line naming what is behind the headline, for example SRV-02 offline since 06:12.
- Since — how long the tile has been in the state it is in now.
- Open issues — why the tile is red or yellow, in words: every item that needs action (red bar) or is to watch (yellow bar), with its reference number — the first five, then and N more (the Needs action panel at the top of the page always lists all of them). An acknowledged item stays in the list, greyed, with who acknowledged it and until when. A green tile says No issues, all is OK; a tile with no fresh reading says No fresh data and when it last read. So a red Servers tile always names the server and what is wrong with it, for example TRI-DC01: failed logon attempts.
- Data stamp — the real date and time of the reading the tile used. A tile whose reading is older than expected says so on its last line; a tile with no reading at all reads No data and takes no part in the customer's state.
- Facts, lists and links — the numbers behind the headline, the named items (up to five, then "and N more"), and links that open the Assets, Alerts or Investigate page already filtered to this customer and this topic.
The time frame — 24 h, 7 d, 30 d
The three buttons at the top of the page — 24 h, 7 d and 30 d — set the stretch of time the operations tiles count over: Alerts, Scheduled tasks, Manual runs and AI. Each of those four tiles prints the stretch it used on its own last line, for example Time frame: last 7 days. The health topics — servers, computers, backups, disk space, switches, firewalls, directories and the rest — describe the situation as it stands right now, so these buttons do not change them, and they never change a customer's colour.
Scheduled tasks counts the runs your tasks actually made inside that stretch. 12 of 14 runs OK means fourteen scheduled runs finished in the chosen stretch and twelve of them finished without an error (a run that is still running, or that somebody cancelled, is neither — the tile's facts show it as Cancelled or still running, and it is never counted as "OK"); the tile's list names every run that failed, with its task, the machine it ran on and the time it started. A task set to run every hour therefore shows around 24 runs over 24 h and around 168 over 7 d. When no run was due in that stretch the tile reads No runs in 7 days, and its second line still says how many tasks are enabled, so a quiet stretch is never mistaken for nothing being scheduled.
"I'm aware" — acknowledging an item
- Open the customer's page (or find the item in the all-customers panel) and click I'm aware on the item's row.
- Type a note if you want one (a ticket number, who is on it — up to 120 characters), choose how long the acknowledgement stands (7 days by default, at most 90), and click Acknowledge.
- The item leaves the needs-action count, its tile turns yellow instead of red, and the item stays listed under Acknowledged — still listed, not counted with who acknowledged it, since when and until when. Everyone sees the same acknowledgement.
- It clears itself when the problem goes away or when the date passes. Withdraw ends it at once. If the item stands on an alert, acknowledging it also acknowledges the alert on the Alerts page, and acknowledging the alert there counts here too — one record, two places.
Every acknowledgement, withdrawal, expiry and automatic recovery is written to the audit trail and appears on the Investigate page under the category dashboard. Viewers see the page read-only, without the acknowledge and withdraw controls.
Action numbers, and handling several at once
Every row in Needs action now carries a number, shown as #41 in the first column. The number belongs to that problem on that customer for as long as it stays open, so you can put it in a ticket, send it in a message or read it out on a call, and the person who opens the page sees the same thing. Numbers run in one series across the whole installation, so no two actions ever share one. If a problem clears and comes back later it is treated as a new occurrence and takes a new number, so #41 always means the one event you were talking about. Rows in the to watch section of a customer's page carry numbers too, so a problem that grows from yellow to red keeps the number it already had.
To deal with several at once:
- Tick the box at the start of each row you want. The box is only available on rows a button can act on — an open item, or one already marked as known that could be withdrawn.
- To take everything on the view, use Select all in the panel header. If the panel is showing only its first ten rows, Select all opens the full list first, so what is ticked is always what you can see. Clicking it again clears the selection.
- A bar appears at the top of the panel showing how many are selected. Type a note if you want one and choose how long the acknowledgement should stand — you are asked once, and the answer is used for every row you ticked.
- Click I'm aware to mark them all as known, or Withdraw to end the acknowledgements on the ones already marked. Clear drops the selection without changing anything.
A selection that mixes open rows with rows already marked as known is not refused. Each button acts on the rows it can act on and then tells you what it did and what it left alone, with the reason — so one row that somebody else handled a minute ago never blocks the rest.
A site loses power overnight. The next morning the panel lists eleven open actions for Brightwater Labs, #88 through #98, all of them server is offline. You already know why, and the electrician is booked for Thursday.
- Tick the eleven rows (or use Select all if the panel holds nothing else). The bar reads 11 actions selected — 11 open actions.
- Type power cut, electrician Thursday, ticket 5120, choose 7 days, click I'm aware.
Pinning tiles per customer
Every tile on a customer's page carries a pin in its title band. Click it to unpin the tile: it moves to the Unpinned tiles strip at the bottom of the page as a title with a state dot, its items no longer count toward the customer's state and no longer appear in the Needs action now panel, and the customer's card on the all-customers page drops the tile and says Unpinned on this customer's page: …. The tile's own state is still computed (the dot can be red) and its alerts stay on the Alerts page. Click the pin on the strip to put the tile back. Pin state is per customer and shared by everyone; every pin and unpin is written to the audit trail (category dashboard). To hide a tile for every customer, switch it off under Settings → Dashboard instead.
You open the Dashboard. The summary reads 2 of 9 need action; the Needs action now panel lists Backup job "Nightly" failed — Alder Clinic (open for 9 h) and Switch SW-CORE-01 is offline — Fjord Studio (open for 3 days).
- Click Open Fjord Studio. The Network switches tile reads 1 of 4 offline, its list names SW-CORE-01 — offline since 15 Sep 06:10, and the link Switches → opens the Assets page filtered to that customer's switches. The switch is out for a planned replacement on Friday: click I'm aware, type replacement Friday, ticket 4711, keep 7 days, click Acknowledge.
- Back on All customers, Fjord Studio is now yellow with 1 acknowledged, and the panel shows only the backup job. Click Open Alder Clinic, read the failed job's reason on the Backups tile, and open Backup jobs → to fix it.
Adding a custom tile
A custom tile counts any group of assets you can already filter on the Assets page, for each customer, and gives the count a colour rule of your own. It sits next to the built-in tiles on the customers' cards and pages, its number counts toward the customer's state like any built-in tile when it turns red, and it can be acknowledged the same way.
- On the all-customers page click Add custom tile (top right). Admins can also open the editor from Settings → Dashboard → Custom tiles.
- Tile name — short, it is shown on the tile (at most 40 characters). Pick an Icon.
- What to count — Computers, People, Switches, Firewalls, Active Directory accounts, Microsoft 365 accounts or Check Point accounts.
- Filters — the same rows as the Assets page filter: an attribute, include or exclude, contains / equals / greater than / less than / is one of (several accepted values separated by a vertical bar, for example
server|domain controller), and a value. An asset is counted when it matches every row. Up to 8 rows; + Add filter adds one. - Colour rule — Good when nothing matches with Watch (yellow) from N matches and Needs action (red) from M matches, or Information only (the count, no colour).
- Who sees it — Everyone who can open the overview (needs the Settings permission) or Only me. A tile only you see never colours a customer for anyone.
- Customers — All customers, or Selected customers only and tick them in the list. Customers added later are not ticked automatically.
- Watch the Preview and the Matches per customer, right now table on the right; they follow every change. Click Save tile.
To change or remove a tile, open the customer's page and click Edit in the tile's title band (or the tile's row under Settings → Dashboard → Custom tiles); Delete tile asks once more before it deletes. Every save and delete is written to the audit trail (category dashboard). Clicking a custom tile's link opens the Assets page with exactly its filters, for that customer.
You want to see, per customer, how many computers still have the whole Domain Users group in their local Administrators group. Click Add custom tile. Name: Domain Users are local admins; icon: the key. What to count: Computers. Filter: attribute Local administrators (local_admins), include, contains, value Domain Users. Colour rule: Good when nothing matches, watch from 1, needs action from 6. Who sees it: Everyone. Customers: All customers. The table on the right shows, for example, Brightwater Labs 5 — Watch and Alder Clinic 0 — OK. Click Save tile.
Settings → Dashboard
Admins shape the Customer Overview for everyone under Settings → Dashboard. Every control saves as soon as you leave the field, and a saved value shows on the page at its next reload (the top bar says when). The section holds:
- Landing view — Automatic (one customer with assets opens that customer's page, several open the all-customers page), All customers, or One customer with the customer chosen below it. Someone who cannot see the chosen customer lands on the automatic choice.
- Customer cards — the default order of the cards on the all-customers page, Worst first or By name. Each person may still switch the order on the page; their choice is remembered for their login.
- Thresholds and numbers — one group per health topic that has thresholds (for example Computers: the share of computers off at once that turns the tile yellow, the share that turns it red, and after how many hours a computer counts as offline; Disk space: the free-space shares for yellow and red, and an optional "also red under N GB free" for very large disks), then the model's own numbers: Freshness (data counts as out of date after this many times the collector's schedule), History (a health snapshot every N minutes, kept for N days) and Acknowledgements (the length offered first, the longest length anyone may choose, and after how many clean history runs an acknowledgement ends on its own). Every field shows its allowed range; a value outside it is refused with the reason and the old value stays.
- Tiles shown on every customer — every tile with an On/Off button and arrows for the order. A tile switched off disappears from every customer's page and card and takes no part in any customer's state. To hide a tile on one customer only, unpin it on that customer's page instead. A tile that arrives with a product update appears in this list on its own.
- "Needs action now" panel — whether the panel at the top of the page is drawn, with a separate switch for the all-customers view and for one customer's page. Both start as Shown. Hiding a panel only stops it being drawn: no customer's state, counts or tile colours change, the same items stay on the cards and tiles, and they remain on the Alerts page. Use it when your team works from the customer cards and does not need the gathered list.
- Links that leave this page — whether the links at the bottom of each tile open in a New tab (the default) or in the Same tab. These are the links out to the page holding the detail: Assets, Alerts, Investigate, the Scheduler, Settings and Help. With New tab the overview stays open behind them, so you keep your place and your scroll position while you look something up. Moving around inside the overview itself — Open customer, All customers, Share link and + Add custom tile — always stays in this tab, whichever way this is set.
- Page refresh — how often the Customer Overview reloads its data, 15 to 600 seconds (60 by default).
Your file servers carry 4 TB disks; 10 % free on such a disk is still 400 GB, so the yellow at 10 % comes far too early, while a 60 GB system disk at 5 % free (3 GB) is already a problem. Open Settings → Dashboard and, in the Disk space group, set turns yellow under (% free) to 8, turns red under (% free) to 4, and also turns red under (GB free, 0 = off) to 25. Each field saves when you leave it; the line under the heading reads Saved.
Expected outcome: at the next reload of the Customer Overview the Disk space tiles use the new rules: a 4 TB disk with 300 GB free (7 %) shows yellow, a 4 TB disk with 20 GB free shows red because of the GB rule although 20 GB is only 0.5 %, and the 60 GB system disk at 3 GB free (5 %) shows yellow instead of red. Typing 60 into turns yellow under (% free) is refused — the range is 1 to 50 — and the field keeps its old value. Alert rules are untouched: to be notified about disk space, keep or add a threshold alert rule.Ask the assistant about the overview
The AI assistant can read the Customer Overview and answer questions about it in plain words. It sees exactly what you see — only the customers your login may open — and it can only read: it cannot mark an item as known, pin a tile or change a setting. Questions it answers from the page's own data:
- Which customers need action right now, and why? — each customer that needs action, with the items behind it and how long each has been open.
- Is anything acknowledged for Alder Clinic, and until when? — the items marked as known, with who marked them, the date the mark runs out, and the note that was typed.
- What is the state of the Backups tile at Fjord Studio? — one topic on one customer, with the tile's own headline, its detail line and how old its data is.
- Which custom tiles exist, and what does each one count? — the custom tiles, what each counts, its colour rule, and whether everyone sees it or only its owner.
An answer is only as fresh as the data behind the page, and it is built from the same reading the page shows.
Dependencies
None — the page reads what the collectors, the ping service, the alert engine and the backup, directory and network integrations already store. A provider a customer does not use is listed under Not configured; a customer with no servers or computers yet reads No servers yet. The host and container health that the old Dashboard showed is on the Services page.
Assets
The Assets page is the central inventory of everything Octotor manages — computers (workstations and servers), switches, firewalls, and users (AD-synced or manual).
Guided tours
The Tour button in the top-right of the Assets page runs a guided walkthrough on the real page. It dims the screen, highlights one control at a time, and explains what it is for. Where a step needs a click, an arrow points at exactly what to click — make the click yourself and the tour follows you, or press Next and it does that click for you.
The Assets page ships with these tours:
- View computer and user info — 20 steps, the whole page end to end: the list, the filters, a device record and its tabs, then a person record and what each connected directory says about them.
- Which switch port is this machine on? — the answer in two clicks.
- Add a device by hand and Add a person — for what discovery does not bring in. The device tour walks the fields that matter later: the customer, the OS family that decides which scripts can run, the monitoring options, the default protocol, the alert templates, and why the machine still needs a credential before Octotor can act on it. Both stop on the form; neither creates anything for you.
- Add a switch — a switch is not a computer with a different icon. The tour covers the type and OS family that give it a Port Map and an SNMP panel, the SNMP community credential it needs on its Credentials tab, switching on SNMP monitoring and the MAC-table walk, saving them, and using Test to prove the poll works rather than waiting for the schedule.
- Filter by any attribute — opens the Attr Filter panel and picks the first attribute for you, so you can see what it reaches that the top filters do not. An attribute needs a value beside it before the list narrows, and filters stack with + Add.
- What the search box matches — and what it does not: devices and people have separate search boxes that look for different things.
- What the Alerts button does and What the Monitoring button does — the two filter panels on the toolbar, how to find the machines nobody is watching, and how to change alert flags or switch monitoring on across many machines at once from the bulk action bar.
- Run a command on a machine — three clicks, and where the output goes. This one follows you to the Run page: it carries on there, finds the
collect-infoscript and stops on the Run button without running anything. - Give a machine a credential — the usual reason a job fails immediately.
- What changed on this machine? — Changes versus Timeline, and expanding a single timeline entry to see its source, detail and reference.
Tours that would create or modify something stop one step short of the Save button, so taking a tour never changes your data. That includes the bulk actions: a tour will point at Enable Monitor or Apply and tell you what it would do, but it never presses one.
Every step has a Next button, so you are never stuck. Stop any tour with End tour or the Esc key, and start one again whenever you like from the Tour button. Ending a tour leaves the page exactly as you left it.
The first tour runs automatically on your first visit, once per browser. After that, every tour waits to be chosen from the Tour button.
Worked example — finding a machine's switch port
A user reports slow file transfers on TRI-LT007 and you want to know which switch port it is plugged into, and at what speed.
- Open Assets and click Tour (top-right, next to Import CSV).
- Choose Which switch port is this machine on? from the menu.
- The tour highlights the first row of the Devices table and says "Open the machine you are chasing." Click the machine's name —
TRI-LT007. - The record opens and the tour highlights the Attributes tab. Click it.
- The tour points at the Network group, which holds
connected_switch_ip(for example10.40.10.2),switch_port(for exampleGigabitEthernet1/0/14) andswitch_port_speed.
What this tells you: if switch_port_speed reads 100 Mbps on a gigabit port, the link has negotiated down — almost always a bad cable or a damaged socket. You have the port number in hand, so the fix can be dispatched without anyone walking to the comms room.
Note: these values come from SNMP polling of the switch itself, so they appear only for machines whose switch is registered as an asset and polled. On an unpolled switch the Network group has no switch fields, and the tour says it has lost its place rather than pointing at nothing.
Creating an Asset
Asset Detail Tabs
| Tab | What it shows |
|---|---|
| Overview | Name, type, hostname, IP, OS, status, monitoring toggle, related assets |
| Attributes | Custom fields — email, disk space, RAM, network info, etc. Editable by admins/operators |
| Credentials | SSH/WinRM credentials linked to this asset. Link or unlink credentials here |
| Relations | Links to other assets (belongs-to, has-user, connected-to) |
| Jobs | Execution history — scripts run on this asset, with status and output |
| Changes | Full attribute change history for this asset (every old → new value), with filters by source (manual, collector, import, bulk), user, and time range. Deep-link via assets.html?open=<id>&tab=changes |
| Timeline | Unified chronological view across the asset's lifetime: every offline/online status flip, every alert (fired/resolved), every job run, and every manual action. Filter chips: All / Status / Alerts / Jobs / Manual. Date range: Last 24h / 7 days / 30 days / 90 days / 1 year. Each row is click-to-expand for source/detail/ref. Source data: alert_transition_log (status flips), alerts (lifecycle), action_log (manual), jobs (runs). Read-only. |
| Identity | IP validity score, DNS resolution chain, verification history, locked IP toggle. See Identity Verification below |
Identity Verification
Octotor verifies that each asset's IP address actually belongs to the expected hostname. This prevents mismatched mappings in DHCP environments where IPs rotate between devices.
How It Works — Verification Flow
AUTOPING CYCLE (runs every N seconds for each monitored asset)
│
├─ 1. CHECK LOCKED IP
│ └─ IP locked? ──▶ Skip DNS, score = 5, ping stored IP
│
├─ 2. CHECK CUSTOMER DNS CONFIG
│ └─ No DNS configured? ──▶ Skip DNS, score unchanged, ping stored IP
│
├─ 3. FORWARD DNS LOOKUP (hostname + domain → DNS server)
│ │ Example: "salespc1" + "contoso.com" → query DNS at 10.5.5.10
│ │
│ ├─ DNS server not responding ──▶ Score = 0, reason: "DNS server not available"
│ │ ⚠ Admin alert raised
│ ├─ No A record found ──▶ Score = 2, use stored IP
│ └─ Got IP (e.g. 10.5.5.96)
│ └─ Different from stored IP? ──▶ Update stored IP automatically
│
├─ 4. PING (using resolved or stored IP, with fallback chain)
│ ├─ OFFLINE ──▶ Stop here. Score is NOT changed (avoids penalizing offline devices)
│ └─ ONLINE ──▶ Continue to step 5
│
├─ 5. REVERSE DNS LOOKUP (IP → hostname, optional)
│ │ Queries: "What hostname owns 10.5.5.96?"
│ │
│ ├─ No reverse zone / no PTR record ──▶ Score = 3 (Medium)
│ │ Forward lookup OK but unconfirmed by reverse
│ │
│ ├─ Reverse returns MATCHING hostname ──▶ Score = 4 (High)
│ │ Both forward and reverse agree
│ │
│ └─ Reverse returns DIFFERENT hostname ──▶ Score = 1 (Stale!)
│ The IP belongs to a different device — record is stale
│
└─ 6. STORE RESULT
Update asset: ip_validity_score, ip_validity_reason, ip_validated_at
SSH IDENTITY GATE (runs before every job/script execution)
│
├─ 1. SSH CONNECT to resolved IP
│
├─ 2. RUN HOSTNAME PROBE
│ │ Linux: "hostname" | Windows: "[System.Net.Dns]::GetHostName()"
│ │
│ ├─ MATCH ──▶ Score = 5 (Verified — highest possible)
│ │ Proceed with job execution
│ │
│ └─ MISMATCH
│ ├─ Strict mode ──▶ ABORT job, flag asset, self-heal IPs
│ └─ Warn mode ──▶ Log warning, run job anyway, self-heal IPs
│
└─ 3. SELF-HEALING (on mismatch)
├─ Search for the actual hostname in customer assets
├─ Found? ──▶ Reassign IP to correct asset automatically
└─ Not found? ──▶ Log "unknown host" for admin review
When Is Reverse DNS Used?
Reverse DNS (PTR lookup) runs during the autoping scoring phase (step 5 above) — after a successful forward lookup and only for online assets. It asks: "What hostname does this IP map to?"
- If reverse matches the forward result → higher confidence (score 3 → 4)
- If reverse returns a different hostname → the A record is stale (score drops to 1)
- If no reverse zone exists → forward-only scoring (score stays at 3)
Reverse DNS is not required. Without it, DNS verification caps at score 3 (Medium). SSH verification can still reach score 5 regardless of reverse DNS.
5.5.10.in-addr.arpa for 10.5.5.0/24) and enable dynamic updates. DHCP will then register PTR records automatically.DNS Server Alerts
If a customer's DNS server is unreachable (timeout or connection refused), Octotor:
- Sets validity reason to "DNS server not available"
- Raises an admin alert in the Investigate page (category: identity, requires action)
- Falls back to the stored IP for pinging (does not break monitoring)
IP Validity Score (0-5)
| Score | Label | Meaning |
|---|---|---|
| 5 | Verified | SSH hostname probe confirmed identity, or IP is locked |
| 4 | High | DNS forward + reverse lookup both match |
| 3 | Medium | DNS forward lookup OK, no reverse (PTR) record available |
| 2 | Low | DNS lookup failed, using stored IP |
| 1 | Stale | DNS or SSH mismatch detected — IP may belong to a different device |
| 0 | Unknown | No DNS configured for customer, no verification done |
Attribute Locking
Any attribute on an asset can be locked by an admin. Locked attributes cannot be overwritten by automated sources (collectors, DNS, imports). Only an admin can change a locked value manually.
- Lock IP: The "Lock IP" checkbox next to the primary IP in the Overview tab prevents DNS and collectors from changing the stored IP. Score is set to 5. Use this for devices with static/reserved IPs (servers, network gear).
- Lock attributes: Each attribute card in the Attributes tab shows a lock icon. Click to lock — the icon changes to solid and a "locked" badge appears. Click again to unlock.
- Manual edit does NOT auto-lock. Changing a value manually does not lock it. The value can still be overwritten by collectors on the next cycle unless explicitly locked.
[192.168.2.3, 192.168.2.14] and the next [192.168.2.14, 192.168.2.3]. Octotor's DNS resolver uses the first record returned, so with the IP unlocked, autoping rewrites asset.ip on every cycle to whichever record DNS handed back first. The asset visibly flaps between online and offline as the alternate address is reached or unreachable, and a status alert fires on every offline transition. Locking the IP is the fix: autoping skips DNS resolution entirely, the operator's chosen IP is preserved, and the ping fallback chain still verifies reachability via asset.ip → secondary_ip → wifi_ip → hostname. For genuinely dual-homed hosts, set the primary as asset.ip, add the second interface as the secondary_ip attribute, and lock — autoping then pings both candidates per cycle and reports online if either responds.
Per-Component Settings
Each identity verification step can be independently enabled or disabled in Settings > Monitoring > Identity Verification:
| Setting | Options | What it controls |
|---|---|---|
| DNS Resolution | On / Off | Autoping DNS lookup and IP scoring |
| SSH Identity Gate | On / Off | Hostname probe before job execution |
| Require Successful Probe | On / Off | Abort job if the identity probe fails (timeout, no output, credential rejected). The job then ends with status identity_unverified (shown as "identity not verified"), not identity_mismatch, because the host's name was never compared. The first line of the job output names the cause. Only active when the SSH or WinRM gate is on. |
| Collector Identity Check | On / Off | Hostname comparison after script execution |
| Mismatch Behavior | Strict / Warn | What happens when any enabled check finds a mismatch |
| Validity TTL | Minutes (0 = never) | Score expires after this many minutes and resets to 0 on the next autoping cycle. Default: 60 minutes. |
Worked example — identity not verified. SSH Identity Gate and Require Successful Probe are both on, and the credential for srv-app-01 has an expired password. You run linux/uptime.sh on it. The hostname probe is refused, the job does not run, and it ends with status identity_unverified. The job output starts with [octotor] Identity not verified: auth rejected — the job was not run. On the Investigate page, choose identity not verified in the Status filter to list every job stopped this way. A job that reached the host and got a different name back still ends with identity_mismatch.
With all checks off, Octotor connects to the stored IP and runs commands without any identity verification. These settings can be overridden per scheduled task — see Scheduler > Identity Override.
NetMap Compatibility
DNS verification works correctly with per-customer NetMap (Tailscale SNAT translation). DNS server IPs are automatically translated through NetMap before queries are sent. The two systems operate at different layers:
- DNS server access — if the customer's DNS server (e.g.
192.168.0.11) is behind a NetMap translation, Octotor automatically uses the translated IP (e.g.10.99.0.11) to reach the DNS server - DNS results use real IPs — the customer's DNS server returns the actual LAN address (e.g.
10.155.155.50) - NetMap translates at ping/SSH time only — converts the real IP to a Tailscale-routable address (e.g.
10.18.0.50)
The asset always stores the real IP. If an asset was accidentally stored with a translated (NetMap) IP, DNS resolution will correct it to the real IP automatically.
Example: TRIPLEOR-LAB asset on WiFi segment
Real IP: 10.18.18.50 (what DNS returns, what the asset stores)
NetMap: 10.18.18.0/24 → 10.18.0.0/24
Translated IP: 10.18.0.50 (used ONLY for ping/SSH via Tailscale)
Reverse lookup: queries 10.18.18.50 (real IP) → hostname ✓
Verification Mode (Settings > Monitoring)
| Mode | Behavior on Mismatch |
|---|---|
| Strict (default) | Abort job, flag asset as ip_mismatch, trigger self-healing |
| Warn | Log warning, continue with job execution, still trigger self-healing |
| Off | No identity check |
Customer DNS Setup
To enable DNS-based verification, configure DNS for each customer in Settings > Customers > Edit:
- DNS Domain — the Active Directory domain (e.g.
contoso.com). Appended to bare hostnames for lookups. - DNS Server 1 & 2 — the customer's DNS servers (typically the domain controllers).
Key Features
- Search & Filter — filter by type, status, customer, Last Seen (1h/24h/7d/30d/never), and IP Validity score (0-5). The Status filter applies server-side, so selecting e.g. "online" returns matching assets across all pages — not just the current page. Search applies within the active filters (e.g. search "helpdesk" with customer "TRIPLEOR" selected shows only TRIPLEOR's HELPDESK-01). Searching a MAC address works in any notation —
00:0a:fc:ff:ff:0e,00-0A-FC-FF-FF-0E,000a.fcff.ff0eor bare hex, full or partial (6+ hex chars) — and also finds devices Octotor only knows from the network: a MAC learned on a switch port returns the mapped computer (or the switch that learned it, if unmapped), and a MAC present in a Check Point firewall's DHCP leases returns that firewall. Example: searching00-0A-FC-FF-FF-0Efinds the computer plugged into the switch port where that MAC was learned, even when no asset carries the MAC as an attribute. - Status Since vs Last Seen — two different timestamps. Status Since (table column and drawer Overview row) is when the asset's current status began — it updates on every status change, in both directions. Last Seen (drawer Overview row, and the Last Seen sort/filter) is the last time Octotor successfully reached the asset — live while the asset is online (it tracks the most recent good check), frozen at the last good ping once it goes offline. Worked example: a server is up and pinged OK every 5 minutes for a week, then goes down at 07:44 — its row shows Status Since = today 07:44 (when it went offline) and Last Seen = today 07:39 (the last good ping before the outage). While it stays down, Status Since keeps holding 07:44; when it recovers at 09:10, both move — Status Since = 09:10 (online since) and Last Seen starts tracking again. Assets that existed before this feature show "—" for Status Since until their first status change.
- Type filter — "Users & Computers" vs "All" — the Type dropdown opens on Users & Computers, which lists the real-world things you manage (people, machines, switches, firewalls) but hides account sub-objects (AD / M365 / etc. accounts), since those belong to a person or computer and are viewed through its drawer. Choose All to list literally everything, account sub-objects included — or pick a specific provider (e.g. Active Directory) to list just those accounts.
- Adaptive columns — in a mixed list (Users & Computers or All) the two middle columns (Identity and Detail) plus the Status column adapt to each row's type, so every row shows data that is actually relevant to it instead of empty computer-only columns:
- Computer — Identity = active IP, Detail = OS, Status = online/offline.
- User (person) — Identity = email, Detail = job title.
- AD user account — Name shows the UPN, Identity = the leaf OU (e.g.
OU=LAPTOPS), Detail = last logon, Status = Enabled/Disabled. - AD computer (machine) account — Identity = the leaf OU, Detail = last logon, Status = Enabled/Disabled.
- Attribute filter — filter the list by any attribute value (e.g.
account_state= Disabled). The attribute dropdown is the shared global attribute set (the sameasset_attribute_defsthe Alerts > New Rule dropdown uses). Caveat worth knowing: because several providers reuse the same attribute key, filtering or monitoring byaccount_statealone catches all of them (AD, M365, Google, …) — the attribute is matched by its key, not by provider. To scope to one provider, combine the attribute filter with the Type filter (e.g. Type = Active Directory +account_state= Disabled). This is true on both the Assets page and the Alerts rule page — a provider tag like[ad]in the Alerts dropdown labels which definition the entry came from; it does not by itself restrict monitoring to that provider. - Filter Pinning — click the 📌 pin button to persist your current filters across page navigation and refreshes. Pinned filters are stored in the browser session. Click again to unpin and clear.
- Live Monitor — real-time ping status grid. Toggle monitoring per asset in the detail panel
- CSV Import/Export — bulk import assets from CSV, or export the current view
- Pending Attribute Updates — when a collector script gathers data, attribute changes appear here for review and approval. Filter by asset name to review updates per asset. Use bulk approve/reject for efficiency
- Discovered Identities (Discovery queue) — when an account collector (e.g. AD user discovery) finds accounts that don't exist in Octotor yet, they appear in the Discovery panel for per-item approve/reject. Approving creates the account asset (and, when no owner matched, a new person asset) and links them. Rejecting suppresses that identity on later sweeps. Enable Auto-approve discovered identities in Settings > Attributes to skip the queue and create directly.
- Deciding approve vs reject — the queue helps you spot dead accounts before approving: the Last activity column shows how long ago the account was actually used (AD last logon / Entra last sign-in; amber > 90 days, red > 180 days), the search box filters by account name, UPN, or owner, and the "Inactive > X days" filter isolates provably-stale rows for bulk-reject — rows with no activity data from the source are not included (absence is not proof of staleness). The ⓘ details button on each row opens everything the collector saw — OU, groups, description, password dates, MFA, license, manager — so you can decide without leaving the queue. Worked example: filter "Inactive > 1 year", check the details of the handful that remain (an OU named "Disabled Users" or a password unchanged for 3 years confirms dead wood), select all, Reject Selected.
- Multi-Select — select multiple assets for bulk ping, run command, toggle monitoring, or lock/unlock all attributes across selected assets
- Lock All / Unlock All — in the Attributes tab, use the "Lock All" button to lock every attribute with a value on the asset. Also available in the multi-select toolbar to lock/unlock across multiple assets at once.
Machine role, OS name and chassis — telling servers, workstations and laptops apart
The standard inventory scripts (windows/collect-info.ps1, linux/collect-info.sh, linux-embedded/collect-info-qnap.sh) fill three attributes in the SYSTEM group of every computer. OS Version only holds a build number, and the same build number is used by a desktop Windows and a Windows Server (10.0.17763 is both Windows 10 1809 and Server 2019), so these three attributes are how Octotor knows what kind of machine it is looking at. The Customer Overview's Servers tile counts a computer as a server by its Machine role.
| Attribute | Values | Where it comes from |
|---|---|---|
| OS Name | the product name, for example Microsoft Windows Server 2019 Standard, Debian GNU/Linux 12 (bookworm) or QNAP QTS | Windows: the operating system's caption. Linux: PRETTY_NAME in /etc/os-release. QNAP: fixed text. |
| Machine role | server, workstation or domain controller | The Customer Overview's Servers tile counts a computer whose role is server or domain controller, and its link opens the Assets page filtered the same way (is one of server, domain controller). Windows: the operating system's product type (a domain controller reports itself as one). Linux: server, unless a graphical login session or a display manager is running, or the chassis is a laptop or tablet — then workstation. QNAP: always server. |
| Chassis | laptop, desktop, server, tablet or other | The machine's SMBIOS chassis type (Windows: the system enclosure; Linux: /sys/class/dmi/id/chassis_type or dmidecode). Most virtual machines report other or desktop, so use Machine role, not Chassis, to find servers. QNAP devices report no chassis. |
The values apply automatically on every inventory run (the three definitions are Auto-approve). A run that cannot read the enclosure or the login sessions leaves the stored values alone: these three attributes are never cleared by a collector.
- The computer FILES-01 runs Windows 10 Pro and shares the office files. The inventory reports Machine role = workstation, so the Customer Overview would not count it under Servers.
- Open Assets, click FILES-01, open the Attributes tab and the SYSTEM group.
- Set Machine role to server and save.
- Click the lock icon next to the attribute (you need the administrator role; locking is an admin action). A locked value is never changed by a collector run. Without the lock, the next inventory run would set it back to workstation, because auto-approve applies collector updates on their own (see the next section).
Expected outcome: FILES-01 keeps Machine role = server across inventory runs and is counted as a server. To hand the attribute back to the collector, unlock it.
Collector updates & pending approval (who wins — collector, import, or you?)
Every attribute value has an owner: the last thing that set it — a collector, a CSV import, or a human edit. Whether a collector's update (or removal) applies silently or asks for your approval follows two simple rules:
| Situation | What happens |
|---|---|
| Def's Auto-approve is off (Settings > Attributes) | Every collector change goes to Pending Attribute Updates — values and removals alike. |
| Auto-approve on, value is collector-owned | Updates and removals apply automatically. A removal deletes the value and history records (cleared). |
| Auto-approve on, value was set manually or by CSV import | The value is protected: a collector removal is never applied silently — it goes to Pending once, even with auto-approve on. This is why you can see pending rows for an auto-approve attribute. |
- You imported computers from CSV in April; each row set
Last Logged-in User. Those values are now import-owned (protected). - Months later the collector runs on TRI-LAB-01 and reports the field is empty on the machine. Because the stored value is protected, a (cleared) proposal lands in Pending Attribute Updates instead of applying.
- You approve it. The value is removed, history records old → (cleared), and the attribute becomes collector-owned.
- From now on every collector update and removal for that attribute on that asset applies automatically — no more pending rows. If a human edits the value again (or a new import overwrites it), it becomes protected again and the next collector change asks once more.
Second example: a removed M365 license. The license value was collector-owned and the def is auto-approve, so when the tenant removed the license, the next sync cleared it silently — the empty card stays in the drawer and its history clock shows O365_BUSINESS_PREMIUM → (cleared), who and when.
Duplicate Detection
Octotor automatically detects possible duplicate assets during each auto-ping cycle. If two or more assets within the same customer share the same IP address and are both online, they are flagged as possible duplicates.
- Visual indicator — flagged assets show a ⚠ warning icon next to their name in the asset list and a "Possible Duplicate" badge in the detail panel.
- Auto-clear on verification — when an asset's identity is verified via SSH or WinRM probe (hostname matches), the duplicate flag is automatically cleared for that asset.
- Manual clear — use the "Clear Duplicate" button in the detail panel or right-click context menu to manually clear the flag. Note: the flag will reappear on the next ping cycle if the duplicate condition still exists. To permanently prevent re-flagging, lock the IP on the asset.
- Self-healing — if the assets' IPs diverge (e.g. DHCP reassignment), the flag is automatically cleared.
VM-TEST-01) whose AD/DNS address now belongs to a different live host (OFFICE365). Identity verification correctly flags it, but it recurs every cycle because DNS keeps resolving the stale name to that IP and the AD collector keeps refreshing the stale asset. Resolve it root-cause first:
- Fix the stale DNS record (root cause). Remove or correct the A record that maps the old name to the contested IP (e.g. delete
VM-TEST-01 → 192.0.2.103). Once it no longer resolves to that address, autoping stops pointing the stale asset at the live host and the mismatch clears on its own — regardless of anything else. - Keep the object in AD but exclude it from Octotor. Delete the stale asset (and its machine account); when the next collector sweep re-queues it, click Reject in the Discovery queue rather than Approve. A rejected entry is suppressed on later sweeps, so the AD object can stay in place without re-creating the asset.
- Lock the IP on the correct asset (belt-and-suspenders). Open the genuine owner of the address (here
OFFICE365) and lock its IP. Autoping then skips DNS for it and pins the address, so its identity never drifts even if a stale record reappears.
identity_mismatch noise until you address it via step 1 or 2 — and the AD computer collector will keep refreshing the stale asset (no duplicate is created, and it is not deleted — directory deletion-sync is a separate planned feature).
AD User Auto-Discovery
The windows/collect-ad-users.ps1 collector turns a Domain Controller asset into an identity source. Schedule it (or Run it) against a DC; it queries every AD user and emits one record per account (SAM, UPN, email, state Enabled/Disabled/Locked, OU, groups, last logon, password dates, SID, description).
- Known accounts refresh in place — matched by SAM/UPN within the DC's customer; attribute updates follow the normal auto-approve/lock rules and are logged to attribute history.
- New accounts queue for review — the Discovery panel on this page shows each new identity with its proposed owner. Owner matching tries UPN and email against your person assets' Email attribute; unmatched records propose a new person (name, email, job title, department, phone from AD).
- Rejected identities stay rejected — later sweeps skip them, so service accounts you don't want in Octotor only need to be rejected once.
- State changes drive alerts — the unified Account State attribute (Enabled/Disabled/Locked) feeds Alert Center status rules for accounts and users.
AD Computer Auto-Discovery & Machine Accounts
The windows/collect-ad-computers.ps1 collector does the same for AD computer objects. Run it against a DC; it emits one record per computer (name, DNS hostname, OS, OU, enabled state, last logon, and the ManagedBy owner when set).
- Computers mirror the person model — directory state does not live on the computer asset itself. Instead each discovered computer gets a linked machine account: an Active Directory account asset shown under the computer's name (same as dsa.msc; the AD
NAME$sAMAccountName convention is kept on the SAM Account Name attribute) connected via the same account of relation used for people. The machine account carries Account State, OU, Description and the other directory attributes; the computer asset stays a clean device record. - Known computers refresh in place — matched by hostname/name within the DC's customer; the machine account is created or refreshed on every sweep (it heals automatically if deleted). Computers created from the Discovery queue start with auto-ping monitoring enabled, same as manually added ones.
- New computers queue for review — they appear in the Discovery panel marked "· computer". Approving creates the computer asset plus its machine account and links them; rejecting suppresses the computer on later sweeps.
- Owner auto-link — when the AD computer has ManagedBy set, the matched person is linked to the computer via an assigned to relation.
- Linked accounts on the computer drawer — open a computer asset to see its machine account(s) in the Linked accounts card on the Overview tab, with full attribute detail (provider sections, filter chips, history) on the Attributes tab — same experience as user assets.
- Directory-state alerts — Alert Center status rules with target type computer and trigger Enabled/Disabled/Locked fire on the machine account's Account State: when a sweep observes the state flip in AD (e.g. the computer object is disabled), the alert fires; when it flips back, the alert auto-resolves. Machine accounts do not count toward the computer-asset license limit.
Asset Enable / Disable
Assets can be administratively disabled via Asset > Edit > Account Status. A disabled asset:
- Is excluded from auto-ping monitoring
- Is excluded from TCP port monitoring
- Is excluded from scheduled task target resolution
- Cannot be targeted by Run Command (hidden from asset picker)
- Shows as "DISABLED" in the status column (grayed out row)
- Remains visible and editable in the Assets page for record-keeping
Customer Assignment
Every asset must belong to a customer. When creating or editing an asset, select the customer from the dropdown. The customer is shown in the asset list and detail panel. Assets can be filtered by customer using the toolbar dropdown.
SSH Port
Each computer, firewall, and switch asset has an SSH Port attribute (under Attributes tab). Default is 22. If the target listens on a non-standard SSH port, set this attribute and Octotor will use it for both connectivity checks and SSH connections.
Dependencies
- Customers — at least one customer must exist before creating assets (Settings > Customers)
- Credentials — assets need linked credentials before scripts can be executed on them
- Attribute Definitions — custom attributes are defined in Settings > Attributes
User Assets & Accounts
Octotor models people and their identities as first-class assets. A user asset (a person) owns one or more account assets — one per identity system the person has a presence in (Active Directory, Microsoft 365, Google Workspace, Slack, monday.com, Jira, local, other). Accounts are linked to their owner via the account of relation, so the person stays a single clean record while every directory keeps its own attribute set, state and history.
The model at a glance
- Person (user asset) — name, email, job title, department, phones, notes. Created manually (Add Asset > User), via CSV, or automatically by AD discovery when an unmatched account proposes a new person.
- Account asset — typed by its provider (e.g.
ad). Carries the provider's attributes: SAM Account Name, UPN, the unified Account State (Enabled/Disabled/Locked), OU Path, Group Membership, password dates, SID, Description. Collected attributes show the AUTO badge with per-attribute history. - Machine account — computers get the same treatment: each discovered computer is linked to its AD machine account (shown under the computer's name; the
NAME$sAMAccountName stays on the SAM Account Name attribute). See Assets > AD Computer Auto-Discovery. - Account State drives alerts — Alert Center status rules with target type user or computer fire when a linked account's state flips (e.g. an account is disabled or locked in AD) and auto-resolve when it flips back.
Working with a person
- Overview tab — User details card, linked-account cards (provider icon + state pill + Open), Relations, Notes. Unlink lives on the Relations tab.
- Attributes tab — search + All/Filled/Empty/Auto/Manual filter chips, set-progress bar, a read-only provider section per linked account (collected values, SYNCED pill), and the person's own attribute groups as mini-cards.
- Add account — from the person's Overview: pick a provider tile, fill the provider's fields, create. The account asset is created and linked in one step. The same modal has a Link existing mode — attach an account that already exists (perhaps mis-owned) to this person instead of creating a new one.
Setting or changing an account's owner
Discovery matches an imported account to a person by display name — so an account whose name doesn't match an existing person (common for firewall/appliance local logins, which carry only a username) lands on a freshly-created duplicate person. Three ways to fix or prevent that, all restricted to the correct kind (a user account can only be owned by a person; a machine/host account only by a computer):
- Change owner (after the fact) — open the account's own drawer > Overview. The OWNER row shows the current owner and a Change button. Search a person, pick them, confirm. If the previous owner is left with no accounts, Octotor offers to delete that now-empty duplicate in the same step.
- Set owner before approving — on Assets > Discovered Identities, the Owner column has a set-owner button. Pick the real person before clicking ✓ Approve, and the new account links straight to them — no duplicate is ever created.
- Link existing — from a person's Overview > + Add account > Link existing, search the account and attach it here (it moves off its old owner).
jsmith (email jsmith@tripleor.com) was imported and, because its name didn't match, created a duplicate person “jsmith” — while the real person Jamie Smith already owned the matching AD and Microsoft 365 accounts.
Fix: open the
jsmith account > Overview > OWNER row > Change > search “Jamie” > pick Jamie Smith > Change owner. When prompted “the previous owner ‘jsmith’ now has no accounts — delete it?”, choose OK.
Result: the Check Point login now sits under Jamie Smith alongside their AD and M365 accounts, and the duplicate person is gone. On the next firewall sync the link is preserved (an existing account is only refreshed, never re-matched). To stop it recurring, set the owner in the Discovered Identities queue before approving future imports.
Account Providers (Settings)
Settings > Account Providers is the registry of the identity systems Octotor can hold accounts for. Per provider: display name, icon (curated picker), enabled toggle, and a read-only view of its attribute schema with collected-by info. The enabled toggle is the master switch: a disabled provider disappears from the Assets page Type dropdowns (Devices and Users) and from the Add Account modal, but always stays visible here so it can be re-enabled. Fresh installs ship with Active Directory, Microsoft 365, Check Point, Local and Other enabled; Google Workspace, Slack, Monday and Jira start disabled — flip the toggle to use them. Example: to track Google Workspace accounts, enable Google Workspace here, then it appears in the Users Type filter and the Add Account modal. Provider attribute definitions themselves are managed in Settings > Attributes — pick the provider as the asset type. User accounts and machine accounts share one definition list per provider; attributes that don't apply to a kind simply stay "Not set". A provider can only be deleted when no live accounts use it and no collector targets it.
Filling accounts automatically
The AD collectors (windows/collect-ad-users.ps1 + windows/collect-ad-computers.ps1) sweep a Domain Controller and create/refresh accounts through the Discovery queue — see Assets > AD User Auto-Discovery for the full flow, owner matching and the auto-approve setting. Which providers a collector writes to is set per script via the COLLECTS tiles on the Toolkit page.
Two views: Devices & Users (and what “All” means)
On the Assets page the Type filter splits everything into two views: Devices (computers and device-side objects) and Users (people and their identities). Each view opens on a sensible default — Devices on Computers, Users on User (person) — so you first see the clean list of real machines and real people.
- All devices lists every device-side object and folds in all of their linked accounts — AD machine accounts, and Check Point host objects. “All” means every object, not just computers.
- All users lists every person and folds in all of their linked accounts — AD / Microsoft 365 / Google user accounts, and Check Point user objects.
- Pick a specific type (Computers, User (person), or a single provider such as Active Directory / Check Point) to narrow the list to just that kind.
Changing an asset's type
An asset's Type can be changed from its drawer: open the asset, click Edit on the Overview tab, pick the new type and click Save changes. Only the five generic types are available — computer, user, switch, firewall, other. Every applied type change is written to the audit trail (Investigate shows a type_changed entry with the old and new type and the operator).
- Account assets never change type. Accounts (Active Directory, Microsoft 365, Check Point, Local, … rows) are created and managed by their own flows — the Add Account modal, collectors and discovery — and the generic edit rejects any attempt to re-type them (or to re-type a device into an account type).
- Attribute values are kept, not deleted. Attributes are defined per type, so after a change the drawer renders the new type's attribute schema — but the values recorded under the old type stay stored. Change the asset back and they reappear untouched.
Worked example: a box was created as computer but is really a managed switch. Open its drawer → Edit → Type: switch → Save changes. The asset now shows the switch attribute schema (ports, SNMP fields); its old computer attributes (OS build, CPU, …) are retained invisibly and would return if it were ever re-typed to computer. Investigate shows type_changed: computer → switch.
Two freshness stamps on firewall assets
A firewall's Overview tab shows two separate timestamps, because two different pipelines feed the asset:
- Last Collector — when an attribute collector last ran against the box (the
checkpoint-spark/system-inforecipe or any collector job). This is the stamp that tells you how fresh attribute values like CP: License Expiry are. - Last Account Sync — when the hourly Check Point account sync last pulled user/host objects. This runs on its own schedule and never touches the collected attributes.
Worked example: the account sync ran an hour ago but no collector job has run for 12 days. Last Account Sync shows today; Last Collector shows the 12-day-old date — so a stale CP: License Expiry value is immediately explainable (the collector simply hasn't run), instead of the two freshness signals being blended into one misleading recent stamp. To refresh attributes, run the system-info recipe against the firewall.
Automatic user→computer mapping (primary-user linking)
Octotor links who a computer belongs to — a person→computer assigned to link — from the machine's primary user, automatically. The primary user is the account with the most interactive logons (local, unlock, RDP) on that machine over the last 14 days, read from the Windows Security log by the collector (Linux uses login history from the last command; its closing "wtmp begins" or "wtmpdb begins" line is not a login and is never taken as a user name). This reflects who actually uses the box, unlike AD's ManagedBy, which usually names whoever joined the machine to the domain (often an IT admin). Octotor no longer uses ManagedBy for ownership — the primary user is authoritative.
Each machine reports three attributes on its next collection: Primary User (DOMAIN\user), Primary User Confidence (share of interactive logons that were the winner, 0–1), and Primary User Source (e.g. eventlog:14d).
What happens automatically
When a collection runs on a computer and its primary user resolves to a known person (via that person's AD account SAM Account Name), Octotor:
- Assigns the person to the computer if it has no owner yet.
- Corrects a wrong existing owner — it removes the incorrect link and sets the detected person. This self-cleans old bad links (e.g. an IT admin wrongly linked to many machines) as each machine is re-collected.
This only happens when the detected user accounts for at least a configured share of the machine's logins over the last 14 days (Settings → Collector → Auto-map users to computers, default 50%), or when you set the primary user by hand and lock it (a locked value always wins, at any confidence). Turn the whole behavior off with the Auto-map users to computers checkbox in the same place.
The "Suggest users" panel (fallback for exceptions)
Confidently-mapped machines are handled automatically and don't appear here. On the Assets page, Suggest users opens a panel that lists only the exceptions:
- Proposed — a low-confidence match with no current owner. Assign links it; Ignore dismisses it.
- Conflict — the detected user differs from the person already linked. Three buttons: Reassign (replace with the detected user), Unlink (remove the owner and stop auto-mapping this machine), Ignore (keep the current owner and stop auto-mapping this machine).
- No matching user — the primary user is a local account (or otherwise has no AD account in Octotor), so there's no person to link. Two buttons: Create local user makes a person (named after the username, reused across machines with that username in the same customer) plus a local account (username + host, marked as admin if it's in the machine's local Administrators group) and assigns it to the computer; Ignore dismisses the machine so it stops appearing (e.g. a shared kiosk or a local-admin-only box you don't want to track).
Bulk actions. Nothing is pre-selected — tick the checkbox on any rows (including conflicts) and use Assign Selected, Ignore Selected, or Unlink Selected to act on them all at once, or use the header checkbox to select every row shown.
Reviewing what you ignored. Click Show ignored to list every machine opted out of auto-mapping (via Unlink or Ignore), with its current owner and who opted it out. Restore (per row) or Restore Selected removes the opt-out, so the machine re-enters auto-mapping on its next collection.
WS-1042 and finds 10 interactive logons in 14 days, all TRIPLEOR\jsmith → it stores primary_user = TRIPLEOR\jsmith, primary_user_confidence = 1.0. Because 1.0 ≥ 0.5 and jsmith resolves to Jamie Smith, Octotor immediately creates the Jamie Smith → WS-1042 assignment during that collection — no clicks. If WS-1042 had previously been linked to the IT admin (from the old ManagedBy behavior), that wrong link is removed in the same step. You never see WS-1042 in the Suggest-users panel because it's already correct. A machine whose primary user has no AD account in Octotor shows No matching user in the panel and is left alone.
get_user_link_suggestions, read-only).Pinning an owner — lock the Primary User, not the owner
Auto-map keeps the owner in sync with the machine's detected Primary User. On the next collection it will overwrite a manually-assigned owner to match whoever logged in most — unless you tell it not to. There is no "lock the owner"; there is only "lock the Primary User field", and the owner always follows that field.
- To keep person X as the owner: open the computer's Attributes, set Primary User to X's username, then click the lock icon on it. Locked → the collector can't change it → X stays the owner.
- Just assigning X by hand is not enough — if Primary User is unlocked (or locked to someone else), the next collect replaces X.
- Other ways to stop changes on a machine: Unlink or Ignore it in the Suggest-users panel (opts it out entirely), or turn off Auto-map users to computers in Settings.
RECEPTION-PC should always belong to Morgan, even though the night cleaner logs in more. Open RECEPTION-PC → Attributes → set Primary User = TRIPLEOR\mreed → click the lock. From now on every collection leaves it as Morgan; the cleaner's logins no longer flip the owner. Remove the lock later and auto-map resumes.Local administrators on a computer
The collector script windows/win-user/usr-local-admins.ps1 (a JSON collector) records the membership of each computer's local Administrators group into the Local Administrators attribute (under the computer's Attributes, Software & Users group). Each entry shows the Name (DOMAIN\principal), Type (User/Group) and Source (Active Directory or Local).
HELPDESK-01 the attribute lists TRIPLEOR\jsmith (User, Active Directory), HELPDESK-01\Administrator (User, Local), and so on. To find every computer where a jsmith principal has local-admin rights, go to Assets → attribute filter → local_admins contains jsmith. It's a substring match across the whole list, so it finds both the AD and any local JSMITH entry.Linux computers report the same Local Administrators attribute — the members of the sudo and wheel groups — collected by linux/collect-info.sh (folded into the standard collection) or the standalone linux/local-admins.sh. The table, drawer render and local_admins filter are identical to Windows, so local_admins contains jsmith matches Linux and Windows machines together.
DHCP client & server (computers)
Every computer collection records whether the machine's primary network adapter gets its IP from DHCP and, when it does, which DHCP Server issued the lease. Both appear under the computer's Attributes → Network group: DHCP Client (Yes/No) and DHCP Server (the server IP). On Windows they come from the adapter's IP configuration; on Linux from NetworkManager / the DHCP lease file.
Yes, DHCP Server = 10.20.0.1. A server with a fixed address shows DHCP Client = No (and no DHCP Server). To list every statically-addressed machine, use Assets → attribute filter → dhcp_client equals false.Password Never Expires (AD accounts)
The AD user collector (windows/collect-ad-users.ps1) records the Password Never Expires flag on each Active Directory account (under the account's Attributes → Security section, Yes/No). It's a password-hygiene signal — accounts whose passwords never expire are worth reviewing.
password_never_expires equals true. A service account like svc-backup will typically show Password Never Expires = Yes.Run
The Run page is where you execute scripts on target assets and follow multi-step protocols. It has three tabs: Command, Protocol, and History.
Running a Script
Multi-Asset Execution
Select multiple assets using the checkboxes. Octotor runs the script on each asset in parallel. Each asset gets its own output tab showing individual results.
Max Job Output
Per-job stdout/stderr is capped to prevent runaway scripts (e.g. accidentally tailing a multi-GB log file) from saturating the worker container. The cap is configured in Settings > Instance > Max Job Output (MB), defaults to 10 MB, range 1–1024 MB.
When a job's output exceeds the cap, the worker appends a one-line truncation marker, broadcasts it to the live view, and stops appending further output. The script continues to run to completion — only the captured-output stream is bounded. Exit code, action-log entries, and any side effects on the target (file writes, state changes) are preserved.
... > C:\Temp\out.txt) and retrieve via SCP/SMB rather than streaming through Octotor.Running a Protocol
Credential Selection
| Priority | Source | Description |
|---|---|---|
| 1 | Manual selection | You pick a specific credential from the dropdown |
| 2 | Asset-linked | Credential directly linked to the target asset |
| 3 | Per-customer default | Credential set as default for this customer + OS family |
| 4 | Global OS default | Credential set as default for the asset's OS family (linux/windows/mac) |
| 5 | Fail | No eligible credential found — error shown |
History Tab
Browse past executions. Click any entry to view the full output, operator who ran it, timing, and status.
- Run page → Command tab → pick target
WIN-DB01(a Windows asset). - Script list → Windows folder →
disk-free.ps1. - Credentials auto-select the
ACME_WIN_ADMINwindows-OS default — leave it. - Click Run → confirm. Ping succeeds, WinRM port 5985 is open, the script executes.
- Live output streams:
C: 42.1 GB free of 120 GB (35%); exit code 0; status done.
Dependencies
- Assets — at least one asset must exist with a hostname/IP
- Toolkit — at least one script must be available
- Credentials — matching credentials must exist (linked to asset or set as OS default)
Toolkit
The Toolkit is the script library. It contains system scripts (built-in, read-only) and custom scripts (created by admins). Scripts are organized by folders: Linux, Windows, Mac, Network, and Custom subfolders.
Script Types
| Type | Badge | Who can edit | Location |
|---|---|---|---|
| System scripts | SYSTEM | No one (read-only, baked into the image) | linux/, windows/, mac/, network/ |
| Custom scripts | USER | Admin only | custom/, custom/group-name/ |
Supported Script Extensions
| Extension | Language | Typical OS |
|---|---|---|
| .sh | Bash / Shell | Linux, Mac |
| .ps1 | PowerShell | Windows |
| .py | Python | Any |
| .bat | Batch | Windows |
| .cmd | Command | Windows |
Creating a Custom Script
Script Properties
- Enabled/Disabled — disabled scripts are hidden from the Run page
- Collector — marks the script as a data collector. When enabled, the script's output is parsed and stored as asset attributes (subject to the Auto Attribute Updates setting in Settings > Attributes)
- Parse Mode — how collector output is interpreted (JSON or AI-assisted)
- OS Family — which operating systems this script targets
Writing a Collector Script
A collector script is just an ordinary toolkit script with the Collector flag turned on. After the job finishes, the runtime parses the script's stdout, matches every key in that output against Settings > Attributes (the asset_attribute_defs table), and writes the matching values onto the asset.
The contract
- Output a single JSON object on stdout. Keys must match the registered attribute
keyexactly (case-sensitive). Values must match the def'sdata_type. Anything that doesn't match is silently skipped. - One value per key. Numbers as numeric JSON literals (
3.5, not"3.5"). Booleans astrue/false. Dates parseable byDate.parse()(e.g."2026-05-03"). Objects/arrays (e.g. a NIC list) are stringified before storage. - Stdout-only. Lines starting with
[STDERR]or[octotor]are stripped before parsing — anything else outside the JSON object will break the parse. (Output from jobs run before the rename shows the historical[octopus]prefix; it is stripped the same way.) - Unknown keys are skipped, not errors. If you emit
"freeRam": 3.5but the def isram_free_gb, the runtime logsskipped: freeRam(unknown_key)and moves on. No alert. No retry. - Locked attributes are skipped. If an admin locked
ram_free_gbon this asset (Attributes tab → lock icon), the collector cannot overwrite it. - Pending vs auto-apply. If the def has
auto_approve=true, the value is written directly. Otherwise it goes to the pending-approval queue (Assets > Pending Attribute Updates) until an admin approves. - Removals (clear-on-removal contract). For a small, fixed set of fields the built-in collectors report removals: an empty-string value (
"license": "") means "I checked — this value is gone at the source", and Octotor clears the stored attribute (auto-approve on) or queues a (cleared) proposal for review (auto-approve off). An omitted key still means "not collected this run" and never touches the stored value. Values last set manually are never auto-cleared — a removal against a manual value always goes to the pending queue. Custom collector scripts cannot clear arbitrary fields: only keys in the built-in contract (api/services/collector-contract.js) are honored; empty values for every other key are skipped exactly as before.
Worked example — removed M365 license clears automatically
- User
tbrooks@tripleor.comshows License =O365_BUSINESS_PREMIUMon their m365 account asset (collected by the M365 sync). - The tenant admin removes Taylor's license in the Microsoft 365 admin center.
- On the next M365 sync, the collector reports
"license": ""for Taylor (evaluated, gone). Since thelicensedef ships with Auto-approve on, the attribute is cleared immediately — the drawer no longer shows a license, and the attribute history recordsO365_BUSINESS_PREMIUM → (cleared)with source collector. - If an operator had manually typed that license value earlier (source manual), the sync would instead add a (cleared) row to Assets > Pending Attribute Updates — approving it deletes the attribute, rejecting keeps the manual value.
Discovering the keys you can emit
Three ways to get the canonical key list — pick whichever fits your workflow:
- Browse — Settings > Attributes shows every key + label + type + auto-approve flag.
- API —
GET /api/attributes/defs?asset_type=computerreturns JSON for the current asset type. - Export —
GET /api/attributes/defs/exportdownloadsseed-attributes.jsonwith every def the system knows about.
Example — query RAM on a Linux/macOS asset (Bash)
Targets attribute keys ram_gb and ram_free_gb (both data_type=number; ram_free_gb is auto-approve).
#!/bin/bash
# check-ram.sh — emit RAM totals as JSON for the Octotor collector.
# Mark this script as Collector with parse_mode=json in Toolkit.
RAM_MB=$(free -m | awk 'NR==2{print $2}')
RAM_FREE_MB=$(free -m | awk 'NR==2{print $7}')
RAM_GB=$(awk "BEGIN{printf \"%.1f\", $RAM_MB/1024}")
RAM_FREE_GB=$(awk "BEGIN{printf \"%.1f\", $RAM_FREE_MB/1024}")
cat <<EOF
{
"ram_gb": $RAM_GB,
"ram_free_gb": $RAM_FREE_GB
}
EOF
Example — query RAM on a Windows asset (PowerShell)
Same two attribute keys, formatted as a numeric JSON object via ConvertTo-Json.
# check-ram.ps1 — emit RAM totals as JSON for the Octotor collector.
# Mark this script as Collector with parse_mode=json in Toolkit.
$os = Get-CimInstance Win32_OperatingSystem
$ramTotalGB = [math]::Round($os.TotalVisibleMemorySize / 1MB, 1)
$ramFreeGB = [math]::Round($os.FreePhysicalMemory / 1MB, 1)
$payload = [ordered]@{
ram_gb = $ramTotalGB
ram_free_gb = $ramFreeGB
}
$payload | ConvertTo-Json -Compress
Add your own custom attribute — end to end (antivirus example)
Say you want every computer to show whether an antivirus product is installed, and you want to filter on it. Three steps, no code changes to Octotor:
- Define the attribute. Go to Settings > Attributes → Add attribute. Asset type
computer, Keyantivirus_installed, Label Antivirus Installed, Typeboolean, Auto-approve on (so it writes without a pending review). The key is the contract — your script must emit exactly this name. - Write a script that outputs that key. Anything on stdout that isn't the JSON object is ignored, so emit one JSON object. The value type must match the def (
booleanhere). See the copy-paste example below. - Flag it as a Collector. Upload/enter the script on the Toolkit page, open it, turn on Collector, set Parse Mode
JSONand OS Familywindows. Run it (or schedule it on the Scheduler) against your computers.
On the next run the collector writes antivirus_installed onto each computer. It then shows in the computer's Attributes, and you can filter it on the Assets page (attribute filter → antivirus_installed equals false to find unprotected machines) and ask the Goose agent about it.
# check-antivirus.ps1 — report whether a real antivirus product is registered.
# Mark this script as Collector with parse_mode=json in Toolkit.
# Requires the attribute def key `antivirus_installed` (boolean) to exist first.
$ErrorActionPreference = 'SilentlyContinue'
# Windows Security Center lists registered AV products (excludes Defender-only-off cases).
$av = Get-CimInstance -Namespace 'root/SecurityCenter2' -ClassName 'AntiVirusProduct'
$installed = [bool]($av | Where-Object { $_.displayName })
$names = ($av | ForEach-Object { $_.displayName } | Where-Object { $_ }) -join ', '
# Emit the exact attribute keys. `antivirus_installed` must be a registered boolean
# attribute; `antivirus` (text) is optional — add that def too if you want the names.
$payload = [ordered]@{
antivirus_installed = $installed
antivirus = $names
}
$payload | ConvertTo-Json -Compress
antivirus_installed but register av_installed and the runtime logs skipped: antivirus_installed(unknown_key) and writes nothing. Define the attribute first, then match the key.How to know it worked (no shell access needed)
- Save the script in Toolkit and toggle Collector ON (action password may be required).
- Run it once on a test asset via the Run page.
- Open that asset's drawer (Assets > click the row) and switch to the Jobs tab. Your run appears at the top with a
collected Nbadge — that N is exactly the number of attributes the runtime auto-applied from the script's output.collected 0means the script ran successfully but the runtime didn't accept any of the keys it emitted. - Expand the job row in the Jobs tab to see the script's full stdout — that's the JSON your script actually emitted. Compare it to the registered keys in Settings > Attributes: any key not on that list is treated as
unknown_keyand silently skipped, and any value that doesn't match the def'sdata_typeis treated astype_validationand skipped. - Switch to the Attributes tab — if a key landed and was auto-approved, the new value appears under its group (HARDWARE / NETWORK / etc.) with an AUTO badge and a "from collector script" subline.
- If the def has
auto_approve=false, the value goes to the pending queue instead — open Assets > Pending Attribute Updates and you'll see a row with old → new values waiting for an admin to approve or reject. - For a full audit trail of what changed and when, use the asset's Changes tab and filter by source = collector. Each row shows
old → new, the timestamp, and whichcollector:job#Nwrote it. - If your collector is wired into a scheduled task that drives an alert rule, the Alert Center detail panel Source row will read "Scheduled task · <your task name>" + "collector script <your script> updated <key> (job #N)". End-to-end chain complete.
unknown_key / type_validation / locked / value_too_long / empty_value) are recorded on the job row in the database but not yet surfaced in the UI — for now, the fastest way to diagnose collected 0 is to compare your script's stdout (visible in the expanded Jobs row) against Settings > Attributes by hand. A "collector dry-run + skip-reason inspector" UI is planned for a future release.Skip-reason vocabulary
| Reason | Meaning | Fix |
|---|---|---|
unknown_key | Emitted key has no matching def for this asset_type | Check Settings > Attributes for the exact key |
type_validation | Value didn't match the def's data_type | Number = numeric literal, boolean = true/false, date = ISO-parseable |
value_too_long | Value exceeds 1000 characters | Trim or split into multiple keys |
empty_value | Value is "", null, or undefined | Omit the key entirely instead of emitting a blank |
locked | Admin locked this attribute on this asset | Unlock from the asset's Attributes tab if intentional |
ai. The runtime sends the raw output plus the attribute-def schema to the local LLM (Ollama via LiteLLM), which extracts a matching JSON object. Trade-off: every collector run pays for an LLM call, and the result is only as good as the model — for fixed-format scripts, JSON parse mode is faster and deterministic.AI Validation
Octotor uses a local AI model to review scripts before saving. It checks for:
- Blocked patterns — destructive commands (rm -rf /, format disk, credential harvesting, reverse shells)
- Warnings — sudo usage, service restarts, registry modifications, network changes
Risk Classification
Every script is assigned a risk level based on AI validation. The risk level determines whether an action password is required to execute the script.
| Level | Badge | Meaning | Execution gate |
|---|---|---|---|
| High | HIGH | Destructive or privileged operations | Requires action password |
| Medium | MED | System modifications | Requires action password (if configured) |
| Low | LOW | Read-only or informational | No password required |
Risk levels are assigned automatically by AI during validation and displayed as colored badges in the script list and detail panel. Admins can change the risk level manually; downgrading requires the risk_downgrade action password (see Security).
Content Hash
Each script has a SHA-256 content hash (visible in the detail panel) that is recalculated on every save. This allows admins to verify a script hasn't been modified outside the UI.
Dependencies
- AI (optional) — Ollama + LiteLLM must be running for script validation. Without AI, scripts can be saved directly if "Skip AI Validation" is enabled
Uptime collection
Computer assets carry an uptime_seconds attribute (integer; seconds since last boot). Two paths populate it:
- Inside the full collectors —
windows/collect-info.ps1,linux/collect-info.sh, andlinux-embedded/collect-info-qnap.shemituptime_secondson every run. Same cadence as the rest of the collector data (usually 4 hours). - Dedicated one-shot scripts —
windows/uptime.ps1,linux/uptime.sh,linux-embedded/uptime-qnap.shemit JUST{"uptime_seconds": N}. Schedule these on a short cadence (e.g. every 5–15 minutes) when you want fast reactivity for "asset rebooted" or "uptime exceeded" alerts without paying for the full ~20-WMI-call collect-info run.
The Identity & Status row in the asset Overview tab renders the value adaptively: 15 seconds / 1 minute 15 seconds / 2 hours / 5 days 4 hours 22 minutes 15 seconds. Trailing zero components are trimmed; middle zeros are preserved (so a host up exactly 1 day and 15 seconds renders as 1 day 0 hours 0 minutes 15 seconds, not the misleading 1 day 15 seconds).
Threshold-rule conversion table
Alert rules compare against uptime_seconds directly. Common thresholds in seconds:
| Wall clock | Threshold value | Example rule |
|---|---|---|
| 1 hour | 3600 | uptime_seconds < 3600 — fires when an asset rebooted in the last hour |
| 1 day | 86400 | — |
| 7 days | 604800 | — |
| 30 days | 2592000 | uptime_seconds > 2592000 — warn that the asset is overdue for a reboot |
| 90 days | 7776000 | uptime_seconds > 7776000 — critical: patching cycle is missing |
| 1 year | 31536000 | — |
No default uptime rules are seeded — create your own under Alert Center > Rules > New Rule, pick the uptime_seconds attribute, choose a comparator and value from the table above.
Worked example rules
Two concrete examples for common uptime alert needs. Open Alert Center > Rules > New Rule and use the field values verbatim.
Rule 1 — Long uptime (reboot overdue)
Notifies on assets up for more than 3 months (90 days).
| Field | Value |
|---|---|
| Name | Long uptime — reboot overdue (>90d) |
| Severity | warning (orange — reboot reminder, not a crisis) |
| Category | availability |
| Rule type | threshold |
| Threshold attribute | Uptime (seconds since last boot) |
| Operator | > |
| Value | 7776000 (90 days × 86 400 s/day) |
| Dedupe window (min) | 1440 (kept for older rules; an open alert is never duplicated whatever this value is — the reminder cadence is the Cooldown below) |
| Cooldown (min) | 10080 (7 days — with Notify again while still breaching on, one reminder a week while the asset stays above the threshold: a weekly nag, not a daily one) |
| Notify channels | Whatever you've configured (email / Telegram / Slack / webhook) |
| Target scope | Leave empty — uptime_seconds only exists on computer-type assets per the def |
After save, every asset that's been up > 90 days fires once. After a reboot, the rule auto-resolves on the next collector cycle (uptime crosses back below 7,776,000). If 30 days later it's back above 90 d, the rule fires again.
Reminders while the problem lasts — "Notify again while still breaching"
Every rule has this option in its Schedule section; it is on for new rules. While an alert stays open — nobody acknowledged it and the condition has not cleared — Octotor sends the rule's notification again every Cooldown minutes, so a problem that lasts for days keeps reminding you. Acknowledging the alert in the Alert Center stops the reminders; so does turning the option off on the rule, or setting Cooldown to 0. Each reminder is written to the Investigate page as renotified, and the reminder message is marked STILL OPEN with "Reminder N — open since …". Every attempt is logged, delivered or not: the Investigate line reads "attempt N — reminder M: … sent, … failed, … skipped", so a channel that keeps failing shows a rising attempt number while the reminder number stays put; the alert worker's status on the Services page shows attempts and deliveries separately (renotify_attempts / renotified).
Worked example: the seeded rule Backup job failed on server (Cooldown 1440) fires at 02:11 when the nightly job fails because the backup storage is full. Nobody fixes it that day. At 02:11 the next day the same channels receive "STILL OPEN — reminder 1", and again every 24 hours until the job succeeds (the alert resolves itself) or someone clicks Acknowledge. Rule 1 above uses Cooldown 10080, so its reminder is weekly.
Rule 2 — Recently rebooted
Notifies on assets up less than 3 hours.
| Field | Value |
|---|---|
| Name | Asset recently rebooted (<3h) |
| Severity | info (or warning if you want it more prominent) |
| Category | availability |
| Rule type | threshold |
| Threshold attribute | Uptime (seconds since last boot) |
| Operator | < |
| Value | 10800 (3 h × 3 600 s/h) |
| Dedupe window (min) | 60 (kept for older rules; has no effect on an open alert) |
| Cooldown (min) | 240 (4 h — longer than this alert can stay open, so no reminder is ever sent; you can also turn Notify again while still breaching off on this rule) |
| Notify channels | Same as Rule 1 |
| Target scope | Leave empty |
Rule 2 cadence gotcha — schedule uptime.{ps1,sh} hourly
The uptime value on each asset only updates when a collector script runs. The full collect-info cadence is typically every 4 hours, so a 3-hour window can be missed entirely between two collector runs:
09:00 Asset reboots (uptime = 0) 10:00 Asset is at 1 h uptime (no collector running) 11:00 Asset is at 2 h uptime (no collector running) 12:00 Asset is at 3 h uptime (no collector running — exactly at the threshold) 13:00 collect-info runs (uptime = 4 h is what gets recorded) 13:00 Rule 2 checks "is uptime < 3 h?" → NO (it's 4 h) → rule doesn't fire
Result: asset rebooted, but you never get the "recently rebooted" alert. The 3-hour window came and went between two collector runs.
Fix: schedule the dedicated uptime.ps1 / uptime.sh scripts on a cadence shorter than the rule window. Configure at Scheduler > New Task.
Cadence trade-offs:
| Cron | Chances per 3-h window | Verdict |
|---|---|---|
*/15 * * * * | 12 | Overkill |
*/30 * * * * | 6 | Solid but more than needed |
0 * * * * | 3 | Recommended |
0 */2 * * * | 2 (worst case 1) | Tight — risky if one job misses |
0 */4 * * * | 1 max | Equivalent to full collect-info — dedicated script adds nothing |
Rule 1 doesn't have this concern — the default 4-hourly collect-info is plenty for a "uptime > 90 days" check.
Storm-cap awareness
If a maintenance window reboots 100 hosts at once, Rule 2 would fire 100 times within a short window. Octotor's per-rule storm cap (default 100/min, configurable per-rule) prevents the notification firehose — beyond the cap, alerts are recorded with storm_suppressed=true and the notification channel just gets a single "+97 more" summary instead of a flood. Consider setting storm_cap to e.g. 20 on Rule 2 if you're worried about mass-reboot churn.
Scheduler
The Scheduler runs scripts automatically on a recurring schedule. Tasks are defined using cron expressions and can target assets by type, attribute values, and customer scope.
Besides Script tasks, two non-asset task types exist: Goose Recipe (natural-language instruction executed by the AI agent) and M365 Sync (triggers a Microsoft 365 connector sync — see Help > M365 Connectors, Part 6). Non-asset types hide the target/execution sections; an M365 Sync task needs only a connector and a schedule.
Trigger: Time schedule vs On alert (auto-remediation)
Every task has a Trigger: Time schedule (the classic cron behavior) or On alert. An On-alert task carries no cron — it runs only when an Alert Center rule that links to it fires. This turns any monitoring Octotor does (offline/status, threshold, custom checks, events) into an automated response. Pro tier; attaching an action to a rule is admin-only.
To wire one up:
- Scheduler > New task → set Trigger = On alert. Pick the script, target, and credential as usual. Under Alert-trigger options choose Run on:
- The task's own target — runs against the assets the task's target filter selects (e.g. a specific firewall).
- The asset that fired the alert — runs against whichever asset tripped the rule. Because Octotor fires per asset, a rule matching 5 of 7 hosts runs the task on those 5 hosts individually.
- Set the guardrails: Cooldown (minimum minutes between runs) and Max runs / hour (after which Octotor stops and logs an "auto-remediation stopped — manual intervention needed" warning). These prevent a flapping alert from hammering the target or looping forever.
- Alert Center > Rules > New/Edit rule → under Run task on fire, pick your alert-triggered task. Save.
Now, whenever that rule fires, the task runs (subject to cooldown/cap). Dispatches, cooldown suppressions, and cap stops are all recorded in the action log (category alert) so you can see exactly when a remediation ran or was throttled. Creating or editing a rule never triggers the task — only real fires do.
Configuring the guardrails — worked examples
The two guardrails are set on the task (Scheduler ▸ task ▸ Alert-trigger options). They are independent:
| Field | What it does | Range | Default |
|---|---|---|---|
| Cooldown (minutes) | Minimum time that must pass after a run before the same task runs again. A fire inside the window is suppressed (logged, not run). 0 disables the cooldown. | 0–1440 | 10 |
| Max runs / hour | Ceiling on runs in any rolling 60-minute window. Once reached, further fires are suppressed and Octotor logs a single "auto-remediation stopped — manual intervention needed" warning. 0 would disable the cap (not recommended). | 1–100 | 3 |
| Verify after (seconds) | Post-fix verification: if the alert that triggered the task is still open this many seconds after the task ran, Octotor runs the task again automatically. Retries bypass the cooldown (a 10-minute cooldown would otherwise swallow a 5-minute verify window) but are bounded by Max retries. Alerts you have acknowledged are never retried — acknowledging means a human owns the incident. 0 turns verification off (the task runs once per fire). | 0, or 60–86400 | 0 (off) |
| Max retries | How many extra runs one alert may trigger through verification. The first run doesn't count — 2 means up to 3 runs total per alert. Every re-fire is recorded in the action log (category alert, "remediation re-dispatched"). | 0–10 | 2 |
Example 1 — VPN tunnel reset (steady, safe)
Cooldown 10 · Max/hour 3. The tunnel drops and the ping rule fires:
| Time | Rule fires? | Action |
|---|---|---|
| 10:00 | yes | Run — reset the tunnel (run #1) |
| 10:02 | yes (still flapping) | Suppressed — inside the 10-min cooldown |
| 10:11 | yes | Run — cooldown elapsed (run #2) |
| 10:22 | yes | Run (run #3) |
| 10:33 | yes | Suppressed — 3 runs already this hour → "auto-remediation stopped, manual intervention needed" alert fires once |
| 11:05 | yes | Run — the rolling hour has cleared the older runs |
Net effect: a real reset is attempted, brief flapping doesn't hammer the firewall, and if three resets in an hour don't fix it you get paged instead of an infinite loop.
Example 2 — restart a service, react fast but bounded
Cooldown 2 · Max/hour 6. Good when the remediation is cheap and you want a quick retry cadence but still a ceiling — up to 6 restarts an hour, no more than one every 2 minutes.
Example 3 — one-shot, never repeat automatically
Cooldown 1440 (24 h) · Max/hour 1. The task runs at most once per fire-storm per day — useful for a heavy or disruptive remediation you want to run once and then leave to a human until tomorrow.
remediation_dispatched / suppressed_cooldown / suppressed_cap / remediation_capped).Job History (per task)
Click Hist on any task (or the task name) to open its execution history. Each run lists its jobs with Job# · Asset · Customer · Asset type · Status · Exit · Started · Finished, plus skipped runs (e.g. "no credential available"). Click View on a job to see the full record — the same baseline the Investigate page uses (Triggered-by, Customer, Asset-type, Source/Dst IP) followed by the complete script output. Tasks that span multiple customers show which customer each job belonged to.
System Timezone
All scheduled tasks fire in the timezone set at Settings > Instance > System Timezone. On first save, the dropdown defaults to your browser's timezone (auto-detected) — operators in different regions can override. The Edit Task modal shows the current timezone below the cron expression input so you always know what wall-clock time your tasks will fire at.
Cron expression syntax
Cron expressions are five fields, space-separated, each with its own range:
| Position | Field | Range | Wildcards |
|---|---|---|---|
| 1 | Minute | 0–59 | * any, */N every N, A,B,C list, A-B range |
| 2 | Hour | 0–23 | same |
| 3 | Day of month | 1–31 | same |
| 4 | Month | 1–12 | same |
| 5 | Day of week | 0–7 (0/7=Sun) | same; 1-5 = Mon-Fri |
Worked examples
| Cron | Fires when |
|---|---|
*/5 * * * * | Every 5 minutes (00:00, 00:05, 00:10, …) |
17 * * * * | Every hour at minute 17 (00:17, 01:17, 02:17, …) |
0 */4 * * * | Every 4 hours starting at midnight (00:00, 04:00, 08:00, …) |
3 17 * * * | Daily at 17:03 |
0 6,18 * * * | Twice daily — 06:00 and 18:00 |
0 9-17 * * 1-5 | Every hour, Mon–Fri 09:00 through 17:00 |
0 8 * * 1-5 | Weekdays at 08:00 |
30 18 * * 5 | Fridays at 18:30 |
0 2 * * 0 | Sundays at 02:00 |
0 6 1 * * | 1st day of every month at 06:00 |
0 6 1,15 * * | 1st and 15th of every month at 06:00 |
0 6 1 1,7 * | 1st of January and 1st of July at 06:00 (semi-annual) |
Common gotchas
- Don't put colons inside a field.
0 17:03 * * *looks like "17:03" but in cron syntax that's minute=0, hour=17:03 (invalid). The right pattern for "daily at 17:03" is3 17 * * *— minute first, hour second, two separate fields. - Day-of-month and day-of-week are OR-ed, not AND-ed.
0 6 15 * 1fires on the 15th of any month or any Monday — not "Mondays that are also the 15th." If you mean "every Monday in March," use0 6 * 3 1. - Timezone is system-wide. Cron expressions are interpreted in Settings > Instance > System Timezone. The Edit Task modal shows the active TZ under the cron field.
- The cron has no "start time" memory. If you save
0 * * * *at 18:42, the first firing is 19:00 (the next minute=0). Cron doesn't track when you saved the task.
Creating a Scheduled Task
Common Cron Patterns
| Expression | Meaning |
|---|---|
| */5 * * * * | Every 5 minutes |
| 0 * * * * | Every hour |
| 0 6 * * * | Daily at 06:00 |
| 0 8 * * 1-5 | Weekdays at 08:00 |
| 0 0 * * 1 | Every Monday at midnight |
| 0 6 1 * * | First of every month at 06:00 |
Task Targeting
Tasks can narrow their scope using multiple filters that stack:
| Filter | Effect |
|---|---|
| Asset Type | Only run on assets of this type (e.g. "computer") |
| Attribute Filter | Only run on assets where a specific attribute contains a value (e.g. location contains "Warehouse") |
| Customer Scope | Only run on assets belonging to a specific customer |
| (none set) | Runs on all non-disabled assets |
Connectivity Check
Before each job runs, Octotor checks if the target asset is reachable:
Skip targets the online monitor reports offline
When this option is ticked, a run does not create a job for a target that the online monitor checked recently and found offline. Without the option, such a target gets a job that the connectivity check then cancels, which fills the Run page and the job history with cancelled rows.
"Recently" means inside the same time window the Assets page uses before it shows a status as Unknown: the value of Settings > Monitoring > Mark asset as Unknown after (seconds) when it is set to a value above 0, otherwise twice the online-monitor interval. A target still gets a job when any of the following is true:
- the online monitor is switched off, or has never checked the target
- the target is reached through a jump host (the online monitor checks it directly, the job goes through the jump host)
- the port monitor reports the target's SSH, RDP or WinRM port as open in the same window
- the task has Auto-proceed if connectivity check fails ticked
- an alert started the task for the asset that raised the alert
Each run that leaves targets out writes one line, shown under Last run in the task list and in the task's History: for example 3 targets skipped: offline per online monitor. The History line also names the first ten targets.
New tasks have the option ticked. Tasks that existed before version 3.3.12 have it cleared, so they behave as before until you tick it. If a target blocks ping but accepts SSH or WinRM and the port monitor is not enabled for it, clear the option for that task, or enable the port monitor on the asset.
Worked example. The task Nightly inventory targets the 40 computers of customer TRIPLEOR. Three of them, tor-ws-07, tor-ws-12 and tor-lab-02, are switched off; the online monitor (interval 300 seconds) last checked them 2 minutes before the run and found them offline.
- Open Scheduler, click Edit on Nightly inventory.
- Under Run options, tick Skip targets the online monitor reports offline and click Save.
- At the next run the task queues 37 jobs instead of 40. The task row shows
3 targets skipped: offline per online monitorunder the last-run time, and the History panel shows the same line with the three names.
Credential Resolution
For each target asset, the scheduler resolves credentials in this order:
| Priority | Source |
|---|---|
| 1 | Task-level credential (set in task configuration) |
| 2 | Asset-linked credential (linked in asset detail) |
| 3 | Per-customer default (set in Settings > Credentials for this customer + OS family) |
| 4 | Global OS default credential (set as default for the asset's OS family) |
| 5 | Skip — asset is skipped with a warning in the action log |
Task History
Click a task name or the clock button to view its execution history:
- Runs — each execution grouped by timestamp, showing per-asset job status (done/failed/cancelled), exit codes, and timing
- Skipped / Info — assets that were skipped (no credential available), targets left out because the online monitor reports them offline (
offline_skipped), or runs that found zero matching targets
Task Options
| Option | Effect |
|---|---|
| Enabled | Task fires on its cron schedule when enabled |
| Run Once | Task auto-disables after its first execution |
| Auto-proceed on ping fail | Skip connectivity check — attempt SSH even if ping and TCP port check fail |
| Skip targets the online monitor reports offline | Do not create a job for a target the online monitor recently found offline; the run records how many it left out (see above) |
| Timeout (sec) | How long one job of this task may run, in seconds (10 to 3600). Leave it empty to use the global value from Settings > Management Protocols (SSH or WinRM > Timeout (seconds); the SSH default is 30). Set it when the script needs longer than the global value, for example a backup collector that reads a long job history. Every job prints the limit it runs under (Timeout 240 s (the task's "Timeout (sec)" field)) and a job that is cut off says which field set the limit. |
| Override Identity Verification | When checked, the task uses its own identity settings instead of the global ones from Settings > Monitoring. All 5 settings (DNS, SSH gate, require probe, collector check, mismatch behavior) can be configured per task. |
Auto-Refresh
The "Auto" button in the page header enables 10-second auto-refresh of the task list. When you trigger a task manually, the list also auto-reloads after 2 and 5 seconds to show the updated status without requiring a manual page refresh.
Dependencies
- Toolkit — the script must exist in the toolkit
- Assets — at least one asset must match the target filters
- Credentials — matching credentials must exist for the target assets (task-level, linked, or OS default)
Investigate
The Investigation page provides a unified timeline of all system activity — audit logs and job executions merged into a single, filterable view. Use it to answer questions like "what happened to this asset?" or "what failed today?".
How It Works
Investigation merges data from three sources:
| Source | What it contains | Badge color |
|---|---|---|
| Logs | Audit events — logins, asset changes, config updates, scheduler skips, maintenance actions | Grey |
| Jobs | Script executions — queued, running, done, failed, cancelled. | Blue |
| Attribute changes | Attribute change history — every old → new transition of every asset attribute, including removals shown as (cleared). Triggered-by tells you whether a human edit (👤), a CSV import (📥) or a collector (📡) made the change. | Grey |
Attribute changes — investigating history
Pick Source → Attribute changes and two extra filters appear: Attribute (grouped by provider, same as the Assets page) and Value (old or new) — the value filter matches either side of a change, so you can find every place a value ever appeared.
production log on to?"
- Source → Attribute changes
- Attribute → Last Logged-in User (under Computer)
- Value (old or new) →
production, Customer → tripleor → Apply
Every row is one transition on one machine — e.g. DOMAIN\alice → DOMAIN\production on TRI-LAB-01 two weeks ago. The View modal shows the full record (old value, new value, change source). You can ask the AI Assist the same question in plain words, or ask Goose: "which computers did user production log on to at tripleor?"
Unmatched M365 sign-ins
Administrators see a button Unmatched sign-ins above the filters (the number in brackets is how many sign-in names of the last 7 days still need a decision). It opens the list of Microsoft 365 sign-ins whose sign-in name matches no M365 account in Octotor, with a reference number on every row, and the actions Link to account… and Ignore this principal for one row or for every ticked row. The full description and a worked example are under M365 Connectors, Part 8.
The event line
Every row carries a consistent set of fields so any event is scannable at a glance:
| Field | What it shows |
|---|---|
| # | The row's own id — shown for every event (logs and jobs alike), never blank. Earlier this column only filled for jobs. |
| Triggered by | The mechanism that initiated the event: 👤 Operator (a human), ⏱ Scheduler (a scheduled task), ⚙ System (autoping / TCP monitor / alert engine / maintenance), 🤖 Goose AI, 🔔 Alert rule, or 🔑 API token. |
| Operator | The human behind the event, if any. Blank for pure system / scheduler / alert-rule events. (Available in the View modal; promote to a column via the chooser.) |
| Customer | Which customer the event belongs to. Resolved from the event's customer attribution, or from the target asset. |
| Asset type / Source IP / Dst IP | Shown when applicable (the event targets an asset / carries a source address). Always present in the View modal; optional columns via the chooser. |
Use the Columns ▾ button to promote any of the optional fields (Operator, Asset type, Source IP, Dst IP) into the table. Your selection is remembered in this browser.
Filters
All filters are optional and work together (AND logic). Results update immediately as you change filters. Use the 📌 pin button to persist filters across page navigation.
| Filter | What it does |
|---|---|
| Date range | From/To date pickers — narrow to a specific time window |
| Source | Show only Logs, only Jobs, or All |
| Category | auth, asset, job, scheduler, settings, sync, goose, ai, identity, maintenance |
| Status | ok, done, error, failed, warning, cancelled, running, queued, identity_mismatch (the host answered with a different name), identity not verified (the identity probe got no answer, so the job did not run) |
| Operator | Username of who performed the action (includes "scheduler: task_name") |
| Asset name | Filter events related to a specific asset |
| Customer | Narrow to a single customer. The dropdown only lists customers you are scoped to, and the filter narrows within your existing access — it can never widen it. |
| Search text | Free text search across detail, script path, target name |
Attribute Cross-Filters
Click Attr Filter to filter events by asset attributes. You can add multiple attribute conditions (AND logic). Each filter has:
- Attribute — select from available attribute definitions (e.g., OS Family, Location)
- Mode — Include (show matching) or Exclude (hide matching)
- Comparison — contains, equals, > (greater than), < (less than), or is one of: the value lists every accepted value separated by a vertical bar, for example
server|domain controllermatches a machine role of either kind - Value — the value to match against
View Details
Click View on any event row to see full details:
- Job events — opens the modal with the full record (id, triggered-by, customer, asset type, source/dst IP, status, exit code, duration) followed by the complete script output
- Log events — shows the full record (id, triggered-by, operator, customer, asset type, source/dst IP, target, timestamp, status) plus the complete, untruncated detail text
AI Investigation
When enabled, the AI query bar appears at the top of the page. Type a natural language question and the AI will:
- Translate your question into filter parameters (using knowledge of all asset attributes)
- Execute the query (respecting your permissions — customer scope, role, group)
- Fetch asset details for mentioned assets (IP, hostname, OS, all attributes)
- Summarize the results in plain language
The AI can answer both event questions ("what failed today?") and asset questions ("what is the IP of ast01?") because it has access to asset details during summarization.
Follow-up questions: The AI remembers your previous questions in the current session. You can ask "what jobs ran on it today?" after asking about a specific asset — the AI knows what "it" refers to. Use the Clear button to reset the conversation.
AI Conversation Logging: When enabled in Settings > AI Configuration, all AI queries and responses are logged to the action log for admin review.
AI Toggle
AI investigation has two levels of control:
| Level | Who controls | Effect |
|---|---|---|
| Admin setting | Admin (Settings > AI Configuration) | Enables/disables AI investigation for all users |
| User toggle | Each user (on the Investigation page) | Personal preference to show/hide the AI bar |
Export
Click Export CSV to download the current filtered results as a CSV file.
Permissions
| Role | What they see in Investigation |
|---|---|
| Admin | All events from all sources, all customers |
| Operator | Events for their assigned customers — both logs and jobs |
| Viewer | Log events for their assigned customers only — job events are excluded (no Run page access) |
Dependencies
- Activity to investigate — Investigate reads the
action_logand job history, so a brand-new instance shows little until logins, jobs, and collectors start writing events. - AI investigation (optional) — the AI summary bar needs AI enabled in Settings > AI Configuration and a reachable model (local
oct-litellm/oct-ollama, or an allowed external LLM).
Alert Center
The Alert Center surfaces operational events that need attention — asset outages, identity mismatches, threshold breaches — in a single dedicated page. Unlike the Investigate timeline (full audit log), the Alert Center shows only actionable items and supports acknowledge/resolve workflows.
Evaluation engine
A dedicated container, oct-alert-worker, runs the evaluation loop. It listens on the PostgreSQL channel alert_check and evaluates matching rules on every notification. The worker never calls oct-api over HTTP — all state flows through the database, consistent with the single-responsibility container model (see About).
What fires an alert
The rule engine is live end-to-end. Six rule types can raise alerts — create and scope them in Alerts Admin > Rules:
- status — an asset enters a watched state (e.g.
computer→offline). The built-in case is availability: when autoping detects an online→offline transition for an asset with Create alert when this asset goes offline enabled, an alert is raised and auto-resolves when the asset returns. - threshold — a numeric collector attribute crosses a bound (e.g.
disk_free_gb < 10). - os_event — a matching Windows / syslog event is ingested.
- ingest — an external webhook or email event matches.
- signin — a Microsoft 365 / Entra sign-in matches (e.g. a failed sign-in, or a sign-in from an unexpected country). Fed by the M365 connector's sign-in poll.
- custom — one of 9 check-types: run a script and check its result, Windows service state, TCP port reachable, HTTP(S) endpoint responds, process running, disk free space, file exists, LDAP bind, or AI analysis of output.
Watch every data disk on every server
The collect-info scripts report every data disk a server has — not only the system disk. Each disk gets its own attributes (size, free GB, free %, and the volume label), named by its drive letter on Windows (Disk Free D: (%)) or its mount path on Linux (Disk Free /data (%)). Two extra attributes summarize the whole server: Data Disk Free — Worst (%) holds the lowest free-space percentage across all of that server's data disks, and Data Disk With Least Free Space names which disk that is. When a disk is removed from the server, its attributes are cleared on the next collect run. The asset's Overview tab shows one usage line per data disk, fullest first.
This means ONE alert rule covers every data disk on every server. When it fires, the alert text names the disk (for example "disk: D: DATA").
- Open Alerts Admin > Rules and click New rule.
- Name:
Data disk low. Rule type:threshold. - Attribute key: pick
Data Disk Free — Worst (%). Operator:<=. Value:10. Data type:number. - Click Create rule.
Dependencies
oct-alert-workercontainer running — it listens on thealert_checkchannel and runs the evaluation loop. Confirm it on Services Status > Service Heartbeats.- Master alert toggle ON (Alerts Admin > Globals) — when off, rules stay visible but every fire is a no-op.
- autoping monitoring the asset — availability (status/offline) alerts are driven by autoping transitions, so the asset must be a monitored target.
- A notification channel (Alerts Admin > Channels) — only needed to push beyond the in-app Alert Center (email / Telegram / webhook).
computer / trigger offline rule — any implicit offline alert raised earlier can no longer auto-resolve and must be resolved manually in the Alert Center. New offline events from then on are handled by the explicit rule, which auto-resolves normally. A fix is planned.Enable offline alerts on an asset
- Open the asset on the Assets page and click Edit.
- Check Create alert when this asset goes offline and Save.
- To enable for many at once: select the assets on the Assets page, then click Enable Alerts in the bulk-action bar (Disable Alerts reverses it).
- Assets page → open
DB01→ Edit → check Create alert when this asset goes offline → Save. (Autoping must already be monitoring DB01.) - DB01 goes down. Within one autoping cycle the Alert Center shows a new critical row — title "DB01 is offline", category
availability. - Click the row title → the explain pane shows Status (open), Cause (autoping online→offline at the exact timestamp), and the available Actions (Ack / Resolve).
- DB01 comes back → within a cycle the alert auto-resolves with a ✅ "back online" note — no manual cleanup.
Acknowledge + resolve
Open alerts show Ack and Resolve buttons per row. Acknowledged means an operator is aware and working on it; Resolved marks the issue closed. Acknowledging here also marks the matching item on the Customer Overview as acknowledged (one record for both pages). An acknowledged, resolved or auto-resolved alert shows a Reopen button: it sets the alert back to open — if the problem is gone, monitoring resolves it again on its next check — and removes any "I'm aware" the Customer Overview holds for it. Bulk operations (up to 1000 per batch) are available by selecting multiple rows. Viewers can browse the list but cannot ack, resolve or reopen.
Storm cap
To prevent flooding the table from misbehaving rules or genuine incidents affecting many assets, the engine caps alert creation at 100 per rule per minute by default. Events above the cap are merged into the first alert of that minute bucket — dedupe_count increments and a STORM badge is shown in the title cell. The cap is operator-configurable in Settings > Alerts > Alert Center (range 1–10000).
Nav badge
A badge next to the Alerts nav link polls /api/alerts/count every 30 seconds and tints by highest-open severity: red for critical, orange for warning, blue for info. It hides when there are no open alerts and caps at 99+.
Settings
- Master toggle — disables the evaluation engine entirely (rules still visible, fires become no-ops)
- Storm cap — see above
- Retention — days to keep resolved alerts before pruning by scheduled maintenance
Inline explain row + Enhanced view
Click an alert's title in the table — a second row slides in below it with a friendly explanation of what happened. The inline row has three sections:
- Status — what the alert's current state means in plain language. Wording varies per status: open, acknowledged by <operator> at <time>, auto-resolved (with rule-type-specific "back to normal" wording — back to online for status rules, back below threshold for threshold rules, etc.), resolved manually.
- Cause — what triggered the alert: process / script / task that detected it, the timestamp, and the key payload field. Built from the
alert_transition_logrow that fired this alert (linked via the newsource_transition_log_idcolumn from migration 078, so the Cause line is exact, not time-window-correlated). - Actions — buttons available at this status with a short explanation of what each does. Ack drops the open-critical badge count without resetting dedup; Resolve closes the alert and resets the dedup window.
The toolbar Enhanced view button (top-right of the page header) toggles a global mode where every alert renders the explain row automatically, no per-row clicking needed. The toggle persists for the lifetime of the browser tab via sessionStorage (closing the tab clears it).
Referring to a specific alert
Each alert row has a clickable #ID in the leftmost column (e.g. #285). Click the ID to:
- Update the URL to
/alerts.html?alert_id=285(no page reload — useshistory.pushState) - Expand that row's inline explain pane
- Copy the deeplink URL to your clipboard (a toast confirms)
Paste the URL into chat / email / a ticket — anyone with access to the Alert Center will land on that exact alert with the explain pane already open. The deeplink also clears the status filter so the alert is visible regardless of its current state (open / acknowledged / resolved).
Want to filter the table to a single alert? Type the ID number in the small # id input on the filter bar and press Enter. The page narrows to that one row.
Pin filter
Click the 📌 button in the filter bar to pin your current filter selections. They will persist across page reloads in the same tab — useful for parking a "show me only critical, last 24h, customer X" view while you switch to another page and come back. Pinning matches the existing pattern on the Assets and Investigate pages: pin survives navigation within the tab, dies when you close the tab. Click the Clear button to unpin and reset filters.
Sort columns
Most column headers are clickable. The default sort is Created descending (newest first). Click any sortable header (#, Severity, Category, Title, Asset, Customer, Created, Status) to re-sort by that column descending; click the same header again to toggle ascending. The active column shows ▼ (descending) or ▲ (ascending); inactive columns show a faint ↕. Sort preference persists for the tab via sessionStorage and is applied server-side so pagination stays correct.
Alerts Admin
The Alerts Admin page (/alerts-admin.html) is the rule-engine configuration surface for the Alert Center. It is admin-only by default; administrators may grant per-group access via Settings > Groups. Write actions (create/edit/delete rules, channels, maintenance windows, globals) remain admin-only regardless of group grant.
Five tabs
- Rules — list/create/edit/delete alert rules across all 5 rule types (status, threshold, os_event, ingest, custom with 9 check-types including AI-analysis). Scoped by customer. Every rule can notify again while still breaching (on by default): while its alert stays open, the notification repeats every Cooldown minutes — see the worked example under Uptime collection.
- Channels — notification destinations (email SMTP / Telegram Bot API / webhook URL). Secrets are encrypted at rest (AES-GCM). Per-customer scope via junction table. Message templates support
{{...}}variables including{{phase_label}}(ALERT, RESOLVED or STILL OPEN),{{phase_emoji}}(the matching symbol),{{reminder_line}}(on a reminder: "Reminder N — open since …"; empty on the first alert and on the resolved message — keep it in a custom template or your reminders carry no number),{{alert_id}},{{alert_severity}},{{rule_name}},{{asset_name}},{{asset_ip}},{{customer_name}},{{category}},{{triggered_by}}(what initiated the alert — the rule, or availability monitoring) and{{asset_type}}. The default templates already include them. - Maintenance Windows — scheduled alert suppression (per-asset / per-customer / global; optional category filter). During an active window, matching events log to
action_logwithout firing. - Globals — master enable, storm cap (default 100/min/rule), retention days, notifications kill-switch, AI-alert settings (local model, external-AI allow, daily token budget).
- Audit — recent rule engine events (
notify_sent/notify_failed/rule_suppressed/action_deferred) plusoct-alert-workerheartbeat + queue depth.
Maintenance Windows
Scheduled, time-bounded alert suppression. While a window is active, any rule firing that matches its scope is logged to action_log as rule_suppressed_by_maintenance and no row is inserted into alerts — alerts don't backfill when the window ends.
Scope selection (all three knobs stack — leave all empty for global):
- Customer — the window suppresses alerts whose asset belongs to this customer. Leave empty to ignore customer scope.
- Asset IDs (comma-separated integers) — the window suppresses alerts only on these specific assets. Takes precedence over customer scope.
- Suppress categories — when "Suppress all" is OFF, list the rule
categoryvalues to suppress (e.g.availability, policy). Rules in other categories still fire.
The State column shows whether a window is currently active, upcoming, or past. Upcoming and past windows can be edited freely; editing an active window's end_at in the past ends it immediately.
Asset filter (rule scoping)
Every rule (any rule_type) carries an optional Asset filter that narrows which assets the rule applies to before any per-customer scope or per-asset override is consulted. Two independent knobs (both optional, stacked with AND):
- Asset type — only assets of this type (computer / user / switch / firewall / printer). Leave empty for any type.
- Attribute filter — pick an attribute key from the dropdown (sourced from Settings > Attributes), set Incl/Excl mode, type a substring to match the value (case-insensitive). Leave the key empty to disable. Same shape as the scheduler-task target query attribute filter — the operator UX is identical between the two pages.
The filter is stored as keys on alert_rules.target_query: type, attr_key, attr_value, attr_mode. It composes with all other axes (per-customer rule scope, per-asset overrides, deduplication, maintenance windows, flap detection, alert dependencies, action chains). Use Preview affected assets inside the rule modal to see exactly which assets the filter selects before saving.
Rule–asset coverage preview
Two complementary lookups answer the question "which rules touch which assets?":
- Lookup by asset (top of the Rules tab): type an asset name or IP, pick from the dropdown, and the list below shows every enabled rule that would fire on that asset — with a per-row match reason (e.g. "customer scope + has attribute
disk_free_gb"). Click Edit to jump straight into the rule modal. - Preview affected assets (button inside the rule edit modal, next to Save): before saving a new or edited rule, click it to see up to 20 assets that match — names, IPs, customer, match reason. If more than 20 match, the panel says so and points you back to Lookup by asset for targeted inspection. Works for both saved rules (
rule_id) and unsaved drafts (rule_draft).
A soft badge on a row means the match depends on runtime conditions the planner can't pre-compute — typically os_event rules (fire only when a matching event arrives) or custom rules with target_query.scheduled_task_id (asset inclusion depends on that scheduled task's own scope). Treat soft matches as "could apply" rather than "will apply."
Configuring a Telegram notification channel
Send Octotor alerts to a Telegram channel end-to-end. Steps 1–4 happen in Telegram / a browser; steps 5–8 happen in Octotor. One bot can serve many channels, and an existing bot can be reused.
| # | Step | Where | What you do |
|---|---|---|---|
| 1 | Create a bot | Telegram → @BotFather | Send /newbot, give a name + a username ending in bot. BotFather returns a bot token like 123456:ABC-DEF… — copy it. |
| 2 | Create the channel | Telegram | Menu → New Channel, name it (Private is fine). A group works too. |
| 3 | Add the bot as admin | Telegram | Channel name → Administrators → Add Admin → pick your bot → enable Post Messages. A bot can only post to a channel it administers. |
| 4 | Find the chat ID | Browser | Post any message in the channel, then open https://api.telegram.org/bot<TOKEN>/getUpdates. In the JSON find "chat":{"id":-100…} — that -100… number is the chat ID. (Public channel? use @channelname directly.) |
| 5 | Create the channel record | Octotor → Alerts Admin → Channels tab | Click + New Channel and fill the form (below). |
| 6 | (Optional) scope to a customer | Channels tab → Customers | Empty = global (all customers). Select customers to restrict. |
| 7 | Test send | Channels tab → Test send | A test message should land in Telegram within seconds; failures show the reason inline. |
| 8 | Attach to a rule | Rules tab → Edit a rule | In Notify channels type the channel name (comma-separate multiple, e.g. ops-email, oncall-telegram). |
The + New Channel form fields:
| Field | Value |
|---|---|
| Name | A short handle the rules reference, e.g. oncall-telegram |
| Type | telegram |
| Enabled | leave checked |
| Bot token | paste the token from step 1 |
| Chat ID | the -100… number (or @channelname) from step 4 |
| Parse mode | leave HTML (default) |
The token is encrypted at rest (AES-GCM) and never returned on read — when you edit the channel later, the field shows "(set — leave empty to keep)".
The token and chat ID below are fabricated placeholders — use the real values BotFather and getUpdates give you.
- @BotFather →
/newbot→ nameOctotor Alerts, usernameacme_octotor_bot→ token<BOT_TOKEN>(looks like111111111:AA…example…). - New private channel
ACME On-call; addacme_octotor_botas admin with Post Messages on. - Post "hi" in the channel, open
…/bot<BOT_TOKEN>/getUpdates→"chat":{"id":<CHAT_ID>}(a-100…number). - Alerts Admin → Channels → + New Channel: Name
oncall-telegram, Typetelegram, Bot token<BOT_TOKEN>, Chat ID<CHAT_ID>, Parse modeHTML→ Save. - Click Test send → "🔔 Test message from Octotor" appears in
ACME On-call. - Rules tab → edit the Host offline rule → Notify channels =
oncall-telegram→ Save.
ACME On-call Telegram channel, and auto-resolves with a ✅ message when the host returns.
{{…}} variables ({{phase_label}}, {{phase_emoji}}, {{reminder_line}}, {{alert_severity}}, {{rule_name}}, {{asset_name}}, {{asset_ip}}, {{customer_name}}, {{triggered_by}}, {{asset_type}}, …) are listed under Channels above.Goose Agent
Goose is an AI-powered IT operations agent that can manage assets, run scripts, investigate events, and execute scheduled recipes — all through natural language chat.
How It Works
Goose runs on the Octotor server and communicates via the MCP (Model Context Protocol). It has access to 46 tools that map to the Octotor REST API:
| Category | Tools | What they do |
|---|---|---|
| Assets | get_asset, list_assets, create_asset, update_asset, search_assets_by_attribute, ping_asset, get_user_link_suggestions | View, manage, and reach IT assets; suggest person→computer links from each machine's primary user |
| Jobs | run_script, run_command, get_jobs, get_job_output, wait_for_job | Execute scripts/commands on assets via SSH or WinRM |
| Batch Jobs | run_script_batch, wait_for_jobs, get_job_summaries | Run scripts on multiple assets at once, wait for all jobs to complete, and get a summary of results |
| Events | get_events, get_attribute_history | Query the unified events timeline; query attribute change history — who/what changed an asset attribute and when, including removals shown as "(cleared)" |
| Scheduler | get_scheduler_tasks, create_task, toggle_task, get_task_history | Manage scheduled tasks and inspect their run history |
| System | get_system_status, get_license, get_credentials, get_customers, list_users, list_scripts, get_update_status | System health, license state (tier / seat usage / expiry / feature limits), configuration, user directory, toolkit inventory, and software update status (current vs latest published version, last check result) |
| Identity | get_identity, get_identity_history | Resolve a person by name/email/UPN to their directory accounts (OU, last logon, group membership, account state); inspect identity-verification event history for an asset |
| Runbooks | list_runbooks, read_runbook | Read operational procedures from /opt/octopus/runbooks/ |
| SNMP | get_snmp_devices, get_switch_ports | List monitored switches and read a switch's port map (MAC/IP per port, link speed, effective status) |
| Backup | get_backup_state, get_backup_sessions | Backup state of protected computers (last success, last result, overdue, days without a successful backup) and the Veeam job run history of a backup server or one computer |
| Alerts | get_alerts, get_alert_counts | List alert rules with status and read open/auto-resolved alert counts |
| Customer Overview | get_customer_overview, list_custom_tiles | Read the Customer Overview: each customer's state, its counts, every tile with its headline and detail, the topics not configured and the tiles unpinned, plus the needs-action items with who acknowledged them, until when and the note; and the list of custom tiles with what each counts and who sees it |
| Check Point | get_firewall, list_jump_hosts, list_recipes, run_recipe, run_checkpoint_sync | Inspect Check Point firewalls and jump hosts, list and run CLI recipes, and trigger an account sync |
api/services/tool-definitions.js. If this table drifts from that file, api/services/tool-definitions.js is the source of truth.Local AI model and cloud AI
Goose needs an AI model to answer. There are two kinds. The local AI model runs on the Octotor server itself in the oct-ollama container and needs no internet access. The cloud AI model runs at the AI provider and needs Cloud AI Access set to Enabled and a provider key in Settings > AI Configuration. Which model each activity uses is chosen under AI Engine per Activity on the same page.
From version 3.3.12 the installer does not install the local AI model unless the install command carries --local-ai, because the model download is about 11 GB. On such a server the Goose page shows the line The local AI model is not installed on this server, the Settings > AI Configuration status shows Ollama: not installed, and Goose works with the cloud AI model.
To add the local AI model to a server that does not have it:
- Sign in to the server over SSH.
- Open
/opt/octopus/.envwithsudoand change the lineLOCAL_AI=falsetoLOCAL_AI=true. - Run the upgrade command once:
curl -fsSL https://get.octotor.com/upgrade | sudo bash. It downloads the model container and starts it.
To remove it again, set LOCAL_AI=false and run the upgrade command once more. The model files are kept on disk, so adding it back later does not download the model again.
Worked example. A server was installed with the default command. The Goose page shows The local AI model is not installed on this server. The administrator opens Settings > AI Configuration, sets Cloud AI Access to Enabled, saves the Anthropic API Key, and under AI Engine per Activity sets Goose Chat to Cloud (Claude). Goose now answers "how many assets are offline?" through the cloud AI model. Later the site decides to work without internet access for AI: the administrator sets LOCAL_AI=true in /opt/octopus/.env and runs the upgrade command. The Services page now lists oct-ollama as running, and the Goose page no longer shows the line.
Navigation Safety
In-flight Goose requests survive page navigation. If you start a Goose chat and navigate to another page before the reply arrives, the pending request is persisted to sessionStorage; when you return to the Goose page the reply is re-attached automatically — no lost answers. This applies to both autonomous responses and those held in the Confirmation-Mode pending queue.
Chat Interface
The Goose page provides a chat interface where admins can type natural language requests:
- "Check disk space on all linux servers" — Goose runs collect-info on matching assets
- "What failed this week?" — Goose investigates the events timeline
- "Create a scheduled task to run backup.sh every night at 2am" — Goose creates the task
Confirmation Modes
Configured in Settings > AI Configuration > Goose Agent:
| Mode | Behavior |
|---|---|
| Autonomous | Goose executes all actions without asking |
| Confirm Writes | Read operations are automatic. Write operations (run script, create asset, etc.) require admin approval via the Pending Actions panel |
| Confirm All | Every action requires approval |
Pending Actions
When confirmation mode is active, Goose's write operations appear as pending actions on the Goose page and dashboard. Admins can approve or reject each action before it executes.
Goose Recipes (Scheduler)
Scheduled tasks can use type "Goose Recipe" instead of a script. The recipe is natural language text that Goose executes on the cron schedule:
Check disk usage on all linux assets for customer TRIPLEOR. If any disk is below 10% free, run linux/disk-cleanup.sh. Log results to action_log.
Recipes can reference toolkit scripts by name — Goose knows what's available.
Batch Tools
Goose can run scripts across multiple assets in a single operation using batch tools:
| Tool | Purpose |
|---|---|
| run_script_batch | Execute a script on multiple assets at once. Accepts a list of asset IDs, a script path, and optional credential. Returns a list of job IDs for tracking |
| wait_for_jobs | Wait for a list of jobs to complete. Polls until all jobs reach a terminal state (done, failed, cancelled) or a timeout is reached |
| get_job_summaries | Retrieve a compact summary of multiple jobs — status, exit code, asset name, and truncated output for each job. Useful for reviewing batch results at a glance |
Firewalls & CLI appliances
Goose can also work with Check Point / CLI-appliance firewalls and their jump hosts:
- Ask about a firewall's inventory — "what interfaces / VLANs / VPN tunnels / DHCP leases does the firewall have", "is 2FA required on the VPN", "what model and version is it". Goose reads the collected inventory (interfaces, site-to-site tunnels, DHCP leases, remote-access posture, linked account counts).
- Query synced accounts — a firewall's local user and host objects sync into Assets as accounts (like Active Directory / Microsoft 365); ask about them the same way you ask about any account.
- List & run diagnostic actions — Goose can list the appliance recipes available and run a read/diagnostic one (e.g. show VPN status, list DHCP) for you; it tunnels through the jump host automatically. Destructive actions (e.g. resetting a VPN tunnel) are never run from chat — Goose will point you to the Run page, where the action password is collected.
- Trigger an account sync and see the outcome in the events timeline.
Security
- Goose authenticates to the API via Bearer token — same permission boundaries as any API consumer
- Customer scoping, group credential access, and token scopes all apply
- All Goose actions are logged to the audit trail as
operator: "token:goose-agent" - Goose cannot see credential passwords (always masked)
- Access controlled by group permissions — operators can access Goose if their group includes the 'goose' page
Permissions
| Role | Goose Access |
|---|---|
| Admin | Full access — chat, approve/reject actions, configure |
| Operator | No access (unless group includes 'goose' page) |
| Viewer | No access |
Dependencies
oct-goosecontainer running — it runs the agent loop and calls the API under the Goose bearer token.- A reachable model — local
oct-litellm/oct-ollama, or an allowed external LLM; AI must be enabled in Settings > AI Configuration. - Data to reason over — Goose answers from assets, events, jobs and related tables, so it's most useful once collectors and activity have populated them.
- Page access — admin, or a group that includes the
goosepage.
Security & Action Passwords
Octotor provides a layered security system that protects sensitive operations with action passwords and optional TOTP verification. These controls prevent unauthorized changes even if an admin session is compromised.
Action Password System
Action passwords are a separate credential plane from login passwords. When configured, sensitive operations require entering the action password before they can proceed.
| Level | What it protects | Default |
|---|---|---|
| Master password | All operations below (unless overridden) | Not set |
| Per-action passwords | Individual operations (override master) | Inherit from master |
Setting the master action password
- Go to Settings > Security (admin only).
- In Master Action Password, enter a password and confirm it.
- Click Set. From now on every protected operation (table below) prompts for this password before it runs.
- (Optional) enable Require TOTP with every action prompt to add a second factor — first enrol TOTP for at least one admin (see the lockout rail below).
Configuring a per-action password
- In Settings > Security, find the operation in the Per-action list.
- Switch its mode from Inherit to Custom.
- Type the password for that specific action and click its Set button.
- That operation now requires its own password; everything still on Inherit keeps using the master.
- Settings > Security > set the Master Action Password to
Winter-Ops-2026!→ Set. All 13 protected operations now inherit it. - Find Create/modify scheduled tasks (
action_password_scheduler_create) → mode Custom → passwordoncall-sched-42→ Set. Repeat for Enable/disable and Run scheduled tasks manually. - Share
oncall-sched-42with the on-call team; keep the masterWinter-Ops-2026!with the senior admin only.
oncall-sched-42, but any attempt to open Access security settings or run a high-risk script still prompts for the master password they don't have — so scheduler work is delegated without handing over the keys to everything.
Protected Operations
| # | Action | Setting Key |
|---|---|---|
| 1 | Import scripts | action_password_script_import |
| 2 | Modify scripts | action_password_script_modify |
| 3 | Enable/disable scripts | action_password_script_enable |
| 4 | Delete scripts | action_password_script_delete |
| 5 | Move scripts between folders | action_password_script_move |
| 6 | Execute high-risk scripts | action_password_execution_high |
| 7 | Execute medium-risk scripts | action_password_execution_medium |
| 8 | Run ad-hoc commands | action_password_adhoc_command |
| 9 | Create/modify scheduled tasks | action_password_scheduler_create |
| 10 | Enable/disable scheduled tasks | action_password_scheduler_enable |
| 11 | Run scheduled tasks manually | action_password_scheduler_run_now |
| 12 | Downgrade script risk level | action_password_risk_downgrade |
| 13 | Access security settings | action_password_settings_security |
Per-Action Modes
| Mode | Behavior |
|---|---|
| Inherit | Uses the master password (default for all actions) |
| Custom | Uses a different password for this specific action |
TOTP Enforcement
When Require TOTP with every action prompt is enabled (Settings > Security), every action password prompt also requires a valid TOTP code. This provides two-factor protection: something you know (password) + something you have (authenticator app).
Rate Limiting & Lockout
| Protection | Limit | Effect |
|---|---|---|
| Rate limit | 5 attempts per minute per IP | HTTP 429 — try again after the window expires |
| Lockout | 10 consecutive failures | HTTP 423 — account locked, requires admin reset or 60-second cooldown |
Security Page Gate
The Security section in Settings is protected by a gate. When a master action password is configured, you must enter it (and optionally TOTP) before the security settings become visible. This prevents casual browsing of security configuration.
Changing the Master Password
When a master password is already configured, the Security page shows:
- Change Password — enter current password + new password
- Remove Password — enter current password to disable action password protection entirely
Script Risk Classification
Every script in the Toolkit has a risk level that determines the action password requirements when executing it.
| Level | Badge | Meaning | Action password |
|---|---|---|---|
| High | HIGH | Destructive or privileged operations (disk wipe, user management, service restart) | Uses execution_high password |
| Medium | MED | System modifications (package install, config change, file write) | Uses execution_medium password |
| Low | LOW | Read-only or informational (disk check, status query, log review) | No password required |
Risk levels are assigned automatically by AI validation when a script is saved, and can be adjusted manually by admins. Downgrading a risk level requires the risk_downgrade action password.
Content Hashing
Every script has a SHA-256 content hash that is recalculated when the script is saved. This hash is stored in the database and displayed in the Toolkit detail panel, allowing admins to verify script integrity.
Reset the Octotor admin login password
Use this when nobody can sign in as an administrator — the password was lost, or the only admin account is locked out. It is a host-level recovery procedure: it runs on the server that Octotor is installed on and requires sudo (or docker-group) access there. Anyone who can run it already controls the machine, so it grants no privilege they did not have; guard shell access to the host accordingly. If any administrator can still sign in, do not use this procedure — set the password from Settings ▸ Users & Access instead. The host-level route exists for the case where no administrator session is available, which the web interface cannot resolve by design.
Passwords are stored only as bcrypt hashes, so the old one cannot be read back — it can only be replaced. The procedure below never puts your new password into SQL: it is hashed first, and only the hash reaches the database.
- Sign in to the Octotor server over SSH as a user with
sudo. - Read the database role and name from the container so the commands below are correct even if this install did not use the defaults.
DBU=$(sudo docker exec oct-postgres printenv POSTGRES_USER); DBN=$(sudo docker exec oct-postgres printenv POSTGRES_DB)— on a default install both printoctopus. - Confirm the account name.
sudo docker exec oct-postgres psql -U "$DBU" -d "$DBN" -c "SELECT id, username, role, active FROM users ORDER BY id"— pick the administrator you want to recover. If the account showsactive = f, addactive=trueto the update in step 5. - Hash the new password.
H=$(sudo docker exec oct-api node -e 'console.log(require("bcrypt").hashSync(process.argv[1],12))' 'NewPasswordHere') - Apply it and force a change at next sign-in.
sudo docker exec oct-postgres psql -U "$DBU" -d "$DBN" -c "UPDATE users SET password_hash='$H', force_password_change=true WHERE username='admin'"— the command must answerUPDATE 1.UPDATE 0means the username did not match; re-check step 3. - Verify before you leave the shell.
curl -sk -o /dev/null -w '%{http_code}\n' -X POST https://localhost:8443/api/auth/login -H 'Content-Type: application/json' -d '{"username":"admin","password":"NewPasswordHere"}'—200means the reset worked,401means it did not. - Clear your shell history (
history -c) — step 4 leaves the password in it. - Sign in to the web interface as that user. Because force password change was set, Octotor immediately asks for a new password, so the value you typed in step 4 is only a temporary transit password and is never the one you keep.
Worked example. An install reachable at https://192.0.2.26:8443 has one administrator and nobody knows its password. Step 3 returns 1|admin|admin|t. The operator runs step 4 with 'Transit-9f2Kd!', then step 5, which answers UPDATE 1. Step 6 returns 200. The operator opens https://192.0.2.26:8443, signs in as admin with Transit-9f2Kd!, and is taken straight to the change-password screen, where the real password is set. Total time: under a minute.
Notes: substitute your own port if the install does not use 8443. If the container names differ from oct-api / oct-postgres, list them with sudo docker ps first. The reset is recorded in the database change itself but produces no Investigate entry, so note it in your own change log. If TOTP is enrolled for the account you will still be asked for the code after signing in — clear it with UPDATE users SET totp_enabled=false, totp_secret=NULL WHERE username='admin' in the same session if the authenticator is also lost.
Host firewall on the Octotor server
An installation made with the Octotor installer (version 3.3.12 or later) turns on a firewall on the server itself. From the network, the server then accepts only three things: SSH on port 22, the web interface on its port (8443 unless a different port was chosen at install time), and ping. Every other incoming connection is dropped. When Tailscale is installed on the server before Octotor, all traffic arriving over Tailscale is also accepted. The rules are restored automatically after a reboot. Outgoing connections from Octotor to your assets are not affected.
To check the firewall, sign in to the server over SSH and run sudo /opt/octopus/octotor-harden.sh status. The line inbound firewall reads ACTIVE when it is on.
To install without the firewall, add --no-inbound to the install command. To remove it from a running server, run sudo /opt/octopus/octotor-harden.sh disable-inbound.
An upgrade never turns the firewall on or off. On a server installed before version 3.3.12 it is off, and the upgrade prints the command that turns it on. To turn it on:
- Sign in to the server over SSH.
- Run
sudo /opt/octopus/octotor-harden.sh enable-inbound --in-ports="22 8443". Replace 8443 with your web port if it is different. - Open a second SSH session to the server. If it connects, run
sudo /opt/octopus/octotor-harden.sh confirmin it within 120 seconds. If you do not confirm, the rules remove themselves after 120 seconds, so a mistake cannot lock you out.
Worked example. A server at 192.0.2.26 was installed with version 3.3.11 and has just been upgraded. The upgrade output ends with Inbound host firewall: OFF on this host. The administrator runs sudo /opt/octopus/octotor-harden.sh enable-inbound --in-ports="22 8443", opens a second SSH session to 192.0.2.26, which connects, and runs sudo /opt/octopus/octotor-harden.sh confirm there. sudo /opt/octopus/octotor-harden.sh status now shows inbound firewall: ACTIVE. The web interface at https://192.0.2.26:8443 still opens, and a test web server started on port 9999 of that machine can no longer be reached from another computer on the network.
Licensing
Every Octotor install — including Community — runs from a signed license file. Without a valid license the system starts in activation mode: nothing collects, no jobs run, and only the activation page is reachable until a license is applied. The License page (linked from Settings, or reached from the banner's Manage →) is where an admin views status, usage, and features, and applies or replaces a license. Licensing applies instantly — no restart.
Activating a new install
- Step 1 — Download the request. On the activation page, click Download license-request.json and send it to your Octotor vendor. It contains your instance ID and a machine fingerprint — the license is bound to this exact install.
- Step 2 — Apply the license. When you receive
license.oct, drop it on the activation page and click Apply license. The signature and machine binding are verified before it is accepted; a bad file is rejected without ever going live. On success the app loads. - Air-gapped? You can also copy
license.octto/opt/octopus/license/over SSH — it is picked up within a minute.
What the License page shows
- Status — tier, who it's issued to, license ID, expiry (with days remaining), and the machine fingerprint. Check now re-verifies immediately.
- Usage — live counts against each cap: seats, customers, M365 tenants, credentials, custom scripts, custom groups, operator users, scheduled tasks. Bars turn red at the limit. View → on Seats opens the exact list of seat-consuming assets.
- Features — which capabilities your license includes (Scheduler, Collectors, Full toolkit, Alert Center, SNMP, M365 and Backup collectors, Goose, …). The list of rows comes from the product itself, so every feature that has a license gate appears here; each row is on unless your license file sets it off. A row marked included by default means your license file was issued before that feature existed — such a key is not in the file, and the product treats it as included.
- Manage — Update license (renew / add seats / change tier), Download request, Redeem unlock code, Download diagnostics, Remove license.
Seats — how they're counted
A seat is one managed object: a user, a computer, or a managed network device (switch, firewall). Accounts (AD/M365/local directory accounts) and groups do not consume seats. This is why the Assets page can show far more rows than your seat count — it folds in accounts, which the seat meter excludes.
Emergency unlock (break-glass)
If an install is locked out — a license expired mid-renewal, or a disaster-recovery restore landed on a new machine so the license no longer matches — your vendor can issue a one-time unlock code. Paste it under Redeem unlock code (on the activation page or the License page). It grants temporary operation (up to 72 hours) at your licensed tier while a proper license is issued. Each code is single-use and bound to this install.
Worked example — renewing before expiry
Your banner reads "Your license expires in 9 days (2026-08-05)." You email your vendor and receive octotor-acme-2027.oct. On the License page you click Update license, choose the file, and click Apply. The page verifies the signature and that it matches this machine, then swaps it in. The Status card now reads Expires 2027-08-05 · in 365 days, the banner is gone, and no service restarted. If the file had been for a different company's install, the update would have been rejected and your current license left untouched.
Settings
Settings is the admin control center. It covers system configuration, user management, security, credentials, and integrations. Admin access only.
Sections
| Section | What you configure |
|---|---|
| Instance | Instance name, default customer, job timeout |
| Customers | Customer registry — add/edit/delete customers. Each asset must belong to a customer |
| Dashboard | The Customer Overview: which view opens first, the default order of the customer cards, the thresholds behind the colours, how long data may be out of date, history, acknowledgements, which tiles every customer shows and in what order, and how often the page reloads. See Dashboard for the step-by-step |
| Users & Access | Create/edit/clone/delete users, set roles, manage group memberships, assign customer access, TOTP setup |
| Monitoring | Auto-ping settings (write-on-change), live monitor refresh interval, "Mark asset as Unknown after (seconds)" — how stale an asset's last check may be before Assets/Live Monitor display it as Unknown; 0 = automatic (2× the ping interval). Example: with a 60-second ping interval but a check sweep that takes ~2.5 minutes, the automatic 120-second window makes healthy assets flip to Unknown for part of each cycle — setting 300 stops the flapping (it also sets how recent a check must be for the Scheduler option "Skip targets the online monitor reports offline"; alerting unaffected). Also: TCP monitoring (SSH/RDP/WinRM port checks), identity verification (DNS, SSH gate, WinRM gate, per-OS default gate, require probe, collector check, mismatch behavior, validity TTL) |
| Management Protocols | Global enable/disable per protocol (SSH, WinRM), execution defaults per OS family, SSH config (port, timeout), WinRM config (port, timeout, auth method). See WinRM Remote Management section. |
| Attributes | Define custom asset attribute fields (key, label, type, auto-approve) |
| Credentials | Create/edit/delete SSH and WinRM credentials, set OS defaults, per-customer defaults, sudo toggle, assign customer access. Groups can restrict which credentials operators see |
| Groups | Create custom permission groups, assign pages/scripts/protocols/credentials |
| Security | Master action password, per-action passwords, TOTP enforcement, script signing (coming soon). See the Security help section for details. |
| AI Configuration | LLM status (model name, RAM usage, loaded/unloaded), load/unload model, toggle AI features (script validation, override AI blocks, investigation, conversation logging), Goose agent settings (enable/disable, confirmation mode), Cloud AI Access (enable/disable, provider selection, encrypted-at-rest API key with last-4 preview) |
| API Tokens | Create/revoke Bearer tokens for API and Goose access. Each token has scopes, expiration, IP restriction, rate limit, and activity logging level |
| NetMap | Network address translation — map customer LAN subnets to Tailscale-routed subnets. Add, edit, or delete mappings. |
| Maintenance | Database maintenance — data retention policies, scheduled cleanup, backup freshness monitoring, vacuum, DB state monitoring. See Database Maintenance section. |
API Tokens — creating and using one
Settings > API Tokens issues Bearer tokens for programmatic access to the same API the web UI uses. Each token carries scopes, an expiry, an optional IP allow-list, a rate limit, and a log level. A token acts as the user who created it and is bound by that user's permissions and customer scope — a token can never do more than its owner. (This feature is licensed: if API Tokens is not in your license the Create button is disabled.)
- Create. Settings > API Tokens → + Create Token. Give it a name (e.g.
ci-inventory), pick scopes (e.g. read-onlyassets:read), set an expiry, optionally restrict to an IP. The raw token is shown once — copy it now; it is stored only as a hash and cannot be retrieved again. - Use. Send it as an
Authorization: Bearerheader:curl -H "Authorization: Bearer <your-token>" \ https://your-octotor/api/assets - Verify / revoke. The token list shows last-used time. Delete a row to revoke instantly (the next request with it returns 401).
TOKEN="oct_live_…" # created by an operator scoped to ACME
curl -s -H "Authorization: Bearer $TOKEN" \
"https://your-octotor/api/assets?customer_name=ACME" | jq '.[].name'
The same token used against a customer the owner can't see returns an empty set (scope is enforced server-side), and a write (POST /api/assets) is rejected unless the token's scopes include it.Cloud AI API Key (Anthropic)
Settings > AI Configuration > Cloud AI Access stores the cloud LLM API key encrypted at rest in the database (AES-256-GCM with the instance MASTER_KEY — same scheme as credentials and TOTP secrets). The key is decrypted only when oct-api writes the LiteLLM config file at toggle time, and the LiteLLM container reads it from there at startup. The full key never leaves oct-api: the UI shows only the last four characters once configured.
| Action | What happens |
|---|---|
| Set / Update | Inline password field appears; entering the key and clicking Save prompts for the master action password. On confirm, the key is encrypted and stored in settings.external_llm_api_key_claude_encrypted; the LiteLLM config file is rewritten with the literal key; oct-litellm restarts to pick it up. |
| Delete | Master action password required. The DB row is removed; the LiteLLM config falls back to the legacy EXTERNAL_LLM_API_KEY environment variable (if set in .env) or to no key at all. |
| View | Status row shows Configured: ••••XXXX (last four) or Not set. The full key is never returned by any API endpoint. |
EXTERNAL_LLM_API_KEY from .env as before. Migrating from the .env-only path is an opt-in that brings DB-dump safety and the lifecycle UI (rotate/delete/audit) above the host-filesystem baseline.Attribute Updates Flow
User Setup Flow
Credential Setup Flow
Sudo Support
Credentials can have a Sudo toggle. When enabled, the script is copied to a temporary file on the target and run with sudo, and the credential's password is passed to sudo on its standard input. This can be overridden per-task in the Scheduler with the Sudo Override setting (force/never/default).
Sudo's password prompt is switched off, so the prompt text never mixes with what the script prints. Example: a Linux server where the account opsadmin must type a password for sudo, collected with linux/collect-info.sh and a credential that has Sudo on — the job ends done, and the asset's CPU, RAM, disk, OS version and the other attributes appear on the asset, not only its IP address and OS family.
Per-Customer Default Credentials
In Settings > Credentials, you can set a credential as the default for a specific customer + OS family combination. This is useful when different customers have different service accounts.
Effective Permissions
In Settings > Users, click a user to see their Effective Permissions — a summary showing exactly which pages, scripts, credentials, and customers they can access, and which group grants each permission.
CLI Password Reset
If an admin forgets their login password, it can be reset from the host command line:
cd /opt/octopus && ./setup-prod.sh --reset-password
This prompts for a username and new password, then updates the bcrypt hash in the database directly. No login session is required.
To reset the master action password (if locked out):
docker exec oct-postgres psql -U octopus -c "UPDATE settings SET value='' WHERE key='action_password_master';"
SNMP Collector — switch port mapping
The SNMP collector (oct-snmp-collector) polls network gear (switches, routers, firewalls) over SNMP and builds a live picture of which device is on which switch port. It never changes anything on the gear — it only reads standard tables (SNMP GET/WALK, no SET). It is on by default — but it only sends packets once SNMP devices are configured: with an empty device list the collector idles and nothing is polled. Turn the master switch off in Settings > SNMP if you never want SNMP traffic from this box.
What it does
- Reads the switch MAC table — every MAC address the switch has learned, and which port it was learned on.
- Maps computers to ports — when a learned MAC matches a computer asset's
LAN MAC(orWiFi MAC), the collector sets that computer's Switch Port and Switch IP attributes, and creates a Connected to relation to the switch (visible in the Relations tab of both assets). - Flags unknowns — a MAC with no matching asset (and a resolved IP) can be surfaced as a discovery-pending device; MACs it can't resolve are counted, not queued.
Reading the "Switch Port" value
The Switch Port attribute stores the raw port description the switch itself reports (the SNMP ifDescr field). It is deliberately kept verbatim so it matches exactly what you'd see in the switch's own management UI — and because the format is vendor-specific, there is no single "clean" form to normalise to:
| Vendor / model | Example value | How to read it |
|---|---|---|
| HPE OfficeConnect 1820 | 3 Gigabit - Level | Physical port 3, a Gigabit port. - Level is HPE's fixed description text for the port on this model — it carries no per-port meaning (every port reads "N Gigabit - Level"); the actionable part is the leading number. The switch also exposes a bare ifName of just "3" for the same port. |
| Cisco IOS | GigabitEthernet0/3 | Port Gi0/3. |
| Generic | Port 12 / eth12 | Whatever the firmware names the interface. |
Rule of thumb: the leading number is the physical port; the rest is the vendor's speed/description text. If a value looks unfamiliar, compare it against the switch's own web UI or CLI (show interfaces description on Cisco) — the collector stores the same string those show.
The switch port map
Open a switch asset to see its Port Map: one row per active port, the MAC(s) learned there, and the asset each MAC resolves to (or unknown if nothing in inventory matches). A port that has learned many MACs is flagged as a likely uplink/trunk — that's normal for the link to a virtualization host or another switch (every downstream device's MAC appears there), so a trunk full of "unknown" entries is expected, not a fault.
Configuring a switch (on the asset)
SNMP monitoring is configured on the switch asset, exactly like SSH/WinRM on a computer — there is no separate device registry. Open the switch on the Assets page:
- Create an SNMP credential — v2c (a community string, e.g.
public) or v3 (user + auth/priv). Credentials are encrypted at rest under a dedicated key that only the collector can read; the community/keys are never shown back or logged. - On the switch's Credentials tab, link that SNMP credential (the same way you link an SSH or WinRM credential to a computer). The credential carries the SNMP version.
- On the Overview tab's SNMP Monitoring card: tick SNMP monitoring enabled, choose the roles — Walk MAC table (an access switch) and/or Walk ARP table (the VLAN's gateway, which maps MAC → IP) — set the port (default 161), and Save. These are stored as switch attributes.
- Test (poll now) on the same card confirms the collector can reach the switch and reads its system name.
- Turn on the master switch (Settings ▸ SNMP) and (optionally) schedule an SNMP Walk task for periodic polling.
Global settings (Settings > SNMP Collector)
Connection and tuning knobs live under Settings > SNMP Collector: the master enable toggle, default port (161), and the timers — response timeout (per SNMP request), walk deadline (max time for one full table walk), and per-device timeout (max budget per switch per cycle) — plus discovery/event tuning (stability polls, dedup window, caps, MAC-table retention). Poll cadence is not global: how often each switch is polled is set per SNMP Walk task in the Scheduler (schedule-only — the collector never polls on its own timer).
Port status & speed
For each interface the collector reads three standard SNMP dimensions and derives one effective status shown in the Port Map: admin status (ifAdminStatus — is the port enabled?), operational status (ifOperStatus — is the link up?), and spanning-tree state (dot1dStpPortState — is it forwarding, or held blocked by STP?). Speed comes from ifHighSpeed. The effective status is one of: up, down (enabled but no link — e.g. an empty or unplugged port), disabled (admin-shut), blocked (up but STP is holding it), lower-layer-down, absent (no module/SFP), or dormant/testing/unknown. Status is a state, not a fault: an enabled port with nothing plugged in is simply down — it is never flagged as an error just for being down. Some switches don't expose spanning-tree over SNMP — there the status falls back to admin+operational only and never shows blocked.
Port errors are a separate dimension. Whether a port is actually faulting comes from the switch's own error counters (ifInErrors / ifOutErrors), not from up/down state. The Port Map shows a red error count badge on any port that has recorded errors, and the collector flags a port as actively erroring when that counter rises between polls. The switch carries a Ports With Errors attribute (count of ports whose errors rose this poll) — put a threshold Alert rule on it (> 0) to be notified when links start erroring; the alert detail names the offending ports. A change to any port's status or speed, and any port that starts erroring, is written to the event log (Investigate → category snmp_sync). The switch also carries a Ports Down attribute (count of down / lower-layer-down ports) for a "lost ports" threshold alert.
Power over Ethernet. On PoE-capable switches the Port Map shows a per-port PoE badge from the standard POWER-ETHERNET-MIB — delivering (with the negotiated power class), searching, off, or fault. Non-PoE switches simply show no PoE badge.
Vendor differences (why some fields read "unknown")
The collector speaks only standard SNMP MIBs, which keeps it working across vendors without per-model configuration. Two things help it stay accurate on gear from different makers:
- Vendor identification. Each switch reports a standard
sysObjectID; the collector reads it to record the switch's vendor (shown as Vendor (SNMP) in the Attributes ▸ Network group). This is only a hint — every reading is still confirmed from the actual data, never assumed from the label. - VLAN learning mode. Most switches learn MAC addresses per VLAN (IVL), so the forwarding table tells us each device's VLAN. Some (e.g. Alcatel OmniSwitch) use Shared VLAN Learning (SVL), where the forwarding table carries no per-device VLAN at all. The collector detects this and shows VLAN Learning (SNMP) =
IVLorSVL. On an SVL switch the per-device VLAN is left blank rather than shown as a wrong value — a blank VLAN there means "the switch doesn't expose it by standard means", not a fault.
Wherever a vendor exposes a value only through its own private MIB (for example the per-device VLAN on an SVL switch, or wireless clients on an access point), Octotor reports it as unknown rather than guessing. A blank field is deliberate — it means the standard tables didn't carry it.
Uplink / trunk ports
A switch's forwarding table tells you which port a device is reachable through, not where it's physically plugged in. An uplink/trunk port that connects to another switch therefore lists every downstream device's MAC — so without special handling all of them would be wrongly mapped to that one port. Octotor treats uplink ports as transit: their devices are still shown in the Port Map (labelled "via uplink (transit)") but are not assigned a switch-port or a "connected to" relation, and never raise a new-device discovery on that switch.
Uplinks are detected two ways: (1) mark them per switch — enter the port numbers in Uplink ports on the switch's SNMP Monitoring card (e.g. 24,53); and (2) auto — any port with more learned MACs than Settings ▸ SNMP Collector ▸ Uplink auto-threshold (default 3, 0 = off). Marking is authoritative; the threshold catches the obvious ones you didn't mark. (Automatic neighbour detection via LLDP is planned.)
To go the other way, use Access ports on the same card: any port number you list there is forced to access and its devices are mapped normally — even if the auto-threshold would otherwise flag it as an uplink. Admin marking wins: Access ports overrides both the threshold and the Uplink ports list, so a port listed as access is never treated as transit.
Speed alerts (sub-gigabit / speed changes)
To alert on slow links, set Min port speed (Mbps) under Settings ▸ SNMP Collector (default 1000 = 1 Gbps). Every poll the collector counts up-ports below that floor into the switch's Ports Below Speed Floor attribute — create a threshold Alert rule on it (> 0) to be notified when any port negotiates below 1 Gbps (e.g. a bad cable dropping a gigabit link to 100 Mbps). To alert on any speed change, the switch also carries a Ports Speed-Changed last poll attribute (count of ports whose speed differed from the previous poll; it resets to 0 on the next clean poll) — a threshold rule > 0 fires on a change and auto-resolves. To create either: Alerts ▸ + New Rule ▸ type = threshold ▸ pick the attribute ▸ operator > ▸ value 0 ▸ choose a notification channel.
New-device alerts
When the collector sees a stable, IP-resolved MAC that isn't a known asset, it queues it for discovery and writes a device_discovered event (Investigate → snmp_sync). The switch also carries a Pending Devices attribute (count of not-yet-approved devices found via that switch) — put a threshold Alert rule on it (e.g. > 0) to be notified when unknown gear appears on the network.
Switch & device network details
Each SNMP poll now also records the switch's own Switch MAC, Subnet Mask and Default Gateway (Overview → Attributes). For every device the collector maps to a switch port it records the Connected Switch IP (the mgmt IP of the switch it's plugged into) and the Switch Port Speed (the port's negotiated speed) alongside the existing Switch Port / VLAN. Windows and Linux collectors also fill each computer's Default Gateway, Subnet Mask and DNS Servers ("ipconfig /all"-style). Collector-written attributes carry the AUTO provenance badge (not MANUAL).
Switch-to-switch topology
When two managed switches are linked, the collector records a Connected to relation between them (Overview → Relations), so you can see which switch uplinks to which. It's detected from LLDP neighbours when the switches expose it, and falls back to matching a switch's own MAC in another switch's forwarding table. (This complements uplink/access marking — it identifies the neighbour, not just that a port is a trunk.)
Finding a port on the Port Map
Use the search box on a switch's Port Map tab to filter rows by port number, port name, connected asset name, MAC or IP — handy on a busy 48-port switch. Speed/uplink labels and the transit markers are preserved while filtering.
Scheduled SNMP-Walk history
A scheduled SNMP Walk task now shows its runs in the task History panel (triggered / nothing-to-poll / skipped / rejected), even though an SNMP poll doesn't create a job the way a script task does.
Roles — why two kinds
A plain L2 switch knows MAC → port but not IP addresses. To resolve MAC → IP (needed to auto-assign an unknown device to a customer by subnet), the collector reads the ARP table of the VLAN's L3 gateway (a router, L3 switch, or firewall). This is standard, routed SNMP — the collector works across VLANs and remote sites; it never needs to sit on the same network segment as the device.
Ask the AI assistant
The Goose AI assistant can query SNMP data directly through two read-only tools: get_snmp_devices (list the monitored switches and their poll state) and get_switch_ports (read a switch's full port map — MAC/IP per port, link speed, effective status). Ask e.g. "which ports are down on SW-CORE-01?" or "what's plugged into the core switch?"
Security
- Read-only: the collector issues SNMP GET/WALK only — it has no code path that can write to (reconfigure) a switch. Use read-only community strings; prefer SNMPv3 with authPriv where the gear supports it (v2c sends the community in clear text on the LAN).
- Key separation: the collector holds only its own SNMP key, never the master encryption key — a compromised collector cannot decrypt other Octotor credentials.
- Master switch on by default (idles until devices are configured; one click in Settings > SNMP turns it off) and egress restricted to SNMP (UDP 161) + the database.
Licence
The SNMP collector is a Pro-tier feature.
Backup Collector — Veeam backup state on your assets
The backup collector reads the job history of a Veeam Backup & Replication server and writes the result onto the computers that server protects. On each protected computer you see when its last successful backup ran and how the last run ended. On the backup server you see how many jobs succeeded, ended with warnings, failed, or are overdue, and how many failed recently. Six alert rules fire when a backup fails (now, or at any time in the last 24 hours), ends with a warning, or is late. There are two collector scripts: windows/veeam-vbr-collect.ps1 (the full collector, reads the job history) and windows/veeam-vbr-collect-light.ps1 (the light collector, reads the newest run of every job only — for servers with so much history that the full collector cannot finish; see Full or light collector? below). Both scripts only read from Veeam: they never start, stop, edit, or delete a backup job. This feature needs a Pro or Enterprise license.
What the collector writes
On every computer it matched to a backed-up item (the BACKUP group in the Attributes tab):
| Attribute | Meaning |
|---|---|
| Backup — Last Successful Run | The newest restore point Veeam holds for this computer, or the end time of the newest job run that ended with Success. This value is never cleared. |
| Backup — Last Result | How the newest job run ended: Success, Warning, Failed, or Not protected (the computer is no longer in any backup job on that server). |
| Backup Job Name | The Veeam job or jobs that include this computer. |
| Backup Server | The Veeam server that reported it. |
| Backup Overdue | Yes when the last successful run is older than the job's own schedule allows (schedule interval times 1.25, or 30 hours when the schedule cannot be read). |
| Backup Copy — Last Successful Run | The newest successful backup copy run, when a copy job exists. |
| Backup — Last Warning or Error Message | The last warning or error lines of the newest run that ended with Warning or Failed. Empty after a Success. |
On the backup server itself: Backup Product, Backup Data — Last Collected (the time of the newest run of either script), Backup Data — Last Full Collection (the time of the newest run of the full collector), the job counts (Backup Jobs — Total / Successful / With Warnings / Failed / No Last Result / Disabled / Overdue) with a matching list of job names for each count, Backup Jobs — Failed Recently (with its list of names) for every job that had a failed run in the last 24 hours, or since the previous full collection when that is longer ago, even if that job is idle or green again by now, and Backed-Up Items With No Asset for items Veeam protects that Octotor could not match to an asset.
Full or light collector?
The full collector reads every job run of the last 30 days and every restore point on the server. On a server with years of history that read can take longer than any task limit allows: on one customer server with about 8,300 restore points the job-history read gave up after 15 minutes and the restore-point read took 17 minutes, so every full run was cut off and nothing was ever written. The light collector reads only the newest run of every job, which takes about two minutes on the same server, most of it loading the Veeam module.
| Full collector | Light collector | |
|---|---|---|
| Script | windows/veeam-vbr-collect.ps1 | windows/veeam-vbr-collect-light.ps1 |
| Reads | Every job, the job runs of the last 30 days, and every restore point | Every job and the newest run of each job |
| Timeout (sec) to set | 240; 900 or more on a server with a long history (and on some servers no limit is enough — use the light collector there) | 240 |
| How often | Once a night, after the backup window | Every few hours, for example every 4 hours |
| What you get | Everything described on this page | Everything except the six items below |
What a light run does not report:
- Backup Jobs — Failed Recently is not updated (it needs the run history). The value from the last full run stays.
- A light run records the newest run of each job only. Runs that started and finished between two light runs never reach the Backup jobs tab.
- A computer that was removed from every backup job is not marked "Not protected" by a light run; only a full run does that.
- Backup — Last Successful Run comes from the newest job run only. When that run did not succeed, the date already stored on the computer stays, and Backup Overdue is judged from that stored date with the same rule as a full run.
- On a Veeam 13 server, backup copy jobs show No Last Result in a light run (Veeam 13 exposes their runs only through the history the light run does not read). Keep the nightly full run on Veeam 13 servers where it finishes.
- A light run matches backed-up items to computers by the machine name and the DNS name Veeam records on the run. The two extra clues a full run has (the guest name on the restore point, the agent computer list) are not available, so a machine whose Veeam name differs from its computer name (for example FS-02_replica) can appear under Backed-Up Items With No Asset in light runs while a full run matches it. Typing the Veeam name into that computer's Name in the backup software attribute (see How computers are matched below) makes it match in light runs as well.
Use both where the full collector can finish: the light collector every few hours so a failed backup is noticed within hours, the full collector once a night for the history. Where the full collector cannot finish at all, use the light collector only.
Set it up step by step
- Mark the backup server. Open Assets, open the Veeam server, go to the Attributes tab, and set Veeam Backup Server to Yes. The collector task targets this attribute, so only servers you mark are ever queried.
- Give Octotor a Windows credential for that server. On the same asset, open the Credentials tab and link a Windows account. The account must be allowed to load the Veeam PowerShell module; the Veeam role Backup Viewer is enough, because the script only reads. Veeam 13 or newer: the backup server must also have PowerShell 7 installed (Microsoft's free download,
https://aka.ms/powershell), because Veeam 13 provides its PowerShell module for PowerShell 7 only. The collector checks the installed Veeam version, runs its Veeam part in PowerShell 7 when the version is 13 or newer, and tells you in plain words when PowerShell 7 is missing. Veeam 12 and older need nothing extra. - Schedule the collector. Open Scheduler and click + New task. Script:
windows/veeam-vbr-collect.ps1. Target: an attribute filter Veeam Backup Server equals true. Schedule: once a day after the backup window ends, for example30 6 * * *(06:30 every day). In the Execution section set Timeout (sec) to 240: the collector reads the whole job history and a server with many jobs needs more than the 30-second SSH default (a cut-off run showsSSH connection timed out after 30 sand names the field to raise). The same applies to a server reached over WinRM: a run started from the Run page uses the Timeout field of that page (or the WinRM default of 180 seconds when the field is empty), so give a manual run at least 240 seconds too. A server with a long job history needs more: on a Veeam 13 server with 8 jobs and about 1,500 recorded runs the collector took 9½ minutes, so set Timeout (sec) to 900 when the task covers such servers (a cut-off run showstimed out after N sand names the field to raise). Save the task. - Add the light collector (recommended, required where the full one cannot finish). Click + New task again. Script:
windows/veeam-vbr-collect-light.ps1. Target: the same attribute filter Veeam Backup Server equals true. Schedule: every 4 hours, for example10 */4 * * *(10 minutes past 00:00, 04:00, 08:00 and so on). In the Execution section set Timeout (sec) to 240. Save the task. A backup server where the full collector is always cut off (the run ends withtimed out after N sand no output, whatever limit you set) gets this task only; leave the full task off for that server or exclude it with a filter. - Check the first run. After the task has run, open the backup server asset. The Backup jobs tab lists every job run and every backed-up item with its result. The Attributes tab shows the BACKUP group with the counts. Open one of the protected computers: its BACKUP group now carries its own values.
- Alerts. Six rules are seeded and enabled under Alerts: Backup job failed on server (critical), Backup job failed recently on server (critical — fires for a job that failed in the last 24 hours, or since the previous collection when that is longer ago, even when that job is idle or green again by the time the collector runs), Last backup of this computer failed (critical), Backup overdue for this computer (warning), Backup job warning on server (warning), Last backup of this computer ended with a warning (warning). Threshold rules only fire for assets whose Threshold alert switch (asset Overview ▸ Alerts card) is on; by default the collector switches it on for every computer it matches and for the backup server (see the setting below).
Settings
- Settings ▸ Backup Collector ▸ Switch on threshold alerts for the computers the collector finds — Yes (default) means every collector run turns the Threshold alert switch on for the matched computers and the backup server, and writes each switch-on to the audit trail. No means the collector leaves the per-asset switches alone.
- Settings ▸ Maintenance ▸ Backup job history (days) — how long job sessions stay in the Backup jobs tab (default 90 days).
Worked example
The backup server BK-01 at customer Tripleor runs three Veeam jobs. The file server FS-02 is in the job 02 File servers, which runs every night at 01:00. You marked BK-01 as a Veeam Backup Server, linked its Windows credential, and scheduled the collector for 06:30 daily.
- On 8 September the 01:00 run of 02 File servers ends with Failed because the file server was unreachable.
- At 06:30 the collector runs on BK-01. On FS-02 it writes Backup — Last Result = Failed, Backup — Last Warning or Error Message = "Failed to connect to FS-02: The network path was not found", and leaves Backup — Last Successful Run at 7 September 01:12 (the last good restore point). On BK-01 it writes Backup Jobs — Failed = 1 and Backup Jobs — Failed (names) = "02 File servers".
- The rule Last backup of this computer failed raises a critical alert on FS-02, and Backup job failed on server raises one on BK-01 naming the failed job. The error text itself sits in FS-02's Backup — Last Warning or Error Message attribute. Your notification channels deliver both.
- You open BK-01 ▸ Backup jobs, click Failed, and open the Log of the FS-02 row to read the Veeam log lines. View job output opens the Jobs tab with the full collector output.
- You fix the network issue and re-run the job in Veeam. After the next collector run at 06:30 the next day, FS-02 shows Backup — Last Result = Success and a new Backup — Last Successful Run; the message attribute is emptied; both alerts resolve.
Worked example, light collector. The backup server BK-02 at customer Tripleor has been running Veeam since 2023 and holds about 8,000 restore points. Every run of the full collector on it ends with WinRM connection timed out after 900 s and no output, so its protected computers never received backup data.
- You create a second task: Script
windows/veeam-vbr-collect-light.ps1, target Veeam Backup Server equals true, schedule10 */4 * * *, Timeout (sec) = 240, and you exclude BK-02 from the full task's target with a second filter (Name exclude equals BK-02). - At 08:10 the light collector runs on BK-02 and finishes in 95 seconds. On the seven computers in its jobs it writes Backup — Last Result, Backup Job Name, Backup Server and, for every computer whose newest run succeeded, Backup — Last Successful Run. On BK-02 it writes Backup Jobs — Total = 7, the other counts, and Backup Data — Last Collected = 08:10. Backup Data — Last Full Collection and Backup Jobs — Failed Recently stay empty: no full run has ever finished here.
- At 12:10 the next light run finds the job 05 Mail server failed at 11:30. MAIL-01 gets Backup — Last Result = Failed and the error message; its Backup — Last Successful Run keeps the 08:10 value; Backup Overdue stays No because that success is younger than the job's daily interval times 1.25. The rule Last backup of this computer failed raises the alert within the same minute.
- Two days later the job is still failing. At 12:10 the light run cannot find a success in the newest run, so Octotor judges Backup Overdue from the stored date: it is now older than 30 hours, so MAIL-01 turns overdue and the Backup overdue for this computer warning fires next to the critical alert.
When a run fails, or finishes but lands no backup data
A collector run that cannot read Veeam still ends as a green job (exit code 0) — the reason is inside its output, not in the job status. Open the backup server asset, go to the Jobs tab, and open the collector run; the errors list at the end of its output says what happened. The same message is recorded in Investigate (category backup, "nothing landed"). The messages you can see:
Veeam Backup & Replication 13.x needs PowerShell 7 on the backup server, and PowerShell 7 (pwsh.exe) is not installed there— install PowerShell 7 on that server (Microsoft's installer,https://aka.ms/powershell, default folderC:\Program Files\PowerShell\7), then run the task again. Nothing else changes: the collector finds PowerShell 7 by itself.Veeam PowerShell not available under PowerShell 5.1 ...followed by the error of each attempt (Import-Module Veeam.Backup.PowerShell: ...andAdd-PSSnapin VeeamPSSnapIn: ...) — the Veeam console (which carries the PowerShell module) is not installed on that machine, or the account is not allowed to use it. Check that the credential's account can open the Veeam console on the server.PowerShell 7 (...pwsh.exe) did not return the collector result (exit code N): ...— PowerShell 7 is installed but the Veeam part did not complete; the text after the colon is what PowerShell 7 wrote (its error, or whatever it printed instead of the result). Runpwshon the server as the same account and typeImport-Module Veeam.Backup.PowerShellto see the full message.... needs PowerShell 7, which is installed, but this run could not hand the work to it: ...— the account could not write its temporary script file, or was not allowed to startpwsh.exe(application control or antivirus). The text after the colon names which. Allow it for the collector's account, then run the task again.SSH connection timed out after N s/WinRM connection timed out after N s— the run did not finish inside the time limit named in the message. Raise the task's Timeout (sec) (or the Run page's Timeout for a manual run); a server with a long job history can need several minutes. When the full collector is cut off even at 900 seconds or more, the server's history is too large for it: switch that server to the light collector (windows/veeam-vbr-collect-light.ps1, Timeout 240), see Full or light collector? above.- Status identity mismatch before any output — the pre-run identity check did not get an answer over the protocol the task forces. Set the task's Protocol to Auto so each server is reached the way its asset is configured (SSH or WinRM).
Ask the AI assistant
The Goose AI assistant reads the same data through two read-only tools: get_backup_state (which computers are protected, their last result, and how many days since a successful backup) and get_backup_sessions (the job run history of a backup server or of one computer, with the log lines of failed items). Ask for example "Which computers at Tripleor have no successful backup in the last 2 days?" or "Why did the backup of FS-02 fail last night?"
How computers are matched
Each backed-up item is matched by name to a computer asset of the same customer as the backup server: the item name, the DNS name Veeam recorded for the guest on its newest restore point, the short form of either, and the computer's attribute Name in the backup software (see the next paragraph). The DNS name is what makes a virtual machine match when its name in the hypervisor differs from its host name (for example a machine named FS-02_replica in Hyper-V whose Windows host name is FS-02: it lands on the asset FS-02). When two Veeam items map to the same asset, the newest backup wins and the job names are combined. If two assets could match the same item, nothing is written to either of them and the item is listed under Backed-Up Items With No Asset with the note "(ambiguous)". Items with no matching asset are listed there too, so you can create or rename the asset, or type the item's name into Name in the backup software on the right computer, and the next run will match it.
When the name in Veeam is not the computer's host name. A hypervisor names a virtual machine freely, and some Veeam servers record no guest DNS name for an item, so a machine called AI-LAB-01 in Hyper-V whose Windows host name is ailab01 never matches by itself. The computer attribute Name in the backup software (Attributes tab, BACKUP group; empty until you fill it) tells Octotor what Veeam calls the computer:
- Find the names that did not match. Open the backup server in Assets and read Backed-Up Items With No Asset (names) on its Attributes tab (the attribute without "(names)" is only the count). Or open Investigate, choose the category backup, and read the part unmatched names: of the collector run's event; searching for the item name finds the run.
- Tell Octotor which computer it is. Open that computer in Assets, go to the Attributes tab, click Edit attributes, type the name exactly as Veeam shows it into Name in the backup software (upper or lower case does not matter), and click Save changes.
- Wait for the next collector run. It matches the item to that computer and writes its backup values; the name leaves Backed-Up Items With No Asset (names) and the count goes down by one.
The attribute is manual: the collector never writes it and never clears it. One name, one computer: if the name you type equals another computer's name or host name in the same customer, the item is reported as "(ambiguous)" and written to neither computer until you remove the duplicate. Note the side effect: the other computer's backup values stop updating meanwhile — it keeps its last state and is not marked "Not protected" — so a typo here can leave a second machine looking fine while it is no longer refreshed. The "(ambiguous)" entry in the unmatched list is the sign.
Worked example. Customer Tripleor runs the virtual machine AI-LAB-01 on Hyper-V. Inside it, Windows is called ailab01, and that is the asset's name in Octotor. Veeam backs the machine up under the Hyper-V name and records no guest DNS name, so after every run the backup server shows Backed-Up Items With No Asset (names) = AI-LAB-01 (and the count = 1) and the asset ailab01 has no backup values. You open ailab01 › Attributes › Edit attributes, type AI-LAB-01 into Name in the backup software, and click Save changes. After the next collector run, ailab01 shows Backup — Last Successful Run and Backup — Last Result, and AI-LAB-01 is gone from the unmatched list.
Reading the Backup jobs tab
Each row is one job run, or one backed-up item inside a run: the job name on the first line and Backed-up item: name under it. On a computer's own Backup jobs tab the item line is left out, because the item is that computer; a backup job and its backup copy job appear as two rows per day, told apart by the Type column. The result chip shows the item's own result when it has one, otherwise the job's. Log expands the last log lines Veeam recorded for a failed or warning item. The filter chips re-read the rows from the server. The tab is hidden on installs without a Pro or Enterprise license and on switches, persons, and account assets.
M365 Connectors
M365 Connectors sync Microsoft 365 / Entra objects into Octotor straight from the platform — no Windows box or on-prem agent. Phase 1 collects users, license assignment, MFA registration status, and Entra-joined devices; they land through the same discovery pipeline as AD collection (auto-approve or pending queue per the discovery_auto_approve setting). One connector per customer.
Master switch
Settings > M365 Connectors > Collector master switch (default Disabled). While disabled the collector container makes no outbound connections at all — connectors stay stored but inert, scheduled syncs skip, and Test connection refuses to run. Certificate generation still works while disabled (it is local-only crypto). Enable the switch only when you are ready for Octotor to talk to Microsoft's endpoints (login.microsoftonline.com and graph.microsoft.com — nothing else).
How authentication works
Octotor uses certificate-based app-only Graph access (Microsoft's recommended pattern for unattended services). Octotor generates an RSA-3072 keypair per connector; the private key never leaves Octotor and is stored encrypted under a dedicated key that only the collector container holds. You upload the public certificate to your Entra app registration. At sync time the collector signs a short-lived JWT with the private key and exchanges it for a Graph token — no client secrets, nothing to rotate in two places.
Setting up a connector — step by step
One-time per tenant, ~10 minutes. Steps 1–2 and 5 happen in the Microsoft Entra portal and require a Global Administrator of the customer tenant; steps 3–4 and 6 happen in Octotor. (This walkthrough was validated live against a real tenant on 2026-07-03.)
Part 1 — register the application (Entra portal)
- Sign in to
entra.microsoft.comwith a Global Administrator account of the tenant you are connecting. - Go to Identity > Applications > App registrations > + New registration.
- Name: e.g.
Octotor Collector(any name works). Supported account types: "Accounts in this organizational directory only" (single tenant). Redirect URI: leave empty. Click Register. - On the app's Overview page, copy two values for step 4: Directory (tenant) ID and Application (client) ID. Neither is a secret — they are identifiers.
Part 2 — grant read-only Graph permissions
- In the app: API permissions > + Add a permission > Microsoft Graph > Application permissions (NOT Delegated).
- Tick the base set:
User.Read.All,Organization.Read.All,Device.Read.All. Then the optional set — each unlocks extra data and degrades gracefully (sync still works, the sync summary notes what's missing):AuditLog.Read.All— MFA Status/Methods, per-user last sign-in, and the sign-in events feed (Part 7; sign-ins additionally require an Entra ID P1/P2 tenant)Reports.Read.All— mailbox size (usage reports). Also a tenant setting: Microsoft hides user names in usage reports by default on newer tenants. To change it you need a Global Administrator: open admin.microsoft.com, in the left menu click Show all if Settings is hidden, then Settings › Org settings, stay on the Services tab (not Security & privacy), scroll to Reports and open it, clear the box Conceal user, group, and site names in all reports (older tenants word it Display concealed user, group, and site names in all reports) and click Save. While it is on, the sync summary says report identities are concealed and no mailbox sizes are collected; the next sync after the change fills them.GroupMember.Read.All— group membership (all group types, Teams tagged)RoleManagement.Read.Directory— activated directory roles per user (Global Administrator, …)MailboxSettings.Read— mail-forwarding visibility: user-created inbox rules that forward/redirect mail (classic BEC indicator). Detects rule-based forwarding only — the admin-set "Email forwarding" mailbox property is a separate Exchange API and is not covered.
- Click "Grant admin consent for <tenant>" and confirm — the Status column must show green checks on every row. This is the step that requires the Global Admin role; without consent, Test fails with a consent error.
Part 3 — create the connector and its certificate (Octotor)
- Open Settings > M365 Connectors > Add connector: pick the customer this tenant belongs to, paste the Tenant ID and Application (client) ID from Part 1, click Create + generate certificate.
- The CERT pill turns ready within a few seconds (Octotor generates an RSA-3072 keypair; the private key is stored encrypted and never leaves the collector). If the pill stays pending (typically: the connector was created before the collector container was started) or shows error, click the row's Regenerate button to re-request key generation — the collector also retries all stuck-pending connectors automatically on startup. Example: on a fresh install where
COMPOSE_PROFILES=m365was set after the connector was created, the pill stays pending; start the collector container and it turns ready on boot without any clicks. - Click Cert on the row — it downloads
octotor-m365-connector-<id>.cer(the public half only; there is no private-key download).
Part 4 — upload the certificate to Entra
- In the Entra app: Certificates & secrets > Certificates tab > Upload certificate, pick the downloaded
.cerfile, add. - Sanity check: the thumbprint Entra now shows must equal the THUMBPRINT on the connector row in Octotor. If they differ you uploaded the wrong file.
Part 5 — test and sync
- In Octotor: set the Collector master switch to Enabled and Save (until now the collector has made no outbound connection at all).
- Click Test on the connector row. Expected: the TEST pill goes pending → ok within a few seconds; hovering the row shows your organization name (Octotor acquired a token AND read
/v1.0/organization— proving both the cert upload and the admin consent). - Sync runs land discovered users and Entra devices in the Assets > Discovery panel (or create them directly when Auto-approve discovered identities is on). Scheduled/recurring sync is configured in the Scheduler ("M365 Sync" task type).
- On a synced device, the Entra values (OS, compliance, join type, account state, last seen, MDM enrollment, owner) live on a Microsoft 365 device account linked to the computer — exactly like an AD machine account, and like user accounts. The computer's Attributes tab shows the account as a "Microsoft 365 · read-only · collected" card; deleting the account asset removes the collected Entra data. A hybrid-joined machine carries both its AD machine account and its M365 device account on the same computer. The registered owner also links the device to its person (like AD's assigned-to).
- Order matters on a new tenant: approve the users first, then the computers. The owner of a computer can only be proposed when that user already exists in Octotor as an approved person. On the first sync of a new tenant the users and the computers reach the Discovery page together, so the computers show no proposed owner yet. Approve the users, let the next sync run (it refreshes every waiting computer with its owner), and only then approve the computers. A computer approved before that gets no owner and must be assigned by hand. Worked example: tenant with 17 users and 80 computers synced at 06:27; users approved by 07:26; after the 07:30 sync 59 of the waiting computers carry a proposed owner, the 10 computers approved at 06:40 do not.
- Collected per user account: state, licenses, MFA status + methods, last sign-in, account created, last password change, usage location, office, employee ID, company, manager, mailbox size, group membership (all group types; Teams-backed groups tagged (team)), directory roles (activated assignments — Global Administrator etc.), and mail forwarding (enabled inbox rules that forward/redirect, shown as rule → address; None when the mailbox has no such rule — so a rule appearing or disappearing is a change an alert rule can fire on). Mailbox size needs
Reports.Read.All; groups needGroupMember.Read.All; last sign-in needsAuditLog.Read.All+ Entra P1/P2; roles needRoleManagement.Read.Directory; mail forwarding needsMailboxSettings.Read— each degrades gracefully with a note in the sync summary when missing.
Part 6 — schedule recurring syncs
- Open Scheduler and click + New task.
- Set Task type to M365 Sync — the asset/script sections disappear and an M365 connector picker appears (connectors themselves are managed by admins in Settings > M365 Connectors).
- Pick the connector, name the task (e.g.
m365-nightly), choose a schedule (nightly is typical — a sync only writes attribute changes), Save. - Run Now on the task row triggers an immediate sync. Dispatch is fire-and-forget: the task history shows the dispatch (ok / skipped / error), and the sync's own result (
sweep_completed/sweep_failedwith counts) appears in Investigate under the m365_sync category. - When the collector master switch is OFF, scheduled syncs are skipped (visible in the task history) — nothing runs and no outbound connection is made.
Part 7 — sign-in events + alerts
Each sync also collects sign-in events (successes and failures) from Entra's auditLogs/signIns — requires AuditLog.Read.All (application) and an Entra ID P1/P2 tenant; without them this phase is skipped with a note in the sync summary, and the user/device phases still run.
- Where to see them: open an M365 account asset (Assets > Users > Type = Microsoft 365) — its drawer shows a Sign-ins panel with the latest events (time, status, location, IP, app).
- Alerting: two rule shapes ship under the signin rule type in Alert Center > Rules (both seeded enabled, global):
- M365 sign-in outside allowed countries — a successful sign-in from a country outside the allowlist (default
IL) fires a security alert; one open alert per account (re-occurrences bump the count). Edit the rule to change the country list. - M365 sign-in failure burst — ≥5 failed sign-ins for one account within 15 minutes (both numbers editable).
- M365 sign-in outside allowed countries — a successful sign-in from a country outside the allowlist (default
- Change alerts (license / groups / roles / any attribute): threshold rules support the changed (any transition) operator — pick the attribute (e.g.
license,groups,roles,mail_forwarding), operator changed, no value needed. Fires whenever a sync lands a different value, with old → new in the alert detail; the first-ever collection of an attribute does not fire. Scope globally (Customer = Global) or to one user via the rule's target attribute filter (e.g.upn equals jsmith@…). When the same attribute key exists on several providers, the Attribute-key picker offers an all types entry plus per-provider entries (e.g. Groups (m365)) — a provider-scoped rule fires only for assets of that type. - Per-asset opt-in: threshold/changed rules only evaluate assets whose Threshold alert flag is on. Toggle it on any asset — device, user, or provider account — via the asset drawer > Edit > Alert Settings card, or in bulk from either table's selection bar (Bulk Alert Settings…). Accounts created by the collectors opt in automatically.
- Limits to know: events with no location data are skipped by location rules; sign-ins for accounts not (yet) approved into Octotor are stored but not evaluated (they appear in the Unmatched sign-ins list, Part 8); each sync reads at most 5000 new events (the sync summary says so loudly when the cap is hit).
- Detection latency = your sync cadence. A 30-minute recurring M365 Sync task gives ~30-minute alerting latency; nightly sync means next-morning alerts.
- Retention: sign-in events are pruned after Settings > Maintenance > M365 Sign-ins (days) — default 90.
Part 8 — unmatched sign-ins
A sign-in whose user principal name (the sign-in name, for example jsmith@tripleor.example) matches no Microsoft 365 account in Octotor is still stored, but it has no account to appear under. Typical causes: a guest from a partner company, a service account that was never approved into Octotor, a user created in Entra after the last sync, or someone trying names that do not exist. The Unmatched sign-ins list shows these sign-ins so you can decide what each one is.
- Sync summary: every M365 sync records
signins: fetched=N inserted=M unlinked=K ignored=Iin Investigate (category m365_sync).unlinkedis the number of new sign-ins that matched no account; when it is above 0 the summary also names the three sign-in names with the most of them, for example(top UPNs: guest.user@partner.example (12), svc-scan@tripleor.example (4)).ignoredcounts new sign-ins of names you put on the ignore list. - Where to open the list: Settings > M365 Connectors — each connector row has a link Unmatched sign-ins (N) under the tenant name, where N is the number of sign-in names of the last 7 days that still need a decision. The link opens the list on the Investigate page, filtered to that connector. On the Investigate page itself, the button Unmatched sign-ins above the filters opens the same list for all connectors. The list is available to administrators, like the connectors.
- What each row shows: a reference number, the sign-in name, the customer and tenant, how many sign-ins it made in the period, the time of the last one, the countries they came from, and how many failed (count and percent).
- Reference numbers: each sign-in name gets one number per connector the first time it appears. The number is stored, so it stays the same when the list is reloaded, sorted or filtered, and when the same name signs in again next week. Quote it to a colleague as
#42; they type 42 in the Reference # box and click Find to open the same row, whatever its state. The number is kept after you link or ignore the name. - Link to account… — choose the M365 account the sign-ins belong to (the list offers the accounts of the same customer). Octotor stores the link, moves the stored sign-ins of that name to the account (they then appear in the account's Sign-ins panel), and attaches future sign-ins of that name to the account automatically. The account's own sign-in name is not changed; if the account has no sign-in name recorded yet, the linked name is recorded on it. Sign-ins that are moved are not re-checked by the sign-in alert rules; rules apply to sign-ins collected after the link.
- Ignore this principal — puts the name on the connector's ignore list. Its sign-ins are still stored (so nothing is lost for a later investigation), but they leave the list and the sync summary counts them under
ignoredinstead ofunlinked. To undo, set Show to Ignored, tick the row and click Stop ignoring. - Several rows at once: tick the box at the start of each row (or the box in the header to tick every row), then use the bar that appears above the table: Link to account…, Ignore these principals, or Stop ignoring. When the ticked rows belong to different customers, the link applies to the rows of the account's customer; the other rows are skipped and the message after the action says how many.
- AI assistant: the assistant can answer questions about this list with the tool
get_unmatched_signins— for example "which unknown sign-in names failed most this week for TRIPLEOR?" or "what is unmatched sign-in #42?".
Worked example. The nightly sync of customer TRIPLEOR records signins: fetched=310 inserted=305 unlinked=9 ignored=0 (top UPNs: j.smith@tripleor.example (6), scanner@tripleor.example (3)).
- Open Settings > M365 Connectors. The TRIPLEOR row shows the link Unmatched sign-ins (2) under the tenant name. Click it.
- The Investigate page opens with the list. Row #57 is
j.smith@tripleor.example: 6 sign-ins, last one this morning, country IL, 0 of 6 failed. This is John Smith signing in with his old name; his account in Octotor is jsmith (jsmith@tripleor.example). - Click Link to account… on row #57, choose jsmith (jsmith@tripleor.example) in M365 account, and click Link. The message reads Linked 1 principal to jsmith (6 stored sign-ins moved), and row #57 leaves the list. The six sign-ins now show in the Sign-ins panel of the jsmith account.
- Row #58 is
scanner@tripleor.example: 3 sign-ins, all failed, country IL — the office copier trying to send mail. Click Ignore this principal. The row leaves the list; at the next sync its sign-ins are counted asignored=3.
Troubleshooting
- Error mentioning consent / "required Microsoft Graph permission" — Part 2 step 3 (admin consent) is missing, or a permission wasn't added. Grant consent, then see the next point.
AADSTScredential / certificate error — the cert upload (Part 4) didn't happen, or a wrong Tenant/Client ID was entered (Part 3).AADSTS90002 Tenant not found= wrong Tenant ID.- Changed Entra permissions but Octotor still reports the old error — the collector caches its Graph token for ~1 hour, and the cached token predates your change. Click Test on the connector (it forces a fresh token) or wait out the hour.
- Mailbox size stays empty and the sync summary says report identities are concealed — the tenant hides names in usage reports. As a Global Administrator open admin.microsoft.com › Settings (click Show all if hidden) › Org settings › tab Services › Reports, clear Conceal user, group, and site names in all reports, Save, then run the sync again.
- MFA Status shows Unknown for everyone —
AuditLog.Read.Allisn't granted/consented (it is optional); the sync summary in Investigate says exactly this when it happens. - Microsoft renamed its endpoints (rare) — the two hostnames the collector talks to (
login.microsoftonline.com,graph.microsoft.com) are configurable under Settings > M365 Connectors > Microsoft endpoints. They double as the collector's outbound allow-list, so only change them for a real Microsoft endpoint change; empty = built-in default; applies on the next sync/test.
Statuses
| Column | Values |
|---|---|
| CERT | pending (generating) → ready · error (hover the row for the reason) |
| TEST | not run · pending (dispatched to the collector) · ok · error (hover for the redacted reason) |
| STATE | Enabled / Disabled — per-connector switch, independent of the master switch |
Security notes
- The private key is encrypted with a key (
M365_CONNECTOR_KEY) that exists only in the collector container — the API server cannot decrypt connector keys, and there is no private-key download. - Deleting a connector destroys the encrypted private key. The Entra app registration is untouched — remove it tenant-side if the customer is offboarded.
- Graph permissions above are read-only. Octotor never writes to the tenant.
- Test/keygen errors shown in the UI are redacted — tokens, assertions, and key material never appear in logs or the audit trail.
Sync scheduling (recurring collection) arrives with the Scheduler task type M365 Sync — see the Scheduler section once available.
How Permissions Work
Octotor uses a layered permission system. Each layer narrows what a user can see and do.
Layer 1: Customer (Asset Visibility)
Each user is assigned to specific customers or "All Customers". This is the outermost filter — a user can never see assets belonging to a customer they're not assigned to.
| Setting | Effect |
|---|---|
| All Customers | User sees all assets from every customer (default) |
| Specific customers | User sees only assets belonging to their assigned customers |
Layer 2: Role (Ceiling)
Every user has one role. The role defines the maximum actions possible.
| Role | Can do | Cannot do |
|---|---|---|
| Admin | Everything | Nothing restricted |
| Operator | View assets, execute scripts, view logs, run protocols | Manage settings, manage users, delete assets, manage credentials, manage scheduler |
| Viewer | View dashboard, view assets, view own logs, investigate (logs only) | Everything else — job events hidden in Investigation |
Layer 3: Groups (Scope)
Custom groups narrow an operator's access. Without any custom group, an operator sees everything their role allows. With a custom group, they only see what the group grants.
Multiple Groups
A user can be in multiple custom groups. Their effective permissions are the union of all groups.
Built-in Groups
| Group | Auto-assigned to | Editable? |
|---|---|---|
| Admins | Admin users | No — admins bypass all checks |
| Operators | Operator users | No — use custom groups to narrow |
| Viewers | Viewer users | No — viewer permissions are fixed |
The built-in group follows the role. When you change a user's role under Settings ▸ Users & Access (click Edit, pick the new Role, click Save), Octotor removes the user from the old built-in group and adds them to the new one in the same save; custom groups are not changed. Example: change the role of jdoe from Operator to Admin and save — the Groups column then shows Admins and no longer shows Operators. Two changes are refused with a message: you cannot take the admin role away from your own account, and the last active admin cannot be demoted — make another user admin first. The Groups column shows every membership: the built-in group in grey (fixed), custom groups in blue with a ✕ to remove them.
Permission Change Effect
Permission changes take effect within 30 seconds — no logout/login required. The system checks permissions on every API request using a short-lived cache.
Network Address Translation (NetMap)
When managing assets across multiple customer sites, IP address ranges can overlap. For example, two customers may both use 192.168.0.0/24 on their LANs. To avoid conflicts when routing through Tailscale, subnet routers use SNAT to remap one customer's range to a unique range.
NetMap tells Octotor which IP translations to apply per customer, so ping and SSH reach the correct Tailscale-routed address. Asset IPs in the database always remain the real LAN addresses — translation happens at runtime only.
Example
| Customer | TRIPLEOR |
| Original Network | 192.168.0.0/16 (their real LAN) |
| Mapped Network | 10.99.0.0/16 (Tailscale SNAT'd) |
| Asset stored IP | 192.168.0.10 |
| Octotor pings | 10.99.0.10 (translated) |
Key Rules
- Translation is per-customer — the same IP range can be real for one customer and translated for another.
- Original and mapped CIDR prefix lengths must match (e.g., both /16 or both /24).
- A customer can have multiple mappings (different subnets mapped independently).
- If no mapping matches, the stored IP is used as-is.
Adding a mapping
- Go to Settings > NetMap (admin only).
- Click + Add mapping and pick the Customer.
- Enter the Original network — the customer's real LAN CIDR, e.g.
192.168.0.0/16. - Enter the Mapped network — the Tailscale-SNAT'd CIDR, e.g.
10.99.0.0/16. It must have the same prefix length as the original. - Click Save. Within ~60s (the rule-cache TTL) every ping / SSH / WinRM / SNMP to that customer's assets connects to the translated address, while the stored/displayed IP stays the real LAN one.
192.168.0.10 but the job connects to 10.99.0.10. If a probe still hits the real IP, the mapping's prefix length probably doesn't match the original.CLI Appliances (Check Point, Cisco, …)
Some devices — firewalls, switches, routers — aren't managed by installing an agent or running an ordinary shell script. You drive them through their own command-line interface: you type a command, the device shows a menu or asks a question, you answer, and so on. Octotor supports these devices as CLI appliances, and automates those back-and-forth sessions with recipes.
1. Add the device as a CLI appliance
On the Assets page add the device (e.g. a Check Point firewall) and set its
OS family to CLI appliance (Check Point / Cisco). This tells Octotor to connect over SSH,
skip the operating-system probes it runs on servers, and never try sudo. Add a
Vendor attribute (Check Point Quantum Spark, Cisco IOS, …) so the right recipes are offered for
that device. Attach an SSH credential just like any other asset.
2. Pick an action and fill in the plain-language form
On the Run page, choose the device and then an action (a recipe). Each action shows a short description and, if it needs any input, a form with clearly-labelled fields — for example “VPN peer gateway (IP address)” with a hint and an example value. There is no code or command syntax to learn; you fill in what the field asks for and press Run. Octotor validates the input (an IP field must be a real IP, etc.) before anything is sent to the device.
3. What happens under the hood
Interactive actions run in a dedicated, isolated worker container (oct-recipe-worker) so a session that
stalls on one device can never affect ordinary SSH/WinRM jobs. The worker opens an SSH session, walks the device's
menus step by step (waiting for each prompt before it types the next answer), captures the full transcript into the
job output, and enforces safety limits: per-step and overall timeouts, and a guard that refuses to send
dangerous inputs (for example, a Check Point reset-all-tunnels menu option is blocked; only the
specific peer you chose is reset).
Seeded example: Check Point site-to-site VPN
- Show VPN tunnel status — read-only; lists the current site-to-site tunnels. Safe to run any time.
- Reset VPN tunnel — clears the encrypted connection to the one peer gateway you enter; the tunnel renegotiates automatically within seconds. Because it changes device state it is a destructive action and prompts for the action password (see Security).
Scheduling & automatic reset (end-to-end)
The same action can run on a schedule or be fired automatically by an alert:
- Scheduled: Scheduler → New task → Task type = Script → pick the recipe as the Script. The same plain-language form appears right there in the task editor — fill in the values (e.g. the peer gateway) and they're saved with the task. It runs on your cron schedule.
- Automatic (alert-triggered): create the task with Trigger = On alert and its recipe values, then in Alerts Admin point an alert rule's Run task on fire at it. Now, for example, when a firewall's monitored tunnel/endpoint goes down, Octotor automatically runs the Reset VPN tunnel recipe against the peer you configured — no operator action needed. Per-task cooldown and max-per-hour guardrails prevent reset storms.
Because the recipe's parameters are stored on the task, the automation always knows exactly which peer to act on.
Collecting firewall inventory (Check Point)
Beyond running recipes, Octotor can pull a full inventory snapshot from a Check Point Quantum Spark firewall. Run the System info action (or schedule a Check Point sync) and the device's Overview fills in with its model, software version, serial number, license expiry, uptime, and — rendered as sortable tables on the device panel:
- Network interfaces — each port and VLAN with its IP, subnet mask, and DHCP pool.
- Site-to-site VPN tunnels — peer gateway, encryption domain, authentication, and enabled state.
- DHCP leases — active client leases with client name, IP, MAC and the lease window (the real lease database, filterable per interface/VLAN).
- Remote-access security — whether gateway-wide two-factor authentication is required, and which users have VPN access.
Syncing firewall users & hosts into Assets
A Check Point sync reads the firewall's local user objects and host objects and files them into Assets exactly the way the Active Directory and Microsoft 365 connectors do: each object is matched to an existing person or computer (or proposed for approval in the discovery queue), then linked as an account under that owner. Host objects become device-side accounts and fold into Devices; user objects become user-side accounts and fold into Users — see User Assets & Accounts. The sync honours the same auto-approve setting as AD and M365, so on a strict tenant unmatched objects wait for you in the discovery queue.
To run it on a schedule, create a Scheduler task with Task type = Check Point
Sync. The Target section picks the firewalls: choose a specific firewall for one device, or set
Asset type = firewall to sync every firewall in scope — optionally narrowed by the Customer dropdown.
Worked example: task ALL-FW-NIGHTLY, Task type Check Point Sync, Customer Any customer, Asset type
firewall, no specific asset, cron 0 3 * * * — every enabled firewall (or CLI appliance) across all
customers syncs its users and hosts at 03:00, one sync per firewall, and each run appears separately in Investigate under the
checkpoint_sync category.
Jump Hosts — reaching a device through a bastion
Some devices are not reachable directly from the Octotor server — you first SSH into a jump host (bastion) on the customer's network and from there to the device. Configure this once under Settings ▸ Jump Hosts: give the jump host its address and an SSH credential. Then, on the device's Assets ▸ Overview ▸ Edit, pick that Jump Host from the dropdown. From then on every SSH connection to that asset goes through the bastion: appliance recipes, the Check Point account sync, and ordinary SSH jobs of any kind — scripts, commands, collectors and scheduled tasks — on any device type, Windows hosts with OpenSSH included. The device's own credential is used on the second hop. The job output shows the line Routing via jump host user@host:port (SSH).
Worked example: a Veeam backup server BK-1040 at a customer site is only reachable through that site's Linux bastion site-jump (192.0.2.10). Create a credential for the bastion login, add a jump host named site-jump with that address and credential under the customer, then open BK-1040 ▸ Overview ▸ Edit and set Jump Host = site-jump. The scheduled backup collector task for BK-1040 now runs over SSH through site-jump; its job output starts with the routing line, then Checking SSH port 22 on 192.168.10.5 via the jump host…, then the script output.
- The reachability check before a job (normally ping + port check) and the identity check (hostname probe) also run through the jump host when one is attached, so a target that only the bastion can see does not fail the pre-flight.
- If the attached jump host is disabled, or its credential was deleted, the job fails with a clear message — while a jump host is attached, Octotor never silently falls back to a direct connection. Before a jump host or a credential is deleted, the Settings page tells you which jump hosts or assets depend on it.
- Deleting a jump host detaches it from every asset that used it (the asset's Jump Host field goes back to Direct) and the next job on those assets connects directly. If they are only reachable through a bastion, create the jump host again and re-attach it.
- If the jump host itself cannot be reached, the job output says Could not reach the jump host user@host:port and the target is not blamed; if the bastion answered but could not open a connection to the target, the output says the target did not respond via the jump host.
- WinRM jobs on an asset with a jump host attached fail with a message that says so — WinRM is not routed through a jump host. Run the job over SSH (OpenSSH on the Windows host) or set the asset's Jump Host to Direct.
- No offline alerts for assets behind a jump host. Availability monitoring (ping and port checks) runs from the Octotor server directly, which cannot see a device that is only reachable through a bastion, so such an asset would look permanently offline. An asset with a jump host attached is therefore excluded from availability (offline) alerts; any availability alert that was open when the jump host was attached is resolved automatically. Threshold alerts on collected values (disk space, backup results, and so on) keep working, because the collector job runs through the jump host.
- The jump credential is stored encrypted in the database like every other credential — nothing is kept in plain text or in environment variables.
- Jump hosts and credentials are scoped to their customer: an operator only sees the jump hosts and credentials that belong to the customers they manage, and a credential from one customer cannot be attached to another customer's jump host.
Credentials for CLI appliances
When you create the SSH credential for an appliance (or its jump host), set Applies to = CLI appliance. Credentials carry a name of their own — the Assets ▸ Credentials panel lists them by that name, with the login shown on a separate Login: line, so two credentials that share a username (say two admin accounts on different firewalls) stay easy to tell apart.
License Agreement
Download .mdOctotor is distributed under a Source-Available license. The Licensee may inspect the source installed on a Licensed Instance for the Licensee's internal purposes — including security review, understanding how the Software operates, compliance verification, and reporting bugs — while reuse, redistribution, and competing products are not permitted. Octotor and the Octotor logo are trade names and unregistered trademarks of Caprior. Governing law: State of Israel.
Loading license text…
About Octotor
| Version | — |
| Build Date | — |
| Instance Name | — |
| Instance ID | — |
| Your Username | — |
| Your Role | — |
WinRM Remote Management
Octotor supports Windows Remote Management (WinRM) as an alternative to SSH for executing commands on Windows machines. WinRM uses PowerShell remoting over HTTP (port 5985) with NTLM authentication.
Windows Target Requirements
Run the following on each Windows target (as Administrator):
Enable-PSRemoting -Force Set-Item WSMan:\localhost\Service\AllowUnencrypted -Value $true Set-Item WSMan:\localhost\Service\Auth\Basic -Value $true
WinRM must be enabled and the firewall must allow port 5985 (HTTP). HTTPS (port 5986) and Kerberos authentication are planned for a future release.
Protocol Resolution
Octotor determines which protocol (SSH or WinRM) to use for each asset using this hierarchy:
| # | Priority | Source |
|---|---|---|
| 1 | Run Command override | One-time selection in the Run Command modal (not saved) |
| 2 | Task force protocol | Scheduled task configuration: Auto / Force SSH / Force WinRM |
| 3 | Asset override | Per-asset Connection Protocol field in the asset edit modal |
| 4 | Global default | Settings > Management Protocols > Execution Defaults (per OS family) |
| 5 | Fallback | SSH (always available) |
If WinRM is resolved but globally disabled (Settings > Management Protocols > WinRM = Disabled), the worker automatically falls back to SSH and logs a warning.
Execution Flow
Identity Verification
WinRM supports hostname identity verification, similar to the SSH gate. When enabled, Octotor connects via WinRM and runs [System.Net.Dns]::GetHostName() to verify the remote machine's identity before executing the actual command. Configure the default gate per OS family in Settings > Monitoring > Identity Verification.
Management Protocols Settings
| # | Setting | Description |
|---|---|---|
| 1 | Protocol Status (SSH/WinRM) | Global enable/disable. Disabled protocols are hidden from all UI and the worker falls back to SSH. |
| 2 | Execution Defaults | Default protocol per OS family (Windows: WinRM or SSH, Linux: SSH) |
| 3 | WinRM Default Port | Default: 5985. Override per-asset via the WinRM Port attribute. |
| 4 | WinRM Timeout | Connection timeout in seconds. Default: 30. |
| 5 | WinRM Auth Method | Currently NTLM (Negotiate). Kerberos and Certificate planned for future. |
Services Status
Overview
The Services page provides a live dashboard of system health. It is available to administrators only and auto-refreshes every 10 seconds.
Sections
| # | Section | Description |
|---|---|---|
| 1 | Host | CPU load averages, memory usage, database size, and backup freshness indicator. |
| 2 | Containers | All running oct-* containers with status, uptime, CPU %, memory, and restart count. Requires Docker socket mount (configured automatically by the installer). On a server installed without the local AI model, oct-ollama is listed in grey as not installed: that is the chosen setup, not a fault. If the server was installed with the local AI model and the container is gone, it is listed in red as missing. |
| 3 | Service Heartbeats | Each background service reports its last heartbeat and the interval it is expected to report at (the scheduler and the worker containers every 30 seconds, autoping and TCP monitoring at their configured check interval, maintenance at the period of its schedule — daily, weekly or monthly). A timer-driven service shows stale in red when its last heartbeat is older than twice that interval; autoping, TCP monitoring and maintenance write their heartbeat at the end of each check cycle, so they get three intervals before they show stale. Example: the scheduler is expected every 30 seconds, so it shows stale once its last heartbeat is more than 60 seconds old; autoping at a 60-second interval shows stale after 180 seconds. A service you turned off in Settings (autoping, TCP monitoring or scheduled maintenance) shows no expected interval and is never marked stale. |
| 4 | Active Work | Count of currently running and queued jobs. |
| 5 | Recent Errors | Last 10 error entries from the action log. |
| 6 | Service Controls | Placeholder for stop/start/restart controls — planned for a future release. |
Architecture
Background services run in a dedicated oct-worker container, separate from the API. This isolation means a stuck background task cannot affect API responsiveness. Services communicate via the database (LISTEN/NOTIFY) and write heartbeats to the service_heartbeats table so the API can report their health.
- An operator reports a
whoamijob sitting in queued for 20 minutes. You open Services. - Service Heartbeats shows
ssh-workerwith a stale flag — last heartbeat 18 minutes ago (healthy services update every ≤30s). - Containers confirms
oct-ssh-worker's restart count jumped and it isn't consuming the queue. - You restart the worker on the host (
docker compose restart oct-ssh-worker); its heartbeat goes green within 30s and the queued job runs to done.
Software Updates
Overview
Octotor checks once a day whether a newer release has been published, and shows the result in Settings ▸ Updates. When an update exists, users with Settings access also see a dismissible banner under the navigation bar. The check is anonymous: Octotor fetches one static file (the published version list) and sends nothing about this installation — no identifiers, no counts, no parameters. Installing an update stays a deliberate command-line step; nothing installs itself.
The Updates panel
Open Settings ▸ Updates. The Status panel shows:
| # | Field | Meaning |
|---|---|---|
| 1 | Current version | The version this installation is running |
| 2 | Latest known | The newest published version for your major release line, as of the last check |
| 3 | Last check | When the last check ran and whether it succeeded — a failed check (for example, a site firewall blocking the deployment host) is recorded here and is harmless |
Check now runs a check immediately. Daily update check is the opt-out: set it to Disabled and save to stop the background check — the Check now button keeps working either way.
Worked example: checking for and installing an update
- Open Settings ▸ Updates and click Check now.
- Suppose the panel now shows Current version
v3.2.0and Latest knownv3.2.1, with the note "An update is available". - On the host machine (SSH, not this web UI), run the upgrade one-liner:
curl -fsSL https://get.octotor.com/upgrade | sudo bash
It downloads the current release bundle, verifies the image signatures, backs up the database, and upgrades in place. To install a specific version instead of the latest:curl -fsSL https://get.octotor.com/upgrade | sudo bash -s -- --version=v3.2.1 - After the upgrade completes, reload this UI — the version in the corner and in Settings ▸ Updates now reads
v3.2.1, and the update banner disappears on the next check.
When the upgrade has finished and the new version answers, it deletes the Octotor container images of versions older than the one you upgraded from. The images of the new version and of the version you came from stay on disk, so going back one version needs no download. The upgrade lists every image it deleted and prints the disk space freed. To keep all old images, add --keep-old-images: curl -fsSL https://get.octotor.com/upgrade | sudo bash -s -- --keep-old-images. The upgrade keeps the local AI model choice recorded on the server (see Goose Agent > Local AI model and cloud AI) and never changes the host firewall.
If the panel shows "You are on the latest published version for this major", there is nothing to install. A separate note about a newer major version means a bigger upgrade exists — contact licensing to discuss it; the daily check never installs or changes anything by itself.
Support Bundle
Overview
When you contact support about a problem, they usually need to see the system's state: versions, service health, recent failures. The support bundle collects that into one downloadable file. Nothing is ever sent anywhere automatically — there is no upload feature by design. The file downloads to your computer, and you send it to support yourself by email or your own file share.
What is and is not in the bundle
| # | Included | Never included |
|---|---|---|
| 1 | Version, migration level, service heartbeats | Credentials or credential data |
| 2 | License state summary (tier, expiry) | Encryption keys, JWT secrets, API tokens |
| 3 | Recent failed jobs (metadata only) + alert counts | .env contents |
| 4 | Error entries from the action log | Job outputs and commands (can embed secrets) |
| 5 | Settings, with secret-looking values masked | License key material |
Worked example: sending a bundle to support
- Support asks: "please send a diagnostic bundle."
- Open Settings ▸ Support and click Generate bundle.
- Your browser downloads a file such as
octotor-support-octotor-2026-07-28.tgz, and the panel confirms "Bundle download started". - Attach that file to your reply to support (email or your file share). That's the whole flow — Octotor itself has sent nothing.
Host-side diagnostics (when the web UI can't help)
Container-level problems (a service that won't start, docker issues) aren't visible from inside the app. For those, run the host script on the server over SSH:
sudo bash /opt/octopus/scripts/octotor-diag.sh
It writes /tmp/octotor-diag-<date>.tgz with container status, redacted log tails, the compose configuration with all environment values stripped, disk/memory info, and network reachability checks. Send that file the same way — by your own hand.
Database Maintenance
Overview
The Maintenance section in Settings provides database lifecycle management: retention policies, optimization, and visibility into database health. All maintenance actions are logged and visible in the Investigate page.
Data Retention
Configure how long each type of data is kept before automatic cleanup:
| Setting | Default | What It Deletes |
|---|---|---|
| Event Log Retention | 90 days | Action log entries (login, config changes, identity alerts, all system operations) |
| Job History Retention | 90 days | Completed/failed jobs and their output text. Running and queued jobs are never deleted. |
| Identity History Retention | 30 days | DNS/SSH/collector verification records from the Identity tab |
| AI Conversations Retention | 90 days | Goose chat history and recipe execution logs |
| Attribute History Retention | 180 days | Attribute change log ("RAM changed from 8GB to 16GB") |
Scheduled Maintenance
When enabled, maintenance runs automatically on a cron schedule. Each run:
- Prunes data older than the retention limits
- Runs VACUUM ANALYZE (reclaims dead tuples, updates query planner)
- Deletes old backup files beyond the backup retention period
Cron examples:
| Expression | Meaning |
|---|---|
0 2 * * * | Daily at 2:00 AM |
0 3 * * 0 | Every Sunday at 3:00 AM |
0 */6 * * * | Every 6 hours |
30 1 1 * * | 1st of every month at 1:30 AM |
Manual Actions
| Action | What It Does | Risk |
|---|---|---|
| Backup Status | Shows the most recent backup file, how long ago it was created, and a health indicator: green (✓ < 24h), yellow (⚠ 24–48h overdue), red (✗ > 48h — check host cron). Backups run via host cron (daily at 2 AM) using backup.sh. | None (read-only) |
| Optimize (VACUUM ANALYZE) | Reclaims space from deleted rows and updates query planner statistics. No locks, no downtime. | None |
| Deep Optimize (VACUUM FULL) | Rewrites all tables to reclaim maximum disk space. Locks all tables during operation — users may see errors. | Brief downtime |
| Manual Prune | Delete rows older than N days from a selected table. Shows a preview count before deleting. | Permanent — deleted data cannot be recovered |
Backup Architecture
Backups run via a host cron job (installed by setup-prod.sh). The cron entry runs backup.sh daily at 2 AM, which calls docker compose exec oct-postgres pg_dump — the postgres container's native pg_dump is always version-matched to the database. The last 7 backups are kept; older files are automatically removed.
Backup files are stored in data/backups/, which is mounted into the oct-api container as /data/backups. This allows the Settings > Maintenance page to list, download, and delete backup files. The Backup Status card shows freshness (how long since the last backup) with a color-coded health indicator.
To run a backup manually: cd /opt/octopus && ./backup.sh
To change the backup schedule: crontab -e on the host and edit the backup.sh cron entry.
Backup Security
Backup files contain the full database including:
- Encrypted credentials — AES-256 encrypted with MASTER_KEY (ciphertext, not plaintext)
- Password hashes — bcrypt hashes of user passwords
- Customer data — asset names, IPs, hostnames, attributes
The MASTER_KEY itself is not in the backup (it's in the .env file). Backup files should be stored securely and not shared.
Restore from Backup
A backup is a full logical pg_dump of the database — restoring it brings back every record: assets, attributes, users and permissions, settings, scheduler tasks, job history, alerts, and credentials. Two things live outside the dump and must be handled, or the restore is incomplete:
- Credentials need the original
MASTER_KEY. Every stored secret is AES-GCM encrypted with theMASTER_KEYfrom.env(SNMP credentials withSNMP_CONNECTOR_KEY). Restore the database onto a stack whose.envhas a different key and every credential is unreadable — you would re-enter them all. Keep the original.envwith the backup. - The license is machine-bound.
license.oct+install-key.pemlive on the host under/opt/octopus/license/, not in the dump. On a fresh install the install key is new, so the old license fails its machine check — reissue the license for the new install (or restore the originallicense/folder if it's the same host).
./restore.sh data/backups/<file>.sql.gz. It restores into a throwaway *_verify database, compares every table's row count against the live DB, then drops it — the live data is never touched. A clean run ends with ✓ backup restores cleanly.Actual restore (onto a fresh install or after data loss):
- Stand the stack up, but put the original
MASTER_KEY/SNMP_CONNECTOR_KEY/JWT_SECRET/POSTGRES_PASSWORDin.envbefore first boot. - Load the dump into the database:
Or use the guarded helper:cd /opt/octopus ./backup.sh pre-restore # safety snapshot of current state gunzip -c data/backups/<file>.sql.gz \ | docker compose exec -T oct-postgres psql -U octopus -d octopus docker compose restart oct-api./restore.sh data/backups/<file>.sql.gz --into-live(asks you to typeRESTOREto confirm). - Reissue the license for the new install (unless you restored the original
/opt/octopus/license/).
.env, a full recovery re-configures nothing beyond the license (and only on new hardware). With the dump alone (no .env), you additionally re-enter credentials. The full runbook is docs/restore-procedure.md.Database State Table
Shows per-table statistics: row count, disk size, dead tuples (indicates fragmentation), and when PostgreSQL last auto-vacuumed. Use "Get Info" to refresh individual tables or "Refresh All" for the complete view.
Octotor — IT Asset Management & Remote Operations Platform