Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions .github/SECURITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Security Policy

## Reporting a Vulnerability

Please do not open a public issue or pull request for a potential security
vulnerability. Use GitHub's private vulnerability reporting for the public CLI
distribution repository:

https://github.com/boringcache/cli/security/advisories/new

Include the CLI version, platform, relevant release or workflow link, expected
impact, and enough reproduction detail for us to verify the report. Do not
include live credentials, customer data, or secrets.

## Supported Versions

The latest published CLI release is supported. Security fixes are normally
shipped as a new release rather than backported to older binaries.

## Scope

This public repository is the CLI distribution channel. It owns the installer,
release binaries, checksums, signed checksum bundles, release notes, and public
documentation. Product source is maintained separately in the private
BoringCache monorepo.

Reports about the CLI, installer, release pipeline, artifact integrity, or the
authorization boundary between the CLI and BoringCache service are all welcome
through the private reporting link above.
11 changes: 11 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
version: 2

updates:
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: weekly
groups:
github-actions:
patterns:
- "*"
42 changes: 42 additions & 0 deletions .github/workflows/verify.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: Verify Distribution

on:
push:
branches: ["main"]
pull_request:
branches: ["main"]
workflow_dispatch:

permissions:
contents: read

concurrency:
group: verify-distribution-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
verify:
name: Verify distribution
runs-on: ubuntu-24.04
timeout-minutes: 5

steps:
- name: Checkout distribution
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Check installer syntax
run: |
sh -n install.sh
sh -n install-web/install.sh
sh -n scripts/test-installer-trust.sh

- name: Test installer trust contract
run: scripts/test-installer-trust.sh

- name: Check public trust files
run: |
test -s .github/SECURITY.md
if grep -R -n --exclude-dir=.git 'boringcache/one@v1' README.md INSTALLATION.md docs install-web; then
echo 'Mutable boringcache/one references are not allowed in public guidance.' >&2
exit 1
fi
17 changes: 16 additions & 1 deletion INSTALLATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ BoringCache CLI. The normal install command is:
curl -sSL https://install.boringcache.com/install.sh | sh
```

The installer always verifies `SHA256SUMS`. When `cosign` is available it also
verifies `SHA256SUMS.bundle` automatically. To make Sigstore verification
mandatory, install `cosign` first and run:

```bash
curl -sSL https://install.boringcache.com/install.sh | BORINGCACHE_VERIFY_SIGNATURE=1 sh
```

When testing the installer itself, use:

```bash
Expand Down Expand Up @@ -59,6 +67,7 @@ The release workflow publishes:
- `boringcache-windows-amd64.exe`
- `boringcache-windows-arm64.exe`
- `SHA256SUMS`
- `SHA256SUMS.bundle`

## Installation Locations

Expand All @@ -71,7 +80,13 @@ The script installs to the first writable location:
## Security Notes

