mirror of
https://github.com/go-gitea/gitea.git
synced 2026-05-11 04:55:34 +02:00
actions: align iframe sandbox with CSP and avoid duplicate v4 zip parse
- Drop `allow-scripts` from the iframe sandbox attribute. The response CSP `default-src 'none'; sandbox` already blocks scripts, so the attribute was contradictory. Now both layers express the same intent: opaque origin, no scripts, no forms. - Skip listPreviewPaths in ArtifactsPreviewRawView and parse the v4 zip exactly once per request via serveArtifactV4PreviewRaw. Previously a cache miss caused two open+parse cycles for the same zip. The page handler still uses the cache. Co-Authored-By: Claude (Opus 4.7) <noreply@anthropic.com>
This commit is contained in:
parent
5fdb61540f
commit
b13474a895
@ -1279,6 +1279,48 @@ func ArtifactsPreviewView(ctx *context_module.Context) {
|
||||
ctx.HTML(http.StatusOK, tplArtifactPreviewAction)
|
||||
}
|
||||
|
||||
// serveArtifactV4PreviewRaw opens the v4 artifact zip once and serves a single file from it,
|
||||
// avoiding the redundant parse that listPreviewPaths would do for raw fetches.
|
||||
func serveArtifactV4PreviewRaw(ctx *context_module.Context, artifact *actions_model.ActionArtifact, requested string) {
|
||||
obj, reader, err := openArtifactV4ZipReader(artifact)
|
||||
if err != nil {
|
||||
if !errors.Is(err, zip.ErrFormat) {
|
||||
ctx.ServerError("openArtifactV4ZipReader", err)
|
||||
return
|
||||
}
|
||||
fallbackPath := artifactPreviewFallbackPath(artifact)
|
||||
selectedPath := ChoosePreviewPath([]string{fallbackPath}, requested)
|
||||
if selectedPath == "" {
|
||||
ctx.HTTPError(http.StatusNotFound, "artifact file not found")
|
||||
return
|
||||
}
|
||||
f, err := storage.ActionsArtifacts.Open(artifact.StoragePath)
|
||||
if err != nil {
|
||||
ctx.ServerError("ActionsArtifacts.Open", err)
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
previewArtifactByReadSeeker(ctx, selectedPath, f)
|
||||
return
|
||||
}
|
||||
defer obj.Close()
|
||||
|
||||
paths, files := listArtifactV4ZipFiles(reader)
|
||||
selectedPath := ChoosePreviewPath(paths, requested)
|
||||
if selectedPath == "" {
|
||||
ctx.HTTPError(http.StatusNotFound, "artifact file not found")
|
||||
return
|
||||
}
|
||||
zf := files[selectedPath]
|
||||
r, err := zf.Open()
|
||||
if err != nil {
|
||||
ctx.ServerError("zip.File.Open", err)
|
||||
return
|
||||
}
|
||||
defer r.Close()
|
||||
previewArtifactByReader(ctx, selectedPath, r)
|
||||
}
|
||||
|
||||
func ArtifactsPreviewRawView(ctx *context_module.Context) {
|
||||
artifactName := ctx.PathParam("artifact_name")
|
||||
|
||||
@ -1286,61 +1328,17 @@ func ArtifactsPreviewRawView(ctx *context_module.Context) {
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
paths, err := listPreviewPaths(artifacts)
|
||||
if err != nil {
|
||||
ctx.ServerError("listPreviewPaths", err)
|
||||
return
|
||||
}
|
||||
selectedPath := ChoosePreviewPath(paths, GetRequestedPreviewPath(ctx))
|
||||
if selectedPath == "" {
|
||||
ctx.HTTPError(http.StatusNotFound, "artifact file not found")
|
||||
return
|
||||
}
|
||||
requested := GetRequestedPreviewPath(ctx)
|
||||
|
||||
if len(artifacts) == 1 && actions.IsArtifactV4(artifacts[0]) {
|
||||
artifact := artifacts[0]
|
||||
serveArtifactV4PreviewRaw(ctx, artifacts[0], requested)
|
||||
return
|
||||
}
|
||||
|
||||
obj, reader, err := openArtifactV4ZipReader(artifact)
|
||||
if err != nil {
|
||||
if !errors.Is(err, zip.ErrFormat) {
|
||||
ctx.ServerError("openArtifactV4ZipReader", err)
|
||||
return
|
||||
}
|
||||
|
||||
fallbackPath := artifactPreviewFallbackPath(artifact)
|
||||
if selectedPath != fallbackPath {
|
||||
ctx.HTTPError(http.StatusNotFound, "artifact file not found")
|
||||
return
|
||||
}
|
||||
|
||||
f, err := storage.ActionsArtifacts.Open(artifact.StoragePath)
|
||||
if err != nil {
|
||||
ctx.ServerError("ActionsArtifacts.Open", err)
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
previewArtifactByReadSeeker(ctx, selectedPath, f)
|
||||
return
|
||||
}
|
||||
defer obj.Close()
|
||||
|
||||
_, files := listArtifactV4ZipFiles(reader)
|
||||
zf, ok := files[selectedPath]
|
||||
if !ok {
|
||||
ctx.HTTPError(http.StatusNotFound, "artifact file not found")
|
||||
return
|
||||
}
|
||||
|
||||
r, err := zf.Open()
|
||||
if err != nil {
|
||||
ctx.ServerError("zip.File.Open", err)
|
||||
return
|
||||
}
|
||||
defer r.Close()
|
||||
|
||||
previewArtifactByReader(ctx, selectedPath, r)
|
||||
paths := listPreviewPathsForLegacyArtifacts(artifacts)
|
||||
selectedPath := ChoosePreviewPath(paths, requested)
|
||||
if selectedPath == "" {
|
||||
ctx.HTTPError(http.StatusNotFound, "artifact file not found")
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@ -49,7 +49,8 @@
|
||||
</div>
|
||||
<div class="twelve wide column">
|
||||
{{if .SelectedPath}}
|
||||
<iframe class="artifact-preview-frame" src="{{.PreviewRawURL}}/{{PathEscapeSegments .SelectedPath}}" sandbox="allow-scripts" referrerpolicy="no-referrer"></iframe>
|
||||
{{/* iframe sandbox="" matches the response CSP `sandbox` directive: opaque origin, no scripts, no forms, no popups. */}}
|
||||
<iframe class="artifact-preview-frame" src="{{.PreviewRawURL}}/{{PathEscapeSegments .SelectedPath}}" sandbox="" referrerpolicy="no-referrer"></iframe>
|
||||
{{else}}
|
||||
<div class="ui attached segment">{{ctx.Locale.Tr "none"}}</div>
|
||||
{{end}}
|
||||
|
||||
@ -51,8 +51,8 @@ func TestActionsArtifactPreviewSingleFile(t *testing.T) {
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
assert.Contains(t, resp.Body.String(), "abc.txt")
|
||||
assert.Contains(t, resp.Body.String(), "/preview/raw/abc.txt")
|
||||
assert.Contains(t, resp.Body.String(), "sandbox=\"allow-scripts\"")
|
||||
assert.Contains(t, resp.Body.String(), "referrerpolicy=\"no-referrer\"")
|
||||
assert.Contains(t, resp.Body.String(), `sandbox=""`)
|
||||
assert.Contains(t, resp.Body.String(), `referrerpolicy="no-referrer"`)
|
||||
|
||||
req = NewRequestf(t, "GET", "/%s/actions/runs/187/artifacts/artifact-download/preview/raw", repo.FullName())
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user