Skip to main content

A zero-dependency CLI tool for validating SCIM 2.0 User, Group, Agent, and AgenticApplication payloads (RFC 7643/7644)

Project description

scim-sanity

Catch SCIM integration bugs before they hit production

A lightweight CLI linter for SCIM 2.0 payloads – now with early support for provisioning AI agents and agentic applications

Works offline · Pure Python standard library · No external dependencies required.

Python 3.7+ License: MIT pre-commit.ci status

Built for the Agentic Future

The rapid growth of AI agents requires robust identity management distinct from traditional users. The October 2025 IETF draft introduces dedicated Agent and AgenticApplication resource types in SCIM, enabling standardized provisioning, ownership tracking, and lifecycle control for non-human workloads.

scim-sanity adds early validation for these schemas, helping developers and IAM teams adopt the new standard confidently and avoid integration issues in multi-agent environments.

Why scim-sanity?

SCIM (System for Cross-domain Identity Management) integrations are notoriously tricky. Common mistakes like missing required fields, setting immutable attributes, or invalid PATCH operations can cause silent failures or break production systems. scim-sanity validates your SCIM payloads locally before they hit your API, catching these issues early.

Features

Zero dependencies - Works with Python standard library only (optional Click for better CLI)
SCIM 2.0 compliant - Validates against RFC 7643 and RFC 7644
Agent extension support - Validates Agent and AgenticApplication resources (draft-abbey-scim-agent-extension-00)
Comprehensive checks - Catches 15+ common integration errors
Color output - Beautiful, readable error messages with line numbers
PATCH support - Validates both full resources and PATCH operations
Enterprise extension - Supports enterprise user extension schema

Installation

Using pipx (recommended)

pipx install scim-sanity

Using pip

pip install scim-sanity

From source

git clone https://github.com/thomaselliottbetz/scim-sanity.git
cd scim-sanity
python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate
pip install -e .

Verifying Installation

After installation, verify that scim-sanity is working correctly:

Option 1: Using the command (if installed via pip/pipx or with venv activated)

scim-sanity --help

Option 2: Using Python module (works from anywhere)

python3 -m scim_sanity --help

Quick test:

# Test with a valid user resource
echo '{"schemas":["urn:ietf:params:scim:schemas:core:2.0:User"],"userName":"test@example.com"}' | python3 -m scim_sanity --stdin
# Expected output: ✅ Valid SCIM resource

# Test with an invalid resource (missing userName)
echo '{"schemas":["urn:ietf:params:scim:schemas:core:2.0:User"]}' | python3 -m scim_sanity --stdin
# Expected output: Error about missing userName

# Test with an Agent resource
echo '{"schemas":["urn:ietf:params:scim:schemas:core:2.0:Agent"],"name":"test-agent"}' | python3 -m scim_sanity --stdin
# Expected output: ✅ Valid SCIM resource

Usage

scim-sanity can be run in several ways depending on your installation method:

Running the Tool

If installed via pip/pipx or with virtual environment activated:

scim-sanity [options] [file]

Using Python module (always works):

python3 -m scim_sanity [options] [file]
# or
python -m scim_sanity [options] [file]

Command Options

  • <file> - Path to a JSON file containing a SCIM resource or PATCH operation
  • --patch - Validate the input as a SCIM PATCH operation instead of a full resource
  • --stdin - Read JSON from standard input instead of a file
  • -h, --help - Show help message and exit

Basic Usage Examples

Validate a SCIM resource file

# Validate a User resource
scim-sanity user.json

# Validate a Group resource
scim-sanity group.json

# Validate an Agent resource (auto-detected from schema URI)
scim-sanity agent.json

# Validate an AgenticApplication resource (auto-detected from schema URI)
scim-sanity agentic-app.json

# Using Python module
python3 -m scim_sanity user.json

Validate a PATCH operation

scim-sanity --patch patch.json

# Using Python module
python3 -m scim_sanity --patch patch.json

Validate from stdin

# Validate a User resource from stdin
echo '{"schemas":["urn:ietf:params:scim:schemas:core:2.0:User"],"userName":"user@example.com"}' | scim-sanity --stdin

# Validate a PATCH operation from stdin
echo '{"schemas":["urn:ietf:params:scim:api:messages:2.0:PatchOp"],"Operations":[{"op":"replace","path":"displayName","value":"New Name"}]}' | scim-sanity --stdin --patch

# Pipe from another command
curl -s https://api.example.com/user/123 | scim-sanity --stdin

Common Workflows

Pre-commit Validation

Validate SCIM payloads before committing or deploying:

