provide custom webhook secret to all resources which take webhooks

This commit is contained in:
mbecker20
2024-08-11 22:05:26 -07:00
parent 197e938346
commit 8d75fa3f2f
25 changed files with 302 additions and 93 deletions
+6
View File
@@ -216,6 +216,12 @@ impl Resolve<CreateBuildWebhook, User> for State {
..
} = core_config();
let webhook_secret = if build.config.webhook_secret.is_empty() {
webhook_secret
} else {
&build.config.webhook_secret
};
let host = webhook_base_url.as_ref().unwrap_or(host);
let url = format!("{host}/listener/github/build/{}", build.id);
+6
View File
@@ -217,6 +217,12 @@ impl Resolve<CreateRepoWebhook, User> for State {
..
} = core_config();
let webhook_secret = if repo.config.webhook_secret.is_empty() {
webhook_secret
} else {
&repo.config.webhook_secret
};
let host = webhook_base_url.as_ref().unwrap_or(host);
let url = match action {
RepoWebhookAction::Clone => {
+6
View File
@@ -348,6 +348,12 @@ impl Resolve<CreateStackWebhook, User> for State {
..
} = core_config();
let webhook_secret = if stack.config.webhook_secret.is_empty() {
webhook_secret
} else {
&stack.config.webhook_secret
};
let host = webhook_base_url.as_ref().unwrap_or(host);
let url = match action {
StackWebhookAction::Refresh => {
+11 -1
View File
@@ -105,7 +105,11 @@ impl Resolve<UpdateResourceSync, User> for State {
}
impl Resolve<RefreshResourceSyncPending, User> for State {
#[instrument(name = "RefreshResourceSyncPending", level = "debug", skip(self, user))]
#[instrument(
name = "RefreshResourceSyncPending",
level = "debug",
skip(self, user)
)]
async fn resolve(
&self,
RefreshResourceSyncPending { sync }: RefreshResourceSyncPending,
@@ -420,6 +424,12 @@ impl Resolve<CreateSyncWebhook, User> for State {
..
} = core_config();
let webhook_secret = if sync.config.webhook_secret.is_empty() {
webhook_secret
} else {
&sync.config.webhook_secret
};
let host = webhook_base_url.as_ref().unwrap_or(host);
let url = match action {
SyncWebhookAction::Refresh => {
+7 -2
View File
@@ -31,15 +31,20 @@ pub async fn handle_build_webhook(
let lock = build_locks().get_or_insert_default(&build_id).await;
let _lock = lock.lock().await;
verify_gh_signature(headers, &body).await?;
let request_branch = extract_branch(&body)?;
let build = resource::get::<Build>(&build_id).await?;
verify_gh_signature(headers, &body, &build.config.webhook_secret)
.await?;
if !build.config.webhook_enabled {
return Err(anyhow!("build does not have webhook enabled"));
}
let request_branch = extract_branch(&body)?;
if request_branch != build.config.branch {
return Err(anyhow!("request branch does not match expected"));
}
let user = git_webhook_user().to_owned();
let req = ExecuteRequest::RunBuild(RunBuild { build: build_id });
let update = init_execution_update(&req, &user).await?;
+8 -4
View File
@@ -216,6 +216,7 @@ pub fn router() -> Router {
async fn verify_gh_signature(
headers: HeaderMap,
body: &str,
custom_secret: &str,
) -> anyhow::Result<()> {
// wait random amount of time
tokio::time::sleep(random_duration(0, 500)).await;
@@ -229,10 +230,13 @@ async fn verify_gh_signature(
return Err(anyhow!("failed to unwrap signature"));
}
let signature = signature.unwrap().replace("sha256=", "");
let mut mac = HmacSha256::new_from_slice(
core_config().webhook_secret.as_bytes(),
)
.expect("github webhook | failed to create hmac sha256");
let secret_bytes = if custom_secret.is_empty() {
core_config().webhook_secret.as_bytes()
} else {
custom_secret.as_bytes()
};
let mut mac = HmacSha256::new_from_slice(secret_bytes)
.expect("github webhook | failed to create hmac sha256");
mac.update(body.as_bytes());
let expected = mac.finalize().into_bytes().encode_hex::<String>();
if signature == expected {
+14 -5
View File
@@ -33,15 +33,24 @@ pub async fn handle_procedure_webhook(
procedure_locks().get_or_insert_default(&procedure_id).await;
let _lock = lock.lock().await;
verify_gh_signature(headers, &body).await?;
let procedure = resource::get::<Procedure>(&procedure_id).await?;
verify_gh_signature(
headers,
&body,
&procedure.config.webhook_secret,
)
.await?;
if !procedure.config.webhook_enabled {
return Err(anyhow!("procedure does not have webhook enabled"));
}
let request_branch = extract_branch(&body)?;
if request_branch != target_branch {
return Err(anyhow!("request branch does not match expected"));
}
let procedure = resource::get::<Procedure>(&procedure_id).await?;
if !procedure.config.webhook_enabled {
return Err(anyhow!("procedure does not have webhook enabled"));
}
let user = git_webhook_user().to_owned();
let req = ExecuteRequest::RunProcedure(RunProcedure {
procedure: procedure_id,
+28 -11
View File
@@ -30,15 +30,20 @@ pub async fn handle_repo_clone_webhook(
let lock = repo_locks().get_or_insert_default(&repo_id).await;
let _lock = lock.lock().await;
verify_gh_signature(headers, &body).await?;
let request_branch = extract_branch(&body)?;
let repo = resource::get::<Repo>(&repo_id).await?;
verify_gh_signature(headers, &body, &repo.config.webhook_secret)
.await?;
if !repo.config.webhook_enabled {
return Err(anyhow!("repo does not have webhook enabled"));
}
let request_branch = extract_branch(&body)?;
if request_branch != repo.config.branch {
return Err(anyhow!("request branch does not match expected"));
}
let user = git_webhook_user().to_owned();
let req =
crate::api::execute::ExecuteRequest::CloneRepo(CloneRepo {
@@ -64,15 +69,20 @@ pub async fn handle_repo_pull_webhook(
let lock = repo_locks().get_or_insert_default(&repo_id).await;
let _lock = lock.lock().await;
verify_gh_signature(headers, &body).await?;
let request_branch = extract_branch(&body)?;
let repo = resource::get::<Repo>(&repo_id).await?;
verify_gh_signature(headers, &body, &repo.config.webhook_secret)
.await?;
if !repo.config.webhook_enabled {
return Err(anyhow!("repo does not have webhook enabled"));
}
let request_branch = extract_branch(&body)?;
if request_branch != repo.config.branch {
return Err(anyhow!("request branch does not match expected"));
}
let user = git_webhook_user().to_owned();
let req = crate::api::execute::ExecuteRequest::PullRepo(PullRepo {
repo: repo_id,
@@ -96,23 +106,30 @@ pub async fn handle_repo_build_webhook(
let lock = repo_locks().get_or_insert_default(&repo_id).await;
let _lock = lock.lock().await;
verify_gh_signature(headers, &body).await?;
let request_branch = extract_branch(&body)?;
let repo = resource::get::<Repo>(&repo_id).await?;
verify_gh_signature(headers, &body, &repo.config.webhook_secret)
.await?;
if !repo.config.webhook_enabled {
return Err(anyhow!("repo does not have webhook enabled"));
}
let request_branch = extract_branch(&body)?;
if request_branch != repo.config.branch {
return Err(anyhow!("request branch does not match expected"));
}
let user = git_webhook_user().to_owned();
let req = crate::api::execute::ExecuteRequest::BuildRepo(BuildRepo {
repo: repo_id,
});
let req =
crate::api::execute::ExecuteRequest::BuildRepo(BuildRepo {
repo: repo_id,
});
let update = init_execution_update(&req, &user).await?;
let crate::api::execute::ExecuteRequest::BuildRepo(req) = req else {
let crate::api::execute::ExecuteRequest::BuildRepo(req) = req
else {
unreachable!()
};
State.resolve(req, (user, update)).await?;
Ok(())
}
}
+14 -4
View File
@@ -31,15 +31,20 @@ pub async fn handle_stack_refresh_webhook(
let lock = stack_locks().get_or_insert_default(&stack_id).await;
let _lock = lock.lock().await;
verify_gh_signature(headers, &body).await?;
let request_branch = extract_branch(&body)?;
let stack = resource::get::<Stack>(&stack_id).await?;
verify_gh_signature(headers, &body, &stack.config.webhook_secret)
.await?;
if !stack.config.webhook_enabled {
return Err(anyhow!("stack does not have webhook enabled"));
}
let request_branch = extract_branch(&body)?;
if request_branch != stack.config.branch {
return Err(anyhow!("request branch does not match expected"));
}
let user = git_webhook_user().to_owned();
State
.resolve(RefreshStackCache { stack: stack.id }, user)
@@ -58,15 +63,20 @@ pub async fn handle_stack_deploy_webhook(
let lock = stack_locks().get_or_insert_default(&stack_id).await;
let _lock = lock.lock().await;
verify_gh_signature(headers, &body).await?;
let request_branch = extract_branch(&body)?;
let stack = resource::get::<Stack>(&stack_id).await?;
verify_gh_signature(headers, &body, &stack.config.webhook_secret)
.await?;
if !stack.config.webhook_enabled {
return Err(anyhow!("stack does not have webhook enabled"));
}
let request_branch = extract_branch(&body)?;
if request_branch != stack.config.branch {
return Err(anyhow!("request branch does not match expected"));
}
let user = git_webhook_user().to_owned();
let req = ExecuteRequest::DeployStack(DeployStack {
stack: stack_id,
+14 -4
View File
@@ -31,15 +31,20 @@ pub async fn handle_sync_refresh_webhook(
let lock = sync_locks().get_or_insert_default(&sync_id).await;
let _lock = lock.lock().await;
verify_gh_signature(headers, &body).await?;
let request_branch = extract_branch(&body)?;
let sync = resource::get::<ResourceSync>(&sync_id).await?;
verify_gh_signature(headers, &body, &sync.config.webhook_secret)
.await?;
if !sync.config.webhook_enabled {
return Err(anyhow!("sync does not have webhook enabled"));
}
let request_branch = extract_branch(&body)?;
if request_branch != sync.config.branch {
return Err(anyhow!("request branch does not match expected"));
}
let user = git_webhook_user().to_owned();
State
.resolve(RefreshResourceSyncPending { sync: sync_id }, user)
@@ -58,15 +63,20 @@ pub async fn handle_sync_execute_webhook(
let lock = sync_locks().get_or_insert_default(&sync_id).await;
let _lock = lock.lock().await;
verify_gh_signature(headers, &body).await?;
let request_branch = extract_branch(&body)?;
let sync = resource::get::<ResourceSync>(&sync_id).await?;
verify_gh_signature(headers, &body, &sync.config.webhook_secret)
.await?;
if !sync.config.webhook_enabled {
return Err(anyhow!("sync does not have webhook enabled"));
}
let request_branch = extract_branch(&body)?;
if request_branch != sync.config.branch {
return Err(anyhow!("request branch does not match expected"));
}
let user = git_webhook_user().to_owned();
let req = ExecuteRequest::RunSync(RunSync { sync: sync_id });
let update = init_execution_update(&req, &user).await?;
+1
View File
@@ -243,6 +243,7 @@ impl TryFrom<Build> for monitor_client::entities::build::Build {
use_buildx,
labels: Default::default(),
webhook_enabled: true,
webhook_secret: Default::default(),
commit: Default::default(),
},
};
+1
View File
@@ -163,6 +163,7 @@ impl From<BuildConfig>
extra_args: value.extra_args,
use_buildx: value.use_buildx,
webhook_enabled: value.webhook_enabled,
webhook_secret: Default::default(),
image_registry: value.image_registry.into(),
}
}
+1
View File
@@ -157,6 +157,7 @@ impl From<BuildConfig>
})
},
webhook_enabled: value.webhook_enabled,
webhook_secret: Default::default(),
}
}
}
+1 -1
View File
@@ -33,7 +33,7 @@ Users will have to manage their own versioning though.
- **Sync**: Sync resources declared in toml files in Github repos.
- Manage resources declaratively, with git history for configuration rollbacks.
- See the actions which will be performed in the UI, and execute them upon manual confirmation.
- Use a Github webhook to automatically execute syncs on git push.
- Use a Git webhook to automatically execute syncs on git push.
- **Resource Tagging**
- Attach multiple *tags* to resources, which can be used to group related resources together. These can be used to filter resources in the UI.
+19 -12
View File
@@ -127,6 +127,15 @@ pub struct BuildConfig {
#[partial_default(default_git_https())]
pub git_https: bool,
/// The git account used to access private repos.
/// Passing empty string can only clone public repos.
///
/// Note. A token for the account must be available in the core config or the builder server's periphery config
/// for the configured git provider.
#[serde(default)]
#[builder(default)]
pub git_account: String,
/// The repo used as the source of the build.
#[serde(default)]
#[builder(default)]
@@ -143,14 +152,17 @@ pub struct BuildConfig {
#[builder(default)]
pub commit: String,
/// The git account used to access private repos.
/// Passing empty string can only clone public repos.
///
/// Note. A token for the account must be available in the core config or the builder server's periphery config
/// for the configured git provider.
/// Whether incoming webhooks actually trigger action.
#[serde(default = "default_webhook_enabled")]
#[builder(default = "default_webhook_enabled()")]
#[partial_default(default_webhook_enabled())]
pub webhook_enabled: bool,
/// Optionally provide an alternate webhook secret for this build.
/// If its an empty string, use the default secret from the config.
#[serde(default)]
#[builder(default)]
pub git_account: String,
pub webhook_secret: String,
/// The optional command run after repo clone and before docker build.
#[serde(default)]
@@ -185,12 +197,6 @@ pub struct BuildConfig {
#[builder(default)]
pub use_buildx: bool,
/// Whether incoming webhooks actually trigger action.
#[serde(default = "default_webhook_enabled")]
#[builder(default = "default_webhook_enabled()")]
#[partial_default(default_webhook_enabled())]
pub webhook_enabled: bool,
/// Any extra docker cli arguments to be included in the build command
#[serde(default)]
#[builder(default)]
@@ -298,6 +304,7 @@ impl Default for BuildConfig {
use_buildx: Default::default(),
image_registry: Default::default(),
webhook_enabled: default_webhook_enabled(),
webhook_secret: Default::default(),
}
}
}
+7
View File
@@ -66,6 +66,12 @@ pub struct ProcedureConfig {
#[builder(default = "default_webhook_enabled()")]
#[partial_default(default_webhook_enabled())]
pub webhook_enabled: bool,
/// Optionally provide an alternate webhook secret for this procedure.
/// If its an empty string, use the default secret from the config.
#[serde(default)]
#[builder(default)]
pub webhook_secret: String,
}
impl ProcedureConfig {
@@ -83,6 +89,7 @@ impl Default for ProcedureConfig {
Self {
stages: Default::default(),
webhook_enabled: default_webhook_enabled(),
webhook_secret: Default::default()
}
}
}
+30 -23
View File
@@ -111,6 +111,23 @@ pub struct RepoConfig {
#[partial_default(default_git_provider())]
pub git_provider: String,
/// Whether to use https to clone the repo (versus http). Default: true
///
/// Note. Monitor does not currently support cloning repos via ssh.
#[serde(default = "default_git_https")]
#[builder(default = "default_git_https()")]
#[partial_default(default_git_https())]
pub git_https: bool,
/// The git account used to access private repos.
/// Passing empty string can only clone public repos.
///
/// Note. A token for the account must be available in the core config or the builder server's periphery config
/// for the configured git provider.
#[serde(default)]
#[builder(default)]
pub git_account: String,
/// The github repo to clone.
#[serde(default)]
#[builder(default)]
@@ -127,28 +144,23 @@ pub struct RepoConfig {
#[builder(default)]
pub commit: String,
/// The git account used to access private repos.
/// Passing empty string can only clone public repos.
///
/// Note. A token for the account must be available in the core config or the builder server's periphery config
/// for the configured git provider.
#[serde(default)]
#[builder(default)]
pub git_account: String,
/// Whether to use https to clone the repo (versus http). Default: true
///
/// Note. Monitor does not currently support cloning repos via ssh.
#[serde(default = "default_git_https")]
#[builder(default = "default_git_https()")]
#[partial_default(default_git_https())]
pub git_https: bool,
/// Explicitly specify the folder to clone the repo in.
#[serde(default)]
#[builder(default)]
pub path: String,
/// Whether incoming webhooks actually trigger action.
#[serde(default = "default_webhook_enabled")]
#[builder(default = "default_webhook_enabled()")]
#[partial_default(default_webhook_enabled())]
pub webhook_enabled: bool,
/// Optionally provide an alternate webhook secret for this repo.
/// If its an empty string, use the default secret from the config.
#[serde(default)]
#[builder(default)]
pub webhook_secret: String,
/// Command to be run after the repo is cloned.
/// The path is relative to the root of the repo.
#[serde(default)]
@@ -189,12 +201,6 @@ pub struct RepoConfig {
#[serde(default)]
#[builder(default)]
pub skip_secret_interp: bool,
/// Whether incoming webhooks actually trigger action.
#[serde(default = "default_webhook_enabled")]
#[builder(default = "default_webhook_enabled()")]
#[partial_default(default_webhook_enabled())]
pub webhook_enabled: bool,
}
impl RepoConfig {
@@ -241,6 +247,7 @@ impl Default for RepoConfig {
env_file_path: default_env_file_path(),
skip_secret_interp: Default::default(),
webhook_enabled: default_webhook_enabled(),
webhook_secret: Default::default(),
}
}
}
+7
View File
@@ -358,6 +358,12 @@ pub struct StackConfig {
#[partial_default(default_webhook_enabled())]
pub webhook_enabled: bool,
/// Optionally provide an alternate webhook secret for this stack.
/// If its an empty string, use the default secret from the config.
#[serde(default)]
#[builder(default)]
pub webhook_secret: String,
/// Whether to send StackStateChange alerts for this stack.
#[serde(default = "default_send_alerts")]
#[builder(default = "default_send_alerts()")]
@@ -421,6 +427,7 @@ impl Default for StackConfig {
commit: Default::default(),
git_account: Default::default(),
webhook_enabled: default_webhook_enabled(),
webhook_secret: Default::default(),
send_alerts: default_send_alerts(),
}
}
+7
View File
@@ -240,6 +240,12 @@ pub struct ResourceSyncConfig {
#[builder(default = "default_webhook_enabled()")]
#[partial_default(default_webhook_enabled())]
pub webhook_enabled: bool,
/// Optionally provide an alternate webhook secret for this sync.
/// If its an empty string, use the default secret from the config.
#[serde(default)]
#[builder(default)]
pub webhook_secret: String,
}
impl ResourceSyncConfig {
@@ -280,6 +286,7 @@ impl Default for ResourceSyncConfig {
resource_path: default_resource_path(),
delete: Default::default(),
webhook_enabled: default_webhook_enabled(),
webhook_secret: Default::default(),
}
}
}
+47 -22
View File
@@ -401,12 +401,6 @@ export interface BuildConfig {
* Note. Monitor does not currently support cloning repos via ssh.
*/
git_https: boolean;
/** The repo used as the source of the build. */
repo?: string;
/** The branch of the repo. */
branch: string;
/** Optionally set a specific commit hash. */
commit?: string;
/**
* The git account used to access private repos.
* Passing empty string can only clone public repos.
@@ -415,6 +409,19 @@ export interface BuildConfig {
* for the configured git provider.
*/
git_account?: string;
/** The repo used as the source of the build. */
repo?: string;
/** The branch of the repo. */
branch: string;
/** Optionally set a specific commit hash. */
commit?: string;
/** Whether incoming webhooks actually trigger action. */
webhook_enabled: boolean;
/**
* Optionally provide an alternate webhook secret for this build.
* If its an empty string, use the default secret from the config.
*/
webhook_secret?: string;
/** The optional command run after repo clone and before docker build. */
pre_build?: SystemCommand;
/** Configuration for the registry to push the built image to. */
@@ -430,8 +437,6 @@ export interface BuildConfig {
skip_secret_interp?: boolean;
/** Whether to use buildx to build (eg `docker buildx build ...`) */
use_buildx?: boolean;
/** Whether incoming webhooks actually trigger action. */
webhook_enabled: boolean;
/** Any extra docker cli arguments to be included in the build command */
extra_args?: string[];
/**
@@ -871,6 +876,11 @@ export interface ProcedureConfig {
stages?: ProcedureStage[];
/** Whether incoming webhooks actually trigger action. */
webhook_enabled: boolean;
/**
* Optionally provide an alternate webhook secret for this procedure.
* If its an empty string, use the default secret from the config.
*/
webhook_secret?: string;
}
/**
@@ -980,12 +990,12 @@ export interface RepoConfig {
builder_id?: string;
/** The git provider domain. Default: github.com */
git_provider: string;
/** The github repo to clone. */
repo?: string;
/** The repo branch. */
branch: string;
/** Optionally set a specific commit hash. */
commit?: string;
/**
* Whether to use https to clone the repo (versus http). Default: true
*
* Note. Monitor does not currently support cloning repos via ssh.
*/
git_https: boolean;
/**
* The git account used to access private repos.
* Passing empty string can only clone public repos.
@@ -994,14 +1004,21 @@ export interface RepoConfig {
* for the configured git provider.
*/
git_account?: string;
/**
* Whether to use https to clone the repo (versus http). Default: true
*
* Note. Monitor does not currently support cloning repos via ssh.
*/
git_https: boolean;
/** The github repo to clone. */
repo?: string;
/** The repo branch. */
branch: string;
/** Optionally set a specific commit hash. */
commit?: string;
/** Explicitly specify the folder to clone the repo in. */
path?: string;
/** Whether incoming webhooks actually trigger action. */
webhook_enabled: boolean;
/**
* Optionally provide an alternate webhook secret for this repo.
* If its an empty string, use the default secret from the config.
*/
webhook_secret?: string;
/**
* Command to be run after the repo is cloned.
* The path is relative to the root of the repo.
@@ -1028,8 +1045,6 @@ export interface RepoConfig {
env_file_path: string;
/** Whether to skip secret interpolation into the repo environment variable file. */
skip_secret_interp?: boolean;
/** Whether incoming webhooks actually trigger action. */
webhook_enabled: boolean;
}
export interface RepoInfo {
@@ -1522,6 +1537,11 @@ export interface StackConfig {
commit?: string;
/** Whether incoming webhooks actually trigger action. */
webhook_enabled: boolean;
/**
* Optionally provide an alternate webhook secret for this stack.
* If its an empty string, use the default secret from the config.
*/
webhook_secret?: string;
/** Whether to send StackStateChange alerts for this stack. */
send_alerts: boolean;
}
@@ -1732,6 +1752,11 @@ export interface ResourceSyncConfig {
delete?: boolean;
/** Whether incoming webhooks actually trigger action. */
webhook_enabled: boolean;
/**
* Optionally provide an alternate webhook secret for this sync.
* If its an empty string, use the default secret from the config.
*/
webhook_secret?: string;
}
export type PendingSyncUpdatesData =
@@ -287,16 +287,31 @@ export const BuildConfig = ({
},
},
{
label: "Github Webhook",
label: "Git Webhook",
description:
"Configure your repo provider to send webhooks to Monitor",
components: {
["Guard" as any]: () => {
if (update.branch ?? config.branch) {
return null;
}
return (
<ConfigItem label="Configure Branch">
<div>Must configure Branch before webhooks will work.</div>
</ConfigItem>
);
},
["build" as any]: () => (
<ConfigItem label="Webhook Url">
<CopyGithubWebhook path={`/build/${id}`} />
</ConfigItem>
),
webhook_enabled: webhook !== undefined && !webhook.managed,
webhook_secret: {
description:
"Provide a custom webhook secret for this resource, or use the global default.",
placeholder: "Input custom secret",
},
["managed" as any]: () => {
const inv = useInvalidate();
const { toast } = useToast();
@@ -192,7 +192,7 @@ const ProcedureConfigInner = ({
<Section>
<Card>
<CardHeader className="p-4">
<ConfigItem label="Github Webhook" className="items-start">
<ConfigItem label="Git Webhook" className="items-start">
<div className="flex flex-col gap-4">
<div className="flex items-center gap-4">
<div className="flex items-center gap-2">
@@ -223,6 +223,19 @@ const ProcedureConfigInner = ({
disabled={disabled}
/>
</div>
<div className="flex items-center justify-end gap-4 w-full">
<div className="text-muted-foreground">Custom Secret:</div>
<Input
value={
config.webhook_secret ?? procedure.config?.webhook_secret
}
onChange={(e) =>
setConfig({ ...config, webhook_secret: e.target.value })
}
disabled={disabled}
className="w-[400px] max-w-full"
/>
</div>
</div>
</ConfigItem>
</CardHeader>
@@ -150,10 +150,20 @@ export const RepoConfig = ({ id }: { id: string }) => {
},
},
{
label: "Github Webhooks",
label: "Git Webhooks",
description:
"Configure your repo provider to send webhooks to Monitor",
components: {
["Guard" as any]: () => {
if (update.branch ?? config.branch) {
return null;
}
return (
<ConfigItem label="Configure Branch">
<div>Must configure Branch before webhooks will work.</div>
</ConfigItem>
);
},
["pull" as any]: () => (
<ConfigItem label="Pull">
<CopyGithubWebhook path={`/repo/${id}/pull`} />
@@ -170,6 +180,11 @@ export const RepoConfig = ({ id }: { id: string }) => {
</ConfigItem>
),
webhook_enabled: webhooks !== undefined && !webhooks.managed,
webhook_secret: {
description:
"Provide a custom webhook secret for this resource, or use the global default.",
placeholder: "Input custom secret",
},
["managed" as any]: () => {
const inv = useInvalidate();
const { toast } = useToast();
@@ -101,10 +101,20 @@ export const ResourceSyncConfig = ({
},
},
{
label: "Github Webhooks",
label: "Git Webhooks",
description:
"Configure your repo provider to send webhooks to Monitor",
components: {
["Guard" as any]: () => {
if (update.branch ?? config.branch) {
return null;
}
return (
<ConfigItem label="Configure Branch">
<div>Must configure Branch before webhooks will work.</div>
</ConfigItem>
);
},
["refresh" as any]: () => (
<ConfigItem
label="Refresh Pending"
@@ -122,6 +132,11 @@ export const ResourceSyncConfig = ({
</ConfigItem>
),
webhook_enabled: webhooks !== undefined && !webhooks.managed,
webhook_secret: {
description:
"Provide a custom webhook secret for this resource, or use the global default.",
placeholder: "Input custom secret",
},
["managed" as any]: () => {
const inv = useInvalidate();
const { toast } = useToast();
@@ -380,6 +380,11 @@ export const StackConfig = ({
!!(update.branch ?? config.branch) &&
webhooks !== undefined &&
!webhooks.managed,
webhook_secret: {
description:
"Provide a custom webhook secret for this resource, or use the global default.",
placeholder: "Input custom secret",
},
["managed" as any]: () => {
const inv = useInvalidate();
const { toast } = useToast();