Skip to content

Commit

Permalink
allow repo-specific configuration of gh_token and gh_hook_token
Browse files Browse the repository at this point in the history
Define custom getters for retrieving GH secret values. As the
getter for each token type defaults to looking for a global value
if a repo-specific vaue isn't found, existing deployments don't
need to change.
  • Loading branch information
yasunariw committed Dec 25, 2020
1 parent 0062099 commit 97c9aee
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 4 deletions.
7 changes: 6 additions & 1 deletion lib/action.ml
Original file line number Diff line number Diff line change
Expand Up @@ -218,12 +218,17 @@ module Action (Github_api : Api.Github) (Slack_api : Api.Slack) = struct
| _ -> Lwt.return @@ Ok ()

let process_github_notification (ctx : Context.t) headers body =
let validate_signature secrets payload =
let repo = Github.repo_of_notification payload in
let signing_key = Context.gh_hook_token_of_secrets secrets repo.url in
Github.validate_signature ?signing_key ~headers body
in
try%lwt
let secrets = Context.get_secrets_exn ctx in
match Github.parse_exn headers body with
| exception exn -> Exn_lwt.fail ~exn "failed to parse payload"
| payload ->
match Github.validate_signature ?signing_key:secrets.gh_hook_token ~headers body with
match validate_signature secrets payload with
| Error e -> action_error e
| Ok () ->
( match%lwt refresh_repo_config ctx payload with
Expand Down
6 changes: 4 additions & 2 deletions lib/api_remote.ml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ module Github : Api.Github = struct
let get_config ~(ctx : Context.t) ~repo =
let secrets = Context.get_secrets_exn ctx in
let url = contents_url ~repo ~path:ctx.config_filename in
let headers = build_headers ?token:secrets.gh_token () in
let token = Context.gh_token_of_secrets secrets repo.url in
let headers = build_headers ?token () in
match%lwt http_request ~headers `GET url with
| Error e -> Lwt.return @@ fmt_error "error while querying remote: %s\nfailed to get config from file %s" e url
| Ok res ->
Expand All @@ -41,7 +42,8 @@ module Github : Api.Github = struct
let get_api_commit ~(ctx : Context.t) ~repo ~sha =
let secrets = Context.get_secrets_exn ctx in
let url = commits_url ~repo ~sha in
let headers = build_headers ?token:secrets.gh_token () in
let token = Context.gh_token_of_secrets secrets repo.url in
let headers = build_headers ?token () in
match%lwt http_request ~headers `GET url with
| Ok res -> Lwt.return @@ Ok (Github_j.api_commit_of_string res)
| Error e -> Lwt.return @@ fmt_error "error while querying remote: %s\nfailed to get api commit from file %s" e url
Expand Down
7 changes: 7 additions & 0 deletions lib/config.atd
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
type status_rule <ocaml from="Rule"> = abstract
type prefix_rule <ocaml from="Rule"> = abstract
type label_rule <ocaml from="Rule"> = abstract
type 'v map_as_object <ocaml from="Common"> = abstract

(* This type of rule is used for CI build notifications. *)
type status_rules = {
Expand Down Expand Up @@ -36,10 +37,16 @@ type webhook = {
channel : string; (* name of the Slack channel to post the message *)
}

type gh_repo_secrets = {
?gh_token : string option; (* GitHub personal access token, if repo access requires it *)
?gh_hook_token : string option; (* GitHub webhook token to secure the webhook *)
}

(* This is the structure of the secrets file which stores sensitive information, and
shouldn't be checked into version control. *)
type secrets = {
slack_hooks : webhook list;
?gh_token : string option; (* GitHub personal access token, if repo access requires it *)
?gh_hook_token : string option; (* GitHub webhook token to secure the webhook *)
~repositories <ocaml default="Common.StringMap.empty"> : gh_repo_secrets map_as_object;
}
13 changes: 12 additions & 1 deletion lib/context.ml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,16 @@ let get_secrets_exn ctx =
| None -> context_error "secrets is uninitialized"
| Some secrets -> secrets

let gh_token_of_secrets (secrets : Config_t.secrets) repo_url =
match Map.find secrets.repositories repo_url with
| None -> secrets.gh_token
| Some repo_secrets -> repo_secrets.gh_token

let gh_hook_token_of_secrets (secrets : Config_t.secrets) repo_url =
match Map.find secrets.repositories repo_url with
| None -> secrets.gh_hook_token
| Some repo_secrets -> repo_secrets.gh_hook_token

let hook_of_channel ctx channel_name =
let secrets = get_secrets_exn ctx in
match List.find secrets.slack_hooks ~f:(fun webhook -> String.equal webhook.channel channel_name) with
Expand Down Expand Up @@ -64,8 +74,9 @@ let refresh_state ctx =
let print_config ctx repo_url =
let cfg = State.find_repo_config_exn ctx.state repo_url in
let secrets = get_secrets_exn ctx in
let token = gh_hook_token_of_secrets secrets repo_url in
log#info "using prefix routing:";
Rule.Prefix.print_prefix_routing cfg.prefix_rules.rules;
log#info "using label routing:";
Rule.Label.print_label_routing cfg.label_rules.rules;
log#info "signature checking %s" (if Option.is_some secrets.gh_hook_token then "enabled" else "disabled")
log#info "signature checking %s" (if Option.is_some token then "enabled" else "disabled")

0 comments on commit 97c9aee

Please sign in to comment.