Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
8b91534
fix(node): gate agent-task reads behind the same visibility rules as …
euxaristia Aug 12, 2026
e1d5149
fix(node): query the task limit-clamp test as the delegator
euxaristia Aug 12, 2026
d3f0880
fix(node): scope task visibility lookups to the page's repos
euxaristia Aug 12, 2026
c765498
Preserve authorized task reads across shipped clients.
euxaristia Aug 13, 2026
b26db4b
Bound denied task history scans.
euxaristia Aug 13, 2026
e3b1372
Signal incomplete task scans with recoverable cursors and map read er…
euxaristia Aug 14, 2026
d43829b
Stop disclosing denied task rows in the scan-wall cursor and add Grap…
euxaristia Aug 15, 2026
81a1776
Normalize task cursors and gate mutation endpoints behind visibility.
euxaristia Aug 15, 2026
b1ddf9d
Update complete_task test in test_support to exercise both 404 on unr…
euxaristia Aug 15, 2026
15d5748
Bind task to repo id in complete_task test in test_support.
euxaristia Aug 15, 2026
70b2509
Preserve timestamp fractional width and anchor continuation tests on …
euxaristia Aug 15, 2026
1029cdb
Match on Value::Object to extract task ID in GraphQL continuation test.
euxaristia Aug 15, 2026
1ed73ae
Remove unused mut binding on visible_newer in GraphQL query test.
euxaristia Aug 15, 2026
0ec4c71
Hide unauthorized claim and keep assigned tasks from being stolen
euxaristia Aug 16, 2026
1b9820b
Keep task-list incomplete for the scan ceiling only.
euxaristia Aug 16, 2026
ecf478e
fix(node): pin claim guards and map mutation errors through AppError
euxaristia Aug 18, 2026
ecfbfe8
fix(node): match bare and did:key assignee forms in claim and list
euxaristia Aug 18, 2026
5ac011f
fix(node): check task creation status and add assignee expression index
euxaristia Aug 31, 2026
cb41fc3
fix(node)!: Replace task cursors with opaque continuation tokens
euxaristia Aug 21, 2026
193a965
fix(node): End the candidate stream only after the batch is examined
euxaristia Aug 21, 2026
a65d7c7
fix(gl): Reject a non-positive task-list limit and fault the write un…
euxaristia Aug 21, 2026
62893e6
fix(node): Bind task cursors to the caller and brake the task read ro…
euxaristia Aug 21, 2026
d0a34f1
fix(node): Brake anonymous GraphQL task reads on the same per-IP bucket
euxaristia Aug 22, 2026
94605f8
fix(gl,node): parse typed task pages, track cursor cycles, and normal…
euxaristia Aug 22, 2026
e6cf84e
fix(node): Cap aliased GraphQL task reads per request and derive has_…
euxaristia Aug 23, 2026
e3f4031
fix(node): Check database continuation when scan budget ends on exact…
euxaristia Aug 23, 2026
7d641a3
fix(node): Document and pin the bound on the task scan-ceiling probe
euxaristia Aug 24, 2026
7da135c
Index task keyset pages so the scan ceiling bounds database work.
euxaristia Aug 31, 2026
664fad4
Reject oversized task pages so list never returns more than the reque…
euxaristia Aug 31, 2026
eccaf90
Enforce task page limits on legacy responses and drop redundant singl…
euxaristia Sep 2, 2026
b079c11
Address review feedback on task-read authorization gating and client …
euxaristia Sep 2, 2026
1d85e99
Address review feedback on task-read authorization gating, WebSocket …
euxaristia Sep 4, 2026
a4f777b
Address review feedback on quarantined task claims, WebSocket auth, a…
euxaristia Sep 4, 2026
dc4795d
Reject forged signatures during WebSocket authentication upgrade.
euxaristia Sep 4, 2026
ea5469b
Accumulate forged WebSocket handshake response until headers terminate.
euxaristia Sep 4, 2026
0c1d5e4
Withhold quarantined-repo tasks on all read surfaces before party che…
euxaristia Sep 5, 2026
41fef3a
docs: Align task-read documentation with enforced visibility and rate…
euxaristia Sep 7, 2026
d9aded2
docs: Distinguish task list and get behavior in rate-limit guidance.
euxaristia Sep 7, 2026
ab054fb
fix(node): Batch task quarantine checks to bound read costs.
euxaristia Sep 9, 2026
80ba7a3
docs(node): clarify the shared task-read budget
euxaristia Sep 9, 2026
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
13 changes: 13 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,19 @@ GITLAWB_IPFS_RESOLVE_BUDGET_SECS=10
# from the concurrency caps above). 0 disables. Default 600.
GITLAWB_IPFS_RATE_LIMIT=600

