Skip to content

General Fixes#56

Open
SimplicityGuy wants to merge 100 commits intowillfarrell:mainfrom
SimplicityGuy:main
Open

General Fixes#56
SimplicityGuy wants to merge 100 commits intowillfarrell:mainfrom
SimplicityGuy:main

Conversation

@SimplicityGuy
Copy link
Copy Markdown
Collaborator

@SimplicityGuy SimplicityGuy commented Jul 16, 2022

  • cleanup of script based on shellcheck.net
  • general reformatting
  • updated alpine version
  • addressed issues:
    • top-level script name is not picked up
    • jq parsing errors if some properties are not set

SimplicityGuy and others added 30 commits June 30, 2025 13:55
Replace -S flag with -s flag to run crond in single-user mode.
This prevents "can't set groups: Operation not permitted" errors
since su-exec already handles the user switching to docker user.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Fix shellcheck warning in entrypoint.sh (add -r flag to read command)
- Fix incorrect source URL in Dockerfile (was pointing to alertmanager-discord)
- Update docker-compose.yml to version 3.8 and change config volume to read-only
- Update GitHub Actions to use latest action versions for better security and features
- Remove invalid -s flag from crond CMD (already fixed in previous commit)

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
BusyBox v1.37.0 crond doesn't support the -s flag that was attempted
in previous versions. This fix adds argument filtering in entrypoint.sh
to gracefully handle and remove any -s flags passed to crond, preventing
the "unrecognized option: s" error.

The solution maintains all previous fixes including proper user switching
via su-exec and running crond as root for cron job execution.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
… the CMD instruction. Docker doesn't perform shell variable expansion in the exec form of CMD.
The issue was that BusyBox crond was trying to interpret subdirectories
in /opt/crontab as usernames. This fix:

- Installs the generated crontab to /etc/crontabs/docker where BusyBox
  expects user crontab files
- Updates the crond command to use /etc/crontabs instead of /opt/crontab
- Ensures proper permissions (600) on the crontab file

This resolves the "no such user" errors for 'crontab' and 'jobs' directories.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Resolves permission error "cannot create regular file '/etc/crontabs/docker'"
by moving crontab files to /opt/crontab/crontabs/ owned by docker user.

Changes:
- Modified entrypoint.sh to write crontab to /opt/crontab/crontabs/docker
- Updated Dockerfile to create crontabs directory with docker:docker ownership
- Added SUID bit to /usr/bin/crontab for proper crontab management
- Changed CMD to use custom crontabs directory (-c /opt/crontab/crontabs)
- Removed root requirement for crond execution (now runs as docker user)
- Enhanced documentation with security model and troubleshooting sections
- Updated all file path references in CLAUDE.md and README.md

Security improvements:
- Container now runs crond as non-root docker user
- Privilege separation via su-exec (starts as root, drops to docker user)
- Better handling of read-only volume mounts

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Enhances CI/CD workflows with performance optimizations and security
improvements.

Changes:
- Add Docker build caching for faster builds (cache-from/cache-to with GitHub Actions cache)
- Update Discord notification action from v1.12.0 to v1.15.5
- Pin Discord action to commit SHA (b8381b25576cb341b2af39926ab42c5056cc44ed) for security
- Applied Discord action update to both build.yml and cleanup.yml workflows

Performance Impact:
- Build caching reduces rebuild time by reusing layers across workflow runs
- Cache stored in GitHub Actions cache with mode=max for optimal storage

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Configures Dependabot to automatically monitor and update dependencies
for the docker-crontab project.

Configuration:
- GitHub Actions: Weekly updates on Mondays at 9am PT
- Docker base images: Weekly updates for alpine and docker:dind-alpine
- Auto-assign to SimplicityGuy with appropriate labels
- Group updates by ecosystem for cleaner PRs

Monitoring:
- GitHub Actions in workflows directory
- Dockerfile base images (docker:dind-alpine, alpine:latest)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Implements automated Docker base image update workflow that checks for
and creates PRs when base images are updated.

Features:
- Runs weekly on Mondays at 9am UTC
- Manual trigger via workflow_dispatch
- Checks alpine:latest and docker:dind-alpine for updates
- Builds test image to verify compatibility
- Creates PR with update details and digests
- Auto-assigns to SimplicityGuy with appropriate labels
- Discord notifications for workflow status