- Downloads use HTTPS.
- Release assets include `SHA256SUMS`.
- The installer always verifies the binary against `SHA256SUMS`.
- When `cosign` is available, the installer verifies `SHA256SUMS.bundle`
automatically; `BORINGCACHE_VERIFY_SIGNATURE=1` makes this fail closed.
- Sigstore verification accepts only the monorepo CLI release workflow on a
semantic-version tag or the checksum-repair workflow on `main`.
- The installer verifies the downloaded binary can run before finishing.
- Product source is maintained in the BoringCache monorepo; this public repo is
the distribution channel.
- Potential vulnerabilities should be reported through the private process in
[the security policy](.github/SECURITY.md), not a public issue.
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ cd your-project
boringcache onboard
```

The installer always verifies the release checksum. If `cosign` is installed,
it also verifies the signed checksum bundle automatically. To require the
signature and fail closed, run:

```bash
curl -sSL https://install.boringcache.com/install.sh | BORINGCACHE_VERIFY_SIGNATURE=1 sh
```

`boringcache onboard` authenticates the CLI, chooses a workspace, writes `.boringcache.toml` when it can, and lines up the same cache names across local runs, Docker builds, and GitHub Actions.

If you want to start sign-in from the terminal by email, use `boringcache onboard --email you@example.com`. For a brand-new account, pass `--name` and `--username` too.
Expand Down Expand Up @@ -38,7 +46,13 @@ Use adapter commands when the build tool already speaks a remote-cache protocol
Use `cache-registry` when the repo already has a checked-in local endpoint setup or another process should keep the proxy alive. `cache-registry` is the proxy. `run --proxy` and adapter commands temporarily start that same proxy for one command.
When `.boringcache.toml` stores the Docker command, `boringcache docker` is the short form. Use the longer version when you want to pass the Docker command inline.

If you are wiring GitHub Actions, use [`boringcache/one@v1`](https://github.com/boringcache/one) after onboard so CI can reuse the same repo config and trust model.
If you are wiring GitHub Actions, pin the verified `boringcache/one` v1.13.99
distribution commit after onboard so CI can reuse the same repo config and
trust model:

```yaml
- uses: boringcache/one@b55458ec8a4165e3fd70b1a1645f518a2095ed02 # v1.13.99
```

## Docs

Expand Down
12 changes: 6 additions & 6 deletions docs/github-actions.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ The preferred path is:
1. install the CLI locally
2. run `boringcache onboard`
3. commit `.boringcache.toml` when it helps
4. use [`boringcache/one@v1`](https://github.com/boringcache/one) in GitHub Actions
4. use the verified, immutable [`boringcache/one`](https://github.com/boringcache/one) release commit in GitHub Actions

That keeps CI and local runs on the same workspace, entries, and cache profiles.

Example:

```yaml
- uses: boringcache/one@v1
- uses: boringcache/one@b55458ec8a4165e3fd70b1a1645f518a2095ed02 # v1.13.99
with:
workspace: my-org/my-project
cache-profiles: bundle-install
Expand All @@ -21,10 +21,10 @@ Example:
BORINGCACHE_SAVE_TOKEN: ${{ secrets.BORINGCACHE_SAVE_TOKEN }}
```

For proxy-backed modes, `boringcache/one@v1` also accepts first-class `metadata-hints` so sessions and misses stay grouped by stable labels instead of per-run noise:
For proxy-backed modes, `boringcache/one` also accepts first-class `metadata-hints` so sessions and misses stay grouped by stable labels instead of per-run noise:

```yaml
- uses: boringcache/one@v1
- uses: boringcache/one@b55458ec8a4165e3fd70b1a1645f518a2095ed02 # v1.13.99
with:
mode: bazel
workspace: my-org/my-project
Expand All @@ -39,7 +39,7 @@ For proxy-backed modes, `boringcache/one@v1` also accepts first-class `metadata-

Keep those hints low-cardinality. Good values are `project=web`, `benchmark=grpc-bazel`, `tool=gradle`, `lane=ci`, or `workflow=build`. Avoid commit SHAs, run ids, timestamps, and cold/warm labels for normal sessions; BoringCache classifies new and recurring misses from cache target and lifecycle data.

If the repo already defines `[proxy]` or adapter `metadata-hints` in `.boringcache.toml`, `boringcache/one@v1` inherits them through the CLI dry-run plan. Prefer repo config for durable defaults and use the action input only when the workflow needs an explicit override.
If the repo already defines `[proxy]` or adapter `metadata-hints` in `.boringcache.toml`, `boringcache/one` inherits them through the CLI dry-run plan. Prefer repo config for durable defaults and use the action input only when the workflow needs an explicit override.
The canonical repo-config starting points in [Tool guides](tool-guides.md) are
meant to be shared between local CLI runs and GitHub Actions for exactly this
reason.
Expand Down Expand Up @@ -81,7 +81,7 @@ You can still override a configured adapter from the workflow when needed:
BORINGCACHE_SAVE_TOKEN: ${{ secrets.BORINGCACHE_SAVE_TOKEN }}
```

Use `boringcache/one@v1` when you want the action to keep owning tool setup such as Bazel rc files, Maven or Gradle cache config, buildx setup, or container networking.
Use `boringcache/one` when you want the action to keep owning tool setup such as Bazel rc files, Maven or Gradle cache config, buildx setup, or container networking. Keep the full commit pin and update it deliberately after verifying a newer public release.
When you run `boringcache docker` directly in GitHub Actions, the CLI derives the same branch/default/PR human tags from GitHub metadata that archive and proxy flows use. The action path passes provider-neutral metadata so Docker cache artifacts report the resolved human import/export tags and CI context.

