diff --git a/images/devcontainer/default.nix b/images/devcontainer/default.nix index 337f24c..3dfd5b2 100644 --- a/images/devcontainer/default.nix +++ b/images/devcontainer/default.nix @@ -1,12 +1,12 @@ # A fat and modifiable Nix image -{ dockerTools +{ stdenv +, dockerTools , bashInteractive , cacert , closureInfo , coreutils , curl , direnv -, gcc-unwrapped , gitReallyMinimal , glibc , gnugrep @@ -21,15 +21,44 @@ , openssh , procps , shadow +, sudo , xz +, patchelf , mkUserEnvironment +, writeScriptBin }: let channel = builtins.getEnv("NIXPKGS_CHANNEL"); + /** + This entrypoint patches node binary copied by vscode. This always succeeds + as vscode is always slower to run node, as our entrypoint to patch it. + + This solution is prefered to LD_LIBRARY_PATH, as setting LD_LIBRARY_PATH + globally messes environment, as libraries found this way will always have + priority. Only other other alternative i can think of to patch node is to + have a LD_PRELOAD set with that returns the right libraries, but that + solution even if it is more clean can present more runtime issues. + **/ + entrypoint = writeScriptBin "entrypoint.sh" '' + #!${bashInteractive}/bin/bash -e + + until ${patchelf}/bin/patchelf \ + --set-rpath "${stdenv.cc.cc.lib}/lib" \ + --set-interpreter "${glibc}/lib64/ld-linux-x86-64.so.2" \ + $HOME/.vscode-server/bin/*/node 2>/dev/null; do true; done + + echo "vscode server binaries successfully patched" + + "$@" + ''; + # generate a user profile for the image profile = mkUserEnvironment { derivations = [ + # container entrypoint + entrypoint + # core utils coreutils procps @@ -53,9 +82,9 @@ let # for user management shadow + sudo # for the vscode extension - gcc-unwrapped iproute ]; }; @@ -71,7 +100,7 @@ let export USER=nobody ${nix}/bin/nix-store --load-db < ${closureInfo { rootPaths = [ profile ]; }}/registration - # set the user profile + # set default profile ${profile}/bin/nix-env --profile nix/var/nix/profiles/default --set ${profile} # minimal @@ -79,6 +108,11 @@ let ln -s /nix/var/nix/profiles/default/bin/sh bin/sh ln -s /nix/var/nix/profiles/default/bin/env usr/bin/env + # install sudo + mkdir -p usr/bin usr/lib/sudo + cp ${sudo}/bin/sudo usr/bin/sudo + cp -r ${sudo}/libexec/sudo/* usr/lib/sudo + # might as well... ln -s /nix/var/nix/profiles/default/bin/bash bin/bash @@ -94,23 +128,19 @@ let # make sure /tmp exists mkdir -m 0777 tmp - # allow ubuntu ELF binaries to run. VSCode copies it's own. - mkdir -p lib64 - ln -s ${glibc}/lib64/ld-linux-x86-64.so.2 lib64/ld-linux-x86-64.so.2 - # VSCode assumes that /sbin/ip exists mkdir sbin ln -s /nix/var/nix/profiles/default/bin/ip sbin/ip ''; config = { - Cmd = [ "/nix/var/nix/profiles/default/bin/bash" ]; + Entrypoint = [ "/nix/var/nix/profiles/default/bin/entrypoint.sh" ]; + Cmd = [ "sleep" "infinity" ]; Env = [ "ENV=/nix/var/nix/profiles/default/etc/profile.d/nix.sh" "GIT_SSL_CAINFO=/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt" - "LD_LIBRARY_PATH=/nix/var/nix/profiles/default/lib" "PAGER=less" - "PATH=/nix/var/nix/profiles/default/bin" + "PATH=/usr/bin:/nix/var/nix/profiles/default/bin" "SSL_CERT_FILE=/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt" ( if channel != "" then @@ -119,6 +149,30 @@ let "NIX_PATH=nixpkgs=${../nix/fake_nixpkgs}" ) ]; + + # commands to run before build of every Dockerfile using this image + OnBuild = [ + # fix permissions of sudo and set suid bit + "RUN chmod -R u+s,u+rx,g+x,o+x /usr/bin/sudo && chown -R root:root /usr/lib/sudo" + + # expose USERNAME, USER_UID, USER_GID as build arguments + "ARG USERNAME=vscode" + "ARG USER_UID=1000" + "ARG USER_GID=$USER_UID" + + # add user and group, add user to wheel group + "RUN groupadd -f -g $USER_GID $USERNAME && useradd -s /bin/bash --uid $USER_UID --gid $USER_GID -G wheel -m $USERNAME" + + # fix permissions of nix store + "RUN chown -R $USER_UID:$USER_GID /nix" + + # change user, change workdir and create user profile + "USER $USERNAME" + "WORKDIR /home/$USERNAME" + "RUN nix-env --profile /nix/var/nix/profiles/per-user/$USERNAME/profile -iA" + "ENV USER=$USERNAME" + "ENV PATH=/usr/bin:/nix/var/nix/profiles/per-user/$USERNAME/profile/bin:/nix/var/nix/profiles/default/bin" + ]; Labels = { # https://github.com/microscaling/microscaling/blob/55a2d7b91ce7513e07f8b1fd91bbed8df59aed5a/Dockerfile#L22-L33 "org.label-schema.vcs-ref" = "master"; diff --git a/images/devcontainer/root/etc/bashrc b/images/devcontainer/root/etc/bashrc index 814bc54..ddbb073 100644 --- a/images/devcontainer/root/etc/bashrc +++ b/images/devcontainer/root/etc/bashrc @@ -1,6 +1,19 @@ # interactive session if [[ $- == *i* ]]; then -PS1='\[\033[0;32;40m\][nix]$\[\033[0m\] ' +# Provide a nice prompt if the terminal supports it. +if [ "$TERM" != "dumb" -o -n "$INSIDE_EMACS" ]; then + PROMPT_COLOR="1;31m" + let $UID && PROMPT_COLOR="1;32m" + if [ -n "$INSIDE_EMACS" -o "$TERM" == "eterm" -o "$TERM" == "eterm-color" ]; then + # Emacs term mode doesn't support xterm title escape sequence (\e]0;) + PS1="\n\[\033[$PROMPT_COLOR\][\u@\h:\w]\\$\[\033[0m\] " + else + PS1="\n\[\033[$PROMPT_COLOR\][\[\e]0;\u@\h: \w\a\]\u@\h:\w]\\$\[\033[0m\] " + fi + if test "$TERM" = "xterm"; then + PS1="\[\033]2;\h:\u:\w\007\]$PS1" + fi +fi fi diff --git a/images/devcontainer/root/etc/nix/nix.conf b/images/devcontainer/root/etc/nix/nix.conf new file mode 100644 index 0000000..2feb3e8 --- /dev/null +++ b/images/devcontainer/root/etc/nix/nix.conf @@ -0,0 +1 @@ +sandbox = relaxed diff --git a/images/devcontainer/root/etc/sudo.conf b/images/devcontainer/root/etc/sudo.conf new file mode 100644 index 0000000..280237c --- /dev/null +++ b/images/devcontainer/root/etc/sudo.conf @@ -0,0 +1,2 @@ +Plugin sudoers_policy /usr/lib/sudo/sudoers.so +Plugin sudoers_io /usr/lib/sudo/sudoers.so diff --git a/images/devcontainer/root/etc/sudoers b/images/devcontainer/root/etc/sudoers new file mode 100644 index 0000000..bcea2bd --- /dev/null +++ b/images/devcontainer/root/etc/sudoers @@ -0,0 +1,2 @@ +root ALL=(ALL:ALL) SETENV: ALL +%wheel ALL=(ALL:ALL) NOPASSWD:ALL