Workflow:
1. Check for base image updates by pulling latest versions
2. Compare digests to detect changes
3. Build test image with new base images
4. Create PR with automated documentation
5. Send Discord notification

Security:
- Uses commit SHA pinning for create-pull-request action
- Test build ensures compatibility before PR creation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Rename "crontab" workflow to "Build" for clarity
- Rename "update-dependencies" to "Update Dependencies" for consistency
- Use Title Case for all workflow names to match GitHub Actions conventions
- Automatically clean up GitHub Actions caches when PRs are closed
- Prevents cache accumulation and keeps repository tidy
- Uses concurrency control to prevent duplicate cleanup runs
- Continues on deletion errors to ensure workflow completes
- Includes 10-minute timeout for safety
Replace old cleanup workflow with improved implementation:
- Migrate from snok/container-retention-policy to dataaxiom/ghcr-cleanup-action
- Automatic package discovery (no hardcoded package names needed)
- More flexible retention policies (keep 2 most recent tagged images)
- Better handling of partial and untagged images
- Remove Discord notifications to reduce dependencies
- Maintain monthly cleanup schedule (15th at midnight UTC)
- Add manual workflow_dispatch trigger for on-demand cleanup
- Add support for linux/arm64, linux/arm/v7, and linux/arm/v6 platforms
- Increase job timeout from default to 90 minutes to accommodate
  multi-platform builds with QEMU emulation
- Update both Docker Buildx setup and build steps with new platforms

This enables the crontab image to run on:
- linux/amd64: 64-bit x86 (Intel/AMD)
- linux/arm64: 64-bit ARM (Raspberry Pi 4+, AWS Graviton)
- linux/arm/v7: 32-bit ARM v7 (Raspberry Pi 2/3)
- linux/arm/v6: 32-bit ARM v6 (Raspberry Pi Zero/1)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
The cleanup workflow was failing with a 404 error because it was
looking for package "docker-crontab" (derived from repository name)
instead of the actual package name "crontab" (defined in build.yml).

Add explicit package parameter to match IMAGE_NAME from build workflow:
- Build workflow: IMAGE_NAME: ${{ github.actor }}/crontab
- Cleanup workflow: package: crontab

Fixes error:
  GET /users/SimplicityGuy/packages/container/docker-crontab/versions
  - 404 not found

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add automatic platform detection to download the correct rq binary for
each target architecture during Docker builds. This fixes builds for
ARM platforms (arm64, armv7, armv6) which were previously failing due
to hardcoded x86_64 binary.

Changes:
- Add TARGETPLATFORM, TARGETOS, TARGETARCH, TARGETVARIANT build args
- Implement platform mapping case statement:
  - linux/amd64 → x86_64-unknown-linux-musl
  - linux/arm64 → aarch64-unknown-linux-gnu
  - linux/arm/v7 → armv7-unknown-linux-gnueabihf
  - linux/arm/v6 → arm-unknown-linux-gnueabi
- Add graceful fallback to x86_64 for unknown platforms
- Update hadolint ignore to include SC2086 for shell expansion

This aligns the Dockerfile with the CI/CD workflow which builds for
linux/amd64, linux/arm64, linux/arm/v7, and linux/arm/v6 platforms.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
BusyBox crond does not automatically forward job output to the container's
main process. This change redirects all cron job and onstart command output
to /proc/1/fd/1 (stdout) and /proc/1/fd/2 (stderr) so that Docker can
capture and display job execution logs.

Users will now see:
- Job start/end messages in docker logs
- Command output from executed containers
- Real-time job execution feedback

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add update-dependencies.sh script for automated dependency management
  - Supports Docker base images, rq binary, and GitHub Actions
  - Includes dry-run mode and automatic backups
  - Provides colored output and update summaries

- Update Dockerfile base images:
  - Alpine: latest → 3.23 (pinned for stability)
  - Docker dind: 28.2.2-dind-alpine3.21 → 29.1.3-dind-alpine3.23

- Update GitHub Actions:
  - actions/checkout: v4 → v6

