Skip to content

Commit 3c33b09

Browse files
committed
modified: internal/cli/site.go
1 parent 655684c commit 3c33b09

5 files changed

Lines changed: 783 additions & 72 deletions

File tree

README.md

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,12 @@ sudo ols site create example.com --wp
4848
sudo ols site update example.com --php85
4949
```
5050

51+
### Enable OWASP + reCAPTCHA and add security headers on a site
52+
53+
```bash
54+
sudo ols site update example.com --enable-owasp --enable-recaptcha --hsts
55+
```
56+
5157
### Show site information
5258

5359
```bash
@@ -69,8 +75,8 @@ ols site list
6975
### Preview operations without making changes
7076

7177
```bash
72-
ols --dry-run site create example.com --wp --le --php85
73-
ols --dry-run site update example.com --wp --php83
78+
ols --dry-run site create example.com --wp --le --php85 --enable-owasp --hsts
79+
ols --dry-run site update example.com --enable-recaptcha --disable-owasp
7480
ols --dry-run site info example.com
7581
ols --dry-run site show example.com
7682
ols --dry-run site list
@@ -81,8 +87,8 @@ ols --dry-run site list
8187
| Command | Purpose | Common options |
8288
| --- | --- | --- |
8389
| `ols install` | Install/align OpenLiteSpeed runtime and related packages | `--php81` `--php82` `--php83` `--php84` `--php85` `--database` `--config` `--http-port` `--https-port` `--ssl-cert` `--ssl-key` `--no-listeners` |
84-
| `ols site create <domain>` | Create a new site/vhost | `--wp` `--le` `--php81` `--php82` `--php83` `--php84` `--php85` |
85-
| `ols site update <domain>` | Update an existing site (PHP target is required) | `--wp` `--php81` `--php82` `--php83` `--php84` `--php85` |
90+
| `ols site create <domain>` | Create a new site/vhost | `--wp` `--le` `--php81` `--php82` `--php83` `--php84` `--php85` `--enable-owasp` `--disable-owasp` `--enable-recaptcha` `--disable-recaptcha` `--hsts` |
91+
| `ols site update <domain>` | Update an existing site (PHP target optional when only security flags are used) | `--wp` `--php81` `--php82` `--php83` `--php84` `--php85` `--enable-owasp` `--disable-owasp` `--enable-recaptcha` `--disable-recaptcha` `--hsts` |
8692
| `ols site info <domain>` | Show site metadata and detected status | *(none)* |
8793
| `ols site show <domain>` | Print OLS virtual host config (`vhconf.conf`) | *(none)* |
8894
| `ols site list` | List managed sites discovered from OLS vhost directory | *(none)* |
@@ -95,8 +101,8 @@ Global options (apply to all commands): `--dry-run`, `--color`
95101

96102
| Subcommand | Syntax | Options |
97103
| --- | --- | --- |
98-
| `create` | `ols site create <domain>` | `--wp` `--le` `--php81` `--php82` `--php83` `--php84` `--php85` |
99-
| `update` | `ols site update <domain>` | `--wp` and exactly one of `--php81` `--php82` `--php83` `--php84` `--php85` |
104+
| `create` | `ols site create <domain>` | `--wp` `--le` `--php81` `--php82` `--php83` `--php84` `--php85` `--enable-owasp` `--disable-owasp` `--enable-recaptcha` `--disable-recaptcha` `--hsts` |
105+
| `update` | `ols site update <domain>` | `--wp` (requires one of `--php81` `--php82` `--php83` `--php84` `--php85`), or security flags only: `--enable-owasp` `--disable-owasp` `--enable-recaptcha` `--disable-recaptcha` `--hsts` |
100106
| `info` | `ols site info <domain>` | *(none)* |
101107
| `show` | `ols site show <domain>` | *(none)* |
102108
| `list` | `ols site list` | *(none)* |

internal/cli/site.go

Lines changed: 77 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,26 @@ type phpFlags struct {
2626
v85 bool
2727
}
2828

29+
type toggleFlags struct {
30+
enable bool
31+
disable bool
32+
}
33+
34+
func (f toggleFlags) selected(feature string) (*bool, error) {
35+
if f.enable && f.disable {
36+
return nil, apperr.New(apperr.CodeValidation, fmt.Sprintf("conflicting flags for %s; choose only one of --enable-%s/--disable-%s", feature, feature, feature))
37+
}
38+
if f.enable {
39+
enabled := true
40+
return &enabled, nil
41+
}
42+
if f.disable {
43+
disabled := false
44+
return &disabled, nil
45+
}
46+
return nil, nil
47+
}
48+
2949
func (f phpFlags) selected(defaultVersion string) (string, error) {
3050
selected := ""
3151
count := 0
@@ -85,27 +105,41 @@ func newSiteCmd(svc siteManager, rootOpts *rootOptions) *cobra.Command {
85105

86106
func newSiteCreateCmd(svc siteManager, rootOpts *rootOptions) *cobra.Command {
87107
php := &phpFlags{}
108+
owasp := &toggleFlags{}
109+
recaptcha := &toggleFlags{}
88110
var withWordPress bool
89111
var withLE bool
112+
var withHSTS bool
90113

91114
cmd := &cobra.Command{
92115
Use: "create <domain>",
93116
Short: "Create a new OpenLiteSpeed virtual host",
94117
Example: "ols site create example.com --wp\n" +
95-
"ols site create example.com --wp --php84\n" +
96-
"ols --dry-run site create example.com --wp --le --php85",
118+
"ols site create example.com --wp --php84 --enable-owasp --enable-recaptcha\n" +
119+
"ols --dry-run site create example.com --wp --le --php85 --hsts",
97120
Args: cobra.ExactArgs(1),
98121
RunE: func(cmd *cobra.Command, args []string) error {
99122
phpVersion, err := php.selected("85")
100123
if err != nil {
101124
return err
102125
}
126+
owaspEnabled, err := owasp.selected("owasp")
127+
if err != nil {
128+
return err
129+
}
130+
recaptchaEnabled, err := recaptcha.selected("recaptcha")
131+
if err != nil {
132+
return err
133+
}
103134
err = svc.CreateSite(cmd.Context(), service.CreateSiteOptions{
104-
Domain: args[0],
105-
WithWordPress: withWordPress,
106-
WithLE: withLE,
107-
PHPVersion: phpVersion,
108-
DryRun: rootOpts.DryRun,
135+
Domain: args[0],
136+
WithWordPress: withWordPress,
137+
WithLE: withLE,
138+
PHPVersion: phpVersion,
139+
OWASPEnabled: owaspEnabled,
140+
RecaptchaEnabled: recaptchaEnabled,
141+
EnableHSTSHeaders: withHSTS,
142+
DryRun: rootOpts.DryRun,
109143
})
110144
if err != nil {
111145
return fmt.Errorf("site create failed: %w", err)
@@ -116,34 +150,57 @@ func newSiteCreateCmd(svc siteManager, rootOpts *rootOptions) *cobra.Command {
116150

117151
cmd.Flags().BoolVar(&withWordPress, "wp", false, "install WordPress with required dependencies")
118152
cmd.Flags().BoolVar(&withLE, "le", false, "configure Let's Encrypt certificate")
153+
cmd.Flags().BoolVar(&owasp.enable, "enable-owasp", false, "enable OWASP ModSecurity at virtual host level")
154+
cmd.Flags().BoolVar(&owasp.disable, "disable-owasp", false, "disable OWASP ModSecurity at virtual host level")
155+
cmd.Flags().BoolVar(&recaptcha.enable, "enable-recaptcha", false, "enable reCAPTCHA at virtual host level")
156+
cmd.Flags().BoolVar(&recaptcha.disable, "disable-recaptcha", false, "disable reCAPTCHA at virtual host level")
157+
cmd.Flags().BoolVar(&withHSTS, "hsts", false, "add recommended security extra headers to static context /")
119158
addPHPVersionFlags(cmd, php)
120159
return cmd
121160
}
122161

123162
func newSiteUpdateCmd(svc siteManager, rootOpts *rootOptions) *cobra.Command {
124163
php := &phpFlags{}
164+
owasp := &toggleFlags{}
165+
recaptcha := &toggleFlags{}
125166
var withWordPress bool
167+
var withHSTS bool
126168

127169
cmd := &cobra.Command{
128170
Use: "update <domain>",
129171
Short: "Update existing site configuration",
130172
Example: "ols site update example.com --php83\n" +
131-
"ols site update example.com --wp --php84\n" +
132-
"ols --dry-run site update example.com --wp --php85",
173+
"ols site update example.com --enable-owasp --enable-recaptcha\n" +
174+
"ols --dry-run site update example.com --wp --php85 --hsts",
133175
Args: cobra.ExactArgs(1),
134176
RunE: func(cmd *cobra.Command, args []string) error {
135177
phpVersion, err := php.selected("")
136178
if err != nil {
137179
return err
138180
}
139-
if phpVersion == "" {
140-
return apperr.New(apperr.CodeValidation, "missing PHP version flag; provide one of --php81/--php82/--php83/--php84/--php85")
181+
owaspEnabled, err := owasp.selected("owasp")
182+
if err != nil {
183+
return err
184+
}
185+
recaptchaEnabled, err := recaptcha.selected("recaptcha")
186+
if err != nil {
187+
return err
188+
}
189+
190+
if withWordPress && phpVersion == "" {
191+
return apperr.New(apperr.CodeValidation, "missing PHP version flag for --wp; provide one of --php81/--php82/--php83/--php84/--php85")
192+
}
193+
if phpVersion == "" && !withWordPress && owaspEnabled == nil && recaptchaEnabled == nil && !withHSTS {
194+
return apperr.New(apperr.CodeValidation, "no update action provided; pass PHP version and/or security flags such as --enable-owasp, --enable-recaptcha, --disable-owasp, --disable-recaptcha, --hsts")
141195
}
142196
err = svc.UpdateSitePHP(cmd.Context(), service.UpdateSiteOptions{
143-
Domain: args[0],
144-
WithWordPress: withWordPress,
145-
PHPVersion: phpVersion,
146-
DryRun: rootOpts.DryRun,
197+
Domain: args[0],
198+
WithWordPress: withWordPress,
199+
PHPVersion: phpVersion,
200+
OWASPEnabled: owaspEnabled,
201+
RecaptchaEnabled: recaptchaEnabled,
202+
EnableHSTSHeaders: withHSTS,
203+
DryRun: rootOpts.DryRun,
147204
})
148205
if err != nil {
149206
return fmt.Errorf("site update failed: %w", err)
@@ -153,6 +210,11 @@ func newSiteUpdateCmd(svc siteManager, rootOpts *rootOptions) *cobra.Command {
153210
}
154211

155212
cmd.Flags().BoolVar(&withWordPress, "wp", false, "ensure WordPress and LiteSpeed Cache plugin are present")
213+
cmd.Flags().BoolVar(&owasp.enable, "enable-owasp", false, "enable OWASP ModSecurity at virtual host level")
214+
cmd.Flags().BoolVar(&owasp.disable, "disable-owasp", false, "disable OWASP ModSecurity at virtual host level")
215+
cmd.Flags().BoolVar(&recaptcha.enable, "enable-recaptcha", false, "enable reCAPTCHA at virtual host level")
216+
cmd.Flags().BoolVar(&recaptcha.disable, "disable-recaptcha", false, "disable reCAPTCHA at virtual host level")
217+
cmd.Flags().BoolVar(&withHSTS, "hsts", false, "add recommended security extra headers to static context /")
156218
addPHPVersionFlags(cmd, php)
157219
return cmd
158220
}

internal/cli/site_test.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,32 @@ func TestPHPFlagsSelectedDefault(t *testing.T) {
3030
t.Fatalf("expected default 85, got %s", got)
3131
}
3232
}
33+
34+
func TestToggleFlagsSelectedEnable(t *testing.T) {
35+
flags := toggleFlags{enable: true}
36+
got, err := flags.selected("owasp")
37+
if err != nil {
38+
t.Fatalf("unexpected error: %v", err)
39+
}
40+
if got == nil || !*got {
41+
t.Fatal("expected enabled toggle")
42+
}
43+
}
44+
45+
func TestToggleFlagsSelectedDisable(t *testing.T) {
46+
flags := toggleFlags{disable: true}
47+
got, err := flags.selected("recaptcha")
48+
if err != nil {
49+
t.Fatalf("unexpected error: %v", err)
50+
}
51+
if got == nil || *got {
52+
t.Fatal("expected disabled toggle")
53+
}
54+
}
55+
56+
func TestToggleFlagsSelectedConflict(t *testing.T) {
57+
flags := toggleFlags{enable: true, disable: true}
58+
if _, err := flags.selected("owasp"); err == nil {
59+
t.Fatal("expected validation error for conflicting toggle flags")
60+
}
61+
}

0 commit comments

Comments
 (0)