Recent changes to this wiki:

Added a comment: maybe some equivalent of CryptPassword
diff --git a/doc/forum/dm-crypt__47__LUKS_encryption_and_key_management/comment_3_a749abb97ebafd26bb695663b68673c5._comment b/doc/forum/dm-crypt__47__LUKS_encryption_and_key_management/comment_3_a749abb97ebafd26bb695663b68673c5._comment
new file mode 100644
index 00000000..f4448ddf
--- /dev/null
+++ b/doc/forum/dm-crypt__47__LUKS_encryption_and_key_management/comment_3_a749abb97ebafd26bb695663b68673c5._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="david"
+ avatar="http://cdn.libravatar.org/avatar/22c2d800db6a7699139df604a67cb221"
+ subject="maybe some equivalent of CryptPassword"
+ date="2018-10-16T11:51:23Z"
+ content="""
+Storing plaintext luks passwords on disk doesn't sound great for most applications, but I wonder if the encrypted form could be stored in privdata. Something using e.g. \"cryptsetup luksDump\" or \"cryptsetup luksHeaderBackup\". I have no idea how practical it is to generate such data without being logged into the machine in question.
+"""]]

Added a comment: needs update-initramfs
diff --git a/doc/forum/__34__predictable__34___network_interface_names/comment_2_25a2911fa57ea3da20f25b25d7c4406b._comment b/doc/forum/__34__predictable__34___network_interface_names/comment_2_25a2911fa57ea3da20f25b25d7c4406b._comment
new file mode 100644
index 00000000..e284c8f1
--- /dev/null
+++ b/doc/forum/__34__predictable__34___network_interface_names/comment_2_25a2911fa57ea3da20f25b25d7c4406b._comment
@@ -0,0 +1,13 @@
+[[!comment format=mdwn
+ username="david"
+ avatar="http://cdn.libravatar.org/avatar/22c2d800db6a7699139df604a67cb221"
+ subject="needs update-initramfs"
+ date="2018-10-14T21:03:28Z"
+ content="""
+I guess that's a more productive line of thinking, I wouldn't expect these vm's to have more than one network interface. One gotcha that took a bit to figure out is that the masking needs update-initramfs to be seen at boot. The following seems to be working for me:
+
+[[!format haskell \"\"\"
+& File.hasContent \"/etc/systemd/network/99-default.link\" []
+        `onChange` ( Cmd.cmdProperty \"update-initramfs\" [\"-u\"] `changesFile` \"/initrd.img\" )
+\"\"\"]]
+"""]]

Added Apt.backportInstalledMin.
This commit was sponsored by Boyd Stephen Smith Jr. on Patreon.
diff --git a/debian/changelog b/debian/changelog
index b0f7121b..5b283861 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -17,6 +17,7 @@ propellor (5.5.0) UNRELEASED; urgency=medium
   * Borg: Added UsesEnvVar.
   * Added DiskImage.noBootloader, useful for eg, direct booting with
     qemu. Thanks, David Bremner.
+  * Added Apt.backportInstalledMin.
 
  -- Joey Hess <id@joeyh.name>  Thu, 09 Aug 2018 10:54:41 -0400
 
diff --git a/doc/forum/Apt.backportInstalledMin___63__/comment_1_4e5e6b479e478897eea3337b9468db15._comment b/doc/forum/Apt.backportInstalledMin___63__/comment_1_4e5e6b479e478897eea3337b9468db15._comment
new file mode 100644
index 00000000..83b976d2
--- /dev/null
+++ b/doc/forum/Apt.backportInstalledMin___63__/comment_1_4e5e6b479e478897eea3337b9468db15._comment
@@ -0,0 +1,11 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 1"""
+ date="2018-10-14T16:28:46Z"
+ content="""
+Indeed, that's the kind of improvement I will gladly
+accept any time, and should be very easy to add. So don't hesitate to add
+properties like that and send patches.
+
+(In this case I had 5 minutes so I implemented it already.)
+"""]]
diff --git a/src/Propellor/Property/Apt.hs b/src/Propellor/Property/Apt.hs
index 064221f9..6d7fc4d6 100644
--- a/src/Propellor/Property/Apt.hs
+++ b/src/Propellor/Property/Apt.hs
@@ -241,6 +241,10 @@ type Package = String
 installed :: [Package] -> Property DebianLike
 installed = installed' ["-y"]
 
+-- | Minimal install of package, without recommends.
+installedMin :: [Package] -> Property DebianLike
+installedMin = installed' ["--no-install-recommends", "-y"]
+
 installed' :: [String] -> [Package] -> Property DebianLike
 installed' params ps = robustly $ check (not <$> isInstalled' ps) go
 	`describe` unwords ("apt installed":ps)
@@ -253,20 +257,23 @@ installed' params ps = robustly $ check (not <$> isInstalled' ps) go
 -- dependencies from stable-backports too, you will need to include those
 -- dependencies in the list of packages passed to this function.
 backportInstalled :: [Package] -> Property Debian
-backportInstalled ps = withOS desc $ \w o -> case o of
+backportInstalled = backportInstalled' ["-y"]
+
+-- | Minimal install from the stable-backports suite, without recommends.
+backportInstalledMin :: [Package] -> Property Debian
+backportInstalledMin = backportInstalled' ["--no-install-recommends", "-y"]
+
+backportInstalled' :: [String] -> [Package] -> Property Debian
+backportInstalled' params ps = withOS desc $ \w o -> case o of
 	(Just (System (Debian _ suite) _)) -> case backportSuite suite of
 		Nothing -> unsupportedOS'
 		Just bs -> ensureProperty w $
-			runApt (["install", "-y"] ++ ((++ '/':bs) <$> ps))
+			runApt (("install":params) ++ ((++ '/':bs) <$> ps))
 				`changesFile` dpkgStatus
 	_ -> unsupportedOS'
   where
 	desc = unwords ("apt installed backport":ps)
 
--- | Minimal install of package, without recommends.
-installedMin :: [Package] -> Property DebianLike
-installedMin = installed' ["--no-install-recommends", "-y"]
-
 removed :: [Package] -> Property DebianLike
 removed ps = check (any (== IsInstalled) <$> getInstallStatus ps)
 	(runApt (["-y", "remove"] ++ ps))

comment
diff --git a/doc/forum/__34__predictable__34___network_interface_names/comment_1_6bf05129a9aa5b427c0838753b5b0673._comment b/doc/forum/__34__predictable__34___network_interface_names/comment_1_6bf05129a9aa5b427c0838753b5b0673._comment
new file mode 100644
index 00000000..c3e4e663
--- /dev/null
+++ b/doc/forum/__34__predictable__34___network_interface_names/comment_1_6bf05129a9aa5b427c0838753b5b0673._comment
@@ -0,0 +1,12 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 1"""
+ date="2018-10-14T16:18:37Z"
+ content="""
+I don't think this is specific to disk image creation, you just need a
+property that arranges whatever configuration will lead to the names you
+want.
+
+You may be looking for /lib/systemd/network/99-default.link which can be
+masked to get the kernel's traditional names.
+"""]]

diff --git a/doc/forum/Apt.backportInstalledMin___63__.mdwn b/doc/forum/Apt.backportInstalledMin___63__.mdwn
new file mode 100644
index 00000000..64d95c72
--- /dev/null
+++ b/doc/forum/Apt.backportInstalledMin___63__.mdwn
@@ -0,0 +1 @@
+I just installed git-annex using Apt.backportInstalled on a server and was kindof of horrified by the dependendencies dragged in. I suspect much of this is probably just youtube-dl, which should be fixed soon, but anyway, shouldn't there be a way to install from backports without recommends?

diff --git a/doc/forum/__34__predictable__34___network_interface_names.mdwn b/doc/forum/__34__predictable__34___network_interface_names.mdwn
new file mode 100644
index 00000000..88b4b414
--- /dev/null
+++ b/doc/forum/__34__predictable__34___network_interface_names.mdwn
@@ -0,0 +1,3 @@
+When using propellor to install/create VM images, one naturally wants to set some kind of sane network configuration. Unfortunately the name of the network interface in the guest (or newly installed system) varies according to the hardware setup. As a concrete example, in a newly created stretch amd64 image it is ens0, while in a stretch s390x image it is enc0.  I guess the Debian installer must have some way of figuring this out and creating a sane /etc/network/interfaces. Is this something that Property.DiskImage can help with, or do I need to carry per-VM configuration information? I don't mind so much the extra config info, but it's a bit annoying that I need to boot the vm to see what the network device is called.
+
+I guess the Luddite solution is to turn off interface renaming via boot options; I'm not sure that option will always be available to me, e.g. when deploying images on someone else's host.

Added a comment: insufficient magic
diff --git a/doc/todo/support_for_libvirt_KVM_VMs/comment_5_364df45dda89ed83cf8db6fa4cbdc186._comment b/doc/todo/support_for_libvirt_KVM_VMs/comment_5_364df45dda89ed83cf8db6fa4cbdc186._comment
new file mode 100644
index 00000000..5062ed5d
--- /dev/null
+++ b/doc/todo/support_for_libvirt_KVM_VMs/comment_5_364df45dda89ed83cf8db6fa4cbdc186._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="david"
+ avatar="http://cdn.libravatar.org/avatar/22c2d800db6a7699139df604a67cb221"
+ subject="insufficient magic"
+ date="2018-10-14T11:12:36Z"
+ content="""
+right, changing the backing image would probably break everything.
+"""]]

comment
diff --git a/doc/todo/support_for_libvirt_KVM_VMs/comment_4_dbd2c399c8ef8ac56ae06f1a701fdc45._comment b/doc/todo/support_for_libvirt_KVM_VMs/comment_4_dbd2c399c8ef8ac56ae06f1a701fdc45._comment
new file mode 100644
index 00000000..8ce06a1c
--- /dev/null
+++ b/doc/todo/support_for_libvirt_KVM_VMs/comment_4_dbd2c399c8ef8ac56ae06f1a701fdc45._comment
@@ -0,0 +1,19 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 4"""
+ date="2018-10-14T01:10:16Z"
+ content="""
+I do think that the conditional property would be a good way for this to
+work.
+
+I think there could also be VMs where you don't want the overhead of
+running propellor inside the VM (especially if the emulation is slow, or
+you don't want to allocate that much memory to the VM, or just have a lot
+of VMs), and the content is disposable. Then propellor could restart the VM
+when it changes the disk image.
+
+There's room for multiple ways to do it.. 
+
+The disk image building side of this looks easy to me, so if you do the libvirt
+stuff, Sean, I might contribute something. :)
+"""]]

name bikeshedding
diff --git a/debian/changelog b/debian/changelog
index cc0e0a15..b0f7121b 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -15,6 +15,8 @@ propellor (5.5.0) UNRELEASED; urgency=medium
     the line to /etc/sudoers, but that would override more specific lines
     in the include directory.
   * Borg: Added UsesEnvVar.
+  * Added DiskImage.noBootloader, useful for eg, direct booting with
+    qemu. Thanks, David Bremner.
 
  -- Joey Hess <id@joeyh.name>  Thu, 09 Aug 2018 10:54:41 -0400
 
diff --git a/doc/forum/support_for_non-bootable_disk_images/comment_5_ee60d5bf1cdd1fd0e4319eed99f614c1._comment b/doc/forum/support_for_non-bootable_disk_images/comment_5_ee60d5bf1cdd1fd0e4319eed99f614c1._comment
new file mode 100644
index 00000000..9ebe3062
--- /dev/null
+++ b/doc/forum/support_for_non-bootable_disk_images/comment_5_ee60d5bf1cdd1fd0e4319eed99f614c1._comment
@@ -0,0 +1,13 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 5"""
+ date="2018-10-14T00:39:51Z"
+ content="""
+Ah right, [[todo/support_for_libvirt_KVM_VMs]];
+your patch is kind of a prerequisite for that. Pulling the kernel and
+initrd out of the chroot is a good idea!
+
+"Host" is slightly ambiguous around disk image building because
+a disk image can be built for a Host by `imageBuiltFor`. I've gone ahead
+and merged it in with the NoBootloader name.
+"""]]
diff --git a/propellor.cabal b/propellor.cabal
index 518505a4..0454fc92 100644
--- a/propellor.cabal
+++ b/propellor.cabal
@@ -74,7 +74,6 @@ Library
     Propellor.Property.Cron
     Propellor.Property.DebianMirror
     Propellor.Property.Debootstrap
-    Propellor.Property.DirectBoot
     Propellor.Property.DiskImage
     Propellor.Property.DiskImage.PartSpec
     Propellor.Property.Dns
diff --git a/src/Propellor/Property/DirectBoot.hs b/src/Propellor/Property/DirectBoot.hs
deleted file mode 100644
index 4807471e..00000000
--- a/src/Propellor/Property/DirectBoot.hs
+++ /dev/null
@@ -1,7 +0,0 @@
-module Propellor.Property.DirectBoot(installed) where
-
-import Propellor.Base
-import Propellor.Types.Bootloader
-
-installed :: Property (HasInfo + UnixLike)
-installed = pureInfoProperty "direct boot" [DirectBoot]
diff --git a/src/Propellor/Property/DiskImage.hs b/src/Propellor/Property/DiskImage.hs
index a41af18c..fa41808e 100644
--- a/src/Propellor/Property/DiskImage.hs
+++ b/src/Propellor/Property/DiskImage.hs
@@ -18,6 +18,7 @@ module Propellor.Property.DiskImage (
 	imageBuiltFrom,
 	imageExists,
 	GrubTarget(..),
+	noBootloader,
 ) where
 
 import Propellor.Base
@@ -228,7 +229,7 @@ imageBuilt' rebuild img mkchroot tabletype partspec =
 			ubootFlashKernelFinalized p
 		[FlashKernelInstalled, UbootInstalled p] -> 
 			ubootFlashKernelFinalized p
-                [DirectBoot] -> directBootFinalized
+		[NoBootloader] -> noBootloaderFinalized
 		_ -> unbootable "multiple bootloaders are installed; don't know which to use"
 
 -- | This property is automatically added to the chroot when building a
@@ -470,9 +471,6 @@ grubFinalized grubtarget _img mnt loopdevs =
 ubootFinalized :: (FilePath -> FilePath -> Property Linux) -> Finalization
 ubootFinalized p (RawDiskImage img) mnt _loopdevs = p img mnt
 
-directBootFinalized :: Finalization
-directBootFinalized _img _mnt _loopDevs = doNothing
-
 flashKernelFinalized :: Finalization
 flashKernelFinalized _img mnt _loopdevs = FlashKernel.flashKernelMounted mnt
 
@@ -481,6 +479,15 @@ ubootFlashKernelFinalized p img mnt loopdevs =
 	ubootFinalized p img mnt loopdevs
 		`before` flashKernelFinalized img mnt loopdevs
 
+-- | Normally a boot loader is installed on a disk image. However,
+-- when the disk image will be booted by eg qemu booting the kernel and
+-- initrd, no boot loader is needed, and this property can be used.
+noBootloader :: Property (HasInfo + UnixLike)
+noBootloader = pureInfoProperty "no bootloader" [NoBootloader]
+
+noBootloaderFinalized :: Finalization
+noBootloaderFinalized _img _mnt _loopDevs = doNothing
+
 isChild :: FilePath -> Maybe MountPoint -> Bool
 isChild mntpt (Just d)
 	| d `equalFilePath` mntpt = False
diff --git a/src/Propellor/Types/Bootloader.hs b/src/Propellor/Types/Bootloader.hs
index cdb37a31..52a6da02 100644
--- a/src/Propellor/Types/Bootloader.hs
+++ b/src/Propellor/Types/Bootloader.hs
@@ -10,7 +10,7 @@ data BootloaderInstalled
 	= GrubInstalled GrubTarget
 	| FlashKernelInstalled
 	| UbootInstalled (FilePath -> FilePath -> Property Linux)
-        | DirectBoot
+	| NoBootloader
 	deriving (Typeable)
 
 -- | Platforms that grub can boot.
@@ -20,7 +20,7 @@ instance Show BootloaderInstalled where
 	show (GrubInstalled _) = "GrubInstalled"
 	show FlashKernelInstalled = "FlashKernelInstalled"
 	show (UbootInstalled _) = "UbootInstalled"
-        show DirectBoot = "DirectBoot"
+	show NoBootloader = "NoBootloader"
 
 instance IsInfo [BootloaderInstalled] where
 	propagateInfo _ = PropagateInfo False