# Validate all JSON files in a directory
for file in payloads/*.json; do
  echo "Validating $file..."
  scim-sanity "$file" || exit 1
done

CI/CD Integration

Use in your CI pipeline to catch SCIM errors early:

# In your CI script
if ! scim-sanity user-payload.json; then
  echo "SCIM validation failed!"
  exit 1
fi

Testing API Responses

Validate responses from your SCIM API:

# Test a GET response
curl -s https://api.example.com/scim/v2/Users/123 | scim-sanity --stdin

# Test a POST request body before sending
scim-sanity new-user.json && curl -X POST https://api.example.com/scim/v2/Users -d @new-user.json

Interactive Development

Quick validation while developing:

# Validate and see errors immediately
scim-sanity my-payload.json

# If valid, proceed with API call
scim-sanity my-payload.json && curl -X POST ... -d @my-payload.json

Exit Codes

The tool uses standard exit codes for scripting:

  • 0 - Validation passed (resource is valid)
  • 1 - Validation failed (errors found) or an error occurred

Use exit codes in scripts:

if scim-sanity payload.json; then
  echo "Payload is valid, proceeding..."
  # Continue with your workflow
else
  echo "Validation failed, stopping..."
  exit 1
fi

Pre-commit Integration

Automatically validate SCIM payloads on every commit to enforce compliance in developer workflows. This is ideal for Infrastructure as Code (IaC) repositories, provisioning templates, security automation pipelines, and any codebase managing SCIM resources.

Installation

  1. Install pre-commit:

    pip install pre-commit
    
  2. Install the git hook:

    pre-commit install
    
  3. Add .pre-commit-config.yaml to your repository root:

# Pre-commit hook configuration for scim-sanity
# See https://pre-commit.com for more information
repos:
  - repo: local
    hooks:
      - id: scim-sanity
        name: Validate SCIM resources with scim-sanity
        entry: python -m scim_sanity
        language: system
        types: [json]
        exclude: |
          (?x)^(
            .*/node_modules/.*|
            .*/\.venv/.*|
            .*/venv/.*|
            .*/ENV/.*|
            .*/env/.*|
            .*/\.tox/.*|
            .*/dist/.*|
            .*/build/.*|
            .*package\.json$|
            .*package-lock\.json$|
            .*tsconfig.*\.json$|
            .*jsconfig\.json$|
            .*\.pre-commit-config\.yaml$|
            .*\.gitignore$|
            .*\.vscode/.*|
            .*\.idea/.*|
            .*\.pytest_cache/.*|
            .*\.mypy_cache/.*|
            .*\.coverage$|
            .*coverage\.json$
          )$
        pass_filenames: true
        require_serial: true
        always_run: false
        stages: [commit]

How It Works

The hook automatically validates all JSON files on commit, excluding common configuration files and dependency directories. Files without SCIM schema URNs will be validated by scim-sanity and will fail if they don't conform to SCIM specifications, ensuring only valid SCIM resources are committed.

On valid commit:

$ git commit -m "Add new user resource"
scim-sanity................................................................Passed
[main abc1234] Add new user resource

On invalid commit:

$ git commit -m "Add invalid user resource"
scim-sanity................................................................Failed
- hook id: scim-sanity
- exit code: 1

Found 1 error(s):

❌ Missing required attribute: 'userName' (schema: urn:ietf:params:scim:schemas:core:2.0:User) at userName

Pre-commit.ci Integration

The pre-commit.ci badge at the top of this README shows the status of pre-commit checks on pull requests. To enable pre-commit.ci for this repository:

  1. Enable the service at https://pre-commit.ci (sign in with GitHub)
  2. Install the GitHub App on this repository
  3. Pre-commit.ci will automatically run hooks on pull requests

Note: The badge will show a "not found" status until the service is enabled and has run at least once.

Understanding Output

Valid Resource

When validation passes, you'll see:

✅ Valid SCIM resource

or for PATCH operations:

✅ Valid PATCH operation

Invalid Resource

When validation fails, errors are displayed with clear messages:

Found 3 error(s):

❌ Missing required attribute: 'userName' (schema: urn:ietf:params:scim:schemas:core:2.0:User) at userName
❌ Immutable attribute 'id' should not be set by client (mutability: readOnly) at id
❌ Attribute 'displayName' has null value. Use PATCH 'remove' operation to clear attributes instead at displayName

Each error message includes:

  • Error type - What went wrong
  • Location - The attribute path where the error occurred
  • Guidance - How to fix the issue

Error Messages Explained

  • Missing required attribute - A required field for the resource type is missing
  • Immutable attribute - You're trying to set a read-only field (like id or meta)
  • Null value - Using null to clear a value (use PATCH remove instead)
  • Invalid schema - Unknown or invalid schema URN
  • Invalid structure - Data doesn't match expected SCIM structure (e.g., multi-valued attribute not an array)

Validation Checks

scim-sanity performs the following checks:

