feat(site): increase TTL and max TTL validation to 30 days (#8258)

Co-authored-by: Dean Sheather <dean@deansheather.com>
This commit is contained in:
Josh Vawdrey
2023-07-19 23:43:10 +10:00
committed by GitHub
parent 4232a2eb96
commit 6318c4c09f
10 changed files with 47 additions and 23 deletions

View File

@ -1,2 +1,5 @@
-- Set a cap of 7 days on template max_ttl
--
-- NOTE: this migration was added in August 2022, but the cap has been changed
-- to 30 days in July 2023.
UPDATE templates SET max_ttl = 604800000000000 WHERE max_ttl > 604800000000000;

View File

@ -32,10 +32,10 @@ import (
var (
ttlMin = time.Minute //nolint:revive // min here means 'minimum' not 'minutes'
ttlMax = 7 * 24 * time.Hour
ttlMax = 30 * 24 * time.Hour
errTTLMin = xerrors.New("time until shutdown must be at least one minute")
errTTLMax = xerrors.New("time until shutdown must be less than 7 days")
errTTLMax = xerrors.New("time until shutdown must be less than 30 days")
errDeadlineTooSoon = xerrors.New("new deadline must be at least 30 minutes in the future")
errDeadlineBeforeStart = xerrors.New("new deadline must be before workspace start time")
)

View File

@ -1837,13 +1837,13 @@ func TestWorkspaceUpdateTTL(t *testing.T) {
},
{
name: "maximum ttl",
ttlMillis: ptr.Ref((24 * 7 * time.Hour).Milliseconds()),
ttlMillis: ptr.Ref((24 * 30 * time.Hour).Milliseconds()),
expectedError: "",
},
{
name: "above maximum ttl",
ttlMillis: ptr.Ref((24*7*time.Hour + time.Minute).Milliseconds()),
expectedError: "time until shutdown must be less than 7 days",
ttlMillis: ptr.Ref((24*30*time.Hour + time.Minute).Milliseconds()),
expectedError: "time until shutdown must be less than 30 days",
},
}

View File

@ -158,10 +158,19 @@ describe("validationSchema", () => {
expect(validate).not.toThrowError()
})
it("disallows a ttl of 7 days + 1 hour", () => {
it("allows a ttl of 30 days", () => {
const values: WorkspaceScheduleFormValues = {
...valid,
ttl: 24 * 7 + 1,
ttl: 24 * 30,
}
const validate = () => validationSchema.validateSync(values)
expect(validate).not.toThrowError()
})
it("disallows a ttl of 30 days + 1 hour", () => {
const values: WorkspaceScheduleFormValues = {
...valid,
ttl: 24 * 30 + 1,
}
const validate = () => validationSchema.validateSync(values)
expect(validate).toThrowError(Language.errorTtlMax)

View File

@ -48,7 +48,7 @@ export const Language = {
errorNoStop:
"Time until shutdown must be greater than zero when autostop is enabled.",
errorTtlMax:
"Please enter a limit that is less than or equal to 168 hours (7 days).",
"Please enter a limit that is less than or equal to 720 hours (30 days).",
daysOfWeekLabel: "Days of Week",
daySundayLabel: "Sun",
dayMondayLabel: "Mon",
@ -172,7 +172,7 @@ export const validationSchema = Yup.object({
ttl: Yup.number()
.integer()
.min(0)
.max(24 * 7 /* 7 days */, Language.errorTtlMax)
.max(24 * 30 /* 30 days */, Language.errorTtlMax)
.test("positive-if-autostop", Language.errorNoStop, function (value) {
const parent = this.parent as WorkspaceScheduleFormValues
if (parent.autostopEnabled) {

View File

@ -48,9 +48,9 @@
},
"error": {
"descriptionMax": "Please enter a description that is less than or equal to 128 characters.",
"defaultTTLMax": "Please enter a limit that is less than or equal to 168 hours (7 days).",
"defaultTTLMax": "Please enter a limit that is less than or equal to 720 hours (30 days).",
"defaultTTLMin": "Default time until autostop must not be less than 0.",
"maxTTLMax": "Please enter a limit that is less than or equal to 168 hours (7 days).",
"maxTTLMax": "Please enter a limit that is less than or equal to 720 hours (30 days).",
"maxTTLMin": "Maximum time until autostop must not be less than 0."
}
}

View File

@ -9,12 +9,12 @@
"iconLabel": "Icon",
"formAriaLabel": "Template settings form",
"selectEmoji": "Select emoji",
"defaultTTLMaxError": "Please enter a limit that is less than or equal to 168 hours (7 days).",
"defaultTTLMaxError": "Please enter a limit that is less than or equal to 720 hours (30 days).",
"defaultTTLMinError": "Default time until autostop must not be less than 0.",
"defaultTTLHelperText_zero": "Workspaces will run until stopped manually.",
"defaultTTLHelperText_one": "Workspaces will default to stopping after {{count}} hour. If Coder detects workspace connection activity, the autostop timer is bumped up one hour.",
"defaultTTLHelperText_other": "Workspaces will default to stopping after {{count}} hours. If Coder detects workspace connection activity, the autostop timer is bumped up one hour.",
"maxTTLMaxError": "Please enter a limit that is less than or equal to 168 hours (7 days).",
"maxTTLMaxError": "Please enter a limit that is less than or equal to 720 hours (30 days).",
"maxTTLMinError": "Maximum time until autostop must not be less than 0.",
"maxTTLHelperText_zero": "Workspaces may run indefinitely.",
"maxTTLHelperText_one": "Workspaces must stop within 1 hour of starting, regardless of any active connections.",

View File

@ -41,7 +41,7 @@ import capitalize from "lodash/capitalize"
import { VariableInput } from "./VariableInput"
const MAX_DESCRIPTION_CHAR_LIMIT = 128
const MAX_TTL_DAYS = 7
const MAX_TTL_DAYS = 30
const TTLHelperText = ({
ttl,
@ -78,15 +78,15 @@ const validationSchema = Yup.object({
.integer()
.min(0, "Default time until autostop must not be less than 0.")
.max(
24 * MAX_TTL_DAYS /* 7 days in hours */,
"Please enter a limit that is less than or equal to 168 hours (7 days).",
24 * MAX_TTL_DAYS /* 30 days in hours */,
"Please enter a limit that is less than or equal to 720 hours (30 days).",
),
max_ttl_hours: Yup.number()
.integer()
.min(0, "Maximum time until autostop must not be less than 0.")
.max(
24 * MAX_TTL_DAYS /* 7 days in hours */,
"Please enter a limit that is less than or equal to 168 hours(7 days).",
24 * MAX_TTL_DAYS /* 30 days in hours */,
"Please enter a limit that is less than or equal to 720 hours (30 days).",
),
})
@ -98,6 +98,9 @@ const defaultInitialValues: CreateTemplateData = {
default_ttl_hours: 24,
// max_ttl is an enterprise-only feature, and the server ignores the value if
// you are not licensed. We hide the form value based on entitlements.
//
// The maximum value is 30 days but we default to 7 days as it's a much more
// sensible value for most teams.
max_ttl_hours: 24 * 7,
allow_user_cancel_workspace_jobs: false,
allow_user_autostart: false,

View File

@ -8,7 +8,7 @@ export interface TemplateScheduleFormValues extends UpdateTemplateMeta {
locked_cleanup_enabled: boolean
}
const MAX_TTL_DAYS = 7
const MAX_TTL_DAYS = 30
export const getValidationSchema = (): Yup.AnyObjectSchema =>
Yup.object({
@ -21,7 +21,7 @@ export const getValidationSchema = (): Yup.AnyObjectSchema =>
.toString(),
)
.max(
24 * MAX_TTL_DAYS /* 7 days in hours */,
24 * MAX_TTL_DAYS /* 30 days in hours */,
i18next
.t("defaultTTLMaxError", { ns: "templateSettingsPage" })
.toString(),
@ -33,7 +33,7 @@ export const getValidationSchema = (): Yup.AnyObjectSchema =>
i18next.t("maxTTLMinError", { ns: "templateSettingsPage" }).toString(),
)
.max(
24 * MAX_TTL_DAYS /* 7 days in hours */,
24 * MAX_TTL_DAYS /* 30 days in hours */,
i18next.t("maxTTLMaxError", { ns: "templateSettingsPage" }).toString(),
),
failure_ttl_ms: Yup.number()

View File

@ -159,10 +159,19 @@ describe("TemplateSchedulePage", () => {
expect(validate).not.toThrowError()
})
it("disallows a default ttl of 7 days + 1 hour", () => {
it("allows a default ttl of 30 days", () => {
const values: UpdateTemplateMeta = {
...validFormValues,
default_ttl_ms: 24 * 7 + 1,
default_ttl_ms: 24 * 30,
}
const validate = () => getValidationSchema().validateSync(values)
expect(validate).not.toThrowError()
})
it("disallows a default ttl of 30 days + 1 hour", () => {
const values: UpdateTemplateMeta = {
...validFormValues,
default_ttl_ms: 24 * 30 + 1,
}
const validate = () => getValidationSchema().validateSync(values)
expect(validate).toThrowError(