@@ -14,6 +14,7 @@ import (
1414
1515 "github.com/steipete/gogcli/internal/app"
1616 "github.com/steipete/gogcli/internal/config"
17+ "github.com/steipete/gogcli/internal/secrets"
1718)
1819
1920func setTestConfigHome (t * testing.T ) {
@@ -396,6 +397,93 @@ func TestConfigGmailNoSendBlocksBeforeAuth(t *testing.T) {
396397 }
397398}
398399
400+ func TestConfigNoSendAccountBlocksBeforeDryRun (t * testing.T ) {
401+ t .Parallel ()
402+
403+ store := config .NewConfigStore (config.Layout {ConfigDir : t .TempDir ()})
404+ if err := store .Write (config.File {
405+ AccountAliases :
map [
string ]
string {
"work" :
"[email protected] " },
406+ NoSendAccounts :
map [
string ]
bool {
"[email protected] " :
true },
407+ }); err != nil {
408+ t .Fatalf ("WriteConfig: %v" , err )
409+ }
410+ runtime := & app.Runtime {Config : store }
411+ tests := [][]string {
412+ {
"gmail" ,
"send" ,
"--account" ,
"[email protected] " ,
"--to" ,
"[email protected] " ,
"--subject" ,
"S" ,
"--body" ,
"B" ,
"--dry-run" },
413+ {
"gmail" ,
"autoreply" ,
"from:[email protected] " ,
"--account" ,
"[email protected] " ,
"--subject" ,
"S" ,
"--body" ,
"B" ,
"--dry-run" },
414+ {
"gmail" ,
"forward" ,
"msg-1" ,
"--account" ,
"[email protected] " ,
"--to" ,
"[email protected] " ,
"--dry-run" },
415+ {
"gmail" ,
"drafts" ,
"send" ,
"draft-1" ,
"--account" ,
"[email protected] " ,
"--dry-run" },
416+ // Alias resolving to a guarded account is blocked too.
417+ {
"gmail" ,
"send" ,
"--account" ,
"work" ,
"--to" ,
"[email protected] " ,
"--subject" ,
"S" ,
"--body" ,
"B" ,
"--dry-run" },
418+ }
419+ for _ , args := range tests {
420+ result := executeWithTestRuntime (t , args , runtime )
421+ err := result .err
422+ if err == nil {
423+ t .Fatalf ("expected error for %v" , args )
424+ }
425+ if ! strings .Contains (err .Error (), "no-send" ) {
426+ t .Fatalf ("unexpected error for %v: %v" , args , err )
427+ }
428+ }
429+ }
430+
431+ func TestConfigNoSendAccountDoesNotOverblockDryRun (t * testing.T ) {
432+ t .Parallel ()
433+
434+ store := config .NewConfigStore (config.Layout {ConfigDir : t .TempDir ()})
435+ if err := store .
Write (config.
File {
NoSendAccounts :
map [
string ]
bool {
"[email protected] " :
true }});
err != nil {
436+ t .Fatalf ("WriteConfig: %v" , err )
437+ }
438+ runtime := & app.Runtime {Config : store }
439+ tests := [][]string {
440+ // Send from a different account is not blocked.
441+ {
"gmail" ,
"send" ,
"--account" ,
"[email protected] " ,
"--to" ,
"[email protected] " ,
"--subject" ,
"S" ,
"--body" ,
"B" ,
"--dry-run" },
442+ // Non-send commands for the guarded account are not blocked.
443+ {
"gmail" ,
"drafts" ,
"create" ,
"--account" ,
"[email protected] " ,
"--to" ,
"[email protected] " ,
"--subject" ,
"S" ,
"--body" ,
"B" ,
"--dry-run" },
444+ }
445+ for _ , args := range tests {
446+ result := executeWithTestRuntime (t , args , runtime )
447+ if result .err != nil {
448+ t .Fatalf ("expected success for %v, got %v\n stderr=%q" , args , result .err , result .stderr )
449+ }
450+ }
451+ }
452+
453+ func TestGmailSendDryRunWithoutGuardsSkipsAccountResolution (t * testing.T ) {
454+ t .Parallel ()
455+
456+ // No per-account guards configured: dry-run must succeed without any
457+ // account being resolvable (resolution would otherwise read the
458+ // keyring before the dry-run exit).
459+ store := config .NewConfigStore (config.Layout {ConfigDir : t .TempDir ()})
460+ runtime := & app.Runtime {Config : store }
461+ args := []
string {
"gmail" ,
"send" ,
"--to" ,
"[email protected] " ,
"--subject" ,
"S" ,
"--body" ,
"B" ,
"--dry-run" }
462+ result := executeWithTestRuntime (t , args , runtime )
463+ if result .err != nil {
464+ t .Fatalf ("expected success for %v, got %v\n stderr=%q" , args , result .err , result .stderr )
465+ }
466+ }
467+
468+ func TestGmailSendDryRunWithInactiveGuardsSkipsAccountResolution (t * testing.T ) {
469+ t .Parallel ()
470+
471+ store := config .NewConfigStore (config.Layout {ConfigDir : t .TempDir ()})
472+ if err := store .
Write (config.
File {
NoSendAccounts :
map [
string ]
bool {
"[email protected] " :
false }});
err != nil {
473+ t .Fatalf ("WriteConfig: %v" , err )
474+ }
475+ runtime := & app.Runtime {Config : store }
476+ runtime .Auth .OpenSecretsStore = func () (secrets.Store , error ) {
477+ t .Fatal ("inactive no-send entries must not trigger account resolution" )
478+ return nil , errors .New ("unexpected account resolution" )
479+ }
480+ args := []
string {
"gmail" ,
"send" ,
"--to" ,
"[email protected] " ,
"--subject" ,
"S" ,
"--body" ,
"B" ,
"--dry-run" }
481+ result := executeWithTestRuntime (t , args , runtime )
482+ if result .err != nil {
483+ t .Fatalf ("expected success for %v, got %v\n stderr=%q" , args , result .err , result .stderr )
484+ }
485+ }
486+
399487func TestConfigIndependentCommandsDoNotRequireHome (t * testing.T ) {
400488 t .Setenv ("HOME" , "" )
401489 t .Setenv ("USERPROFILE" , "" )
0 commit comments