mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2026-06-09 10:32:16 -04:00
feat: expose access token creation date in API responses (#12620)
## Checklist Following the previous contribution that added admin-level management of user access tokens (particularly useful for bot/service accounts), this change exposes the created_at field in the API response when listing or retrieving access tokens. This information is needed to implement token rotation policies for these users — knowing when a token was created allows administrators to identify and revoke stale tokens. ### Tests for Go changes - I added test coverage for Go changes... - [X] in their respective `*_test.go` for unit tests. - [X] `make pr-go` before pushing ### Documentation - [X] I did not document these changes and I do not expect someone else to do it. ### Release notes - [X] This change will be noticed by a Forgejo user or admin (feature, bug fix, performance, etc.). I suggest to include a release note for this change. <!--start release-notes-assistant--> ## Release notes <!--URL:https://codeberg.org/forgejo/forgejo--> - Features - [PR](https://codeberg.org/forgejo/forgejo/pulls/12620): <!--number 12620 --><!--line 0 --><!--description ZXhwb3NlIGFjY2VzcyB0b2tlbiBjcmVhdGlvbiBkYXRlIGluIEFQSSByZXNwb25zZXM=-->expose access token creation date in API responses<!--description--> <!--end release-notes-assistant--> Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/12620 Reviewed-by: Andreas Ahlenstorf <aahlenst@noreply.codeberg.org>
This commit is contained in:
parent
aec047c7b5
commit
0ef80f6b0f
5 changed files with 17 additions and 5 deletions
|
|
@ -11,11 +11,12 @@ import (
|
|||
// AccessToken represents an API access token.
|
||||
// swagger:response AccessToken
|
||||
type AccessToken struct {
|
||||
ID int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Token string `json:"sha1"`
|
||||
TokenLastEight string `json:"token_last_eight"`
|
||||
Scopes []string `json:"scopes"`
|
||||
ID int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Token string `json:"sha1"`
|
||||
TokenLastEight string `json:"token_last_eight"`
|
||||
Scopes []string `json:"scopes"`
|
||||
Created time.Time `json:"created_at"`
|
||||
// Indicates that an access token only has access to the specified repositories. Will be null if the access token
|
||||
// is not limited to a set of specified repositories.
|
||||
Repositories []*RepositoryMeta `json:"repositories"`
|
||||
|
|
|
|||
|
|
@ -117,6 +117,7 @@ func ListAccessTokens(ctx *context.APIContext) {
|
|||
Name: tokens[i].Name,
|
||||
TokenLastEight: tokens[i].TokenLastEight,
|
||||
Scopes: tokens[i].Scope.StringSlice(),
|
||||
Created: tokens[i].CreatedUnix.AsTime(),
|
||||
Repositories: reposByTokenID[tokens[i].ID],
|
||||
}
|
||||
// Provide a consistent sort order on repositories, helpful for test consistency. Hard to do any earlier
|
||||
|
|
@ -229,6 +230,7 @@ func CreateAccessToken(ctx *context.APIContext) {
|
|||
ID: t.ID,
|
||||
TokenLastEight: t.TokenLastEight,
|
||||
Scopes: t.Scope.StringSlice(),
|
||||
Created: t.CreatedUnix.AsTime(),
|
||||
Repositories: tokenRepositories,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
5
templates/swagger/v1_json.tmpl
generated
5
templates/swagger/v1_json.tmpl
generated
|
|
@ -22792,6 +22792,11 @@
|
|||
"type": "object",
|
||||
"title": "AccessToken represents an API access token.",
|
||||
"properties": {
|
||||
"created_at": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"x-go-name": "Created"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ func TestAPIAdminCreateUserAccessToken(t *testing.T) {
|
|||
assert.NotEmpty(t, newToken.Token)
|
||||
assert.NotEmpty(t, newToken.TokenLastEight)
|
||||
assert.Contains(t, newToken.Scopes, "all")
|
||||
assert.NotZero(t, newToken.Created)
|
||||
|
||||
// Verify the token exists in DB
|
||||
unittest.AssertExistsAndLoadBean(t, &auth_model.AccessToken{
|
||||
|
|
@ -143,6 +144,7 @@ func TestAPIAdminListUserAccessTokens(t *testing.T) {
|
|||
if tk.Name == "list-test-token" {
|
||||
found = true
|
||||
assert.NotEmpty(t, tk.TokenLastEight)
|
||||
assert.NotZero(t, tk.Created)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ func TestAPIGetTokens(t *testing.T) {
|
|||
assert.Equal(t, []string{""}, at.Scopes)
|
||||
assert.Empty(t, at.Token)
|
||||
assert.Equal(t, "69d28c91", at.TokenLastEight)
|
||||
assert.NotZero(t, at.Created)
|
||||
assert.Nil(t, at.Repositories) // not repo-specific access token - nil expected, not an empty array
|
||||
})
|
||||
|
||||
|
|
@ -753,6 +754,7 @@ func TestAPITokenCreation(t *testing.T) {
|
|||
resp := MakeRequest(t, req, http.StatusCreated)
|
||||
var token api.AccessToken
|
||||
DecodeJSON(t, resp, &token)
|
||||
assert.NotZero(t, token.Created)
|
||||
})
|
||||
|
||||
t.Run("repo-specific", func(t *testing.T) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue