From 9e18d1de77b2c9bb24a51c2e99b060c6d06818ee Mon Sep 17 00:00:00 2001
From: Ophestra <cat@gensokyo.uk>
Date: Fri, 14 Mar 2025 23:23:57 +0900
Subject: [PATCH] helper/proc: pass extra files and start

For integration with native container tooling.

Signed-off-by: Ophestra <cat@gensokyo.uk>
---
 helper/bwrap.go             |  2 +-
 helper/direct.go            |  5 ++---
 helper/proc/files.go        |  9 ++++++---
 internal/executable_test.go | 17 +++++++++++++++++
 4 files changed, 26 insertions(+), 7 deletions(-)
 create mode 100644 internal/executable_test.go

diff --git a/helper/bwrap.go b/helper/bwrap.go
index 86aff4d..a1f6e42 100644
--- a/helper/bwrap.go
+++ b/helper/bwrap.go
@@ -45,7 +45,7 @@ func (b *bubblewrap) Start(stat bool) error {
 	b.Cmd.Args = slices.Grow(b.Cmd.Args, 4+len(args))
 	b.Cmd.Args = append(b.Cmd.Args, "--args", strconv.Itoa(int(b.argsFd)), "--", b.name)
 	b.Cmd.Args = append(b.Cmd.Args, args...)
-	return proc.Fulfill(b.ctx, b.Cmd, b.files, b.extraFiles)
+	return proc.Fulfill(b.ctx, &b.ExtraFiles, b.Cmd.Start, b.files, b.extraFiles)
 }
 
 // MustNewBwrap initialises a new Bwrap instance with wt as the null-terminated argument writer.
diff --git a/helper/direct.go b/helper/direct.go
index fcc7b4e..9e27913 100644
--- a/helper/direct.go
+++ b/helper/direct.go
@@ -9,8 +9,7 @@ import (
 	"git.gensokyo.uk/security/fortify/helper/proc"
 )
 
-// direct wraps *exec.Cmd and manages status and args fd.
-// Args is always 3 and status if set is always 4.
+// direct starts the helper directly and manages status and args fd.
 type direct struct {
 	lock sync.RWMutex
 	*helperCmd
@@ -28,7 +27,7 @@ func (h *direct) Start(stat bool) error {
 
 	args := h.finalise(stat)
 	h.Cmd.Args = append(h.Cmd.Args, args...)
-	return proc.Fulfill(h.ctx, h.Cmd, h.files, h.extraFiles)
+	return proc.Fulfill(h.ctx, &h.ExtraFiles, h.Cmd.Start, h.files, h.extraFiles)
 }
 
 // New initialises a new direct Helper instance with wt as the null-terminated argument writer.
diff --git a/helper/proc/files.go b/helper/proc/files.go
index 24cc722..e41c3ef 100644
--- a/helper/proc/files.go
+++ b/helper/proc/files.go
@@ -60,7 +60,10 @@ func (f *ExtraFilesPre) copy(e []*os.File) []*os.File {
 }
 
 // Fulfill calls the [File.Fulfill] method on all files, starts cmd and blocks until all fulfillment completes.
-func Fulfill(ctx context.Context, cmd *exec.Cmd, files []File, extraFiles *ExtraFilesPre) (err error) {
+func Fulfill(ctx context.Context,
+	v *[]*os.File, start func() error,
+	files []File, extraFiles *ExtraFilesPre,
+) (err error) {
 	var ecs int
 	for _, o := range files {
 		ecs += o.ErrCount()
@@ -77,8 +80,8 @@ func Fulfill(ctx context.Context, cmd *exec.Cmd, files []File, extraFiles *Extra
 		}
 	}
 
-	cmd.ExtraFiles = extraFiles.Files()
-	if err = cmd.Start(); err != nil {
+	*v = extraFiles.Files()
+	if err = start(); err != nil {
 		return
 	}
 
diff --git a/internal/executable_test.go b/internal/executable_test.go
new file mode 100644
index 0000000..1fdd40a
--- /dev/null
+++ b/internal/executable_test.go
@@ -0,0 +1,17 @@
+package internal_test
+
+import (
+	"os"
+	"testing"
+
+	"git.gensokyo.uk/security/fortify/internal"
+)
+
+func TestExecutable(t *testing.T) {
+	for i := 0; i < 16; i++ {
+		if got := internal.MustExecutable(); got != os.Args[0] {
+			t.Errorf("MustExecutable: %q, want %q",
+				got, os.Args[0])
+		}
+	}
+}