diff --git a/extras/repo-canary/Cargo.lock b/extras/canaries/repo-canary/Cargo.lock similarity index 93% rename from extras/repo-canary/Cargo.lock rename to extras/canaries/repo-canary/Cargo.lock index 1d09816ab0c..891dfe1e1c3 100644 --- a/extras/repo-canary/Cargo.lock +++ b/extras/canaries/repo-canary/Cargo.lock @@ -13,11 +13,24 @@ dependencies = [ "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ansi_term" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "anyhow" version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "arc-swap" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "arrayref" version = "0.3.5" @@ -28,6 +41,15 @@ name = "arrayvec" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "atty" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "autocfg" version = "0.1.7" @@ -61,6 +83,11 @@ dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "base64" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "bitflags" version = "1.2.1" @@ -76,35 +103,11 @@ dependencies = [ "constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "block-buffer" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "block-padding 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "block-padding" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "bumpalo" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "byte-tools" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "byteorder" version = "1.3.2" @@ -128,6 +131,20 @@ dependencies = [ "ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "cargo-readme" +version = "3.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cc" version = "1.0.47" @@ -150,6 +167,20 @@ dependencies = [ "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "clap" +version = "2.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cloudabi" version = "0.0.3" @@ -254,14 +285,6 @@ dependencies = [ "sct 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "digest" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "dirs" version = "2.0.2" @@ -334,11 +357,6 @@ dependencies = [ "synstructure 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "fake-simd" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "flate2" version = "1.0.12" @@ -388,14 +406,6 @@ dependencies = [ "num_cpus 1.11.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "generic-array" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "getrandom" version = "0.1.13" @@ -727,11 +737,6 @@ dependencies = [ "unicode-normalization 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "opaque-debug" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "parking_lot" version = "0.9.0" @@ -758,11 +763,10 @@ dependencies = [ [[package]] name = "pem" -version = "0.6.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1011,13 +1015,16 @@ dependencies = [ name = "repo-canary" version = "0.1.0" dependencies = [ + "cargo-readme 3.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "reqwest 0.9.22 (registry+https://github.com/rust-lang/crates.io-index)", + "signal-hook 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "simplelog 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", "snafu 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tough 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tough 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1184,14 +1191,21 @@ dependencies = [ ] [[package]] -name = "sha2" -version = "0.8.0" +name = "signal-hook" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "signal-hook-registry 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "signal-hook-registry" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "arc-swap 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1227,6 +1241,15 @@ dependencies = [ "snafu-derive 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "snafu" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "doc-comment 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "snafu-derive 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "snafu-derive" version = "0.5.0" @@ -1237,6 +1260,16 @@ dependencies = [ "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "snafu-derive" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "sourcefile" version = "0.1.4" @@ -1255,6 +1288,11 @@ dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "syn" version = "0.15.44" @@ -1308,6 +1346,14 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "thread_local" version = "0.3.6" @@ -1462,22 +1508,29 @@ dependencies = [ "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "toml" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "tough" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "olpc-cjson 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "pem 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "pem 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "reqwest 0.9.22 (registry+https://github.com/rust-lang/crates.io-index)", "ring 0.16.9 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "serde_plain 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "snafu 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "snafu 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "url 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1495,11 +1548,6 @@ dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "typenum" -version = "1.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "unicase" version = "2.5.1" @@ -1529,6 +1577,11 @@ name = "unicode-segmentation" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "unicode-width" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "unicode-xid" version = "0.1.0" @@ -1572,6 +1625,11 @@ dependencies = [ "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "vec_map" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "version_check" version = "0.1.5" @@ -1742,25 +1800,28 @@ dependencies = [ [metadata] "checksum adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5d2e7343e7fc9de883d1b0341e0b13970f764c14101234857d2ddafa1cb1cac2" "checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" +"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum anyhow 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)" = "57114fc2a6cc374bce195d3482057c846e706d252ff3604363449695684d7a0d" +"checksum arc-swap 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d7b8a9123b8027467bce0099fe556c628a53c8d83df0507084c31e9ba2e39aff" "checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" "checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" +"checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" "checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" "checksum backtrace 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)" = "924c76597f0d9ca25d762c25a4d369d51267536465dc5064bdf0eb073ed477ea" "checksum backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6575f128516de27e3ce99689419835fce9643a9b215a14d2b5b685be018491" "checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" +"checksum base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" "checksum blake2b_simd 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b83b7baab1e671718d78204225800d6b170e648188ac7dc992e9d6bddf87d0c0" -"checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" -"checksum block-padding 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" "checksum bumpalo 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad807f2fc2bf185eeb98ff3a901bd46dc5ad58163d0fa4577ba0d25674d71708" -"checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" "checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" "checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb" +"checksum cargo-readme 3.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6f802a8fcc14bebdf651fd33323654451bdd168c884b22c270dfd8afb403a50" "checksum cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)" = "aa87058dce70a3ff5621797f1506cb837edd02ac4c0ae642b4542dce802908b8" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" "checksum chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e8493056968583b0193c1bb04d6f7684586f3726992d6c573261941a895dbd68" +"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "995a44c877f9212528ccc74b21a232f66ad69001e40ede5bcee2ac9ef2657120" "checksum cookie 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "888604f00b3db336d2af898ec3c1d5d0ddf5e6d462220f2ededc33a87ac4bbd5" @@ -1772,7 +1833,6 @@ dependencies = [ "checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" "checksum crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce446db02cdc3165b94ae73111e570793400d0794e46125cc4056c81cbb039f4" "checksum ct-logs 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4d3686f5fa27dbc1d76c751300376e167c5a43387f44bb451fd1c24776e49113" -"checksum digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" "checksum dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3" "checksum dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b" "checksum doc-comment 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "923dea538cea0aa3025e8685b20d6ee21ef99c4f77e954a30febbaac5ec73a97" @@ -1782,7 +1842,6 @@ dependencies = [ "checksum error-chain 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3ab49e9dcb602294bc42f9a7dfc9bc6e936fca4418ea300dbfb84fe16de0b7d9" "checksum failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f8273f13c977665c5db7eb2b99ae520952fe5ac831ae4cd09d80c4c7042b5ed9" "checksum failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0bc225b78e0391e4b8683440bf2e63c2deeeb2ce5189eab46e2b68c6d3725d08" -"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" "checksum flate2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)" = "ad3c5233c9a940c8719031b423d7e6c16af66e031cb0420b0896f5245bf181d3" "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" @@ -1790,7 +1849,6 @@ dependencies = [ "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" "checksum futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1b980f2816d6ee8673b6517b52cb0e808a180efc92e5c19d02cdda79066703ef" "checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" -"checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" "checksum getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e7db7ca94ed4cd01190ceee0d8a8052f08a247aa1b469a7f68c6a3b71afcf407" "checksum h2 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)" = "a5b34c246847f938a410a03c5458c7fee2274436675e76d8b903c08efc29c462" "checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" @@ -1827,10 +1885,9 @@ dependencies = [ "checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" "checksum num_cpus 1.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "155394f924cdddf08149da25bfb932d226b4a593ca7468b08191ff6335941af5" "checksum olpc-cjson 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9409e2493366c8f19387c98c5189ab9c937541b5bf48f11390d038a59fdfd9c1" -"checksum opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" "checksum parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" "checksum parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" -"checksum pem 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39eb474073dfddbf7156515344266245d91ce698ddbf15e0498cef22b836f45a" +"checksum pem 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a1581760c757a756a41f0ee3ff01256227bdf64cb752839779b95ffb01c59793" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" "checksum percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" "checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" @@ -1875,20 +1932,25 @@ dependencies = [ "checksum serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "2f72eb2a68a7dc3f9a691bfda9305a1c017a6215e5a4545c258500d2099a37c2" "checksum serde_plain 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "625fb0da2b006092b426a94acc1611bec52f2ec27bb27b266a9f93c29ee38eda" "checksum serde_urlencoded 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "642dd69105886af2efd227f75a520ec9b44a820d65bc133a9131f7d229fd165a" -"checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d" +"checksum signal-hook 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "7a9c17dd3ba2d36023a5c9472ecddeda07e27fd0b05436e8c1e0c8f178185652" +"checksum signal-hook-registry 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94f478ede9f64724c5d173d7bb56099ec3e2d9fc2774aac65d34b8b890405f41" "checksum simplelog 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "05a3e303ace6adb0a60a9e9e2fbc6a33e1749d1e43587e2125f7efa9c5e107c5" "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" "checksum smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6" "checksum snafu 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9d0bf93d08d6a44363b47d737f1f5bebbf5e6a1eaaa3d4c128ceeaca6b718292" +"checksum snafu 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "41207ca11f96a62cd34e6b7fdf73d322b25ae3848eb9d38302169724bb32cf27" "checksum snafu-derive 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "624e94bd38e471f67883b467711e7a7ad7dbe284f5fb7e661dc8a671fc5b26a0" +"checksum snafu-derive 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4c5e338c8b0577457c9dda8e794b6ad7231c96e25b1b0dd5842d52249020c1c0" "checksum sourcefile 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4bf77cb82ba8453b42b6ae1d692e4cdc92f9a47beaf89a847c8be83f4e328ad3" "checksum spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" "checksum string 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d24114bfcceb867ca7f71a0d3fe45d45619ec47a6fbfa98cb14e14250bfa5d6d" +"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" "checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" "checksum syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "661641ea2aa15845cddeb97dad000d22070bb5c1fb456b96c1cba883ec691e92" "checksum synstructure 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)" = "575be94ccb86e8da37efb894a87e2b660be299b41d8ef347f9d6d79fbe61b1ba" "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" "checksum term 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c0863a3345e70f61d613eab32ee046ccd1bcc5f9105fe402c61fcd0c13eeb8b5" +"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" "checksum tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)" = "5a09c0b5bb588872ab2f09afa13ee6e9dac11e10a0ec9e8e3ba39a5a5d530af6" @@ -1902,20 +1964,22 @@ dependencies = [ "checksum tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1d14b10654be682ac43efee27401d792507e30fd8d26389e1da3b185de2e4119" "checksum tokio-threadpool 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "2bd2c6a3885302581f4401c82af70d792bb9df1700e7437b0aeb4ada94d5388c" "checksum tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "f2106812d500ed25a4f38235b9cae8f78a09edf43203e16e59c3b769a342a60e" -"checksum tough 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "80ee2c10a417fdf8700a56c4aa1ae9893b76995a154231d96fdd59996244dc34" +"checksum toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" +"checksum tough 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0fb6e600bf6ac77bb48e0ab2e1d6b2abcb124ddbc3f68b2f60dfb72f17bf1007" "checksum try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382" "checksum try_from 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "283d3b89e1368717881a9d51dad843cc435380d8109c9e47d38780a324698d8b" -"checksum typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9" "checksum unicase 2.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2e2e6bd1e59e56598518beb94fd6db628ded570326f0a98c679a304bd9f00150" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" "checksum unicode-normalization 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "09c8070a9942f5e7cfccd93f490fdebd230ee3c3c9f107cb25bad5351ef671cf" "checksum unicode-segmentation 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49f5526225fd8b77342d5986ab5f6055552e9c0776193b5b63fd53b46debfad7" +"checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" "checksum untrusted 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60369ef7a31de49bcb3f6ca728d4ba7300d9a1658f94c727d4cab8c8d9f4aece" "checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" "checksum url 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "75b414f6c464c879d7f9babf951f23bc3743fb7313c081b2e6ca719067ea9d61" "checksum uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "90dbc611eb48397705a6b0f6e917da23ae517e4d127123d2cf7674206627d32a" +"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" "checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" "checksum want 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b6395efa4784b027708f7451087e647ec73cc74f5d9bc2e418404248d679a230" "checksum wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d" diff --git a/extras/repo-canary/Cargo.toml b/extras/canaries/repo-canary/Cargo.toml similarity index 67% rename from extras/repo-canary/Cargo.toml rename to extras/canaries/repo-canary/Cargo.toml index de925f2d30f..a82abfac114 100644 --- a/extras/repo-canary/Cargo.toml +++ b/extras/canaries/repo-canary/Cargo.toml @@ -4,12 +4,18 @@ version = "0.1.0" authors = ["Erikson Tung "] edition = "2018" publish = false +build = "build.rs" [dependencies] +chrono = "0.4" +signal-hook = "0.1.12" log = "0.4" rand = "0.7.0" reqwest = { version = "0.9.17", default-features = false, features = ["rustls-tls"] } simplelog = "0.7" snafu = "0.5.0" tempfile = "3.1.0" -tough = { version = "0.1.0", features = ["http"] } +tough = { version = "0.2.0", features = ["http"] } + +[build-dependencies] +cargo-readme = "3.1" diff --git a/extras/canaries/repo-canary/Dockerfile b/extras/canaries/repo-canary/Dockerfile new file mode 100644 index 00000000000..932a3bca4c4 --- /dev/null +++ b/extras/canaries/repo-canary/Dockerfile @@ -0,0 +1,13 @@ +FROM rust:1.38.0 as builder +WORKDIR /opt/build +COPY . . +RUN cargo install --path . + +FROM amazonlinux:2 +RUN yum -y update && yum clean all +RUN mkdir -p /usr/share/repo-canary + +COPY root.json /usr/share/repo-canary/ +COPY --from=builder /opt/build/target/release/repo-canary /usr/bin/ + +ENTRYPOINT ["/usr/bin/repo-canary"] diff --git a/extras/canaries/repo-canary/README.md b/extras/canaries/repo-canary/README.md new file mode 100644 index 00000000000..5b782a2e928 --- /dev/null +++ b/extras/canaries/repo-canary/README.md @@ -0,0 +1,38 @@ +# repo-canary + +Current version: 0.1.0 + +## Introduction + +`repo-canary` is a TUF repository canary that validates a specified TUF repository using [tough](https://crates.io/crates/tough). + +It validates by loading the repository, checking the metadata files and attempting retrieval of its listed targets. + +If any `tough` library error is encountered at any step of the validation process, a non-zero exit code is returned. +Exit codes are mapped to specific `tough` library errors as follows: + +| `tough` error | exit code | +| ------------- |------- | +| `VerifyTrustedMetadata` | 64 | +| `VerifyMetadata` | 65 | +| `VersionMismatch` | 66 | +| `Transport` | 67 | +| `ExpiredMetadata` | 68 | +| `MetaMissing` | 69 | +| `OlderMetadata` | 70 | + + +Other exit code to errors mappings: + +| Other errors | exit code | +| ------------- |------- | +| Missing target in repo | 71 | +| Failed to download target | 72 | +| *Metadata about to expire | 73 | + +(*: see `--check-upcoming-expiration-days` option in usage info) + + +## Colophon + +This text was generated from `README.tpl` using [cargo-readme](https://crates.io/crates/cargo-readme), and includes the rustdoc from `src/main.rs`. \ No newline at end of file diff --git a/extras/canaries/repo-canary/README.tpl b/extras/canaries/repo-canary/README.tpl new file mode 100644 index 00000000000..7b992c507f5 --- /dev/null +++ b/extras/canaries/repo-canary/README.tpl @@ -0,0 +1,9 @@ +# {{crate}} + +Current version: {{version}} + +{{readme}} + +## Colophon + +This text was generated from `README.tpl` using [cargo-readme](https://crates.io/crates/cargo-readme), and includes the rustdoc from `src/main.rs`. diff --git a/extras/canaries/repo-canary/build.rs b/extras/canaries/repo-canary/build.rs new file mode 100644 index 00000000000..49828a1c42f --- /dev/null +++ b/extras/canaries/repo-canary/build.rs @@ -0,0 +1,32 @@ +// Automatically generate README.md from rustdoc. + +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; + +fn main() { + // Check for environment variable "SKIP_README". If it is set, + // skip README generation + if env::var_os("SKIP_README").is_some() { + return; + } + + let mut source = File::open("src/main.rs").unwrap(); + let mut template = File::open("README.tpl").unwrap(); + + let content = cargo_readme::generate_readme( + &PathBuf::from("."), // root + &mut source, // source + Some(&mut template), // template + // The "add x" arguments don't apply when using a template. + true, // add title + false, // add badges + false, // add license + true, // indent headings + ) + .unwrap(); + + let mut readme = File::create("README.md").unwrap(); + readme.write_all(content.as_bytes()).unwrap(); +} diff --git a/extras/repo-canary/root.json b/extras/canaries/repo-canary/root.json similarity index 100% rename from extras/repo-canary/root.json rename to extras/canaries/repo-canary/root.json diff --git a/extras/repo-canary/src/main.rs b/extras/canaries/repo-canary/src/main.rs similarity index 59% rename from extras/repo-canary/src/main.rs rename to extras/canaries/repo-canary/src/main.rs index 7fc3f7bcf86..bf7eb4dbfce 100644 --- a/extras/repo-canary/src/main.rs +++ b/extras/canaries/repo-canary/src/main.rs @@ -1,23 +1,63 @@ +/*! +# Introduction + +`repo-canary` is a TUF repository canary that validates a specified TUF repository using [tough](https://crates.io/crates/tough). + +It validates by loading the repository, checking the metadata files and attempting retrieval of its listed targets. + +If any `tough` library error is encountered at any step of the validation process, a non-zero exit code is returned. +Exit codes are mapped to specific `tough` library errors as follows: + +| `tough` error | exit code | +| ------------- |------- | +| `VerifyTrustedMetadata` | 64 | +| `VerifyMetadata` | 65 | +| `VersionMismatch` | 66 | +| `Transport` | 67 | +| `ExpiredMetadata` | 68 | +| `MetaMissing` | 69 | +| `OlderMetadata` | 70 | + + +Other exit code to errors mappings: + +| Other errors | exit code | +| ------------- |------- | +| Missing target in repo | 71 | +| Failed to download target | 72 | +| *Metadata about to expire | 73 | + +(*: see `--check-upcoming-expiration-days` option in usage info) + +*/ + #![deny(rust_2018_idioms)] #![warn(clippy::pedantic)] #[macro_use] extern crate log; + +use chrono::{DateTime, Duration, Utc}; use rand::seq::SliceRandom; +use signal_hook::{iterator::Signals, SIGINT, SIGQUIT, SIGTERM}; use simplelog::{Config as LogConfig, LevelFilter, SimpleLogger}; use snafu::ResultExt; +use std::collections::HashMap; use std::fs::{File, OpenOptions}; use std::path::{Path, PathBuf}; -use std::process; use std::str::FromStr; use std::string::ToString; +use std::sync::atomic::{AtomicI32, Ordering}; use std::{env, io}; +use std::{process, thread}; use tempfile::tempdir; use tough::{error as tough_error, HttpTransport, Limits, Repository, Settings}; +static SIGNAL: AtomicI32 = AtomicI32::new(0); + type HttpRepo<'a> = Repository<'a, HttpTransport>; -// Custom exit codes +// Custom exit codes to be picked up by CloudWatch event rules const TRUSTED_ROOT_VALIDATION_FAILURE: i32 = 64; const METADATA_VALIDATION_FAILURE: i32 = 65; const VERSION_MISMATCH: i32 = 66; @@ -27,6 +67,8 @@ const MISSING_METADATA: i32 = 69; const ROLLBACK_DETECTED: i32 = 70; const MISSING_TARGET: i32 = 71; const TARGET_DOWNLOAD_FAILURE: i32 = 72; + +const METADATA_ABOUT_TO_EXPIRE: i32 = 73; const OTHER_ERROR: i32 = 1; mod error { @@ -63,6 +105,12 @@ mod error { backtrace: Backtrace, }, + #[snafu(display("Failed to set up signal handler: {}", source))] + Signal { + source: std::io::Error, + backtrace: Backtrace, + }, + #[snafu(display("Logger setup error: {}", source))] Logger { source: log::SetLoggerError }, } @@ -76,6 +124,7 @@ struct Args { metadata_base_url: String, target_base_url: String, trusted_root_path: PathBuf, + upcoming_expiration_in: u16, percent_target_files: u8, } @@ -83,18 +132,22 @@ struct Args { fn usage() -> ! { let program_name = env::args().next().unwrap_or_else(|| "program".to_string()); eprintln!( - r"Usage: {} - --metadata-base-url URL - --target-base-url URL - --trusted-root-path PATH_TO_root.json - [ --percentage-of-targets-to-retrieve 0-100 ] 'Randomly samples specified percentage of targets' - [ --log-level trace|debug|info|warn|error ] - - If --percentage-of-targets-to-retrieve is not specified, {} will attempt to retrieve all - targets listed in the TUF repository. + r"TUF Repository canary. Non-zero exit codes are mapped to specific `tough` library errors. + + USAGE: + {} + + REQUIRED: + --metadata-base-url URL The TUF repository metadata base URL + --target-base-url URL The TUF repository targets base URL + --trusted-root-path PATH/TO/root.json Path to the trusted root.json + + OPTIONS: + [ --check-upcoming-expiration-days 0-365 ] Outputs a list of metadata files expiring within specified number of days (default 0 - don't check). Short-curcuits and exits non-zero if there are any. + [ --percentage-targets-to-retrieve 0-100 ] Randomly samples and retrieves specified percentage of targets (default 100) + [ --log-level trace|debug|info|warn|error ] Specifies logging level (default info) ", program_name, - program_name ); process::exit(2); } @@ -108,6 +161,7 @@ fn usage_msg>(msg: S) -> ! { /// Parse the args to the program and return an Args struct fn parse_args(args: env::Args) -> Args { let mut log_level = None; + let mut upcoming_expiration_in = None; let mut metadata_base_url = None; let mut percent_target_files: Option = None; let mut target_base_url = None; @@ -140,7 +194,21 @@ fn parse_args(args: env::Args) -> Args { ) } - "--percentage-of-targets-to-retrieve" => { + "--check-upcoming-expiration-days" => { + let days = iter + .next() + .unwrap_or_else(|| { + usage_msg("Did not give argument (days) to --check-upcoming-expiration-days") + }) + .parse::() + .unwrap_or_else(|_| usage_msg("Invalid argument: expecting days from 1-365")); + if days > 365 { + usage_msg("Invalid argument: expecting days from 1 to 365") + } + upcoming_expiration_in = Some(days); + } + + "--percentage-targets-to-retrieve" => { let percentage = iter .next() .unwrap_or_else(|| { @@ -172,6 +240,7 @@ fn parse_args(args: env::Args) -> Args { Args { log_level: log_level.unwrap_or_else(|| LevelFilter::Info), metadata_base_url: metadata_base_url.unwrap_or_else(|| usage()), + upcoming_expiration_in: upcoming_expiration_in.unwrap_or_else(|| 0), percent_target_files: percent_target_files.unwrap_or_else(|| 100), target_base_url: target_base_url.unwrap_or_else(|| usage()), trusted_root_path: trusted_root_path.unwrap_or_else(|| usage()), @@ -203,8 +272,8 @@ fn retrieve_percentage_of_targets

( where P: AsRef, { - let targets = repo.targets(); - let percentage = percentage as f32 / 100.0; + let targets = &repo.targets().signed.targets; + let percentage = f32::from(percentage) / 100.0; let num_to_retrieve = (targets.len() as f32 * percentage).ceil(); let mut rng = &mut rand::thread_rng(); let mut sampled_targets: Vec = targets.keys().map(|key| key.to_string()).collect(); @@ -213,6 +282,10 @@ where .cloned() .collect(); for target in sampled_targets { + let recv_signal = SIGNAL.load(Ordering::SeqCst); + if recv_signal != 0 { + return Ok(recv_signal + 128); + } let target_reader = repo.read_target(&target); match target_reader { Err(ref err) => return Ok(match_report_tough_error(err)), @@ -240,6 +313,35 @@ where Ok(0) } +/// Checks for upcoming role expirations, gathers them in a list along with their expiration date. +fn find_upcoming_metadata_expiration( + repo: &HttpRepo<'_>, + days: u16, +) -> HashMap> { + let mut expirations = HashMap::new(); + let time_limit = Utc::now() + Duration::days(i64::from(days)); + info!( + "Looking for metadata expirations happening from now to {:?}", + time_limit + ); + if repo.root().signed.expires <= time_limit { + expirations.insert(tough::schema::RoleType::Root, repo.root().signed.expires); + } + if repo.snapshot().signed.expires <= time_limit { + expirations.insert( + tough::schema::RoleType::Snapshot, + repo.snapshot().signed.expires, + ); + } + if repo.timestamp().signed.expires <= time_limit { + expirations.insert( + tough::schema::RoleType::Timestamp, + repo.timestamp().signed.expires, + ); + } + expirations +} + fn main() -> Result<()> { // Parse and store the args passed to the program let args = parse_args(env::args()); @@ -248,6 +350,15 @@ fn main() -> Result<()> { // Create the datastore path for storing the metadata files let datastore = tempdir().context(error::CreateTempdir)?; + let signals = Signals::new(&[SIGINT, SIGTERM, SIGQUIT]).context(error::Signal)?; + thread::spawn(move || { + for sig in signals.forever() { + // No, we're not supposed to print here, but by the time we check STOP in our main loop + // it could be many seconds later and the user will have no indication that their input was received. + SIGNAL.store(sig, Ordering::SeqCst); + info!("Received termination signal, will exit after next operation"); + } + }); info!("Loading TUF repo"); let transport = HttpTransport::new(); @@ -269,16 +380,38 @@ fn main() -> Result<()> { }, ); // Check for errors from loading the TUF repository - let rc = match &repo { - Err(err) => match_report_tough_error(err), + let mut rc = 0; + match &repo { + Err(err) => rc = match_report_tough_error(err), Ok(repo) => { info!("Loaded TUF repo"); - // Try retrieving listed targets - info!( - "Downloading {}% of listed targets", - args.percent_target_files - ); - retrieve_percentage_of_targets(repo, datastore.path(), args.percent_target_files)? + if args.upcoming_expiration_in != 0 { + // Check for upcoming metadata expirations + let upcoming_expirations = + find_upcoming_metadata_expiration(repo, args.upcoming_expiration_in); + if !upcoming_expirations.is_empty() { + for (role, date) in upcoming_expirations { + warn!( + "{} expiring within {} day(s) on {}", + role, args.upcoming_expiration_in, date + ) + } + rc = METADATA_ABOUT_TO_EXPIRE; + } + } + // If there are no errors so far + if rc == 0 { + // Try retrieving listed targets + info!( + "Downloading {}% of listed targets", + args.percent_target_files + ); + rc = retrieve_percentage_of_targets( + repo, + datastore.path(), + args.percent_target_files, + )? + } } }; diff --git a/extras/repo-canary/Dockerfile b/extras/repo-canary/Dockerfile deleted file mode 100644 index bb80279e4d3..00000000000 --- a/extras/repo-canary/Dockerfile +++ /dev/null @@ -1,17 +0,0 @@ -FROM rust:1.38.0 as builder -WORKDIR /opt/build -COPY . . -RUN cargo install --path . --force -q - -FROM amazonlinux:2 -ARG METADATA_BASE_URL -ENV METADATA_BASE_URL $METADATA_BASE_URL -ARG TARGET_BASE_URL -ENV TARGET_BASE_URL $TARGET_BASE_URL -RUN yum -y update && yum clean all -RUN mkdir -p /usr/share/repo-canary - -COPY root.json /usr/share/repo-canary/ -COPY --from=builder /opt/build/target/release/repo-canary /usr/bin/ - -CMD /usr/bin/repo-canary --metadata-base-url $METADATA_BASE_URL --target-base-url $TARGET_BASE_URL --trusted-root-path /usr/share/repo-canary/root.json --percentage-of-targets-to-retrieve 50 diff --git a/tools/infra/stacks/Makefile b/tools/infra/stacks/Makefile index dc0ebb315ab..bdce060aacf 100644 --- a/tools/infra/stacks/Makefile +++ b/tools/infra/stacks/Makefile @@ -1,5 +1,5 @@ SHELL := bash -stacks := $(wildcard *.yml) +stacks := $(wildcard *.yml */*.yml) list: @printf "%s\n" $(stacks) diff --git a/tools/infra/stacks/canaries/canary-infra.yml b/tools/infra/stacks/canaries/canary-infra.yml new file mode 100644 index 00000000000..9c21f481748 --- /dev/null +++ b/tools/infra/stacks/canaries/canary-infra.yml @@ -0,0 +1,88 @@ +Resources: + VPC: + Type: 'AWS::EC2::VPC' + Properties: + CidrBlock: 10.0.0.0/16 + VPCInternetGateway: + Type: 'AWS::EC2::InternetGateway' + AttachGateway: + Type: 'AWS::EC2::VPCGatewayAttachment' + Properties: + VpcId: !Ref VPC + InternetGatewayId: !Ref VPCInternetGateway + CanaryECSCluster: + Type: 'AWS::ECS::Cluster' + Properties: {} + CanaryTaskExecutionRole: + Type: 'AWS::IAM::Role' + Properties: + RoleName: CanaryTaskExecutionRole + AssumeRolePolicyDocument: + Statement: + - Effect: Allow + Principal: + Service: ecs-tasks.amazonaws.com + Action: + - 'sts:AssumeRole' + Policies: + - PolicyName: AmazonECSTaskExecutionPolicy + PolicyDocument: + Statement: + - Effect: Allow + Action: + - 'ecr:GetAuthorizationToken' + - 'ecr:BatchCheckLayerAvailability' + - 'ecr:GetDownloadUrlForLayer' + - 'ecr:BatchGetImage' + - 'logs:CreateLogStream' + - 'logs:PutLogEvents' + - 'logs:DescribeLogStreams' + - 'logs:GetLogEvents' + - 'cloudwatch:PutMetricData' + Resource: '*' + CanaryTaskEventRole: + Type: 'AWS::IAM::Role' + Properties: + RoleName: CanaryTaskEventRole + AssumeRolePolicyDocument: + Statement: + - Effect: Allow + Principal: + Service: events.amazonaws.com + Action: + - 'sts:AssumeRole' + Policies: + - PolicyName: AmazonEC2ContainerServiceEventsRole + PolicyDocument: + Statement: + - Effect: Allow + Action: + - 'ecs:RunTask' + - 'iam:PassRole' + Resource: '*' +Outputs: + VPCId: + Description: "Canary VPC ID" + Value: !Ref VPC + Export: + Name: !Sub "${AWS::StackName}-VpcId" + VPCInternetGatewayId: + Description: "Canary VPC Internet Gateway ID" + Value: !Ref VPCInternetGateway + Export: + Name: !Sub "${AWS::StackName}-VpcInternetGatewayId" + ECSClusterArn: + Description: "ECS Cluster ARN" + Value: !GetAtt CanaryECSCluster.Arn + Export: + Name: !Sub "${AWS::StackName}-ECSClusterArn" + CanaryTaskExecutionRoleArn: + Description: "Canary Task Execution Role ARN" + Value: !GetAtt CanaryTaskExecutionRole.Arn + Export: + Name: !Sub "${AWS::StackName}-CanaryTaskExecutionRoleArn" + CanaryTaskEventRoleArn: + Description: "Canary Task Event Role ARN" + Value: !GetAtt CanaryTaskEventRole.Arn + Export: + Name: !Sub "${AWS::StackName}-CanaryTaskEventRoleArn" diff --git a/tools/infra/stacks/canaries/repo-canaries.yml b/tools/infra/stacks/canaries/repo-canaries.yml new file mode 100644 index 00000000000..f086dc6e154 --- /dev/null +++ b/tools/infra/stacks/canaries/repo-canaries.yml @@ -0,0 +1,380 @@ +Parameters: + CanaryInfraStack: + Type: String + Description: 'Enter the name of the canary infrastructure stack that sets up the VPC and ECS cluster.' + TaskName: + Type: String + Default: repo-canary + Description: 'Enter the name of the canary container image.' + SNSSubscriptionEndpoint: + Type: String + Description: 'Enter the SNS subscription endpoint for CloudWatch alarms.' + SNSSubscriptionProtocol: + Type: String + Default: email + Description: 'Enter the SNS subscription endpoint protocol. Default is email.' + RepoMetadataBaseUrl: + Type: String + Description: 'Enter the metadata base url that specifies the TUF repository metadata files source.' + RepoTargetBaseUrl: + Type: String + Description: 'Enter the target base url that specifies where the listed targets in the TUF repository can be retrieved.' +Resources: + VPCRouteTable: + Type: 'AWS::EC2::RouteTable' + Properties: + VpcId: + Fn::ImportValue: + !Sub "${CanaryInfraStack}-VpcId" + ExternalRoute: + Type: 'AWS::EC2::Route' + Properties: + DestinationCidrBlock: 0.0.0.0/0 + GatewayId: + Fn::ImportValue: + !Sub "${CanaryInfraStack}-VpcInternetGatewayId" + RouteTableId: !Ref VPCRouteTable + VPCSubnet: + Type: 'AWS::EC2::Subnet' + Properties: + CidrBlock: 10.0.0.0/24 + VpcId: + Fn::ImportValue: + !Sub "${CanaryInfraStack}-VpcId" + SubnetRouteAssociation: + Type: 'AWS::EC2::SubnetRouteTableAssociation' + Properties: + RouteTableId: !Ref VPCRouteTable + SubnetId: !Ref VPCSubnet + VPCSecurityGroup: + Type: 'AWS::EC2::SecurityGroup' + Properties: + GroupDescription: !Sub 'Allow traffic to ${TaskName}' + VpcId: + Fn::ImportValue: + !Sub "${CanaryInfraStack}-VpcId" + CheckUpcomingExpirationLogGroup: + Type: 'AWS::Logs::LogGroup' + Properties: + LogGroupName: !Sub '/ecs/${TaskName}-check-upcoming-expiration' + RetentionInDays: 30 + RetrieveTargetsLogGroup: + Type: 'AWS::Logs::LogGroup' + Properties: + LogGroupName: !Sub '/ecs/${TaskName}-retrieve-targets' + RetentionInDays: 30 + FailedStartLogGroup: + Type: 'AWS::Logs::LogGroup' + Properties: + LogGroupName: !Sub '/aws/events/${TaskName}-start-failures' + FoundUpcomingExpirationLogGroup: + Type: 'AWS::Logs::LogGroup' + Properties: + LogGroupName: !Sub '/aws/events/${TaskName}-found-upcoming-expiration' + RepoValidationFailureLogGroup: + Type: 'AWS::Logs::LogGroup' + Properties: + LogGroupName: !Sub '/aws/events/${TaskName}-validation-failures' + TUFRepoCanarySNSNotificationTopic: + Type: 'AWS::SNS::Topic' + Properties: + DisplayName: TUF Repo Canary Notifications + TUFRepoCanarySNSSubscription: + Type: 'AWS::SNS::Subscription' + Properties: + Endpoint: !Sub '${SNSSubscriptionEndpoint}' + Protocol: !Sub '${SNSSubscriptionProtocol}' + TopicArn: !Ref TUFRepoCanarySNSNotificationTopic + TUFRepoCanaryImgRepo: + Type: 'AWS::ECR::Repository' + Properties: + RepositoryName: !Sub '${TaskName}' + + CheckUpcomingExpirationTask: + Type: 'AWS::ECS::TaskDefinition' + Properties: + TaskRoleArn: + Fn::ImportValue: + !Sub "${CanaryInfraStack}-CanaryTaskExecutionRoleArn" + ExecutionRoleArn: + Fn::ImportValue: + !Sub "${CanaryInfraStack}-CanaryTaskExecutionRoleArn" + Family: !Sub '${TaskName}-check-upcoming-expiration' + NetworkMode: awsvpc + Cpu: '256' + Memory: '512' + RequiresCompatibilities: + - FARGATE + ContainerDefinitions: + - Name: !Sub '${TaskName}-check-upcoming-expiration' + Command: + - '--metadata-base-url' + - !Sub '${RepoMetadataBaseUrl}' + - '--target-base-url' + - !Sub '${RepoTargetBaseUrl}' + - '--trusted-root-path' + - '/usr/share/repo-canary/root.json' + - '--check-upcoming-expiration' + - '3' + - '--percentage-targets-to-retrieve' + - '0' + Memory: 512 + Cpu: 256 + Image: !Join + - / + - - !Join + - . + - - !Ref 'AWS::AccountId' + - dkr.ecr + - !Ref 'AWS::Region' + - amazonaws.com + - !Sub '${TaskName}:latest' + LogConfiguration: + LogDriver: awslogs + Options: + awslogs-group: !Ref CheckUpcomingExpirationLogGroup + awslogs-region: !Ref 'AWS::Region' + awslogs-stream-prefix: 'ecs' + CheckUpcomingExpirationScheduledTask: + Type: 'AWS::Events::Rule' + Properties: + Description: !Sub 'Schedules ${TaskName}-check-upcoming-expiration task to run every 20 minutes starting at minute 0 of the hour' + ScheduleExpression: cron(0/20 * * * ? *) + State: ENABLED + Targets: + - Id: !Sub '${TaskName}-check-upcoming-expiration-Fargate-Task' + RoleArn: + Fn::ImportValue: + !Sub "${CanaryInfraStack}-CanaryTaskEventRoleArn" + EcsParameters: + TaskDefinitionArn: !Ref CheckUpcomingExpirationTask + TaskCount: 1 + LaunchType: FARGATE + PlatformVersion: LATEST + NetworkConfiguration: + AwsVpcConfiguration: + AssignPublicIp: ENABLED + SecurityGroups: + - !Ref VPCSecurityGroup + Subnets: + - !Ref VPCSubnet + Arn: + Fn::ImportValue: + !Sub "${CanaryInfraStack}-ECSClusterArn" + CheckExpirationFailedInvocationAlarm: + Type: 'AWS::CloudWatch::Alarm' + Properties: + AlarmName: TUF Repo Canary check expiration task invocation failure + AlarmDescription: 'TUF Repo Canary check upcoming expiration task could not be invoked' + Namespace: AWS/Events + MetricName: FailedInvocations + Dimensions: + - Name: RuleName + Value: !Ref CheckUpcomingExpirationScheduledTask + Period: 1200 + Statistic: Average + Threshold: 0 + TreatMissingData: notBreaching + ComparisonOperator: GreaterThanThreshold + EvaluationPeriods: 3 + DatapointsToAlarm: 2 + ActionsEnabled: true + AlarmActions: + - !Ref TUFRepoCanarySNSNotificationTopic + CheckUpcomingExpirationRule: + Type: 'AWS::Events::Rule' + Properties: + Description: 'TUF Repo Canary check-upcoming-expiration task exited with code 73 (found upcoming metadata expirations) or 68 (already expired)' + Name: !Sub '${TaskName}-upcoming-metadata-expiration' + EventPattern: !Sub '{"source": ["aws.ecs"],"detail-type": ["ECS Task State Change"],"detail": {"containers": {"name": ["${TaskName}-check-upcoming-expiration"],"exitCode":[73,68],"lastStatus": ["STOPPED"]}}}' + Targets: + - Arn: !Join + - ":" + - - "arn:aws:logs" + - !Ref 'AWS::Region' + - !Ref 'AWS::AccountId' + - 'log-group' + - !Ref FoundUpcomingExpirationLogGroup + Id: 'tuf-repo-metadata-upcoming-expiration' + CheckUpcomingExpirationAlarm: + Type: 'AWS::CloudWatch::Alarm' + Properties: + AlarmName: TUF repository metadata files upcoming expiration + AlarmDescription: 'TUF Repo Canary found metadata files that are about to expire in 3 days' + Namespace: AWS/Events + MetricName: TriggeredRules + Dimensions: + - Name: RuleName + Value: !Ref CheckUpcomingExpirationRule + Period: 1200 + Statistic: Average + Threshold: 0 + TreatMissingData: notBreaching + ComparisonOperator: GreaterThanThreshold + EvaluationPeriods: 1 + DatapointsToAlarm: 1 + ActionsEnabled: true + AlarmActions: + - !Ref TUFRepoCanarySNSNotificationTopic + + RetrieveTargetTask: + Type: 'AWS::ECS::TaskDefinition' + Properties: + TaskRoleArn: + Fn::ImportValue: + !Sub "${CanaryInfraStack}-CanaryTaskExecutionRoleArn" + ExecutionRoleArn: + Fn::ImportValue: + !Sub "${CanaryInfraStack}-CanaryTaskExecutionRoleArn" + Family: !Sub '${TaskName}-retrieve-targets' + NetworkMode: awsvpc + Cpu: '256' + Memory: '512' + RequiresCompatibilities: + - FARGATE + ContainerDefinitions: + - Name: !Sub '${TaskName}-retrieve-targets' + Command: + - '--metadata-base-url' + - !Sub '${RepoMetadataBaseUrl}' + - '--target-base-url' + - !Sub '${RepoTargetBaseUrl}' + - '--trusted-root-path' + - '/usr/share/repo-canary/root.json' + - '--percentage-targets-to-retrieve' + - '30' + Memory: 512 + Cpu: 256 + Image: !Join + - / + - - !Join + - . + - - !Ref 'AWS::AccountId' + - dkr.ecr + - !Ref 'AWS::Region' + - amazonaws.com + - !Sub '${TaskName}:latest' + LogConfiguration: + LogDriver: awslogs + Options: + awslogs-group: !Ref RetrieveTargetsLogGroup + awslogs-region: !Ref 'AWS::Region' + awslogs-stream-prefix: 'ecs' + RetrieveTargetScheduledTask: + Type: 'AWS::Events::Rule' + Properties: + Description: !Sub 'Schedules ${TaskName}-retrieve-targets task to run every 20 minutes starting at minute 10 of the hour' + ScheduleExpression: cron(10/20 * * * ? *) + State: ENABLED + Targets: + - Id: !Sub '${TaskName}-retrieve-targets-Fargate-Task' + RoleArn: + Fn::ImportValue: + !Sub "${CanaryInfraStack}-CanaryTaskEventRoleArn" + EcsParameters: + TaskDefinitionArn: !Ref RetrieveTargetTask + TaskCount: 1 + LaunchType: FARGATE + PlatformVersion: LATEST + NetworkConfiguration: + AwsVpcConfiguration: + AssignPublicIp: ENABLED + SecurityGroups: + - !Ref VPCSecurityGroup + Subnets: + - !Ref VPCSubnet + Arn: + Fn::ImportValue: + !Sub "${CanaryInfraStack}-ECSClusterArn" + RetrieveTargetFailedInvocationAlarm: + Type: 'AWS::CloudWatch::Alarm' + Properties: + AlarmName: TUF Repo Canary retrieve targets invocation failure + AlarmDescription: 'TUF Repo Canary retrieve targets task could not be invoked' + Namespace: AWS/Events + MetricName: FailedInvocations + Dimensions: + - Name: RuleName + Value: !Ref RetrieveTargetScheduledTask + Period: 1200 + Statistic: Average + Threshold: 0 + TreatMissingData: notBreaching + ComparisonOperator: GreaterThanThreshold + EvaluationPeriods: 3 + DatapointsToAlarm: 2 + ActionsEnabled: true + AlarmActions: + - !Ref TUFRepoCanarySNSNotificationTopic + + ValidationFailedRule: + Type: 'AWS::Events::Rule' + Properties: + Description: 'TUF Repo Canary task exited with non-zero exit code' + Name: !Sub '${TaskName}-non-zero-exit-code' + EventPattern: !Sub '{"source": ["aws.ecs"],"detail-type": ["ECS Task State Change"],"detail": {"containers": {"name": ["${TaskName}-check-upcoming-expiration","${TaskName}-retrieve-targets"],"exitCode":[1,64,65,66,67,68,69,70,71,72],"lastStatus": ["STOPPED"]}}}' + Targets: + - Arn: !Join + - ":" + - - "arn:aws:logs" + - !Ref 'AWS::Region' + - !Ref 'AWS::AccountId' + - 'log-group' + - !Ref RepoValidationFailureLogGroup + Id: 'tuf-repo-validation-failure' + ValidationFailedAlarm: + Type: 'AWS::CloudWatch::Alarm' + Properties: + AlarmName: TUF repository validation failure + AlarmDescription: 'TUF Repo Canary failed to validate TUF repository' + Namespace: AWS/Events + MetricName: TriggeredRules + Dimensions: + - Name: RuleName + Value: !Ref ValidationFailedRule + Period: 900 + Statistic: Average + Threshold: 0 + TreatMissingData: notBreaching + ComparisonOperator: GreaterThanThreshold + EvaluationPeriods: 4 + DatapointsToAlarm: 3 + ActionsEnabled: true + AlarmActions: + - !Ref TUFRepoCanarySNSNotificationTopic + + TUFRepoCanaryFailedStartAlarm: + Type: 'AWS::CloudWatch::Alarm' + Properties: + AlarmName: TUF Repo Canary Task Start Failure + AlarmDescription: 'TUF Repo Canary task failed to start' + Namespace: AWS/Events + MetricName: TriggeredRules + Dimensions: + - Name: RuleName + Value: !Ref TUFRepoCanaryFailedStartRule + Period: 600 + Statistic: Average + Threshold: 0 + TreatMissingData: notBreaching + ComparisonOperator: GreaterThanThreshold + EvaluationPeriods: 4 + DatapointsToAlarm: 3 + ActionsEnabled: true + AlarmActions: + - !Ref TUFRepoCanarySNSNotificationTopic + TUFRepoCanaryFailedStartRule: + Type: 'AWS::Events::Rule' + Properties: + Description: 'TUF Repo Canary fail to start' + Name: 'repo-canary-failed-to-start' + EventPattern: !Sub '{"source": ["aws.ecs"],"detail-type": ["ECS Task State Change"],"detail": {"containers": {"name": ["${TaskName}-retrieve-targets","${TaskName}-check-upcoming-expiration"],"lastStatus": ["STOPPED"]},"stoppedReason":["Task failed to start"]}}' + Targets: + - Arn: !Join + - ":" + - - "arn:aws:logs" + - !Ref 'AWS::Region' + - !Ref 'AWS::AccountId' + - 'log-group' + - !Ref FailedStartLogGroup + Id: !Sub '${TaskName}-failed-start' diff --git a/tools/infra/stacks/infra-pr-build.yml b/tools/infra/stacks/infra-pr-build.yml index c48d80aa798..aa458427fcd 100644 --- a/tools/infra/stacks/infra-pr-build.yml +++ b/tools/infra/stacks/infra-pr-build.yml @@ -1,4 +1,4 @@ -gppParameters: +Parameters: BuildSpecPath: Type: String AllowedPattern: '.+\.yml$' diff --git a/tools/infra/tuf-repo-canary/RepoCanary.template.yaml b/tools/infra/tuf-repo-canary/RepoCanary.template.yaml deleted file mode 100644 index a91944f13d0..00000000000 --- a/tools/infra/tuf-repo-canary/RepoCanary.template.yaml +++ /dev/null @@ -1,265 +0,0 @@ -Parameters: - TaskName: - Type: String - Default: tuf-repo-canary - SNSSubscriptionEndpoint: - Type: String - SNSSubscriptionProtocol: - Type: String - Default: email -Resources: - VPC: - Type: 'AWS::EC2::VPC' - Properties: - CidrBlock: 10.0.0.0/16 - VPCSubnet: - Type: 'AWS::EC2::Subnet' - Properties: - CidrBlock: 10.0.0.0/24 - VpcId: !Ref VPC - VPCInternetGateway: - Type: 'AWS::EC2::InternetGateway' - AttachGateway: - Type: 'AWS::EC2::VPCGatewayAttachment' - Properties: - VpcId: !Ref VPC - InternetGatewayId: !Ref VPCInternetGateway - VPCRouteTable: - Type: 'AWS::EC2::RouteTable' - Properties: - VpcId: !Ref VPC - ExternalRoute: - Type: 'AWS::EC2::Route' - Properties: - DestinationCidrBlock: 0.0.0.0/0 - GatewayId: !Ref VPCInternetGateway - RouteTableId: !Ref VPCRouteTable - SubnetRouteAssociation: - Type: 'AWS::EC2::SubnetRouteTableAssociation' - Properties: - RouteTableId: !Ref VPCRouteTable - SubnetId: !Ref VPCSubnet - VPCSecurityGroup: - Type: 'AWS::EC2::SecurityGroup' - Properties: - GroupDescription: !Sub 'Allow traffic to ${TaskName}' - VpcId: !Ref VPC - LogGroup: - Type: 'AWS::Logs::LogGroup' - Properties: - LogGroupName: !Sub '/ecs/${TaskName}' - RetentionInDays: 30 - FailedStartLogGroup: - Type: 'AWS::Logs::LogGroup' - Properties: - LogGroupName: !Sub '/aws/events/${TaskName}-start-failures' - RepoValidationFailureLogGroup: - Type: 'AWS::Logs::LogGroup' - Properties: - LogGroupName: '/aws/events/tuf-repo-validation-failures' - TUFRepoCanarySNSNotificationTopic: - Type: 'AWS::SNS::Topic' - Properties: - DisplayName: TUF Repo Canary Notifications - TUFRepoCanarySNSSubscription: - Type: 'AWS::SNS::Subscription' - Properties: - Endpoint: !Sub '${SNSSubscriptionEndpoint}' - Protocol: !Sub '${SNSSubscriptionProtocol}' - TopicArn: !Ref TUFRepoCanarySNSNotificationTopic - TUFRepoCanaryImgRepo: - Type: 'AWS::ECR::Repository' - Properties: - RepositoryName: !Sub '${TaskName}' - ECSCluster: - Type: 'AWS::ECS::Cluster' - Properties: {} - TUFRepoCanaryTask: - Type: 'AWS::ECS::TaskDefinition' - Properties: - TaskRoleArn: !GetAtt TUFRepoCanaryTaskExecutionRole.Arn - ExecutionRoleArn: !GetAtt TUFRepoCanaryTaskExecutionRole.Arn - Family: !Sub '${TaskName}' - NetworkMode: awsvpc - Cpu: '256' - Memory: '512' - RequiresCompatibilities: - - FARGATE - ContainerDefinitions: - - Memory: 512 - Cpu: 256 - Image: !Join - - / - - - !Join - - . - - - !Ref 'AWS::AccountId' - - dkr.ecr - - !Ref 'AWS::Region' - - amazonaws.com - - !Sub '${TaskName}:latest' - Name: !Sub '${TaskName}' - LogConfiguration: - LogDriver: awslogs - Options: - awslogs-group: !Ref LogGroup - awslogs-region: !Ref 'AWS::Region' - awslogs-stream-prefix: 'ecs' - TUFRepoCanaryTaskExecutionRole: - Type: 'AWS::IAM::Role' - Properties: - RoleName: TUFRepoCanaryTaskExecutionRole - AssumeRolePolicyDocument: - Statement: - - Effect: Allow - Principal: - Service: ecs-tasks.amazonaws.com - Action: - - 'sts:AssumeRole' - Policies: - - PolicyName: AmazonECSTaskExecutionPolicy - PolicyDocument: - Statement: - - Effect: Allow - Action: - - 'ecr:GetAuthorizationToken' - - 'ecr:BatchCheckLayerAvailability' - - 'ecr:GetDownloadUrlForLayer' - - 'ecr:BatchGetImage' - - 'logs:CreateLogStream' - - 'logs:PutLogEvents' - - 'logs:DescribeLogStreams' - - 'logs:GetLogEvents' - - 'cloudwatch:PutMetricData' - Resource: '*' - TUFRepoCanaryTaskEventRole: - Type: 'AWS::IAM::Role' - Properties: - RoleName: TUFRepoCanaryTaskEventRole - AssumeRolePolicyDocument: - Statement: - - Effect: Allow - Principal: - Service: events.amazonaws.com - Action: - - 'sts:AssumeRole' - Policies: - - PolicyName: AmazonEC2ContainerServiceEventsRole - PolicyDocument: - Statement: - - Effect: Allow - Action: - - 'ecs:RunTask' - - 'iam:PassRole' - Resource: '*' - TUFRepoCanaryFailedInvocationAlarm: - Type: 'AWS::CloudWatch::Alarm' - Properties: - AlarmName: TUF Repo Canary Invocation Failure - AlarmDescription: 'TUF Repo Canary task could not be invoked' - Namespace: AWS/Events - MetricName: FailedInvocations - Dimensions: - - Name: RuleName - Value: !Ref TUFRepoCanaryScheduledTask - Period: 600 - Statistic: Average - Threshold: 0 - TreatMissingData: notBreaching - ComparisonOperator: GreaterThanThreshold - EvaluationPeriods: 4 - DatapointsToAlarm: 3 - ActionsEnabled: true - AlarmActions: - - !Ref TUFRepoCanarySNSNotificationTopic - TUFRepoCanaryScheduledTask: - Type: 'AWS::Events::Rule' - Properties: - Description: !Sub 'Schedules ${TaskName} task to run every 10 minutes' - ScheduleExpression: cron(0/10 * * * ? *) - State: ENABLED - Targets: - - Id: !Sub '${TaskName}-Fargate-Task' - RoleArn: !GetAtt TUFRepoCanaryTaskEventRole.Arn - EcsParameters: - TaskDefinitionArn: !Ref TUFRepoCanaryTask - TaskCount: 1 - LaunchType: FARGATE - PlatformVersion: LATEST - NetworkConfiguration: - AwsVpcConfiguration: - AssignPublicIp: ENABLED - SecurityGroups: - - !Ref VPCSecurityGroup - Subnets: - - !Ref VPCSubnet - Arn: !GetAtt ECSCluster.Arn - TUFRepoCanaryFailedAlarm: - Type: 'AWS::CloudWatch::Alarm' - Properties: - AlarmName: TUF Repo Validation Failure - AlarmDescription: 'TUF Repo Canary task exited non-zero (indicating TUF Repo validation failure)' - Namespace: AWS/Events - MetricName: TriggeredRules - Dimensions: - - Name: RuleName - Value: !Ref TUFRepoCanaryFailedRule - Period: 600 - Statistic: Average - Threshold: 0 - TreatMissingData: notBreaching - ComparisonOperator: GreaterThanThreshold - EvaluationPeriods: 4 - DatapointsToAlarm: 3 - ActionsEnabled: true - AlarmActions: - - !Ref TUFRepoCanarySNSNotificationTopic - TUFRepoCanaryFailedRule: - Type: 'AWS::Events::Rule' - Properties: - Description: 'TUF repository validation failure' - Name: 'repo-canary-nonzero-exit-code' - EventPattern: !Sub '{"source": ["aws.ecs"],"detail-type": ["ECS Task State Change"],"detail": {"containers": {"name": ["${TaskName}"],"exitCode":[1,64,65,66,67,68,69,70,71,72,73],"lastStatus": ["STOPPED"]}}}' - Targets: - - Arn: !Join - - ":" - - - "arn:aws:logs" - - !Ref 'AWS::Region' - - !Ref 'AWS::AccountId' - - 'log-group' - - !Ref RepoValidationFailureLogGroup - Id: 'tuf-repo-validation-failure' - TUFRepoCanaryFailedStartAlarm: - Type: 'AWS::CloudWatch::Alarm' - Properties: - AlarmName: TUF Repo Canary Task Start Failure - AlarmDescription: 'TUF Repo Canary task failed to start' - Namespace: AWS/Events - MetricName: TriggeredRules - Dimensions: - - Name: RuleName - Value: !Ref TUFRepoCanaryFailedStartRule - Period: 600 - Statistic: Average - Threshold: 0 - TreatMissingData: notBreaching - ComparisonOperator: GreaterThanThreshold - EvaluationPeriods: 4 - DatapointsToAlarm: 3 - ActionsEnabled: true - AlarmActions: - - !Ref TUFRepoCanarySNSNotificationTopic - TUFRepoCanaryFailedStartRule: - Type: 'AWS::Events::Rule' - Properties: - Description: 'TUF Repo Canary fail to start' - Name: 'repo-canary-failed-to-start' - EventPattern: !Sub '{"source": ["aws.ecs"],"detail-type": ["ECS Task State Change"],"detail": {"containers": {"name": ["${TaskName}"],"lastStatus": ["STOPPED"]},"stoppedReason":["Task failed to start"]}}' - Targets: - - Arn: !Join - - ":" - - - "arn:aws:logs" - - !Ref 'AWS::Region' - - !Ref 'AWS::AccountId' - - 'log-group' - - !Ref FailedStartLogGroup - Id: !Sub '${TaskName}-failed-start'