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
46 changes: 46 additions & 0 deletions CODE_OF_CONDUCT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Code of conduct

## The short version

Be decent to the people you are working with. Argue with the code, not with the person who wrote it.

## What is expected

- **Criticise the work, not its author.** "This drops the lock when the store times out" is a
review. "You clearly did not think about this" is not, and it is also less useful, because it
says nothing about what to change.
- **Assume the other person had a reason.** Most surprising code is a constraint you have not met
yet. Ask what it was before deciding it was carelessness.
- **Take disagreement in good faith.** A maintainer refusing a feature is not rejecting you; this
project says no to things on purpose, and the reason will be given.
- **Respect the time people give.** Reports with the version and the logs, patches with tests, and
answers to review questions are all ways of doing that.

## What is not acceptable

Harassment in any form, including sexual attention, slurs, and comments demeaning to someone's
identity or background. Personal attacks. Publishing anyone's private information. Sustained
disruption of discussions, which includes reopening a settled decision for the fifth time.

None of this depends on whether you meant it as a joke, and none of it becomes acceptable because a
patch is good.

## Scope

Issues, pull requests, code review, discussions, and any space where somebody is acting as part of
this project.

## Reporting

Email <contact@ferrlabs.com> with `CONDUCT` in the subject. Reports are read by the maintainers and
kept confidential, including from the person reported, unless you agree otherwise. If your report
concerns a maintainer, say so and it will be handled by someone else.

Expect an acknowledgement within 3 working days. The response depends on what happened, from a
private word to a permanent ban, and you will be told what was decided.

## Attribution

