Skip to content

KC-1398: Add cspm-report command for CSPM/SSPM/GRC posture snapshots - #2274

Open
jpkeepersecurity wants to merge 1 commit into
releasefrom
KC-1398
Open

KC-1398: Add cspm-report command for CSPM/SSPM/GRC posture snapshots#2274
jpkeepersecurity wants to merge 1 commit into
releasefrom
KC-1398

Conversation

@jpkeepersecurity

Copy link
Copy Markdown
Contributor

Summary

  • Adds a new cspm-report enterprise CLI command (keepercommander/commands/cspm.py)
    callable via Commander Service Mode's existing POST /api/v1/executecommand endpoint —
    no new HTTP infrastructure required.
  • Registers the command in register_enterprise_commands() in base.py.

What it exports

Core fields (zero extra API calls — sourced entirely from params.enterprise):
user status, auth method, MFA state, roles, teams, admin permissions, role enforcements,
and subscription/license data.

Optional enrichment via flags:

Flag Field(s) added Source
--include-last-login last_login RMD rmd/get_enterprise_stat_details
--include-has-records has_records, last_logged_in RMD (shared call with above)
--include-security-audit security_score enterprise/get_security_report_data
--include-devices devices[] dm/device_admin_list + params.enterprise
--page / --page-size Pagination, max 5000 per page

Files changed

File Change
keepercommander/commands/cspm.py Created — new command, helpers, and parser
keepercommander/commands/base.py Modified — 3 lines to register the command in register_enterprise_commands()

Performance

  • Supplemental calls (RMD, security audit, devices) run concurrently via ThreadPoolExecutor
  • Device batches (dm/device_admin_list, 100 users/batch) also fire concurrently (up to 10 workers)
  • Device fetch is scoped to the current page's users only — not the full enterprise — reducing
    API calls from ceil(total/100) to ceil(page_size/100) per page request

Test plan

  • cspm-report --format json returns valid JSON with total, page, has_more, subscription, users
  • --include-last-login populates last_login on all non-invited users
  • --include-last-login and --include-has-records together issue only one RMD call
  • --include-devices returns devices[] only for users in the current page
  • Pagination: page=1 and page=2 return non-overlapping user sets; last page has has_more: false
  • Command not in --commands allow-list returns 403 Forbidden
  • Invited users show auth_method: "pending" and status: "invited"
  • Locked users show status: "locked" or status: "locked_by_idp" depending on lock value
  • SSO users show auth_method: "sso"

Output Examples for Reviewers

1. Minimal call — no optional flags

Request:

curl -s -X POST http://localhost:8080/api/v1/executecommand \
  -H "Content-Type: application/json" \
  -H "api-key: YOUR_API_KEY" \
  -d '{"command": "cspm-report --format json --page 1 --page-size 3"}'

Response:

{
  "status": "success",
  "command": "cspm-report",
  "data": {
    "total": 7,
    "page": 1,
    "page_size": 3,
    "has_more": true,
    "subscription": {
      "seats_purchased": 25,
      "seats_allocated": 7,
      "seats_pending": 1,
      "expiration": "2027-01-15T00:00:00",
      "add_ons": [
        {
          "name": "enterprise_breachwatch",
          "enabled": true,
          "seats": 25,
          "expiration": "2027-01-15T00:00:00"
        }
      ]
    },
    "users": [
      {
        "email": "admin@company.com",
        "user_id": 100001,
        "status": "active",
        "is_admin": true,
        "auth_method": "master_password",
        "tfa_enabled": true,
        "roles": ["Administrators"],
        "teams": [],
        "admin_permissions": ["manage_users", "manage_teams", "run_reports", "manage_roles"],
        "role_enforcements": {
          "master_password_minimum_length": "12",
          "master_password_restrict_reuse": "5"
        }
      },
      {
        "email": "alice@company.com",
        "user_id": 100002,
        "status": "active",
        "is_admin": false,
        "auth_method": "sso",
        "tfa_enabled": true,
        "roles": ["Standard Users", "Security Team"],
        "teams": ["Engineering", "Platform"],
        "admin_permissions": [],
        "role_enforcements": {
          "master_password_minimum_length": "10"
        }
      },
      {
        "email": "bob@company.com",
        "user_id": 100003,
        "status": "invited",
        "is_admin": false,
        "auth_method": "pending",
        "tfa_enabled": false,
        "roles": [],
        "teams": [],
        "admin_permissions": [],
        "role_enforcements": {}
      }
    ]
  }
}

2. Full call — all optional flags enabled

Request:

curl -s -X POST http://localhost:8080/api/v1/executecommand \
  -H "Content-Type: application/json" \
  -H "api-key: YOUR_API_KEY" \
  -d '{
    "command": "cspm-report --format json --page 1 --page-size 3 --include-last-login --include-has-records --include-security-audit --include-devices"
  }'

Response:

{
  "status": "success",
  "command": "cspm-report",
  "data": {
    "total": 7,
    "page": 1,
    "page_size": 3,
    "has_more": true,
    "subscription": {
      "seats_purchased": 25,
      "seats_allocated": 7,
      "seats_pending": 1,
      "expiration": "2027-01-15T00:00:00",
      "add_ons": [
        {
          "name": "enterprise_breachwatch",
          "enabled": true,
          "seats": 25,
          "expiration": "2027-01-15T00:00:00"
        }
      ]
    },
    "users": [
      {
        "email": "admin@company.com",
        "user_id": 100001,
        "status": "active",
        "is_admin": true,
        "auth_method": "master_password",
        "tfa_enabled": true,
        "roles": ["Administrators"],
        "teams": [],
        "admin_permissions": ["manage_users", "manage_teams", "run_reports", "manage_roles"],
        "role_enforcements": {
          "master_password_minimum_length": "12",
          "master_password_restrict_reuse": "5"
        },
        "last_login": "2026-08-07T09:14:32",
        "has_records": true,
        "last_logged_in": "2026-08-07T09:14:32",
        "security_score": 98,
        "devices": [
          {
            "device_name": "Admin's MacBook Pro",
            "client_version": "16.11.2",
            "device_platform": "macOS",
            "device_category": "Desktop",
            "device_status": "APPROVED",
            "login_state": "LOGGED_IN",
            "last_modified": "2026-08-07T09:14:32",
            "ip_address": null,
            "location": null
          }
        ]
      },
      {
        "email": "alice@company.com",
        "user_id": 100002,
        "status": "active",
        "is_admin": false,
        "auth_method": "sso",
        "tfa_enabled": true,
        "roles": ["Standard Users", "Security Team"],
        "teams": ["Engineering", "Platform"],
        "admin_permissions": [],
        "role_enforcements": {
          "master_password_minimum_length": "10"
        },
        "last_login": "2026-08-06T14:32:11",
        "has_records": true,
        "last_logged_in": "2026-08-06T14:32:11",
        "security_score": 94,
        "devices": [
          {
            "device_name": "Alice's iPhone 15 Pro",
            "client_version": "16.11.0",
            "device_platform": "iOS",
            "device_category": "Mobile",
            "device_status": "APPROVED",
            "login_state": "LOGGED_IN",
            "last_modified": "2026-08-06T14:32:11",
            "ip_address": null,
            "location": null
          },
          {
            "device_name": "Alice's MacBook Pro",
            "client_version": "16.11.2",
            "device_platform": "macOS",
            "device_category": "Desktop",
            "device_status": "APPROVED",
            "login_state": "LOGGED_IN",
            "last_modified": "2026-07-30T10:00:00",
            "ip_address": null,
            "location": null
          }
        ]
      },
      {
        "email": "bob@company.com",
        "user_id": 100003,
        "status": "invited",
        "is_admin": false,
        "auth_method": "pending",
        "tfa_enabled": false,
        "roles": [],
        "teams": [],
        "admin_permissions": [],
        "role_enforcements": {},
        "last_login": "N/A",
        "has_records": false,
        "last_logged_in": null,
        "security_score": null,
        "devices": []
      }
    ]
  }
}

3. Locked user example

A user locked by an IdP (e.g. deprovisioned from Okta):

{
  "email": "charlie@company.com",
  "user_id": 100004,
  "status": "locked_by_idp",
  "is_admin": false,
  "auth_method": "sso",
  "tfa_enabled": false,
  "roles": ["Standard Users"],
  "teams": ["Sales"],
  "admin_permissions": [],
  "role_enforcements": {},
  "last_login": "2026-05-12T16:44:00",
  "has_records": true,
  "last_logged_in": "2026-05-12T16:44:00",
  "security_score": 61,
  "devices": [
    {
      "device_name": "Charlie's Android",
      "client_version": "16.9.1",
      "device_platform": "Android",
      "device_category": "Mobile",
      "device_status": "APPROVED",
      "login_state": "LOGGED_OUT",
      "last_modified": "2026-05-12T16:44:00",
      "ip_address": null,
      "location": null
    }
  ]
}

4. Device pending approval example

A device submitted for approval that has not yet been confirmed by an admin:

{
  "device_name": "Dave's iPad Pro",
  "client_version": "16.10.0",
  "device_platform": null,
  "device_category": "tablet",
  "device_status": "NEEDS_APPROVAL",
  "login_state": null,
  "last_modified": "2026-08-07T08:01:55",
  "ip_address": "203.0.113.45",
  "location": "São Paulo, BR"
}

5. Pagination — second page

Request:

curl -s -X POST http://localhost:8080/api/v1/executecommand \
  -H "Content-Type: application/json" \
  -H "api-key: YOUR_API_KEY" \
  -d '{"command": "cspm-report --format json --page 2 --page-size 3"}'

Response (last page):

{
  "status": "success",
  "command": "cspm-report",
  "data": {
    "total": 7,
    "page": 2,
    "page_size": 3,
    "has_more": false,
    "subscription": { "...": "same as page 1" },
    "users": [
      { "email": "dave@company.com", "user_id": 100004, "...": "..." },
      { "email": "eve@company.com",  "user_id": 100005, "...": "..." },
      { "email": "frank@company.com","user_id": 100006, "...": "..." }
    ]
  }
}

has_more: false signals the last page. Consumers should stop paginating.


6. Error responses

Missing or invalid API key (401):

{
  "status": "error",
  "error": "Please provide a valid api key"
}

Command not in allow-list (403):

{
  "status": "error",
  "error": "Not permitted to perform this function"
}

Expired API key (401):

{
  "status": "error",
  "error": "API key has expired"
}

Introduces a new enterprise CLI command callable via Commander Service
Mode's existing executecommand endpoint. Exports user status, MFA,
roles, enforcements, devices, last login (RMD-sourced), and security
scores. Supplemental API calls run concurrently; device fetches are
scoped to the current page to avoid full-enterprise scans on paginated
requests.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant