Skip to content

Commit

Permalink
Merge pull request #6 from instriq/develop
Browse files Browse the repository at this point in the history
refactor(core): migrate to Perl and modularize codebase
  • Loading branch information
htrgouvea authored Nov 25, 2024
2 parents 74cf3b2 + f917777 commit 708f796
Show file tree
Hide file tree
Showing 21 changed files with 526 additions and 229 deletions.
6 changes: 3 additions & 3 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
version: 2
updates:
- package-ecosystem: "pip"
directory: "/"
- package-ecosystem: github-actions
directory: /
schedule:
interval: "weekly"
interval: weekly
12 changes: 8 additions & 4 deletions .github/workflows/dependabot_metrics.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,14 @@ jobs:
WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}

steps:
- uses: actions/checkout@v4
- name: Checkout repository
uses: actions/checkout@v4

- name: Install dependencies
run: |
pip install -r requirements.txt
- name: Test the basic usage
cpanm --installdeps .
- name: Run DependaBot metrics and send to Slack
run: |
python3 scripts/dependabot_metrics.py --org $ORGANIZATION --token $TOKEN | python3 scripts/slack_webhook.py --webhook $WEBHOOK
message=$(perl sentra.pl -o $ORGANIZATION -t $TOKEN)
perl sentra.pl -w $WEBHOOK -m "$message"
12 changes: 8 additions & 4 deletions .github/workflows/maintaned.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,14 @@ jobs:
WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}

steps:
- uses: actions/checkout@v4
- name: Checkout repository
uses: actions/checkout@v4

- name: Install dependencies
run: |
pip install -r requirements.txt
- name: Test the basic usage
cpanm --installdeps .
- name: Check maintained repositories and send to Slack
run: |
python3 scripts/search_files.py --org $ORGANIZATION --token $TOKEN --maintained | python3 scripts/slack_webhook.py --webhook $WEBHOOK
message=$(perl sentra.pl -o $ORGANIZATION -t $TOKEN --maintained)
perl sentra.pl -w $WEBHOOK -m "$message"
14 changes: 9 additions & 5 deletions .github/workflows/search_files.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Search for dependabot files
name: Search for DependaBot files

on:
schedule:
Expand All @@ -13,10 +13,14 @@ jobs:
WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}

steps:
- uses: actions/checkout@v4
- name: Checkout repository
uses: actions/checkout@v4

- name: Install dependencies
run: |
pip install -r requirements.txt
- name: Test the basic usage
cpanm --installdeps .
- name: Search for DependaBot files and send to Slack
run: |
python3 scripts/search_files.py --org $ORGANIZATION --token $TOKEN --dependency | python3 scripts/slack_webhook.py --webhook $WEBHOOK
message=$(perl sentra.pl -o $ORGANIZATION -t $TOKEN --dependency)
perl sentra.pl -w $WEBHOOK -m "$message"
28 changes: 28 additions & 0 deletions .github/workflows/test_suite.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Test Suite

on:
pull_request:
branches:
- main
- develop

jobs:
test:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Setup Perl
run: |
sudo apt-get update
sudo apt-get install -y perl
sudo apt-get install -y cpanminus
- name: Install dependencies
run: sudo cpanm --installdeps --with-test .

- name: Run tests
working-directory: ./tests
run: prove -r
5 changes: 5 additions & 0 deletions .perlcriticrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
severity = 3

[-TestingAndDebugging::RequireUseStrict]
[-TestingAndDebugging::RequireUseWarnings]
[-Subroutines::ProhibitManyArgs]
55 changes: 38 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<p align="center">
<h3 align="center"><b>Runbooks</b></h3>
<p align="center">Some automates to help in day-by-day ops.</p>
<h3 align="center"><b>Sentra</b></h3>
<p align="center">The first autonomous source code posture risk score tool.</p>
<p align="center">
<a href="https://github.com/instriq/runbooks/blob/master/LICENSE.md">
<a href="https://github.com/instriq/sentra/blob/master/LICENSE.md">
<img src="https://img.shields.io/badge/license-MIT-blue.svg">
</a>
</p>
Expand All @@ -12,38 +12,59 @@

### Summary

This repository is a concentration of several scripts that were developed during some day-to-day operations, to help gain speed and increase the maturity of security processes. These are scripts that can be used independently or together.
Sentra is a collection of Perl modules designed to help gain speed and increase the maturity of security processes. These modules can be used independently or together to analyze GitHub repositories, manage Dependabot alerts, and send notifications via Slack.

---

### Scripts
### Modules

| Name | Description |
-------|-------------|
| dependabot_metrics.py | Fetches and analyzes DependaBot alerts from GitHub repositories of a specified organization. |
| slack_webhook.py | An output forwarder script for webhooks. |
| classify_pull_requests.py | PR classification based on SemVer approach |
|------|-------------|
| DependabotMetrics | Fetches and analyzes Dependabot alerts from GitHub repositories of a specified organization. |
| SearchFiles | Checks repositories for specific files and last update times. |
| SlackWebhook | An output forwarder for sending messages to Slack via webhooks. |

---

### Download
### Installation

```bash
# Download
$ git clone https://github.com/instriq/runbooks && cd runbooks

# Install libs dependencies
$ pip3 install -r requirements.txt
# Clone the repository
$ git clone https://github.com/instriq/sentra && cd sentra

# Install Perl module dependencies
$ cpanm --installdeps .
```

---

### Usage

```
$ perl sentra.pl
Sentra v0.0.1
Core Commands
==============
Command Description
------- -----------
-o, --org Specify the name of the organization
-t, --token Set the GitHub Token to use during actions
-w, --webhook Set the webhook address for Slack
-m, --message Message to send via Slack webhook
-mt, --maintained Check last commit date of repositories
-d, --dependency Check for dependabot.yaml file in repositories
-p, --per_page Set the number of items per page in API requests (default: 100)
```

---

### Contribution

Your contributions and suggestions are heartily ♥ welcome. [See here the contribution guidelines.](/.github/CONTRIBUTING.md) Please, report bugs via [issues page](https://github.com/instriq/runbooks/issues) and for security issues, see here the [security policy.](/SECURITY.md) (✿ ◕‿◕)
Your contributions and suggestions are heartily ♥ welcome. [See here the contribution guidelines.](/.github/CONTRIBUTING.md) Please, report bugs via [issues page](https://github.com/instriq/sentra/issues) and for security issues, see here the [security policy.](/SECURITY.md) (✿ ◕‿◕)

---

### License

This work is licensed under [MIT License.](/LICENSE.md)
This work is licensed under [MIT License.](/LICENSE.md)
11 changes: 11 additions & 0 deletions cpanfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
requires "Getopt::Long", "2.54";
requires "Mojo::UserAgent";
requires "Mojo::JSON";
requires "DateTime";
requires "DateTime::Format::ISO8601";

on 'test' => sub {
requires "Test::More";
requires "Test::MockModule";
requires "Mojo::Transaction::HTTP";
};
66 changes: 66 additions & 0 deletions lib/Sentra/Engine/DependabotMetrics.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package Sentra::Engine::DependabotMetrics {
use strict;
use warnings;
use Mojo::UserAgent;
use Mojo::JSON qw(decode_json);

sub new {
my ($class, $org, $token, $per_page) = @_;

my $ua = Mojo::UserAgent->new;
my $headers = {
'X-GitHub-Api-Version' => '2022-11-28',
'Accept' => 'application/vnd.github+json',
'User-Agent' => 'Sentra 0.0.1',
'Authorization' => "Bearer $token"
};

my @repos;
my $repo_page = 1;
while (1) {
my $repo_url = "https://api.github.com/orgs/$org/repos?per_page=$per_page&page=$repo_page";
my $repo_tx = $ua->get($repo_url => $headers);

my $res = $repo_tx->result or return "Error fetching repositories: " . $repo_tx->error->{message} . "\n";
$res->is_success or return "Error fetching repositories: " . $res->message . "\n";

my $repo_data = $res->json;
last unless @$repo_data;
push @repos, map { "$org/$_->{name}" } grep { !$_->{archived} } @$repo_data;
$repo_page++;
}

return "Error when trying to request information from GitHub, please review the parameters provided." unless @repos;

my $total_alerts = 0;
my %severity_count = (low => 0, medium => 0, high => 0, critical => 0);

for my $repo (@repos) {
my $alert_page = 1;
while (1) {
my $alert_url = "https://api.github.com/repos/$repo/dependabot/alerts?state=open&per_page=$per_page&page=$alert_page";
my $alert_tx = $ua->get($alert_url => $headers);

my $res = $alert_tx->result or return "Error fetching alerts for $repo: " . $alert_tx->error->{message} . "\n";
$res->is_success or return "Error fetching alerts for $repo: " . $res->message . "\n";

my $alert_data = $res->json;
last unless @$alert_data;
$total_alerts += scalar @$alert_data;
for my $alert (@$alert_data) {
my $severity = $alert->{security_vulnerability}{severity} || 'unknown';
$severity_count{$severity}++ if exists $severity_count{$severity};
}
$alert_page++;
}
}

my $output = "";
$output .= "Severity $_: $severity_count{$_}\n" for keys %severity_count;
$output .= "Total DependaBot Alerts: $total_alerts\n";

return $output;
}
}

1;
59 changes: 59 additions & 0 deletions lib/Sentra/Engine/SearchFiles.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package Sentra::Engine::SearchFiles {
use strict;
use warnings;
use Mojo::UserAgent;
use Mojo::JSON qw(decode_json);
use DateTime;
use DateTime::Format::ISO8601;

sub new {
my ($class, $org, $token, $maintained, $dependency, $per_page) = @_;

my $ua = Mojo::UserAgent->new;
my $headers = {
'Authorization' => "Bearer $token",
'Accept' => 'application/vnd.github+json',
'X-GitHub-Api-Version' => '2022-11-28'
};

my $output = '';

my $repo_url = "https://api.github.com/orgs/$org/repos?per_page=$per_page";
my $repo_tx = $ua->get($repo_url => $headers);

my $res = $repo_tx->result or return "Error fetching repositories: " . $repo_tx->error->{message} . "\n";
$res->is_success or return "Error fetching repositories: " . $res->message . "\n";

my $repos = $res->json;
for my $repo (@$repos) {
next if $repo->{archived};
my $full_name = "$org/$repo->{name}";

if ($dependency) {
my $dependabot_url = "https://api.github.com/repos/$full_name/contents/.github/dependabot.yaml";
my $dependabot_tx = $ua->get($dependabot_url => $headers);
$output .= "The dependabot.yml file was not found in this repository: https://github.com/$full_name\n"
if $dependabot_tx->result->code == 404;
}

if ($maintained) {
my $commits_url = "https://api.github.com/repos/$full_name/commits";
my $commits_tx = $ua->get($commits_url => $headers);
my $commits_res = $commits_tx->result;
if ($commits_res && $commits_res->is_success) {
my $commits = $commits_res->json;
if (@$commits) {
my $last_commit_date_str = $commits->[0]{commit}{committer}{date};
my $last_commit_date = DateTime::Format::ISO8601->parse_datetime($last_commit_date_str);
$output .= "The repository https://github.com/$full_name has not been updated for more than 90 days.\n"
if DateTime->now->subtract(days => 90) > $last_commit_date;
}
}
}
}

return $output || "No issues found.";
}
}

1;
29 changes: 29 additions & 0 deletions lib/Sentra/Engine/SlackWebhook.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package Sentra::Engine::SlackWebhook {
use strict;
use warnings;
use Mojo::UserAgent;
use Mojo::JSON qw(encode_json);

sub new {
my ($class, $message, $webhook) = @_;

my $ua = Mojo::UserAgent->new;
my $payload = encode_json({text => $message});

my $tx = $ua->post($webhook => {
'Content-Type' => 'application/json'
} => $payload);

my $res = $tx->result;
unless ($res) {
my $err = $tx->error;
return "Failed to send message: [" . ($err->{message} || "Unknown error") . "]\n";
}

return "Failed to send message: [" . $res->message . "]\n" unless $res->is_success;

return "Message sent successfully! [" . $res->body . "]\n";
}
}

1;
25 changes: 25 additions & 0 deletions lib/Sentra/Utils/Helper.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package Sentra::Utils::Helper {
use strict;
use warnings;

sub new {
return <<"EOT";
Sentra v0.0.1
Core Commands
==============
Command Description
------- -----------
-o, --org Specify the name of the organization
-t, --token Set the GitHub Token to use during actions
-w, --webhook Set the webhook address for Slack
-m, --message Message to send via Slack webhook
-mt, --maintained Check last commit date of repositories
-d, --dependency Check for dependabot.yaml file in repositories
-p, --per_page Set the number of items per page in API requests (default: 100)
EOT
}
}

1;
3 changes: 0 additions & 3 deletions requirements.txt

This file was deleted.

Loading

0 comments on commit 708f796

Please sign in to comment.