You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This issue is the plan of record for bringing Crossterm’s CI up to a level that can safely support required checks and, later, GitHub-based releases. It is related to the release discussion in #1023, but publishing and trusted publishing remain separate follow-up work.
The work will land as small PRs. Each PR should link this issue, and this checklist will be updated as work lands.
Implementation plan
1. Harden the existing workflow
Rename the existing workflow to ci.yml while preserving approximately its current coverage.
Pin actions/checkout to 3d3c42e5aac5ba805825da76410c181273ba90b1 (v7.0.1) with persist-credentials: false.
Replace hecrj/setup-rust-action@master with dtolnay/rust-toolchain@2c7215f132e9ebf062739d9130488b56d53c060c, a durable commit from the action’s master history.
Set explicit contents: read permissions and grant no write permissions or secrets.
The initial Rust installer pin used a generated toolchain-branch commit. #1083 corrects it to master history because the workflows supply the toolchain input explicitly and unreachable generated commits may eventually be garbage-collected.
This PR changed workflow execution and security, not Rust policy or test coverage.
2. Establish the lockfile baseline
Begin tracking the repository-root Cargo.lock generated from the existing manifests.
Establish a resolution baseline that does not contain the identified vulnerable or yanked bytes 1.6.0 and futures-util 0.3.30 releases.
Confirm that obsolete transitive dependencies observed during the audit, such as adler, are absent from the baseline.
Keep manifest requirements unchanged unless a newer minimum is genuinely required.
Include a dependency-tree summary and run the full existing test suite.
The repository did not previously track its root lockfile, so this was not an update against a committed dependency graph. It recorded the versions Cargo resolved at that point from the existing semver requirements. Future refreshes can be reviewed as normal lockfile diffs against this baseline.
Any unmaintained development-only dependency without a safe replacement must receive a documented temporary advisory exception and a linked follow-up issue.
The temporary async-std exception was resolved in #1079.
3. Set and enforce Rust 1.85 as the MSRV
Narrow #1059 to the MSRV policy change, lockfile adjustment if required, and changelog entry.
Keep source rewrites limited to the mechanical changes required when MSRV-aware Clippy sees Rust 1.85.
Set rust-version = "1.85.0".
Define MSRV as covering the library with no default features and with every public feature enabled; development tools and examples do not independently define the crate’s MSRV.
Add required Rust 1.85 checks for both configurations.
The current Rust 1.63 declaration is not retained: the all-public-features graph currently resolves a dependency requiring Rust 1.85. Preserving 1.63 would require selecting and maintaining older transitive releases.
4. Migrate to the Rust 2024 edition
Run rustup run 1.85.0 cargo fix --edition --allow-dirty --locked --all-targets --all-features while the manifest still declares Rust 2021, then review every generated change.
Preserve the existing matching behavior of exported macros unless a broader input grammar is chosen deliberately; Cargo’s migration uses expr_2021 fragments to avoid silently changing public macro behavior.
Replace the generated unsafe environment-variable mutations in test_no_color with the existing temp-env test helper rather than retaining generated FIXME blocks.
Set edition = "2024" only after applying and reviewing the migration fixups.
Run Rustfmt after changing the manifest and review its style-edition churn separately from the semantic migration fixups.
Confirm that resolver version 3, implied by the 2024 edition, does not unexpectedly change the tracked lockfile or dependency graph.
Verify the no-default-features and all-public-features library configurations with Rust 1.85.0, then run formatting, Clippy, docs, doctests, all-target/all-feature tests, explicit feature checks, and package verification.
Add a changelog entry explaining the edition change and any edition-driven semantic changes retained after review.
Rust 1.85 is the first release supporting Rust 2024, so the edition change fits the newly declared MSRV. Follow Cargo’s documented two-step migration: run cargo fix --edition first, then update the manifest. The 2024 edition also implies resolver version 3, which is Rust-version aware.
A local trial on the merged Rust 1.85 baseline completed successfully. Cargo produced fixups in five source files; changing the manifest and running Rustfmt expanded the mechanical diff to 29 files. Rust 1.85 checks for the library with no default features and all features passed, as did the full all-target/all-feature test suite on macOS.
Add focused format, clippy, docs, test, doctest, msrv, and package jobs.
Run stable tests on Linux, macOS, and Windows with all targets and features, keeping tests single-threaded initially.
Run tests for the deliberate Unix compatibility points: defaults, serde, event-stream, no defaults, events, and events,event-stream,use-dev-tty,bracketed-paste.
Run tests for windows and windows,events; document that bare no-defaults is intentionally rejected on Windows.
Verify cargo package --locked on Linux and Windows.
Add a stable ci-success aggregation job intended to be the only required status check.
Move beta and nightly compatibility to a weekly and manually dispatched workflow.
Document the required local commands in the contribution guide.
Add an advisory beta-Clippy check that warns about likely next-stable lint failures without blocking pull requests.
Do not add CI caching until job timings demonstrate a need.
The feature matrix records deliberate compatibility points rather than an exhaustive powerset. Consider cargo-hack later if broader coverage justifies the additional runtime, policy, and pinned-tool maintenance. Stable Clippy remains required; beta Clippy is advisory because it is useful early warning but changes independently of the repository.
Completed in #1085: a justfile makes the growing set of local formatting, lint, documentation, MSRV, feature, test, and package checks easier to run correctly. The workflow commands remain the source of truth, with just recipes providing memorable entry points rather than creating a second CI policy.
6. Add dependency, API, and workflow integrity checks
Add deny.toml and require cargo-deny 0.20.2.
Allow the reviewed SPDX licenses used by the dependency graph: MIT, Apache-2.0, Apache-2.0 WITH LLVM-exception, and Unicode-3.0.
Fail on vulnerabilities, yanked releases, unknown registries, unreviewed Git sources, and unapproved licenses.
Add cargo-semver-checks 0.49.0 against the latest crates.io release.
Keep semver checking informational on ordinary PRs; make it blocking later in the release-preparation workflow.
Run Actionlint 1.7.12 and Zizmor 1.28.0 for workflow changes.
Use pinned, maintained first-party actions for cargo-deny and Zizmor and Actionlint's official container image.
Add grouped monthly Cargo dependency updates with increase-if-necessary, leaving manifest requirements unchanged when they already permit the update.
When repository administration is available, enable Zizmor SARIF through its official action and decide whether Code Scanning findings should block merges.
The dependency and workflow-policy subset was completed in #1084. The license list was refined against the resolved all-features graph, including development dependencies: Unicode-3.0 is required, while the initially proposed Unicode-DFS-2016, 0BSD, Zlib, and Unlicense allowances are not needed. API compatibility reporting remains a later review unit because it has different policy and failure semantics. Zizmor SARIF is deliberately deferred until repository Code Scanning settings can be configured; the required read-only audit still runs for every pull request.
Repository settings
After ci-success passes on master and representative fork PRs:
Create a master ruleset requiring pull requests and ci-success.
Prevent force pushes and branch deletion.
Require review conversations to be resolved.
Do not initially require every matrix job separately or require stale branches to be continuously rebased.
Re-evaluate the Actions approval setting so safe, read-only CI can run automatically for external contributors.
Do not use pull_request_target.
Acceptance criteria
Fork PRs run with read-only permissions, no secrets, pinned actions, and no persisted credentials.
Linux, macOS, Windows, public feature combinations, Rust 1.85, Rustdoc, doctests, and package verification are covered.
The publishable package is verified on both Unix and Windows.
Fixable advisories and yanked dependencies fail CI.
Public API compatibility is reported without automatically choosing the release version.
Workflow changes validate themselves.
master cannot merge while ci-success is failing.
No CI job has crates.io, tag, release, or other publishing authority.
Assumptions
This issue covers CI and repository protections only; the release workflow remains a follow-up linked to crates.io out of date #1023.
Release-plz is not introduced in this work.
crossterm-winapi provenance and release coordination are handled in the later release-process plan.
No public Rust API changes are intended; the Rust 2024 migration follows the MSRV change and remains compatible with Rust 1.85.
Summary
This issue is the plan of record for bringing Crossterm’s CI up to a level that can safely support required checks and, later, GitHub-based releases. It is related to the release discussion in #1023, but publishing and trusted publishing remain separate follow-up work.
The work will land as small PRs. Each PR should link this issue, and this checklist will be updated as work lands.
Implementation plan
1. Harden the existing workflow
ci.ymlwhile preserving approximately its current coverage.actions/checkoutto3d3c42e5aac5ba805825da76410c181273ba90b1(v7.0.1) withpersist-credentials: false.hecrj/setup-rust-action@masterwithdtolnay/rust-toolchain@2c7215f132e9ebf062739d9130488b56d53c060c, a durable commit from the action’smasterhistory.contents: readpermissions and grant no write permissions or secrets.fail-fast: false, deliberate runner versions, andworkflow_dispatch.Completed in #1076.
The initial Rust installer pin used a generated toolchain-branch commit. #1083 corrects it to
masterhistory because the workflows supply thetoolchaininput explicitly and unreachable generated commits may eventually be garbage-collected.This PR changed workflow execution and security, not Rust policy or test coverage.
2. Establish the lockfile baseline
Cargo.lockgenerated from the existing manifests.bytes 1.6.0andfutures-util 0.3.30releases.adler, are absent from the baseline.Completed in #1078.
The repository did not previously track its root lockfile, so this was not an update against a committed dependency graph. It recorded the versions Cargo resolved at that point from the existing semver requirements. Future refreshes can be reviewed as normal lockfile diffs against this baseline.
Any unmaintained development-only dependency without a safe replacement must receive a documented temporary advisory exception and a linked follow-up issue.
The temporary
async-stdexception was resolved in #1079.3. Set and enforce Rust 1.85 as the MSRV
rust-version = "1.85.0".Completed in #1059.
The current Rust 1.63 declaration is not retained: the all-public-features graph currently resolves a dependency requiring Rust 1.85. Preserving 1.63 would require selecting and maintaining older transitive releases.
4. Migrate to the Rust 2024 edition
rustup run 1.85.0 cargo fix --edition --allow-dirty --locked --all-targets --all-featureswhile the manifest still declares Rust 2021, then review every generated change.expr_2021fragments to avoid silently changing public macro behavior.unsafeenvironment-variable mutations intest_no_colorwith the existingtemp-envtest helper rather than retaining generatedFIXMEblocks.edition = "2024"only after applying and reviewing the migration fixups.Rust 1.85 is the first release supporting Rust 2024, so the edition change fits the newly declared MSRV. Follow Cargo’s documented two-step migration: run
cargo fix --editionfirst, then update the manifest. The 2024 edition also implies resolver version 3, which is Rust-version aware.A local trial on the merged Rust 1.85 baseline completed successfully. Cargo produced fixups in five source files; changing the manifest and running Rustfmt expanded the mechanical diff to 29 files. Rust 1.85 checks for the library with no default features and all features passed, as did the full all-target/all-feature test suite on macOS.
Completed in #1081.
5. Establish the required CI gate
Completed in #1083.
format,clippy,docs,test,doctest,msrv, andpackagejobs.serde,event-stream, no defaults,events, andevents,event-stream,use-dev-tty,bracketed-paste.windowsandwindows,events; document that bare no-defaults is intentionally rejected on Windows.cargo package --lockedon Linux and Windows.ci-successaggregation job intended to be the only required status check.Do not add CI caching until job timings demonstrate a need.
The feature matrix records deliberate compatibility points rather than an exhaustive powerset. Consider cargo-hack later if broader coverage justifies the additional runtime, policy, and pinned-tool maintenance. Stable Clippy remains required; beta Clippy is advisory because it is useful early warning but changes independently of the repository.
Completed in #1085: a
justfilemakes the growing set of local formatting, lint, documentation, MSRV, feature, test, and package checks easier to run correctly. The workflow commands remain the source of truth, withjustrecipes providing memorable entry points rather than creating a second CI policy.6. Add dependency, API, and workflow integrity checks
deny.tomland requirecargo-deny 0.20.2.cargo-semver-checks 0.49.0against the latest crates.io release.increase-if-necessary, leaving manifest requirements unchanged when they already permit the update.The dependency and workflow-policy subset was completed in #1084. The license list was refined against the resolved all-features graph, including development dependencies:
Unicode-3.0is required, while the initially proposedUnicode-DFS-2016,0BSD,Zlib, andUnlicenseallowances are not needed. API compatibility reporting remains a later review unit because it has different policy and failure semantics. Zizmor SARIF is deliberately deferred until repository Code Scanning settings can be configured; the required read-only audit still runs for every pull request.Repository settings
After
ci-successpasses onmasterand representative fork PRs:masterruleset requiring pull requests andci-success.pull_request_target.Acceptance criteria
mastercannot merge whileci-successis failing.Assumptions
crossterm-winapiprovenance and release coordination are handled in the later release-process plan.