Commit 2ddf2389c0
Verified · cmc
Layout: unified · split
internal/control/token.go +2 −10
| @@ -122,19 +122,11 @@ func runTokenList(c *Ctx, args []string) int { | ||
| 122 | 122 | for _, t := range tokens { |
| 123 | 123 | ds = append(ds, out{t.Name, t.Scope, t.CreatedAt, t.ExpiresAt, t.LastUsedAt, t.CreatedBy}) |
| 124 | 124 | } |
| 125 | now := time.Now() | |
| 125 | 126 | return c.emit(ds, func(w io.Writer) { |
| 126 | 127 | tb := c.table(w, "NAME", "SCOPE", "EXPIRES") |
| 127 | 128 | for _, d := range ds { |
| 128 | exp := "never expires" | |
| 129 | if d.ExpiresAt != nil { | |
| 130 | ts := d.ExpiresAt.UTC().Format(time.RFC3339Nano) | |
| 131 | if c.Term.Cols == 0 { | |
| 132 | exp = "expires " + stamp(ts) | |
| 133 | } else { | |
| 134 | exp = "expires " + relAge(ts, termNow()) | |
| 135 | } | |
| 136 | } | |
| 137 | tb.row(cRef(d.Name), cState(d.Scope), cText(exp)) | |
| 129 | tb.row(cRef(d.Name), cState(d.Scope), cText(expiresText(d.ExpiresAt, now))) | |
| 138 | 130 | } |
| 139 | 131 | tb.flush() |
| 140 | 132 | }) |
internal/control/token_test.go +24
| @@ -45,6 +45,30 @@ func TestExpiringCredentialCannotMint(t *testing.T) { | ||
| 45 | 45 | } |
| 46 | 46 | } |
| 47 | 47 | |
| 48 | // #286: at a terminal, a token expiring in the future must not render | |
| 49 | // through relAge, which clamps a future time to zero and prints | |
| 50 | // "expires just now". | |
| 51 | func TestTokenListFutureExpiryAtTerminal(t *testing.T) { | |
| 52 | st, _, uid := newQueueTestRepo(t) | |
| 53 | exp := time.Now().Add(90 * 24 * time.Hour) | |
| 54 | if err := st.CreateAPIToken(uid, "laptop", "h-laptop", "read", &exp, 0); err != nil { | |
| 55 | t.Fatal(err) | |
| 56 | } | |
| 57 | c, errOut := pruneCtx(st, t.TempDir(), store.User{ID: uid, Username: "alice"}) | |
| 58 | c.Term = Term{Cols: 80} | |
| 59 | var out bytes.Buffer | |
| 60 | c.Stdout = &out | |
| 61 | if code := Dispatch(c, []string{"token", "list"}); code != protocol.ExitOK { | |
| 62 | t.Fatalf("exit %d: %s", code, errOut) | |
| 63 | } | |
| 64 | if strings.Contains(out.String(), "just now") { | |
| 65 | t.Fatalf("token list at a terminal printed \"just now\" for a future expiry:\n%s", out.String()) | |
| 66 | } | |
| 67 | if !strings.Contains(out.String(), "expires ") { | |
| 68 | t.Fatalf("token list:\n%s", out.String()) | |
| 69 | } | |
| 70 | } | |
| 71 | ||
| 48 | 72 | func TestTokenCreateDefaultsToReadAndRecordsCreator(t *testing.T) { |
| 49 | 73 | st, _, uid := newQueueTestRepo(t) |
| 50 | 74 | if err := st.CreateAPIToken(uid, "parent", "h-parent", "full", nil, 0); err != nil { |