Skip to content

Commit

Permalink
feat: revise parameters, improve error handling and checks (#51)
Browse files Browse the repository at this point in the history
  • Loading branch information
DerekRoberts authored Sep 21, 2023
1 parent a82bea9 commit 39db7a2
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 54 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/pr-closed.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
# Clean up OpenShift when PR closed, no conditions
cleanup-openshift:
name: Cleanup OpenShift
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
steps:
- name: Remove OpenShift artifacts
run: |
Expand Down
10 changes: 4 additions & 6 deletions .github/workflows/pr-open.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ jobs:
deploys:
name: Deploys
runs-on: ubuntu-latest
permissions:
packages: read
strategy:
matrix:
name: [database, backend, frontend]
Expand All @@ -27,20 +25,20 @@ jobs:
file: backend/openshift.deploy.yml
overwrite: true
parameters: -p MIN_REPLICAS=1 -p MAX_REPLICAS=2
triggers: ('backend/')
verification_path: /
penetration_test: true
verification_path: /api
- name: frontend
file: frontend/openshift.deploy.yml
overwrite: true
parameters: -p MIN_REPLICAS=1 -p MAX_REPLICAS=2
penetration_test: true
triggers: ('frontend/')
penetration_test: false
steps:
- uses: actions/checkout@v4
- name: Deploys
uses: ./
with:
file: ${{ matrix.file }}
name: ${{ matrix.name }}
oc_namespace: ${{ secrets.OC_NAMESPACE }}
oc_server: ${{ secrets.OC_SERVER }}
oc_token: ${{ secrets.OC_TOKEN }}
Expand Down
40 changes: 25 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,28 +36,21 @@ Testing has only been done with public containers on ghcr.io (GitHub Container R

# Overwrite objects using `oc apply` or only create with `oc create`
# Expected errors from `oc create` are handled with `set +o pipefail`
overwrite: true
overwrite: "true"


### Typical / recommended

# Name for any penetration test issues or artifacts
name: "frontend"

# Template parameters/variables to pass
parameters: -p PR_NO=${{ github.event.number }}
parameters: -p ZONE=${{ github.event.number }}

# Run a ZAProxy penetration test against any routes? [true/false]
# Requires `name` to be set if enabled/true
penetration_test: false

# Allow ZAProxy alerts to fail the workflow? [true/false]
penetration_test_fail: false

# Provide a name for ZAProxy workflow artifacts; e.g. frontend, backend
# Without this multiple package artifact names can collide
penetration_test_artifact: frontend

# Provide a name to enable ZAProxy issue creation; e.g. frontend, backend
# If the issue exists, it adds new comments to the existing issue.
penetration_test_issue: frontend

# Timeout seconds, only affects the OpenShift deployment (apply/create)
# Default = "15m"
timeout: "15m"
Expand Down Expand Up @@ -87,9 +80,26 @@ Testing has only been done with public containers on ghcr.io (GitHub Container R
# Useful for consuming other repos, defaults to the current one
repository: ${{ github.repository }}

# Create an issue for penetration test results? [true|false]
# Default = "true"
penetration_test_create_issue: "true"

# Allow ZAProxy alerts to fail the workflow? [true/false]
# Warning: annoying!
penetration_test_fail: false

# Specify GITHUB_TOKEN or Personal Access Token (PAT) for issue writing
# Defaults to inheriting from the calling workflow
penetration_test_token: ${{ github.token }}


### Deprecated / will fail and provide directions

# Replaced by `name` param
penetration_test_artifact: frontend

# # Replaced by `name` param
penetration_test_issue: frontend
```
# Example, Single Template
Expand Down Expand Up @@ -149,6 +159,7 @@ steps:
- name: Deploys
uses: bcgov-nr/action-deployer-openshift.yml@main
with:
name: ${{ matrix.name }}
file: ${{ matrix.file }}
oc_namespace: ${{ secrets.OC_NAMESPACE }}
oc_server: ${{ secrets.OC_SERVER }}
Expand All @@ -158,7 +169,6 @@ steps:
-p COMMON_TEMPLATE_VAR=whatever-${{ github.event.number }}
${{ matrix.parameters }}
penetration_test: true
penetration_test_issue: ${{ matrix.name }}
triggers: ${{ matrix.triggers }}
```
Expand All @@ -180,11 +190,11 @@ deploys:
oc_server: ${{ secrets.OC_SERVER }}
oc_token: ${{ secrets.OC_TOKEN }}
overwrite: true
verification_url: health
parameters:
-p MIN_REPLICAS=1 -p MAX_REPLICAS=2
-p PR_NUMBER=${{ github.event.number }}
triggers: ${{ matrix.triggers }}
verification_url: health
```
# Route Verification vs Penetration Testing
Expand Down
83 changes: 51 additions & 32 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,17 @@ inputs:
required: true

### Typical / recommended
name:
description: Name for any penetration test issues or artifacts; e.g. frontend
default: "name_unset"
parameters:
description: Template parameters/variables to pass (e.g. -p ZONE=...)
penetration_test:
description: Run a ZAProxy penetration test against any routes? [true|false]
default: "false"
penetration_test_fail:
description: Allow ZAProxy alerts to fail the workflow? [true|false]
default: "false"
penetration_test_artifact:
description: Provide a name to attach ZAProxy scan artifacts to workflows; e.g. frontend, backend
default: "unnamed"
penetration_test_issue:
description: Provide a name to enable ZAProxy issue creation; e.g. frontend, backend
default: ""
timeout:
description: Timeout for deployment. [default=15m]
default: "15m"
Expand All @@ -44,12 +42,6 @@ inputs:
verification_path:
description: Sets the health endpoint to be used during check stage, does not require the '/' at the begining
default: ""
verification_retry_attempts:
description: Number of times to attempt deployment verification
default: "3"
verification_retry_seconds:
description: Seconds to wait between deployment verification attempts
default: "10"

### Usually a bad idea / not recommended
diff_branch:
Expand All @@ -58,9 +50,24 @@ inputs:
repository:
description: Optionally, specify a different repo to clone
default: ${{ github.repository }}
penetration_test_create_issue:
description: Create an issue with penetration test results? [true|false]
default: "true"
penetration_test_token:
description: Specify token (GH or PAT), instead of inheriting one from the calling workflow
default: ${{ github.token }}
verification_retry_attempts:
description: Number of times to attempt deployment verification
default: "3"
verification_retry_seconds:
description: Seconds to wait between deployment verification attempts
default: "10"

### Deprecated
penetration_test_artifact:
description: Provide a name to attach ZAProxy scan artifacts to workflows; e.g. frontend, backend
penetration_test_issue:
description: Provide a name to enable ZAProxy issue creation; e.g. frontend, backend

runs:
using: composite
Expand All @@ -74,6 +81,7 @@ runs:
shell: bash
run: |
# Expand for inputs and variables
set -eu
# Bug mitigation - OpenShift hates images with capitals in org/repo names
REPO=${{ inputs.repository }}
Expand All @@ -83,27 +91,34 @@ runs:
exit 1
fi
# Deprecation notices
if [ ! -z ${{ inputs.penetration_test_artifact }} ]||[ ! -z ${{ inputs.penetration_test_issue }} ]; then
echo -e "Params penetration_test_artifact and penetration_test_issue have been deprecated. \n"
echo -e "Please use param: name instead. Exiting.\n"
exit 1
fi
# Process template, consuming variables/parameters
TEMPLATE="$(oc process -f ${{ inputs.file }} ${{ inputs.parameters }} --local)"
# ImageStream, DeploymentConfig and Route Host from template
DC=$(jq -rn "${TEMPLATE} | .items[] | select(.kind==\"DeploymentConfig\").metadata.name //empty")
IS=$(jq -rn "${TEMPLATE} | .items[] | select(.kind==\"ImageStream\").metadata.name //empty")
ROUTE_HOST=$(jq -rn "${TEMPLATE} | .items[] | select(.kind==\"Route\").spec.host //empty")
# Route path from inputs or template (inputs.verification_path takes priority)
ROUTE_PATH=${{ inputs.verification_path }}
[ ! -z "${ROUTE_PATH}" ]|| \
ROUTE_PATH=$(jq -rn "${TEMPLATE} | .items[] | select(.kind==\"Route\").spec.path //empty")
# Build URL from route and path, but only if ROUTE_HOST is populated
[ -z "${ROUTE_HOST}" ]|| URL_HOST_PATH="${ROUTE_HOST}/${ROUTE_PATH}"
echo imageStream=${IS} >> $GITHUB_OUTPUT
echo deploymentConfig=${DC} >> $GITHUB_OUTPUT
# Removes any double slashles, e.g. inputs.verification_path
echo url=${URL_HOST_PATH} | sed 's // / g' >> $GITHUB_OUTPUT
# Output URL (host + path), but only if ROUTE_HOST is populated
ROUTE_HOST=$(jq -rn "${TEMPLATE} | .items[] | select(.kind==\"Route\").spec.host //empty")
if [ ! -z ${ROUTE_HOST} ]; then
# Path from inputs takes priority over template
ROUTE_PATH=${{ inputs.verification_path }}
[ ! -z ${ROUTE_PATH} ]|| \
ROUTE_PATH=$(jq -rn "${TEMPLATE} | .items[] | select(.kind==\"Route\").spec.path //empty")
# Removes any duplicate slashes and pass to GITHUB_OUTPUT
URL_HOST_PATH="${ROUTE_HOST}/${ROUTE_PATH}"
echo url=${URL_HOST_PATH} | sed 's // / g' >> $GITHUB_OUTPUT
fi
# Triggers
TRIGGERS=${{ inputs.triggers }}
Expand All @@ -127,7 +142,7 @@ runs:
echo "Triggers not matched, deployment skipped"
- name: Deploy
if: steps.vars.outputs.triggered
if: steps.vars.outputs.triggered == 'true'
shell: bash
run: |
# Expand for deployment steps
Expand Down Expand Up @@ -160,7 +175,9 @@ runs:
[ -z "${DC}" ]|| oc rollout status dc/${DC} -w
- name: Route Verification
if: steps.vars.outputs.url && steps.vars.outputs.triggered &&( inputs.penetration_test != 'true' )
if: steps.vars.outputs.url &&
( steps.vars.outputs.triggered == 'true' )&&
( inputs.penetration_test != 'true' )
shell: bash
run: |
# Expand for route verification
Expand Down Expand Up @@ -189,16 +206,18 @@ runs:
exit 1
- name: Penetration Test
if: steps.vars.outputs.url && steps.vars.outputs.triggered &&( inputs.penetration_test == 'true' )
if: steps.vars.outputs.url &&
( steps.vars.outputs.triggered == 'true' )&&
( inputs.penetration_test == 'true' )
uses: zaproxy/[email protected]
with:
target: https://${{ steps.vars.outputs.url }}
allow_issue_writing: "${{ inputs.penetration_test_create_issue }}"
artifact_name: "zap_${{ inputs.name }}"
cmd_options: "-a"
fail_action: "${{ inputs.penetration_test_fail }}"
# allow_... is purposefully obscured - if a title is provided, then = true
allow_issue_writing: "${{ inputs.penetration_test_issue && true || false }}"
artifact_name: "zap_${{ inputs.penetration_test_artifact }}"
issue_title: "ZAP: ${{ inputs.penetration_test_issue }}"
issue_title: "ZAP: ${{ inputs.name }}"
target: https://${{ steps.vars.outputs.url }}
token: "${{ inputs.penetration_test_token }}"

# Action repo needs to be present for cleanup/tests
- name: Checkout to make sure action.yml is present (tests)
Expand Down

0 comments on commit 39db7a2

Please sign in to comment.