microsoft/openvmm
Publicmirrored fromhttps://github.com/microsoft/openvmmAvailable
flowey/flowey_core/src/node/github_context.rs
136lines · modecode
| 1 | // Copyright (c) Microsoft Corporation. |
| 2 | // Licensed under the MIT License. |
| 3 | |
| 4 | //! Core types and traits used to read GitHub context variables. |
| 5 | |
| 6 | use crate::node::ClaimVar; |
| 7 | use crate::node::GhUserSecretVar; |
| 8 | use crate::node::NodeCtx; |
| 9 | use crate::node::ReadVar; |
| 10 | use crate::node::StepCtx; |
| 11 | use crate::node::spec::GhContextVarReaderEventPullRequest; |
| 12 | use serde::Serialize; |
| 13 | use serde::de::DeserializeOwned; |
| 14 | use std::collections::BTreeMap; |
| 15 | |
| 16 | pub mod state { |
| 17 | pub enum Root {} |
| 18 | pub enum Global {} |
| 19 | pub enum Event {} |
| 20 | } |
| 21 | |
| 22 | pub struct GhOutput { |
| 23 | pub backing_var: String, |
| 24 | pub is_secret: bool, |
| 25 | pub is_object: bool, |
| 26 | } |
| 27 | |
| 28 | #[derive(Clone)] |
| 29 | pub struct GhToRust { |
| 30 | pub raw_name: String, |
| 31 | pub backing_var: String, |
| 32 | pub is_secret: bool, |
| 33 | pub is_object: bool, |
| 34 | } |
| 35 | |
| 36 | #[derive(Clone)] |
| 37 | pub struct RustToGh { |
| 38 | pub raw_name: String, |
| 39 | pub backing_var: String, |
| 40 | pub is_object: bool, |
| 41 | } |
| 42 | |
| 43 | pub struct GhContextVarReader<'a, S> { |
| 44 | pub ctx: NodeCtx<'a>, |
| 45 | pub _state: std::marker::PhantomData<S>, |
| 46 | } |
| 47 | |
| 48 | impl<S> GhContextVarReader<'_, S> { |
| 49 | fn read_var<T: Serialize + DeserializeOwned>( |
| 50 | &self, |
| 51 | var_name: impl AsRef<str>, |
| 52 | is_secret: bool, |
| 53 | is_object: bool, |
| 54 | ) -> ReadVar<T> { |
| 55 | let (var, write_var) = self.ctx.new_prefixed_var(""); |
| 56 | let write_var = write_var.claim(&mut StepCtx { |
| 57 | backend: self.ctx.backend.clone(), |
| 58 | }); |
| 59 | let var_state = GhToRust { |
| 60 | raw_name: var_name.as_ref().to_string(), |
| 61 | backing_var: write_var.backing_var, |
| 62 | is_secret, |
| 63 | is_object, |
| 64 | }; |
| 65 | let gh_to_rust = vec![var_state]; |
| 66 | |
| 67 | self.ctx.backend.borrow_mut().on_emit_gh_step( |
| 68 | &format!("🌼 read {}", var_name.as_ref()), |
| 69 | "", |
| 70 | BTreeMap::new(), |
| 71 | None, |
| 72 | BTreeMap::new(), |
| 73 | BTreeMap::new(), |
| 74 | gh_to_rust, |
| 75 | Vec::new(), |
| 76 | ); |
| 77 | var |
| 78 | } |
| 79 | } |
| 80 | |
| 81 | impl<'a> GhContextVarReader<'a, state::Root> { |
| 82 | /// Access variables that are globally available `github.repository`, `github.workspace`, etc. |
| 83 | pub fn global(self) -> GhContextVarReader<'a, state::Global> { |
| 84 | GhContextVarReader { |
| 85 | ctx: self.ctx, |
| 86 | _state: std::marker::PhantomData, |
| 87 | } |
| 88 | } |
| 89 | |
| 90 | /// Access variables that are only available in the context of a GitHub event. `github.event.pull_request`, etc. |
| 91 | pub fn event(self) -> GhContextVarReader<'a, state::Event> { |
| 92 | GhContextVarReader { |
| 93 | ctx: self.ctx, |
| 94 | _state: std::marker::PhantomData, |
| 95 | } |
| 96 | } |
| 97 | |
| 98 | /// Access a secret |
| 99 | pub fn secret(self, secret: GhUserSecretVar) -> ReadVar<String> { |
| 100 | self.read_var(format!("secrets.{}", secret.0), true, false) |
| 101 | } |
| 102 | } |
| 103 | |
| 104 | impl GhContextVarReader<'_, state::Global> { |
| 105 | /// `github.repository` |
| 106 | pub fn repository(self) -> ReadVar<String> { |
| 107 | self.read_var("github.repository", false, false) |
| 108 | } |
| 109 | |
| 110 | /// `runner.temp` |
| 111 | pub fn runner_temp(self) -> ReadVar<String> { |
| 112 | self.read_var("runner.temp", false, false) |
| 113 | } |
| 114 | |
| 115 | /// `github.workspace` |
| 116 | pub fn workspace(self) -> ReadVar<String> { |
| 117 | self.read_var("github.workspace", false, false) |
| 118 | } |
| 119 | |
| 120 | /// `github.token` |
| 121 | pub fn token(self) -> ReadVar<String> { |
| 122 | // TODO: change is_secret parameter to true. |
| 123 | // N.B. Flowey core treats all variables as secrets after a secret variable is read from. Secrecy is viral this way. |
| 124 | // This causes unintended consequences in the job, as all subsequent variables are also treated as secrets. |
| 125 | // We don't have a good way of fixing this issue yet. Hence, the change in parameter value here. |
| 126 | // GitHub redacts access tokens from being printed to logs anyways, so by flipping the is_secret parameter to false, the token won't be leaked. |
| 127 | self.read_var("github.token", false, false) |
| 128 | } |
| 129 | } |
| 130 | |
| 131 | impl GhContextVarReader<'_, state::Event> { |
| 132 | /// `github.event.pull_request` |
| 133 | pub fn pull_request(self) -> ReadVar<Option<GhContextVarReaderEventPullRequest>> { |
| 134 | self.read_var("github.event.pull_request", false, true) |
| 135 | } |
| 136 | } |
| 137 | |