Skip to content

Commit

Permalink
Add additional tests (#9)
Browse files Browse the repository at this point in the history
* add tests

* update docs

* update docs

* update docs

* update docs
  • Loading branch information
Zac Rosenbauer authored Apr 11, 2021
1 parent 22f0dae commit e9b6efb
Show file tree
Hide file tree
Showing 7 changed files with 171 additions and 10 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/monitor.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
uses: bluenovaio/action-tls-monitor@main
with:
domain: ${{ matrix.domain }}
expiration_days: "700"
expiration_days: "7"
approved_protocols: TLSv1.2,TLSv1.3
alert_method: slack
alert_token: ${{ secrets.SLACK_WEBHOOK_URL_OPS }}
Expand Down
21 changes: 17 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ Monitor SSL/TLS certificates for your domains.

You can run against a single domain or use the matrix strategy to run against multiple domains.

**Single Domain**
#### Single Domain

```yaml
name: SSL/TLS Monitor
on:
Expand All @@ -31,7 +32,8 @@ jobs:
alert_token: ${{ secrets.SLACK_WEBHOOK_URL }}
```
**Multiple Domains**
#### Multiple Domains
```yaml
name: SSL/TLS Monitor
on:
Expand Down Expand Up @@ -60,5 +62,16 @@ jobs:
## Alerting
Alerting is built in to this action but its also possible to just use the outputs to send your own alerts or do
another action (i.e. trigger a certificate update/renewal). Currently, only [slack](https://slack.com) is supported.
Alerting is built in to this action. It is also possible to ignore the alerts and use the outputs to send your own alerts or do
another action (i.e. trigger a certificate update/renewal).
### Slack Alerts
Slack is supported out of the box. The alerts are formatted and have a default emoji and name. You should start to see alerts
similar to the below image if an issue is found.
<details><summary>Slack Alert Example</summary>
![Slack Alert](/docs/images/alert-slack.png)
</details>
Binary file added docs/images/alert-slack.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
89 changes: 89 additions & 0 deletions src/lib/__tests__/validate.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { validate } from '../validate';
import { Protocol, TLSInfo } from '../tls';

const ONE_DAY_MS = 1000 * 60 * 60 * 24;

const exampleInput = {
expirationDays: 7,
approvedProtocols: [Protocol.TLSv1dot2, Protocol.TLSv1dot3],
tlsInfo: {
validFrom: new Date(Date.now() - (ONE_DAY_MS * 300)),
validTo: new Date(Date.now() + (ONE_DAY_MS * 30)),
protocol: Protocol.TLSv1dot3
} as TLSInfo
};

describe('validate', () => {
it('returns errorMessage for non-approved Protocol', () => {
expect(validate({
...exampleInput,
tlsInfo: {
...exampleInput.tlsInfo,
protocol: Protocol.TLSv1dot1
}
})).toEqual({
expired: false,
expiresSoon: false,
protocolNotApproved: true,
errorMessage: 'Issues found with certificate - Invalid protocol: TLSv1.1'
});
});

it('returns errorMessage for missing Protocol', () => {
expect(validate({
...exampleInput,
tlsInfo: {
...exampleInput.tlsInfo,
protocol: null
}
})).toEqual({
expired: false,
expiresSoon: false,
protocolNotApproved: true,
errorMessage: 'Issues found with certificate - Invalid protocol: unknown'
});
});

it('returns errorMessage expired certificate', () => {
expect(validate({
...exampleInput,
tlsInfo: {
...exampleInput.tlsInfo,
validTo: new Date(Date.now() - (ONE_DAY_MS * 3))
}
})).toEqual({
expired: true,
expiresSoon: false,
protocolNotApproved: false,
errorMessage: 'Issues found with certificate - Certificate has expired'
});
});

it('returns errorMessage for soon to expire certificate', () => {
expect(validate({
...exampleInput,
expirationDays: 40
})).toEqual({
expired: false,
expiresSoon: true,
protocolNotApproved: false,
errorMessage: 'Issues found with certificate - Certificate will expire in less than 40 days'
});
});

it('returns multiple errorMessages if applicable', () => {
expect(validate({
...exampleInput,
expirationDays: 40,
tlsInfo: {
...exampleInput.tlsInfo,
protocol: null
}
})).toEqual({
expired: false,
expiresSoon: true,
protocolNotApproved: true,
errorMessage: 'Issues found with certificate - Invalid protocol: unknown, Certificate will expire in less than 40 days'
});
});
});
59 changes: 59 additions & 0 deletions src/lib/alerts/__tests__/slack.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import * as slack from '../slack';

const validTo = (new Date()).toISOString();
const validFrom = (new Date()).toISOString();

describe('buildMessage', () => {
it('returns a built message', () => {
expect(slack.buildMessage({
domain: 'example.com',
errorMessage: 'An error of some kind',
validTo,
validFrom,
protocol: 'TLSv1.3'
})).toEqual({
icon_emoji: ':warning:',
username: 'SSL/TLS Monitor',
blocks: [
{
type: 'header',
text: {
type: 'plain_text',
text: 'SSL/TLS Monitor Alert',
emoji: true
}
},
{
type: 'section',
fields: [
{
type: 'mrkdwn',
text: `*Domain:*\n<example.com|example.com>`
},
{
type: 'mrkdwn',
text: `*Error:*\nAn error of some kind`
}
]
},
{
type: 'section',
fields: [
{
type: 'mrkdwn',
text: `*Valid To:*\n${validTo}`
},
{
type: 'mrkdwn',
text: `*Valid From:*\n${validFrom}`
},
{
type: 'mrkdwn',
text: `*Protocol:*\nTLSv1.3`
}
]
}
]
});
});
});
4 changes: 2 additions & 2 deletions src/lib/alerts/slack.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { IncomingWebhook } from '@slack/webhook';
import { IncomingWebhook, IncomingWebhookSendArguments } from '@slack/webhook';

import { AlertInput } from './types';

function buildMessage (input: AlertInput) {
export function buildMessage (input: AlertInput): IncomingWebhookSendArguments {
return {
icon_emoji: ':warning:',
username: 'SSL/TLS Monitor',
Expand Down
6 changes: 3 additions & 3 deletions src/lib/validate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ interface ValidationResult {
errorMessage: string | null;
}

function getDaysBetweenDates (date1: Date, date2: Date) {
export function getDaysBetweenDates (date1: Date, date2: Date): number {
const difference = date1.getTime() - date2.getTime();
return Math.ceil(difference / (1000 * 60 * 60 * 24));
}
Expand All @@ -34,7 +34,7 @@ export function validate (input: ValidationInput): ValidationResult {
expired = true;
}

if (getDaysBetweenDates(input.tlsInfo.validTo, new Date()) <= input.expirationDays) {
if (!expired && getDaysBetweenDates(input.tlsInfo.validTo, new Date()) <= input.expirationDays) {
errors.push(`Certificate will expire in less than ${input.expirationDays} days`);
expiresSoon = true;
}
Expand All @@ -43,6 +43,6 @@ export function validate (input: ValidationInput): ValidationResult {
expired,
expiresSoon,
protocolNotApproved,
errorMessage: errors.length ? `Issues found with certificate: ${errors.join(', ')}` : null
errorMessage: errors.length ? `Issues found with certificate - ${errors.join(', ')}` : null
};
}

0 comments on commit e9b6efb

Please sign in to comment.