@@ -10,7 +10,7 @@ use tonic::transport::Server;
1010 about = "gRPC sidecar server for Asherah envelope encryption"
1111) ]
1212struct Cli {
13- /// Unix domain socket path
13+ /// The unix domain socket the server will listen on
1414 #[ arg(
1515 short = 's' ,
1616 long,
@@ -19,84 +19,108 @@ struct Cli {
1919 ) ]
2020 socket_file : String ,
2121
22- /// Service name
22+ /// The name of this service
2323 #[ arg( long, env = "ASHERAH_SERVICE_NAME" ) ]
2424 service : String ,
2525
26- /// Product ID
26+ /// The name of the product that owns this service
2727 #[ arg( long, env = "ASHERAH_PRODUCT_NAME" ) ]
2828 product : String ,
2929
30- /// Metastore type: memory, rdbms, dynamodb
31- #[ arg( long, default_value = " memory", env = "ASHERAH_METASTORE_MODE" ) ]
30+ /// Determines the type of metastore to use for persisting keys
31+ #[ arg( long, value_parser = [ "rdbms" , "dynamodb" , " memory"] , env = "ASHERAH_METASTORE_MODE" ) ]
3232 metastore : String ,
3333
34- /// Database connection string (required for rdbms metastore)
34+ /// The database connection string (required if -- metastore=rdbms )
3535 #[ arg( long, env = "ASHERAH_CONNECTION_STRING" ) ]
3636 conn : Option < String > ,
3737
38- /// KMS type: static, aws
39- #[ arg( long, default_value = " static", env = "ASHERAH_KMS_MODE" ) ]
38+ /// Configures the master key management service
39+ #[ arg( long, value_parser = [ "aws" , " static" ] , default_value = "aws ", env = "ASHERAH_KMS_MODE" ) ]
4040 kms : String ,
4141
42- /// AWS region-to-ARN mapping as JSON (required for aws KMS )
42+ /// A comma separated list of key-value pairs in the form of REGION1=ARN1[,REGION2=ARN2] (required if --kms= aws)
4343 #[ arg( long, env = "ASHERAH_REGION_MAP" ) ]
4444 region_map : Option < String > ,
4545
46- /// Preferred AWS region (required for aws KMS )
46+ /// The preferred AWS region (required if --kms= aws)
4747 #[ arg( long, env = "ASHERAH_PREFERRED_REGION" ) ]
4848 preferred_region : Option < String > ,
4949
50- /// Key expiration duration (e.g., 90m, 2h, 5400s, or 5400)
50+ /// The amount of time a key is considered valid
5151 #[ arg( long, value_parser = parse_go_duration, env = "ASHERAH_EXPIRE_AFTER" ) ]
5252 expire_after : Option < i64 > ,
5353
54- /// Key revocation check interval (e.g., 10m, 1h, 600s, or 600)
54+ /// The amount of time before cached keys are considered stale
5555 #[ arg( long, value_parser = parse_go_duration, env = "ASHERAH_CHECK_INTERVAL" ) ]
5656 check_interval : Option < i64 > ,
5757
58- /// Enable session caching
58+ /// Enable shared session caching
5959 #[ arg( long, env = "ASHERAH_ENABLE_SESSION_CACHING" ) ]
60- session_cache : Option < bool > ,
60+ enable_session_caching : bool ,
6161
62- /// Maximum sessions in cache
63- #[ arg( long, env = "ASHERAH_SESSION_CACHE_MAX_SIZE" ) ]
64- session_cache_max_size : Option < u32 > ,
62+ /// Define the maximum number of sessions to cache
63+ #[ arg( long, default_value = "1000" , env = "ASHERAH_SESSION_CACHE_MAX_SIZE" ) ]
64+ session_cache_max_size : u32 ,
6565
66- /// Session cache TTL (e.g., 2h, 120m, 7200s, or 7200)
67- #[ arg( long, value_parser = parse_go_duration, env = "ASHERAH_SESSION_CACHE_DURATION" ) ]
68- session_cache_duration : Option < i64 > ,
66+ /// The amount of time a session will remain cached
67+ #[ arg( long, value_parser = parse_go_duration, default_value = "2h" , env = "ASHERAH_SESSION_CACHE_DURATION" ) ]
68+ session_cache_duration : i64 ,
6969
70- /// Custom DynamoDB endpoint
70+ /// An optional endpoint URL (hostname only or fully qualified URI) (only supported by --metastore=dynamodb)
7171 #[ arg( long, env = "ASHERAH_DYNAMODB_ENDPOINT" ) ]
7272 dynamodb_endpoint : Option < String > ,
7373
74- /// DynamoDB region
74+ /// The AWS region for DynamoDB requests (defaults to globally configured region) (only supported by --metastore=dynamodb)
7575 #[ arg( long, env = "ASHERAH_DYNAMODB_REGION" ) ]
7676 dynamodb_region : Option < String > ,
7777
78- /// DynamoDB table name
78+ /// The table name for DynamoDB (only supported by --metastore=dynamodb)
7979 #[ arg( long, env = "ASHERAH_DYNAMODB_TABLE_NAME" ) ]
8080 dynamodb_table_name : Option < String > ,
8181
82- /// Replica read consistency (aurora, eventual, global, session)
83- #[ arg( long, env = "ASHERAH_REPLICA_READ_CONSISTENCY" ) ]
82+ /// Required for Aurora sessions using write forwarding
83+ #[ arg( long, value_parser = [ "eventual" , "global" , "session" ] , env = "ASHERAH_REPLICA_READ_CONSISTENCY" ) ]
8484 replica_read_consistency : Option < String > ,
8585
86- /// Enable region suffix on system keys
86+ /// Configure the metastore to use regional suffixes (only supported by --metastore=dynamodb)
8787 #[ arg( long, env = "ASHERAH_ENABLE_REGION_SUFFIX" ) ]
88- enable_region_suffix : Option < bool > ,
88+ enable_region_suffix : bool ,
8989
90- /// Enable debug logging
91- #[ arg( long) ]
90+ /// Enable verbose logging output
91+ #[ arg( short = 'v' , long, env = "ASHERAH_VERBOSE" ) ]
9292 verbose : bool ,
9393}
9494
95+ /// Parse region map from Go-style `REGION1=ARN1[,REGION2=ARN2]` or JSON format.
96+ fn parse_region_map ( s : & str ) -> Option < std:: collections:: HashMap < String , String > > {
97+ let trimmed = s. trim ( ) ;
98+ if trimmed. is_empty ( ) {
99+ return None ;
100+ }
101+ if let Ok ( map) = serde_json:: from_str ( trimmed) {
102+ return Some ( map) ;
103+ }
104+ let mut map = std:: collections:: HashMap :: new ( ) ;
105+ for pair in trimmed. split ( ',' ) {
106+ let pair = pair. trim ( ) ;
107+ if pair. is_empty ( ) {
108+ continue ;
109+ }
110+ let ( k, v) = pair. split_once ( '=' ) . unwrap_or ( ( pair, "" ) ) ;
111+ if !v. is_empty ( ) {
112+ map. insert ( k. to_string ( ) , v. to_string ( ) ) ;
113+ }
114+ }
115+ if map. is_empty ( ) {
116+ None
117+ } else {
118+ Some ( map)
119+ }
120+ }
121+
95122fn cli_to_config ( cli : & Cli ) -> asherah_config:: ConfigOptions {
96- let region_map = cli
97- . region_map
98- . as_ref ( )
99- . and_then ( |s| serde_json:: from_str ( s) . ok ( ) ) ;
123+ let region_map = cli. region_map . as_deref ( ) . and_then ( parse_region_map) ;
100124
101125 asherah_config:: ConfigOptions {
102126 service_name : Some ( cli. service . clone ( ) ) ,
@@ -108,14 +132,14 @@ fn cli_to_config(cli: &Cli) -> asherah_config::ConfigOptions {
108132 preferred_region : cli. preferred_region . clone ( ) ,
109133 expire_after : cli. expire_after ,
110134 check_interval : cli. check_interval ,
111- enable_session_caching : cli. session_cache ,
112- session_cache_max_size : cli. session_cache_max_size ,
113- session_cache_duration : cli. session_cache_duration ,
135+ enable_session_caching : Some ( cli. enable_session_caching ) ,
136+ session_cache_max_size : Some ( cli. session_cache_max_size ) ,
137+ session_cache_duration : Some ( cli. session_cache_duration ) ,
114138 dynamo_db_endpoint : cli. dynamodb_endpoint . clone ( ) ,
115139 dynamo_db_region : cli. dynamodb_region . clone ( ) ,
116140 dynamo_db_table_name : cli. dynamodb_table_name . clone ( ) ,
117141 replica_read_consistency : cli. replica_read_consistency . clone ( ) ,
118- enable_region_suffix : cli. enable_region_suffix ,
142+ enable_region_suffix : Some ( cli. enable_region_suffix ) ,
119143 verbose : Some ( cli. verbose ) ,
120144 ..Default :: default ( )
121145 }
@@ -125,16 +149,9 @@ fn cli_to_config(cli: &Cli) -> asherah_config::ConfigOptions {
125149async fn main ( ) -> Result < ( ) > {
126150 let cli = Cli :: parse ( ) ;
127151
128- // Check ASHERAH_VERBOSE env var in addition to --verbose flag
129- let verbose = cli. verbose
130- || std:: env:: var ( "ASHERAH_VERBOSE" )
131- . is_ok_and ( |v| matches ! ( v. as_str( ) , "1" | "true" | "yes" ) ) ;
132-
133- env_logger:: Builder :: from_env ( env_logger:: Env :: default ( ) . default_filter_or ( if verbose {
134- "debug"
135- } else {
136- "info"
137- } ) )
152+ env_logger:: Builder :: from_env (
153+ env_logger:: Env :: default ( ) . default_filter_or ( if cli. verbose { "debug" } else { "info" } ) ,
154+ )
138155 . init ( ) ;
139156
140157 let config = cli_to_config ( & cli) ;
0 commit comments