Skip to content

Refactor merge conan and container auth preserve actions taskID#36560

Merged
wxiaoguang merged 3 commits intogo-gitea:mainfrom
ChristopherHX:package-jwt-cary-taskid
Feb 9, 2026
Merged

Refactor merge conan and container auth preserve actions taskID#36560
wxiaoguang merged 3 commits intogo-gitea:mainfrom
ChristopherHX:package-jwt-cary-taskid

Conversation

@ChristopherHX
Copy link
Copy Markdown
Contributor

  • Remove duplicated code
  • Allow further ActionsUser package permission checks

* Remove duplicated code
* Allow further ActionsUser package permission checks
@GiteaBot GiteaBot added the lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. label Feb 8, 2026
@github-actions github-actions bot added modifies/api This PR adds API routes or modifies them modifies/go Pull requests that update Go code labels Feb 8, 2026
@ChristopherHX
Copy link
Copy Markdown
Contributor Author

ChristopherHX commented Feb 8, 2026

RE #36173

  • without this it is barely possible to get the origin task of the actions user
  • wasn't sure if I should add a generic extra userdata approach here, if we want more bot account extra info

Maybe also check if the taskid is still running..., or...

@GiteaBot GiteaBot added lgtm/need 1 This PR needs approval from one additional maintainer to be merged. and removed lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. labels Feb 8, 2026
@GiteaBot GiteaBot added lgtm/done This PR has enough approvals to get merged. There are no important open reservations anymore. and removed lgtm/need 1 This PR needs approval from one additional maintainer to be merged. labels Feb 9, 2026
@wxiaoguang wxiaoguang enabled auto-merge (squash) February 9, 2026 02:36
@wxiaoguang wxiaoguang merged commit 34b34d2 into go-gitea:main Feb 9, 2026
24 checks passed
@GiteaBot GiteaBot added this to the 1.26.0 milestone Feb 9, 2026
zjjhot added a commit to zjjhot/gitea that referenced this pull request Feb 9, 2026
* giteaofficial/main:
  Refactor merge conan and container auth preserve actions taskID (go-gitea#36560)
  Fix assignee sidebar links and empty placeholder after go-gitea#32465 refactor (go-gitea#36559)
  Fix various version parsing problems (go-gitea#36553)
  Fix highlight diff result (go-gitea#36539)
  Refactor Nuget Auth to reuse Basic Auth Token Validation (go-gitea#36558)
  Update go dependencies (go-gitea#36548)
  Prevent navigation keys from triggering actions during IME composition (go-gitea#36540)
  Fix various mermaid bugs (go-gitea#36547)
  Add `elk` layout support to mermaid (go-gitea#36486)
  Allow configuring default PR base branch (fixes go-gitea#36412) (go-gitea#36425)
  [skip ci] Updated translations via Crowdin
  Color command/error logs in Actions log (go-gitea#36538)
  Add paging headers (go-gitea#36521)
  Fix issues filter dropdown showing empty label scope section (go-gitea#36535)
  [SECURITY] fix: Adjust the toolchain version (go-gitea#36537)
  Hide `add-matcher` and `remove-matcher` from actions job logs (go-gitea#36520)
  Improve timeline entries for WIP prefix changes in pull requests (go-gitea#36518)
silverwind added a commit to silverwind/gitea that referenced this pull request Feb 12, 2026
* origin/main: (34 commits)
  Fine tune diff highlighting (go-gitea#36592)
  Add code editor setting dropdowns (go-gitea#36534)
  Update to go 1.26.0 and golangci-lint 2.9.0 (go-gitea#36588)
  Improve diff highlighting (go-gitea#36583)
  Fix markup code block layout (go-gitea#36578)
  Remove striped tables in UI (go-gitea#36509)
  Fix vertical alignment of `.commit-sign-badge` children (go-gitea#36570)
  Fix mirror sync parser and fix mirror messages (go-gitea#36504)
  Update JS and PY deps (go-gitea#36576)
  Add viewer controller for mermaid (zoom, drag) (go-gitea#36557)
  Misc typescript tweaks (go-gitea#36523)
  Use full-file highlighting for diff sections (go-gitea#36561)
  fix(diff): reprocess htmx content after loading more files (go-gitea#36568)
  [skip ci] Updated translations via Crowdin
  Add wrap to runner label list (go-gitea#36565)
  fix: add dnf5 command for Fedora in RPM package instructions (go-gitea#36527)
  Enable pagination on GiteaDownloader.getIssueReactions() (go-gitea#36549)
  Refactor merge conan and container auth preserve actions taskID (go-gitea#36560)
  Fix assignee sidebar links and empty placeholder after go-gitea#32465 refactor (go-gitea#36559)
  Fix various version parsing problems (go-gitea#36553)
  ...
silverwind added a commit to silverwind/gitea that referenced this pull request Feb 12, 2026
* origin/main: (152 commits)
  Fine tune diff highlighting (go-gitea#36592)
  Add code editor setting dropdowns (go-gitea#36534)
  Update to go 1.26.0 and golangci-lint 2.9.0 (go-gitea#36588)
  Improve diff highlighting (go-gitea#36583)
  Fix markup code block layout (go-gitea#36578)
  Remove striped tables in UI (go-gitea#36509)
  Fix vertical alignment of `.commit-sign-badge` children (go-gitea#36570)
  Fix mirror sync parser and fix mirror messages (go-gitea#36504)
  Update JS and PY deps (go-gitea#36576)
  Add viewer controller for mermaid (zoom, drag) (go-gitea#36557)
  Misc typescript tweaks (go-gitea#36523)
  Use full-file highlighting for diff sections (go-gitea#36561)
  fix(diff): reprocess htmx content after loading more files (go-gitea#36568)
  [skip ci] Updated translations via Crowdin
  Add wrap to runner label list (go-gitea#36565)
  fix: add dnf5 command for Fedora in RPM package instructions (go-gitea#36527)
  Enable pagination on GiteaDownloader.getIssueReactions() (go-gitea#36549)
  Refactor merge conan and container auth preserve actions taskID (go-gitea#36560)
  Fix assignee sidebar links and empty placeholder after go-gitea#32465 refactor (go-gitea#36559)
  Fix various version parsing problems (go-gitea#36553)
  ...
@argoyle
Copy link
Copy Markdown
Contributor

argoyle commented Feb 16, 2026

I think this change broke access token auth to the container registry

@ChristopherHX
Copy link
Copy Markdown
Contributor Author

I currently see no evidence for an authentication problem with container registry, e.g. used an application access token for login, after retrieving token the login worked.

I will have a look at this, you mean problems like this?

% docker push 192.168.64.1:3005/test01/node:24-slim
The push refers to repository [192.168.64.1:3005/test01/node]
78366de4470b: Layer already exists 
2255562e10e2: Pushing [==================================================>]  3.318kB/3.318kB
dc951f13e3b6: Unavailable 
7410cd49e87a: Unavailable 
d3d5d8ab26d2: Pushing [>                                                  ]   98.3kB/28.11MB
unknown: failed commit on ref "layer-sha256:2255562e10e2c0206c7cf8f5aee30eac92c623bc97610e3e93443721d8434217": unexpected status from PUT request to http://192.168.64.1:3005/v2/test01/node/blobs/uploads/19g8ektsjgpjmotaludmvabhw?digest=sha256%3A2255562e10e2c0206c7cf8f5aee30eac92c623bc97610e3e93443721d8434217: 500 Internal Server Error
2026/02/16 16:19:06 cmd/web.go:330:listen() [I] Listen: http://0.0.0.0:3005
2026/02/16 16:19:06 cmd/web.go:334:listen() [I] AppURL(ROOT_URL): http://192.168.64.1:3005/
2026/02/16 16:19:06 modules/graceful/server.go:52:NewServer() [I] Starting new Web server: tcp:0.0.0.0:3005 on PID: 42310
2026/02/16 16:19:11 HTTPRequest [I] router: completed HEAD /v2/test01/node/blobs/sha256:2255562e10e2c0206c7cf8f5aee30eac92c623bc97610e3e93443721d8434217 for 192.168.64.56:39316, 401 Unauthorized in 0.2ms @ container/container.go:131(container.ReqContainerAccess)
2026/02/16 16:19:11 HTTPRequest [I] router: completed HEAD /v2/test01/node/blobs/sha256:99e6c0d9cd6c442dd449c059df44d38ae5db2d47cc4398460d5b27a6e00e8aa8 for 192.168.64.56:39336, 401 Unauthorized in 0.1ms @ container/container.go:131(container.ReqContainerAccess)
2026/02/16 16:19:11 HTTPRequest [I] router: completed HEAD /v2/test01/node/blobs/sha256:d3d5d8ab26d25b9040a3c2160d7ddfe3911ae81035d5b1b0904f3ebda32476b6 for 192.168.64.56:39330, 401 Unauthorized in 0.1ms @ container/container.go:131(container.ReqContainerAccess)
2026/02/16 16:19:11 HTTPRequest [I] router: completed HEAD /v2/test01/node/blobs/sha256:dc951f13e3b6bb9bc50c7120afdfbbc9cb05ffbccb28dd63cdef4fcb421ac11e for 192.168.64.56:39342, 401 Unauthorized in 0.1ms @ container/container.go:131(container.ReqContainerAccess)
2026/02/16 16:19:11 HTTPRequest [I] router: completed HEAD /v2/test01/node/blobs/sha256:7410cd49e87a93d9c09b795816529cdc69aa3cbc26cbf84803d852d8dfb64977 for 192.168.64.56:39326, 401 Unauthorized in 0.0ms @ container/container.go:131(container.ReqContainerAccess)
2026/02/16 16:19:11 HTTPRequest [I] router: completed HEAD /v2/test01/node/blobs/sha256:78366de4470bda526a4bf3f537235afe855625c9046a1b42473d93c3413be7b0 for 192.168.64.56:39358, 401 Unauthorized in 0.1ms @ container/container.go:131(container.ReqContainerAccess)
2026/02/16 16:19:11 HTTPRequest [I] router: completed POST /v2/token for 192.168.64.56:39374, 404 Not Found in 0.0ms @ container/container.go:190(container.AuthenticateNotImplemented)
2026/02/16 16:19:11 HTTPRequest [I] router: completed GET /v2/token?scope=%2A&scope=repository%3Atest01%2Fnode%3Apull%2Cpush&service=container_registry for 192.168.64.56:39374, 200 OK in 4.1ms @ container/container.go:154(container.Authenticate)
2026/02/16 16:19:11 HTTPRequest [I] router: completed HEAD /v2/test01/node/blobs/sha256:2255562e10e2c0206c7cf8f5aee30eac92c623bc97610e3e93443721d8434217 for 192.168.64.56:39316, 404 Not Found in 0.8ms @ container/container.go:506(container.HeadBlob)
2026/02/16 16:19:11 HTTPRequest [I] router: completed HEAD /v2/test01/node/blobs/sha256:78366de4470bda526a4bf3f537235afe855625c9046a1b42473d93c3413be7b0 for 192.168.64.56:39358, 200 OK in 1.1ms @ container/container.go:506(container.HeadBlob)
2026/02/16 16:19:11 HTTPRequest [I] router: completed HEAD /v2/test01/node/blobs/sha256:99e6c0d9cd6c442dd449c059df44d38ae5db2d47cc4398460d5b27a6e00e8aa8 for 192.168.64.56:39390, 404 Not Found in 0.9ms @ container/container.go:506(container.HeadBlob)
2026/02/16 16:19:11 HTTPRequest [I] router: completed POST /v2/test01/node/blobs/uploads/ for 192.168.64.56:39316, 202 Accepted in 0.9ms @ container/container.go:236(container.PostBlobsUploads)
2026/02/16 16:19:11 HTTPRequest [I] router: completed HEAD /v2/test01/node/blobs/sha256:d3d5d8ab26d25b9040a3c2160d7ddfe3911ae81035d5b1b0904f3ebda32476b6 for 192.168.64.56:39382, 404 Not Found in 1.5ms @ container/container.go:506(container.HeadBlob)
2026/02/16 16:19:11 HTTPRequest [I] router: completed HEAD /v2/test01/node/blobs/sha256:dc951f13e3b6bb9bc50c7120afdfbbc9cb05ffbccb28dd63cdef4fcb421ac11e for 192.168.64.56:39386, 404 Not Found in 1.6ms @ container/container.go:506(container.HeadBlob)
2026/02/16 16:19:11 HTTPRequest [I] router: completed HEAD /v2/test01/node/blobs/sha256:7410cd49e87a93d9c09b795816529cdc69aa3cbc26cbf84803d852d8dfb64977 for 192.168.64.56:39406, 404 Not Found in 1.7ms @ container/container.go:506(container.HeadBlob)
2026/02/16 16:19:11 HTTPRequest [I] router: completed POST /v2/test01/node/blobs/uploads/ for 192.168.64.56:39390, 202 Accepted in 1.0ms @ container/container.go:236(container.PostBlobsUploads)
2026/02/16 16:19:11 HTTPRequest [I] router: completed POST /v2/test01/node/blobs/uploads/ for 192.168.64.56:39382, 202 Accepted in 0.9ms @ container/container.go:236(container.PostBlobsUploads)
2026/02/16 16:19:11 HTTPRequest [I] router: completed POST /v2/test01/node/blobs/uploads/ for 192.168.64.56:39406, 202 Accepted in 1.4ms @ container/container.go:236(container.PostBlobsUploads)
2026/02/16 16:19:11 HTTPRequest [I] router: completed POST /v2/test01/node/blobs/uploads/ for 192.168.64.56:39386, 202 Accepted in 2.0ms @ container/container.go:236(container.PostBlobsUploads)
2026/02/16 16:19:11 .../container/container.go:422:PutBlobsUpload() [E] Package registry API internal error: 500 database table is locked: package_blob_upload
2026/02/16 16:19:11 HTTPRequest [I] router: completed PUT /v2/test01/node/blobs/uploads/19g8ektsjgpjmotaludmvabhw?digest=sha256%3A2255562e10e2c0206c7cf8f5aee30eac92c623bc97610e3e93443721d8434217 for 192.168.64.56:39358, 500 Internal Server Error in 2.3ms @ container/container.go:400(container.PutBlobsUpload)
2026/02/16 16:19:11 .../container/container.go:422:PutBlobsUpload() [E] Package registry API internal error: 500 offset mismatch between file and model
2026/02/16 16:19:11 HTTPRequest [I] router: completed PUT /v2/test01/node/blobs/uploads/19g8ektsjgpjmotaludmvabhw?digest=sha256%3A2255562e10e2c0206c7cf8f5aee30eac92c623bc97610e3e93443721d8434217 for 192.168.64.56:39358, 500 Internal Server Error in 0.3ms @ container/container.go:400(container.PutBlobsUpload)
2026/02/16 16:19:11 .../container/container.go:422:PutBlobsUpload() [E] Package registry API internal error: 500 unexpected EOF
2026/02/16 16:19:11 .../container/container.go:422:PutBlobsUpload() [E] Package registry API internal error: 500 unexpected EOF
2026/02/16 16:19:11 HTTPRequest [I] router: completed PUT /v2/test01/node/blobs/uploads/h9iie1icji0f8aqembhpnnvs6?digest=sha256%3Adc951f13e3b6bb9bc50c7120afdfbbc9cb05ffbccb28dd63cdef4fcb421ac11e for 192.168.64.56:39386, 500 Internal Server Error in 2.7ms @ container/container.go:400(container.PutBlobsUpload)
2026/02/16 16:19:11 HTTPRequest [I] router: completed PUT /v2/test01/node/blobs/uploads/6m6qh2jsymeokob4p0knxthu3?digest=sha256%3A7410cd49e87a93d9c09b795816529cdc69aa3cbc26cbf84803d852d8dfb64977 for 192.168.64.56:39406, 500 Internal Server Error in 3.0ms @ container/container.go:400(container.PutBlobsUpload)
2026/02/16 16:19:11 HTTPRequest [I] router: completed PUT /v2/test01/node/blobs/uploads/jtuzaa8yvioix8ucmv0jc2dqw?digest=sha256%3A99e6c0d9cd6c442dd449c059df44d38ae5db2d47cc4398460d5b27a6e00e8aa8 for 192.168.64.56:39390, 201 Created in 4.5ms @ container/container.go:400(container.PutBlobsUpload)
2026/02/16 16:19:11 .../container/container.go:422:PutBlobsUpload() [E] Package registry API internal error: 500 unexpected EOF
2026/02/16 16:19:11 HTTPRequest [I] router: completed PUT /v2/test01/node/blobs/uploads/rkb9lk6rcopr7hatd9jyhrv8c?digest=sha256%3Ad3d5d8ab26d25b9040a3c2160d7ddfe3911ae81035d5b1b0904f3ebda32476b6 for 192.168.64.56:39382, 500 Internal Server Error in 4.4ms @ container/container.go:400(container.PutBlobsUpload)

My binary seem to have database locking issues with sqlite instead of authentication issues.

@argoyle
Copy link
Copy Markdown
Contributor

argoyle commented Feb 16, 2026

Both push and pull gives 401 for me with latest nightly. I built an image from Feb 8 which brought back the old working behaviour. So something since that date broke it at least.

@ChristopherHX
Copy link
Copy Markdown
Contributor Author

ChristopherHX commented Feb 16, 2026

I also tried to rebuild at current HEAD of nightly cfc60b2142af18f843325b94313a8aafbbfe6908, authentication works unchanged on gitea side...

2026/02/16 16:38:24 HTTPRequest [I] router: completed HEAD /v2/test01/node/manifests/24-slim for 192.168.64.56:43450, 401 Unauthorized in 0.1ms @ container/container.go:131(container.ReqContainerAccess)
2026/02/16 16:38:24 HTTPRequest [I] router: completed POST /v2/token for 192.168.64.56:49576, 404 Not Found in 0.0ms @ container/container.go:190(container.AuthenticateNotImplemented)
2026/02/16 16:38:24 HTTPRequest [I] router: completed GET /v2/token?scope=%2A&scope=repository%3Atest01%2Fnode%3Apull&service=container_registry for 192.168.64.56:49576, 200 OK in 3.9ms @ container/container.go:154(container.Authenticate)
2026/02/16 16:38:24 HTTPRequest [I] router: completed HEAD /v2/test01/node/manifests/24-slim for 192.168.64.56:43450, 200 OK in 0.5ms @ container/container.go:640(container.HeadManifest)
2026/02/16 16:38:24 HTTPRequest [I] router: completed GET /v2/test01/node/manifests/sha256:39d7b5d7dbd148ee6b48a4755b06fa15338b3b0bbd59695d3980055596bae3c4 for 192.168.64.56:43470, 200 OK in 1.1ms @ container/container.go:660(container.GetManifest)
2026/02/16 16:38:24 HTTPRequest [I] router: completed GET /v2/test01/node/blobs/sha256:99e6c0d9cd6c442dd449c059df44d38ae5db2d47cc4398460d5b27a6e00e8aa8 for 192.168.64.56:43470, 200 OK in 0.9ms @ container/container.go:525(container.GetBlob)
2026/02/16 16:38:24 HTTPRequest [I] router: completed GET /v2/test01/node/blobs/sha256:2255562e10e2c0206c7cf8f5aee30eac92c623bc97610e3e93443721d8434217 for 192.168.64.56:43470, 200 OK in 0.9ms @ container/container.go:525(container.GetBlob)
2026/02/16 16:38:24 HTTPRequest [I] router: completed GET /v2/test01/node/blobs/sha256:78366de4470bda526a4bf3f537235afe855625c9046a1b42473d93c3413be7b0 for 192.168.64.56:43482, 200 OK in 0.9ms @ container/container.go:525(container.GetBlob)
2026/02/16 16:38:24 HTTPRequest [I] router: completed GET /v2/test01/node/blobs/sha256:7410cd49e87a93d9c09b795816529cdc69aa3cbc26cbf84803d852d8dfb64977 for 192.168.64.56:43484, 200 OK in 3.1ms @ container/container.go:525(container.GetBlob)
2026/02/16 16:38:24 HTTPRequest [I] router: completed GET /v2/test01/node/blobs/sha256:d3d5d8ab26d25b9040a3c2160d7ddfe3911ae81035d5b1b0904f3ebda32476b6 for 192.168.64.56:43470, 200 OK in 94.4ms @ container/container.go:525(container.GetBlob)
2026/02/16 16:38:24 HTTPRequest [I] router: completed GET /v2/test01/node/blobs/sha256:dc951f13e3b6bb9bc50c7120afdfbbc9cb05ffbccb28dd63cdef4fcb421ac11e for 192.168.64.56:43482, 200 OK in 175.7ms @ container/container.go:525(container.GetBlob)

No idea how your gitea log looks like, mine has exactly one 401, after the token exchange everything works both pull and push.

EDIT
Anonymous pull works for me as well for a public package, so unclear what issue you are facing right now for me

@wxiaoguang
Copy link
Copy Markdown
Contributor

Both push and pull gives 401 for me with latest nightly. I built an image from Feb 8 which brought back the old working behaviour. So something since that date broke it at least.

Could you provide some more clues?

For example:

  • If you use new tokens (new login) issued by new build, is there still a 401 problem?
  • Does the "old token" cause the problem? For example: you are using a token issued by old release?

Thank you very much.

@argoyle
Copy link
Copy Markdown
Contributor

argoyle commented Feb 16, 2026

The tokens were created by 1.25.3 I think. Haven't tried to issue a new token.

@argoyle
Copy link
Copy Markdown
Contributor

argoyle commented Feb 16, 2026

It's a token I use for my CI workflows.

@wxiaoguang
Copy link
Copy Markdown
Contributor

wxiaoguang commented Feb 16, 2026

It's a token I use for my CI workflows.

  • The token is a "user" token issued from 1.25.3
  • You are using Actions to run CI tasks and use the token to push to container registry

Do I understand correctly?

@argoyle
Copy link
Copy Markdown
Contributor

argoyle commented Feb 16, 2026

Yes, I've created a technical user and issued an access token for it with the required scopes. I started on 1.25.3 and switched to nightly since I needed my fix for Gitlab release migration. It's been working fine until my nodes were replaced today and I got a newer nightly. 😁 And rolling back to a version before Feb 9 works fine again.

@argoyle
Copy link
Copy Markdown
Contributor

argoyle commented Feb 16, 2026

I also use the same token to allow Kubernetes to pull images which also failed.

@wxiaoguang
Copy link
Copy Markdown
Contributor

wxiaoguang commented Feb 16, 2026

Not sure whether ChristopherHX has some ideas about the problem.

Till now I didn't find potential related code change for the problem. To continue debugging, some more clues would be very helpful (at least, to me ....)

  • What's your old token? If it is a container JWT token, could you decode the "claims" part and share the decoded content (no need to share the full token): https://www.jwt.io/
  • For newer nightly, if you issue a new user token like the old one, would the new token work as expected?

@ChristopherHX
Copy link
Copy Markdown
Contributor Author

ChristopherHX commented Feb 16, 2026

For me would be helpful

  • gitea server log part of a failed docker pull like I posted
    • this would tell me is your Access token blocked, is the temporary jwt token blocked (this code is touched)
  • the error message from kubernetes / docker pull
  • docker client version?

Actually I don't think the old token can be a jwt once, since this is always regenerated by the container auth endpoint (In Github ghcr.io this has maximum one hour lifetime if I am not mistaken) that takes the Basic Auth Access token and returns a new jwt token (after this PR with an additional field that has value 0, since this is not an actions token)

I also read over and over again this change, but except of the Auth name and the additional jwt field (the token might be longer now). I cannot see why and how exactly this fails on your end


EDIT
Doing

	ActionsUserTaskID int64 `json:",omitempty"`

Would omit ActionsUserTaskID from the token if zero, then it should be the same as before...

@argoyle
Copy link
Copy Markdown
Contributor

argoyle commented Feb 17, 2026

I managed to get some stomach bug yesterday and have been totally floored today. Will try to get you the logs tomorrow.

@argoyle
Copy link
Copy Markdown
Contributor

argoyle commented Feb 23, 2026

Finally got around to trying out the nightly again.
Pulling images (still with a token generated with 1.25.x) fails with:

  Warning  Failed     38s (x3 over 83s)  kubelet            spec.containers{schemas-app}: Failed to pull image "oci.unbound.se/unboundsoftware/schemas-app:a5122a8f0f581fc24db15ef3c6c9c597129219fe": failed to pull and unpack image "oci.unbound.se/unboundsoftware/schemas-app:a5122a8f0f581fc24db15ef3c6c9c597129219fe": failed to resolve reference "oci.unbound.se/unboundsoftware/schemas-app:a5122a8f0f581fc24db15ef3c6c9c597129219fe": unexpected status from HEAD request to https://oci.unbound.se/v2/unboundsoftware/schemas-app/manifests/a5122a8f0f581fc24db15ef3c6c9c597129219fe: 401 Unauthorized

And authenticating to the registry from the workflow gives this in my docker daemon logs:

time="2026-02-23T19:55:19.839803382Z" level=info msg="Error logging in to endpoint, trying next endpoint" endpoint="{false https://oci.unbound.se 0xc0007b9860}" error="login attempt to https://oci.unbound.se/v2/ failed with status: 401 Unauthorized"
Handler for POST /v1.51/auth returned error: login attempt to https://oci.unbound.se/v2/ failed with status: 401 Unauthorized

Creating a new token (by exec:ing into the running Gitea container and running gitea admin user generate-access-token --username kubernetes --token-name "push 1.26.x" --scopes "write:package") makes no difference.

@wxiaoguang
Copy link
Copy Markdown
Contributor

On main branch, I exactly followed the steps:

$ ./gitea admin user generate-access-token --username MyUserName --token-name "push 1.26.x" --scopes "write:package"
Access token was successfully created: TheToken

$ docker logout MyHost

$ docker login MyHost
Username: MyUserName
Password: TheToken
Login Succeeded

$ (run some docker build and push) ...
...
The push refers to repository [.......]
2d35ebdb57d9: Pushed
72022a26ae74: Pushed
0.1.1: digest: sha256:72f200cfe330a7d035a923c5cc1c6c84bdc92a187f8510838119a80700194be8 size: 855

Unable to reproduce .....

@argoyle
Copy link
Copy Markdown
Contributor

argoyle commented Feb 23, 2026

Very strange. The only thing I did was to replace gitea/gitea:1.25.3-rootless with gitea/gitea:main-nightly-rootless at January 17th.

It worked fine up until February 16th when apparantly my nodes were replaced and I got and updated version of the nightly.

Rolling back to "my own" image built from February 9th makes it work again.

Something between the 9th and the 16th is making my system behave differently.

I'm perfectly fine with that it might be something on my end but I need help to identify what that might be. Any pointers to where I should start?

@wxiaoguang
Copy link
Copy Markdown
Contributor

Something in my mind:

  1. (by ChristopherHX) gitea server log part of a failed docker pull like I posted and the related information
  2. Try to reproduce it in a simpler environment, for example: a simple local setup with docker-compose, and share the setup steps and configs.
    • If it can be reproduced in a clean & new setup, maybe others can also reproduce.
  3. Try to figure out which commit caused the regression. There are still many commits between Feb 9th to Feb 16th. Maybe the problem is not caused by this PR .....
    • Maybe it needs to build some images by some approaches like git bisect and find the exact commit.
  4. Add some debug logs to see the auth internal steps and data

@argoyle
Copy link
Copy Markdown
Contributor

argoyle commented Feb 24, 2026

This is the only relevant thing I found in the Gitea log:

2026/02/23 20:06:26 routers/api/packages/api.go:101:verifyAuth.1() [E] Failed to verify user: token signature is invalid: signature is invalid

@argoyle
Copy link
Copy Markdown
Contributor

argoyle commented Feb 24, 2026

This is Claudes investigation result:

⏺ Here's what the investigation found:

  The Error

  The log you shared confirms the exact failure point:

  Failed to verify user: token signature is invalid: signature is invalid

  This occurs in Phase 2 of the OCI registry auth flow — the JWT bearer token that was signed during docker login (Phase 1) fails signature verification when Docker makes subsequent requests
  (push/pull).

  PRs Merged Feb 9-16

  Only three PRs touched relevant code:

  1. PR #36560 (Feb 9) — Refactored container auth into unified packages auth. Changed PackageMeta JWT struct (added ActionsUserTaskID field) and user lookup logic, but did NOT change the JWT
   signing/verification code itself.
  2. PR #36588 (Feb 11) — Upgraded Go from 1.25 to 1.26. This is the most likely culprit.
  3. PR #36591 (Feb 16) — Just added //nolint comments. No behavioral changes.

  Most Likely Root Cause: Go 1.26 + JWT Secret Race Condition

  The "signature is invalid" error means the HMAC key used to sign the token differs from the key used to verify it. There's a latent race condition in GetGeneralTokenSigningSecret():

  - If called before loadOAuth2From() stores the real oauth2.JWT_SECRET from app.ini, it generates a temporary random secret
  - Tokens signed with the temp secret become permanently invalid once the real secret loads
  - Go 1.26's new Green Tea GC and heap randomization change goroutine scheduling/timing enough to expose this race during startup
  - This explains why maintainers can't reproduce it — in clean test setups, the secret loads before the first request, but in your K8s environment with readiness probes/ingress, traffic may
  arrive earlier in the startup sequence

  Suggested Next Steps

  1. Quick test — exec into the Gitea pod at startup and check if oauth2.JWT_SECRET in app.ini is stable (not being regenerated on restart)
  2. Check startup logs — look for "save oauth2.JWT_SECRET" messages, which would indicate the secret was regenerated
  3. Try GOEXPERIMENT=nogreenteagc — if you rebuild with Go 1.26 but disable the new GC, and the issue goes away, that confirms the timing theory
  4. Report upstream — the race condition in GetGeneralTokenSigningSecret() using atomic.Pointer is a real bug regardless; the Go 1.26 upgrade just makes it more likely to trigger

Rebuilding without greenteagc now to see if that helps.

@wxiaoguang
Copy link
Copy Markdown
Contributor

wxiaoguang commented Feb 24, 2026

This PR also changes the behavior of loadOAuth2From: fix: duplicate startup warnings in admin panel (#36641)

LoadCommonSettings -> loadCommonSettingsFrom -> loadOAuth2From

@wxiaoguang
Copy link
Copy Markdown
Contributor

This PR also changes the behavior of loadOAuth2From: fix: duplicate startup warnings in admin panel (#36641)

LoadCommonSettings -> loadCommonSettingsFrom -> loadOAuth2From

OK, I can confirm it is caused by #36641.

The reason is quite complicated ...... due to various legacy fragile logic of the setting handling.

Will propose a fix.

@wxiaoguang
Copy link
Copy Markdown
Contributor

I think this one will fix: Fix incorrect setting loading order #36735

@wxiaoguang
Copy link
Copy Markdown
Contributor

The new nightly build is ready. Hopefully the problem is fixed. Thank you very much.

@argoyle
Copy link
Copy Markdown
Contributor

argoyle commented Feb 24, 2026

Still having problems. This is in the logs now:

2026/02/24 18:44:04 routers/api/packages/api.go:101:verifyAuth.1() [E] Failed to verify user: token signature is invalid: signature is invalid
2026/02/24 18:44:04 HTTPRequest [I] router: completed HEAD /v2/shiny/salary-service/manifests/99caac123801b6e1ac7da0a4aa9973d445cbf773 for 100.114.81.192:56318, 401 Unauthorized in 0.2ms @ packages/api.go:97(packages.verifyAuth)
2026/02/24 18:44:06 HTTPRequest [I] router: completed HEAD /v2/unboundsoftware/schemas/manifests/3bb0511277d2d2edda3590af4d728a91b3b0e39d for 100.123.95.128:64086, 401 Unauthorized in 0.1ms @ container/container.go:131(container.ReqContainerAccess)
2026/02/24 18:44:06 HTTPRequest [I] router: completed POST /v2/token for 100.101.7.0:34004, 404 Not Found in 0.1ms @ container/container.go:190(container.AuthenticateNotImplemented)
2026/02/24 18:44:06 HTTPRequest [I] router: completed HEAD /v2/unboundsoftware/schemas/manifests/3bb0511277d2d2edda3590af4d728a91b3b0e39d for 172.20.70.223:40602, 200 OK in 22.5ms @ container/container.go:640(container.HeadManifest)
2026/02/24 18:44:06 HTTPRequest [I] router: completed POST /v2/token for 100.101.7.0:54030, 404 Not Found in 0.1ms @ container/container.go:190(container.AuthenticateNotImplemented)

@wxiaoguang
Copy link
Copy Markdown
Contributor

2026/02/24 18:44:04 routers/api/packages/api.go:101:verifyAuth.1() [E] Failed to verify user: token signature is invalid: signature is invalid

Strange, still signature is invalid. It's still likely caused by mismatched JWT_SECRET.

I guess you are using a non-persistent config file without JWT_SECRET, then every restart, Gitea will generate a new JWT_SECRET, the old one is lost and all old tokens become invalid.

I am not sure why it still happens, my guesses are:

  1. Is your "nightly" build cached (not the latest one?) you can check it by the "app version", it contains a git commit id
  2. Is your client still using the old token? Need to logout and re-login
  3. If none of the above is the reason, can you try to build your image and try to reproduce?
    • 75efc51 (the commit contains the latest Fix incorrect setting loading order)
    • 8fdda2d (the commit before the loadOAuth2From fix, aka duplicate startup warnings in admin panel)
    • 34b34d2 (this PR)
    • c401cda (the commit before this PR)

@argoyle
Copy link
Copy Markdown
Contributor

argoyle commented Feb 24, 2026

Aaaah, true, ignore me while I make sure I'm actually not using a cached image 😆

@argoyle
Copy link
Copy Markdown
Contributor

argoyle commented Feb 24, 2026

It's working perfectly fine! Thanks a lot for the fix. ❤️

Sirherobrine23 pushed a commit to Sirherobrine23/gitea that referenced this pull request Mar 4, 2026
…itea#36560)

* Remove duplicated code
* Allow further ActionsUser package permission checks

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

lgtm/done This PR has enough approvals to get merged. There are no important open reservations anymore. modifies/api This PR adds API routes or modifies them modifies/go Pull requests that update Go code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants