From 5ad1f23e6d029ed0c2a186cc52bbcaec29959352 Mon Sep 17 00:00:00 2001 From: "Valentin (developer-digital)" Date: Wed, 11 Mar 2026 07:26:40 +0000 Subject: [PATCH] fix(contacts): guard --from-file against all conflicting flags Flags --org, --title, --url, --note, --address and --custom were missing from the conflict check that rejects mixing --from-file with individual update flags. Omitting them meant the guard could be silently bypassed, letting users pass contradictory inputs without an error. Added all six flags to the existing conditional, and extended TestContactsUpdate_FromFile_CantCombineWithFlags with a table-driven sub-test covering each previously unguarded flag. --- internal/cmd/contacts_crud.go | 5 +++- .../cmd/contacts_update_json_more_test.go | 23 ++++++++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/internal/cmd/contacts_crud.go b/internal/cmd/contacts_crud.go index f574e668..e59b6239 100644 --- a/internal/cmd/contacts_crud.go +++ b/internal/cmd/contacts_crud.go @@ -440,7 +440,10 @@ func (c *ContactsUpdateCmd) Run(ctx context.Context, kctx *kong.Context, flags * } if strings.TrimSpace(c.FromFile) != "" { - if flagProvided(kctx, "given") || flagProvided(kctx, "family") || flagProvided(kctx, "email") || flagProvided(kctx, "phone") || flagProvided(kctx, "birthday") || flagProvided(kctx, "notes") || flagProvided(kctx, "relation") { + if flagProvided(kctx, "given") || flagProvided(kctx, "family") || flagProvided(kctx, "email") || flagProvided(kctx, "phone") || + flagProvided(kctx, "org") || flagProvided(kctx, "title") || flagProvided(kctx, "url") || + flagProvided(kctx, "note") || flagProvided(kctx, "address") || flagProvided(kctx, "custom") || + flagProvided(kctx, "birthday") || flagProvided(kctx, "notes") || flagProvided(kctx, "relation") { return usage("can't combine --from-file with other update flags") } return c.updateFromJSON(ctx, svc, resourceName, u) diff --git a/internal/cmd/contacts_update_json_more_test.go b/internal/cmd/contacts_update_json_more_test.go index ec985356..9fbb4d65 100644 --- a/internal/cmd/contacts_update_json_more_test.go +++ b/internal/cmd/contacts_update_json_more_test.go @@ -189,8 +189,29 @@ func TestContactsUpdate_FromFile_CantCombineWithFlags(t *testing.T) { } _ = tmp.Close() + // Previously covered: --email err = runKong(t, &ContactsUpdateCmd{}, []string{"people/c1", "--from-file", tmp.Name(), "--email", "x@example.com"}, context.Background(), &RootFlags{Account: "a@b.com"}) if err == nil || !strings.Contains(err.Error(), "can't combine --from-file") { - t.Fatalf("expected combine error, got %v", err) + t.Fatalf("expected combine error for --email, got %v", err) + } + + // Flags that were previously missing from the conflict guard: org, title, url, note, address, custom + conflictCases := []struct { + name string + extra []string + }{ + {"org", []string{"--org", "Acme"}}, + {"title", []string{"--title", "CEO"}}, + {"url", []string{"--url", "https://example.com"}}, + {"note", []string{"--note", "some note"}}, + {"address", []string{"--address", "123 Main St"}}, + {"custom", []string{"--custom", "key=value"}}, + } + for _, tc := range conflictCases { + args := append([]string{"people/c1", "--from-file", tmp.Name()}, tc.extra...) + runErr := runKong(t, &ContactsUpdateCmd{}, args, context.Background(), &RootFlags{Account: "a@b.com"}) + if runErr == nil || !strings.Contains(runErr.Error(), "can't combine --from-file") { + t.Fatalf("expected combine error for --%s, got %v", tc.name, runErr) + } } }