LogoLogo
Knowledge BaseCommunityRelease NotesRequest Demo
  • Overview
  • Quick Start
    • Onboarding Guide
  • Data Sources & Transports
    • Supported Logs
      • 1Password Logs
      • Apache Logs
      • AppOmni Logs
      • Asana Logs
      • Atlassian Logs
      • Auditd Logs
      • Auth0 Logs
      • AWS Logs
        • AWS ALB
        • AWS Aurora
        • AWS CloudFront
        • AWS CloudTrail
        • AWS CloudWatch
        • AWS Config
        • AWS EKS
        • AWS GuardDuty
        • AWS Security Hub
        • Amazon Security Lake
        • AWS S3
        • AWS Transit Gateway
        • AWS VPC
        • AWS WAF
      • Azure Monitor Logs
      • Bitwarden Logs
      • Box Logs
      • Carbon Black Logs
      • Cisco Umbrella Logs
      • Cloudflare Logs
      • CrowdStrike Logs
        • CrowdStrike Falcon Data Replicator
        • CrowdStrike Event Streams
      • Docker Logs
      • Dropbox Logs
      • Duo Security Logs
      • Envoy Logs
      • Fastly Logs
      • Fluentd Logs
      • GCP Logs
      • GitHub Logs
      • GitLab Logs
      • Google Workspace Logs
      • Heroku Logs
      • Jamf Pro Logs
      • Juniper Logs
      • Lacework Logs
        • Lacework Alert Channel Webhook
        • Lacework Export
      • Material Security Logs
      • Microsoft 365 Logs
      • Microsoft Entra ID Audit Logs
      • Microsoft Graph Logs
      • MongoDB Atlas Logs
      • Netskope Logs
      • Nginx Logs
      • Notion Logs
      • Okta Logs
      • OneLogin Logs
      • Orca Security Logs (Beta)
      • Osquery Logs
      • OSSEC Logs
      • Proofpoint Logs
      • Push Security Logs
      • Rapid7 Logs
      • Salesforce Logs
      • SentinelOne Logs
      • Slack Logs
      • Snowflake Audit Logs (Beta)
      • Snyk Logs
      • Sophos Logs
      • Sublime Security Logs
      • Suricata Logs
      • Sysdig Logs
      • Syslog Logs
      • Tailscale Logs
      • Teleport Logs
      • Tenable Vulnerability Management Logs
      • Thinkst Canary Logs
      • Tines Logs
      • Tracebit Logs
      • Windows Event Logs
      • Wiz Logs
      • Zeek Logs
      • Zendesk Logs
      • Zoom Logs
      • Zscaler Logs
        • Zscaler ZIA
        • Zscaler ZPA
    • Custom Logs
      • Log Schema Reference
      • Transformations
      • Script Log Parser (Beta)
      • Fastmatch Log Parser
      • Regex Log Parser
      • CSV Log Parser
    • Data Transports
      • HTTP Source
      • AWS Sources
        • S3 Source
        • CloudWatch Logs Source
        • SQS Source
          • SNS Source
        • EventBridge
      • Google Cloud Sources
        • Cloud Storage (GCS) Source
        • Pub/Sub Source
      • Azure Blob Storage Source
    • Monitoring Log Sources
    • Ingestion Filters
      • Raw Event Filters
      • Normalized Event Filters (Beta)
    • Data Pipeline Tools
      • Chronosphere Onboarding Guide
      • Cribl Onboarding Guide
      • Fluent Bit Onboarding Guide
        • Fluent Bit Configuration Examples
      • Fluentd Onboarding Guide
        • General log forwarding via Fluentd
        • MacOS System Logs to S3 via Fluentd
        • Syslog to S3 via Fluentd
        • Windows Event Logs to S3 via Fluentd (Legacy)
        • GCP Audit to S3 via Fluentd
      • Observo Onboarding Guide
      • Tarsal Onboarding Guide
    • Tech Partner Log Source Integrations
  • Detections
    • Using Panther-managed Detections
      • Detection Packs
    • Rules and Scheduled Rules
      • Writing Python Detections
        • Python Rule Caching
        • Data Models
        • Global Helper Functions
      • Modifying Detections with Inline Filters (Beta)
      • Derived Detections (Beta)
        • Using Derived Detections to Avoid Merge Conflicts
      • Using the Simple Detection Builder
      • Writing Simple Detections
        • Simple Detection Match Expression Reference
        • Simple Detection Error Codes
    • Correlation Rules (Beta)
      • Correlation Rule Reference
    • PyPanther Detections (Beta)
      • Creating PyPanther Detections
      • Registering, Testing, and Uploading PyPanther Detections
      • Managing PyPanther Detections in the Panther Console
      • PyPanther Detections Style Guide
      • pypanther Library Reference
      • Using the pypanther Command Line Tool
    • Signals
    • Policies
    • Testing
      • Data Replay (Beta)
    • Framework Mapping and MITRE ATT&CK® Matrix
  • Cloud Security Scanning
    • Cloud Resource Attributes
      • AWS
        • ACM Certificate
        • CloudFormation Stack
        • CloudWatch Log Group
        • CloudTrail
        • CloudTrail Meta
        • Config Recorder
        • Config Recorder Meta
        • DynamoDB Table
        • EC2 AMI
        • EC2 Instance
        • EC2 Network ACL
        • EC2 SecurityGroup
        • EC2 Volume
        • EC2 VPC
        • ECS Cluster
        • EKS Cluster
        • ELBV2 Application Load Balancer
        • GuardDuty Detector
        • GuardDuty Detector Meta
        • IAM Group
        • IAM Policy
        • IAM Role
        • IAM Root User
        • IAM User
        • KMS Key
        • Lambda Function
        • Password Policy
        • RDS Instance
        • Redshift Cluster
        • Route 53 Domains
        • Route 53 Hosted Zone
        • S3 Bucket
        • WAF Web ACL
  • Alerts & Destinations
    • Alert Destinations
      • Amazon SNS Destination
      • Amazon SQS Destination
      • Asana Destination
      • Blink Ops Destination
      • Custom Webhook Destination
      • Discord Destination
      • GitHub Destination
      • Google Pub/Sub Destination (Beta)
      • Incident.io Destination
      • Jira Cloud Destination
      • Jira Data Center Destination (Beta)
      • Microsoft Teams Destination
      • Mindflow Destination
      • OpsGenie Destination
      • PagerDuty Destination
      • Rapid7 Destination
      • ServiceNow Destination (Custom Webhook)
      • Slack Bot Destination
      • Slack Destination (Webhook)
      • Splunk Destination (Beta)
      • Tines Destination
      • Torq Destination
    • Assigning and Managing Alerts
      • Managing Alerts in Slack
    • Alert Runbooks
      • Panther-managed Policies Runbooks
        • AWS CloudTrail Is Enabled In All Regions
        • AWS CloudTrail Sending To CloudWatch Logs
        • AWS KMS CMK Key Rotation Is Enabled
        • AWS Application Load Balancer Has Web ACL
        • AWS Access Keys Are Used Every 90 Days
        • AWS Access Keys are Rotated Every 90 Days
        • AWS ACM Certificate Is Not Expired
        • AWS Access Keys not Created During Account Creation
        • AWS CloudTrail Has Log Validation Enabled
        • AWS CloudTrail S3 Bucket Has Access Logging Enabled
        • AWS CloudTrail Logs S3 Bucket Not Publicly Accessible
        • AWS Config Is Enabled for Global Resources
        • AWS DynamoDB Table Has Autoscaling Targets Configured
        • AWS DynamoDB Table Has Autoscaling Enabled
        • AWS DynamoDB Table Has Encryption Enabled
        • AWS EC2 AMI Launched on Approved Host
        • AWS EC2 AMI Launched on Approved Instance Type
        • AWS EC2 AMI Launched With Approved Tenancy
        • AWS EC2 Instance Has Detailed Monitoring Enabled
        • AWS EC2 Instance Is EBS Optimized
        • AWS EC2 Instance Running on Approved AMI
        • AWS EC2 Instance Running on Approved Instance Type
        • AWS EC2 Instance Running in Approved VPC
        • AWS EC2 Instance Running On Approved Host
        • AWS EC2 Instance Running With Approved Tenancy
        • AWS EC2 Instance Volumes Are Encrypted
        • AWS EC2 Volume Is Encrypted
        • AWS GuardDuty is Logging to a Master Account
        • AWS GuardDuty Is Enabled
        • AWS IAM Group Has Users
        • AWS IAM Policy Blocklist Is Respected
        • AWS IAM Policy Does Not Grant Full Administrative Privileges
        • AWS IAM Policy Is Not Assigned Directly To User
        • AWS IAM Policy Role Mapping Is Respected
        • AWS IAM User Has MFA Enabled
        • AWS IAM Password Used Every 90 Days
        • AWS Password Policy Enforces Complexity Guidelines
        • AWS Password Policy Enforces Password Age Limit Of 90 Days Or Less
        • AWS Password Policy Prevents Password Reuse
        • AWS RDS Instance Is Not Publicly Accessible
        • AWS RDS Instance Snapshots Are Not Publicly Accessible
        • AWS RDS Instance Has Storage Encrypted
        • AWS RDS Instance Has Backups Enabled
        • AWS RDS Instance Has High Availability Configured
        • AWS Redshift Cluster Allows Version Upgrades
        • AWS Redshift Cluster Has Encryption Enabled
        • AWS Redshift Cluster Has Logging Enabled
        • AWS Redshift Cluster Has Correct Preferred Maintenance Window
        • AWS Redshift Cluster Has Sufficient Snapshot Retention Period
        • AWS Resource Has Minimum Number of Tags
        • AWS Resource Has Required Tags
        • AWS Root Account Has MFA Enabled
        • AWS Root Account Does Not Have Access Keys
        • AWS S3 Bucket Name Has No Periods
        • AWS S3 Bucket Not Publicly Readable
        • AWS S3 Bucket Not Publicly Writeable
        • AWS S3 Bucket Policy Does Not Use Allow With Not Principal
        • AWS S3 Bucket Policy Enforces Secure Access
        • AWS S3 Bucket Policy Restricts Allowed Actions
        • AWS S3 Bucket Policy Restricts Principal
        • AWS S3 Bucket Has Versioning Enabled
        • AWS S3 Bucket Has Encryption Enabled
        • AWS S3 Bucket Lifecycle Configuration Expires Data
        • AWS S3 Bucket Has Logging Enabled
        • AWS S3 Bucket Has MFA Delete Enabled
        • AWS S3 Bucket Has Public Access Block Enabled
        • AWS Security Group Restricts Ingress On Administrative Ports
        • AWS VPC Default Security Group Restricts All Traffic
        • AWS VPC Flow Logging Enabled
        • AWS WAF Has Correct Rule Ordering
        • AWS CloudTrail Logs Encrypted Using KMS CMK
      • Panther-managed Rules Runbooks
        • AWS CloudTrail Modified
        • AWS Config Service Modified
        • AWS Console Login Failed
        • AWS Console Login Without MFA
        • AWS EC2 Gateway Modified
        • AWS EC2 Network ACL Modified
        • AWS EC2 Route Table Modified
        • AWS EC2 SecurityGroup Modified
        • AWS EC2 VPC Modified
        • AWS IAM Policy Modified
        • AWS KMS CMK Loss
        • AWS Root Activity
        • AWS S3 Bucket Policy Modified
        • AWS Unauthorized API Call
    • Tech Partner Alert Destination Integrations
  • Investigations & Search
    • Search
      • Search Filter Operators
    • Data Explorer
      • Data Explorer SQL Search Examples
        • CloudTrail logs queries
        • GitHub Audit logs queries
        • GuardDuty logs queries
        • Nginx and ALB Access logs queries
        • Okta logs queries
        • S3 Access logs queries
        • VPC logs queries
    • Visualization and Dashboards
      • Custom Dashboards (Beta)
      • Panther-Managed Dashboards
    • Standard Fields
    • Saved and Scheduled Searches
      • Templated Searches
        • Behavioral Analytics and Anomaly Detection Template Macros (Beta)
      • Scheduled Search Examples
    • Search History
    • Data Lakes
      • Snowflake
        • Snowflake Configuration for Optimal Search Performance
      • Athena
  • PantherFlow (Beta)
    • PantherFlow Quick Reference
    • PantherFlow Statements
    • PantherFlow Operators
      • Datatable Operator
      • Extend Operator
      • Join Operator
      • Limit Operator
      • Project Operator
      • Range Operator
      • Sort Operator
      • Search Operator
      • Summarize Operator
      • Union Operator
      • Visualize Operator
      • Where Operator
    • PantherFlow Data Types
    • PantherFlow Expressions
    • PantherFlow Functions
      • Aggregation Functions
      • Date/time Functions
      • String Functions
      • Array Functions
      • Math Functions
      • Control Flow Functions
      • Regular Expression Functions
      • Snowflake Functions
      • Data Type Functions
      • Other Functions
    • PantherFlow Example Queries
      • PantherFlow Examples: Threat Hunting Scenarios
      • PantherFlow Examples: SOC Operations
      • PantherFlow Examples: Panther Audit Logs
  • Enrichment
    • Custom Lookup Tables
      • Creating a GreyNoise Lookup Table
      • Lookup Table Examples
        • Using Lookup Tables: 1Password UUIDs
      • Lookup Table Specification Reference
    • Identity Provider Profiles
      • Okta Profiles
      • Google Workspace Profiles
    • Anomali ThreatStream
    • IPinfo
    • Tor Exit Nodes
    • TrailDiscover (Beta)
  • Panther AI (Beta)
    • Managing Panther AI Response History
  • System Configuration
    • Role-Based Access Control
    • Identity & Access Integrations
      • Azure Active Directory SSO
      • Duo SSO
      • G Suite SSO
      • Okta SSO
        • Okta SCIM
      • OneLogin SSO
      • Generic SSO
    • Panther Audit Logs
      • Querying and Writing Detections for Panther Audit Logs
      • Panther Audit Log Actions
    • Notifications and Errors (Beta)
      • System Errors
    • Panther Deployment Types
      • SaaS
      • Cloud Connected
        • Configuring Snowflake for Cloud Connected
        • Configuring AWS for Cloud Connected
        • Pre-Deployment Tools
      • Legacy Configurations
        • Snowflake Connected (Legacy)
        • Customer-configured Snowflake Integration (Legacy)
        • Self-Hosted Deployments (Legacy)
          • Runtime Environment
  • Panther Developer Workflows
    • Panther Developer Workflows Overview
    • Using panther-analysis
      • Public Fork
      • Private Clone
      • Panther Analysis Tool
        • Install, Configure, and Authenticate with the Panther Analysis Tool
        • Panther Analysis Tool Commands
        • Managing Lookup Tables and Enrichment Providers with the Panther Analysis Tool
      • CI/CD for Panther Content
        • Deployment Workflows Using Panther Analysis Tool
          • Managing Panther Content via CircleCI
          • Managing Panther Content via GitHub Actions
        • Migrating to a CI/CD Workflow
    • Panther API
      • REST API (Beta)
        • Alerts
        • Alert Comments
        • API Tokens
        • Data Models
        • Globals
        • Log Sources
        • Queries
        • Roles
        • Rules
        • Scheduled Rules
        • Simple Rules
        • Policies
        • Users
      • GraphQL API
        • Alerts & Errors
        • Cloud Account Management
        • Data Lake Queries
        • Log Source Management
        • Metrics
        • Schemas
        • Token Rotation
        • User & Role Management
      • API Playground
    • Terraform
      • Managing AWS S3 Log Sources with Terraform
      • Managing HTTP Log Sources with Terraform
    • pantherlog Tool
    • Converting Sigma Rules
  • Resources
    • Help
      • Operations
      • Security and Privacy
        • Security Without AWS External ID
      • Glossary
      • Legal
    • Panther System Architecture
Powered by GitBook
On this page
  • Overview
  • Registering PyPanther Detections
  • Viewing registered rules
  • Importing instances of Rule
  • Registering vs. enabling a rule
  • Testing PyPanther Detections
  • Defining tests
  • Running tests
  • Testing custom helper functions and data fixtures
  • Uploading PyPanther Detections to Panther
  • upload limitations

Was this helpful?

  1. Detections
  2. PyPanther Detections (Beta)

Registering, Testing, and Uploading PyPanther Detections

PreviousCreating PyPanther DetectionsNextManaging PyPanther Detections in the Panther Console

Last updated 28 days ago

Was this helpful?

Overview

PyPanther Detections are in closed beta starting with Panther version 1.108. Please share any bug reports and feature requests with your Panther support team.

A PyPanther Detection must be before it is to your Panther instance. It's also recommended to for your PyPanther Detections.

Registering PyPanther Detections

Registering a PyPanther rule means including it in your Panther deployment package.

To register a rule, pass it in to register() in your main.py file. When you run the pypanther upload or test commands, only rules passed in to register() will be uploaded to your Panther instance or tested.

If a previously uploaded rule is not passed in to register() on a subsequent invocation of upload, it will be deleted in your Panther instance.

Registering a rule more than once is not allowed. This means each collection passed into register() must contain unique rules.

It’s not required to register rules used as base rules with so long as you do not want the base rules themselves uploaded into your Panther instance.

# Sample main.py file

from pypanther import register, get_panther_rules

# Register a single rule (that was defined as a class called "BoxNewLogin")
register(BoxNewLogin)

# Register all Panther-managed rules
register(get_panther_rules())

Viewing registered rules

  • To see all rules that are registered given your currently configured repository, run the pypanther list rules CLI command.

Importing instances of Rule

You can use the get_rules() function to easily fetch rules you might want to register in main.py. get_rules() takes in an imported package (folder) or module (file) name, and returns all rules defined in that package or module that inherit the pypanther Rule class.

Example using get_rules():

# main.py
import custom_rules

all_my_rules = get_rules(custom_rules)

register(all_my_rules)

Registering vs. enabling a rule

All rules have an enabled property, which is different from being registered. See the table below for all possible outcomes:

enabled = True
enabled = False

Registered

Uploaded to Panther and enabled. Unit tests are run during testing.

Uploaded to Panther and disabled. Unit tests are run during testing.

Not registered

Not uploaded to Panther. If uploaded previously, deleted. Unit tests are not run during testing.

Not uploaded to Panther. If uploaded previously, deleted. Unit tests are not run during testing.

Testing PyPanther Detections

Defining tests

