Skip to content

Commit 7f7f194

Browse files
authored
Add List fine-grained personal access tokens with access to organization resources API (#3215)
Fixes: #3213.
1 parent 020ef00 commit 7f7f194

File tree

4 files changed

+428
-0
lines changed

4 files changed

+428
-0
lines changed

github/github-accessors.go

Lines changed: 72 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

github/github-accessors_test.go

Lines changed: 84 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

github/orgs_personal_access_tokens.go

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,106 @@ import (
99
"context"
1010
"fmt"
1111
"net/http"
12+
"net/url"
13+
"strings"
1214
)
1315

16+
// PersonalAccessToken represents the minimal representation of an organization programmatic access grant.
17+
//
18+
// GitHub API docs: https://docs.github.com/en/rest/orgs/personal-access-tokens?apiVersion=2022-11-28
19+
type PersonalAccessToken struct {
20+
// "Unique identifier of the fine-grained personal access token.
21+
// The `pat_id` used to get details about an approved fine-grained personal access token.
22+
ID *int64 `json:"id"`
23+
24+
// Owner is the GitHub user associated with the token.
25+
Owner *User `json:"owner"`
26+
27+
// RepositorySelection is the type of repository selection requested.
28+
// Possible values are: "none", "all", "subset".
29+
RepositorySelection *string `json:"repository_selection"`
30+
31+
// URL to the list of repositories the fine-grained personal access token can access.
32+
// Only follow when `repository_selection` is `subset`.
33+
RepositoriesURL *string `json:"repositories_url"`
34+
35+
// Permissions are the permissions requested, categorized by type.
36+
Permissions *PersonalAccessTokenPermissions `json:"permissions"`
37+
38+
// Date and time when the fine-grained personal access token was approved to access the organization.
39+
AccessGrantedAt *Timestamp `json:"access_granted_at"`
40+
41+
// Whether the associated fine-grained personal access token has expired.
42+
TokenExpired *bool `json:"token_expired"`
43+
44+
// Date and time when the associated fine-grained personal access token expires.
45+
TokenExpiresAt *Timestamp `json:"token_expires_at"`
46+
47+
// Date and time when the associated fine-grained personal access token was last used for authentication.
48+
TokenLastUsedAt *Timestamp `json:"token_last_used_at"`
49+
}
50+
51+
// ListFineGrainedPATOptions specifies optional parameters to ListFineGrainedPersonalAccessTokens.
52+
type ListFineGrainedPATOptions struct {
53+
// The property by which to sort the results.
54+
// Default: created_at
55+
// Value: created_at
56+
Sort string `url:"sort,omitempty"`
57+
58+
// The direction to sort the results by.
59+
// Default: desc
60+
// Value: asc, desc
61+
Direction string `url:"direction,omitempty"`
62+
63+
// A list of owner usernames to use to filter the results.
64+
Owner []string `url:"-"`
65+
66+
// The name of the repository to use to filter the results.
67+
Repository string `url:"repository,omitempty"`
68+
69+
// The permission to use to filter the results.
70+
Permission string `url:"permission,omitempty"`
71+
72+
// Only show fine-grained personal access tokens used before the given time.
73+
// This is a timestamp in ISO 8601 format: YYYY-MM-DDTHH:MM:SSZ.
74+
LastUsedBefore string `url:"last_used_before,omitempty"`
75+
76+
// Only show fine-grained personal access tokens used after the given time.
77+
// This is a timestamp in ISO 8601 format: YYYY-MM-DDTHH:MM:SSZ.
78+
LastUsedAfter string `url:"last_used_after,omitempty"`
79+
80+
ListOptions
81+
}
82+
83+
// ListFineGrainedPersonalAccessTokens lists approved fine-grained personal access tokens owned by organization members that can access organization resources.
84+
// Only GitHub Apps can call this API, using the `Personal access tokens` organization permissions (read).
85+
//
86+
// GitHub API docs: https://docs.github.com/rest/orgs/personal-access-tokens#list-fine-grained-personal-access-tokens-with-access-to-organization-resources
87+
//
88+
//meta:operation GET /orgs/{org}/personal-access-tokens
89+
func (s *OrganizationsService) ListFineGrainedPersonalAccessTokens(ctx context.Context, org string, opts *ListFineGrainedPATOptions) ([]*PersonalAccessToken, *Response, error) {
90+
u := fmt.Sprintf("orgs/%v/personal-access-tokens", org)
91+
// The `owner` parameter is a special case that uses the `owner[]=...` format and needs a custom function to format it correctly.
92+
u, err := addListFineGrainedPATOptions(u, opts)
93+
if err != nil {
94+
return nil, nil, err
95+
}
96+
97+
req, err := s.client.NewRequest(http.MethodGet, u, opts)
98+
if err != nil {
99+
return nil, nil, err
100+
}
101+
102+
var pats []*PersonalAccessToken
103+
104+
resp, err := s.client.Do(ctx, req, &pats)
105+
if err != nil {
106+
return nil, resp, err
107+
}
108+
109+
return pats, resp, nil
110+
}
111+
14112
// ReviewPersonalAccessTokenRequestOptions specifies the parameters to the ReviewPersonalAccessTokenRequest method.
15113
type ReviewPersonalAccessTokenRequestOptions struct {
16114
Action string `json:"action"`
@@ -34,3 +132,36 @@ func (s *OrganizationsService) ReviewPersonalAccessTokenRequest(ctx context.Cont
34132

35133
return s.client.Do(ctx, req, nil)
36134
}
135+
136+
// addListFineGrainedPATOptions adds the owner parameter to the URL query string with the correct format if it is set.
137+
//
138+
// GitHub API expects the owner parameter to be a list of strings in the `owner[]=...` format.
139+
// For multiple owner values, the owner parameter is repeated in the query string.
140+
//
141+
// Example:
142+
// owner[]=user1&owner[]=user2
143+
// This will filter the results to only include fine-grained personal access tokens owned by `user1` and `user2`.
144+
//
145+
// This function ensures the owner parameter is formatted correctly in the URL query string.
146+
func addListFineGrainedPATOptions(s string, opts *ListFineGrainedPATOptions) (string, error) {
147+
u, err := addOptions(s, opts)
148+
if err != nil {
149+
return s, err
150+
}
151+
152+
if len(opts.Owner) > 0 {
153+
ownerVals := make([]string, len(opts.Owner))
154+
for i, owner := range opts.Owner {
155+
ownerVals[i] = fmt.Sprintf("owner[]=%s", url.QueryEscape(owner))
156+
}
157+
ownerQuery := strings.Join(ownerVals, "&")
158+
159+
if strings.Contains(u, "?") {
160+
u += "&" + ownerQuery
161+
} else {
162+
u += "?" + ownerQuery
163+
}
164+
}
165+
166+
return u, nil
167+
}

0 commit comments

Comments
 (0)