Skip to content

Commit

Permalink
new_entry_point
Browse files Browse the repository at this point in the history
  • Loading branch information
patoroco committed Oct 13, 2023
1 parent 81e1fb9 commit 06b2541
Show file tree
Hide file tree
Showing 14 changed files with 400 additions and 23,865 deletions.
13 changes: 9 additions & 4 deletions .prettierrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,15 @@
"printWidth": 120,
"tabWidth": 2,
"useTabs": false,
"semi": true,
"singleQuote": false,
"semi": false,
"singleQuote": true,
"quoteProps": "as-needed",
"jsxSingleQuote": false,
"trailingComma": "none",
"bracketSpacing": false,
"bracketSpacing": true,
"bracketSameLine": true,
"arrowParens": "avoid",
"parser": "typescript"
"proseWrap": "always",
"htmlWhitespaceSensitivity": "css",
"endOfLine": "lf"
}
123 changes: 123 additions & 0 deletions __ignore__/digitalocean.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import { createApiClient, modules } from 'dots-wrapper'
import { IListRequest } from 'dots-wrapper/dist/types/list-request'

import { ActionConfig } from './utils'

import { IFirewallInboundRule, IFirewallOutboundRule } from 'dots-wrapper/dist/modules/firewall'

interface ClientInterface {
firewall: Readonly<{
getFirewall: ({
firewall_id
}: modules.firewall.IGetFirewallApiRequest) => Promise<Readonly<modules.firewall.GetFirewallResponse>>
listFirewalls: ({ page, per_page }: IListRequest) => Promise<Readonly<modules.firewall.ListFirewallsResponse>>
updateFirewall: ({
droplet_ids,
id,
inbound_rules,
name,
outbound_rules,
tags
}: modules.firewall.IFirewall) => Promise<Readonly<modules.firewall.UpdateFirewallResponse>>
}>
}

export function getDOClient(config: ActionConfig) {
return createApiClient({ token: config.DO_TOKEN })
}

export async function getFirewall({ firewall: firewallClient }: ClientInterface, name: string) {
const {
data: { firewalls }
} = await firewallClient.listFirewalls({})

const firewall = firewalls.find(f => f.name == name)
if (firewall == undefined) {
throw new Error(`The firewall with name '${name}', doesn't exist.`)
}

return firewall
}

function applyRule(config: ActionConfig, rule: IFirewallInboundRule = { protocol: '', ports: '', sources: {} }) {
const cloneRule = { ...rule }
const { port, action, protocol, IP } = config

if (rule.ports != port.toString() || rule.protocol != protocol) return cloneRule

if (!cloneRule.sources.addresses) {
cloneRule.sources.addresses = []
}
const addresses = cloneRule.sources.addresses
if (action == 'add') {
if (!addresses.includes(IP)) {
addresses.push(IP)
}
} else if (action == 'remove') {
cloneRule.sources.addresses = addresses.filter(address => address != IP)
}

return cloneRule
}

export function generateInboundRules(oldRules: IFirewallInboundRule[], config: ActionConfig): IFirewallInboundRule[] {
const { port, action, protocol } = config
const existingRules = oldRules.filter(r => r.ports == port.toString() && r.protocol == protocol)

if (!existingRules.length) {
oldRules.push(applyRule(config))
return oldRules
}

return oldRules.map((r, index) => {
if (action == 'remove' || (action == 'add' && index == 0)) {
return applyRule(config, r)
} else {
return r
}
})
}

export async function updateInboundRules(
{ firewall: firewallClient }: ClientInterface,
firewall: modules.firewall.IFirewall,
inboundRules: IFirewallInboundRule[],
dryrun = true
) {
printFirewallRules(inboundRules, '(updated)')

if (dryrun) {
return
}

const updated = {
...firewall,
inbound_rules: inboundRules,
outbound_rules: prepareOutboundRules(firewall.outbound_rules)
}

const {
data: { firewall: response }
} = await firewallClient.updateFirewall(updated)

console.log((response as any).status)
}

export function printFirewallRules(inboundRules: IFirewallInboundRule[], title = '') {
console.log('----------------------')
console.log(`Firewall Inbound Rules ${title}`)
console.log('----------------------')
inboundRules.forEach(rule => {
console.log(`${rule.ports}::${rule.protocol} - ${rule.sources.addresses}`)
})
}

