|
| 1 | +use async_trait::async_trait; |
1 | 2 | use git2::Repository; |
2 | 3 | use lazy_static::lazy_static; |
3 | 4 | use regex::Regex; |
| 5 | +use reqwest::Client; |
| 6 | +use serde::Deserialize; |
4 | 7 | use serde_json::Value; |
5 | 8 | use simplelog::SharedLogger; |
6 | 9 | use std::collections::BTreeMap; |
@@ -42,6 +45,11 @@ impl GitHubActionsProvider { |
42 | 45 | } |
43 | 46 | } |
44 | 47 |
|
| 48 | +#[derive(Deserialize)] |
| 49 | +struct OIDCResponse { |
| 50 | + value: Option<String>, |
| 51 | +} |
| 52 | + |
45 | 53 | lazy_static! { |
46 | 54 | static ref PR_REF_REGEX: Regex = Regex::new(r"^refs/pull/(?P<pr_number>\d+)/merge$").unwrap(); |
47 | 55 | } |
@@ -129,6 +137,7 @@ impl RunEnvironmentDetector for GitHubActionsProvider { |
129 | 137 | } |
130 | 138 | } |
131 | 139 |
|
| 140 | +#[async_trait(?Send)] |
132 | 141 | impl RunEnvironmentProvider for GitHubActionsProvider { |
133 | 142 | fn get_repository_provider(&self) -> RepositoryProvider { |
134 | 143 | RepositoryProvider::GitHub |
@@ -236,6 +245,46 @@ impl RunEnvironmentProvider for GitHubActionsProvider { |
236 | 245 | .to_string(); |
237 | 246 | Ok(commit_hash) |
238 | 247 | } |
| 248 | + |
| 249 | + /// Get the OIDC token for GitHub Actions. |
| 250 | + /// |
| 251 | + /// This requires that the workflow has the `id-token` permission enabled. |
| 252 | + /// |
| 253 | + /// Docs: |
| 254 | + /// - https://docs.github.com/en/actions/how-tos/secure-your-work/security-harden-deployments/oidc-with-reusable-workflows |
| 255 | + /// - https://docs.github.com/en/actions/concepts/security/openid-connect |
| 256 | + /// - https://docs.github.com/en/actions/reference/security/oidc#methods-for-requesting-the-oidc-token |
| 257 | + async fn get_oidc_token(&self) -> Option<String> { |
| 258 | + // The `ACTIONS_ID_TOKEN_REQUEST_TOKEN` environment variable is set when the `id-token` permission is granted. |
| 259 | + // This is necessary to authenticate with OIDC, but not strictly set just for OIDC. |
| 260 | + let request_token = get_env_variable("ACTIONS_ID_TOKEN_REQUEST_TOKEN").ok(); |
| 261 | + let request_url = get_env_variable("ACTIONS_ID_TOKEN_REQUEST_URL").ok(); |
| 262 | + |
| 263 | + if request_token.is_none() || request_url.is_none() { |
| 264 | + warn!( |
| 265 | + "The Workflow is missing the 'id-token: write' permission required to request an OIDC token. \ |
| 266 | + Please refer to https://docs.github.com/en/actions/how-to-guides/security-hardening-your-workflows/about-security-hardening-with-openid-connect for more information." |
| 267 | + ); |
| 268 | + |
| 269 | + return None; |
| 270 | + } |
| 271 | + |
| 272 | + let request_url = request_url.unwrap(); |
| 273 | + let request_url = format!("{request_url}&audience=codspeed"); |
| 274 | + let request_token = request_token.unwrap(); |
| 275 | + |
| 276 | + Client::new() |
| 277 | + .get(request_url) |
| 278 | + .header("Accept", "application/json") |
| 279 | + .header("Authorization", format!("Bearer {request_token}")) |
| 280 | + .send() |
| 281 | + .await |
| 282 | + .ok()? |
| 283 | + .json::<OIDCResponse>() |
| 284 | + .await |
| 285 | + .ok()? |
| 286 | + .value |
| 287 | + } |
239 | 288 | } |
240 | 289 |
|
241 | 290 | #[cfg(test)] |
|
0 commit comments