Compare commits

...

3 Commits

Author SHA1 Message Date
Sofia Papagiannaki
30a76f605c Fix static handler redirect logic to ensure proper clean up URLs before redirection.
(cherry picked from commit f50ec8e0d10c24fd79f6c454974a2fc6e9694ef2)
2025-05-06 07:32:28 -05:00
Kevin Minehart
0951f3b56e CI: Use docker creds from ci/common (#104827)
Use docker creds from ci/common

(cherry picked from commit fd4afdbd2c)
2025-05-02 16:33:51 -06:00
Kevin Minehart
db6ac304e7 CI: move grafana-delivery-bot path in Drone (#104886)
* move delivery bot creds to vault

* format-drone

(cherry picked from commit ec35e861e0)
2025-05-02 16:33:39 -06:00
5 changed files with 201 additions and 57 deletions

View File

@@ -970,10 +970,8 @@ steps:
from_secret: docker_password
DOCKER_USER:
from_secret: docker_username
GITHUB_APP_ID:
from_secret: delivery-bot-app-id
GITHUB_APP_INSTALLATION_ID:
from_secret: delivery-bot-app-installation-id
GITHUB_APP_ID: "329617"
GITHUB_APP_INSTALLATION_ID: "37346161"
GITHUB_APP_PRIVATE_KEY:
from_secret: delivery-bot-app-private-key
failure: ignore
@@ -2481,10 +2479,8 @@ steps:
from_secret: docker_username
GCP_KEY:
from_secret: gcp_grafanauploads
GITHUB_APP_ID:
from_secret: delivery-bot-app-id
GITHUB_APP_INSTALLATION_ID:
from_secret: delivery-bot-app-installation-id
GITHUB_APP_ID: "329617"
GITHUB_APP_INSTALLATION_ID: "37346161"
GITHUB_APP_PRIVATE_KEY:
from_secret: delivery-bot-app-private-key
image: google/cloud-sdk:431.0.0
@@ -2506,10 +2502,8 @@ steps:
from_secret: docker_username
GCP_KEY:
from_secret: gcp_grafanauploads
GITHUB_APP_ID:
from_secret: delivery-bot-app-id
GITHUB_APP_INSTALLATION_ID:
from_secret: delivery-bot-app-installation-id
GITHUB_APP_ID: "329617"
GITHUB_APP_INSTALLATION_ID: "37346161"
GITHUB_APP_PRIVATE_KEY:
from_secret: delivery-bot-app-private-key
image: google/cloud-sdk:431.0.0
@@ -3570,10 +3564,8 @@ steps:
from_secret: docker_username
GCP_KEY:
from_secret: gcp_grafanauploads
GITHUB_APP_ID:
from_secret: delivery-bot-app-id
GITHUB_APP_INSTALLATION_ID:
from_secret: delivery-bot-app-installation-id
GITHUB_APP_ID: "329617"
GITHUB_APP_INSTALLATION_ID: "37346161"
GITHUB_APP_PRIVATE_KEY:
from_secret: delivery-bot-app-private-key
image: google/cloud-sdk:431.0.0
@@ -5511,13 +5503,13 @@ name: prerelease_bucket
---
get:
name: username
path: infra/data/ci/grafanaci-docker-hub
path: ci/data/common/dockerhub
kind: secret
name: docker_username
---
get:
name: password
path: infra/data/ci/grafanaci-docker-hub
path: ci/data/common/dockerhub
kind: secret
name: docker_password
---
@@ -5636,20 +5628,8 @@ kind: secret
name: dagger_token
---
get:
name: app-id
path: infra/data/ci/grafana-release-eng/grafana-delivery-bot
kind: secret
name: delivery-bot-app-id
---
get:
name: app-installation-id
path: infra/data/ci/grafana-release-eng/grafana-delivery-bot
kind: secret
name: delivery-bot-app-installation-id
---
get:
name: app-private-key
path: infra/data/ci/grafana-release-eng/grafana-delivery-bot
name: PRIVATE_KEY
path: ci/data/repo/grafana/grafana/delivery-bot-app
kind: secret
name: delivery-bot-app-private-key
---
@@ -5660,6 +5640,6 @@ kind: secret
name: gcr_credentials
---
kind: signature
hmac: edf04b96b7e774fef31baeb64263f90458ce617d6d3ac09ed8f0f9b59e4f643e
hmac: f0da71ffaa44671a6c0666891461ea51386f1c5c6b3b0c8bda1c056fdb501989
...

View File

@@ -159,16 +159,17 @@ func staticHandler(ctx *web.Context, log log.Logger, opt StaticOptions) bool {
if fi.IsDir() {
// Redirect if missing trailing slash.
if !strings.HasSuffix(ctx.Req.URL.Path, "/") {
path := fmt.Sprintf("%s/", ctx.Req.URL.Path)
if !strings.HasPrefix(path, "/") {
redirectPath := path.Clean(ctx.Req.URL.Path)
redirectPath = fmt.Sprintf("%s/", redirectPath)
if !strings.HasPrefix(redirectPath, "/") {
// Disambiguate that it's a path relative to this server
path = fmt.Sprintf("/%s", path)
redirectPath = fmt.Sprintf("/%s", redirectPath)
} else {
// A string starting with // or /\ is interpreted by browsers as a URL, and not a server relative path
rePrefix := regexp.MustCompile(`^(?:/\\|/+)`)
path = rePrefix.ReplaceAllString(path, "/")
redirectPath = rePrefix.ReplaceAllString(redirectPath, "/")
}
http.Redirect(ctx.Resp, ctx.Req, path, http.StatusFound)
http.Redirect(ctx.Resp, ctx.Req, redirectPath, http.StatusFound)
return true
}

View File

@@ -0,0 +1,174 @@
package httpstatic
import (
"io"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"testing"
claims "github.com/grafana/authlib/types"
"github.com/grafana/grafana/pkg/models/usertoken"
"github.com/grafana/grafana/pkg/services/authn"
"github.com/grafana/grafana/pkg/services/authn/authntest"
"github.com/grafana/grafana/pkg/services/contexthandler"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/web"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestStatic(t *testing.T) {
// Create a temporary directory for test files
tmpDir, err := os.MkdirTemp("", "static-test")
require.NoError(t, err)
defer os.RemoveAll(tmpDir)
// Create test files
testFiles := map[string]string{
"test.txt": "Test content",
"subdir/test.txt": "Subdir content",
}
for path, content := range testFiles {
fullPath := filepath.Join(tmpDir, path)
err := os.MkdirAll(filepath.Dir(fullPath), 0o755)
require.NoError(t, err)
err = os.WriteFile(fullPath, []byte(content), 0o644)
require.NoError(t, err)
}
tests := []struct {
dir string
name string
path string
options StaticOptions
expectedStatus int
expectedBody string
expectedLocation string
}{
{
name: "should serve existing file",
path: "/test.txt",
expectedStatus: http.StatusOK,
expectedBody: "Test content",
dir: tmpDir,
},
{
name: "should serve file from subdirectory",
path: "/subdir/test.txt",
expectedStatus: http.StatusOK,
expectedBody: "Subdir content",
dir: tmpDir,
},
{
name: "should redirect directory without trailing slash",
path: "/subdir",
expectedStatus: http.StatusFound,
expectedLocation: "/subdir/",
dir: tmpDir,
},
{
name: "should handle prefix",
path: "/static/test.txt",
options: StaticOptions{Prefix: "/static"},
expectedStatus: http.StatusOK,
expectedBody: "Test content",
dir: tmpDir,
},
{
name: "should handle excluded path",
path: "/test.txt",
options: StaticOptions{Exclude: []string{"/test.txt"}},
expectedStatus: http.StatusNotFound,
dir: tmpDir,
},
{
name: "should add custom headers",
path: "/test.txt",
options: StaticOptions{AddHeaders: func(ctx *web.Context) { ctx.Resp.Header().Set("X-Test", "test") }},
expectedStatus: http.StatusOK,
expectedBody: "Test content",
dir: tmpDir,
},
{
name: "should clean up path before redirecting",
path: "/subdir/..%2F%5C127.0.0.1:80%2F%3F%2F..%2F..",
options: StaticOptions{Prefix: "subdir"},
expectedStatus: http.StatusFound,
expectedLocation: "/",
dir: tmpDir,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
sc := setupScenarioContext(t, "")
sc.m.Use(Static(tt.dir, tt.options))
// Create a test request
req := httptest.NewRequest("GET", tt.path, nil)
w := httptest.NewRecorder()
// Execute the handler
sc.m.ServeHTTP(w, req)
// Verify the response
resp := w.Result()
require.Equal(t, tt.expectedStatus, resp.StatusCode)
if tt.expectedBody != "" {
body, err := io.ReadAll(resp.Body)
require.NoError(t, err)
assert.Equal(t, tt.expectedBody, string(body))
}
if tt.options.AddHeaders != nil {
assert.Equal(t, "test", resp.Header.Get("X-Test"))
}
if tt.expectedLocation != "" {
assert.Equal(t, tt.expectedLocation, resp.Header.Get("Location"))
}
})
}
}
type scenarioContext struct {
t *testing.T
cfg *setting.Cfg
m *web.Mux
ctxHdlr *contexthandler.ContextHandler
}
func getContextHandler(t *testing.T, cfg *setting.Cfg) *contexthandler.ContextHandler {
t.Helper()
if cfg == nil {
cfg = setting.NewCfg()
}
return contexthandler.ProvideService(
cfg,
&authntest.FakeService{ExpectedIdentity: &authn.Identity{ID: "0", Type: claims.TypeAnonymous, SessionToken: &usertoken.UserToken{}}},
featuremgmt.WithFeatures(),
)
}
func setupScenarioContext(t *testing.T, url string) *scenarioContext {
cfg := setting.NewCfg()
ctxHdlr := getContextHandler(t, cfg)
sc := &scenarioContext{
t: t,
cfg: cfg,
ctxHdlr: ctxHdlr,
}
sc.m = web.New()
sc.m.Use(ctxHdlr.Middleware)
return sc
}

View File

@@ -931,8 +931,8 @@ def publish_images_step(ver_mode, docker_repo, trigger = None):
"GCP_KEY": from_secret(gcp_grafanauploads),
"DOCKER_USER": from_secret("docker_username"),
"DOCKER_PASSWORD": from_secret("docker_password"),
"GITHUB_APP_ID": from_secret("delivery-bot-app-id"),
"GITHUB_APP_INSTALLATION_ID": from_secret("delivery-bot-app-installation-id"),
"GITHUB_APP_ID": "329617",
"GITHUB_APP_INSTALLATION_ID": "37346161",
"GITHUB_APP_PRIVATE_KEY": from_secret("delivery-bot-app-private-key"),
}
@@ -949,8 +949,8 @@ def publish_images_step(ver_mode, docker_repo, trigger = None):
environment = {
"DOCKER_USER": from_secret("docker_username"),
"DOCKER_PASSWORD": from_secret("docker_password"),
"GITHUB_APP_ID": from_secret("delivery-bot-app-id"),
"GITHUB_APP_INSTALLATION_ID": from_secret("delivery-bot-app-installation-id"),
"GITHUB_APP_ID": "329617",
"GITHUB_APP_INSTALLATION_ID": "37346161",
"GITHUB_APP_PRIVATE_KEY": from_secret("delivery-bot-app-private-key"),
}

View File

@@ -55,8 +55,8 @@ def secrets():
vault_secret(gar_pull_secret, "secret/data/common/gar", ".dockerconfigjson"),
vault_secret(drone_token, "infra/data/ci/drone", "machine-user-token"),
vault_secret(prerelease_bucket, "infra/data/ci/grafana/prerelease", "bucket"),
vault_secret(docker_username, "infra/data/ci/grafanaci-docker-hub", "username"),
vault_secret(docker_password, "infra/data/ci/grafanaci-docker-hub", "password"),
vault_secret(docker_username, "ci/data/common/dockerhub", "username"),
vault_secret(docker_password, "ci/data/common/dockerhub", "password"),
vault_secret(
gcp_upload_artifacts_key,
"infra/data/ci/grafana/releng/artifacts-uploader-service-account",
@@ -153,21 +153,10 @@ def secrets():
"infra/data/ci/grafana-release-eng/rgm",
"dagger_token",
),
# grafana-delivery-bot secrets
vault_secret(
"delivery-bot-app-id",
"infra/data/ci/grafana-release-eng/grafana-delivery-bot",
"app-id",
),
vault_secret(
"delivery-bot-app-installation-id",
"infra/data/ci/grafana-release-eng/grafana-delivery-bot",
"app-installation-id",
),
vault_secret(
"delivery-bot-app-private-key",
"infra/data/ci/grafana-release-eng/grafana-delivery-bot",
"app-private-key",
"ci/data/repo/grafana/grafana/delivery-bot-app",
"PRIVATE_KEY",
),
vault_secret(
"gcr_credentials",