diff --git a/Cargo.lock b/Cargo.lock index 4a45d85c..f57173b2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -55,7 +55,7 @@ dependencies = [ "anyhow", "clap", "hipcheck-sdk", - "kdl", + "kdl 4.7.1", "log", "pathbuf", "schemars", @@ -1314,7 +1314,7 @@ dependencies = [ "gix-utils", "itoa", "thiserror 2.0.6", - "winnow 0.6.18", + "winnow 0.6.22", ] [[package]] @@ -1396,7 +1396,7 @@ dependencies = [ "smallvec", "thiserror 2.0.6", "unicode-bom", - "winnow 0.6.18", + "winnow 0.6.22", ] [[package]] @@ -1616,7 +1616,7 @@ dependencies = [ "itoa", "smallvec", "thiserror 2.0.6", - "winnow 0.6.18", + "winnow 0.6.22", ] [[package]] @@ -1728,7 +1728,7 @@ dependencies = [ "gix-validate", "memmap2", "thiserror 2.0.6", - "winnow 0.6.18", + "winnow 0.6.22", ] [[package]] @@ -2065,7 +2065,7 @@ dependencies = [ "indicatif", "itertools", "jiff", - "kdl", + "kdl 6.2.2", "log", "logos", "maplit", @@ -2642,11 +2642,23 @@ version = "4.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e03e2e96c5926fe761088d66c8c2aee3a4352a2573f4eaca50043ad130af9117" dependencies = [ - "miette", + "miette 5.10.0", "nom", "thiserror 1.0.69", ] +[[package]] +name = "kdl" +version = "6.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d63de1aa3d632a8dd61da7cddfc499e9f88e6265d85bd84002419c3cdd3dc8f" +dependencies = [ + "miette 7.4.0", + "num", + "thiserror 1.0.69", + "winnow 0.6.22", +] + [[package]] name = "kstring" version = "2.0.2" @@ -2864,12 +2876,24 @@ version = "5.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59bb584eaeeab6bd0226ccf3509a69d7936d148cf3d036ad350abe35e8c6856e" dependencies = [ - "miette-derive", + "miette-derive 5.10.0", "once_cell", "thiserror 1.0.69", "unicode-width 0.1.11", ] +[[package]] +name = "miette" +version = "7.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "317f146e2eb7021892722af37cf1b971f0a70c8406f487e24952667616192c64" +dependencies = [ + "cfg-if", + "miette-derive 7.4.0", + "thiserror 1.0.69", + "unicode-width 0.1.11", +] + [[package]] name = "miette-derive" version = "5.10.0" @@ -2881,6 +2905,17 @@ dependencies = [ "syn 2.0.95", ] +[[package]] +name = "miette-derive" +version = "7.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23c9b935fbe1d6cbd1dac857b54a688145e2d93f48db36010514d0f612d0ad67" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.95", +] + [[package]] name = "mime" version = "0.3.17" @@ -2967,12 +3002,76 @@ dependencies = [ "winapi", ] +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + [[package]] name = "num-conv" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +[[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.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -4404,7 +4503,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.18", + "winnow 0.6.22", ] [[package]] @@ -5061,9 +5160,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.6.18" +version = "0.6.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" +checksum = "39281189af81c07ec09db316b302a3e67bf9bd7cbf6c820b50e35fee9c2fa980" dependencies = [ "memchr", ] @@ -5128,7 +5227,7 @@ dependencies = [ "convert_case", "env_logger", "glob", - "kdl", + "kdl 4.7.1", "log", "pathbuf", "regex", diff --git a/config/Hipcheck.kdl b/config/Hipcheck.kdl index c813c719..299aa49c 100644 --- a/config/Hipcheck.kdl +++ b/config/Hipcheck.kdl @@ -22,7 +22,7 @@ analyze { category "practices" { analysis "mitre/activity" policy="(lte $ P52w)" weight=3 analysis "mitre/binary" { - binary-file "./config/Binary.toml" + binary-file #rel("Binary.toml") binary-file-threshold 0 } analysis "mitre/fuzz" policy="(eq #t $)" @@ -31,23 +31,23 @@ analyze { category "attacks" { analysis "mitre/typo" { - typo-file "./config/Typos.toml" + typo-file #rel("Typos.toml") count-threshold 0 } category "commit" { analysis "mitre/affiliation" { - orgs-file "./plugins/affiliation/test/example_orgs.kdl" + orgs-file #rel("Orgs.kdl") count-threshold 0 } analysis "mitre/entropy" policy="(eq 0 (count (filter (gt 8.0) $)))" { - langs-file "./config/Langs.toml" + langs-file #rel("Langs.toml") entropy-threshold 10.0 commit-percentage 0.0 } analysis "mitre/churn" policy="(lte (divz (count (filter (gt 3) $)) (count $)) 0.02)" { - langs-file "./config/Langs.toml" + langs-file #rel("Langs.toml") } } } diff --git a/config/Orgs.kdl b/config/Orgs.kdl new file mode 100644 index 00000000..38642626 --- /dev/null +++ b/config/Orgs.kdl @@ -0,0 +1,157 @@ +strategy "independent" + +orgs { + org "AT&T" country="United States" { + host "att.com" + } + org "Alibaba" country="China" { + host "alibaba.com" + } + org "Amazon" country="United States" { + host "amazon.com" + } + org "Blue Box Cloud" country="United States" { + host "blueboxcloud.com" + } + org "CERN" country="Switzerland" { + host "home.cern" + } + org "Cisco" country="United States" { + host "cisco.com" + } + org "Cloud Foundry" country="United States" { + host "cloudfoundry.org" + } + org "Code Think" country="United Kingdom" { + host "codethink.co.uk" + } + org "Comcast" country="United States" { + host "comcast.com" + } + org "CoreOS" country="United States" { + host "coreos.com" + } + org "Dell EMC" country="United States" { + host "dellemc.com" + host "emc.com" + } + org "DT Dream" country="China" { + host "dtdream.com" + } + org "Facebook" country="United States" { + host "facebook.com" + } + org "Fujitsu" country="Japan" { + host "fujitsu.com" + } + org "Google" country="United States" { + host "google.com" + } + org "HP" country="United States" { + host "hp.com" + host "hpe.com" + } + org "Heroku" country="United States" { + host "heroku.com" + } + org "Huawei" country="China" { + host "huawei.com" + } + org "IBM" country="United States" { + host "ibm.com" + } + org "Influx Data" country="United States" { + host "influxdata.com" + } + org "Intel" country="United States" { + host "intel.com" + } + org "MIT" country="United States" { + host "mit.edu" + } + org "MITRE" country="United States" { + host "mitre.org" + } + org "Microsoft" country="United States" { + host "microsoft.com" + } + org "NTT" country="Japan" { + host "ntt.com" + } + org "Oracle" country="United States" { + host "oracle.com" + } + org "Orange" country="France" { + host "orange.com" + } + org "Percona" country="United States" { + host "persona.com" + } + org "Pivotal" country="United States" { + host "pivotal.io" + host "pivotallabs.com" + } + org "Rackspace" country="United States" { + host "rackspace.com" + } + org "Rakuten" country="Japan" { + host "rakuten.com" + } + org "Red Hat" country="United States" { + host "redhat.com" + } + org "RightScale" country="United States" { + host "rightscale.com" + } + org "SAP" country="Germany" { + host "sap.com" + } + org "SINA" country="China" { + host "sina.com" + } + org "SUSE" country="Germany" { + host "suse.com" + } + org "SalesForce" country="United States" { + host "salesforce.com" + } + org "Stark & Wayne" country="United States" { + host "starkandwayne.com" + } + org "Stripe" country="United States" { + host "stripe.com" + } + org "Swisscom" country="Switzerland" { + host "swisscom.com" + } + org "Apache" country="United States" { + host "apache.org" + } + org "ThoughtWorks" country="United States" { + host "thoughtworks.com" + } + org "Undead Labs" country="United States" { + host "undeadlabs.com" + } + org "VMWare" country="United States" { + host "vmware.com" + } + org "Walmart" country="United States" { + host "walmart.com" + } + org "ZTE" country="China" { + host "zte.com.cn" + } + org "ZJI" country="China" { + host "zji.edu.cn" + } + org "NPM" country="United States" { + host "npmjs.com" + } + org "UK Digital Cabinet Office" country="United Kingdom" { + host "digital.cabinet-office.gov.uk" + } + org "RBC Royal Bank" country="Canada" { + host "rbcon.com" + } +} diff --git a/config/Orgs.toml b/config/Orgs.toml deleted file mode 100644 index b8c8a9d9..00000000 --- a/config/Orgs.toml +++ /dev/null @@ -1,289 +0,0 @@ -############################################################################### -# Orgs.toml -# -# This configuration file defines the set of organizations against which -# affiliation may be checked for committers and authors in a repository, -# and how that affiliation determination will be made (the "strategy"). -############################################################################### - - -#============================================================================== -# Strategy -# -# This section defines one of two forms of a strategy, either a single string -# representing the mode (which may be "independent", "affiliated", "all", or -# "none"), or a mode and a list of references (either "country:" -# or "org:"). Together, these define the list of organizations to be -# considered for matching, and whether to flag identities as concerning if -# if they're _affiliated_ with an org in the list ("affiliated" mode), or are -# _not affiliated_ with an org in the list ("independent" mode). -#============================================================================== - -# The strategy spec can be short, implicitly being affiliated with or -# independent from all the orgs in the file. -strategy = "independent" - -# The strategy spec would alternatively look like this. -# With this mode, you can more completely specify the orgs or countries -# to include in the list, and mark whether we're rejecting those affiliated -# with or independent from the selected org list. -# -# strategy_spec = { mode = "affiliated", list = ["country:United States", "org:MITRE"] } - - -#============================================================================== -# Orgs -# -# This section defines a list of organizations, including their name, primary -# affiliated country, and any email hosts known to be connected to them. -#============================================================================== - -[[orgs]] -name = "AT&T" -hosts = ["att.com"] -country = "United States" - -[[orgs]] -name = "Alibaba" -hosts = ["alibaba.com"] -country = "China" - -[[orgs]] -name = "Amazon" -hosts = ["amazon.com"] -country = "United States" - -[[orgs]] -name = "Blue Box Cloud" -hosts = ["blueboxcloud.com"] -country = "United States" - -[[orgs]] -name = "CERN" -hosts = ["home.cern"] -country = "Switzerland" - -[[orgs]] -name = "Cisco" -hosts = ["cisco.com"] -country = "United States" - -[[orgs]] -name = "Cloud Foundry" -hosts = ["cloudfoundry.org"] -country = "United States" - -[[orgs]] -name = "Code Think" -hosts = ["codethink.co.uk"] -country = "United Kingdom" - -[[orgs]] -name = "Comcast" -hosts = ["comcast.com"] -country = "United States" - -[[orgs]] -name = "CoreOS" -hosts = ["coreos.com"] -country = "United States" - -[[orgs]] -name = "Dell EMC" -hosts = ["dellemc.com", "emc.com"] -country = "United States" - -[[orgs]] -name = "DT Dream" -hosts = ["dtdream.com"] -country = "China" - -[[orgs]] -name = "Facebook" -hosts = ["facebook.com"] -country = "United States" - -[[orgs]] -name = "Fujitsu" -hosts = ["fujitsu.com"] -country = "Japan" - -[[orgs]] -name = "Google" -hosts = ["google.com"] -country = "United States" - -[[orgs]] -name = "HP" -hosts = ["hp.com", "hpe.com"] -country = "United States" - -[[orgs]] -name = "Heroku" -hosts = ["heroku.com"] -country = "United States" - -[[orgs]] -name = "Huawei" -hosts = ["huawei.com"] -country = "China" - -[[orgs]] -name = "IBM" -hosts = ["ibm.com"] -country = "United States" - -[[orgs]] -name = "Influx Data" -hosts = ["influxdata.com"] -country = "United States" - -[[orgs]] -name = "Intel" -hosts = ["intel.com"] -country = "United States" - -[[orgs]] -name = "MIT" -hosts = ["mit.edu"] -country = "United States" - -[[orgs]] -name = "MITRE" -hosts = ["mitre.org"] -country = "United States" - -[[orgs]] -name = "Microsoft" -hosts = ["microsoft.com"] -country = "United States" - -[[orgs]] -name = "NTT" -hosts = ["ntt.com"] -country = "Japan" - -[[orgs]] -name = "Oracle" -hosts = ["oracle.com"] -country = "United States" - -[[orgs]] -name = "Orange" -hosts = ["orange.com"] -country = "France" - -[[orgs]] -name = "Percona" -hosts = ["persona.com"] -country = "United States" - -[[orgs]] -name = "Pivotal" -hosts = ["pivotal.io", "pivotallabs.com"] -country = "United States" - -[[orgs]] -name = "Rackspace" -hosts = ["rackspace.com"] -country = "United States" - -[[orgs]] -name = "Rakuten" -hosts = ["rakuten.com"] -country = "Japan" - -[[orgs]] -name = "Red Hat" -hosts = ["redhat.com"] -country = "United States" - -[[orgs]] -name = "RightScale" -hosts = ["rightscale.com"] -country = "United States" - -[[orgs]] -name = "SAP" -hosts = ["sap.com"] -country = "Germany" - -[[orgs]] -name = "SINA" -hosts = ["sina.com"] -country = "China" - -[[orgs]] -name = "SUSE" -hosts = ["suse.com"] -country = "Germany" - -[[orgs]] -name = "SalesForce" -hosts = ["salesforce.com"] -country = "United States" - -[[orgs]] -name = "Stark & Wayne" -hosts = ["starkandwayne.com"] -country = "United States" - -[[orgs]] -name = "Stripe" -hosts = ["stripe.com"] -country = "United States" - -[[orgs]] -name = "Swisscom" -hosts = ["swisscom.com"] -country = "Switzerland" - -[[orgs]] -name = "Apache" -hosts = ["apache.org"] -country = "United States" - -[[orgs]] -name = "ThoughtWorks" -hosts = ["thoughtworks.com"] -country = "United States" - -[[orgs]] -name = "Undead Labs" -hosts = ["undeadlabs.com"] -country = "United States" - -[[orgs]] -name = "VMWare" -hosts = ["vmware.com"] -country = "United States" - -[[orgs]] -name = "Walmart" -hosts = ["walmart.com"] -country = "United States" - -[[orgs]] -name = "ZTE" -hosts = ["zte.com.cn"] -country = "China" - -[[orgs]] -name = "ZJI" -hosts = ["zji.edu.cn"] -country = "China" - -[[orgs]] -name = "NPM" -hosts = ["npmjs.com"] -country = "United States" - -[[orgs]] -name = "UK Digital Cabinet Office" -hosts = ["digital.cabinet-office.gov.uk"] -country = "United Kingdom" - -[[orgs]] -name = "RBC Royal Bank" -hosts = ["rbcon.com"] -country = "Canada" diff --git a/config/local.Hipcheck.kdl b/config/local.Hipcheck.kdl index 5362d115..a20e0445 100644 --- a/config/local.Hipcheck.kdl +++ b/config/local.Hipcheck.kdl @@ -22,7 +22,7 @@ analyze { category "practices" { analysis "mitre/activity" policy="(lte $ P52w)" weight=3 analysis "mitre/binary" { - binary-file "./config/Binary.toml" + binary-file #rel("Binary.toml") binary-file-threshold 0 } analysis "mitre/fuzz" policy="(eq #t $)" @@ -31,23 +31,23 @@ analyze { category "attacks" { analysis "mitre/typo" { - typo-file "./config/Typos.toml" + typo-file #rel("Typos.toml") count-threshold 0 } category "commit" { analysis "mitre/affiliation" { - orgs-file "./plugins/affiliation/test/example_orgs.kdl" + orgs-file #rel("Orgs.kdl") count-threshold 0 } analysis "mitre/entropy" policy="(eq 0 (count (filter (gt 8.0) $)))" { - langs-file "./config/Langs.toml" + langs-file #rel("Langs.toml") entropy-threshold 10.0 commit-percentage 0.0 } analysis "mitre/churn" policy="(lte (divz (count (filter (gt 3) $)) (count $)) 0.02)" { - langs-file "./config/Langs.toml" + langs-file #rel("Langs.toml") } } } diff --git a/hipcheck/Cargo.toml b/hipcheck/Cargo.toml index 5bfb0a06..cf0935ca 100644 --- a/hipcheck/Cargo.toml +++ b/hipcheck/Cargo.toml @@ -73,7 +73,7 @@ indextree = "4.7.3" indicatif = { version = "0.17.9", features = ["rayon"] } itertools = "0.13.0" jiff = "0.1.14" -kdl = "4.7.1" +kdl = "6.2.2" log = "0.4.22" logos = "0.15.0" maplit = "1.0.2" diff --git a/hipcheck/src/plugin/download_manifest.rs b/hipcheck/src/plugin/download_manifest.rs index aaa27c34..d45e5bde 100644 --- a/hipcheck/src/plugin/download_manifest.rs +++ b/hipcheck/src/plugin/download_manifest.rs @@ -78,10 +78,10 @@ impl ParseKdlNode for HashWithDigest { return None; } // Per RFD #0004, the hash algorithm is of type String - let specified_algorithm = node.get("alg")?.value().as_string()?; + let specified_algorithm = node.get("alg")?.as_string()?; let hash_algorithm = HashAlgorithm::try_from(specified_algorithm).ok()?; // Per RFD #0004, the digest is of type String - let digest = node.get("digest")?.value().as_string()?.to_string(); + let digest = node.get("digest")?.as_string()?.to_string(); Some(HashWithDigest::new(hash_algorithm, digest)) } } @@ -152,7 +152,7 @@ impl ParseKdlNode for Compress { return None; } // Per RFD #0004, the format is of type String - let specified_format = node.get("format")?.value().as_string()?; + let specified_format = node.get("format")?.as_string()?; let format = ArchiveFormat::try_from(specified_format).ok()?; Some(Compress { format }) } @@ -181,9 +181,9 @@ impl ParseKdlNode for Size { return None; } let specified_size = node.get("bytes")?; - let bytes = match specified_size.value() { + let bytes = match specified_size { // Negative size and a size of 0 do not make sense - KdlValue::Base10(bytes) => { + KdlValue::Integer(bytes) => { let bytes = *bytes; if bytes.is_positive() { bytes as u64 @@ -238,9 +238,9 @@ impl ParseKdlNode for DownloadManifestEntry { return None; } // Per RFD #0004, version is of type String - let version = PluginVersion(node.get("version")?.value().as_string()?.to_string()); + let version = PluginVersion(node.get("version")?.as_string()?.to_string()); // Per RFD #0004, arch is of type String - let arch = Arch::from_str(node.get("arch")?.value().as_string()?).ok()?; + let arch = Arch::from_str(node.get("arch")?.as_string()?).ok()?; // there should be one child for each plugin and it should contain the url, hash, compress // and size information diff --git a/hipcheck/src/plugin/plugin_manifest.rs b/hipcheck/src/plugin/plugin_manifest.rs index f15c9d5f..889aa811 100644 --- a/hipcheck/src/plugin/plugin_manifest.rs +++ b/hipcheck/src/plugin/plugin_manifest.rs @@ -85,7 +85,7 @@ impl ParseKdlNode for Entrypoints { let mut entrypoints = Entrypoints::new(); for entrypoint_spec in node.children()?.nodes() { // per RFD #0004, the value for "arch" is of type String - let arch = Arch::from_str(entrypoint_spec.get("arch")?.value().as_string()?).ok()?; + let arch = Arch::from_str(entrypoint_spec.get("arch")?.as_string()?).ok()?; // per RFD #0004, the actual entrypoint is the first positional arg after "arch" and is // of type String let entrypoint = entrypoint_spec @@ -148,10 +148,10 @@ impl ParseKdlNode for PluginDependency { None => return None, }; - let version = PluginVersion(node.get("version")?.value().as_string()?.to_string()); + let version = PluginVersion(node.get("version")?.as_string()?.to_string()); let manifest = match node.get("manifest") { Some(manifest) => { - let manifest_location = manifest.value().as_string()?; + let manifest_location = manifest.as_string()?; if let Ok(url) = url::Url::parse(manifest_location) { Some(ManifestLocation::Url(url)) } else { diff --git a/hipcheck/src/policy/macros.rs b/hipcheck/src/policy/macros.rs new file mode 100644 index 00000000..3aed011b --- /dev/null +++ b/hipcheck/src/policy/macros.rs @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: Apache-2.0 + +use crate::{hc_error, Result}; +use std::{path::Path, sync::LazyLock}; + +use pathbuf::pathbuf; + +use regex::Regex; + +static MACRO_REGEX: LazyLock = + LazyLock::new(|| Regex::new(r"#([a-z]{2,})(?:\(([^)]*)\)){0,1}").unwrap()); + +/// Expects a non-None opt_var of format `""`. Parses to a Path object and appends to parent +/// of the PolicyFile's path so that we can specify file paths as relative to the PolicyFile. +fn rel(opt_var: Option<&str>, file_path: &Path) -> Result { + let Some(var) = opt_var else { + return Err(hc_error!("#rel macro expects an argument")); + }; + + // Parse `" Result { + let mut s = s.to_owned(); + // @Note - continues working until all macros resolved. If a macro returns another + // macro continually, this will loop infinitely. + while let Some(caps) = MACRO_REGEX.captures(s.as_str()) { + let full = caps.get(0).unwrap(); // the full string + let macro_name = caps.get(1).unwrap(); // the name of the macro + let opt_parens = caps.get(2); // optional value in parentheses + + log::debug!("Handling macro: {}", macro_name.as_str()); + + // Call the right macro function given the `macro_name`, and get the string + // to replace `full` with. + let replace = match macro_name.as_str() { + "rel" => rel(opt_parens.map(|x| x.as_str()), file_path)?, + other => { + return Err(hc_error!("Unknown policy file macro name '{}'", other)); + } + }; + + // Replace the character range specified by `full`, thus removing the macro + s.replace_range(full.start()..full.end(), replace.as_str()); + } + + Ok(s.to_owned()) +} diff --git a/hipcheck/src/policy/mod.rs b/hipcheck/src/policy/mod.rs index cac8c14a..52d186dc 100644 --- a/hipcheck/src/policy/mod.rs +++ b/hipcheck/src/policy/mod.rs @@ -3,6 +3,7 @@ //! Data types and functions for parsing policy KDL files mod config_to_policy; +mod macros; pub mod policy_file; mod tests; @@ -58,7 +59,11 @@ impl PolicyFile { )); } file::exists(policy_path)?; - let policy = PolicyFile::from_str(&file::read_string(policy_path)?)?; + + let raw_data = file::read_string(policy_path)?; + let data = macros::preprocess_policy_file(raw_data.as_str(), policy_path)?; + + let policy = PolicyFile::from_str(&data)?; Ok(policy) } diff --git a/hipcheck/src/policy/policy_file.rs b/hipcheck/src/policy/policy_file.rs index 0335fb0c..284802ac 100644 --- a/hipcheck/src/policy/policy_file.rs +++ b/hipcheck/src/policy/policy_file.rs @@ -82,13 +82,13 @@ impl ParseKdlNode for PolicyPlugin { return None; } }; - let version = PluginVersion::new(node.get("version")?.value().as_string()?.to_string()); + let version = PluginVersion::new(node.get("version")?.as_string()?.to_string()); // The manifest is technically optional, as there should be a default Hipcheck plugin artifactory sometime in the future // But for now it is essentially mandatory, so a plugin without a manifest will return an error downstream let manifest = match node.get("manifest") { Some(entry) => { - let raw_url = entry.value().as_string()?; + let raw_url = entry.as_string()?; let path = pathbuf::pathbuf![raw_url]; if let Ok(url) = Url::parse(raw_url) { Some(ManifestLocation::Url(url)) @@ -163,13 +163,12 @@ fn try_to_serde_json(value: &kdl::KdlValue) -> Result { use kdl::KdlValue::*; let value = value.clone(); Ok(match value { - RawString(s) => Value::String(s), String(s) => Value::String(s), - Base2(i) | Base8(i) | Base10(i) | Base16(i) => Value::Number( - serde_json::Number::from_i128(i.into()) + Integer(i) => Value::Number( + serde_json::Number::from_i128(i) .ok_or_else(|| hc_error!("kdl value contained an extremely large int"))?, ), - Base10Float(f) => Value::Number( + Float(f) => Value::Number( serde_json::Number::from_f64(f) .ok_or_else(|| hc_error!("kdl value contained infinite or NaN float"))?, ), @@ -283,11 +282,11 @@ impl ParseKdlNode for PolicyAnalysis { } }; let policy_expression = match node.get("policy") { - Some(entry) => Some(entry.value().as_string()?.to_string()), + Some(entry) => Some(entry.as_string()?.to_string()), None => None, }; let weight = match node.get("weight") { - Some(entry) => Some(entry.value().as_i64()? as u16), + Some(entry) => Some(entry.as_integer()? as u16), None => None, }; @@ -360,7 +359,7 @@ impl ParseKdlNode for PolicyCategory { let name = node.entries().first()?.value().as_string()?.to_string(); let weight = match node.get("weight") { - Some(entry) => Some(entry.value().as_i64()? as u16), + Some(entry) => Some(entry.as_integer()? as u16), None => None, }; @@ -463,10 +462,8 @@ impl ParseKdlNode for InvestigateIfFail { for node in node.entries() { // Trim leading and trailing quotation marks from each policy in the list - let mut policy = node.value().to_string(); - policy.remove(0); - policy.pop(); - policies.push(PolicyPluginName::new(&policy).ok()?) + let policy = node.value().as_string()?; + policies.push(PolicyPluginName::new(policy).ok()?) } Some(Self(policies))