feat: Update toolbox-base and template with latest Docker configurations and documentation
\n- Updated Dockerfiles in both toolbox-base and toolbox-template - Modified build scripts and docker-compose configurations - Added new audit tools and documentation files - Created new toolbox-DocStack and toolbox-QADocker implementations - Updated README and maintenance documentation
This commit is contained in:
195
ToolboxStack/output/toolbox-DocStack/build.sh
Executable file
195
ToolboxStack/output/toolbox-DocStack/build.sh
Executable file
@@ -0,0 +1,195 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Security: Validate input parameters to prevent command injection
|
||||
sanitized_input() {
|
||||
local input="$1"
|
||||
# Check for potentially dangerous characters/commands
|
||||
case "$input" in
|
||||
*[\;\|\&\`\$]*)
|
||||
echo "Error: Invalid input detected: $input" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Validate dependencies
|
||||
if ! command -v docker &> /dev/null; then
|
||||
echo "Error: docker is required but not installed." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! docker buildx version &> /dev/null; then
|
||||
echo "Error: docker buildx is required but not available." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Get the toolbox name from the directory name (or you can pass it as an argument)
|
||||
TOOLBOX_NAME="${TOOLBOX_NAME_OVERRIDE:-$(basename "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")}"
|
||||
sanitized_input "$TOOLBOX_NAME"
|
||||
IMAGE_NAME="tsysdevstack-toolboxstack-$(echo "${TOOLBOX_NAME#toolbox-}" | tr '[:upper:]' '[:lower:]')"
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
# Sanitize user input
|
||||
USER_ID="${USER_ID_OVERRIDE:-$(id -u)}"
|
||||
sanitized_input "$USER_ID"
|
||||
GROUP_ID="${GROUP_ID_OVERRIDE:-$(id -g)}"
|
||||
sanitized_input "$GROUP_ID"
|
||||
USERNAME="${USERNAME_OVERRIDE:-toolbox}"
|
||||
sanitized_input "$USERNAME"
|
||||
TEA_VERSION="${TEA_VERSION_OVERRIDE:-0.11.1}"
|
||||
sanitized_input "$TEA_VERSION"
|
||||
BUILDER_NAME="${BUILDER_NAME:-tsysdevstack-toolboxstack-builder}"
|
||||
sanitized_input "$BUILDER_NAME"
|
||||
CACHE_DIR="${SCRIPT_DIR}/.build-cache"
|
||||
TAG="${TAG_OVERRIDE:-dev}"
|
||||
sanitized_input "$TAG"
|
||||
RELEASE_TAG="${RELEASE_TAG_OVERRIDE:-release-current}"
|
||||
sanitized_input "$RELEASE_TAG"
|
||||
VERSION_TAG="${VERSION_TAG_OVERRIDE:-}"
|
||||
if [[ -n "$VERSION_TAG" ]]; then
|
||||
sanitized_input "$VERSION_TAG"
|
||||
fi
|
||||
PUSH="${PUSH_OVERRIDE:-false}"
|
||||
|
||||
echo "Building ${IMAGE_NAME} with UID=${USER_ID} GID=${GROUP_ID} USERNAME=${USERNAME}"
|
||||
echo "Primary tag: ${TAG}"
|
||||
|
||||
# Ensure builder exists
|
||||
if ! docker buildx inspect "${BUILDER_NAME}" >/dev/null 2>&1; then
|
||||
echo "Creating builder: ${BUILDER_NAME}"
|
||||
# Use the default docker driver instead of docker-container to access local images
|
||||
if ! docker buildx create --driver docker --name "${BUILDER_NAME}" --use >/dev/null; then
|
||||
echo "Error: Failed to create Docker buildx builder." >&2
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "Using existing builder: ${BUILDER_NAME}"
|
||||
if ! docker buildx use "${BUILDER_NAME}" >/dev/null; then
|
||||
echo "Error: Failed to use Docker buildx builder." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Ensure cache directory exists
|
||||
if ! mkdir -p "${CACHE_DIR}"; then
|
||||
echo "Error: Failed to create cache directory: ${CACHE_DIR}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Starting build..."
|
||||
BUILD_OUTPUT=$(mktemp)
|
||||
trap 'rm -f "$BUILD_OUTPUT"' EXIT
|
||||
|
||||
# Build the image
|
||||
if ! docker buildx build \
|
||||
--builder "${BUILDER_NAME}" \
|
||||
--load \
|
||||
--progress=plain \
|
||||
--build-arg USER_ID="${USER_ID}" \
|
||||
--build-arg GROUP_ID="${GROUP_ID}" \
|
||||
--build-arg USERNAME="${USERNAME}" \
|
||||
--build-arg TEA_VERSION="${TEA_VERSION}" \
|
||||
--cache-from "type=local,src=${CACHE_DIR}" \
|
||||
--cache-to "type=local,dest=${CACHE_DIR},mode=max" \
|
||||
--tag "${IMAGE_NAME}:${TAG}" \
|
||||
--allow network.host \
|
||||
"${SCRIPT_DIR}" 2>&1 | tee "${BUILD_OUTPUT}"; then
|
||||
echo "Error: Docker build failed. Check output above for details." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Build completed successfully."
|
||||
|
||||
# Run post-build verification
|
||||
echo "Running post-build verification..."
|
||||
if ! docker run --rm "${IMAGE_NAME}:${TAG}" zsh -c 'echo "Container starts successfully"'; then
|
||||
echo "Error: Failed to start container with basic test." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Verify critical tools are available
|
||||
echo "Verifying critical tools..."
|
||||
CRITICAL_TOOLS=("zsh" "git" "curl" "jq" "fish" "fzf" "bat" "fd" "rg" "htop" "btop")
|
||||
for tool in "${CRITICAL_TOOLS[@]}"; do
|
||||
if ! docker run --rm "${IMAGE_NAME}:${TAG}" which "$tool" >/dev/null 2>&1; then
|
||||
echo "Error: Critical tool '$tool' not found in PATH." >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
# Verify aqua tools are available
|
||||
echo "Verifying aqua tools..."
|
||||
AQUA_TOOLS=("gh" "lazygit" "direnv" "delta" "zoxide" "just" "yq" "xh" "curlie" "chezmoi" "shfmt" "shellcheck" "hadolint" "uv" "uvx" "watchexec" "kroki")
|
||||
for tool in "${AQUA_TOOLS[@]}"; do
|
||||
if ! docker run --rm "${IMAGE_NAME}:${TAG}" which "$tool" >/dev/null 2>&1; then
|
||||
echo "Error: Aqua tool '$tool' not found in PATH." >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
# Verify AI CLI tools are available
|
||||
echo "Verifying AI CLI tools..."
|
||||
AI_TOOLS=("code" "qwen" "gemini" "codex" "opencode")
|
||||
for tool in "${AI_TOOLS[@]}"; do
|
||||
if ! docker run --rm "${IMAGE_NAME}:${TAG}" which "$tool" >/dev/null 2>&1; then
|
||||
echo "Error: AI CLI tool '$tool' not found in PATH." >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
# Verify testing tools are available
|
||||
echo "Verifying testing tools..."
|
||||
TESTING_TOOLS=("bats" "shellcheck" "shfmt" "hadolint")
|
||||
for tool in "${TESTING_TOOLS[@]}"; do
|
||||
if ! docker run --rm "${IMAGE_NAME}:${TAG}" which "$tool" >/dev/null 2>&1; then
|
||||
echo "Error: Testing tool '$tool' not found in PATH." >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
echo "All verifications passed."
|
||||
|
||||
# Push if requested
|
||||
if [[ "${PUSH}" == "true" ]]; then
|
||||
echo "Pushing ${IMAGE_NAME}:${TAG}"
|
||||
if ! docker push "${IMAGE_NAME}:${TAG}"; then
|
||||
echo "Error: Failed to push ${IMAGE_NAME}:${TAG}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "${TAG}" == "dev" && -n "${VERSION_TAG}" ]]; then
|
||||
if ! docker tag "${IMAGE_NAME}:${TAG}" "${IMAGE_NAME}:${VERSION_TAG}"; then
|
||||
echo "Error: Failed to tag ${IMAGE_NAME}:${VERSION_TAG}" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "Pushing ${IMAGE_NAME}:${VERSION_TAG}"
|
||||
if ! docker push "${IMAGE_NAME}:${VERSION_TAG}"; then
|
||||
echo "Error: Failed to push ${IMAGE_NAME}:${VERSION_TAG}" >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "${TAG}" == "dev" ]]; then
|
||||
if ! docker tag "${IMAGE_NAME}:${TAG}" "${IMAGE_NAME}:${RELEASE_TAG}"; then
|
||||
echo "Error: Failed to tag ${IMAGE_NAME}:${RELEASE_TAG}" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "Pushing ${IMAGE_NAME}:${RELEASE_TAG}"
|
||||
if ! docker push "${IMAGE_NAME}:${RELEASE_TAG}"; then
|
||||
echo "Error: Failed to push ${IMAGE_NAME}:${RELEASE_TAG}" >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Run security scan if TRIVY is available
|
||||
if command -v trivy &> /dev/null; then
|
||||
echo "Running security scan with Trivy..."
|
||||
trivy image --exit-code 0 --severity HIGH,CRITICAL "${IMAGE_NAME}:${TAG}"
|
||||
else
|
||||
echo "Trivy not found. Install Trivy to perform security scanning."
|
||||
fi
|
||||
|
||||
echo "Build process completed successfully with all verifications."
|
||||
Reference in New Issue
Block a user