Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jul 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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;
4 changes: 2 additions & 2 deletions coderd/workspaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
)
Expand Down
6 changes: 3 additions & 3 deletions coderd/workspaces_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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",
},
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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) {
Expand Down
4 changes: 2 additions & 2 deletions site/src/i18n/en/createTemplatePage.json
Original file line number Diff line number Diff line change
Expand Up @@ -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."
}
}
Expand Down
4 changes: 2 additions & 2 deletions site/src/i18n/en/templateSettingsPage.json
Original file line number Diff line number Diff line change
Expand Up @@ -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.",
Expand Down
13 changes: 8 additions & 5 deletions site/src/pages/CreateTemplatePage/CreateTemplateForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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).",
),
})

Expand All @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand All @@ -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(),
Expand All @@ -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()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down