You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 0a15e76
Browse filesBrowse the repository at this point in the historyBrowse files
* feat(node): owner-only push enforcement behind GITLAWB_ENFORCE_OWNER_PUSH (#31)
A valid did:key signature on git-receive-pack is authentication, not
authorization: any party can generate a key, derive its DID, sign, and push to
an unprotected branch. Owner checks only ran on protected branches, so a
non-owner could write to unprotected branches of an arbitrary repo.
Add an opt-in flag GITLAWB_ENFORCE_OWNER_PUSH (default false, mirroring
GITLAWB_REQUIRE_SIGNED_PEER_WRITES) that requires the authenticated pusher to be
the repo owner on every branch. Default-off keeps live nodes unaffected.
Design follows the maintainer's review on #31:
- Authorize on the canonical AuthenticatedDid injected by require_signature, via
Extension<AuthenticatedDid> on the handler — not a re-parse of the headers.
The legacy branch-protection check is left as-is.
- Fail closed: an absent identity or a non-owner caller is rejected. The policy
lives in a pure fn (owner_push_rejection) so it is unit-tested without a DB.
- The gate runs before branch protection, so one rejection yields one error body.
- Factor the duplicated owner-match into auth::is_repo_owner, reused by
receive-pack, protect.rs, and visibility.rs (each keeps its own message).
events.rs / peers.rs are left out — they aren't owner checks.
- Name the push gate by intent (caller_authorized_to_push) so the planned
Phase 2 UCAN git/push capability is a pure addition, not a rewrite.
Tests: owner (full + short DID) allowed, non-owner rejected, missing-DID
rejected, flag-off legacy. Docs: .env.example + docs/RUN-A-NODE.md.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(node): address review on #68 — 403 status, finish owner-match consolidation
Per @beardthelion's review:
- Return 403 Forbidden (not 400) for authorization denials: the owner-push gate,
the branch-protection denial, and the owner checks in protect.rs / visibility.rs.
400 reads as a malformed request and some git/CI clients retry it.
- Finish the is_repo_owner consolidation: route the branch-protection check and
the repos list filter through the helper. The branch-protection check now uses
the verified AuthenticatedDid (auth.0) instead of re-parsing the headers.
- Drop the second identity source on the push path entirely: the post-push event
recording also uses auth.0, so extract_did_from_auth (and the handler's
HeaderMap param + import) are removed.
- Tests assert the Forbidden variant (so a future status regression fails loudly)
and add direct coverage for is_repo_owner / caller_authorized_to_push.
- Docs: warn that enabling the flag blocks delegated and CI agents until the
Phase 2 UCAN git/push capability is honored.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: FrozenRaspberry <3733873+FrozenRaspberry@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
0 commit comments