diff --git a/.github/workflows/appinspect_api.yml b/.github/workflows/appinspect_api.yml index 99a88cd..8a6f02b 100644 --- a/.github/workflows/appinspect_api.yml +++ b/.github/workflows/appinspect_api.yml @@ -45,3 +45,9 @@ jobs: splunkUser: ${{ secrets.SPLUNKBASE_USER }} splunkPassword: ${{ secrets.SPLUNKBASE_PASSWORD }} includedTags: cloud + - name: Release + uses: fnkr/github-action-ghr@v1 + if: startsWith(github.ref, 'refs/tags/') + env: + GHR_PATH: ./dist/github_app_for_splunk.spl + GITHUB_TOKEN: ${{ secrets.API_TOKEN }} diff --git a/.github/workflows/appinspect_cli.yml b/.github/workflows/appinspect_cli.yml index d80e9ed..c0c0e6c 100644 --- a/.github/workflows/appinspect_cli.yml +++ b/.github/workflows/appinspect_cli.yml @@ -42,11 +42,23 @@ jobs: sed -i "s/$old_str/$new_str/g" package.json sed -i "s/$old_str/$new_str/g" ./github_app_for_splunk/default/app.conf - - name: Build Package - run: COPYFILE_DISABLE=1 tar -cvzf package.tar.gz ./github_app_for_splunk + - name: Install slim + run: | + pip install https://download.splunk.com/misc/packaging-toolkit/splunk-packaging-toolkit-1.0.1.tar.gz + + - name: Create package + run: | + mkdir build + slim package ./github_app_for_splunk - name: Run App Inspect CLI uses: splunk/appinspect-cli-action@v1 with: - app_path: package.tar.gz + app_path: github_app_for_splunk-1.0.0.tar.gz included_tags: cloud, splunk_appinspect + + - name: Upload package + uses: actions/upload-artifact@v3 + with: + name: github_app_for_splunk-1.0.0.tar.gz + path: ./github_app_for_splunk-1.0.0.tar.gz diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..4fc208e --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Splunk GitHub + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/docs/ghe_audit_logs.MD b/docs/ghe_audit_logs.MD index c9eed4b..a0fee5b 100644 --- a/docs/ghe_audit_logs.MD +++ b/docs/ghe_audit_logs.MD @@ -65,9 +65,12 @@ The following are the required scopes for the personal access token allowing the - **Hostname** - - This is the hostname of your GitHub Enterprise instance. Make sure there are no trailing `/` in the URL provided. This could either be a FQDN or an IP address. Do not append any paths beyond the tld. + - This is the hostname of your GitHub Enterprise instance. Make sure there are no trailing `/` in the URL provided. This could either be a FQDN or an IP address. Do not append any paths beyond the tld. **Most Users Will Not Need to change this!** - Example: [https://api.github.com](https://api.github.com) +- **Account Type** + - This is the type of GitHub account you are using. GitHub Enterprise Cloud users should keep it at `enterprise`, however some users that only have an enterprise tier paid Organization should change it to `organization`. If you can't tell which you have, go to your user icon in GitHub in the upper right corner. If you have an entry listed as "Your enterprises", then you should use `enterprise`, otherwise use `organization`. + - **Enterprise** - The enterprise name for which to fetch audit log events diff --git a/docs/images/79E9DCE3-B358-4BAC-9667-7866C2CE4D00.png b/docs/images/79E9DCE3-B358-4BAC-9667-7866C2CE4D00.png index d9933d9..188b3e3 100644 Binary files a/docs/images/79E9DCE3-B358-4BAC-9667-7866C2CE4D00.png and b/docs/images/79E9DCE3-B358-4BAC-9667-7866C2CE4D00.png differ diff --git a/github_app_for_splunk/appserver/static/example_customtables.js b/github_app_for_splunk/appserver/static/example_customtables.js index ca9f045..0dced37 100644 --- a/github_app_for_splunk/appserver/static/example_customtables.js +++ b/github_app_for_splunk/appserver/static/example_customtables.js @@ -16,7 +16,7 @@ require([ id: "search2", preview: true, cache: true, - search: "index=github_webhook \"workflow_run.name\"=\"*\" | spath \"repository.full_name\" | search repository.full_name=* | eval started=if(action=\"requested\",_time,NULL), completed=if(action=\"completed\",_time, NULL), created=round(strptime('workflow_run.created_at',\"%Y-%m-%dT%H:%M:%SZ\")) | stats latest(created) as created, latest(started) as started, latest(completed) as completed, latest(duration) as duration, latest(workflow_run.conclusion) as workflow_run.conclusion by repository.full_name,workflow_run.name,workflow_run.id | eval started=if(isnull(started), created, started) | eval duration=if(isnotnull(completed),tostring(completed-started,\"Duration\"),\"In Progress\") | rename workflow_run.conclusion as status, repository.full_name as \"Repository Name\", workflow_run.name as \"Workflow Name\", workflow_run.id as \"Run ID\" | table status, \"Repository Name\", \"Workflow Name\", \"Run ID\", duration,completed|sort completed|fields - completed", + search: "`github_webhooks` \"workflow_run.name\"=\"*\" | spath \"repository.full_name\" | search repository.full_name=* | eval started=if(action=\"requested\",_time,NULL), completed=if(action=\"completed\",_time, NULL), created=round(strptime('workflow_run.created_at',\"%Y-%m-%dT%H:%M:%SZ\")) | stats latest(created) as created, latest(started) as started, latest(completed) as completed, latest(duration) as duration, latest(workflow_run.conclusion) as workflow_run.conclusion by repository.full_name,workflow_run.name,workflow_run.id | eval started=if(isnull(started), created, started) | eval duration=if(isnotnull(completed),tostring(completed-started,\"Duration\"),\"In Progress\") | rename workflow_run.conclusion as status, repository.full_name as \"Repository Name\", workflow_run.name as \"Workflow Name\", workflow_run.id as \"Run ID\" | table status, \"Repository Name\", \"Workflow Name\", \"Run ID\", duration,completed|sort completed|fields - completed", earliest_time: mvc.tokenSafe("$field1.earliest$"), latest_time: mvc.tokenSafe("$field1.latest$") }); @@ -102,7 +102,7 @@ require([ window.open("/app/github_app_for_splunk/workflow_details?form.workflow_id="+workflowIDCell.value+"&form.repoName="+repoNameCell.value+"&form.workflowName="+workflowName.value+"&form.field1.earliest=-24h%40h&form.field1.latest=now&form.timeRange.earliest=-30d%40d&form.timeRange.latest=now&form.workflowCount=25",'_self'); }); - this._searchManager.set({ search: 'index=github_webhook (workflow_run.id='+workflowIDCell.value+' OR workflow_job.run_id='+workflowIDCell.value+') | eval started=if(action=="requested", _time, null), completed=if(action=="completed", _time,null) | stats latest(workflow_run.conclusion) as Status, earliest(started) as Started, latest(completed) as Completed, latest(workflow_run.head_branch) as Branch, latest(workflow_run.event) as Trigger | eval Duration=tostring(Completed-Started, "Duration") | eval Started=strftime(Started,"%Y-%m-%dT%H:%M:%S"), Completed=strftime(Completed,"%Y-%m-%dT%H:%M:%S")| fields Status, Started, Completed, Duration, Branch, Trigger | eval Details="Click here for Workflow Details" | transpose|rename column AS Details| rename "row 1" AS values'}); + this._searchManager.set({ search: '`github_webhooks` (workflow_run.id='+workflowIDCell.value+' OR workflow_job.run_id='+workflowIDCell.value+') | eval started=if(action=="requested", _time, null), completed=if(action=="completed", _time,null) | stats latest(workflow_run.conclusion) as Status, earliest(started) as Started, latest(completed) as Completed, latest(workflow_run.head_branch) as Branch, latest(workflow_run.event) as Trigger | eval Duration=tostring(Completed-Started, "Duration") | eval Started=strftime(Started,"%Y-%m-%dT%H:%M:%S"), Completed=strftime(Completed,"%Y-%m-%dT%H:%M:%S")| fields Status, Started, Completed, Duration, Branch, Trigger | eval Details="Click here for Workflow Details" | transpose|rename column AS Details| rename "row 1" AS values'}); // $container is the jquery object where we can put out content. // In this case we will render our chart and add it to the $container $container.append(this._TableView.render().el); diff --git a/github_app_for_splunk/default/data/ui/nav/default.xml b/github_app_for_splunk/default/data/ui/nav/default.xml index d80e7a3..e952452 100644 --- a/github_app_for_splunk/default/data/ui/nav/default.xml +++ b/github_app_for_splunk/default/data/ui/nav/default.xml @@ -10,6 +10,7 @@ + diff --git a/github_app_for_splunk/default/data/ui/views/code_scanning_overview.xml b/github_app_for_splunk/default/data/ui/views/code_scanning_overview.xml index 9522135..eeaab84 100644 --- a/github_app_for_splunk/default/data/ui/views/code_scanning_overview.xml +++ b/github_app_for_splunk/default/data/ui/views/code_scanning_overview.xml @@ -2,7 +2,7 @@ - `github_webhooks` (eventtype="GitHub::CodeScanning" OR eventtype="GitHub::Push") | eval action='action', tool=if(isnotnull('alert.tool.name'),'alert.tool.name','unknown'), repository=if(isnotnull('repository.name'),'repository.name','unknown'), severity=if(isnotnull('alert.rule.security_severity_level'),'alert.rule.security_severity_level','none'), create_time=if(isnotnull('alert.created_at'),'alert.created_at','unknown'), received_time='_time', alert_url=if(isnotnull('alert.html_url'),'alert.html_url','unknown'), eventtype='eventtype', created=strptime(create_time, "%Y-%m-%dT%H:%M:%S%Z"), duration=received_time - created, duration_str=tostring(avg(duration), "duration") + `github_webhooks` (eventtype="GitHub::CodeScanning" OR eventtype="GitHub::Push") | eval action='action', tool=if(isnotnull('alert.tool.name'),'alert.tool.name','unknown'), repository=if(isnotnull('repository.name'),'repository.name','unknown'), severity=if(isnotnull('alert.rule.security_severity_level'),'alert.rule.security_severity_level','none'), create_time=if(isnotnull('alert.created_at'),'alert.created_at','unknown'), received_time='_time', alert_url=if(isnotnull('alert.html_url'),'alert.html_url','unknown'), eventtype='eventtype', created=strptime(create_time, "%Y-%m-%dT%H:%M:%S%Z"), resolved_at=case('alert.dismissed_at' != "null", 'alert.dismissed_at', isnotnull('alert.fixed_at'), 'alert.fixed_at', isnotnull('alert.resolved_at'),'alert.resolved_at', 1=1, _time), duration = toString(round(strptime(resolved_at, "%Y-%m-%dT%H:%M:%S") - strptime(create_time, "%Y-%m-%dT%H:%M:%S"))), duration_str=tostring(avg(duration), "duration") $timeTkn.earliest$ $timeTkn.latest$ @@ -46,62 +46,78 @@ + Mean Time to Resolution (MTTR) + + + | search eventtype="GitHub::CodeScanning" (action=fixed OR action=closed_by_user) tool=$tool_name$ repository=$repoTkn$ +| eval action=action, , repository=if(isnotnull('repository.name'),'repository.name','unknown') +| eval age = avg(duration) +| appendpipe [ stats avg(age) as totalTime ] +| eval mttr = toString(round(totalTime), "duration"), clean_mttr = replace (mttr , "\+" , " days, ") +| stats max(clean_mttr) + + + + + + + + Created - Created | search tool=$tool_name$ repository=$repoTkn$ action="created" | stats count - + + Fixed - Fixed | search tool=$tool_name$ repository=$repoTkn$ action="fixed" | stats count - + + Reopened - Reopened | search tool=$tool_name$ repository=$repoTkn$ action="reopened" | stats count - + + Alert Found/Fixed Ratio - Alert Found/Fixed Ratio | search tool=$tool_name$ repository=$repoTkn$ (action=created OR action=fixed) -| timechart count(_raw) by action +| timechart count(_raw) by action | accum created -| accum fixed -| rename created as "Found" +| accum fixed +| rename created as "Found" | rename fixed as "Fixed" - + + Commit/Alert Ratio - Commit/Alert Ratio | search (eventtype="GitHub::Push" repository=$repoTkn$) OR ((action=created OR action=reopened) tool=$tool_name$ repository=$repoTkn$ ) | timechart count(_raw) by eventtype @@ -122,8 +138,8 @@ + New Alerts by Tool - New Alerts by Tool | search tool=$tool_name$ repository=$repoTkn$ (action=created OR action=appeared_in_branch) | timechart count(_raw) by tool @@ -141,8 +157,9 @@ Fixed Alerts | search (action=fixed OR action=closed_by_user) repository=$repoTkn$ tool=$tool_name$ -| table repository, tool, alert_url,duration_str -| rename repository AS "Repository" duration_str AS "Time to Resolution",tool AS "Tool", alert_url AS "Alert URL" +|eval clean_duration = replace (duration_str , "\+" , " days, ") +| table repository, tool, alert_url,clean_duration +| rename repository AS "Repository" clean_duration AS "Time to Resolution",tool AS "Tool", alert_url AS "Alert URL" | sort -"Time to Resolution" @@ -157,11 +174,8 @@ | search (action=created OR action=reopened) repository=$repoTkn$ tool=$tool_name$ | chart usenull=f count over repository by severity + - - - - diff --git a/github_app_for_splunk/default/data/ui/views/dependabot_alerts.xml b/github_app_for_splunk/default/data/ui/views/dependabot_alerts.xml new file mode 100644 index 0000000..3496568 --- /dev/null +++ b/github_app_for_splunk/default/data/ui/views/dependabot_alerts.xml @@ -0,0 +1,181 @@ +
+ + + + `github_webhooks` eventtype="GitHub::VulnerabilityAlert" | eval action='action', repository=if(isnotnull('repository.name'),'repository.name','unknown'), severity=if(isnotnull('alert.severity'),'alert.severity','none'), create_time=if(isnotnull('alert.created_at'),'alert.created_at','unknown'), received_time='_time', alert_url=if(isnotnull('alert.external_reference'),'alert.external_reference','unknown'), eventtype='eventtype', created=strptime(create_time, "%Y-%m-%dT%H:%M:%S%Z"), resolved_at=case('alert.dismissed_at' != "null", 'alert.dismissed_at', isnotnull('alert.fixed_at'), 'alert.fixed_at', isnotnull('alert.resolved_at'),'alert.resolved_at', 1=1, _time), duration = toString(round(strptime(resolved_at, "%Y-%m-%dT%H:%M:%S") - strptime(create_time, "%Y-%m-%dT%H:%M:%S"))), duration_str=tostring(avg(duration), "duration") + + $timeTkn.earliest$ + $timeTkn.latest$ + 1 + +
+ + + + -24h@h + now + + + + + All + * + * + " + " + , + repository + repository + + | dedup repository | table repository + + + + + severity + severity + " + " + + | table severity | dedup severity + + All + * + * + +
+ + + + Mean Time to Resolution (MTTR) + + | search severity=$severity_label$ repository=$repoTkn$ action="resolve" + | eval age = avg(duration) + | appendpipe [ stats avg(age) as totalTime ] + | eval mttr = toString(round(totalTime), "duration"), clean_mttr = replace (mttr , "\+" , " days, ") + | stats max(clean_mttr) + + + + + + + + + + + Created + + | search severity=$severity_label$ repository=$repoTkn$ action="create" | stats count + + + + + + + + + + Fixed + + | search severity=$severity_label$ repository=$repoTkn$ (action="resolve") | stats count + + + + + + + + + Dismissed + + | search severity=$severity_label$ repository=$repoTkn$ (action="dismiss") | stats count + + + + + + + + + + + Alert Found/Fixed Ratio + + | search severity=$severity_label$ repository=$repoTkn$ (action=create OR action=resolve OR action=dismiss) +| timechart count(_raw) by action +| accum create +| accum resolve +| rename create as "Found" +| rename resolve as "Fixed" +| rename dismiss as "Dismissed" + + + + + + + + + + + Vulnerabilities by Repo + + | search severity=$severity_label$ repository=$repoTkn$ action=create | chart count by repository + + + + + + + + + + + + New Alerts by Severity + + | search severity=$severity_label$ repository=$repoTkn$ (action=create) | timechart count(_raw) by severity + + + + + + + + + + + + + Fixed Alerts + + | search (action=resolve OR action=dismiss) repository=$repoTkn$ severity=$severity_label$ +| table action, repository, severity, alert_url,duration_str +| rename action AS "Action", repository AS "Repository" duration_str AS "Time to Resolution",severity AS "Severity", alert_url AS "Alert URL" +| sort -"Time to Resolution" + + + +
+
+
+ + + + Alerts by Repo + + | search (action=create) repository=$repoTkn$ severity=$severity_label$| chart usenull=f count over repository by severity + + + + + + + + + +
+
+
+
\ No newline at end of file diff --git a/github_app_for_splunk/default/data/ui/views/integration_overview.xml b/github_app_for_splunk/default/data/ui/views/integration_overview.xml index 04fad00..f3d6fdb 100644 --- a/github_app_for_splunk/default/data/ui/views/integration_overview.xml +++ b/github_app_for_splunk/default/data/ui/views/integration_overview.xml @@ -27,7 +27,7 @@ - index=_internal component=ExecProcessor "TA_splunk_ghe_audit_log_monitoring" "stream_events(): Fetched:" OR "API Rate limits"| rex "\'x_rl_limit\'\: \'(?<x_rl_limit>\d+?)\', \'x_rl_remainig\'\: \'(?<x_rl_remaining>\d+?)\', 'x_rl_reset_timestamp\'\: \'(?<x_rl_reset_timestamp>\d+?)\', \'x_rl_used\'\: \'(?<x_rl_used>\d+?)\'" | rex "stream_events\(\)\: Fetched: (?<event_count>\d+?) events" | timechart sum(event_count) as fetched_event max(x_rl_limit) as x_rl_limit, min(x_rl_remaining) as x_rl_remaining, max(x_rl_used) as x_rl_used | stats max(x_rl_limit) as "Rate Limit", avg(x_rl_used) as "Average Rate Limit Used", min(fetched_event) as "Minimum Fetched Events", avg(fetched_event) as "Average Fetched Events", max(fetched_event) as "Maximum Fetched Events" + index=_internal component=ExecProcessor "github-audit-log-monitoring-add-on-for-splunk" "stream_events(): Fetched:" OR "API Rate limits"| rex "\'x_rl_limit\'\: \'(?<x_rl_limit>\d+?)\', \'x_rl_remainig\'\: \'(?<x_rl_remaining>\d+?)\', 'x_rl_reset_timestamp\'\: \'(?<x_rl_reset_timestamp>\d+?)\', \'x_rl_used\'\: \'(?<x_rl_used>\d+?)\'" | rex "stream_events\(\)\: Fetched: (?<event_count>\d+?) events" | timechart sum(event_count) as fetched_event max(x_rl_limit) as x_rl_limit, min(x_rl_remaining) as x_rl_remaining, max(x_rl_used) as x_rl_used | stats max(x_rl_limit) as "Rate Limit", avg(x_rl_used) as "Average Rate Limit Used", min(fetched_event) as "Minimum Fetched Events", avg(fetched_event) as "Average Fetched Events", max(fetched_event) as "Maximum Fetched Events" -24h@h now 1 @@ -57,7 +57,7 @@ Rate Limit Usage - index=_internal component=ExecProcessor "TA_splunk_ghe_audit_log_monitoring" "API Rate limits"| rex "\'x_rl_limit\'\: \'(?<x_rl_limit>\d+?)\', \'x_rl_remainig\'\: \'(?<x_rl_remaining>\d+?)\', 'x_rl_reset_timestamp\'\: \'(?<x_rl_reset_timestamp>\d+?)\', \'x_rl_used\'\: \'(?<x_rl_used>\d+?)\'" | timechart max(x_rl_limit) as "Rate Limit", min(x_rl_remaining) as "Rate Limit Remaining", max(x_rl_used) as "Rate Limit Used" + index=_internal component=ExecProcessor "github-audit-log-monitoring-add-on-for-splunk" "API Rate limits"| rex "\'x_rl_limit\'\: \'(?<x_rl_limit>\d+?)\', \'x_rl_remainig\'\: \'(?<x_rl_remaining>\d+?)\', 'x_rl_reset_timestamp\'\: \'(?<x_rl_reset_timestamp>\d+?)\', \'x_rl_used\'\: \'(?<x_rl_used>\d+?)\'" | timechart max(x_rl_limit) as "Rate Limit", min(x_rl_remaining) as "Rate Limit Remaining", max(x_rl_used) as "Rate Limit Used" $timeRng.earliest$ $timeRng.latest$ 1 @@ -101,7 +101,7 @@ Fetched Events - index=_internal component=ExecProcessor "TA_splunk_ghe_audit_log_monitoring" "stream_events(): Fetched:" | rex "stream_events\(\)\: Fetched: (?<event_count>\d+?) events" | timechart sum(event_count) as fetched_event + index=_internal component=ExecProcessor "github-audit-log-monitoring-add-on-for-splunk" "stream_events(): Fetched:" | rex "stream_events\(\)\: Fetched: (?<event_count>\d+?) events" | timechart sum(event_count) as fetched_event $timeRng.earliest$ $timeRng.latest$ 1 diff --git a/github_app_for_splunk/default/data/ui/views/secret_scanning_overview.xml b/github_app_for_splunk/default/data/ui/views/secret_scanning_overview.xml index 5fc7164..1cdf640 100644 --- a/github_app_for_splunk/default/data/ui/views/secret_scanning_overview.xml +++ b/github_app_for_splunk/default/data/ui/views/secret_scanning_overview.xml @@ -1,8 +1,8 @@ -
+ - `github_webhooks` eventtype="GitHub::SecretScanning" | eval action='action', enterprise=if(isnotnull('enterprise.name'),'enterprise.name','unknown'), organization=if(isnotnull('organization.login'),'organization.login','unknown'), repository=if(isnotnull('repository.name'),'repository.name','unknown'), secret_type=if(isnotnull('alert.secret_type'),'alert.secret_type','unknown'), resolution=if(isnotnull('alert.resolution'),'alert.resolution','unknown'), resolved_at=if(isnotnull('alert.resolved_at'),'alert.resolved_at','unknown'), resolved_by=if(isnotnull('alert.resolved_by.login'),'alert.resolved_by.login','unknown') + `github_webhooks` eventtype="GitHub::SecretScanning" | eval action='action', enterprise=if(isnotnull('enterprise.name'),'enterprise.name','unknown'), organization=if(isnotnull('organization.login'),'organization.login','unknown'), repository=if(isnotnull('repository.name'),'repository.name','unknown'), secret_type=if(isnotnull('alert.secret_type'),'alert.secret_type','unknown'), resolution=if(isnotnull('alert.resolution'),'alert.resolution','unknown'), create_time=if(isnotnull('alert.created_at'),'alert.created_at','unknown'), created=strptime(create_time, "%Y-%m-%dT%H:%M:%S%Z"), resolved_at=case('alert.dismissed_at' != "null", 'alert.dismissed_at', isnotnull('alert.fixed_at'), 'alert.fixed_at', isnotnull('alert.resolved_at'),'alert.resolved_at', 1=1, _time), duration = toString(round(strptime(resolved_at, "%Y-%m-%dT%H:%M:%S") - strptime(create_time, "%Y-%m-%dT%H:%M:%S"))), duration_str=tostring(avg(duration), "duration"),'alert.resolved_at','unknown'), resolved_by=if(isnotnull('alert.resolved_by.login'),'alert.resolved_by.login','unknown'), url='alert.html_url' $timeTkn.earliest$ $timeTkn.latest$ @@ -59,6 +59,22 @@ + + + Mean Time To Resolution (MTTR) + + | search repository=$repoTkn$ organization=$orgTkn$ secret_type=$secret_type$ action="resolved" + | eval age = avg(duration) + | appendpipe [ stats avg(age) as totalTime ] + | eval mttr = toString(round(totalTime), "duration"), clean_mttr = replace (mttr , "\+" , " days, ") + | stats max(clean_mttr) + + + + + + + Found Secrets @@ -66,7 +82,7 @@ | search repository=$repoTkn$ organization=$orgTkn$ secret_type=$secret_type$ action="created" | stats count - + @@ -78,19 +94,32 @@ | search repository=$repoTkn$ organization=$orgTkn$ secret_type=$secret_type$ action="resolved" | stats count - + + + + + + Secrets by Type + + | search repository=$repoTkn$ organization=$orgTkn$ secret_type=$secret_type$ action="created" | chart count by secret_type + + + + + + - Secret Types + Secrets by Repository - | search repository=$repoTkn$ organization=$orgTkn$ secret_type=$secret_type$ | chart count by secret_type + | search repository=$repoTkn$ organization=$orgTkn$ secret_type=$secret_type$ action="created" | chart count by repository - + @@ -98,17 +127,17 @@ Secrets Found/Fixed Ratio | search repository=$repoTkn$ organization=$orgTkn$ secret_type=$secret_type$ (action=created OR action=resolved) -| timechart count(_raw) by action +| timechart count(_raw) by action | accum created -| accum resolved -| rename created as "Found" +| accum resolved +| rename created as "Found" | rename resolved as "Fixed" - + @@ -117,12 +146,11 @@ Fixed Secrets - | search action=resolved repository=$repoTkn$ organization=$orgTkn$ secret_type=$secret_type$ | table secret_type, organization, repository, resolution, resolved_by, _time - | rename secret_type as "Secret Type" - | rename organization as "Organization" - | rename repository as "Repository" - | rename resolution as "Resolution" - | rename resolved_by as "Resolved By" + | search action=resolved repository=$repoTkn$ organization=$orgTkn$ secret_type=$secret_type$ +| eval mttr = toString(round(duration), "duration"), clean_mttr = replace (mttr , "\+" , " days, ") +| table secret_type, organization, repository, resolution, resolved_by, clean_mttr +| rename secret_type as "Secret Type", organization as "Organization", repository as "Repository", resolution as "Resolution", resolved_by as "Resolved By", clean_mttr as "Time to Resolution" + @@ -134,11 +162,8 @@
Found Secrets - | search action=created repository=$repoTkn$ organization=$orgTkn$ secret_type=$secret_type$ | table secret_type, organization, repository, action, _time - | rename secret_type as "Secret Type" - | rename organization as "Organization" - | rename repository as "Repository" - | rename action as "Action" + | search action=created repository=$repoTkn$ organization=$orgTkn$ secret_type=$secret_type$ | table secret_type, organization, repository, url, create_time + | rename secret_type as "Secret Type", organization as "Organization", repository as "Repository", url as "URL", create_time as "Created At" diff --git a/github_app_for_splunk/default/data/ui/views/security_alert_overview.xml b/github_app_for_splunk/default/data/ui/views/security_alert_overview.xml index 8cefd7c..a85551d 100644 --- a/github_app_for_splunk/default/data/ui/views/security_alert_overview.xml +++ b/github_app_for_splunk/default/data/ui/views/security_alert_overview.xml @@ -2,7 +2,15 @@ - index=gh_vuln OR (`github_webhooks` alert.created_at=*) | eval reason=if(isnotnull('alert.affected_package_name'),'alert.affected_package_name','alert.rule.name'), id=if(isnotnull('alert.external_identifier'),'alert.external_identifier','alert.rule.id'), severity=if(isnotnull('alert.severity'),'alert.severity','alert.rule.security_severity_level'), type=if(isnotnull('alert.external_identifier'),"Dependabot Alert","Code Scanning Alert") | stats latest(action) as status, earliest(alert.created_at) as created_at, latest(alert.number) as number by repository.full_name, reason, id, type, severity | eval source=if(type=="Dependabot Alert","dependabot","code-scanning") | eval age = toString(round(now() - strptime(created_at, "%Y-%m-%dT%H:%M:%S")),"Duration") + index=gh_vuln OR (`github_webhooks` alert.created_at=*) + | eval type=case((eventtype="GitHub::CodeScanning"), "Code Scanning Alert", (eventtype="GitHub::VulnerabilityAlert"), "Dependabot Alert", (eventtype="GitHub::SecretScanning"), "Secret Scanning Alert") + | eval url=case((eventtype="GitHub::CodeScanning"), 'alert.html_url', (eventtype="GitHub::VulnerabilityAlert"), 'repository.html_url'+"/security/dependabot/"+'alert.number', (eventtype="GitHub::SecretScanning"), 'alert.html_url') + | eval reason=case((type="Dependabot Alert"),'alert.affected_package_name',(type="Code Scanning Alert"), 'alert.rule.name', (type="Secret Scanning Alert"), 'alert.secret_type'), id=case((type="Dependabot Alert"),'alert.external_identifier',(type="Code Scanning Alert"), 'alert.rule.id', (type="Secret Scanning Alert"), 'alert.number'), severity=case((type="Dependabot Alert"),'alert.severity',(type="Code Scanning Alert"), 'alert.rule.security_severity_level', (type="Secret Scanning Alert"), "high"), repository = 'repository.full_name' + | stats latest(action) as status, earliest(alert.created_at) as created_at, latest(alert.number) as number by repository, reason, id, type, severity, url + | eval source=type + | eval age = toString(round(now() - strptime(created_at, "%Y-%m-%dT%H:%M:%S")),"Duration") + | search severity IN("*") status IN("*") type IN("*") + | sort -age $timeTkn.earliest$ $timeTkn.latest$ @@ -27,7 +35,7 @@ repository.name repository.name - index=github_webhook alert.created_at=* | dedup repository.name | table repository.name + `github_webhooks` alert.created_at=* | dedup repository.name | table repository.name $timeTkn.earliest$ $timeTkn.latest$ @@ -62,6 +70,9 @@ + @@ -78,7 +89,7 @@ Open Alerts By Repository - | search status IN("create","created") | stats count by repository.full_name + | search status IN("create","created") | stats count by repository @@ -229,11 +240,9 @@ |search severity IN($severityTkn$) status IN($statusTkn$) type IN($typeTkn$) | sort -age - repository.full_name, reason, id, type,severity,status, created_at, age + repository, reason, id, type,severity,status, created_at, age - - https://github.com/$row.repository.full_name|n$/security/$row.source$/$row.number$ - + $row.url|n$ @@ -244,7 +253,7 @@ - {"critical":#DC4E41,"high":#F1813F,"moderate":#F8BE34} + {"critical":#DC4E41,"high":#F1813F,"moderate":#F8BE34, "medium":#F8BE34}
diff --git a/github_app_for_splunk/default/data/ui/views/value_stream_analytics.xml b/github_app_for_splunk/default/data/ui/views/value_stream_analytics.xml index 70a1de8..5cadbbc 100644 --- a/github_app_for_splunk/default/data/ui/views/value_stream_analytics.xml +++ b/github_app_for_splunk/default/data/ui/views/value_stream_analytics.xml @@ -1,7 +1,7 @@ - index=github_webhook (eventtype="GitHub::Issue" (action IN("opened","milestoned")) OR (action="labeled" AND label.name IN("in progress","to do"))) OR (eventtype="GitHub::Push" issueNumber=*) OR (eventtype="GitHub::PullRequest" action IN("opened","closed") issueNumber=*) repository.name IN("$repoTkn$") issueNumber!=9 | eval openTime=if(action=="opened",_time,NULL) | eval inProgressTime=if(action=="labeled",if('label.name'=="to do",_time,NULL),if(action=="milestoned",_time,NULL)) | eval workTime=if(action="labeled",if('label.name'="in progress",_time,NULL),if(eventtype=="GitHub::Push",_time,NULL)) | eval mergeTime=if(eventtype="GitHub::PullRequest",if(action=="opened",_time,NULL),if(eventtype="GitHub::Push",if(ref="refs/heads/main",_time,NULL),NULL)) | eval reviewTime=if(eventtype="GitHub::PullRequest",if('pull_request.merged'="true",_time,NULL),if(eventtype="GitHub::Push",if(ref="refs/heads/main",_time,NULL),NULL)) | eval sha=after | join type=left max=0 sha [ search index="github_webhook" eventtype="GitHub::Workflow" | eval sha='workflow_job.head_sha' | stats min(_time) as startTestTime, max(_time) as endTestTime by sha, workflow_job.id | eval testTimeDiff=endTestTime-startTestTime] | eval release='milestone.title' | join type=left release [search index=github_webhook eventtype="GitHub::Release" | eval release='release.tag_name' | stats max(_time) as releaseTime by release] | stats max(issue.title) as issue.title, latest(milestone.title) as release, min(openTime) as opened, min(inProgressTime) as in_progress, min(workTime) as working , max(mergeTime) as merge, max(reviewTime) as review, avg(testTimeDiff) as avgTestDuration, max(endTestTime) as endTestTime, max(releaseTime) as releaseTime by repository.name,issueNumber | search opened=* + `github_webhooks` (eventtype="GitHub::Issue" (action IN("opened","milestoned")) OR (action="labeled" AND label.name IN("in progress","to do"))) OR (eventtype="GitHub::Push" issueNumber=*) OR (eventtype="GitHub::PullRequest" action IN("opened","closed") issueNumber=*) repository.name IN("$repoTkn$") issueNumber!=9 | eval openTime=if(action=="opened",_time,NULL) | eval inProgressTime=if(action=="labeled",if('label.name'=="to do",_time,NULL),if(action=="milestoned",_time,NULL)) | eval workTime=if(action="labeled",if('label.name'="in progress",_time,NULL),if(eventtype=="GitHub::Push",_time,NULL)) | eval mergeTime=if(eventtype="GitHub::PullRequest",if(action=="opened",_time,NULL),if(eventtype="GitHub::Push",if(ref="refs/heads/main",_time,NULL),NULL)) | eval reviewTime=if(eventtype="GitHub::PullRequest",if('pull_request.merged'="true",_time,NULL),if(eventtype="GitHub::Push",if(ref="refs/heads/main",_time,NULL),NULL)) | eval sha=after | join type=left max=0 sha [ search `github_webhooks` eventtype="GitHub::Workflow" | eval sha='workflow_job.head_sha' | stats min(_time) as startTestTime, max(_time) as endTestTime by sha, workflow_job.id | eval testTimeDiff=endTestTime-startTestTime] | eval release='milestone.title' | join type=left release [search `github_webhooks` eventtype="GitHub::Release" | eval release='release.tag_name' | stats max(_time) as releaseTime by release] | stats max(issue.title) as issue.title, latest(milestone.title) as release, min(openTime) as opened, min(inProgressTime) as in_progress, min(workTime) as working , max(mergeTime) as merge, max(reviewTime) as review, avg(testTimeDiff) as avgTestDuration, max(endTestTime) as endTestTime, max(releaseTime) as releaseTime by repository.name,issueNumber | search opened=* $timeTkn.earliest$ $timeTkn.latest$ diff --git a/github_app_for_splunk/default/data/ui/views/workflow_analysis.xml b/github_app_for_splunk/default/data/ui/views/workflow_analysis.xml index 2bb9aed..887da28 100644 --- a/github_app_for_splunk/default/data/ui/views/workflow_analysis.xml +++ b/github_app_for_splunk/default/data/ui/views/workflow_analysis.xml @@ -20,7 +20,7 @@ Workflow Conclusions Over Time - index=github_webhook "workflow_run.name"="*" | spath "repository.full_name" | search repository.full_name="$repos$" | stats latest(_time) as _time, latest(workflow_run.conclusion) as workflow_run.conclusion by repository.full_name,workflow_run.name,workflow_run.id | timechart count by workflow_run.conclusion span=1h | rename null as "in-progress" + `github_webhooks` "workflow_run.name"="*" | spath "repository.full_name" | search repository.full_name="$repos$" | stats latest(_time) as _time, latest(workflow_run.conclusion) as workflow_run.conclusion by repository.full_name,workflow_run.name,workflow_run.id | timechart count by workflow_run.conclusion span=1h | rename null as "in-progress" $field1.earliest$ $field1.latest$ 1 diff --git a/github_app_for_splunk/default/data/ui/views/workflow_details.xml b/github_app_for_splunk/default/data/ui/views/workflow_details.xml index cc562c7..2662cbf 100644 --- a/github_app_for_splunk/default/data/ui/views/workflow_details.xml +++ b/github_app_for_splunk/default/data/ui/views/workflow_details.xml @@ -2,7 +2,7 @@ - index=github_webhook "workflow_run.name"="$workflowName$" | fields * | spath "repository.full_name" + `github_webhooks` "workflow_run.name"="$workflowName$" | fields * | spath "repository.full_name" $timeRange.earliest$ $timeRange.latest$ @@ -157,7 +157,7 @@ Workflow Information - index=github_webhook (workflow_run.id=$workflow_id$ OR workflow_job.run_id=$workflow_id$) | eval started=if(action=="requested", _time, null), completed=if(action=="completed", _time,null) | stats latest(workflow_run.name) as WorkflowName, latest(workflow_run.id) as WorkflowID, latest(workflow_run.conclusion) as Status, latest(repository.full_name) as RepositoryName,earliest(started) as Started, latest(completed) as Completed, latest(workflow_run.head_branch) as Branch, latest(workflow_run.event) as Trigger, latest(workflow_run.run_number) as RunNumber, latest(workflow_run.run_attempt) as Attempt, latest(workflow_run.html_url) as URL | eval Duration=tostring(Completed-Started, "Duration"), Completed=strftime(Completed,"%Y-%m-%dT%H:%M:%S"), Started=strftime(Started,"%Y-%m-%dT%H:%M:%S") | fields WorkflowName, RepositoryName, Status, WorkflowID, RunNumber, Attempt, Started, Completed, Duration, Branch, Trigger, URL|transpose|rename column AS Details| rename "row 1" AS values + `github_webhooks` (workflow_run.id=$workflow_id$ OR workflow_job.run_id=$workflow_id$) | eval started=if(action=="requested", _time, null), completed=if(action=="completed", _time,null) | stats latest(workflow_run.name) as WorkflowName, latest(workflow_run.id) as WorkflowID, latest(workflow_run.conclusion) as Status, latest(repository.full_name) as RepositoryName,earliest(started) as Started, latest(completed) as Completed, latest(workflow_run.head_branch) as Branch, latest(workflow_run.event) as Trigger, latest(workflow_run.run_number) as RunNumber, latest(workflow_run.run_attempt) as Attempt, latest(workflow_run.html_url) as URL | eval Duration=tostring(Completed-Started, "Duration"), Completed=strftime(Completed,"%Y-%m-%dT%H:%M:%S"), Started=strftime(Started,"%Y-%m-%dT%H:%M:%S") | fields WorkflowName, RepositoryName, Status, WorkflowID, RunNumber, Attempt, Started, Completed, Duration, Branch, Trigger, URL|transpose|rename column AS Details| rename "row 1" AS values 0 1 pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy