aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--main.go55
-rw-r--r--main_test.go81
2 files changed, 111 insertions, 25 deletions
diff --git a/main.go b/main.go
index 3eaf722c..ce1a4cd2 100644
--- a/main.go
+++ b/main.go
@@ -5,6 +5,7 @@ import (
_ "embed"
"errors"
"fmt"
+ "io"
"log"
"os"
"os/signal"
@@ -52,11 +53,38 @@ func main() {
log.Fatal("this program must not run as root")
}
+ err := buildCommand(os.Stderr).Parse(os.Args[1:])
+ if errors.Is(err, errSuccess) || errors.Is(err, command.ErrHelp) {
+ internal.Exit(0)
+ panic("unreachable")
+ }
+ if errors.Is(err, command.ErrNoMatch) || errors.Is(err, command.ErrEmptyTree) {
+ internal.Exit(1)
+ panic("unreachable")
+ }
+ if err == nil {
+ log.Fatal("unreachable")
+ }
+
+ var flagError command.FlagError
+ if !errors.As(err, &flagError) {
+ log.Printf("command: %v", err)
+ internal.Exit(1)
+ panic("unreachable")
+ }
+ fmsg.Verbose(flagError.Error())
+ if flagError.Success() {
+ internal.Exit(0)
+ }
+ internal.Exit(1)
+}
+
+func buildCommand(out io.Writer) command.Command {
var (
flagVerbose bool
flagJSON bool
)
- c := command.New(os.Stderr, log.Printf, "fortify", func([]string) error { fmsg.Store(flagVerbose); return nil }).
+ c := command.New(out, log.Printf, "fortify", func([]string) error { fmsg.Store(flagVerbose); return nil }).
Flag(&flagVerbose, "v", command.BoolFlag(false), "Print debug messages to the console").
Flag(&flagJSON, "json", command.BoolFlag(false), "Serialise output as JSON when applicable")
@@ -264,30 +292,7 @@ func main() {
c.Command("shim", command.UsageInternal, func([]string) error { shim.Main(); return errSuccess })
c.Command("init", command.UsageInternal, func([]string) error { init0.Main(); return errSuccess })
- err := c.Parse(os.Args[1:])
- if errors.Is(err, errSuccess) || errors.Is(err, command.ErrHelp) {
- internal.Exit(0)
- panic("unreachable")
- }
- if errors.Is(err, command.ErrNoMatch) || errors.Is(err, command.ErrEmptyTree) {
- internal.Exit(1)
- panic("unreachable")
- }
- if err == nil {
- log.Fatal("unreachable")
- }
-
- var flagError command.FlagError
- if !errors.As(err, &flagError) {
- log.Printf("command: %v", err)
- internal.Exit(1)
- panic("unreachable")
- }
- fmsg.Verbose(flagError.Error())
- if flagError.Success() {
- internal.Exit(0)
- }
- internal.Exit(1)
+ return c
}
func runApp(a fst.App, config *fst.Config) {
diff --git a/main_test.go b/main_test.go
new file mode 100644
index 00000000..d965f3e5
--- /dev/null
+++ b/main_test.go
@@ -0,0 +1,81 @@
+package main
+
+import (
+ "bytes"
+ "errors"
+ "flag"
+ "testing"
+
+ "git.gensokyo.uk/security/fortify/command"
+)
+
+func TestHelp(t *testing.T) {
+ testCases := []struct {
+ name string
+ args []string
+ want string
+ }{
+ {
+ "main", []string{}, `
+Usage: fortify [-h | --help] [-v] [--json] COMMAND [OPTIONS]
+
+Commands:
+ app Launch app defined by the specified config file
+ run Configure and start a permissive default sandbox
+ show Show the contents of an app configuration
+ ps List active apps and their state
+ version Show fortify version
+ license Show full license text
+ template Produce a config template
+ help Show this help message
+
+`,
+ },
+ {
+ "run", []string{"run", "-h"}, `
+Usage: fortify run [-h | --help] [--dbus-config <value>] [--dbus-system <value>] [--mpris] [--dbus-log] [--id <value>] [-a <int>] [-g <value>] [-d <value>] [-u <value>] [--wayland] [-X] [--dbus] [--pulse] COMMAND [OPTIONS]
+
+Flags:
+ -X Share X11 socket and allow connection
+ -a int
+ Fortify application ID
+ -d string
+ Application home directory (default "os")
+ -dbus
+ Proxy D-Bus connection
+ -dbus-config string
+ Path to D-Bus proxy config file, or "builtin" for defaults (default "builtin")
+ -dbus-log
+ Force logging in the D-Bus proxy
+ -dbus-system string
+ Path to system D-Bus proxy config file, or "nil" to disable (default "nil")
+ -g value
+ Groups inherited by the app process
+ -id string
+ App ID, leave empty to disable security context app_id
+ -mpris
+ Allow owning MPRIS D-Bus path, has no effect if custom config is available
+ -pulse
+ Share PulseAudio socket and cookie
+ -u string
+ Passwd name within sandbox (default "chronos")
+ -wayland
+ Allow Wayland connections
+
+`,
+ },
+ }
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ out := new(bytes.Buffer)
+ c := buildCommand(out)
+ if err := c.Parse(tc.args); !errors.Is(err, command.ErrHelp) && !errors.Is(err, flag.ErrHelp) {
+ t.Errorf("Parse: error = %v; want %v",
+ err, command.ErrHelp)
+ }
+ if got := out.String(); got != tc.want {
+ t.Errorf("Parse: %s want %s", got, tc.want)
+ }
+ })
+ }
+}