bouine

Projects that follow the best practices below can voluntarily self-certify and show that they've achieved an Open Source Security Foundation (OpenSSF) best practices badge.

There is no set of practices that can guarantee that software will never have defects or vulnerabilities; even formal methods can fail if the specifications or assumptions are wrong. Nor is there any set of practices that can guarantee that a project will sustain a healthy and well-functioning development community. However, following best practices can help improve the results of projects. For example, some practices enable multi-person review before release, which can both help find otherwise hard-to-find technical vulnerabilities and help build trust and a desire for repeated interaction among developers from different companies. To earn a badge, all MUST and MUST NOT criteria must be met, all SHOULD criteria must be met OR be unmet with justification, and all SUGGESTED criteria must be met OR unmet (we want them considered at least). If you want to enter justification text as a generic comment, instead of being a rationale that the situation is acceptable, start the text block with '//' followed by a space. Feedback is welcome via the GitHub site as issues or pull requests There is also a mailing list for general discussion.

We gladly provide the information in several locales, however, if there is any conflict or inconsistency between the translations, the English version is the authoritative version.
If this is your project, please show your badge status on your project page! The badge status looks like this: Badge level for project 14035 is silver Here is how to embed it:
You can show your badge status by embedding this in your markdown file:
[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/14035/badge)](https://www.bestpractices.dev/projects/14035)
or by embedding this in your HTML:
<a href="https://www.bestpractices.dev/projects/14035"><img src="https://www.bestpractices.dev/projects/14035/badge"></a>


These are the Silver level criteria. You can also view the Passing or Gold level criteria.

Baseline Series: Baseline Level 1 Baseline Level 2 Baseline Level 3

        

 Basics 17/17 ●

  • General

    Note that other projects may use the same name.

    ⚡ Bouine is a cloud-native HTTP cache in Go - RFC9111 compliant, zero-alloc hit path, gossip clustering, no external K/V store

    Please use SPDX license expression format; examples include "Apache-2.0", "BSD-2-Clause", "BSD-3-Clause", "GPL-2.0+", "LGPL-3.0+", "MIT", and "(BSD-2-Clause OR Ruby)". Do not include single quotes or double quotes.
    If there is more than one language, list them as comma-separated values (spaces optional) and sort them from most to least used. If there is a long list, please list at least the first three most common ones. If there is no language (e.g., this is a documentation-only or test-only project), use the single character "-". Please use a conventional capitalization for each language, e.g., "JavaScript".
    The Common Platform Enumeration (CPE) is a structured naming scheme for information technology systems, software, and packages. It is used in a number of systems and databases when reporting vulnerabilities.
  • Prerequisites


    The project MUST achieve a passing level badge. [achieve_passing]

  • Basic project website content


    The information on how to contribute MUST include the requirements for acceptable contributions (e.g., a reference to any required coding standard). (URL required) [contribution_requirements]

    https://github.com/bouine-cache/bouine/blob/main/CONTRIBUTING.md

    CONTRIBUTING.md documents the requirements for acceptable contributions:

    • Coding standards ("Coding standards summary" referencing AGENTS.md)
    • Performance discipline ("Performance discipline" referencing AGENTS.md)
    • Testing discipline ("Testing discipline" referencing AGENTS.md)
    • A PR checklist ("Pull request checklist" mirroring AGENTS.md)
    • Commit message conventions (Conventional Commits)
    • Required tooling setup (make hooks mandatory, Go 1.26, Docker, etc.)

  • Project oversight


    The project SHOULD have a legal mechanism where all developers of non-trivial amounts of project software assert that they are legally authorized to make these contributions. The most common and easily-implemented approach for doing this is by using a Developer Certificate of Origin (DCO), where users add "signed-off-by" in their commits and the project links to the DCO website. However, this MAY be implemented as a Contributor License Agreement (CLA), or other legal mechanism. (URL required) [dco]
    The DCO is the recommended mechanism because it's easy to implement, tracked in the source code, and git directly supports a "signed-off" feature using "commit -s". To be most effective it is best if the project documentation explains what "signed-off" means for that project. A CLA is a legal agreement that defines the terms under which intellectual works have been licensed to an organization or project. A contributor assignment agreement (CAA) is a legal agreement that transfers rights in an intellectual work to another party; projects are not required to have CAAs, since having CAA increases the risk that potential contributors will not contribute, especially if the receiver is a for-profit organization. The Apache Software Foundation CLAs (the individual contributor license and the corporate CLA) are examples of CLAs, for projects which determine that the risks of these kinds of CLAs to the project are less than their benefits.

    The project uses the Developer Certificate of Origin (DCO) v1.1. Every commit must include a Signed-off-by: trailer certifying the contributor's right to submit the work under the project's Apache 2.0 license. This is enforced by a commit-msg prek hook ( scripts/check-dco.sh ) that rejects commits missing the trailer, and by a CI job ( dco in .github/workflows/ci.yml ) that checks all commits in a PR. Contributors add the trailer with git commit -s . The
    full DCO text and instructions are documented at CONTRIBUTING.md#developer-certificate-of-origin-dco (https://github.com/bouine-cache/bouine/blob/main/CONTRIBUTING.md#developer-certificate-of-origin-dco).



    The project MUST clearly define and document its project governance model (the way it makes decisions, including key roles). (URL required) [governance]
    There needs to be some well-established documented way to make decisions and resolve disputes. In small projects, this may be as simple as "the project owner and lead makes all final decisions". There are various governance models, including benevolent dictator and formal meritocracy; for more details, see Governance models. Both centralized (e.g., single-maintainer) and decentralized (e.g., group maintainers) approaches have been successfully used in projects. The governance information does not need to document the possibility of creating a project fork, since that is always possible for FLOSS projects.

    URL: https://github.com/bouine-cache/bouine/blob/main/GOVERNANCE.md

    bouine uses a maintainer collective governance model documented in GOVERNANCE.md . The document defines key roles (lead maintainer, maintainers, contributors), the decision-making process for standard and architectural changes (consensus with lead maintainer as tie-breaker), dispute resolution escalation (discuss → maintainer review → lead maintainer decides), how maintainers are added/removed, and access continuity in case a contributor becomes unavailable. The file is protected by CODEOWNERS and linked from both README.md and CONTRIBUTING.md.



    The project MUST adopt a code of conduct and post it in a standard location. (URL required) [code_of_conduct]
    Projects may be able to improve the civility of their community and to set expectations about acceptable conduct by adopting a code of conduct. This can help avoid problems before they occur and make the project a more welcoming place to encourage contributions. This should focus only on behavior within the community/workplace of the project. Example codes of conduct are the Linux kernel code of conduct, the Contributor Covenant Code of Conduct, the Debian Code of Conduct, the Ubuntu Code of Conduct, the Fedora Code of Conduct, the GNOME Code Of Conduct, the KDE Community Code of Conduct, the Python Community Code of Conduct, The Ruby Community Conduct Guideline, and The Rust Code of Conduct.

    URL: https://github.com/bouine-cache/bouine/blob/main/CODE_OF_CONDUCT.md

    The project adopts the Contributor Covenant v2.1 code of conduct, posted at the repository root (CODE_OF_CONDUCT.md ), a standard location recognized by GitHub. It is linked from CONTRIBUTING.md and referenced in .github/ISSUE_TEMPLATE/config.yml . Enforcement responsibilities, scope, and a 4-level escalation ladder (Correction → Warning → Temporary Ban → Permanent Ban) are documented.



    The project MUST clearly define and publicly document the key roles in the project and their responsibilities, including any tasks those roles must perform. It MUST be clear who has which role(s), though this might not be documented in the same way. (URL required) [roles_responsibilities]
    The documentation for governance and roles and responsibilities may be in one place.

    URL: https://github.com/bouine-cache/bouine/blob/main/GOVERNANCE.md#2-roles

    GOVERNANCE.md defines four key roles (lead maintainer, maintainer, contributor, AI agent) with their responsibilities and concrete key tasks. Who holds each role is visible via the @bouine-cache/maintainers https://github.com/orgs/bouine-cache/teams/maintainers GitHub team page and the lead maintainer's GitHub handle (@theotime-leveque ). The CODEOWNERS file maps codebase areas to the maintainer team for auto-requested reviews.



    The project MUST be able to continue with minimal interruption if any one person dies, is incapacitated, or is otherwise unable or unwilling to continue support of the project. In particular, the project MUST be able to create and close issues, accept proposed changes, and release versions of software, within a week of confirmation of the loss of support from any one individual. This MAY be done by ensuring someone else has any necessary keys, passwords, and legal rights to continue the project. Individuals who run a FLOSS project MAY do this by providing keys in a lockbox and a will providing any needed legal rights (e.g., for DNS names). (URL required) [access_continuity]

    URL: https://github.com/bouine-cache/bouine/blob/main/GOVERNANCE.md#4-access-continuity

    GOVERNANCE.md §4 documents that the GitHub org has two admins ( @thylong and @chridupin-33 ), both with full admin access to the repo and org. If either becomes unavailable, the remaining admin can within one week:
    create/close issues (triage+admin perms), merge PRs (branch protection can be overridden by admins), release software (credentials in GitHub Secrets, cosign uses keyless OIDC tied to the workflow not an individual, releases triggered by git tag push), and respond to security reports (all maintainers are security contacts via GitHub PVR). No external
    infrastructure (DNS, standalone CI, external registries) requires credentials outside GitHub, eliminating the need for a
    lockbox or will.



    The project SHOULD have a "bus factor" of 2 or more. (URL required) [bus_factor]
    A "bus factor" (aka "truck factor") is the minimum number of project members that have to suddenly disappear from a project ("hit by a bus") before the project stalls due to lack of knowledgeable or competent personnel. The truck-factor tool can estimate this for projects on GitHub. For more information, see Assessing the Bus Factor of Git Repositories by Cosentino et al.

    URL: https://github.com/bouine-cache/bouine/blob/main/GOVERNANCE.md#4-access-continuity

    bouine has a bus factor of 2. The @bouine-cache/maintainers GitHub team has two members with admin access to the repository and organization ( @thylong and @chridupin-33 ), both familiar with the codebase architecture release pipeline, and security response process. The loss of either one leaves the other fully capable of continuing the
    project. All credentials live in GitHub Secrets, not on individual machines.


  • Documentation


    The project MUST have a documented roadmap that describes what the project intends to do and not do for at least the next year. (URL required) [documentation_roadmap]
    The project might not achieve the roadmap, and that's fine; the purpose of the roadmap is to help potential users and contributors understand the intended direction of the project. It need not be detailed.

    URL: https://github.com/bouine-cache/bouine/blob/main/ROADMAP.md

    ROADMAP.md documents the project's intended direction for the next 12 months across six feature areas (multilayer caching, authentication, fasthttp migration, eviction algorithms, competitive benchmarks, blog), with targets, non-goals, and a deferred backlog. Linked from README.md, CONTRIBUTING.md, and GOVERNANCE.md; protected by CODEOWNERS.



    The project MUST include documentation of the architecture (aka high-level design) of the software produced by the project. If the project does not produce software, select "not applicable" (N/A). (URL required) [documentation_architecture]
    A software architecture explains a program's fundamental structures, i.e., the program's major components, the relationships among them, and the key properties of these components and relationships.

    URL: https://github.com/bouine-cache/bouine/blob/main/docs/architecture.md

    docs/architecture.md is the project's architecture reference. It documents the major components (8-layer model: L1 Server through L8 AI Insights), their relationships (dependency matrix, allowed imports), the module layout mapping layers to Go packages, the HTTP stack design, implementation decisions, and operational characteristics. Each layer has a doc.go with purpose, public surface, invariants, and performance notes. Architectural decisions are
    recorded as ADRs in docs/decisions/ (30 ADRs in MADR format).



    The project MUST document what the user can and cannot expect in terms of security from the software produced by the project (its "security requirements"). (URL required) [documentation_security]
    These are the security requirements that the software is intended to meet.

    URL: https://github.com/bouine-cache/bouine/blob/main/SECURITY.md#security-requirements

    SECURITY.md has a "Security Requirements" section documenting what bouine does and does not guarantee It covers TLS (min 1.2, prefer 1.3), cluster mTLS, admin auth (bearer/mTLS), HTTP smuggling defenses, header hygiene (RFC 9110 §7.6.1), private response protection, path traversal prevention, resource limits, secret-free logging, signed releases (cosign + SBOM), and vulnerability scanning (govulncheck, gitleaks, Trivy). Security non-goals are explicitly
    listed: no data-plane auth, no rate limiting, no WAF/DDoS scrubbing, no encryption at rest, no multi-tenant isolation, no built-in ACME. The full STRIDE threat model is in docs/security/threat-model.md .



    The project MUST provide a "quick start" guide for new users to help them quickly do something with the software. (URL required) [documentation_quick_start]
    The idea is to show users how to get started and make the software do anything at all. This is critically important for potential users to get started.

    URL: https://github.com/bouine-cache/bouine/blob/main/README.md#quick-start

    The README has a "Quick Start" section that gets a user from zero to a cached request in under a minute: create a minimal bouine.yaml , run bouine via Docker, make two curl requests to see MISS then HIT, and check the admin /healthz endpoint. It includes a worked demo showing the expected output.



    The project MUST make an effort to keep the documentation consistent with the current version of the project results (including software produced by the project). Any known documentation defects making it inconsistent MUST be fixed. If the documentation is generally current, but erroneously includes some older information that is no longer true, just treat that as a defect, then track and fix as usual. [documentation_current]
    The documentation MAY include information about differences or changes between versions of the software and/or link to older versions of the documentation. The intent of this criterion is that an effort is made to keep the documentation consistent, not that the documentation must be perfect.

    The project makes an active effort to keep documentation consistent with the current version. A documentation audit identified and fixed 8 staleness defects: stale version in install URL, outdated conformance score, stale Fiber references in the threat model, non-existent runbook filenames in the index, missing ADRs and a number collision in the ADR index, a broken anchor typo in the issue template, an outdated phase dropdown, and stale threshold/queue references. The CHANGELOG is maintained with an Unreleased section and enforced by a pre-push reminder hook plus a release-time promotion workflow. Conformance scores are verified live in CI against a floor of 339. The AGENTS.md working loop (§16) requires documentation updates as part of every task, and CODEOWNERS protects all docs for maintainer review.



    The project repository front page and/or website MUST identify and hyperlink to any achievements, including this best practices badge, within 48 hours of public recognition that the achievement has been attained. (URL required) [documentation_achievements]
    An achievement is any set of external criteria that the project has specifically worked to meet, including some badges. This information does not need to be on the project website front page. A project using GitHub can put achievements on the repository front page by adding them to the README file.

    URL: https://github.com/bouine-cache/bouine/blob/main/README.md (lines 10-19, the badge row in the repository front page)

    The README displays all project achievements as hyperlinked badges in the header: CI status, Codecov coverage, Release workflow, latest release, Docker pulls, Docker image version, Artifact Hub, Apache 2.0 license, and the OpenSSF Best Practices badge (line 19, linking to https://www.bestpractices.dev/projects/14035 ). All badges are clickable hyperlinks to their respective achievement pages.


  • Accessibility and internationalization


    The project (both project sites and project results) SHOULD follow accessibility best practices so that persons with disabilities can still participate in the project and use the project results where it is reasonable to do so. [accessibility_best_practices]
    For web applications, see the Web Content Accessibility Guidelines (WCAG 2.0) and its supporting document Understanding WCAG 2.0; see also W3C accessibility information. For GUI applications, consider using the environment-specific accessibility guidelines (such as Gnome, KDE, XFCE, Android, iOS, Mac, and Windows). Some TUI applications (e.g. `ncurses` programs) can do certain things to make themselves more accessible (such as `alpine`'s `force-arrow-cursor` setting). Most command-line applications are fairly accessible as-is. This criterion is often N/A, e.g., for program libraries. Here are some examples of actions to take or issues to consider:
    • Provide text alternatives for any non-text content so that it can be changed into other forms people need, such as large print, braille, speech, symbols or simpler language ( WCAG 2.0 guideline 1.1)
    • Color is not used as the only visual means of conveying information, indicating an action, prompting a response, or distinguishing a visual element. ( WCAG 2.0 guideline 1.4.1)
    • The visual presentation of text and images of text has a contrast ratio of at least 4.5:1, except for large text, incidental text, and logotypes ( WCAG 2.0 guideline 1.4.3)
    • Make all functionality available from a keyboard (WCAG guideline 2.1)
    • A GUI or web-based project SHOULD test with at least one screen-reader on the target platform(s) (e.g. NVDA, Jaws, or WindowEyes on Windows; VoiceOver on Mac & iOS; Orca on Linux/BSD; TalkBack on Android). TUI programs MAY work to reduce overdraw to prevent redundant reading by screen-readers.

    The project follows WCAG 2.0 AA where reasonable. The CLI is text-based and inherently accessible. The embedded dashboard uses semantic HTML landmarks, ARIA roles and labels, a skip-to-content link, :focus-visible keyboard indicators, prefers-reduced-motion support, AA-compliant color contrast, keyboard-operable sortable tables, proper form labels, and alt text on all images/SVGs. An accessibility statement is published at docs/accessibility.md listing implemented measures and known limitations. The README has alt text on all badge images.



    The software produced by the project SHOULD be internationalized to enable easy localization for the target audience's culture, region, or language. If internationalization (i18n) does not apply (e.g., the software doesn't generate text intended for end-users and doesn't sort human-readable text), select "not applicable" (N/A). [internationalization]
    Localization "refers to the adaptation of a product, application or document content to meet the language, cultural and other requirements of a specific target market (a locale)." Internationalization is the "design and development of a product, application or document content that enables easy localization for target audiences that vary in culture, region, or language." (See W3C's "Localization vs. Internationalization".) Software meets this criterion simply by being internationalized. No localization for another specific language is required, since once software has been internationalized it's possible for others to work on localization.

    The documentation is fully available in 3 different languages on the official website: https://bouine.org


  • Other


    If the project sites (website, repository, and download URLs) store passwords for authentication of external users, the passwords MUST be stored as iterated hashes with a per-user salt by using a key stretching (iterated) algorithm (e.g., Argon2id, Bcrypt, Scrypt, or PBKDF2). If the project sites do not store passwords for this purpose, select "not applicable" (N/A). [sites_password_security]
    Note that the use of GitHub meets this criterion. This criterion only applies to passwords used for authentication of external users into the project sites (aka inbound authentication). If the project sites must log in to other sites (aka outbound authentication), they may need to store authorization tokens for that purpose differently (since storing a hash would be useless). This applies criterion crypto_password_storage to the project sites, similar to sites_https.

    No passwords are stored, no authentication is provided.


 Change Control 1/1 ●

  • Previous versions


    The project MUST maintain the most often used older versions of the product or provide an upgrade path to newer versions. If the upgrade path is difficult, the project MUST document how to perform the upgrade (e.g., the interfaces that have changed and detailed suggested steps to help upgrade). [maintenance_or_update]

    bouine maintains older versions and provides documented upgrade paths. The SECURITY.md supported-versions table shows the latest minor receives security fixes and the previous minor is supported for 6 months. The CHANGELOG.md (Keep a Changelog format, SemVer) documents all notable changes per release, with breaking changes explicitly flagged (e.g., "Breaking (SDK): removed Client.Reload "). The cluster protocol maintains an N/N-1 compatibility window for rolling upgrades, documented in docs/architecture.md §5 . Migration guides exist for Varnish (docs/migration/varnish.md ), NGINX ( docs/migration/nginx.md ), and cluster mode changes ( docs/migration/cluster-mode.md ). The Go SDK ( pkg/bouineapi ) follows semver — wire types in pkg/api are additive, and breaking changes require a major version bump with a migration note per AGENTS.md §13.


 Reporting 3/3 ●

  • Bug-reporting process


    The project MUST use an issue tracker for tracking individual issues. [report_tracker]

    The project uses GitHub Issues at https://github.com/bouine-cache/bouine/issues, referenced in the README and CONTRIBUTING.md.


  • Vulnerability report process


    The project MUST give credit to the reporter(s) of all vulnerability reports resolved in the last 12 months, except for the reporter(s) who request anonymity. If there have been no vulnerabilities resolved in the last 12 months, select "not applicable" (N/A). (URL required) [vulnerability_report_credit]

    No vulnerabilities raised in the past 12 months.



    The project MUST have a documented process for responding to vulnerability reports. (URL required) [vulnerability_response_process]
    This is strongly related to vulnerability_report_process, which requires that there be a documented way to report vulnerabilities. It also related to vulnerability_report_response, which requires response to vulnerability reports within a certain time frame.

    URL: https://github.com/bouine-cache/bouine/blob/main/SECURITY.md#vulnerability-response-process

    SECURITY.md documents a six-step vulnerability response process: (1) triage within 3 business days with severity assignment, (2) assess and reproduce within 1 week, (3) develop a fix on a private branch with maintainer review, threat model update, and CHANGELOG entry, (4) release a signed tagged release (out-of-band for critical, batched for medium/low), (5) publish GHSA advisory and request CVE, (6) post-release review within one week to strengthen
    controls. Reporters receive weekly status updates during the embargo, and target fix timeframes are 30 days for high-severity and 90 days for medium-severity issues.


 Quality 19/19 ●

  • Coding standards


    The project MUST identify the specific coding style guides for the primary languages it uses, and require that contributions generally comply with it. (URL required) [coding_standards]
    In most cases this is done by referring to some existing style guide(s), possibly listing differences. These style guides can include ways to improve readability and ways to reduce the likelihood of defects (including vulnerabilities). Many programming languages have one or more widely-used style guides. Examples of style guides include Google's style guides and SEI CERT Coding Standards.

    URL: https://github.com/bouine-cache/bouine/blob/main/AGENTS.md#4-coding-standards-go-126 (with CONTRIBUTING.md#coding-standards-summary as the human-facing entry point)

    bouine's primary (and only) language is Go 1.26. The coding style guide is documented in AGENTS.md §4 and summarized in CONTRIBUTING.md § "Coding standards" . It identifies specific style guides and rules: gofmt -s + goimports for formatting, 100-column soft limit, idiomatic Go naming (short receivers, no Hungarian notation), no panic outside main, no init() doing work, no global mutable state, context.Context as first argument for I/O
    functions, no bare goroutines, no reflection on the hot path, comments explain why and cite RFC clauses. Enforced automatically via golangci-lint (17 linters including govet , staticcheck , errcheck , gosec , gocritic , revive depguard , gocyclo , funlen , forbidigo ) in prek hooks and CI. Contributions must comply — the PR checklist in CONTRIBUTING.md requires prek run --all-files to pass.



    The project MUST automatically enforce its selected coding style(s) if there is at least one FLOSS tool that can do so in the selected language(s). [coding_standards_enforced]
    This MAY be implemented using static analysis tool(s) and/or by forcing the code through code reformatters. In many cases the tool configuration is included in the project's repository (since different projects may choose different configurations). Projects MAY allow style exceptions (and typically will); where exceptions occur, they MUST be rare and documented in the code at their locations, so that these exceptions can be reviewed and so that tools can automatically handle them in the future. Examples of such tools include ESLint (JavaScript), Rubocop (Ruby), and devtools check (R).

    bouine automatically enforces its Go coding style via multiple FLOSS tools, all configured in the repository:Formatters (in .golangci.yaml ):

    • gofmt -s (simplify) — enforces standard Go formatting
    • goimports with local prefix github.com/bouine-cache/bouine Linters (17 enabled in .golangci.yaml , mandated by AGENTS.md §14.4 ):
    • govet , staticcheck , errcheck , gosec , bodyclose , contextcheck , noctx , nilerr , gocritic , revive ,
      forbidigo , gocyclo (≤15), funlen (≤80), depguard (layer enforcement), unparam , ineffassign , unused ,
      misspell
      Enforcement points:
    • prek pre-commit hook — runs gofmt -s , golangci-lint --new-from-rev=HEAD~ on changed lines, go mod tidy check,
      go test -race -short on every commit
    • prek pre-push hook — runs full go test -race and govulncheck
    • CI ( ci.yml ) — re-runs prek run --all-files as its first stage, so bypassed local hooks still fail the build Style exceptions are rare and must be documented at their location (e.g., gosec suppressions require a comment citing the threat model per AGENTS.md §6 ).

  • Working build system


    Build systems for native binaries MUST honor the relevant compiler and linker (environment) variables passed in to them (e.g., CC, CFLAGS, CXX, CXXFLAGS, and LDFLAGS) and pass them to compiler and linker invocations. A build system MAY extend them with additional flags; it MUST NOT simply replace provided values with its own. If no native binaries are being generated, select "not applicable" (N/A). [build_standard_variables]
    It should be easy to enable special build features like Address Sanitizer (ASAN), or to comply with distribution hardening best practices (e.g., by easily turning on compiler flags to do so).

    bouine is pure Go (no import "C" ), but produces native binaries and uses CGO_ENABLED=1 in CI for the race detector. The build system honors relevant compiler/linker variables:

    • GO — respected via ?= in the Makefile, so GO=gccgo make build works
    • GOFLAGS — respected via ?= and passed to go build
    • CC — honored by the Go toolchain when CGO is enabled (used by the race detector)
    • CGO_CFLAGS , CGO_CXXFLAGS , CGO_LDFLAGS — honored by the Go toolchain for cgo compilation
    • LDFLAGS — the Makefile now uses += to append project-specific Go -ldflags to any caller-provided LDFLAGS , so distribution hardening flags or ASAN-related linker options are passed through rather than overwritten
      This makes it easy to enable special build features like ASAN ( CGO_CFLAGS="-fsanitize=address" CGO_LDFLAGS="-fsanitize=address" make build ) or distribution hardening flags.


    The build and installation system SHOULD preserve debugging information if they are requested in the relevant flags (e.g., "install -s" is not used). If there is no build or installation system (e.g., typical JavaScript libraries), select "not applicable" (N/A). [build_preserve_debug]
    E.G., setting CFLAGS (C) or CXXFLAGS (C++) should create the relevant debugging information if those languages are used, and they should not be stripped during installation. Debugging information is needed for support and analysis, and also useful for measuring the presence of hardening features in the compiled binaries.

    The build system preserves debugging information when requested. Symbol stripping ( -s -w ) is now controlled by a STRIPFLAGS variable (default: -s -w ) in both the Makefile and Dockerfile. To produce a debug build with full DWARF info and symbol table:

    • Makefile: make build STRIPFLAGS=
    • Dockerfile: docker build --build-arg STRIPFLAGS= .
      The Go toolchain natively generates DWARF debug info; the strip flags were the only thing removing it. With STRIPFLAGS=empty, go tool nm and go tool objdump work on the resulting binary, and hardening audit tools can inspect the binary No install -s is used anywhere in the build or installation process.


    The build system for the software produced by the project MUST NOT recursively build subdirectories if there are cross-dependencies in the subdirectories. If there is no build or installation system (e.g., typical JavaScript libraries), select "not applicable" (N/A). [build_non_recursive]
    The project build system's internal dependency information needs to be accurate, otherwise, changes to the project may not build correctly. Incorrect builds can lead to defects (including vulnerabilities). A common mistake in large build systems is to use a "recursive build" or "recursive make", that is, a hierarchy of subdirectories containing source files, where each subdirectory is independently built. Unless each subdirectory is fully independent, this is a mistake, because the dependency information is incorrect.

    bouine uses a single Go module ( go.mod at repo root). The build command go build ./cmd/bouine invokes the Go toolchain, which resolves all cross-package dependencies through the import graph — there are no recursive make -C subdir calls, no per-subdirectory Makefiles, and no recursive build hierarchy. The Makefile is a thin wrapper with a single build target that calls go build once. The Go toolchain guarantees correct dependency ordering across packages within the module.



    The project MUST be able to repeat the process of generating information from source files and get exactly the same bit-for-bit result. If no building occurs (e.g., scripting languages where the source code is used directly instead of being compiled), select "not applicable" (N/A). [build_repeatable]
    GCC and clang users may find the -frandom-seed option useful; in some cases, this can be resolved by forcing some sort order. More suggestions can be found at the reproducible build site.

    bouine supports bit-for-bit reproducible builds via SOURCE_DATE_EPOCH.

    The build already uses - trimpath (strips filesystem paths from the binary) and CGO_ENABLED=0 in the Dockerfile (eliminates C compiler variability). The remaining non-determinism was the build timestamp injected via -ldflags -X ...buildinfo.Date= . When SOURCE_DATE_EPOCH is set, both the Makefile and Dockerfile derive a stable ISO timestamp from it instead of using date -u . Verified: two consecutive builds with SOURCE_DATE_EPOCH=1700000000 make build produce identical SHA-256 checksums


  • Installation system


    The project MUST provide a way to easily install and uninstall the software produced by the project using a commonly-used convention. [installation_common]
    Examples include using a package manager (at the system or language level), "make install/uninstall" (supporting DESTDIR), a container in a standard format, or a virtual machine image in a standard format. The installation and uninstallation process (e.g., its packaging) MAY be implemented by a third party as long as it is FLOSS.

    bouine provides multiple commonly-used installation and uninstallation methods:

    • Homebrew (macOS): brew install bouine-cache/bouine/bouine / brew uninstall bouine-cache/bouine/bouine
    • Go install: go install github.com/bouine-cache/bouine/cmd/bouine@latest
    • Docker (standard OCI container image on Docker Hub): docker pull bouinecache/bouine:latest / docker rmi bouinecache/bouine:latest
    • Helm (Kubernetes package manager, chart published on Artifact Hub): helm install bouine bouine/bouine / helm uninstall bouine
    • Prebuilt binaries: downloadable from GitHub Releases with standard tar -xzf extraction

    All four are commonly-used conventions. The Helm chart and Docker image are the primary distribution channels for
    production deployments.



    The installation system for end-users MUST honor standard conventions for selecting the location where built artifacts are written to at installation time. For example, if it installs files on a POSIX system it MUST honor the DESTDIR environment variable. If there is no installation system or no standard convention, select "not applicable" (N/A). [installation_standard_variables]

    The Makefile provides make install and make uninstall targets that honor the DESTDIR environment variable, the standard POSIX convention for staged installs. The install location is controlled by PREFIX (default: /usr/local ), so make install DESTDIR=/tmp/staging PREFIX=/opt/bouine writes to /tmp/staging/opt/bouine/bin/bouine . Both targets use the standard install command with explicit permissions (0755). Verified: install writes the binary, uninstall removes it.



    The project MUST provide a way for potential developers to quickly install all the project results and support environment necessary to make changes, including the tests and test environment. This MUST be performed with a commonly-used convention. [installation_development_quick]
    This MAY be implemented using a generated container and/or installation script(s). External dependencies would typically be installed by invoking system and/or language package manager(s), per external_dependencies.

    make setup-dev provides a one-command setup that installs all development tools ( golangci-lint , govulncheck , gitleaks , templ ), downloads Go module dependencies, installs prek hooks, and verifies the build and short tests pass. The only prerequisites are Go 1.26.x (pinned in go.mod ), prek (installed via brew / pip / uv ), and Docker (for integration/conformance tests). The target is documented in CONTRIBUTING.md § "Setting up" and AGENTS.md §14.1 , and uses commonly-used conventions: go install for tool installation, go mod download for dependencies, and make for orchestration.


  • Externally-maintained components


    The project MUST list external dependencies in a computer-processable way. (URL required) [external_dependencies]
    Typically this is done using the conventions of package manager and/or build system. Note that this helps implement installation_development_quick.

    URL: https://github.com/bouine-cache/bouine/blob/main/go.mod

    The project uses Go modules: go.mod enumerates all direct dependencies, and go.sum pins their
    checksums. CI enforces hygiene with a go mod tidy pre-commit hook ( .pre-commit-config.yaml ) that fails if go.mod / go.sum drift, plus govulncheck on pre-push and in CI. [osps_qa_02_01]



    Projects MUST monitor or periodically check their external dependencies (including convenience copies) to detect known vulnerabilities, and fix exploitable vulnerabilities or verify them as unexploitable. [dependency_monitoring]
    This can be done using an origin analyzer / dependency checking tool / software composition analysis tool such as OWASP's Dependency-Check, Sonatype's Nexus Auditor, Synopsys' Black Duck Software Composition Analysis, and Bundler-audit (for Ruby). Some package managers include mechanisms to do this. It is acceptable if the components' vulnerability cannot be exploited, but this analysis is difficult and it is sometimes easier to simply update or fix the part.

    bouine monitors external dependencies through multiple mechanisms:

    1. govulncheck — runs in CI ( .github/workflows/ci.yml , on every push) and as a pre-push prek hook ( .pre-commit-config.yaml ). It analyzes the Go dependency graph against the Go vulnerability database and reports known vulnerabilities in direct and transitive dependencies.
    2. Dependabot ( .github/dependabot.yml ) — automatically checks for outdated dependencies weekly across Go modules, GitHub Actions, and Docker base images. Grouped updates for OTel and golang.org/x packages. Creates PRs to bump versions, which triggers CI including govulncheck.
    3. Trivy ( release.yml ) — scans the released container image for HIGH/CRITICAL vulnerabilities ( exit-code: 1 ) before publishing. Blocks releases if exploitable vulnerabilities are found.
    4. docs/deps.md — the dependency allow-list includes a manual license audit of the production build graph, and every new dependency requires an ADR and a security review pass per AGENTS.md §5.


    The project MUST either:
    1. make it easy to identify and update reused externally-maintained components; or
    2. use the standard components provided by the system or programming language.
    Then, if a vulnerability is found in a reused component, it will be easy to update that component. [updateable_reused_components]
    A typical way to meet this criterion is to use system and programming language package management systems. Many FLOSS programs are distributed with "convenience libraries" that are local copies of standard libraries (possibly forked). By itself, that's fine. However, if the program *must* use these local (forked) copies, then updating the "standard" libraries as a security update will leave these additional copies still vulnerable. This is especially an issue for cloud-based systems; if the cloud provider updates their "standard" libraries but the program won't use them, then the updates don't actually help. See, e.g., "Chromium: Why it isn't in Fedora yet as a proper package" by Tom Callaway.

    The project uses Go modules: go.mod enumerates all direct dependencies, and go.sum pins their
    checksums. CI enforces hygiene with a go mod tidy pre-commit hook ( .pre-commit-config.yaml ) that fails if go.mod / go.sum drift, plus govulncheck on pre-push and in CI. [osps_qa_02_01]



    The project SHOULD avoid using deprecated or obsolete functions and APIs where FLOSS alternatives are available in the set of technology it uses (its "technology stack") and to a supermajority of the users the project supports (so that users have ready access to the alternative). [interfaces_current]

    bouine avoids deprecated or obsolete functions and APIs through automated enforcement. staticcheck is enabled in .golangci.yaml and runs in prek hooks and CI. Its SA1019 check (which flags use of deprecated APIs) is not suppressed anywhere in the project. The only staticcheck exclusion is SA5011 in test files (a known false positive with t.Fatal ). Dependabot bumps dependencies weekly, ensuring the project stays on current API versions. The Go toolchain is pinned to 1.26.x via go.mod . The one internal // Deprecated: comment in responsewriter.go marks an internal API that callers should not use; it is not a deprecated external API.


  • Automated test suite


    An automated test suite MUST be applied on each check-in to a shared repository for at least one branch. This test suite MUST produce a report on test success or failure. [automated_integration_testing]
    This requirement can be viewed as a subset of test_continuous_integration, but focused on just testing, without requiring continuous integration.

    The test-linux job in .github/workflows/ci.yml runs go test -race -count=1 -timeout=120s -coverprofile=coverage.out ./... on every pull request and every push to main . It produces a visible pass/fail report in the GitHub Actions UI and prints a coverage summary ( go tool cover -func ). Coverage results are uploaded to Codecov for trend tracking. Additionally, the test-arm job runs the same test suite on ubuntu-24.04-arm for architecture coverage on PRs. The prek job runs go test -race -short as a pre-commit hook mirror. All jobs gate merging — a test failure blocks the PR.



    The project MUST add regression tests to an automated test suite for at least 50% of the bugs fixed within the last six months. [regression_tests_added50]

    An audit of substantive bug fix commits in the last 6 months shows that every fix included regression tests in the same commit.

    Examples: 84fa0f0 (purge deletes Vary variants) added tests in handler_test.go and tiered_test.go ; b566ba1 (Vary:* non-matchable) added tests in vary_test.go ; c3ee147 (tombstone queue overflow) added tests in tiered_test.go ; 2d641a1 (reflected-XSS) added tests in handler_invalidation_test.go ; b9f3333 (attacker-controlled route label) added tests in dataplane_source_test.go ; 847e4cd (SWR use-after-close) added tests in handler_test.go . This far exceeds the 50% threshold. The AGENTS.md working loop (§16) and PR checklist require "Tests added or updated; coverage not reduced" for every change, and the prek hook runs go test -race -short on every commit.



    The project MUST have FLOSS automated test suite(s) that provide at least 80% statement coverage if there is at least one FLOSS tool that can measure this criterion in the selected language. [test_statement_coverage80]
    Many FLOSS tools are available to measure test coverage, including gcov/lcov, Blanket.js, Istanbul, JCov, and covr (R). Note that meeting this criterion is not a guarantee that the test suite is thorough, instead, failing to meet this criterion is a strong indicator of a poor test suite.

    The production code has 87.9% statement coverage (measured with go test -coverprofile across all non-test-infrastructure, non-generated packages). Every production package individually exceeds 80%:

    • internal/cache : 91.9%, internal/admin : 96.5%, internal/server : 80.1%, internal/config : 80.3%, internal/origin : 81.1%, internal/storage : 81.7%, internal/cluster : 84.0%, internal/cloudflare : 91.7%, internal/dashboard : 93.4%, internal/dashboard/insights : 88.1%, pkg/api : 98.5%, pkg/bouineapi : 97.9%
    • 6 packages are at 100%: observability/accesslog , observability/responsewriter , platform , runtime/shutdown, storage/cachaner , storage/evictor

    The total across all packages (including test infrastructure at 0% and generated templ code) is 56.6%, but the 0% packages are: cmd/bouine (4-line main() ), internal/testutil/testkey (no test files, test helper), and internal/dashboard/templates (generated _templ.go files, not manually editable). The FLOSS tool ( go test -coverprofile ) measures coverage per-package; the aggregate of 87.9% across production packages meets the 80% threshold.


  • New functionality testing


    The project MUST have a formal written policy that as major new functionality is added, tests for the new functionality MUST be added to an automated test suite. [test_policy_mandated]

    URL: https://github.com/bouine-cache/bouine/blob/main/AGENTS.md#8-testing-rules

    Justification: AGENTS.md §8 contains a formal written policy: "When major new functionality is added to the software tests for that functionality MUST be added to an automated test suite in the same pull request. A PR that adds major functionality without tests will be rejected by reviewers and will fail the CI gate." The policy defines "major new functionality" as any change that adds a new user-visible capability, configuration option, API endpoint, or code path
    in the cache, storage, cluster, or server layers. It is reinforced in CONTRIBUTING.md § "Testing discipline" and in the PR checklist.



    The project MUST include, in its documented instructions for change proposals, the policy that tests are to be added for major new functionality. [tests_documented_added]
    However, even an informal rule is acceptable as long as the tests are being added in practice.

    The test-adding policy is documented in CONTRIBUTING.md ("The working loop", step 4: "Implement smallest reasonable change, follow neighboring patterns, add tests as you go") and in the PR checklist ("Pull request checklist": "Tests added or updated; coverage not reduced"). AGENTS.md mandates "Add tests as you go, not at the end" and requires "Tests added/updated; coverage not reduced" on every PR.


  • Warning flags


    Projects MUST be maximally strict with warnings in the software produced by the project, where practical. [warnings_strict]
    Some warnings cannot be effectively enabled on some projects. What is needed is evidence that the project is striving to enable warning flags where it can, so that errors are detected early.

    The project is maximally strict with warnings:

    • 19 linters enabled in .golangci.yaml (govet, staticcheck, errcheck, gosec, bodyclose, contextcheck, noctx, nilerr, gocritic, revive, forbidigo, gocyclo ≤15, funlen ≤80, depguard, unparam, ineffassign, unused, misspell, lll)
    • forbidigo bans fmt.Println , panic , os.Exit outside main
    • depguard enforces architectural layer boundaries
    • Pre-commit hook runs golangci-lint on every commit ( --new-from-rev=HEAD~ )
    • CI re-runs prek run --all-files as first stage
    • govulncheck runs on pre-push and CI
    • -race flag always on in CI and pre-commit tests
    • Coverage gates: ≥85% per package, ≥95% for cache / storage

 Security 13/13 ●

  • Secure development knowledge


    The project MUST implement secure design principles (from "know_secure_design"), where applicable. If the project is not producing software, select "not applicable" (N/A). [implement_secure_design]
    For example, the project results should have fail-safe defaults (access decisions should deny by default, and projects' installation should be secure by default). They should also have complete mediation (every access that might be limited must be checked for authority and be non-bypassable). Note that in some cases principles will conflict, in which case a choice must be made (e.g., many mechanisms can make things more complex, contravening "economy of mechanism" / keep it simple).

    docs/security/threat-model.md §2.1 documents how bouine implements secure design principles, with concrete examples for each:

    • Fail-safe defaults — admin API denies by default (401 without token), upstream TLS verification on by default, Set-Cookie responses not cached by default, container runs non-root with read-only rootfs by default
    • Complete mediation — every admin write request authenticated through a single middleware chain with no bypass; every data-plane request passes through route matcher and RFC 9111 freshness evaluation; peer-fetch requires mTLS on every call
    • Least privilege — non-root container with dropped capabilities, minimal CI permissions, admin token scoped to admin ops only, separate CAs for data-plane and cluster mTLS
    • Economy of mechanism — single HTTP stack ( net/http ), declarative YAML config (no eval), no web framework
    • Defense in depth — smuggling defenses + header hygiene + private response protection + path traversal prevention + resource limits, each layer independent
    • Separation of privilege — separate admin and data ports, separate cluster and data-plane CAs, tokens in env vars not config files
    • Psychological acceptability — secure defaults documented in Helm chart and SECURITY.md hardening checklist, insecure options require explicit opt-in

  • Use basic good cryptographic practices

    Note that some software does not need to use cryptographic mechanisms. If your project produces software that (1) includes, activates, or enables encryption functionality, and (2) might be released from the United States (US) to outside the US or to a non-US-citizen, you may be legally required to take a few extra steps. Typically this just involves sending an email. For more information, see the encryption section of Understanding Open Source Technology & US Export Controls.

    The default security mechanisms within the software produced by the project MUST NOT depend on cryptographic algorithms or modes with known serious weaknesses (e.g., the SHA-1 cryptographic hash algorithm or the CBC mode in SSH). [crypto_weaknesses]
    Concerns about CBC mode in SSH are discussed in CERT: SSH CBC vulnerability.

    Go's TLS 1.2+ default cipher suites prefer AEAD modes (GCM, ChaCha20-Poly1305) and exclude SHA-1-dependent suites. CBC mode is not used in SSH (bouine doesn't implement SSH). xxhash is used for cache keys (non-cryptographic, no security claim). crypto/sha256 is used for checksums. No SHA-1 or CBC mode dependencies.



    The project SHOULD support multiple cryptographic algorithms, so users can quickly switch if one is broken. Common symmetric key algorithms include AES, Twofish, and Serpent. Common cryptographic hash algorithm alternatives include SHA-2 (including SHA-224, SHA-256, SHA-384 AND SHA-512) and SHA-3. [crypto_algorithm_agility]

    bouine supports multiple cryptographic algorithms through Go's crypto/tls package, which provides algorithm agility by default:

    • TLS 1.3 (preferred when MinVersion >= 1.3 ): AES-256-GCM, AES-128-GCM, ChaCha20-Poly1305 for symmetric encryption; SHA-256, SHA-384 for transcript hashing. The cipher suite list is managed by Go's stdlib and cannot be customized for TLS 1.3 (all suites are AEAD, all are secure).
    • TLS 1.2 (minimum supported): Go's default cipher suite list includes AES-128-GCM, AES-256-GCM, ChaCha20-Poly1305 — multiple symmetric algorithms so users can switch if one is broken. The CipherSuites field on tls.Config is available for operators to further restrict or reorder suites via the TLS config struct.
    • Hash algorithms: Go's stdlib provides SHA-224, SHA-256, SHA-384, SHA-512 (SHA-2 family) and SHA-3. bouine uses these
      for TLS transcript hashing and certificate verification. Cache keys use xxhash (non-cryptographic, by design — performance-critical path).
      If a cipher or hash is found broken, operators can update Go's toolchain (which updates the default suite list) or pin specific cipher suites via the TLS config. No code change is required to switch algorithms.


    The project MUST support storing authentication credentials (such as passwords and dynamic tokens) and private cryptographic keys in files that are separate from other information (such as configuration files, databases, and logs), and permit users to update and replace them without code recompilation. If the project never processes authentication credentials and private cryptographic keys, select "not applicable" (N/A). [crypto_credential_agility]

    bouine supports storing authentication credentials and private cryptographic keys in files separate from configuration:

    • Admin bearer token — can be set via ${ADMIN_TOKEN} env var expansion in the YAML config (the loader supports ${VAR} substitution), or left empty to auto-generate a random token at startup. The token value is never compiled into the binary. Operators can rotate it by changing the env var or config value and restarting — no recompilation.
    • TLS private keys — the TLS config struct references cert and key files by path ( cert_file , key_file ), loaded at runtime from disk. Operators replace the files on disk and restart to rotate — no recompilation, no config change needed if the paths stay the same.
    • Cluster mTLS keys — the cluster config ( ClusterTLS struct) similarly references cert_file and key_file by path loaded at runtime.
    • Origin mTLS client certs — upstream pool TLS config references cert/key files by path. All credentials and keys are in separate files or environment variables, never hardcoded, and can be updated and replaced without recompilation.


    The software produced by the project SHOULD support secure protocols for all of its network communications, such as SSHv2 or later, TLS1.2 or later (HTTPS), IPsec, SFTP, and SNMPv3. Insecure protocols such as FTP, HTTP, telnet, SSLv3 or earlier, and SSHv1 SHOULD be disabled by default, and only enabled if the user specifically configures it. If the software produced by the project does not support network communications, select "not applicable" (N/A). [crypto_used_network]

    bouine supports secure protocols for all network communications, with insecure protocols disabled by default:

    • Data plane: HTTP/1.1 and HTTP/2 over TLS (HTTPS). Minimum TLS version is 1.2 ( tls.Config{MinVersion: tls.VersionTLS12} in listener.go:143 ), configurable to 1.3. Plaintext HTTP (h2c) is available only via explicit configuration for in-mesh traffic; the default Helm chart enables TLS.
    • Cluster (peer-to-peer): mTLS required for all gossip and peer-fetch traffic. Separate CA from the data plane. No plaintext cluster communication is supported.
    • Origin (upstream): TLS verification enabled by default ( insecure_skip_verify refused in release builds). Optional mTLS for client cert authentication.
    • Admin API: Separate port, bearer token or mTLS authentication. The Helm chart binds it to cluster-internal only by default (not exposed to the Internet).
    • Insecure protocols disabled by default: SSLv3 and earlier are not supported (Go's crypto/tls minimum is TLS 1.0, but bouine sets the minimum to 1.2). FTP, telnet, SSHv1 are not used. insecure_skip_verify is refused in release builds. The admin API rejects insecure HTTP for write methods.


    The software produced by the project SHOULD, if it supports or uses TLS, support at least TLS version 1.2. Note that the predecessor of TLS was called SSL. If the software does not use TLS, select "not applicable" (N/A). [crypto_tls12]

    bouine requires at least TLS 1.2 on all TLS surfaces.

    The HTTPS listener sets tls.Config{MinVersion: tls.VersionTLS12} by default ( internal/server/listener.go:143 ). The minimum version is configurable via tls.min_version in the config ( internal/config/config.go:101 ), but the default and minimum supported value is 1.2. Cluster mTLS and origin TLS also inherit Go's secure defaults with TLS 1.2 as the floor. The test utility (internal/testutil/tlsutil/tlsutil.go:92 ) explicitly asserts MinVersion >= tls.VersionTLS12 .



    The software produced by the project MUST, if it supports TLS, perform TLS certificate verification by default when using TLS, including on subresources. If the software does not use TLS, select "not applicable" (N/A). [crypto_certificate_verification]

    bouine performs TLS certificate verification by default on all TLS surfaces:

    • Origin (upstream) TLS — Go's default tls.Config performs full certificate verification ( InsecureSkipVerify: false is the Go default). There is no InsecureSkipVerify field in the production config or origin/peer-fetch code. The threat model (T02) confirms: "TLS verify enabled by default; insecure_skip_verify refused in release builds."
    • Cluster mTLS — peer-fetch and gossip use a tls.Config with certificate verification enabled (separate CA, mutual verification).
    • Data-plane TLS — the HTTPS listener terminates TLS with standard certificate verification; clients verify the server certificate.
    • Admin API — when mTLS is configured, client certificates are verified.
      The only InsecureSkipVerify: true occurrences are in test files ( broadcast_test.go:342 , listener_test.go:96 ), both annotated with //nolint:gosec // G402: test-only . No production code disables certificate verification.


    The software produced by the project MUST, if it supports TLS, perform certificate verification before sending HTTP headers with private information (such as secure cookies). If the software does not use TLS, select "not applicable" (N/A). [crypto_verification_private]

    bouine performs TLS certificate verification before any HTTP headers (including private ones) are sent. Go's net/http client and server establish the TLS handshake (including certificate verification) before any HTTP data is exchanged — this is inherent to the TLS protocol (handshake completes before application data flows). Since InsecureSkipVerify is false by default in all production code paths (confirmed: no InsecureSkipVerify in non-test origin, cluster, or server code), certificate verification always completes before HTTP headers with private information (such as Authorization , Cookie , admin bearer tokens) are sent to origin or peers.


  • Secure release


    The project MUST cryptographically sign releases of the project results intended for widespread use, and there MUST be a documented process explaining to users how they can obtain the public signing keys and verify the signature(s). The private key for these signature(s) MUST NOT be on site(s) used to directly distribute the software to the public. If releases are not intended for widespread use, select "not applicable" (N/A). [signed_releases]
    The project results include both source code and any generated deliverables where applicable (e.g., executables, packages, and containers). Generated deliverables MAY be signed separately from source code. These MAY be implemented as signed git tags (using cryptographic digital signatures). Projects MAY provide generated results separately from tools like git, but in those cases, the separate results MUST be separately signed.

    URL: https://github.com/bouine-cache/bouine/blob/main/README.md#verifying-release-signatures

    All releases are cryptographically signed using cosign with keyless signing (Sigstore, via GitHub Actions OIDC). The release.yml workflow signs both the binary checksums ( cosign sign-blob ) and the Docker image ( cosign sign ). The private key is never stored on any distribution server — signatures are generated in CI using ephemeral OIDC credentials tied to the GitHub workflow. The README documents the verification process with step-by-step commands for both binary releases ( cosign verify-blob ) and Docker images ( cosign verify ), including the certificate identity and OIDC issuer to trust. An SPDX SBOM is also generated for each release.



    It is SUGGESTED that in the version control system, each important version tag (a tag that is part of a major release, minor release, or fixes publicly noted vulnerabilities) be cryptographically signed and verifiable as described in signed_releases. [version_tags_signed]

    Release tags are annotated tag objects created by the maintainer.

    While the tags themselves are not GPG-signed, each tag triggers the release.yml GitHub Actions workflow which produces cosign-signed artifacts (binary checksums and Docker images) using keyless Sigstore signing tied to the GitHub OIDC identity of the workflow. The certificate identity is bound to refs/tags/v* in the bouine-cache/bouine repository, so the signature proves the release was built from that specific tag by the official CI pipeline. Users verify via cosign verify-blob as documented in the README. Additionally, git tags could be GPG/SSH-signed in the future for defense-in-depth, but the cosign-signed release artifacts already provide cryptographic verification of the release provenance.


  • Other security issues


    The project results MUST check all inputs from potentially untrusted sources to ensure they are valid (an *allowlist*), and reject invalid inputs, if there are any restrictions on the data at all. [input_validation]
    Note that comparing input against a list of "bad formats" (aka a *denylist*) is normally not enough, because attackers can often work around a denylist. In particular, numbers are converted into internal formats and then checked if they are between their minimum and maximum (inclusive), and text strings are checked to ensure that they are valid text patterns (e.g., valid UTF-8, length, syntax, etc.). Some data may need to be "anything at all" (e.g., a file uploader), but these would typically be rare.

    bouine validates all inputs from potentially untrusted sources using allowlist and bounds-checking patterns:
    HTTP data plane — MaxHeaderBytes 64 KiB, ReadHeaderTimeout 10s, MaxConnections configurable, fast-path H1
    parser caps at 100 headers and 16 KiB read buffer, HTTP smuggling detection rejects CL+TE conflicts and duplicate Content-Length.Admin API — MaxBodyBytes (default 1 MiB) enforced via http.MaxBytesReader , batch purge capped at MaxBatchSize (default 1000) with empty-entry rejection, JSON decoder uses DisallowUnknownFields() , regex ban predicates validated via regexp.Compile before use, bearer token checked with subtle.ConstantTimeCompare .Config validation — Config.Validate() checks: pool names unique, routes reference valid pools, HTTP methods validated against an 8-method allowlist ( isKnownHTTPMethod ), cluster mode restricted to "strong" / "eventual" allowlist, eviction algorithm restricted to "sieve" / "cachaner" allowlist, all durations and sizes >= 0, JitterPercent 0-50, static root must be absolute path, index files must not contain / , YAML strict mode rejects unknown fields.Static file serving — path traversal prevention via path.Clean + isPathContained() check (rejects paths escaping root with 403), only GET/HEAD allowed, file size capped at MaxBytes , fuzz-tested with FuzzPathTraversal .Cluster protocol — binary frames validated with magic byte ( 0x42 ), version byte, message type, minimum length checks, string length cap (64 KiB) payload bounds checking on every field read, hop limit enforced (max 2, returns 508), request/response body size limits (512 bytes / 64 MiB), unrecognized gossip message types logged and dropped.Query param allowlist — keepParams in keypolicy.go implements an explicit allowlist: only listed params participate in the cache key, all others stripped.
    Fuzz tests — 13 fuzz functions cover H1 parsing, header parsing, smuggling detection, path traversal, cluster codec
    round-trips, cache key building, Cache-Control parsing, Vary variant keys, cache state machine, and storage object
    decoding. All ensure no panics on arbitrary input.



    Hardening mechanisms SHOULD be used in the software produced by the project so that software defects are less likely to result in security vulnerabilities. [hardening]
    Hardening mechanisms may include HTTP headers like Content Security Policy (CSP), compiler flags to mitigate attacks (such as -fstack-protector), or compiler flags to eliminate undefined behavior. For our purposes least privilege is not considered a hardening mechanism (least privilege is important, but separate).

    bouine uses multiple hardening mechanisms so that software defects are less likely to result in security vulnerabilities:Container hardening (Helm chart values.yaml + Dockerfile):

    • Runs as non-root ( runAsNonRoot: true , runAsUser: 65534 )
    • Read-only root filesystem ( readOnlyRootFilesystem: true )
    • All Linux capabilities dropped ( capabilities.drop: [ALL] )
    • No privilege escalation ( allowPrivilegeEscalation: false )
    • Seccomp profile RuntimeDefault (blocks unsafe syscalls)
    • Distroless base image ( gcr.io/distroless/static-debian13:nonroot ) — no shell, no package manager, no attack surface

    Language-level hardening (Go):

    • Go is a memory-safe language with garbage collection — no buffer overflows, no use-after-free, no format string vulnerabilities
    • panic forbidden outside main (enforced by forbidigo linter) — errors are returned, not crashed
    • os.Exit forbidden outside main — graceful shutdown via context cancellation
    • fmt.Print* forbidden outside main — structured logging via slog only
      Code-level hardening:
    • HTTP smuggling detection rejects ambiguous framing (CL+TE, duplicate CL, obs-fold)
    • Hop-by-hop headers stripped per RFC 9110 §7.6.1
    • Private responses ( Set-Cookie , Authorization ) not cached by default
    • Storage paths derived from xxhash64 of cache keys, never from user-controlled strings (path traversal prevention)
    • All parsers have byte caps (headers <= 64 KiB, URLs bounded, strings <= 64 KiB in cluster protocol)
    • Every queue is bounded (connection limits, in-flight caps, latch caps, body size limits)
    • gosec linter enforces zero security findings; suppressions require threat model justification


    The project MUST provide an assurance case that justifies why its security requirements are met. The assurance case MUST include: a description of the threat model, clear identification of trust boundaries, an argument that secure design principles have been applied, and an argument that common implementation security weaknesses have been countered. (URL required) [assurance_case]
    An assurance case is "a documented body of evidence that provides a convincing and valid argument that a specified set of critical claims regarding a system’s properties are adequately justified for a given application in a given environment" ("Software Assurance Using Structured Assurance Case Models", Thomas Rhodes et al, NIST Interagency Report 7608). Trust boundaries are boundaries where data or execution changes its level of trust, e.g., a server's boundaries in a typical web application. It's common to list secure design principles (such as Saltzer and Schroeer) and common implementation security weaknesses (such as the OWASP top 10 or CWE/SANS top 25), and show how each are countered. The BadgeApp assurance case may be a useful example. This is related to documentation_security, documentation_architecture, and implement_secure_design.

    URL: https://github.com/bouine-cache/bouine/blob/main/docs/security/threat-model.md#8-assurance-case

    docs/security/threat-model.md §8 provides a structured assurance case with all four required components:

    1. Threat model description (§8.1) — references the STRIDE-based threat model in §§1-7 with 13 assets, 6 trust boundaries, 8 attacker classes, and 40+ threat rows with controls and residual risk.
    2. Trust boundaries (§8.2) — 6 boundaries clearly identified (Internet/data-plane, listener/engine, bouine/origin, bouine/peer, operator/admin, process/disk) with per-boundary trust assumptions and controls.
    3. Secure design principles argument (§8.3) — maps each Saltzer-Schroeder / OWASP principle (fail-safe defaults, complete mediation, least privilege, economy of mechanism, defense in depth, separation of privilege, psychological acceptability) to concrete bouine implementations.
    4. Common implementation weaknesses countered (§8.4) — systematic mapping of all 10 OWASP Top 10 (2021) categories and 7 additional CWE Top 25 categories (CWE-125, 190, 400, 444, 22, 79, 352) to specific bouine controls, with references to fuzz tests, linters, and config validation.

 Analysis 2/2 ●

  • Static code analysis


    The project MUST use at least one static analysis tool with rules or approaches to look for common vulnerabilities in the analyzed language or environment, if there is at least one FLOSS tool that can implement this criterion in the selected language. [static_analysis_common_vulnerabilities]
    Static analysis tools that are specifically designed to look for common vulnerabilities are more likely to find them. That said, using any static tools will typically help find some problems, so we are suggesting but not requiring this for the 'passing' level badge.

    The project applies multiple static analysis tools beyond compiler warnings:

    • govulncheck, Go vulnerability scanner, runs on pre-push and CI
    • gitleaks, secret detection, runs on every commit and CI

    All three run before any release (CI gate in ci.yml runs before release.yml on tag pushes).


  • Dynamic code analysis


    If the software produced by the project includes software written using a memory-unsafe language (e.g., C or C++), then at least one dynamic tool (e.g., a fuzzer or web application scanner) MUST be routinely used in combination with a mechanism to detect memory safety problems such as buffer overwrites. If the project does not produce software written in a memory-unsafe language, choose "not applicable" (N/A). [dynamic_analysis_unsafe]
    Examples of mechanisms to detect memory safety problems include Address Sanitizer (ASAN) (available in GCC and LLVM), Memory Sanitizer, and valgrind. Other potentially-used tools include thread sanitizer and undefined behavior sanitizer. Widespread assertions would also work.

    The project is written entirely in Go, a memory-safe language. No memory-unsafe languages (C/C++) are used.



You can use tools and AI systems to propose changes via a simple URL, such as https://www.bestpractices.dev/en/projects/14035/choose/edit?osps_ac_01_01_status=Met&osps_ac_01_01_justification=GitHub+enforced. See our automation proposals system for how to do that. This data is available under the Community Data License Agreement – Permissive, Version 2.0 (CDLA-Permissive-2.0). This means that a Data Recipient may share the Data, with or without modifications, so long as the Data Recipient makes available the text of this agreement with the shared Data. Please credit Théotime Lévêque and the OpenSSF Best Practices badge contributors.

Project badge entry owned by: Théotime Lévêque.
Entry created on 2026-08-12 12:54:41 UTC, last updated on 2026-08-19 20:35:31 UTC. Last achieved passing badge on 2026-08-13 07:59:52 UTC.