diff --git a/Cargo.lock b/Cargo.lock index 98d9721de..916f6d4dc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -26,10 +26,19 @@ dependencies = [ "cfg-if", "getrandom", "once_cell", - "version_check", + "version_check 0.9.4", "zerocopy", ] +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + [[package]] name = "alerter" version = "1.10.0" @@ -115,6 +124,17 @@ version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +[[package]] +name = "async-recursion" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.64", +] + [[package]] name = "async-stream" version = "0.3.5" @@ -196,7 +216,7 @@ dependencies = [ "hex", "http 0.2.12", "hyper 0.14.28", - "ring", + "ring 0.17.8", "time", "tokio", "tracing", @@ -838,6 +858,9 @@ name = "bytes" version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" +dependencies = [ + "serde", +] [[package]] name = "bytes-utils" @@ -1226,6 +1249,12 @@ version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" +[[package]] +name = "dyn-clone" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" + [[package]] name = "either" version = "1.12.0" @@ -1429,7 +1458,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", - "version_check", + "version_check 0.9.4", ] [[package]] @@ -1439,8 +1468,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi", + "wasm-bindgen", ] [[package]] @@ -1918,6 +1949,18 @@ dependencies = [ "generic-array", ] +[[package]] +name = "instant" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "ipconfig" version = "0.3.2" @@ -1966,6 +2009,20 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "jsonwebtoken" +version = "8.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6971da4d9c3aa03c3d8f3ff0f4155b534aad021292003895a469716b2a230378" +dependencies = [ + "base64 0.21.7", + "pem", + "ring 0.16.20", + "serde", + "serde_json", + "simple_asn1", +] + [[package]] name = "jwt" version = "0.16.0" @@ -2020,6 +2077,9 @@ name = "log" version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +dependencies = [ + "serde", +] [[package]] name = "logger" @@ -2303,6 +2363,8 @@ dependencies = [ "mongo_indexed", "monitor_client", "mungos", + "nom_pem", + "octorust", "ordered_hash_map", "parse_csl", "partial_derive2", @@ -2394,6 +2456,25 @@ dependencies = [ "tempfile", ] +[[package]] +name = "nom" +version = "4.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6" +dependencies = [ + "memchr", + "version_check 0.1.5", +] + +[[package]] +name = "nom_pem" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46345232a84add363a2b3bf214777cf13443f6dab781161aafbdadb8b1f0bd2d" +dependencies = [ + "nom", +] + [[package]] name = "ntapi" version = "0.4.1" @@ -2413,6 +2494,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + [[package]] name = "num-conv" version = "0.1.0" @@ -2456,6 +2547,39 @@ dependencies = [ "memchr", ] +[[package]] +name = "octorust" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35a776c05d0cdd02480c12cf1484e0f3bf610eab717ba6fb2c51449b60c7a88f" +dependencies = [ + "async-recursion", + "async-trait", + "bytes", + "chrono", + "http 0.2.12", + "jsonwebtoken", + "log", + "mime", + "parse_link_header", + "pem", + "percent-encoding", + "reqwest 0.11.27", + "reqwest-conditional-middleware", + "reqwest-middleware", + "reqwest-retry", + "reqwest-tracing", + "ring 0.16.20", + "schemars", + "serde", + "serde_json", + "serde_urlencoded", + "thiserror", + "tokio", + "url", + "uuid", +] + [[package]] name = "once_cell" version = "1.19.0" @@ -2603,6 +2727,17 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core 0.8.6", +] + [[package]] name = "parking_lot" version = "0.12.2" @@ -2610,7 +2745,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" dependencies = [ "lock_api", - "parking_lot_core", + "parking_lot_core 0.9.10", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall 0.2.16", + "smallvec", + "winapi", ] [[package]] @@ -2621,7 +2770,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.5.1", "smallvec", "windows-targets 0.52.5", ] @@ -2632,6 +2781,17 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffa94c2e5674923c67d7f3dfce1279507b191e10eb064881b46ed3e1256e5ca6" +[[package]] +name = "parse_link_header" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3687fe9debbbf2a019f381a8bc6b42049b22647449b39af54b3013985c0cf6de" +dependencies = [ + "http 0.2.12", + "lazy_static", + "regex", +] + [[package]] name = "partial_derive2" version = "0.4.3" @@ -2661,6 +2821,15 @@ dependencies = [ "digest", ] +[[package]] +name = "pem" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" +dependencies = [ + "base64 0.13.1", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -2834,6 +3003,15 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "redox_syscall" version = "0.5.1" @@ -2843,12 +3021,41 @@ dependencies = [ "bitflags 2.5.0", ] +[[package]] +name = "regex" +version = "1.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + [[package]] name = "regex-lite" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30b661b2f27137bdbc16f00eda72866a92bb28af1753ffbd56744fb6e2e9cd8e" +[[package]] +name = "regex-syntax" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" + [[package]] name = "reqwest" version = "0.11.27" @@ -2864,15 +3071,18 @@ dependencies = [ "http 0.2.12", "http-body 0.4.6", "hyper 0.14.28", + "hyper-rustls 0.24.2", "hyper-tls 0.5.0", "ipnet", "js-sys", "log", "mime", + "mime_guess", "native-tls", "once_cell", "percent-encoding", "pin-project-lite", + "rustls 0.21.12", "rustls-pemfile 1.0.4", "serde", "serde_json", @@ -2881,11 +3091,13 @@ dependencies = [ "system-configuration", "tokio", "tokio-native-tls", + "tokio-rustls 0.24.1", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", + "webpki-roots", "winreg 0.50.0", ] @@ -2932,6 +3144,72 @@ dependencies = [ "winreg 0.52.0", ] +[[package]] +name = "reqwest-conditional-middleware" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59e50a2e70970896c99d1b8f20ddc30a70b30d3ac6e619a03a8353b64a49b277" +dependencies = [ + "async-trait", + "reqwest 0.11.27", + "reqwest-middleware", + "task-local-extensions", +] + +[[package]] +name = "reqwest-middleware" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a735987236a8e238bf0296c7e351b999c188ccc11477f311b82b55c93984216" +dependencies = [ + "anyhow", + "async-trait", + "http 0.2.12", + "reqwest 0.11.27", + "serde", + "task-local-extensions", + "thiserror", +] + +[[package]] +name = "reqwest-retry" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c6a11c05102e5bec712c0619b8c7b7eda8b21a558a0bd981ceee15c38df8be4" +dependencies = [ + "anyhow", + "async-trait", + "chrono", + "futures", + "getrandom", + "http 0.2.12", + "hyper 0.14.28", + "parking_lot 0.11.2", + "reqwest 0.11.27", + "reqwest-middleware", + "retry-policies", + "task-local-extensions", + "tokio", + "tracing", + "wasm-timer", +] + +[[package]] +name = "reqwest-tracing" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "190838e54153d7a7e2ea98851304b3ce92daeabf14c54d32b01b84a3e636f683" +dependencies = [ + "anyhow", + "async-trait", + "getrandom", + "matchit", + "reqwest 0.11.27", + "reqwest-middleware", + "task-local-extensions", + "tracing", +] + [[package]] name = "resolv-conf" version = "0.7.0" @@ -2966,6 +3244,32 @@ dependencies = [ "syn 2.0.64", ] +[[package]] +name = "retry-policies" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e09bbcb5003282bcb688f0bae741b278e9c7e8f378f561522c9806c58e075d9b" +dependencies = [ + "anyhow", + "chrono", + "rand", +] + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin 0.5.2", + "untrusted 0.7.1", + "web-sys", + "winapi", +] + [[package]] name = "ring" version = "0.17.8" @@ -2976,8 +3280,8 @@ dependencies = [ "cfg-if", "getrandom", "libc", - "spin", - "untrusted", + "spin 0.9.8", + "untrusted 0.9.0", "windows-sys 0.52.0", ] @@ -3044,7 +3348,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" dependencies = [ "log", - "ring", + "ring 0.17.8", "rustls-webpki 0.101.7", "sct", ] @@ -3105,8 +3409,8 @@ version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ - "ring", - "untrusted", + "ring 0.17.8", + "untrusted 0.9.0", ] [[package]] @@ -3115,9 +3419,9 @@ version = "0.102.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff448f7e92e913c4b7d4c6d8e4540a1724b319b4152b8aef6d4cf8339712b33e" dependencies = [ - "ring", + "ring 0.17.8", "rustls-pki-types", - "untrusted", + "untrusted 0.9.0", ] [[package]] @@ -3141,6 +3445,34 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "schemars" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09c024468a378b7e36765cd36702b7a90cc3cba11654f6685c8f233408e89e92" +dependencies = [ + "bytes", + "chrono", + "dyn-clone", + "schemars_derive", + "serde", + "serde_json", + "url", + "uuid", +] + +[[package]] +name = "schemars_derive" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1eee588578aff73f856ab961cd2f79e36bc45d7ded33a7562adba4667aecc0e" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 2.0.64", +] + [[package]] name = "scopeguard" version = "1.2.0" @@ -3153,8 +3485,8 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ - "ring", - "untrusted", + "ring 0.17.8", + "untrusted 0.9.0", ] [[package]] @@ -3230,6 +3562,17 @@ dependencies = [ "syn 2.0.64", ] +[[package]] +name = "serde_derive_internals" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.64", +] + [[package]] name = "serde_json" version = "1.0.119" @@ -3386,6 +3729,18 @@ dependencies = [ "libc", ] +[[package]] +name = "simple_asn1" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" +dependencies = [ + "num-bigint", + "num-traits", + "thiserror", + "time", +] + [[package]] name = "slab" version = "0.4.9" @@ -3426,6 +3781,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + [[package]] name = "spin" version = "0.9.8" @@ -3593,6 +3954,15 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" +[[package]] +name = "task-local-extensions" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba323866e5d033818e3240feeb9f7db2c4296674e4d9e16b97b7bf8f490434e8" +dependencies = [ + "pin-utils", +] + [[package]] name = "tempfile" version = "3.10.1" @@ -3710,7 +4080,7 @@ dependencies = [ "libc", "mio", "num_cpus", - "parking_lot", + "parking_lot 0.12.2", "pin-project-lite", "signal-hook-registry", "socket2", @@ -4075,7 +4445,7 @@ dependencies = [ "lazy_static", "log", "lru-cache", - "parking_lot", + "parking_lot 0.12.2", "resolv-conf", "smallvec", "thiserror", @@ -4171,7 +4541,7 @@ version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" dependencies = [ - "version_check", + "version_check 0.9.4", ] [[package]] @@ -4195,6 +4565,12 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + [[package]] name = "untrusted" version = "0.9.0" @@ -4221,6 +4597,7 @@ dependencies = [ "form_urlencoded", "idna 0.5.0", "percent-encoding", + "serde", ] [[package]] @@ -4264,6 +4641,12 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" +[[package]] +name = "version_check" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" + [[package]] name = "version_check" version = "0.9.4" @@ -4357,6 +4740,21 @@ version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +[[package]] +name = "wasm-timer" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f" +dependencies = [ + "futures", + "js-sys", + "parking_lot 0.11.2", + "pin-utils", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "web-sys" version = "0.3.69" diff --git a/Cargo.toml b/Cargo.toml index 9ee8d21ca..fbcb0b16c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -80,6 +80,7 @@ envy = "0.4.2" # CRYPTO uuid = { version = "1.9.1", features = ["v4", "fast-rng", "serde"] } urlencoding = "2.1.3" +nom_pem = "4.0.0" bcrypt = "0.15.1" base64 = "0.22.1" hmac = "0.12.1" @@ -100,5 +101,7 @@ aws-sdk-ecr = "1.33.0" # MISC derive_builder = "0.20.0" typeshare = "1.0.3" +octorust = "0.7.0" colored = "2.1.0" bson = "2.11.0" + diff --git a/bin/core/Cargo.toml b/bin/core/Cargo.toml index ded486f4b..f7049b96a 100644 --- a/bin/core/Cargo.toml +++ b/bin/core/Cargo.toml @@ -45,9 +45,11 @@ axum-extra.workspace = true tower-http.workspace = true serde_json.workspace = true typeshare.workspace = true +octorust.workspace = true tracing.workspace = true reqwest.workspace = true futures.workspace = true +nom_pem.workspace = true anyhow.workspace = true dotenv.workspace = true bcrypt.workspace = true diff --git a/bin/core/src/api/read/build.rs b/bin/core/src/api/read/build.rs index 2e484c324..178aad9e5 100644 --- a/bin/core/src/api/read/build.rs +++ b/bin/core/src/api/read/build.rs @@ -3,13 +3,14 @@ use std::{ sync::OnceLock, }; -use anyhow::Context; +use anyhow::{anyhow, Context}; use async_timing_util::unix_timestamp_ms; use futures::TryStreamExt; use monitor_client::{ api::read::*, entities::{ build::{Build, BuildActionState, BuildListItem, BuildState}, + config::core::CoreConfig, permission::PermissionLevel, update::UpdateStatus, user::User, @@ -25,7 +26,9 @@ use resolver_api::{Resolve, ResolveToString}; use crate::{ config::core_config, resource, - state::{action_states, build_state_cache, db_client, State}, + state::{ + action_states, build_state_cache, db_client, github_client, State, + }, }; impl Resolve for State { @@ -307,3 +310,54 @@ impl Resolve for State { Ok(res) } } + +impl Resolve for State { + async fn resolve( + &self, + GetBuildWebhookEnabled { build }: GetBuildWebhookEnabled, + user: User, + ) -> anyhow::Result { + let Some(github) = github_client() else { + return Err(anyhow!("github_webhook_app is not configured")); + }; + + let build = resource::get_check_permissions::( + &build, + &user, + PermissionLevel::Read, + ) + .await?; + + if build.config.repo.is_empty() { + return Ok(GetBuildWebhookEnabledResponse { enabled: false }); + } + + let mut split = build.config.repo.split('/'); + let owner = split.next().context("Build repo has no owner")?; + let repo = + split.next().context("Build repo has no repo after the /")?; + + let github_repos = github.repos(); + let webhooks = github_repos + .list_all_webhooks(owner, repo) + .await + .context("failed to list all webhooks on repo")? + .body; + + let CoreConfig { + host, + github_webhook_base_url, + .. + } = core_config(); + let host = github_webhook_base_url.as_ref().unwrap_or(host); + let url = format!("{host}/listener/github/build/{}", build.id); + + for webhook in webhooks { + if webhook.active && webhook.config.url == url { + return Ok(GetBuildWebhookEnabledResponse { enabled: true }); + } + } + + Ok(GetBuildWebhookEnabledResponse { enabled: false }) + } +} diff --git a/bin/core/src/api/read/mod.rs b/bin/core/src/api/read/mod.rs index 12e150c43..db62745a7 100644 --- a/bin/core/src/api/read/mod.rs +++ b/bin/core/src/api/read/mod.rs @@ -42,12 +42,12 @@ enum ReadRequest { GetAvailableAwsEcrLabels(GetAvailableAwsEcrLabels), // ==== USER ==== - ListUsers(ListUsers), GetUsername(GetUsername), + GetPermissionLevel(GetPermissionLevel), + ListUsers(ListUsers), ListApiKeys(ListApiKeys), ListApiKeysForServiceUser(ListApiKeysForServiceUser), ListPermissions(ListPermissions), - GetPermissionLevel(GetPermissionLevel), ListUserTargetPermissions(ListUserTargetPermissions), // ==== USER GROUP ==== @@ -66,15 +66,13 @@ enum ReadRequest { // ==== SERVER TEMPLATE ==== GetServerTemplate(GetServerTemplate), + GetServerTemplatesSummary(GetServerTemplatesSummary), ListServerTemplates(ListServerTemplates), ListFullServerTemplates(ListFullServerTemplates), - GetServerTemplatesSummary(GetServerTemplatesSummary), // ==== SERVER ==== GetServersSummary(GetServersSummary), GetServer(GetServer), - ListServers(ListServers), - ListFullServers(ListFullServers), GetServerState(GetServerState), GetPeripheryVersion(GetPeripheryVersion), GetDockerContainers(GetDockerContainers), @@ -84,27 +82,30 @@ enum ReadRequest { GetHistoricalServerStats(GetHistoricalServerStats), GetAvailableAccounts(GetAvailableAccounts), GetAvailableSecrets(GetAvailableSecrets), + ListServers(ListServers), + ListFullServers(ListFullServers), // ==== DEPLOYMENT ==== GetDeploymentsSummary(GetDeploymentsSummary), GetDeployment(GetDeployment), - ListDeployments(ListDeployments), - ListFullDeployments(ListFullDeployments), GetDeploymentContainer(GetDeploymentContainer), GetDeploymentActionState(GetDeploymentActionState), GetDeploymentStats(GetDeploymentStats), GetLog(GetLog), SearchLog(SearchLog), + ListDeployments(ListDeployments), + ListFullDeployments(ListFullDeployments), ListCommonDeploymentExtraArgs(ListCommonDeploymentExtraArgs), // ==== BUILD ==== GetBuildsSummary(GetBuildsSummary), GetBuild(GetBuild), - ListBuilds(ListBuilds), - ListFullBuilds(ListFullBuilds), GetBuildActionState(GetBuildActionState), GetBuildMonthlyStats(GetBuildMonthlyStats), GetBuildVersions(GetBuildVersions), + GetBuildWebhookEnabled(GetBuildWebhookEnabled), + ListBuilds(ListBuilds), + ListFullBuilds(ListFullBuilds), ListCommonBuildExtraArgs(ListCommonBuildExtraArgs), #[to_string_resolver] ListGithubOrganizations(ListGithubOrganizations), @@ -114,23 +115,24 @@ enum ReadRequest { // ==== REPO ==== GetReposSummary(GetReposSummary), GetRepo(GetRepo), + GetRepoActionState(GetRepoActionState), + GetRepoWebhooksEnabled(GetRepoWebhooksEnabled), ListRepos(ListRepos), ListFullRepos(ListFullRepos), - GetRepoActionState(GetRepoActionState), // ==== SYNC ==== GetResourceSyncsSummary(GetResourceSyncsSummary), GetResourceSync(GetResourceSync), + GetResourceSyncActionState(GetResourceSyncActionState), ListResourceSyncs(ListResourceSyncs), ListFullResourceSyncs(ListFullResourceSyncs), - GetResourceSyncActionState(GetResourceSyncActionState), // ==== BUILDER ==== GetBuildersSummary(GetBuildersSummary), GetBuilder(GetBuilder), + GetBuilderAvailableAccounts(GetBuilderAvailableAccounts), ListBuilders(ListBuilders), ListFullBuilders(ListFullBuilders), - GetBuilderAvailableAccounts(GetBuilderAvailableAccounts), // ==== ALERTER ==== GetAlertersSummary(GetAlertersSummary), @@ -229,6 +231,8 @@ impl Resolve for State { .unwrap_or_else(|| config.host.clone()), transparent_mode: config.transparent_mode, ui_write_disabled: config.ui_write_disabled, + github_webhook_app: config.github_webhook_app.app_id != 0 + && config.github_webhook_app.installation_id != 0, }) } } diff --git a/bin/core/src/api/read/repo.rs b/bin/core/src/api/read/repo.rs index b62f917a3..0e3f8ee1a 100644 --- a/bin/core/src/api/read/repo.rs +++ b/bin/core/src/api/read/repo.rs @@ -1,7 +1,8 @@ -use anyhow::Context; +use anyhow::{anyhow, Context}; use monitor_client::{ api::read::*, entities::{ + config::core::CoreConfig, permission::PermissionLevel, repo::{Repo, RepoActionState, RepoListItem, RepoState}, user::User, @@ -10,8 +11,9 @@ use monitor_client::{ use resolver_api::Resolve; use crate::{ + config::core_config, resource, - state::{action_states, repo_state_cache, State}, + state::{action_states, github_client, repo_state_cache, State}, }; impl Resolve for State { @@ -118,3 +120,69 @@ impl Resolve for State { Ok(res) } } + +impl Resolve for State { + async fn resolve( + &self, + GetRepoWebhooksEnabled { repo }: GetRepoWebhooksEnabled, + user: User, + ) -> anyhow::Result { + let Some(github) = github_client() else { + return Err(anyhow!("github_webhook_app is not configured")); + }; + + let repo = resource::get_check_permissions::( + &repo, + &user, + PermissionLevel::Read, + ) + .await?; + + if repo.config.repo.is_empty() { + return Ok(GetRepoWebhooksEnabledResponse { + clone_enabled: false, + pull_enabled: false, + }); + } + + let mut split = repo.config.repo.split('/'); + let owner = split.next().context("Repo repo has no owner")?; + let repo_name = + split.next().context("Repo repo has no repo after the /")?; + + let github_repos = github.repos(); + let webhooks = github_repos + .list_all_webhooks(owner, repo_name) + .await + .context("failed to list all webhooks on repo")? + .body; + + let CoreConfig { + host, + github_webhook_base_url, + .. + } = core_config(); + let host = github_webhook_base_url.as_ref().unwrap_or(host); + let clone_url = + format!("{host}/listener/github/repo/{}/clone", repo.id); + let pull_url = + format!("{host}/listener/github/repo/{}/pull", repo.id); + + let mut clone_enabled = false; + let mut pull_enabled = false; + + for webhook in webhooks { + if webhook.active && webhook.config.url == clone_url { + clone_enabled = true + } + if webhook.active && webhook.config.url == pull_url { + pull_enabled = true + } + } + + Ok(GetRepoWebhooksEnabledResponse { + clone_enabled, + pull_enabled, + }) + } +} diff --git a/bin/core/src/config.rs b/bin/core/src/config.rs index 8884e6a57..f62e83122 100644 --- a/bin/core/src/config.rs +++ b/bin/core/src/config.rs @@ -4,8 +4,8 @@ use anyhow::Context; use merge_config_files::parse_config_file; use monitor_client::entities::{ config::core::{ - AwsCredentials, CoreConfig, Env, HetznerCredentials, MongoConfig, - OauthCredentials, + AwsCredentials, CoreConfig, Env, GithubWebhookAppConfig, + HetznerCredentials, MongoConfig, OauthCredentials, }, logger::LogConfig, }; @@ -109,6 +109,17 @@ pub fn core_config() -> &'static CoreConfig { .monitor_github_oauth_secret .unwrap_or(config.github_oauth.secret), }, + github_webhook_app: GithubWebhookAppConfig { + app_id: env + .monitor_github_webhook_app_app_id + .unwrap_or(config.github_webhook_app.app_id), + installation_id: env + .monitor_github_webhook_app_installation_id + .unwrap_or(config.github_webhook_app.installation_id), + pk_path: env + .monitor_github_webhook_app_pk_path + .unwrap_or(config.github_webhook_app.pk_path), + }, aws: AwsCredentials { access_key_id: env .monitor_aws_access_key_id diff --git a/bin/core/src/state.rs b/bin/core/src/state.rs index 9ebe57d14..1353a1067 100644 --- a/bin/core/src/state.rs +++ b/bin/core/src/state.rs @@ -1,10 +1,17 @@ use std::sync::{Arc, OnceLock}; +use anyhow::{anyhow, Context}; use monitor_client::entities::{ - build::BuildState, deployment::DeploymentState, - procedure::ProcedureState, repo::RepoState, + build::BuildState, + config::core::{CoreConfig, GithubWebhookAppConfig}, + deployment::DeploymentState, + procedure::ProcedureState, + repo::RepoState, sync::ResourceSyncState, }; +use octorust::auth::{ + Credentials, InstallationTokenGenerator, JWTCredentials, +}; use tokio::sync::{Mutex, OnceCell}; use crate::{ @@ -36,6 +43,53 @@ pub fn jwt_client() -> &'static JwtClient { JWT_CLIENT.get_or_init(|| JwtClient::new(core_config())) } +pub fn github_client() -> Option<&'static octorust::Client> { + static GITHUB_CLIENT: OnceLock> = + OnceLock::new(); + GITHUB_CLIENT + .get_or_init(|| { + let CoreConfig { + github_webhook_app: + GithubWebhookAppConfig { + app_id, + installation_id, + pk_path, + }, + .. + } = core_config(); + if *app_id == 0 || *installation_id == 0 { + return None; + } + let private_key = std::fs::read(pk_path) + .context("github webhook app | failed to load private key") + .unwrap(); + + let private_key = nom_pem::decode_block(&private_key) + .map_err(|e| anyhow!("{e:?}")) + .context("github webhook app | failed to decode private key") + .unwrap(); + + let jwt = JWTCredentials::new(*app_id, private_key.data) + .context( + "github webhook app | failed to make github JWTCredentials", + ) + .unwrap(); + + let token_generator = + InstallationTokenGenerator::new(*installation_id, jwt); + + Some( + octorust::Client::new( + "github-app", + Credentials::InstallationToken(token_generator), + ) + .context("failed to initialize github client") + .unwrap(), + ) + }) + .as_ref() +} + pub fn action_states() -> &'static ActionStates { static ACTION_STATES: OnceLock = OnceLock::new(); ACTION_STATES.get_or_init(ActionStates::default) diff --git a/client/core/rs/src/api/read/build.rs b/client/core/rs/src/api/read/build.rs index 6b5cce346..778e615e2 100644 --- a/client/core/rs/src/api/read/build.rs +++ b/client/core/rs/src/api/read/build.rs @@ -258,3 +258,28 @@ pub struct ListCommonBuildExtraArgs { #[typeshare] pub type ListCommonBuildExtraArgsResponse = Vec; + +// + +/// Get whether a Build's target repo has a webhook for the build configured. Response: [GetBuildWebhookEnabledResponse]. +/// +/// Note. Will fail with 500 if `github_webhook_app` is not configured in core config. +#[typeshare] +#[derive( + Serialize, Deserialize, Debug, Clone, Request, EmptyTraits, +)] +#[empty_traits(MonitorReadRequest)] +#[response(GetBuildWebhookEnabledResponse)] +pub struct GetBuildWebhookEnabled { + /// Id or name + #[serde(alias = "id", alias = "name")] + pub build: String, +} + +/// Response for [GetBuildWebhookEnabled] +#[typeshare] +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct GetBuildWebhookEnabledResponse { + /// Whether pushes to branch trigger build + pub enabled: bool, +} diff --git a/client/core/rs/src/api/read/mod.rs b/client/core/rs/src/api/read/mod.rs index cb966c8fa..6799721ae 100644 --- a/client/core/rs/src/api/read/mod.rs +++ b/client/core/rs/src/api/read/mod.rs @@ -91,6 +91,8 @@ pub struct GetCoreInfoResponse { pub transparent_mode: bool, /// Whether UI write access should be disabled pub ui_write_disabled: bool, + /// Whether github webhook management api is available + pub github_webhook_app: bool, } // @@ -106,4 +108,4 @@ pub struct GetCoreInfoResponse { pub struct GetAvailableAwsEcrLabels {} #[typeshare] -pub type GetAvailableAwsEcrLabelsResponse = Vec; \ No newline at end of file +pub type GetAvailableAwsEcrLabelsResponse = Vec; diff --git a/client/core/rs/src/api/read/procedure.rs b/client/core/rs/src/api/read/procedure.rs index aac4073c4..76003dfba 100644 --- a/client/core/rs/src/api/read/procedure.rs +++ b/client/core/rs/src/api/read/procedure.rs @@ -108,5 +108,3 @@ pub struct GetProceduresSummaryResponse { /// The number of procedures with unknown state. pub unknown: u32, } - -// diff --git a/client/core/rs/src/api/read/repo.rs b/client/core/rs/src/api/read/repo.rs index fe3836fad..ddf3c4695 100644 --- a/client/core/rs/src/api/read/repo.rs +++ b/client/core/rs/src/api/read/repo.rs @@ -110,3 +110,30 @@ pub struct GetReposSummaryResponse { /// The number of repos with unknown state. pub unknown: u32, } + +// + +/// Get a target Repo's configured webhooks. Response: [GetRepoWebhooksEnabledResponse]. +/// +/// Note. Will fail with 500 if `github_webhook_app` is not configured in core config. +#[typeshare] +#[derive( + Serialize, Deserialize, Debug, Clone, Request, EmptyTraits, +)] +#[empty_traits(MonitorReadRequest)] +#[response(GetRepoWebhooksEnabledResponse)] +pub struct GetRepoWebhooksEnabled { + /// Id or name + #[serde(alias = "id", alias = "name")] + pub repo: String, +} + +/// Response for [GetRepoWebhooksEnabled] +#[typeshare] +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct GetRepoWebhooksEnabledResponse { + /// Whether pushes to branch trigger clone + pub clone_enabled: bool, + /// Whether pushes to branch trigger pull + pub pull_enabled: bool, +} diff --git a/client/core/rs/src/entities/config/core.rs b/client/core/rs/src/entities/config/core.rs index 3d8d08a84..392f03b72 100644 --- a/client/core/rs/src/entities/config/core.rs +++ b/client/core/rs/src/entities/config/core.rs @@ -79,6 +79,13 @@ pub struct Env { /// Override `local_auth` pub monitor_local_auth: Option, + /// Override `google_oauth.enabled` + pub monitor_google_oauth_enabled: Option, + /// Override `google_oauth.id` + pub monitor_google_oauth_id: Option, + /// Override `google_oauth.secret` + pub monitor_google_oauth_secret: Option, + /// Override `github_oauth.enabled` pub monitor_github_oauth_enabled: Option, /// Override `github_oauth.id` @@ -86,12 +93,12 @@ pub struct Env { /// Override `github_oauth.secret` pub monitor_github_oauth_secret: Option, - /// Override `google_oauth.enabled` - pub monitor_google_oauth_enabled: Option, - /// Override `google_oauth.id` - pub monitor_google_oauth_id: Option, - /// Override `google_oauth.secret` - pub monitor_google_oauth_secret: Option, + /// Override `github_webhook_app.app_id` + pub monitor_github_webhook_app_app_id: Option, + /// Override `github_webhook_app.installation_id` + pub monitor_github_webhook_app_installation_id: Option, + /// Override `github_webhook_app.pk_path` + pub monitor_github_webhook_app_pk_path: Option, /// Override `mongo.uri` pub monitor_mongo_uri: Option, @@ -183,15 +190,6 @@ fn default_config_path() -> String { /// ## default: 0 (pruning disabled) /// keep_stats_for_days = 0 /// -/// ## token that has to be given to github during repo webhook config as the secret -/// ## default: empty (none) -/// github_webhook_secret = "your_random_webhook_secret" -/// -/// ## an alternate base url that is used to recieve github webhook requests -/// ## if empty or not specified, will use 'host' address as base -/// ## default: empty (none) -/// # github_webhook_base_url = "https://github-webhook.monitor.dev" -/// /// ## these will be used by the GUI to attach to builds. /// ## when attached to build, image will be pushed to repo under the specified organization. /// ## if empty, the "docker organization" config option will not be shown. @@ -210,15 +208,33 @@ fn default_config_path() -> String { /// ## default: false /// # local_auth = true /// +/// ## Use to configure google oauth +/// # google_oauth.enabled = true +/// # google_oauth.id = "your_google_client_id" +/// # google_oauth.secret = "your_google_client_secret" +/// /// ## Use to configure github oauth /// # github_oauth.enabled = true /// # github_oauth.id = "your_github_client_id" /// # github_oauth.secret = "your_github_client_secret" /// -/// ## Use to configure google oauth -/// # google_oauth.enabled = true -/// # google_oauth.id = "your_google_client_id" -/// # google_oauth.secret = "your_google_client_secret" +/// ## an alternate base url that is used to recieve github webhook requests +/// ## if empty or not specified, will use 'host' address as base +/// ## default: empty (none) +/// # github_webhook_base_url = "https://github-webhook.monitor.dev" +/// +/// ## token that has to be given to github during repo webhook config as the secret +/// ## default: empty (none) +/// github_webhook_secret = "your_random_webhook_secret" +/// +/// ## Configure github webhook app. Enables webhook management apis. +/// # github_webhook_app.app_id = 1234455 # Find on the app page. +/// # github_webhook_app.installation_id = 1234455 # Get after installing the app to user / organization. +/// +/// ## Path to github webhook app private key. +/// ## This is defaulted to `/github-private-key.pem`, and doesn't need to be changed if running in Docker. +/// ## Just mount the private key pem file on the host to `/github-private-key.pem` in the container. +/// # github_webhook_app.pk_path = "/path/to/pk.pem" /// /// ## MUST comment back in some way to configure mongo. /// # mongo.uri = "mongodb://username:password@localhost:27017" @@ -315,25 +331,6 @@ pub struct CoreConfig { #[serde(default)] pub keep_alerts_for_days: u64, - /// Used to verify validity from github webhooks. - /// Should be some secure hash maybe 20-40 chars. - /// It needs to be given to github when configuring the webhook. - #[serde(default)] - pub github_webhook_secret: String, - - /// Used to form the frontend listener url, if None will use 'host'. - /// - /// This can be used if core sits on an internal network which is - /// unreachable directly from the open internet. - /// A reverse proxy in a public network (with its own DNS) - /// can forward webhooks to the internal monitor - pub github_webhook_base_url: Option, - - /// Allowed github orgs used with monitor. - /// Default: none. - #[serde(default)] - pub github_organizations: Vec, - /// Allowed docker orgs used with monitor. /// Default: none. #[serde(default)] @@ -355,13 +352,37 @@ pub struct CoreConfig { #[serde(default)] pub local_auth: bool, + /// Configure google oauth + #[serde(default)] + pub google_oauth: OauthCredentials, + /// Configure github oauth #[serde(default)] pub github_oauth: OauthCredentials, - /// Configure google oauth + /// Used to verify validity from github webhooks. + /// Should be some secure hash maybe 20-40 chars. + /// It needs to be given to github when configuring the webhook. #[serde(default)] - pub google_oauth: OauthCredentials, + pub github_webhook_secret: String, + + /// Used to form the frontend listener url, if None will use 'host'. + /// + /// This can be used if core sits on an internal network which is + /// unreachable directly from the open internet. + /// A reverse proxy in a public network (with its own DNS) + /// can forward webhooks to the internal monitor + pub github_webhook_base_url: Option, + + /// Configure a Github Webhook app. + /// Allows users to manage repo webhooks from within the Monitor UI. + #[serde(default)] + pub github_webhook_app: GithubWebhookAppConfig, + + /// Allowed github orgs used with monitor. + /// Default: none. + #[serde(default)] + pub github_organizations: Vec, /// Configure core mongo connection. /// @@ -397,7 +418,8 @@ pub struct CoreConfig { /// Configure aws ecr registries. #[serde(default, alias = "aws_ecr_registry")] - pub aws_ecr_registries: HashMap, + pub aws_ecr_registries: + HashMap, } fn default_title() -> String { @@ -565,4 +587,30 @@ impl AwsEcrConfig { account_id: config.account_id.to_string(), } } -} \ No newline at end of file +} + +/// Provide configuration for a Github Webhook app. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct GithubWebhookAppConfig { + /// Github app id + pub app_id: i64, + /// Github app installation id + pub installation_id: i64, + /// Private key path. Default: /github-private-key.pem. + #[serde(default = "default_private_key_path")] + pub pk_path: String, +} + +fn default_private_key_path() -> String { + String::from("/github-private-key.pem") +} + +impl Default for GithubWebhookAppConfig { + fn default() -> Self { + GithubWebhookAppConfig { + app_id: 0, + installation_id: 0, + pk_path: default_private_key_path(), + } + } +} diff --git a/client/core/ts/src/responses.ts b/client/core/ts/src/responses.ts index 6915a73bb..b94fca1fb 100644 --- a/client/core/ts/src/responses.ts +++ b/client/core/ts/src/responses.ts @@ -21,12 +21,12 @@ export type ReadResponses = { GetAvailableAwsEcrLabels: Types.GetAvailableAwsEcrLabelsResponse; // ==== USER ==== - ListUsers: Types.ListUsersResponse; GetUsername: Types.GetUsernameResponse; + GetPermissionLevel: Types.GetPermissionLevelResponse; + ListUsers: Types.ListUsersResponse; ListApiKeys: Types.ListApiKeysResponse; ListApiKeysForServiceUser: Types.ListApiKeysForServiceUserResponse; ListPermissions: Types.ListPermissionsResponse; - GetPermissionLevel: Types.GetPermissionLevelResponse; ListUserTargetPermissions: Types.ListUserTargetPermissionsResponse; // ==== USER GROUP ==== @@ -45,15 +45,13 @@ export type ReadResponses = { // ==== SERVER TEMPLATE ==== GetServerTemplate: Types.GetServerTemplateResponse; + GetServerTemplatesSummary: Types.GetServerTemplatesSummaryResponse; ListServerTemplates: Types.ListServerTemplatesResponse; ListFullServerTemplates: Types.ListFullServerTemplatesResponse; - GetServerTemplatesSummary: Types.GetServerTemplatesSummaryResponse; // ==== SERVER ==== GetServersSummary: Types.GetServersSummaryResponse; GetServer: Types.GetServerResponse; - ListServers: Types.ListServersResponse; - ListFullServers: Types.ListFullServersResponse; GetServerState: Types.GetServerStateResponse; GetPeripheryVersion: Types.GetPeripheryVersionResponse; GetSystemInformation: Types.GetSystemInformationResponse; @@ -64,27 +62,30 @@ export type ReadResponses = { GetHistoricalServerStats: Types.GetHistoricalServerStatsResponse; GetAvailableAccounts: Types.GetAvailableAccountsResponse; GetAvailableSecrets: Types.GetAvailableSecretsResponse; + ListServers: Types.ListServersResponse; + ListFullServers: Types.ListFullServersResponse; // ==== DEPLOYMENT ==== GetDeploymentsSummary: Types.GetDeploymentsSummaryResponse; GetDeployment: Types.GetDeploymentResponse; - ListDeployments: Types.ListDeploymentsResponse; - ListFullDeployments: Types.ListFullDeploymentsResponse; GetDeploymentContainer: Types.GetDeploymentContainerResponse; GetDeploymentActionState: Types.GetDeploymentActionStateResponse; GetDeploymentStats: Types.GetDeploymentStatsResponse; GetLog: Types.GetLogResponse; SearchLog: Types.SearchLogResponse; + ListDeployments: Types.ListDeploymentsResponse; + ListFullDeployments: Types.ListFullDeploymentsResponse; ListCommonDeploymentExtraArgs: Types.ListCommonDeploymentExtraArgsResponse; // ==== BUILD ==== GetBuildsSummary: Types.GetBuildsSummaryResponse; GetBuild: Types.GetBuildResponse; - ListBuilds: Types.ListBuildsResponse; - ListFullBuilds: Types.ListFullBuildsResponse; GetBuildActionState: Types.GetBuildActionStateResponse; GetBuildMonthlyStats: Types.GetBuildMonthlyStatsResponse; GetBuildVersions: Types.GetBuildVersionsResponse; + GetBuildWebhookEnabled: Types.GetBuildWebhookEnabledResponse; + ListBuilds: Types.ListBuildsResponse; + ListFullBuilds: Types.ListFullBuildsResponse; ListCommonBuildExtraArgs: Types.ListCommonBuildExtraArgsResponse; ListGithubOrganizations: Types.ListGithubOrganizationsResponse; ListDockerOrganizations: Types.ListDockerOrganizationsResponse; @@ -92,16 +93,17 @@ export type ReadResponses = { // ==== REPO ==== GetReposSummary: Types.GetReposSummaryResponse; GetRepo: Types.GetRepoResponse; + GetRepoActionState: Types.GetRepoActionStateResponse; + GetRepoWebhooksEnabled: Types.GetRepoWebhooksEnabledResponse; ListRepos: Types.ListReposResponse; ListFullRepos: Types.ListFullReposResponse; - GetRepoActionState: Types.GetRepoActionStateResponse; // ==== BUILDER ==== GetBuildersSummary: Types.GetBuildersSummaryResponse; GetBuilder: Types.GetBuilderResponse; + GetBuilderAvailableAccounts: Types.GetBuilderAvailableAccountsResponse; ListBuilders: Types.ListBuildersResponse; ListFullBuilders: Types.ListFullBuildersResponse; - GetBuilderAvailableAccounts: Types.GetBuilderAvailableAccountsResponse; // ==== ALERTER ==== GetAlertersSummary: Types.GetAlertersSummaryResponse; @@ -112,9 +114,9 @@ export type ReadResponses = { // ==== SYNC ==== GetResourceSyncsSummary: Types.GetResourceSyncsSummaryResponse; GetResourceSync: Types.GetResourceSyncResponse; + GetResourceSyncActionState: Types.GetResourceSyncActionStateResponse; ListResourceSyncs: Types.ListResourceSyncsResponse; ListFullResourceSyncs: Types.ListFullResourceSyncsResponse; - GetResourceSyncActionState: Types.GetResourceSyncActionStateResponse; // ==== TOML ==== ExportAllResourcesToToml: Types.ExportAllResourcesToTomlResponse; diff --git a/client/core/ts/src/types.ts b/client/core/ts/src/types.ts index 44aab9ad9..8fa83bea5 100644 --- a/client/core/ts/src/types.ts +++ b/client/core/ts/src/types.ts @@ -399,10 +399,10 @@ export interface BuildConfig { * These values remain hidden in the final image by using * docker secret mounts. See ``. * - * To use the values, add commands like this in the Dockerfile: + * The values can be used in RUN commands: * ``` * RUN --mount=type=secret,id=SECRET_KEY \ - * SECRET_VALUE=$(cat /run/secrets/SECRET_KEY) ... + * SECRET_KEY=$(cat /run/secrets/SECRET_KEY) ... * ``` */ secret_args?: EnvironmentVar[] | string; @@ -2110,6 +2110,22 @@ export interface ListCommonBuildExtraArgs { query?: BuildQuery; } +/** + * Get whether a Build's target repo has a webhook for the build configured. Response: [GetBuildWebhookEnabledResponse]. + * + * Note. Will fail with 500 if `github_webhook_app` is not configured in core config. + */ +export interface GetBuildWebhookEnabled { + /** Id or name */ + build: string; +} + +/** Response for [GetBuildWebhookEnabled] */ +export interface GetBuildWebhookEnabledResponse { + /** Whether pushes to branch trigger build */ + enabled: boolean; +} + /** Get a specific builder by id or name. Response: [Builder]. */ export interface GetBuilder { /** Id or name */ @@ -2320,6 +2336,8 @@ export interface GetCoreInfoResponse { transparent_mode: boolean; /** Whether UI write access should be disabled */ ui_write_disabled: boolean; + /** Whether github webhook management api is available */ + github_webhook_app: boolean; } /** @@ -2448,6 +2466,24 @@ export interface GetReposSummaryResponse { unknown: number; } +/** + * Get a target Repo's configured webhooks. Response: [GetRepoWebhooksEnabledResponse]. + * + * Note. Will fail with 500 if `github_webhook_app` is not configured in core config. + */ +export interface GetRepoWebhooksEnabled { + /** Id or name */ + repo: string; +} + +/** Response for [GetRepoWebhooksEnabled] */ +export interface GetRepoWebhooksEnabledResponse { + /** Whether pushes to branch trigger clone */ + clone_enabled: boolean; + /** Whether pushes to branch trigger pull */ + pull_enabled: boolean; +} + /** Find resources matching a common query. Response: [FindResourcesResponse]. */ export interface FindResources { /** The mongo query as JSON */ @@ -3946,12 +3982,12 @@ export type ReadRequest = | { type: "GetVersion", params: GetVersion } | { type: "GetCoreInfo", params: GetCoreInfo } | { type: "GetAvailableAwsEcrLabels", params: GetAvailableAwsEcrLabels } - | { type: "ListUsers", params: ListUsers } | { type: "GetUsername", params: GetUsername } + | { type: "GetPermissionLevel", params: GetPermissionLevel } + | { type: "ListUsers", params: ListUsers } | { type: "ListApiKeys", params: ListApiKeys } | { type: "ListApiKeysForServiceUser", params: ListApiKeysForServiceUser } | { type: "ListPermissions", params: ListPermissions } - | { type: "GetPermissionLevel", params: GetPermissionLevel } | { type: "ListUserTargetPermissions", params: ListUserTargetPermissions } | { type: "GetUserGroup", params: GetUserGroup } | { type: "ListUserGroups", params: ListUserGroups } @@ -3962,13 +3998,11 @@ export type ReadRequest = | { type: "ListProcedures", params: ListProcedures } | { type: "ListFullProcedures", params: ListFullProcedures } | { type: "GetServerTemplate", params: GetServerTemplate } + | { type: "GetServerTemplatesSummary", params: GetServerTemplatesSummary } | { type: "ListServerTemplates", params: ListServerTemplates } | { type: "ListFullServerTemplates", params: ListFullServerTemplates } - | { type: "GetServerTemplatesSummary", params: GetServerTemplatesSummary } | { type: "GetServersSummary", params: GetServersSummary } | { type: "GetServer", params: GetServer } - | { type: "ListServers", params: ListServers } - | { type: "ListFullServers", params: ListFullServers } | { type: "GetServerState", params: GetServerState } | { type: "GetPeripheryVersion", params: GetPeripheryVersion } | { type: "GetDockerContainers", params: GetDockerContainers } @@ -3978,41 +4012,45 @@ export type ReadRequest = | { type: "GetHistoricalServerStats", params: GetHistoricalServerStats } | { type: "GetAvailableAccounts", params: GetAvailableAccounts } | { type: "GetAvailableSecrets", params: GetAvailableSecrets } + | { type: "ListServers", params: ListServers } + | { type: "ListFullServers", params: ListFullServers } | { type: "GetDeploymentsSummary", params: GetDeploymentsSummary } | { type: "GetDeployment", params: GetDeployment } - | { type: "ListDeployments", params: ListDeployments } - | { type: "ListFullDeployments", params: ListFullDeployments } | { type: "GetDeploymentContainer", params: GetDeploymentContainer } | { type: "GetDeploymentActionState", params: GetDeploymentActionState } | { type: "GetDeploymentStats", params: GetDeploymentStats } | { type: "GetLog", params: GetLog } | { type: "SearchLog", params: SearchLog } + | { type: "ListDeployments", params: ListDeployments } + | { type: "ListFullDeployments", params: ListFullDeployments } | { type: "ListCommonDeploymentExtraArgs", params: ListCommonDeploymentExtraArgs } | { type: "GetBuildsSummary", params: GetBuildsSummary } | { type: "GetBuild", params: GetBuild } - | { type: "ListBuilds", params: ListBuilds } - | { type: "ListFullBuilds", params: ListFullBuilds } | { type: "GetBuildActionState", params: GetBuildActionState } | { type: "GetBuildMonthlyStats", params: GetBuildMonthlyStats } | { type: "GetBuildVersions", params: GetBuildVersions } + | { type: "GetBuildWebhookEnabled", params: GetBuildWebhookEnabled } + | { type: "ListBuilds", params: ListBuilds } + | { type: "ListFullBuilds", params: ListFullBuilds } | { type: "ListCommonBuildExtraArgs", params: ListCommonBuildExtraArgs } | { type: "ListGithubOrganizations", params: ListGithubOrganizations } | { type: "ListDockerOrganizations", params: ListDockerOrganizations } | { type: "GetReposSummary", params: GetReposSummary } | { type: "GetRepo", params: GetRepo } + | { type: "GetRepoActionState", params: GetRepoActionState } + | { type: "GetRepoWebhooksEnabled", params: GetRepoWebhooksEnabled } | { type: "ListRepos", params: ListRepos } | { type: "ListFullRepos", params: ListFullRepos } - | { type: "GetRepoActionState", params: GetRepoActionState } | { type: "GetResourceSyncsSummary", params: GetResourceSyncsSummary } | { type: "GetResourceSync", params: GetResourceSync } + | { type: "GetResourceSyncActionState", params: GetResourceSyncActionState } | { type: "ListResourceSyncs", params: ListResourceSyncs } | { type: "ListFullResourceSyncs", params: ListFullResourceSyncs } - | { type: "GetResourceSyncActionState", params: GetResourceSyncActionState } | { type: "GetBuildersSummary", params: GetBuildersSummary } | { type: "GetBuilder", params: GetBuilder } + | { type: "GetBuilderAvailableAccounts", params: GetBuilderAvailableAccounts } | { type: "ListBuilders", params: ListBuilders } | { type: "ListFullBuilders", params: ListFullBuilders } - | { type: "GetBuilderAvailableAccounts", params: GetBuilderAvailableAccounts } | { type: "GetAlertersSummary", params: GetAlertersSummary } | { type: "GetAlerter", params: GetAlerter } | { type: "ListAlerters", params: ListAlerters }