AnalysisType: rule
Filename: snyk_project_settings.py
RuleID: "Snyk.Project.Settings"
DisplayName: "Snyk Project Settings"
Enabled: true
LogTypes:
- Snyk.GroupAudit
- Snyk.OrgAudit
Tags:
- Snyk
Reference: https://docs.snyk.io/snyk-admin/introduction-to-snyk-projects/view-and-edit-project-settings
Severity: Medium
Description: >
Detects when Snyk Project settings are changed
DedupPeriodMinutes: 60
Threshold: 1
SummaryAttributes:
- event
Tests:
- Name: Snyk Org Project Stop Monitor
ExpectedResult: true
Log:
{
"content":
{
"origin": "github",
"target":
{
"branch": "some-branch",
"id": 222222222,
"name": "repo-name",
"owner": "github-org",
},
"targetFile": "go.mod",
"type": "gomodules",
},
"created": "2023-03-30 15:38:18.58",
"event": "org.project.stop_monitor",
"groupId": "8fffffff-1555-4444-b000-b55555555555",
"orgId": "21111111-a222-4eee-8ddd-a99999999999",
"projectId": "05555555-8555-2333-5aaa-600000000000",
"userId": "05555555-3333-4ddd-8ccc-75555555555",
}
- Name: Project Ignore Create
ExpectedResult: true
Log:
{
"content":
{
"created": "2023-03-20T12:23:06.356Z",
"ignorePath": "*",
"ignoredBy": { "id": "05555555-3333-4ddd-8ccc-75555555555" },
"issueId": "SNYK-JS-UNDICI-3323845",
"reason": "dev dependency",
"reasonType": "wont-fix",
},
"created": "2023-03-20 12:23:08.363",
"event": "org.project.ignore.create",
"groupId": "8fffffff-1555-4444-b000-b55555555555",
"orgId": "21111111-a222-4eee-8ddd-a99999999999",
"projectId": "05555555-8555-2333-5aaa-600000000000",
"userId": "05555555-3333-4ddd-8ccc-75555555555",
}
- Name: Snyk Group SSO Membership sync
ExpectedResult: false
Log:
{
"content": {},
"created": "2023-03-15 13:13:13.133",
"event": "group.sso.membership.sync",
"groupId": "8fffffff-1555-4444-b000-b55555555555",
}
- Name: Snyk Org Project Edit
ExpectedResult: false
Log:
{
"content": {
"snapshotId": "69af7170-87cc-4939-bbaf-1fd99f80cde4"
},
"created": "2024-09-02 23:49:37.552000000",
"event": "org.project.edit",
"orgId": "69af7170-87cc-4939-bbaf-1fd99f80cde4",
"projectId": "69af7170-87cc-4939-bbaf-1fd99f80cde4"
}
- Name: Snyk No New Code Issues Found
ExpectedResult: false
Log:
{
"content": {
"after": {
"description": "No new Code Analysis issues found",
"state": "success"
},
"before": {
"state": "processing"
},
"prCheckPublicId": "69af7170-87cc-4939-bbaf-1fd99f80cde4",
"prChecksGroupPublicId": "69af7170-87cc-4939-bbaf-1fd99f80cde4"
},
"created": "2024-08-27 14:02:48.823000000",
"event": "org.project.pr_check.edit",
"orgId": "69af7170-87cc-4939-bbaf-1fd99f80cde4",
"projectId": "69af7170-87cc-4939-bbaf-1fd99f80cde4"
}
# ------ paired body: snyk_project_settings.py ------
from panther_snyk_helpers import snyk_alert_context
# The bodies of these actions are quite diverse.
# When projects are added, the logged detail is the sourceOrgId.
# org.project.stop_monitor is logged for individual files
# that are ignored.
ACTIONS = [
"org.sast_settings.edit",
"org.project.attributes.edit",
"org.project.add",
"org.project.delete",
"org.project.fix_pr.manual_open",
"org.project.ignore.create",
"org.project.ignore.delete",
"org.project.ignore.edit",
"org.project.monitor",
"org.project.pr_check.edit",
"org.project.remove",
"org.project.settings.delete",
"org.project.settings.edit",
"org.project.stop_monitor",
# AND the equivalent for licenses",
"org.license_rule.create",
"org.license_rule.delete",
"org.license_rule.edit",
]
def rule(event):
if event.deep_get("content", "after", "description") == "No new Code Analysis issues found":
return False
action = event.get("event", "<NO_EVENT>")
return action in ACTIONS
def title(event):
group_or_org = "<GROUP_OR_ORG>"
operation = "<NO_OPERATION>"
action = event.get("event", "<NO_EVENT>")
if "." in action:
group_or_org = action.split(".")[0].title()
operation = ".".join(action.split(".")[1:]).title()
return (
f"Snyk: [{group_or_org}] "
f"[{operation}] "
f"performed by [{event.deep_get('userId', default='<NO_USERID>')}]"
)
def alert_context(event):
a_c = snyk_alert_context(event)
# merge event in for the alert_context
a_c.update(event)
return a_c
def dedup(event):
return (
f"{event.deep_get('userId', default='<NO_USERID>')}"
f"{event.deep_get('orgId', default='<NO_ORGID>')}"
f"{event.deep_get('groupId', default='<NO_GROUPID>')}"
f"{event.deep_get('event', default='<NO_EVENT>')}"
)
def severity(event):
action = event.get("event", "<NO_EVENT>")
if action == "org.project.fix_pr.manual_open":
return "INFO"
return "LOW"