Required Attributes

  • ✅ Ensures userName is present for User resources
  • ✅ Ensures displayName is present for Group resources
  • ✅ Ensures name is present and non-empty for Agent resources
  • ✅ Ensures name is present and non-empty for AgenticApplication resources
  • ✅ Validates all required schema attributes

Schema Validation

  • ✅ Validates schema URNs (core User, Group, Agent, AgenticApplication, enterprise extension)
  • ✅ Auto-detects resource type from schema URIs (no flags needed)
  • ✅ Rejects unknown or invalid schema URNs
  • ✅ Ensures schemas field is present and non-empty

Mutability Rules

  • ✅ Flags immutable attributes (e.g., id, meta) being set by client
  • ✅ Validates read-only attributes are not modified

PATCH Operations

  • ✅ Validates PATCH operation structure
  • ✅ Ensures valid op values (add, remove, replace)
  • ✅ Checks for duplicate paths in operations
  • ✅ Validates required fields per operation type

Data Semantics

  • ✅ Rejects null values (use PATCH remove instead)
  • ✅ Validates complex attribute structures
  • ✅ Validates multi-valued attributes are arrays

Examples

Valid User Resource

{
  "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
  "userName": "john.doe@example.com",
  "name": {
    "givenName": "John",
    "familyName": "Doe"
  },
  "emails": [
    {
      "value": "john.doe@example.com",
      "type": "work",
      "primary": true
    }
  ],
  "active": true
}

Valid Group Resource

{
  "schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"],
  "displayName": "Engineering Team",
  "members": [
    {
      "value": "user-id-123",
      "display": "John Doe",
      "type": "User"
    }
  ]
}

Valid PATCH Operation

{
  "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
  "Operations": [
    {
      "op": "replace",
      "path": "displayName",
      "value": "New Name"
    },
    {
      "op": "add",
      "path": "emails",
      "value": [
        {
          "value": "newemail@example.com",
          "type": "work"
        }
      ]
    }
  ]
}

Valid User with Enterprise Extension

{
  "schemas": [
    "urn:ietf:params:scim:schemas:core:2.0:User",
    "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"
  ],
  "userName": "manager@example.com",
  "name": {
    "givenName": "Jane",
    "familyName": "Manager"
  },
  "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User": {
    "employeeNumber": "EMP-001",
    "department": "Engineering",
    "manager": {
      "value": "ceo-id",
      "displayName": "CEO"
    }
  }
}

Valid Agent Resource

{
  "schemas": ["urn:ietf:params:scim:schemas:core:2.0:Agent"],
  "name": "research-assistant",
  "displayName": "Research Assistant",
  "agentType": "Assistant",
  "active": true,
  "description": "An AI research assistant agent"
}

Minimal Agent Resource (only name is required):

{
  "schemas": ["urn:ietf:params:scim:schemas:core:2.0:Agent"],
  "name": "helpdesk-bot"
}

Valid AgenticApplication Resource

{
  "schemas": ["urn:ietf:params:scim:schemas:core:2.0:AgenticApplication"],
  "name": "assistant-platform",
  "displayName": "Assistant Platform",
  "description": "A platform for AI research agents",
  "active": true
}

Minimal AgenticApplication Resource (only name is required):

{
  "schemas": ["urn:ietf:params:scim:schemas:core:2.0:AgenticApplication"],
  "name": "my-agentic-app"
}

Invalid Examples (Common Mistakes)

Missing Required Field

{
  "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"]
  // Missing userName - will fail validation
}

Error: ❌ Missing required attribute: 'userName'

Setting Immutable Attribute

{
  "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
  "userName": "user@example.com",
  "id": "12345"  // ❌ Cannot set id - it's read-only
}

Error: ❌ Immutable attribute 'id' should not be set by client

Using Null Values

{
  "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
  "userName": "user@example.com",
  "displayName": null  // ❌ Use PATCH remove instead
}

Error: ❌ Attribute 'displayName' has null value. Use PATCH 'remove' operation to clear attributes instead

Invalid Multi-valued Attribute

{
  "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
  "userName": "user@example.com",
  "emails": "not-an-array"  // ❌ emails must be an array
}

Error: ❌ Multi-valued attribute 'emails' must be an array

Troubleshooting

Command not found

If you get command not found: scim-sanity:

  1. Check if virtual environment is activated (if installed from source):

    source venv/bin/activate  # or .venv/bin/activate
    
  2. Use Python module instead:

    python3 -m scim_sanity --help
    
  3. Verify installation:

    pip show scim-sanity  # Should show package info
    

File not found errors

Make sure you're providing the correct path:

# Use absolute or relative paths
scim-sanity ./path/to/file.json
scim-sanity /absolute/path/to/file.json

JSON parsing errors

If you see "Invalid JSON" errors:

  • Verify your file is valid JSON (use jq or an online JSON validator)
  • Check for trailing commas or syntax errors
  • Ensure the file encoding is UTF-8

Validation passes but API still rejects