comment
diff --git a/doc/todo/support_for_libvirt_KVM_VMs/comment_2_54538a03d7085513538baa2970983ae0._comment b/doc/todo/support_for_libvirt_KVM_VMs/comment_2_54538a03d7085513538baa2970983ae0._comment
new file mode 100644
index 00000000..497e364a
--- /dev/null
+++ b/doc/todo/support_for_libvirt_KVM_VMs/comment_2_54538a03d7085513538baa2970983ae0._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 2"""
+ date="2018-10-14T00:36:55Z"
+ content="""
+@david, but you'd not then want to change the backing raw image, I assume,
+or does qcow somehow deal with that?
+"""]]

Added a comment: qcow and raw imgs
diff --git a/doc/todo/support_for_libvirt_KVM_VMs/comment_2_9aa111329fc476a2b978aabe4cc4c0f0._comment b/doc/todo/support_for_libvirt_KVM_VMs/comment_2_9aa111329fc476a2b978aabe4cc4c0f0._comment
new file mode 100644
index 00000000..db451976
--- /dev/null
+++ b/doc/todo/support_for_libvirt_KVM_VMs/comment_2_9aa111329fc476a2b978aabe4cc4c0f0._comment
@@ -0,0 +1,14 @@
+[[!comment format=mdwn
+ username="david"
+ avatar="http://cdn.libravatar.org/avatar/22c2d800db6a7699139df604a67cb221"
+ subject="qcow and raw imgs"
+ date="2018-10-13T23:48:46Z"
+ content="""
+Maybe this is obvious, but it's cheap to generate a qcow image \"backed\" by an existing raw image
+
+To quote from a script I have lying around to let a non-root user boot a root owned, read-only image
+[[!format txt \"\"\"
+qemu-img create -b /srv/vm/$vm.img -f qcow2 $img
+\"\"\"]]
+
+"""]]

Added a comment: Naming and other hard problems
diff --git a/doc/forum/support_for_non-bootable_disk_images/comment_4_33cf3405000896fb42b9165a206e2417._comment b/doc/forum/support_for_non-bootable_disk_images/comment_4_33cf3405000896fb42b9165a206e2417._comment
new file mode 100644
index 00000000..55e4e20b
--- /dev/null
+++ b/doc/forum/support_for_non-bootable_disk_images/comment_4_33cf3405000896fb42b9165a206e2417._comment
@@ -0,0 +1,15 @@
+[[!comment format=mdwn
+ username="david"
+ avatar="http://cdn.libravatar.org/avatar/22c2d800db6a7699139df604a67cb221"
+ subject="Naming and other hard problems"
+ date="2018-10-13T23:16:07Z"
+ content="""
+I'm not too attached to the terminology, \"direct booting\" just what an unscientific survey of sysadmin types came up with. QemuBoot is more descriptive, although I do wonder if it's really specific to Qemu.  As far as I understand (which is just from reading the Xen wiki), Xen dom0 can also (and originally could only) boot this way.  In fact I think the last Xen VPS I had worked like this, which was a pain as a guest admin. Maybe the connecting thread is that the boot is controlled by the host rather than the guest VM.  HostBoot would be one option, although NoBootloader is also fine with me. I think things like QemuBootloader or whatever would likely be layered on top.
+
+I'm less sure about copying kernel and initrd than when I first wrote that. If it's reasonable to depend on the existence of the foo.img.chroot,  then it's quite convenient to boot from the already conveniently present kernel and initramfs.
+
+I'll have to see how hard it is to get basic networking with just qemu. It might make sense to use libvirt to run the VMs, especially since that's what the production deployment uses.  I saw [[spwhitton]] had some ideas about libvirt.
+
+
+
+"""]]

code review
diff --git a/doc/forum/support_for_non-bootable_disk_images/comment_3_8dd7f3dd8c80fda70233e395da2204b2._comment b/doc/forum/support_for_non-bootable_disk_images/comment_3_8dd7f3dd8c80fda70233e395da2204b2._comment
new file mode 100644
index 00000000..d1761e51
--- /dev/null
+++ b/doc/forum/support_for_non-bootable_disk_images/comment_3_8dd7f3dd8c80fda70233e395da2204b2._comment
@@ -0,0 +1,33 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 3"""
+ date="2018-10-13T21:41:25Z"
+ content="""
+Code^Wwhitespace review:
+
+* I noticed some places were using spaces for indentation;
+  please use tabs in propellor.
+* In "module Propellor.Property.DirectBoot(installed)'
+  there should be a space after the name of the module.
+* Needs comments explaining what properties are for.
+
+Naming ideas: Basically this is using qemu as the bootloader, rather than
+going through an (emulated) BIOS to start a bootloader. So I'm thinking
+names like QemuBootloader or NoBootloader, or NoBIOS. Don't want to
+bikeshed this too hard, it would be ok to keep the DirectBoot name, but
+I think Propellor.Property.DirectBoot at least needs a comment explaining what it's
+for, it would be confusing for a propellor user to stumble across that
+module without context.
+
+Your idea to copy the kernel and initrd out of the image so qemu can use
+them seems to point toward having a Property that gets one of these images
+booted up using qemu. And then the QemuBootloader name would make a lot of
+sense, because it would allow for later expansion to other emulators. Not
+that you have to build such a thing, but it's worth considering that someone
+may later want to.
+
+(In fact I could use such a thing, but I don't know how I'd want it to
+work. Should propellor only use the chroot for initial image build, and
+then ssh into the booted VM and run propellor in there when there are
+config updates? Or restart the VM when the image is changed?)
+"""]]

