-
-
Notifications
You must be signed in to change notification settings - Fork 272
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* added repo secrets api * Apply suggestions from code review Co-authored-by: XAMPPRocky <[email protected]> * Also use method chaining in other places * Reformat project --------- Co-authored-by: XAMPPRocky <[email protected]>
- Loading branch information
1 parent
b0beb85
commit 4b8bd44
Showing
9 changed files
with
459 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
use base64::{engine::general_purpose::STANDARD as B64, Engine}; | ||
use crypto_box::{self, aead::OsRng, PublicKey}; | ||
use octocrab::{models::repos::secrets::CreateRepositorySecret, Octocrab}; | ||
use std::convert::TryInto; | ||
|
||
#[tokio::main] | ||
async fn main() -> octocrab::Result<()> { | ||
let token = std::env::var("GITHUB_TOKEN").expect("GITHUB_TOKEN env variable is required"); | ||
|
||
let octocrab = Octocrab::builder().personal_token(token).build()?; | ||
let repo = octocrab.repos("owner", "repo"); | ||
let secrets = repo.secrets(); | ||
|
||
let public_key = secrets.get_public_key().await?; | ||
|
||
let crypto_pk = { | ||
let pk_bytes = B64.decode(public_key.key).unwrap(); | ||
let pk_array: [u8; crypto_box::KEY_SIZE] = pk_bytes.try_into().unwrap(); | ||
PublicKey::from(pk_array) | ||
}; | ||
|
||
let encrypted_value = crypto_box::seal(&mut OsRng, &crypto_pk, b"Very secret value").unwrap(); | ||
|
||
let result = secrets | ||
.create_or_update_secret( | ||
"TEST_SECRET_RS", | ||
&CreateRepositorySecret { | ||
encrypted_value: &B64.encode(encrypted_value), | ||
key_id: &public_key.key_id, | ||
}, | ||
) | ||
.await?; | ||
|
||
println!("{:?}", result); | ||
|
||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
use http::StatusCode; | ||
use snafu::GenerateImplicitData; | ||
|
||
use super::RepoHandler; | ||
use crate::models::repos::secrets::{CreateRepositorySecret, CreateRepositorySecretResponse}; | ||
|
||
/// A client to GitHub's repository secrets API. | ||
/// | ||
/// Created with [`Octocrab::repos`]. | ||
pub struct RepoSecretsHandler<'octo> { | ||
repo: &'octo RepoHandler<'octo>, | ||
} | ||
|
||
impl<'octo> RepoSecretsHandler<'octo> { | ||
pub(crate) fn new(repo: &'octo RepoHandler<'octo>) -> Self { | ||
Self { repo } | ||
} | ||
|
||
/// Lists all secrets available in a repository without revealing their encrypted values. | ||
/// You must authenticate using an access token with the `repo` scope to use this endpoint. | ||
/// GitHub Apps must have the `secrets` repository permission to use this endpoint. | ||
/// ```no_run | ||
/// # async fn run() -> octocrab::Result<()> { | ||
/// # let octocrab = octocrab::Octocrab::default(); | ||
/// let all_secrets = octocrab.repos("owner", "repo") | ||
/// .secrets() | ||
/// .get_secrets() | ||
/// .await?; | ||
/// # Ok(()) | ||
/// # } | ||
pub async fn get_secrets( | ||
&self, | ||
) -> crate::Result<crate::models::repos::secrets::RepositorySecrets> { | ||
let route = format!( | ||
"/repos/{owner}/{repo}/actions/secrets", | ||
owner = self.repo.owner, | ||
repo = self.repo.repo | ||
); | ||
self.repo.crab.get(route, None::<&()>).await | ||
} | ||
|
||
/// Gets your public key, which you need to encrypt secrets. | ||
/// You need to encrypt a secret before you can create or update secrets. | ||
/// Anyone with read access to the repository can use this endpoint. | ||
/// If the repository is private you must use an access token with the `repo` scope. | ||
/// GitHub Apps must have the `secrets` repository permission to use this endpoint. | ||
/// ```no_run | ||
/// # async fn run() -> octocrab::Result<()> { | ||
/// # let octocrab = octocrab::Octocrab::default(); | ||
/// let public_key = octocrab.repos("owner", "repo") | ||
/// .secrets() | ||
/// .get_public_key() | ||
/// .await?; | ||
/// # Ok(()) | ||
/// # } | ||
pub async fn get_public_key(&self) -> crate::Result<crate::models::PublicKey> { | ||
let route = format!( | ||
"/repos/{owner}/{repo}/actions/secrets/public-key", | ||
owner = self.repo.owner, | ||
repo = self.repo.repo | ||
); | ||
self.repo.crab.get(route, None::<&()>).await | ||
} | ||
|
||
/// Gets a single repository secret without revealing its encrypted value. | ||
/// You must authenticate using an access token with the `repo` scope to use this endpoint. | ||
/// GitHub Apps must have the `secrets` repository permission to use this endpoint. | ||
/// ```no_run | ||
/// # async fn run() -> octocrab::Result<()> { | ||
/// # let octocrab = octocrab::Octocrab::default(); | ||
/// let secret_info = octocrab.repos("owner", "repo") | ||
/// .secrets() | ||
/// .get_secret("TOKEN") | ||
/// .await?; | ||
/// # Ok(()) | ||
/// # } | ||
pub async fn get_secret( | ||
&self, | ||
secret_name: impl AsRef<str>, | ||
) -> crate::Result<crate::models::repos::secrets::RepositorySecret> { | ||
let route = format!( | ||
"/repos/{owner}/{repo}/actions/secrets/{secret_name}", | ||
owner = self.repo.owner, | ||
repo = self.repo.repo, | ||
secret_name = secret_name.as_ref() | ||
); | ||
self.repo.crab.get(route, None::<&()>).await | ||
} | ||
|
||
/// Creates or updates a repository secret with an encrypted value. | ||
/// Encrypt your secret using [`crypto_box`](https://crates.io/crates/crypto_box). | ||
/// You must authenticate using an access token with the `repo` scope to use this endpoint. | ||
/// GitHub Apps must have the `secrets` repository permission to use this endpoint. | ||
/// ```no_run | ||
/// # async fn run() -> octocrab::Result<()> { | ||
/// # let octocrab = octocrab::Octocrab::default(); | ||
/// use octocrab::models::repos::secrets::{CreateRepositorySecret, CreateRepositorySecretResponse}; | ||
/// | ||
/// let result = octocrab.repos("owner", "repo") | ||
/// .secrets() | ||
/// .create_or_update_secret("GH_TOKEN", &CreateRepositorySecret{ | ||
/// key_id: "123456", | ||
/// encrypted_value: "some-b64-encrypted-string", | ||
/// }) | ||
/// .await?; | ||
/// | ||
/// match result { | ||
/// CreateRepositorySecretResponse::Created => println!("Created secret!"), | ||
/// CreateRepositorySecretResponse::Updated => println!("Updated secret!"), | ||
/// } | ||
/// # Ok(()) | ||
/// # } | ||
pub async fn create_or_update_secret( | ||
&self, | ||
secret_name: impl AsRef<str>, | ||
secret: &CreateRepositorySecret<'_>, | ||
) -> crate::Result<CreateRepositorySecretResponse> { | ||
let route = format!( | ||
"/repos/{owner}/{repo}/actions/secrets/{secret_name}", | ||
owner = self.repo.owner, | ||
repo = self.repo.repo, | ||
secret_name = secret_name.as_ref() | ||
); | ||
|
||
let resp = { | ||
let resp = self.repo.crab._put(route, Some(secret)).await?; | ||
crate::map_github_error(resp).await? | ||
}; | ||
|
||
match resp.status() { | ||
StatusCode::CREATED => Ok(CreateRepositorySecretResponse::Created), | ||
StatusCode::NO_CONTENT => Ok(CreateRepositorySecretResponse::Updated), | ||
status_code => Err(crate::Error::Other { | ||
source: format!( | ||
"Unexpected status code from request: {}", | ||
status_code.as_str() | ||
) | ||
.into(), | ||
backtrace: snafu::Backtrace::generate(), | ||
}), | ||
} | ||
} | ||
|
||
/// Deletes a secret in an organization using the secret name. | ||
/// You must authenticate using an access token with the `admin:org` scope to use this endpoint. | ||
/// GitHub Apps must have the `secrets` organization permission to use this endpoint. | ||
/// ```no_run | ||
/// # async fn run() -> octocrab::Result<()> { | ||
/// # let octocrab = octocrab::Octocrab::default(); | ||
/// let repo = octocrab.repos("owner", "repo") | ||
/// .secrets() | ||
/// .delete_secret("GH_TOKEN") | ||
/// .await?; | ||
/// | ||
/// # Ok(()) | ||
/// # } | ||
pub async fn delete_secret(&self, secret_name: impl AsRef<str>) -> crate::Result<()> { | ||
let route = format!( | ||
"/repos/{owner}/{repo}/actions/secrets/{secret_name}", | ||
owner = self.repo.owner, | ||
repo = self.repo.repo, | ||
secret_name = secret_name.as_ref() | ||
); | ||
|
||
let resp = self.repo.crab._delete(route, None::<&()>).await?; | ||
crate::map_github_error(resp).await?; | ||
Ok(()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
use super::super::*; | ||
|
||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] | ||
pub struct RepositorySecret { | ||
pub name: String, | ||
pub created_at: DateTime<Utc>, | ||
pub updated_at: DateTime<Utc>, | ||
} | ||
|
||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] | ||
#[non_exhaustive] | ||
pub struct RepositorySecrets { | ||
pub total_count: i32, | ||
pub secrets: Vec<RepositorySecret>, | ||
} | ||
|
||
#[derive(Debug, Clone, PartialEq, Serialize)] | ||
pub struct CreateRepositorySecret<'a> { | ||
/// Value for your secret, | ||
/// encrypted with LibSodium using the public key retrieved from the Get an organization public key endpoint. | ||
pub encrypted_value: &'a str, | ||
/// ID of the key you used to encrypt the secret. | ||
pub key_id: &'a str, | ||
} | ||
|
||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] | ||
#[serde(rename_all = "snake_case")] | ||
pub enum CreateRepositorySecretResponse { | ||
Created, | ||
Updated, | ||
} |
Oops, something went wrong.