Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

OpenSSF Best Practices: Silver Evidence

Rullst holds the Silver OpenSSF Best Practices badge (project 13321), granted on 10 October 2026. This page is the evidence guide for the Silver form, with one row per Silver criterion:

  • the answer to select;
  • a justification ready to paste;
  • the evidence link.

Only a project owner can edit the form. Keep this guide and the form in agreement when an answer changes.

The criteria list was taken from the official Silver criteria on 9 October 2026: 55 criteria (44 MUST, 10 SHOULD, 1 SUGGESTED). Several also appear in the passing form and are already answered there.

How to use it. Open the project’s Silver form, select the answer in the second column and paste the justification. Where the form requires a URL (marked “URL required”), paste the evidence link after the justification. Pages added together with this guide (the assurance case, release verification and reproducible archives) resolve only after the change is merged to main and the book is published.

Blocking

These MUST criteria are not met yet:

CriterionWhat is missing
documentation_achievementsThe README does not show the Best Practices badge yet. PR #447 adds it; merge it, then answer Met with the justification in the Basics table.

Owner confirmations recorded on 9 October 2026:

  • vulnerability_report_credit: the only advisory in the last 12 months (application-key configuration, fixed in 12.1.1) was opened by the maintainer from the project’s own review; no outside reporter needs credit.
  • documentation_current and documentation_roadmap: SECURITY.md names 12.3.0, and ROADMAP.md has a dated twelve-month section.
  • sites_password_security: the demo applications on rullst.win are project sites. They are built from the Rullst starters, which hash passwords with Argon2id (rullst-auth); the answer is Met.

Basics

