Skip to content

Add rootless steamcmd base image under apps/steamcmd with apt-based install, renovate-compatible version pinning, /config runtime seeding, hardened runtime init flow, and readonly-rootfs compatibility#1415

Merged
Crow-Control merged 29 commits intomainfrom
copilot/build-rootless-steamcmd-container
Feb 20, 2026
Merged

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Feb 19, 2026

This PR adds a new rootless SteamCMD base image at apps/steamcmd for downstream game-specific containers, and incorporates follow-up fixes from review feedback to stabilize runtime behavior, security posture, and CI tests.

Changes Made

  • Added app-scoped SteamCMD image files:
    • apps/steamcmd/Dockerfile
    • apps/steamcmd/docker-bake.hcl
    • apps/steamcmd/container-test.yaml
    • apps/steamcmd/start.sh
  • Built on ghcr.io/trueforge-org/ubuntu:24.4.0@sha256:..., final runtime user remains apps.
  • Installed SteamCMD from apt/multiverse with noninteractive license preseeding:
    • steamcmd:i386=0~${VERSION}
  • Kept renovate-compatible apt pin metadata in bake config and Docker-tag-safe image versioning.
  • Runtime seeding happens in start.sh (not build-time write to /config):
    • seeds SteamCMD runtime into /config/Steam/steamcmd when missing.
  • Added runtime env-driven app initialization:
    • STEAM_APP_IDS (comma-separated)
    • STEAM_INSTALL_DIR (default /config/steamapps)
    • STEAM_APP_VALIDATE=true
    • STEAMCMD_SKIP_APP_UPDATE=true
  • Added credential + pre-update controls:
    • STEAM_USERNAME/STEAM_PASSWORD (with STEAM_USER fallback)
    • STEAMCMD_PRE_UPDATE=true by default
  • Applied review-thread hardening/fixes:
    • non-SteamCMD command passthrough (exec "$@" for non-+... argv)
    • fail-fast when authenticated login is requested without STEAM_PASSWORD
    • avoid password exposure in process argv by using temporary SteamCMD +runscript files
    • cleanup traps for temporary runscript files
    • input validation for app IDs and install-dir whitespace
  • Added readonly-rootfs compatibility updates:
    • ensures /config exists and is owned by apps in the image
    • moves temporary runtime script files to /config/steamcmd/tmp (no required writes to rootfs paths)
  • image-all remains linux/amd64 only (arm disabled).

Test Coverage

  • Container test validates:
    • SteamCMD execution (steamcmd +quit) with deterministic output check (Steam Console Client)
    • pinned installed package version matches .package-version
    • required runtime files:
      • /start.sh
      • /usr/local/bin/steamcmd
      • /usr/local/share/steamcmd/steamcmd.sh
  • CI test-failure fix applied by removing a brittle /config file-existence command check that was invalid in isolated command-check containers.

Validation

  • Targeted CI-failure investigation was performed via workflow runs + failed job logs.
  • Targeted build/runtime validation was run without manually invoking healthcheck.sh.
  • Runtime checks include passthrough behavior, authenticated-login fail-fast, env-driven update flow behavior, and readonly-rootfs execution with only /config writable.

✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI changed the title [WIP] Build rootless steamcmd container for game-specific use Add rootless steamcmd base image under apps/steamcmd for downstream game containers Feb 19, 2026
Copilot AI requested a review from Crow-Control February 19, 2026 12:53
@Crow-Control
Copy link
Copy Markdown
Member

@copilot ensure tests also actually run steamcmd

@Crow-Control
Copy link
Copy Markdown
Member

@copilot ensure its version pinned to actual steamcmd version

And I'm not sure if apt-get is the most up-to-date source for steamcmd either

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Feb 19, 2026

@copilot ensure tests also actually run steamcmd

