diff --git a/crates/openshell-providers/src/profiles.rs b/crates/openshell-providers/src/profiles.rs index d31085b..7fc9fcb 100644 --- a/crates/openshell-providers/src/profiles.rs +++ b/crates/openshell-providers/src/profiles.rs @@ -1672,12 +1672,29 @@ mod tests { }), "github profile should include read-only GraphQL endpoint" ); + // api.github.com endpoints use access: read-only. + // github.com uses explicit rules (no access preset) to allow + // POST git-upload-pack for clone/fetch while blocking push. assert!( proto .endpoints .iter() + .filter(|endpoint| endpoint.host == "api.github.com") .all(|endpoint| endpoint.access == "read-only"), - "github profile endpoints should all be read-only" + "api.github.com endpoints should be read-only" + ); + let git_endpoint = proto + .endpoints + .iter() + .find(|endpoint| endpoint.host == "github.com") + .expect("github.com endpoint"); + assert!( + git_endpoint.access.is_empty(), + "github.com should use explicit rules, not an access preset" + ); + assert!( + !git_endpoint.rules.is_empty(), + "github.com should have explicit L7 rules" ); assert_eq!(proto.binaries.len(), 4); } diff --git a/providers/github.yaml b/providers/github.yaml index 4ce5af2..61d7ff8 100644 --- a/providers/github.yaml +++ b/providers/github.yaml @@ -30,9 +30,27 @@ endpoints: access: read-only enforcement: enforce # github.com is the git transport (clone / fetch by default). + # Explicit rules instead of `access: read-only` so that POST to + # git-upload-pack (clone/fetch) is allowed while git-receive-pack + # (push) stays blocked. - host: github.com port: 443 protocol: rest - access: read-only enforcement: enforce + rules: + - allow: + method: GET + path: "**" + - allow: + method: HEAD + path: "**" + - allow: + method: OPTIONS + path: "**" + - allow: + method: POST + path: "**/git-upload-pack" + - allow: + method: POST + path: "**/info/refs" binaries: [/usr/bin/gh, /usr/local/bin/gh, /usr/bin/git, /usr/local/bin/git]