Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
e1ca1b6
fix(node): gate agent-task reads behind the same visibility rules as …
euxarist Aug 12, 2026
171a434
fix(node): query the task limit-clamp test as the delegator
euxarist Aug 12, 2026
f22ebac
fix(node): scope task visibility lookups to the page's repos
euxarist Aug 12, 2026
8d5adee
Preserve authorized task reads across shipped clients.
euxarist Aug 13, 2026
7149a37
Bound denied task history scans.
euxarist Aug 13, 2026
f0f031f
Signal incomplete task scans with recoverable cursors and map read er…
euxarist Aug 14, 2026
c268c03
Stop disclosing denied task rows in the scan-wall cursor and add Grap…
euxarist Aug 15, 2026
d4b5e99
Normalize task cursors and gate mutation endpoints behind visibility.
euxarist Aug 15, 2026
4f58cdd
Update complete_task test in test_support to exercise both 404 on unr…
euxarist Aug 15, 2026
21b576a
Bind task to repo id in complete_task test in test_support.
euxarist Aug 15, 2026
7d48166
Preserve timestamp fractional width and anchor continuation tests on …
euxarist Aug 15, 2026
536ffb4
Match on Value::Object to extract task ID in GraphQL continuation test.
euxarist Aug 15, 2026
e6efc9e
Remove unused mut binding on visible_newer in GraphQL query test.
euxarist Aug 15, 2026
f15ca13
Hide unauthorized claim and keep assigned tasks from being stolen
euxarist Aug 16, 2026
86c1dc7
Keep task-list incomplete for the scan ceiling only.
euxarist Aug 16, 2026
b054189
fix(node): pin claim guards and map mutation errors through AppError
euxarist Aug 18, 2026
ffe87c6
fix(node): match bare and did:key assignee forms in claim and list
euxarist Aug 18, 2026
1a89c0e
fix(node): check task creation status and add assignee expression index
euxarist Aug 31, 2026
7c2741e
fix(node)!: Replace task cursors with opaque continuation tokens
euxarist Aug 21, 2026
b175fdb
fix(node): End the candidate stream only after the batch is examined
euxarist Aug 21, 2026
8f202b6
fix(gl): Reject a non-positive task-list limit and fault the write un…
euxarist Aug 21, 2026
2445f78
fix(node): Bind task cursors to the caller and brake the task read ro…
euxarist Aug 21, 2026
2a646d1
fix(node): Brake anonymous GraphQL task reads on the same per-IP bucket
euxarist Aug 22, 2026
58bce06
fix(gl,node): parse typed task pages, track cursor cycles, and normal…
euxarist Aug 22, 2026
585b335
fix(node): Cap aliased GraphQL task reads per request and derive has_…
euxarist Aug 23, 2026
a60272f
fix(node): Check database continuation when scan budget ends on exact…
euxarist Aug 23, 2026
1c6d67a
fix(node): Document and pin the bound on the task scan-ceiling probe
euxarist Aug 24, 2026
eebcfd8
Index task keyset pages so the scan ceiling bounds database work.
euxarist Aug 31, 2026
f0a001a
Reject oversized task pages so list never returns more than the reque…
euxarist Aug 31, 2026
deaee40
Enforce task page limits on legacy responses and drop redundant singl…
euxarist Sep 2, 2026
7c3969f
Address review feedback on task-read authorization gating and client …
euxarist Sep 2, 2026
a0eac99
Address review feedback on task-read authorization gating, WebSocket …
euxarist Sep 4, 2026
36a2748
Address review feedback on quarantined task claims, WebSocket auth, a…
euxarist Sep 4, 2026
fc4fa03
Reject forged signatures during WebSocket authentication upgrade.
euxarist Sep 4, 2026
16d2466
Accumulate forged WebSocket handshake response until headers terminate.
euxarist Sep 4, 2026
e864f92
Withhold quarantined-repo tasks on all read surfaces before party che…
euxarist Sep 5, 2026
43b34ad
docs: Align task-read documentation with enforced visibility and rate…
euxarist Sep 7, 2026
ac0cac1
docs: Distinguish task list and get behavior in rate-limit guidance.
euxarist Sep 7, 2026
b7bd108
fix(node): Batch task quarantine checks to bound read costs.
euxarist Sep 9, 2026
8b0a8cb
docs(node): clarify the shared task-read budget
euxarist Sep 9, 2026
6ebf754
fix(node,gl): bound scoped repo lookup and validate MCP cursor
euxarist Sep 10, 2026
7527be8
test(db): verify scoped lookup work in prepared plans
euxarist Sep 12, 2026
29fbec5
docs(db): remove stray dedup comment escapes
euxarist Sep 12, 2026
7a98ab1
fix(node): address #464 review findings
cairn-intern Sep 25, 2026
e394f90
test(node): pin the delegator deny on a pre-assigned claim
cairn-intern Sep 26, 2026
96726a3
test(node): exercise streamed byte-budget guard with chunked body
cairn-intern Sep 26, 2026
4f12e15
fix(node): pin declared-length byte-budget arm in oversized content-l…
cairn-intern Sep 26, 2026
3d4ac67
fix(node): fail closed on claim for unresolvable repo
cairn-intern Sep 27, 2026
7ad01be
fix(node): pad sealed task cursor to fixed width
cairn-intern Sep 28, 2026
daa3e98
fix(node): address beardthelion round-six P3 findings on task cursor
cairn-intern Sep 30, 2026
408d588
fix(node): address beardthelion round-seven P3 findings on task cursor
cairn-intern Oct 1, 2026
7a1f644
test(node): address beardthelion round-eight P3 findings on task cursor
cairn-intern Oct 1, 2026
1514f3d
Merge branch 'main' into recreate-396-fix-task-read-auth-gate-v2
cairn-intern Nov 7, 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 @@ -320,6 +320,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 secure by default: `GITLAWB_ENFORCE_OWNER_PUSH` defaults to `true`, so a valid HTTP Signature identifies a pusher and the node additionally requires that pusher to be the repository owner. Set `GITLAWB_ENFORCE_OWNER_PUSH=false` only for the duration of a rolling upgrade whose pushers are not yet the repo owner. Authentication is not authorization on its own (anyone can mint a `did:key` and sign), so owner enforcement is the only thing that prevents every signed caller from pushing to every repository, private ones included.
- 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.
- GraphQL mutations require a signed identity (a verified signer bound to the acting DID), are limited to the agent-task queue, and are covered by a CI completeness fence that requires signer acquisition and actor binding on every registered mutation; repo writes are not exposed over GraphQL and remain REST-only.
- Pull-request review comments do not yet have threaded line-level anchors, and merges do not enforce approval requirements.
Expand Down Expand Up @@ -419,6 +419,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