commit b05d3c1e54246d4040691b8bf8243f8736665505
Author: mudler <mudler@mocaccino.org>
Date:   Mon Oct 3 11:03:48 2022 +0200

    Initial import

diff --git a/Earthfile b/Earthfile
new file mode 100644
index 0000000..c6c8edf
--- /dev/null
+++ b/Earthfile
@@ -0,0 +1,64 @@
+VERSION 0.6
+# Note the base image needs to have dracut.
+# TODO: This needs to come from pre-built kernels in c3os repos, kcrypt included.
+# Framework images should use our initrd
+ARG BASE_IMAGE=quay.io/c3os/core-opensuse
+
+build-kcrypt:
+    FROM golang:alpine
+    COPY . /work
+    WORKDIR /work
+    RUN CGO_ENABLED=0 go build -o kcrypt
+    SAVE ARTIFACT /work/kcrypt AS LOCAL kcrypt
+
+build-dracut:
+    FROM $BASE_IMAGE
+    COPY . /work
+    COPY +build-kcrypt/kcrypt /usr/bin/kcrypt
+    WORKDIR /work
+    RUN cp -r dracut/* /usr/lib/dracut/modules.d
+    RUN cp dracut.conf /etc/dracut.conf.d/10-kcrypt.conf
+    RUN kernel=$(ls /lib/modules | head -n1) && \
+        dracut -f "/boot/initrd-${kernel}" "${kernel}" && \
+        ln -sf "initrd-${kernel}" /boot/initrd
+    ARG INITRD=$(readlink -f /boot/initrd)
+    SAVE ARTIFACT $INITRD AS LOCAL initrd
+
+image:
+    FROM $BASE_IMAGE
+    ARG IMAGE=dracut
+    ARG INITRD=$(readlink -f /boot/initrd)
+    ARG NAME=$(basename $INITRD)
+    COPY +build-dracut/$NAME $INITRD
+    COPY +build-kcrypt/kcrypt /usr/bin/kcrypt
+    # This is the discovery plugin that needs to be replaced!
+    # TODO: After install, copy any discovery plugin found to /oem - this is weak - another way is to inject the binary into the initrd, but a the moment it is not working properly.
+    COPY +dummy-discovery/dummy-discovery /system/discovery/kcrypt-discovery-dummy
+    # XXX: this is not working properly, but avoids the /oem copy.
+    #RUN kcrypt inject-initrd $INITRD /system/discovery/kcrypt-discovery-dummy /system/discovery/kcrypt-discovery-dummy
+    SAVE IMAGE $IMAGE
+
+dummy-discovery:
+    FROM golang:alpine
+    COPY . /work
+    WORKDIR /work
+    RUN CGO_ENABLED=0 go build -o dummy-discovery ./examples/dummy-discovery
+    SAVE ARTIFACT /work/dummy-discovery AS LOCAL kcrypt-discovery-dummy
+
+
+iso: 
+    ARG ISO_NAME=test
+    ARG IMAGE
+    FROM quay.io/c3os/osbuilder-tools
+
+    WORKDIR /build
+    RUN zypper in -y jq docker wget
+    RUN mkdir -p files-iso/boot/grub2
+    RUN wget https://raw.githubusercontent.com/c3os-io/c3os/master/overlay/files-iso/boot/grub2/grub.cfg -O files-iso/boot/grub2/grub.cfg
+    WITH DOCKER --allow-privileged --load $IMAGE=(+image)
+        RUN /entrypoint.sh --name $ISO_NAME --debug build-iso --date=false --local --overlay-iso /build/files-iso $IMAGE --output /build/
+    END
+   # See: https://github.com/rancher/elemental-cli/issues/228
+    RUN sha256sum $ISO_NAME.iso > $ISO_NAME.iso.sha256
+    SAVE ARTIFACT /build/$ISO_NAME.iso iso AS LOCAL build/$ISO_NAME.iso
+    SAVE ARTIFACT /build/$ISO_NAME.iso.sha256 sha256 AS LOCAL build/$ISO_NAME.iso.sha256
diff --git a/dracut.conf b/dracut.conf
new file mode 100644
index 0000000..448ac5e
--- /dev/null
+++ b/dracut.conf
@@ -0,0 +1 @@
+add_dracutmodules+=" kcrypt "
\ No newline at end of file
diff --git a/dracut/29kcrypt/kcrypt.service b/dracut/29kcrypt/kcrypt.service
new file mode 100644
index 0000000..c0d4dc9
--- /dev/null
+++ b/dracut/29kcrypt/kcrypt.service
@@ -0,0 +1,9 @@
+[Unit]
+Description=kcrypt mount
+DefaultDependencies=no
+Before=cos-immutable-rootfs.service
+
+[Service]
+Type=oneshot
+RemainAfterExit=no
+ExecStart=/sbin/kcrypt-mount-local
diff --git a/dracut/29kcrypt/module-setup.sh b/dracut/29kcrypt/module-setup.sh
new file mode 100644
index 0000000..aa308fe
--- /dev/null
+++ b/dracut/29kcrypt/module-setup.sh
@@ -0,0 +1,38 @@
+#!/bin/bash
+
+# called by dracut
+check() {
+    require_binaries "$systemdutildir"/systemd || return 1
+    return 255
+}
+
+# called by dracut 
+depends() {
+    echo systemd rootfs-block dm fs-lib 
+    #tpm2-tss
+    return 0
+}
+
+# called by dracut
+installkernel() {
+    instmods overlay
+}
+
+# called by dracut
+install() {
+    declare moddir=${moddir}
+    declare systemdutildir=${systemdutildir}
+    declare systemdsystemunitdir=${systemdsystemunitdir}
+    declare initdir="${initdir}"
+
+    inst_multiple \
+        kcrypt
+    inst_script "${moddir}/mount-local.sh" "/sbin/kcrypt-mount-local"
+    #inst_hook pre-trigger 10 "$moddir/mount-local.sh"
+    inst_simple "${moddir}/kcrypt.service" \
+        "${systemdsystemunitdir}/kcrypt.service"
+    mkdir -p "${initdir}/${systemdsystemunitdir}/initrd-fs.target.requires"
+    ln_r "../kcrypt.service" \
+        "${systemdsystemunitdir}/initrd-fs.target.requires/kcrypt.service"
+    dracut_need_initqueue
+}
\ No newline at end of file
diff --git a/dracut/29kcrypt/mount-local.sh b/dracut/29kcrypt/mount-local.sh
new file mode 100755
index 0000000..827402d
--- /dev/null
+++ b/dracut/29kcrypt/mount-local.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
+# ex: ts=8 sw=4 sts=4 et filetype=sh
+
+OEM=$(blkid -L COS_OEM)
+if [ "$OEM" != "" ]; then
+    mkdir /oem
+    mount $OEM /oem
+fi
+
+kcrypt unlock-all
+
+if [ "$OEM" != "" ]; then
+umount /oem
+fi
diff --git a/examples/dummy-discovery/main.go b/examples/dummy-discovery/main.go
new file mode 100644
index 0000000..84fecd9
--- /dev/null
+++ b/examples/dummy-discovery/main.go
@@ -0,0 +1,48 @@
+package main
+
+import (
+	"encoding/json"
+	"fmt"
+	"os"
+
+	"github.com/jaypipes/ghw/pkg/block"
+	"github.com/keirros-io/kcrypt/pkg/bus"
+
+	"github.com/mudler/go-pluggable"
+)
+
+func main() {
+	if len(os.Args) >= 2 && bus.IsEventDefined(os.Args[1]) {
+		checkErr(start())
+	}
+}
+
+func checkErr(err error) {
+	if err != nil {
+		fmt.Println(err)
+		os.Exit(1)
+	}
+	os.Exit(0)
+}
+
+func start() error {
+	factory := pluggable.NewPluginFactory()
+
+	// Input: bus.EventInstallPayload
+	// Expected output: map[string]string{}
+	factory.Add(bus.EventDiscoveryPassword, func(e *pluggable.Event) pluggable.EventResponse {
+		b := &block.Partition{}
+		var errString string
+		err := json.Unmarshal([]byte(e.Data), b)
+		if err != nil {
+			errString = err.Error()
+		}
+
+		return pluggable.EventResponse{
+			Data:  "hardcoded password",
+			Error: errString,
+		}
+	})
+
+	return factory.Run(pluggable.EventType(os.Args[1]), os.Stdin, os.Stdout)
+}
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..770cbcd
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,32 @@
+module github.com/keirros-io/kcrypt
+
+go 1.18
+
+require (
+	github.com/anatol/luks.go v0.0.0-20220803222236-155595903818
+	github.com/hashicorp/go-multierror v1.1.1
+	github.com/jaypipes/ghw v0.9.0
+	github.com/mudler/go-pluggable v0.0.0-20220716112424-189d463e3ff3
+	github.com/otiai10/copy v1.7.0
+	github.com/urfave/cli v1.22.9
+)
+
+require (
+	github.com/StackExchange/wmi v1.2.1 // indirect
+	github.com/anatol/devmapper.go v0.0.0-20220716012224-693a1447fc15 // indirect
+	github.com/chuckpreslar/emission v0.0.0-20170206194824-a7ddd980baf9 // indirect
+	github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d // indirect
+	github.com/ghodss/yaml v1.0.0 // indirect
+	github.com/go-ole/go-ole v1.2.6 // indirect
+	github.com/hashicorp/errwrap v1.0.0 // indirect
+	github.com/jaypipes/pcidb v1.0.0 // indirect
+	github.com/mitchellh/go-homedir v1.1.0 // indirect
+	github.com/pkg/errors v0.9.1 // indirect
+	github.com/russross/blackfriday/v2 v2.0.1 // indirect
+	github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
+	golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect
+	golang.org/x/sys v0.0.0-20220803195053-6e608f9ce704 // indirect
+	golang.org/x/text v0.3.7 // indirect
+	gopkg.in/yaml.v2 v2.4.0 // indirect
+	howett.net/plist v1.0.0 // indirect
+)
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..975385d
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,136 @@
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA=
+github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8=
+github.com/anatol/devmapper.go v0.0.0-20220716012224-693a1447fc15 h1:741Z9HQjbLXe4SnZ6liQTYINeD559oFl/vOtzA21KM0=
+github.com/anatol/devmapper.go v0.0.0-20220716012224-693a1447fc15/go.mod h1:Ow7/kdG1m4K6UDTOwJeYJv9bkSLoL44qSu7S/Bxxi4Y=
+github.com/anatol/luks.go v0.0.0-20220803222236-155595903818 h1:IyYgXFMhnSIbkDnDrTnMrPDYlc/uYhG5UcGX6NVkO58=
+github.com/anatol/luks.go v0.0.0-20220803222236-155595903818/go.mod h1:1lE8PgTi0cS+3YsxbWcpfvGfjiPrRdcKJZc9j70OOTs=
+github.com/anatol/vmtest v0.0.0-20220413190228-7a42f1f6d7b8 h1:t4JGeY9oaF5LB4Rdx9e2wARRRPAYt8Ow4eCf5SwO3fA=
+github.com/chuckpreslar/emission v0.0.0-20170206194824-a7ddd980baf9 h1:xz6Nv3zcwO2Lila35hcb0QloCQsc38Al13RNEzWRpX4=
+github.com/chuckpreslar/emission v0.0.0-20170206194824-a7ddd980baf9/go.mod h1:2wSM9zJkl1UQEFZgSd68NfCgRz1VL1jzy/RjCg+ULrs=
+github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
+github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
+github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
+github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
+github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
+github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
+github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
+github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
+github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
+github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
+github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
+github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
+github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/jaypipes/ghw v0.9.0 h1:TWF4wNIGtZcgDJaiNcFgby5BR8s2ixcUe0ydxNO2McY=
+github.com/jaypipes/ghw v0.9.0/go.mod h1:dXMo19735vXOjpIBDyDYSp31sB2u4hrtRCMxInqQ64k=
+github.com/jaypipes/pcidb v1.0.0 h1:vtZIfkiCUE42oYbJS0TAq9XSfSmcsgo9IdxSm9qzYU8=
+github.com/jaypipes/pcidb v1.0.0/go.mod h1:TnYUvqhPBzCKnH34KrIX22kAeEbDCSRJ9cqLRCuNDfk=
+github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
+github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
+github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
+github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mudler/go-pluggable v0.0.0-20220716112424-189d463e3ff3 h1:t4X6t8WisUy5mExfS58RBOkzaEGmuor5kOUMQS8lT2g=
+github.com/mudler/go-pluggable v0.0.0-20220716112424-189d463e3ff3/go.mod h1:WmKcT8ONmhDQIqQ+HxU+tkGWjzBEyY/KFO8LTGCu4AI=
+github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
+github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
+github.com/onsi/ginkgo v1.14.2 h1:8mVmC9kjFFmA8H4pKMUhcblgifdkOIXPvbhN1T36q1M=
+github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
+github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
+github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
+github.com/onsi/gomega v1.10.3 h1:gph6h/qe9GSUw1NhH1gp+qb+h8rXD8Cy60Z32Qw3ELA=
+github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc=
+github.com/otiai10/copy v1.7.0 h1:hVoPiN+t+7d2nzzwMiDHPSOogsWAStewq3TwU05+clE=
+github.com/otiai10/copy v1.7.0/go.mod h1:rmRl6QPdJj6EiUqXQ/4Nn2lLXoNQjFCQbbNrxgc/t3U=
+github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=
+github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs=
+github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo=
+github.com/otiai10/mint v1.3.3 h1:7JgpsBaN0uMkyju4tbYHu0mnM55hNKVYLsXmwr15NQI=
+github.com/otiai10/mint v1.3.3/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
+github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
+github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
+github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
+github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
+github.com/tmc/scp v0.0.0-20170824174625-f7b48647feef h1:7D6Nm4D6f0ci9yttWaKjM1TMAXrH5Su72dojqYGntFY=
+github.com/urfave/cli v1.22.9 h1:cv3/KhXGBGjEXLC4bH0sLuJ9BewaAbpk5oyMOveu4pw=
+github.com/urfave/cli v1.22.9/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c=
+golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220803195053-6e608f9ce704 h1:Y7NOhdqIOU8kYI7BxsgL38d0ot0raxvcW+EMQU2QrT4=
+golang.org/x/sys v0.0.0-20220803195053-6e608f9ce704/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
+google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
+google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
+google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM=
+howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g=
diff --git a/main.go b/main.go
new file mode 100644
index 0000000..1b28a60
--- /dev/null
+++ b/main.go
@@ -0,0 +1,342 @@
+package main
+
+import (
+	"fmt"
+	"io/ioutil"
+	"log"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"strings"
+	"time"
+
+	luks "github.com/anatol/luks.go"
+	multierror "github.com/hashicorp/go-multierror"
+	"github.com/jaypipes/ghw"
+	"github.com/jaypipes/ghw/pkg/block"
+	"github.com/keirros-io/kcrypt/pkg/bus"
+	"github.com/mudler/go-pluggable"
+	cp "github.com/otiai10/copy"
+	"github.com/urfave/cli"
+)
+
+// TODO: Ask to discovery a pass to unlock. keep waiting until we get it and a timeout is exhausted with retrials (exp backoff)
+func getPassword(b *block.Partition) (password string, err error) {
+	bus.Reload()
+
+	bus.Manager.Response(bus.EventDiscoveryPassword, func(p *pluggable.Plugin, r *pluggable.EventResponse) {
+		password = r.Data
+		if r.Errored() {
+			err = fmt.Errorf("failed discovery: %s", r.Error)
+		}
+	})
+	bus.Manager.Publish(bus.EventDiscoveryPassword, b)
+
+	if password == "" {
+		return password, fmt.Errorf("received empty password")
+	}
+
+	return
+}
+
+func luksUnlock(device, mapper, password string) error {
+	dev, err := luks.Open(device)
+	if err != nil {
+		// handle error
+		return err
+	}
+	defer dev.Close()
+
+	// set LUKS flags before unlocking the volume
+	if err := dev.FlagsAdd(luks.FlagAllowDiscards); err != nil {
+		log.Print(err)
+	}
+
+	// UnsealVolume+SetupMapper is equivalent of `cryptsetup open /dev/sda1 volumename`
+	volume, err := dev.UnsealVolume(0, []byte(password))
+	if err == luks.ErrPassphraseDoesNotMatch {
+		return fmt.Errorf("incorrect password")
+	} else if err != nil {
+		return err
+	}
+	return volume.SetupMapper(mapper)
+}
+
+func unlockDisk(b *block.Partition) error {
+	pass, err := getPassword(b)
+	if err != nil {
+		return fmt.Errorf("error retreiving password remotely: %w", err)
+	}
+
+	return luksUnlock(fmt.Sprintf("/dev/%s", b.Name), b.UUID, pass)
+}
+
+func createLuks(dev, password, version string, cryptsetupArgs ...string) error {
+	if version == "" {
+		version = "luks2"
+	}
+	args := []string{"luksFormat", "--type", version, "--iter-time", "5", "-q", dev}
+	args = append(args, cryptsetupArgs...)
+	cmd := exec.Command("cryptsetup", args...)
+	cmd.Stdin = strings.NewReader(password)
+	cmd.Stdout = os.Stdout
+	cmd.Stderr = os.Stderr
+
+	if err := cmd.Run(); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func createDiskImage() (*os.File, error) {
+	disk, err := ioutil.TempFile("", "luksv2.go.disk")
+	if err != nil {
+		return nil, err
+	}
+
+	if err := disk.Truncate(24 * 1024 * 1024); err != nil {
+		return nil, err
+	}
+
+	return disk, err
+}
+
+// TODO: A crypt disk utility to call after install, that with discovery discoveries the password that should be used
+// this function should delete COS_PERSISTENT. delete the partition and create a luks+type in place.
+
+// Take a part label, and recreates it with LUKS. IT OVERWRITES DATA!
+func luksify(label string) error {
+	// blkid
+	persistent, b, err := findPartition(label)
+	if err != nil {
+		return err
+	}
+
+	pass, err := getPassword(b)
+	if err != nil {
+		return err
+	}
+
+	if err := createLuks(persistent, pass, "luks2"); err != nil {
+		return err
+	}
+
+	if err := luksUnlock(persistent, b.UUID, pass); err != nil {
+		return err
+	}
+
+	out, err := sh(fmt.Sprintf("mkfs.ext4 %s -n %s", b.UUID, label))
+
+	if err != nil {
+		return fmt.Errorf("err: %w, out: %s", err, out)
+	}
+
+	return nil
+}
+
+func findPartition(label string) (string, *block.Partition, error) {
+	block, err := ghw.Block()
+	if err == nil {
+		for _, disk := range block.Disks {
+			for _, p := range disk.Partitions {
+				if p.Label == label {
+					return p.Name, p, nil
+				}
+
+			}
+		}
+	} else {
+		return "", nil, err
+	}
+
+	return "", nil, fmt.Errorf("not found")
+}
+
+func sh(c string) (string, error) {
+	o, err := exec.Command("/bin/sh", "-c", c).CombinedOutput()
+	return string(o), err
+}
+
+const (
+	GZType = "gz"
+	XZType = "xz"
+	LZMAType = "lzma"
+)
+
+// TODO: replace with golang native code
+func detect(archive string) (string, error) {
+	out, err := sh(fmt.Sprintf("file %s", archive))
+	if err != nil {
+		return "", err
+	}
+	out = strings.ToLower(out)
+	if strings.Contains(out, "xz") {
+		return XZType, nil
+
+		} else if strings.Contains(out, "lzma") {
+			return LZMAType, nil
+
+	} else if strings.Contains(out, "gz") {
+		return GZType, nil
+
+	}
+
+	return "", fmt.Errorf("Unknown")
+}
+
+// TODO: replace with golang native code
+func extractInitrd(initrd string, dst string) error {
+	os.MkdirAll(dst, os.ModePerm)
+	var out string
+	var err error
+	format, err := detect(initrd)
+	if err != nil {
+		return err
+	}
+	if format == XZType || format == LZMAType {
+		out, err = sh(fmt.Sprintf("cd %s && xz -dc <  %s | cpio -idmv", dst, initrd))
+	} else if format == GZType {
+		out, err = sh(fmt.Sprintf("cd %s && zcat %s | cpio -idmv", dst, initrd))
+	}
+	fmt.Println(out)
+
+	return err
+}
+
+func createInitrd(initrd string, src string, format string) error {
+	fmt.Printf("Creating '%s' from '%s' as '%s'\n",initrd, src,format)
+
+	if _, err := os.Stat(src); err != nil {
+		return err
+	}
+	var err error
+	var out string
+	if format == XZType {
+		out, err = sh(fmt.Sprintf("cd %s && find . 2>/dev/null | cpio -H newc --quiet --null -o -R root:root | xz -0 --check=crc32 > %s", src, initrd))
+	} else if format == GZType {
+		out, err = sh(fmt.Sprintf("cd %s && find . | cpio -H newc -o -R root:root | gzip -9 > %s", src, initrd))
+	} else if format == LZMAType {
+		out, err = sh(fmt.Sprintf("cd %s && find . 2>/dev/null | cpio -H newc -o -R root:root | xz -9 --format=lzma > %s", src, initrd))
+	}
+	fmt.Println(out)
+
+	return err
+}
+
+// TODO: A inject initramfs command to add the discovery e.g. to use inside Dockerfiles
+
+func injectInitrd(initrd string, file, dst string) error {
+
+    fmt.Printf("Injecting '%s' as '%s' into '%s'\n",file, dst,initrd)
+	format, err := detect(initrd)
+	if err != nil {
+		return err
+	}
+	tmp, err := ioutil.TempDir("", "kcrypt")
+	if err != nil {
+		return fmt.Errorf("cannot create tempdir, %s", err)
+	}
+	defer os.RemoveAll(tmp)
+
+    fmt.Printf("Extracting '%s' in '%s' ...\n",initrd, tmp)
+	if err := extractInitrd(initrd, tmp); err != nil {
+		return fmt.Errorf("cannot extract initrd, %s", err)
+	}
+
+	d:=filepath.Join(tmp, dst)
+	fmt.Printf("Copying '%s' in '%s' ...\n",file, d)
+	if err := cp.Copy(file, d); err != nil {
+		return fmt.Errorf("cannot copy file, %s", err)
+	}
+
+	return createInitrd(initrd, tmp, format)
+}
+
+// TODO: a custom toolkit version, to build out initrd pre-built with this component
+func unlockAll() error {
+	bus.Manager.Initialize()
+
+	block, err := ghw.Block()
+	if err == nil {
+		for _, disk := range block.Disks {
+			for _, p := range disk.Partitions {
+				if p.Type == "crypto_LUKS" {
+					fmt.Printf("Unmounted Luks found at '%s' LABEL '%s' \n", p.Name, p.Label)
+					err = multierror.Append(err, unlockDisk(p))
+					if err != nil {
+						fmt.Printf("Unlocking failed: '%s'\n", err.Error())
+					}
+					time.Sleep(10 * time.Second)
+				}
+			}
+		}
+	}
+	return err
+}
+
+func main() {
+	app := &cli.App{
+		Name:    "keiros-kcrypt",
+		Version: "0.1",
+		Author:  "Ettore Di Giacinto",
+		Usage:   "keiros escrow key agent component",
+		Description: ``,
+		UsageText: ``,
+		Copyright: "Ettore Di Giacinto",
+		Commands: []cli.Command{
+			{
+
+				Name: "extract-initrd",
+				Action: func(c *cli.Context) error {
+					if c.NArg() != 2 {
+						return fmt.Errorf("requires 3 args. initrd,, dst")
+					}
+					return extractInitrd(c.Args()[0], c.Args()[1])
+				},
+			},
+			{
+
+				Name:        "encrypt",
+				Description: "Encrypts a partition",
+				Action: func(c *cli.Context) error {
+					if c.NArg() != 1 {
+						return fmt.Errorf("requires 1 arg, the partition label")
+					}
+					return luksify(c.Args().First())
+				},
+			},
+			{
+
+				Name: "inject-initrd",
+				Action: func(c *cli.Context) error {
+					if c.NArg() != 3 {
+						return fmt.Errorf("requires 3 args. initrd, srcfile, dst")
+					}
+					return injectInitrd(c.Args()[0], c.Args()[1], c.Args()[2])
+				},
+			},
+			{
+				Name:      "unlock-all",
+				UsageText: "unlock-all",
+				Usage:     "Try to unlock all LUKS partitions",
+				Description: `
+Typically run during initrd to unlock all the LUKS partitions found
+		`,
+				ArgsUsage: "kcrypt unlock-all",
+				Flags: []cli.Flag{
+
+					&cli.StringFlag{},
+				},
+				Action: func(c *cli.Context) error {
+					return unlockAll()
+				},
+			},
+		},
+	}
+
+	if err := app.Run(os.Args); err != nil {
+		fmt.Println(err.Error())
+		os.Exit(1)
+	}
+}
diff --git a/pkg/bus/bus.go b/pkg/bus/bus.go
new file mode 100644
index 0000000..f3b5a2b
--- /dev/null
+++ b/pkg/bus/bus.go
@@ -0,0 +1,65 @@
+package bus
+
+import (
+	"fmt"
+	"os"
+
+	"github.com/mudler/go-pluggable"
+)
+
+// Manager is the bus instance manager, which subscribes plugins to events emitted.
+var Manager = NewBus()
+
+func NewBus() *Bus {
+	return &Bus{
+		Manager: pluggable.NewManager(AllEvents),
+	}
+}
+
+func Reload() {
+	Manager = NewBus()
+	Manager.Initialize()
+}
+
+type Bus struct {
+	*pluggable.Manager
+	registered bool
+}
+
+func (b *Bus) LoadProviders() {
+	wd, _ := os.Getwd()
+	b.Manager.Autoload("kcrypt-discovery", "/system/discovery", "/oem/kcrypt", wd).Register()
+}
+
+func (b *Bus) Initialize() {
+	if b.registered {
+		return
+	}
+
+	b.LoadProviders()
+	for i := range b.Manager.Events {
+		e := b.Manager.Events[i]
+		b.Manager.Response(e, func(p *pluggable.Plugin, r *pluggable.EventResponse) {
+			if os.Getenv("BUS_DEBUG") == "true" {
+				fmt.Println(
+					fmt.Sprintf("[provider event: %s]", e),
+					"received from",
+					p.Name,
+					"at",
+					p.Executable,
+					r,
+				)
+			}
+			if r.Errored() {
+				err := fmt.Sprintf("Provider %s at %s had an error: %s", p.Name, p.Executable, r.Error)
+				fmt.Println(err)
+				os.Exit(1)
+			} else {
+				if r.State != "" {
+					fmt.Println(fmt.Sprintf("[provider event: %s]", e), r.State)
+				}
+			}
+		})
+	}
+	b.registered = true
+}
diff --git a/pkg/bus/events.go b/pkg/bus/events.go
new file mode 100644
index 0000000..b39b5ac
--- /dev/null
+++ b/pkg/bus/events.go
@@ -0,0 +1,45 @@
+package bus
+
+import (
+	"github.com/mudler/go-pluggable"
+)
+
+const (
+	// Package events.
+
+	// EventChallenge is issued before installation begins to gather information about how the device should be provisioned.
+	EventDiscoveryPassword pluggable.EventType = "discovery.password"
+)
+
+// AllEvents is a convenience list of all the events streamed from the bus.
+var AllEvents = []pluggable.EventType{
+	EventDiscoveryPassword,
+}
+
+// IsEventDefined checks wether an event is defined in the bus.
+// It accepts strings or EventType, returns a boolean indicating that
+// the event was defined among the events emitted by the bus.
+func IsEventDefined(i interface{}) bool {
+	checkEvent := func(e pluggable.EventType) bool {
+		for _, ee := range AllEvents {
+			if ee == e {
+				return true
+			}
+		}
+
+		return false
+	}
+
+	switch f := i.(type) {
+	case string:
+		return checkEvent(pluggable.EventType(f))
+	case pluggable.EventType:
+		return checkEvent(f)
+	default:
+		return false
+	}
+}
+
+func EventError(err error) pluggable.EventResponse {
+	return pluggable.EventResponse{Error: err.Error()}
+}