Compare commits
4 Commits
8ed10dd503
...
v0.5.2
| Author | SHA1 | Date | |
|---|---|---|---|
| 3c5e0a26f3 | |||
| 456d25d4f3 | |||
| 3bea73f857 | |||
| c651b00d08 |
+12
-3
@@ -330,7 +330,19 @@ func runWhitelist(args []string, role store.Role, out, errOut io.Writer) int {
|
||||
return 2
|
||||
}
|
||||
dir := store.Direction(args[0])
|
||||
if dir != store.DirIn && dir != store.DirOut {
|
||||
fmt.Fprintf(errOut, "whitelist direction must be \"in\" or \"out\", got %q\n", args[0])
|
||||
fmt.Fprintln(errOut, "usage: emcli whitelist <in|out> <add|remove|list> [flags]")
|
||||
return 2
|
||||
}
|
||||
sub, rest := args[1], args[2:]
|
||||
switch sub {
|
||||
case "add", "remove", "list": // valid
|
||||
default:
|
||||
fmt.Fprintf(errOut, "unknown whitelist subcommand %q (want add|remove|list)\n", sub)
|
||||
fmt.Fprintln(errOut, "usage: emcli whitelist <in|out> <add|remove|list> [flags]")
|
||||
return 2
|
||||
}
|
||||
fs := flag.NewFlagSet("whitelist", flag.ContinueOnError)
|
||||
fs.SetOutput(errOut)
|
||||
account := fs.String("account", "", "account name")
|
||||
@@ -371,9 +383,6 @@ func runWhitelist(args []string, role store.Role, out, errOut io.Writer) int {
|
||||
for _, a := range addrs {
|
||||
fmt.Fprintln(out, a)
|
||||
}
|
||||
default:
|
||||
fmt.Fprintf(errOut, "unknown whitelist subcommand %q\n", sub)
|
||||
return 2
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -110,6 +110,51 @@ func TestAccountEditPartialPreservesOtherFields(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// A missing direction (e.g. `whitelist list`) must report the real problem —
|
||||
// the in|out direction — not the misleading "--account is required".
|
||||
func TestWhitelistMissingDirectionReported(t *testing.T) {
|
||||
adminEnv(t)
|
||||
code, _, errOut := run(t, "whitelist", "list", "--account", "bobby")
|
||||
if code == 0 {
|
||||
t.Fatal("missing direction must be a usage error")
|
||||
}
|
||||
if strings.Contains(errOut, "--account is required") {
|
||||
t.Fatalf("misleading error; want a direction complaint, got: %q", errOut)
|
||||
}
|
||||
if !strings.Contains(errOut, "in") || !strings.Contains(errOut, "out") {
|
||||
t.Fatalf("error should name the in|out direction, got: %q", errOut)
|
||||
}
|
||||
}
|
||||
|
||||
// A missing subcommand (e.g. `whitelist out --account x`) must report the real
|
||||
// problem — the add|remove|list subcommand — not "--account is required".
|
||||
func TestWhitelistMissingSubcommandReported(t *testing.T) {
|
||||
adminEnv(t)
|
||||
code, _, errOut := run(t, "whitelist", "out", "--account", "bobby")
|
||||
if code == 0 {
|
||||
t.Fatal("missing subcommand must be a usage error")
|
||||
}
|
||||
if strings.Contains(errOut, "--account is required") {
|
||||
t.Fatalf("misleading error; want a subcommand complaint, got: %q", errOut)
|
||||
}
|
||||
if !strings.Contains(errOut, "add") || !strings.Contains(errOut, "list") {
|
||||
t.Fatalf("error should name the add|remove|list subcommand, got: %q", errOut)
|
||||
}
|
||||
}
|
||||
|
||||
// The happy path still works after the direction/subcommand validation.
|
||||
func TestWhitelistListWorks(t *testing.T) {
|
||||
adminEnv(t)
|
||||
run(t, "account", "add", "--name", "bobby", "--imap-host", "h", "--username", "u@x.com")
|
||||
if code, _, e := run(t, "whitelist", "out", "add", "--account", "bobby", "--address", "@x.com"); code != 0 {
|
||||
t.Fatalf("add failed: %s", e)
|
||||
}
|
||||
code, out, _ := run(t, "whitelist", "out", "list", "--account", "bobby")
|
||||
if code != 0 || !strings.Contains(out, "@x.com") {
|
||||
t.Fatalf("list: code=%d out=%q", code, out)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuditListCoreRenders(t *testing.T) {
|
||||
st, err := store.Open(filepath.Join(t.TempDir(), "e.db"))
|
||||
if err != nil {
|
||||
|
||||
+16
-1
@@ -8,6 +8,7 @@ import (
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
_ "modernc.org/sqlite"
|
||||
)
|
||||
@@ -77,10 +78,24 @@ func (s *Store) migrate() error {
|
||||
|
||||
func (s *Store) Close() error { return s.db.Close() }
|
||||
|
||||
// expandUserHome replaces a leading "~" or "~/" in p with the user's home
|
||||
// directory. Only a leading tilde is expanded (the usual shell convention) —
|
||||
// "~user" and a tilde elsewhere in the path are left untouched. This guards
|
||||
// against an EMCLI_DB set to a literal "~/..." (no shell to expand it), which
|
||||
// would otherwise be opened relative to the cwd and create a stray "~" dir.
|
||||
func expandUserHome(p string) string {
|
||||
if p == "~" || strings.HasPrefix(p, "~/") {
|
||||
if home, err := os.UserHomeDir(); err == nil {
|
||||
return filepath.Join(home, strings.TrimPrefix(p[1:], "/"))
|
||||
}
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
// DefaultDBPath resolves EMCLI_DB or the per-OS default location.
|
||||
func DefaultDBPath() (string, error) {
|
||||
if p := os.Getenv("EMCLI_DB"); p != "" {
|
||||
return p, nil
|
||||
return expandUserHome(p), nil
|
||||
}
|
||||
if runtime.GOOS == "windows" {
|
||||
if dir := os.Getenv("AppData"); dir != "" {
|
||||
|
||||
@@ -2,10 +2,53 @@ package store
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// A leading "~" in EMCLI_DB must be expanded to the home dir, so a literal
|
||||
// tilde (no shell to expand it) can't be opened relative to the cwd and
|
||||
// silently create a stray "~" directory.
|
||||
func TestDefaultDBPathExpandsLeadingTilde(t *testing.T) {
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
t.Skipf("no home dir: %v", err)
|
||||
}
|
||||
cases := map[string]string{
|
||||
"~/.config/emcli/emcli.db": filepath.Join(home, ".config", "emcli", "emcli.db"),
|
||||
"~": home,
|
||||
}
|
||||
for in, want := range cases {
|
||||
t.Setenv("EMCLI_DB", in)
|
||||
got, err := DefaultDBPath()
|
||||
if err != nil {
|
||||
t.Fatalf("DefaultDBPath(%q): %v", in, err)
|
||||
}
|
||||
if got != want {
|
||||
t.Fatalf("EMCLI_DB=%q -> %q, want %q", in, got, want)
|
||||
}
|
||||
if strings.Contains(got, "~") {
|
||||
t.Fatalf("EMCLI_DB=%q left a literal tilde: %q", in, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A non-leading tilde or "~user" is NOT a path we should rewrite — leave it be.
|
||||
func TestDefaultDBPathLeavesOtherPathsUntouched(t *testing.T) {
|
||||
for _, p := range []string{"/var/lib/emcli.db", "./rel/emcli.db", "~user/db"} {
|
||||
t.Setenv("EMCLI_DB", p)
|
||||
got, err := DefaultDBPath()
|
||||
if err != nil {
|
||||
t.Fatalf("DefaultDBPath(%q): %v", p, err)
|
||||
}
|
||||
if got != p {
|
||||
t.Fatalf("EMCLI_DB=%q was rewritten to %q", p, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// openTemp opens a fresh store in a temp dir and initialises keys so that
|
||||
// account tests (which do crypto) work without needing their own setup.
|
||||
func openTemp(t *testing.T) *Store {
|
||||
|
||||
@@ -54,7 +54,7 @@ checksum, makes it executable in `~/.local/bin` (ensure that's on your PATH), an
|
||||
|
||||
| Variable | Default | Purpose |
|
||||
|---|---|---|
|
||||
| `EMCLI_VERSION` | `v0.5.0` | Release tag to fetch |
|
||||
| `EMCLI_VERSION` | `v0.5.2` | Release tag to fetch |
|
||||
| `EMCLI_BASE_URL` | `https://gitea.dcglab.co.uk/steve/emcli` | Repo base URL |
|
||||
| `EMCLI_INSTALL_DIR` | `$HOME/.local/bin` | Install location |
|
||||
|
||||
|
||||
@@ -7,17 +7,17 @@
|
||||
# bash install.sh
|
||||
#
|
||||
# Environment overrides:
|
||||
# EMCLI_VERSION release tag to fetch (default: v0.5.0)
|
||||
# EMCLI_VERSION release tag to fetch (default: v0.5.2)
|
||||
# EMCLI_BASE_URL repo base URL (default: https://gitea.dcglab.co.uk/steve/emcli)
|
||||
# EMCLI_INSTALL_DIR where to put the binary (default: $HOME/.local/bin)
|
||||
#
|
||||
# Release assets follow this naming scheme:
|
||||
# emcli_<version>_<os>_<arch>[.exe] e.g. emcli_0.5.0_linux_amd64
|
||||
# emcli_<version>_<os>_<arch>[.exe] e.g. emcli_0.5.2_linux_amd64
|
||||
# checksums.txt (sha256, one "<sum> <asset>" line per asset)
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
VERSION="${EMCLI_VERSION:-v0.5.0}"
|
||||
VERSION="${EMCLI_VERSION:-v0.5.2}"
|
||||
BASE_URL="${EMCLI_BASE_URL:-https://gitea.dcglab.co.uk/steve/emcli}"
|
||||
INSTALL_DIR="${EMCLI_INSTALL_DIR:-$HOME/.local/bin}"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user