Files
ansible-testing/.gitlab-ci.yml
T

293 lines
7.9 KiB
YAML

stages:
- validate
- build
- platform
- test
- normalize
- report
default:
interruptible: true
retry:
max: 1
when:
- runner_system_failure
- stuck_or_timeout_failure
variables:
PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip"
ARTIFACT_ROOT: "$CI_PROJECT_DIR/artifacts"
KUBE_NAMESPACE: "test-automation"
ANSIBLE_IMAGE: "$CI_REGISTRY_IMAGE/ansible:$CI_COMMIT_SHA"
DEMO_TARGET_IMAGE: "$CI_REGISTRY_IMAGE/demo-target:$CI_COMMIT_SHA"
TARGET_ENVIRONMENT:
value: "test"
description: "GitLab environment scope used to select credentials"
.python_job:
image: python:3.13-alpine
cache:
key: python-ci-v1
paths:
- .cache/pip/
before_script:
- python3 -m pip install --disable-pip-version-check -r requirements-ci.txt
validate:assets:
extends: .python_job
stage: validate
script:
- python3 scripts/parse-assets.py assets.yml --expected-environment "$TARGET_ENVIRONMENT" --dotenv artifacts/metadata.env --matrix artifacts/asset-matrix.json
artifacts:
expire_in: 30 days
reports:
dotenv: artifacts/metadata.env
paths:
- artifacts/asset-matrix.json
validate:python:
extends: .python_job
stage: validate
script:
- python3 -m compileall -q scripts methodologies/ansible/scripts methodologies/zap/scripts
- python3 methodologies/ansible/scripts/normalize.py methodologies/ansible/fixtures/sample-output.json artifacts/normalized/sample-ansible.json
artifacts:
expire_in: 7 days
paths:
- artifacts/normalized/sample-ansible.json
.kaniko_build:
stage: build
image:
name: gcr.io/kaniko-project/executor:v1.23.2-debug
entrypoint: [""]
before_script:
- mkdir -p /kaniko/.docker
- printf '{"auths":{"%s":{"username":"%s","password":"%s"}}}' "$CI_REGISTRY" "$CI_REGISTRY_USER" "$CI_REGISTRY_PASSWORD" > /kaniko/.docker/config.json
build:ansible:
extends: .kaniko_build
script:
- /kaniko/executor --context "$CI_PROJECT_DIR" --dockerfile "$CI_PROJECT_DIR/methodologies/ansible/Dockerfile" --destination "$ANSIBLE_IMAGE"
rules:
- if: '$RUN_DEMO == "true"'
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
changes:
- methodologies/ansible/**/*
build:demo-target:
extends: .kaniko_build
script:
- /kaniko/executor --context "$CI_PROJECT_DIR" --dockerfile "$CI_PROJECT_DIR/targets/ubuntu-weak/Dockerfile" --destination "$DEMO_TARGET_IMAGE"
rules:
- if: '$RUN_DEMO == "true"'
platform:verify:
stage: platform
image: alpine:3.20
needs:
- validate:assets
script:
- test -d /cache/tools
- df -h /cache/tools
resource_group: test-automation-platform
rules:
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
when: manual
- when: never
# Tool jobs are introduced behind explicit opt-in variables. Their Kubernetes
# Job templates and adapters are added as each tool contract is implemented.
test:ansible:
stage: test
image:
name: "$CI_REGISTRY_IMAGE/ansible:latest"
entrypoint: [""]
needs:
- validate:assets
environment:
name: "$TARGET_ENVIRONMENT"
action: verify
script:
- |
SECRETS_DIR="$CI_PROJECT_DIR/.run/secrets"
python3 methodologies/ansible/scripts/build-secrets.py --out-dir "$SECRETS_DIR"
export ANSIBLE_VARS_FILE="$SECRETS_DIR/ansible-vars.yml"
if [ -f "$SECRETS_DIR/ansible-private-key" ]; then
export ANSIBLE_PRIVATE_KEY_FILE="$SECRETS_DIR/ansible-private-key"
fi
bash methodologies/ansible/run.sh --limit "${ANSIBLE_LIMIT:-all}"
artifacts:
when: always
expire_in: 90 days
paths:
- artifacts/raw/ansible/
- artifacts/normalized/
- artifacts/rendered/
rules:
- if: '$RUN_ANSIBLE == "true"'
- when: never
test:zap:
stage: test
image:
name: zaproxy/zap-stable:latest
entrypoint: [""]
needs:
- validate:assets
environment:
name: "$TARGET_ENVIRONMENT"
action: verify
script:
- test -n "${ZAP_TARGET_URL:-}" || { echo "ZAP_TARGET_URL is required" >&2; exit 1; }
- NORMALIZE_ZAP=false bash methodologies/zap/run.sh "$ZAP_TARGET_URL"
artifacts:
when: always
expire_in: 90 days
paths:
- artifacts/raw/zaproxy/
rules:
- if: '$RUN_ZAP == "true"'
- when: never
demo:ansible:
stage: test
image:
name: "$ANSIBLE_IMAGE"
entrypoint: [""]
services:
- name: "$DEMO_TARGET_IMAGE"
alias: demo-target
needs:
- build:ansible
- build:demo-target
variables:
DEMO_SSH_PASSWORD: "DemoPassword1!"
INVENTORY: "$CI_PROJECT_DIR/targets/ubuntu-weak/assets.yml"
PLAYBOOK: "$CI_PROJECT_DIR/methodologies/ansible/playbooks/demo_target.yml"
LIMIT: "linux_vms"
TEST_PROJECT_ID: "demo-ubuntu-weak"
TEST_PROJECT_NAME: "Ubuntu Weak Target Demonstration"
TEST_ENVIRONMENT: "test"
TEST_CUSTOMER: "Internal"
TEST_LOCATION: "testserv"
script:
- |
python3 <<'PY'
import socket
import time
for _ in range(60):
try:
with socket.create_connection(("demo-target", 22), 2):
break
except OSError:
time.sleep(2)
else:
raise SystemExit("SSH target did not become ready")
PY
- bash methodologies/ansible/run.sh
artifacts:
when: always
expire_in: 30 days
paths:
- artifacts/raw/ansible/
- artifacts/normalized/
rules:
- if: '$RUN_DEMO == "true"'
demo:zap:
stage: test
image:
name: zaproxy/zap-stable:latest
entrypoint: [""]
services:
- name: "$DEMO_TARGET_IMAGE"
alias: demo-target
needs:
- build:demo-target
variables:
NORMALIZE_ZAP: "false"
script:
- |
python3 <<'PY'
import socket
import time
for _ in range(60):
try:
with socket.create_connection(("demo-target", 443), 2):
break
except OSError:
time.sleep(2)
else:
raise SystemExit("HTTPS target did not become ready")
PY
- bash methodologies/zap/run.sh https://demo-target
artifacts:
when: always
expire_in: 30 days
paths:
- artifacts/raw/zaproxy/
rules:
- if: '$RUN_DEMO == "true"'
normalize:demo-zap:
extends: .python_job
stage: normalize
needs:
- job: demo:zap
artifacts: true
variables:
TEST_PROJECT_ID: "demo-ubuntu-weak"
TEST_PROJECT_NAME: "Ubuntu Weak Target Demonstration"
TEST_ENVIRONMENT: "test"
TEST_CUSTOMER: "Internal"
TEST_LOCATION: "testserv"
script:
- python3 methodologies/zap/scripts/normalize.py artifacts/raw/zaproxy/zap.json artifacts/raw/zaproxy/tls.json artifacts/normalized/zaproxy-demo-web.json --target https://demo-target
artifacts:
expire_in: 30 days
paths:
- artifacts/normalized/zaproxy-demo-web.json
rules:
- if: '$RUN_DEMO == "true"'
report:demo:
extends: .python_job
stage: report
needs:
- job: demo:ansible
artifacts: true
- job: normalize:demo-zap
artifacts: true
script:
- ANSIBLE_REPORT="$(find artifacts/normalized -name 'ansible-*.json' -print -quit)"
- test -n "$ANSIBLE_REPORT"
- python3 scripts/aggregate-reports.py "$ANSIBLE_REPORT" artifacts/normalized/zaproxy-demo-web.json --output artifacts/normalized/combined-demo.json
- python3 scripts/render-normalized.py artifacts/normalized/combined-demo.json --output-dir artifacts/rendered
artifacts:
when: always
expire_in: 90 days
paths:
- artifacts/normalized/combined-demo.json
- artifacts/rendered/combined-project-scope.md
- artifacts/rendered/combined-project-scope.html
- artifacts/rendered/combined-project-scope.pdf
rules:
- if: '$RUN_DEMO == "true"'
report:sample:
extends: .python_job
stage: report
needs:
- validate:assets
- validate:python
script:
- python3 scripts/render-normalized.py artifacts/normalized/sample-ansible.json --output-dir artifacts/rendered
artifacts:
when: always
expire_in: 90 days
paths:
- artifacts/normalized/
- artifacts/rendered/