From 405849ca6f03bc098d8203f929ed3bf46a45370d Mon Sep 17 00:00:00 2001 From: Eli Schleifer <1265982+EliSchleifer@users.noreply.github.com> Date: Thu, 29 Aug 2024 18:11:23 -0700 Subject: [PATCH] Add [neveredit] rule to protect write once files from modification (#43) Hackathon project - to add new rule to protect files that should not get edited. other things: By guidance since we build an executable cargo.lock should be checked in. so i checked that in. --- .config/toolbox.toml | 8 +- .gitignore | 4 - .trunk/trunk.yaml | 30 +- Cargo.lock | 1437 ++++++++++++++++++++++++++++ Cargo.toml | 2 + README.md | 26 +- src/config.rs | 11 + src/diagnostic.rs | 4 +- src/git.rs | 44 +- src/main.rs | 63 +- src/rules/if_change_then_change.rs | 15 +- src/rules/mod.rs | 1 + src/rules/never_edit.rs | 134 +++ src/rules/pls_no_land.rs | 12 +- tests/integration_testing.rs | 29 +- tests/never_edit_test.rs | 114 +++ 16 files changed, 1857 insertions(+), 77 deletions(-) create mode 100644 Cargo.lock create mode 100644 src/rules/never_edit.rs create mode 100644 tests/never_edit_test.rs diff --git a/.config/toolbox.toml b/.config/toolbox.toml index a330627..f32ad26 100644 --- a/.config/toolbox.toml +++ b/.config/toolbox.toml @@ -1,10 +1,14 @@ # Configuration for trunk toolbox. Generate default by calling 'trunk-toolbox genconfig' [ifchange] -enabled = true +enabled = false [donotland] -enabled = true +enabled = false [todo] +enabled = false + +[neveredit] enabled = true +paths = [] # paths to protect from modification diff --git a/.gitignore b/.gitignore index 088ba6b..f2e972d 100644 --- a/.gitignore +++ b/.gitignore @@ -2,9 +2,5 @@ # will have compiled files and executables /target/ -# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries -# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html -Cargo.lock - # These are backup files generated by rustfmt **/*.rs.bk diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml index 96f93a8..c7aa315 100644 --- a/.trunk/trunk.yaml +++ b/.trunk/trunk.yaml @@ -2,7 +2,7 @@ version: 0.1 plugins: sources: - id: trunk - ref: v1.4.3 + ref: v1.6.2 uri: https://github.com/trunk-io/plugins runtimes: enabled: @@ -11,13 +11,13 @@ runtimes: - node@18.12.1 - rust@1.76.0 cli: - version: 1.20.1 + version: 1.22.3 api: address: api.trunk-staging.io:8443 tools: enabled: - - gh@2.44.1 + - gh@2.55.0 runtimes: - rust lint: @@ -32,7 +32,7 @@ lint: batch: true success_codes: [0] read_output_from: tmp_file - disable_upstream: true + disable_upstream: false version_command: parse_regex: ${semver} run: trunk-toolbox --version @@ -45,21 +45,21 @@ lint: - tests/** enabled: - - shellcheck@0.9.0 + - shellcheck@0.10.0 - shfmt@3.6.0 - - trunk-toolbox@0.2.0 - - checkov@3.2.26 - - trivy@0.49.1 - - trufflehog@3.68.2 - - oxipng@9.0.0 + - trunk-toolbox@0.3.2 + - checkov@3.2.238 + - trivy@0.54.1 + - trufflehog@3.81.9 + - oxipng@9.1.2 - yamllint@1.35.1 - git-diff-check - - taplo@0.8.1 - - actionlint@1.6.27 + - taplo@0.9.3 + - actionlint@1.7.1 - clippy@1.76.0 - - gitleaks@8.18.2 - - markdownlint@0.39.0 - - prettier@3.2.5 + - gitleaks@8.18.4 + - markdownlint@0.41.0 + - prettier@3.3.3 - rustfmt@1.76.0 actions: enabled: diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..21aeb66 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,1437 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" +dependencies = [ + "lazy_static", + "regex", +] + +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + +[[package]] +name = "anstream" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" + +[[package]] +name = "anstyle-parse" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +dependencies = [ + "anstyle", + "windows-sys", +] + +[[package]] +name = "anyhow" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" + +[[package]] +name = "assert_cmd" +version = "2.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00ad3f3a942eee60335ab4342358c161ee296829e0d16ff42fc1d6cb07815467" +dependencies = [ + "anstyle", + "bstr", + "doc-comment", + "predicates 3.1.0", + "predicates-core", + "predicates-tree", + "wait-timeout", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bstr" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c48f0051a4b4c5e0b6d365cd04af53aeaa209e3cc15ec2cdb69e73cc87fbd0dc" +dependencies = [ + "memchr", + "regex-automata", + "serde", +] + +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "jobserver", + "libc", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "4.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80c21025abd42669a92efc996ef13cfb2c5c627858421ea58d5c3b331a6c134f" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "458bf1f341769dfcf849846f65dffdf9146daa56bcd2a47cb4e1de9915567c99" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim 0.11.0", +] + +[[package]] +name = "clap_derive" +version = "4.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "clap_lex" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + +[[package]] +name = "confique" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c37945ed2efccb10339a12eea282a5af9ebac77720d088723b2bbbdc44eca964" +dependencies = [ + "confique-macro", + "json5", + "serde", + "serde_yaml", + "toml", +] + +[[package]] +name = "confique-macro" +version = "0.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3821efdaaab3c5297054a90201cc3afa2061fc6ba2bc5d2fa558b850a7dabefe" +dependencies = [ + "heck 0.3.3", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "content_inspector" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7bda66e858c683005a53a9a60c69a4aca7eeaa45d124526e389f7aec8e62f38" +dependencies = [ + "memchr", +] + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "darling" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.10.0", + "syn 1.0.109", +] + +[[package]] +name = "darling_macro" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" +dependencies = [ + "darling_core", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_builder" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d67778784b508018359cbc8696edb3db78160bab2c2a28ba7f56ef6932997f8" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c11bdc11a0c47bc7d37d582b5285da6849c96681023680b906673c5707af7b0f" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_builder_macro" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebcda35c7a396850a55ffeac740804b40ffec779b98fffbb1738f4033f0ee79e" +dependencies = [ + "derive_builder_core", + "syn 1.0.109", +] + +[[package]] +name = "difflib" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "doc-comment" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" + +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + +[[package]] +name = "env_logger" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + +[[package]] +name = "float-cmp" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" +dependencies = [ + "num-traits", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + +[[package]] +name = "function_name" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef632c665dc6e2b99ffa4d913f7160bd902c4d3e4cb732d81dc3d221f848512" +dependencies = [ + "function_name-proc-macro", +] + +[[package]] +name = "function_name-proc-macro" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "569d2238870f92cff64fc810013b61edaf446ebcfba36b649b96bc5b4078328a" +dependencies = [ + "proc-macro-crate", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "git2" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2994bee4a3a6a51eb90c218523be382fd7ea09b16380b9312e9dbe955ff7c7d1" +dependencies = [ + "bitflags 1.3.2", + "libc", + "libgit2-sys", + "log", + "url", +] + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "glob-match" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985c9503b412198aa4197559e9a318524ebc4519c229bfa05a535828c950b9d" + +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" + +[[package]] +name = "jobserver" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6" +dependencies = [ + "libc", +] + +[[package]] +name = "json5" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96b0db21af676c1ce64250b5f40f3ce2cf27e4e47cb91ed91eb6fe9350b430c1" +dependencies = [ + "pest", + "pest_derive", + "serde", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + +[[package]] +name = "libgit2-sys" +version = "0.14.2+1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f3d95f6b51075fe9810a7ae22c7095f12b98005ab364d8544797a825ce946a4" +dependencies = [ + "cc", + "libc", + "libz-sys", + "pkg-config", +] + +[[package]] +name = "libz-sys" +version = "1.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037731f5d3aaa87a5675e895b63ddff1a87624bc29f77004ea829809654e48f6" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "memchr" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" + +[[package]] +name = "normalize-line-endings" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" + +[[package]] +name = "num" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e63899ad0da84ce718c14936262a41cee2c79c981fc0a0e7c7beb47d5a07e8c1" +dependencies = [ + "num-integer", + "num-traits", + "rand", + "rustc-serialize", +] + +[[package]] +name = "num-complex" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b288631d7878aaf59442cffd36910ea604ecd7745c36054328595114001c9656" +dependencies = [ + "num-traits", + "rustc-serialize", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d869c01cc0c455284163fd0092f1f93835385ccab5a98a0dcc497b2f8bf055a9" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee314c74bd753fc86b4780aa9475da469155f3848473a261d2d18e35245a784e" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", + "rustc-serialize", +] + +[[package]] +name = "num-traits" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pest" +version = "2.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219c0dcc30b6a27553f9cc242972b67f75b60eb0db71f0b5462f38b058c41546" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e1288dbd7786462961e69bfd4df7848c1e37e8b74303dbdab82c3a9cdd2809" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1381c29a877c6d34b8c176e734f35d7f7f5b3adaefe940cb4d1bb7af94678e2e" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "pest_meta" +version = "2.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0934d6907f148c22a3acbda520c7eed243ad7487a30f51f6ce52b58b7077a8a" +dependencies = [ + "once_cell", + "pest", + "sha2", +] + +[[package]] +name = "pkg-config" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb" + +[[package]] +name = "predicates" +version = "2.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59230a63c37f3e18569bdb90e4a89cbf5bf8b06fea0b84e65ea10cc4df47addd" +dependencies = [ + "difflib", + "float-cmp", + "itertools", + "normalize-line-endings", + "predicates-core", + "regex", +] + +[[package]] +name = "predicates" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68b87bfd4605926cdfefc1c3b5f8fe560e3feca9d5552cf68c466d3d8236c7e8" +dependencies = [ + "anstyle", + "difflib", + "predicates-core", +] + +[[package]] +name = "predicates-core" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174" + +[[package]] +name = "predicates-tree" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368ba315fb8c5052ab692e68a0eefec6ec57b23a36959c14496f0b0df2c0cecf" +dependencies = [ + "predicates-core", + "termtree", +] + +[[package]] +name = "prettyplease" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" +dependencies = [ + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "proc-macro-crate" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" +dependencies = [ + "toml", +] + +[[package]] +name = "proc-macro2" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +dependencies = [ + "fuchsia-cprng", + "libc", + "rand_core 0.3.1", + "rdrand", + "winapi", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + +[[package]] +name = "rayon" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7237101a77a10773db45d62004a272517633fbcc3df19d96455ede1122e051" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "regex" +version = "1.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + +[[package]] +name = "rustc-serialize" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe834bc780604f4674073badbad26d7219cadfb4a2275802db12cbae17498401" + +[[package]] +name = "rustix" +version = "0.38.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" +dependencies = [ + "bitflags 2.4.2", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "rustversion" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + +[[package]] +name = "ryu" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" + +[[package]] +name = "schemafy_core" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bec29dddcfe60f92f3c0d422707b8b56473983ef0481df8d5236ed3ab8fdf24" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "schemafy_lib" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af3d87f1df246a9b7e2bfd1f4ee5f88e48b11ef9cfc62e63f0dead255b1a6f5f" +dependencies = [ + "Inflector", + "proc-macro2", + "quote", + "schemafy_core", + "serde", + "serde_derive", + "serde_json", + "syn 1.0.109", + "uriparse", +] + +[[package]] +name = "serde" +version = "1.0.196" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-sarif" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51eda7853590f74ef6f8b9d868f20679f2072b4b86c8970d5ce320b42d457198" +dependencies = [ + "anyhow", + "derive_builder", + "prettyplease", + "proc-macro2", + "quote", + "schemafy_lib", + "serde", + "serde_json", + "strum", + "strum_macros", + "syn 1.0.109", + "thiserror", +] + +[[package]] +name = "serde_derive" +version = "1.0.196" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "serde_json" +version = "1.0.113" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69801b70b1c3dac963ecb03a364ba0ceda9cf60c71cfe475e99864759c8b8a79" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_yaml" +version = "0.9.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adf8a49373e98a4c5f0ceb5d05aa7c648d75f63774981ed95b7c7443bbd50c6e" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "spectral" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae3c15181f4b14e52eeaac3efaeec4d2764716ce9c86da0c934c3e318649c5ba" +dependencies = [ + "num", +] + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "strsim" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" + +[[package]] +name = "strum" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" + +[[package]] +name = "strum_macros" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "rustversion", + "syn 1.0.109", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a365e8cd18e44762ef95d87f284f4b5cd04107fec2ff3052bd6a3e6069669e67" +dependencies = [ + "cfg-if", + "fastrand", + "rustix", + "windows-sys", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "termtree" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" + +[[package]] +name = "thiserror" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + +[[package]] +name = "trunk-toolbox" +version = "0.0.0" +dependencies = [ + "anyhow", + "assert_cmd", + "clap", + "confique", + "content_inspector", + "env_logger", + "function_name", + "git2", + "glob", + "glob-match", + "lazy_static", + "log", + "predicates 2.1.5", + "rayon", + "regex", + "serde", + "serde-sarif", + "serde_json", + "spectral", + "tempfile", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "ucd-trie" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" + +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-segmentation" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" + +[[package]] +name = "unsafe-libyaml" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab4c90930b95a82d00dc9e9ac071b4991924390d46cbd0dfe566148667605e4b" + +[[package]] +name = "uriparse" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0200d0fc04d809396c2ad43f3c95da3582a2556eba8d453c1087f4120ee352ff" +dependencies = [ + "fnv", + "lazy_static", +] + +[[package]] +name = "url" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wait-timeout" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +dependencies = [ + "libc", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" diff --git a/Cargo.toml b/Cargo.toml index a4ebd9c..dda2c14 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,8 @@ serde-sarif = "0.3.4" content_inspector = "0.2.4" rayon = "1.5.1" confique = "0.2.5" +glob = "0.3.1" +glob-match = "0.2.1" [dev-dependencies] assert_cmd = "2.0" diff --git a/README.md b/README.md index ed8f078..14eb502 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ Keeps you from accidentally commiting code to a repository that is experimental, Valid triggers for this rule are: DONOTLAND, DO-NOT-LAND, DO_NOT_LAND, donotland, do-not-land, do_not_land -##### Why if this bad? +##### Why is this bad? Anything you intentionally don't want in your repo should really not be there. This lets you flag the code you are writing to do testing without worrying that you'll forget you dropped it in your files before pushing your Pull Request. @@ -76,7 +76,7 @@ By default, this rule is disabled and must be enabled with: enabled = true ``` -##### Why if this bad? +##### Why is this bad? TODOs should be treated like any other lint issue. Sometimes you need to land code that still has these issues, but you want to keep track of them and avoid them when possible. @@ -93,7 +93,7 @@ uploadResultsSync(); Allows you to enforce code synchronization. Often, we have code in one file that is reliant on code in another loosely - say an enum has 4 options and you want to make sure consumers of that enum are kept in sync as new enums are added. This rule will make sure the code is updated in both places when a modification occurs to the code block. -##### Why if this bad? +##### Why is this bad? If code has baked-in assumptions that are not enforced through a check - then they can easily get out of sync. This rule allows you to encode that dependency and ensure all related code is updated when a modification occurs. @@ -114,6 +114,26 @@ enum Flavor { x += 9; // why not ``` +#### never-edit + +##### What it does + +Allows you to enforce code does not get modified once checked into the repo. + +##### Why is this bad? + +If code is immutable - like database migration scripts - you want to ensure that no one edits those files +once they are checked in. This rule allows you to create restricted lists of files that cannot be edited +once added to the repo. + +##### Example + +This rule will report a violation if src/write_once.txt is modified or deleted in git given this config in toolbox.toml + +[neveredit] +enabled = true +paths = ["**/write_once*"] + ### Disclaimer We know, we know...toolbox? That's only one step above 'UTILS', but a toolbox is a real thing, you can buy one in a store and put all kind of interesting things inside of them that make doing work a lot easier. Have you ever tried to change a wall socket without a screwdriver? We have...and it's not fun. diff --git a/src/config.rs b/src/config.rs index 4969053..01c78e6 100644 --- a/src/config.rs +++ b/src/config.rs @@ -12,6 +12,9 @@ pub struct Conf { #[config(nested)] pub todo: TodoConf, + + #[config(nested)] + pub neveredit: NeverEditConf, } impl Conf { @@ -38,3 +41,11 @@ pub struct TodoConf { #[config(default = false)] pub enabled: bool, } + +#[derive(Config)] +pub struct NeverEditConf { + #[config(default = false)] + pub enabled: bool, + #[config(default = [])] + pub paths: Vec, +} diff --git a/src/diagnostic.rs b/src/diagnostic.rs index 12fe256..f74da44 100644 --- a/src/diagnostic.rs +++ b/src/diagnostic.rs @@ -28,14 +28,14 @@ pub struct Position { #[derive(Serialize)] pub struct Range { - pub path: String, pub start: Position, pub end: Position, } #[derive(Serialize)] pub struct Diagnostic { - pub range: Range, + pub path: String, + pub range: Option, pub severity: Severity, pub code: String, pub message: String, diff --git a/src/git.rs b/src/git.rs index d88e8c1..47a3205 100644 --- a/src/git.rs +++ b/src/git.rs @@ -1,5 +1,5 @@ use git2::{AttrCheckFlags, AttrValue, Delta, DiffOptions, Repository}; -use std::collections::HashSet; +use std::collections::HashMap; use std::path::{Path, PathBuf}; #[derive(Debug, Clone)] @@ -13,13 +13,20 @@ pub struct Hunk { pub end: u64, } +#[derive(Debug, PartialEq, Eq, Hash)] +pub enum FileStatus { + Added, + Modified, + Deleted, +} + #[derive(Debug, Default)] -pub struct NewOrModified { +pub struct FileChanges { /// Set of modified line ranges in new/existing files pub hunks: Vec, - /// Set of new/modified files - pub paths: HashSet, + /// Map of changed files and FileStatus + pub paths: HashMap, } fn is_lfs(repo: &Repository, path: &Path) -> bool { @@ -34,7 +41,7 @@ fn is_lfs(repo: &Repository, path: &Path) -> bool { } } -pub fn modified_since(upstream: &str, repo_path: Option<&Path>) -> anyhow::Result { +pub fn modified_since(upstream: &str, repo_path: Option<&Path>) -> anyhow::Result { let path = repo_path.unwrap_or(Path::new(".")); let repo = Repository::open(path)?; @@ -72,10 +79,31 @@ pub fn modified_since(upstream: &str, repo_path: Option<&Path>) -> anyhow::Resul // // See https://docs.rs/git2/latest/git2/struct.Diff.html#method.foreach and the underlying API // docs at https://libgit2.org/libgit2/#HEAD/group/diff/git_diff_foreach. - let mut ret = NewOrModified::default(); + let mut ret = FileChanges::default(); let mut maybe_current_hunk: Option = None; diff.foreach( - &mut |_, _| true, + &mut |delta, _| { + if let Some(path) = delta.new_file().path() { + if !is_lfs(&repo, path) { + match delta.status() { + Delta::Added => { + ret.paths + .insert(path.to_string_lossy().to_string(), FileStatus::Added); + } + Delta::Modified => { + ret.paths + .insert(path.to_string_lossy().to_string(), FileStatus::Modified); + } + Delta::Deleted => { + ret.paths + .insert(path.to_string_lossy().to_string(), FileStatus::Deleted); + } + _ => {} + } + } + } + true + }, None, None, Some(&mut |delta, _, line| { @@ -104,7 +132,6 @@ pub fn modified_since(upstream: &str, repo_path: Option<&Path>) -> anyhow::Resul }) }); } else if let Some(current_hunk) = &maybe_current_hunk { - ret.paths.insert(current_hunk.path.clone()); ret.hunks.push(current_hunk.clone()); maybe_current_hunk = None; } @@ -124,7 +151,6 @@ pub fn modified_since(upstream: &str, repo_path: Option<&Path>) -> anyhow::Resul )?; if let Some(current_hunk) = &maybe_current_hunk { - ret.paths.insert(current_hunk.path.clone()); ret.hunks.push(current_hunk.clone()); } diff --git a/src/main.rs b/src/main.rs index ca7aa90..67bef3a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,7 @@ use confique::Config; use horton::config::Conf; use horton::diagnostic; use horton::rules::if_change_then_change::ictc; +use horton::rules::never_edit::never_edit; use horton::rules::pls_no_land::pls_no_land; use horton::run::{Cli, OutputFormat, Run, Subcommands}; @@ -15,10 +16,14 @@ fn generate_line_string(original_results: &diagnostic::Diagnostics) -> String { .diagnostics .iter() .map(|d| { - format!( - "{}:{}:{}: {} ({})", - d.range.path, d.range.start.line, d.range.start.character, d.message, d.severity - ) + if let Some(range) = &d.range { + format!( + "{}:{}:{}: {} ({})", + d.path, range.start.line, range.start.character, d.message, d.severity + ) + } else { + format!("{}: {} ({})", d.path, d.message, d.severity) + } }) .collect::>() .join("\n"); @@ -34,29 +39,29 @@ fn generate_sarif_string( .diagnostics .iter() .map(|d| { + let mut physical_location = sarif::PhysicalLocationBuilder::default(); + physical_location.artifact_location( + sarif::ArtifactLocationBuilder::default() + .uri(d.path.clone()) + .build() + .unwrap(), + ); + + if let Some(range) = &d.range { + physical_location.region( + sarif::RegionBuilder::default() + .start_line(range.start.line as i64 + 1) + .start_column(range.start.character as i64 + 1) + .end_line(range.end.line as i64 + 1) + .end_column(range.end.character as i64 + 1) + .build() + .unwrap(), + ); + } sarif::ResultBuilder::default() .level(d.severity.to_string()) .locations([sarif::LocationBuilder::default() - .physical_location( - sarif::PhysicalLocationBuilder::default() - .artifact_location( - sarif::ArtifactLocationBuilder::default() - .uri(d.range.path.clone()) - .build() - .unwrap(), - ) - .region( - sarif::RegionBuilder::default() - .start_line(d.range.start.line as i64 + 1) - .start_column(d.range.start.character as i64 + 1) - .end_line(d.range.end.line as i64 + 1) - .end_column(d.range.end.character as i64 + 1) - .build() - .unwrap(), - ) - .build() - .unwrap(), - ) + .physical_location(physical_location.build().unwrap()) .build() .unwrap()]) .message( @@ -77,7 +82,7 @@ fn generate_sarif_string( .text(format!( "{:?} files processed in {:?}", run_context.paths.len(), - start_time.elapsed() + start_time.elapsed(), )) .build() .unwrap(), @@ -153,6 +158,14 @@ fn run() -> anyhow::Result<()> { Err(e) => return Err(e), } + //TODO: refactor this to use a threadpool for all the rules. using rayon::join() won't scale + //beyond two things + let ne_result = never_edit(&run, &cli.upstream); + match ne_result { + Ok(result) => ret.diagnostics.extend(result), + Err(e) => return Err(e), + } + let mut output_string = generate_line_string(&ret); if cli.output_format == OutputFormat::Sarif { output_string = generate_sarif_string(&ret, &run, &start)?; diff --git a/src/rules/if_change_then_change.rs b/src/rules/if_change_then_change.rs index 2f5dca7..008217f 100644 --- a/src/rules/if_change_then_change.rs +++ b/src/rules/if_change_then_change.rs @@ -32,7 +32,6 @@ pub struct IctcBlock { impl IctcBlock { fn get_range(&self) -> diagnostic::Range { diagnostic::Range { - path: self.path.to_str().unwrap().to_string(), start: diagnostic::Position { line: self.begin.unwrap(), character: 0, @@ -138,7 +137,7 @@ pub fn ictc(run: &Run, upstream: &str) -> anyhow::Result anyhow::Result anyhow::Result anyhow::Result { diagnostics.push(diagnostic::Diagnostic { - range: block.get_range(), + path: block.path.to_str().unwrap().to_string(), + range: Some(block.get_range()), severity: diagnostic::Severity::Warning, code: "if-change-mismatched".to_string(), message: "Expected preceding IfChange tag".to_string(), @@ -220,7 +222,8 @@ pub fn ictc(run: &Run, upstream: &str) -> anyhow::Result { diagnostics.push(diagnostic::Diagnostic { - range: block.get_range(), + path: block.path.to_str().unwrap().to_string(), + range: Some(block.get_range()), severity: diagnostic::Severity::Warning, code: "if-change-mismatched".to_string(), message: "Expected matching ThenChange tag".to_string(), diff --git a/src/rules/mod.rs b/src/rules/mod.rs index a0163b0..5f87d8d 100644 --- a/src/rules/mod.rs +++ b/src/rules/mod.rs @@ -1,2 +1,3 @@ pub mod if_change_then_change; +pub mod never_edit; pub mod pls_no_land; diff --git a/src/rules/never_edit.rs b/src/rules/never_edit.rs new file mode 100644 index 0000000..b45f849 --- /dev/null +++ b/src/rules/never_edit.rs @@ -0,0 +1,134 @@ +use crate::config::NeverEditConf; +use crate::git::FileStatus; +use crate::run::Run; +use glob::glob; +use glob_match::glob_match; + +use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; + +use crate::diagnostic; +use crate::git; + +pub fn is_never_edit(file_path: &str, config: &NeverEditConf) -> bool { + for glob_path in &config.paths { + if glob_match(glob_path, file_path) { + log::info!("matched: {} with {}", glob_path, file_path); + return true; + } + } + false +} + +pub fn never_edit(run: &Run, upstream: &str) -> anyhow::Result> { + let config = &run.config.neveredit; + + if !config.enabled { + return Ok(vec![]); + } + + let mut diagnostics: Vec = Vec::new(); + + if config.paths.is_empty() { + diagnostics.push(diagnostic::Diagnostic { + path: "toolbox.toml".to_string(), + range: None, + severity: diagnostic::Severity::Warning, + code: "never-edit-config".to_string(), + message: "no protected paths provided in config".to_string(), + }); + return Ok(diagnostics); + } + + for glob_path in &config.paths { + let mut matches_something = false; + match glob(glob_path) { + Ok(paths) => { + for entry in paths { + match entry { + Ok(_path) => { + matches_something = true; + break; + } + Err(e) => println!("Error reading path: {:?}", e), + } + } + if !matches_something { + diagnostics.push(diagnostic::Diagnostic { + path: "toolbox.toml".to_string(), + range: None, + severity: diagnostic::Severity::Warning, + code: "never-edit-bad-config".to_string(), + message: format!("{:?} does not protect any existing files", glob_path), + }); + } + } + Err(_e) => { + diagnostics.push(diagnostic::Diagnostic { + path: "toolbox.toml".to_string(), + range: None, + severity: diagnostic::Severity::Warning, + code: "never-edit-bad-config".to_string(), + message: format!("{:?} is not a valid glob pattern", glob_path), + }); + } + } + } + + // Build up list of files that are being checked and are protected + let protected_files: Vec<_> = run + .paths + .par_iter() + .filter_map(|file| { + file.to_str().and_then(|file_str| { + if is_never_edit(file_str, config) { + Some(file_str.to_string()) + } else { + None + } + }) + }) + .collect(); + + // Fast exit if we don't have any files changed that are protected + if protected_files.is_empty() { + return Ok(diagnostics); + } + + let modified = git::modified_since(upstream, None)?; + + for protected_file in &protected_files { + if let Some(status) = modified.paths.get(protected_file) { + match status { + FileStatus::Modified => { + diagnostics.push(diagnostic::Diagnostic { + path: protected_file.clone(), + range: None, + severity: diagnostic::Severity::Error, + code: "never-edit-modified".to_string(), + message: "file is protected and should not be modified".to_string(), + }); + } + FileStatus::Deleted => { + diagnostics.push(diagnostic::Diagnostic { + path: protected_file.clone(), + range: None, + severity: diagnostic::Severity::Warning, + code: "never-edit-deleted".to_string(), + message: "file is protected and should not be deleted".to_string(), + }); + } + _ => {} + } + } + } + + diagnostics.push(diagnostic::Diagnostic { + path: "".to_string(), + range: None, + severity: diagnostic::Severity::Note, + code: "toolbox-perf".to_string(), + message: format!("{:?} protected files checked", protected_files.len()), + }); + + Ok(diagnostics) +} diff --git a/src/rules/pls_no_land.rs b/src/rules/pls_no_land.rs index db3fa64..44f9279 100644 --- a/src/rules/pls_no_land.rs +++ b/src/rules/pls_no_land.rs @@ -93,8 +93,8 @@ fn pls_no_land_impl(path: &PathBuf, config: &Conf) -> anyhow::Result anyhow::Result anyhow::Result anyhow::Result anyhow::Result<()> { Command::new("git") .arg("add") @@ -100,6 +116,7 @@ impl TestRepo { Ok(()) } + #[allow(dead_code)] pub fn git_commit_all(&self, message: &str) { self.git_add_all().expect("add worked"); @@ -118,6 +135,11 @@ impl TestRepo { self.run_horton_with("HEAD", "sarif") } + #[allow(dead_code)] + pub fn set_toolbox_toml(&self, config: &str) { + self.write(".config/toolbox.toml", config.as_bytes()); + } + pub fn run_horton_with( &self, upstream_ref: &str, @@ -127,17 +149,14 @@ impl TestRepo { let modified_paths = horton::git::modified_since(upstream_ref, Some(self.dir.path()))?.paths; - let strings: Result, _> = modified_paths - .into_iter() - .map(|path| path.into_os_string().into_string()) - .collect(); + let files: Vec = modified_paths.keys().map(|key| key.to_string()).collect(); cmd.env("RUST_LOG", "debug"); cmd.arg("--upstream") .arg(upstream_ref) .current_dir(self.dir.path()); cmd.arg("--output-format").arg(format); - for path in strings.unwrap() { + for path in files { cmd.arg(path); } diff --git a/tests/never_edit_test.rs b/tests/never_edit_test.rs new file mode 100644 index 0000000..16f2e11 --- /dev/null +++ b/tests/never_edit_test.rs @@ -0,0 +1,114 @@ +use spectral::prelude::*; + +mod integration_testing; +use integration_testing::TestRepo; + +#[test] +fn assert_modified_locked_file() -> anyhow::Result<()> { + let test_repo: TestRepo = TestRepo::make().unwrap(); + + test_repo.write("src/write_once.txt", "immutable text".as_bytes()); + test_repo.write("src/write_many.txt", "immutable text".as_bytes()); + test_repo.git_add_all()?; + test_repo.git_commit_all("create write once and write many file"); + + // enable and configure never_edit + let toml = r#" + [neveredit] + enabled = true + paths = ["src/foo", "src/bar/**", "**/write_once*"] +"#; + + // write to the protected file + test_repo.write("src/write_once.txt", "edit the text".as_bytes()); + test_repo.write("src/write_many.txt", "edit the text".as_bytes()); + + test_repo.set_toolbox_toml(toml); + + let horton = test_repo.run_horton()?; + + assert_that(&horton.exit_code).contains_value(0); + assert_that(&horton.stdout).contains("file is protected and should not be modified"); + assert_that(&horton.stdout.contains("src/write_many.txt")).is_false(); + + Ok(()) +} + +#[test] +fn assert_deleted_locked_file() -> anyhow::Result<()> { + let test_repo: TestRepo = TestRepo::make().unwrap(); + + test_repo.write("src/locked/file.txt", "immutable text".as_bytes()); + test_repo.write("src/editable.txt", "mutable text".as_bytes()); + test_repo.git_add_all()?; + test_repo.git_commit_all("create locked and editable files"); + + // enable and configure never_edit + let toml = r#" + [neveredit] + enabled = true + paths = ["src/locked/**"] +"#; + + // write to the protected file + test_repo.delete("src/locked/file.txt"); + + test_repo.set_toolbox_toml(toml); + + let horton = test_repo.run_horton()?; + + assert_that(&horton.exit_code).contains_value(0); + assert_that(&horton.stdout).contains("file is protected and should not be deleted"); + assert_that(&horton.stdout).contains("src/locked/file.txt"); + + Ok(()) +} + +#[test] +fn honor_disabled_in_config() -> anyhow::Result<()> { + let test_repo: TestRepo = TestRepo::make().unwrap(); + + test_repo.write("src/locked/file.txt", "immutable text".as_bytes()); + test_repo.git_add_all()?; + test_repo.git_commit_all("create locked and editable files"); + + // enable and configure never_edit + let toml = r#" + [neveredit] + enabled = false + paths = ["src/locked/**"] +"#; + + // write to the protected file + test_repo.delete("src/locked/file.txt"); + + test_repo.set_toolbox_toml(toml); + + let horton = test_repo.run_horton()?; + + assert_that(&horton.exit_code).contains_value(0); + assert_that(&horton.stdout.contains("src/locked/file.txt")).is_false(); + assert_that(&horton.stdout).contains("1 files processed"); + + Ok(()) +} + +#[test] +fn warn_for_config_not_protecting_anything() -> anyhow::Result<()> { + let test_repo: TestRepo = TestRepo::make().unwrap(); + + // enable and configure never_edit + let toml = r#" + [neveredit] + enabled = true + paths = ["bad_path/**"] +"#; + test_repo.set_toolbox_toml(toml); + + let horton: integration_testing::HortonOutput = test_repo.run_horton()?; + + assert_that(&horton.exit_code).contains_value(0); + assert_that(&horton.stdout).contains("does not protect any existing files"); + + Ok(()) +}