Compare commits

...
Author SHA1 Message Date
Kevin McConnell c1d304999d Add ONCE backup and restore hooks
By default, ONCE pauses the application container when taking a backup.
This guarantees a consistent snapshot of the data, but for a large
installation and/or a slow destination path (like a network mount), that
pause could be a bit disruptive to live traffic.

But ONCE also support a pause-free path: if a `pre-backup` hook is
present in the container, ONCE will run that and skip the pause. So by
supplying necessary hooks, we can avoid any disruption from backups.

- `pre-backup` runs the existing script/admin/prepare-backup, which uses
  SQLite's online backup API to get a consistent snapshop. k

- `post-restore` moves our snaphotted file back into place, and removes
  the orphaned sidecar files
2026-08-03 12:30:54 +01:00
Mike Dalessio d28ab55bf4 Document the self-hosted trust model in SECURITY.md (#230)
Nothing in the repository records that unrestricted bot webhook delivery is
deliberate, so the missing private-network guard reads as an oversight next to
the guarded unfurl path. Researchers report it as server-side request forgery,
repeatedly.
2026-07-31 13:09:59 -04:00
Stanko Krtalić 50f25cea80 Merge pull request #229 from basecamp/fix-version-number
Fix version number for CI built images
2026-07-30 18:51:01 +02:00
Stanko K.R. d79225ecd1 Fix version number for CI built images 2026-07-30 18:34:54 +02:00
8 changed files with 59 additions and 1 deletions

No files matched your search

+13
View File
@@ -67,6 +67,17 @@ jobs:
CANONICAL_IMAGE="${REGISTRY}/${IMAGE_REF,,}" CANONICAL_IMAGE="${REGISTRY}/${IMAGE_REF,,}"
echo "canonical=${CANONICAL_IMAGE}" >> "$GITHUB_OUTPUT" echo "canonical=${CANONICAL_IMAGE}" >> "$GITHUB_OUTPUT"
- name: Compute app version
id: version
shell: bash
run: |
set -eu
if [[ "${GITHUB_REF}" == refs/tags/v* ]]; then
echo "version=${GITHUB_REF#refs/tags/v}" >> "$GITHUB_OUTPUT"
else
echo "version=${GITHUB_SHA::7}" >> "$GITHUB_OUTPUT"
fi
- name: Extract Docker metadata (tags, labels) with arch suffix - name: Extract Docker metadata (tags, labels) with arch suffix
id: meta id: meta
uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f # v5.8.0 uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f # v5.8.0
@@ -94,6 +105,8 @@ jobs:
build-args: | build-args: |
OCI_SOURCE=${{ env.SOURCE_URL }} OCI_SOURCE=${{ env.SOURCE_URL }}
OCI_DESCRIPTION=${{ env.IMAGE_DESCRIPTION }} OCI_DESCRIPTION=${{ env.IMAGE_DESCRIPTION }}
APP_VERSION=${{ steps.version.outputs.version }}
GIT_REVISION=${{ github.sha }}
platforms: ${{ matrix.platform }} platforms: ${{ matrix.platform }}
push: ${{ github.event_name != 'pull_request' }} push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }} tags: ${{ steps.meta.outputs.tags }}
+3
View File
@@ -66,6 +66,9 @@ ENV HTTP_WRITE_TIMEOUT=300
COPY --from=build --chown=rails:rails /usr/local/bundle /usr/local/bundle COPY --from=build --chown=rails:rails /usr/local/bundle /usr/local/bundle
COPY --from=build --chown=rails:rails /rails /rails COPY --from=build --chown=rails:rails /rails /rails
# Install ONCE backup/restore hooks
COPY --chmod=755 hooks /hooks
# Set version and revision # Set version and revision
ARG APP_VERSION ARG APP_VERSION
ENV APP_VERSION=$APP_VERSION ENV APP_VERSION=$APP_VERSION
+4
View File
@@ -53,3 +53,7 @@ If you'd rather run the Docker image yourself, you can read more about that in t
You are welcome - and encouraged - to modify Campfire to your liking. You are welcome - and encouraged - to modify Campfire to your liking.
Please see our [development guide](docs/development.md) for how to get Campfire set up for local development. Please see our [development guide](docs/development.md) for how to get Campfire set up for local development.
## Security
See [SECURITY.md](SECURITY.md) for how to report a vulnerability and a description of our trust model.
+22
View File
@@ -0,0 +1,22 @@
# Security
Report vulnerabilities through our [HackerOne program](https://hackerone.com/basecamp) or at
https://github.com/basecamp/once-campfire/security. Note that Campfire is in scope for our security
program, but is not bounty eligible.
## Trust model
Campfire is self-hosted and single-tenant, so the administrator is the server operator,
with shell, network, and database access already. Anything requiring the administrator
role grants nothing they do not already have, and is not a vulnerability.
We do want reports of anything a **non-administrator** can reach, and of any credential or
network path held by the Campfire process but not by the operator's own shell.
## Intentional behavior
Bot webhook URLs are unrestricted: an administrator can point one at any address,
including internal ones, because operators legitimately wire bots to their own services.
Link unfurling is different because any member can trigger it by pasting a URL, so it
validates destinations through `RestrictedHTTP::PrivateNetworkGuard`. The difference is who
picks the destination.
+2
View File
@@ -24,6 +24,8 @@ class Webhook < ApplicationRecord
Net::HTTP::Post.new(uri, "Content-Type" => "application/json").tap { |request| request.body = payload } Net::HTTP::Post.new(uri, "Content-Type" => "application/json").tap { |request| request.body = payload }
end end
# No PrivateNetworkGuard, unlike Opengraph::Fetch: only an administrator sets this URL,
# and operators legitimately point bots at their own internal services.
def http def http
Net::HTTP.new(uri.host, uri.port).tap do |http| Net::HTTP.new(uri.host, uri.port).tap do |http|
http.use_ssl = (uri.scheme == "https") http.use_ssl = (uri.scheme == "https")
+1 -1
View File
@@ -1,2 +1,2 @@
Rails.application.config.app_version = ENV.fetch("APP_VERSION", "0") Rails.application.config.app_version = ENV["APP_VERSION"].presence || ENV["GIT_REVISION"].presence || "0"
Rails.application.config.git_revision = ENV["GIT_REVISION"] Rails.application.config.git_revision = ENV["GIT_REVISION"]
+12
View File
@@ -0,0 +1,12 @@
#!/bin/bash
set -euo pipefail
db_name="${RAILS_ENV:-production}.sqlite3"
snapshot="/rails/storage/backups/$db_name"
db="/rails/storage/db/$db_name"
if [ -f "$snapshot" ]; then
mkdir -p "$(dirname "$db")"
cp "$snapshot" "$db"
rm -f "$db-wal" "$db-shm"
fi
+2
View File
@@ -0,0 +1,2 @@
#!/bin/bash
exec /rails/script/admin/prepare-backup