- Update .gitignore to exclude backup files created by update script

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Previous implementation using /proc/1/fd/1 and /proc/1/fd/2 failed because
cron jobs run as child processes of crond (not PID 1/tini) and cannot
access PID 1's file descriptors. Changed to use standard Unix piping
(2>&1 | cat) which properly routes output to Docker's logging system.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
The update script was using hardcoded version numbers which caused
"Pattern not found" warnings when workflow versions didn't match.
Now extracts current versions directly from the workflow file using
grep/sed, making the script maintainable and eliminating version
sync issues.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Quote IMAGE and CONTAINER variables in generated docker run/exec
  commands to prevent shell metacharacter injection (entrypoint.sh:77, 90)
- Quote ONSTART_COMMAND in onstart execution loop to prevent
  word-splitting on paths with spaces or metacharacters (entrypoint.sh:242)
- Add chmod 700 on crontabs directory so only the docker user can
  read or modify crontab files (entrypoint.sh:232)
- Remove unnecessary #hadolint ignore=DL3007 directives from both
  FROM lines since pinned version tags are already used (Dockerfile:1, 49)
- Remove SC2086 suppression and quote variables in wget/tar commands
  to address the underlying shell warning (Dockerfile:20, 44-45)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Rename update-dependencies.sh to update-project.sh with expanded scope:
- Add pre-commit autoupdate --freeze support
- Scan all workflow files for GitHub Actions updates (not just build.yml)
- Add docker build verification step after updates
- Add --skip-tests flag and git dirty-tree warning
- Use portable sed for macOS/Linux compatibility
- Adopt emoji-based section logging style

Also rename workflow, update dependabot with security update groups,
and fix stale GitHub Action versions in build.yml.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
entrypoint.sh:
- Fix CRONTAB_FILE evaluated before HOME_DIR is resolved
- Fix jq pipeline crash on array-format configs (JSON/YAML)
- Reject unsupported @every schedule with clear error
- Remove fragile \* escape/unescape round-trip in schedule parsing
- Fix [ -a ] test operator to [ -n ] for DOCKER_PORT_2375_TCP check
- Add --rm to docker run to prevent container leak on every cron job
- Sanitize COMMENT field to strip newlines (injection prevention)
- Detect slug collisions and append counter suffix
- Write scripts atomically via temp file then mv
- Track onstart job PIDs and warn on non-zero exit
- Warn when no config file is found
- Scope IFS to read command instead of setting globally

Dockerfile:
- Fix LABEL created using BUILD_DATE build-arg instead of literal $(date)
- Fix crond -d 7 (nearly silent) to -d 0 (most verbose)
- Add gcompat for ARM glibc-linked rq binary compatibility
- Validate DOCKER_GID is numeric before use

CI/CD & config:
- Fix update-project.yml grep pattern to match actual Dockerfile FROM lines
- Fix update-project.yml update detection logic (was inverted)
- Pass BUILD_DATE build-arg in build.yml
- Remove deprecated docker-compose version key
- Update EOL alpine:3.5 to alpine:3.21 in docker-compose and samples
- Replace unsupported @every 2m with */2 * * * * in all sample configs
- Fix corrupted TOML table key for logrotate entry
- Fix TOML sample using ${PWD} instead of named volume
- Add backups/ to .gitignore

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
fix: resolve 17 bugs found during comprehensive code review
* fix: resolve multiple bugs found during comprehensive code review