comment
diff --git a/doc/forum/__35__propellor_on_irc.oftc.net/comment_1_6e9595651c19d98353254f0914b685e1._comment b/doc/forum/__35__propellor_on_irc.oftc.net/comment_1_6e9595651c19d98353254f0914b685e1._comment
new file mode 100644
index 00000000..187004c7
--- /dev/null
+++ b/doc/forum/__35__propellor_on_irc.oftc.net/comment_1_6e9595651c19d98353254f0914b685e1._comment
@@ -0,0 +1,9 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 1"""
+ date="2018-10-13T21:36:16Z"
+ content="""
++1 user for initiative ;)
+
+Although I will not want to help with any big type errors on irc ;)
+"""]]

diff --git a/doc/forum/__35__propellor_on_irc.oftc.net.mdwn b/doc/forum/__35__propellor_on_irc.oftc.net.mdwn
new file mode 100644
index 00000000..9f644611
--- /dev/null
+++ b/doc/forum/__35__propellor_on_irc.oftc.net.mdwn
@@ -0,0 +1,2 @@
+This might be wildly optimistic, but I registered the IRC channel #propellor on irc.oftc.net. I have no strong opinions on irc networks, but #git-annex is already there. Please join so you can answer my questions ;).
+

Added a comment: As commits
diff --git a/doc/forum/support_for_non-bootable_disk_images/comment_2_cced7ce2491cf440ee1d576b75ab4539._comment b/doc/forum/support_for_non-bootable_disk_images/comment_2_cced7ce2491cf440ee1d576b75ab4539._comment
new file mode 100644
index 00000000..51cad6ff
--- /dev/null
+++ b/doc/forum/support_for_non-bootable_disk_images/comment_2_cced7ce2491cf440ee1d576b75ab4539._comment
@@ -0,0 +1,10 @@
+[[!comment format=mdwn
+ username="david"
+ avatar="http://cdn.libravatar.org/avatar/22c2d800db6a7699139df604a67cb221"
+ subject="As commits"
+ date="2018-10-08T13:03:06Z"
+ content="""
+I pushed the changes to
+
+https://salsa.debian.org/bremner/propellor/commits/proposed/direct-boot
+"""]]

Added a comment: Initial attempt at a patch
diff --git a/doc/forum/support_for_non-bootable_disk_images/comment_1_94727e8ddf14f868225b99c83fbf406d._comment b/doc/forum/support_for_non-bootable_disk_images/comment_1_94727e8ddf14f868225b99c83fbf406d._comment
new file mode 100644
index 00000000..b4ade339
--- /dev/null
+++ b/doc/forum/support_for_non-bootable_disk_images/comment_1_94727e8ddf14f868225b99c83fbf406d._comment
@@ -0,0 +1,65 @@
+[[!comment format=mdwn
+ username="david"
+ avatar="http://cdn.libravatar.org/avatar/22c2d800db6a7699139df604a67cb221"
+ subject="Initial attempt at a patch"
+ date="2018-10-08T12:48:38Z"
+ content="""
+Here is a simple approach, that at least allows the image building to complete. I also managed to boot one of the images on AMD64. Probably it needs more testing, and I'm sure there are style and naming issues.
+[[!format text \"\"\"
+diff --git a/src/Propellor/Property/DirectBoot.hs b/src/Propellor/Property/DirectBoot.hs
+new file mode 100644
+index 00000000..4807471e
+--- /dev/null
++++ b/src/Propellor/Property/DirectBoot.hs
+@@ -0,0 +1,7 @@
++module Propellor.Property.DirectBoot(installed) where
++
++import Propellor.Base
++import Propellor.Types.Bootloader
++
++installed :: Property (HasInfo + UnixLike)
++installed = pureInfoProperty \"direct boot\" [DirectBoot]
+diff --git a/src/Propellor/Property/DiskImage.hs b/src/Propellor/Property/DiskImage.hs
+index 289de151..a41af18c 100644
+--- a/src/Propellor/Property/DiskImage.hs
++++ b/src/Propellor/Property/DiskImage.hs
+@@ -228,6 +228,7 @@ imageBuilt' rebuild img mkchroot tabletype partspec =
+                        ubootFlashKernelFinalized p
+                [FlashKernelInstalled, UbootInstalled p] -> 
+                        ubootFlashKernelFinalized p
++                [DirectBoot] -> directBootFinalized
+                _ -> unbootable \"multiple bootloaders are installed; don't know which to use\"
+ 
+ -- | This property is automatically added to the chroot when building a
+@@ -469,6 +470,9 @@ grubFinalized grubtarget _img mnt loopdevs =
+ ubootFinalized :: (FilePath -> FilePath -> Property Linux) -> Finalization
+ ubootFinalized p (RawDiskImage img) mnt _loopdevs = p img mnt
+ 
++directBootFinalized :: Finalization
++directBootFinalized _img _mnt _loopDevs = doNothing
++
+ flashKernelFinalized :: Finalization
+ flashKernelFinalized _img mnt _loopdevs = FlashKernel.flashKernelMounted mnt
+ 
+diff --git a/src/Propellor/Types/Bootloader.hs b/src/Propellor/Types/Bootloader.hs
+index 65117bd2..cdb37a31 100644
+--- a/src/Propellor/Types/Bootloader.hs
++++ b/src/Propellor/Types/Bootloader.hs
+@@ -10,6 +10,7 @@ data BootloaderInstalled
+        = GrubInstalled GrubTarget
+        | FlashKernelInstalled
+        | UbootInstalled (FilePath -> FilePath -> Property Linux)
++        | DirectBoot
+        deriving (Typeable)
+ 
+ -- | Platforms that grub can boot.
+@@ -19,6 +20,7 @@ instance Show BootloaderInstalled where
+        show (GrubInstalled _) = \"GrubInstalled\"
+        show FlashKernelInstalled = \"FlashKernelInstalled\"
+        show (UbootInstalled _) = \"UbootInstalled\"
++        show DirectBoot = \"DirectBoot\"
+ 
+ instance IsInfo [BootloaderInstalled] where
+        propagateInfo _ = PropagateInfo False
+\"\"\"]]
+"""]]

removed
diff --git a/doc/forum/support_for_non-bootable_disk_images/comment_1_4c4a376db9071336011abbf2993022f2._comment b/doc/forum/support_for_non-bootable_disk_images/comment_1_4c4a376db9071336011abbf2993022f2._comment
deleted file mode 100644
index 60cbc9f0..00000000
--- a/doc/forum/support_for_non-bootable_disk_images/comment_1_4c4a376db9071336011abbf2993022f2._comment
+++ /dev/null
@@ -1,68 +0,0 @@
-[[!comment format=mdwn
- username="david"
- avatar="http://cdn.libravatar.org/avatar/22c2d800db6a7699139df604a67cb221"
- subject="Initial attempt"
- date="2018-10-08T12:43:42Z"
- content="""
-I tried to solve this in the stupidest possible way. I'll paste diff here, as it's small and I'm not really confident it's ready for merging.
-
-
-[[!format \"\"\"
-diff --git a/src/Propellor/Property/DirectBoot.hs b/src/Propellor/Property/DirectBoot.hs
-new file mode 100644
-index 00000000..4807471e
---- /dev/null
-+++ b/src/Propellor/Property/DirectBoot.hs
-@@ -0,0 +1,7 @@
-+module Propellor.Property.DirectBoot(installed) where
-+
-+import Propellor.Base
-+import Propellor.Types.Bootloader
-+
-+installed :: Property (HasInfo + UnixLike)
-+installed = pureInfoProperty \"direct boot\" [DirectBoot]
-diff --git a/src/Propellor/Property/DiskImage.hs b/src/Propellor/Property/DiskImage.hs
-index 289de151..a41af18c 100644
---- a/src/Propellor/Property/DiskImage.hs
-+++ b/src/Propellor/Property/DiskImage.hs
-@@ -228,6 +228,7 @@ imageBuilt' rebuild img mkchroot tabletype partspec =
-                        ubootFlashKernelFinalized p
-                [FlashKernelInstalled, UbootInstalled p] -> 
-                        ubootFlashKernelFinalized p
-+                [DirectBoot] -> directBootFinalized
-                _ -> unbootable \"multiple bootloaders are installed; don't know which to use\"
- 
- -- | This property is automatically added to the chroot when building a
-@@ -469,6 +470,9 @@ grubFinalized grubtarget _img mnt loopdevs =
- ubootFinalized :: (FilePath -> FilePath -> Property Linux) -> Finalization
- ubootFinalized p (RawDiskImage img) mnt _loopdevs = p img mnt
- 
-+directBootFinalized :: Finalization
-+directBootFinalized _img _mnt _loopDevs = doNothing
-+
- flashKernelFinalized :: Finalization
- flashKernelFinalized _img mnt _loopdevs = FlashKernel.flashKernelMounted mnt
- 
-diff --git a/src/Propellor/Types/Bootloader.hs b/src/Propellor/Types/Bootloader.hs
-index 65117bd2..cdb37a31 100644
---- a/src/Propellor/Types/Bootloader.hs
-+++ b/src/Propellor/Types/Bootloader.hs
-@@ -10,6 +10,7 @@ data BootloaderInstalled
-        = GrubInstalled GrubTarget
-        | FlashKernelInstalled
-        | UbootInstalled (FilePath -> FilePath -> Property Linux)
-+        | DirectBoot
-        deriving (Typeable)
- 
- -- | Platforms that grub can boot.
-@@ -19,6 +20,7 @@ instance Show BootloaderInstalled where
-        show (GrubInstalled _) = \"GrubInstalled\"
-        show FlashKernelInstalled = \"FlashKernelInstalled\"
-        show (UbootInstalled _) = \"UbootInstalled\"
-+        show DirectBoot = \"DirectBoot\"
- 
- instance IsInfo [BootloaderInstalled] where
-        propagateInfo _ = PropagateInfo False
-
-\"\"\"]]
-"""]]

Added a comment: Initial attempt
diff --git a/doc/forum/support_for_non-bootable_disk_images/comment_1_4c4a376db9071336011abbf2993022f2._comment b/doc/forum/support_for_non-bootable_disk_images/comment_1_4c4a376db9071336011abbf2993022f2._comment
new file mode 100644
index 00000000..60cbc9f0
--- /dev/null
+++ b/doc/forum/support_for_non-bootable_disk_images/comment_1_4c4a376db9071336011abbf2993022f2._comment
@@ -0,0 +1,68 @@
+[[!comment format=mdwn
+ username="david"
+ avatar="http://cdn.libravatar.org/avatar/22c2d800db6a7699139df604a67cb221"
+ subject="Initial attempt"
+ date="2018-10-08T12:43:42Z"
+ content="""
+I tried to solve this in the stupidest possible way. I'll paste diff here, as it's small and I'm not really confident it's ready for merging.
+
+
+[[!format \"\"\"
+diff --git a/src/Propellor/Property/DirectBoot.hs b/src/Propellor/Property/DirectBoot.hs
+new file mode 100644
+index 00000000..4807471e
+--- /dev/null
++++ b/src/Propellor/Property/DirectBoot.hs
+@@ -0,0 +1,7 @@
++module Propellor.Property.DirectBoot(installed) where
++
++import Propellor.Base
++import Propellor.Types.Bootloader
++
++installed :: Property (HasInfo + UnixLike)
++installed = pureInfoProperty \"direct boot\" [DirectBoot]
+diff --git a/src/Propellor/Property/DiskImage.hs b/src/Propellor/Property/DiskImage.hs
+index 289de151..a41af18c 100644
+--- a/src/Propellor/Property/DiskImage.hs
++++ b/src/Propellor/Property/DiskImage.hs
+@@ -228,6 +228,7 @@ imageBuilt' rebuild img mkchroot tabletype partspec =
+                        ubootFlashKernelFinalized p
+                [FlashKernelInstalled, UbootInstalled p] -> 
+                        ubootFlashKernelFinalized p
++                [DirectBoot] -> directBootFinalized
+                _ -> unbootable \"multiple bootloaders are installed; don't know which to use\"
+ 
+ -- | This property is automatically added to the chroot when building a
+@@ -469,6 +470,9 @@ grubFinalized grubtarget _img mnt loopdevs =
+ ubootFinalized :: (FilePath -> FilePath -> Property Linux) -> Finalization
+ ubootFinalized p (RawDiskImage img) mnt _loopdevs = p img mnt
+ 
++directBootFinalized :: Finalization
++directBootFinalized _img _mnt _loopDevs = doNothing
++
+ flashKernelFinalized :: Finalization
+ flashKernelFinalized _img mnt _loopdevs = FlashKernel.flashKernelMounted mnt
+ 
+diff --git a/src/Propellor/Types/Bootloader.hs b/src/Propellor/Types/Bootloader.hs
+index 65117bd2..cdb37a31 100644
+--- a/src/Propellor/Types/Bootloader.hs
++++ b/src/Propellor/Types/Bootloader.hs
+@@ -10,6 +10,7 @@ data BootloaderInstalled
+        = GrubInstalled GrubTarget
+        | FlashKernelInstalled
+        | UbootInstalled (FilePath -> FilePath -> Property Linux)
++        | DirectBoot
+        deriving (Typeable)
+ 
+ -- | Platforms that grub can boot.
+@@ -19,6 +20,7 @@ instance Show BootloaderInstalled where
+        show (GrubInstalled _) = \"GrubInstalled\"
+        show FlashKernelInstalled = \"FlashKernelInstalled\"
+        show (UbootInstalled _) = \"UbootInstalled\"
++        show DirectBoot = \"DirectBoot\"
+ 
+ instance IsInfo [BootloaderInstalled] where
+        propagateInfo _ = PropagateInfo False
+
+\"\"\"]]
+"""]]

diff --git a/doc/forum/support_for_non-bootable_disk_images.mdwn b/doc/forum/support_for_non-bootable_disk_images.mdwn
new file mode 100644
index 00000000..1c62c599
--- /dev/null
+++ b/doc/forum/support_for_non-bootable_disk_images.mdwn
@@ -0,0 +1,59 @@
+qemu-system-s390x has the apparent quirk that it can only boot via something like
+
+ `qemu-system-s390x -kernel kernel.debian -initrd initrd.debian -m 512 -nographic --drive file=rootimage.img,format=raw,if=none,id=c1`
+
+This means I think what I want to do is something like the following
+
+[[!format haskell """
+  & imageBuilt (RawDiskImage "/srv/vm/bricklin.img") bricklinChroot
+          MSDOS
+          [ partition EXT4 `mountedAt` "/"
+			`addFreeSpace` MegaBytes 100
+			`mountOpt` errorReadonly
+	  , swapPartition (MegaBytes 256)
+	]
+  where
+    bricklinChroot d = debootstrapped mempty d $ props
+      & osDebian (Stable "stretch") S390X
+      & Apt.installed [ "linux-image-s390x" ]
+"""]]
+
+This seems to build the image OK (see end of post), but propellor fails because the image is not bootable (the image contents might need adjustment as well, but first things first).
+I'm not sure what this style of booting is called, but I see people providing "cloud images" meant to be used this way, with separate initrd and and kernel.  Is it sensible to customize imageBuilt for this purpose, or would it be better write my own `nonBootableImageBuilt` or something like that?
+
+
+[[!format text """
+/srv/vm/bricklin.img.chroot apt installed linux-image-s390x ... done
+/srv/vm/bricklin.img.chroot cache cleaned ... ok
+creating /srv/vm/bricklin.img of size 1.02 gigabytes
+Reading package lists...
+Building dependency tree...
+Reading state information...
+The following packages were automatically installed and are no longer required:
+[snip]
+Use 'apt autoremove' to remove them.
+The following NEW packages will be installed:
+  kpartx
+0 upgraded, 1 newly installed, 0 to remove and 5 not upgraded.
+Need to get 33.8 kB of archives.
+After this operation, 76.8 kB of additional disk space will be used.
+Get:1 http://deb.debian.org/debian stretch/main amd64 kpartx amd64 0.6.4-5 [33.8 kB]
+Fetched 33.8 kB in 0s (118 kB/s)
+                                Selecting previously unselected package kpartx.
+(Reading database ... 238863 files and directories currently installed.)
+Preparing to unpack .../kpartx_0.6.4-5_amd64.deb ...
+Unpacking kpartx (0.6.4-5) ...
+Setting up kpartx (0.6.4-5) ...
+Processing triggers for man-db (2.7.6.1-2) ...
+Setting up swapspace version 1, size = 248 MiB (260042752 bytes)
+no label, UUID=65c5b131-98bf-4b8c-afad-9c75405c6391
+loop deleted : /dev/loop0
+    433,093,140  99%  220.62MB/s    0:00:01 (xfr#11289, to-chk=0/14615)   
+** warning: image is not bootable: no bootloader is installed
+loop deleted : /dev/loop0
+concave.cs.unb.ca built disk image /srv/vm/bricklin.img ... failed
+concave.cs.unb.ca s390x server image (bricklin) ... failed
+concave.cs.unb.ca overall ... failed
+"""]]
+
+

Added a comment: In this case I really should make a package
diff --git a/doc/forum/installing_small_binary_files/comment_1_7537a56c67658ad47460a3b80690ecfd._comment b/doc/forum/installing_small_binary_files/comment_1_7537a56c67658ad47460a3b80690ecfd._comment
new file mode 100644
index 00000000..95a11dae
--- /dev/null
+++ b/doc/forum/installing_small_binary_files/comment_1_7537a56c67658ad47460a3b80690ecfd._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="david"
+ avatar="http://cdn.libravatar.org/avatar/22c2d800db6a7699139df604a67cb221"
+ subject="In this case I really should make a package"
+ date="2018-10-04T10:19:35Z"
+ content="""
+After some reflection I realized that have propellor drop things in /usr/share/qemu is just going to make me sad in the long run. I still think the general question is potentially useful, but I guess it's a bit hypothetical at this point.
+"""]]

diff --git a/doc/forum/installing_small_binary_files.mdwn b/doc/forum/installing_small_binary_files.mdwn
new file mode 100644
index 00000000..080f49a1
--- /dev/null
+++ b/doc/forum/installing_small_binary_files.mdwn
@@ -0,0 +1 @@
+I need to install a small firmware file (it's actually free software, but I need it to boot the emulator I could build it with). I could of course make a debian package and put that package in a repo, but that seems like a lot of fuss for a 32k file. OTOH, I'm a bit loathe to use PrivData for this. Anyone care to either suggest a better way, or convince me it's fine to store firmware in PrivData?

Added a comment
diff --git a/doc/forum/configuring_texlive_papersize/comment_1_e4c1bd36c3739d4dd9bf7316c9021a14._comment b/doc/forum/configuring_texlive_papersize/comment_1_e4c1bd36c3739d4dd9bf7316c9021a14._comment
new file mode 100644
index 00000000..ac85d2b3
--- /dev/null
+++ b/doc/forum/configuring_texlive_papersize/comment_1_e4c1bd36c3739d4dd9bf7316c9021a14._comment
@@ -0,0 +1,20 @@
+[[!comment format=mdwn
+ username="spwhitton"
+ avatar="http://cdn.libravatar.org/avatar/9c3f08f80e67733fd506c353239569eb"
+ subject="comment 1"
+ date="2018-09-18T22:17:07Z"
+ content="""
+I have this (the laptop is otherwise en_GB):
+
+    -- iris is in the US
+    & \"en_US.UTF-8\" `Locale.selectedFor`
+    	[ \"LC_PAPER\"
+    	, \"LC_ADDRESS\"
+    	, \"LC_MONETARY\"
+    	, \"LC_TELEPHONE\"
+    	, \"LC_TIME\"
+    	]
+    & \"/etc/papersize\" `File.hasContent` [\"letter\"]
+    	`onChange` Apt.reConfigure \"libpaper1\" []
+
+"""]]

Added a comment
diff --git a/doc/forum/Adding_support_for_a_SQL_server/comment_7_054a8fa511b28ba6a299e3dfd9ed4dd6._comment b/doc/forum/Adding_support_for_a_SQL_server/comment_7_054a8fa511b28ba6a299e3dfd9ed4dd6._comment
new file mode 100644
index 00000000..ca5cf43d
--- /dev/null
+++ b/doc/forum/Adding_support_for_a_SQL_server/comment_7_054a8fa511b28ba6a299e3dfd9ed4dd6._comment
@@ -0,0 +1,10 @@
+[[!comment format=mdwn
+ username="Nicolas.Schodet"
+ avatar="http://cdn.libravatar.org/avatar/0d7ec808ec329d04ee9a93c0da3c0089"
+ subject="comment 7"
+ date="2018-09-17T21:57:48Z"
+ content="""
+Database is a database name.
+
+I will make the change as soon as I have some time, thanks for the review!
+"""]]

diff --git a/doc/forum/configuring_texlive_papersize.mdwn b/doc/forum/configuring_texlive_papersize.mdwn
new file mode 100644
index 00000000..1890887d
--- /dev/null
+++ b/doc/forum/configuring_texlive_papersize.mdwn
@@ -0,0 +1 @@
+I just observed that installing texlive via propellor means I have A4 paper chose as a default. Which is all very good from an ideological point of view, but it means I can't submit this grant application ;).  Is it worth having a propellor property that runs paperconfig?

comment
diff --git a/doc/todo/Apt.trustsKey_should_not_invoke_apt-key/comment_1_49003d4fdd0e75d477415cb0bb6bbd3c._comment b/doc/todo/Apt.trustsKey_should_not_invoke_apt-key/comment_1_49003d4fdd0e75d477415cb0bb6bbd3c._comment
new file mode 100644
index 00000000..67ad5260
--- /dev/null
+++ b/doc/todo/Apt.trustsKey_should_not_invoke_apt-key/comment_1_49003d4fdd0e75d477415cb0bb6bbd3c._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 1"""
+ date="2018-09-17T18:16:56Z"
+ content="""
+Fine by me as long as it cleans up or overwrites the file that apt-key
+installed earlier.
+"""]]

review
diff --git a/doc/forum/Adding_support_for_a_SQL_server/comment_6_8ebb3d150b06c086d8ad45b9d994877f._comment b/doc/forum/Adding_support_for_a_SQL_server/comment_6_8ebb3d150b06c086d8ad45b9d994877f._comment
new file mode 100644
index 00000000..bd924fed
--- /dev/null
+++ b/doc/forum/Adding_support_for_a_SQL_server/comment_6_8ebb3d150b06c086d8ad45b9d994877f._comment
@@ -0,0 +1,41 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 6"""
+ date="2018-09-17T17:21:52Z"
+ content="""
+Some review, sorry it took me so long to take a look at it..
+
+It's not clear to me how to construct a `Database`;
+what is the `String` inside it? The path? A database name?
+What makes for a legal or illegal database name?
+(May be more obvious to people who use mysql than to me.)
+
+Looks like `Show Privilege` is being used to generate configuration.
+I dislike using `Show` for that, because it precludes it being used with
+Read, and is generally unclear that the strings in show need to be
+formatted exactly as they are.
+
+You could simplify allPrivileges using `Enum`,
+with `[minBound..maxBound]`.
+
+Reverting `databaseExists` and also reverting `installed`
+leads to the package being installed and then removed repeatedly.
+Perhaps `databaseExists` could avoid doing anything when the
+server has already been removed.
+
+Some of the SQL construction doesn't seem entirely safe with quoting.
+While there's no security problem with it, it may have a correctness
+problem..
+
+... In `userGrantedOnDatabase` when it creates the privLevel
+it looks like it doesn't escape the dbname at all,
+and I guess this means it doesn't need to be escaped, or
+can't contain back quotes.
+
+... In `userGranted'` the quser is delimited by single quotes,
+but it's actually valid to have a `User` with a single quote in their name,
+and many of the Klingons out there probably depend on that.
+
+... In `hashPassword` it looks like the password is also assumed to not
+contain single quotes.
+"""]]

todo
diff --git a/doc/todo/apt_mark_support.mdwn b/doc/todo/apt_mark_support.mdwn
new file mode 100644
index 00000000..50591222
--- /dev/null
+++ b/doc/todo/apt_mark_support.mdwn
@@ -0,0 +1,27 @@
+I'd like a property that removes all packages that were not installed by
+the current set of propellor properties. For systems that are fully
+specified by propellor, this would keep the cruft from piling up.
+
+This could be done using apt-mark. Before propellor installs anything with
+apt, go through the apt-mark list and set all packages to auto. When apt is
+run to install a package, it will mark it as manually installed. Since
+Apt.installed skips running apt when packages are already installed, it
+would need to either be changed to run apt anyway, or to run apt-mark
+manual. And then after all other properties, run apt-get autoremove.
+
+Running the autoremove at the end is supported by the propellor monad,
+but there's currently no way to run something before all properties.
+The first Apt.install to run could handle the apt-mark-list-to-auto part,
+although there's also not currently any state for the property to keep
+track of if it's run before.
+
+It would also be possible to not do the apt-mark at the beginning. Instead,
+make the Propellor monad a Writer (polymorphized somehow perhaps like Info
+is) and have Apt.install track the packages that are installed. (Or it
+could be changed to a HasInfo property, and then the list of packages would
+accumulate in Info, but there are likely things that use Apt.installed
+inside ensureProperty which that would cause problems for.) 
+
+Either way, an action run at the end can then update the apt-mark data to
+reflect the gathered list of packages, and run apt-get autoremove.
+--[[Joey]]

Added a comment
diff --git a/doc/forum/bind_mounting_in_Sbuild_chroots/comment_1_0f41fc776bb0d595af239f087e5a1d35._comment b/doc/forum/bind_mounting_in_Sbuild_chroots/comment_1_0f41fc776bb0d595af239f087e5a1d35._comment
new file mode 100644
index 00000000..71927311
--- /dev/null
+++ b/doc/forum/bind_mounting_in_Sbuild_chroots/comment_1_0f41fc776bb0d595af239f087e5a1d35._comment
@@ -0,0 +1,12 @@
+[[!comment format=mdwn
+ username="spwhitton"
+ avatar="http://cdn.libravatar.org/avatar/9c3f08f80e67733fd506c353239569eb"
+ subject="comment 1"
+ date="2018-09-08T16:54:24Z"
+ content="""
+You could use
+
+    & File.containsLine \"/etc/schroot/sbuild/fstab\" \"...\"
+
+but yes, I think it's cleaner to use the sbuild chroots only for building, and for interactive use some other chroot.
+"""]]

diff --git a/doc/forum/bind_mounting_in_Sbuild_chroots.mdwn b/doc/forum/bind_mounting_in_Sbuild_chroots.mdwn
new file mode 100644
index 00000000..f2fb8e11
--- /dev/null
+++ b/doc/forum/bind_mounting_in_Sbuild_chroots.mdwn
@@ -0,0 +1,2 @@
+I typically bind mount some user writable directory into an Sbuild chroot, so that I can e.g. access in a git repo or package to install.
+Is there a clean way to do this with propellor's Sbuild module, or is the intent maintain a seperate container / chroot of some kind for interactive debugging?

create new bug
diff --git a/doc/todo/Apt.trustsKey_should_not_invoke_apt-key.mdwn b/doc/todo/Apt.trustsKey_should_not_invoke_apt-key.mdwn
new file mode 100644
index 00000000..d2f9e6db
--- /dev/null
+++ b/doc/todo/Apt.trustsKey_should_not_invoke_apt-key.mdwn
@@ -0,0 +1,9 @@
+[Over at the Debian BTS](https://bugs.debian.org/907290), David Bremner points out that the apt-key manpage, on Debian stable, says
+
+> Instead of using this [add] [sub]command a keyring should be placed
+> directly in the /etc/apt/trusted.gpg.d/ directory with a
+> descriptive name and either "gpg" or "asc" as file extension.
+
+So ISTM that `Apt.trustsKey` should be implemented simply with `File.hasContents`, i.e., the property should delete any old `.gpg` file and then create a `.asc` file with the text  string content of the `AptKey`.
+
+--spwhitton

Added a comment
diff --git a/doc/forum/Adding_support_for_a_SQL_server/comment_5_10eb776b64b213ca8f8166aacfba9a4d._comment b/doc/forum/Adding_support_for_a_SQL_server/comment_5_10eb776b64b213ca8f8166aacfba9a4d._comment
new file mode 100644
index 00000000..df119fe7
--- /dev/null
+++ b/doc/forum/Adding_support_for_a_SQL_server/comment_5_10eb776b64b213ca8f8166aacfba9a4d._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="Nicolas.Schodet"
+ avatar="http://cdn.libravatar.org/avatar/0d7ec808ec329d04ee9a93c0da3c0089"
+ subject="comment 5"
+ date="2018-08-31T20:53:01Z"
+ content="""
+Also added a function to grant global privileges, useful for a backup user.
+"""]]

Added a comment
diff --git a/doc/forum/Adding_support_for_a_SQL_server/comment_4_22895a34904df9023fcdac0b3937a7c5._comment b/doc/forum/Adding_support_for_a_SQL_server/comment_4_22895a34904df9023fcdac0b3937a7c5._comment
new file mode 100644
index 00000000..786da77a
--- /dev/null
+++ b/doc/forum/Adding_support_for_a_SQL_server/comment_4_22895a34904df9023fcdac0b3937a7c5._comment
@@ -0,0 +1,16 @@
+[[!comment format=mdwn
+ username="Nicolas.Schodet"
+ avatar="http://cdn.libravatar.org/avatar/0d7ec808ec329d04ee9a93c0da3c0089"
+ subject="comment 4"
+ date="2018-08-30T21:14:32Z"
+ content="""
+Hello,
+
+I have made a first version to support MySQL databases and users for classic web applications.
+
+You can pull the mysql branch at http://git.ni.fr.eu.org/nicolas/propellor.git
+
+Can you have a look? I find userGrantedOnDatabase.setup' a little hard to read. Is it OK, or do you see a clearer way to write it?
+
+Thanks!
+"""]]

Added a comment: OIC
diff --git a/doc/forum/integration_with_gitolite/comment_6_232d8ab023d060d7d9c000e4c6783ef8._comment b/doc/forum/integration_with_gitolite/comment_6_232d8ab023d060d7d9c000e4c6783ef8._comment
new file mode 100644
index 00000000..80130d5b
--- /dev/null
+++ b/doc/forum/integration_with_gitolite/comment_6_232d8ab023d060d7d9c000e4c6783ef8._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="david"
+ avatar="http://cdn.libravatar.org/avatar/22c2d800db6a7699139df604a67cb221"
+ subject="OIC"
+ date="2018-08-27T14:14:09Z"
+ content="""
+Oh, I see now we are doing essentially the same thing. For those of you following along at home, mine is using that cryptic path because for the key because I am using both gitolite's native key handling and propellor to install keys.
+"""]]

Added a comment
diff --git a/doc/forum/integration_with_gitolite/comment_5_1e71a38b32148228b94c7429e721685f._comment b/doc/forum/integration_with_gitolite/comment_5_1e71a38b32148228b94c7429e721685f._comment
new file mode 100644
index 00000000..8a1e6473
--- /dev/null
+++ b/doc/forum/integration_with_gitolite/comment_5_1e71a38b32148228b94c7429e721685f._comment
@@ -0,0 +1,15 @@
+[[!comment format=mdwn
+ username="spwhitton"
+ avatar="http://cdn.libravatar.org/avatar/9c3f08f80e67733fd506c353239569eb"
+ subject="comment 5"
+ date="2018-08-26T17:14:20Z"
+ content="""
+It's these lines:
+
+	-- make my SSH key available to gitolite
+	& File.hasContent \"/srv/git/.gitolite/keydir/spwhitton.pub\"
+		[SPW.mySSHKey]
+	`onChange` (userScriptProperty (User \"git\")
+		[\"gitolite compile\", \"gitolite trigger POST_COMPILE\"]
+		`assume` MadeChange)
+"""]]

comment
diff --git a/doc/forum/making_sure_a_package_is_at_the_latest_version/comment_3_48fe0419c259c9555b6349c3221a80a0._comment b/doc/forum/making_sure_a_package_is_at_the_latest_version/comment_3_48fe0419c259c9555b6349c3221a80a0._comment
new file mode 100644
index 00000000..ae45baec
--- /dev/null
+++ b/doc/forum/making_sure_a_package_is_at_the_latest_version/comment_3_48fe0419c259c9555b6349c3221a80a0._comment
@@ -0,0 +1,10 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 3"""
+ date="2018-08-26T15:14:50Z"
+ content="""
+One approach would be to have a property like spwhitton suggests,
+and use it with the `Apt.robustly` combinator. That way, when you update
+the config to specify a new package version, and apt fails to install it,
+propellor will run apt update and then retry the install.
+"""]]

comment
diff --git a/doc/todo/spin_failure_HEAD/comment_4_684adfe4d134b4e27ed00db62f8e3372._comment b/doc/todo/spin_failure_HEAD/comment_4_684adfe4d134b4e27ed00db62f8e3372._comment
new file mode 100644
index 00000000..3f6aebcb
--- /dev/null
+++ b/doc/todo/spin_failure_HEAD/comment_4_684adfe4d134b4e27ed00db62f8e3372._comment
@@ -0,0 +1,43 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 4"""
+ date="2018-08-26T14:50:22Z"
+ content="""
+As far as I know, this was fixed in a series of commits,
+[[!commit 01fc1375cece096ab2dec480b843ecdbc4f0d94e]]
+[[!commit 1555c6f88a0446d3e29149eff8315817696731e1]]
+[[!commit 53fe5ffaac4a243bb9fd3cf0e757128150a6a199]]
+
+The problem was intermittent for me, I think based on network timing and
+different buffering behavior with different timings,
+which made it hard to debug, but I've not seen it since and I was seeing it
+frequently enough to be fairly sure I fixed it.
+
+So I wonder if you might have some sort of version skew issue on the host
+being spun (eg, it could have an old version of propellor installed and be
+failing before spin can update it to the fixed version). The easy way to
+verify you have the fixed version is to run `git config propellor.debug 1`
+in /usr/local/propellor/ on the host being spun, and look for
+"--upload-pack ./propellor --gitpush" in a debug message.
+
+If you're confident the remote propellor has the above commits in it,
+you're going to need to do some debugging.
+Setting `GIT_TRACE_PACKET=1` on the remote system was very helpful in
+understanding the problem, and should probably be your first step.
+Setting that environment inside Propellor.Spin.gitPullFromUpdateServer
+should work, of course you'll have to get the remote host to build
+propellor with that change somehow despite --spin to it not working.
+
+	diff --git a/src/Propellor/Spin.hs b/src/Propellor/Spin.hs
+	index 4a945e82..aa73e3b7 100644
+	--- a/src/Propellor/Spin.hs
+	+++ b/src/Propellor/Spin.hs
+	@@ -359,6 +359,7 @@ spinCommitMessage = "propellor spin"
+	 -- to receive the data.
+	 gitPullFromUpdateServer :: IO ()
+	 gitPullFromUpdateServer = req NeedGitPush gitPushMarker $ \_ -> do
+	+	setEnv "GIT_TRACE_PACKET" "1" True
+	 	-- IO involving stdin can cause data to be buffered in the Handle
+ 		-- (even when it's set NoBuffering), but we need to pass a FD to
+	 	-- git fetch containing all of stdin after the gitPushMarker,
+"""]]

fix html
diff --git a/doc/todo/spin_failure_HEAD.mdwn b/doc/todo/spin_failure_HEAD.mdwn
index 1a591b35..e49df633 100644
--- a/doc/todo/spin_failure_HEAD.mdwn
+++ b/doc/todo/spin_failure_HEAD.mdwn
@@ -81,7 +81,7 @@ Sending privdata (73139 bytes) to kite.kitenet.net ... done
 [2017-06-18 16:31:16 EDT] received marked GITPUSH
 [2017-06-18 16:31:16 EDT] command line:  GitPush 11 12
 16:31:16.361717 pkt-line.c:80           packet:        fetch< 17abde8439d17d49676f549f357f45eb2adce868 refs/remotes/db48x/master
-<pre>
+</pre>
 
 > > So there's an actual protocol error here; the first 13 lines
 > > of git protocol were not sent.

response
diff --git a/doc/forum/can__39__t_get_Apt.trustsKey_to_work/comment_3_1aa2a2c87eab63305143768575c2f0d9._comment b/doc/forum/can__39__t_get_Apt.trustsKey_to_work/comment_3_1aa2a2c87eab63305143768575c2f0d9._comment
new file mode 100644
index 00000000..f76ac16c
--- /dev/null
+++ b/doc/forum/can__39__t_get_Apt.trustsKey_to_work/comment_3_1aa2a2c87eab63305143768575c2f0d9._comment
@@ -0,0 +1,15 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 3"""
+ date="2018-08-26T14:34:18Z"
+ content="""
+@david, you might need to edit your config.cabal and specify a newer
+propellor version, although cabal usually picks the most recent version of
+a dependency. Propellor got the patch from this page in version 5.3.4.
+
+Anyway, I don't think the version of propellor matters, the error message
+you quote is related to
+<https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=844724>.
+I think that the apt key you're using has been generated on a newer system
+and won't work with older gpg.
+"""]]

Added a comment: pulling from a central repo via ssh
diff --git a/doc/forum/--spin_tries_to_pull_from_central_repository__63__/comment_4_75a0a229527a7c0c1633b4bd8e461607._comment b/doc/forum/--spin_tries_to_pull_from_central_repository__63__/comment_4_75a0a229527a7c0c1633b4bd8e461607._comment
new file mode 100644
index 00000000..e60cd5bb
--- /dev/null
+++ b/doc/forum/--spin_tries_to_pull_from_central_repository__63__/comment_4_75a0a229527a7c0c1633b4bd8e461607._comment
@@ -0,0 +1,27 @@
+[[!comment format=mdwn
+ username="david"
+ avatar="http://cdn.libravatar.org/avatar/22c2d800db6a7699139df604a67cb221"
+ subject="pulling from a central repo via ssh"
+ date="2018-08-25T18:50:39Z"
+ content="""
+I ended up updating to a more recent propellor for other reasons, but here's my hack to have propellor fetch over ssh:
+[[!format haskell \"\"\"
+rootSsh :: Property (HasInfo + UnixLike)
+rootSsh = propertyList \"ssh setup for root\" $ props
+  & Ssh.userKeyAt (Just keypath) (User \"root\") (Context \"propellor\") (SshRsa, Tethera.Keys.propellor_deploy_ssh)
+  & Ssh.knownHost hosts \"gitolite.tethera.net\" (User \"root\")
+  & File.containsBlock configpath [ \"Host propellor-deploy\"
+                               , \"     Hostname gitolite.tethera.net\"
+                               , \"     User git\"
+                               , \"     IdentityFile ~/.ssh/propellor_deploy\"
+                               ]
+  where
+    keypath = \"/root/.ssh/propellor_deploy\"
+    configpath = \"/root/.ssh/config\"
+\"\"\"]]
+
+Propellor is used to initially deply a passwordless role key that can be used to pull from the central repo.
+One thing that surprised me a bit is that Ssh.userKeyAt expects an absolute path, or a path relative to /usr/local/propellor.
+
+
+"""]]

Added a comment: version 2
diff --git a/doc/forum/integration_with_gitolite/comment_4_448d79859b2b35e1731adfaa460aa844._comment b/doc/forum/integration_with_gitolite/comment_4_448d79859b2b35e1731adfaa460aa844._comment
new file mode 100644
index 00000000..2aaacf0b
--- /dev/null
+++ b/doc/forum/integration_with_gitolite/comment_4_448d79859b2b35e1731adfaa460aa844._comment
@@ -0,0 +1,33 @@
+[[!comment format=mdwn
+ username="david"
+ avatar="http://cdn.libravatar.org/avatar/22c2d800db6a7699139df604a67cb221"
+ subject="version 2"
+ date="2018-08-25T17:25:03Z"
+ content="""
+I didn't see how you were handling keys, Sean. Did I miss something obvious or are you handling them outside propellor?
+
+Anyway, here's my second version
+[[!format haskell \"\"\"
+gitoliteKeys :: User -> [(FilePath, String)] -> Property UnixLike
+gitoliteKeys user@(User username) keys = property' (\"set up gitolite keys for \" ++ username) $ \w -> do
+      home <- liftIO (User.homedir user)
+      ensureProperty w $ go home
+  where
+    go :: FilePath -> Property UnixLike
+    go home = installKeys keys
+                `onChange` recompile
+                `requires` File.dirExists keydir
+        where
+          keydir = home </> \".gitolite/keydir/zzz/propellor\"
+          recompile = Cmd.userScriptProperty user [ \"gitolite trigger POST_COMPILE\" ]
+                      `changesFile` (home </> \"gitolite/.ssh/authorized_keys\")
+          installKeys :: [(FilePath, String)] -> Property UnixLike
+          installKeys [] = doNothing
+          installKeys ((path, content):rest) = File.hasContent (keydir </> path ++ \".pub\") [content]
+                                               `before` installKeys rest
+\"\"\"]]
+
+I spent a while talking to the gitolite author, and managed to write something more optimal than \"gitolite trigger POST_COMPILE\", but then I realized that
+had my username hardcoded into it. So it takes about 1s longer to run, but is more robust this way.
+
+"""]]

removed
diff --git a/doc/forum/integration_with_gitolite/comment_4_acaa1d125ea406c2a5617a4effc4b115._comment b/doc/forum/integration_with_gitolite/comment_4_acaa1d125ea406c2a5617a4effc4b115._comment
deleted file mode 100644
index 3a02b96e..00000000
--- a/doc/forum/integration_with_gitolite/comment_4_acaa1d125ea406c2a5617a4effc4b115._comment
+++ /dev/null
@@ -1,33 +0,0 @@
-[[!comment format=mdwn
- username="david"
- avatar="http://cdn.libravatar.org/avatar/22c2d800db6a7699139df604a67cb221"
- subject="getting closer"
- date="2018-08-25T17:16:48Z"
- content="""
-maybe I suffer from Haskell blindness, but I didn't see how you handled keys
-
-here's my latest revision
-[[!format haskell \"\"\"
-gitoliteKeys :: User -> [(FilePath, String)] -> Property UnixLike
-gitoliteKeys user@(User username) keys = property' (\"set up gitolite keys for \" ++ username) $ \w -> do
-      home <- liftIO (User.homedir user)
-      ensureProperty w $ go home
-  where
-    go :: FilePath -> Property UnixLike
-    go home = installKeys keys
-                `onChange` recompile
-                `requires` File.dirExists keydir
-        where
-          keydir = home </> \".gitolite/keydir/zzz/propellor\"
-          recompile = Cmd.userScriptProperty user [ \"gitolite ../triggers/post-compile/ssh-authkeys\"
-                                                  , \"gitolite ../triggers/post-compile/ssh-authkeys-shell-users bremner\"
-                                                  ]
-                      `changesFile` (home </> \"gitolite/.ssh/authorized_keys\")
-          installKeys :: [(FilePath, String)] -> Property UnixLike
-          installKeys [] = doNothing
-          installKeys ((path, content):rest) = File.hasContent (keydir </> path ++ \".pub\") [content]
-                                               `before` installKeys rest
-\"\"\"]]
-
-It still has one piece of hardcoding in it (the shell user bremner)
-"""]]

Added a comment: getting closer
diff --git a/doc/forum/integration_with_gitolite/comment_4_acaa1d125ea406c2a5617a4effc4b115._comment b/doc/forum/integration_with_gitolite/comment_4_acaa1d125ea406c2a5617a4effc4b115._comment
new file mode 100644
index 00000000..3a02b96e
--- /dev/null
+++ b/doc/forum/integration_with_gitolite/comment_4_acaa1d125ea406c2a5617a4effc4b115._comment
@@ -0,0 +1,33 @@
+[[!comment format=mdwn
+ username="david"
+ avatar="http://cdn.libravatar.org/avatar/22c2d800db6a7699139df604a67cb221"
+ subject="getting closer"
+ date="2018-08-25T17:16:48Z"
+ content="""
+maybe I suffer from Haskell blindness, but I didn't see how you handled keys
+
+here's my latest revision
+[[!format haskell \"\"\"
+gitoliteKeys :: User -> [(FilePath, String)] -> Property UnixLike
+gitoliteKeys user@(User username) keys = property' (\"set up gitolite keys for \" ++ username) $ \w -> do
+      home <- liftIO (User.homedir user)
+      ensureProperty w $ go home
+  where
+    go :: FilePath -> Property UnixLike
+    go home = installKeys keys
+                `onChange` recompile
+                `requires` File.dirExists keydir
+        where
+          keydir = home </> \".gitolite/keydir/zzz/propellor\"
+          recompile = Cmd.userScriptProperty user [ \"gitolite ../triggers/post-compile/ssh-authkeys\"
+                                                  , \"gitolite ../triggers/post-compile/ssh-authkeys-shell-users bremner\"
+                                                  ]
+                      `changesFile` (home </> \"gitolite/.ssh/authorized_keys\")
+          installKeys :: [(FilePath, String)] -> Property UnixLike
+          installKeys [] = doNothing
+          installKeys ((path, content):rest) = File.hasContent (keydir </> path ++ \".pub\") [content]
+                                               `before` installKeys rest
+\"\"\"]]
+
+It still has one piece of hardcoding in it (the shell user bremner)
+"""]]

Added a comment: just needs Apt.update?
diff --git a/doc/forum/making_sure_a_package_is_at_the_latest_version/comment_2_7a911c68e4c81031c98dbefce730ade8._comment b/doc/forum/making_sure_a_package_is_at_the_latest_version/comment_2_7a911c68e4c81031c98dbefce730ade8._comment
new file mode 100644
index 00000000..8e74d21f
--- /dev/null
+++ b/doc/forum/making_sure_a_package_is_at_the_latest_version/comment_2_7a911c68e4c81031c98dbefce730ade8._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="david"
+ avatar="http://cdn.libravatar.org/avatar/22c2d800db6a7699139df604a67cb221"
+ subject="just needs Apt.update?"
+ date="2018-08-25T13:04:50Z"
+ content="""
+Thinking about this a bit more, it should be enough to require Apt.update once per host, then rely on Apt.installed to do the right thing. I'll have to test this next time I roll out a new version. In theory I could run apt.update for a single source, but that seems to be tricky on the apt level.
+"""]]

Added a comment
diff --git a/doc/forum/making_sure_a_package_is_at_the_latest_version/comment_1_6a73c8b0de1999f05af184bf63ad014a._comment b/doc/forum/making_sure_a_package_is_at_the_latest_version/comment_1_6a73c8b0de1999f05af184bf63ad014a._comment
new file mode 100644
index 00000000..98fb61eb
--- /dev/null
+++ b/doc/forum/making_sure_a_package_is_at_the_latest_version/comment_1_6a73c8b0de1999f05af184bf63ad014a._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="spwhitton"
+ avatar="http://cdn.libravatar.org/avatar/9c3f08f80e67733fd506c353239569eb"
+ subject="comment 1"
+ date="2018-08-24T23:12:17Z"
+ content="""
+The existing properties cannot do what you want.  You are going to need to write a new one.  Simplest implementation would be something that calls `apt-get install foo=1.2.3`.
+"""]]

