Skip to content

Commit

Permalink
Create .dockerignore
Browse files Browse the repository at this point in the history
  • Loading branch information
dogruis committed Dec 11, 2024
1 parent e83b04f commit 5089346
Show file tree
Hide file tree
Showing 10 changed files with 142 additions and 91 deletions.
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.gitignore
8 changes: 4 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- run: sudo apt-get update && sudo apt-get install -y --no-install-recommends binfmt-support qemu-user-static

- run: ./build.sh
- run: ./test.sh shellsu-amd64
- run: ./test.sh shellsu-i386
- run: ./test.sh --debian shellsu-amd64
- run: ./test.sh --debian shellsu-i386
- run: ./test.sh --alpine shellsu
- run: ./test.sh --debian shellsu
- run: docker build --pull --file hub/Dockerfile.alpine hub
- run: docker build --pull --file hub/Dockerfile.debian hub
44 changes: 10 additions & 34 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,50 +5,26 @@ FROM debian:bookworm-slim
RUN set -eux; \
apt-get update; \
apt-get install -y --no-install-recommends \
arch-test \
file \
bash \
login \
; \
rm -rf /var/lib/apt/lists/*

# Set environment variable for build flags
ENV BUILD_FLAGS="-v"

# Prepare the `shellsu` build and test script
RUN set -eux; \
{ \
echo '#!/usr/bin/env bash'; \
echo 'set -Eeuo pipefail -x'; \
echo 'ARCH="${ARCH:-$(uname -m)}"'; \
echo 'cp /usr/local/bin/shellsu /usr/local/bin/shellsu-$ARCH'; \
echo 'file "/usr/local/bin/shellsu-$ARCH"'; \
echo 'if arch-test "$ARCH"; then'; \
echo ' try() { for (( i = 0; i < 30; i++ )); do if timeout 1s "$@"; then return 0; fi; done; return 1; }'; \
echo ' try "/usr/local/bin/shellsu-$ARCH" --version'; \
echo ' try "/usr/local/bin/shellsu-$ARCH" nobody id'; \
echo ' try "/usr/local/bin/shellsu-$ARCH" nobody ls -l /proc/self/fd'; \
echo 'fi'; \
} > /usr/local/bin/shellsu-build-and-test.sh; \
chmod +x /usr/local/bin/shellsu-build-and-test.sh

# Disable CGO (not relevant for Bash, but keeping for alignment with original pattern)
ENV CGO_ENABLED 0

# Copy `shellsu` script into the container
WORKDIR /usr/local/bin
COPY shellsu /usr/local/bin/shellsu
COPY shellsu.sh /usr/local/bin/shellsu
RUN chmod +x /usr/local/bin/shellsu
RUN chmod u+s /usr/local/bin/shellsu

# Test `shellsu` for various architectures
RUN ARCH=amd64 shellsu-build-and-test.sh
RUN ARCH=i386 shellsu-build-and-test.sh
RUN ARCH=armel shellsu-build-and-test.sh
RUN ARCH=armhf shellsu-build-and-test.sh
RUN ARCH=arm64 shellsu-build-and-test.sh
RUN ARCH=mips64el shellsu-build-and-test.sh
RUN ARCH=ppc64el shellsu-build-and-test.sh
RUN ARCH=riscv64 shellsu-build-and-test.sh
RUN ARCH=s390x shellsu-build-and-test.sh
# Test `shellsu` to verify functionality
RUN set -eux; \
# Run the script with basic tests
./shellsu --help; \
./shellsu --version

# Final verification step
RUN set -eux; ls -lAFh /usr/local/bin/shellsu-*; file /usr/local/bin/shellsu-*
# Final verification step (list files and check permissions)
RUN set -eux; ls -lAFh /usr/local/bin/shellsu; file /usr/local/bin/shellsu
16 changes: 13 additions & 3 deletions Dockerfile.test-alpine
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
FROM alpine:3.20

RUN apk add --no-cache bash shadow

# Add "nobody" to ALL groups to create edge cases for testing
RUN cut -d: -f1 /etc/group | xargs -rtn1 addgroup nobody

Expand All @@ -11,18 +13,24 @@ RUN { \
echo 'spec="$1"; shift'; \
echo; \
echo 'expec="$1"; shift'; \
echo 'real="$(shellsu "$spec" id -u):$(shellsu "$spec" id -g):$(shellsu "$spec" id -G)"'; \
echo 'real="$(/usr/local/bin/shellsu "$spec" id -u):$(/usr/local/bin/shellsu "$spec" id -g):$(/usr/local/bin/shellsu "$spec" id -G)"'; \
echo '[ "$expec" = "$real" ]'; \
echo; \
echo 'expec="$1"; shift'; \
echo 'real="$(shellsu "$spec" id -un):$(shellsu "$spec" id -gn):$(shellsu "$spec" id -Gn)" || true'; \
echo 'real="$(/usr/local/bin/shellsu "$spec" id -un):$(/usr/local/bin/shellsu "$spec" id -gn):$(/usr/local/bin/shellsu "$spec" id -Gn)" || true'; \
echo '[ "$expec" = "$real" ]'; \
} > /usr/local/bin/shellsu-t \
&& chmod +x /usr/local/bin/shellsu-t

# Copy the `shellsu` binary/script into the image
COPY shellsu /usr/local/bin/
RUN ls -la
RUN pwd
COPY shellsu /usr/local/bin/shellsu
RUN chmod +x /usr/local/bin/shellsu
RUN chmod u+s /usr/local/bin/shellsu
RUN ls -la /usr/local/bin/
RUN echo $PATH
RUN ls -l $(which su)

# Adjust permissions for testing unusual cases
RUN chgrp nobody /usr/local/bin/shellsu \
Expand All @@ -35,6 +43,8 @@ ENV HOME /omg/really/shellsu/nowhere

# Validate initial state
RUN id
RUN cat /etc/passwd
RUN cat /etc/group

# Test various user/group configurations
RUN shellsu-t 0 "0:0:$(id -G root)" "root:root:$(id -Gn root)"
Expand Down
26 changes: 23 additions & 3 deletions Dockerfile.test-debian
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
FROM debian:bookworm-slim

# Install necessary dependencies
RUN set -eux; \
apt-get update; \
apt-get install -y --no-install-recommends \
file \
bash \
login \
; \
rm -rf /var/lib/apt/lists/*


# Add "nobody" to ALL groups to create edge cases for testing
RUN cut -d: -f1 /etc/group | xargs -rtI'{}' usermod -aG '{}' nobody
# Emulate Alpine's "games" user, which is part of the "users" group
Expand All @@ -13,18 +24,25 @@ RUN { \
echo 'spec="$1"; shift'; \
echo; \
echo 'expec="$1"; shift'; \
echo 'real="$(shellsu "$spec" id -u):$(shellsu "$spec" id -g):$(shellsu "$spec" id -G)"'; \
echo 'real="$(/usr/local/bin/shellsu "$spec" id -u):$(/usr/local/bin/shellsu "$spec" id -g):$(/usr/local/bin/shellsu "$spec" id -G)"'; \
echo '[ "$expec" = "$real" ]'; \
echo; \
echo 'expec="$1"; shift'; \
echo 'real="$(shellsu "$spec" id -un):$(shellsu "$spec" id -gn):$(shellsu "$spec" id -Gn)" || true'; \
echo 'real="$(/usr/local/bin/shellsu "$spec" id -un):$(/usr/local/bin/shellsu "$spec" id -gn):$(/usr/local/bin/shellsu "$spec" id -Gn)" || true'; \
echo '[ "$expec" = "$real" ]'; \
} > /usr/local/bin/shellsu-t \
&& chmod +x /usr/local/bin/shellsu-t

# Copy the `shellsu` binary/script into the image
COPY shellsu /usr/local/bin/
RUN ls -la
RUN pwd
COPY shellsu /usr/local/bin/shellsu
COPY shellsu /usr/local/bin/shellsu
RUN chmod +x /usr/local/bin/shellsu
RUN chmod u+s /usr/local/bin/shellsu
RUN ls -la /usr/local/bin/
RUN echo $PATH
RUN ls -l $(which su)

# Adjust permissions for testing unusual cases
RUN chgrp nogroup /usr/local/bin/shellsu \
Expand All @@ -37,6 +55,8 @@ ENV HOME /omg/really/shellsu/nowhere

# Validate initial state
RUN id
RUN cat /etc/passwd
RUN cat /etc/group

# Test various user/group configurations
RUN shellsu-t 0 "0:0:$(id -G root)" "root:root:$(id -Gn root)"
Expand Down
21 changes: 9 additions & 12 deletions build.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
set -e

# Navigate to the directory containing this script
Expand All @@ -7,20 +7,17 @@ cd "$(dirname "$(readlink -f "$BASH_SOURCE")")"
set -x

# Build the Docker image
docker build --pull -t shellsu .
docker build --no-cache --pull -t shellsu .

# Clean up any pre-existing artifacts
rm -f shellsu* SHA256SUMS*

# Extract the `shellsu` binaries from the built image
docker run --rm shellsu sh -c 'cd /go/bin && tar -c shellsu*' | tar -xv
docker run --rm --entrypoint cat shellsu /usr/local/bin/shellsu > shellsu

# Generate SHA256 checksums for the extracted files
sha256sum shellsu* | tee SHA256SUMS
chmod +x shellsu

# Inspect the extracted files
file shellsu*
ls -lFh shellsu* SHA256SUMS*
sha256sum shellsu | tee SHA256SUMS

# Run the built binary to verify functionality
"./shellsu-$(dpkg --print-architecture)" --help
file shellsu
ls -lFh shellsu SHA256SUMS

"./shellsu" --help
2 changes: 1 addition & 1 deletion hub/Dockerfile.alpine
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
FROM alpine:3.20

# https://github.com/tianon/shellsu/releases
# https://github.com/dogruis/shellsu/releases
ENV SHELLSU_VERSION 1.17

RUN set -eux; \
Expand Down
2 changes: 1 addition & 1 deletion hub/Dockerfile.debian
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
FROM debian:bookworm-slim

# https://github.com/tianon/shellsu/releases
# https://github.com/dogruis/shellsu/releases
ENV SHELLSU_VERSION 1.17

RUN set -eux; \
Expand Down
60 changes: 45 additions & 15 deletions shellsu.sh
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
#!/bin/bash
#!/usr/bin/env bash
set -Eeuo pipefail

# Script Metadata
VERSION="1.0"
SCRIPT_NAME="$(basename "$0")"
LICENSE_TEXT="Apache-2.0 (see https://github.com/tianon/gosu)"
LICENSE_TEXT="MIT (see https://github.com/dogruis/shellsu)"

# Helper Functions
usage() {
cat <<EOF
Usage: $SCRIPT_NAME user-spec command [args...]
eg: $SCRIPT_NAME tianon bash
eg: $SCRIPT_NAME dogruis bash
$SCRIPT_NAME nobody:root bash -c 'whoami && id'
$SCRIPT_NAME 1000:1 id
Options:
--help, -h Show this help message
--version, -v Show version information
$SCRIPT_NAME version: $VERSION
$SCRIPT_NAME license: $LICENSE_TEXT
EOF
Expand All @@ -29,17 +33,35 @@ error_exit() {
exit 1
}

# Parse and validate user:group spec
parse_user_spec() {
# Resolve numeric IDs to user/group names
resolve_user_spec() {
local spec="$1"
USER="${spec%%:*}"
GROUP="${spec#*:}"
[[ "$USER" == "$GROUP" ]] && GROUP=""
local user=""
local group=""

# Split into user and group if user:group format is given
IFS=':' read -r user group <<< "$spec"

# If user is numeric, resolve to username
if [[ "$user" =~ ^[0-9]+$ ]]; then
user=$(getent passwd "$user" | cut -d: -f1)
fi

# If group is numeric, resolve to group name
if [[ -n "$group" && "$group" =~ ^[0-9]+$ ]]; then
group=$(getent group "$group" | cut -d: -f1)
fi

# Validate user and group exist
if ! id "$user" &>/dev/null; then
error_exit "User '$user' does not exist."
fi

id "$USER" &>/dev/null || error_exit "User '$USER' does not exist."
if [[ -n "$GROUP" ]]; then
getent group "$GROUP" &>/dev/null || error_exit "Group '$GROUP' does not exist."
if [[ -n "$group" && ! $(getent group "$group" &>/dev/null) ]]; then
error_exit "Group '$group' does not exist."
fi

echo "$user:$group"
}

# Switch user and group, then execute the command
Expand All @@ -52,19 +74,20 @@ execute_as_user() {
# Resolve group ID if specified
if [[ -n "$group" ]]; then
GROUP_ID=$(getent group "$group" | cut -d: -f3)
# Use su with group specification
sg "$group" <<EOF
exec su -s /bin/bash -c "$(printf '%q ' "${cmd[@]}")" "$user"
EOF
else
# Execute the command with user privileges using su
exec su -s /bin/bash -c "$(printf '%q ' "${cmd[@]}")" "$user"
fi
}

# Main Script Logic
main() {
if [[ "$#" -lt 2 ]]; then
usage
exit 1
if [[ "$#" -lt 1 ]]; then
error_exit "Incorrect usage. You must specify a user-spec and a command. For example: $SCRIPT_NAME dogruis bash"
fi

case "$1" in
Expand All @@ -78,11 +101,18 @@ main() {
;;
esac

# Ensure no conflicting options are provided (only one of --help or --version should be used)
if [[ "$#" -lt 2 ]]; then
error_exit "You must provide both a user-spec and a command. Usage: $SCRIPT_NAME user-spec command [args...]"
fi

USER_SPEC="$1"
shift
COMMAND=("$@")

parse_user_spec "$USER_SPEC"
# Resolve user and group from the spec
IFS=':' read -r USER GROUP <<< "$(resolve_user_spec "$USER_SPEC")"

execute_as_user "$USER" "$GROUP" "${COMMAND[@]}"
}

Expand Down
Loading

0 comments on commit 5089346

Please sign in to comment.