Using Nix flakes together with pub and private ssh dependencies

Hey there,

I’d like to use Nix to build a Flutter application in a reproducible manner. For this I am using Nix flakes inside of Docker.

The setup:

Flutter pubspec.yaml

name: some_flutter_app


dependencies:
  flutter:
    sdk: flutter

  some_private_package:
    git:
      url: git@bitbucket.org:some_org/some_private_package.git

A Nix flake (excuse the mess, I’ve been tinkering with this)

{
  description = "Flutter development environment";

  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
    flake-utils.url = "github:numtide/flake-utils";
  };

  outputs = { self, nixpkgs, flake-utils, ... }:
    flake-utils.lib.eachDefaultSystem (system:
      let
        pkgs = import nixpkgs {
          inherit system;
          config = {
            allowUnfree = true;
          };
        };
      in
      {
        devShells.default = pkgs.mkShell {
          buildInputs = with pkgs; [
            # Flutter SDK and dependencies
            flutter
            dart
            
            # Additional tools
            jq
            just
            cocoapods
            
            # Ensure SSH is available
            openssh
            git
          ];
          
          # Environment variables
          shellHook = ''
            echo "Flutter development environment loaded"
            export PUB_CACHE=$HOME/.pub-cache
            export PATH=$PATH:$PUB_CACHE/bin
          '';
        };

        packages = {
          default = self.packages.${system}.some-app;
          
          # Include the SSH test in the all-packages build
          all-packages = pkgs.symlinkJoin {
            name = "all-packages";
            paths = [
              self.packages.${system}.some-app
            ];
          };
          
          some-app = pkgs.stdenv.mkDerivation {
            name = "some-app";
            src = ./.; # Source is the current directory
            
            nativeBuildInputs = with pkgs; [
              flutter
              dart
              cacert
              makeWrapper
              # Add SSH and Git support
              openssh
              git
            ];
            
            # For Docker build, allow SSH agent passthrough
            __noChroot = true;
            
            buildPhase = ''
              # Create a temporary home directory for Flutter
              export HOME=$(mktemp -d)
              export PUB_CACHE=$HOME/.pub-cache
              
              # Enable SSH agent forwarding for private git dependencies
              export SSH_AUTH_SOCK=/run/host-services/ssh-auth.sock
              
              mkdir -p $PUB_CACHE
              
              # Setup certificates for Dart/Flutter according to nixpkgs recommendation
              # Create a wrapper for dart with certificate path
              mkdir -p $HOME/bin
              cat > $HOME/bin/dart-with-certs <<EOF
              #!${pkgs.bash}/bin/bash
              exec ${pkgs.dart}/bin/dart --root-certs-file=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt "\$@"
              EOF
              chmod +x $HOME/bin/dart-with-certs
              
              # Tell Flutter to use our wrapped Dart for pub commands
              export NIX_FLUTTER_PUB_DART="$HOME/bin/dart-with-certs"
              export PATH=$HOME/bin:$PATH
              
              # Setup SSH for Git dependencies
              # This assumes SSH agent is forwarded or keys are available
              mkdir -p $HOME/.ssh
              chmod 700 $HOME/.ssh
              
              # Create SSH config to disable host key checking for Bitbucket
              cat > $HOME/.ssh/config <<EOF
              Host bitbucket.org
                StrictHostKeyChecking no
                UserKnownHostsFile /dev/null
              EOF
              chmod 600 $HOME/.ssh/config
              
              # Add BitBucket to known hosts explicitly (can help in some environments)
              ${pkgs.openssh}/bin/ssh-keyscan bitbucket.org >> $HOME/.ssh/known_hosts
              
              # Configure Git to use our SSH setup and specify the path to SSH
              export GIT_SSH_COMMAND="${pkgs.openssh}/bin/ssh -F $HOME/.ssh/config"
              
              # Disable analytics and configure Flutter
              flutter config --no-analytics >/dev/null
              flutter pub get
              
              # Build the app (using linux for compatibility)
              flutter build linux --release
            '';
            
            
            meta = {
              description = "";
              platforms = pkgs.flutter.meta.platforms;
            };
          };
        };
      }
    );
}

and a Docker file:

FROM nixos/nix

# Enable Nix flakes
RUN echo "experimental-features = nix-command flakes" >> /etc/nix/nix.conf

RUN nix-env -iA nixpkgs.cacert nixpkgs.openssh
ENV SSL_CERT_FILE=/etc/ssl/certs/ca-bundle.crt
ENV PATH=$PATH:/root/.nix-profile/bin


COPY . /app/
WORKDIR /app

# Add bitbucket.org's host key to known_hosts before cloning
RUN --mount=type=ssh \
    sh -c "mkdir -p -m 0700 ~/.ssh && ssh-keyscan bitbucket.org >> ~/.ssh/known_hosts"

# Check if has correct git ssh rights
RUN --mount=type=ssh \
    sh -c "ssh -vT git@bitbucket.org && git ls-remote git+ssh://git@bitbucket.org/some_org/some_private_package.git"

RUN --mount=type=ssh nix build --extra-experimental-features 'nix-command flakes' .#ssh-test

# Default command to start a shell
CMD ["bash"] 

SSH works correctly inside Docker, and I do have access to the private repository from within the container. However, as I understand it, Nix handles SSH and the SSH agent in a specific way. This prevents the git tool used by Flutter to pull dependencies from receiving the necessary SSH keys.

My questions are:

  • Is this an ‘intended’ setup? Or am I missing something fundamental?
  • How do I get the SSH keys loaded so Flutter can use them to pull private dependencies?

Thanks,
Norbert