Skip to content

Commit

Permalink
Workflow to Test Action
Browse files Browse the repository at this point in the history
- Readme
- Update to Dockerfile
- Added workflow to test action
  • Loading branch information
sachasmart committed Sep 24, 2023
1 parent 58cfd82 commit a0feec4
Show file tree
Hide file tree
Showing 5 changed files with 215 additions and 39 deletions.
81 changes: 81 additions & 0 deletions .github/workflows/terrafir.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
name: Terrafir Test Action

on:
push:
branches:
- master
workflow_dispatch:
inputs:
target:
description: "Test github action"
required: false
default: "run_terrafir_github_action"
type: choice
options:
- run_terrafir_github_action
cloud_provider:
description: "Cloud provider to use"
required: true
default: "aws"
type: choice
options:
- aws
- gcp
- azure

env:
TF_LOG: INFO
CLOUD_PROVIDER: aws
REGION: us-east-2

jobs:
run_terrafir_github_action:
if: ${{ github.event.trigger != 'workflow_dispatch' || inputs.target == 'all' || inputs.target == 'run_terrafir_github_action' }}
runs-on: ubuntu-latest
name: Run Terrafir GitHub Action
defaults:
run:
working-directory: .
steps:
- name: Checkout Code
uses: actions/checkout@v2

- name: Setup Terraform
uses: hashicorp/setup-terraform@v1
with:
terraform_version: 1.5.7

- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v1
if: env.CLOUD_PROVIDER == 'aws'
with:
aws-access-key-id: ${{ secrets.ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.ACCESS_KEY }}
aws-region: ${{ env.REGION }}

- name: Configure GCP Credentials
uses: google-github-actions/[email protected]
if: env.CLOUD_PROVIDER == 'gcp'
with:
project_id: ${{ secrets.GCP_PROJECT_ID }}
service_account_key: ${{ secrets.GCP_SA_KEY }}
export_default_credentials: true

- name: Configure Azure Credentials
uses: azure/login@v1
if: env.CLOUD_PROVIDER == 'azure'
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}

- name: Save plan to Runner workspace
id: plan
run: |
terraform plan --out tfplan.binary
terraform show -json tfplan.binary > input.json
- name: Run Terrafir
uses: sachasmart/terrafir-github-action@v1
with:
path: input.json
email: ${{ secrets.TERRAFIR_EMAIL }}
apiKey: ${{ secrets.TERRAFIR_API_KEY }}
17 changes: 14 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,12 +1,23 @@
FROM golang:1.21.1-alpine3.14 AS base

FROM scratch as scratch
WORKDIR /app

COPY go.mod go.sum ./
COPY ./common ./common
COPY ./types ./types
COPY ./input.json ./input.json

FROM golang:1.21.1-alpine3.18 as base

WORKDIR /app

COPY go.mod go.sum ./
COPY main.go ./

RUN go mod download

COPY --from=scratch /app/input.json ./
COPY --from=scratch /app/common ./common
COPY --from=scratch /app/types ./types


ENTRYPOINT [ "go", "run", "main.go" ]

102 changes: 97 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# terrafir-github-action
# Terrafir Github Action
## 👋 Overview
This Github Action is used to assess Terraform plans using [Terrafir](https://www.terrafir.com). It is intended to be used in a CI/CD pipeline to assess Terraform plans before they are applied. You can see the output of the plan in the Terrafir dashboard or the Github Action output.

## 🚀 Usage
### Inputs
| Name | Description | Required |
| --- | --- | --- |
| apiKey | The API key used to authenticate with Terrafir | true |
| email | The email address of the user who owns the API key | true |
| __WIP: verbose__ | Whether or not to print the assessment to the Github Action output | false |


### Flow
Expand All @@ -9,11 +18,11 @@
title: Terrafir Github Action
---
flowchart TD
A["`__Github Action__
A["Github Action
Inputs:
- Terrafir API Key
- Plan to Assess
`"]--Spins up Docker Container - Dockerfile-->B[Container]
- Terrafir API Key (apiKey)
- Email of Terrafir Account (email)
"]--Spins up Docker Container - Dockerfile-->B[Container]
B --Make Post Request to Terrafir API-->C[Terrafir API]
C --Authorizes Request-->D[AuthService]
D -.Allow Plan Assessment.->E
Expand All @@ -22,3 +31,86 @@ flowchart TD
C --Processes Assessment and Returns Result to Container-->B
B --Receives Assessment and Creates Github Comment Output-->A
```

### Sample CI/CD Pipeline Using Terrafir Github Action
```yaml
name: Terrafir Test Action

on:
push:
branches:
- master
workflow_dispatch:
inputs:
target:
description: "Test github action"
required: false
default: "run_terrafir_github_action"
type: choice
options:
- run_terrafir_github_action
cloud_provider:
description: "Cloud provider to use"
required: true
default: "aws"
type: choice
options:
- aws
- gcp
- azure

env:
CLOUD_PROVIDER: aws
REGION: us-east-2

jobs:
run_terrafir_github_action:
if: ${{ github.event.trigger != 'workflow_dispatch' || inputs.target == 'all' || inputs.target == 'run_terrafir_github_action' }}
runs-on: ubuntu-latest
name: Run Terrafir GitHub Action
defaults:
run:
working-directory: .
steps:
- name: Checkout Code
uses: actions/checkout@v2

- name: Setup Terraform
uses: hashicorp/setup-terraform@v1
with:
terraform_version: 1.5.7

- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v1
if: env.CLOUD_PROVIDER == 'aws'
with:
aws-access-key-id: ${{ secrets.ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.ACCESS_KEY }}
aws-region: ${{ env.REGION }}

- name: Configure GCP Credentials
uses: google-github-actions/[email protected]
if: env.CLOUD_PROVIDER == 'gcp'
with:
project_id: ${{ secrets.GCP_PROJECT_ID }}
service_account_key: ${{ secrets.GCP_SA_KEY }}
export_default_credentials: true

- name: Configure Azure Credentials
uses: azure/login@v1
if: env.CLOUD_PROVIDER == 'azure'
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}

- name: Save plan to Runner workspace
id: plan
run: |
terraform plan --out tfplan.binary
terraform show -json tfplan.binary > input.json # Currently needs to output to input.json
- name: Run Terrafir
uses: sachasmart/terrafir-github-action@v1
with:
email: ${{ secrets.TERRAFIR_EMAIL }}
apiKey: ${{ secrets.TERRAFIR_API_KEY }}
```
11 changes: 4 additions & 7 deletions action.yml
Original file line number Diff line number Diff line change
@@ -1,24 +1,21 @@
name: 'Terrafir Plan Assessment'
description: 'Assess the plan file for security vulnerabilities'
description: 'Use Terrafir to assess the Terraform plan file for security vulnerabilities'
branding:
icon: 'shield'
color: 'blue'
inputs:
api-key:
apiKey:
description: 'API key for Terrafir'
required: true
email:
description: 'Email for Terrafir'
required: true
plan-file:
description: 'Path to the terraform plan file'
outputs:
time:
description: 'The time plan was assessed' #TODO
runs:
using: 'docker'
image: 'Dockerfile'
args:
- ${{ inputs.api-key }}
- ${{ inputs.email }}
- ${{ github.workspace }}/${{ inputs.plan-file }}
- ${{ inputs.apiKey }}
- ${{ inputs.email }}
43 changes: 19 additions & 24 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package main
import (
"bytes"
"encoding/json"
"flag"
"fmt"
"io"
"log"
Expand All @@ -17,17 +16,25 @@ import (
)

var (
apiKey = flag.String("apiKey", "", "API key Terrafir API.")
email = flag.String("email", "", "Email address to send the request to.")
inputFilePath = flag.String("input", "", "Input file path to the plan that will be assessed.")
verboseMode = flag.String("verbose", "", "Verbose mode")
apiKey = getEnv("INPUT_APIKEY", "")
email = getEnv("INPUT_EMAIL", "")
path = getEnv("INPUT_PATH", "")
verboseMode = getEnv("verboseMode", "")
)

func getEnv(key, defaultValue string) string {
fmt.Println(os.Environ())
value := os.Getenv(key)
if value == "" {
fmt.Print("Using default value for ", key, ": ", defaultValue, "\n")
return defaultValue
}
return value
}+

func main() {
flag.Parse()
preRequestCheck()
checkEnvironmentVariables(*apiKey, *email, *inputFilePath)
sendRequest(*apiKey, *email, *inputFilePath)
sendRequest(apiKey, email)
}

func preRequestCheck() {
Expand All @@ -43,15 +50,15 @@ func preRequestCheck() {
color.Green(fmt.Sprintf("API is available %s", response.Status))
}

func sendRequest(apiKey string, email string, inputFilePath string) {
color.Green(fmt.Sprintf("Using input file: %s", inputFilePath))
func sendRequest(apiKey string, email string) {
color.Green(fmt.Sprintf("Using input file: %s", "./input.json"))

payload := &bytes.Buffer{}
writer := multipart.NewWriter(payload)
file, errFile1 := os.Open(inputFilePath)
file, errFile1 := os.Open("./input.json")
defer file.Close()
part1,
errFile1 := writer.CreateFormFile("plan", filepath.Base(inputFilePath))
errFile1 := writer.CreateFormFile("plan", filepath.Base("./input.json"))
_, errFile1 = io.Copy(part1, file)
if errFile1 != nil {
fmt.Println(errFile1)
Expand Down Expand Up @@ -99,15 +106,3 @@ func formattedBody(body []byte) {

fmt.Println(formattedBody)
}

func checkEnvironmentVariables(apiKey string, email string, input string) {
if apiKey == "" {
log.Fatalf("API key not provided.")
}
if email == "" {
log.Fatalf("Email address not provided.")
}
if input == "" {
log.Fatalf("Input not provided.")
}
}

0 comments on commit a0feec4

Please sign in to comment.