Current section

Files

Jump to
go_over src go_over.gleam
Raw

src/go_over.gleam

import gleam/int
import gleam/io
import gleam/json
import gleam/list
import gleam/option
import gleam/result
import gleam/string
import go_over/advisories/advisories
import go_over/config.{type Config, Config}
import go_over/packages
import go_over/retired/outdated
import go_over/retired/retired
import go_over/util/constants
import go_over/util/print
import go_over/util/util.{has_flag, iff_nil, throwaway}
import go_over/warning.{type Warning, Warning}
import shellout
import simplifile
type Flags {
Flags(
force: Bool,
fake: Bool,
outdated: Bool,
ignore_indirect: Bool,
format: option.Option(config.Format),
)
}
fn merge_flags_and_config(flgs: Flags, cfg: Config) -> Config {
Config(
cache: cfg.cache,
force: flgs.force,
outdated: cfg.outdated || flgs.outdated,
ignore_indirect: cfg.ignore_indirect || flgs.ignore_indirect,
fake: flgs.fake,
format: option.unwrap(flgs.format, cfg.format),
ignore_packages: cfg.ignore_packages,
ignore_severity: cfg.ignore_severity,
ignore_ids: cfg.ignore_ids,
)
}
fn spin_up(cfg: Config) -> Config {
let args = shellout.arguments()
let format =
list.find(args, fn(arg) { string.starts_with(arg, "--format") })
|> result.try(fn(arg) { string.split_once(arg, "=") })
|> result.map(fn(arg) {
case arg {
#(_, val) -> val
}
})
|> result.map(config.parse_config_format)
|> option.from_result
let flags =
Flags(
force: has_flag(args, "force"),
outdated: has_flag(args, "outdated"),
ignore_indirect: has_flag(args, "ignore-indirect"),
fake: has_flag(args, "fake"),
format: format,
)
merge_flags_and_config(flags, cfg)
}
fn get_vulnerable_packages(
pkgs: List(packages.Package),
conf: Config,
) -> List(Warning) {
advisories.check_for_advisories(pkgs, conf.force || !conf.cache)
|> list.map(fn(p) {
let #(pkg, adv) = p
#(pkg, config.filter_advisory_ids(conf, adv))
})
|> list.filter(fn(p) {
case p {
#(_, []) -> False
_ -> True
}
})
|> list.flat_map(fn(p) {
let #(pkg, adv) = p
warning.adv_to_warning(pkg, adv)
})
}
fn get_retired_packges(
pkgs: List(packages.Package),
conf: Config,
) -> List(Warning) {
pkgs
|> list.map(fn(pkg) {
case retired.check_retired(pkg, conf.force || !conf.cache) {
option.Some(ret) -> option.Some(#(pkg, ret))
option.None -> option.None
}
})
|> option.values
|> list.map(fn(p) {
let #(pkg, ret) = p
warning.retired_to_warning(pkg, ret)
})
}
fn get_outdated_packages(
pkgs: List(packages.Package),
conf: Config,
) -> List(Warning) {
pkgs
|> list.map(fn(pkg) {
case outdated.check_outdated(pkg, conf.force || !conf.cache) {
option.Some(ret) -> option.Some(#(pkg, ret))
option.None -> option.None
}
})
|> option.values
|> list.map(fn(p) {
let #(pkg, ret) = p
warning.outdated_to_warning(pkg, ret)
})
}
fn print_warnings_count(vulns: List(Warning)) -> Nil {
{
"⛔ "
<> int.to_string(list.length(vulns))
<> " WARNING(s) FOUND!"
<> constants.long_ass_dashes
}
|> io.print_error
}
fn print_warnings(vulns: List(Warning), conf: Config) -> Nil {
case conf.format {
config.Minimal -> {
print_warnings_count(vulns)
vulns
|> list.map(warning.format_as_string_minimal)
|> string.join("")
|> io.print_error
}
config.JSON -> {
vulns
|> list.map(warning.format_as_json)
|> json.preprocessed_array
|> json.to_string
|> io.print_error
}
_ -> {
print_warnings_count(vulns)
vulns
|> list.map(warning.format_as_string)
|> string.join(constants.long_ass_dashes)
|> io.print_error
}
}
shellout.exit(1)
}
pub fn main() {
let conf = spin_up(config.read_config("./gleam.toml"))
throwaway(
!conf.cache,
util.freeze1(simplifile.delete, constants.go_over_path()),
)
let pkgs =
packages.read_manifest("./manifest.toml")
|> config.filter_packages(conf, _)
|> config.filter_indirect(conf, _)
let vulnerable_packages = get_vulnerable_packages(pkgs, conf)
let retired_packages = get_retired_packges(pkgs, conf)
let outdated_packages = case conf.outdated {
True -> get_outdated_packages(pkgs, conf)
False -> []
}
iff_nil(
conf.fake,
util.freeze2(
print_warnings,
[
Warning(
option.None,
"fake",
"x.y.z",
"Retired",
warning.Vulnerable,
"Critical",
warning.Direct,
),
Warning(
option.None,
"another_fake",
"1.2.3",
"Vulnerable",
warning.Vulnerable,
"High",
warning.Direct,
),
Warning(
option.None,
"and_another",
"4.5.6",
"Vulnerable",
warning.Vulnerable,
"Moderate",
warning.Direct,
),
Warning(
option.None,
"one_more",
"7.8.9",
"Vulnerable",
warning.Vulnerable,
"LOW",
warning.Indirect,
),
Warning(
option.None,
"this_one_was_retired",
"10.11.12",
"Retired",
warning.Retired,
"Package Retired",
warning.Indirect,
),
],
conf,
),
)
let warnings =
list.append(retired_packages, vulnerable_packages)
|> list.append(outdated_packages)
|> config.filter_severity(conf, _)
case warnings {
[] -> print.success("✅ All good! ✨")
vulns -> print_warnings(vulns, conf)
}
}