mirror of
https://github.com/coder/coder.git
synced 2025-07-21 01:28:49 +00:00
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:
@ -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;
|
||||
|
@ -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")
|
||||
)
|
||||
|
@ -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",
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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) {
|
||||
|
@ -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."
|
||||
}
|
||||
}
|
||||
|
@ -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.",
|
||||
|
@ -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,
|
||||
|
@ -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()
|
||||
|
@ -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(
|
||||
|
Reference in New Issue
Block a user