util/syspolicy/setting: use a custom marshaler for time.Duration

jsonv2 now returns an error when you marshal or unmarshal a time.Duration
without an explicit format flag. This is an intentional, temporary choice until
the default [time.Duration] representation is decided (see golang/go#71631).

setting.Snapshot can hold time.Duration values inside a map[string]any,
so the jsonv2 update breaks marshaling. In this PR, we start using
a custom marshaler until that decision is made or golang/go#71664
lets us specify the format explicitly.

This fixes `tailscale syspolicy list` failing when KeyExpirationNotice
or any other time.Duration policy setting is configured.

Fixes #16683

Signed-off-by: Nick Khyl <nickk@tailscale.com>
This commit is contained in:
Nick Khyl
2025-07-28 12:23:40 -05:00
committed by Nick Khyl
parent a9f3fd1c67
commit 4df02bbb48
2 changed files with 32 additions and 1 deletions

View File

@@ -491,6 +491,18 @@ func TestMarshalUnmarshalSnapshot(t *testing.T) {
snapshot: NewSnapshot(map[Key]RawItem{"ListPolicy": RawItemOf([]string{"Value1", "Value2"})}),
wantJSON: `{"Settings": {"ListPolicy": {"Value": ["Value1", "Value2"]}}}`,
},
{
name: "Duration/Zero",
snapshot: NewSnapshot(map[Key]RawItem{"DurationPolicy": RawItemOf(time.Duration(0))}),
wantJSON: `{"Settings": {"DurationPolicy": {"Value": "0s"}}}`,
wantBack: NewSnapshot(map[Key]RawItem{"DurationPolicy": RawItemOf("0s")}),
},
{
name: "Duration/NonZero",
snapshot: NewSnapshot(map[Key]RawItem{"DurationPolicy": RawItemOf(2 * time.Hour)}),
wantJSON: `{"Settings": {"DurationPolicy": {"Value": "2h0m0s"}}}`,
wantBack: NewSnapshot(map[Key]RawItem{"DurationPolicy": RawItemOf("2h0m0s")}),
},
{
name: "Empty/With-Summary",
snapshot: NewSnapshot(