function prepareOutboundRules(outboundRules: IFirewallOutboundRule[]): IFirewallOutboundRule[] {
return outboundRules.map(rule => {
const clonedRule = { ...rule }
if (clonedRule.ports == 'all') {
clonedRule.ports = '0'
}
return clonedRule
})
}
22 changes: 11 additions & 11 deletions src/main.ts → __ignore__/main.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {getConfig, ActionConfig} from "./utils";
import {getDOClient, getFirewall, generateInboundRules, updateInboundRules, printFirewallRules} from "./digitalocean";
import { getConfig, ActionConfig } from './utils'
import { getDOClient, getFirewall, generateInboundRules, updateInboundRules, printFirewallRules } from './digitalocean'

async function main() {
// const config: ActionConfig = {
Expand All @@ -12,19 +12,19 @@ async function main() {
// firewallName: "ubuntu-dokku"
// };

const config = await getConfig();
const config = await getConfig()

console.log(`Current IP: ${config.IP}`);
console.log(`Current IP: ${config.IP}`)
if (config.dryrun) {
console.log("Running in DryRun MODE...");
console.log('Running in DryRun MODE...')
}

const client = getDOClient(config);
const firewall = await getFirewall(client, config.firewallName);
printFirewallRules(firewall.inbound_rules, "(original)");
const client = getDOClient(config)
const firewall = await getFirewall(client, config.firewallName)
printFirewallRules(firewall.inbound_rules, '(original)')

const newRules = generateInboundRules(firewall.inbound_rules, config);
await updateInboundRules(client, firewall, newRules, config.dryrun);
const newRules = generateInboundRules(firewall.inbound_rules, config)
await updateInboundRules(client, firewall, newRules, config.dryrun)
}

main();
main()
60 changes: 60 additions & 0 deletions __ignore__/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import * as core from '@actions/core'
import fetch from 'node-fetch'

export interface ActionConfig {
DO_TOKEN: string
firewallName: string
action: 'add' | 'remove'
IP: string
port: number
protocol: 'tcp' | 'udp'
dryrun: boolean
}

export async function getConfig(): Promise<ActionConfig> {
const token = core.getInput('digitaloceanToken')
if (token == undefined || token.length == 0) {
throw new Error("You must specify the 'digitaloceanToken' input.")
}

const firewallName = core.getInput('firewallName')
if (firewallName == undefined || firewallName.length == 0) {
throw new Error("You must specify the 'firewallName' input.")
}

const action = core.getInput('actionToDo')
if (action != 'add' && action != 'remove') {
throw new Error(`The input 'actionToDo' must one of these values: 'add' or 'remove'. Current value: '${action}'`)
}

const port = parseInt(core.getInput('port'))
if (core.getInput('port').length == 0 || port <= 0) {
throw new Error("The input 'port' must be a number greater than 0.")
}

const protocol = core.getInput('protocol')
if (protocol != 'tcp' && protocol != 'udp') {
throw new Error(`The input 'protocol' must be 'tcp' or 'udp'. Current value: ${protocol}`)
}

const dryrun = core.getInput('dryRun') == 'true'

// TODO: try/catch for getting the IP
const IP = await getLocalIP()

return {
DO_TOKEN: token,
firewallName,
action,
IP,
port,
protocol,
dryrun
}
}

// TODO: remove the export here and test the full configuration
export async function getLocalIP(): Promise<string> {
const response = await fetch('https://ifconfig.me/ip')
return response.text()
}
15 changes: 15 additions & 0 deletions __tests__/main.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import fetch from 'node-fetch'
import { getLocalIP } from '../src/utils'

const { Response } = jest.requireActual('node-fetch')
jest.mock('node-fetch', () => jest.fn())

test('pass correctly the IP address', async () => {
const mockedFetch = fetch as jest.MockedFunction<typeof fetch>
mockedFetch.mockImplementationOnce(() => new Response('12.34.56.78'))

const localIP = await getLocalIP()
expect(localIP).toBe('12.34.56.78')
})

//TODO: test what happens when the connection fails
2 changes: 1 addition & 1 deletion action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,5 @@ inputs:
default: false

runs:
using: "node12"
using: "node20"
main: "dist/index.js"
Loading

0 comments on commit 06b2541

Please sign in to comment.