Adapted from the [Contributor Covenant](https://www.contributor-covenant.org), version 2.1,
rewritten in this project's own words rather than pasted, because a policy nobody read is a policy
nobody follows.
93 changes: 93 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# Contributing

Bug reports and patches are welcome. This file says what happens to them and what a change needs to
carry before it can be merged, so that nothing about the process is a surprise.

## Reporting a bug

Open an [issue](https://github.com/FerrLabs/LFSX/issues). What makes a report actionable, in rough
order of usefulness:

- The version (`lfsx-server --version`) and how it is deployed: volume or bucket, which auth
provider, behind what proxy.
- What the client did and what it saw. The output of `git lfs push` with `GIT_TRACE=1` and
`GIT_CURL_VERBOSE=1` usually contains the whole story.
- The server's logs around the same moment, at `RUST_LOG=debug` if the default says nothing.
- What you expected instead. Sometimes the disagreement is about the protocol rather than the code,
and that is worth knowing early.

Never paste a token. The traces above contain the `Authorization` header.

For anything with a security consequence, read [SECURITY.md](SECURITY.md) instead: those go through
a private advisory rather than an issue.

## Proposing a change

Open an issue before a large change. Not as a formality: this server refuses features on purpose,
and it is better to hear that a direction is out of scope before writing it than after. Small fixes
can go straight to a pull request.

A pull request for anything larger references its issue, and the branch is named for what it does
(`feat/bucket-cache`, `fix/lock-takeover`).

## What a change has to carry

**Tests.** A fix carries the test that fails without it. A feature carries the tests for its edge
cases and its error paths, not only the happy one. A test earns its place by failing when the
behaviour it guards breaks: if you cannot say which bug it would catch, it is noise rather than
coverage.

**A green gate.** `cargo test`, `cargo clippy --all-targets -- -D warnings` and `cargo fmt --check`
all pass. The bucket suite runs against MinIO and Garage in CI, so a storage change is exercised
against two real implementations rather than a stub alone.

**Documentation, in the same change.** A new environment variable belongs in
[`docs/configuration.md`](docs/configuration.md), a new behaviour in the page that covers it, and a
user-visible change on the marketing site. Docs that trail behind the code are worse than missing
docs, because they are believed.

**Conventional commits.** `type(scope): description`, in the imperative, one line. The title of a
pull request becomes the commit on `main` and drives the version bump, so `feat:` and `fix:` are
load-bearing. Reserve `!` for a genuine breaking change: a removed flag, a renamed field, a format
that rejects what it used to accept. Adding something is not breaking.

**Comments that earn their place.** The code here explains itself through names and structure; a
comment is for the reason a reader could not recover from the code, usually why an obvious approach
was rejected. See the existing source for the register.

## What happens next

A pull request is reviewed, and the review takes the work seriously enough to disagree with it.
Expect questions about the failure mode you did not mention and the test that would have caught it.
Nothing merges without a green CI and a review.

## Building it

[`docs/development.md`](docs/development.md) has the commands, what each suite actually exercises,
and how to run the coverage report and the fuzz targets.

The one thing that page does not cover is the bucket suite, which needs an S3-compatible store to
point at:

```bash
docker run -d --name minio -p 9000:9000 \
-e MINIO_ROOT_USER=lfsxkey -e MINIO_ROOT_PASSWORD=lfsxsecret \
quay.io/minio/minio server /data

# once http://127.0.0.1:9000/minio/health/live answers
docker exec minio mc alias set local http://127.0.0.1:9000 lfsxkey lfsxsecret
docker exec minio mc mb --ignore-existing local/lfsx-test

LFSX_TEST_S3_ENDPOINT=http://127.0.0.1:9000 cargo test --test bucket
```

The bucket has to exist before the suite runs: nothing in the server creates one, and
`an_instance_that_cannot_reach_its_bucket_is_not_ready` depends on a missing bucket staying missing.
The name comes from `LFSX_TEST_S3_BUCKET`, which defaults to `lfsx-test`.

Without `LFSX_TEST_S3_ENDPOINT` those tests skip rather than fail, so a plain `cargo test` stays
useful on a laptop with nothing installed.

## Licence

Contributions are licensed under the [MPL-2.0](LICENSE), the licence this project ships under.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,12 @@ Full documentation lives at **[lfsx.dev](https://lfsx.dev)**. The same pages are
| [Performance](docs/performance.md) | Measured, not asserted |
| [Inspecting a repository](docs/inspecting.md), [Releases](docs/releases.md) | |

## Contributing

Bug reports and patches are welcome. [`CONTRIBUTING.md`](CONTRIBUTING.md) says what a change has to
carry and what happens to it after that; [`SECURITY.md`](SECURITY.md) covers anything with a
security consequence, which goes through a private advisory rather than an issue.

## Development

```bash
Expand Down
55 changes: 55 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Security policy

## Reporting a vulnerability

Report privately through [GitHub Security Advisories](https://github.com/FerrLabs/LFSX/security/advisories/new),
which reaches the maintainers without the report becoming public first. If that page is unavailable
to you, email <contact@ferrlabs.com> with `SECURITY` in the subject, which is the address the
[organisation policy](https://github.com/FerrLabs/.github/blob/main/SECURITY.md) names.

Please do not open a public issue for a vulnerability. An issue is visible to everyone the moment it
exists, including to whoever would use it.

**What to expect:** an acknowledgement within 3 working days, an assessment of whether it is a
vulnerability and how severe within 10 working days, and a fixed release before any public
disclosure. If a report turns out not to be a vulnerability we will say so and why, rather than
leaving it unanswered.

Include what you have: the version, whether the deployment uses a volume or a bucket, which auth
provider, and the smallest sequence of requests that shows the problem. A proof of concept against
a server you control is welcome and is not required.

## What is in scope

The server and the CLI in this repository, the published container image, and the Helm chart:

- Serving an object to a caller the forge would refuse, or refusing one it would admit.
- Reading or writing outside the storage root through a crafted object identifier or repository
name.
- Accepting an object whose bytes do not hash to its declared digest.
- Handing out a pre-signed URL that grants more than the batch response was about to grant.
- Two callers being told they hold the same lock.
- Leaking a token, an encryption key or a bucket credential into a log, an error or the pod spec.

## What is not in scope

- Anything reachable only with `LFSX_AUTH=disabled`, which accepts every request by design and says
so at boot. That mode is for a trusted network.
- The permissions the forge itself grants. LFSX mirrors them; if a token can push to a repository
upstream, it can push objects for that repository here, and that is the model rather than a bug.
- Denial of service by volume from an authenticated client. There is a transfer cap and a lookup
budget, and the reverse proxy owns request-rate limiting, which
[the documentation says outright](docs/reverse-proxy.md).
- Reports produced by a scanner with no analysis of whether the finding is reachable here.

## Supported versions

The latest minor release. This project is young enough that backporting to an older line would
promise more than one maintainer can keep; upgrading is the fix.

## Verifying what you run

Every release archive ships a checksum, a build provenance attestation and a cosign signature
bundle, and the container image is signed at push. [`docs/releases.md`](docs/releases.md) has the
commands to check each of them, which is worth doing before you trust a binary that guards your
assets.
Loading