AnalysisType: rule
Filename: github_action_failed.py
RuleID: "GitHub.Action.Failed"
DisplayName: "GitHub Action Failed"
Enabled: false
LogTypes:
- GitHub.Audit
Tags:
- GitHub
- Configuration Required
Severity: High
Description: A monitored github action has failed.
Runbook: |
Inspect the action failure link and take appropriate response.
There are no general plans of response for this activity.
Reference: https://docs.github.com/en/actions/creating-actions/setting-exit-codes-for-actions#about-exit-codes
Tests:
- Name: GitHub - Branch Protection Disabled
ExpectedResult: false
Log:
{
"actor": "cat",
"action": "protected_branch.destroy",
"created_at": 1621305118553,
"org": "my-org",
"p_log_type": "GitHub.Audit",
"repo": "my-org/my-repo",
}
- Name: GitHub Action Failed - No Configuration
ExpectedResult: false
Log:
{
"_document_id": "pWWWWWWWWWWWWWWWWWWWWW",
"action": "workflows.completed_workflow_run",
"actor": "github_handle",
"at_sign_timestamp": "2023-01-31 18:58:27.638",
"business": "github-business-only-if-enterprise-audit-log",
"completed_at": "2023-01-31T18:58:27.000Z",
"conclusion": "failure",
"created_at": "2023-01-31 18:58:27.638",
"event": "schedule",
"head_branch": "master",
"head_sha": "66dddddddddddddddddddddddddddddddddddddd",
"name": "sync-panther-analysis-from-upstream",
"operation_type": "modify",
"org": "panther-labs",
"p_log_type": "GitHub.Audit",
"public_repo": false,
"repo": "your-org/panther-analysis-copy",
"run_attempt": 3,
"run_number": 99,
"started_at": "2023-01-31 18:58:04",
"workflow_id": 44444444,
"workflow_run_id": 5555555555,
}
- Name: GitHub Action Failed - Monitored Action Configured
ExpectedResult: true
Mocks:
- objectName: MONITORED_ACTIONS
returnValue: >-
{
"your-org/panther-analysis-copy": [ "sync-panther-analysis-from-upstream"]
}
Log:
{
"_document_id": "pWWWWWWWWWWWWWWWWWWWWW",
"action": "workflows.completed_workflow_run",
"actor": "github_handle",
"at_sign_timestamp": "2023-01-31 18:58:27.638",
"business": "github-business-only-if-enterprise-audit-log",
"completed_at": "2023-01-31T18:58:27.000Z",
"conclusion": "failure",
"created_at": "2023-01-31 18:58:27.638",
"event": "schedule",
"head_branch": "master",
"head_sha": "66dddddddddddddddddddddddddddddddddddddd",
"name": "sync-panther-analysis-from-upstream",
"operation_type": "modify",
"org": "panther-labs",
"p_log_type": "GitHub.Audit",
"public_repo": false,
"repo": "your-org/panther-analysis-copy",
"run_attempt": 3,
"run_number": 99,
"started_at": "2023-01-31 18:58:04",
"workflow_id": 44444444,
"workflow_run_id": 5555555555,
}
# ------ paired body: github_action_failed.py ------
import json
from unittest.mock import MagicMock
from panther_github_helpers import github_alert_context
# The keys for MONITORED_ACTIONS are gh_org/repo_name
# The values for MONITORED_ACTIONS are a list of ["action_names"]
MONITORED_ACTIONS = {}
def rule(event):
global MONITORED_ACTIONS # pylint: disable=global-statement
if isinstance(MONITORED_ACTIONS, MagicMock):
MONITORED_ACTIONS = json.loads(MONITORED_ACTIONS()) # pylint: disable=not-callable
repo = event.get("repo", "")
action_name = event.get("name", "")
return all(
[
event.get("action", "") == "workflows.completed_workflow_run",
event.get("conclusion", "") == "failure",
repo in MONITORED_ACTIONS,
action_name in MONITORED_ACTIONS.get(repo, []),
]
)
def title(event):
repo = event.get("repo", "<NO_REPO>")
action_name = event.get("name", "<NO_ACTION_NAME>")
return f"GitHub Action [{action_name}] in [{repo}] has failed"
def alert_context(event):
a_c = github_alert_context(event)
a_c["action"] = event.get("name", "<NO_ACTION_NAME>")
a_c["action_run_link"] = (
f"https://github.com/{a_c.get('repo')}/actions/"
f"runs/{event.get('workflow_run_id', '<NO_RUN_ID>')}"
)
return a_c