diff --git a/Makefile b/Makefile index 62e4e486..bc39bbed 100644 --- a/Makefile +++ b/Makefile @@ -30,6 +30,7 @@ docs/snippets/sponsors.html: docs/snippets/sponsors.json docs/snippets/render-sp refresh-schemas: curl https://www.schemastore.org/github-workflow.json > crates/zizmor/src/data/github-workflow.json curl https://www.schemastore.org/github-action.json > crates/zizmor/src/data/github-action.json + curl https://www.schemastore.org/dependabot-2.0.json > crates/zizmor/src/data/dependabot-2.0.json .PHONY: webhooks-to-contexts webhooks-to-contexts: diff --git a/crates/github-actions-models/README.md b/crates/github-actions-models/README.md index 84c8a2bb..83c330af 100644 --- a/crates/github-actions-models/README.md +++ b/crates/github-actions-models/README.md @@ -8,7 +8,8 @@ github-actions-models [![GitHub Sponsors](https://img.shields.io/github/sponsors/woodruffw?style=flat&logo=githubsponsors&labelColor=white&color=white)](https://github.com/sponsors/woodruffw) [![Discord](https://img.shields.io/badge/Discord-%235865F2.svg?logo=discord&logoColor=white)](https://discord.com/invite/PGU3zGZuGG) -Unofficial, high-quality data models for GitHub Actions workflows, actions, and related components. +Unofficial, high-quality data models for GitHub Actions workflows, actions, and +Dependabot configuration files. ## Why? diff --git a/crates/github-actions-models/src/dependabot/v2.rs b/crates/github-actions-models/src/dependabot/v2.rs index 40d5d4ed..b2ce29bc 100644 --- a/crates/github-actions-models/src/dependabot/v2.rs +++ b/crates/github-actions-models/src/dependabot/v2.rs @@ -88,6 +88,26 @@ pub enum Registry { }, } +/// Cooldown settings for Dependabot updates. +#[derive(Deserialize, Debug)] +#[serde(rename_all = "kebab-case")] +pub struct Cooldown { + pub default_days: Option, + pub semver_major_days: Option, + pub semver_minor_days: Option, + pub semver_patch_days: Option, + pub include: Vec, + pub exclude: Vec, +} + +/// A `directory` or `directories` field in a Dependabot `update` directive. +#[derive(Deserialize, Debug, PartialEq)] +#[serde(rename_all = "kebab-case")] +pub enum Directories { + Directory(String), + Directories(Vec), +} + /// A single `update` directive. #[derive(Deserialize, Debug)] #[serde(rename_all = "kebab-case")] @@ -97,7 +117,9 @@ pub struct Update { #[serde(default)] pub assignees: IndexSet, pub commit_message: Option, - pub directory: String, + pub cooldown: Option, + #[serde(flatten)] + pub directories: Directories, #[serde(default)] pub groups: IndexMap, #[serde(default)] diff --git a/crates/github-actions-models/tests/sample-dependabot/v2/cooldown.yml b/crates/github-actions-models/tests/sample-dependabot/v2/cooldown.yml new file mode 100644 index 00000000..c1a588da --- /dev/null +++ b/crates/github-actions-models/tests/sample-dependabot/v2/cooldown.yml @@ -0,0 +1,20 @@ +# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/optimizing-pr-creation-version-updates#setting-up-a-cooldown-period-for-dependency-updates + +version: 2 +updates: + - package-ecosystem: "pip" + directory: "/" + schedule: + interval: "daily" + cooldown: + default-days: 5 + semver-major-days: 30 + semver-minor-days: 7 + semver-patch-days: 3 + include: + - "requests" + - "numpy" + - "pandas*" + - "django" + exclude: + - "pandas" diff --git a/crates/github-actions-models/tests/sample-dependabot/v2/grafana.yml b/crates/github-actions-models/tests/sample-dependabot/v2/grafana.yml new file mode 100644 index 00000000..f2429341 --- /dev/null +++ b/crates/github-actions-models/tests/sample-dependabot/v2/grafana.yml @@ -0,0 +1,40 @@ +# https://github.com/grafana/grafana/blob/0de6d103c286ae8c0380dd420dfaec24ee706fe9/.github/dependabot.yml + +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" + - package-ecosystem: "gomod" + directories: + - "/" + - "/apps/playlist" + - "/apps/secret" + - "/apps/investigations" + - "/pkg/aggregator" + - "/pkg/apimachinery" + - "/pkg/apis/folder" + - "/pkg/apiserver" + - "/pkg/build" + - "/pkg/build/wire" + - "/pkg/promlib" + - "/pkg/semconv" + - "/pkg/storage/unified/apistore" + - "/pkg/storage/unified/resource" + - "/pkg/util/xorm" + schedule: + interval: "daily" + time: "02:00" + timezone: Etc/UTC + open-pull-requests-limit: 10 + - package-ecosystem: "docker" + directories: + - "/" + - "/packaging/docker/custom" + - "/scripts/verify-repo-update" + schedule: + interval: "daily" + time: "02:00" + timezone: Etc/UTC + open-pull-requests-limit: 10 diff --git a/crates/github-actions-models/tests/test_dependabot_v2.rs b/crates/github-actions-models/tests/test_dependabot_v2.rs index 91842e34..3c5694aa 100644 --- a/crates/github-actions-models/tests/test_dependabot_v2.rs +++ b/crates/github-actions-models/tests/test_dependabot_v2.rs @@ -1,7 +1,7 @@ use std::path::Path; use github_actions_models::dependabot::v2::{ - Dependabot, Interval, PackageEcosystem, RebaseStrategy, + Dependabot, Directories, Interval, PackageEcosystem, RebaseStrategy, }; use indexmap::IndexSet; @@ -33,7 +33,7 @@ fn test_contents() { let pip = &dependabot.updates[0]; assert_eq!(pip.package_ecosystem, PackageEcosystem::Pip); - assert_eq!(pip.directory, "/"); + assert_eq!(pip.directories, Directories::Directory("/".into())); assert_eq!(pip.schedule.interval, Interval::Daily); assert_eq!(pip.open_pull_requests_limit, 5); // default @@ -42,7 +42,10 @@ fn test_contents() { github_actions.package_ecosystem, PackageEcosystem::GithubActions ); - assert_eq!(github_actions.directory, "/"); + assert_eq!( + github_actions.directories, + Directories::Directory("/".into()) + ); assert_eq!(github_actions.open_pull_requests_limit, 99); assert_eq!(github_actions.rebase_strategy, RebaseStrategy::Disabled); assert_eq!(github_actions.groups.len(), 1); @@ -56,7 +59,10 @@ fn test_contents() { github_actions.package_ecosystem, PackageEcosystem::GithubActions ); - assert_eq!(github_actions.directory, ".github/actions/upload-coverage/"); + assert_eq!( + github_actions.directories, + Directories::Directory(".github/actions/upload-coverage/".into()) + ); assert_eq!(github_actions.open_pull_requests_limit, 99); assert_eq!(github_actions.rebase_strategy, RebaseStrategy::Disabled); assert_eq!(github_actions.groups.len(), 1); diff --git a/crates/zizmor/src/audit/mod.rs b/crates/zizmor/src/audit/mod.rs index 980bb63b..5f1900d5 100644 --- a/crates/zizmor/src/audit/mod.rs +++ b/crates/zizmor/src/audit/mod.rs @@ -10,6 +10,7 @@ use crate::{ models::{ AsDocument, action::{Action, CompositeStep}, + dependabot::Dependabot, workflow::{Job, NormalJob, ReusableWorkflowCallJob, Step, Workflow}, }, registry::input::InputKey, @@ -48,6 +49,7 @@ pub(crate) mod use_trusted_publishing; pub(crate) enum AuditInput { Workflow(Workflow), Action(Action), + Dependabot(Dependabot), } impl AuditInput { @@ -55,6 +57,7 @@ impl AuditInput { match self { AuditInput::Workflow(workflow) => &workflow.key, AuditInput::Action(action) => &action.key, + AuditInput::Dependabot(dependabot) => &dependabot.key, } } @@ -62,6 +65,7 @@ impl AuditInput { match self { AuditInput::Workflow(workflow) => workflow.link.as_deref(), AuditInput::Action(action) => action.link.as_deref(), + AuditInput::Dependabot(dependabot) => dependabot.link.as_deref(), } } @@ -69,6 +73,7 @@ impl AuditInput { match self { AuditInput::Workflow(workflow) => workflow.location(), AuditInput::Action(action) => action.location(), + AuditInput::Dependabot(dependabot) => dependabot.location(), } } } @@ -78,6 +83,7 @@ impl<'a> AsDocument<'a, 'a> for AuditInput { match self { AuditInput::Workflow(workflow) => workflow.as_document(), AuditInput::Action(action) => action.as_document(), + AuditInput::Dependabot(dependabot) => dependabot.as_document(), } } } @@ -94,6 +100,12 @@ impl From for AuditInput { } } +impl From for AuditInput { + fn from(value: Dependabot) -> Self { + Self::Dependabot(value) + } +} + /// A supertrait for all audits. /// /// Workflow audits, action audits, and all future audit types @@ -270,6 +282,14 @@ pub(crate) trait Audit: AuditCore { Ok(results) } + fn audit_dependabot<'doc>( + &self, + _dependabot: &'doc Dependabot, + _config: &Config, + ) -> anyhow::Result>> { + Ok(vec![]) + } + fn audit_raw<'doc>( &self, _input: &'doc AuditInput, @@ -308,6 +328,7 @@ pub(crate) trait Audit: AuditCore { let mut results = match input { AuditInput::Workflow(workflow) => self.audit_workflow(workflow, config), AuditInput::Action(action) => self.audit_action(action, config), + AuditInput::Dependabot(dependabot) => self.audit_dependabot(dependabot, config), }?; results.extend(self.audit_raw(input, config)?); diff --git a/crates/zizmor/src/data/dependabot-2.0.json b/crates/zizmor/src/data/dependabot-2.0.json new file mode 100644 index 00000000..17cd87e5 --- /dev/null +++ b/crates/zizmor/src/data/dependabot-2.0.json @@ -0,0 +1,1189 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://json.schemastore.org/dependabot-2.0.json", + "additionalProperties": false, + "definitions": { + "timezone": { + "type": "string", + "enum": [ + "Africa/Abidjan", + "Africa/Accra", + "Africa/Addis_Ababa", + "Africa/Algiers", + "Africa/Asmara", + "Africa/Asmera", + "Africa/Bamako", + "Africa/Bangui", + "Africa/Banjul", + "Africa/Bissau", + "Africa/Blantyre", + "Africa/Brazzaville", + "Africa/Bujumbura", + "Africa/Cairo", + "Africa/Casablanca", + "Africa/Ceuta", + "Africa/Conakry", + "Africa/Dakar", + "Africa/Dar_es_Salaam", + "Africa/Djibouti", + "Africa/Douala", + "Africa/El_Aaiun", + "Africa/Freetown", + "Africa/Gaborone", + "Africa/Harare", + "Africa/Johannesburg", + "Africa/Juba", + "Africa/Kampala", + "Africa/Khartoum", + "Africa/Kigali", + "Africa/Kinshasa", + "Africa/Lagos", + "Africa/Libreville", + "Africa/Lome", + "Africa/Luanda", + "Africa/Lubumbashi", + "Africa/Lusaka", + "Africa/Malabo", + "Africa/Maputo", + "Africa/Maseru", + "Africa/Mbabane", + "Africa/Mogadishu", + "Africa/Monrovia", + "Africa/Nairobi", + "Africa/Ndjamena", + "Africa/Niamey", + "Africa/Nouakchott", + "Africa/Ouagadougou", + "Africa/Porto-Novo", + "Africa/Sao_Tome", + "Africa/Timbuktu", + "Africa/Tripoli", + "Africa/Tunis", + "Africa/Windhoek", + "America/Adak", + "America/Anchorage", + "America/Anguilla", + "America/Antigua", + "America/Araguaina", + "America/Argentina/Buenos_Aires", + "America/Argentina/Catamarca", + "America/Argentina/ComodRivadavia", + "America/Argentina/Cordoba", + "America/Argentina/Jujuy", + "America/Argentina/La_Rioja", + "America/Argentina/Mendoza", + "America/Argentina/Rio_Gallegos", + "America/Argentina/Salta", + "America/Argentina/San_Juan", + "America/Argentina/San_Luis", + "America/Argentina/Tucuman", + "America/Argentina/Ushuaia", + "America/Aruba", + "America/Asuncion", + "America/Atikokan", + "America/Atka", + "America/Bahia", + "America/Bahia_Banderas", + "America/Barbados", + "America/Belem", + "America/Belize", + "America/Blanc-Sablon", + "America/Boa_Vista", + "America/Bogota", + "America/Boise", + "America/Buenos_Aires", + "America/Cambridge_Bay", + "America/Campo_Grande", + "America/Cancun", + "America/Caracas", + "America/Catamarca", + "America/Cayenne", + "America/Cayman", + "America/Chicago", + "America/Chihuahua", + "America/Coral_Harbour", + "America/Cordoba", + "America/Costa_Rica", + "America/Creston", + "America/Cuiaba", + "America/Curacao", + "America/Danmarkshavn", + "America/Dawson", + "America/Dawson_Creek", + "America/Denver", + "America/Detroit", + "America/Dominica", + "America/Edmonton", + "America/Eirunepe", + "America/El_Salvador", + "America/Ensenada", + "America/Fort_Nelson", + "America/Fort_Wayne", + "America/Fortaleza", + "America/Glace_Bay", + "America/Godthab", + "America/Goose_Bay", + "America/Grand_Turk", + "America/Grenada", + "America/Guadeloupe", + "America/Guatemala", + "America/Guayaquil", + "America/Guyana", + "America/Halifax", + "America/Havana", + "America/Hermosillo", + "America/Indiana/Indianapolis", + "America/Indiana/Knox", + "America/Indiana/Marengo", + "America/Indiana/Petersburg", + "America/Indiana/Tell_City", + "America/Indiana/Vevay", + "America/Indiana/Vincennes", + "America/Indiana/Winamac", + "America/Indianapolis", + "America/Inuvik", + "America/Iqaluit", + "America/Jamaica", + "America/Jujuy", + "America/Juneau", + "America/Kentucky/Louisville", + "America/Kentucky/Monticello", + "America/Knox_IN", + "America/Kralendijk", + "America/La_Paz", + "America/Lima", + "America/Los_Angeles", + "America/Louisville", + "America/Lower_Princes", + "America/Maceio", + "America/Managua", + "America/Manaus", + "America/Marigot", + "America/Martinique", + "America/Matamoros", + "America/Mazatlan", + "America/Mendoza", + "America/Menominee", + "America/Merida", + "America/Metlakatla", + "America/Mexico_City", + "America/Miquelon", + "America/Moncton", + "America/Monterrey", + "America/Montevideo", + "America/Montreal", + "America/Montserrat", + "America/Nassau", + "America/New_York", + "America/Nipigon", + "America/Nome", + "America/Noronha", + "America/North_Dakota/Beulah", + "America/North_Dakota/Center", + "America/North_Dakota/New_Salem", + "America/Nuuk", + "America/Ojinaga", + "America/Panama", + "America/Pangnirtung", + "America/Paramaribo", + "America/Phoenix", + "America/Port-au-Prince", + "America/Port_of_Spain", + "America/Porto_Acre", + "America/Porto_Velho", + "America/Puerto_Rico", + "America/Punta_Arenas", + "America/Rainy_River", + "America/Rankin_Inlet", + "America/Recife", + "America/Regina", + "America/Resolute", + "America/Rio_Branco", + "America/Rosario", + "America/Santa_Isabel", + "America/Santarem", + "America/Santiago", + "America/Santo_Domingo", + "America/Sao_Paulo", + "America/Scoresbysund", + "America/Shiprock", + "America/Sitka", + "America/St_Barthelemy", + "America/St_Johns", + "America/St_Kitts", + "America/St_Lucia", + "America/St_Thomas", + "America/St_Vincent", + "America/Swift_Current", + "America/Tegucigalpa", + "America/Thule", + "America/Thunder_Bay", + "America/Tijuana", + "America/Toronto", + "America/Tortola", + "America/Vancouver", + "America/Virgin", + "America/Whitehorse", + "America/Winnipeg", + "America/Yakutat", + "America/Yellowknife", + "Antarctica/Casey", + "Antarctica/Davis", + "Antarctica/DumontDUrville", + "Antarctica/Macquarie", + "Antarctica/Mawson", + "Antarctica/McMurdo", + "Antarctica/Palmer", + "Antarctica/Rothera", + "Antarctica/South_Pole", + "Antarctica/Syowa", + "Antarctica/Troll", + "Antarctica/Vostok", + "Arctic/Longyearbyen", + "Asia/Aden", + "Asia/Almaty", + "Asia/Amman", + "Asia/Anadyr", + "Asia/Aqtau", + "Asia/Aqtobe", + "Asia/Ashgabat", + "Asia/Ashkhabad", + "Asia/Atyrau", + "Asia/Baghdad", + "Asia/Bahrain", + "Asia/Baku", + "Asia/Bangkok", + "Asia/Barnaul", + "Asia/Beirut", + "Asia/Bishkek", + "Asia/Brunei", + "Asia/Calcutta", + "Asia/Chita", + "Asia/Choibalsan", + "Asia/Chongqing", + "Asia/Chungking", + "Asia/Colombo", + "Asia/Dacca", + "Asia/Damascus", + "Asia/Dhaka", + "Asia/Dili", + "Asia/Dubai", + "Asia/Dushanbe", + "Asia/Famagusta", + "Asia/Gaza", + "Asia/Harbin", + "Asia/Hebron", + "Asia/Ho_Chi_Minh", + "Asia/Hong_Kong", + "Asia/Hovd", + "Asia/Irkutsk", + "Asia/Istanbul", + "Asia/Jakarta", + "Asia/Jayapura", + "Asia/Jerusalem", + "Asia/Kabul", + "Asia/Kamchatka", + "Asia/Karachi", + "Asia/Kashgar", + "Asia/Kathmandu", + "Asia/Katmandu", + "Asia/Khandyga", + "Asia/Kolkata", + "Asia/Krasnoyarsk", + "Asia/Kuala_Lumpur", + "Asia/Kuching", + "Asia/Kuwait", + "Asia/Macao", + "Asia/Macau", + "Asia/Magadan", + "Asia/Makassar", + "Asia/Manila", + "Asia/Muscat", + "Asia/Nicosia", + "Asia/Novokuznetsk", + "Asia/Novosibirsk", + "Asia/Omsk", + "Asia/Oral", + "Asia/Phnom_Penh", + "Asia/Pontianak", + "Asia/Pyongyang", + "Asia/Qatar", + "Asia/Qostanay", + "Asia/Qyzylorda", + "Asia/Rangoon", + "Asia/Riyadh", + "Asia/Saigon", + "Asia/Sakhalin", + "Asia/Samarkand", + "Asia/Seoul", + "Asia/Shanghai", + "Asia/Singapore", + "Asia/Srednekolymsk", + "Asia/Taipei", + "Asia/Tashkent", + "Asia/Tbilisi", + "Asia/Tehran", + "Asia/Tel_Aviv", + "Asia/Thimbu", + "Asia/Thimphu", + "Asia/Tokyo", + "Asia/Tomsk", + "Asia/Ujung_Pandang", + "Asia/Ulaanbaatar", + "Asia/Ulan_Bator", + "Asia/Urumqi", + "Asia/Ust-Nera", + "Asia/Vientiane", + "Asia/Vladivostok", + "Asia/Yakutsk", + "Asia/Yangon", + "Asia/Yekaterinburg", + "Asia/Yerevan", + "Atlantic/Azores", + "Atlantic/Bermuda", + "Atlantic/Canary", + "Atlantic/Cape_Verde", + "Atlantic/Faeroe", + "Atlantic/Faroe", + "Atlantic/Jan_Mayen", + "Atlantic/Madeira", + "Atlantic/Reykjavik", + "Atlantic/South_Georgia", + "Atlantic/St_Helena", + "Atlantic/Stanley", + "Australia/ACT", + "Australia/Adelaide", + "Australia/Brisbane", + "Australia/Broken_Hill", + "Australia/Canberra", + "Australia/Currie", + "Australia/Darwin", + "Australia/Eucla", + "Australia/Hobart", + "Australia/LHI", + "Australia/Lindeman", + "Australia/Lord_Howe", + "Australia/Melbourne", + "Australia/North", + "Australia/NSW", + "Australia/Perth", + "Australia/Queensland", + "Australia/South", + "Australia/Sydney", + "Australia/Tasmania", + "Australia/Victoria", + "Australia/West", + "Australia/Yancowinna", + "Brazil/Acre", + "Brazil/DeNoronha", + "Brazil/East", + "Brazil/West", + "Canada/Atlantic", + "Canada/Central", + "Canada/Eastern", + "Canada/Mountain", + "Canada/Newfoundland", + "Canada/Pacific", + "Canada/Saskatchewan", + "Canada/Yukon", + "Chile/Continental", + "Chile/EasterIsland", + "Cuba", + "Egypt", + "Eire", + "Etc/GMT", + "Etc/GMT+0", + "Etc/GMT+1", + "Etc/GMT+10", + "Etc/GMT+11", + "Etc/GMT+12", + "Etc/GMT+2", + "Etc/GMT+3", + "Etc/GMT+4", + "Etc/GMT+5", + "Etc/GMT+6", + "Etc/GMT+7", + "Etc/GMT+8", + "Etc/GMT+9", + "Etc/GMT-0", + "Etc/GMT-1", + "Etc/GMT-10", + "Etc/GMT-11", + "Etc/GMT-12", + "Etc/GMT-13", + "Etc/GMT-14", + "Etc/GMT-2", + "Etc/GMT-3", + "Etc/GMT-4", + "Etc/GMT-5", + "Etc/GMT-6", + "Etc/GMT-7", + "Etc/GMT-8", + "Etc/GMT-9", + "Etc/GMT0", + "Etc/Greenwich", + "Etc/UCT", + "Etc/Universal", + "Etc/UTC", + "Etc/Zulu", + "Europe/Amsterdam", + "Europe/Andorra", + "Europe/Astrakhan", + "Europe/Athens", + "Europe/Belfast", + "Europe/Belgrade", + "Europe/Berlin", + "Europe/Bratislava", + "Europe/Brussels", + "Europe/Bucharest", + "Europe/Budapest", + "Europe/Busingen", + "Europe/Chisinau", + "Europe/Copenhagen", + "Europe/Dublin", + "Europe/Gibraltar", + "Europe/Guernsey", + "Europe/Helsinki", + "Europe/Isle_of_Man", + "Europe/Istanbul", + "Europe/Jersey", + "Europe/Kaliningrad", + "Europe/Kiev", + "Europe/Kirov", + "Europe/Kyiv", + "Europe/Lisbon", + "Europe/Ljubljana", + "Europe/London", + "Europe/Luxembourg", + "Europe/Madrid", + "Europe/Malta", + "Europe/Mariehamn", + "Europe/Minsk", + "Europe/Monaco", + "Europe/Moscow", + "Europe/Nicosia", + "Europe/Oslo", + "Europe/Paris", + "Europe/Podgorica", + "Europe/Prague", + "Europe/Riga", + "Europe/Rome", + "Europe/Samara", + "Europe/San_Marino", + "Europe/Sarajevo", + "Europe/Saratov", + "Europe/Simferopol", + "Europe/Skopje", + "Europe/Sofia", + "Europe/Stockholm", + "Europe/Tallinn", + "Europe/Tirane", + "Europe/Tiraspol", + "Europe/Ulyanovsk", + "Europe/Uzhgorod", + "Europe/Vaduz", + "Europe/Vatican", + "Europe/Vienna", + "Europe/Vilnius", + "Europe/Volgograd", + "Europe/Warsaw", + "Europe/Zagreb", + "Europe/Zaporozhye", + "Europe/Zurich", + "GB", + "GB-Eire", + "Hongkong", + "Iceland", + "Indian/Antananarivo", + "Indian/Chagos", + "Indian/Christmas", + "Indian/Cocos", + "Indian/Comoro", + "Indian/Kerguelen", + "Indian/Mahe", + "Indian/Maldives", + "Indian/Mauritius", + "Indian/Mayotte", + "Indian/Reunion", + "Iran", + "Israel", + "Jamaica", + "Japan", + "Kwajalein", + "Libya", + "Mexico/BajaNorte", + "Mexico/BajaSur", + "Mexico/General", + "Navajo", + "NZ", + "NZ-CHAT", + "Pacific/Apia", + "Pacific/Auckland", + "Pacific/Bougainville", + "Pacific/Chatham", + "Pacific/Chuuk", + "Pacific/Easter", + "Pacific/Efate", + "Pacific/Enderbury", + "Pacific/Fakaofo", + "Pacific/Fiji", + "Pacific/Funafuti", + "Pacific/Galapagos", + "Pacific/Gambier", + "Pacific/Guadalcanal", + "Pacific/Guam", + "Pacific/Honolulu", + "Pacific/Johnston", + "Pacific/Kanton", + "Pacific/Kiritimati", + "Pacific/Kosrae", + "Pacific/Kwajalein", + "Pacific/Majuro", + "Pacific/Marquesas", + "Pacific/Midway", + "Pacific/Nauru", + "Pacific/Niue", + "Pacific/Norfolk", + "Pacific/Noumea", + "Pacific/Pago_Pago", + "Pacific/Palau", + "Pacific/Pitcairn", + "Pacific/Pohnpei", + "Pacific/Ponape", + "Pacific/Port_Moresby", + "Pacific/Rarotonga", + "Pacific/Saipan", + "Pacific/Samoa", + "Pacific/Tahiti", + "Pacific/Tarawa", + "Pacific/Tongatapu", + "Pacific/Truk", + "Pacific/Wake", + "Pacific/Wallis", + "Pacific/Yap", + "Poland", + "Portugal", + "PRC", + "ROC", + "Singapore", + "US/Alaska", + "US/Aleutian", + "US/Arizona", + "US/Central", + "US/East-Indiana", + "US/Eastern", + "US/Hawaii", + "US/Indiana-Starke", + "US/Michigan", + "US/Mountain", + "US/Pacific", + "US/Samoa" + ] + }, + "dependency-type": { + "type": "string", + "enum": ["direct", "indirect", "all", "production", "development"], + "x-intellij-enum-metadata": { + "direct": { + "description": "All explicitly defined dependencies." + }, + "indirect": { + "description": "Dependencies of direct dependencies (also known as sub-dependencies, or transient dependencies)." + }, + "all": { + "description": "All explicitly defined dependencies. For bundler, pip, composer, cargo, also the dependencies of direct dependencies." + }, + "production": { + "description": "Only dependencies in the 'Product dependency group'." + }, + "development": { + "description": "Only dependencies in the 'Development dependency group'." + } + } + }, + "update-types": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "version-update:semver-major", + "version-update:semver-minor", + "version-update:semver-patch" + ] + }, + "minItems": 1, + "uniqueItems": true + }, + "insecure-external-code-execution": { + "type": "string", + "enum": ["allow", "deny"] + }, + "versioning-strategy": { + "type": "string", + "enum": [ + "auto", + "increase", + "increase-if-necessary", + "lockfile-only", + "widen" + ], + "x-intellij-enum-metadata": { + "auto": { + "description": "Try to differentiate between apps and libraries. Use 'increase' for apps and 'widen' for libraries." + }, + "increase": { + "description": "Always increase the minimum version requirement to match the new version. If a range already exists, typically this only increases the lower bound." + }, + "increase-if-necessary": { + "description": "Leave the constraint if the original constraint allows the new version, otherwise, bump the constraint." + }, + "lockfile-only": { + "description": "Only create pull requests to update lockfiles. Ignore any new versions that would require package manifest changes." + }, + "widen": { + "description": "Widen the allowed version requirements to include both the new and old versions, when possible. Typically, this only increases the maximum allowed version requirement." + } + } + }, + "package-ecosystem-values": { + "enum": [ + "bun", + "bundler", + "cargo", + "composer", + "devcontainers", + "docker", + "docker-compose", + "dotnet-sdk", + "elm", + "gitsubmodule", + "github-actions", + "gomod", + "gradle", + "helm", + "maven", + "mix", + "npm", + "nuget", + "pip", + "pub", + "rust-toolchain", + "swift", + "terraform", + "uv", + "vcpkg" + ] + }, + "schedule-day": { + "type": "string", + "enum": [ + "monday", + "tuesday", + "wednesday", + "thursday", + "friday", + "saturday", + "sunday" + ] + }, + "schedule-interval": { + "type": "string", + "enum": [ + "daily", + "weekly", + "monthly", + "quarterly", + "semiannually", + "yearly", + "cron" + ] + }, + "update": { + "type": "object", + "additionalProperties": false, + "properties": { + "allow": { + "description": "Customize which updates are allowed", + "type": "array", + "items": { + "type": "object", + "properties": { + "dependency-name": { + "type": "string" + }, + "dependency-type": { + "$ref": "#/definitions/dependency-type" + } + }, + "anyOf": [ + { "required": ["dependency-name"] }, + { "required": ["dependency-type"] } + ], + "additionalProperties": false + } + }, + "assignees": { + "description": "Assignees to set on pull requests", + "type": "array", + "items": { + "type": "string", + "minLength": 1 + }, + "minItems": 1, + "uniqueItems": true + }, + "commit-message": { + "description": "Dependabot attempts to detect your commit message preferences and use similar patterns. Use this option to specify your preferences explicitly.", + "type": "object", + "properties": { + "prefix": { + "description": "A prefix for all commit messages. When you specify a prefix for commit messages, GitHub will automatically add a colon between the defined prefix and the commit message provided the defined prefix ends with a letter, number, closing parenthesis, or closing bracket. This means that, for example, if you end the prefix with a whitespace, there will be no colon added between the prefix and the commit message.", + "type": "string", + "maxLength": 50 + }, + "prefix-development": { + "description": "A separate prefix for all commit messages that update dependencies in the Development dependency group. When you specify a value for this option, the prefix is used only for updates to dependencies in the Production dependency group. This is not supported by all package ecosystems.", + "type": "string", + "maxLength": 50 + }, + "include": { + "description": "Specifies that any prefix is followed by a list of the dependencies updated in the commit.", + "type": "string", + "enum": ["scope"], + "default": "scope" + } + }, + "anyOf": [ + { "required": ["prefix"] }, + { "required": ["prefix-development"] }, + { "required": ["include"] } + ], + "additionalProperties": false + }, + "cooldown": { + "description": "Defines a cooldown period for dependency updates, allowing updates to be delayed for a configurable number of days. This feature enables users to customize how often Dependabot generates new version updates, offering greater control over update frequency.", + "type": "object", + "properties": { + "default-days": { + "description": "Default cooldown period for dependencies without specific rules (optional).", + "type": "integer", + "minimum": 0 + }, + "semver-major-days": { + "description": "Cooldown period for major version updates (optional, applies only to package managers supporting SemVer).", + "type": "integer", + "minimum": 0 + }, + "semver-minor-days": { + "description": "Cooldown period for minor version updates (optional, applies only to package managers supporting SemVer).", + "type": "integer", + "minimum": 0 + }, + "semver-patch-days": { + "description": "Cooldown period for patch version updates (optional, applies only to package managers supporting SemVer).", + "type": "integer", + "minimum": 0 + }, + "include": { + "description": "List of dependencies to apply cooldown (up to 150 items). Supports wildcards (`*`).", + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 150 + }, + "exclude": { + "description": "List of dependencies excluded from cooldown (up to 150 items). Supports wildcards (`*`).", + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 150 + } + }, + "additionalProperties": false + }, + "directories": { + "description": "Locations of package manifests", + "type": "array", + "items": { + "type": "string", + "minLength": 1 + }, + "minItems": 1, + "uniqueItems": true + }, + "directory": { + "description": "Location of package manifests", + "type": "string", + "default": "/" + }, + "exclude-paths": { + "description": "List of file paths to exclude from dependency updates", + "type": "array", + "minItems": 0, + "uniqueItems": true, + "items": { + "type": "string" + } + }, + "groups": { + "description": "Configure groups for dependencies. Each 'groups' property is arbitrary will appear in pull request titles and branch names. For example, the code snippet '{\"groups\": {\"NPM dependencies\": {\"patterns\": [\"*\"]}}}' sets the group name to 'NPM dependencies'.", + "type": "object", + "additionalProperties": { + "type": "object", + "properties": { + "applies-to": { + "description": "Use to specify a whether the rules in the group apply to version updates or security updates.", + "type": "string", + "enum": ["version-updates", "security-updates"] + }, + "dependency-type": { + "description": "Specify a dependency type to be included in the group.", + "type": "string", + "enum": ["development", "production"] + }, + "patterns": { + "description": "Define strings of characters that match with a dependency name (or multiple dependency names) to include those dependencies in the group.", + "type": "array", + "items": { + "type": "string", + "minLength": 1 + }, + "uniqueItems": true, + "minItems": 1 + }, + "exclude-patterns": { + "description": "Exclude certain dependencies from the group. If a dependency is excluded from a group, Dependabot will continue to raise single pull requests to update the dependency to its latest version.", + "type": "array", + "items": { + "type": "string", + "minLength": 1 + }, + "uniqueItems": true, + "minItems": 1 + }, + "update-types": { + "description": "Specify the semantic versioning level to include in the group", + "type": "array", + "items": { + "type": "string", + "enum": ["major", "minor", "patch"] + }, + "minItems": 1, + "uniqueItems": true + } + }, + "anyOf": [ + { "required": ["dependency-type"] }, + { "required": ["patterns"] }, + { "required": ["exclude-patterns"] }, + { "required": ["update-types"] } + ], + "additionalProperties": false + }, + "minProperties": 1 + }, + "ignore": { + "description": "Ignore certain dependencies or versions", + "type": "array", + "items": { + "type": "object", + "properties": { + "dependency-name": { + "description": "Use to ignore updates for dependencies with matching names, optionally using * to match zero or more characters.", + "type": "string" + }, + "update-types": { + "$ref": "#/definitions/update-types", + "description": "Use to ignore types of updates. You can combine this with 'dependency-name: \"*\"' to ignore particular update-types for all dependencies." + }, + "versions": { + "description": "Use to ignore specific versions or ranges of versions. If you want to define a range, use the standard pattern for the package manager.", + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1, + "uniqueItems": true + } + }, + "anyOf": [ + { "required": ["dependency-name"] }, + { "required": ["update-types"] }, + { "required": ["versions"] } + ], + "additionalProperties": false + } + }, + "insecure-external-code-execution": { + "$ref": "#/definitions/insecure-external-code-execution", + "description": "Allow or deny code execution in manifest files" + }, + "labels": { + "description": "Labels to set on pull requests", + "type": "array", + "items": { + "type": "string", + "minLength": 1 + }, + "minItems": 0, + "uniqueItems": true, + "default": ["dependencies"] + }, + "milestone": { + "description": "Associate all pull requests raised for a package manager with a milestone. You need to specify the numeric identifier of the milestone and not its label.", + "type": "integer", + "minimum": 1 + }, + "open-pull-requests-limit": { + "description": "Limit number of open pull requests for version updates", + "type": "integer", + "minimum": 0, + "default": 5 + }, + "package-ecosystem": { + "$comment": "These values are restricted by a top-level if-then-else when 'enable-beta-ecosystems' is not enabled.", + "description": "Package manager to use", + "type": "string", + "anyOf": [ + { "$ref": "#/definitions/package-ecosystem-values" }, + { "minLength": 1 } + ] + }, + "pull-request-branch-name": { + "description": "Pull request branch name preferences", + "type": "object", + "properties": { + "separator": { + "description": "Change separator for PR branch name", + "type": "string", + "default": "/", + "enum": ["-", "_", "/"] + } + }, + "required": ["separator"], + "additionalProperties": false + }, + "rebase-strategy": { + "description": "Disable automatic rebasing. 'auto' is the default and Dependabot will rebase open pull requests when changes are detected. 'disabled' will disable automatic rebasing.", + "type": "string", + "enum": ["auto", "disabled"], + "default": "auto" + }, + "registries": { + "$comment": "'registries' must be either an array of strings, or the string constant '*'.", + "oneOf": [ + { + "type": "array", + "items": { + "type": "string", + "minLength": 1 + }, + "uniqueItems": true, + "minItems": 1 + }, + { + "type": "string", + "const": "*" + } + ] + }, + "schedule": { + "description": "Schedule preferences", + "type": "object", + "properties": { + "interval": { + "$ref": "#/definitions/schedule-interval" + }, + "day": { + "$ref": "#/definitions/schedule-day", + "description": "Specify an alternative day to check for updates" + }, + "time": { + "type": "string", + "description": "Specify an alternative time of day to check for updates (format: hh:mm)", + "pattern": "^([01][0-9]|2[0-3]):[0-5][0-9]$" + }, + "timezone": { + "$ref": "#/definitions/timezone", + "description": "The time zone identifier must be from the Time Zone database maintained by IANA" + }, + "cronjob": { + "type": "string", + "description": "Specify a valid cron expression for updates" + } + }, + "allOf": [ + { + "$comment": "If interval type is 'cron', enforce 'cronjob' property.", + "if": { + "properties": { + "interval": { + "const": "cron" + } + } + }, + "then": { + "required": ["interval", "cronjob"] + }, + "else": { + "required": ["interval"] + } + } + ] + }, + "target-branch": { + "description": "Specify a different branch for manifest files and for pull requests.", + "type": "string", + "minLength": 1 + }, + "vendor": { + "description": "Tell Dependabot to vendor dependencies when updating them. Don't use this option if you're using 'gomod'.", + "type": "boolean" + }, + "versioning-strategy": { + "$ref": "#/definitions/versioning-strategy", + "description": "How to update manifest version requirements" + } + }, + "allOf": [ + { + "required": ["package-ecosystem", "schedule"] + }, + { + "oneOf": [ + { "required": ["directories"] }, + { "required": ["directory"] } + ] + } + ] + }, + "registry": { + "type": "object", + "description": "The top-level registries key is optional. It allows you to specify authentication details that Dependabot can use to access private package registries.", + "additionalProperties": false, + "patternProperties": { + ".+": { + "type": "object", + "additionalProperties": false, + "properties": { + "type": { + "description": "Identifies the type of registry.", + "enum": [ + "cargo-registry", + "composer-repository", + "docker-registry", + "git", + "hex-organization", + "hex-repository", + "maven-repository", + "npm-registry", + "nuget-feed", + "pub-repository", + "python-index", + "rubygems-server", + "terraform-registry" + ] + }, + "url": { + "description": "The URL to use to access the dependencies in this registry. The protocol is optional. If not specified, 'https://' is assumed. Dependabot adds or ignores trailing slashes as required.", + "type": "string" + }, + "username": { + "description": "The username that Dependabot uses to access the registry.", + "type": "string" + }, + "password": { + "description": "A reference to a Dependabot secret containing the password for the specified user.", + "type": "string" + }, + "key": { + "description": "A reference to a Dependabot secret containing an access key for this registry.", + "type": "string" + }, + "token": { + "description": "A reference to a Dependabot secret containing an access token for this registry.", + "type": "string" + }, + "replaces-base": { + "description": "For registries with type: python-index, if the boolean value is true, pip resolves dependencies by using the specified URL rather than the base URL of the Python Package Index (by default https://pypi.org/simple).", + "type": "boolean" + }, + "organization": { + "description": "", + "type": "string" + }, + "repo": { + "description": "", + "type": "string" + }, + "auth-key": { + "description": "", + "type": "string" + }, + "public-key-fingerprint": { + "description": "", + "type": "string" + } + }, + "required": ["type", "url"] + } + }, + "minProperties": 1 + } + }, + "properties": { + "version": { + "title": "Config file version", + "description": "Dependabot configuration files require this key, and its value must be 2", + "type": "integer", + "enum": [2] + }, + "enable-beta-ecosystems": { + "description": "Enable ecosystems that have beta-level support", + "type": "boolean" + }, + "updates": { + "type": "array", + "items": { + "$ref": "#/definitions/update", + "title": "Package Ecosystem", + "description": "Element for each one package manager that you want GitHub Dependabot to monitor for new versions" + } + }, + "registries": { + "$ref": "#/definitions/registry" + } + }, + "required": ["version", "updates"], + "title": "GitHub Dependabot v2 config", + "type": "object", + "allOf": [ + { + "$comment": "If 'enable-beta-ecosystems' is NOT enabled, enforce known 'package-ecosystem' values.", + "if": { + "properties": { + "enable-beta-ecosystems": { + "const": true + } + }, + "required": ["enable-beta-ecosystems"] + }, + "then": {}, + "else": { + "properties": { + "updates": { + "items": { + "properties": { + "package-ecosystem": { + "$ref": "#/definitions/package-ecosystem-values" + } + } + } + } + } + } + } + ] +} diff --git a/crates/zizmor/src/github_api.rs b/crates/zizmor/src/github_api.rs index 6e72f101..bc80e550 100644 --- a/crates/zizmor/src/github_api.rs +++ b/crates/zizmor/src/github_api.rs @@ -633,6 +633,14 @@ impl Client { let mut contents = String::with_capacity(entry.size() as usize); entry.read_to_string(&mut contents)?; group.register(InputKind::Action, contents, key, options.strict)?; + } else if matches!( + file_path.file_name(), + Some("dependabot.yml" | "dependabot.yaml") + ) { + let key = InputKey::remote(slug, file_path.to_string())?; + let mut contents = String::with_capacity(entry.size() as usize); + entry.read_to_string(&mut contents)?; + group.register(InputKind::Dependabot, contents, key, options.strict)?; } } diff --git a/crates/zizmor/src/main.rs b/crates/zizmor/src/main.rs index 2ba16a1e..4db92176 100644 --- a/crates/zizmor/src/main.rs +++ b/crates/zizmor/src/main.rs @@ -364,6 +364,8 @@ pub(crate) enum CollectionMode { WorkflowsOnly, /// Collect only action definitions (i.e. `action.yml`). ActionsOnly, + /// Collect only Dependabot configuration files (i.e. `dependabot.yml`). + DependabotOnly, } impl CollectionMode { @@ -387,6 +389,13 @@ impl CollectionMode { CollectionMode::All | CollectionMode::Default | CollectionMode::ActionsOnly ) } + + pub(crate) fn dependabot(&self) -> bool { + matches!( + self, + CollectionMode::All | CollectionMode::Default | CollectionMode::DependabotOnly + ) + } } #[derive(Copy, Clone, Debug, ValueEnum)] diff --git a/crates/zizmor/src/models.rs b/crates/zizmor/src/models.rs index a25a27ac..8a22d777 100644 --- a/crates/zizmor/src/models.rs +++ b/crates/zizmor/src/models.rs @@ -11,6 +11,7 @@ use crate::models::inputs::HasInputs; pub(crate) mod action; pub(crate) mod coordinate; +pub(crate) mod dependabot; pub(crate) mod inputs; pub(crate) mod uses; pub(crate) mod workflow; diff --git a/crates/zizmor/src/models/dependabot.rs b/crates/zizmor/src/models/dependabot.rs new file mode 100644 index 00000000..57e2c50e --- /dev/null +++ b/crates/zizmor/src/models/dependabot.rs @@ -0,0 +1,79 @@ +//! Dependabot config models. +//! +//! These models enrich the models under [`github_actions_models::dependabot`], +//! providing higher-level APIs for zizmor to use. + +use github_actions_models::dependabot; +use terminal_link::Link; + +use crate::{ + finding::location::{SymbolicFeature, SymbolicLocation}, + models::AsDocument, + registry::input::{CollectionError, InputKey}, + utils::{DEPENDABOT_VALIDATOR, from_str_with_validation}, +}; + +pub(crate) struct Dependabot { + pub(crate) key: InputKey, + pub(crate) link: Option, + document: yamlpath::Document, + inner: dependabot::v2::Dependabot, +} + +impl<'a> AsDocument<'a, 'a> for Dependabot { + fn as_document(&'a self) -> &'a yamlpath::Document { + &self.document + } +} + +impl std::ops::Deref for Dependabot { + type Target = dependabot::v2::Dependabot; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl std::fmt::Debug for Dependabot { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{key}", key = self.key) + } +} + +impl Dependabot { + pub(crate) fn from_string(contents: String, key: InputKey) -> Result { + let inner = from_str_with_validation(&contents, &DEPENDABOT_VALIDATOR)?; + + let document = yamlpath::Document::new(&contents)?; + + let link = match key { + InputKey::Local(_) => None, + InputKey::Remote(_) => { + // NOTE: InputKey's Display produces a URL, hence `key.to_string()`. + Some(Link::new(key.presentation_path(), &key.to_string()).to_string()) + } + }; + + Ok(Self { + key, + link, + document, + inner, + }) + } + + /// Returns this Dependabot config's [`SymbolicLocation`]. + /// + /// See [`Workflow::location`] for an explanation of why this isn't + /// implemented through the [`Locatable`] trait. + pub(crate) fn location(&self) -> SymbolicLocation<'_> { + SymbolicLocation { + key: &self.key, + annotation: "this config".to_string(), + link: None, + route: Default::default(), + feature_kind: SymbolicFeature::Normal, + kind: Default::default(), + } + } +} diff --git a/crates/zizmor/src/registry/input.rs b/crates/zizmor/src/registry/input.rs index 8433894a..ca14c074 100644 --- a/crates/zizmor/src/registry/input.rs +++ b/crates/zizmor/src/registry/input.rs @@ -15,7 +15,7 @@ use crate::{ audit::AuditInput, config::{Config, ConfigError}, github_api::{Client, ClientError}, - models::{action::Action, workflow::Workflow}, + models::{action::Action, dependabot::Dependabot, workflow::Workflow}, }; /// Errors that can occur while collecting inputs. @@ -99,6 +99,8 @@ pub(crate) enum InputKind { Workflow, /// An action definition. Action, + /// A Dependabot configuration file. + Dependabot, } impl std::fmt::Display for InputKind { @@ -106,6 +108,7 @@ impl std::fmt::Display for InputKind { match self { InputKind::Workflow => write!(f, "workflow"), InputKind::Action => write!(f, "action"), + InputKind::Dependabot => write!(f, "dependabot config"), } } } @@ -348,6 +351,9 @@ impl InputGroup { let input: Result = match kind { InputKind::Workflow => Workflow::from_string(contents, key.clone()).map(|wf| wf.into()), InputKind::Action => Action::from_string(contents, key.clone()).map(|a| a.into()), + InputKind::Dependabot => { + Dependabot::from_string(contents, key.clone()).map(|d| d.into()) + } }; match input { @@ -375,6 +381,11 @@ impl InputGroup { // When collecting individual files, we don't know which part // of the input path is the prefix. let (key, kind) = match (path.file_stem(), path.extension()) { + (Some("dependabot"), Some("yml" | "yaml")) => ( + // NOTE: Safe unwrap because we just checked the filename. + InputKey::local(Group(path.as_str().into()), path, None).unwrap(), + InputKind::Dependabot, + ), (Some("action"), Some("yml" | "yaml")) => ( // NOTE: Safe unwrap because we just checked the filename. InputKey::local(Group(path.as_str().into()), path, None).unwrap(), @@ -466,6 +477,25 @@ impl InputGroup { })?; group.register(InputKind::Action, contents, key, options.strict)?; } + + if options.mode.dependabot() + && entry.is_file() + && matches!( + entry.file_name(), + Some("dependabot.yml" | "dependabot.yaml") + ) + { + // NOTE: Safe unwrap because we just checked the filename. + let key = InputKey::local(Group(path.as_str().into()), entry, Some(path)).unwrap(); + let contents = std::fs::read_to_string(entry).map_err(|e| { + CollectionError::Inner( + CollectionError::Io(e).into(), + key.to_string(), + InputKind::Dependabot, + ) + })?; + group.register(InputKind::Dependabot, contents, key, options.strict)?; + } } Ok(group) diff --git a/crates/zizmor/src/utils.rs b/crates/zizmor/src/utils.rs index 949e8742..b1bae77d 100644 --- a/crates/zizmor/src/utils.rs +++ b/crates/zizmor/src/utils.rs @@ -18,13 +18,18 @@ use std::{fmt::Write, sync::LazyLock}; use crate::{audit::AuditInput, models::AsDocument, registry::input::CollectionError}; +pub(crate) static WORKFLOW_VALIDATOR: LazyLock = LazyLock::new(|| { + validator_for(&serde_json::from_str(include_str!("./data/github-workflow.json")).unwrap()) + .unwrap() +}); + pub(crate) static ACTION_VALIDATOR: LazyLock = LazyLock::new(|| { validator_for(&serde_json::from_str(include_str!("./data/github-action.json")).unwrap()) .unwrap() }); -pub(crate) static WORKFLOW_VALIDATOR: LazyLock = LazyLock::new(|| { - validator_for(&serde_json::from_str(include_str!("./data/github-workflow.json")).unwrap()) +pub(crate) static DEPENDABOT_VALIDATOR: LazyLock = LazyLock::new(|| { + validator_for(&serde_json::from_str(include_str!("./data/dependabot-2.0.json")).unwrap()) .unwrap() }); diff --git a/docs/snippets/help.txt b/docs/snippets/help.txt index 60079a89..be73a170 100644 --- a/docs/snippets/help.txt +++ b/docs/snippets/help.txt @@ -43,7 +43,7 @@ Options: --cache-dir The directory to use for HTTP caching. By default, a host-appropriate user-caching directory will be used --collect - Control which kinds of inputs are collected for auditing [default: default] [possible values: all, default, workflows-only, actions-only] + Control which kinds of inputs are collected for auditing [default: default] [possible values: all, default, workflows-only, actions-only, dependabot-only] --strict-collection Fail instead of warning on syntax and schema errors in collected inputs --completions