For Docker and BuildKit registry caches on pull requests, restore-only is the default.
Expand Down
4 changes: 3 additions & 1 deletion docs/quick-start.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,7 @@ boringcache docker

The next docs to read are usually [Adapter commands](adapter-commands.md) and [Tool guides](tool-guides.md).

If the repo uses GitHub Actions, the next step is usually [`boringcache/one@v1`](https://github.com/boringcache/one).
If the repo uses GitHub Actions, the next step is usually the immutable
[`boringcache/one`](https://github.com/boringcache/one) v1.13.99 distribution
commit `b55458ec8a4165e3fd70b1a1645f518a2095ed02`.
See [GitHub Actions](github-actions.md).
2 changes: 1 addition & 1 deletion docs/tool-guides.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ The pattern is simple:
`cache-registry` itself is warm by default. Use `--on-demand` only for advanced shared-proxy setups that prefer immediate startup over warmed first reads.

The snippets below are intended to be copy-pasteable `.boringcache.toml`
starting points. They work for local CLI runs and for `boringcache/one@v1`
starting points. They work for local CLI runs and for `boringcache/one`
because the action asks the CLI for the same repo plan.

Shared defaults for the examples:
Expand Down
2 changes: 1 addition & 1 deletion install-web/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ <h3>🎯 Next Steps</h3>
<li><strong>Move into your repo:</strong> <code>cd your-project</code></li>
<li><strong>Connect the CLI:</strong> <code>boringcache onboard</code></li>
<li><strong>Wrap one repeated step:</strong> <code>boringcache run -- bundle install</code></li>
<li><strong>Wire CI when ready:</strong> <code>boringcache/one@v1</code></li>
<li><strong>Wire CI when ready:</strong> <code>boringcache/one@b55458ec8a4165e3fd70b1a1645f518a2095ed02</code> (v1.13.99)</li>
</ol>
<p>📖 <strong>Documentation:</strong> Visit <a href="https://boringcache.com/docs">boringcache.com/docs</a> for setup paths and CLI docs.</p>
</div>
Expand Down
86 changes: 58 additions & 28 deletions install-web/install.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/bin/sh
# BoringCache CLI Installation Script
# Usage: curl -sSL -H "Cache-Control: no-cache" -H "Pragma: no-cache" https://install.boringcache.com/install.sh | sh
# Strict: curl -sSL https://install.boringcache.com/install.sh | BORINGCACHE_VERIFY_SIGNATURE=1 sh

set -e

Expand All @@ -14,6 +15,9 @@ NC='\033[0m' # No Color
# GitHub repository
REPO="boringcache/cli"
BINARY_NAME="boringcache"
CHECKSUM_CERTIFICATE_IDENTITY_REGEXP='^https://github\.com/boringcache/monorepo/\.github/workflows/(cli-release\.yml@refs/tags/v[0-9]+\.[0-9]+\.[0-9]+|cli-release-checksums\.yml@refs/heads/main)$'
CHECKSUM_CERTIFICATE_OIDC_ISSUER='https://token.actions.githubusercontent.com'
VERIFY_CHECKSUM_SIGNATURE=0

# Function to print colored output
print_status() {
Expand Down Expand Up @@ -110,33 +114,52 @@ verify_checksum() {
fi
}

prepare_checksum_signature_verification() {
VERIFY_CHECKSUM_SIGNATURE=0

case "${BORINGCACHE_VERIFY_SIGNATURE:-auto}" in
auto)
if command -v cosign >/dev/null 2>&1; then
VERIFY_CHECKSUM_SIGNATURE=1
print_status "cosign found; release signature verification is enabled."
else
print_warning "cosign not found; continuing with SHA-256 checksum verification."
print_warning "Install cosign and set BORINGCACHE_VERIFY_SIGNATURE=1 for fail-closed signature verification."
fi
;;
1|true|required)
if ! command -v cosign >/dev/null 2>&1; then
print_error "BORINGCACHE_VERIFY_SIGNATURE=1 requires cosign in PATH."
return 1
fi
VERIFY_CHECKSUM_SIGNATURE=1
;;
0|false|off)
;;
*)
print_error "BORINGCACHE_VERIFY_SIGNATURE must be auto, 1, or 0."
return 1
;;
esac
}