CriterionAnswerJustification to pasteEvidence
achieve_passingMetRullst holds the passing badge (project 13321).bestpractices.dev/projects/13321
contribution_requirements (URL required)MetCONTRIBUTING.md states the requirements: tests for new functionality and regression tests for fixes, Conventional Commits, cargo fmt, strict Clippy and the full test suite, and the pull-request template.CONTRIBUTING.md
dco (URL required)UnmetNot adopted. Almost all changes come from the single maintainer, and contributors license their work under MIT through GitHub’s terms of service (inbound=outbound), which is not a per-contribution assertion. Adopting it means requiring git commit -s in CONTRIBUTING.md and a DCO check on pull requests.CONTRIBUTING.md
governance (URL required)MetGOVERNANCE.md documents who decides, how proposals are accepted, rejected or deferred, the change and release controls, and continuity.GOVERNANCE.md
code_of_conduct (URL required)MetRullst adopts the Contributor Covenant 2.1 in the standard location.CODE_OF_CONDUCT.md
roles_responsibilities (URL required)MetGOVERNANCE.md names the maintainer and release decision maker, the successor maintainer and the contributor role, with each role’s duties and limits (including AI assistants).GOVERNANCE.md, roles
access_continuity (URL required)MetSince 8 October 2026 a successor maintainer holds GitHub organization ownership (with 2FA), release-environment approval, ownership of every crate on crates.io and recovery access to the security inbox, verified through the APIs and a test issue (#440) and re-checked yearly.GOVERNANCE.md, continuity, successor checklist
bus_factor (URL required)UnmetThere is one active maintainer. The successor holds every credential needed to continue the project, but does not maintain it day to day, so fewer than two people can currently carry the work.GOVERNANCE.md
documentation_roadmap (URL required)MetROADMAP.md describes what is planned (v12 maintenance, the v13 line and its priorities, ideas after 13.0) and what is not (abandoned milestones such as M39, work assigned to a separate programme). The v13 maintenance scope records what was removed and why.ROADMAP.md, v13 maintenance scope
documentation_architecture (URL required)MetThe framework specification documents the directory conventions, crates and capabilities and the core APIs; the architecture-decisions guide and security architecture describe the main components and their boundaries.Framework spec, architecture choices
documentation_security (URL required)MetSECURITY.md, the security architecture, the security-layers guide and the claims ledger state what users can and cannot expect, including the limits of each control.Security architecture, which layer to use, SECURITY.md
documentation_quick_start (URL required)MetThe README quickstart and the “Start here” and “Zero to a complete app” guides take a new user from installation to a running application.README quickstart, Start here
documentation_currentMetGuide code is compiled as doctests, and every documentation change runs the book build, offline link and anchor checks on Markdown and rendered HTML, a browser smoke test and a spell check. Documentation is updated with the behavior it describes.documentation.yml, book doctests
documentation_achievements (URL required)Unmet until PR #447 mergesAfter PR #447: the README front page shows and links the OpenSSF Best Practices badge next to the OpenSSF Scorecard badge.README
accessibility_best_practicesMetBrowser smoke tests of the documentation site check the skip link, ARIA states, keyboard navigation and reduced motion. cargo rullst audit --report checks image text alternatives, form labels and page language in generated applications. No formal WCAG conformance is claimed.site-browser-smoke.mjs, audit report
internationalizationUnmetDocumentation, CLI and generated starters are English only. The framework has a few locale hooks (account mail in English, Portuguese and Spanish; a configurable HTML lang), but no general message-catalog localization.account mail
sites_password_securityMetProject sites that keep accounts are the demo applications on rullst.win; they are built from the Rullst starters, whose sign-in stores only Argon2id password hashes (rullst-auth). The repository, releases, book and crates.io use GitHub/crates.io sign-in and store no passwords.rullst-auth

Change Control

CriterionAnswerJustification to pasteEvidence
maintenance_or_updateMetv12 is maintained on a protected branch with patch and minor releases while v13 develops on main. Deprecated APIs stay for at least one minor release, every major has a migration guide, and cargo rullst upgrade previews and applies upgrades.Compatibility policy, v13 migration

Reporting

CriterionAnswerJustification to pasteEvidence
report_trackerMetIndividual issues are tracked in GitHub Issues with bug and feature templates; the bug template sends security reports to private disclosure.GitHub Issues
vulnerability_report_credit (URL required)MetThe vulnerabilities fixed in the last 12 months were found by the project’s own reviews, so there was no outside reporter to credit. SECURITY.md commits to crediting reporters in the changelog and advisories unless they ask for anonymity.SECURITY.md
vulnerability_response_process (URL required)MetSECURITY.md documents private reporting (email or GitHub private vulnerability reporting), what to include, response and patch targets by severity, and credit; the advisory-exceptions policy covers severity, ownership and temporary exceptions.SECURITY.md, advisory exceptions

Quality

CriterionAnswerJustification to pasteEvidence
coding_standards (URL required)MetRust code follows the standard Rust style (rustfmt defaults) and Clippy. CONTRIBUTING.md and AGENTS.md add project rules, such as no panics in production paths, parameterized SQL and Conventional Commits.CONTRIBUTING.md, AGENTS.md
coding_standards_enforcedMetEvery pull request runs cargo fmt --all -- --check and cargo clippy --workspace --all-targets --all-features -- -D warnings, plus zero-panic Clippy gates on library code.ci.yml, zero-panics.yml
build_standard_variablesMetBuilds use Cargo, which honors RUSTFLAGS, CARGO_ENCODED_RUSTFLAGS and linker settings. There are no first-party build scripts or Makefiles that replace them; the only native C/C++ code (optional bundled DuckDB) is compiled by the cc crate, which reads CC, CFLAGS, CXX and CXXFLAGS.Cargo.toml
build_preserve_debugMetDebug information follows Cargo profiles, and the workspace does not force stripping. It can be requested with standard settings such as CARGO_PROFILE_RELEASE_DEBUG=true; the test profile omits DWARF by default to bound disk use and honors CARGO_PROFILE_TEST_DEBUG.Cargo.toml
build_non_recursiveMetOne Cargo workspace resolves and builds a single dependency graph; there are no recursive Makefiles or sub-builds.Cargo.toml
build_repeatableMetPublished .crate archives are bit-for-bit reproducible from the same commit and pinned toolchain. CI repackages two crates from a fresh checkout on every pull request, the release job reproduces every archive before publication, and an independent rebuild matched the crates.io checksum of rullst-macros 12.2.0. Native CLI binaries are attested but not claimed reproducible.Reproducible crate archives
installation_commonMetThe CLI installs with cargo install cargo-rullst --version =13.0.0-alpha.4 --locked (Cargo skips prereleases, so a plain cargo install cargo-rullst selects the end-of-life 12.x CLI) and uninstalls with cargo uninstall cargo-rullst; libraries are added as normal Cargo dependencies with the same exact version.Getting started
installation_standard_variablesMetcargo install honors CARGO_INSTALL_ROOT, --root and CARGO_HOME, Cargo’s conventions for the installation location. Libraries are never installed system-wide.Getting started
installation_development_quickMetAfter cloning, rustup installs the toolchain pinned in rust-toolchain.toml, and cargo build and cargo test work; CONTRIBUTING.md lists the steps.CONTRIBUTING.md, development setup
external_dependencies (URL required)MetThe Cargo manifests and Cargo.lock list every dependency with exact versions and checksums; each release also attaches a CycloneDX SBOM.Cargo.lock, Cargo.toml
dependency_monitoringMetDependabot checks Cargo and GitHub Actions weekly for main and v12. cargo audit runs on every push and pull request and daily, cargo deny on every push and pull request, and a release stops on any advisory.dependabot.yml, audit.yml, cargo-deny.yml
updateable_reused_componentsMetDependencies come from crates.io through Cargo and update with cargo update or Dependabot. The only vendored files are versioned htmx and Pico CSS browser assets (the version is in the file name), which are updated by hand.Cargo.toml
interfaces_currentMetCI builds with -D warnings, so calling a deprecated dependency API fails the build. Every remaining allow(deprecated) is in a test of one of Rullst’s own deprecated compatibility APIs.ci.yml
automated_integration_testingMetEvery push and pull request to main, v12 and v13 runs the automated test suite in GitHub Actions and reports the result on the commit; a nightly run covers Linux, macOS and Windows.ci.yml
regression_tests_added50MetCONTRIBUTING.md requires a regression test for bug fixes. Of 1,139 fix commits on main and v12 from 9 April to 9 October 2026, 972 (85%) changed or added tests.CONTRIBUTING.md
test_statement_coverage80MetLine coverage measured with cargo-llvm-cov was 92.56% on main (Codecov, 9 October 2026), and CI fails below 90%.Codecov, coverage.yml
test_policy_mandatedMetCONTRIBUTING.md: “Major new functionality must include automated tests of its public behavior, failure cases and relevant trust boundaries.”CONTRIBUTING.md
tests_documented_addedMetThe test requirement is in CONTRIBUTING.md and in the pull-request template checklist.PULL_REQUEST_TEMPLATE.md
warnings_strictMetAll CI builds use -D warnings; Clippy runs on all targets and features with -D warnings, Core denies clippy::unwrap_used and clippy::expect_used, and zero-panic gates deny panicking calls in library code.ci.yml

Security

CriterionAnswerJustification to pasteEvidence
implement_secure_designMetThe assurance case shows how each Saltzer and Schroeder principle is applied, with code: least privilege in workflows and API tokens, fail-safe defaults, complete mediation by the router-wide security baseline, separation of privilege in the release pipeline.Assurance case
crypto_weaknessesMetDefaults are AES-256-GCM, HMAC-SHA256, Ed25519, ECDSA P-256 and Argon2id, with TLS through rustls only. SHA-1 appears only as HMAC-SHA1 for TOTP, as RFC 6238 and authenticator apps require.Assurance case
crypto_algorithm_agilityUnmetRullst deliberately uses one modern algorithm per purpose (AES-256-GCM, Argon2id, HMAC-SHA256, Ed25519; JWTs use HS256 only). Stored ciphertext carries key IDs, so keys rotate without code changes, but changing an algorithm needs a release; TLS negotiates among several rustls cipher suites.Vault
crypto_credential_agilityMetKeys and credentials are read from the environment or configuration (APP_KEY, RULLST_ENCRYPTION_KEY or a keyring), never compiled in. Keyrings with key IDs allow rotation, and documented placeholder keys are refused.Assurance case
crypto_used_networkMetProvider integrations use HTTPS through rustls, AI provider URLs must be HTTPS (or literal loopback for local models), and remote PostgreSQL requires sslmode=verify-full; the security headers add HSTS.Assurance case
crypto_tls12MetTLS is provided by rustls, which supports TLS 1.2 and 1.3 only.Cargo.lock
crypto_certificate_verificationMetrustls verifies certificates by default, and no first-party code disables verification (no danger_accept_invalid_certs or custom no-op verifier).Assurance case
crypto_verification_privateMetBecause certificate verification is never disabled, the TLS handshake is verified before any API key or bearer token is sent in an HTTP header.Assurance case
signed_releasesMetSince v12.0.0, every crate archive and evidence file (and, from v12.1.0, every CLI binary) is signed as a GitHub artifact attestation through Sigstore keyless signing, so no long-lived private key exists on any distribution site. From v12.1.2 the Sigstore bundle is attached; SECURITY.md documents verification with gh attestation verify.SECURITY.md, verifying a release
version_tags_signedUnmetRelease tags are annotated but not signed; their integrity relies on protected branches, release admission of the exact commit and the attested artifacts. To start, sign tags with git tag -s using a GPG or SSH key registered with GitHub (or keyless with gitsign) and add git verify-tag to release admission.release.yml
input_validationMetRequests are parsed into typed structures with ValidatedJson and ValidatedForm; identifiers, paths, storage keys and operators are checked against allowlists, and invalid input is rejected with a typed error.Forms and validation, assurance case
hardeningMetSecure headers (HSTS, nonce CSP, frame denial, COOP, COEP, CORP), unsafe limited to five reviewed files, forbid(unsafe_code) in four crates, zero-panic Clippy gates, bounded JSON size and depth, and fail-closed defaults.Security architecture
assurance_case (URL required)MetThe assurance case summarizes the threat models, lists the trust boundaries, argues the secure design principles and maps common weaknesses to mechanisms and named tests, with an explicit limits section.Assurance case

Analysis

CriterionAnswerJustification to pasteEvidence
static_analysis_common_vulnerabilitiesMetCodeQL analyzes Rust and JavaScript/TypeScript after every push to main, on pull requests to the maintained lines and weekly. Clippy, cargo audit, cargo deny and the IDOR route audit also run in CI.codeql.yml
dynamic_analysis_unsafeMetRust is memory-safe outside unsafe, which is limited to five reviewed OS-integration files. AddressSanitizer and ThreadSanitizer run nightly on twelve crates; Miri, Kani and 42 fuzz targets run as on-demand campaigns.sanitizers.yml, fuzzing.yml

Summary

AnswerCountCriteria
Met49All others
Unmet6documentation_achievements (MUST, until PR #447 merges), dco, bus_factor, internationalization, crypto_algorithm_agility (SHOULD), version_tags_signed (SUGGESTED)

Once PR #447 is merged, every MUST criterion is answered Met. The unmet SHOULD and SUGGESTED criteria do not block Silver if their justifications are filled in. See also the OpenSSF Scorecard evidence.