* fix(node): bound GraphQL query cost * fix(node)!: bound repo names so emitted cursors always parse The reposPage cursor embeds base64(JSON(owner_did, name)) while parse_repo_cursor rejects cursors over 4096 bytes, but repo names were unbounded on every write path. A single long-named visible repo made the server emit an endCursor it then rejected as "invalid repository cursor", dead-ending pagination for every caller past that row. Bound names to MAX_REPO_NAME_LEN (100 bytes) at the create_repo and fork_repo handlers via a shared validate_repo_name helper (bad charset is still a 400), and reject overlong peer-supplied names in Db::upsert_mirror_repo (the sync caller already drops the error and skips the mirror). Also in this round: - docs/graphql-pagination.md states the 200 page-size maximum and corrects the over-budget remedy: a smaller limit does not reduce the reposPage or repos price, which is charged at the full MAX_VISIBLE_REPO_PAGE_SIZE scan regardless of limit. - Tests pin refUpdates(limit: -1) clamping to zero rows, the parse_repo_cursor wrong-shape-JSON arm with its exact "invalid repository cursor" message, the longest-admissible-name cursor round-trip, and the mirror write-path rejection. BREAKING CHANGE: the GraphQL `repos` field now returns an error instead of the full list when more than MAX_VISIBLE_REPO_PAGE_SIZE (200) repositories are visible; larger lists must use `reposPage` with `limit`/`after`. Repository names are additionally limited to 100 bytes at creation, fork, and mirror-registration time. * fix(node): address beardthelion P3 findings on name bound and input messages - Assert each rejection's own message in the reposPage invalid-inputs loop: the loop no longer accepts either message for every query, so a misattributed message (limit arm returning the cursor message) goes red. - Pin the create/fork name-bound wiring through the handler: new test drives create_repo with an overlong name via test_state_lazy and asserts the 400; deleting the validate_repo_name call site would proceed to the lazy DB pool and fail with a connection error instead. - Document the API-side vs disk-side validate_repo_name divergence on the new function, and tie the store's literal 100 to MAX_REPO_NAME_LEN so the two validators cannot drift apart on length. --------- Co-authored-by: Marlowe <[email protected]> Co-authored-by: cairn-intern <[email protected]>
5.0 KiB
Contributing to Twigpine
Thanks for your interest in contributing. Twigpine is an open protocol — agents and humans welcome.
Quick start for contributors
# Clone and build
git clone https://github.com/Twigpine/node
cd node
# Build everything
cargo build
# Run the workspace test suite
cargo test --workspace
# Run a local node (requires a Postgres instance — see docker-compose.yml)
cargo run -p gitlawb-node
# Build the CLI
cargo run -p gl -- --help
The fastest dev loop is docker compose up postgres -d for the database, then cargo run -p gitlawb-node for the node.
Repository layout
crates/
├── gitlawb-core/ crypto primitives (DID, CID, HTTP sigs, UCAN, ref certs)
├── gitlawb-node/ axum HTTP server, git smart HTTP, P2P, GraphQL
├── gl/ CLI — identity, repos, MCP server, Base L2 names
├── git-remote-gitlawb/ git remote helper for gitlawb:// URLs
├── gitlawb-attest/ provenance attestations for ref-update certificates
└── icaptcha-client/ client for the iCaptcha proof-of-intelligence service
docs/ Operator guides
scripts/ Build helpers
Smart contracts live in a separate repo: github.com/Twigpine/contracts.
Ways to contribute
- Bug reports — open an issue with steps to reproduce
- Feature requests — open an issue describing the use case
- Code — open a PR (see guidelines below)
- Documentation — fixes and improvements always welcome
- Node operators — run a node and join the network
- Agent integrations — build tools using
gl mcp serve
PR guidelines
- One thing per PR. Small, focused PRs get reviewed faster.
- Tests. New functionality should have tests. Run
cargo test --workspacebefore opening a PR. - No breaking changes without discussion. Open an issue first for protocol-level changes.
- Conventional commits. Use
feat:,fix:,docs:,refactor:,test:,chore:. Releases are automated by release-please — your commit prefixes drive the next version bump. - Format and lint. Run
cargo fmt --allandcargo clippy --workspace --all-targets -- -D warningsbefore submitting. CI will reject anything that fails these. - Security-surface rules.
AGENTS.mdcarries the authorization invariants PRs most often break; it is written for coding agents and humans alike, so read it before touching endpoints, visibility, or migrations.
What gets merged, what gets closed
We welcome contributions from humans and agents alike. To keep review sustainable, PRs are expected to clear a basic quality bar:
- Link an issue. Bug fixes and features should reference an issue (
Closes #123). For protocol-level changes (identity, signatures, UCAN, ref certs, wire formats), open the issue before writing code. - One change per PR. Unrelated churn slows review and gets sent back.
- Tests and a green pipeline. New behavior needs tests;
cargo fmt,cargo clippy, and the full CI suite must pass. - A real description. Say what changes and why. "Update code" is not a description.
A triage bot labels PRs that are missing these and leaves a short note. Nothing is closed automatically while you're engaging. A flagged PR still missing a description after 14 days of inactivity gets a stale warning, and is closed 7 days later if still untouched. A missing issue link alone never triggers closure; that label stays advisory. Closed PRs can be reopened at any time once updated.
Development environment
Requirements:
- Rust stable (≥ 1.91) — install via rustup
- PostgreSQL 16+ — required for the node (it uses
pg_input_is_valid, which exists only on PostgreSQL 16 and later). Use the bundleddocker-compose.ymlfor local dev. - Docker (optional, for full-stack local testing)
Environment variables:
cp .env.example .env
# edit .env
The minimum required variable is DATABASE_URL. Everything else has sensible defaults — see .env.example.
Running tests
# All workspace tests
cargo test --workspace
# Specific crate
cargo test -p gitlawb-core
cargo test -p gitlawb-node
Areas actively looking for help
- TypeScript SDK (
@gitlawb/sdk) — client library for the HTTP API - Python SDK (
gitlawb) — for ML/agent pipeline integration - UCAN authorization — add trusted issuer anchoring, capability checks, and authorization-aware revocation
- Filecoin storage tier — wire up cold storage deals
- Documentation — guides, tutorials, API examples
- Node operators — run a public node and report issues
Code of conduct
Be constructive and respectful. This is a technical project — focus on ideas and code, not people.
License
By contributing, you agree that your contributions will be dual licensed under MIT and Apache-2.0, at the user's option.