Skip to content

OSS_pygoat-devsecops-basic #7

OSS_pygoat-devsecops-basic

OSS_pygoat-devsecops-basic #7

name: OSS_pygoat-devsecops-basic
on:
# push:
# branches:
# - main
workflow_dispatch:
permissions:
id-token: write
contents: read
env:
#DEFECTDOJO_PRODUCTID: 4
# basic settings
useCommonDefectDojoProduct: true # for DEMO purposes
pushDockerImage: false # for DEMO purposes
continue-on-error: true # for DEMO purposes
# # advanced settings
# useCommonDefectDojoProduct: false # advanced setting
# pushDockerImage: true # advanced setting
# continue-on-error: false # advanced setting
useAzureCliForK8s: false
doImageScanWithDockerHubScout: false
adjustDNS: false
listArtifacts: true
DEFECTDOJO_URL: https://defectdojo-002.cad4devops.com:8443/api/v2
DEFECTDOJO_COMMONUSER: Student000
DEFECTDOJO_COMMONPRODUCTNAME: GitHub-OSS-pygoat-devsecops-workshop-001-product-000
DEFECTDOJO_TOKEN: ${{ secrets.DEFECTDOJO_TOKEN }}
appUrl: http://gh-pygoat-test.cad4devops.com
containerName: owaspzapproxy
doActiveScan: false
dockerWaitTime: 30s
tag: "${{ github.run_id }}"
host: gh-pygoat-test.cad4devops.com
kubernetesServiceConnection: OSS_Microk8s
loopWaitTime: 10s
maxAlerts: 5000
owaspImageName: softwaresecurityproject/zap-stable
owaspZapApiPort: 8090
owaspZapWebPort: 8080
owaspzap-report-json: owasp-zap.json
owaspzap-report-sarif: owasp-zap.sarif
sarifTemplate: sarif-json
traditionalJsonTemplate: traditional-json
jobs:
build-build_and_push_app:
name: Build and Push App
runs-on: ubuntu-latest
env:
image: ${{ vars.DOCKER_USERNAME }}.azurecr.io/devsecops-pygoat
environment:
name: dev
steps:
- name: Fixes docker image name if not being pushed to Azure Container Registry
run: |-
echo "image=devsecops-pygoat" >> $GITHUB_ENV
if: vars.DOCKER_USERNAME == ''
- name: test action get auth token
if: env.useCommonDefectDojoProduct == 'true'
run: |-
echo "testing action"
# get token from common user
echo "DEFECTDOJO_COMMONUSER: ${{ env.DEFECTDOJO_COMMONUSER }}"
echo "DEFECTDOJO_COMMONPASSWORD: ${{ secrets.DEFECTDOJO_COMMONPASSWORD }}"
# throw error if token is not set
if [ -z "${{ secrets.DEFECTDOJO_COMMONPASSWORD }}" ]; then
echo "Error: DEFECTDOJO_COMMONPASSWORD is not set. Please set the secret in the dev environment."
exit 1
fi
DEFECTDOJO_TOKEN_COMMON=`curl --fail --location --request POST "${{ env.DEFECTDOJO_URL }}/api-token-auth/" \
--header 'Content-Type: application/json' \
--data-raw "{
\"username\": \"${{ env.DEFECTDOJO_COMMONUSER }}\",
\"password\": \"${{ secrets.DEFECTDOJO_COMMONPASSWORD }}\"
}" | jq -r '.token'`
if [ -z "${DEFECTDOJO_TOKEN_COMMON}" ]; then
echo "Error: Failed to get token from common user ${{ env.DEFECTDOJO_COMMONUSER }}. Please check the credentials."
exit 1
else
#echo "DEFECTDOJO_TOKEN: $DEFECTDOJO_TOKEN_COMMON"
echo "DEFECTDOJO_TOKEN is set"
echo "DEFECTDOJO_TOKEN=$DEFECTDOJO_TOKEN_COMMON" >> $GITHUB_ENV
exit 0
fi
- name: test action get product id
if: env.useCommonDefectDojoProduct == 'true'
run: |-
echo "testing action"
# now get the product id
echo "DEFECTDOJO_COMMONPRODUCTNAME: ${{ env.DEFECTDOJO_COMMONPRODUCTNAME }}"
DEFECTDOJO_PRODUCTID_COMMON=`curl --fail --location --request GET "${{ env.DEFECTDOJO_URL }}/products/?name=${{ env.DEFECTDOJO_COMMONPRODUCTNAME }}" \
--header "Authorization: Token ${{ env.DEFECTDOJO_TOKEN }}" | jq -r '.results[0].id'`
if [ -z "${DEFECTDOJO_PRODUCTID_COMMON}" ]; then
echo "Error: Failed to get product id for ${{ env.DEFECTDOJO_COMMONPRODUCTNAME }}. Please check the product name."
exit 1
else
echo "DEFECTDOJO_PRODUCTID: $DEFECTDOJO_PRODUCTID_COMMON"
echo "DEFECTDOJO_PRODUCTID is set"
echo "DEFECTDOJO_PRODUCTID=$DEFECTDOJO_PRODUCTID_COMMON" >> $GITHUB_ENV
exit 0
fi
- name: test env settings
if: env.useCommonDefectDojoProduct == 'true'
run: |-
#echo $DEFECTDOJO_TOKEN
#echo ${{ env.DEFECTDOJO_TOKEN }}
echo $DEFECTDOJO_PRODUCTID
echo ${{ env.DEFECTDOJO_PRODUCTID }}
- name: checkout
uses: actions/[email protected]
- name: Setup Python
uses: actions/[email protected]
with:
python-version: "3.8"
architecture: x64
- name: Install Dependencies
run: pip install -r requirements.txt
- name: Check some variables
run: |-
echo "DOCKER_REGISTRY: ${{ vars.DOCKER_USERNAME }}.azurecr.io, DOCKER_USERNAME: ${{ vars.DOCKER_USERNAME }}"
echo "DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}"
- name: Build Docker image
run: docker build . --file "Dockerfile" -t ${{ env.image }}:${{ github.run_id }} -t ${{ env.image }}:latest
- name: Docker Login
if: env.pushDockerImage == 'true'
uses: docker/[email protected]
with:
registry: "${{ vars.DOCKER_USERNAME }}.azurecr.io"
username: "${{ vars.DOCKER_USERNAME }}"
password: "${{ secrets.DOCKER_PASSWORD }}"
- name: Push Docker image ${{ env.image }}:${{ github.run_id }}
if: env.pushDockerImage == 'true'
run: docker push ${{ env.image }}:${{ github.run_id }}
- name: Push Docker image ${{ env.image }}:latest
if: env.pushDockerImage == 'true'
run: docker push ${{ env.image }}:latest
test-run_devopsshield_scan_linux:
name: Run DevOps Shield Scan Linux
needs:
- build-build_and_push_app
runs-on: ubuntu-latest
environment:
name: dev
steps:
- name: checkout
uses: actions/[email protected]
- name: DevOps Shield Security Scanner Linux
run: |-
# Run DevOps Shield CLI with dosType=GitHub for current repository
echo "Current Repo: ${{ github.repository }}"
echo "Current Org: ${{ github.repository_owner }}"
echo "GitHub Token: ${{ secrets.TOKEN_FOR_DOS }}"
# throw error if token is not set
if [ -z "${{ secrets.TOKEN_FOR_DOS }}" ]; then
echo "Error: TOKEN_FOR_DOS is not set. Please set the secret in the dev environment. You need to create a personal access token (classic). In general, you only need read permissions."
exit 1
fi
# check os linux or windows
echo "Linux OS"
docker run --name devopsshield \
-v "${{ github.workspace }}:/devopsshield" \
--rm -t \
-e dosOrganizationName=${{ github.repository_owner }} \
-e dosPatToken=${{ secrets.TOKEN_FOR_DOS }} \
-e dosType=GitHub \
devopsshield/devopsshield
ls ${{ github.workspace }}
cat ${{ github.workspace }}/DevOpsShield-SecurityScanner-Report.sarif
cat ${{ github.workspace }}/DevOpsShield-SecurityScanner-Report.csv
mkdir "${{ github.workspace }}/devops-shield-reports-linux"
cp ${{ github.workspace }}/DevOpsShield-SecurityScanner-Report.sarif "${{ github.workspace }}/devops-shield-reports-linux"
cp ${{ github.workspace }}/DevOpsShield-SecurityScanner-Report.csv "${{ github.workspace }}/devops-shield-reports-linux"
shell: bash
- name: Fix DOS SARIF (temporary workaround)
run: |-
Write-Host "Fixing DOS Sarif"
# read sarif and fix it
$SarifFile = "${{ github.workspace }}/devops-shield-reports-linux/DevOpsShield-SecurityScanner-Report.sarif"
$SarifFileFixed = "${{ github.workspace }}/devops-shield-reports-linux/DevOpsShield-SecurityScanner-Report-Fixed.sarif"
$sarifObject = Get-Content -Path $SarifFile | ConvertFrom-Json -Depth 100
foreach ($run in $sarifObject.runs) {
foreach ($result in $run.results) {
# echo ruleId
Write-Host $result.ruleId
# loop through fixes
foreach ($fix in $result.fixes) {
# echo fix
Write-Host $fix
# echo fix description
$description = $fix.description
# echo description id
$descriptionId = $description.id
Write-Host `t`t$descriptionId
# echo description arguments
$descriptionArguments = $description.arguments
foreach ($argument in $descriptionArguments) {
Write-Host `t`t`t$argument
}
# check if there are more than one argument
if ($descriptionArguments.Count -gt 1) {
# throw error
Write-Error "Error: More than one argument found"
exit 1
}
# prepare new description text
$newText = "$descriptionId - $($descriptionArguments[0])"
$fix.description = $newText
# echo new fix description
Write-Host `t`t$newText
# change description object
# create new custom object for description with a single text property
$newDescription = [PSCustomObject]@{ text = $newText }
# replace description object with new object
$fix.description = $newDescription
}
}
}
$sarifObject | ConvertTo-Json -Depth 100 | Set-Content -Path $SarifFileFixed
shell: pwsh
- name: Upload DevOps Shield Reports
uses: actions/[email protected]
with:
name: devops-shield-reports-linux
path: "${{ github.workspace }}/devops-shield-reports-linux"
test-run_sca_analysis:
name: Run SCA Analysis
needs:
- build-build_and_push_app
runs-on: ubuntu-latest
env:
image: ${{ vars.DOCKER_USERNAME }}.azurecr.io/devsecops-pygoat
environment:
name: dev
steps:
- name: checkout
uses: actions/[email protected]
- name: Safety Dependency Check
run: |-
pip install safety
mkdir -p ${{ github.workspace }}/dependency-check-reports
safety check -r requirements.txt --continue-on-error --output json > ${{ github.workspace }}/dependency-check-reports/dependency-check-report-safety-check.json
- name: Pip Audit Dependency Check
run: |-
pip install pip-audit
mkdir -p ${{ github.workspace }}/dependency-check-reports
# suppress the error code to continue the pipeline even if there are vulnerabilities
pip-audit -r requirements.txt --format json --output ${{ github.workspace }}/dependency-check-reports/dependency-check-report-pip-audit.json || true
#cat ${{ github.workspace }}/dependency-check-reports/dependency-check-report-pip-audit.json
- uses: actions/[email protected]
with:
name: dependency-check-reports
path: "${{ github.workspace }}/dependency-check-reports"
- name: Docker Login
if: env.doImageScanWithDockerHubScout == 'true'
uses: docker/[email protected]
with:
registry: "${{ vars.DOCKER_USERNAME }}.azurecr.io"
username: "${{ vars.DOCKER_USERNAME }}"
password: "${{ secrets.DOCKER_PASSWORD }}"
- name: Image Scanning
if: env.doImageScanWithDockerHubScout == 'true'
run: |-
# Install the Docker Scout CLI
curl -sSfL https://raw.githubusercontent.com/docker/scout-cli/main/install.sh | sh -s --
# Login to Docker Hub required for Docker Scout CLI
#docker login -u ${{ vars.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }}
# Get a CVE report for the built image and fail the pipeline when critical or high CVEs are detected
docker scout cves ${{ env.image }}:${{ env.tag }} --only-severity critical,high --format sarif --output ${{ github.workspace }}/image-scan-report.json
- name: Publish Image Scan Report
if: success() || failure()
uses: actions/[email protected]
with:
name: image-scan-report
path: "${{ github.workspace }}/image-scan-report.json"
test-run_unit_tests:
name: Run Unit Tests
needs:
- build-build_and_push_app
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/[email protected]
- name: Setup Python
uses: actions/[email protected]
with:
python-version: "3.8"
architecture: x64
- name: Install Dependencies
run: pip install -r requirements.txt
- name: UnitTests with PyTest
run: |-
python -m pip install pytest-azurepipelines pytest-cov
python -m pytest introduction/tests/unit/ --junitxml=${{ github.workspace }}/TEST-output.xml --cov=. --cov-report=xml
- name: Publish UnitTest Report
if: success() || failure()
uses: actions/[email protected]
with:
name: unit-test-results
path: "${{ github.workspace }}/TEST-output.xml"
test-run_sast_analysis:
name: Run SAST Analysis
needs:
- build-build_and_push_app
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/[email protected]
- name: Bandit Scan
run: |-
pip3 install --upgrade pip
pip3 install --upgrade setuptools
pip3 install bandit
bandit -ll -ii -r ./introduction -f json -o ${{ github.workspace }}/sast-report.json --exit-zero
- name: Publish SAST Scan Report
if: success() || failure()
uses: actions/[email protected]
with:
name: bandit-sast-report
path: "${{ github.workspace }}/sast-report.json"
test-upload_reports:
name: Upload Reports
needs:
- test-run_devopsshield_scan_linux
- test-run_sast_analysis
- test-run_unit_tests
- test-run_sca_analysis
- build-build_and_push_app
runs-on: ubuntu-latest
environment:
name: dev
env:
DEFECTDOJO_PRODUCTID: ${{ vars.DEFECTDOJO_PRODUCTID }}
DEFECTDOJO_TOKEN: ${{ secrets.DEFECTDOJO_TOKEN }}
DEFECTDOJO_COMMONPASSWORD: ${{ secrets.DEFECTDOJO_COMMONPASSWORD }}
DEFECTDOJO_ENGAGEMENT_REASON: "CI/CD Pipeline Scan"
DEFECTDOJO_ANCHORE_DISABLE: "false"
DEFECTDOJO_ENGAGEMENT_API_TEST: "true"
DEFECTDOJO_ENGAGEMENT_BUILD_SERVER: "null"
DEFECTDOJO_ENGAGEMENT_CHECK_LIST: "true"
DEFECTDOJO_ENGAGEMENT_DEDUPLICATION_ON_ENGAGEMENT: "true"
DEFECTDOJO_ENGAGEMENT_ORCHESTRATION_ENGINE: "null"
DEFECTDOJO_ENGAGEMENT_PEN_TEST: "true"
DEFECTDOJO_ENGAGEMENT_PERIOD: 7
DEFECTDOJO_ENGAGEMENT_SOURCE_CODE_MANAGEMENT_SERVER: "null"
DEFECTDOJO_ENGAGEMENT_STATUS: Not Started
DEFECTDOJO_ENGAGEMENT_THREAT_MODEL: "true"
DEFECTDOJO_NOT_ON_MASTER: "false"
DEFECTDOJO_SCAN_ACTIVE: "true"
DEFECTDOJO_SCAN_CLOSE_OLD_FINDINGS: "true"
DEFECTDOJO_SCAN_ENVIRONMENT: Default
DEFECTDOJO_SCAN_MINIMUM_SEVERITY: Info
DEFECTDOJO_SCAN_PUSH_TO_JIRA: "false"
DEFECTDOJO_SCAN_TEST_TYPE: SAST and SCA Scan
DEFECTDOJO_SCAN_VERIFIED: "true"
steps:
- name: checkout
uses: actions/[email protected]
- name: Download Reports From Pipeline Artifacts
uses: actions/[email protected]
with:
path: "${{ github.workspace }}"
- name: check if secrets are set
if: false
run: |-
echo "DEFECTDOJO_URL: ${{ env.DEFECTDOJO_URL }}"
echo "DEFECTDOJO_PRODUCTID: ${{ vars.DEFECTDOJO_PRODUCTID }}"
echo "DEFECTDOJO_TOKEN: ${{ secrets.DEFECTDOJO_TOKEN }}"
echo "DEFECTDOJO_COMMONUSER: ${{ env.DEFECTDOJO_COMMONUSER }}"
echo "DEFECTDOJO_COMMONPASSWORD: ${{ secrets.DEFECTDOJO_COMMONPASSWORD }}"
# throw error if token is not set and common password is not set
if [ -z "${{ secrets.DEFEECTDOJO_TOKEN }}" ]; then
echo "Warning: DEFEECTDOJO_TOKEN is not set. Please set the secret in the dev environment."
echo "Checking for DEFECTDOJO_COMMONPASSWORD"
if [ -z "${{ secrets.DEFEECTDOJO_COMMONPASSWORD }}" ]; then
echo "Error: DEFECTDOJO_TOKEN is not set. Please set the secret in the dev environment."
echo "Error: DEFECTDOJO_COMMONPASSWORD is not set. Please set the secret in the dev environment."
echo "You need to set either DEFECTDOJO_TOKEN or DEFECTDOJO_COMMONPASSWORD to run the pipeline."
exit 1
else
echo "DEFECTDOJO_COMMONPASSWORD is set"
echo "Trying to get token from common user ${{ env.DEFECTDOJO_COMMONUSER }}..."
# get token from common user
DEFECTDOJO_TOKEN=`curl --fail --location --request POST "${{ env.DEFECTDOJO_URL }}/api-token-auth/" \
--header 'Content-Type: application/json' \
--data-raw "{
\"username\": \"${{ env.DEFECTDOJO_COMMONUSER }}\",
\"password\": \"${{ secrets.DEFECTDOJO_COMMONPASSWORD }}\"
}" | jq -r '.token'`
if [ -z "${DEFECTDOJO_TOKEN}" ]; then
echo "Error: Failed to get token from common user ${{ env.DEFECTDOJO_COMMONUSER }}. Please check the credentials."
exit 1
else
echo "DEFECTDOJO_TOKEN: $DEFECTDOJO_TOKEN"
echo "DEFECTDOJO_TOKEN is set"
exit 0
fi
exit 0
fi
else
echo "DEFECTDOJO_TOKEN is set"
exit 0
fi
- name: check if secrets are set
if: env.useCommonDefectDojoProduct == 'true'
shell: pwsh
run: |-
echo "DEFECTDOJO_URL: $env:DEFECTDOJO_URL"
echo "DEFECTDOJO_PRODUCTID: $env:DEFECTDOJO_PRODUCTID"
echo "DEFECTDOJO_TOKEN: $env:DEFECTDOJO_TOKEN"
echo "DEFECTDOJO_COMMONUSER: $env:DEFECTDOJO_COMMONUSER"
echo "DEFECTDOJO_COMMONPASSWORD: $env:DEFECTDOJO_COMMONPASSWORD"
# throw error if token is not set and common password is not set
$defectDojoTokenIsSet = $null -ne $env:DEFECTDOJO_TOKEN -and $env:DEFECTDOJO_TOKEN -ne ""
Write-Host "DefectDojo Token is set: $defectDojoTokenIsSet"
$defectDojoCommonPasswordIsSet = $null -ne $env:DEFECTDOJO_COMMONPASSWORD -and $env:DEFECTDOJO_COMMONPASSWORD -ne ""
Write-Host "DefectDojo Common Password is set: $defectDojoCommonPasswordIsSet"
if ($defectDojoTokenIsSet) {
Write-Host "DEFECTDOJO_TOKEN is set"
exit 0
}
else {
Write-Host "Warning: DEFEECTDOJO_TOKEN is not set. Please set the secret in the dev environment."
Write-Host "checking for DEFECTDOJO_COMMONPASSWORD"
if ($defectDojoCommonPasswordIsSet) {
Write-Host "DEFECTDOJO_COMMONPASSWORD is set"
Write-Host "Trying to get token from common user ${{ env.DEFECTDOJO_COMMONUSER }}..."
# get token from common user
$DEFECTDOJO_TOKEN_COMMON = (Invoke-RestMethod -Method Post -Uri "${env:DEFECTDOJO_URL}/api-token-auth/" `
-ContentType 'application/json' `
-Body (@{
"username" = "$env:DEFECTDOJO_COMMONUSER";
"password" = "$env:DEFECTDOJO_COMMONPASSWORD"
} | ConvertTo-Json)).token
if ($DEFECTDOJO_TOKEN_COMMON) {
#Write-Host "DEFECTDOJO_TOKEN: $DEFECTDOJO_TOKEN_COMMON"
Write-Host "DEFECTDOJO_TOKEN is set"
#echo "DEFECTDOJO_TOKEN=$DEFECTDOJO_TOKEN_COMMON" >> $GITHUB_ENV
echo "DEFECTDOJO_TOKEN=$DEFECTDOJO_TOKEN_COMMON" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append
# now to fetch the product id
# Get the product id
$DEFECTDOJO_PRODUCTID_COMMON = Invoke-RestMethod -Method Get -Uri "${env:DEFECTDOJO_URL}/products/?name=${env:DEFECTDOJO_COMMONPRODUCTNAME}" `
-Headers @{ "Authorization" = "Token $DEFECTDOJO_TOKEN_COMMON" }
Write-Host "DEFECTDOJO_PRODUCTID_COMMON: $DEFECTDOJO_PRODUCTID_COMMON"
if ($DEFECTDOJO_PRODUCTID_COMMON) {
$DEFECTDOJO_PRODUCTID_COMMON_ID = $DEFECTDOJO_PRODUCTID_COMMON.results[0].id
Write-Host "DEFECTDOJO_PRODUCTID: $DEFECTDOJO_PRODUCTID_COMMON_ID"
Write-Host "DEFECTDOJO_PRODUCTID is set"
#echo "DEFECTDOJO_PRODUCTID=$DEFECTDOJO_PRODUCTID_COMMON_ID" >> $GITHUB_ENV
echo "DEFECTDOJO_PRODUCTID=$DEFECTDOJO_PRODUCTID_COMMON_ID" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append
exit 0
}
else {
Write-Host "Error: Failed to get product id for $DEFECTDOJO_COMMONPRODUCTNAME. Please check the product name."
exit 1
}
}
else {
Write-Host "Error: Failed to get token from common user ${env:DEFECTDOJO_COMMONUSER}. Please check the credentials."
exit 1
}
}
else {
Write-Host "Error: DEFECTDOJO_TOKEN is not set. Please set the secret in the dev environment."
Write-Host "Error: DEFECTDOJO_COMMONPASSWORD is not set. Please set the secret in the dev environment."
Write-Host "You need to set either DEFECTDOJO_TOKEN or DEFECTDOJO_COMMONPASSWORD to run the pipeline."
exit 1
}
}
- name: test env settings
if: env.useCommonDefectDojoProduct == 'true'
shell: pwsh
run: |-
#echo $env:DEFECTDOJO_TOKEN
echo $env:DEFECTDOJO_PRODUCTID
- name: Create DefectDojo Engagement with Common Product
if: env.useCommonDefectDojoProduct == 'true'
run: |-
TODAY=`date +%Y-%m-%d`
ENDDAY=$(date -d "+${{ env.DEFECTDOJO_ENGAGEMENT_PERIOD }} days" +%Y-%m-%d)
ENGAGEMENTID=`curl --fail --location --request POST "${{ env.DEFECTDOJO_URL }}/engagements/" \
--header "Authorization: Token ${{ env.DEFECTDOJO_TOKEN }}" \
--header 'Content-Type: application/json' \
--data-raw "{
\"tags\": [\"GITHUB\"],
\"name\": \"pygoat-${{ github.run_id }}\",
\"description\": \"${{ github.event.head_commit.message }}\",
\"version\": \"${{ github.ref }}\",
\"first_contacted\": \"${TODAY}\",
\"target_start\": \"${TODAY}\",
\"target_end\": \"${ENDDAY}\",
\"reason\": \"${{ env.DEFECTDOJO_ENGAGEMENT_REASON }}\",
\"tracker\": \"${{ github.server_url }}/${{ github.repository }}/\",
\"threat_model\": \"${{ env.DEFECTDOJO_ENGAGEMENT_THREAT_MODEL }}\",
\"api_test\": \"${{ env.DEFECTDOJO_ENGAGEMENT_API_TEST }}\",
\"pen_test\": \"${{ env.DEFECTDOJO_ENGAGEMENT_PEN_TEST }}\",
\"check_list\": \"${{ env.DEFECTDOJO_ENGAGEMENT_CHECK_LIST }}\",
\"status\": \"${{ env.DEFECTDOJO_ENGAGEMENT_STATUS }}\",
\"engagement_type\": \"CI/CD\",
\"build_id\": \"${{ github.run_id }}\",
\"commit_hash\": \"${{ github.sha }}\",
\"branch_tag\": \"${{ github.ref }}\",
\"deduplication_on_engagement\": \"${{ env.DEFECTDOJO_ENGAGEMENT_DEDUPLICATION_ON_ENGAGEMENT }}\",
\"product\": \"${{ env.DEFECTDOJO_PRODUCTID }}\",
\"source_code_management_uri\": \"${{ github.server_url }}/${{ github.repository }}\",
\"build_server\": ${{ env.DEFECTDOJO_ENGAGEMENT_BUILD_SERVER }},
\"source_code_management_server\": ${{ env.DEFECTDOJO_ENGAGEMENT_SOURCE_CODE_MANAGEMENT_SERVER }},
\"orchestration_engine\": ${{ env.DEFECTDOJO_ENGAGEMENT_ORCHESTRATION_ENGINE }}
}" | jq -r '.id'` &&
echo ${ENGAGEMENTID} > ENGAGEMENTID.env
- name: Create DefectDojo Engagement
if: env.useCommonDefectDojoProduct == 'false'
run: |-
TODAY=`date +%Y-%m-%d`
ENDDAY=$(date -d "+${{ env.DEFECTDOJO_ENGAGEMENT_PERIOD }} days" +%Y-%m-%d)
ENGAGEMENTID=`curl --fail --location --request POST "${{ env.DEFECTDOJO_URL }}/engagements/" \
--header "Authorization: Token ${{ secrets.DEFECTDOJO_TOKEN }}" \
--header 'Content-Type: application/json' \
--data-raw "{
\"tags\": [\"GITHUB\"],
\"name\": \"pygoat-${{ github.run_id }}\",
\"description\": \"${{ github.event.head_commit.message }}\",
\"version\": \"${{ github.ref }}\",
\"first_contacted\": \"${TODAY}\",
\"target_start\": \"${TODAY}\",
\"target_end\": \"${ENDDAY}\",
\"reason\": \"${{ env.DEFECTDOJO_ENGAGEMENT_REASON }}\",
\"tracker\": \"${{ github.server_url }}/${{ github.repository }}/\",
\"threat_model\": \"${{ env.DEFECTDOJO_ENGAGEMENT_THREAT_MODEL }}\",
\"api_test\": \"${{ env.DEFECTDOJO_ENGAGEMENT_API_TEST }}\",
\"pen_test\": \"${{ env.DEFECTDOJO_ENGAGEMENT_PEN_TEST }}\",
\"check_list\": \"${{ env.DEFECTDOJO_ENGAGEMENT_CHECK_LIST }}\",
\"status\": \"${{ env.DEFECTDOJO_ENGAGEMENT_STATUS }}\",
\"engagement_type\": \"CI/CD\",
\"build_id\": \"${{ github.run_id }}\",
\"commit_hash\": \"${{ github.sha }}\",
\"branch_tag\": \"${{ github.ref }}\",
\"deduplication_on_engagement\": \"${{ env.DEFECTDOJO_ENGAGEMENT_DEDUPLICATION_ON_ENGAGEMENT }}\",
\"product\": \"${{ env.DEFECTDOJO_PRODUCTID }}\",
\"source_code_management_uri\": \"${{ github.server_url }}/${{ github.repository }}\",
\"build_server\": ${{ env.DEFECTDOJO_ENGAGEMENT_BUILD_SERVER }},
\"source_code_management_server\": ${{ env.DEFECTDOJO_ENGAGEMENT_SOURCE_CODE_MANAGEMENT_SERVER }},
\"orchestration_engine\": ${{ env.DEFECTDOJO_ENGAGEMENT_ORCHESTRATION_ENGINE }}
}" | jq -r '.id'` &&
echo ${ENGAGEMENTID} > ENGAGEMENTID.env
- name: list artifacts
if: env.listArtifacts == 'true'
run: |-
ls -l ${{ github.workspace }}
#ls -l ${{ github.workspace }}/image-scan-report
ls -l ${{ github.workspace }}/dependency-check-reports
ls -l ${{ github.workspace }}/bandit-sast-report
ls -l ${{ github.workspace }}/devops-shield-reports-linux
- name: Upload Reports To DefectDojo with Common Product
if: env.useCommonDefectDojoProduct == 'true'
run: |-
TODAY=`date +%Y-%m-%d`
ENGAGEMENTID=`cat ENGAGEMENTID.env`
echo "TODAY: $TODAY"
echo "ENGAGEMENTID: $ENGAGEMENTID"
array=('type=("SARIF" "pip-audit Scan" "SARIF" "Bandit Scan")' 'file=("devops-shield-reports-linux/DevOpsShield-SecurityScanner-Report-Fixed.sarif" "dependency-check-reports/dependency-check-report-pip-audit.json" "image-scan-report/image-scan-report.json" "bandit-sast-report/sast-report.json")')
for elt in "${array[@]}";do eval $elt;done
for scan in 0 1 2 3; do \
echo ""
echo "======================= Scan No $scan ======================="
echo "Uploading ${type[$scan]} report"
echo "Uploading ${file[$scan]}"
#echo "Contents are:"
#cat ${{ github.workspace }}/${file[$scan]}
# check if the file exists
if [ -f ${{ github.workspace }}/${file[$scan]} ]; then
echo "File exists"
else
echo "File does not exist"
continue
fi
curl --fail --location --request POST "${{ env.DEFECTDOJO_URL }}/import-scan/" \
--header "Authorization: Token ${{ env.DEFECTDOJO_TOKEN }}" \
--form "scan_date=${TODAY}" \
--form "minimum_severity=${{ env.DEFECTDOJO_SCAN_MINIMUM_SEVERITY }}" \
--form "active=${{ env.DEFECTDOJO_SCAN_ACTIVE }}" \
--form "verified=${{ env.DEFECTDOJO_SCAN_VERIFIED }}" \
--form "scan_type=${type[$scan]}" \
--form "engagement=${ENGAGEMENTID}" \
--form "file=@${{ github.workspace }}/${file[$scan]}" \
--form "close_old_findings=${{ env.DEFECTDOJO_SCAN_CLOSE_OLD_FINDINGS }}" \
--form "push_to_jira=${{ env.DEFECTDOJO_SCAN_PUSH_TO_JIRA }}" \
--form "test_type=${{ env.DEFECTDOJO_SCAN_TEST_TYPE }}" \
--form "environment=${{ env.DEFECTDOJO_SCAN_ENVIRONMENT }}"
done
- name: Upload Reports To DefectDojo
if: env.useCommonDefectDojoProduct == 'false'
run: |-
TODAY=`date +%Y-%m-%d`
ENGAGEMENTID=`cat ENGAGEMENTID.env`
echo "TODAY: $TODAY"
echo "ENGAGEMENTID: $ENGAGEMENTID"
array=('type=("SARIF" "pip-audit Scan" "SARIF" "Bandit Scan")' 'file=("devops-shield-reports-linux/DevOpsShield-SecurityScanner-Report-Fixed.sarif" "dependency-check-reports/dependency-check-report-pip-audit.json" "image-scan-report/image-scan-report.json" "bandit-sast-report/sast-report.json")')
for elt in "${array[@]}";do eval $elt;done
for scan in 0 1 2 3; do \
echo ""
echo "======================= Scan No $scan ======================="
echo "Uploading ${type[$scan]} report"
echo "Uploading ${file[$scan]}"
#echo "Contents are:"
#cat ${{ github.workspace }}/${file[$scan]}
# check if the file exists
if [ -f ${{ github.workspace }}/${file[$scan]} ]; then
echo "File exists"
else
echo "File does not exist"
continue
fi
curl --fail --location --request POST "${{ env.DEFECTDOJO_URL }}/import-scan/" \
--header "Authorization: Token ${{ secrets.DEFECTDOJO_TOKEN }}" \
--form "scan_date=${TODAY}" \
--form "minimum_severity=${{ env.DEFECTDOJO_SCAN_MINIMUM_SEVERITY }}" \
--form "active=${{ env.DEFECTDOJO_SCAN_ACTIVE }}" \
--form "verified=${{ env.DEFECTDOJO_SCAN_VERIFIED }}" \
--form "scan_type=${type[$scan]}" \
--form "engagement=${ENGAGEMENTID}" \
--form "file=@${{ github.workspace }}/${file[$scan]}" \
--form "close_old_findings=${{ env.DEFECTDOJO_SCAN_CLOSE_OLD_FINDINGS }}" \
--form "push_to_jira=${{ env.DEFECTDOJO_SCAN_PUSH_TO_JIRA }}" \
--form "test_type=${{ env.DEFECTDOJO_SCAN_TEST_TYPE }}" \
--form "environment=${{ env.DEFECTDOJO_SCAN_ENVIRONMENT }}"
done
deploy_test-deploy_to_test_k8s_cluster:
name: Deploy To Test K8S Cluster
needs:
- test-upload_reports
runs-on: ubuntu-latest
env:
RESOURCE_GROUP: rg-k8s-pygoat-dev-001
CLUSTER_NAME: aks-k8s-pygoat-dev-001
NAMESPACE: pygoat-test
Pygoat_Service: pygoat-svc
DnsResourceGroup: rg-dns-prod
zoneName: cad4devops.com
dnsRecordSetName: gh-pygoat-test
image: ${{ vars.DOCKER_USERNAME }}.azurecr.io/devsecops-pygoat
environment:
name: OSS_pygoat-test
steps:
- name: checkout
uses: actions/[email protected]
- name: download artifact
uses: actions/[email protected]
- uses: actions/[email protected]
- uses: cschleiden/replace-tokens@v1
with:
tokenPrefix: "#{"
tokenSuffix: "}#"
files: '["${{ github.workspace }}/manifests/k8s-*.yaml"]'
env:
host: ${{ env.host }}
image: ${{ env.image }}
tag: ${{ env.tag }}
- name: See the files
run: |-
cat ${{ github.workspace }}/manifests/k8s-deployment.yaml
cat ${{ github.workspace }}/manifests/k8s-ingress.yaml
- name: Azure login
if: env.useAzureCliForK8s == 'true'
uses: azure/login@v2
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- name: Create k8s namespace ${{ env.NAMESPACE }}
if: env.useAzureCliForK8s == 'true'
uses: azure/cli@v2
with:
azcliversion: latest
inlineScript: |
az account show
az aks get-credentials --resource-group ${{ env.RESOURCE_GROUP }} --name ${{ env.CLUSTER_NAME }}
az aks install-cli
echo "Sleeping for 10 seconds - waiting for kubectl to be ready"
sleep 10
kubectl version --client
kubectl get nodes
kubectl get namespaces
# create namespace if it does not exist
kubectl create namespace ${{ env.NAMESPACE }} --dry-run=client -o yaml | kubectl apply -f -
- uses: tale/kubectl-action@v1
continue-on-error: true
with:
base64-kube-config: ${{ secrets.KUBE_CONFIG }}
kubectl-version: v1.28.9
- name: Create k8s namespace ${{ env.NAMESPACE }}
continue-on-error: true
run: |-
kubectl version --client
kubectl get nodes
kubectl get namespaces
# create namespace if it does not exist
kubectl create namespace ${{ env.NAMESPACE }} --dry-run=client -o yaml | kubectl apply -f -
- name: Install k8s manifests - namespace ${{ env.NAMESPACE }}
if: env.useAzureCliForK8s == 'true'
uses: azure/cli@v2
with:
azcliversion: latest
inlineScript: |
az account show
az aks get-credentials --resource-group ${{ env.RESOURCE_GROUP }} --name ${{ env.CLUSTER_NAME }}
az aks install-cli
echo "Sleeping for 10 seconds - waiting for kubectl to be ready"
sleep 10
kubectl version --client
# apply the manifests
kubectl apply -f ${{ github.workspace }}/manifests/k8s-deployment.yaml -n ${{ env.NAMESPACE }}
kubectl apply -f ${{ github.workspace }}/manifests/k8s-service.yaml -n ${{ env.NAMESPACE }}
kubectl apply -f ${{ github.workspace }}/manifests/k8s-ingress.yaml -n ${{ env.NAMESPACE }}
# wait for the service to be ready
kubectl wait --for=condition=available --timeout=600s deployment.apps/pygoat-app -n ${{ env.NAMESPACE }}
- name: Install k8s manifests - namespace ${{ env.NAMESPACE }}
continue-on-error: true
run: |-
kubectl version --client
# apply the manifests
kubectl apply -f ${{ github.workspace }}/manifests/k8s-deployment.yaml -n ${{ env.NAMESPACE }}
kubectl apply -f ${{ github.workspace }}/manifests/k8s-service.yaml -n ${{ env.NAMESPACE }}
kubectl apply -f ${{ github.workspace }}/manifests/k8s-ingress.yaml -n ${{ env.NAMESPACE }}
# wait for the service to be ready
kubectl wait --for=condition=available --timeout=600s deployment.apps/pygoat-app -n ${{ env.NAMESPACE }}
- name: Adjust DNS for environment
if: env.adjustDNS == 'true'
uses: azure/cli@v2
with:
azcliversion: latest
inlineScript: |
az account show
az aks get-credentials --resource-group ${{ env.RESOURCE_GROUP }} --name ${{ env.CLUSTER_NAME }}
az aks install-cli
echo "Sleeping for 10 seconds - waiting for kubectl to be ready"
sleep 10
kubectl version --client
kubectl get pods -n ${{ env.NAMESPACE }}
kubectl get services -n ${{ env.NAMESPACE }}
# get external IP from the service
externalIp=$(kubectl get service ${{ env.Pygoat_Service }} -n ${{ env.NAMESPACE }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo "External IP: $externalIp"
az network dns record-set a add-record \
-g ${{ env.DnsResourceGroup }} \
-z ${{ env.zoneName }} \
-n ${{ env.dnsRecordSetName }} \
-a $externalIp
- name: Get Resources - namespace ${{ env.NAMESPACE }}
continue-on-error: true
run: |-
kubectl version --client
kubectl get pods -n ${{ env.NAMESPACE }}
kubectl get services -n ${{ env.NAMESPACE }}
# get external IP from the service
externalIp=$(kubectl get service ${{ env.Pygoat_Service }} -n ${{ env.NAMESPACE }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo "External IP: $externalIp"
dast-run_integration_tests:
name: Run Integration Tests
needs:
- deploy_test-deploy_to_test_k8s_cluster
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/[email protected]
- name: Integration Tests with Selenium
if: success() || failure()
run: |-
python -m pip install -r requirements.txt
python -m pip install pytest-cov
python -m pytest introduction/tests/integration/ --junitxml=${{ github.workspace }}/selenium-test-output.xml --cov=. --cov-report=xml
- name: Publish Selenium Report
if: success() || failure()
uses: actions/[email protected]
with:
name: selenium-test-results
path: "${{ github.workspace }}/selenium-test-output.xml"
dast-run_dast_scan:
name: Run DAST Scan
needs:
- deploy_test-deploy_to_test_k8s_cluster
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/[email protected]
- name: load owasp detached
run: "docker run --name ${{ env.containerName }} -d -u zap \\\n -p ${{ env.owaspZapWebPort }}:${{ env.owaspZapWebPort }} \\\n -p ${{ env.owaspZapApiPort }}:${{ env.owaspZapApiPort }} \\\n -i ${{ env.owaspImageName }} zap.sh -daemon \\\n -port ${{ env.owaspZapApiPort }} -host 0.0.0.0 \\\n -config api.disablekey=true \\\n -config api.addrs.addr.name=.* \\\n -config api.addrs.addr.regex=true\n\n# wait for docker to load\necho \"waiting for docker to load for ${{ env.dockerWaitTime }}\"\nsleep ${{ env.dockerWaitTime }}\n\n# wait for zap to start\necho \"waiting for zap to start with loop time ${{ env.loopWaitTime }}\"\necho \"\"\nwhile [ \"$(curl -s http://localhost:${{ env.owaspZapApiPort }}/JSON/core/view/version/ | jq -r '.version')\" == \"null\" ]; do\n echo \"\"\n echo \"waiting for zap to start with loop time ${{ env.loopWaitTime }}\"\n sleep ${{ env.loopWaitTime }}\n curl -s http://localhost:${{ env.owaspZapApiPort }}/JSON/core/view/version/ | jq -r '.version'\ndone\n\n# check zap version\necho \"\"\ncurl \"http://localhost:${{ env.owaspZapApiPort }}/JSON/core/view/version/\"\n\n# To start the spider scan\necho \"\"\ncurl \"http://localhost:${{ env.owaspZapApiPort }}/JSON/spider/action/scan/?url=${{ env.appUrl }}\"\n\n# loop until response is 100\necho \"\"\nwhile [ \"$(curl -s http://localhost:${{ env.owaspZapApiPort }}/JSON/spider/view/status/?scanId=0 | jq -r '.status')\" != \"100\" ]; do\n echo \"\"\n echo \"waiting for spider to finish with loop time ${{ env.loopWaitTime }}\"\n sleep ${{ env.loopWaitTime }}\n curl -s http://localhost:${{ env.owaspZapApiPort }}/JSON/spider/view/status/?scanId=0 | jq -r '.status'\ndone\n\n# To view the status of spider\necho \"\"\ncurl \"http://localhost:${{ env.owaspZapApiPort }}/JSON/spider/view/status/?scanId=0\"\n\n# To start the the active scan if doActiveScan is true\nif [ \"${{ env.doActiveScan }}\" == \"true\" ]; then\n echo \"\"\n echo \"starting active scan\"\n curl \"http://localhost:${{ env.owaspZapApiPort }}/JSON/ascan/action/scan/?url=${{ env.appUrl }}&recurse=true&inScopeOnly=&scanPolicyName=&method=&postData=&contextId=\"\n \n # To view the the status of active scan\n echo \"\"\n curl \"http://localhost:${{ env.owaspZapApiPort }}/JSON/ascan/view/status/?scanId=0\"\n\n # loop until response is 100\n echo \"\"\n while [ \"$(curl -s http://localhost:${{ env.owaspZapApiPort }}/JSON/ascan/view/status/?scanId=0 | jq -r '.status')\" != \"100\" ]; do\n echo \"\"\n echo \"waiting for active scan to finish with loop time ${{ env.loopWaitTime }}\"\n sleep ${{ env.loopWaitTime }}\n curl -s http://localhost:${{ env.owaspZapApiPort }}/JSON/ascan/view/status/?scanId=0 | jq -r '.status'\n done\n\n # To view the alerts of active scan\n echo \"\"\n curl \"http://localhost:${{ env.owaspZapApiPort }}/JSON/ascan/view/status/?scanId=0\"\n\n # To view the alerts of active scan\n echo \"\"\n echo \"viewing ${{ env.maxAlerts }} alerts\"\n curl \"http://localhost:${{ env.owaspZapApiPort }}/JSON/core/view/alerts/?baseurl=${{ env.appUrl }}&start=0&count=${{ env.maxAlerts }}\"\nfi\n\necho \"\"\necho \"generating JSON report ${{ env.owaspzap-report-json }}\"\n#curl \"http://localhost:${{ env.owaspZapApiPort }}/OTHER/core/other/jsonreport/\"\ncurl \"http://localhost:${{ env.owaspZapApiPort }}/JSON/reports/action/generate/?template=${{ env.traditionalJsonTemplate }}&title=repoTitle&reportFileName=${{ env.owaspzap-report-json }}\"\necho \"\"\necho \"contents of ${{ env.owaspzap-report-json }}\"\ndocker exec ${{ env.containerName }} cat /home/zap/${{ env.owaspzap-report-json }}\necho \"\"\necho \"generating SARIF report ${{ env.owaspzap-report-sarif }}.json\"\ncurl \"http://localhost:${{ env.owaspZapApiPort }}/JSON/reports/action/generate/?template=${{ env.sarifTemplate }}&title=repoTitle&reportFileName=${{ env.owaspzap-report-sarif }}.json\"\necho \"\"\necho \"create folder for owaspzap reports\"\nmkdir -p \"${{ runner.temp }}/owaspzap\"\necho \"\"\necho \"contents of ${{ env.owaspzap-report-sarif }}.json\"\ndocker exec ${{ env.containerName }} cat /home/zap/${{ env.owaspzap-report-sarif }}.json\necho \"\"\necho \"copying $(owaspzap-report-sarif-json) to artifact directory\"\ndocker cp \"${{ env.containerName }}:/home/zap/${{ env.owaspzap-report-json }}\" \"${{ runner.temp }}/owaspzap/${{ env.owaspzap-report-json }}\"\necho \"\"\necho \"copying ${{ env.owaspzap-report-sarif }}.json to artifact directory\"\ndocker cp \"${{ env.containerName }}:/home/zap/${{ env.owaspzap-report-sarif }}.json\" \"${{ runner.temp }}/owaspzap/${{ env.owaspzap-report-sarif }}\""
- name: Publish OWASP ZAP Reports
uses: actions/[email protected]
with:
name: CodeAnalysisLogs
path: "${{ runner.temp }}/owaspzap"
- name: Publish ZAP Report
if: success() || failure()
uses: actions/[email protected]
with:
name: owasp_zap_report
path: "${{ runner.temp }}/owaspzap"
deploy_prod-deploy_prod:
name: Deploy To Prod K8S Cluster
needs:
- dast-run_integration_tests
- dast-run_dast_scan
runs-on: ubuntu-latest
environment:
name: OSS_pygoat-prod
env:
appUrl: http://gh-pygoat.cad4devops.com
host: gh-pygoat.cad4devops.com
RESOURCE_GROUP: rg-k8s-pygoat-dev-001
CLUSTER_NAME: aks-k8s-pygoat-dev-001
NAMESPACE: pygoat
Pygoat_Service: pygoat-svc
DnsResourceGroup: rg-dns-prod
zoneName: cad4devops.com
dnsRecordSetName: gh-pygoat
image: ${{ vars.DOCKER_USERNAME }}.azurecr.io/devsecops-pygoat
steps:
- name: checkout
uses: actions/[email protected]
- name: download artifact
uses: actions/[email protected]
- uses: actions/[email protected]
- uses: cschleiden/replace-tokens@v1
with:
tokenPrefix: "#{"
tokenSuffix: "}#"
files: '["${{ github.workspace }}/manifests/k8s-*.yaml"]'
env:
host: ${{ env.host }}
image: ${{ env.image }}
tag: ${{ env.tag }}
- name: See the files
run: |-
cat ${{ github.workspace }}/manifests/k8s-deployment.yaml
cat ${{ github.workspace }}/manifests/k8s-ingress.yaml
- name: Azure login
if: env.useAzureCliForK8s == 'true'
uses: azure/login@v2
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- name: Create k8s namespace ${{ env.NAMESPACE }}
if: env.useAzureCliForK8s == 'true'
uses: azure/cli@v2
with:
azcliversion: latest
inlineScript: |
az account show
az aks get-credentials --resource-group ${{ env.RESOURCE_GROUP }} --name ${{ env.CLUSTER_NAME }}
az aks install-cli
echo "Sleeping for 10 seconds - waiting for kubectl to be ready"
sleep 10
kubectl version --client
kubectl get nodes
kubectl get namespaces
# create namespace if it does not exist
kubectl create namespace ${{ env.NAMESPACE }} --dry-run=client -o yaml | kubectl apply -f -
- uses: tale/kubectl-action@v1
continue-on-error: true
with:
base64-kube-config: ${{ secrets.KUBE_CONFIG }}
kubectl-version: v1.28.9
- name: Create k8s namespace ${{ env.NAMESPACE }}
continue-on-error: true
run: |-
kubectl version --client
kubectl get nodes
kubectl get namespaces
# create namespace if it does not exist
kubectl create namespace ${{ env.NAMESPACE }} --dry-run=client -o yaml | kubectl apply -f -
- name: Install k8s manifests - namespace ${{ env.NAMESPACE }}
if: env.useAzureCliForK8s == 'true'
uses: azure/cli@v2
with:
azcliversion: latest
inlineScript: |
az account show
az aks get-credentials --resource-group ${{ env.RESOURCE_GROUP }} --name ${{ env.CLUSTER_NAME }}
az aks install-cli
echo "Sleeping for 10 seconds - waiting for kubectl to be ready"
sleep 10
kubectl version --client
# apply the manifests
kubectl apply -f ${{ github.workspace }}/manifests/k8s-deployment.yaml -n ${{ env.NAMESPACE }}
kubectl apply -f ${{ github.workspace }}/manifests/k8s-service.yaml -n ${{ env.NAMESPACE }}
kubectl apply -f ${{ github.workspace }}/manifests/k8s-ingress.yaml -n ${{ env.NAMESPACE }}
# wait for the service to be ready
kubectl wait --for=condition=available --timeout=600s deployment.apps/pygoat-app -n ${{ env.NAMESPACE }}
- name: Install k8s manifests - namespace ${{ env.NAMESPACE }}
continue-on-error: true
run: |-
kubectl version --client
# apply the manifests
kubectl apply -f ${{ github.workspace }}/manifests/k8s-deployment.yaml -n ${{ env.NAMESPACE }}
kubectl apply -f ${{ github.workspace }}/manifests/k8s-service.yaml -n ${{ env.NAMESPACE }}
kubectl apply -f ${{ github.workspace }}/manifests/k8s-ingress.yaml -n ${{ env.NAMESPACE }}
# wait for the service to be ready
kubectl wait --for=condition=available --timeout=600s deployment.apps/pygoat-app -n ${{ env.NAMESPACE }}
- name: Adjust DNS for environment
if: env.adjustDNS == 'true'
uses: azure/cli@v2
with:
azcliversion: latest
inlineScript: |
az account show
az aks get-credentials --resource-group ${{ env.RESOURCE_GROUP }} --name ${{ env.CLUSTER_NAME }}
az aks install-cli
echo "Sleeping for 10 seconds - waiting for kubectl to be ready"
sleep 10
kubectl version --client
kubectl get pods -n ${{ env.NAMESPACE }}
kubectl get services -n ${{ env.NAMESPACE }}
# get external IP from the service
externalIp=$(kubectl get service ${{ env.Pygoat_Service }} -n ${{ env.NAMESPACE }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo "External IP: $externalIp"
az network dns record-set a add-record \
-g ${{ env.DnsResourceGroup }} \
-z ${{ env.zoneName }} \
-n ${{ env.dnsRecordSetName }} \
-a $externalIp
- name: Get Resources - namespace ${{ env.NAMESPACE }}
continue-on-error: true
run: |-
kubectl version --client
kubectl get pods -n ${{ env.NAMESPACE }}
kubectl get services -n ${{ env.NAMESPACE }}
# get external IP from the service
externalIp=$(kubectl get service ${{ env.Pygoat_Service }} -n ${{ env.NAMESPACE }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo "External IP: $externalIp"