Skip to content

Commit ce58111

Browse files
cacama-valvatadetjensrobert
authored andcommitted
init cmd added inquire placeholders and cleaned up prompt and help messages
1 parent 0346bf3 commit ce58111

File tree

3 files changed

+103
-64
lines changed

3 files changed

+103
-64
lines changed

src/asset_files/rcds.yaml.j2

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,7 @@ deploy:
2626
pwn/notsh: true
2727
web/bar: true
2828

29-
profiles:
30-
{% for prof in options.profiles %}
29+
profiles: {% for prof in options.profiles %}
3130
{{ prof.profile_name}}:
3231
frontend_url: {{ prof.frontend_url }}
3332
frontend_token: {{ prof.frontend_token }}

src/init/example_values.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Example strings for rcds.yaml
2+
3+
pub static FLAG_REGEX: &str = "ctf{.*}";
4+
pub static REGISTRY_DOMAIN: &str = "ghcr.io/youraccount";
5+
pub static REGISTRY_BUILD_USER: &str = "admin";
6+
pub static REGISTRY_BUILD_PASS: &str = "notrealcreds";
7+
pub static REGISTRY_CLUSTER_USER: &str = "cluster_user";
8+
pub static REGISTRY_CLUSTER_PASS: &str = "alsofake";
9+
pub static DEFAULTS_DIFFICULTY: &str = "1";
10+
pub static DEFAULTS_RESOURCES_CPU: &str = "1";
11+
pub static DEFAULTS_RESOURCES_MEMORY: &str = "500M";
12+
pub static POINTS_DIFFICULTY: &str = "1";
13+
pub static POINTS_MIN: &str = "200";
14+
pub static POINTS_MAX: &str = "500";
15+
pub static PROFILES_PROFILE_NAME: &str = "default";
16+
pub static PROFILES_FRONTEND_URL: &str = "https://ctf.coolguy.invalid";
17+
pub static PROFILES_FRONTEND_TOKEN: &str = "secretsecretsecret";
18+
pub static PROFILES_CHALLENGES_DOMAIN: &str = "chals.coolguy.invalid";
19+
pub static PROFILES_KUBECONTEXT: &str = "ctf-cluster";
20+
pub static PROFILES_S3_BUCKET_NAME: &str = "ctf-bucket";
21+
pub static PROFILES_S3_ENDPOINT: &str = "s3.coolguy.invalid";
22+
pub static PROFILES_S3_REGION: &str = "us-west-2";
23+
pub static PROFILES_S3_ACCESSKEY: &str = "accesskey";
24+
pub static PROFILES_S3_SECRETACCESSKEY: &str = "secretkey";

src/init/mod.rs

Lines changed: 78 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use serde;
55
use std::fmt;
66

77
pub mod templates;
8+
pub mod example_values;
89