scim-sanity validates SCIM 2.0 compliance, but your API might have:

  • Additional custom validation rules
  • Different schema extensions
  • Server-specific requirements

Always test with your actual API endpoint as well.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Development

# Clone the repository
git clone https://github.com/thomaselliottbetz/scim-sanity.git
cd scim-sanity

# Create virtual environment
python -m venv venv
source venv/bin/activate

# Install with dev dependencies
pip install -e ".[dev]"

# Run tests
pytest

# Run linter (if configured)
# flake8 scim_sanity tests

License

This project is licensed under the MIT License - see the LICENSE file for details.

Agent and AgenticApplication Support

Overview

scim-sanity now supports validation of Agent and AgenticApplication resources as defined in the IETF draft extension "SCIM Agents and Agentic Applications Extension" (draft-abbey-scim-agent-extension-00). This extension enables SCIM-based provisioning and management of AI agents and agentic applications as first-class identities.

Terminology Note

Throughout this documentation, you may see:

  • AgenticApplication (one word) when referring to the schema name or technical identifier
  • Agentic Applications (two words) when referencing the IETF draft extension title
  • agentic applications (lowercase) in descriptive prose

All refer to the same resource type - the variation is intentional for readability and technical accuracy.

Why Agent Support?

With the rise of AI agents and agentic applications, organizations need to manage these workloads as distinct identities separate from traditional users. The IETF draft extension provides:

  • Standardized schema for agent identity management via SCIM
  • Separation of concerns - Agents are distinct from Users/Groups
  • Interoperability - Enables SCIM-based agent discovery and provisioning
  • Unified management - Reuses existing SCIM infrastructure

Common use cases include:

  • Provisioning AI assistants and chatbots as SCIM resources
  • Managing access and entitlements for agent workloads
  • Tracking agent ownership and accountability
  • Integrating agent identity management with existing IAM systems

Key Features

  • Auto-detection: Resource type is automatically detected from schema URIs - no special flags needed
  • Minimal validation: Only validates required fields (name for Agents/AgenticApplications) per the draft specification
  • Schema compliance: Validates against the complete Agent and AgenticApplication schemas
  • Backward compatible: Existing User/Group validation continues to work unchanged

Schema URIs

  • Agent: urn:ietf:params:scim:schemas:core:2.0:Agent
  • AgenticApplication: urn:ietf:params:scim:schemas:core:2.0:AgenticApplication

Validation Rules

For Agent resources:

  • name attribute is REQUIRED and must be non-empty
  • All other attributes (displayName, agentType, active, etc.) are optional
  • Validates mutability rules (e.g., subject, owners are read-only)

For AgenticApplication resources:

  • name attribute is REQUIRED and must be non-empty
  • All other attributes (displayName, description, active) are optional

Example Usage

# Validate an Agent resource
echo '{"schemas":["urn:ietf:params:scim:schemas:core:2.0:Agent"],"name":"my-agent"}' | scim-sanity --stdin

# Validate an AgenticApplication resource  
echo '{"schemas":["urn:ietf:params:scim:schemas:core:2.0:AgenticApplication"],"name":"my-app"}' | scim-sanity --stdin

# Validate from file
scim-sanity agent.json
scim-sanity agentic-application.json

The validator automatically detects the resource type from the schema URI, so you use the same command-line interface for all resource types.

References

Roadmap

  • Enhanced validation for agent-specific attributes (owner, capabilities, subject)
  • Potential integration as a tool in agent frameworks and MCP servers
  • Support for evolving non-human identity standards

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

scim_sanity-0.2.0.tar.gz (25.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

scim_sanity-0.2.0-py3-none-any.whl (17.9 kB view details)

Uploaded Python 3

File details

Details for the file scim_sanity-0.2.0.tar.gz.

File metadata

  • Download URL: scim_sanity-0.2.0.tar.gz
  • Upload date:
  • Size: 25.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.7

File hashes

Hashes for scim_sanity-0.2.0.tar.gz
Algorithm Hash digest
SHA256 d0d5479d0925a0bbf9ad79d95c793528c23784ffedfcb2c231f76d913d16d579
MD5 09a11e89f7cdb283ed8326b11cf3408e
BLAKE2b-256 1d0ba860d1cf5ef6a31a3935b3eecce9fe691e9fbf31af2c2bbcd6c4d5a70e8d

See more details on using hashes here.

File details

Details for the file scim_sanity-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: scim_sanity-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 17.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.7

File hashes

Hashes for scim_sanity-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e1c71ac21d5cca8b375aea5c6e1266d8739586856a2c0bfab8308107000d1e7a
MD5 7c7df3a7ea5b11b31c393c93a51be397
BLAKE2b-256 a797986d32ecab5416027fa741e6c3c7c3f38ce4ab6e152515120d5bfd2d8b00

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page