diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index abbd1c3..9be5e6c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,13 +35,10 @@ jobs: - name: Compile-check benches run: cargo build --workspace --benches - # Informational: surfaces formatting drift without blocking merges. - # Flip continue-on-error to false (or remove the line) once the - # codebase is fmt-clean. + # Gate: codebase is fmt-clean as of v0.1.0; keep it that way. fmt: - name: fmt (informational) + name: fmt runs-on: ubuntu-latest - continue-on-error: true steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable diff --git a/Cargo.toml b/Cargo.toml index 7ead7b1..322663f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ members = [ [workspace.package] version = "0.1.0" edition = "2021" -license = "MIT" +license = "Apache-2.0" authors = ["Levi J. Neuwirth "] rust-version = "1.75" diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md new file mode 100644 index 0000000..1f46b21 --- /dev/null +++ b/README.md @@ -0,0 +1,253 @@ +# LeVCS + +A distributed version control system with first-class federation, signed +authority chains, and a cascading merge engine. Content-addressed by +BLAKE3, signed with Ed25519, and built to fix what git can't. + +> **Status: v0.1.0 — protocol substrate complete, workflow surface deferred.** +> The object model, federation API, merge cascade, and instance server +> all work end-to-end. There is no PR review surface, issue tracker, or +> web UI yet — those are the next layer up. See +> [`doc/technical-report.md`](doc/technical-report.md) for a full +> framing of where this project is and why. + +--- + +## What's different from git + +- **Identity is in the protocol.** A repo's membership is a versioned, + signed authority object with explicit roles + (Reader/Contributor/Maintainer/Owner). Force-push enforcement and + push authorization are protocol-level, not server policy. +- **Federation is first-class.** Every repo has a global `repo_id` + (BLAKE3 of its genesis authority); instances mirror each other in + three storage modes (full / release-only / metadata-only). +- **Merge is a cascade**, not a line-level diff. Per-file dispatch to + a handler ranked by aggressiveness: textual fallback, format-aware + (JSON / YAML / TOML / XML / Markdown / prose), tree-sitter for + source code (Rust, Python, JS/TS, Go, C/C++, Java, Ruby, Bash), and + wasm-sandboxed plugins for the long tail. +- **BLAKE3, not SHA-1.** Tree-hashed, ~5 GiB/s on a laptop, 32-byte + IDs everywhere. +- **Releases are signed objects**, not mutable name pointers. + +For a deeper comparison and context, see the +[technical report](doc/technical-report.md). + +--- + +## Building + +LeVCS is a Rust workspace. You'll need a recent stable toolchain +(workspace MSRV is 1.75) and a C compiler for the tree-sitter grammars. + +```sh +cargo build --release +``` + +Two binaries land in `target/release/`: + +- `levcs` — the user-facing CLI. +- `levcs-instance` — the federation HTTP server. + +Install them somewhere on `PATH`: + +```sh +sudo install -m 0755 \ + target/release/levcs target/release/levcs-instance \ + /usr/local/bin/ +``` + +--- + +## Quick start (single user, local only) + +```sh +# Generate an identity key (stored in $XDG_CONFIG_HOME/levcs/keys.toml). +levcs key generate --label me + +# Create a repository wherever you have files to track. +mkdir /tmp/demo && cd /tmp/demo +echo "hello" > a.txt + +levcs init --key me +levcs track --all +levcs commit -m "first commit" +levcs log +``` + +That's a fully working LeVCS repo. Branch and merge: + +```sh +levcs branch feature/x +echo "more" >> a.txt +levcs commit -m "wip" +levcs branch main +levcs merge feature/x +``` + +If a merge produces conflicts, drop into the resolution TUI: + +```sh +levcs merge --resolve +``` + +Cut a release: + +```sh +levcs release v0.1.0 --notes "first release" +``` + +--- + +## Hosting an instance + +To dogfood the federation surface, run `levcs-instance` on a VPS behind +nginx or Caddy. The full walkthrough is in +[`deploy/README.md`](deploy/README.md): build, systemd unit, reverse +proxy templates, firewall, and the laptop-side bootstrap. + +The compressed version: + +```sh +sudo cp deploy/levcs-instance.service /etc/systemd/system/ +sudo cp deploy/instance.toml.example /etc/levcs/instance.toml +sudo $EDITOR /etc/levcs/instance.toml +sudo systemctl enable --now levcs-instance +# ... then drop deploy/Caddyfile.example into /etc/caddy/Caddyfile +``` + +From your laptop, point the local repo at the instance and push: + +```sh +levcs instance --set https://levcs.example.com/levcs/v1 +levcs push refs/branches/main +``` + +The first push to a fresh instance auto-inits the repo with your +genesis authority. Subsequent pushes are role-checked against the +authority chain. + +--- + +## Repository layout + +``` +crates/ + levcs-core/ Object model (Blob/Tree/Commit/Release/Authority), + hash, store, refs, repository abstractions. + levcs-identity/ Authority objects, Ed25519 keys, signing/verify. + levcs-merge/ Cascade engine, format and tree-sitter handlers, + plugin runtime, merge records. + levcs-protocol/ Pack codec, wire types, request signing, P2P. + levcs-client/ Thin HTTP client over the federation API. + levcs-instance/ Axum HTTP server (the federation peer). + levcs-cli/ The `levcs` user-facing CLI. + levcs-tui/ Conflict-resolution terminal UI. + +deploy/ Production deployment artifacts (systemd, Caddy, nginx). +scripts/ Reproducible benchmark and ops scripts. +doc/ Technical report and architecture docs. +.github/workflows/ CI configuration. +``` + +--- + +## Testing + +```sh +cargo test --workspace +``` + +Runs the full suite — unit tests, integration tests, federation +end-to-end tests including the three-instance "dogfood" scenario, the +merge conformance corpus, and property-based fuzz tests. ~194 tests at +v0.1.0; full run is well under a minute on a modern laptop. + +Useful subsets: + +```sh +# A single crate's tests +cargo test -p levcs-merge + +# A specific integration test +cargo test -p levcs-instance --test dogfood + +# Property tests only +cargo test -p levcs-merge --test proptest_textual +``` + +--- + +## Benchmarks + +Microbenchmarks live in each crate's `benches/` directory and use +`criterion`. A reproducible runner with metadata capture and optional +flamegraph generation is at `scripts/bench.sh`: + +```sh +scripts/bench.sh --quick # smoke test (~ a minute total) +scripts/bench.sh # full criterion run (~ a few minutes) +scripts/bench.sh --flamegraph # generate per-bench SVG flamegraphs +scripts/bench.sh --bench pack_codec # one bench only +``` + +Output goes to `bench-results/-/` with a parsed +`summary.txt`, criterion's HTML reports, and a `metadata.txt` capturing +rustc version, kernel, CPU, and git rev for run-to-run comparison. + +Headline numbers on a Ryzen 7 laptop: + +- **Pack decode** at 10 × 1 MiB entries: ~2.3 ms (4.3 GiB/s). +- **Blob serialize + BLAKE3** at 1 MiB: ~190 µs (5.1 GiB/s). +- **Textual three-way merge** of a 100 KiB document: ~4.6 ms. + +Pack encoding is the throughput floor at ~380 MiB/s — bottlenecked by +zstd level 3 on incompressible data. + +--- + +## Documentation + +- **[`doc/technical-report.md`](doc/technical-report.md)** — Distribution + document. What LeVCS is, how to use it, and how it differs from / + improves upon git. Targets technical evaluators and the workflow-spec + reader. +- **[`deploy/README.md`](deploy/README.md)** — Comprehensive VPS + deployment walkthrough. +- **`spec/`** — The protocol specification and trust-root revision. + Currently kept private; ask the maintainer for a copy. + +--- + +## Contributing + +This is a young project. The most useful contributions right now are: + +1. **Trying it.** Run `levcs init` on a real project, push to a local + instance, and report friction. +2. **Workflow design.** The next major piece of work is the workflow + spec — PR/review surface, issues, CI conventions. Discussion welcome. +3. **Plugin handlers.** The wasm plugin protocol exists; concrete + handlers (e.g. protobuf, SQL migrations) are needed to validate it. +4. **Tightening CI.** The `fmt` and `clippy` GitHub jobs are + informational; flipping them to gating would close a small but real + quality gap. + +Please open an issue or reach out before starting non-trivial work so +we can coordinate. + +--- + +## License + +Released under the Apache License 2.0 — see [`LICENSE`](LICENSE) for the +full text. + +--- + +## Citation + +If LeVCS supports academic work, please cite the v0.1.0 release. A +formal citation entry will land with the workflow spec; in the meantime +a repository-URL reference is fine. diff --git a/crates/levcs-cli/src/cli.rs b/crates/levcs-cli/src/cli.rs index 7657fb0..373968e 100644 --- a/crates/levcs-cli/src/cli.rs +++ b/crates/levcs-cli/src/cli.rs @@ -200,13 +200,30 @@ pub struct GcArgs { #[derive(Subcommand, Debug)] pub enum KeyCmd { - Generate { label: String, #[arg(long)] encrypt: bool }, + Generate { + label: String, + #[arg(long)] + encrypt: bool, + }, List, - Show { label: String }, - Export { label: String, path: PathBuf }, - Import { label: String, path: PathBuf }, - Remove { label: String }, - Rename { old: String, new: String }, + Show { + label: String, + }, + Export { + label: String, + path: PathBuf, + }, + Import { + label: String, + path: PathBuf, + }, + Remove { + label: String, + }, + Rename { + old: String, + new: String, + }, } #[derive(Subcommand, Debug)] @@ -215,18 +232,24 @@ pub enum AuthorityCmd { List, Add { key: String, - #[arg(long)] role: String, - #[arg(long)] handle: Option, - #[arg(long = "signing-key")] signing_key: Option, + #[arg(long)] + role: String, + #[arg(long)] + handle: Option, + #[arg(long = "signing-key")] + signing_key: Option, }, Remove { key: String, - #[arg(long = "signing-key")] signing_key: Option, + #[arg(long = "signing-key")] + signing_key: Option, }, Promote { key: String, - #[arg(long)] role: String, - #[arg(long = "signing-key")] signing_key: Option, + #[arg(long)] + role: String, + #[arg(long = "signing-key")] + signing_key: Option, }, } diff --git a/crates/levcs-cli/src/ctx.rs b/crates/levcs-cli/src/ctx.rs index c257289..199acea 100644 --- a/crates/levcs-cli/src/ctx.rs +++ b/crates/levcs-cli/src/ctx.rs @@ -69,9 +69,7 @@ pub fn load_secret(label: Option<&str>) -> Result<(String, SecretKey)> { keychain_path() )); } else { - return Err(anyhow!( - "multiple keys in keychain; pass --key