Skip to content

enhance(actions): add OIDC workload identity support - #39052

Open
0xMax42 wants to merge 18 commits into
go-gitea:mainfrom
0xMax42:feat/actions-oidc
Open

0xMax42 wants to merge 18 commits into
go-gitea:mainfrom
0xMax42:feat/actions-oidc

Conversation

@0xMax42

@0xMax42 0xMax42 commented Aug 22, 2026 •

Copy link
Copy Markdown
Contributor

Adds OpenID Connect workload identity to Gitea Actions: jobs declaring id-token: write can request short-lived tokens to authenticate to cloud providers and other services without stored secrets. Tokens follow GitHub's format, so clients like @actions/core and existing trust policies carry over.

  • Issuer at /api/actions/oidc with discovery and JWKS, signed with a dedicated RS256 key
  • GitHub's claims, including workflow_ref, job_workflow_ref and the immutable repo:owner@id/repo@id:ref:... subject
  • id-token: write or write-all grant it, default permissions and fork pull requests never get it, owner and repository maximum permissions can disable it
  • Reusable workflows record the fully qualified ref they were loaded from
  • github.ref_type is branch for pull request runs, like on GitHub

Fixes #26383
Fixes #33681

Docs: https://gitea.com/gitea/docs/pulls/526

Before:

Bildschirmfoto_20260822_190337

After:

Bildschirmfoto_20260822_190410

Assisted-by: ChatGPT:gpt-5.6-sol, Claude Code:claude-opus-5-5

@GiteaBot GiteaBot added the lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. label Aug 22, 2026
@0xMax42

0xMax42 commented Aug 22, 2026

Copy link
Copy Markdown
Contributor Author

Manual validation note

In addition to the automated test suite, which is currently passing, I have
manually tested the current implementation on a Gitea instance.

The following scenarios were verified:

  • regular workflow with id-token: write → OIDC runtime context is available
    and a token can be minted successfully
  • regular workflow with id-token: none → OIDC runtime context is absent
  • regular workflow with id-token: read → OIDC runtime context is absent
  • repository-level maximum permission disabling OIDC → runtime context is
    absent even when the workflow requests id-token: write
  • re-enabling OIDC at repository level → token issuance works again
  • cross-repository reusable workflow with id-token: write → token issuance
    succeeds and root/reusable workflow provenance is reported separately and
    correctly
  • reusable workflow where the caller has id-token: none while the called
    workflow requests id-token: write → OIDC runtime context is absent, i.e.
    the called workflow cannot elevate the caller's permission

The positive end-to-end test also verified the issued token using only the
public OIDC discovery document and JWKS, including signature, issuer, audience,
lifetime, repository/ref/SHA claims, and workflow provenance.

This is mainly a note for tracking the current Draft validation state; I still
intend to perform my own complete code/security review before marking the PR
ready for review.

@silverwind

silverwind commented Aug 22, 2026 •

Copy link
Copy Markdown
Member

Make sure your agent has read AGENTS.md and followed it exactly. Based on this long PR description, I see that it didn't read it. Please re-review the whole work under the AGENTS.md constraints.

@0xMax42 0xMax42 changed the title feat(actions): add OIDC workload identity support enhance(actions): add OIDC workload identity support Aug 22, 2026
@0xMax42

0xMax42 commented Aug 22, 2026

Copy link
Copy Markdown
Contributor Author

Make sure your agent has read AGENTS.md and followed it exactly. Based on this long PR description, I see that it didn't read it. Please re-review the whole work under the AGENTS.md constraints.

Sorry! I’ve now amended the pull request description in line with the guidelines in AGENTS.md, and I’ve added the screenshots I’d already prepared.

I’ll check the entire change once more against the guidelines in AGENTS.md before removing the pull request from draft status.

@silverwind

Copy link
Copy Markdown
Member

Thanks, yes that's a more managable size now :)

Comment thread services/actions/oidc.go Outdated
Comment thread services/actions/auth.go Outdated
Comment thread services/actions/auth_test.go Outdated
@silverwind silverwind added the topic/gitea-actions related to the actions of Gitea label Aug 22, 2026
Comment thread models/actions/token_permissions.go Outdated
@0xMax42

0xMax42 commented Aug 22, 2026

Copy link
Copy Markdown
Contributor Author

While reviewing/testing this, I noticed an unrelated existing issue in the OAuth2 JWT signing-key setup: auto-generated ECDSA keys always use P-256, even when ES384 or ES512 is configured. This appears to make those algorithms fail when using an automatically generated key.

I don't think this belongs in this PR. Would you prefer a separate issue for it? I can open one later and look at it independently.

@0xMax42

0xMax42 commented Aug 22, 2026

Copy link
Copy Markdown
Contributor Author

