Skip to content

Feature non zipped actions artifacts (action v7 / nodejs/npm v6.2.0)#36786

Draft
ChristopherHX wants to merge 34 commits intogo-gitea:mainfrom
ChristopherHX:non-zip-artifacts
Draft

Feature non zipped actions artifacts (action v7 / nodejs/npm v6.2.0)#36786
ChristopherHX wants to merge 34 commits intogo-gitea:mainfrom
ChristopherHX:non-zip-artifacts

Conversation

@ChristopherHX
Copy link
Contributor

@ChristopherHX ChristopherHX commented Feb 28, 2026

  • content_encoding contains a slash => v4 artifact
  • updated proto files to support mime_type and no longer return errors for upload-artifact v7
  • json and txt files are now previewed in browser
  • Depends on something similar to Refactor storage content-type handling of SignedURL #36804 to work reliable for ServeDirect

Closes #36829


@GiteaBot GiteaBot added the lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. label Feb 28, 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 28, 2026
@ChristopherHX ChristopherHX added type/feature Completely new functionality. Can only be merged if feature freeze is not active. topic/gitea-actions related to the actions of Gitea labels Feb 28, 2026
Signed-off-by: ChristopherHX <christopher.homberger@web.de>
@ChristopherHX
Copy link
Contributor Author

GITHUB_SERVER_URL hack + @actions/artifact can be used like

           const { default: artifact } = await import("@actions/artifact");
           var artifactName = "my-single-file";
           process.env.GITHUB_SERVER_URL = "https://github.com" // Escape isGHES bomb
           var uploadResult = await artifact.uploadArtifact(
             artifactName,
             ['package.json'],
             './',
             {skipArchive: true}
           )

Status: int(actions.ArtifactStatusUploadConfirmed),
RunID: runID,
Status: int(actions.ArtifactStatusUploadConfirmed),
FinalizedArtifactsV4: true,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Replaces || artifact.ArtifactName+".zip" != artifact.ArtifactPath || artifact.ContentEncoding != ArtifactV4ContentEncoding below so this filter is no longer needed

…n the code and fixed it later by changing the other end
Signed-off-by: ChristopherHX <christopher.homberger@web.de>
@ChristopherHX ChristopherHX changed the title Feature non zipped actions artifacts Feature non zipped actions artifacts (action v7 / nodejs/npm v6.2.0) Mar 7, 2026
@ChristopherHX ChristopherHX requested a review from Copilot March 7, 2026 22:30
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR updates the Actions artifacts v4 implementation to support actions/upload-artifact@v7 “non-zipped” artifacts by propagating a MIME type through the API and serving artifacts inline with safer headers for browser preview.

Changes:

  • Extend the v4 Twirp proto/API to accept mime_type and store it in ActionArtifact.ContentEncoding (while keeping .zip behavior for older clients/versions).
  • Adjust artifact lookup/filtering to treat v4 artifacts as those whose content_encoding looks like a MIME type and update listing logic accordingly.
  • Serve single v4 artifacts inline (plus CSP sandbox) and update integration tests around download behavior.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
tests/integration/api_actions_artifact_v4_test.go Refactors download test to run across ServeDirect modes and asserts response headers.
routers/web/repo/actions/view.go Serves single v4 artifacts inline and adds CSP sandbox header; keeps zip bundling for v1–v3.
routers/api/actions/artifactsv4.go Adds MIME/type-aware create/list/download behavior and ServeDirect URL response header parameters.
routers/api/actions/artifact.proto Adds mime_type to CreateArtifactRequest and sets go_package.
routers/api/actions/artifact.pb.go Regenerated protobuf bindings for the updated proto.
modules/actions/artifacts.go Changes v4 detection and adjusts v4 download (ServeDirect + fallback) to use stored MIME type/path.
models/actions/artifact.go Updates v4 “finalized artifacts” filtering to match MIME-like content_encoding.
Comments suppressed due to low confidence (1)

routers/api/actions/artifactsv4.go:277

  • getArtifactByName now selects by run_id + artifact_name + content_encoding LIKE '/', but the DB uniqueness is (run_id, artifact_name, artifact_path). If the same artifact name exists with different artifact_path (e.g. .zip vs non-zipped v7), this query can return an arbitrary record and may not match the artifactID that was signed/verified. Consider looking up by the signed artifactID (and verify artifact.RunID/ArtifactName), or include artifact_path in the lookup to make selection deterministic.
func (r *artifactV4Routes) getArtifactByName(ctx *ArtifactContext, runID int64, name string) (*actions.ActionArtifact, error) {
	var art actions.ActionArtifact
	has, err := db.GetEngine(ctx).Where(builder.Eq{"run_id": runID, "artifact_name": name}, builder.Like{"content_encoding", "/"}).Get(&art)
	if err != nil {
		return nil, err
	} else if !has {
		return nil, util.ErrNotExist
	}
	return &art, nil

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 696 to +698
if len(artifacts) == 1 && actions.IsArtifactV4(artifacts[0]) {
ctx.Resp.Header().Set("Content-Disposition", fmt.Sprintf("inline; filename=%s; filename*=UTF-8''%s", url.PathEscape(artifacts[0].ArtifactPath), artifacts[0].ArtifactPath))
ctx.Resp.Header().Set("Content-Security-Policy", "sandbox; default-src 'none';")
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

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

The Content-Disposition header uses filename* but the value is not RFC5987-encoded (it uses the raw ArtifactPath). This can produce an invalid header for spaces/non-ASCII and can lead to inconsistent filenames across browsers. Encode the filename* value (percent-encode UTF-8, similar to url.PathEscape/custom RFC5987 encoder) and consider quoting filename= as well.

Copilot uses AI. Check for mistakes.
u, err := storage.ActionsArtifacts.URL(artifact.StoragePath, artifact.ArtifactPath, ctx.Req.Method, nil)
reqParams := url.Values{}
reqParams.Set("response-content-type", artifact.ContentEncoding)
reqParams.Set("response-content-disposition", fmt.Sprintf("inline; filename=%s; filename*=UTF-8''%s", url.PathEscape(artifact.ArtifactPath), artifact.ArtifactPath))
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

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

The signed ServeDirect URL sets response-content-disposition using filename* but the value is not RFC5987-encoded (raw artifact.ArtifactPath). This can break filenames for spaces/non-ASCII when the storage backend returns the header. Encode the filename* value before embedding it in the disposition string.

Suggested change
reqParams.Set("response-content-disposition", fmt.Sprintf("inline; filename=%s; filename*=UTF-8''%s", url.PathEscape(artifact.ArtifactPath), artifact.ArtifactPath))
reqParams.Set("response-content-disposition", fmt.Sprintf("inline; filename=%s; filename*=UTF-8''%s", url.PathEscape(artifact.ArtifactPath), url.PathEscape(artifact.ArtifactPath)))

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. modifies/api This PR adds API routes or modifies them modifies/go Pull requests that update Go code topic/gitea-actions related to the actions of Gitea type/feature Completely new functionality. Can only be merged if feature freeze is not active.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Gitea Actions is incompatible with actions/upload-artifact@v6 and later versions

3 participants