1
- use anyhow:: { Context , Result , anyhow} ;
2
- use base64:: Engine ;
1
+ use anyhow:: Result ;
3
2
use clap:: Parser ;
4
- use glob:: glob;
5
- use serde_yaml:: Value ;
6
- use std:: fs;
7
- use std:: io:: Write ;
8
- use std:: path:: Path ;
9
- use std:: process:: { Command , Stdio } ;
10
-
11
- #[ derive( Parser , Debug ) ]
12
- struct Args {
13
- /// Base64-encoded private GPG key
14
- #[ clap( long) ]
3
+ use dotenv:: dotenv;
4
+ use sops_gitops_github_action:: import_gpg_key;
5
+ use sops_gitops_github_action:: update_sops_config;
6
+
7
+ /// CLI arguments for the sops-gitops-github-action
8
+ #[ derive( Debug , Parser ) ]
9
+ #[ command( name = "sops-gitops-github-action1" ) ]
10
+ struct MyArgs {
11
+ /// The base64-encoded private GPG key
12
+ #[ arg( long) ]
15
13
private_key : String ,
16
- /// Comma-separated list of base64-encoded public GPG keys
17
- #[ clap( long) ]
14
+
15
+ /// A comma-separated list of base64-encoded public GPG keys
16
+ #[ arg( long) ]
18
17
public_keys : String ,
19
18
}
20
19
21
20
#[ tokio:: main]
22
21
async fn main ( ) -> Result < ( ) > {
23
- let args = Args :: parse ( ) ;
22
+ dotenv ( ) . ok ( ) ;
23
+ let args = MyArgs :: parse ( ) ;
24
24
25
25
// Step 1: Decode and import the private key
26
26
println ! ( "Importing private key..." ) ;
@@ -40,202 +40,3 @@ async fn main() -> Result<()> {
40
40
println ! ( "Action completed!" ) ;
41
41
Ok ( ( ) )
42
42
}
43
-
44
- fn import_gpg_key ( encoded_key : & str ) -> Result < ( ) , anyhow:: Error > {
45
- let decoded_key = base64:: engine:: general_purpose:: STANDARD
46
- . decode ( encoded_key)
47
- . context ( "Failed to decode base64 key" ) ?;
48
- let mut process = Command :: new ( "gpg" )
49
- . args ( [ "--import" ] )
50
- . stdin ( Stdio :: piped ( ) )
51
- . spawn ( )
52
- . context ( "Failed to spawn gpg process" ) ?;
53
-
54
- if let Some ( stdin) = process. stdin . as_mut ( ) {
55
- stdin. write_all ( & decoded_key) ?;
56
- }
57
- process. wait ( ) . context ( "Failed to wait for gpg process" ) ?;
58
- Ok ( ( ) )
59
- }
60
-
61
- fn update_sops_config ( public_keys : & str ) -> Result < ( ) , anyhow:: Error > {
62
- let sops_config_path = "./.sops.yaml" ;
63
- let mut config: Value = if Path :: new ( sops_config_path) . exists ( ) {
64
- let content =
65
- fs:: read_to_string ( sops_config_path) . context ( "Failed to read existing .sops.yaml" ) ?;
66
- serde_yaml:: from_str ( & content) . context ( "Failed to parse .sops.yaml" ) ?
67
- } else {
68
- serde_yaml:: from_str ( "creation_rules: []" ) . unwrap ( )
69
- } ;
70
-
71
- // Update the creation rules with public keys
72
- let creation_rules = config
73
- . get_mut ( "creation_rules" )
74
- . and_then ( Value :: as_sequence_mut)
75
- . ok_or_else ( || anyhow ! ( "Invalid .sops.yaml structure" ) ) ?;
76
-
77
- for public_key in public_keys. split ( ',' ) {
78
- let fingerprint = get_key_fingerprint ( public_key) ?;
79
- let rule = serde_yaml:: to_value ( & serde_yaml:: Mapping :: from_iter ( [ (
80
- Value :: String ( "pgp" . to_string ( ) ) ,
81
- Value :: Sequence ( vec ! [ Value :: String ( fingerprint) ] ) ,
82
- ) ] ) ) ?;
83
- creation_rules. push ( rule) ;
84
- }
85
-
86
- // Write back the updated configuration
87
- let updated_config =
88
- serde_yaml:: to_string ( & config) . context ( "Failed to serialize updated .sops.yaml" ) ?;
89
- fs:: write ( sops_config_path, updated_config) . context ( "Failed to write updated .sops.yaml" ) ?;
90
- Ok ( ( ) )
91
- }
92
-
93
- fn get_key_fingerprint ( encoded_key : & str ) -> Result < String , anyhow:: Error > {
94
- let _decoded_key = base64:: engine:: general_purpose:: STANDARD
95
- . decode ( encoded_key)
96
- . context ( "Failed to decode base64 key" ) ?;
97
- let output = Command :: new ( "gpg" )
98
- . args ( [
99
- "--with-colons" ,
100
- "--import-options" ,
101
- "show-only" ,
102
- "--import" ,
103
- "--fingerprint" ,
104
- ] )
105
- . stdin ( Stdio :: piped ( ) )
106
- . stdout ( Stdio :: piped ( ) )
107
- . spawn ( )
108
- . context ( "Failed to spawn gpg process" ) ?
109
- . wait_with_output ( )
110
- . context ( "Failed to wait for gpg process" ) ?;
111
-
112
- let output_str = String :: from_utf8 ( output. stdout ) . context ( "Failed to parse gpg output" ) ?;
113
- let fingerprint = output_str
114
- . lines ( )
115
- . find ( |line| line. starts_with ( "fpr" ) )
116
- . and_then ( |line| line. split ( ':' ) . nth ( 9 ) )
117
- . map ( String :: from)
118
- . context ( "Failed to extract fingerprint from gpg output" ) ?;
119
- Ok ( fingerprint)
120
- }
121
-
122
- #[ allow( unused) ]
123
- fn setup_workspace ( ) -> Result < ( ) , anyhow:: Error > {
124
- println ! ( "Setting up workspace..." ) ;
125
- fs:: copy ( "/generator/." , "." ) ?;
126
- Ok ( ( ) )
127
- }
128
-
129
- #[ allow( unused) ]
130
- fn debug_output ( ) -> Result < ( ) , anyhow:: Error > {
131
- println ! ( "Working dir: {}" , std:: env:: current_dir( ) ?. display( ) ) ;
132
- println ! ( "================================================" ) ;
133
- for entry in fs:: read_dir ( "." ) ? {
134
- let entry = entry?;
135
- println ! ( "{:?}" , entry. path( ) ) ;
136
- }
137
- println ! ( "================================================" ) ;
138
- Ok ( ( ) )
139
- }
140
-
141
- #[ allow( unused) ]
142
- fn sops_config_file_exists ( ) -> Result < bool , anyhow:: Error > {
143
- let path = Path :: new ( "actions/generator/workspace/.sops.yaml" ) ;
144
- Ok ( path. exists ( ) )
145
- }
146
-
147
- #[ allow( unused) ]
148
- fn create_default_sops_config_file ( ) -> Result < ( ) , anyhow:: Error > {
149
- println ! ( "Creating .sops.yaml..." ) ;
150
- let team_key_fpr = get_key_fingerprint ( "team_private_key" ) ?;
151
- let content = format ! (
152
- "creation_rules:\n - key_groups:\n - pgp:\n - {}" ,
153
- team_key_fpr
154
- ) ;
155
- fs:: write ( "actions/generator/workspace/.sops.yaml" , content) ?;
156
- Ok ( ( ) )
157
- }
158
-
159
- #[ allow( unused) ]
160
- fn public_keys_provided ( ) -> Result < bool , anyhow:: Error > {
161
- let public_keys_file = "actions/generator/public_keys.txt" ;
162
- let content = fs:: read_to_string ( public_keys_file) . unwrap_or_default ( ) ;
163
- let public_keys: Vec < & str > = content. lines ( ) . collect ( ) ;
164
- Ok ( !public_keys. is_empty ( ) )
165
- }
166
-
167
- #[ allow( unused) ]
168
- fn update_sops_configuration_file ( ) -> Result < ( ) , anyhow:: Error > {
169
- println ! ( "Updating .sops.yaml file with public keys..." ) ;
170
- let public_keys_file = "actions/generator/public_keys.txt" ;
171
- let binding = fs:: read_to_string ( public_keys_file) ?;
172
- let public_keys = binding. lines ( ) . collect :: < Vec < _ > > ( ) ;
173
-
174
- let mut config = fs:: read_to_string ( "actions/generator/workspace/.sops.yaml" ) ?;
175
- for key in public_keys {
176
- let key_fingerprint = get_key_fingerprint ( key) ?;
177
- config. push_str ( & format ! ( "\n - {}" , key_fingerprint) ) ;
178
- }
179
- fs:: write ( "actions/generator/workspace/.sops.yaml" , config) ?;
180
- Ok ( ( ) )
181
- }
182
-
183
- #[ allow( unused) ]
184
- fn find_secret_files ( workspace : & str ) -> Result < Vec < String > , anyhow:: Error > {
185
- let mut secret_files = Vec :: new ( ) ;
186
- for entry in glob ( & format ! ( "{}/**/*.yaml" , workspace) ) ? {
187
- let path = entry?;
188
- let content = fs:: read_to_string ( & path) ?;
189
- if content. contains ( "sops:" ) {
190
- secret_files. push ( path. to_string_lossy ( ) . to_string ( ) ) ;
191
- }
192
- }
193
- Ok ( secret_files)
194
- }
195
-
196
- #[ allow( unused) ]
197
- fn update_secret_file ( file_path : & str ) -> Result < ( ) , anyhow:: Error > {
198
- println ! ( "Updating secret file: {}" , file_path) ;
199
- if Path :: new ( file_path) . exists ( ) {
200
- println ! ( "The secret file {} exists." , file_path) ;
201
- Command :: new ( "sops" )
202
- . args ( [ "updatekeys" , file_path, "--yes" ] )
203
- . stdout ( Stdio :: inherit ( ) )
204
- . stderr ( Stdio :: inherit ( ) )
205
- . output ( )
206
- . with_context ( || format ! ( "Failed to re-encrypt secret file: {}" , file_path) ) ?;
207
- } else {
208
- println ! ( "Creating secret file: {}" , file_path) ;
209
- create_secret_file ( file_path) ?;
210
- }
211
- Ok ( ( ) )
212
- }
213
-
214
- #[ allow( unused) ]
215
- fn create_secret_file ( file_path : & str ) -> Result < ( ) , anyhow:: Error > {
216
- fs:: create_dir_all ( Path :: new ( file_path) . parent ( ) . unwrap ( ) ) ?;
217
- let sops_config_path = "actions/generator/workspace/.sops.yaml" ;
218
-
219
- let mut child = Command :: new ( "sops" )
220
- . args ( [ "--config" , sops_config_path, "-e" , "/dev/stdin" ] )
221
- . stdin ( Stdio :: piped ( ) )
222
- . stdout ( Stdio :: from ( fs:: File :: create ( file_path) ?) )
223
- . spawn ( )
224
- . context ( "Failed to spawn sops process" ) ?;
225
-
226
- if let Some ( stdin) = child. stdin . as_mut ( ) {
227
- writeln ! ( stdin, "key: value" ) . context ( "Failed to write to stdin" ) ?;
228
- } else {
229
- return Err ( anyhow:: anyhow!( "Failed to open stdin for sops process" ) ) ;
230
- }
231
-
232
- child. wait ( ) . context ( "Failed to wait for sops process" ) ?;
233
- Ok ( ( ) )
234
- }
235
-
236
- #[ allow( unused) ]
237
- fn set_message ( ) -> Result < ( ) , anyhow:: Error > {
238
- let message = "encrypt sops secrets and update sops.yaml" ;
239
- println ! ( "message={}" , message) ;
240
- Ok ( ( ) )
241
- }
0 commit comments