Source file template.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
let parse s =
  let lexbuf = Template_lexer.Encoding.from_string s in
  let lexer = Sedlexing.with_tokenizer Template_lexer.token lexbuf in
  let parser = MenhirLib.Convert.Simplified.traditional2revised Template_parser.template in
  parser lexer

let parse_file file =
  In_channel.with_open_bin (Path.project file) @@ fun ic ->
  let s = In_channel.input_all ic in
  parse s

let try_substitute_iden ?use_sudo node =
  match node with
  | Template_ast.Text _ -> Ok node
  | Template_ast.Iden name ->
    let secret_name = Storage.Secret_name.inject name in
    (try
       let plaintext = Util.Secret.decrypt_silently ?use_sudo secret_name in
       let secret = Secret.Validation.parse_exn plaintext in
       Ok (Template_ast.Text secret.text)
     with
    | Failure s -> Error (name, Printf.sprintf "unable to decrypt secret: %s" s)
    | exn -> Error (name, Printf.sprintf "could not decrypt secret: %s" (Printexc.to_string exn)))

let substitute_all ?use_sudo ast =
  let results = List.map (try_substitute_iden ?use_sudo) ast in
  let successes, failures =
    List.partition_map
      (function
        | Ok node -> Left node
        | Error (name, msg) -> Right (name, msg))
      results
  in
  match failures with
  | [] -> Ok successes
  | failures -> Error failures

let build_text_from_ast ast =
  List.map
    (fun node ->
      match node with
      | Template_ast.Text s -> s
      | Template_ast.Iden secret_name -> Exn.die "found unsubstituted secret %s" secret_name)
    ast
  |> String.concat ""