chore: Make deployment admin page show better durations (#6856)

* chore: Make deployment admin page show better durations

Also fix group mappings
This commit is contained in:
Steven Masley
2023-03-29 16:26:20 -05:00
committed by GitHub
parent 872037bf85
commit 90da09bc2c
8 changed files with 115 additions and 37 deletions

View File

@ -190,19 +190,6 @@ func (d *Duration) String() string {
return time.Duration(*d).String()
}
func (d *Duration) MarshalJSON() ([]byte, error) {
return json.Marshal(d.String())
}
func (d *Duration) UnmarshalJSON(b []byte) error {
var s string
err := json.Unmarshal(b, &s)
if err != nil {
return err
}
return d.Set(s)
}
func (Duration) Type() string {
return "duration"
}

View File

@ -170,7 +170,7 @@ backed by Tailscale and WireGuard.
--http-address string, $CODER_HTTP_ADDRESS (default: 127.0.0.1:3000)
HTTP bind address of the server. Unset to disable the HTTP endpoint.
--max-token-lifetime duration, $CODER_MAX_TOKEN_LIFETIME (default: 2562047h47m16.854775807s)
--max-token-lifetime duration, $CODER_MAX_TOKEN_LIFETIME (default: 876600h0m0s)
The maximum lifetime duration users can specify when creating an API
token.

View File

@ -6,7 +6,6 @@ import (
"database/sql"
"errors"
"fmt"
"math"
"net"
"net/http"
"strconv"
@ -354,19 +353,10 @@ func (api *API) tokenConfig(rw http.ResponseWriter, r *http.Request) {
return
}
var maxTokenLifetime time.Duration
// if --max-token-lifetime is unset (default value is math.MaxInt64)
// send back a falsy value
if values.MaxTokenLifetime.Value() == time.Duration(math.MaxInt64) {
maxTokenLifetime = 0
} else {
maxTokenLifetime = values.MaxTokenLifetime.Value()
}
httpapi.Write(
r.Context(), rw, http.StatusOK,
codersdk.TokenConfig{
MaxTokenLifetime: maxTokenLifetime,
MaxTokenLifetime: values.MaxTokenLifetime.Value(),
},
)
}

View File

@ -4,7 +4,6 @@ import (
"context"
"encoding/json"
"flag"
"math"
"net/http"
"os"
"path/filepath"
@ -1113,7 +1112,10 @@ when required by your organization's security policy.`,
Description: "The maximum lifetime duration users can specify when creating an API token.",
Flag: "max-token-lifetime",
Env: "CODER_MAX_TOKEN_LIFETIME",
Default: time.Duration(math.MaxInt64).String(),
// The default value is essentially "forever", so just use 100 years.
// We have to add in the 25 leap days for the frontend to show the
// "100 years" correctly.
Default: ((100 * 365 * time.Hour * 24) + (25 * time.Hour * 24)).String(),
Value: &c.MaxTokenLifetime,
Group: &deploymentGroupNetworkingHTTP,
YAML: "maxTokenLifetime",

View File

@ -233,7 +233,7 @@ Output Stackdriver compatible logs to a given file.
| ----------- | -------------------------------------- |
| Type | <code>duration</code> |
| Environment | <code>$CODER_MAX_TOKEN_LIFETIME</code> |
| Default | <code>2562047h47m16.854775807s</code> |
| Default | <code>876600h0m0s</code> |
The maximum lifetime duration users can specify when creating an API token.

View File

@ -0,0 +1,73 @@
import { optionValue } from "./OptionsTable"
import { DeploymentOption } from "api/types"
const defaultOption: DeploymentOption = {
name: "",
description: "",
flag: "",
flag_shorthand: "",
value: "",
hidden: false,
}
describe("optionValue", () => {
it.each<{
option: DeploymentOption
expected: string | string[] | unknown
}>([
{
option: {
...defaultOption,
name: "Max Token Lifetime",
value: 3600 * 1e9,
},
expected: "1 hour",
},
{
option: {
...defaultOption,
name: "Max Token Lifetime",
value: 24 * 3600 * 1e9,
},
expected: "1 day",
},
{
option: {
...defaultOption,
name: "Session Duration",
value: 3600 * 1e9,
},
expected: "1 hour",
},
{
option: {
...defaultOption,
name: "Session Duration",
value: 24 * 3600 * 1e9,
},
expected: "1 day",
},
{
option: {
...defaultOption,
name: "Strict-Transport-Security",
value: 1000,
},
expected: "1000s",
},
{
option: {
...defaultOption,
name: "OIDC Group Mapping",
value: {
"123": "foo",
"456": "bar",
"789": "baz",
},
},
expected: [`"123"->"foo"`, `"456"->"bar"`, `"789"->"baz"`],
},
])(`[$option.name]optionValue($option.value)`, ({ option, expected }) => {
expect(optionValue(option)).toEqual(expected)
})
})

View File

@ -13,6 +13,7 @@ import {
} from "components/DeploySettingsLayout/Option"
import { FC } from "react"
import { DisabledBadge } from "./Badges"
import { intervalToDuration, formatDuration } from "date-fns"
const OptionsTable: FC<{
options: DeploymentOption[]
@ -34,7 +35,11 @@ const OptionsTable: FC<{
</TableHead>
<TableBody>
{Object.values(options).map((option) => {
if (option.value === null || option.value === "") {
if (
option.value === null ||
option.value === "" ||
option.value === undefined
) {
return null
}
return (
@ -45,7 +50,7 @@ const OptionsTable: FC<{
</TableCell>
<TableCell>
<OptionValue>{option.value}</OptionValue>
<OptionValue>{optionValue(option)}</OptionValue>
</TableCell>
</TableRow>
)
@ -56,6 +61,31 @@ const OptionsTable: FC<{
)
}
// optionValue is a helper function to format the value of a specific deployment options
export function optionValue(
option: DeploymentOption,
): string[] | string | unknown {
switch (option.name) {
case "Max Token Lifetime":
case "Session Duration":
// intervalToDuration takes ms, so convert nanoseconds to ms
return formatDuration(
intervalToDuration({ start: 0, end: (option.value as number) / 1e6 }),
)
case "Strict-Transport-Security":
if (option.value === 0) {
return "Disabled"
}
return (option.value as number).toString() + "s"
case "OIDC Group Mapping":
return Object.entries(option.value as Record<string, string>).map(
([key, value]) => `"${key}"->"${value}"`,
)
default:
return option.value
}
}
const useStyles = makeStyles((theme) => ({
table: {
"& td": {

View File

@ -12,10 +12,6 @@ describe("unit/CreateTokenForm", () => {
maxTokenLifetime: number
expected: LifetimeDay[]
}>([
{
maxTokenLifetime: 0,
expected: lifetimeDayPresets,
},
{ maxTokenLifetime: 6 * 24 * NANO_HOUR, expected: [] },
{
maxTokenLifetime: 20 * 24 * NANO_HOUR,