-
-
Notifications
You must be signed in to change notification settings - Fork 277
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
e192894
commit c45dbf2
Showing
10 changed files
with
487 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
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,42 @@ | ||
use base64::{engine::general_purpose::STANDARD as B64, Engine}; | ||
use crypto_box::{self, aead::OsRng, PublicKey}; | ||
use octocrab::{ | ||
models::orgs::secrets::{CreateOrganizationSecret, Visibility}, | ||
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 org = octocrab.orgs("owner"); | ||
let secrets = org.secrets(); | ||
|
||
let public_key = secrets.get_public_key().await?; | ||
|
||
let crypto_pk = { | ||
let org_pk_bytes = B64.decode(public_key.key).unwrap(); | ||
let pk_array: [u8; crypto_box::KEY_SIZE] = org_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", | ||
&CreateOrganizationSecret { | ||
encrypted_value: &B64.encode(encrypted_value), | ||
key_id: &public_key.key_id, | ||
visibility: Visibility::Private, | ||
selected_repository_ids: None, | ||
}, | ||
) | ||
.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,161 @@ | ||
use http::StatusCode; | ||
use snafu::GenerateImplicitData; | ||
|
||
use super::OrgHandler; | ||
use crate::models::orgs::secrets::{CreateOrganizationSecret, CreateOrganizationSecretResponse}; | ||
|
||
/// A client to GitHub's organization API. | ||
/// | ||
/// Created with [`Octocrab::orgs`]. | ||
pub struct OrgSecretsHandler<'octo> { | ||
org: &'octo OrgHandler<'octo>, | ||
} | ||
|
||
impl<'octo> OrgSecretsHandler<'octo> { | ||
pub(crate) fn new(org: &'octo OrgHandler<'octo>) -> Self { | ||
Self { org } | ||
} | ||
|
||
fn owner(&self) -> &String { | ||
&self.org.owner | ||
} | ||
|
||
/// Lists all secrets available in an organization without revealing their encrypted values. | ||
/// 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 org = octocrab.orgs("owner"); | ||
/// let secrets = org.secrets(); | ||
/// let all_secrets = secrets.get_secrets().await?; | ||
/// # Ok(()) | ||
/// # } | ||
pub async fn get_secrets( | ||
&self, | ||
) -> crate::Result<crate::models::orgs::secrets::OrganizationSecrets> { | ||
let route = format!("/orgs/{org}/actions/secrets", org = self.owner()); | ||
self.org.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. | ||
// 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 org = octocrab.orgs("owner"); | ||
/// let secrets = org.secrets(); | ||
/// let public_key = secrets.get_public_key().await?; | ||
/// # Ok(()) | ||
/// # } | ||
pub async fn get_public_key(&self) -> crate::Result<crate::models::PublicKey> { | ||
let route = format!("/orgs/{org}/actions/secrets/public-key", org = self.owner()); | ||
self.org.crab.get(route, None::<&()>).await | ||
} | ||
|
||
/// Gets a specific secret from the organization without revealing its encrypted values. | ||
/// 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 org = octocrab.orgs("owner"); | ||
/// let secrets = org.secrets(); | ||
/// let secret_info = secrets.get_secret("TOKEN").await?; | ||
/// # Ok(()) | ||
/// # } | ||
pub async fn get_secret( | ||
&self, | ||
secret_name: impl AsRef<str>, | ||
) -> crate::Result<crate::models::orgs::secrets::OrganizationSecret> { | ||
let route = format!( | ||
"/orgs/{org}/actions/secrets/{secret_name}", | ||
org = self.owner(), | ||
secret_name = secret_name.as_ref() | ||
); | ||
self.org.crab.get(route, None::<&()>).await | ||
} | ||
|
||
/// Creates or updates an organization 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 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(); | ||
/// use octocrab::models::orgs::secrets::{ | ||
/// CreateOrganizationSecret, CreateOrganizationSecretResponse, | ||
/// Visibility | ||
/// }; | ||
/// | ||
/// let org = octocrab.orgs("owner"); | ||
/// let secrets = org.secrets(); | ||
/// let result = secrets.create_or_update_secret("GH_TOKEN", &CreateOrganizationSecret{ | ||
/// key_id: "123456", | ||
/// encrypted_value: "some-b64-encrypted-string", | ||
/// visibility: Visibility::Selected, | ||
/// selected_repository_ids: None, | ||
/// }).await?; | ||
/// | ||
/// match result { | ||
/// CreateOrganizationSecretResponse::Created => println!("Created secret!"), | ||
/// CreateOrganizationSecretResponse::Updated => println!("Updated secret!"), | ||
/// } | ||
/// # Ok(()) | ||
/// # } | ||
pub async fn create_or_update_secret( | ||
&self, | ||
secret_name: impl AsRef<str>, | ||
secret: &CreateOrganizationSecret<'_>, | ||
) -> crate::Result<crate::models::orgs::secrets::CreateOrganizationSecretResponse> { | ||
let route = format!( | ||
"/orgs/{org}/actions/secrets/{secret_name}", | ||
org = self.owner(), | ||
secret_name = secret_name.as_ref() | ||
); | ||
|
||
let resp = { | ||
let resp = self.org.crab._put(route, Some(secret)).await?; | ||
crate::map_github_error(resp).await? | ||
}; | ||
|
||
match resp.status() { | ||
StatusCode::CREATED => Ok(CreateOrganizationSecretResponse::Created), | ||
StatusCode::NO_CONTENT => Ok(CreateOrganizationSecretResponse::Updated), | ||
status_code => Err(crate::Error::Other { | ||
source: format!( | ||
"Unexpected status code from request: {}", | ||
status_code.as_str() | ||
) | ||
.into(), | ||
backtrace: snafu::Backtrace::generate(), | ||
}), | ||
} | ||
} | ||
|
||
/// Deletes an organization secret. | ||
/// 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 org = octocrab.orgs("owner"); | ||
/// let secrets = org.secrets(); | ||
/// | ||
/// secrets.delete_secret("GH_TOKEN").await?; | ||
/// | ||
/// # Ok(()) | ||
/// # } | ||
pub async fn delete_secret(&self, secret_name: impl AsRef<str>) -> crate::Result<()> { | ||
let route = format!( | ||
"/orgs/{org}/actions/secrets/{secret_name}", | ||
org = self.owner(), | ||
secret_name = secret_name.as_ref() | ||
); | ||
|
||
let resp = self.org.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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
use super::*; | ||
pub mod secrets; | ||
|
||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] | ||
#[non_exhaustive] | ||
|
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,48 @@ | ||
use super::super::*; | ||
|
||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] | ||
#[serde(rename_all = "snake_case")] | ||
pub enum Visibility { | ||
All, | ||
Private, | ||
Selected, | ||
} | ||
|
||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] | ||
pub struct OrganizationSecret { | ||
pub name: String, | ||
pub created_at: DateTime<Utc>, | ||
pub updated_at: DateTime<Utc>, | ||
pub visibility: Visibility, | ||
#[serde(skip_serializing_if = "Option::is_none")] | ||
pub selected_repositories_url: Option<String>, | ||
} | ||
|
||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] | ||
#[non_exhaustive] | ||
pub struct OrganizationSecrets { | ||
pub total_count: i32, | ||
pub secrets: Vec<OrganizationSecret>, | ||
} | ||
|
||
#[derive(Debug, Clone, PartialEq, Serialize)] | ||
pub struct CreateOrganizationSecret<'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, | ||
/// Which type of organization repositories have access to the organization secret. | ||
pub visibility: Visibility, | ||
/// An array of repository ids that can access the organization secret. | ||
/// You can only provide a list of repository ids when the visibility is set to selected. | ||
#[serde(skip_serializing_if = "Option::is_none")] | ||
pub selected_repository_ids: Option<&'a [u32]>, | ||
} | ||
|
||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] | ||
#[serde(rename_all = "snake_case")] | ||
pub enum CreateOrganizationSecretResponse { | ||
Created, | ||
Updated, | ||
} |
Oops, something went wrong.