Migrate BMS skill to Python-only CLI with audit logging

This commit is contained in:
Steve W
2026-04-08 15:53:38 +00:00
parent 59d6e5ba3a
commit f5fb984bc3
16 changed files with 408 additions and 324 deletions

197
README.md
View File

@@ -1,15 +1,6 @@
# openclaw-bms
Python rewrite of the OpenClaw Kaseya BMS skill for ticket and note workflows.
## Goals
- reliable ticket CRUD
- reliable ticket note CRUD
- correct account/location relationship handling
- cache stable CRM lookups
- support template-based ticket creation cleanly
- keep a small shell compatibility layer for existing `scripts/*.sh` entrypoints
Python-first OpenClaw skill for Kaseya BMS ticket and note workflows.
## Installation
@@ -17,10 +8,16 @@ Python rewrite of the OpenClaw Kaseya BMS skill for ticket and note workflows.
python3 -m pip install -e .
```
Or run directly from the repo:
Primary usage:
```bash
bash scripts/bms.sh --help
bms --help
```
Alternative direct module invocation:
```bash
python3 -m openclaw_bms --help
```
## Configuration
@@ -29,39 +26,35 @@ bash scripts/bms.sh --help
export BMS_TENANT="your-tenant"
export BMS_USERNAME="your-user"
export BMS_PASSWORD="your-password"
export BMS_MFA_CODE="123456" # when needed
export BMS_MFA_CODE="123456" # when needed
export BMS_API_BASE="https://api.bms.kaseya.com"
export BMS_TOKEN_FILE="$HOME/.bms_token.json"
export BMS_CACHE_FILE="$HOME/.cache/openclaw-bms/cache.json"
```
## Key behavior
## Core behavior
### Accounts and Locations
Locations are account-scoped.
Locations are tied to accounts.
Use:
That means a location named `Main` under one account is a different object from `Main` under another account.
Always resolve locations in the context of an account.
Commands:
```bash
bms accounts
bms locations --account 12345
```
Do not assume a location name like `Main` is globally unique. A location name can exist under multiple accounts with different IDs.
Cached for 24 hours:
- accounts list
- locations per account
Refresh explicitly:
```bash
bms accounts --refresh
bms locations --account 12345
bms locations --account 12345 --refresh
```
### Tickets
Caching:
- accounts cached for 24 hours
- locations cached per account for 24 hours
### Ticket CRUD
List/search:
@@ -69,6 +62,12 @@ List/search:
bms tickets list --status Open --assignee "Jane Doe"
```
Get:
```bash
bms tickets get 12345
```
Create:
```bash
@@ -85,7 +84,7 @@ bms tickets create \
--open-date 2026-04-07T14:00:00+00:00
```
Template-based create:
Create from template:
```bash
bms tickets create \
@@ -96,65 +95,123 @@ bms tickets create \
--queue-id 9
```
Template logic:
- fetches the template
- merges template defaults with CLI overrides
- CLI values win
- validates required fields before the create call
- requires routing via either `queue-id` or `assignee-id`
- makes exactly one create API call per invocation
- treats create as success only when the response includes success=true and a valid ticket ID
Template create flow:
- fetch template
- merge template defaults with explicit CLI overrides
- validate required fields before the API call
- require either `queue-id` or `assignee-id`
- make exactly one create API call per invocation
- require a valid ticket ID in the response before reporting success
### Notes
Patch:
```bash
bms tickets patch 12345 /StatusId 6
```
Assign:
```bash
bms tickets assign 12345 --details "Routing to tier 2" --type-id 1 --status-id 6 --queue-id 7
```
Delete:
```bash
bms tickets delete 12345
```
### Ticket Note CRUD
List notes:
```bash
bms notes list 33919447
bms notes list 12345
```
Add a note with a custom date:
Add note with custom date:
```bash
bms notes add 33919447 --message "Backfilled note" --note-date 2026-04-01T15:00:00+00:00
bms notes add 12345 --message "Backfilled note" --note-date 2026-04-01T15:00:00+00:00
```
Update a note with a custom date:
Update note with custom date:
```bash
bms notes update 33919447 1001 --message "Corrected note" --note-date 2026-04-01T16:00:00+00:00
bms notes update 12345 1001 --message "Corrected note" --note-date 2026-04-01T16:00:00+00:00
```
Delete a note:
Delete note:
```bash
bms notes delete 33919447 1001
bms notes delete 12345 1001
```
## Architectural decisions
### Lookups
```bash
bms lookup statuses
bms lookup priorities
bms lookup types
bms lookup sources
```
Notes:
- `types` maps to issue-type lookup in the public BMS v2 Swagger.
- `sources` is not exposed in the public BMS v2 Swagger; the command fails explicitly and expects tenant-specific source IDs.
### Templates
```bash
bms templates tickets list
bms templates tickets get 7
bms templates notes list
bms templates timelogs list
```
Templates are read-only.
## Audit logging
Write operations only are logged.
Reads are not logged.
Logged operations:
- auth login
- auth refresh
- ticket create
- ticket patch
- ticket delete
- ticket assign
- note add
- note update
- note delete
Log path:
```text
~/.bms-actions/YYYY-MM-DD.jsonl
```
Entry shape:
- `timestamp`
- `command`
- `args_sanitized`
- `result` or `error`
- `status`
- `revert_info` when available
Secrets are redacted:
- `BMS_PASSWORD`
- `BMS_MFA_CODE`
- tokens
- authorization headers
## Architecture
- Python standard library only
- avoids packaging friction for a personal skill
- console entry point via `pyproject.toml`
- no shell wrappers required
- service layer separated from CLI
- easier to audit and extend
- caching stored in a JSON file
- simple, transparent, sufficient for account/location lookups
- shell scripts kept as compatibility wrappers
- existing command habits keep working
## Audit notes
Primary audit focus was on:
- ticket create safety
- note CRUD support
- account/location correctness
- template create correctness
Changes from bash version:
- removed fragile mixed endpoint usage
- fixed account/location handling through CRM endpoints
- added explicit cache for accounts and per-account locations
- added `open-date` support for ticket creation
- added `note-date` support for note create and update
- added full note CRUD in the Python CLI
- reduced duplicate-create risk by validating before create and checking response semantics after create
- file-based cache for stable CRM data
- file-based audit log for write history and rollback context