I've now completed my own review of the implementation and tests. The remaining piece is documentation, which I'll add separately.

In the meantime, feel free to take a look already — feedback and comments are very welcome.

@0xMax42

0xMax42 commented Aug 22, 2026

Copy link
Copy Markdown
Contributor Author

Also verified that the Gitea Actions runner masks ACTIONS_ID_TOKEN_REQUEST_TOKEN in job logs as expected, including when environment variables are printed directly.

@0xMax42
0xMax42 force-pushed the feat/actions-oidc branch from 47a494c to de5952f Compare August 23, 2026 17:52
@0xMax42
0xMax42 marked this pull request as ready for review August 23, 2026 17:56
@github-actions github-actions Bot added the type/enhancement An improvement of existing functionality label Aug 23, 2026
@0xMax42
0xMax42 force-pushed the feat/actions-oidc branch from 8d8ce04 to a54eaa8 Compare August 23, 2026 19:54
lunny and others added 12 commits August 30, 2026 10:12
Derive token permissions and identity claims from canonical server state, persist authoritative workflow paths, and cover capability access and signing behavior.

Assisted-by: OpenCode:gpt-5.6-sol
Legacy schedules can create runs without an authoritative workflow path. Keep OIDC unavailable for these runs, as before OIDC support was introduced, until the schedule is rebuilt.

Assisted-by: OpenCode:gpt-5.6-sol
Fail OIDC token issuance when reusable workflow provenance cannot be resolved
or does not include the resolved workflow commit.

Assisted-by: OpenCode:gpt-5.6-sol
Treat the unsupported id-token read mode as none while preserving write-all
and explicit id-token write behavior.

Assisted-by: OpenCode:gpt-5.6-sol
Avoid evaluating OIDC eligibility while the provider is unavailable so
disabled OIDC cannot interfere with normal task context generation.

Assisted-by: OpenCode:gpt-5.6-sol
Cover workflow path persistence for scheduled runs and scoped workflow
dispatches.

Assisted-by: OpenCode:gpt-5.6-terra
Verify that cyclic reusable workflow parent chains are rejected while
computing effective token permissions.

Assisted-by: OpenCode:gpt-5.6-terra
Avoid resolving OIDC provenance and effective permissions for jobs that
did not explicitly request id-token write access.

Assisted-by: OpenCode:gpt-5.6-luna
Verify that reusable workflow callers restrict both repository unit
permissions and OIDC token permissions.

Assisted-by: OpenCode:gpt-5.6-luna
Keep invalid authorization and task state failures as 401 responses while
surfacing unexpected task lookup failures as logged internal server errors.

Assisted-by: OpenCode:gpt-5.6-luna
Reject token issuance when the root workflow source commit or reference is
missing, and cover root, reusable, scoped, and signing-key provenance cases.

Assisted-by: OpenCode:gpt-5.6-terra
Verify the discovery-to-JWKS chain and require the expected bearer
challenge for rejected OIDC token requests.

Assisted-by: OpenCode:gpt-5.6-luna
@0xMax42
0xMax42 force-pushed the feat/actions-oidc branch 2 times, most recently from f77c47b to f0728b3 Compare August 30, 2026 08:36
Follow upstream commit 32728fc and avoid reintroducing github.com/google/uuid as a direct dependency.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Cancelling-task issuance, optional key initialization, and migrated schedules currently have lifecycle and reliability defects.

Review effort: Balanced
Findings: 1 High severity · 3 Medium severity

Open (4)
What changed in this PR

Adds OIDC workload identities to Gitea Actions, including permission enforcement, provenance claims, token endpoints, configuration UI, and tests.

Changes:

  • Adds OIDC discovery, JWKS, and token issuance endpoints.
  • Tracks workflow provenance and enforces effective id-token permissions.
  • Adds configuration UI, migration, and automated coverage.
File Description
tests/​integration/​actions_trigger_test.go Verifies triggered-run workflow paths.
tests/​integration/​actions_scoped_workflow_test.go Verifies scoped workflow paths.
tests/​integration/​actions_schedule_test.go Verifies scheduled workflow paths.
tests/​integration/​actions_oidc_test.go Tests the complete OIDC flow.
tests/​integration/​actions_concurrency_test.go Checks scheduled concurrency provenance.
templates/​shared/​actions/​permissions_table.tmpl Adds the ID-token permission control.
services/​actions/​workflow.go Records dispatched workflow paths.
services/​actions/​task.go Exposes OIDC request context to runners.
services/​actions/​schedule_tasks.go Propagates scheduled workflow paths.
services/​actions/​permission_parser.go Parses id-token permissions.
services/​actions/​permission_parser_test.go Tests permission parsing.
services/​actions/​oidc.go Implements OIDC authorization and claims.
services/​actions/​oidc_test.go Tests OIDC services and claims.
services/​actions/​notifier_helper.go Records detected workflow paths.
services/​actions/​init.go Initializes OIDC signing support.
services/​actions/​auth.go Restricts runtime JWTs to HS256.
services/​actions/​auth_test.go Tests JWT algorithm rejection.
routers/​web/​shared/​actions/​general.go Parses ID-token settings.
routers/​api/​actions/​oidc.go Implements OIDC HTTP handlers.
routers/​api/​actions/​actions.go Registers OIDC routes.
options/​locale/​locale_en-US.json Adds OIDC permission labels.
modules/​actions/​workflows.go Captures detected workflow paths.
modules/​actions/​scoped_workflows.go Captures scoped workflow paths.
models/​repo/​repo_unit_test.go Tests ID-token defaults and limits.
models/​repo/​repo_unit_actions.go Extends token permission storage.
models/​actions/​utils.go Copies schedule workflow provenance.
models/​actions/​token_permissions.go Clamps reusable-workflow permissions.
models/​actions/​token_permissions_test.go Tests effective OIDC permissions.
models/​actions/​schedule.go Stores scheduled workflow paths.
models/​actions/​run.go Stores run workflow paths.
models/​actions/​config.go Adds owner-level OIDC limits.
modelmigration/​v28/​v353.go Adds workflow-path columns.
modelmigration/​v28/​v353_test.go Tests the schema migration.
modelmigration/​migrations.go Registers migration 353.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread services/actions/init.go Outdated
Comment thread modelmigration/v28/v353.go Outdated
Comment thread routers/api/actions/oidc.go Outdated
Comment thread services/actions/oidc.go Outdated
Assisted-by: Claude Code:claude-opus-5-5

# Conflicts:
#	modelmigration/migrations.go
#	modelmigration/v28/v353.go
#	modelmigration/v28/v353_test.go
#	modules/actions/workflows.go
Tokens now follow GitHub's format so existing clients and trust
policies carry over: the immutable subject, a single string audience,
the workflow name and fully qualified reusable workflow refs recorded
when the workflow is loaded, so a same-named tag can't pose as a branch.

A dedicated signing key replaces the OAuth2 provider key, which could
end startup when missing, and a separate request token keeps the
runtime token that runners also send to cache servers from minting
OIDC tokens. Cancelling tasks can still request one for cleanup.

The workflow directory is derived from the recorded commit instead of
a stored path, which migrated schedules lacked, and the reusable
workflow permission walk is dropped since callers already clamp their
children when they are expanded.

Assisted-by: Claude Code:claude-opus-5-5
* origin/main:
  fix: copy new access token to clipboard (go-gitea#39496)
release/v28 ends at migration 355, so 356 starts the next version.

Assisted-by: Claude Code:claude-opus-5-5
@silverwind

silverwind commented Sep 30, 2026 •

Copy link
Copy Markdown
Member

Reworked this on top of main, with GitHub compatibility as the priority:

  1. Tokens match GitHub's format: the immutable repo:owner@id/repo@id:ref:... subject (:pull_request only for pull_request), a string aud, workflow as the workflow name, and job_workflow_ref/job_workflow_sha on every job
  2. Reusable workflows record the fully qualified ref they were loaded from, so a same-named tag can't pose as a protected branch and the claim stays stable when the branch moves (migration in v29)
  3. Dedicated RS256 signing key created on first use instead of the OAuth2 provider key, no more fatal startup path
  4. Separate ID token request token, so the runtime token that runners also send to cache servers can't mint OIDC tokens
  5. Running and cancelling tasks can request tokens
  6. The workflow directory is derived from the recorded commit, dropping the workflow_path columns and the migrated schedule gap
  7. Dropped the reusable workflow permission walk (children are already clamped at expansion) and the HS256 narrowing
  8. github.ref_type is branch for pull request runs, like on GitHub
  9. Discovery advertises claims_supported and scopes_supported
  10. Tests reduced to one integration test plus focused unit tests

The docs in https://gitea.com/gitea/docs/pulls/526 are updated to match.

Written by Claude Code (claude-opus-5-5)

@silverwind

silverwind commented Sep 30, 2026 •

Copy link
Copy Markdown
Member

Cut out about 1k lines from the PR while fixing the issues above, migration is moved to v29, pr description updated and shortened.

@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 Sep 30, 2026
@lunny lunny added this to the 29.0.0 milestone Sep 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

lgtm/need 1 This PR needs approval from one additional maintainer to be merged. topic/gitea-actions related to the actions of Gitea type/enhancement An improvement of existing functionality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Native OIDC Token for workload identity federation Gitea as an OIDC IdP for Actions

5 participants