CYBER-0 initial concept ready
This commit is contained in:
+289
@@ -0,0 +1,289 @@
|
||||
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:
|
||||
- test -n "${ANSIBLE_SECRET_VARS:-}" || { echo "ANSIBLE_SECRET_VARS file variable is required" >&2; exit 1; }
|
||||
- test -f "$ANSIBLE_SECRET_VARS" || { echo "ANSIBLE_SECRET_VARS must be a GitLab file variable" >&2; exit 1; }
|
||||
- export ANSIBLE_VARS_FILE="$ANSIBLE_SECRET_VARS"
|
||||
- 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/
|
||||
Reference in New Issue
Block a user