OpenSSF Best Practices checklist

Source: docs/openssf-best-practices.md · Edit on GitHub

This is the maintainer’s working checklist for the OpenSSF Best Practices badge at the passing level (https://www.bestpractices.dev). It records, criterion by criterion, what the repository proves today and what is missing. It is a preparation aid, not the application: the badge is only earned by registering the project and answering the questionnaire (HUMAN item H5).

How to read it:

  • Met means there is evidence in this repository (file or workflow named in the table).
  • Unmet means there is no evidence yet, or the criterion depends on a GitHub setting or an event (a release) that cannot be shown from the files. The last column says what is missing and which HUMAN item (H1 …) closes it.
  • N/A means the criterion does not apply, with the reason.
  • A criterion is marked Met only when the file is there. “Workflow exists” is not “workflow is green on main”; the maintainer must confirm the latter (H4) before answering Met in the form.
  • The criterion identifiers and their MUST/SHOULD/SUGGESTED strength are quoted from memory of the current form. Verify every row against the live form at bestpractices.dev when filling it in; criteria are occasionally reworded or added.
  • Level of MUST (M), SHOULD (S) and SUGGESTED (U) is given in the second column.

Last reviewed against the repository at the state of branch t5.6-readiness (no release, no tags).

Summary#

SectionMetUnmetN/A
Basics (incl. repository and versioning)1460
Change control and reporting361
Quality1120
Security619
Analysis701
Total411511

Counted in the tables below. The Unmet MUST criteria that block the badge today are:

  • GitHub-dependent (H1, H2): repo_public, sites_https, discussion, report_archive, vulnerability_report_private;
  • release-dependent (T5.7): version_unique, release_notes, delivery_mitm;
  • history-dependent: report_responses (no reports have been filed yet; answer honestly).

The remaining Unmet rows are SHOULD or SUGGESTED.

Basics#

IDLevelStatusEvidence / what is missing
description_goodMMetFirst paragraph of README.md states what Querdian does and for whom.
interactMMetREADME “Contributing and reporting” section links the issue tracker, CONTRIBUTING.md and SECURITY.md. The issue tracker itself must be enabled (H1).
contributionMMetCONTRIBUTING.md: DCO, clean-room rule, workflow, test commands.
contribution_requirementsSMetCONTRIBUTING.md (DCO, conventional commits, license allowlist, make lint test); style is enforced by .golangci.yml and .editorconfig. The requirement for tests lives in the definition of done in TASKS.md; CONTRIBUTING.md does not repeat it (see gaps in the self-assessment).
floss_licenseMMetLICENSE is Apache-2.0.
floss_license_osiUMetApache-2.0 is OSI approved.
license_locationMMetLICENSE in the repository root.
documentation_basicsMMetREADME plus docs/: quickstart, policy guide, operations, troubleshooting, limitations.
documentation_interfaceMMetExternal interfaces are the HTTP API (route inventory in endpoints.md, error format in troubleshooting.md), the CRDs (policy-guide.md), the config file and flags (operations.md) and the metrics.
sites_httpsMUnmetThe project site is the GitHub repository (https://github.com/querdian-dev/querdian), which is HTTPS, but the repository’s existence and visibility cannot be shown from the files. Closed by H1.
discussionMUnmetIssues and pull requests on GitHub satisfy this (searchable, URL-addressable, no client-side proprietary software), once the repository is public with issues enabled (H1). There is no separate forum, chat or mailing list; that is fine for the criterion.
englishMMetAll documentation and code comments are English; bug reports are accepted in English.
maintainedMMet107 commits by one maintainer, tasks tracked in TASKS.md. Honest caveat: there is one maintainer (MAINTAINERS.md).
repo_publicMUnmetorigin is git@github.com:querdian-dev/querdian.git but public visibility must be set and confirmed (H1).
repo_trackMMetgit history with author, date and message per change.
repo_interimMMetgit history contains the intermediate work (task branches and merges), not only releases.
repo_distributedUMetgit.
version_uniqueMUnmetNo release, no tag yet. release.yml only accepts tags matching vMAJOR.MINOR.PATCH[-pre]. Closed by T5.7 (the first tag).
version_semverUUnmetSame: SemVer is the stated scheme (PLAN section 14) and enforced by the release workflow, but nothing has been released yet.
version_tagsUUnmetgit tag is empty. Closed by T5.7.

Change control and reporting#

IDLevelStatusEvidence / what is missing
release_notesMUnmetNothing released. Prepared: CHANGELOG.md and release-notes-0.1.0.md (drafts); GoReleaser also generates a changelog from commit messages (.goreleaser.yaml). Closed by T5.7.
release_notes_vulnsMN/AThe release notes must identify fixed publicly known vulnerabilities. There are none to report; state “no known vulnerabilities fixed” in the notes and keep this up to date.
report_processMMetREADME “Contributing and reporting” and CONTRIBUTING.md point to the GitHub issue tracker; SECURITY.md covers vulnerabilities. There are no issue templates (.github/ISSUE_TEMPLATE does not exist); optional.
report_trackerSUnmetGitHub issues, once the repository is public with issues enabled (H1).
report_responsesMUnmetNo issue has ever been filed; there is no response history to show. The form asks for a majority acknowledged within 2-12 months; answer honestly once there is a history.
enhancement_responsesSUnmetSame; no history.
report_archiveMUnmetGitHub issues are archived and searchable once public (H1).
vulnerability_report_processMMetSECURITY.md publishes the process and the advisory URL.
vulnerability_report_privateMUnmetSECURITY.md points to https://github.com/querdian-dev/querdian/security/advisories/new, which only works when private vulnerability reporting is enabled in the repository settings (H2). Nothing in the repo can prove it.
vulnerability_report_responseMMetSECURITY.md commits to acknowledging reports within 3 working days (criterion: initial response within 14 days). No report has been received, so the track record is empty.

Quality#

IDLevelStatusEvidence / what is missing
buildMMetmake build (Makefile), go build; reproducible flags in .goreleaser.yaml (-trimpath, CGO_ENABLED=0).
build_common_toolsSMetGo toolchain and make.
build_floss_toolsSMetGo, make, GoReleaser, Docker/BuildKit, Helm: all FLOSS.
testMMetmake test, make test-race, make envtest, make fuzz, make e2e (143 Go files, 75 of them tests; 10 fuzz targets; black-box differential suites against Prometheus, Loki and Tempo under test/e2e/).
test_invocationSMetStandard go test ./... via make test; documented in CONTRIBUTING.md.
test_mostUUnmetStatement coverage is not measured anywhere (no -cover in Makefile or workflows). The code is heavily tested, but there is no number.
test_continuous_integrationUMetci.yml runs lint, test-race, envtest, fuzz (30 s per target), govulncheck, licenses and generate on every PR. Caveat: make e2e, make chart-lint and make release-check are not run in CI (documented in the self-assessment gaps).
test_policyMMetThe definition of done in TASKS.md (“New code has unit tests”) is the project’s written policy; GOVERNANCE.md requires review by a second maintainer. Recommendation: repeat the sentence in CONTRIBUTING.md so the form can point at a contributor-facing document.
tests_are_addedMMetThe history shows tests added with the functionality (every internal/ package has tests; E2E suites accompany every enforcer).
tests_documented_addedUMetTASKS.md definition of done (see test_policy).
warningsMMetmake lint runs golangci-lint with standard, errorlint, gosec, misspell, revive, unconvert (.golangci.yml).
warnings_fixedMMetlint is a CI job and the definition of done requires make lint green. Confirm the job is green on main (H4).
warnings_strictUUnmetThe linter set is moderate, not maximally strict.

Security#

IDLevelStatusEvidence / what is missing
know_secure_designMMetSelf-attestation by the maintainer (H9). Evidence of practice: fail-closed and default-deny principles in PLAN section 2, threat model.
know_common_errorsMMetSelf-attestation (H9). Evidence: the threat model covers injection and parser divergence, parameter pollution, header trust, oracle attacks, resource exhaustion, token replay.
crypto_publishedMN/AQuerdian does not implement cryptography. JWT/JWKS verification uses github.com/coreos/go-oidc/v3; TLS to the issuer uses Go’s crypto/tls (minimum TLS 1.2, internal/auth/auth.go).
crypto_callSN/ASame: no own implementation; libraries are called, nothing is re-implemented.
crypto_flossMN/ASame; all crypto dependencies are FLOSS.
crypto_keylengthMN/AQuerdian generates no keys; key sizes are the issuer’s choice.
crypto_workingMN/ANo broken algorithms are implemented or selected by the project.
crypto_weaknessesSN/ANo project-chosen algorithms.
crypto_pfsSN/AQuerdian does not terminate TLS (documented in operations.md).
crypto_password_storageMN/ANo passwords are stored or verified.
crypto_randomMN/ANo cryptographic keys or nonces are generated outside tests.
delivery_mitmMUnmetNothing is delivered yet. The pipeline is built for it: HTTPS GitHub releases and ghcr.io, cosign keyless signatures, GitHub build-provenance attestations (release.yml). Closed by T5.7 and verification per releasing.md.
delivery_unsignedSMetNo hash or key is fetched over plain HTTP in the Makefile, workflows, Dockerfile (images pinned by digest) or quickstart.
vulnerabilities_fixed_60_daysMMetNo known unpatched vulnerability; govulncheck is a CI job and Renovate is configured (renovate.json). Renovate only runs if the app is installed (H11). Confirm no open alert (H4).
vulnerabilities_critical_fixedMMetSame evidence.
no_leaked_credentialsMMetA search of the tree for private key blocks finds none. The quickstart contains deliberately public demo passwords (alice-demo, admin/admin, the Grafana client secret in hack/quickstart); they protect a throw-away kind cluster and are labelled DEMO ONLY. Enable GitHub secret scanning and push protection (H4).

Analysis#

IDLevelStatusEvidence / what is missing
static_analysisMMetCodeQL for Go (codeql.yml) on every PR, on main and weekly; golangci-lint with gosec in lint.
static_analysis_common_vulnerabilitiesUMetCodeQL security queries and gosec.
static_analysis_fixedMMetCI must pass; confirm the Code scanning tab has no open high/critical alerts before answering (H4).
static_analysis_oftenUMetEvery PR and weekly.
dynamic_analysisUMetFuzzing of lexers, parsers, DNF normalisation and rewriters (10 Fuzz* targets, 30 s each in CI), the race detector (make test-race), and differential/equivalence suites against real backends.
dynamic_analysis_unsafeSN/AGo is memory safe; there is no cgo and no unsafe use in the product code.
dynamic_analysis_enable_assertionsUMetGo runtime checks are always on; tests assert invariants under fuzz and race builds.
dynamic_analysis_fixedMMetNo known unfixed medium+ finding from dynamic analysis. Note that crashing fuzz inputs are not kept as committed corpora (no testdata/fuzz directories exist), so a regression would rely on the fix’s own unit test.

Interpretation: after H1, H2, H5 and the first release, the project should be able to answer “passing”. The SHOULD/SUGGESTED rows that stay Unmet (test_most, warnings_strict, response history) do not block the badge.

HUMAN actions#

These cannot be done by a commit. Do them in this order.

#ActionCloses
H1Make querdian-dev/querdian public; enable Issues; set description, website and topics.repo_public, sites_https, discussion, report_tracker, report_archive, Scorecard publishing
H2Settings > Code security: enable Private vulnerability reporting.vulnerability_report_private
H3Settings > Rules: create the main ruleset: require pull request, require the status checks listed in releasing.md, block force pushes and deletions, require linear history if desired. With one maintainer, do not require an approving review (it would block merging); the review rule in GOVERNANCE.md cannot be technically enforced until there is a second maintainer.Scorecard Branch-Protection, GOVERNANCE.md
H4Settings > Code security: enable Dependabot alerts (security updates only, Renovate does version updates), secret scanning and push protection, code scanning. Then confirm: all workflows green on main, no open CodeQL or Dependabot alerts, no open govulncheck finding.static_analysis_fixed, warnings_fixed, vulnerabilities_*, no_leaked_credentials
H5Register the project at https://www.bestpractices.dev, answer the questionnaire against this checklist, keep the answers truthful (Unmet stays Unmet), and note the numeric project ID. Then activate the commented badges in the README.the badge
H6Org and repository Actions policy (T0.0): only GitHub-owned and verified-creator actions, plus the allowlist entries listed in releasing.md. Org: 2FA required.supply-chain posture, T0.0
H7Cut v0.0.0-rc.1, then v0.1.0 (releasing.md); set the ghcr.io packages to public.version_*, release_notes, delivery_mitm
H8Confirm the Scorecard workflow publishes results (needs the public repo) and read the first report at https://scorecard.dev/viewer/?uri=github.com/querdian-dev/querdian.Scorecard badge
H9Maintainer self-attestation for know_secure_design and know_common_errors.those two criteria
H10Recruit a second maintainer (GOVERNANCE.md assumes reviews by a maintainer other than the author). Not required for the badge.bus factor, Scorecard Code-Review
H11Install the Renovate GitHub app (or run Renovate self-hosted) for the organization; renovate.json alone does nothing.dependency updates

Badges#

The README carries commented-out badge markup. Uncomment it only after H5 (the numeric ID) and after H8 (the Scorecard publishes). Patterns:

[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/<ID>/badge)](https://www.bestpractices.dev/projects/<ID>)
[![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/querdian-dev/querdian/badge)](https://scorecard.dev/viewer/?uri=github.com/querdian-dev/querdian)

Type to search all documentation pages.