chore(filesystem): reflect major filesystem restructuring changes

- Renamed DocStack to dockstack
- Transformed toolbox-template into toolbox-qadocker with new functionality
- Removed NewToolbox.sh script
- Updated PROMPT and configuration files across all toolboxes
- Consolidated audit and testing scripts
- Updated QWEN.md to reflect new filesystem structure as authoritative source
- Merged PROMPT content into QWEN.md as requested

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

The filesystem structure has been intentionally restructured and is now the authoritative source of truth for the project organization.
This commit is contained in:
2025-10-31 13:26:39 -05:00
parent 199789e2c4
commit ab54d694f2
48 changed files with 1020 additions and 1119 deletions

View File

@@ -0,0 +1,14 @@
{
"name": "TSYSDevStack toolbox-DocStack",
"dockerComposeFile": [
"../docker-compose.yml"
],
"service": "toolbox-DocStack",
"workspaceFolder": "/workspace",
"remoteUser": "toolbox",
"runServices": [
"toolbox-DocStack"
],
"overrideCommand": false,
"postCreateCommand": "zsh -lc 'starship --version >/dev/null'"
}

View File

@@ -0,0 +1,120 @@
# 🧰 Toolbox Template Audit Checklist
This checklist ensures the toolbox-template provides a solid foundation for creating new toolboxes that extend from toolbox-base.
## 🏗️ Structure Audit
- [ ] Template Dockerfile properly extends from toolbox-base:release-current
- [ ] Template Dockerfile follows best practices for extension
- [ ] Template docker-compose.yml properly inherits from base configuration
- [ ] Template build.sh script properly wraps docker build with UID/GID mapping
- [ ] Template run.sh script properly manages container lifecycle
- [ ] Template devcontainer.json properly references base configuration
- [ ] Template SEED file properly defines extension objectives
- [ ] Template PROMPT file properly guides contributors
- [ ] Template README.md properly documents usage and customization
- [ ] Template aqua.yaml properly extends from base tooling
## 🔧 Consistency Audit
- [ ] Template inherits all base security practices
- [ ] Template follows same build process patterns as base
- [ ] Template uses same user model as base (non-root with UID/GID mapping)
- [ ] Template workspace mounting consistent with base
- [ ] Template runtime behavior consistent with base
- [ ] Template error handling consistent with base
- [ ] Template documentation style consistent with base
- [ ] Template testing approach consistent with base
- [ ] Template customization points clearly defined
- [ ] Template extension patterns well-documented
## 🛡️ Security Audit
- [ ] Template maintains all base security guarantees
- [ ] Template doesn't introduce security vulnerabilities
- [ ] Template doesn't weaken base security model
- [ ] Template properly validates user inputs
- [ ] Template properly handles file permissions
- [ ] Template doesn't expose additional attack surfaces
- [ ] Template properly manages secrets/configuration
- [ ] Template follows principle of least privilege
- [ ] Template properly isolates user processes
- [ ] Template maintains non-root execution model
## 🧪 Testing Audit
- [ ] Template includes testing framework
- [ ] Template tests verify proper extension from base
- [ ] Template tests validate added functionality
- [ ] Template tests check for regression issues
- [ ] Template tests cover error conditions
- [ ] Template tests verify security properties
- [ ] Template tests run automatically during build
- [ ] Template tests provide clear failure diagnostics
- [ ] Template tests cover all customization points
- [ ] Template tests align with base testing philosophy
## 📚 Documentation Audit
- [ ] Template README.md clearly explains purpose and usage
- [ ] Template README.md properly documents customization options
- [ ] Template README.md links to base documentation
- [ ] Template README.md includes quick start guide
- [ ] Template README.md covers troubleshooting
- [ ] Template README.md explains extension patterns
- [ ] Template README.md documents versioning strategy
- [ ] Template README.md covers maintenance procedures
- [ ] Template README.md explains collaboration guidelines
- [ ] Template README.md maintains consistent style with base
## 🔄 Maintenance Audit
- [ ] Template properly tracks base image updates
- [ ] Template provides clear upgrade paths
- [ ] Template maintains backward compatibility
- [ ] Template follows same release cadence as base
- [ ] Template properly handles dependency updates
- [ ] Template includes update automation where appropriate
- [ ] Template documents breaking changes
- [ ] Template provides migration guides when needed
- [ ] Template follows same versioning scheme as base
- [ ] Template maintains consistent issue tracking
## 🎯 Usability Audit
- [ ] Template is easy to copy and customize
- [ ] Template provides clear extension points
- [ ] Template includes helpful examples
- [ ] Template reduces boilerplate code
- [ ] Template provides sensible defaults
- [ ] Template includes proper error messages
- [ ] Template supports common customization patterns
- [ ] Template includes helpful documentation
- [ ] Template follows intuitive naming conventions
- [ ] Template minimizes configuration complexity
## 🌐 Compatibility Audit
- [ ] Template works with all supported platforms
- [ ] Template maintains cross-platform consistency
- [ ] Template integrates well with base tooling
- [ ] Template supports common development workflows
- [ ] Template handles various project structures
- [ ] Template works with popular IDEs/editors
- [ ] Template supports CI/CD integration
- [ ] Template compatible with common deployment methods
- [ ] Template supports popular version control systems
- [ ] Template integrates with common development tools
## 🧹 Cleanliness Audit
- [ ] Template includes no unnecessary files
- [ ] Template follows consistent file organization
- [ ] Template includes proper .gitignore
- [ ] Template avoids duplicating base functionality
- [ ] Template includes proper licensing information
- [ ] Template maintains clean directory structure
- [ ] Template includes appropriate comments/documentation
- [ ] Template avoids hardcoded values where possible
- [ ] Template follows consistent naming conventions
- [ ] Template includes proper attribution where needed

