Hardening pass: CI publish gating, entrypoint injection fix, capability cleanup - #17
Merged
Conversation
- build-push no longer publishes on pull_request events (internal PRs previously pushed sha-* tags to GHCR and Docker Hub) - 'latest' tag now gated on actual main-branch push, not PR metadata - all six actions pinned to full commit SHAs (Dependabot still updates) - add concurrency group to cancel superseded runs
- websockets==17.0.1 (was floating; healthcheck + first-run setup depend on it) - remove sudo (unused at runtime); curl retained for binary downloads - use --no-cache-dir for pip
- build simplex-chat args as a bash array instead of an eval'd command string — env values (SIMPLEX_DISPLAY_NAME) are no longer re-parsed by a shell, closing a quoting/injection vector and fixing names with quotes - first-run setup: write .setup-complete ONLY when the bot address was actually captured; a failed boot now retries on next start instead of being skipped forever (previously the sed pipe masked python's exit code) - setup runs as the daemon user via gosu, so bot_address.txt gets correct ownership; setup.log kept under /data for debugging - validate SIMPLEX_SOCAT_PORT is numeric/1-65535 before socat launch - drop nc fallback (netcat not installed); quote daemon PID paths
grep -c prints 0 AND exits nonzero on no match, so '$(grep -c ... || echo 0)'
produced two lines ('0\n0') and '[ $FIXED -ge 2 ]' threw 'integer expression
expected'. Strip whitespace and drop the redundant fallback.
- NET_BIND_SERVICE and NET_RAW were unnecessary (daemon binds :5225, no raw sockets) — cap_drop ALL now stands alone - security_opt: no-new-privileges:true - pin example compose to immutable v0.16.0 per README guidance - tmpfs /tmp for future read-only hardening
… best practice Replaces the mutable v0.16.0 tag with an immutable digest pin, matching the digest-pinning guidance documented in the repo README.
Owner
Author
|
Amendment pushed: the docker-compose.yml example image pin is now an immutable digest ( |
This was referenced Aug 24, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Security & correctness hardening (cumulative)
Follow-up to the full-repo code/security review. One branch, five commits, grouped by area.
🔴 Critical
CI published images on pull_request events —
.github/workflows/docker-publish.ymlbuild-push-actionran withpush: trueon every PR, so any internal branch PR publishedsha-<pr-sha>images to GHCR (packages:write) and re-pushed them to Docker Hub via the stored secrets — without merging anything. Fork PRs were only saved by GitHub's default token restriction.github.event_name != 'pull_request'; PRs get build-only validation. Thelatesttag is additionally gated on an actual push to main.🟡 Warnings
simplex-chatargs were assembled into a string with embedded quotes and run throughsh -c, re-parsing env values (SIMPLEX_DISPLAY_NAME). Replaced with a bash array; values are passed verbatim now.NET_BIND_SERVICE+NET_RAWon top ofcap_drop: ALL; neither is needed (binds :5225, no raw sockets). Dropped; addedno-new-privileges:true..setup-completewas written even when first-run setup failed, so one flaky first boot meantbot_address.txtwas never created. Marker is now written only when the address was actually captured. This also fixed a latent bug in the replacement logic: the old… | sedpipe masked python's exit status (sed always exits 0), so the exit code is now captured directly and output echoed fromsetup.log.$(grep -c … || echo 0)yields two lines ("0" twice) because grep prints 0 and exits nonzero;[ "$FIXED" -ge 2 ]threw "integer expression expected". Whitespace-stripped and the redundant fallback removed.websocketswas unpinned at image build despite a digest-pinned base image and SHA256-verified binaries. Pinned to17.0.1.💡 Suggestions also included
SIMPLEX_SOCAT_PORTvalidated as numeric/1–65535 before socat launchbot_address.txtgets correct ownershipncwait-fallback and unusedsudopackage (curlkept — used by build)v0.16.0per README guidanceconcurrencygroup to cancel superseded runsVerification
bash -n+ shellcheck clean on both scripts (matches CI lint job)Not addressed (deliberate)