From 7d18cbdaa8441637e2d6530ab0d90ee0bd67540f Mon Sep 17 00:00:00 2001 From: Ricardo Valdes Date: Wed, 16 Sep 2026 20:34:29 -0400 Subject: [PATCH] fix: align GitHub filter and rule contracts --- filters/audits/github.md | 40 ++++++++++++ filters/github/github.yml | 14 +++- .../testdata/filter-contracts/github.json | 65 +++++++++++++++++++ 3 files changed, 116 insertions(+), 3 deletions(-) create mode 100644 filters/audits/github.md create mode 100644 plugins/alerts/testdata/filter-contracts/github.json diff --git a/filters/audits/github.md b/filters/audits/github.md new file mode 100644 index 000000000..13db22df6 --- /dev/null +++ b/filters/audits/github.md @@ -0,0 +1,40 @@ +# GitHub normalization and rule review + +Promote senderLogin to origin.user without consuming the vendor field used by rules; normalize workflow failures. + +This draft targets UTMStack `v11`. It contains 1 filter changes +and 0 rule changes for this technology only. Review covered +1 filter configurations and 13 matching shipped rule files. +Unchanged rules are listed in the regression manifest; they are not duplicated in the diff. + +## Contract and validation + +- Compared exact standard names/types with go-sdk v1.1.31 and the supplied UTMStack dictionaries. +- Checked documented pipeline ordering, rename/move behavior, open vendor log fields, + event-side versus alert-side fields, and surviving fields used by affected rule predicates/history/grouping. +- Strict SDK configuration decoding and actual CEL compilation pass for this scope. +- 2 synthetic normalization cases pass, including SDK Event conversion and any + trigger predicate assertions recorded in the manifest. +- The scoped alerts module tests and `git diff --check` pass with the shared contract runner applied. + +The shared alert-contract PR supplies the reusable Go runner for the manifest in +`plugins/alerts/testdata/filter-contracts/github.json`. Apply that support before running `go test ./...` in `plugins/alerts`. + +The model starts from synthetic extraction results. It does not run complex grok, +JSON/KV/XML/CSV extraction, time conversion, dynamic plugins, historical OpenSearch +queries, or the closed EventProcessor. Raw vendor logs and resulting alerts must +still be checked in staging before rollout. No customer false-positive reduction +has been measured and no production rollout is included. + + + +## References + +- [SDK schema](https://github.com/threatwinds/go-sdk/blob/v1.1.31/plugins/plugins.proto) +- [Filter steps](https://github.com/threatwinds/go-sdk/wiki/Filter-Steps-Reference) +- [Standard event schema](https://github.com/threatwinds/go-sdk/wiki/Standard-Event-Schema) +- [Rule implementation](https://github.com/threatwinds/go-sdk/wiki/Implementing-Rules) + +`afterEvents`, empty noncapturing grok names, supported numeric strings, and custom +`log.*` fields are accepted. Existing textual protocol casing and vendor action names +are preserved unless a concrete consumer mismatch requires correction. diff --git a/filters/github/github.yml b/filters/github/github.yml index 7439a3d51..79aa967ba 100644 --- a/filters/github/github.yml +++ b/filters/github/github.yml @@ -679,8 +679,8 @@ pipeline: function: string params: key: actionResult - value: "failed" - where: 'oneOf("log.conclusion", ["failure", "timed_out", "startup_failure", "action_required"])' + value: failure + where: oneOf("log.conclusion", ["failure", "timed_out", "startup_failure", "action_required"]) # Removing unused fields - delete: @@ -696,4 +696,12 @@ pipeline: - log.sender - log.pusher - log.repository.owner - - log.repository \ No newline at end of file + - log.repository + + # Promote standard fields while retaining vendor fields used by rules. + - grok: + source: log.senderLogin + patterns: + - fieldName: origin.user + pattern: '{{.greedy}}' + where: exists("log.senderLogin") && !exists("origin.user") diff --git a/plugins/alerts/testdata/filter-contracts/github.json b/plugins/alerts/testdata/filter-contracts/github.json new file mode 100644 index 000000000..cc3402695 --- /dev/null +++ b/plugins/alerts/testdata/filter-contracts/github.json @@ -0,0 +1,65 @@ +{ + "technology": "GitHub", + "filters": [ + "filters/github/github.yml" + ], + "rules": [ + "rules/github/action_secret_access.yml", + "rules/github/codeowners_modification.yml", + "rules/github/dependabot_config_poisoning.yml", + "rules/github/environment_protection_bypass.yml", + "rules/github/github_app_token_theft.yml", + "rules/github/mass_repository_cloning.yml", + "rules/github/org_member_role_escalation.yml", + "rules/github/repo_visibility_public.yml", + "rules/github/secret_scanning_alerts.yml", + "rules/github/self_hosted_runner_compromise.yml", + "rules/github/sensitive_data_commits.yml", + "rules/github/workflow_injection_pr_target.yml", + "rules/github/workflow_modifications.yml" + ], + "fixtures": [ + { + "name": "github_workflow_success", + "filter": "github/github.yml", + "input": { + "log": { + "sender": { + "login": "operator" + }, + "workflow_run": { + "conclusion": "success" + } + } + }, + "expected": { + "origin.user": "operator", + "log.senderLogin": "operator", + "actionResult": "success" + }, + "absent": [], + "rules": {} + }, + { + "name": "github_workflow_failure", + "filter": "github/github.yml", + "input": { + "log": { + "sender": { + "login": "operator" + }, + "workflow_run": { + "conclusion": "failure" + } + } + }, + "expected": { + "origin.user": "operator", + "log.senderLogin": "operator", + "actionResult": "failure" + }, + "absent": [], + "rules": {} + } + ] +}