Added a comment: definitely network related
diff --git a/doc/todo/spin_failure_HEAD/comment_3_952939a1333d6fc24ed288a80b76f168._comment b/doc/todo/spin_failure_HEAD/comment_3_952939a1333d6fc24ed288a80b76f168._comment
new file mode 100644
index 00000000..98d7f18b
--- /dev/null
+++ b/doc/todo/spin_failure_HEAD/comment_3_952939a1333d6fc24ed288a80b76f168._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="david"
+ avatar="http://cdn.libravatar.org/avatar/22c2d800db6a7699139df604a67cb221"
+ subject="definitely network related"
+ date="2018-08-24T13:58:49Z"
+ content="""
+I can spin the same host from a different host on the office LAN (in fact they are connected to a cheapo hub, so that might not be much of a test), and from itself. So I guess it definitely has to do with networking. Does propellor need anything other than port 22 open?
+"""]]

Added a comment: still in 5.4.1, but only on one machine
diff --git a/doc/todo/spin_failure_HEAD/comment_2_a9b7013305a7f8d58175510b57bbadd2._comment b/doc/todo/spin_failure_HEAD/comment_2_a9b7013305a7f8d58175510b57bbadd2._comment
new file mode 100644
index 00000000..a8866294
--- /dev/null
+++ b/doc/todo/spin_failure_HEAD/comment_2_a9b7013305a7f8d58175510b57bbadd2._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="david"
+ avatar="http://cdn.libravatar.org/avatar/22c2d800db6a7699139df604a67cb221"
+ subject="still in 5.4.1, but only on one machine"
+ date="2018-08-24T10:11:16Z"
+ content="""
+I updated to 5.4.1, and I still consistenly see this trying to spin my office computer from home. Weirdly a VM running Debian stretch on the same network does not repropduce. I'll have to try from a different machine on the office network to see if that makes a difference.
+"""]]

Added a comment: still in 5.3.6
diff --git a/doc/todo/spin_failure_HEAD/comment_1_9c7d9ae7860d9cfc28e7d015b015dc2e._comment b/doc/todo/spin_failure_HEAD/comment_1_9c7d9ae7860d9cfc28e7d015b015dc2e._comment
new file mode 100644
index 00000000..8fb8a027
--- /dev/null
+++ b/doc/todo/spin_failure_HEAD/comment_1_9c7d9ae7860d9cfc28e7d015b015dc2e._comment
@@ -0,0 +1,9 @@
+[[!comment format=mdwn
+ username="david@1439a1cab13195a56248b6a8fd98a62028bcba8a"
+ nickname="david"
+ avatar="http://cdn.libravatar.org/avatar/22c2d800db6a7699139df604a67cb221"
+ subject="still in 5.3.6"
+ date="2018-08-24T02:12:44Z"
+ content="""
+I'm seeing this problem in 5.3.6, but only when the remote is Debian stable. Both ends are running 5.3.6 built from source.
+"""]]

Added a comment: GPG keybox database version 1
diff --git a/doc/forum/can__39__t_get_Apt.trustsKey_to_work/comment_2_d5d1611896fa72bda22e5406285ade2e._comment b/doc/forum/can__39__t_get_Apt.trustsKey_to_work/comment_2_d5d1611896fa72bda22e5406285ade2e._comment
new file mode 100644
index 00000000..90151369
--- /dev/null
+++ b/doc/forum/can__39__t_get_Apt.trustsKey_to_work/comment_2_d5d1611896fa72bda22e5406285ade2e._comment
@@ -0,0 +1,9 @@
+[[!comment format=mdwn
+ username="david"
+ avatar="http://cdn.libravatar.org/avatar/22c2d800db6a7699139df604a67cb221"
+ subject=" GPG keybox database version 1"
+ date="2018-08-24T00:29:50Z"
+ content="""
+I have propellor 5.3.6 running on debian testing. If I spin to the testing host, trustsKey works fine. On stretch I get at 'GPG keybox database version 1' installed. I guess on stretch it's still building propellor from the old sources? In any case, gpg doesn't know what do do with that keybox file (i.e. gpg < file craps out). Weird but true. In any case this breaks apt-key on that host, which is unfortunate. I guess I'll try overriding the trustsKey function in my config.hs
+
+"""]]

Added a comment: Still biting me
diff --git a/doc/forum/--spin_tries_to_pull_from_central_repository__63__/comment_3_6f6485b10beb3e371c6f5371a9a9c2c4._comment b/doc/forum/--spin_tries_to_pull_from_central_repository__63__/comment_3_6f6485b10beb3e371c6f5371a9a9c2c4._comment
new file mode 100644
index 00000000..6b32f1bb
--- /dev/null
+++ b/doc/forum/--spin_tries_to_pull_from_central_repository__63__/comment_3_6f6485b10beb3e371c6f5371a9a9c2c4._comment
@@ -0,0 +1,10 @@
+[[!comment format=mdwn
+ username="david@1439a1cab13195a56248b6a8fd98a62028bcba8a"
+ nickname="david"
+ avatar="http://cdn.libravatar.org/avatar/22c2d800db6a7699139df604a67cb221"
+ subject="Still biting me"
+ date="2018-08-23T20:32:18Z"
+ content="""
+I have a similar problem with inaccessible central repo. This crash is still biting me when spinning from a Debian stable (stretch) host to itself.
+I could potentially make the central repo accessible via adding a key, but I think the pull is too early in the process for that work out. Any other ideas? Can I just turn off this pull for some hosts?
+"""]]

Added a comment
diff --git a/doc/forum/integration_with_gitolite/comment_3_394a42544ad97e30a8e28ed10de7cd3c._comment b/doc/forum/integration_with_gitolite/comment_3_394a42544ad97e30a8e28ed10de7cd3c._comment
new file mode 100644
index 00000000..1cab310c
--- /dev/null
+++ b/doc/forum/integration_with_gitolite/comment_3_394a42544ad97e30a8e28ed10de7cd3c._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="spwhitton"
+ avatar="http://cdn.libravatar.org/avatar/9c3f08f80e67733fd506c353239569eb"
+ subject="comment 3"
+ date="2018-08-23T19:59:13Z"
+ content="""
+It's not a proper module, but my gitolite setup is here: https://git.spwhitton.name/propellor/tree/src/Propellor/Property/SiteSpecific/SPW/Sites.hs#n200
+"""]]

Added a comment: first attempt
diff --git a/doc/forum/integration_with_gitolite/comment_2_42d3e861e2044479523609ff7b339f6b._comment b/doc/forum/integration_with_gitolite/comment_2_42d3e861e2044479523609ff7b339f6b._comment
new file mode 100644
index 00000000..ab7cc893
--- /dev/null
+++ b/doc/forum/integration_with_gitolite/comment_2_42d3e861e2044479523609ff7b339f6b._comment
@@ -0,0 +1,29 @@
+[[!comment format=mdwn
+ username="david@1439a1cab13195a56248b6a8fd98a62028bcba8a"
+ nickname="david"
+ avatar="http://cdn.libravatar.org/avatar/22c2d800db6a7699139df604a67cb221"
+ subject="first attempt"
+ date="2018-08-23T13:36:52Z"
+ content="""
+Here's my first attempt, so you can snicker at my clumsy Haskell.
+
+<pre>
+gitoliteKeys :: User -> Property UnixLike
+gitoliteKeys user@(User username) = property' (\"set up gitolite keys for \" ++ username) $ \w -> do
+      home <- liftIO (User.homedir user)
+      ensureProperty w $ go home
+  where
+    go :: FilePath -> Property UnixLike
+    go home = File.hasContent (home </> \".gitolite/keydir/zzz/propellor\" </> \"bremner@propellor.pub\")
+                        [ Tethera.Keys.bremner_ssh ]
+              `before`
+              (Cmd.userScriptProperty user [ \"gitolite compile\", \"gitolite trigger POST_COMPILE\" ]
+                           `changesFile` (home </> \"gitolite/.ssh/authorized_keys\"))
+</pre>
+
+
+I think the next step is something like 
+<pre>
+Directory.hasContent :: FilePath -> [ (FilePath, [Line]) ] -> Property UnixLike
+</pre>
+"""]]

Added a comment: "For people who use puppet and similar systems"
diff --git a/doc/forum/integration_with_gitolite/comment_1_b2989bbf9e980ceebf2f4cccd4d379e1._comment b/doc/forum/integration_with_gitolite/comment_1_b2989bbf9e980ceebf2f4cccd4d379e1._comment
new file mode 100644
index 00000000..2432b063
--- /dev/null
+++ b/doc/forum/integration_with_gitolite/comment_1_b2989bbf9e980ceebf2f4cccd4d379e1._comment
@@ -0,0 +1,11 @@
+[[!comment format=mdwn
+ username="david@1439a1cab13195a56248b6a8fd98a62028bcba8a"
+ nickname="david"
+ avatar="http://cdn.libravatar.org/avatar/22c2d800db6a7699139df604a67cb221"
+ subject="&quot;For people who use puppet and similar systems&quot;"
+ date="2018-08-23T01:46:30Z"
+ content="""
+Probably the sane way is to [not use the gitolite-admin repo](http://gitolite.com/gitolite/odds-and-ends/#administering-gitolite-directly-on-the-server). Aside from being unfamiliar, that means I have to deal with a bunch small config files (say 50 - 100) in propellor. So far I'm not loving the idea of converting them all to Haskell, even with a script. But maybe I'll come around to it.
+
+
+"""]]

diff --git a/doc/forum/integration_with_gitolite.mdwn b/doc/forum/integration_with_gitolite.mdwn
new file mode 100644
index 00000000..956d35c3
--- /dev/null
+++ b/doc/forum/integration_with_gitolite.mdwn
@@ -0,0 +1,2 @@
+Does anyone have any experience with integrating propellor and gitolite? I'd be happy with just ssh pubkey management.
+There seem to be two main options. The typical way of managing a gitolite site is by pushing a special git repository "gitolite-admin". There are also a script called [ukm](http://gitolite.com/gitolite/ukm.html). I'm not sure what will be the least hassle. Currently I have to manually commit and push various keys (including the keys needed for access to the propellor repos). Part of the problem could be solved by making the propellor repos available anonymously, but I still have my own ssh key(s) to manage.

removed
diff --git a/doc/forum/spinning_localhost.mdwn b/doc/forum/spinning_localhost.mdwn
deleted file mode 100644
index ac8b4d50..00000000
--- a/doc/forum/spinning_localhost.mdwn
+++ /dev/null
@@ -1 +0,0 @@
-I have several machines that don't have internet facing domain-names / IP addresses. They can pull, but they (easily) can't be pushed to. I guess I can manually spin them (or run cron jobs). I guess I need to manually add a unique hostname to each /etc/hosts, which sounds like a job for propellor, not for a human. Does anyone have any good setups to share for this kind of scenario? 

diff --git a/doc/forum/spinning_localhost.mdwn b/doc/forum/spinning_localhost.mdwn
new file mode 100644
index 00000000..ac8b4d50
--- /dev/null
+++ b/doc/forum/spinning_localhost.mdwn
@@ -0,0 +1 @@
+I have several machines that don't have internet facing domain-names / IP addresses. They can pull, but they (easily) can't be pushed to. I guess I can manually spin them (or run cron jobs). I guess I need to manually add a unique hostname to each /etc/hosts, which sounds like a job for propellor, not for a human. Does anyone have any good setups to share for this kind of scenario? 

rename forum/versioned_depends.mdwn to forum/making_sure_a_package_is_at_the_latest_version.mdwn
diff --git a/doc/forum/versioned_depends.mdwn b/doc/forum/making_sure_a_package_is_at_the_latest_version.mdwn
similarity index 100%
rename from doc/forum/versioned_depends.mdwn
rename to doc/forum/making_sure_a_package_is_at_the_latest_version.mdwn

diff --git a/doc/forum/versioned_depends.mdwn b/doc/forum/versioned_depends.mdwn
new file mode 100644
index 00000000..5eff9424
--- /dev/null
+++ b/doc/forum/versioned_depends.mdwn
@@ -0,0 +1,13 @@
+The following property sets up my wacky outbound mail setup.
+<pre>
+smtpLeaf :: Property (HasInfo + DebianLike)
+smtpLeaf = propertyList "smtp leaf node" $ props
+         & Apt.installed["nullmailer", "bsd-mailx"]
+         & File.hasPrivContent "/etc/nullmailer/remotes" anyContext
+         & tetheraApt
+         & Apt.installed ["nullmailer-extras"] & Apt.update & Apt.upgrade
+         & Ssh.userKeys (User "mail") anyContext [ (SshRsa, Tethera.Keys.mail_ssh) ]
+         & Ssh.knownHost hosts "smtp.tethera.net" (User "mail")
+</pre>
+
+The "Apt.update & Apt.upgrade" is there because nullmailer-extras is kindof a work in progress and I need to make sure that when I add a new version to the private apt repo it's drawing from, that get's installed. It works but it seems a bit slow, and more importantly upgrading everything is kindof a heavy side effect (which might even break things), in order to update this one package. Is there a better way to do this? Don't assume I know anything, I started using propellor 2 days ago...

Split mailname property out of Hostname.sane
Since bad mailname guesses can lead to ugly surprises. (API change)
Kept it in the Hostname module for easy discoverability, and similar to
Hostname.searchDomain it sets a value based on the hostname so makes sense
to keep it in that module.
Didn't implement the mailname equivilant of Hostname.setTo, because it's
trivial to write the mailname file with a custom value if desired.
This commit was sponsored by John Pellman on Patreon.
diff --git a/debian/changelog b/debian/changelog
index 1da97c15..080884ab 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,6 +1,8 @@
-propellor (5.4.2) UNRELEASED; urgency=medium
+propellor (5.5.0) UNRELEASED; urgency=medium
 
   * letsencrypt': Pass --expand to support expanding the list of domains
+  * Split mailname property out of Hostname.sane, since bad mailname
+    guesses can lead to ugly surprises. (API change)
 
  -- Joey Hess <id@joeyh.name>  Thu, 09 Aug 2018 10:54:41 -0400
 
diff --git a/doc/forum/mailname_set_by_Propellor.Property.Hostname.sane/comment_6_3c962f6aeff10726ae469ca7f48ab34c._comment b/doc/forum/mailname_set_by_Propellor.Property.Hostname.sane/comment_6_3c962f6aeff10726ae469ca7f48ab34c._comment
new file mode 100644
index 00000000..f9666ca1
--- /dev/null
+++ b/doc/forum/mailname_set_by_Propellor.Property.Hostname.sane/comment_6_3c962f6aeff10726ae469ca7f48ab34c._comment
@@ -0,0 +1,7 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 6"""
+ date="2018-08-19T17:22:18Z"
+ content="""
+Ok, did that.
+"""]]
diff --git a/joeyconfig.hs b/joeyconfig.hs
index 4b9fb785..05c93346 100644
--- a/joeyconfig.hs
+++ b/joeyconfig.hs
@@ -66,6 +66,7 @@ darkstar = host "darkstar.kitenet.net" $ props
 	& osDebian Unstable X86_64
 	& ipv6 "2001:4830:1600:187::2"
 	& Hostname.sane
+	& Hostname.mailname
 	& Apt.serviceInstalledRunning "swapspace"
 	& Laptop.powertopAutoTuneOnBoot
 	& Laptop.trimSSD
@@ -461,6 +462,7 @@ keysafe :: Host
 keysafe = host "keysafe.joeyh.name" $ props
 	& ipv4 "139.59.17.168"
 	& Hostname.sane
+	& Hostname.mailname
 	& osDebian (Stable "stretch") X86_64
 	& Apt.stdSourcesList `onChange` Apt.upgrade
 	& Apt.unattendedUpgrades
@@ -565,6 +567,7 @@ standardSystemUnhardened :: DebianSuite -> Architecture -> Motd -> Property (Has
 standardSystemUnhardened suite arch motd = propertyList "standard system" $ props
 	& osDebian suite arch
 	& Hostname.sane
+	& Hostname.mailname
 	& Hostname.searchDomain
 	& Locale.available "en_US.UTF-8"
 	& File.hasContent "/etc/motd" ("":motd++[""])
diff --git a/propellor.cabal b/propellor.cabal
index 26c05a1d..904a8f64 100644
--- a/propellor.cabal
+++ b/propellor.cabal
@@ -1,5 +1,5 @@
 Name: propellor
-Version: 5.4.1
+Version: 5.5.0
 Cabal-Version: 1.20
 License: BSD2
 Maintainer: Joey Hess <id@joeyh.name>
diff --git a/src/Propellor/Property/HostingProvider/CloudAtCost.hs b/src/Propellor/Property/HostingProvider/CloudAtCost.hs
index 48c19572..839aa14e 100644
--- a/src/Propellor/Property/HostingProvider/CloudAtCost.hs
+++ b/src/Propellor/Property/HostingProvider/CloudAtCost.hs
@@ -13,6 +13,7 @@ import qualified Propellor.Property.User as User
 decruft :: Property DebianLike
 decruft = propertyList "cloudatcost cleanup" $ props
 	& Hostname.sane
+	& Hostname.mailname
 	& grubbugfix
 	& nukecruft
   where
diff --git a/src/Propellor/Property/Hostname.hs b/src/Propellor/Property/Hostname.hs
index 1eb9d690..0ece92a8 100644
--- a/src/Propellor/Property/Hostname.hs
+++ b/src/Propellor/Property/Hostname.hs
@@ -14,8 +14,6 @@ import Data.List
 -- (However, when used inside a chroot, avoids setting the current hostname
 -- as that would impact the system outside the chroot.)
 --
--- Configures </etc/mailname> with the domain part of the hostname.
---
 -- </etc/hosts> is also configured, with an entry for 127.0.1.1, which is
 -- standard at least on Debian to set the FDQN.
 --
@@ -46,8 +44,6 @@ setTo' extractdomain hn = combineProperties desc $ toProps
 	, check (not <$> inChroot) $
 		cmdProperty "hostname" [basehost]
 			`assume` NoChange
-	, "/etc/mailname" `File.hasContent`
-		[if null domain then hn else domain]
 	]
   where
 	desc = "hostname " ++ hn
@@ -85,6 +81,19 @@ searchDomain' extractdomain = property' desc $ \w ->
 			| "search " `isPrefixOf` l = False
 			| otherwise = True
 
+-- Configures </etc/mailname> with the domain part of the hostname of the
+-- `Host` it's used in.
+mailname :: Property UnixLike
+mailname = mailname' extractDomain
+
+mailname' :: ExtractDomain -> Property UnixLike
+mailname' extractdomain = property' ("mailname set from hostname") $ \w ->
+	ensureProperty w . go =<< asks hostName
+  where
+	go mn = "/etc/mailname" `File.hasContent` [if null mn' then mn else mn']
+	  where
+	 	mn' = extractdomain mn
+
 -- | Function to extract the domain name from a HostName.
 type ExtractDomain = HostName -> String
 
diff --git a/src/Propellor/Property/Installer/Target.hs b/src/Propellor/Property/Installer/Target.hs
index 8c865143..c6889dc5 100644
--- a/src/Propellor/Property/Installer/Target.hs
+++ b/src/Propellor/Property/Installer/Target.hs
@@ -24,6 +24,7 @@
 -- > seed ver = host "debian.local" $ props
 -- > 	& osDebian Unstable X86_64
 -- > 	& Hostname.sane
+-- >	& Hostname.mailname
 -- > 	& Apt.stdSourcesList
 -- > 	& Apt.installed ["linux-image-amd64"]
 -- > 	& Grub.installed PC
diff --git a/src/Propellor/Property/OS.hs b/src/Propellor/Property/OS.hs
index c31bef7b..503f303d 100644
--- a/src/Propellor/Property/OS.hs
+++ b/src/Propellor/Property/OS.hs
@@ -58,6 +58,7 @@ import Control.Exception (throw)
 -- >        -- , oldOsRemoved (Confirmed "foo.example.com")
 -- >        ]
 -- > & Hostname.sane
+-- > & Hostname.mailname
 -- > & Apt.installed ["linux-image-amd64"]
 -- > & Apt.installed ["ssh"]
 -- > & User.hasSomePassword "root"

Added a comment
diff --git a/doc/forum/Privdata_corrupted_when_spinning_from_macOS/comment_8_39bead6f61bd8e458bf8eaf992757e62._comment b/doc/forum/Privdata_corrupted_when_spinning_from_macOS/comment_8_39bead6f61bd8e458bf8eaf992757e62._comment
new file mode 100644
index 00000000..776e3fba
--- /dev/null
+++ b/doc/forum/Privdata_corrupted_when_spinning_from_macOS/comment_8_39bead6f61bd8e458bf8eaf992757e62._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="mithrandi"
+ avatar="http://cdn.libravatar.org/avatar/869963bdf99b541c9f0bbfb04b0320f1"
+ subject="comment 8"
+ date="2018-08-18T14:19:42Z"
+ content="""
+I tested printing out the encoding after changing it to make sure it was UTF-8, and it is, but the privdata is somehow still corrupt. Could the problem have something to do with writing out the privdata instead?
+"""]]

Added a comment
diff --git a/doc/forum/mailname_set_by_Propellor.Property.Hostname.sane/comment_5_b4c1265f881e96d999528d8a433176cc._comment b/doc/forum/mailname_set_by_Propellor.Property.Hostname.sane/comment_5_b4c1265f881e96d999528d8a433176cc._comment
new file mode 100644
index 00000000..0f1ba25c
--- /dev/null
+++ b/doc/forum/mailname_set_by_Propellor.Property.Hostname.sane/comment_5_b4c1265f881e96d999528d8a433176cc._comment
@@ -0,0 +1,24 @@
+[[!comment format=mdwn
+ username="spwhitton"
+ avatar="http://cdn.libravatar.org/avatar/9c3f08f80e67733fd506c353239569eb"
+ subject="comment 5"
+ date="2018-08-17T14:36:19Z"
+ content="""
+I worked around the problem in the following way:
+
+    module Propellor.Property.SiteSpecific.SPW.Hostname (sane) where
+
+    import Propellor.Base
+    import qualified Propellor.Property.Hostname as Hostname
+
+    sane :: Property UnixLike
+    sane = Hostname.sane' id
+
+> How about we add a separate mailname property and make Hostname.sane not touch the mailname. mailname could take a Maybe and guess based on the hostname when Nothing is specified.
+
+This seems reasonable.  `Hostname.sane` is often wanted but `Mailname.sane` will be wanted only occasionally, so it makes sense for them to be separate properties.
+
+> Or, the mailname property could only set Info, and Hostname.sane use that info when set and guess when not. But, I suspect that would not have avoided your email-losing misconfiguration from happening in the first place.
+
+This wouldn't be much different from my workaround, indeed.
+"""]]

followup
diff --git a/doc/forum/Privdata_corrupted_when_spinning_from_macOS/comment_7_959c8da37727c46436c5905bc6fabd88._comment b/doc/forum/Privdata_corrupted_when_spinning_from_macOS/comment_7_959c8da37727c46436c5905bc6fabd88._comment
new file mode 100644
index 00000000..a0fefc17
--- /dev/null
+++ b/doc/forum/Privdata_corrupted_when_spinning_from_macOS/comment_7_959c8da37727c46436c5905bc6fabd88._comment
@@ -0,0 +1,9 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 7"""
+ date="2018-08-16T15:37:48Z"
+ content="""
+Since `update` receives the changes to propellor's source code,
+it would have been running the old code at that point. You
+probably need to spin a second time to test your changes to that function.
+"""]]

