Skip to content

Commit f98a2f5

Browse files
authored
feat(schedule): introduce run-level option (#546)
* feat(schedule): introduce `run-level` option * chore(schedule): remove `noshow` for `run-level` option * test(commands): add `run-level` option to `show` command output
1 parent f748032 commit f98a2f5

10 files changed

Lines changed: 44 additions & 1 deletion

File tree

commands_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,7 @@ func TestShowSchedules(t *testing.T) {
310310
schedule backup@default:
311311
at: daily
312312
permission: auto
313+
run-level: auto
313314
command-output: auto
314315
priority: standard
315316
lock-mode: default
@@ -318,6 +319,7 @@ schedule backup@default:
318319
schedule check@default:
319320
at: weekly
320321
permission: auto
322+
run-level: auto
321323
command-output: auto
322324
priority: standard
323325
lock-mode: default

config/profile.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,7 @@ type ScheduleBaseSection struct {
312312
scheduleConfig *ScheduleConfig
313313
Schedule any `mapstructure:"schedule" show:"noshow" examples:"hourly;daily;weekly;monthly;10:00,14:00,18:00,22:00;Wed,Fri 17:48;*-*-15 02:45;Mon..Fri 00:30" description:"Configures the scheduled execution of this profile section. Can be times in systemd timer format or a config structure"`
314314
SchedulePermission string `mapstructure:"schedule-permission" show:"noshow" default:"auto" enum:"auto;system;user;user_logged_on" description:"Specify whether the schedule runs with system or user privileges - see https://creativeprojects.github.io/resticprofile/schedules/configuration/"`
315+
ScheduleRunLevel string `mapstructure:"schedule-run-level" show:"noshow" default:"auto" enum:"auto;lowest;highest" description:"Specify the schedule privilege level (for Windows Task Scheduler only)"`
315316
ScheduleLog string `mapstructure:"schedule-log" show:"noshow" examples:"/resticprofile.log;syslog-tcp://syslog-server:514;syslog:server;syslog:" description:"Redirect the output into a log file or to syslog when running on schedule"`
316317
SchedulePriority string `mapstructure:"schedule-priority" show:"noshow" default:"standard" enum:"background;standard" description:"Set the priority at which the schedule is run"`
317318
ScheduleLockMode string `mapstructure:"schedule-lock-mode" show:"noshow" default:"default" enum:"default;fail;ignore" description:"Specify how locks are used when running on schedule - see https://creativeprojects.github.io/resticprofile/schedules/configuration/"`

config/schedule.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ const (
3535
// ScheduleBaseConfig is the base user configuration that could be shared across all schedules.
3636
type ScheduleBaseConfig struct {
3737
Permission string `mapstructure:"permission" default:"auto" enum:"auto;system;user;user_logged_on" description:"Specify whether the schedule runs with system or user privileges - see https://creativeprojects.github.io/resticprofile/schedules/configuration/"`
38+
RunLevel string `mapstructure:"run-level" default:"auto" enum:"auto;lowest;highest" description:"Specify the schedule privilege level (for Windows Task Scheduler only)"`
3839
Log string `mapstructure:"log" examples:"/resticprofile.log;syslog-tcp://syslog-server:514;syslog:server;syslog:" description:"Redirect the output into a log file or to syslog when running on schedule - see https://creativeprojects.github.io/resticprofile/configuration/logs/"`
3940
CommandOutput string `mapstructure:"command-output" default:"auto" enum:"auto;log;console;all" description:"Sets the destination for command output (stderr/stdout). \"log\" sends output to the log file (if specified), \"console\" sends it to the console instead. \"auto\" sends it to \"both\" if console is a terminal otherwise to \"log\" only - see https://creativeprojects.github.io/resticprofile/configuration/logs/"`
4041
Priority string `mapstructure:"priority" default:"standard" enum:"background;standard" description:"Set the priority at which the schedule is run"`
@@ -50,6 +51,7 @@ type ScheduleBaseConfig struct {
5051
// scheduleBaseConfigDefaults declares built-in scheduling defaults
5152
var scheduleBaseConfigDefaults = ScheduleBaseConfig{
5253
Permission: "auto",
54+
RunLevel: "auto",
5355
CommandOutput: constants.DefaultCommandOutput,
5456
Priority: "standard",
5557
LockMode: "default",
@@ -64,6 +66,9 @@ func (s *ScheduleBaseConfig) init(defaults *ScheduleBaseConfig) {
6466
if s.Permission == "" {
6567
s.Permission = defaults.Permission
6668
}
69+
if s.RunLevel == "" {
70+
s.RunLevel = defaults.RunLevel
71+
}
6772
if s.Log == "" {
6873
s.Log = defaults.Log
6974
}
@@ -98,6 +103,7 @@ func (s *ScheduleBaseConfig) applyOverrides(section *ScheduleBaseSection) {
98103
defaults := *s
99104
// applying the settings of the section
100105
s.Permission = section.SchedulePermission
106+
s.RunLevel = section.ScheduleRunLevel
101107
s.Log = section.ScheduleLog
102108
s.Priority = section.SchedulePriority
103109
s.LockMode = section.ScheduleLockMode

docs/content/schedules/configuration.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,14 @@ Follow this order:
9191
- Change your permission (user to system, or system to user).
9292
- Schedule your updated profile.
9393

94+
## schedule-run-level
95+
96+
In Windows Task Manager, you can also specify a scheduled task privilege level.
97+
98+
The `schedule-run-level` parameter accepts three values:
99+
- `lowest`: Runs the task with the least user privileges.
100+
- `highest`: Runs the task with the highest user privileges available.
101+
- `auto`: Uses `highest` if `schedule-permission` is set to `system`. Otherwise, defaults to `lowest`.
94102

95103
## schedule-lock-mode
96104

schedule/config.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ type Config struct {
1212
CommandName string // restic command
1313
Schedules []string
1414
Permission string
15+
RunLevel string
1516
WorkingDirectory string
1617
Command string // path to resticprofile executable
1718
Arguments CommandArguments

schedule/handler_windows.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ func (h *HandlerWindows) CreateJob(job *Config, schedules []*calendar.Event, per
6262
Arguments: job.Arguments.String(),
6363
WorkingDirectory: job.WorkingDirectory,
6464
JobDescription: job.JobDescription,
65+
RunLevel: job.RunLevel,
6566
}
6667
err := schtasks.Create(jobConfig, schedules, perm)
6768
if err != nil {

schedule_jobs.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@ func scheduleToConfig(sched *config.Schedule) *schedule.Config {
226226
CommandName: origin.Command,
227227
Schedules: sched.Schedules,
228228
Permission: sched.Permission,
229+
RunLevel: sched.RunLevel,
229230
WorkingDirectory: "",
230231
Command: "",
231232
Arguments: schedule.NewCommandArguments(nil),

schtasks/config.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ type Config struct {
99
Arguments string
1010
WorkingDirectory string
1111
JobDescription string
12+
RunLevel string
1213
}

schtasks/taskscheduler.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,24 @@ func Create(config *Config, schedules []*calendar.Event, permission Permission)
5454
task := createTaskDefinition(config, schedules)
5555
task.RegistrationInfo.URI = taskPath
5656

57+
switch config.RunLevel {
58+
case "lowest":
59+
task.Principals.Principal.RunLevel = RunLevelLeastPrivilege
60+
61+
case "highest":
62+
task.Principals.Principal.RunLevel = RunLevelHighest
63+
64+
default:
65+
if permission == SystemAccount {
66+
task.Principals.Principal.RunLevel = RunLevelHighest
67+
} else {
68+
task.Principals.Principal.RunLevel = RunLevelDefault
69+
}
70+
}
71+
5772
switch permission {
5873
case SystemAccount:
5974
task.Principals.Principal.LogonType = LogonTypeServiceForUser
60-
task.Principals.Principal.RunLevel = RunLevelHighest
6175
task.Principals.Principal.UserId = serviceAccount
6276
task.RegistrationInfo.SecurityDescriptor = securityDescriptor // allow authenticated users to read the task status
6377

schtasks/taskscheduler_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,3 +279,11 @@ func TestTaskSchedulerIntegration(t *testing.T) {
279279
})
280280
}
281281
}
282+
283+
func TestRunLevelOption(t *testing.T) {
284+
// atm it's impossible to test `run-level` option
285+
// due to lack info about task `run-level` in schtasks output
286+
// such info only present in xml format, we are currently using csv
287+
// see related: https://github.com/creativeprojects/resticprofile/issues/545
288+
// TODO: implement test when possible
289+
}

0 commit comments

Comments
 (0)