Updated the steamcmd container test to actually execute SteamCMD via a command check (steamcmd +quit) while remaining robust in offline CI by accepting the known offline update error string. Included in commit 78e6a6d.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • client-download.steampowered.com
    • Triggering command: /config/.local/share/Steam/steamcmd/linux32/steamcmd /config/.local/share/Steam/steamcmd/linux32/steamcmd +quit (dns block)
  • media.steampowered.com
    • Triggering command: /config/.local/share/Steam/steamcmd/linux32/steamcmd /config/.local/share/Steam/steamcmd/linux32/steamcmd +quit (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Feb 19, 2026

@copilot ensure its version pinned to actual steamcmd version

And I'm not sure if apt-get is the most up-to-date source for steamcmd either

Done in 20b145c: SteamCMD is now explicitly version-pinned via STEAMCMD_VERSION=0~20180105-5 in bake args and apt-get install steamcmd:i386=${STEAMCMD_VERSION}. I also added a container test assertion using dpkg-query to verify the installed version. This apt package is the bootstrap launcher; running steamcmd still pulls current upstream content from Valve at runtime.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • client-download.steampowered.com
    • Triggering command: /config/.local/share/Steam/steamcmd/linux32/steamcmd /config/.local/share/Steam/steamcmd/linux32/steamcmd +quit plit test la/G�� t(sys.implementation.cache_tag) dpkg-deb temd-helper assemble.deb python3-blinker_--print-foreign-architectures .crt er la/O�� /etc/ssl/certs/Amazon_Root_CA_4.pem r.socket /var/lib/dpkg/info/python3.postinst 9.crt p.ci eb /var/lib/dpkg/info/python3.posti--no-legend (dns block)
  • media.steampowered.com
    • Triggering command: /config/.local/share/Steam/steamcmd/linux32/steamcmd /config/.local/share/Steam/steamcmd/linux32/steamcmd +quit plit test la/G�� t(sys.implementation.cache_tag) dpkg-deb temd-helper assemble.deb python3-blinker_--print-foreign-architectures .crt er la/O�� /etc/ssl/certs/Amazon_Root_CA_4.pem r.socket /var/lib/dpkg/info/python3.postinst 9.crt p.ci eb /var/lib/dpkg/info/python3.posti--no-legend (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot AI changed the title Add rootless steamcmd base image under apps/steamcmd for downstream game containers Add rootless steamcmd base image under apps/steamcmd with pinned package version Feb 19, 2026
@Crow-Control
Copy link
Copy Markdown
Member

Crow-Control commented Feb 19, 2026

@copilot I think we can better download steam directly from... steam... instead of this outdated crap

Also we should actually test it

@Crow-Control
Copy link
Copy Markdown
Member

@copilot I think we can better download steam directly from... steam... instead of this outdated crap

Also we should actually test it

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Feb 19, 2026

@copilot I think we can better download steam directly from... steam... instead of this outdated crap

Also we should actually test it

Done in 938a039: switched to downloading SteamCMD directly from Steam (https://media.steampowered.com/client/steamcmd_linux.tar.gz) and pinned integrity with SHA256 in bake args. Test coverage now executes steamcmd +quit and also verifies /config/steamcmd/steamcmd.sh is created at runtime.

@copilot I think we can better download steam directly from... steam... instead of this outdated crap

Also we should actually test it

Implemented in 938a039: SteamCMD now comes directly from Steam CDN with SHA256 pinning instead of apt packaging. Tests actively run steamcmd +quit and assert the runtime-seeded /config/steamcmd/steamcmd.sh exists.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • client-update.steamstatic.com
    • Triggering command: /config/steamcmd/linux32/steamcmd /config/steamcmd/linux32/steamcmd +quit a0d3a2dd305ffea7log.showSignature=false 4835db337bdb543dshow ./sc�� (dns block)
    • Triggering command: /config/steamcmd/linux32/steamcmd /config/steamcmd/linux32/steamcmd +quit a0d3a2dd305ffea747b2e51b87864138--root grep 6390�� -- runtime-runc/moby /usr/bin/cat 4a02d472b26abf8cd09bae8456219cef248/log.json by/4465f8878f2db-r 3f2099ad16c612cb/ (dns block)
  • steamcdn-a.akamaihd.net
    • Triggering command: /usr/bin/curl curl -fsSL REDACTED -o /tmp/tmp.8mJVYBO2rf/steamcmd_linux.tar.gz 221d by/4465f8878f2db--directory 18f20691a7653e6a/www 5e1266fa06f22a521614bd7d285c0ae2e20/log.json 3f2099ad16c612cb/usr/bin/runc (dns block)
    • Triggering command: /usr/bin/curl curl -fL REDACTED -o /tmp/tmp.OJ7XoYuIhp/steamcmd_linux.tar.gz otless-steamcmd-container^{commit} --global by/92825f87742b881031876fdfae8c55e1266fa06f22a521614bd7d285c0ae2e20/log.json credential.usernbash (dns block)
    • Triggering command: /usr/bin/curl curl -I REDACTED 2fc48f27144c5402/var/run/docker/runtime-runc/moby conf�� rd --global /snap/bin/git by/92825f87742b8bash 81031876fdfae8c5/usr/bin/runc (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot AI changed the title Add rootless steamcmd base image under apps/steamcmd with pinned package version Add rootless steamcmd base image under apps/steamcmd with direct Steam CDN download and pinned checksum Feb 19, 2026
@Crow-Control
Copy link
Copy Markdown
Member

@copilot steamcmd will be online available during testing
Why are you writhing to /config, that is a folder that is going to be wiped.

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Feb 19, 2026

@copilot steamcmd will be online available during testing
Why are you writhing to /config, that is a folder that is going to be wiped.

Addressed in 56d81db: removed runtime writes to /config entirely. steamcmd now runs directly from /usr/local/share/steamcmd with HOME=/tmp/steamcmd. I also tightened the test to run steamcmd +quit and assert online update progress by checking for Update complete, launching in the output.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • client-update.steamstatic.com
    • Triggering command: /usr/local/share/steamcmd/linux32/steamcmd /usr/local/share/steamcmd/linux32/steamcmd +quit (dns block)
    • Triggering command: /usr/local/share/steamcmd/linux32/steamcmd /usr/local/share/steamcmd/linux32/steamcmd +quit 3440b007845d9c24libstdc++6:amd64 iginal f012�� y (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

@Crow-Control
Copy link
Copy Markdown
Member

@copilot ensure version pinning that is renovate compatible (with renovate comment) actual versions from steam.

Also make sure the directory where games are downloaded to is in /config

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Feb 19, 2026

@copilot ensure version pinning that is renovate compatible (with renovate comment) actual versions from steam.

Also make sure the directory where games are downloaded to is in /config

Implemented in 64b9abf: added a Renovate-compatible pin comment on STEAMCMD_SHA256 in apps/steamcmd/docker-bake.hcl (// renovate: datasource=custom.steamcmd ...) and updated runtime so SteamCMD runs from /config/steamcmd (wrapper now creates and cds there before execution). Tests were updated to still run steamcmd +quit, assert online update progress (Update complete, launching), and verify /config/steamcmd exists.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • client-update.steamstatic.com
    • Triggering command: /usr/local/share/steamcmd/linux32/steamcmd /usr/local/share/steamcmd/linux32/steamcmd +quit (dns block)
    • Triggering command: /usr/local/share/steamcmd/linux32/steamcmd /usr/local/share/steamcmd/linux32/steamcmd --version f22709dcb21e1b4723bdce967d0121bff657623e60e96f03b76d2b07394d6920 mktemp -d .deb 1bff657623e60e96f03b76d2b07394d6920 (dns block)
    • Triggering command: /usr/local/share/steamcmd/linux32/steamcmd /usr/local/share/steamcmd/linux32/steamcmd +quit 756139f9447c0f21--version (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot AI changed the title Add rootless steamcmd base image under apps/steamcmd with direct Steam CDN download and pinned checksum Add rootless steamcmd base image under apps/steamcmd with direct Steam CDN download, renovate-compatible pinning, and /config download path Feb 19, 2026
Signed-off-by: Kjeld Schouten <info@kjeldschouten.nl>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 5 comments.

Crow-Control and others added 3 commits February 20, 2026 13:57
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Kjeld Schouten <info@kjeldschouten.nl>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Kjeld Schouten <info@kjeldschouten.nl>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Kjeld Schouten <info@kjeldschouten.nl>
@Crow-Control
Copy link
Copy Markdown
Member

@copilot apply changes based on the comments in this thread

Co-authored-by: Crow-Control <7613738+Crow-Control@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Feb 20, 2026

@copilot apply changes based on the comments in this thread

Done in 65bdcac — I applied the requested thread changes in apps/steamcmd/start.sh: added non-SteamCMD command passthrough, added fail-fast validation for missing STEAM_PASSWORD when using authenticated login, and moved Steam credential usage off argv by switching pre-update/app-update flows to temporary +runscript files at runtime.

@Crow-Control
Copy link
Copy Markdown
Member

@copilot ensure this works using readonlyrootfs (so where only /config is mounted and hence writeable)

Copilot AI changed the title Add rootless steamcmd base image under apps/steamcmd with apt-based install, renovate-compatible VERSION pinning, /config runtime seeding, and runtime app-id/login env initialization Add rootless steamcmd base image under apps/steamcmd with apt-based install, renovate-compatible version pinning, /config runtime seeding, and hardened runtime init flow Feb 20, 2026
Copilot AI requested a review from Crow-Control February 20, 2026 13:25
Co-authored-by: Crow-Control <7613738+Crow-Control@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Feb 20, 2026

@copilot ensure this works using readonlyrootfs (so where only /config is mounted and hence writeable)

Implemented in fe4bdd4: adjusted runtime to support readonly-rootfs with only /config writable by moving SteamCMD temp runscript files to /config/steamcmd/tmp and ensuring /config is created/owned by apps in the image. I also validated with --read-only + writable /config volume that startup/seeding works.

Copilot AI changed the title Add rootless steamcmd base image under apps/steamcmd with apt-based install, renovate-compatible version pinning, /config runtime seeding, and hardened runtime init flow Add rootless steamcmd base image under apps/steamcmd with apt-based install, renovate-compatible version pinning, /config runtime seeding, hardened runtime init flow, and readonly-rootfs compatibility Feb 20, 2026
Signed-off-by: Kjeld Schouten <info@kjeldschouten.nl>
Signed-off-by: Kjeld Schouten <info@kjeldschouten.nl>
Signed-off-by: Kjeld Schouten <info@kjeldschouten.nl>
Removed the commands section from the container test configuration.

Signed-off-by: Kjeld Schouten <info@kjeldschouten.nl>
@trueforge-bot
Copy link
Copy Markdown

trueforge-bot bot commented Feb 20, 2026

📦 App Size Analysis

Note

Comparing ghcr.io/trueforge-org/steamcmd:rollingghcr.io/trueforge-org/steamcmd:sandbox

📈 Size Comparison Table

OS/Platform Previous Current Change Trend
linux/amd64 0 B 140.49 MB +140.49 MB (+∞) 🔼

@Crow-Control Crow-Control merged commit 474b04b into main Feb 20, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants