Skip to content
Open
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
31 changes: 31 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: CI

on:
push:
branches: ["**"]
pull_request:

jobs:
lint-and-test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Install lint tools
run: ./test/install-tools.sh

- name: Validate script syntax
run: ./test/validate-scripts.sh

- name: ShellCheck
run: shellcheck run.sh start_squid.sh test/detect-proxy.sh test/test-proxy.sh test/validate-scripts.sh

- name: Hadolint
run: hadolint Dockerfile test/Dockerfile

- name: Build proxy image
run: docker build -t docker-proxy .

- name: Build test image
run: docker build -t docker-proxy-test ./test
13 changes: 13 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Agent Notes

This file tracks agent updates for the repository.

- Last updated: 2025-09-20
- Updates:
- Added CI workflow, script validation, and lint automation.
- Added lint tool installer and updated CI to use it.
- Added latest-version installer with apt fallback for lint tools.
- Expanded script validation to cover the lint tool installer.
- Addressed shellcheck findings across scripts.
- Updated Dockerfiles to satisfy hadolint guidance.
- Adjusted hadolint ignore placement for apt pin warnings.
24 changes: 14 additions & 10 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
FROM ubuntu:trusty-20190515

MAINTAINER Kevin Littlejohn <kevin@littlejohn.id.au>, \
Alex Fraser <alex@vpac-innovations.com.au>
LABEL maintainer="Kevin Littlejohn <kevin@littlejohn.id.au>, Alex Fraser <alex@vpac-innovations.com.au>"

