Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 38 additions & 19 deletions bots/rhodibot/src/fleet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,20 +48,23 @@ fn rule_id(check_name: &str) -> String {
// Map known checks to stable rule IDs
match check_name {
"README.adoc" => format!("{}-001", RULE_PREFIX),
"LICENSE.txt" => format!("{}-002", RULE_PREFIX),
"SECURITY.md" => format!("{}-003", RULE_PREFIX),
"CONTRIBUTING.md" => format!("{}-004", RULE_PREFIX),
"CODE_OF_CONDUCT.md" => format!("{}-005", RULE_PREFIX),
"LICENSE.txt" | "LICENSE" => format!("{}-002", RULE_PREFIX),
"SECURITY.md" | "SECURITY.adoc" => format!("{}-003", RULE_PREFIX),
"CONTRIBUTING.md" | "CONTRIBUTING.adoc" => format!("{}-004", RULE_PREFIX),
"CODE_OF_CONDUCT.md" | "CODE_OF_CONDUCT.adoc" => format!("{}-005", RULE_PREFIX),
".claude/CLAUDE.md" => format!("{}-006", RULE_PREFIX),
".machine_readable/STATE.scm" => format!("{}-007", RULE_PREFIX),
".machine_readable/META.scm" => format!("{}-008", RULE_PREFIX),
".machine_readable/ECOSYSTEM.scm" => format!("{}-009", RULE_PREFIX),
".machine_readable/STATE.scm" | ".machine_readable/STATE.a2ml" => format!("{}-007", RULE_PREFIX),
".machine_readable/META.scm" | ".machine_readable/META.a2ml" => format!("{}-008", RULE_PREFIX),
".machine_readable/ECOSYSTEM.scm" | ".machine_readable/ECOSYSTEM.a2ml" => format!("{}-009", RULE_PREFIX),
".github/workflows" => format!("{}-010", RULE_PREFIX),
".editorconfig" => format!("{}-011", RULE_PREFIX),
".gitattributes" => format!("{}-012", RULE_PREFIX),
".gitignore" => format!("{}-013", RULE_PREFIX),
"justfile" => format!("{}-014", RULE_PREFIX),
"justfile" | "Justfile" => format!("{}-014", RULE_PREFIX),
".machine_readable/bot_directives" => format!("{}-015", RULE_PREFIX),
"0-AI-MANIFEST.a2ml" => format!("{}-016", RULE_PREFIX),
"www/.well-known/security.txt" => format!("{}-017", RULE_PREFIX),
".machine_readable/root-allow.txt" => format!("{}-018", RULE_PREFIX),
"no-.bot_directives" => format!("{}-LEGACY-001", RULE_PREFIX),
"license-type" => format!("{}-LIC-001", RULE_PREFIX),
name if name.starts_with("no-") => {
Expand All @@ -75,21 +78,27 @@ fn rule_id(check_name: &str) -> String {
fn suggestion_for(check_name: &str) -> Option<String> {
match check_name {
"README.adoc" => Some("Create a README.adoc file with project documentation".to_string()),
"LICENSE.txt" => Some("Add a LICENSE.txt file with MPL-2.0".to_string()),
"SECURITY.md" => Some("Add a SECURITY.md with vulnerability reporting instructions".to_string()),
"CONTRIBUTING.md" => Some("Add a CONTRIBUTING.md with contribution guidelines".to_string()),
"CODE_OF_CONDUCT.md" => Some("Add a CODE_OF_CONDUCT.md (Contributor Covenant recommended)".to_string()),
"LICENSE.txt" | "LICENSE" => Some("Add a LICENSE file with MPL-2.0 (LICENSE is the current spelling)".to_string()),
"SECURITY.adoc" | "SECURITY.md" => Some("Add a SECURITY.adoc with vulnerability reporting instructions".to_string()),
"CONTRIBUTING.adoc" | "CONTRIBUTING.md" => Some("Add a CONTRIBUTING.adoc with contribution guidelines".to_string()),
"CODE_OF_CONDUCT.adoc" | "CODE_OF_CONDUCT.md" => Some("Add a CODE_OF_CONDUCT.adoc (Contributor Covenant recommended)".to_string()),
".claude/CLAUDE.md" => Some("Create .claude/CLAUDE.md with AI assistant instructions".to_string()),
".machine_readable/STATE.scm" => Some("Add .machine_readable/STATE.scm with project state".to_string()),
".machine_readable/META.scm" => Some("Add .machine_readable/META.scm with meta information".to_string()),
".machine_readable/ECOSYSTEM.scm" => Some("Add .machine_readable/ECOSYSTEM.scm with ecosystem position".to_string()),
".machine_readable/STATE.a2ml" | ".machine_readable/STATE.scm" => Some("Add .machine_readable/STATE.a2ml with project state".to_string()),
".machine_readable/META.a2ml" | ".machine_readable/META.scm" => Some("Add .machine_readable/META.a2ml with meta information".to_string()),
".machine_readable/ECOSYSTEM.a2ml" | ".machine_readable/ECOSYSTEM.scm" => Some("Add .machine_readable/ECOSYSTEM.a2ml with ecosystem position".to_string()),
".github/workflows" => Some("Add GitHub Actions workflows in .github/workflows/".to_string()),
".editorconfig" => Some("Add .editorconfig for consistent formatting".to_string()),
".gitattributes" => Some("Add .gitattributes for line ending and diff config".to_string()),
".gitignore" => Some("Add .gitignore for build artifacts".to_string()),
"justfile" => Some("Add a justfile as the primary build system".to_string()),
"Justfile" | "justfile" => Some("Add a Justfile as the primary build system".to_string()),
".machine_readable/bot_directives" => Some("Create .machine_readable/bot_directives/ for bot configs".to_string()),
"no-.bot_directives" => Some("Migrate legacy .bot_directives/ to .machine_readable/bot_directives/".to_string()),
"0-AI-MANIFEST.a2ml" => Some("Add a 0-AI-MANIFEST.a2ml machine-readable manifest at the repository root".to_string()),
"www/.well-known/security.txt" => Some("Create www/.well-known/security.txt; run scripts/migrate-wellknown-to-www.sh to move an existing root .well-known/".to_string()),
".machine_readable/root-allow.txt" => Some("Add .machine_readable/root-allow.txt declaring the permitted root entries".to_string()),
// Move, do not delete: the generic no- arm below would advise
// removing the file, which loses live security-contact metadata.
"no-.well-known/security.txt" => Some("Migrate the root .well-known/ to www/.well-known/ with scripts/migrate-wellknown-to-www.sh - move it, do not delete it".to_string()),
"license-type" => Some("Set repository license to an approved type (MPL-2.0 recommended)".to_string()),
name if name.starts_with("no-") => {
let banned_file = name.strip_prefix("no-").unwrap_or(name);
Expand All @@ -106,10 +115,20 @@ fn suggestion_for(check_name: &str) -> Option<String> {
/// fixable. Files without templates (CONTRIBUTING.md, CODE_OF_CONDUCT.md)
/// would produce empty boilerplate and are excluded.
fn is_fixable(check_name: &str) -> bool {
// Must match the arms of robot-repo-automaton's get_template_content()
// exactly. That function falls through to String::new() for anything it
// does not recognise, so advertising a check as fixable without a
// template behind it makes the automaton open a PR that creates the file
// EMPTY - and inbox-steward auto-merges PRs that pass CI.
//
// This list was previously four entries wider than the templates
// (.gitattributes, .gitignore, .claude/CLAUDE.md and
// .machine_readable/bot_directives), which is how an empty-file PR could
// reach a repository and be merged without anyone reading it.
matches!(check_name,
"SECURITY.md" |
".editorconfig" | ".gitattributes" | ".gitignore" |
".claude/CLAUDE.md" | ".machine_readable/bot_directives"
"LICENSE" | "LICENSE.txt" |
"SECURITY.adoc" | "SECURITY.md" |
".editorconfig"
)
}

Expand Down
Loading
Loading