View File

@@ -0,0 +1,76 @@
# Extend from the toolbox-base image
# NOTE: Always use the full image name to ensure compatibility in standalone builds
FROM tsysdevstack-toolboxstack-toolbox-base:dev
# Set build arguments (these can be overridden at build time)
ARG USER_ID=1000
ARG GROUP_ID=1000
ARG USERNAME=toolbox
# Ensure the non-root user exists with the correct UID/GID
RUN if getent passwd "${USER_ID}" >/dev/null; then \
existing_user="$(getent passwd "${USER_ID}" | cut -d: -f1)"; \
userdel --remove "${existing_user}" 2>/dev/null || true; \
fi \
&& if ! getent group "${GROUP_ID}" >/dev/null; then \
groupadd --gid "${GROUP_ID}" "${USERNAME}"; \
fi \
&& useradd --uid "${USER_ID}" --gid "${GROUP_ID}" --shell /usr/bin/zsh --create-home "${USERNAME}"
# Switch to root user to install packages
USER root
# Install documentation-specific packages here
# Adding pandoc, plantuml, graphviz, and other documentation tools
RUN apt-get update && apt-get install -y --no-install-recommends \
pandoc \
plantuml \
default-jre \
graphviz \
texlive-xetex \
texlive-fonts-recommended \
texlive-latex-extra \
librsvg2-bin \
npm \
nodejs \
python3 \
python3-pip \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# Install additional documentation tools
# Adding Quarto, mdBook, Marp, Typst, and Markwhen
RUN npm install -g @quarto/quarto@1.4.549 \
&& npm install -g @marp-team/marp-cli@3.4.0 \
&& npm install -g @markwhen/mw@0.4.0 \
&& npm install -g joplin-cli@latest
# Install mdBook
RUN curl -sSL https://github.com/rust-lang/mdBook/releases/download/v0.4.41/mdbook-v0.4.41-x86_64-unknown-linux-gnu.tar.gz | tar -xz -C /usr/local/bin
# Install Typst
RUN curl -sSL https://github.com/typst/typst/releases/download/v0.12.0/typst-x86_64-unknown-linux-musl.tar.gz | tar -xz -C /usr/local/bin
# Add toolbox-specific aqua packages to the existing configuration
COPY aqua.yaml /tmp/aqua.additions
RUN su - "${USERNAME}" -c ' \
cat /tmp/aqua.additions | grep -v "^version\|^registries" >> ~/.config/aquaproj-aqua/aqua.yaml && \
AQUA_GLOBAL_CONFIG=/home/${USERNAME}/.config/aquaproj-aqua/aqua.yaml aqua install \
'
# Install toolbox-specific npm packages here
# Example:
# RUN mise exec -- npm install -g @scope/package@version
# Remove sudo to ensure no root escalation is possible at runtime
RUN apt-get remove -y sudo 2>/dev/null || true && apt-get autoremove -y 2>/dev/null || true && rm -rf /var/lib/apt/lists/* 2>/dev/null || true
# Switch back to the non-root user
USER ${USERNAME}
WORKDIR /workspace
# Default command
CMD ["/usr/bin/zsh"]
# Ensure container runs as the toolbox user
USER toolbox

View File

@@ -0,0 +1,27 @@
You are Codex, collaborating with a human on the TSYSDevStack ToolboxStack project.
- Seed context:
- `SEED` captures the initial scope. Edit it once to define goals, then treat it as read-only unless the high-level objectives change.
- Start each session by reading it (`cat SEED`) and summarize progress or adjustments here in PROMPT.
Context snapshot (toolbox-DocStack):
- Working directory: artifacts/ToolboxStack/toolbox-DocStack
- Image: tsysdevstack-toolboxstack-toolbox-DocStack (extends from tsysdevstack-toolboxstack-toolbox-base:release-current)
- Container user: toolbox (non-root, UID/GID mapped to host)
- Mounted workspace: current repo at /workspace (rw)
Current state:
- Extends from the standard toolbox-base image, inheriting all base tooling (shells, CLIs, package managers).
- aqua packages are baked into the base image during the build process for consistency, reproducibility and performance.
- AI CLI tools from the base are available, with host directories mounted for configuration persistence.
- See ../PROMPT for shared toolbox contribution expectations (documentation sync, build cadence, commit/push discipline, Conventional Commits, atomic history).
Collaboration checklist:
1. Translate SEED goals into concrete tooling decisions; mirror outcomes in README.md and this PROMPT (do not rewrite SEED unless the scope resets).
2. Prefer aqua-managed CLIs and mise-managed runtimes for reproducibility.
3. After each tooling change, update README/PROMPT, run ./build.sh, commit (Conventional Commit message, focused diff), and push only once the build succeeds per ../PROMPT.
4. Record verification steps (build/test commands) as they are performed.
5. Maintain UID/GID mapping and non-root execution.
Active focus:
- Initialize toolbox-DocStack using the toolbox-template scaffolding; evolve the Dockerfile/tooling inventory to satisfy the SEED goals.

View File

@@ -0,0 +1,107 @@
# 🧰 TSYSDevStack Toolbox Template
Template for creating new toolboxes that extend from the `toolbox-base` image.
---
## 🚀 Quick Start
1. **Create a new toolbox**
```bash
cp -r /path/to/toolbox-template /path/to/new-toolbox
cd /path/to/new-toolbox
```
2. **Customize the toolbox**
- Edit `Dockerfile` to add toolbox-specific tooling
- Modify `docker-compose.yml` to adjust service configuration
- Update `SEED` to define the toolbox's purpose and goals
3. **Build the toolbox**
```bash
./build.sh
```
4. **Start the toolbox**
```bash
./run.sh up
```
5. **Access the toolbox**
```bash
docker exec -it tsysdevstack-toolboxstack-toolbox-DocStack zsh
```
6. **Stop the toolbox**
```bash
./run.sh down
```
---
## 🧱 Architecture
- **Base Image**: Extends from `tsysdevstack-toolboxstack-toolbox-base:release-current`
- **User**: Runs as non-root `toolbox` user (UID/GID mapped to host)
- **Workspace**: Mounts current directory to `/workspace` (read/write)
- **Runtime**: Inherits all tooling from base plus toolbox-specific additions
---
## 🛠️ Customization
### Dockerfile
Extend the base image with toolbox-specific tooling:
```dockerfile
# Extend from the toolbox-base image
FROM tsysdevstack-toolboxstack-toolbox-base:release-current
# Add toolbox-specific packages or configurations
RUN apt-get update && apt-get install -y --no-install-recommends \
specific-package \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
```
### docker-compose.yml
Adjust service configuration for toolbox-specific needs:
```yaml
services:
my-toolbox:
# Inherits all base configuration
# Add toolbox-specific volumes, ports, etc.
volumes:
- ./custom-config:/home/toolbox/.config/custom-tool
```
### SEED
Define the toolbox's purpose and goals:
```markdown
- Describe what this toolbox should provide (languages, CLIs, workflows)
- List required base image modifications or additional mounts
- Note verification or testing expectations specific to this toolbox
```
---
## 📂 Project Layout
| Path | Purpose |
|------|---------|
| `Dockerfile` | Extends base image with toolbox-specific tooling |
| `docker-compose.yml` | Service configuration for the toolbox |
| `build.sh` | Wrapper around `docker build` with host UID/GID mapping |
| `run.sh` | Helper to bring the service up/down |
| `.devcontainer/devcontainer.json` | VS Code remote container definition |
| `SEED` | Defines the toolbox's purpose and goals |
| `PROMPT` | LLM onboarding prompt for future contributors |
---
## 🤝 Collaboration Notes
- Inherits all collaboration policies from `toolbox-base`
- Document toolbox-specific additions in `README.md` and `PROMPT`
- Update `SEED` only when the high-level objectives change
- Prefer aqua/mise for new tooling to keep installations reproducible
- Keep documentation synchronized for future contributors

View File

@@ -0,0 +1,46 @@
# 📚 DocStack SEED
## 🎯 Purpose
Specialized documentation generation toolbox for creating beautiful PDFs including resumes, proposals, Joplin note exports, and timelines.
## 🧰 Tooling Goals
1. **Core Documentation Tools**
- Pandoc for document conversion
- PlantUML for UML diagrams
- Graphviz for diagram rendering
- Markwhen for timeline creation
2. **PDF Generation Frameworks**
- Quarto for scientific and technical documents
- mdBook for book-style documentation
- Marp for presentation slides
- Typst for modern typesetting
3. **AI-Assisted Documentation**
- Joplin CLI for note management and export
- Code generation tools for AI-assisted writing
4. **Verification & Quality**
- Document validation and linting
- Automated testing of document generation workflows
## 🏗️ Implementation Plan
1. Extend from the toolbox-base image
2. Install documentation-specific packages via apt
3. Add documentation tools via aqua where available
4. Install Node.js-based tools via npm/mise
5. Ensure all tools work together in a cohesive workflow
6. Provide comprehensive testing and verification
## 🧪 Testing Expectations
- Verify all documentation tools can generate output
- Test document conversion workflows (Markdown → PDF, etc.)
- Validate diagram generation (PlantUML, Graphviz)
- Confirm timeline creation with Markwhen
- Ensure PDF generation with all frameworks (Quarto, mdBook, Marp, Typst)
## 📚 Documentation Requirements
- Update README with all installed tools and usage examples
- Document common workflows for each tool category
- Provide troubleshooting guidance for PDF generation issues
- Include examples for resumes, proposals, and note exports

View File

@@ -0,0 +1,9 @@
version: 1.0.0
registries:
- type: standard
ref: v4.431.0
packages:
# Documentation tools
- name: charmbracelet/glow@v1.5.1 # Terminal markdown reader
- name: charmbracelet/gum@v0.14.0 # Stylish shell dialogs
- name: charmbracelet/mods@v1.2.1 # AI model interaction

View 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."

View File

@@ -0,0 +1,35 @@
services:
toolbox-DocStack:
container_name: tsysdevstack-toolboxstack-toolbox-DocStack
image: tsysdevstack-toolboxstack-toolbox-DocStack
build:
context: .
dockerfile: Dockerfile
args:
USER_ID: ${LOCAL_UID:-1000}
GROUP_ID: ${LOCAL_GID:-1000}
USERNAME: ${LOCAL_USERNAME:-toolbox}
user: "${LOCAL_UID:-1000}:${LOCAL_GID:-1000}"
working_dir: /workspace
command: ["sleep", "infinity"]
init: true
tty: true
stdin_open: true
volumes:
- .:/workspace:rw
- ${HOME}/.local/share/mise:/home/toolbox/.local/share/mise:rw
- ${HOME}/.cache/mise:/home/toolbox/.cache/mise:rw
# AI CLI tool configuration and cache directories
- ${HOME}/.config/openai:/home/toolbox/.config/openai:rw
- ${HOME}/.config/gemini:/home/toolbox/.config/gemini:rw
- ${HOME}/.config/qwen:/home/toolbox/.config/qwen:rw
- ${HOME}/.config/code:/home/toolbox/.config/code:rw
- ${HOME}/.config/opencode:/home/toolbox/.config/opencode:rw
- ${HOME}/.cache/openai:/home/toolbox/.cache/openai:rw
- ${HOME}/.cache/gemini:/home/toolbox/.cache/gemini:rw
- ${HOME}/.cache/qwen:/home/toolbox/.cache/qwen:rw
- ${HOME}/.cache/code:/home/toolbox/.cache/code:rw
- ${HOME}/.cache/opencode:/home/toolbox/.cache/opencode:rw
# Additional AI tool directories
- ${HOME}/.config/codex:/home/toolbox/.config/codex:rw
- ${HOME}/.cache/codex:/home/toolbox/.cache/codex:rw

View File

@@ -0,0 +1,111 @@
#!/usr/bin/env bash
set -euo pipefail
usage() {
cat <<'EOU'
Usage: ./release.sh [--dry-run] [--allow-dirty] <semver>
Examples:
./release.sh 0.2.0
./release.sh --dry-run 0.2.0
This script rebuilds the toolbox image, tags it as:
- tsysdevstack-toolboxstack-<name>:dev
- tsysdevstack-toolboxstack-<name>:release-current
- tsysdevstack-toolboxstack-<name>:v<semver>
When run without --dry-run it pushes all three tags.
EOU
}
DRY_RUN=false
ALLOW_DIRTY=false
VERSION=""
while (( $# > 0 )); do
case "$1" in
--dry-run)
DRY_RUN=true
shift
;;
--allow-dirty)
ALLOW_DIRTY=true
shift
;;
-h|--help)
usage
exit 0
;;
-*)
echo "Unknown option: $1" >&2
usage
exit 1
;;
*)
VERSION="$1"
shift
;;
esac
done
if [[ -z "${VERSION}" ]]; then
echo "Error: semantic version is required." >&2
usage
exit 1
fi
if [[ "${VERSION}" =~ ^v?([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then
SEMVER="v${BASH_REMATCH[1]}.${BASH_REMATCH[2]}.${BASH_REMATCH[3]}"
else
echo "Error: version must be semantic (e.g., 0.2.0 or v0.2.0)." >&2
exit 1
fi
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "${SCRIPT_DIR}" && git rev-parse --show-toplevel 2>/dev/null || true)"
if [[ -n "${REPO_ROOT}" && "${ALLOW_DIRTY}" != "true" ]]; then
if ! git -C "${REPO_ROOT}" diff --quiet --ignore-submodules --exit-code; then
echo "Error: git working tree has uncommitted changes. Please commit or stash before releasing." >&2
exit 1
fi
elif [[ -z "${REPO_ROOT}" ]]; then
echo "Warning: unable to resolve git repository root; skipping clean tree check." >&2
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)")}"
IMAGE_NAME="tsysdevstack-toolboxstack-${TOOLBOX_NAME#toolbox-}"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
USER_ID="${USER_ID_OVERRIDE:-$(id -u)}"
GROUP_ID="${GROUP_ID_OVERRIDE:-$(id -g)}"
USERNAME="${USERNAME_OVERRIDE:-toolbox}"
TEA_VERSION="${TEA_VERSION_OVERRIDE:-0.11.1}"
BUILDER_NAME="${BUILDER_NAME:-tsysdevstack-toolboxstack-builder}"
CACHE_DIR="${SCRIPT_DIR}/.build-cache"
TAG="${TAG_OVERRIDE:-dev}"
RELEASE_TAG="${RELEASE_TAG_OVERRIDE:-release-current}"
VERSION_TAG="${VERSION_TAG_OVERRIDE:-}"
if [[ -n "$VERSION_TAG" ]]; then
VERSION_TAG="$SEMVER"
fi
PUSH="${PUSH_OVERRIDE:-false}"
echo "Preparing release for ${SEMVER}"
echo " dry-run: ${DRY_RUN}"
echo " allow-dirty: ${ALLOW_DIRTY}"
if [[ "${DRY_RUN}" == "true" ]]; then
echo "[dry-run] Would build ${IMAGE_NAME}:${TAG}"
TAG_OVERRIDE="${TAG}" PUSH_OVERRIDE=false "${SCRIPT_DIR}/build.sh"
echo "[dry-run] Skipped pushing tags."
else
echo "Building ${IMAGE_NAME}:${TAG}"
TAG_OVERRIDE="${TAG}" PUSH_OVERRIDE=true RELEASE_TAG_OVERRIDE="${RELEASE_TAG}" VERSION_TAG_OVERRIDE="${SEMVER}" "${SCRIPT_DIR}/build.sh"
echo "Release ${SEMVER} pushed as:"
echo " - ${IMAGE_NAME}:dev"
echo " - ${IMAGE_NAME}:release-current"
echo " - ${IMAGE_NAME}:${SEMVER}"
fi

View File

@@ -0,0 +1,74 @@
#!/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 ! command -v docker compose &> /dev/null; then
echo "Error: docker compose is required but not installed." >&2
exit 1
fi
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
COMPOSE_FILE="${SCRIPT_DIR}/docker-compose.yml"
export LOCAL_UID="${USER_ID_OVERRIDE:-$(id -u)}"
sanitized_input "$LOCAL_UID"
export LOCAL_GID="${GROUP_ID_OVERRIDE:-$(id -g)}"
sanitized_input "$LOCAL_GID"
export LOCAL_USERNAME="${USERNAME_OVERRIDE:-toolbox}"
sanitized_input "$LOCAL_USERNAME"
export TOOLBOX_IMAGE="${TOOLBOX_IMAGE_OVERRIDE:-tsysdevstack-toolboxstack-toolbox-DocStack}"
sanitized_input "$TOOLBOX_IMAGE"
if [[ ! -f "${COMPOSE_FILE}" ]]; then
echo "Error: docker-compose.yml not found at ${COMPOSE_FILE}" >&2
exit 1
fi
ACTION="${1:-up}"
sanitized_input "$ACTION"
shift || true
if [[ "${ACTION}" == "up" ]]; then
# Create necessary directories for the toolbox tools with proper permissions
mkdir -p "${HOME}/.local/share/mise" "${HOME}/.cache/mise"
mkdir -p "${HOME}/.config" "${HOME}/.local/share"
mkdir -p "${HOME}/.cache/openai" "${HOME}/.cache/gemini" "${HOME}/.cache/qwen" "${HOME}/.cache/code" "${HOME}/.cache/opencode"
mkdir -p "${HOME}/.config/openai" "${HOME}/.config/gemini" "${HOME}/.config/qwen" "${HOME}/.config/code" "${HOME}/.config/opencode"
mkdir -p "${HOME}/.config/codex" "${HOME}/.cache/codex"
# Set proper permissions for created directories
chmod 700 "${HOME}/.config" "${HOME}/.local/share" "${HOME}/.cache" 2>/dev/null || true
fi
case "${ACTION}" in
up)
docker compose -f "${COMPOSE_FILE}" up --build --detach "$@"
echo "Container started. Use 'docker exec -it tsysdevstack-toolboxstack-toolbox-DocStack zsh' to access the shell."
;;
down)
docker compose -f "${COMPOSE_FILE}" down "$@"
echo "Container stopped."
;;
*)
echo "Usage: $0 [up|down] [additional docker compose args]" >&2
exit 1
;;
esac

View File

@@ -0,0 +1,155 @@
#!/usr/bin/env bash
set -euo pipefail
# Security audit script for the toolbox-template
IMAGE_NAME="${IMAGE_NAME_OVERRIDE:-tsysdevstack-toolboxstack-toolbox-DocStack}"
echo "🔒 Running security audit on ${IMAGE_NAME}"
# Check if Trivy is available for security scanning
if command -v trivy &> /dev/null; then
echo "🔍 Running Trivy security scan..."
trivy image --exit-code 0 --severity HIGH,CRITICAL "${IMAGE_NAME}"
echo "✅ Trivy scan completed"
else
echo "⚠️ Trivy not found. Install Trivy to perform security scanning."
echo " Visit https://aquasecurity.github.io/trivy/ for installation instructions."
fi
# Check for outdated packages
echo "📦 Checking for outdated packages..."
OUTDATED_PACKAGES=$(docker run --rm "${IMAGE_NAME}" apt list --upgradable 2>/dev/null | grep -v "Listing..." | wc -l)
if [[ "${OUTDATED_PACKAGES}" -gt 0 ]]; then
echo "⚠️ ${OUTDATED_PACKAGES} packages can be upgraded"
echo " Run 'apt update && apt upgrade' to update packages"
else
echo "✅ All system packages are up to date"
fi
# Check for unnecessary packages that increase attack surface
echo "🛡️ Checking for unnecessary packages..."
UNNECESSARY_PACKAGES=$(docker run --rm "${IMAGE_NAME}" dpkg -l | grep -E "(telnet|ftp|rsh-client|nfs-common|rpcbind)" | wc -l)
if [[ "${UNNECESSARY_PACKAGES}" -gt 0 ]]; then
echo "⚠️ Found ${UNNECESSARY_PACKAGES} potentially unnecessary packages that increase attack surface"
echo " Consider removing packages like telnet, ftp, rsh-client, nfs-common, rpcbind"
else
echo "✅ No unnecessary packages found that increase attack surface"
fi
# Check for world-writable files/directories
echo "📁 Checking for world-writable files/directories..."
WORLD_WRITABLE=$(docker run --rm "${IMAGE_NAME}" find / -xdev -type f -perm -0002 -not -path "/proc/*" -not -path "/sys/*" 2>/dev/null | wc -l)
if [[ "${WORLD_WRITABLE}" -gt 0 ]]; then
echo "⚠️ Found ${WORLD_WRITABLE} world-writable files/directories"
echo " These should be reviewed and permissions adjusted if necessary"
else
echo "✅ No world-writable files/directories found"
fi
# Check for setuid/setgid binaries
echo "🔑 Checking for setuid/setgid binaries..."
SETUID_BINARIES=$(docker run --rm "${IMAGE_NAME}" find / -xdev \( -perm -4000 -o -perm -2000 \) -type f -not -path "/proc/*" -not -path "/sys/*" 2>/dev/null | wc -l)
if [[ "${SETUID_BINARIES}" -gt 0 ]]; then
echo "⚠️ Found ${SETUID_BINARIES} setuid/setgid binaries"
echo " These should be reviewed for security implications"
else
echo "✅ No setuid/setgid binaries found"
fi
# Check for running services
echo "サービ Checking for running services..."
RUNNING_SERVICES=$(docker run --rm "${IMAGE_NAME}" ps aux 2>/dev/null | grep -v "PID" | wc -l)
if [[ "${RUNNING_SERVICES}" -gt 1 ]]; then
echo "⚠️ Found ${RUNNING_SERVICES} running processes"
echo " These should be reviewed for necessity"
else
echo "✅ No unnecessary running services found"
fi
# Check for listening ports
echo "📡 Checking for listening ports..."
LISTENING_PORTS=$(docker run --rm "${IMAGE_NAME}" netstat -tuln 2>/dev/null | grep LISTEN | wc -l)
if [[ "${LISTENING_PORTS}" -gt 0 ]]; then
echo "⚠️ Found ${LISTENING_PORTS} listening ports"
echo " These should be reviewed for security implications"
else
echo "✅ No unnecessary listening ports found"
fi
# Check for sudo availability
echo "🛑 Checking for sudo availability..."
if docker run --rm "${IMAGE_NAME}" which sudo >/dev/null 2>&1; then
echo "❌ Sudo is available in the image - this is a security risk"
echo " Sudo should be removed to prevent privilege escalation"
else
echo "✅ Sudo is not available in the image"
fi
# Check for root login capability
echo "🔐 Checking for root login capability..."
ROOT_LOGIN_ENABLED=$(docker run --rm "${IMAGE_NAME}" cat /etc/passwd | grep root | grep -v "nologin" | wc -l)
if [[ "${ROOT_LOGIN_ENABLED}" -gt 0 ]]; then
echo "⚠️ Root login might be enabled"
echo " Ensure root login is disabled for security"
else
echo "✅ Root login is properly disabled"
fi
# Check user configuration
echo "👤 Checking user configuration..."
USER_ID=$(docker run --rm "${IMAGE_NAME}" id -u toolbox 2>/dev/null || echo "not_found")
if [[ "${USER_ID}" == "1000" ]]; then
echo "✅ Non-root user 'toolbox' with UID 1000 is properly configured"
else
echo "⚠️ Non-root user configuration might be incorrect"
fi
# Check for hardcoded passwords
echo "🔑 Checking for hardcoded passwords..."
HARDCODED_PASSWORDS=$(docker run --rm "${IMAGE_NAME}" grep -r "password\|passwd" /etc/ 2>/dev/null | grep -v "shadow" | wc -l)
if [[ "${HARDCODED_PASSWORDS}" -gt 0 ]]; then
echo "⚠️ Found ${HARDCODED_PASSWORDS} potential hardcoded password references"
echo " These should be reviewed for security implications"
else
echo "✅ No hardcoded password references found"
fi
# Check for exposed secrets
echo " секр Checking for exposed secrets..."
EXPOSED_SECRETS=$(docker run --rm "${IMAGE_NAME}" find / -xdev -type f -name "*.key" -o -name "*.pem" -o -name "*.cert" 2>/dev/null | wc -l)
if [[ "${EXPOSED_SECRETS}" -gt 0 ]]; then
echo "⚠️ Found ${EXPOSED_SECRETS} potential secret files"
echo " These should be reviewed for security implications"
else
echo "✅ No exposed secret files found"
fi
# Check that this template properly extends from the base image
echo "🔗 Checking inheritance from base image..."
BASE_INHERITANCE=$(docker history "${IMAGE_NAME}" 2>/dev/null | grep "FROM tsysdevstack-toolboxstack-toolbox-base:release-current" | wc -l)
if [[ "${BASE_INHERITANCE}" -gt 0 ]]; then
echo "✅ Template properly extends from toolbox-base:release-current"
else
echo "⚠️ Template might not properly extend from toolbox-base:release-current"
fi
# Summary
echo ""
echo "🔒 Security Audit Summary:"
echo " - Image: ${IMAGE_NAME}"
echo " - Scan completed with recommendations above"
echo ""
echo "💡 Recommendations:"
echo " 1. Install Trivy for comprehensive security scanning"
echo " 2. Regularly update packages to address vulnerabilities"
echo " 3. Remove unnecessary packages to reduce attack surface"
echo " 4. Review world-writable files/directories"
echo " 5. Review setuid/setgid binaries"
echo " 6. Remove sudo to prevent privilege escalation"
echo " 7. Ensure root login is disabled"
echo " 8. Verify non-root user configuration"
echo " 9. Review hardcoded password references"
echo " 10. Check for exposed secrets"
echo " 11. Ensure proper inheritance from base image"

View File

@@ -0,0 +1,112 @@
#!/usr/bin/env bash
set -euo pipefail
# Test script to verify all tools are working properly in the toolbox-template
IMAGE_NAME="${IMAGE_NAME_OVERRIDE:-tsysdevstack-toolboxstack-toolbox-DocStack}"
echo "🧪 Testing all tools in ${IMAGE_NAME}"
# Function to test a command
test_cmd() {
local cmd="$1"
local description="$2"
echo -n "Testing ${cmd} (${description})... "
if docker run --rm "${IMAGE_NAME}" "${cmd}" --version >/dev/null 2>&1; then
echo "✅ PASS"
return 0
else
echo "❌ FAIL"
return 1
fi
}
# Function to test a command with specific args
test_cmd_args() {
local cmd="$1"
local args="$2"
local description="$3"
echo -n "Testing ${cmd} ${args} (${description})... "
if docker run --rm "${IMAGE_NAME}" "${cmd}" ${args} >/dev/null 2>&1; then
echo "✅ PASS"
return 0
else
echo "❌ FAIL"
return 1
fi
}
# Counter for tracking results
PASSED=0
FAILED=0
# Test core tools inherited from base
echo "🔍 Testing core tools inherited from base..."
test_cmd "zsh" "Z shell" && ((PASSED++)) || ((FAILED++))
test_cmd "git" "Git version control" && ((PASSED++)) || ((FAILED++))
test_cmd "curl" "cURL utility" && ((PASSED++)) || ((FAILED++))
test_cmd "jq" "JSON processor" && ((PASSED++)) || ((FAILED++))
test_cmd "fish" "Fish shell" && ((PASSED++)) || ((FAILED++))
test_cmd "fzf" "Fuzzy finder" && ((PASSED++)) || ((FAILED++))
test_cmd "bat" "Cat clone with wings" && ((PASSED++)) || ((FAILED++))
test_cmd "fd" "Simple, fast alternative to find" && ((PASSED++)) || ((FAILED++))
test_cmd "rg" "Ripgrep - line-oriented search tool" && ((PASSED++)) || ((FAILED++))
test_cmd "htop" "Interactive process viewer" && ((PASSED++)) || ((FAILED++))
test_cmd "btop" "Modern and colorful terminal monitor" && ((PASSED++)) || ((FAILED++))
# Test aqua installed tools inherited from base
echo "🔧 Testing aqua installed tools inherited from base..."
test_cmd "gh" "GitHub CLI" && ((PASSED++)) || ((FAILED++))
test_cmd "lazygit" "Simple terminal UI for git commands" && ((PASSED++)) || ((FAILED++))
test_cmd "direnv" "Unclutter your .profile" && ((PASSED++)) || ((FAILED++))
test_cmd "delta" "Syntax-highlighting pager for git, diff, and grep output" && ((PASSED++)) || ((FAILED++))
test_cmd "zoxide" "Smarter cd command" && ((PASSED++)) || ((FAILED++))
test_cmd "just" "Just a command runner" && ((PASSED++)) || ((FAILED++))
test_cmd "yq" "Portable command-line YAML processor" && ((PASSED++)) || ((FAILED++))
test_cmd "xh" "Friendly and fast tool for sending HTTP requests" && ((PASSED++)) || ((FAILED++))
test_cmd "curlie" "The power of curl, the ease of use of httpie" && ((PASSED++)) || ((FAILED++))
test_cmd "chezmoi" "Manage your dotfiles across multiple machines" && ((PASSED++)) || ((FAILED++))
test_cmd "shfmt" "Shell formatter" && ((PASSED++)) || ((FAILED++))
test_cmd "shellcheck" "Shell script analysis tool" && ((PASSED++)) || ((FAILED++))
test_cmd "hadolint" "Dockerfile linter" && ((PASSED++)) || ((FAILED++))
test_cmd "uv" "Python package installer and resolver" && ((PASSED++)) || ((FAILED++))
test_cmd "watchexec" "Execute commands in response to file modifications" && ((PASSED++)) || ((FAILED++))
test_cmd "tea" "Gitea CLI" && ((PASSED++)) || ((FAILED++))
# Test AI CLI tools inherited from base
echo "🤖 Testing AI CLI tools inherited from base..."
test_cmd_args "code" "--version" "just-every/code AI CLI" && ((PASSED++)) || ((FAILED++))
test_cmd_args "qwen" "--version" "QwenLM/qwen-code AI CLI" && ((PASSED++)) || ((FAILED++))
test_cmd_args "gemini" "--version" "google-gemini/gemini-cli AI CLI" && ((PASSED++)) || ((FAILED++))
test_cmd_args "codex" "--version" "openai/codex AI CLI" && ((PASSED++)) || ((FAILED++))
test_cmd_args "opencode" "--version" "sst/opencode AI CLI" && ((PASSED++)) || ((FAILED++))
# Test additional tools inherited from base
echo "🧰 Testing additional tools inherited from base..."
test_cmd "starship" "Cross-shell prompt" && ((PASSED++)) || ((FAILED++))
test_cmd "mise" "Polyglot runtime manager" && ((PASSED++)) || ((FAILED++))
test_cmd_args "aqua" "--version" "Declarative CLI Version Manager" && ((PASSED++)) || ((FAILED++))
# Summary
echo ""
echo "📊 Test Results:"
echo " Passed: ${PASSED}"
echo " Failed: ${FAILED}"
echo " Total: $((PASSED + FAILED))"
if [[ "${FAILED}" -eq 0 ]]; then
echo "🎉 All tests passed!"
exit 0
else
echo "💥 ${FAILED} tests failed!"
exit 1
fi