@@ -452,61 +452,12 @@ RUN git config --global init.defaultBranch main \
452452 && git config --global diff.colorMoved default
453453
454454# Starship configuration (minimal, fast prompt)
455- RUN mkdir -p /home/opencode/.config \
456- && printf '%s\n ' \
457- '# Minimal starship config for fast prompt' \
458- 'format = """' \
459- '$directory\' \
460- ' $git_branch\' \
461- '$git_status\' \
462- ' $character"""' \
463- '' \
464- '[directory]' \
465- 'truncation_length = 3' \
466- 'truncate_to_repo = true' \
467- '' \
468- '[git_branch]' \
469- 'format = " [$branch]($style) "' \
470- 'style = " bold purple"' \
471- '' \
472- '[git_status]' \
473- 'format = '" '"' ([$all_status$ahead_behind]($style) )'"' "'' \
474- '' \
475- '[character]' \
476- 'success_symbol = " [>](bold green)"' \
477- 'error_symbol = " [>](bold red)"' \
478- > /home/opencode/.config/starship.toml
455+ COPY --chown=opencode:opencode packages/core/src/docker/files/starship.toml /home/opencode/.config/starship.toml
479456
480457# Shell aliases
481- RUN printf '%s\n ' \
482- '' \
483- '# Modern CLI aliases' \
484- 'alias ls=" eza --icons"' \
485- 'alias ll=" eza -l --icons"' \
486- 'alias la=" eza -la --icons"' \
487- 'alias lt=" eza --tree --icons"' \
488- 'alias grep=" rg"' \
489- 'alias top=" btop"' \
490- '' \
491- '# Git aliases' \
492- 'alias g=" git"' \
493- 'alias gs=" git status"' \
494- 'alias gd=" git diff"' \
495- 'alias gc=" git commit"' \
496- 'alias gp=" git push"' \
497- 'alias gl=" git pull"' \
498- 'alias gco=" git checkout"' \
499- 'alias gb=" git branch"' \
500- 'alias lg=" lazygit"' \
501- '' \
502- '# Docker aliases (for Docker-in-Docker)' \
503- 'alias d=" docker"' \
504- 'alias dc=" docker compose"' \
505- '' \
506- >> /home/opencode/.bashrc
507-
508- # Set up pipx path
509- RUN echo 'export PATH=" /home/opencode/.local/bin:$PATH"' >> /home/opencode/.bashrc
458+ COPY --chown=opencode:opencode packages/core/src/docker/files/bashrc.extra /home/opencode/.bashrc.extra
459+ RUN cat /home/opencode/.bashrc.extra >> /home/opencode/.bashrc \
460+ && rm /home/opencode/.bashrc.extra
510461
511462# -----------------------------------------------------------------------------
512463# Stage 2: opencode build
@@ -575,18 +526,8 @@ ENV PATH="/opt/opencode/bin:${PATH}"
575526# This allows opencode to authenticate users via PAM (same users as Cockpit)
576527# NOTE: Requires root privileges to write to /etc/pam.d/
577528USER root
578- RUN printf '%s\n ' \
579- '# PAM configuration for OpenCode authentication' \
580- '# Install to /etc/pam.d/opencode' \
581- '' \
582- '# Standard UNIX authentication' \
583- 'auth required pam_unix.so' \
584- 'account required pam_unix.so' \
585- '' \
586- '# Optional: Enable TOTP 2FA (uncomment when pam_google_authenticator is installed)' \
587- '# auth required pam_google_authenticator.so' \
588- > /etc/pam.d/opencode \
589- && chmod 644 /etc/pam.d/opencode
529+ COPY packages/core/src/docker/files/pam/opencode /etc/pam.d/opencode
530+ RUN chmod 644 /etc/pam.d/opencode
590531
591532# Verify PAM config file exists
592533RUN ls -la /etc/pam.d/opencode && cat /etc/pam.d/opencode
@@ -596,38 +537,7 @@ RUN ls -la /etc/pam.d/opencode && cat /etc/pam.d/opencode
596537# -----------------------------------------------------------------------------
597538# Create opencode-broker service for PAM authentication
598539# NOTE: Requires root privileges to write to /etc/systemd/system/
599- RUN printf '%s\n ' \
600- '[Unit]' \
601- 'Description=OpenCode Authentication Broker' \
602- 'Documentation=https://github.com/pRizz/opencode' \
603- 'After=network.target' \
604- '' \
605- '[Service]' \
606- 'Type=notify' \
607- 'ExecStart=/usr/local/bin/opencode-broker' \
608- 'ExecReload=/bin/kill -HUP $MAINPID' \
609- 'Restart=always' \
610- 'RestartSec=5' \
611- '' \
612- '# Security hardening' \
613- 'NoNewPrivileges=false' \
614- 'ProtectSystem=strict' \
615- 'ProtectHome=read-only' \
616- 'PrivateTmp=true' \
617- 'ReadWritePaths=/run/opencode' \
618- '' \
619- '# Socket directory' \
620- 'RuntimeDirectory=opencode' \
621- 'RuntimeDirectoryMode=0755' \
622- '' \
623- '# Logging' \
624- 'StandardOutput=journal' \
625- 'StandardError=journal' \
626- 'SyslogIdentifier=opencode-broker' \
627- '' \
628- '[Install]' \
629- 'WantedBy=multi-user.target' \
630- > /etc/systemd/system/opencode-broker.service
540+ COPY packages/core/src/docker/files/opencode-broker.service /etc/systemd/system/opencode-broker.service
631541
632542# Enable opencode-broker service
633543RUN mkdir -p /etc/systemd/system/multi-user.target.wants \
@@ -638,23 +548,7 @@ RUN mkdir -p /etc/systemd/system/multi-user.target.wants \
638548# -----------------------------------------------------------------------------
639549# Create opencode as a systemd service for Cockpit integration
640550# NOTE: Requires root privileges to write to /etc/systemd/system/
641- RUN printf '%s\n ' \
642- '[Unit]' \
643- 'Description=opencode Web Interface' \
644- 'After=network.target opencode-broker.service' \
645- '' \
646- '[Service]' \
647- 'Type=simple' \
648- 'User=opencode' \
649- 'WorkingDirectory=/home/opencode/workspace' \
650- 'ExecStart=/bin/bash -lc " OPENCODE_PORT=$${OPENCODE_PORT:-$${PORT:-3000}}; OPENCODE_HOST=$${OPENCODE_HOST:-0.0.0.0}; exec /opt/opencode/bin/opencode web --port $${OPENCODE_PORT} --hostname $${OPENCODE_HOST}"' \
651- 'Restart=always' \
652- 'RestartSec=5' \
653- 'Environment=PATH=/opt/opencode/bin:/home/opencode/.local/bin:/home/opencode/.cargo/bin:/home/opencode/.local/share/mise/shims:/home/opencode/.bun/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin' \
654- '' \
655- '[Install]' \
656- 'WantedBy=multi-user.target' \
657- > /etc/systemd/system/opencode.service
551+ COPY packages/core/src/docker/files/opencode.service /etc/systemd/system/opencode.service
658552
659553# Enable opencode service to start at boot (manual symlink since systemctl doesn't work during build)
660554RUN mkdir -p /etc/systemd/system/multi-user.target.wants \
@@ -664,15 +558,9 @@ RUN mkdir -p /etc/systemd/system/multi-user.target.wants \
664558# opencode Configuration
665559# -----------------------------------------------------------------------------
666560# Create opencode.jsonc config file with PAM authentication enabled
667- RUN mkdir -p /home/opencode/.config/opencode \
668- && printf '%s\n ' \
669- '{' \
670- ' " auth": {' \
671- ' " enabled": true' \
672- ' }' \
673- '}' \
674- > /home/opencode/.config/opencode/opencode.jsonc \
675- && chown -R opencode:opencode /home/opencode/.config/opencode \
561+ RUN mkdir -p /home/opencode/.config/opencode
562+ COPY --chown=opencode:opencode packages/core/src/docker/files/opencode.jsonc /home/opencode/.config/opencode/opencode.jsonc
563+ RUN chown -R opencode:opencode /home/opencode/.config/opencode \
676564 && chmod 644 /home/opencode/.config/opencode/opencode.jsonc
677565
678566# Verify config file exists
@@ -684,119 +572,8 @@ RUN ls -la /home/opencode/.config/opencode/opencode.jsonc && cat /home/opencode/
684572# Supports both tini (default, works everywhere) and systemd (for Cockpit on Linux)
685573# Set USE_SYSTEMD=1 environment variable to use systemd init
686574# Note: Entrypoint runs as root to support both modes; tini mode drops to opencode user
687- RUN printf '%s\n ' \
688- '#!/bin/bash' \
689- 'set -euo pipefail' \
690- '' \
691- 'log() {' \
692- ' echo " [opencode-cloud] $*"' \
693- '}' \
694- '' \
695- 'OPENCODE_PORT=" ${OPENCODE_PORT:-${PORT:-3000}}"' \
696- 'OPENCODE_HOST=" ${OPENCODE_HOST:-0.0.0.0}"' \
697- 'export OPENCODE_PORT OPENCODE_HOST' \
698- '' \
699- 'if [ " ${USE_SYSTEMD:-}" = " 1" ]; then' \
700- ' exec /sbin/init' \
701- 'else' \
702- ' # Ensure broker socket directory exists' \
703- ' install -d -m 0755 /run/opencode' \
704- '' \
705- ' # Ensure user records directory exists (ephemeral unless mounted)' \
706- ' install -d -m 0700 /var/lib/opencode-users' \
707- '' \
708- ' restore_users() {' \
709- ' shopt -s nullglob' \
710- ' local records=(/var/lib/opencode-users/*.json)' \
711- ' if [ ${#records[@]} -eq 0 ]; then' \
712- ' return 1' \
713- ' fi' \
714- ' for record in " ${records[@]}"; do' \
715- ' local username password_hash locked' \
716- ' username=" $(jq -r ".username // empty" "${record}" )"' \
717- ' password_hash=" $(jq -r ".password_hash // empty" "${record}" )"' \
718- ' locked=" $(jq -r ".locked // false" "${record}" )"' \
719- ' if [ -z " ${username}" ]; then' \
720- ' log " Skipping invalid user record: ${record}"' \
721- ' continue' \
722- ' fi' \
723- ' if ! id -u " ${username}" >/dev/null 2>&1; then' \
724- ' log " Creating user: ${username}"' \
725- ' useradd -m -s /bin/bash " ${username}"' \
726- ' fi' \
727- ' if [ -n " ${password_hash}" ]; then' \
728- ' usermod -p " ${password_hash}" " ${username}"' \
729- ' fi' \
730- ' if [ " ${locked}" = " true" ]; then' \
731- ' passwd -l " ${username}" >/dev/null' \
732- ' else' \
733- ' passwd -u " ${username}" >/dev/null || true' \
734- ' fi' \
735- ' log " Restored user: ${username}"' \
736- ' done' \
737- ' return 0' \
738- ' }' \
739- '' \
740- ' persist_user_record() {' \
741- ' local username=" $1"' \
742- ' local shadow_hash' \
743- ' shadow_hash=" $(getent shadow "${username}" | cut -d: -f2)"' \
744- ' if [ -z " ${shadow_hash}" ]; then' \
745- ' log " Failed to read shadow hash for ${username}"' \
746- ' return 1' \
747- ' fi' \
748- ' local status locked' \
749- ' status=" $(passwd -S "${username}" | tr -s " " | cut -d" " -f2)"' \
750- ' locked=" false"' \
751- ' if [ " ${status}" = " L" ]; then' \
752- ' locked=" true"' \
753- ' fi' \
754- ' local record_path=" /var/lib/opencode-users/${username}.json"' \
755- ' umask 077' \
756- ' jq -n --arg username " ${username}" --arg hash " ${shadow_hash}" --argjson locked " ${locked}" '" '"' {username:$username,password_hash:$hash,locked:$locked}'"' "' > " ${record_path}"' \
757- ' chmod 600 " ${record_path}"' \
758- ' log " Persisted user record: ${username}"' \
759- ' }' \
760- '' \
761- ' bootstrap_user() {' \
762- ' local username=" ${OPENCODE_BOOTSTRAP_USER:-}"' \
763- ' local password=" ${OPENCODE_BOOTSTRAP_PASSWORD:-}"' \
764- ' local password_hash=" ${OPENCODE_BOOTSTRAP_PASSWORD_HASH:-}"' \
765- ' if [ -z " ${username}" ]; then' \
766- ' return 1' \
767- ' fi' \
768- ' if [ -z " ${password_hash}" ] && [ -z " ${password}" ]; then' \
769- ' log " OPENCODE_BOOTSTRAP_USER is set but no password or hash provided"' \
770- ' exit 1' \
771- ' fi' \
772- ' if ! id -u " ${username}" >/dev/null 2>&1; then' \
773- ' log " Creating bootstrap user: ${username}"' \
774- ' useradd -m -s /bin/bash " ${username}"' \
775- ' fi' \
776- ' if [ -n " ${password_hash}" ]; then' \
777- ' usermod -p " ${password_hash}" " ${username}"' \
778- ' else' \
779- ' echo " ${username}:${password}" | chpasswd' \
780- ' fi' \
781- ' persist_user_record " ${username}"' \
782- ' log " Bootstrap user ready: ${username}"' \
783- ' return 0' \
784- ' }' \
785- '' \
786- ' if restore_users; then' \
787- ' log " User records restored"' \
788- ' else' \
789- ' if ! bootstrap_user; then' \
790- ' log " No persisted users and no bootstrap user configured"' \
791- ' fi' \
792- ' fi' \
793- '' \
794- ' log " Starting opencode on ${OPENCODE_HOST}:${OPENCODE_PORT}"' \
795- ' /usr/local/bin/opencode-broker &' \
796- ' # Use runuser to switch to opencode user without password prompt' \
797- ' exec runuser -u opencode -- sh -lc " cd /home/opencode/workspace && /opt/opencode/bin/opencode web --port ${OPENCODE_PORT} --hostname ${OPENCODE_HOST}"' \
798- 'fi' \
799- > /usr/local/bin/entrypoint.sh && chmod +x /usr/local/bin/entrypoint.sh
575+ COPY packages/core/src/docker/files/entrypoint.sh /usr/local/bin/entrypoint.sh
576+ RUN chmod +x /usr/local/bin/entrypoint.sh
800577
801578# Note: Don't set USER here - entrypoint needs root to use runuser
802579# The tini mode drops privileges to opencode user via runuser
0 commit comments