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
13 changes: 8 additions & 5 deletions .mise/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -1594,11 +1594,14 @@ published=$(git ls-files 'verification/published/**/Dockerfile')
# shellcheck disable=SC2086
conftest test --namespace dockerfile_stages -p config/conftest/policy $published
# Filter to Dockerfiles that actually use heredocs before the `ignore` parser.
for f in $files; do
if rg -q '^RUN[^\\n]*<<' "$f"; then
conftest test --parser ignore --namespace dockerfile_heredoc -p config/conftest/policy "$f"
fi
done
# Combined so each file arrives as {path, contents}, the shape the heredoc policy reads its entries from.
# rg exits 1 when no file matches, which leaves nothing to check rather than an error.
# shellcheck disable=SC2086
heredoc_files=$(rg -l '^RUN[^\\n]*<<' $files) || [ $? -eq 1 ]
if [ -n "$heredoc_files" ]; then
# shellcheck disable=SC2086
conftest test --combine --parser ignore --namespace dockerfile_heredoc -p config/conftest/policy $heredoc_files
fi
"""
shell = "{{ vars.task_shell }}"

Expand Down
14 changes: 10 additions & 4 deletions CHECKS.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# Checks

- **Generated:** 2026-11-09
- **Generated:** 2026-11-10
- **Checks:** 84
- **Tools:** 49
- **Shell-script checks:** 10
- **Checks with a repair pass:** 22
- **Rules:** 378 custom local rules, or non-default strict linter settings
- **Meta rules:** 21 of those rules are rules about rules
- **Rules:** 379 custom local rules, or non-default strict linter settings
- **Meta rules:** 22 of those rules are rules about rules

Every check is listed across every `MISE_ENV`, filed under the tool it runs. Each entry names the env whose config
declares it, the aggregate that runs it as part of `mise run check`, the `fix` or `fmt` pass that repairs what it
Expand Down Expand Up @@ -665,7 +665,7 @@ Rules, from `config/conftest/policy`:
- `pyrefly_python_sync` (`config/conftest/policy/cross/pyrefly_python_sync.rego`):
- pyrefly must pin the Python version it type-checks against.
- pyrefly's pinned Python version must equal the mise `python` pin, the version every lane installs.
- `wasm-bindgen-sync` (`config/conftest/policy/cross/wasm-bindgen-sync.rego`):
- `wasm_bindgen_sync` (`config/conftest/policy/cross/wasm_bindgen_sync.rego`):
- The mise wasm-bindgen pin must match the wasm-bindgen version Cargo.lock resolves.
- `dockerfile` (`config/conftest/policy/dockerfile/dockerfile.rego`):
- A version a Dockerfile hard-codes must match the [tools] pin for the same tool.
Expand Down Expand Up @@ -1202,6 +1202,12 @@ Rules, from `config/semgrep`:
- `python-silent-broad-except` -- Silently discarding every ordinary exception can conceal programming errors and lost
work. Catch the expected exception types and explicitly report, recover from, or propagate the failure. Check-only: a
safe recovery policy cannot be inferred from the handler alone.
- `rego-iterate-normalised-files` (meta) -- Iterate `paths.files` (with `import data.paths`) instead of `input`. The
policy runner reports each path with the native separator of the OS it runs on, so on Windows a rule matching
`file.path` against `.mise/config.toml` or `.github/workflows/` sees backslashes and matches nothing -- and that fails
open, with the namespace reporting clean on that lane while checking nothing. `paths.files` is the same input with
every path normalised to forward slashes, so a rule written once works on every OS. Where `input` is one document
rather than a list of files, bind it to a name that says so and iterate that.
- `rego-rule-summary` (meta) -- This Rego rule has no summary comment. The generated catalogue of every check lists each
policy rule by the first line of the comment above it, and refuses to build without one, so describe what the rule
enforces in a comment opening at column 0 between the previous rule's closing brace and this rule. The file's header
Expand Down
4 changes: 3 additions & 1 deletion config/conftest/policy/advisories/advisories.rego
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
# reason this cannot parse, fails immediately rather than quietly becoming the one exception with no deadline.
package advisories

import data.paths

# The `reason` spelling the date is read from, anchored so trailing prose cannot hide a second date.
expiry_pattern := `^expires ([0-9]{4}-[0-9]{2}-[0-9]{2})$`

Expand All @@ -21,7 +23,7 @@ lapsed_msg := "config/deny.toml: advisory ignore %q lapsed on %s -- drop it, fix
mixed_msg := "config/deny.toml: advisory ignores expire on %d dates, %v; a new entry takes the date the others carry"

entries contains entry if {
some file in input
some file in paths.files
file.path == "config/deny.toml"
some entry in file.contents.advisories.ignore
}
Expand Down
6 changes: 4 additions & 2 deletions config/conftest/policy/ast_grep_rules/ast_grep_rules.rego
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,19 @@
# meta: true
package ast_grep_rules

import data.paths

severity_msg := "%s: ast-grep rule %q has severity %q; every rule here is a gate, so it declares `severity: error`"

# Every rule in the input, paired with the file defining it.
rules contains [file.path, rule] if {
some file in input
some file in paths.files
is_object(file.contents)
rule := file.contents
}

rules contains [file.path, rule] if {
some file in input
some file in paths.files
is_array(file.contents)
some rule in file.contents
}
Expand Down
4 changes: 3 additions & 1 deletion config/conftest/policy/branch_size/branch_size.rego
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,16 @@
# branches that each stay at or under it.
package branch_size

import data.paths

# The most files a pull request may modify and still be reviewed by CodeRabbit.
max_files := 100

too_many_msg := "this branch modifies %d files, over the %d CodeRabbit reviews in one pull request -- split it up"

# Every path in the list, blank lines aside.
changed contains line.Original if {
some file in input
some file in paths.files
some line in file.contents
line.Original != ""
}
Expand Down
50 changes: 26 additions & 24 deletions config/conftest/policy/cargo/cargo.rego
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,29 @@
# exactly "Cargo.toml" and any other match is a member crate.
package cargo

import data.paths

is_member(file) if {
endswith(file.path, "Cargo.toml")
file.path != "Cargo.toml"
}

# Every dependency spec across the dep tables, as [path, name, spec] triples.
dep contains [file.path, name, spec] if {
some file in input
some file in paths.files
endswith(file.path, "Cargo.toml")
some table in {"dependencies", "dev-dependencies", "build-dependencies"}
some name, spec in file.contents[table]
}

dep contains [file.path, name, spec] if {
some file in input
some file in paths.files
endswith(file.path, "Cargo.toml")
some name, spec in file.contents.workspace.dependencies
}

dep contains [file.path, name, spec] if {
some file in input
some file in paths.files
endswith(file.path, "Cargo.toml")
some tgt in file.contents.target
some table in {"dependencies", "dev-dependencies", "build-dependencies"}
Expand Down Expand Up @@ -92,7 +94,7 @@ wildcard(spec) if {
# Member [dependencies]/[dev-dependencies] must inherit via workspace = true so pins stay in [workspace.dependencies].
# (build-dependencies not covered yet.)
deny contains msg if {
some file in input
some file in paths.files
is_member(file)
some table in {"dependencies", "dev-dependencies"}
some name, spec in file.contents[table]
Expand All @@ -103,7 +105,7 @@ deny contains msg if {
# A crate with a [lib] must disable the doctest harness and must not rename the lib.
# Runnable examples belong in tests/ files; keep the lib name as the package name.
deny contains msg if {
some file in input
some file in paths.files
is_member(file)
file.contents.lib
not file.contents.lib.doctest == false
Expand All @@ -112,7 +114,7 @@ deny contains msg if {

# A member crate's [lib] must not rename the library away from the package name.
deny contains msg if {
some file in input
some file in paths.files
is_member(file)
file.contents.lib.name
msg := sprintf("%s: [lib] must not set name (keep it the package name)", [file.path])
Expand All @@ -121,7 +123,7 @@ deny contains msg if {
# Every member must inherit the workspace lint tables.
# generated/rust-rest is exempt: progenitor's emitted source trips lints the workspace table denies.
deny contains msg if {
some file in input
some file in paths.files
is_member(file)
file.path != "generated/rust-rest/Cargo.toml"
not file.contents.lints.workspace == true
Expand All @@ -131,14 +133,14 @@ deny contains msg if {
# Every crate must be a registered workspace member, with no orphan crates.
# Its directory must appear in the root manifest's explicit [workspace].members list.
workspace_member contains m if {
some file in input
some file in paths.files
file.path == "Cargo.toml"
some m in file.contents.workspace.members
}

# Every member crate must be registered in the root [workspace].members.
deny contains msg if {
some file in input
some file in paths.files
is_member(file)
dir := trim_suffix(file.path, "/Cargo.toml")
not workspace_member[dir]
Expand All @@ -150,7 +152,7 @@ deny contains msg if {
inherited_package_field := {"edition", "license", "repository"}

deny contains msg if {
some file in input
some file in paths.files
is_member(file)
some field in inherited_package_field
not file.contents.package[field].workspace == true
Expand All @@ -165,7 +167,7 @@ allowed_crate_name(name) if startswith(name, "et-")
allowed_crate_name(name) if startswith(name, "int-")

deny contains msg if {
some file in input
some file in paths.files
is_member(file)
name := file.contents.package.name
not allowed_crate_name(name)
Expand All @@ -176,7 +178,7 @@ deny contains msg if {
# Publishing is the consequential choice here (a crates.io upload cannot be withdrawn), so each crate declares
# its intent where a reader looks for it instead of the reader having to know the default.
deny contains msg if {
some file in input
some file in paths.files
is_member(file)
not is_boolean(file.contents.package.publish)
msg := sprintf("%s: [package] must set publish explicitly (true, or false for an int- crate)", [file.path])
Expand All @@ -187,7 +189,7 @@ deny contains msg if {
# Keeping it biconditional means the crate list cannot drift into a state where a reader has to open the
# manifest to learn whether a crate ships -- the name alone answers it.
deny contains msg if {
some file in input
some file in paths.files
is_member(file)
name := file.contents.package.name
contains(name, "int-")
Expand All @@ -197,7 +199,7 @@ deny contains msg if {

# A crate without the int- marker must set publish = true.
deny contains msg if {
some file in input
some file in paths.files
is_member(file)
name := file.contents.package.name
not contains(name, "int-")
Expand All @@ -207,7 +209,7 @@ deny contains msg if {

# The version each member crate declares, keyed by crate name.
member_version[name] := version if {
some file in input
some file in paths.files
is_member(file)
name := file.contents.package.name
version := file.contents.package.version
Expand All @@ -218,7 +220,7 @@ member_version[name] := version if {
# so a stale pin here stays invisible to check/test/clippy and first fails during `cargo publish` -- partway
# through a workspace release, once earlier crates are already uploaded and cannot be withdrawn.
deny contains msg if {
some file in input
some file in paths.files
file.path == "Cargo.toml"
some name, spec in file.contents.workspace.dependencies
is_object(spec)
Expand Down Expand Up @@ -265,7 +267,7 @@ path_dep(spec) if {
}

root_dep[name] := spec if {
some file in input
some file in paths.files
file.path == "Cargo.toml"
some name, spec in file.contents.workspace.dependencies
}
Expand Down Expand Up @@ -297,7 +299,7 @@ deny contains msg if {
# cargo only warns locally, which means a missing description fails at upload time -- partway through a
# workspace release, leaving some crates published at the new version and the rest behind.
deny contains msg if {
some file in input
some file in paths.files
is_member(file)
file.contents.package.publish == true
not is_string(file.contents.package.description)
Expand All @@ -322,7 +324,7 @@ is_dep_name(file, name) if {

# A member crate's feature must not share its name with one of its dependencies.
deny contains msg if {
some file in input
some file in paths.files
is_member(file)
file.path != "generated/rust-rest/Cargo.toml"
some feat, _ in file.contents.features
Expand All @@ -334,21 +336,21 @@ dep_feature_hint := "name it for what it gives the crate's user (where it runs,

# The feature names config/cargo-features.toml allows, which a human keeps.
allowed_features contains name if {
some file in input
some file in paths.files
file.path == "config/cargo-features.toml"
some name, _ in file.contents.features
}

# Every feature name a member crate declares.
declared_features contains name if {
some file in input
some file in paths.files
is_member(file)
some name, _ in file.contents.features
}

# A member crate's feature must be one config/cargo-features.toml lists.
deny contains msg if {
some file in input
some file in paths.files
is_member(file)
some feat, _ in file.contents.features
not allowed_features[feat]
Expand Down Expand Up @@ -437,7 +439,7 @@ docs_rs_renders(file) if "docs" in file.contents.package.metadata.docs.rs.featur
# The member crates the feature-docs contract applies to.
# generated/rust-rest is exempt: et-int-gen regenerates its src/lib.rs, which carries no `document_features!` call.
feature_docs_subject contains file if {
some file in input
some file in paths.files
is_member(file)
file.path != "generated/rust-rest/Cargo.toml"
declares_feature(file)
Expand Down Expand Up @@ -477,7 +479,7 @@ deny contains msg if {
# Dependency overrides ([patch]/[replace]) belong in the root manifest, not a member crate.
# There they apply workspace-wide and stay in one place; a member can't override deps.
deny contains msg if {
some file in input
some file in paths.files
is_member(file)
some table in {"patch", "replace"}
file.contents[table]
Expand Down
6 changes: 4 additions & 2 deletions config/conftest/policy/cargo/dependencies.rego
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
# `--namespace cargo` evaluation.
package cargo

import data.paths

# An internal crate is one whose name carries the int- marker, as a prefix or after this repo's own `et-`.
# A plain substring test would also catch third-party names such as `color-print-proc-macro`.
internal_crate_name(name) if startswith(name, "int-")
Expand Down Expand Up @@ -38,7 +40,7 @@ inherits_rename(name, spec) if {

# Each root [workspace.dependencies] key that renames its package, mapped to the package it names.
workspace_package_rename[name] := spec.package if {
some file in input
some file in paths.files
file.path == "Cargo.toml"
some name, spec in file.contents.workspace.dependencies
is_object(spec)
Expand All @@ -62,7 +64,7 @@ standalone_crates := {"et-actix-web-config"}

# A standalone crate must not depend on any of this repo's `et-` crates.
deny contains msg if {
some file in input
some file in paths.files
is_member(file)
crate := file.contents.package.name
crate in standalone_crates
Expand Down
6 changes: 4 additions & 2 deletions config/conftest/policy/checks_badge/checks_badge.rego
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,16 @@
# meta: true
package checks_badge

import data.paths

# How far the rules count moves before the badge has to follow: the badge records it rounded down to this.
step := 20

badge_prefix := "[checks-badge]: "

# The rules count from the `- **Rules:** N ...` line of CHECKS.md's header.
rules_count := to_number(match[1]) if {
some file in input
some file in paths.files
endswith(file.path, "CHECKS.md")
some line in file.contents
some match in regex.find_all_string_submatch_n(`^- \*\*Rules:\*\* ([0-9]+) `, line.Original, 1)
Expand All @@ -28,7 +30,7 @@ expected_badge := concat("", [badge_prefix, badge_url_prefix, format_int(rounded
badge_url_prefix := "https://img.shields.io/badge/checks-%3E%3D"

badge_lines contains line.Original if {
some file in input
some file in paths.files
endswith(file.path, "README.md")
some line in file.contents
startswith(line.Original, badge_prefix)
Expand Down
Loading
Loading