crates/gunnar-ui-server/proto/gunnar/v1/policy.proto
syntax = "proto3";
package gunnar.v1;
import "gunnar/v1/common.proto";
// The pre-receive gate's configuration. It is what makes gunnar a forge
// rather than a bare repo over SSH.
//
// Gates are in-process `Gate` impls, never shell hooks: there is no shell on
// the server. This service configures them; `gunnar-policy` runs them
// between "pack is indexed" and "refs are applied".
service Policy {
rpc GetProtection(GetProtectionRequest) returns (GetProtectionResponse);
rpc SetProtection(SetProtectionRequest) returns (SetProtectionResponse);
rpc DeleteProtection(DeleteProtectionRequest) returns (DeleteProtectionResponse);
rpc GetRefNamePolicy(GetRefNamePolicyRequest) returns (GetRefNamePolicyResponse);
rpc SetRefNamePolicy(SetRefNamePolicyRequest) returns (SetRefNamePolicyResponse);
rpc ListGates(ListGatesRequest) returns (ListGatesResponse);
}
// Branch protection, keyed by ref pattern. The pattern is a git-style glob
// over full ref names: "refs/heads/main", "refs/heads/release/*".
message BranchProtection {
string ref_pattern = 1;
// A non-fast-forward update. Default (false) rejects force-pushes.
bool allow_force_push = 2;
// Default (false) rejects deletions of matching refs.
bool allow_delete = 3;
// Every new commit must carry a valid ssh-sig from a key registered to its
// pusher (the differentiator).
bool require_signature = 4;
// Empty means "any principal with WRITE".
repeated string allowed_principal_ids = 5;
// 0 means no limit. Rejects the 4 GB blob BEFORE it lands.
uint64 max_object_bytes = 6;
// 0 means no limit.
uint64 max_objects_per_push = 7;
// `PullRequests.Merge` into a matching ref refuses to count the pull
// request AUTHOR's own approval. Default (false) keeps the solo-operator
// posture: an appliance with one human must stay mergeable.
bool forbid_self_approval = 8;
// `PullRequests.Merge` into a matching ref needs this many DISTINCT
// verified approvers of the exact source tip. 0 means the baseline that
// always holds: one verified approval. Approvals by the same principal
// count once.
uint32 required_approvals = 9;
}
// A pattern allowlist/denylist over ref names, per repo. Deny wins.
message RefNamePolicy {
repeated string allow_patterns = 1;
repeated string deny_patterns = 2;
}
message GateInfo {
string name = 1;
string description = 2;
bool enabled = 3;
}
message GetProtectionRequest {
RepoPath repo = 1;
// Empty returns every protection rule on the repo.
string ref_pattern = 2;
}
message GetProtectionResponse {
repeated BranchProtection protections = 1;
}
message SetProtectionRequest {
RepoPath repo = 1;
// Upserted on `protection.ref_pattern`.
BranchProtection protection = 2;
}
message SetProtectionResponse {
BranchProtection protection = 1;
}
message DeleteProtectionRequest {
RepoPath repo = 1;
string ref_pattern = 2;
}
message DeleteProtectionResponse {}
message GetRefNamePolicyRequest {
RepoPath repo = 1;
}
message GetRefNamePolicyResponse {
RefNamePolicy policy = 1;
}
message SetRefNamePolicyRequest {
RepoPath repo = 1;
RefNamePolicy policy = 2;
}
message SetRefNamePolicyResponse {
RefNamePolicy policy = 1;
}
message ListGatesRequest {
RepoPath repo = 1;
}
message ListGatesResponse {
repeated GateInfo gates = 1;
}