910
#[derive(serde::Serialize)]
1011
pub struct init_vars {
@@ -14,18 +15,18 @@ pub struct init_vars {
1415
pub registry_build_pass: String,
1516
pub registry_cluster_user: String,
1617
pub registry_cluster_pass: String,
17-
pub defaults_difficulty: String, //u64,
18-
pub defaults_resources_cpu: String, //u64,
19-
pub defaults_resources_memory: String, //(u64, Option(String)),
18+
pub defaults_difficulty: String,
19+
pub defaults_resources_cpu: String,
20+
pub defaults_resources_memory: String,
2021
pub points: Vec<points>,
2122
pub profiles: Vec<profile>,
2223
}
2324

2425
#[derive(Clone, serde::Serialize)]
2526
pub struct points {
26-
pub difficulty: String, //u64,
27-
pub min: String, //u64,
28-
pub max: String, //u64
27+
pub difficulty: String,
28+
pub min: String,
29+
pub max: String,
2930
}
3031

3132
impl fmt::Display for points {
@@ -63,43 +64,47 @@ pub fn interactive_init() -> inquire::error::InquireResult<init_vars> {
6364
//TODO:
6465
// - also provide regex examples in help
6566
// - is this even a good idea to have the user provide the regex
66-
// - with placeholder?
67+
// - what kind of regex is being validated and accepted
6768
inquire::Text::new("Flag regex:")
6869
.with_help_message("This regex will be used to validate the individual flags of your challenges later.")
70+
.with_placeholder(example_values::FLAG_REGEX)
6971
.prompt()?
7072
},
7173

7274
registry_domain: {
7375
inquire::Text::new ("Container registry:")
74-
.with_help_message("This is the domain of your remote container registry, which includes both the endpoint details and your repository name.") //where you will push images to and where your cluster will pull challenge images from.") // TODO
76+
.with_help_message("Hosted challenges will be hosted in a container registry.The connection endpoint and the repository name.")
77+
.with_placeholder(example_values::REGISTRY_DOMAIN)
7578
.prompt()?
7679
},
7780

7881
registry_build_user: {
79-
inquire::Text::new ("Container registry user (YOURS):")
80-
.with_help_message("Your username to the remote container registry, which you will use to push containers to.")
82+
inquire::Text::new ("Container registry 'build' user:")
83+
.with_help_message("The username that will be used to push built containers.")
84+
.with_placeholder(example_values::REGISTRY_BUILD_USER)
8185
.prompt()?
8286
},
8387

8488
// TODO: do we actually want to be in charge of these credentials vs letting the container building utility take care of it?
8589
registry_build_pass: {
86-
inquire::Password::new("Container registry password (YOURS):")
87-
.with_help_message("Your password to the remote container registry, which you will use to push containers to.") // TODO: could this support username:pat too?
90+
inquire::Password::new("Container registry 'build' password:")
91+
.with_help_message("The password to the 'build' user account") // TODO: could this support username:pat too?
8892
.with_display_mode(inquire::PasswordDisplayMode::Masked)
8993
.with_custom_confirmation_message("Enter again:")
9094
.prompt()?
9195
},
9296

9397
registry_cluster_user: {
94-
inquire::Text::new ("Container registry user (CLUSTER'S):")
95-
.with_help_message("The cluster's username to the remote container registry, which it will use to pull containers from.")
98+
inquire::Text::new ("Container registry 'cluster' user:")
99+
.with_help_message("The username that the cluster will use to pull locally-built containers.")
100+
.with_placeholder(example_values::REGISTRY_CLUSTER_USER)
96101
.prompt()?
97102
},
98103

99104
// TODO: would the cluster not use a token of some sort?
100105
registry_cluster_pass: {
101-
inquire::Password::new("Container registry password (CLUSTER'S):")
102-
.with_help_message("The cluster's password to the remote container registry, which it will use to pull containers from.")
106+
inquire::Password::new("Container registry 'cluster' password:")
107+
.with_help_message("The password to the 'cluster' user account")
103108
.with_display_mode(inquire::PasswordDisplayMode::Masked)
104109
.with_custom_confirmation_message("Enter again:")
105110
.prompt()?
@@ -119,23 +124,26 @@ pub fn interactive_init() -> inquire::error::InquireResult<init_vars> {
119124
// default parser calls std::u64::from_str
120125
.with_error_message("Please type a valid number.")
121126
.with_help_message("The rank of the difficulty class as an unsigned integer, with lower numbers being \"easier.\"")
127+
.with_placeholder(example_values::POINTS_DIFFICULTY)
122128
.prompt()?
123129
.to_string()
124130
},
125131
// TODO: support static-point challenges
126132
min: {
127-
inquire::CustomType::<u64>::new("Minimum number of points:")
133+
inquire::CustomType::<u64>::new("Minimum points:")
128134
// default parser calls std::u64::from_str
129135
.with_error_message("Please type a valid number.")
130-
.with_help_message("Challenge points are dynamic: the minimum number of points that challenges within this difficulty class are worth.")
136+
.with_help_message("Challenge points are dynamic. The minimum number of points that challenges within this difficulty class are worth.")
137+
.with_placeholder(example_values::POINTS_MIN)
131138
.prompt()?
132139
.to_string()
133140
},
134141
max: {
135-
inquire::CustomType::<u64>::new("Maximum number of points:")
142+
inquire::CustomType::<u64>::new("Maximum points:")
136143
// default parser calls std::u64::from_str
137144
.with_error_message("Please type a valid number.")
138-
.with_help_message("Challenge points are dynamic: the maximum number of points that challenges within this difficulty class are worth.")
145+
.with_help_message("The maximum number of points that challenges within this difficulty class are worth.")
146+
.with_placeholder(example_values::POINTS_MAX)
139147
.prompt()?
140148
.to_string()
141149
},
@@ -150,7 +158,6 @@ pub fn interactive_init() -> inquire::error::InquireResult<init_vars> {
150158
points_ranks
151159
},
152160

153-
// TODO: how much format validation should these two do now vs offloading to validate() later? current inquire replacement calls are temporary and do the zero checking, just grabbing a String
154161
defaults_difficulty: {
155162
if points_ranks_reference.is_empty() {
156163
String::new()
@@ -165,26 +172,26 @@ pub fn interactive_init() -> inquire::error::InquireResult<init_vars> {
165172
},
166173

167174
defaults_resources_cpu: {
168-
let resources = inquire::Text::new("Default limit of CPUs per challenge:")
169-
.with_help_message("The maximum limit of CPU resources per instance of challenge deployment (\"pod\").")
170-
.with_placeholder("1")
175+
let resources = inquire::Text::new("Default CPU limit:")
176+
.with_help_message("The default limit of CPU resources per challenge pod.\nhttps://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#resource-units-in-kubernetes")
177+
.with_placeholder(example_values::DEFAULTS_RESOURCES_CPU)
171178
.prompt()?;
172179

173180
if resources.is_empty() {
174-
String::from("1")
181+
String::from(example_values::DEFAULTS_RESOURCES_CPU)
175182
} else {
176183
resources
177184
}
178185
},
179186

180187
defaults_resources_memory: {
181-
let resources = inquire::Text::new("Default limit of memory per challenge:")
182-
.with_help_message("The maximum limit of memory resources per instance of challenge deployment (\"pod\").")
183-
.with_placeholder("500M")
188+
let resources = inquire::Text::new("Default memory limit:")
189+
.with_help_message("The default limit of CPU resources per challenge pod.\nhttps://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#resource-units-in-kubernetes")
190+
.with_placeholder(example_values::DEFAULTS_RESOURCES_MEMORY)
184191
.prompt()?;
185192

186193
if resources.is_empty() {
187-
String::from("500M")
194+
String::from(example_values::DEFAULTS_RESOURCES_MEMORY)
188195
} else {
189196
resources
190197
}
@@ -202,54 +209,63 @@ pub fn interactive_init() -> inquire::error::InquireResult<init_vars> {
202209
profile_name: {
203210
inquire::Text::new("Profile name:")
204211
.with_help_message("The name of the deployment profile. One profile named \"default\" is recommended. You can add additional profiles.")
205-
.with_placeholder("default")
212+
.with_placeholder(example_values::PROFILES_PROFILE_NAME)
206213
.prompt()?
207214
},
208215
frontend_url: {
209216
inquire::Text::new("Frontend URL:")
210-
.with_help_message("The URL of the RNG scoreboard.") // TODO: can definitely say more about why this is significant
217+
.with_help_message("The URL of the RNG scoreboard.")
218+
.with_placeholder(example_values::PROFILES_FRONTEND_URL)
211219
.prompt()?
212220
},
213221
frontend_token: {
214222
inquire::Text::new("Frontend token:")
215223
.with_help_message(
216-
"The token for RNG to authenticate itself into the scoreboard.",
217-
) // TODO: again, say more
224+
"The token to authenticate into the RNG scoreboard.",
225+
)
226+
.with_placeholder(example_values::PROFILES_FRONTEND_TOKEN)
218227
.prompt()?
219228
},
220229
challenges_domain: {
221230
inquire::Text::new("Challenges domain:")
222231
.with_help_message("Domain that challenges are hosted under.")
232+
.with_placeholder(example_values::PROFILES_CHALLENGES_DOMAIN)
223233
.prompt()?
224234
},
225235
kubecontext: {
226-
inquire::Text::new("Kube context:")
227-
.with_help_message("The name of the context that kubectl looks for to interface with the cluster.")
236+
inquire::Text::new("Kubecontext name:")
237+
.with_help_message("The name of the context that kubectl uses to connect to the cluster.")
238+
.with_placeholder(example_values::PROFILES_KUBECONTEXT)
228239
.prompt()?
229240
},
230241
s3_bucket_name: {
231242
inquire::Text::new("S3 bucket name:")
232-
.with_help_message("Challenge artifacts and static files will be hosted on and served from S3. The name of the S3 bucket.")
243+
.with_help_message("Challenge artifacts and static files will be hosted on S3. The name of the S3 bucket.")
244+
.with_placeholder(example_values::PROFILES_S3_BUCKET_NAME)
233245
.prompt()?
234246
},
235247
s3_endpoint: {
236248
inquire::Text::new("S3 endpoint:")
237249
.with_help_message("The endpoint of the S3 bucket server.")
250+
.with_placeholder(example_values::PROFILES_S3_ENDPOINT)
238251
.prompt()?
239252
},
240253
s3_region: {
241254
inquire::Text::new("S3 region:")
242-
.with_help_message("The region that the S3 bucket is hosted.")
255+
.with_help_message("The region where the S3 bucket is hosted.")
256+
.with_placeholder(example_values::PROFILES_S3_REGION)
243257
.prompt()?
244258
},
245259
s3_accesskey: {
246260
inquire::Text::new("S3 access key:")
247261
.with_help_message("The public access key to the S3 bucket.")
262+
.with_placeholder(example_values::PROFILES_S3_ACCESSKEY)
248263
.prompt()?
249264
},
250265
s3_secretaccesskey: {
251266
inquire::Text::new("S3 secret key:")
252267
.with_help_message("The secret acess key to the S3 bucket.")
268+
.with_placeholder(example_values::PROFILES_S3_SECRETACCESSKEY)
253269
.prompt()?
254270
},
255271
};
@@ -282,7 +298,7 @@ pub fn blank_init() -> init_vars {
282298
max: String::new(),
283299
}],
284300
profiles: vec![profile {
285-
profile_name: String::from("default"),
301+
profile_name: String::from(example_values::PROFILES_PROFILE_NAME),
286302
frontend_url: String::new(),
287303
frontend_token: String::new(),
288304
challenges_domain: String::new(),
@@ -298,38 +314,38 @@ pub fn blank_init() -> init_vars {
298314

299315
pub fn example_init() -> init_vars {
300316
return init_vars {
301-
flag_regex: String::from("ctf{.*}"), // TODO: do that wildcard in the most common regex flavor since Rust regex supports multiple styles
302-
registry_domain: String::from("ghcr.io/youraccount"),
303-
registry_build_user: String::from("admin"),
304-
registry_build_pass: String::from("notrealcreds"),
305-
registry_cluster_user: String::from("cluster_user"),
306-
registry_cluster_pass: String::from("alsofake"),
307-
defaults_difficulty: String::from("1"),
308-
defaults_resources_cpu: String::from("1"),
309-
defaults_resources_memory: String::from("500M"),
317+
flag_regex: String::from(example_values::FLAG_REGEX), // TODO: do that wildcard in the most common regex flavor since Rust regex supports multiple styles
318+
registry_domain: String::from(example_values::REGISTRY_DOMAIN),
319+
registry_build_user: String::from(example_values::REGISTRY_BUILD_USER),
320+
registry_build_pass: String::from(example_values::REGISTRY_BUILD_PASS),
321+
registry_cluster_user: String::from(example_values::REGISTRY_CLUSTER_USER),
322+
registry_cluster_pass: String::from(example_values::REGISTRY_CLUSTER_USER),
323+
defaults_difficulty: String::from(example_values::DEFAULTS_DIFFICULTY),
324+
defaults_resources_cpu: String::from(example_values::DEFAULTS_RESOURCES_CPU),
325+
defaults_resources_memory: String::from(example_values::DEFAULTS_RESOURCES_MEMORY),
310326
points: vec![
311327
points {
312-
difficulty: String::from("1"),
313-
min: String::from("1"),
314-
max: String::from("1337"),
328+
difficulty: String::from(example_values::POINTS_DIFFICULTY),
329+
min: String::from(example_values::POINTS_MIN),
330+
max: String::from(example_values::POINTS_MAX),
315331
},
316332
points {
317333
difficulty: String::from("2"),
318-
min: String::from("200"),
319-
max: String::from("500"),
334+
min: String::from("1"),
335+
max: String::from("1337"),
320336
},
321337
],
322338
profiles: vec![profile {
323-
profile_name: String::from("default"),
324-
frontend_url: String::from("https://ctf.coolguy.invalid"),
325-
frontend_token: String::from("secretsecretsecret"),
326-
challenges_domain: String::from("chals.coolguy.invalid"),
327-
kubecontext: String::from("ctf-cluster"),
328-
s3_bucket_name: String::from("ctf-bucket"),
329-
s3_endpoint: String::from("s3.coolguy.invalid"),
330-
s3_region: String::from("us-west-2"),
331-
s3_accesskey: String::from("accesskey"),
332-
s3_secretaccesskey: String::from("secretkey"),
339+
profile_name: String::from(example_values::PROFILES_PROFILE_NAME),
340+
frontend_url: String::from(example_values::PROFILES_FRONTEND_URL),
341+
frontend_token: String::from(example_values::PROFILES_FRONTEND_TOKEN),
342+
challenges_domain: String::from(example_values::PROFILES_CHALLENGES_DOMAIN),
343+
kubecontext: String::from(example_values::PROFILES_KUBECONTEXT),
344+
s3_bucket_name: String::from(example_values::PROFILES_S3_BUCKET_NAME),
345+
s3_endpoint: String::from(example_values::PROFILES_S3_ENDPOINT),
346+
s3_region: String::from(example_values::PROFILES_S3_REGION),
347+
s3_accesskey: String::from(example_values::PROFILES_S3_ACCESSKEY),
348+
s3_secretaccesskey: String::from(example_values::PROFILES_S3_SECRETACCESSKEY),
333349
}],
334350
};
335351
}

0 commit comments

Comments
 (0)