followup
diff --git a/doc/forum/mailname_set_by_Propellor.Property.Hostname.sane/comment_4_2c90ee4cd4fe54299ce9742c28730b9a._comment b/doc/forum/mailname_set_by_Propellor.Property.Hostname.sane/comment_4_2c90ee4cd4fe54299ce9742c28730b9a._comment
new file mode 100644
index 00000000..b67a80d8
--- /dev/null
+++ b/doc/forum/mailname_set_by_Propellor.Property.Hostname.sane/comment_4_2c90ee4cd4fe54299ce9742c28730b9a._comment
@@ -0,0 +1,18 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 4"""
+ date="2018-08-16T15:23:09Z"
+ content="""
+I notice that the property is certianly wrong for domains such as
+"foo.org.uk". And I don't want to build in the list of exceptions needed to
+properly deal with those.
+
+How about we add a separate mailname property and make Hostname.sane not
+touch the mailname. mailname could take a Maybe and guess based on the
+hostname when Nothing is specified.
+
+Or, the mailname property could only set Info, and Hostname.sane
+use that info when set and guess when not. But, I suspect that would not
+have avoided your email-losing misconfiguration from happening in the first
+place.
+"""]]

Added a comment
diff --git a/doc/forum/Privdata_corrupted_when_spinning_from_macOS/comment_6_ce746457c2a7654a090885ad960eb983._comment b/doc/forum/Privdata_corrupted_when_spinning_from_macOS/comment_6_ce746457c2a7654a090885ad960eb983._comment
new file mode 100644
index 00000000..01748242
--- /dev/null
+++ b/doc/forum/Privdata_corrupted_when_spinning_from_macOS/comment_6_ce746457c2a7654a090885ad960eb983._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="mithrandi"
+ avatar="http://cdn.libravatar.org/avatar/869963bdf99b541c9f0bbfb04b0320f1"
+ subject="comment 6"
+ date="2018-08-16T15:35:27Z"
+ content="""
+The `hSetEncoding stdin utf8` in `update` doesn't seem to work unfortunately, not sure why not.
+"""]]

response
diff --git a/doc/forum/Privdata_corrupted_when_spinning_from_macOS/comment_5_f12c57263372437edbcdfe89cd69b95d._comment b/doc/forum/Privdata_corrupted_when_spinning_from_macOS/comment_5_f12c57263372437edbcdfe89cd69b95d._comment
new file mode 100644
index 00000000..51f25ecc
--- /dev/null
+++ b/doc/forum/Privdata_corrupted_when_spinning_from_macOS/comment_5_f12c57263372437edbcdfe89cd69b95d._comment
@@ -0,0 +1,17 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 5"""
+ date="2018-08-16T15:12:58Z"
+ content="""
+Ah, good debugging!
+
+The code that runs on the remote side is Propellor.Spin.update,
+and it uses Propellor.Protocol.req which reads from stdin. So,
+I think that putting `hSetEncoding stdin utf8` in the update function
+may fix it for you.
+
+If so, the real fix will involve making propellor force utf8 on both sides
+of its protocol, because the spin might be run in some other locale too.
+(Or chainging to a binary protocol that doesn't suffer 
+from encoding mismatch problems, if someone is ambitious!)
+"""]]

Added a comment
diff --git a/doc/forum/Privdata_corrupted_when_spinning_from_macOS/comment_4_7f6773e21b9bb62961b0c291d0f8b7d0._comment b/doc/forum/Privdata_corrupted_when_spinning_from_macOS/comment_4_7f6773e21b9bb62961b0c291d0f8b7d0._comment
new file mode 100644
index 00000000..733f7d33
--- /dev/null
+++ b/doc/forum/Privdata_corrupted_when_spinning_from_macOS/comment_4_7f6773e21b9bb62961b0c291d0f8b7d0._comment
@@ -0,0 +1,20 @@
+[[!comment format=mdwn
+ username="mithrandi"
+ avatar="http://cdn.libravatar.org/avatar/869963bdf99b541c9f0bbfb04b0320f1"
+ subject="comment 4"
+ date="2018-08-16T13:12:35Z"
+ content="""
+Err, this patch:
+
+    --- a/src/Propellor/Spin.hs
+    +++ b/src/Propellor/Spin.hs
+    @@ -181,6 +181,8 @@
+     -- running the updateServer
+     update :: Maybe HostName -> IO ()
+     update forhost = do
+    +       hPrint stderr =<< hGetEncoding stdin
+    +       hSetEncoding stdin utf8
+            whenM hasGitRepo $
+                    req NeedRepoUrl repoUrlMarker setRepoUrl
+
+"""]]

Added a comment
diff --git a/doc/forum/Privdata_corrupted_when_spinning_from_macOS/comment_3_c51e4ae44dc6401af54f109f2cb70995._comment b/doc/forum/Privdata_corrupted_when_spinning_from_macOS/comment_3_c51e4ae44dc6401af54f109f2cb70995._comment
new file mode 100644
index 00000000..05b5956b
--- /dev/null
+++ b/doc/forum/Privdata_corrupted_when_spinning_from_macOS/comment_3_c51e4ae44dc6401af54f109f2cb70995._comment
@@ -0,0 +1,23 @@
+[[!comment format=mdwn
+ username="mithrandi"
+ avatar="http://cdn.libravatar.org/avatar/869963bdf99b541c9f0bbfb04b0320f1"
+ subject="comment 3"
+ date="2018-08-15T19:15:21Z"
+ content="""
+I tried this patch:
+
+```
+--- a/src/Propellor/Spin.hs
++++ b/src/Propellor/Spin.hs
+@@ -181,6 +181,8 @@ getSshTarget target hst
+ -- running the updateServer
+ update :: Maybe HostName -> IO ()
+ update forhost = do
++       hPrint stderr =<< hGetEncoding stdin
++       hSetEncoding stdin utf8
+        whenM hasGitRepo $
+                req NeedRepoUrl repoUrlMarker setRepoUrl
+```
+
+I get `Just ANSI_X3.4-1968` from the remote side but unfortunately the corruption persists.
+"""]]

Added a comment
diff --git a/doc/forum/Privdata_corrupted_when_spinning_from_macOS/comment_2_2a4f3ddcc92f0cf8be2472d2a45e69cc._comment b/doc/forum/Privdata_corrupted_when_spinning_from_macOS/comment_2_2a4f3ddcc92f0cf8be2472d2a45e69cc._comment
new file mode 100644
index 00000000..d4d596d8
--- /dev/null
+++ b/doc/forum/Privdata_corrupted_when_spinning_from_macOS/comment_2_2a4f3ddcc92f0cf8be2472d2a45e69cc._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="mithrandi"
+ avatar="http://cdn.libravatar.org/avatar/869963bdf99b541c9f0bbfb04b0320f1"
+ subject="comment 2"
+ date="2018-08-15T18:53:03Z"
+ content="""
+I get `Just UTF-8` in both cases and the corruption is not fixed. I think the problem may be on the _receiving_ side? On macOS my `$LC_CTYPE` is set to `\"UTF-8\"` which is passed through by SSH but is an invalid locale on Linux. Running `env LC_CTYPE=C.UTF-8 ./propellor --spin blah` fixes the corruption.
+"""]]

response
diff --git a/doc/forum/Privdata_corrupted_when_spinning_from_macOS/comment_1_0443c1dc8f7a74864c2a981740992ee4._comment b/doc/forum/Privdata_corrupted_when_spinning_from_macOS/comment_1_0443c1dc8f7a74864c2a981740992ee4._comment
new file mode 100644
index 00000000..3b047d9d
--- /dev/null
+++ b/doc/forum/Privdata_corrupted_when_spinning_from_macOS/comment_1_0443c1dc8f7a74864c2a981740992ee4._comment
@@ -0,0 +1,27 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 1"""
+ date="2018-08-14T21:33:55Z"
+ content="""
+Sounds like a problem with sendPrivData, which writes it to a Handle that's 
+connected to propellor on the host being spun.
+
+Handles have an associated encoding, which comes from the locale settings.
+The char8 TextEncoding sounds like what you describe (code point modulo
+256). hSetEncoding can change it.
+
+Here's a patch you could try that prints out the encoding in use and tries
+to force utf8.
+
+	--- a/src/Propellor/Spin.hs
+	+++ b/src/Propellor/Spin.hs
+	@@ -252,6 +252,8 @@ sendRepoUrl hst toh = sendMarked toh repoUrlMarker =<< geturl
+	
+	 sendPrivData :: HostName -> Handle -> PrivMap -> IO ()
+	 sendPrivData hn toh privdata = void $ actionMessage msg $ do
+	+	hPutStrLn stderr . show =<< hGetEncoding toh
+	+	hSetEncoding toh utf8
+ 		sendMarked toh privDataMarker d
+	 	return True
+	   where
+"""]]

Fix another typo
diff --git a/doc/forum/Privdata_corrupted_when_spinning_from_macOS.mdwn b/doc/forum/Privdata_corrupted_when_spinning_from_macOS.mdwn
index 2cc827b1..d4df4bac 100644
--- a/doc/forum/Privdata_corrupted_when_spinning_from_macOS.mdwn
+++ b/doc/forum/Privdata_corrupted_when_spinning_from_macOS.mdwn
@@ -1 +1 @@
-I recently added a binary file as privdata (installed with `File.hasPrivContent`). When I `propellor --dump` the property on either Linux or macOS, the contents is correct. Spinning from Linux also works, but spinning from macOS installs a corrupt version of the file. The corruption looks like every valid UTF-8 sequence has been replaced with a single byte which is the lowest byte of the Unicode codepoint encoded by the sequence, so this must have something to do with encodings, but from staring at the source code I can't figure out what. The data from `--dump` is not corrupted which seems especially strange.
+I recently added a binary file as privdata (installed with `File.hasPrivContent`). When I `propellor --dump` the privdata on either Linux or macOS, the contents is correct. Spinning from Linux also works, but spinning from macOS installs a corrupt version of the file. The corruption looks like every valid UTF-8 sequence has been replaced with a single byte which is the lowest byte of the Unicode codepoint encoded by the sequence, so this must have something to do with encodings, but from staring at the source code I can't figure out what. The data from `--dump` is not corrupted which seems especially strange.

Fix typo
diff --git a/doc/forum/Privdata_corrupted_when_spinning_from_macOS.mdwn b/doc/forum/Privdata_corrupted_when_spinning_from_macOS.mdwn
index e3e6e0f9..2cc827b1 100644
--- a/doc/forum/Privdata_corrupted_when_spinning_from_macOS.mdwn
+++ b/doc/forum/Privdata_corrupted_when_spinning_from_macOS.mdwn
@@ -1 +1 @@
-I recently added a binary file as privdata (installed with `File.hasPrivContents`). When I `propellor --dump` the property on either Linux or macOS, the contents is correct. Spinning from Linux also works, but spinning from macOS installs a corrupt version of the file. The corruption looks like every valid UTF-8 sequence has been replaced with a single byte which is the lowest byte of the Unicode codepoint encoded by the sequence, so this must have something to do with encodings, but from staring at the source code I can't figure out what. The data from `--dump` is not corrupted which seems especially strange.
+I recently added a binary file as privdata (installed with `File.hasPrivContent`). When I `propellor --dump` the property on either Linux or macOS, the contents is correct. Spinning from Linux also works, but spinning from macOS installs a corrupt version of the file. The corruption looks like every valid UTF-8 sequence has been replaced with a single byte which is the lowest byte of the Unicode codepoint encoded by the sequence, so this must have something to do with encodings, but from staring at the source code I can't figure out what. The data from `--dump` is not corrupted which seems especially strange.

diff --git a/doc/forum/Privdata_corrupted_when_spinning_from_macOS.mdwn b/doc/forum/Privdata_corrupted_when_spinning_from_macOS.mdwn
new file mode 100644
index 00000000..e3e6e0f9
--- /dev/null
+++ b/doc/forum/Privdata_corrupted_when_spinning_from_macOS.mdwn
@@ -0,0 +1 @@
+I recently added a binary file as privdata (installed with `File.hasPrivContents`). When I `propellor --dump` the property on either Linux or macOS, the contents is correct. Spinning from Linux also works, but spinning from macOS installs a corrupt version of the file. The corruption looks like every valid UTF-8 sequence has been replaced with a single byte which is the lowest byte of the Unicode codepoint encoded by the sequence, so this must have something to do with encodings, but from staring at the source code I can't figure out what. The data from `--dump` is not corrupted which seems especially strange.

fix sequence
diff --git a/doc/forum/mailname_set_by_Propellor.Property.Hostname.sane/comment_2_d82e10087205a4b2896e4fd07032643d._comment b/doc/forum/mailname_set_by_Propellor.Property.Hostname.sane/comment_3_d82e10087205a4b2896e4fd07032643d._comment
similarity index 91%
rename from doc/forum/mailname_set_by_Propellor.Property.Hostname.sane/comment_2_d82e10087205a4b2896e4fd07032643d._comment
rename to doc/forum/mailname_set_by_Propellor.Property.Hostname.sane/comment_3_d82e10087205a4b2896e4fd07032643d._comment
index 24c0efcf..df002711 100644
--- a/doc/forum/mailname_set_by_Propellor.Property.Hostname.sane/comment_2_d82e10087205a4b2896e4fd07032643d._comment
+++ b/doc/forum/mailname_set_by_Propellor.Property.Hostname.sane/comment_3_d82e10087205a4b2896e4fd07032643d._comment
@@ -1,6 +1,6 @@
 [[!comment format=mdwn
  username="joey"
- subject="""comment 2"""
+ subject="""comment 3"""
  date="2018-08-10T14:56:07Z"
  content="""
 I have probably generalized too much from my own use case then, where

followup
diff --git a/doc/forum/mailname_set_by_Propellor.Property.Hostname.sane/comment_2_d82e10087205a4b2896e4fd07032643d._comment b/doc/forum/mailname_set_by_Propellor.Property.Hostname.sane/comment_2_d82e10087205a4b2896e4fd07032643d._comment
new file mode 100644
index 00000000..24c0efcf
--- /dev/null
+++ b/doc/forum/mailname_set_by_Propellor.Property.Hostname.sane/comment_2_d82e10087205a4b2896e4fd07032643d._comment
@@ -0,0 +1,9 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 2"""
+ date="2018-08-10T14:56:07Z"
+ content="""
+I have probably generalized too much from my own use case then, where
+I always have foo.example.com as the full hostname, but want mail to be
+sent with example.com as the name.
+"""]]

Added a comment
diff --git a/doc/forum/mailname_set_by_Propellor.Property.Hostname.sane/comment_2_ac8e2bdd7bd16058f46ef8352df09700._comment b/doc/forum/mailname_set_by_Propellor.Property.Hostname.sane/comment_2_ac8e2bdd7bd16058f46ef8352df09700._comment
new file mode 100644
index 00000000..3cdfaeaa
--- /dev/null
+++ b/doc/forum/mailname_set_by_Propellor.Property.Hostname.sane/comment_2_ac8e2bdd7bd16058f46ef8352df09700._comment
@@ -0,0 +1,10 @@
+[[!comment format=mdwn
+ username="spwhitton"
+ avatar="http://cdn.libravatar.org/avatar/9c3f08f80e67733fd506c353239569eb"
+ subject="comment 2"
+ date="2018-08-10T10:36:35Z"
+ content="""
+Could you explain why it's right to not use the full hostname, please?
+
+Careless use of `Hostname.sane` on my part recently broke my mail sending setup.  I discovered that I am relying on /etc/mailname containing the full hostname, but maybe I should not be doing that.
+"""]]

letsencrypt': Pass --expand to support expanding the list of domains
diff --git a/debian/changelog b/debian/changelog
index 171cd8fe..1da97c15 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+propellor (5.4.2) UNRELEASED; urgency=medium
+
+  * letsencrypt': Pass --expand to support expanding the list of domains
+
+ -- Joey Hess <id@joeyh.name>  Thu, 09 Aug 2018 10:54:41 -0400
+
 propellor (5.4.1) unstable; urgency=medium
 
   * Modernized and simplified the MetaTypes implementation now that
diff --git a/doc/forum/Certbot_cert_expanding/comment_2_2a16c69729cff4262c9a37b264c60ae0._comment b/doc/forum/Certbot_cert_expanding/comment_2_2a16c69729cff4262c9a37b264c60ae0._comment
new file mode 100644
index 00000000..8aba068a
--- /dev/null
+++ b/doc/forum/Certbot_cert_expanding/comment_2_2a16c69729cff4262c9a37b264c60ae0._comment
@@ -0,0 +1,7 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 2"""
+ date="2018-08-09T14:55:33Z"
+ content="""
+Ok, patched it in.
+"""]]
diff --git a/src/Propellor/Property/LetsEncrypt.hs b/src/Propellor/Property/LetsEncrypt.hs
index 9e4898dd..99c23715 100644
--- a/src/Propellor/Property/LetsEncrypt.hs
+++ b/src/Propellor/Property/LetsEncrypt.hs
@@ -77,6 +77,9 @@ letsEncrypt' (AgreeTOS memail) domain domains webroot =
 		, "--text"
 		, "--noninteractive"
 		, "--keep-until-expiring"
+		-- The list of domains may be changed, adding more, so
+		-- always request expansion.
+		, "--expand"
 		] ++ map (\d -> "--domain="++d) alldomains
 
 	getstats = mapM statcertfiles alldomains

Added a comment
diff --git a/doc/forum/Certbot_cert_expanding/comment_2_a4ca6b57c77651936c7f74f730f832e7._comment b/doc/forum/Certbot_cert_expanding/comment_2_a4ca6b57c77651936c7f74f730f832e7._comment
new file mode 100644
index 00000000..f1af3dca
--- /dev/null
+++ b/doc/forum/Certbot_cert_expanding/comment_2_a4ca6b57c77651936c7f74f730f832e7._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="mithrandi"
+ avatar="http://cdn.libravatar.org/avatar/869963bdf99b541c9f0bbfb04b0320f1"
+ subject="comment 2"
+ date="2018-08-09T13:18:37Z"
+ content="""
+I have now tested this and it works fine.
+"""]]

add news item for propellor 5.4.1
diff --git a/doc/news/version_5.3.3.mdwn b/doc/news/version_5.3.3.mdwn
deleted file mode 100644
index 18f80d5f..00000000
--- a/doc/news/version_5.3.3.mdwn
+++ /dev/null
@@ -1,8 +0,0 @@
-propellor 5.3.3 released with [[!toggle text="these changes"]]
-[[!toggleable text="""
-   * Warn again about new upstream version when ~/.propellor was cloned from the
-     Debian git bundle using an older version of propellor that set up an
-     upstream remote.
-   * Avoid crashing if initial fetch from origin fails when spinning a host.
-   * Added Propllor.Property.Openssl module contributed by contributed by
-     Félix Sipma."""]]
\ No newline at end of file
diff --git a/doc/news/version_5.4.1.mdwn b/doc/news/version_5.4.1.mdwn
new file mode 100644
index 00000000..ebb0e261
--- /dev/null
+++ b/doc/news/version_5.4.1.mdwn
@@ -0,0 +1,14 @@
+propellor 5.4.1 released with [[!toggle text="these changes"]]
+[[!toggleable text="""
+   * Modernized and simplified the MetaTypes implementation now that
+     compatability with ghc 7 is no longer needed.
+   * Use git verify-commit to verify gpg signatures, rather than the old
+     method of parsing git log output. Needs git 2.0.
+   * Added ConfFile.containsShellSetting, ConfFile.lacksShellSetting,
+     and EtcDefault.set properties. Thanks, Sean Whitton
+   * Dns: Support TXT values longer than bind's maximum string length
+     of 255 bytes. Thanks, rsiddharth.
+   * Docker and HostingProvider.CloudAtCost modules are not being
+     maintained, so marked them as such.
+     Seeking a maintainer for the Docker module; I anticipate
+     removing the CloudAtCost module in the next API bump."""]]
\ No newline at end of file

response
diff --git a/doc/forum/Certbot_cert_expanding/comment_1_1f6b33d757294b69172a9b59b2c0ea4f._comment b/doc/forum/Certbot_cert_expanding/comment_1_1f6b33d757294b69172a9b59b2c0ea4f._comment
new file mode 100644
index 00000000..fb7354d1
--- /dev/null
+++ b/doc/forum/Certbot_cert_expanding/comment_1_1f6b33d757294b69172a9b59b2c0ea4f._comment
@@ -0,0 +1,15 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 1"""
+ date="2018-07-31T14:25:34Z"
+ content="""
+Makes sense. The man page says:
+
+            --expand              If an existing certificate is a strict subset of the
+                                  requested names, always expand and replace it with the
+                                  additional names. (default: Ask)
+
+Which reads like it will not change behavior in other cases. 
+Still, it would be good for someone to test it before the change is
+made to propellor..
+"""]]

diff --git a/doc/forum/Certbot_cert_expanding.mdwn b/doc/forum/Certbot_cert_expanding.mdwn
index db67cbf3..90be60d6 100644
--- a/doc/forum/Certbot_cert_expanding.mdwn
+++ b/doc/forum/Certbot_cert_expanding.mdwn
@@ -1,14 +1,16 @@
 When adding a name to the list for a `letsEncrypt` property, certbot fails thusly:
 
-Saving debug log to /var/log/letsencrypt/letsencrypt.log
-Plugins selected: Authenticator webroot, Installer None
-Missing command line flag or config entry for this setting:
-You have an existing certificate that contains a portion of the domains you requested (ref: /etc/letsencrypt/renewal/fusionapp.com.conf)
+    Saving debug log to /var/log/letsencrypt/letsencrypt.log
+    Plugins selected: Authenticator webroot, Installer None
+    Missing command line flag or config entry for this setting:
+    You have an existing certificate that contains a portion of the domains you requested (ref: /etc/letsencrypt/renewal/…)
 
-It contains these names: fusionapp.com, bn.fusionapp.com, bz-entropy.fusionapp.com, bz-ext.fusionapp.com, bz.fusionapp.com, entropy.fusionapp.com, prod.fusionapp.com
+    It contains these names: …
 
-You requested these names for the new certificate: fusionapp.com, entropy.fusionapp.com, bz-entropy.fusionapp.com, bz-ext.fusionapp.com, prod.fusionapp.com, bz.fusionapp.com, bn.fusionapp.com, entropy.fusiontest.net.
+    You requested these names for the new certificate: …
 
-Do you want to expand and replace this existing certificate with the new certificate?
+    Do you want to expand and replace this existing certificate with the new certificate?
 
-(You can set this with the --expand flag)
+    (You can set this with the --expand flag)
+
+I think maybe Propellor should always pass --expand? I haven't tested if that works correctly when not changing the names.

diff --git a/doc/forum/Certbot_cert_expanding.mdwn b/doc/forum/Certbot_cert_expanding.mdwn
new file mode 100644
index 00000000..db67cbf3
--- /dev/null
+++ b/doc/forum/Certbot_cert_expanding.mdwn
@@ -0,0 +1,14 @@
+When adding a name to the list for a `letsEncrypt` property, certbot fails thusly:
+
+Saving debug log to /var/log/letsencrypt/letsencrypt.log
+Plugins selected: Authenticator webroot, Installer None
+Missing command line flag or config entry for this setting:
+You have an existing certificate that contains a portion of the domains you requested (ref: /etc/letsencrypt/renewal/fusionapp.com.conf)
+
+It contains these names: fusionapp.com, bn.fusionapp.com, bz-entropy.fusionapp.com, bz-ext.fusionapp.com, bz.fusionapp.com, entropy.fusionapp.com, prod.fusionapp.com
+
+You requested these names for the new certificate: fusionapp.com, entropy.fusionapp.com, bz-entropy.fusionapp.com, bz-ext.fusionapp.com, prod.fusionapp.com, bz.fusionapp.com, bn.fusionapp.com, entropy.fusiontest.net.
+
+Do you want to expand and replace this existing certificate with the new certificate?
+
+(You can set this with the --expand flag)

inverted
diff --git a/doc/todo/support_for_libvirt_KVM_VMs/comment_1_c73740e45387fe817280b55bb0e32c12._comment b/doc/todo/support_for_libvirt_KVM_VMs/comment_1_c73740e45387fe817280b55bb0e32c12._comment
index 24ad2c45..f4ff3615 100644
--- a/doc/todo/support_for_libvirt_KVM_VMs/comment_1_c73740e45387fe817280b55bb0e32c12._comment
+++ b/doc/todo/support_for_libvirt_KVM_VMs/comment_1_c73740e45387fe817280b55bb0e32c12._comment
@@ -10,9 +10,9 @@ so is `debootstrapTheChrootAndPackIntoQcow2File`,
 so to check if the disk image exists, you'll instead
 want to use the `check` combinator. Something like:
 
-	& check (doesFileExist "/path/to/image.qcow2")
-		debootstrapTheChrootAndPackIntoQcow2File theHost
 	& check (not <$> doesFileExist "/path/to/image.qcow2")
+		debootstrapTheChrootAndPackIntoQcow2File theHost
+	& check (doesFileExist "/path/to/image.qcow2")
 		conducts [theHost] `requires` KVM.booted theHost
 
 Perhaps the redundancy in that can be reduced with a new combinator

response
diff --git a/doc/todo/support_for_libvirt_KVM_VMs/comment_1_c73740e45387fe817280b55bb0e32c12._comment b/doc/todo/support_for_libvirt_KVM_VMs/comment_1_c73740e45387fe817280b55bb0e32c12._comment
new file mode 100644
index 00000000..24ad2c45
--- /dev/null
+++ b/doc/todo/support_for_libvirt_KVM_VMs/comment_1_c73740e45387fe817280b55bb0e32c12._comment
@@ -0,0 +1,29 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 1"""
+ date="2018-07-20T15:54:17Z"
+ content="""
+That seems like a good plan to me, and nice use of the Conductor module.
+
+Of course, `conducts` is a Property, not an IO action and presumably
+so is `debootstrapTheChrootAndPackIntoQcow2File`,
+so to check if the disk image exists, you'll instead
+want to use the `check` combinator. Something like:
+
+	& check (doesFileExist "/path/to/image.qcow2")
+		debootstrapTheChrootAndPackIntoQcow2File theHost
+	& check (not <$> doesFileExist "/path/to/image.qcow2")
+		conducts [theHost] `requires` KVM.booted theHost
+
+Perhaps the redundancy in that can be reduced with a new combinator
+that chooses which action to run.
+
+You may want to also delete the chroot once the disk image is built.
+
+There could also be a minor gotcha with the Conductor module trying to
+conduct the VM before it's gotten set up yet, at worst this would make
+propellor display a warning.
+
+Let me know if you need help with this, 
+although I will next be available on July 30th.
+"""]]

post TODO for feedback
diff --git a/doc/todo/support_for_libvirt_KVM_VMs.mdwn b/doc/todo/support_for_libvirt_KVM_VMs.mdwn
new file mode 100644
index 00000000..529cf721
--- /dev/null
+++ b/doc/todo/support_for_libvirt_KVM_VMs.mdwn
@@ -0,0 +1,27 @@
+I've been thinking about how to add support for libvirt VMs to
+propellor.  TTBOMK setting up the VMs is a matter of creating some
+files in /etc, so that part is straightforward; might not want very
+much abstraction in propellor at all.  The interesting part is
+creating the corresponding disk images.
+
+I first thought that I could just extend propellor's existing support
+for generating disk images by debootstrapping in a chroot and then
+generating an image based on that chroot.  It would just be a matter
+of using `.qcow2` images rather than `.img`.  But the problem with
+this is that once the VM is in use, propellor should not just be
+overwriting the `.qcow2` file.  So something different is needed.
+
+What I have in mind is a conditional property that works something
+like this:
+
+    ifM ( doesFileExist "/path/to/image.qcow2"
+        , debootstrapTheChrootAndPackIntoQcow2File theHost
+        , conducts [theHost] `requires` KVM.booted theHost
+        )
+
+where `theHost :: Host` and either the user's libvirt config or some
+property somewhere ensures it can be SSHed to from localhost.
+
+Does this seem like the right approach?
+
+--spwhitton

two unmaintained modules
diff --git a/debian/changelog b/debian/changelog
index 8d9179e4..659bd8d1 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -6,6 +6,10 @@ propellor (5.4.1) UNRELEASED; urgency=medium
     method of parsing git log output. Needs git 2.0.
   * Added ConfFile.containsShellSetting, ConfFile.lacksShellSetting,
     and EtcDefault.set properties. Thanks, Sean Whitton
+  * Docker and HostingProvider.CloudAtCost modules are not being
+    maintained, so marked them as such, including build-time warnings. 
+    Seeking a maintainer for the Docker module; I anticipate
+    removing the CloudAtCost module in the next API bump.
 
  -- Joey Hess <id@joeyh.name>  Fri, 18 May 2018 10:25:05 -0400
 
