csh

Organizing Public and Private Dotfiles for GNU Stow and Public Version Control

I suck at backing up. For once, I'd like to be able to download all my important stuff, run a single command, and have everything up and running. I've seen many dotfile management schemes, including dotfiles.sh and Mackup, but they all seem just a little bit over-engineered for my tastes. In general, I prefer the Stow method.

The only problem with using GNU Stow for this is that I can't really keep private files separate, and I certainly can't keep passwords out of files that demand to keep them alongside all the intersting settings that are worth sharing. To solve this, I will keep a single Stow package for all private files, and a CSV file containing key-vlaue pairs for all private strings, which be applied and reverted with a simple search-and-replace mechanism before each deployment and publication.

This text should describe what's important to me, and how it will be structured in a backup.

What's Important

There are two categories of important things: public, and private.

Public

Private

The Layout

I scribbled a mockup of the layout of my dotfiles on paper last night. It now looks something like this:

dotfiles/
  emacs/
    .emacs
  git/
    .gitconfig
  ssh/
    .ssh/
      id_rsa.pub
      known_hosts
  private.tar.gz.gpg
    .gnupg/
      ...
    .password-store/
      calher/
        matrix/
          pass.gpg
        ...
      csh/
        bluehome/
          pass.gpg
        roaming-initiative/
          pass.gpg
        sdf/
	  pass.gpg
	notabug/
	  pass.gpg
      calRedditFLOSSyourJS/
        reddit/
	  pass.gpg
      CharlieBrown/
        freenode/
          pass.gpg
	freepost/
	  pass.gpg
    .ssh/
      id_rsa
    substitutions.csv
      sha256sum password hash,base64 password cleartext
      0693a3a41b7bda5568f205cc000bff5f3bf917f65535b721ae273b3a956ea0b5,UGFzc3dvcmQxCg==

Perhaps the most peculiar item in this listing is the file substitutions.csv. This is a list of corresponding strings for a search-and-replace program to use when adding or removing private information to otherwise public files. For example, if I wanted to put the passphrase Password1 in my .gitconfig, I would add the following line after the [sendemail] section.

        smtppass = 0693a3a41b7bda5568f205cc000bff5f3bf917f65535b721ae273b3a956ea0b5

This would be put in the public copy of .gitconfig. After replacing all the strings and applying it to the running system, however, the same line would show the more legible passphrase, Password1.

smtppass = Password1

This should work with any file. I doubt many programs would need me to escape characters in passphrases.

Deployment

The #deployment of the files should be as simple as cloning the repo, stowing the packages into the home directory where they belong, and replacing all the private strings mentioned in substitutions.csv.

git clone https://notabug.org/csh/dotfiles
cd dotfiles
stow tmux bash emacs git ssh
gpg -d private.tar.gz.gpg
tar -xvf private.tar.gz
stow private
private/expose-strings

expose-strings searches every file in the dotfiles/ directory for the first cell of a line in substitutions.csv, base64-decodes the second cell of a line in the file, and puts the result in place of every found instance of the contents of the first cell of a line.

hide-strings will undo all of this, returning the hashes to their original places. It will be run before every commit and upload. Hopefully, version control will not notice.

Publishing

In order to do the #publishing of any new changes made in version control, and put them in public view on the Internet, we must ensure that private/ and private.tar.gz are erased so they do not get tracked or committed. In addition, hide-strings must be run so that passwords don't show up in public files either. Only then can changes be committed and pushed to version control.

An example shell script might look like the following.

#!/bin/sh
cd ~/dotfiles/

# Disconnect private/
rm private.tar.gz private.tar.gz.gpg
stow -d private

# Update private/
tar -cvzf private.tar.gz private
gpg -c private.tar.gz

# Purge everything
./private/hide-strings
rm -r private/ private.tar.gz 

# Push
# No git commit; do manually in Emacs VC/Bash beforehand
git push