# Install base dependencies.
WORKDIR /root
RUN sed -i 's/^# deb-src/deb-src/' /etc/apt/sources.list
# hadolint ignore=DL3008
RUN export DEBIAN_FRONTEND=noninteractive TERM=linux \
&& apt-get update \
&& apt-get install -y --no-install-recommends \
Expand All @@ -18,24 +18,28 @@ RUN export DEBIAN_FRONTEND=noninteractive TERM=linux \
squid-langpack \
ssl-cert \
&& apt-get source -y squid3 squid-langpack \
&& apt-get build-dep -y squid3 squid-langpack
&& apt-get build-dep -y squid3 squid-langpack \
&& mv squid3-3.* /root/squid3-src \
&& rm -rf /var/lib/apt/lists/*

# Customise and build Squid.
# It's silly, but run dpkg-buildpackage again if it fails the first time. This
# is needed because sometimes the `configure` script is busy when building in
# Docker after autoconf sets its mode +x.
COPY squid3.patch mime.conf /root/
RUN cd squid3-3.* \
&& patch -p1 < /root/squid3.patch \
&& export NUM_PROCS=`grep -c ^processor /proc/cpuinfo` \
&& (dpkg-buildpackage -b -j${NUM_PROCS} \
|| dpkg-buildpackage -b -j${NUM_PROCS}) \
WORKDIR /root/squid3-src
RUN patch -p1 < /root/squid3.patch \
&& NUM_PROCS="$(grep -c ^processor /proc/cpuinfo)" \
&& (dpkg-buildpackage -b -j"${NUM_PROCS}" \
|| dpkg-buildpackage -b -j"${NUM_PROCS}") \
&& DEBIAN_FRONTEND=noninteractive TERM=linux dpkg -i \
../squid3-common_3.*_all.deb \
../squid3_3.*.deb \
/root/squid3-common_3.*_all.deb \
/root/squid3_3.*.deb \
&& mkdir -p /etc/squid3/ssl_cert \
&& cat /root/mime.conf >> /usr/share/squid3/mime.conf

WORKDIR /root

COPY squid.conf /etc/squid3/squid.conf
COPY start_squid.sh /usr/local/bin/start_squid.sh

Expand Down
18 changes: 10 additions & 8 deletions run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,15 @@ start_routing () {
sudo ip route add default via "${IPADDR}" dev docker0 table TRANSPROXY
# Mark packets to port 80 and 443 external, so they route through the new
# route table
COMMON_RULES="-t mangle -I PREROUTING -p tcp -i docker0 ! -s ${IPADDR}
-j MARK --set-mark 1"
COMMON_RULES=(
-t mangle -I PREROUTING -p tcp -i docker0 ! -s "${IPADDR}"
-j MARK --set-mark 1
)
echo "Redirecting HTTP to docker-proxy"
sudo iptables $COMMON_RULES --dport 80
sudo iptables "${COMMON_RULES[@]}" --dport 80
if [ "$WITH_SSL" = 'yes' ]; then
echo "Redirecting HTTPS to docker-proxy"
sudo iptables $COMMON_RULES --dport 443
sudo iptables "${COMMON_RULES[@]}" --dport 443
else
echo "Not redirecting HTTPS. To enable, re-run with the argument 'ssl'"
echo "CA certificate will be generated anyway, but it won't be used"
Expand Down Expand Up @@ -71,7 +73,7 @@ stop_routing () {

stop () {
set +e
sudo docker rm -fv ${CONTAINER_NAME} >/dev/null 2>&1
sudo docker rm -fv "${CONTAINER_NAME}" >/dev/null 2>&1
set -e
stop_routing
}
Expand Down Expand Up @@ -99,12 +101,12 @@ run () {
# Run and find the IP for the running container. Bind the forward proxy port
# so clients can get the CA certificate.
CID=$(sudo docker run --privileged -d \
--name ${CONTAINER_NAME} \
--name "${CONTAINER_NAME}" \
--volume="${CACHEDIR}":/var/spool/squid3 \
--volume="${CERTDIR}":/etc/squid3/ssl_cert \
--publish=3128:3128 \
${CONTAINER_NAME})
IPADDR=$(sudo docker inspect --format '{{ .NetworkSettings.IPAddress }}' ${CID})
"${CONTAINER_NAME}")
IPADDR=$(sudo docker inspect --format '{{ .NetworkSettings.IPAddress }}' "${CID}")
start_routing
# Run at console, kill cleanly if ctrl-c is hit
trap interrupted INT
Expand Down
10 changes: 5 additions & 5 deletions start_squid.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/bin/bash

function gen-cert() {
pushd /etc/squid3/ssl_cert > /dev/null
pushd /etc/squid3/ssl_cert > /dev/null || exit
if [ ! -f ca.pem ]; then
openssl req -new -newkey rsa:2048 -sha256 -days 365 -nodes \
-x509 -keyout privkey.pem -out ca.pem \
Expand All @@ -15,16 +15,16 @@ function gen-cert() {
openssl x509 -sha1 -in ca.pem -noout -fingerprint
# Make CA certificate available for download via HTTP Forwarding port
# e.g. GET http://docker-proxy:3128/squid-internal-static/icons/ca.pem
cp `pwd`/ca.* /usr/share/squid3/icons/
popd > /dev/null
cp "$(pwd)"/ca.* /usr/share/squid3/icons/
popd > /dev/null || exit
return $?
}

function start-routing() {
# Setup the NAT rule that enables transparent proxying
IPADDR=$(/sbin/ip -o -f inet addr show eth0 | awk '{ sub(/\/.+/,"",$4); print $4 }')
iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination ${IPADDR}:3129
iptables -t nat -A PREROUTING -p tcp --dport 443 -j DNAT --to-destination ${IPADDR}:3130
iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination "${IPADDR}":3129
iptables -t nat -A PREROUTING -p tcp --dport 443 -j DNAT --to-destination "${IPADDR}":3130
return $?
}

Expand Down
5 changes: 3 additions & 2 deletions test/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
FROM ubuntu:14.04

MAINTAINER Alex Fraser <alex@vpac-innovations.com.au>
LABEL maintainer="Alex Fraser <alex@vpac-innovations.com.au>"

# Install ca-certificates so we can install the proxy's certificate. curl and
# Java are only needed for running the test, not for installing the
# certificate.
WORKDIR /root
# hadolint ignore=DL3008
RUN export DEBIAN_FRONTEND=noninteractive TERM=linux \
&& apt-get update \
&& apt-get install -y --no-install-recommends \
Expand All @@ -19,4 +20,4 @@ COPY detect-proxy.sh test-proxy.sh HttpTest.java /root/
RUN javac HttpTest.java \
&& ./detect-proxy.sh start

CMD /root/test-proxy.sh
CMD ["/root/test-proxy.sh"]
6 changes: 2 additions & 4 deletions test/detect-proxy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,12 @@ function download-cert() {
| grep -q 'Server: squid'
}

download-cert
if [ $? -ne 0 ]; then
if ! download-cert; then
echo "No proxy server detected"
exit 0
fi

grep -q '\-----BEGIN CERTIFICATE-----' docker-proxy.pem
if [ $? -ne 0 ]; then
if ! grep -q '\-----BEGIN CERTIFICATE-----' docker-proxy.pem; then
echo "Proxy detected"
exit 0
fi
Expand Down
90 changes: 90 additions & 0 deletions test/install-tools.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
#!/usr/bin/env bash

set -euo pipefail

install_dir=${INSTALL_DIR:-/usr/local/bin}

mkdir -p "$install_dir"

fetch_latest_tag() {
local repo="$1"
curl -fsSL "https://api.github.com/repos/${repo}/releases/latest" \
| awk -F '"' '/"tag_name"/ { print $4; exit }'
}

install_shellcheck() {
local tag
local arch
local tarball
local tmp_dir

tag=$(fetch_latest_tag "koalaman/shellcheck")
if [[ -z "$tag" ]]; then
return 1
fi
arch=$(uname -m)
case "$arch" in
x86_64) arch="x86_64" ;;
aarch64|arm64) arch="aarch64" ;;
*)
echo "Unsupported architecture for shellcheck: $arch" >&2
exit 1
;;
esac

tarball="shellcheck-${tag}.linux.${arch}.tar.xz"
tmp_dir=$(mktemp -d)
if ! curl -fsSL -o "${tmp_dir}/${tarball}" \
"https://github.com/koalaman/shellcheck/releases/download/${tag}/${tarball}"; then
rm -rf "$tmp_dir"
return 1
fi
tar -xJf "${tmp_dir}/${tarball}" -C "$tmp_dir"
mv "${tmp_dir}/shellcheck-${tag}/shellcheck" "${install_dir}/shellcheck"
chmod +x "${install_dir}/shellcheck"
rm -rf "$tmp_dir"
}

install_hadolint() {
local tag
local arch
local os
local binary

tag=$(fetch_latest_tag "hadolint/hadolint")
if [[ -z "$tag" ]]; then
return 1
fi
os="Linux"
arch=$(uname -m)
case "$arch" in
x86_64) arch="x86_64" ;;
aarch64|arm64) arch="arm64" ;;
*)
echo "Unsupported architecture for hadolint: $arch" >&2
exit 1
;;
esac

binary="hadolint-${os}-${arch}"
if ! curl -fsSL -o "${install_dir}/hadolint" \
"https://github.com/hadolint/hadolint/releases/download/${tag}/${binary}"; then
return 1
fi
chmod +x "${install_dir}/hadolint"
}

if ! install_shellcheck; then
echo "Falling back to apt for shellcheck" >&2
apt-get update
apt-get install -y shellcheck
fi

if ! install_hadolint; then
echo "Falling back to apt for hadolint" >&2
apt-get update
apt-get install -y hadolint
fi

shellcheck --version
hadolint --version
6 changes: 2 additions & 4 deletions test/test-proxy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@

curl -sS -o /dev/null https://httpbin.org/get 2>&1 || exit 1

curl -sS -v -o /dev/null https://httpbin.org/get 2>&1 \
| grep -q 'X-Cache:'

if [ $? -ne 0 ]; then
if ! curl -sS -v -o /dev/null https://httpbin.org/get 2>&1 \
| grep -q 'X-Cache:'; then
echo "Request succeeded but response was not cached" >&2
exit 1
fi
Expand Down
20 changes: 20 additions & 0 deletions test/validate-scripts.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/usr/bin/env bash

set -euo pipefail

scripts=(
"run.sh"
"start_squid.sh"
"test/install-tools.sh"
"test/detect-proxy.sh"
"test/test-proxy.sh"
)

for script in "${scripts[@]}"; do
if [[ ! -f "$script" ]]; then
echo "Missing script: $script" >&2
exit 1
fi
bash -n "$script"
echo "Validated bash syntax: $script"
done