# Per-client-IP rate limit for the anonymous task read routes
# (GET /api/v1/tasks, GET /api/v1/tasks/{id}), in requests per hour.
# Both are publicly reachable (optional_signature). GET /api/v1/tasks runs
# collect_visible_tasks and returns a visibility-filtered page;
# GET /api/v1/tasks/{id} runs get_visible_task and returns an opaque 404 when
# the task is hidden or missing. These reads can require task, repository,
# and visibility-rule queries even when no task is returned, so the brake
# bounds the cost of anonymous probes. Keyed on the resolved client IP via
# GITLAWB_TRUSTED_PROXY. 0 disables. Default: 1200 (a list page
# followed by per-task reads is a normal client pattern, so this sits above
# the /ipfs budget). The GraphQL/WS task-read brake shares this budget.
GITLAWB_TASK_READ_RATE_LIMIT=1200

# ── Creation rate limiting (repo/agent/issue/PR flood brake) ──────────────
# Max creation requests (POST /api/v1/repos, /api/register, fork, issues,
# pulls) per client IP per hour, in addition to the per-DID limit. The per-DID
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ Known limitations:
- Repository write authorization is not secure by default: `GITLAWB_ENFORCE_OWNER_PUSH` defaults to `false` for compatibility, so a valid HTTP Signature identifies a pusher but does not enforce owner-only pushes.
- UCAN proof chains are validated when supplied, but UCAN capabilities are not consulted by write authorization and the root issuer is not independently trust-anchored. UCANs therefore do not yet grant scoped collaborator access.
- Agent lifecycle revocation is not enforced by HTTP Signature authorization; do not rely on removing or revoking an agent record to block a compromised signer.
- Read visibility is not a blanket data-classification boundary: task, IPFS-pin, and Arweave-anchor listings are not repository-gated; withheld path names can be visible to a root reader; and later visibility changes cannot retract content already announced or externally anchored.
- Task list/get reads (REST and GraphQL) are repository/task-gated and omit `ucan_token`. Read visibility is not a blanket data-classification boundary: IPFS-pin and Arweave-anchor listings are not repository-gated; withheld path names can be visible to a root reader; and later visibility changes cannot retract content already announced or externally anchored.
- Peer writes are signed by upgraded nodes, but strict signed-peer enforcement is opt-in during rolling upgrades.
- Current GraphQL mutations require an authenticated signer, but there is no mutation-specific guardrail that prevents a future mutation from omitting that check.
- Pull-request review comments do not yet have threaded line-level anchors, and merges do not enforce approval requirements.
Expand Down Expand Up @@ -412,6 +412,7 @@ Important node settings:
| `GITLAWB_IPFS_REQUEST_BUDGET_SECS` | Absolute wall-clock budget for one admitted `/ipfs/{cid}` request's acquire+walk lifetime. Per-stage clamps bound the acquire and walk stages to the remaining budget, and no stage starts once it is exhausted; the scan then stops with a retryable 503. The object-type probe and content-read `cat-file` subprocesses are budget-checked before starting and each also run under their own deadline (the lesser of `GITLAWB_GIT_SERVICE_TIMEOUT_SECS` and the remaining budget), reaped via process-group teardown, so a hung `cat-file` cannot hold the request's walk slot past it. One hang path is still unbounded: the probe's object-store readability check is a plain filesystem sweep with nothing to reap, so a wedged filesystem can hold the slot past the deadline. Default 600. Accepted range is 1 to 3153600000 (100 years), since the node derives a deadline from this value and a larger one cannot be represented. |
| `GITLAWB_IPFS_RESOLVE_BUDGET_SECS` | Shorter budget for the pre-walk CID resolve inside an admitted `/ipfs/{cid}` request: the lookup that maps the requested CID to its git oid(s), which runs while the scarce walk admission is already held. A well-formed CID with no pin row does no probe and no walk work, so without this it could hold a walk slot for the whole request budget while nothing walked, and enough such requests shed every real retrieval at admission. The effective deadline is the lesser of this and the remaining request budget, so a value above `GITLAWB_IPFS_REQUEST_BUDGET_SECS` degrades to the request budget. Only the resolve is on this clock; walk and probe work stay on the request budget, so a slow but progressing scan is never shed by it. Default 10. Accepted range is 1 to 3153600000 (100 years). |
| `GITLAWB_IPFS_RATE_LIMIT` | Max `/ipfs/{cid}` requests per client IP per hour (route flood brake). 0 disables. Default 600. |
| `GITLAWB_TASK_READ_RATE_LIMIT` | Max anonymous task-read requests (`GET /api/v1/tasks`, `GET /api/v1/tasks/{id}`) per client IP per hour, sharing the budget with the GraphQL/WS task-read brake. Uses `GITLAWB_TRUSTED_PROXY` to resolve the client IP. 0 disables. Default 1200 (above the `/ipfs` budget to allow list pages followed by per-task reads). |
| `GITLAWB_TIGRIS_BUCKET` | Optional S3/Tigris shared repo storage bucket. |
| `GITLAWB_PINATA_JWT` | Optional Pinata/IPFS warm-storage pinning. |
| `GITLAWB_IRYS_URL` | Optional Irys/Arweave permanent anchoring. |
Expand Down
2 changes: 1 addition & 1 deletion SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ These are documented limitations of the current live release. They should be pri
### Private repository reads
- Repository and path-scoped visibility checks are enforced for repository API and Git content reads. A denied whole-repository or root read returns the same 404 shape as a missing repository, so the denial does not reveal private-repository existence.
- Sparse-clone support exposes withheld path globs to callers who may read the repository root. Do not put sensitive information in withheld path names.
- `GET /api/v1/tasks`, `/api/v1/ipfs/pins`, and `/api/v1/arweave/anchors` are not repository-gated. Task records include a UCAN token; pin and anchor listings expose object and ref metadata.
- Task list/get reads (`GET /api/v1/tasks`, `GET /api/v1/tasks/{id}`, and GraphQL `tasks` / `task`) are repository/task-gated through shared visibility collectors and omit `ucan_token`. `/api/v1/ipfs/pins` and `/api/v1/arweave/anchors` are not repository-gated; pin and anchor listings expose object and ref metadata.
- Changing a repository's visibility controls future serving, but cannot retract ref metadata or configured external pins and anchors already announced while the repository was public. Do not push secrets to an announceable repository.
- **Impact:** Visibility policies protect the repository and Git content routes they gate, not every metadata endpoint or previously published content.
- **Remaining boundary:** This read control does not address the independent write-authorization and UCAN-delegation limitations described above.
Expand Down
1 change: 1 addition & 0 deletions crates/gitlawb-node/src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ pub mod replicas;
pub mod repos;
pub mod resolve;
pub mod stars;
pub mod task_cursor;
pub mod tasks;
pub mod visibility;
pub mod webhooks;
Expand Down
Loading
Loading