Define tests for PyPanther Detections by creating instances of the pypanther RuleTest class. Tests are associated with rules by assigning them to a rule’s tests field. Tests can be defined directly within a rule, or separately set to a variable (that's either local or imported).

Each instance of RuleTest must set a name, expected_result, and log. Each test can also optionally define:

  • A mocks field, which takes a list of RuleMocks.

    • These alert function output verification fields should only be included on RuleTests where expected_result=True. Including them on a test where expected_result=False will cause the test to fail. This is because alert functions are only run when a detection returns True.

my_rule_tests: List[RuleTest] = [
    RuleTest(
	name="RuleShouldReturnTrue"
	expected_result=True,
	log={
	    "name":"value"
	}
    ),
    RuleTest(
	name="RuleShouldReturnFalse"
	expected_result=False,
	log={
	    "name":"value"
	}
    )
]

Example: Rule with tests

Note that this rule's tests (defined above the rule class) use mocks, expected_title, expected_dedup, and expected_alert_context.

Example: Rule with tests
from pypanther import LogType, Rule, RuleMock, RuleTest, Severity, panther_managed
from pypanther.helpers.base import deep_get
from pypanther.helpers.default import lookup_aws_account_name
from pypanther.helpers.oss import geoinfo_from_ip_formatted

aws_console_root_login_tests: list[RuleTest] = [
    RuleTest(
        name="Successful Root Login",
        expected_result=True,
        expected_title="AWS root login detected from [111.111.111.111] (111.111.111.111 in SF, California in USA) in account [sample-account]",
        expected_dedup="123456789012-ConsoleLogin-2019-01-01T00:00:00Z",
        expected_alert_context={
            "sourceIPAddress": "111.111.111.111",
            "userIdentityAccountId": "123456789012",
            "userIdentityArn": "arn:aws:iam::123456789012:root",
            "eventTime": "2019-01-01T00:00:00Z",
            "mfaUsed": "No",
        },
        mocks=[
            RuleMock(object_name="geoinfo_from_ip_formatted", return_value="111.111.111.111 in SF, California in USA")
        ],
        log={
            "eventVersion": "1.05",
            "userIdentity": {
                "type": "Root",
                "principalId": "1111",
                "arn": "arn:aws:iam::123456789012:root",
                "accountId": "123456789012",
                "userName": "root",
            },
            "eventTime": "2019-01-01T00:00:00Z",
            "eventSource": "signin.amazonaws.com",
            "eventName": "ConsoleLogin",
            "awsRegion": "us-east-1",
            "sourceIPAddress": "111.111.111.111",
            "userAgent": "Mozilla",
            "requestParameters": None,
            "responseElements": {"ConsoleLogin": "Success"},
            "additionalEventData": {
                "LoginTo": "https://console.aws.amazon.com/console/",
                "MobileVersion": "No",
                "MFAUsed": "No",
            },
            "eventID": "1",
            "eventType": "AwsConsoleSignIn",
            "recipientAccountId": "123456789012",
        },
    ),
    RuleTest(
        name="Non-Login Event",
        expected_result=False,
        mocks=[
            RuleMock(object_name="geoinfo_from_ip_formatted", return_value="111.111.111.111 in SF, California in USA")
        ],
        log={
            "eventVersion": "1.06",
            "userIdentity": {
                "type": "AssumedRole",
                "principalId": "1111:tester",
                "arn": "arn:aws:sts::123456789012:user/tester",
                "accountId": "123456789012",
                "accessKeyId": "1",
                "sessionContext": {
                    "sessionIssuer": {
                        "type": "Role",
                        "principalId": "1111",
                        "arn": "arn:aws:iam::123456789012:user/tester",
                        "accountId": "123456789012",
                        "userName": "tester",
                    },
                    "attributes": {"creationDate": "2019-01-01T00:00:00Z", "mfaAuthenticated": "true"},
                },
            },
            "eventTime": "2019-01-01T00:00:00Z",
            "eventSource": "dynamodb.amazonaws.com",
            "eventName": "DescribeTable",
            "awsRegion": "us-west-2",
            "sourceIPAddress": "111.111.111.111",
            "userAgent": "console.amazonaws.com",
            "requestParameters": {"tableName": "table"},
            "responseElements": None,
            "requestID": "1",
            "eventID": "1",
            "readOnly": True,
            "resources": [{"accountId": "123456789012", "type": "AWS::DynamoDB::Table", "ARN": "arn::::table/table"}],
            "eventType": "AwsApiCall",
            "apiVersion": "2012-08-10",
            "managementEvent": True,
            "recipientAccountId": "123456789012",
        },
    ),
]


@panther_managed
class AWSConsoleRootLogin(Rule):
    id = "AWS.Console.RootLogin-prototype"
    display_name = "Root Console Login"
    dedup_period_minutes = 15
    log_types = [LogType.AWS_CLOUDTRAIL]
    tags = [
        "AWS",
        "Identity & Access Management",
        "Authentication",
        "DemoThreatHunting",
        "Privilege Escalation:Valid Accounts",
    ]
    reports = {"CIS": ["3.6"], "MITRE ATT&CK": ["TA0004:T1078"]}
    default_severity = Severity.HIGH
    default_description = "The root account has been logged into."
    default_runbook = "Investigate the usage of the root account. If this root activity was not authorized, immediately change the root credentials and investigate what actions the root account took.\n"
    default_reference = "https://docs.aws.amazon.com/IAM/latest/UserGuide/id_root-user.html"
    summary_attributes = ["userAgent", "sourceIpAddress", "recipientAccountId", "p_any_aws_arns"]
    tests = aws_console_root_login_tests

    def rule(self, event):
        return (
            event.get("eventName") == "ConsoleLogin"
            and deep_get(event, "userIdentity", "type") == "Root"
            and (deep_get(event, "responseElements", "ConsoleLogin") == "Success")
        )

    def title(self, event):
        ip_address = event.get("sourceIPAddress")
        return f"AWS root login detected from [{ip_address}] ({geoinfo_from_ip_formatted(ip_address)}) in account [{lookup_aws_account_name(event.get('recipientAccountId'))}]"

    def dedup(self, event):
        # Each Root login should generate a unique alert
        return "-".join([event.get("recipientAccountId"), event.get("eventName"), event.get("eventTime")])

    def alert_context(self, event):
        return {
            "sourceIPAddress": event.get("sourceIPAddress"),
            "userIdentityAccountId": deep_get(event, "userIdentity", "accountId"),
            "userIdentityArn": deep_get(event, "userIdentity", "arn"),
            "eventTime": event.get("eventTime"),
            "mfaUsed": deep_get(event, "additionalEventData", "MFAUsed"),
        }

Examples: Mocking entities defined both inside and outside the rule class

You can use RuleMock to define mock values for variables and methods defined either inside or outside of the rule class.

Example: Mocking a variable and function inside the rule class

In the example below, both the INSIDE variable and inside method are defined inside of the rule class, MockTestRule, and mocked in RuleMocks.

from pypanther import LogType, Rule, RuleMock, RuleTest, Severity

class MockTestRule(Rule):
    id = "mock_test_rule"
    display_name = "Mock Test Rule"
    default_description = "This rule provides an example of how to mock objects within a rule in rule tests."
    log_types = [LogType.AZURE_AUDIT]
    default_severity = Severity.INFO
    create_alert = False

    INSIDE: list[str] = []

    def inside(self, event):
        return self.INSIDE

    def rule(self, event):
        return self.inside(event) != []

    tests = [
        RuleTest(
            name="Mock new Test",
            expected_result=True,
            mocks=[
                RuleMock(
                    # Mock the object INSIDE with a new object ["test"]
                    object_name="INSIDE",
                    new=["test"],
                )
            ],
            log={"action": "Blocked", "internalIp": ""},
        ),
        RuleTest(
            name="Mock side_effect Test",
            expected_result=True,
            mocks=[
                RuleMock(
                    # Mock the method inside() with a side effect that checks if the action is "Blocked"
                    object_name="inside",
                    side_effect=lambda e: e.get("action") == "Blocked",
                )
            ],
            log={"action": "Blocked", "internalIp": ""},
        ),
        RuleTest(
            name="Mock return_value Test",
            expected_result=True,
            mocks=[
                RuleMock(
                    # Mock the method inside() with a return value of True
                    object_name="inside",
                    return_value=True,
                )
            ],
            log={"action": "Blocked", "internalIp": ""},
        ),
    ]

Example: Mocking a variable and function defined outside the rule class

In the example below, both the OUTSIDE variable and outside method are defined outside of the rule class, OutsideMockTest, and mocked in RuleMocks.

from pypanther import LogType, Rule, RuleMock, RuleTest, Severity

OUTSIDE = "outside"

def outside():
    return OUTSIDE
    
class OutsideMockTest(Rule):
    id = "outside_mock_test"
    display_name = "Outside Mock Test"
    default_description = (
        "This rule provides an example of how to mock objects outside of the rule class in rule tests."
    )
    log_types = [LogType.AZURE_AUDIT]
    default_severity = Severity.INFO
    create_alert = False

    def rule(self, event):
        return outside() == "outside"

    tests = [
        RuleTest(
            name="Mock outside new",
            expected_result=False,
            mocks=[
                RuleMock(
                    # Mock the object OUTSIDE with a new value "inside"
                    object_name="OUTSIDE",
                    new="inside",
                )
            ],
            log={"action": "Blocked", "internalIp": ""},
        ),
        RuleTest(
            name="Mock outside return_value",
            expected_result=False,
            mocks=[
                RuleMock(
                    # Mock the function outside() with a return value "inside"
                    object_name="outside",
                    return_value="inside",
                )
            ],
            log={"action": "Blocked", "internalIp": ""},
        ),
        RuleTest(
            name="Mock outside side_effect",
            expected_result=False,
            mocks=[
                RuleMock(
                    # Mock the function outside() with a side effect that returns "inside"
                    object_name="outside",
                    side_effect=lambda: "inside",
                )
            ],
            log={"action": "Blocked", "internalIp": ""},
        ),
    ]

Running tests

To run all tests defined for your PyPanther Detections, run:

$ pypanther test

To run only a subset of tests, filter the detections for which tests are run by using a filter flag with test, such as --id or --log-types. See a full list of filter flags by running pypanther test --help.

The test command:

  • Only tests those detections passed into register()

  • Skips tests for Panther-managed rules

If any rules fail a test, the error will print next to the rule name that was tested:

MyRuleNameI:
   FAIL: my test name
     - Expected rule() to return 'True', but got 'False'

Testing custom helper functions and data fixtures

Currently, pypanther will not run these tests during pypanther test, but they can be run locally or as part of your CI/CD workflow.

Example: using pytest to test a custom function

import pandas as pd

# A sample list of account data you may use with your detections
_account_data = [
        {"account_id": "012345678901", "account_age_days": 1543, "environment": "prod"},
        {"account_id": "112345678901", "account_age_days": 1753, "environment": "staging"},
        ...
        {"account_id": "756239201432", "account_age_days": 32, "environment": "development"}
        ]

# Load account data into a pandas dataframe for easy access
AWS_ACCOUNTS = pd.DataFrame.from_dict(_account_data) 

def is_prod_aws_account(account_id: str) -> bool:
    """
    Checks the AWS_ACCOUNTS dataframe to see if an account_id is in production
    """
    return AWS_ACCOUNTS.loc[AWS_ACCOUNTS['account_id'] == account_id, "environment"] == "prod"

Given this function, there are a few ways in which you may want to test both the data fixture (AWS_ACCOUNTS) itself, as well as the function is_prod_aws_account(). For instance:

  • To verify that the AWS_ACCOUNTS data fixture:

    • Has a certain number of rows

    • Has a certain required field

  • To verify that certain account IDs are included in the prod list (and others are not)

To test these characteristics using pytest, you would add the following functions (all with the test_ prefix):

def test_accounts_metadata_is_correct_size():
    """
    Ensure that the account list has 100 rows.
    """
    assert AWS_ACCOUNTS.shape[0] == 100

def test_critical_list_is_marked_prod():
    """
    Ensure that specific accounts are marked as production while other ones are not
    """
    expected_prod_list = ["012345678901", "012345678902", "012345678903"]
    for account_id in expected_prod_list:
        assert is_prod_aws_account(account_id)
    
    expected_non_prod_list = ["012345678905", "012345678906", "012345678907"]
    for account_id in expected_non_prod_list:
        assert not is_prod_aws_account(account_id)

def test_accounts_metadata_has_account_age_field():
    """
    Ensure the metadata data fixture has a field we may require for another helper function
    """
    assert "account_age_days" in AWS_ACCOUNTS.columns

After you define these tests, you can invoke them by running pytest from your command line.

Uploading PyPanther Detections to Panther

In order to use the pypanther upload functionality, it must first be enabled for you. If you would like to upload detections, please reach out to your Panther Support team.

$ pypanther upload

You can see all upload options by running pypanther upload -h, but may find the following options particularly useful:

  • --verbose: Generates verbose output, which includes a list of tests by detection (and their pass/fail statuses), a list of registered detections, and a list of included files

  • --dry-run: Do not upload, but show a summary of the changes that will be applied in the next upload

  • --output {text, json}: Prints output in the provided format

    • text is the default value, but json can be useful if you plan to port the output into another workflow

Sample output for pypanther upload --verbose --output json
{
    "result": "UPLOAD_SUCCEEDED",
    "upload_statistics": {
      "rules": {
        "new": 0,
        "total": 569,
        "modified": 569,
        "deleted": 0
      },
      "schemas": {
        "new": 0,
        "total": 0,
        "modified": 0,
        "deleted": 0
      }
    },
    "tests": {
      "test_results": {
        // Only a subset of rule tests are shown below, for conciseness
        "AWS.ECR.EVENTS": [
          {
            "test_name": "Authorized account, unauthorized region",
            "passed": true,
            "exceptions": [],
            "failed_results": []
          },
          {
            "test_name": "Unauthorized account",
            "passed": true,
            "exceptions": [],
            "failed_results": []
          },
          {
            "test_name": "Authorized account",
            "passed": true,
            "exceptions": [],
            "failed_results": []
          }
        ],
        "Osquery.Mac.OSXAttacksKeyboardEvents": [
          {
            "test_name": "App running on Desktop that is watching keyboard events",
            "passed": true,
            "exceptions": [],
            "failed_results": []
          },
          {
            "test_name": "App is running from approved path",
            "passed": true,
            "exceptions": [],
            "failed_results": []
          },
          {
            "test_name": "Unrelated query does not alert",
            "passed": true,
            "exceptions": [],
            "failed_results": []
          }
        ],
        "Dropbox.User.Disabled.2FA": [
          {
            "test_name": "2FA Disabled",
            "passed": true,
            "exceptions": [],
            "failed_results": []
          },
          {
            "test_name": "Other",
            "passed": true,
            "exceptions": [],
            "failed_results": []
          }
        ],
        "Push.Security.Authorized.IdP.Login": [
          {
            "test_name": "Google Workspace Password Login",
            "passed": true,
            "exceptions": [],
            "failed_results": []
          },
          {
            "test_name": "Microsoft 365 OIDC Login",
            "passed": true,
            "exceptions": [],
            "failed_results": []
          },
          {
            "test_name": "Okta Login",
            "passed": true,
            "exceptions": [],
            "failed_results": []
          },
          {
            "test_name": "Password Login",
            "passed": true,
            "exceptions": [],
            "failed_results": []
          }
        ],
        "GSuite.GroupBannedUser": [
          {
            "test_name": "User Added",
            "passed": true,
            "exceptions": [],
            "failed_results": []
          },
          {
            "test_name": "User Banned from Group",
            "passed": true,
            "exceptions": [],
            "failed_results": []
          }
        ],
        "AWS.S3.ServerAccess.Error": [
          {
            "test_name": "Amazon Access Error",
            "passed": true,
            "exceptions": [],
            "failed_results": []
          },
          {
            "test_name": "Access Error",
            "passed": true,
            "exceptions": [],
            "failed_results": []
          },
          {
            "test_name": "403 on HEAD.BUCKET",
            "passed": true,
            "exceptions": [],
            "failed_results": []
          },
          {
            "test_name": "Internal Server Error",
            "passed": true,
            "exceptions": [],
            "failed_results": []
          }
        ],
        "OneLogin.PasswordAccess": [
          {
            "test_name": "User accessed their own password",
            "passed": true,
            "exceptions": [],
            "failed_results": []
          },
          {
            "test_name": "User accessed another user's password",
            "passed": true,
            "exceptions": [],
            "failed_results": []
          }
        ],
        "Push.Security.New.App.Detected": [
          {
            "test_name": "New App",
            "passed": true,
            "exceptions": [],
            "failed_results": []
          },
          {
            "test_name": "App Updated",
            "passed": true,
            "exceptions": [],
            "failed_results": []
          }
        ],
        "GCP.VPC.Flow.Logs.Disabled": [
          {
            "test_name": "Disable Flow Logs Event",
            "passed": true,
            "exceptions": [],
            "failed_results": []
          },
          {
            "test_name": "Enable Flow Logs Event",
            "passed": true,
            "exceptions": [],
            "failed_results": []
          }
        ],
        "Duo.Admin.Bypass.Code.Viewed": [
          {
            "test_name": "Bypass View",
            "passed": true,
            "exceptions": [],
            "failed_results": []
          },
          {
            "test_name": "Bypass Create",
            "passed": true,
            "exceptions": [],
            "failed_results": []
          }
        ],
        "Netskope.ManyDeletes": [
          {
            "test_name": "True positive",
            "passed": true,
            "exceptions": [],
            "failed_results": []
          },
          {
            "test_name": "True negative",
            "passed": true,
            "exceptions": [],
            "failed_results": []
          }
        ],
        "Slack.AuditLogs.UserPrivilegeEscalation": [
          {
            "test_name": "Owner Transferred",
            "passed": true,
            "exceptions": [],
            "failed_results": []
          },
          {
            "test_name": "Permissions Assigned",
            "passed": true,
            "exceptions": [],
            "failed_results": []
          },
          {
            "test_name": "Role Changed to Admin",
            "passed": true,
            "exceptions": [],
            "failed_results": []
          },
          {
            "test_name": "Role Changed to Owner",
            "passed": true,
            "exceptions": [],
            "failed_results": []
          },
          {
            "test_name": "User Logout",
            "passed": true,
            "exceptions": [],
            "failed_results": []
          }
        ],
        "Dropbox.External.Share": [
          {
            "test_name": "Domain in Allowlist",
            "passed": true,
            "exceptions": [],
            "failed_results": []
          },
          {
            "test_name": "external share",
            "passed": true,
            "exceptions": [],
            "failed_results": []
          }
        ],
        "Slack.AuditLogs.AppAccessExpanded": [
          {
            "test_name": "App Scopes Expanded",
            "passed": true,
            "exceptions": [],
            "failed_results": []
          },
          {
            "test_name": "App Resources Added",
            "passed": true,
            "exceptions": [],
            "failed_results": []
          },
          {
            "test_name": "App Resources Granted",
            "passed": true,
            "exceptions": [],
            "failed_results": []
          },
          {
            "test_name": "Bot Token Upgraded",
            "passed": true,
            "exceptions": [],
            "failed_results": []
          },
          {
            "test_name": "User Logout",
            "passed": true,
            "exceptions": [],
            "failed_results": []
          }
        ]
      },
      "failed_tests_summary": [],
      "test_summary": {
        "skipped_rules": 96,
        "passed_rules": 464,
        "failed_rules": 0,
        "total_rules": 560,
        "passed_tests": 1373,
        "failed_tests": 0,
        "total_tests": 1373
      }
    },
    "registered_rules": [
      "AWS.ECR.EVENTS",
      "Osquery.Mac.OSXAttacksKeyboardEvents",
      "Dropbox.User.Disabled.2FA",
      "Push.Security.Authorized.IdP.Login",
      "GSuite.GroupBannedUser",
      "GCP.IAM.serviceAccounts.signBlob",
      "Okta.App.Unauthorized.Access.Attempt",
      "GCP.K8S.Service.Type.NodePort.Deployed",
      "Snyk.Project.Settings",
      "Notion.SharingSettingsUpdated",
      "GCP.UnusedRegions",
      "AWS.User.Login.Profile.Modified",
      "aws_cloudtrail_security_group_change_ingress_egress",
      "Notion.LoginFromBlockedIP",
      "github_push_protection_bypass_detected",
      "Azure.Audit.ManyFailedSignIns",
      "AWS.EC2.ManualSecurityGroupChange",
      "OneLogin.HighRiskFailedLogin",
      "GCP.Destructive.Queries",
      "Atlassian.User.LoggedInAsUser",
      "AWS.EC2.VPCModified",
      "Zoom.New.Meeting.Passcode.Required.Disabled",
      "Slack.AuditLogs.OrgCreated",
      "Tines.Story.Jobs.Clearance",
      "DUO.User.BypassCode.Used",
      "GCP.IAM.CustomRoleChanges",
      "GSuite.Workspace.GmailDefaultRoutingRuleModified",
      "Box.Access.Granted",
      "CarbonBlack.Audit.Admin.Grant",
      "Github.Repo.Created",
      "gcp_breakglass_container_workload_deployed",
      "AWS.RDS.PublicRestore",
      "AWS.RDS.ManualSnapshotCreated",
      "Crowdstrike.DNS.Request",
      "Crowdstrike.Unusual.Parent.Child.Processes",
      "AWS.GuardDuty.MediumSeverityFinding",
      "Tailscale.HTTPS.Disabled",
      "okta_fastpass_phishing_detection",
      "Teleport.AuthErrors",
      "Teleport.SuspiciousCommands",
      "Okta.Identity.Provider.SignIn",
      "Decoy.Secret.Accessed",
      "AWS.Root.Activity",
      "aws_rds_public_db_restore",
      "okta_user_account_locked_out",
      "gcp_service_account_disabled_or_deleted",
      "aws_efs_fileshare_mount_modified_or_deleted",
      "Asana.Team.Privacy.Public",
      "GSuite.LeakedPassword",
      "GCP.IAM.serviceAccounts.signJwt.Privilege.Escalation",
      "AWS.ECR.CRUD",
      "Standard.MaliciousSSODNSLookup",
      "AWS.Console.LoginWithoutSAML",
      "Notion.TeamspaceOwnerAdded",
      "GCP.Workload.Identity.Pool.Created.or.Updated",
      "Retrieve.SSO.access.token",
      "Snyk.Role.Change",
      "Okta.Refresh.Access.Token.Reuse",
      "github_push_protection_disabled",
      "Azure.Audit.LegacyAuth",
      "AWS.CloudTrail.Created",
      "OneLogin.HighRiskLogin",
      "Push.Security.MFA.Method.Changed",
      "Duo.Admin.Bypass.Code.Created",
      "MongoDB.External.UserInvited.NoConfig",
      "Osquery.Mac.UnwantedChromeExtensions",
      "GitHub.Branch.PolicyOverride",
      "Slack.AuditLogs.OrgDeleted",
      "Teleport.CompanyDomainLoginWithoutSAML",
      "aws_cloudtrail_security_group_change_loadbalancer",
      "Tines.Team.Destruction",
      "Box.Shield.Anomalous.Download",
      "CarbonBlack.Audit.API.Key.Created.Retrieved",
      "GitHub.Repo.HookModified",
      "GSuite.Workspace.GmailPredeliveryScanningDisabled",
      "gcp_bucket_enumeration",
      "GCP.Workforce.Pool.Created.or.Updated",
      "Microsoft365.Brute.Force.Login.by.User",
      "GCP.User.Added.to.IAP.Protected.Service",
      "Okta.PotentiallyStolenSession",
      "AppOmni.Alert.Passthrough",
      "AWS.S3.ServerAccess.IPWhitelist",
      "Auth0.CIC.Credential.Stuffing",
      "AWS.CloudTrail.RootAccessKeyCreated",
      "okta_identity_provider_created",
      "AWS.CloudTrail.SecurityConfigurationChange",
      "aws_root_account_usage",
      "AWS.IPSet.Modified",
      "aws_eks_cluster_created_or_deleted",
      "AWS.CloudTrail.Account.Discovery",
      "Crowdstrike.RealTimeResponse.Session",
      "Crowdstrike.Macos.Plutil.Usage",
      "Osquery.OSSECRootkitDetected",
      "GCP.Log.Bucket.Or.Sink.Deleted",
      "Google.Workspace.Admin.Custom.Role",
      "Notion.Audit.Log.Exported",
      "AWS.RDS.SnapshotShared",
      "Okta.Group.Admin.Role.Assigned",
      "Slack.AuditLogs.AppRemoved",
      "AWS.S3.ServerAccess.Error",
      "AWS.WAF.Disassociation",
      "github_repo_or_org_transferred",
      "OneLogin.PasswordAccess",
      "Push.Security.New.App.Detected",
      "GCP.VPC.Flow.Logs.Disabled",
      "Duo.Admin.Bypass.Code.Viewed",
      "MongoDB.Identity.Provider.Activity",
      "Asana.Service.Account.Created",
      "GCP.Firewall.Rule.Created",
      "DUO.User.Endpoint.Failure",
      "Standard.MFADisabled",
      "Slack.AuditLogs.PassthroughAnomaly",
      "Teleport.LocalUserLoginWithoutMFA",
      "aws_cloudtrail_security_group_change_rds",
      "GCP.Inbound.SSO.Profile.Created",
      "Decoy.Systems.Manager.Parameter.Accessed",
      "Tines.Tenant.AuthToken",
      "Box.Event.Triggered.Externally",
      "Snyk.System.ExternalAccess",
      "CarbonBlack.Audit.Data.Forwarder.Stopped",
      "AWS.EC2.Monitoring",
      "GSuite.Workspace.GmailSecuritySandboxDisabled",
      "GSuite.LoginType",
      "Okta.Rate.Limits",
      "AWS.S3.BucketDeleted",
      "gcp_service_account_modified",
      "Auth0.Integration.Installed",
      "okta_mfa_reset_or_deactivated",
      "gcp_bucket_modified_or_deleted",
      "Github.Repo.VisibilityChange",
      "GCP.GKE.Kubernetes.Cron.Job.Created.Or.Modified",
      "Slack.AuditLogs.ApplicationDoS",
      "aws_elasticache_security_group_created",
      "AWS.IAM.AccessKeyCompromised",
      "Push.Security.New.SaaS.Account.Created",
      "Teleport.CreateUserAccounts",
      "AWS.CloudTrail.IAMAnythingChanged",
      "Snyk.ServiceAccount.Change",
      "Auth0.Custom.Role.Created",
      "aws_route_53_domain_transferred_lock_disabled",
      "Notion.Workspace.Exported",
      "Zoom.PasscodeDisabled",
      "github_secret_scanning_feature_disabled",
      "Role.Assumed.by.AWS.Service",
      "OneLogin.PasswordChanged",
      "Duo.Admin.Create.Admin",
      "Osquery.OutdatedAgent",
      "MongoDB.Logging.Toggled",
      "GitHub.Repo.InitialAccess",
      "GitHub.Action.Failed",
      "Okta.SSO.to.AWS",
      "GCP.Access.Attempts.Violating.VPC.Service.Controls",
      "Crowdstrike.FDR.LOLBAS",
      "Slack.AuditLogs.PotentiallyMaliciousFileShared",
      "Google.Workspace.Advanced.Protection.Program",
      "aws_cloudtrail_ssm_malicious_usage",
      "CarbonBlack.Audit.Flagged",
      "Okta.Identity.Provider.Created.Modified",
      "Zoom.Sign.In.Method.Modified",
      "okta_user_created",
      "GSuite.DeviceCompromise",
      "GSuite.Workspace.PasswordEnforceStrongDisabled",
      "AWS.CloudTrail.UserAccessKeyAuth",
      "okta_network_zone_deactivated_or_deleted",
      "gcp_dlp_re_identifies_sensitive_information",
      "Wiz.Alert.Passthrough",
      "Crowdstrike.Base64EncodedArgs",
      "gcp_sql_database_modified_or_deleted",
      "Slack.AuditLogs.DLPModified",
      "gcp_access_policy_deleted",
      "Asana.Workspace.Default.Session.Duration.Never",
      "Push.Security.Open.Security.Finding",
      "AWS.S3.BucketPolicyModified",
      "Microsoft365.External.Document.Sharing",
      "AWS.DNS.Crypto.Domain",
      "AWS.S3.ServerAccess.Unauthenticated",
      "Crowdstrike.WMI.Query.Detection",
      "Role.Assumed.by.User",
      "OneLogin.AuthFactorRemoved",
      "AWS.KMS.CustomerManagedKeyLoss",
      "Duo.Admin.Lockout",
      "MongoDB.org.Membership.Restriction.Disabled",
      "aws_route_53_domain_transferred_to_another_account",
      "OneLogin.ActiveLoginActivity",
      "GCP.BigQuery.Large.Scan",
      "Slack.AuditLogs.PrivateChannelMadePublic",
      "Google.Workspace.Apps.Marketplace.Allowlist",
      "aws_config_disable_recording",
      "GCP.Logging.Settings.Modified",
      "Notion.SAML.SSO.Configuration.Changed",
      "AWS.EC2.NetworkACLModified",
      "CarbonBlack.Audit.User.Added.Outside.Org",
      "github_self_hosted_runner_changes_detected",
      "AWS.CloudTrail.LoginProfileCreatedOrModified",
      "Zoom.Sign.In.Requirements.Changed",
      "GCP.GCS.IAMChanges",
      "Teleport.LockCreated",
      "GSuite.DeviceUnlockFailure",
      "okta_user_session_start_via_anonymised_proxy",
      "Standard.DNSBase64",
      "GitHub.Advanced.Security.Change",
      "Osquery.UnsupportedMacOS",
      "Snyk.System.PolicySetting",
      "okta_new_behaviours_admin_console",
      "aws_elasticache_security_group_modified_or_deleted",
      "gcp_dns_zone_modified_or_deleted",
      "Zendesk.MobileAppAccessUpdated",
      "Slack.AuditLogs.EKMConfigChanged",
      "AWS.CloudTrail.Password.Policy.Discovery",
      "Asana.Workspace.Email.Domain.Added",
      "GSuite.Workspace.PasswordReuseEnabled",
      "Push.Security.Phishable.MFA.Method",
      "GCP.Firewall.Rule.Modified",
      "AWS.Suspicious.SAML.Activity",
      "GCP.K8s.ExecIntoPod",
      "AWS.VPC.HealthyLogStatus",
      "AWS.S3.ServerAccess.Insecure",
      "gcp_vpn_tunnel_modified_or_deleted",
      "Github.Repository.Transfer",
      "Crowdstrike.API.Key.Created",
      "OneLogin.ThresholdAccountsDeleted",
      "DUO.Admin.Action.MarkedFraudulent",
      "MongoDB.User.Created.Or.Deleted",
      "Okta.Support.Reset",
      "aws_s3_data_management_tampering",
      "Snyk.System.SSO",
      "Auth0.MFA.Factor.Setting.Enabled",
      "GCP.Cloud.Run.Service.Created",
      "Slack.AuditLogs.UserPrivilegeChangedToUser",
      "Google.Workspace.Apps.Marketplace.New.Domain.Application",
      "GCP.Logging.Sink.Modified",
      "Notion.Workspace.Public.Page.Added",
      "AWS.EC2.RouteTableModified",
      "Zendesk.NewAPIToken",
      "CarbonBlack.AlertV2.Passthrough",
      "github_ssh_certificate_config_changed",
      "AWS.LAMBDA.CRUD",
      "Crowdstrike.Remote.Access.Tool.Execution",
      "Zoom.Two.Factor.Authentication.Disabled",
      "GSuite.DeviceSuspiciousActivity",
      "Box.Item.Shared.Externally",
      "GitHub.Branch.ProtectionDisabled",
      "Osquery.SSHListener",
      "okta_password_in_alternateid_field",
      "Notion.LoginFromNewLocation",
      "aws_console_getsignintoken",
      "Auth0.MFA.Policy.Disabled",
      "GCP.K8s.IOC.Activity",
      "AWS.VPC.InboundPortWhitelist",
      "aws_enum_buckets",
      "Okta.Login.Without.Push.Marker",
      "Slack.AuditLogs.EKMSlackbotUnenrolled",
      "AWS.Console.LoginWithoutMFA",
      "Connection.to.Embargoed.Country",
      "Asana.Workspace.Form.Link.Auth.Requirement.Disabled",
      "Standard.NewAWSAccountCreated",
      "Push.Security.Phishing.Attack",
      "Tailscale.Machine.Approval.Requirements.Disabled",
      "gcp_firewall_rule_modified_or_deleted",
      "github_delete_action_invoked",
      "Microsoft365.MFA.Disabled",
      "Teleport.LongLivedCerts",
      "OneLogin.ThresholdAccountsModified",
      "AWS.CloudTrail.Stopped",
      "Duo.Admin.MFA.Restrictions.Updated",
      "AWS.Unsuccessful.MFA.attempt",
      "Okta.Login.Success",
      "Sign-in.with.AWS.CLI.prompt",
      "AWS.SecurityHub.Finding.Evasion",
      "Box.Malicious.Content",
      "Osquery.SuspiciousCron",
      "aws_securityhub_finding_evasion",
      "GCP.GCS.Public",
      "Slack.AuditLogs.ServiceOwnerTransferred",
      "Google.Workspace.Apps.New.Mobile.App.Installed",
      "GSuite.Workspace.TrustedDomainsAllowlist",
      "Okta.Support.Access",
      "Zendesk.AccountOwnerChanged",
      "AWS.Console.RootLogin",
      "GCP.Permissions.Granted.to.Create.or.Manage.Service.Account.Key",
      "CiscoUmbrella.DNS.Blocked",
      "Tailscale.Magic.DNS.Disabled",
      "Crowdstrike.API.Key.Deleted",
      "GSuite.Rule",
      "MongoDB.User.Roles.Changed",
      "Okta.ThreatInsight.Security.Threat.Detected",
      "GitHub.Org.AuthChange",
      "GCP.Cloud.Run.Set.IAM.Policy",
      "aws_delete_identity",
      "Auth0.MFA.Policy.Enabled",
      "GCP.K8s.New.Daemonset.Deployed",
      "AWS.VPC.InboundPortBlacklist",
      "GitHub.Secret.Scanning.Alert.Created",
      "Osquery.Linux.AWSCommandExecuted",
      "aws_guardduty_disruption",
      "GSuite.AdvancedProtection",
      "okta_admin_activity_from_proxy_query",
      "AWS.EC2.SecurityGroupModified",
      "Slack.AuditLogs.EKMUnenrolled",
      "Snyk.User.Management",
      "Asana.Workspace.Guest.Invite.Permissions.Anyone",
      "AWS.ConfigService.Created",
      "Zoom.User.Promoted.to.Privileged.Role",
      "Notion.Many.Pages.Deleted",
      "GCP.IAM.CorporateEmail",
      "github_disable_high_risk_configuration",
      "Teleport.NetworkScanning",
      "GCP.Privilege.Escalation.By.Deployments.Create",
      "Microsoft365.Exchange.External.Forwarding",
      "okta_policy_modified_or_deleted",
      "OneLogin.UnauthorizedAccess",
      "Duo.Admin.New.Admin.API.App.Integration",
      "Box.New.Login",
      "Panther.Detection.Deleted",
      "aws_snapshot_backup_exfiltration",
      "GCP.Cloud.Storage.Buckets.Modified.Or.Deleted",
      "Push.Security.Unauthorized.IdP.Login",
      "Slack.AuditLogs.SSOSettingsChanged",
      "AWS.S3.ServerAccess.UnknownRequester",
      "Okta.Global.MFA.Disabled",
      "Zendesk.SensitiveDataRedactionOff",
      "GSuite.Drive.ExternalFileShare",
      "Crowdstrike.Macos.Add.Trusted.Cert",
      "gcp_full_network_traffic_packet_capture",
      "CiscoUmbrella.DNS.FuzzyMatching",
      "AWS.Macie.Evasion",
      "Teleport.RoleCreated",
      "Tines.Actions.DisabledChanges",
      "Standard.AdminRoleAssigned",
      "GSuite.SuspiciousLogins",
      "Netskope.AdminLoggedOutLoginFailures",
      "Okta.New.Behavior.Accessing.Admin.Console",
      "GitHub.Org.IpAllowlist",
      "aws_disable_bucket_versioning",
      "Auth0.MFA.Risk.Assessment.Enabled",
      "GCP.K8s.Pod.Attached.To.Node.Host.Network",
      "AWS.VPC.UnapprovedOutboundDNS",
      "Osquery.Linux.LoginFromNonOffice",
      "aws_iam_backdoor_users_keys",
      "AWS.EC2.Startup.Script.Change",
      "okta_admin_role_assigned_to_user_or_group",
      "Microsoft.Graph.Passthrough",
      "Crowdstrike.Credential.Dumping.Tool",
      "Asana.Workspace.New.Admin",
      "Dropbox.Admin.sign.in.as.Session",
      "Okta.User.Account.Locked",
      "Notion.Many.Pages.Exported",
      "AWS.ConfigService.DisabledDeleted",
      "aws_attached_malicious_lambda_layer",
      "GCP.CloudBuild.Potential.Privilege.Escalation",
      "github_disabled_outdated_dependency_or_vulnerability",
      "GSuite.CalendarMadePublic",
      "Slack.AuditLogs.IDPConfigurationChanged",
      "GSuite.DriveOverlyVisible",
      "okta_policy_rule_modified_or_deleted",
      "AWS.CloudTrail.UnauthorizedAPICall",
      "GCP.Service.Account.Access.Denied",
      "OneLogin.UserAccountLocked",
      "Duo.Admin.Policy.Updated",
      "Netskope.AdminUserChange",
      "Amazon.EKS.Audit.Multiple403",
      "Box.Content.Workflow.Policy.Violation",
      "Panther.SAML.Modified",
      "aws_sso_idp_change",
      "Auth0.MFA.Risk.Assessment.Disabled",
      "Snyk.Misc.Settings",
      "Crowdstrike.Reverse.Shell.Tool.Executed",
      "AWS.EC2.Vulnerable.XZ.Image.Launched",
      "GitHub.Team.Modified",
      "Zendesk.UserAssumption",
      "Tines.Custom.CertificateAuthority",
      "GSuite.TwoStepVerification",
      "GitHub.Org.Moderators.Add",
      "AWS.Console.Login",
      "Auth0.User.Invitation.Created",
      "GCP.IAM.OrgFolderIAMChanges",
      "aws_iam_s3browser_loginprofile_creation",
      "Osquery.Linux.Mac.VulnerableXZliblzma",
      "Okta.Anonymizing.VPN.Login",
      "Decoy.DynamoDB.Accessed",
      "gcp_kubernetes_admission_controller",
      "okta_admin_role_assignment_created",
      "CiscoUmbrella.DNS.Suspicious",
      "Okta.User.MFA.Factor.Suspend",
      "Notion.PagePerms.APIPermsChanged",
      "Okta.Org2org.Creation.Modification",
      "Salesforce.Admin.Login.As.User",
      "aws_cloudtrail_disable_logging",
      "AWS.Software.Discovery",
      "aws_ec2_disable_encryption",
      "AWS.CloudTrail.CodebuildProjectMadePublic",
      "AWS.CloudTrail.SnapshotMadePublic",
      "github_fork_private_repos_enabled_or_cleared",
      "AWS.Console.RootLoginFailed",
      "Asana.Workspace.Org.Export",
      "GSuite.DocOwnershipTransfer",
      "Slack.AuditLogs.InformationBarrierModified",
      "Okta.AdminRoleAssigned",
      "okta_security_threat_detected",
      "GCP.SQL.ConfigChanges",
      "OneLogin.UserAssumption",
      "Duo.Admin.SSO.SAML.Requirement.Disabled",
      "GCP.Cloudfunctions.Functions.Create",
      "Netskope.ManyDeletes",
      "GCP.K8S.Pot.Create.Or.Modify.Host.Path.Volume.Mount",
      "Standard.BruteForceByIP",
      "Box.Shield.Suspicious.Alert",
      "Teleport.RootLogin",
      "Slack.AuditLogs.UserPrivilegeEscalation",
      "AWS.CloudTrail.IAMCompromisedKeyQuarantine",
      "Dropbox.External.Share",
      "GCP.iam.roles.update.Privilege.Escalation",
      "AWS.IAMUser.ReconAccessDenied",
      "Auth0.Post.Login.Action.Flow",
      "GitHub.User.AccessKeyCreated",
      "Zendesk.UserRoleChanged",
      "MongoDB.2FA.Disabled",
      "AWS.EC2.StopInstances",
      "aws_sts_assumerole_misuse",
      "Tines.Enqueued.Retrying.Job.Destruction",
      "GSuite.UserSuspended",
      "GCP.Service.Account.or.Keys.Created",
      "GitHub.Org.Modified",
      "Push.Security.App.Banner.Acknowledged",
      "Okta.User.MFA.Reset.Single",
      "Osquery.Mac.ApplicationFirewallSettings",
      "okta_api_token_created",
      "GSuite.DriveVisibilityChanged",
      "AWS.Console.Sign-In",
      "aws_iam_s3browser_templated_s3_bucket_policy_creation",
      "aws_cloudtrail_imds_malicious_usage",
      "aws_ec2_startup_script_change",
      "Okta.PasswordAccess",
      "AWS.Modify.Cloud.Compute.Infrastructure",
      "gcp_kubernetes_cronjob",
      "github_new_org_member",
      "GCP.iam.serviceAccountKeys.create",
      "Slack.AuditLogs.IntuneMDMDisabled",
      "MongoDB.Access.Allowed.From.Anywhere",
      "okta_suspicious_activity_enduser_report",
      "Crowdstrike.Cryptomining.Tools",
      "OnePassword.Lut.Sensitive.Item",
      "Notion.PagePerms.GuestPermsChanged",
      "Duo.Admin.User.MFA.Bypass.Enabled",
      "AWS.CloudTrail.IAMEntityCreatedWithoutCloudFormation",
      "GCP.Cloudfunctions.Functions.Update",
      "GCP.K8s.Pod.Using.Host.PID.Namespace",
      "Netskope.NetskopePersonnelActivity",
      "SentinelOne.Threats",
      "Box.Untrusted.Device",
      "Panther.Sensitive.Role",
      "Teleport.SAMLCreated",
      "AWS.IAM.PolicyModified",
      "Decoy.IAM.Assumed",
      "GSuite.ExternalMailForwarding",
      "Dropbox.Linked.Team.Application.Added",
      "Asana.Workspace.Password.Requirements.Simple",
      "GitHub.User.RoleUpdated",
      "Zendesk.UserSuspension",
      "Amazon.EKS.Audit.SystemNamespaceFromPublicIP",
      "Tines.Global.Resource.Destruction",
      "GCP.serviceusage.apiKeys.create.Privilege.Escalation",
      "Github.Organization.App.Integration.Installed",
      "AWS.CloudTrail.IAMAssumeRoleBlacklistIgnored",
      "AWS.EC2.EBS.Encryption.Disabled",
      "Osquery.Mac.AutoUpdateEnabled",
      "aws_sts_getsessiontoken_misuse",
      "okta_api_token_revoked",
      "Cloudflare.Firewall.L7DDoS",
      "Okta.APIKeyCreated",
      "MongoDB.Alerting.Disabled.Or.Deleted",
      "OnePassword.Sensitive.Item",
      "Snyk.Org.Settings",
      "aws_iam_s3browser_user_or_accesskey_creation",
      "SentinelOne.Alert.Passthrough",
      "aws_cloudtrail_new_acl_entries",
      "aws_ec2_vm_export_failure",
      "github_new_secret_created",
      "GSuite.GoogleAccess",
      "Auth0.User.Joined.Tenant",
      "Crowdstrike.Systemlog.Tampering",
      "okta_unauthorized_access_to_app",
      "Crowdstrike.Detection.passthrough",
      "Notion.PageSharedToWeb",
      "DUO.User.Action.Fraudulent",
      "AWS.UnusedRegion",
      "GCP.compute.instances.create.Privilege.Escalation",
      "Netskope.UnauthorizedAPICalls",
      "Box.Large.Number.Downloads",
      "GCP.Access.Attempts.Violating.IAP.Access.Controls",
      "Teleport.SAMLLoginWithoutCompanyDomain",
      "Okta.User.MFA.Reset.All",
      "AWS.RDS.MasterPasswordUpdated",
      "Okta.Password.Extraction.via.SCIM",
      "Dropbox.Ownership.Transfer",
      "Asana.Workspace.Require.App.Approvals.Disabled",
      "AWS.CloudTrail.ResourceMadePublic",
      "GitLab.Audit.Password.Reset.Multiple.Emails",
      "Zoom.All.Meetings.Secured.With.One.Option.Disabled",
      "Slack.AuditLogs.LegalHoldPolicyModified",
      "Tines.SSO.Settings",
      "Crowdstrike.Macos.Osascript.Administrator",
      "Github.Public.Repository.Created",
      "AWS.IAM.Group.Read.Only.Events",
      "Osquery.Mac.OSXAttacks",
      "AWS.EC2.Traffic.Mirroring",
      "okta_application_modified_or_deleted",
      "Okta.APIKeyRevoked",
      "Snyk.OU.Change",
      "GSuite.Workspace.CalendarExternalSharingSetting",
      "MongoDB.External.UserInvited",
      "GCP.Storage.Hmac.Keys.Create",
      "OnePassword.Unusual.Client",
      "aws_passed_role_to_glue_development_endpoint",
      "GCP.DNS.Zone.Modified.or.Deleted",
      "gcp_kubernetes_rolebinding",
      "aws_cloudtrail_new_route_added",
      "aws_ecs_task_definition_cred_endpoint_query",
      "aws_susp_saml_activity",
      "AWS.EC2.GatewayModified",
      "AWS.CloudTrail.NetworkACLPermissiveEntry",
      "Okta.User.Reported.Suspicious.Activity",
      "Panther.User.Modified",
      "GCP.IAM.serviceAccounts.getAccessToken.Privilege.Escalation",
      "AWS.GuardDuty.HighSeverityFinding",
      "GSuite.GovernmentBackedAttack",
      "AWS.CloudTrail.AMIModifiedForPublicAccess",
      "Decoy.S3.Accessed",
      "Notion.Workspace.SCIM.Token.Generated",
      "DUO.User.Denied.AnomalousPush",
      "Box.Large.Number.Permission.Updates",
      "Slack.AuditLogs.AppAdded",
      "github_outside_collaborator_detected",
      "Teleport.ScheduledJobs",
      "Standard.NewUserAccountCreated",
      "Okta.Phishing.Attempt.Blocked.FastPass",
      "GCP.K8S.Privileged.Pod.Created",
      "Asana.Workspace.SAML.Optional",
      "MongoDB.Atlas.ApiKeyCreated",
      "GitLab.Production.Password.Reset.Multiple.Emails",
      "Standard.ImpossibleTravel.Login",
      "Duo.Admin.App.Integration.Secret.Key.Viewed",
      "Zoom.Automatic.Sign.Out.Disabled",
      "Slack.AuditLogs.MFASettingsChanged",
      "GSuite.Workspace.DataExportCreated",
      "Tines.Story.Items.Destruction",
      "AWS.IAM.CredentialsUpdated",
      "Azure.Audit.RiskLevelPassthrough",
      "Notion.AccountChangedAfterLogin",
      "Github.Repo.CollaboratorChange",
      "AWS.IAM.Backdoor.User.Keys",
      "AWS.CloudTrail.RootPasswordChanged",
      "AWS.GuardDuty.LowSeverityFinding",
      "okta_application_sign_on_policy_modified_or_deleted",
      "Cloudflare.HttpRequest.BotHighVolume",
      "aws_rds_change_master_password",
      "GCP.Firewall.Rule.Deleted",
      "gcp_kubernetes_secrets_modified_or_deleted",
      "Slack.AuditLogs.AppAccessExpanded",
      "aws_efs_fileshare_modified_or_deleted"
    ],
    "included_files": [
      "mitre.py",
      "main.py",
      "rules/__init__.py",
      "rules/sigma/__init__.py",
      "rules/sigma/cloud/__init__.py",
      "rules/sigma/cloud/gcp/gcp_dns_zone_modified_or_deleted.py",
      "rules/sigma/cloud/gcp/gcp_kubernetes_rolebinding.py",
      "rules/sigma/cloud/gcp/gcp_full_network_traffic_packet_capture.py",
      "rules/sigma/cloud/gcp/gcp_sql_database_modified_or_deleted.py",
      "rules/sigma/cloud/gcp/gcp_kubernetes_secrets_modified_or_deleted.py",
      "rules/sigma/cloud/gcp/gcp_kubernetes_admission_controller.py",
      "rules/sigma/cloud/gcp/gcp_dlp_re_identifies_sensitive_information.py",
      "rules/sigma/cloud/gcp/gcp_firewall_rule_modified_or_deleted.py",
      "rules/sigma/cloud/gcp/__init__.py",
      "rules/sigma/cloud/gcp/gcp_bucket_modified_or_deleted.py",
      "rules/sigma/cloud/gcp/gcp_access_policy_deleted.py",
      "rules/sigma/cloud/gcp/gcp_service_account_disabled_or_deleted.py",
      "rules/sigma/cloud/gcp/gcp_service_account_modified.py",
      "rules/sigma/cloud/gcp/gcp_vpn_tunnel_modified_or_deleted.py",
      "rules/sigma/cloud/gcp/gcp_kubernetes_cronjob.py",
      "rules/sigma/cloud/gcp/gcp_breakglass_container_workload_deployed.py",
      "rules/sigma/cloud/gcp/gcp_bucket_enumeration.py",
      "rules/sigma/cloud/github/github_new_secret_created.py",
      "rules/sigma/cloud/github/github_delete_action_invoked.py",
      "rules/sigma/cloud/github/github_self_hosted_runner_changes_detected.py",
      "rules/sigma/cloud/github/__init__.py",
      "rules/sigma/cloud/github/github_outside_collaborator_detected.py",
      "rules/sigma/cloud/github/github_repo_or_org_transferred.py",
      "rules/sigma/cloud/github/github_push_protection_disabled.py",
      "rules/sigma/cloud/github/github_secret_scanning_feature_disabled.py",
      "rules/sigma/cloud/github/github_disabled_outdated_dependency_or_vulnerability.py",
      "rules/sigma/cloud/github/github_push_protection_bypass_detected.py",
      "rules/sigma/cloud/github/github_new_org_member.py",
      "rules/sigma/cloud/github/github_disable_high_risk_configuration.py",
      "rules/sigma/cloud/github/github_fork_private_repos_enabled_or_cleared.py",
      "rules/sigma/cloud/github/github_ssh_certificate_config_changed.py",
      "rules/sigma/cloud/okta/okta_admin_role_assigned_to_user_or_group.py",
      "rules/sigma/cloud/okta/okta_network_zone_deactivated_or_deleted.py",
      "rules/sigma/cloud/okta/okta_application_modified_or_deleted.py",
      "rules/sigma/cloud/okta/okta_policy_modified_or_deleted.py",
      "rules/sigma/cloud/okta/okta_mfa_reset_or_deactivated.py",
      "rules/sigma/cloud/okta/okta_security_threat_detected.py",
      "rules/sigma/cloud/okta/okta_policy_rule_modified_or_deleted.py",
      "rules/sigma/cloud/okta/okta_application_sign_on_policy_modified_or_deleted.py",
      "rules/sigma/cloud/okta/__init__.py",
      "rules/sigma/cloud/okta/okta_suspicious_activity_enduser_report.py",
      "rules/sigma/cloud/okta/okta_api_token_revoked.py",
      "rules/sigma/cloud/okta/okta_user_session_start_via_anonymised_proxy.py",
      "rules/sigma/cloud/okta/okta_user_account_locked_out.py",
      "rules/sigma/cloud/okta/okta_unauthorized_access_to_app.py",
      "rules/sigma/cloud/okta/okta_fastpass_phishing_detection.py",
      "rules/sigma/cloud/okta/okta_api_token_created.py",
      "rules/sigma/cloud/okta/okta_user_created.py",
      "rules/sigma/cloud/okta/okta_admin_role_assignment_created.py",
      "rules/sigma/cloud/okta/okta_identity_provider_created.py",
      "rules/sigma/cloud/okta/okta_password_in_alternateid_field.py",
      "rules/sigma/cloud/okta/okta_admin_activity_from_proxy_query.py",
      "rules/sigma/cloud/okta/okta_new_behaviours_admin_console.py",
      "rules/sigma/cloud/aws_cloudtrail/aws_iam_s3browser_templated_s3_bucket_policy_creation.py",
      "rules/sigma/cloud/aws_cloudtrail/aws_elasticache_security_group_created.py",
      "rules/sigma/cloud/aws_cloudtrail/aws_route_53_domain_transferred_to_another_account.py",
      "rules/sigma/cloud/aws_cloudtrail/aws_root_account_usage.py",
      "rules/sigma/cloud/aws_cloudtrail/aws_ec2_startup_script_change.py",
      "rules/sigma/cloud/aws_cloudtrail/aws_config_disable_recording.py",
      "rules/sigma/cloud/aws_cloudtrail/aws_passed_role_to_glue_development_endpoint.py",
      "rules/sigma/cloud/aws_cloudtrail/aws_elasticache_security_group_modified_or_deleted.py",
      "rules/sigma/cloud/aws_cloudtrail/aws_efs_fileshare_mount_modified_or_deleted.py",
      "rules/sigma/cloud/aws_cloudtrail/aws_route_53_domain_transferred_lock_disabled.py",
      "rules/sigma/cloud/aws_cloudtrail/aws_cloudtrail_security_group_change_ingress_egress.py",
      "rules/sigma/cloud/aws_cloudtrail/aws_sso_idp_change.py",
      "rules/sigma/cloud/aws_cloudtrail/aws_cloudtrail_disable_logging.py",
      "rules/sigma/cloud/aws_cloudtrail/aws_disable_bucket_versioning.py",
      "rules/sigma/cloud/aws_cloudtrail/aws_sts_assumerole_misuse.py",
      "rules/sigma/cloud/aws_cloudtrail/aws_cloudtrail_security_group_change_rds.py",
      "rules/sigma/cloud/aws_cloudtrail/aws_iam_backdoor_users_keys.py",
      "rules/sigma/cloud/aws_cloudtrail/aws_cloudtrail_new_acl_entries.py",
      "rules/sigma/cloud/aws_cloudtrail/__init__.py",
      "rules/sigma/cloud/aws_cloudtrail/aws_sts_getsessiontoken_misuse.py",
      "rules/sigma/cloud/aws_cloudtrail/aws_snapshot_backup_exfiltration.py",
      "rules/sigma/cloud/aws_cloudtrail/aws_delete_identity.py",
      "rules/sigma/cloud/aws_cloudtrail/aws_enum_buckets.py",
      "rules/sigma/cloud/aws_cloudtrail/aws_iam_s3browser_loginprofile_creation.py",
      "rules/sigma/cloud/aws_cloudtrail/aws_iam_s3browser_user_or_accesskey_creation.py",
      "rules/sigma/cloud/aws_cloudtrail/aws_attached_malicious_lambda_layer.py",
      "rules/sigma/cloud/aws_cloudtrail/aws_s3_data_management_tampering.py",
      "rules/sigma/cloud/aws_cloudtrail/aws_eks_cluster_created_or_deleted.py",
      "rules/sigma/cloud/aws_cloudtrail/aws_ec2_disable_encryption.py",
      "rules/sigma/cloud/aws_cloudtrail/aws_cloudtrail_security_group_change_loadbalancer.py",
      "rules/sigma/cloud/aws_cloudtrail/aws_console_getsignintoken.py",
      "rules/sigma/cloud/aws_cloudtrail/aws_ec2_vm_export_failure.py",
      "rules/sigma/cloud/aws_cloudtrail/aws_efs_fileshare_modified_or_deleted.py",
      "rules/sigma/cloud/aws_cloudtrail/aws_susp_saml_activity.py",
      "rules/sigma/cloud/aws_cloudtrail/aws_ecs_task_definition_cred_endpoint_query.py",
      "rules/sigma/cloud/aws_cloudtrail/aws_rds_change_master_password.py",
      "rules/sigma/cloud/aws_cloudtrail/aws_cloudtrail_imds_malicious_usage.py",
      "rules/sigma/cloud/aws_cloudtrail/aws_securityhub_finding_evasion.py",
      "rules/sigma/cloud/aws_cloudtrail/aws_rds_public_db_restore.py",
      "rules/sigma/cloud/aws_cloudtrail/aws_cloudtrail_ssm_malicious_usage.py",
      "rules/sigma/cloud/aws_cloudtrail/aws_cloudtrail_new_route_added.py",
      "rules/sigma/cloud/aws_cloudtrail/aws_guardduty_disruption.py",
      "helpers/__init__.py"
    ]
  }
  

If a previously uploaded rule is not passed in to register() on a subsequent invocation of upload, it will be deleted in your Panther instance.

Uploading a PyPanther rule with the same id as an existing v1 rule's RuleId will overwrite it. The same is true in the other direction—i.e., uploading a PyPanther rule with the same RuleId as an existing PyPanther rule's id will overwrite it.

upload limitations

The following limitations currently apply to pypanther upload:

    • This limit does not include Panther-managed rules (i.e., those returned by the get_panther_rules() function)

  • The total size of the zip file pypanther produces for upload cannot exceed 10MB.

  • Only Python files may be uploaded.

Learn about other commands in the .

Each folder containing rules imported with get_rules() must contain an __init__.py file. Learn more about recommended repository structure in the .

(When expected_result=True) Additional fields, prepended with expected_, that verify the output of . For example, expected_severity and expected_title.

See a full list of available fields in the .

The pypanther test command tests all PyPanther Detection classes that have a tests attribute set. In addition to testing rule() and output in this way, if you have created custom helper functions for use in rules, you may want to write targeted tests for these helper functions. To do this, it's recommended to use a common Python testing framework, such as or .

Say you'd like to write a reusable function that reads a list of AWS account IDs from a file and filters it to include only the production ones. (This function could then be used in an .) This function might look like the following:

To upload all PyPanther Detections that are , run:

The upload command will also upload schemas. Learn more in .

You must authenticate when using upload—see .

A maximum of 500 rules can be uploaded at once.

alert functions
registered
pytest
unittest
registered
uploaded
define tests
pypanther CLI command reference
Uploading schemas to Panther
Authenticating CLI commands
inheritance
include or exclude filter
custom
PyPanther Detections Style Guide
RuleTest property reference
alert function