- Fix shared-settings merge order so per-job values override shared defaults
- Fix parse_schedule failure silently producing broken crontab entries
- Fix broken shebang (#\!) in generated job scripts
- Add null command guard in make_image_cmd (parity with make_container_cmd)
- Add temp file cleanup trap on error during script generation
- Clean up intermediate crontab file after copying to crontabs directory
- Downgrade actions/checkout@v6 to @v4 (v6 does not exist)
- Downgrade docker/metadata-action@v6 to @v5 (v6 does not exist)
- Remove -d flag from sample dockerargs (defeats error propagation)
- Rename "null" key to "logrotate" in mapping config samples
- Replace @every examples with valid cron syntax in README
- Fix stale GitLab registry path in README Dockerfile example
- Remove invalid --it flag from README dockerargs example
- Add depends_on to docker-compose.yml to prevent race condition

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* revert: restore correct GitHub Actions versions (v6 is valid)

The previous commit incorrectly downgraded actions/checkout@v6 and
docker/metadata-action@v6 — these versions exist and were correct.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* revert: restore -d and --it Docker flags in samples and README

These are valid Docker flags (-d for detached, --it for interactive
terminal) that were incorrectly removed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: change --it to -it in README dockerargs examples

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: update docs, add badges, fix grammar, document missing config fields

- Update README badges to centered div style with Build, License,
  pre-commit, Docker, Shell, Alpine, and Claude Code badges
- Fix grammar: "to all" → "to allow", "probably has" → "probably have",
  "run on in" → "run in", "images name" → "image name"
- Document undocumented config fields: environment, expose, networks,
  ports, volumes
- Document all supported schedule shortcuts: @yearly/@annually,
  @monthly, @Weekly, @daily/@midnight, @hourly, @random
- Remove stale @every reference from CLAUDE.md
- Add owner field to cleanup-images workflow (matches discogsography)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: handle empty crontab and fix missing closing quote

- Add touch before cat to prevent crash when no valid jobs exist
  (all jobs skipped due to missing schedule/command/unsupported syntax)
- Fix missing closing quote in 'schedule missing' error message

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: quote container name in docker args to handle spaces

Mapping config keys like 'map a volume' are injected as the job name
by normalize_config. Without quoting, --name map a volume produces a
broken docker command. Now generates --name "map a volume".

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: Docker Hub API query missing dind-alpine tags, remove dead code

- Add name=dind-alpine filter to Docker Hub API query in
  update-project.sh so dind-alpine tags appear in results
  (previously, page_size=100 without filtering missed them)
- Remove unused skip_next variable and associated dead code
  from start_app in entrypoint.sh

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: update alpine references from 3.21 to 3.23

Update all sample configs, docker-compose.yml, and README to reference
alpine:3.23 which matches the Dockerfile base image.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* docs: sort schedule shortcuts from most to least frequent

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* security: add SHA256 checksum verification for rq binary download

Add per-platform SHA256 checksums for rq v1.0.2 binaries and verify
the download integrity with sha256sum before extraction. This prevents
supply chain attacks via compromised releases or MITM.

Also add SHELL pipefail directive to builder stage to satisfy hadolint.

Closes #17

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* docs: add comment noting rq checksums were computed offline

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor: replace abandoned rq with yq for config parsing

rq (last release: 2019) has been replaced with yq (mikefarah/yq),
an actively maintained tool available from Alpine repos.

Changes:
- Remove entire Dockerfile builder stage (rq download, upx, checksums)
- Remove gcompat from release stage (only needed for rq glibc binaries)
- Add yq-go to Alpine packages
- Update entrypoint.sh to use yq for YAML and TOML conversion
- Remove rq version update logic from update-project.sh
- Update CLAUDE.md references

This also fixes the arm64/arm glibc-on-musl issue since yq is a
native Alpine package built for all supported architectures.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: route cron job output to docker logs via /proc/1/fd/1

BusyBox crond swallows pipe output (tries to mail it), so the
previous 2>&1 | cat approach silently lost all job output.

Now redirects to /proc/1/fd/1 and /proc/1/fd/2 (PID 1's stdout/stderr)
which is what docker logs reads. Also adds timestamps to job start/end
log messages for observability.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: formatted startup table showing scheduled jobs

Replace raw crontab dump with a clean table showing schedule, job name,
and onstart flag. Also route onstart job output to /proc/1/fd/1 for
docker logs visibility, and clean up status messages.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: update-project workflow and script for single-stage Dockerfile

- Fix update-project.yml: remove builder image grep (builder stage no
  longer exists), only check docker dind base image
- Fix update-project.sh: remove Alpine FROM grep and stale Alpine
  tag lookup (no standalone Alpine stage anymore)
- Fix CLAUDE.md: "multi-stage" → "single-stage", add all platforms

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor: update-project workflow now uses update-project.sh script

Eliminates duplicate logic between the CI workflow and local script.
The workflow now runs the script with --no-backup --skip-tests, checks
for git changes, then handles PR creation and Discord notification.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants