diff --git a/cli/clibase/values.go b/cli/clibase/values.go
index 0ddce1ba8f..ff3d8a7437 100644
--- a/cli/clibase/values.go
+++ b/cli/clibase/values.go
@@ -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"
}
diff --git a/cli/testdata/coder_server_--help.golden b/cli/testdata/coder_server_--help.golden
index eefe266d7c..db804ca8a3 100644
--- a/cli/testdata/coder_server_--help.golden
+++ b/cli/testdata/coder_server_--help.golden
@@ -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.
diff --git a/coderd/apikey.go b/coderd/apikey.go
index c05f0205dc..25a1c767dd 100644
--- a/coderd/apikey.go
+++ b/coderd/apikey.go
@@ -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(),
},
)
}
diff --git a/codersdk/deployment.go b/codersdk/deployment.go
index 9548afec47..60c001ff08 100644
--- a/codersdk/deployment.go
+++ b/codersdk/deployment.go
@@ -4,7 +4,6 @@ import (
"context"
"encoding/json"
"flag"
- "math"
"net/http"
"os"
"path/filepath"
@@ -1113,10 +1112,13 @@ 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(),
- Value: &c.MaxTokenLifetime,
- Group: &deploymentGroupNetworkingHTTP,
- YAML: "maxTokenLifetime",
+ // 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",
},
{
Name: "Enable swagger endpoint",
diff --git a/docs/cli/server.md b/docs/cli/server.md
index 60df9f642a..0cbeb0fde1 100644
--- a/docs/cli/server.md
+++ b/docs/cli/server.md
@@ -233,7 +233,7 @@ Output Stackdriver compatible logs to a given file.
| ----------- | -------------------------------------- |
| Type | duration |
| Environment | $CODER_MAX_TOKEN_LIFETIME |
-| Default | 2562047h47m16.854775807s |
+| Default | 876600h0m0s |
The maximum lifetime duration users can specify when creating an API token.
diff --git a/site/src/components/DeploySettingsLayout/Options.test.tsx b/site/src/components/DeploySettingsLayout/Options.test.tsx
new file mode 100644
index 0000000000..9842778510
--- /dev/null
+++ b/site/src/components/DeploySettingsLayout/Options.test.tsx
@@ -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)
+ })
+})
diff --git a/site/src/components/DeploySettingsLayout/OptionsTable.tsx b/site/src/components/DeploySettingsLayout/OptionsTable.tsx
index efe99034d8..fd8b841096 100644
--- a/site/src/components/DeploySettingsLayout/OptionsTable.tsx
+++ b/site/src/components/DeploySettingsLayout/OptionsTable.tsx
@@ -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<{
{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<{
- {option.value}
+ {optionValue(option)}
)
@@ -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).map(
+ ([key, value]) => `"${key}"->"${value}"`,
+ )
+ default:
+ return option.value
+ }
+}
+
const useStyles = makeStyles((theme) => ({
table: {
"& td": {
diff --git a/site/src/pages/CreateTokenPage/utils.test.tsx b/site/src/pages/CreateTokenPage/utils.test.tsx
index 2bdb20c180..4ab7d18c79 100644
--- a/site/src/pages/CreateTokenPage/utils.test.tsx
+++ b/site/src/pages/CreateTokenPage/utils.test.tsx
@@ -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,