verify_checksum_signature() {
local temp_dir="$1"

if [ "${BORINGCACHE_VERIFY_SIGNATURE:-0}" != "1" ]; then
if [ "${VERIFY_CHECKSUM_SIGNATURE}" != "1" ]; then
return 0
fi

if ! command -v cosign >/dev/null 2>&1; then
print_error "BORINGCACHE_VERIFY_SIGNATURE=1 requires cosign in PATH."
print_error "Install cosign or unset BORINGCACHE_VERIFY_SIGNATURE to use checksum-only verification."
exit 1
if [ ! -s "${temp_dir}/SHA256SUMS.bundle" ]; then
print_error "Signed checksum bundle is missing or empty."
return 1
fi

if [ -f "${temp_dir}/SHA256SUMS.bundle" ]; then
cosign verify-blob \
--bundle "${temp_dir}/SHA256SUMS.bundle" \
--certificate-identity-regexp '^https://github.com/boringcache/.+/.github/workflows/.+@refs/(heads/main|tags/v.+)$' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
"${temp_dir}/SHA256SUMS" >/dev/null
else
cosign verify-blob \
--certificate "${temp_dir}/SHA256SUMS.pem" \
--signature "${temp_dir}/SHA256SUMS.sig" \
--certificate-identity-regexp '^https://github.com/boringcache/.+/.github/workflows/.+@refs/(heads/main|tags/v.+)$' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
"${temp_dir}/SHA256SUMS" >/dev/null
fi
cosign verify-blob \
--bundle "${temp_dir}/SHA256SUMS.bundle" \
--certificate-identity-regexp "${CHECKSUM_CERTIFICATE_IDENTITY_REGEXP}" \
--certificate-oidc-issuer "${CHECKSUM_CERTIFICATE_OIDC_ISSUER}" \
"${temp_dir}/SHA256SUMS" >/dev/null
}

# Function to download and install binary
Expand Down Expand Up @@ -187,14 +210,20 @@ install_binary() {
# Create temporary directory
local temp_dir=$(mktemp -d)
local temp_file="${temp_dir}/${binary_name}"

if ! prepare_checksum_signature_verification; then
rm -rf "${temp_dir}"
exit 1
fi

download_file "${download_url}" "${temp_file}"
download_file "${release_url}/SHA256SUMS" "${temp_dir}/SHA256SUMS"
if [ "${BORINGCACHE_VERIFY_SIGNATURE:-0}" = "1" ]; then
if [ "${VERIFY_CHECKSUM_SIGNATURE}" = "1" ]; then
if ! download_file "${release_url}/SHA256SUMS.bundle" "${temp_dir}/SHA256SUMS.bundle"; then
rm -f "${temp_dir}/SHA256SUMS.bundle"
download_file "${release_url}/SHA256SUMS.sig" "${temp_dir}/SHA256SUMS.sig"
download_file "${release_url}/SHA256SUMS.pem" "${temp_dir}/SHA256SUMS.pem"
print_error "Signed checksum bundle is unavailable for ${version}."
rm -rf "${temp_dir}"
exit 1
fi
fi

Expand All @@ -205,13 +234,13 @@ install_binary() {
exit 1
fi

if ! verify_checksum "${temp_dir}" "${binary_name}"; then
print_error "Checksum verification failed for ${binary_name}"
if ! verify_checksum_signature "${temp_dir}"; then
print_error "Checksum signature verification failed"
exit 1
fi

if ! verify_checksum_signature "${temp_dir}"; then
print_error "Checksum signature verification failed"
if ! verify_checksum "${temp_dir}" "${binary_name}"; then
print_error "Checksum verification failed for ${binary_name}"
exit 1
fi

Expand Down Expand Up @@ -329,5 +358,6 @@ main() {
print_status "📖 Docs: https://boringcache.com/docs"
}

# Run main function
main "$@"
if [ "${BORINGCACHE_INSTALLER_SOURCE_ONLY:-0}" != "1" ]; then
main "$@"
fi
Loading