diff --git a/doc/todo/Outdated_Docker_Package__63__/comment_1_408c060bcec73880502655c333a2ea40._comment b/doc/todo/Outdated_Docker_Package__63__/comment_1_408c060bcec73880502655c333a2ea40._comment
index 6f06f87f..bf75470b 100644
--- a/doc/todo/Outdated_Docker_Package__63__/comment_1_408c060bcec73880502655c333a2ea40._comment
+++ b/doc/todo/Outdated_Docker_Package__63__/comment_1_408c060bcec73880502655c333a2ea40._comment
@@ -4,8 +4,9 @@
  date="2018-06-13T14:32:43Z"
  content="""
 I can't see any docker-engine package in any version of Debian. Unstable
-still has a docker.io, though testing does not. It looks like perhaps
-docker was not included in the last stable release, though I am not sure.
+still has a docker.io, though testing does not (update: it does now; the
+docker package also recently got updated to a more current version).
+Docker was not included in the last stable release.
 
 I have not used docker in quite some time. I use systemd-nspawn containers
 which are much easier to build and maintain. So, it may make sense to
diff --git a/doc/todo/Outdated_Docker_Package__63__/comment_2_8da1d2a1a6e6569a2197ab867665dad1._comment b/doc/todo/Outdated_Docker_Package__63__/comment_2_8da1d2a1a6e6569a2197ab867665dad1._comment
new file mode 100644
index 00000000..e0f14b92
--- /dev/null
+++ b/doc/todo/Outdated_Docker_Package__63__/comment_2_8da1d2a1a6e6569a2197ab867665dad1._comment
@@ -0,0 +1,9 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 2"""
+ date="2018-07-11T16:01:37Z"
+ content="""
+Marked the module as unmaintained. If you would like to take over
+maintanance of it, just send me patches putting your name in the maintainer
+slot etc.
+"""]]
diff --git a/joeyconfig.hs b/joeyconfig.hs
index 0d971b03..7541c78b 100644
--- a/joeyconfig.hs
+++ b/joeyconfig.hs
@@ -33,7 +33,6 @@ import qualified Propellor.Property.Systemd as Systemd
 import qualified Propellor.Property.Journald as Journald
 import qualified Propellor.Property.Fail2Ban as Fail2Ban
 import qualified Propellor.Property.Laptop as Laptop
-import qualified Propellor.Property.HostingProvider.CloudAtCost as CloudAtCost
 import qualified Propellor.Property.HostingProvider.Linode as Linode
 import qualified Propellor.Property.HostingProvider.DigitalOcean as DigitalOcean
 import qualified Propellor.Property.SiteSpecific.GitHome as GitHome
@@ -101,7 +100,6 @@ clam = host "clam.kitenet.net" $ props
 		["Unreliable server. Anything here may be lost at any time!" ]
 	& ipv4 "64.137.164.186"
 
-	& CloudAtCost.decruft
 	& User.hasPassword (User "root")
 	& Ssh.hostKeys hostContext
 		[ (SshDsa, "ssh-dss AAAAB3NzaC1kc3MAAACBAI3WUq0RaigLlcUivgNG4sXpso2ORZkMvfqKz6zkc60L6dpxvWDNmZVEH8hEjxRSYG07NehcuOgQqeyFnS++xw1hdeGjf37JqCUH49i02lra3Zxv8oPpRxyeqe5MmuzUJhlWvBdlc3O/nqZ4bTUfnxMzSYWyy6++s/BpSHttZplNAAAAFQC1DE0vzgVeNAv9smHLObQWZFe2VQAAAIBECtpJry3GC8NVTFsTHDGWksluoFPIbKiZUFFztZGdM0AO2VwAbiJ6Au6M3VddGFANgTlni6d2/9yS919zO90TaFoIjywZeXhxE2CSuRfU7sx2hqDBk73jlycem/ER0sanFhzpHVpwmLfWneTXImWyq37vhAxatJANOtbj81vQ3AAAAIBV3lcyTT9xWg1Q4vERJbvyF8mCliwZmnIPa7ohveKkxlcgUk5d6dnaqFfjVaiXBPN3Qd08WXoQ/a9k3chBPT9nW2vWgzzM8l36j2MbHLmaxGwevAc9+vx4MXqvnGHzd2ex950mC33ct3j0fzMZlO6vqEsgD4CYmiASxhfefj+JCQ==")
diff --git a/src/Propellor/Property/Docker.hs b/src/Propellor/Property/Docker.hs
index 66418253..522aecd9 100644
--- a/src/Propellor/Property/Docker.hs
+++ b/src/Propellor/Property/Docker.hs
@@ -1,11 +1,14 @@
 {-# LANGUAGE FlexibleContexts, TypeSynonymInstances, FlexibleInstances, TypeFamilies #-}
 
--- | Docker support for propellor
+-- | Maintainer: currently unmaintained; your name here!
+--
+-- Docker support for propellor
 --
 -- The existance of a docker container is just another Property of a system,
 -- which propellor can set up. See config.hs for an example.
 
-module Propellor.Property.Docker (
+module Propellor.Property.Docker
+	{-# WARNING "This module does not have a maintainer. It might not work right anymore. If you use it, please consider becoming its maintainer." #-} (
 	-- * Host properties
 	installed,
 	configured,
diff --git a/src/Propellor/Property/HostingProvider/CloudAtCost.hs b/src/Propellor/Property/HostingProvider/CloudAtCost.hs
index 5c4788e2..48c19572 100644
--- a/src/Propellor/Property/HostingProvider/CloudAtCost.hs
+++ b/src/Propellor/Property/HostingProvider/CloudAtCost.hs
@@ -1,4 +1,8 @@
-module Propellor.Property.HostingProvider.CloudAtCost where
+-- | Maintainer: currently unmaintained; your name here!
+
+module Propellor.Property.HostingProvider.CloudAtCost
+	{-# WARNING "This module does not have a maintainer. It might not work right anymore. If you use it, please consider becoming its maintainer." #-}
+	where
 
 import Propellor.Base
 import qualified Propellor.Property.Hostname as Hostname

response
diff --git a/doc/forum/Separation_of_data_and_code/comment_1_0ba5dff744eeba857ab7fadfad883b13._comment b/doc/forum/Separation_of_data_and_code/comment_1_0ba5dff744eeba857ab7fadfad883b13._comment
new file mode 100644
index 00000000..ae50a008
--- /dev/null
+++ b/doc/forum/Separation_of_data_and_code/comment_1_0ba5dff744eeba857ab7fadfad883b13._comment
@@ -0,0 +1,16 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 1"""
+ date="2018-07-06T20:19:27Z"
+ content="""
+I was going to write something asserting that it's entirely data,
+and not code, though typed data expressed in a programming language.
+
+However, I think it's better to say that this code/data distinction is
+much less a useful distinction that commonly thought, one that things,
+especially in the configuration management space often chafe under (see
+all the turing complete ill-specified languages built on top of what
+started out as some pure data format that are in use by almost every other
+configuration management tool), and that Propellor is an attempt to
+move in a more useful and less ridigly defined direction.
+"""]]

diff --git a/doc/forum/Separation_of_data_and_code.mdwn b/doc/forum/Separation_of_data_and_code.mdwn
new file mode 100644
index 00000000..3a09a237
--- /dev/null
+++ b/doc/forum/Separation_of_data_and_code.mdwn
@@ -0,0 +1,11 @@
+I'm using Fedora for the desktop and CentOS on my server. I have many software packages to install. I store them in shell scripts, with lines like this:
+
+    yum -y install vim-common vim-enhanced gvim vim-X11 # the latter for clipboard support
+
+I'm thinking about some more elaborate way to do that (to put some packages to specific hosts and groups). Propellor seems an interesting tool for that, but when I see an [example configuration file](https://git.joeyh.name/index.cgi/propellor.git/tree/joeyconfig.hs), it looks like this is a mixture of data and logic, which is considered [not a very good practice](https://softwareengineering.stackexchange.com/questions/229479/how-did-separation-of-code-and-data-become-a-practice).
+
+I know that Haskell itself is a very declarative language (in the sense it's not imperative), but still I have this feeling of a mixture of code with constants. What do you think of that?
+
+Is there a way to cleanly store names of packages (with comments and some configuration options (e.g. on what hosts they should be used)) in one place and use propellor's logic to install them in another place? 
+
+I understand that the power of propellor is to `do` things apart of just enumerating them, but I think that this separation could be useful.

Dns: Support TXT values longer than bind's maximum string length of 255 bytes. Thanks, rsiddharth.
diff --git a/debian/changelog b/debian/changelog
index 8d9179e4..bad0cad2 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -6,6 +6,8 @@ propellor (5.4.1) UNRELEASED; urgency=medium
     method of parsing git log output. Needs git 2.0.
   * Added ConfFile.containsShellSetting, ConfFile.lacksShellSetting,
     and EtcDefault.set properties. Thanks, Sean Whitton
+  * Dns: Support TXT values longer than bind's maximum string length
+    of 255 bytes. Thanks, rsiddharth.
 
  -- Joey Hess <id@joeyh.name>  Fri, 18 May 2018 10:25:05 -0400
 
diff --git a/doc/forum/DNS_-_Support_for_Multiline_TXT_records/comment_3_00f57bb6a54dee0dfbb799babf72a827._comment b/doc/forum/DNS_-_Support_for_Multiline_TXT_records/comment_3_00f57bb6a54dee0dfbb799babf72a827._comment
new file mode 100644
index 00000000..8809f999
--- /dev/null
+++ b/doc/forum/DNS_-_Support_for_Multiline_TXT_records/comment_3_00f57bb6a54dee0dfbb799babf72a827._comment
@@ -0,0 +1,7 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 3"""
+ date="2018-06-24T15:21:29Z"
+ content="""
+Looks good to me, merged.
+"""]]

Add s user page.
diff --git a/doc/user/s.mdwn b/doc/user/s.mdwn
new file mode 100644
index 00000000..08ef7bc8
--- /dev/null
+++ b/doc/user/s.mdwn
@@ -0,0 +1,3 @@
+s [propels some computers][1] using propellor.
+
+[1]: https://git.ricketyspace.net/propellor/tree/config.hs

Added a comment
diff --git a/doc/forum/DNS_-_Support_for_Multiline_TXT_records/comment_2_ccd261bdc9615b7490ec0f6824f35e19._comment b/doc/forum/DNS_-_Support_for_Multiline_TXT_records/comment_2_ccd261bdc9615b7490ec0f6824f35e19._comment
new file mode 100644
index 00000000..3fbd389f
--- /dev/null
+++ b/doc/forum/DNS_-_Support_for_Multiline_TXT_records/comment_2_ccd261bdc9615b7490ec0f6824f35e19._comment
@@ -0,0 +1,15 @@
+[[!comment format=mdwn
+ username="s@aa9ff9ce06b08acfd2a93ebd342ce6879430fbdd"
+ nickname="s"
+ avatar="http://cdn.libravatar.org/avatar/81bf27f8b35011d1846711fa37a5588f"
+ subject="comment 2"
+ date="2018-06-24T14:58:53Z"
+ content="""
+joeyh, Thanks for the feedback.
+
+I updated the definition of `TXT`'s `rValue` according to your suggestion and removed the `MTXT` record -- [patch][patch].
+
+I would like to get the patch merged into upstream, let me know if I've to refactor it.
+
+[patch]: https://ricketyspace.net/file/0001-update-rValue-of-Dns-TXT-record-type.patch
+"""]]

update link 2
diff --git a/doc/forum/DNS_-_Support_for_Multiline_TXT_records.mdwn b/doc/forum/DNS_-_Support_for_Multiline_TXT_records.mdwn
index 69a62b59..e6f2b478 100644
--- a/doc/forum/DNS_-_Support_for_Multiline_TXT_records.mdwn
+++ b/doc/forum/DNS_-_Support_for_Multiline_TXT_records.mdwn
@@ -16,4 +16,4 @@ I'm [currently using this recipe][2] to provision the DKIM TXT record.
 I want to know if there is a better way to do this without having to add the MTXT record type?
 
 [1]: https://ricketyspace.net/file/0001-add-MTXT-record-type-to-Propellor.Types.DNS.Record.patch
-[2]: https://git.ricketyspace.net/propellor/tree/config.hs#n722
+[2]: https://git.ricketyspace.net/propellor/tree/config.hs?id=67f47e5a23e8c7814014ea58f2dbc9f7c58ede3a#n722

response
diff --git a/doc/forum/Adding_support_for_a_SQL_server/comment_3_14b6968853d30a2054cc675c6005f29f._comment b/doc/forum/Adding_support_for_a_SQL_server/comment_3_14b6968853d30a2054cc675c6005f29f._comment
new file mode 100644
index 00000000..b566f3c5
--- /dev/null
+++ b/doc/forum/Adding_support_for_a_SQL_server/comment_3_14b6968853d30a2054cc675c6005f29f._comment
@@ -0,0 +1,16 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 3"""
+ date="2018-06-23T19:13:59Z"
+ content="""
+Well, cabal files can have flags that enable additional dependencies, but
+using them complicates testing the program since you have to try building
+it with different combinations of flags. And deploying propellor with the
+desired flags turned on would be an additional complication.
+
+I feel that additional libraries that depend on propellor and the sql
+library and provide properties is a better approach. The user can easily
+add the dependency to their ~/.propellor/config.cabal, and the necessary
+dependencies will be automatically installed when propellor is deploying
+itself to a new host.
+"""]]

response
diff --git a/doc/forum/DNS_-_Support_for_Multiline_TXT_records/comment_1_b97c158ae4e3abb6e4c90a2c91e0c207._comment b/doc/forum/DNS_-_Support_for_Multiline_TXT_records/comment_1_b97c158ae4e3abb6e4c90a2c91e0c207._comment
new file mode 100644
index 00000000..5595af19
--- /dev/null
+++ b/doc/forum/DNS_-_Support_for_Multiline_TXT_records/comment_1_b97c158ae4e3abb6e4c90a2c91e0c207._comment
@@ -0,0 +1,25 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 1"""
+ date="2018-06-23T18:42:32Z"
+ content="""
+It seems that the limit is 255 characters, and this
+limit applies to any string in a bind zone file,
+rather than being a maximim line length. A single line can contain multiple
+such strings, although there's probably a maximum line length somewhere 
+too, so using parens to extend across multiple lines is wise.
+
+The values inside the parens are concacenated together, no newline is added
+to the string that bind builds up from them AFAICS.
+
+So it seems your code is stripping out the newlines from the TXT value.
+Which probably doesn't matter for DKIM public key material,
+and I don't think that bind zone files support multiline strings anyway.
+But a single line could be too long and splitting on newlines would not
+help then.
+
+So, I think the thing to do would be to make `rValue` break TXT
+strings into substrings no longer than 255 characters. Then you don't
+need a new constructor, and long SSHFP etc records could also be handled
+that way.
+"""]]

Added a comment
diff --git a/doc/forum/Adding_support_for_a_SQL_server/comment_2_e18fc448f51478617e5b2b9b05ce4a0f._comment b/doc/forum/Adding_support_for_a_SQL_server/comment_2_e18fc448f51478617e5b2b9b05ce4a0f._comment
new file mode 100644
index 00000000..74654902
--- /dev/null
+++ b/doc/forum/Adding_support_for_a_SQL_server/comment_2_e18fc448f51478617e5b2b9b05ce4a0f._comment
@@ -0,0 +1,10 @@
+[[!comment format=mdwn
+ username="Nicolas.Schodet"
+ avatar="http://cdn.libravatar.org/avatar/0d7ec808ec329d04ee9a93c0da3c0089"
+ subject="comment 2"
+ date="2018-06-19T18:56:28Z"
+ content="""
+I am looking for a solution which could be integrated to propellor. Is it possible to include those additional libraries in propellor sources and have them included in the build on demand? I am not very familiar with the haskell build systems.
+
+About generated passwords, a nice solution would be to do it in PrivData.  The user would provide a salt as the private data and it would be combined to context to generate a password.  I can try find how this could be done.
+"""]]

New post - DNS - Support for Multiline TXT records.
diff --git a/doc/forum/DNS_-_Support_for_Multiline_TXT_records.mdwn b/doc/forum/DNS_-_Support_for_Multiline_TXT_records.mdwn
new file mode 100644
index 00000000..69a62b59
--- /dev/null
+++ b/doc/forum/DNS_-_Support_for_Multiline_TXT_records.mdwn
@@ -0,0 +1,19 @@
+bind9 has a limit on the number of characters in a single line TXT record. I was unable to provision the DKIM TXT record using propellor due to this limit.
+
+I added a new MTXT record type to `Propellor.Types.DNS.Record` ([patch][1]).
+
+MTXT creates a multiline TXT record. It splits the record's text (say
+"long string...\n...xyz") at `'\n'` and creates a TXT record of the
+form:
+
+
+    domain IN      TXT     ( "long string..."
+            "...xyz" )
+
+
+I'm [currently using this recipe][2] to provision the DKIM TXT record.
+
+I want to know if there is a better way to do this without having to add the MTXT record type?
+
+[1]: https://ricketyspace.net/file/0001-add-MTXT-record-type-to-Propellor.Types.DNS.Record.patch
+[2]: https://git.ricketyspace.net/propellor/tree/config.hs#n722