From 0976d0a20e6e2a7f3417cb3f67ae137ac40a1b76 Mon Sep 17 00:00:00 2001 From: David Karlsson <35727626+dvdksn@users.noreply.github.com> Date: Tue, 12 May 2026 17:22:54 +0200 Subject: [PATCH 1/2] releaser: add CloudFront Function + KVS redirect path Adds a second redirect path that uses a CloudFront Function backed by a CloudFront KeyValueStore (KVS) instead of Lambda@Edge: O(1) kvs.get(uri) per request instead of iterating the whole redirect map. Wired to the lab environment via two new env vars (DOCS_CLOUDFRONT_KVS_ARN, DOCS_CLOUDFRONT_FUNCTION_NAME) on the existing refs/heads/lab and refs/heads/main entries. The new deploy step is gated on both being non-empty, so prod stays Lambda@Edge-only until those vars are populated. Co-Authored-By: Claude Opus 4.7 --- .github/workflows/build.yml | 11 + .github/workflows/deploy.yml | 13 + docker-bake.hcl | 19 ++ hack/releaser/Dockerfile | 16 ++ hack/releaser/aws.go | 5 +- hack/releaser/aws_kvs.go | 265 ++++++++++++++++++ .../releaser/cloudfront-function-redirects.js | 66 +++++ hack/releaser/env.json | 8 +- hack/releaser/go.mod | 16 ++ hack/releaser/go.sum | 32 +++ 10 files changed, 447 insertions(+), 4 deletions(-) create mode 100644 hack/releaser/aws_kvs.go create mode 100644 hack/releaser/cloudfront-function-redirects.js diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 161fd2bdfffc..f4929072e915 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -67,6 +67,17 @@ jobs: AWS_REGION: us-east-1 AWS_CLOUDFRONT_ID: 0123456789ABCD AWS_LAMBDA_FUNCTION: DockerDocsRedirectFunction-dummy + - + name: Check Cloudfront Function config + uses: docker/bake-action@82490499d2e5613fcead7e128237ef0b0ea210f7 # v7 + with: + source: . + targets: aws-cloudfront-function-update + env: + DRY_RUN: true + AWS_REGION: us-east-1 + AWS_CLOUDFRONT_FUNCTION_NAME: DockerDocsRedirectFunction-dummy + AWS_CLOUDFRONT_KVS_ARN: arn:aws:cloudfront::000000000000:key-value-store/dummy validate: runs-on: ubuntu-24.04 diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 4570805dc6af..72e80d052935 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -125,6 +125,19 @@ jobs: AWS_REGION: us-east-1 # cloudfront and lambda edge functions are only available in us-east-1 region AWS_CLOUDFRONT_ID: ${{ env.DOCS_CLOUDFRONT_ID }} AWS_LAMBDA_FUNCTION: ${{ env.DOCS_LAMBDA_FUNCTION_REDIRECTS }} + - + name: Update CloudFront Function redirects + if: ${{ env.DOCS_CLOUDFRONT_KVS_ARN != '' && env.DOCS_CLOUDFRONT_FUNCTION_NAME != '' }} + uses: docker/bake-action@82490499d2e5613fcead7e128237ef0b0ea210f7 # v7 + with: + source: . + files: | + docker-bake.hcl + targets: aws-cloudfront-function-update + env: + AWS_REGION: us-east-1 # cloudfront and KVS are only available in us-east-1 + AWS_CLOUDFRONT_FUNCTION_NAME: ${{ env.DOCS_CLOUDFRONT_FUNCTION_NAME }} + AWS_CLOUDFRONT_KVS_ARN: ${{ env.DOCS_CLOUDFRONT_KVS_ARN }} - name: Invalidate Cloudfront cache if: ${{ env.DOCS_CLOUDFRONT_ID != '' }} diff --git a/docker-bake.hcl b/docker-bake.hcl index cd32840eb6c8..b6d02337751a 100644 --- a/docker-bake.hcl +++ b/docker-bake.hcl @@ -107,6 +107,12 @@ variable "AWS_CLOUDFRONT_ID" { variable "AWS_LAMBDA_FUNCTION" { default = "" } +variable "AWS_CLOUDFRONT_FUNCTION_NAME" { + default = "" +} +variable "AWS_CLOUDFRONT_KVS_ARN" { + default = "" +} target "_common-aws" { args = { @@ -116,6 +122,8 @@ target "_common-aws" { AWS_S3_CONFIG = AWS_S3_CONFIG AWS_CLOUDFRONT_ID = AWS_CLOUDFRONT_ID AWS_LAMBDA_FUNCTION = AWS_LAMBDA_FUNCTION + AWS_CLOUDFRONT_FUNCTION_NAME = AWS_CLOUDFRONT_FUNCTION_NAME + AWS_CLOUDFRONT_KVS_ARN = AWS_CLOUDFRONT_KVS_ARN } secret = [ "id=AWS_ACCESS_KEY_ID,env=AWS_ACCESS_KEY_ID", @@ -144,6 +152,17 @@ target "aws-cloudfront-update" { output = ["type=cacheonly"] } +target "aws-cloudfront-function-update" { + inherits = ["_common-aws"] + context = "hack/releaser" + target = "aws-cloudfront-function-update" + contexts = { + sitedir = DOCS_SITE_DIR + } + no-cache-filter = ["aws-cloudfront-function-update"] + output = ["type=cacheonly"] +} + variable "VENDOR_MODULE" { default = null } diff --git a/hack/releaser/Dockerfile b/hack/releaser/Dockerfile index c2983b304c56..863571b4ee0c 100644 --- a/hack/releaser/Dockerfile +++ b/hack/releaser/Dockerfile @@ -40,3 +40,19 @@ RUN --mount=type=bind,target=. \ --mount=type=secret,id=AWS_SECRET_ACCESS_KEY \ --mount=type=secret,id=AWS_SESSION_TOKEN \ releaser aws cloudfront-update + +FROM base AS aws-cloudfront-function-update +ARG DRY_RUN=false +ARG AWS_REGION +ARG AWS_CLOUDFRONT_FUNCTION_NAME +ARG AWS_CLOUDFRONT_KVS_ARN +ARG AWS_CLOUDFRONT_FUNCTION_FILE="cloudfront-function-redirects.js" +ARG REDIRECTS_FILE="/site/redirects.json" +ARG REDIRECTS_PREFIXES_FILE="redirects-prefixes.json" +RUN --mount=type=bind,target=. \ + --mount=type=bind,from=sitedir,target=/site \ + --mount=type=bind,from=releaser,source=/out/releaser,target=/usr/bin/releaser \ + --mount=type=secret,id=AWS_ACCESS_KEY_ID \ + --mount=type=secret,id=AWS_SECRET_ACCESS_KEY \ + --mount=type=secret,id=AWS_SESSION_TOKEN \ + releaser aws cloudfront-function-update diff --git a/hack/releaser/aws.go b/hack/releaser/aws.go index 1153a9873912..ee3ceeede2e3 100644 --- a/hack/releaser/aws.go +++ b/hack/releaser/aws.go @@ -20,8 +20,9 @@ import ( ) type AwsCmd struct { - LambdaInvoke AwsLambdaInvokeCmd `kong:"cmd,name=lambda-invoke"` - CloudfrontUpdate AwsCloudfrontUpdateCmd `kong:"cmd,name=cloudfront-update"` + LambdaInvoke AwsLambdaInvokeCmd `kong:"cmd,name=lambda-invoke"` + CloudfrontUpdate AwsCloudfrontUpdateCmd `kong:"cmd,name=cloudfront-update"` + CloudfrontFunctionUpdate AwsCloudfrontFunctionUpdateCmd `kong:"cmd,name=cloudfront-function-update"` } type AwsLambdaInvokeCmd struct { diff --git a/hack/releaser/aws_kvs.go b/hack/releaser/aws_kvs.go new file mode 100644 index 000000000000..018e6c527fc4 --- /dev/null +++ b/hack/releaser/aws_kvs.go @@ -0,0 +1,265 @@ +package main + +import ( + "bytes" + "context" + "crypto/sha256" + "encoding/hex" + "encoding/json" + "fmt" + "log" + "os" + "sort" + "text/template" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/credentials" + "github.com/aws/aws-sdk-go-v2/service/cloudfront" + cftypes "github.com/aws/aws-sdk-go-v2/service/cloudfront/types" + "github.com/aws/aws-sdk-go-v2/service/cloudfrontkeyvaluestore" + kvstypes "github.com/aws/aws-sdk-go-v2/service/cloudfrontkeyvaluestore/types" +) + +// updateKeysBatchSize is the maximum number of put+delete items per +// UpdateKeys call. The service rejects larger batches. +const updateKeysBatchSize = 50 + +type AwsCloudfrontFunctionUpdateCmd struct { + Region string `kong:"name='region',env='AWS_REGION'"` + FunctionName string `kong:"name='function-name',env='AWS_CLOUDFRONT_FUNCTION_NAME'"` + FunctionFile string `kong:"name='function-file',env='AWS_CLOUDFRONT_FUNCTION_FILE'"` + KvsARN string `kong:"name='kvs-arn',env='AWS_CLOUDFRONT_KVS_ARN'"` + RedirectsFile string `kong:"name='redirects-file',env='REDIRECTS_FILE'"` + RedirectsPrefixesFile string `kong:"name='redirects-prefixes-file',env='REDIRECTS_PREFIXES_FILE'"` + DryRun bool `kong:"name='dry-run',env='DRY_RUN'"` +} + +func (s *AwsCloudfrontFunctionUpdateCmd) Run() error { + ctx := context.Background() + + desired, err := loadDesiredRedirects(s.RedirectsFile) + if err != nil { + return fmt.Errorf("load redirects: %w", err) + } + log.Printf("INFO: loaded %d redirect entries from %s", len(desired), s.RedirectsFile) + + funcCode, err := renderFunctionCode(s.FunctionFile, s.RedirectsPrefixesFile) + if err != nil { + return fmt.Errorf("render function code: %w", err) + } + + if s.DryRun { + log.Printf("INFO: dry run. Region=%s FunctionName=%s KvsARN=%s redirects=%d", + s.Region, s.FunctionName, s.KvsARN, len(desired)) + log.Printf("INFO: function code (%d bytes):\n%s", len(funcCode), funcCode) + return nil + } + + cfg, err := config.LoadDefaultConfig(ctx, + config.WithRegion(s.Region), + config.WithCredentialsProvider(awsV2Credentials()), + ) + if err != nil { + return fmt.Errorf("load aws config: %w", err) + } + + if err := syncKVS(ctx, cloudfrontkeyvaluestore.NewFromConfig(cfg), s.KvsARN, desired); err != nil { + return fmt.Errorf("sync KVS: %w", err) + } + + if err := updateFunction(ctx, cloudfront.NewFromConfig(cfg), s.FunctionName, funcCode); err != nil { + return fmt.Errorf("update function: %w", err) + } + + return nil +} + +// loadDesiredRedirects reads redirects.json (map[alias]target) and +// normalizes keys to match the function's lookup form: trailing slashes +// stripped, empty keys dropped. +func loadDesiredRedirects(path string) (map[string]string, error) { + raw, err := os.ReadFile(path) + if err != nil { + return nil, err + } + var in map[string]string + if err := json.Unmarshal(raw, &in); err != nil { + return nil, err + } + out := make(map[string]string, len(in)) + for k, v := range in { + nk := normalizeKey(k) + if nk == "" { + continue + } + out[nk] = v + } + return out, nil +} + +func normalizeKey(k string) string { + for len(k) > 1 && k[len(k)-1] == '/' { + k = k[:len(k)-1] + } + if k == "/" { + return "" + } + return k +} + +func renderFunctionCode(funcFile, prefixesFile string) (string, error) { + tplBytes, err := os.ReadFile(funcFile) + if err != nil { + return "", err + } + prefixesBytes, err := os.ReadFile(prefixesFile) + if err != nil { + return "", err + } + tpl, err := template.New("").Parse(string(tplBytes)) + if err != nil { + return "", err + } + var buf bytes.Buffer + if err := tpl.Execute(&buf, struct{ RedirectsPrefixesJSON string }{ + RedirectsPrefixesJSON: string(prefixesBytes), + }); err != nil { + return "", err + } + return buf.String(), nil +} + +func syncKVS(ctx context.Context, svc *cloudfrontkeyvaluestore.Client, kvsARN string, desired map[string]string) error { + desc, err := svc.DescribeKeyValueStore(ctx, &cloudfrontkeyvaluestore.DescribeKeyValueStoreInput{ + KvsARN: aws.String(kvsARN), + }) + if err != nil { + return fmt.Errorf("describe KVS: %w", err) + } + etag := *desc.ETag + + current := map[string]string{} + pager := cloudfrontkeyvaluestore.NewListKeysPaginator(svc, &cloudfrontkeyvaluestore.ListKeysInput{ + KvsARN: aws.String(kvsARN), + }) + for pager.HasMorePages() { + page, err := pager.NextPage(ctx) + if err != nil { + return fmt.Errorf("list KVS keys: %w", err) + } + for _, item := range page.Items { + current[aws.ToString(item.Key)] = aws.ToString(item.Value) + } + } + log.Printf("INFO: KVS currently holds %d keys; desired %d", len(current), len(desired)) + + var puts []kvstypes.PutKeyRequestListItem + for k, v := range desired { + if cur, ok := current[k]; !ok || cur != v { + puts = append(puts, kvstypes.PutKeyRequestListItem{ + Key: aws.String(k), + Value: aws.String(v), + }) + } + } + var deletes []kvstypes.DeleteKeyRequestListItem + for k := range current { + if _, ok := desired[k]; !ok { + deletes = append(deletes, kvstypes.DeleteKeyRequestListItem{ + Key: aws.String(k), + }) + } + } + // Stable order for reproducible logs. + sort.Slice(puts, func(i, j int) bool { return *puts[i].Key < *puts[j].Key }) + sort.Slice(deletes, func(i, j int) bool { return *deletes[i].Key < *deletes[j].Key }) + + log.Printf("INFO: KVS diff: %d puts, %d deletes", len(puts), len(deletes)) + if len(puts) == 0 && len(deletes) == 0 { + return nil + } + + // Batch puts and deletes together, up to updateKeysBatchSize per call. + for len(puts) > 0 || len(deletes) > 0 { + batchPuts, batchDeletes := []kvstypes.PutKeyRequestListItem{}, []kvstypes.DeleteKeyRequestListItem{} + remaining := updateKeysBatchSize + + take := min(remaining, len(puts)) + batchPuts = puts[:take] + puts = puts[take:] + remaining -= take + + take = min(remaining, len(deletes)) + batchDeletes = deletes[:take] + deletes = deletes[take:] + + out, err := svc.UpdateKeys(ctx, &cloudfrontkeyvaluestore.UpdateKeysInput{ + KvsARN: aws.String(kvsARN), + IfMatch: aws.String(etag), + Puts: batchPuts, + Deletes: batchDeletes, + }) + if err != nil { + return fmt.Errorf("update KVS keys: %w", err) + } + etag = *out.ETag + log.Printf("INFO: applied batch (puts=%d deletes=%d)", len(batchPuts), len(batchDeletes)) + } + return nil +} + +func updateFunction(ctx context.Context, svc *cloudfront.Client, name, code string) error { + desc, err := svc.DescribeFunction(ctx, &cloudfront.DescribeFunctionInput{ + Name: aws.String(name), + Stage: cftypes.FunctionStageDevelopment, + }) + if err != nil { + return fmt.Errorf("describe function: %w", err) + } + + // Compare against currently-published code so we skip republishing + // when nothing has changed. + get, err := svc.GetFunction(ctx, &cloudfront.GetFunctionInput{ + Name: aws.String(name), + Stage: cftypes.FunctionStageLive, + }) + if err == nil && bytes.Equal(get.FunctionCode, []byte(code)) { + log.Printf("INFO: function %q LIVE code unchanged (sha256=%s); skipping publish", + name, sha256hex(code)) + return nil + } + + up, err := svc.UpdateFunction(ctx, &cloudfront.UpdateFunctionInput{ + Name: aws.String(name), + IfMatch: desc.ETag, + FunctionCode: []byte(code), + FunctionConfig: desc.FunctionSummary.FunctionConfig, + }) + if err != nil { + return fmt.Errorf("update function: %w", err) + } + log.Printf("INFO: function %q updated (sha256=%s)", name, sha256hex(code)) + + if _, err := svc.PublishFunction(ctx, &cloudfront.PublishFunctionInput{ + Name: aws.String(name), + IfMatch: up.ETag, + }); err != nil { + return fmt.Errorf("publish function: %w", err) + } + log.Printf("INFO: function %q published to LIVE", name) + return nil +} + +func sha256hex(s string) string { + sum := sha256.Sum256([]byte(s)) + return hex.EncodeToString(sum[:]) +} + +func awsV2Credentials() aws.CredentialsProvider { + return credentials.NewStaticCredentialsProvider( + getEnvOrSecret("AWS_ACCESS_KEY_ID"), + getEnvOrSecret("AWS_SECRET_ACCESS_KEY"), + getEnvOrSecret("AWS_SESSION_TOKEN"), + ) +} diff --git a/hack/releaser/cloudfront-function-redirects.js b/hack/releaser/cloudfront-function-redirects.js new file mode 100644 index 000000000000..c2cd5a6d7b14 --- /dev/null +++ b/hack/releaser/cloudfront-function-redirects.js @@ -0,0 +1,66 @@ +import cf from 'cloudfront'; + +const kvs = cf.kvs(); + +const redirectsPrefixes = {{.RedirectsPrefixesJSON}}; + +async function handler(event) { + const request = event.request; + const lookupKey = request.uri.replace(/\/$/, ''); + + if (lookupKey !== '') { + try { + const target = await kvs.get(lookupKey); + return { + statusCode: 301, + statusDescription: 'Moved Permanently', + headers: { location: { value: target } }, + }; + } catch (err) { + // not found in KVS — fall through + } + } + + for (let x in redirectsPrefixes) { + const rp = redirectsPrefixes[x]; + if (!request.uri.startsWith(`/${rp['prefix']}`)) { + continue; + } + let newlocation = '/'; + if (rp['strip']) { + const re = new RegExp(`(^/${rp['prefix']})`, 'gi'); + newlocation = request.uri.replace(re, '/'); + } + return { + statusCode: 301, + statusDescription: 'Moved Permanently', + headers: { location: { value: newlocation } }, + }; + } + + const headers = request.headers; + const acceptHeader = headers.accept ? headers.accept.value : ''; + const wantsMarkdown = acceptHeader.includes('text/markdown') || + acceptHeader.includes('text/plain'); + + let uri = request.uri; + const hasFileExtension = /\.[^/]*$/.test(uri.split('/').pop()); + + if (!hasFileExtension) { + if (wantsMarkdown) { + const stripped = uri.replace(/\/$/, ''); + uri = stripped === '' ? '/index.md' : stripped + '.md'; + } else { + if (!uri.endsWith('/')) { + uri += '/'; + } + uri += 'index.html'; + } + request.uri = uri; + } else if (wantsMarkdown && uri.endsWith('/index.html')) { + uri = uri === '/index.html' ? '/index.md' : uri.replace(/\/index\.html$/, '.md'); + request.uri = uri; + } + + return request; +} diff --git a/hack/releaser/env.json b/hack/releaser/env.json index d880d2ae27b6..bcf1e1a3070a 100644 --- a/hack/releaser/env.json +++ b/hack/releaser/env.json @@ -6,7 +6,9 @@ "DOCS_AWS_REGION": "us-east-1", "DOCS_S3_BUCKET": "labs-docs-docs.docker.com", "DOCS_CLOUDFRONT_ID": "E1MYDYF65FW3HG", - "DOCS_LAMBDA_FUNCTION_REDIRECTS": "DockerDocsRedirectFunction-labs" + "DOCS_LAMBDA_FUNCTION_REDIRECTS": "DockerDocsRedirectFunction-labs", + "DOCS_CLOUDFRONT_KVS_ARN": "", + "DOCS_CLOUDFRONT_FUNCTION_NAME": "" }, "refs/heads/main": { "HUGO_ENV": "production", @@ -15,6 +17,8 @@ "DOCS_AWS_REGION": "us-east-1", "DOCS_S3_BUCKET": "prod-docs-docs.docker.com", "DOCS_CLOUDFRONT_ID": "E228TTN20HNU8F", - "DOCS_LAMBDA_FUNCTION_REDIRECTS": "DockerDocsRedirectFunction-prod" + "DOCS_LAMBDA_FUNCTION_REDIRECTS": "DockerDocsRedirectFunction-prod", + "DOCS_CLOUDFRONT_KVS_ARN": "", + "DOCS_CLOUDFRONT_FUNCTION_NAME": "" } } diff --git a/hack/releaser/go.mod b/hack/releaser/go.mod index 3e67dbfc13c3..ed4be1a0d3d5 100644 --- a/hack/releaser/go.mod +++ b/hack/releaser/go.mod @@ -5,9 +5,25 @@ go 1.26.0 require ( github.com/alecthomas/kong v1.4.0 github.com/aws/aws-sdk-go v1.55.5 + github.com/aws/aws-sdk-go-v2 v1.41.7 + github.com/aws/aws-sdk-go-v2/config v1.32.17 + github.com/aws/aws-sdk-go-v2/credentials v1.19.16 + github.com/aws/aws-sdk-go-v2/service/cloudfront v1.63.0 + github.com/aws/aws-sdk-go-v2/service/cloudfrontkeyvaluestore v1.12.26 ) require ( + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.23 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.23 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.23 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.24 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.9 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.23 // indirect + github.com/aws/aws-sdk-go-v2/service/signin v1.0.11 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.30.17 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.21 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.42.1 // indirect + github.com/aws/smithy-go v1.25.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/hack/releaser/go.sum b/hack/releaser/go.sum index 8a68e163bf9f..c4e61403fde0 100644 --- a/hack/releaser/go.sum +++ b/hack/releaser/go.sum @@ -6,6 +6,38 @@ github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= github.com/aws/aws-sdk-go v1.55.5 h1:KKUZBfBoyqy5d3swXyiC7Q76ic40rYcbqH7qjh59kzU= github.com/aws/aws-sdk-go v1.55.5/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= +github.com/aws/aws-sdk-go-v2 v1.41.7 h1:DWpAJt66FmnnaRIOT/8ASTucrvuDPZASqhhLey6tLY8= +github.com/aws/aws-sdk-go-v2 v1.41.7/go.mod h1:4LAfZOPHNVNQEckOACQx60Y8pSRjIkNZQz1w92xpMJc= +github.com/aws/aws-sdk-go-v2/config v1.32.17 h1:FpL4/758/diKwqbytU0prpuiu60fgXKUWCpDJtApclU= +github.com/aws/aws-sdk-go-v2/config v1.32.17/go.mod h1:OXqUMzgXytfoF9JaKkhrOYsyh72t9G+MJH8mMRaexOE= +github.com/aws/aws-sdk-go-v2/credentials v1.19.16 h1:r3RJBuU7X9ibt8RHbMjWE6y60QbKBiII6wSrXnapxSU= +github.com/aws/aws-sdk-go-v2/credentials v1.19.16/go.mod h1:6cx7zqDENJDbBIIWX6P8s0h6hqHC8Avbjh9Dseo27ug= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.23 h1:UuSfcORqNSz/ey3VPRS8TcVH2Ikf0/sC+Hdj400QI6U= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.23/go.mod h1:+G/OSGiOFnSOkYloKj/9M35s74LgVAdJBSD5lsFfqKg= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.23 h1:GpT/TrnBYuE5gan2cZbTtvP+JlHsutdmlV2YfEyNde0= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.23/go.mod h1:xYWD6BS9ywC5bS3sz9Xh04whO/hzK2plt2Zkyrp4JuA= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.23 h1:bpd8vxhlQi2r1hiueOw02f/duEPTMK59Q4QMAoTTtTo= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.23/go.mod h1:15DfR2nw+CRHIk0tqNyifu3G1YdAOy68RftkhMDDwYk= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.24 h1:OQqn11BtaYv1WLUowvcA30MpzIu8Ti4pcLPIIyoKZrA= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.24/go.mod h1:X5ZJyfwVrWA96GzPmUCWFQaEARPR7gCrpq2E92PJwAE= +github.com/aws/aws-sdk-go-v2/service/cloudfront v1.63.0 h1:YNpvY2mAGhoTHPEvsqPuDb8K5JBjorbVMaitP8i4OXI= +github.com/aws/aws-sdk-go-v2/service/cloudfront v1.63.0/go.mod h1:brhMG/gR2xEB5lezxL2Cx+hqsEzGUn4LhNUtu7+ePFE= +github.com/aws/aws-sdk-go-v2/service/cloudfrontkeyvaluestore v1.12.26 h1:nHUJWEa2oFFRWJpTVjxZp2QiaQl89Z8O7rmHW/yeu+0= +github.com/aws/aws-sdk-go-v2/service/cloudfrontkeyvaluestore v1.12.26/go.mod h1:1HLozcnJWth+NZw49XJlluaQKcOQvkB+MKNiUx35qQI= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.9 h1:FLudkZLt5ci0ozzgkVo8BJGwvqNaZbTWb3UcucAateA= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.9/go.mod h1:w7wZ/s9qK7c8g4al+UyoF1Sp/Z45UwMGcqIzLWVQHWk= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.23 h1:pbrxO/kuIwgEsOPLkaHu0O+m4fNgLU8B3vxQ+72jTPw= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.23/go.mod h1:/CMNUqoj46HpS3MNRDEDIwcgEnrtZlKRaHNaHxIFpNA= +github.com/aws/aws-sdk-go-v2/service/signin v1.0.11 h1:TdJ+HdzOBhU8+iVAOGUTU63VXopcumCOF1paFulHWZc= +github.com/aws/aws-sdk-go-v2/service/signin v1.0.11/go.mod h1:R82ZRExE/nheo0N+T8zHPcLRTcH8MGsnR3BiVGX0TwI= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.17 h1:7byT8HUWrgoRp6sXjxtZwgOKfhss5fW6SkLBtqzgRoE= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.17/go.mod h1:xNWknVi4Ezm1vg1QsB/5EWpAJURq22uqd38U8qKvOJc= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.21 h1:+1Kl1zx6bWi4X7cKi3VYh29h8BvsCoHQEQ6ST9X8w7w= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.21/go.mod h1:4vIRDq+CJB2xFAXZ+YgGUTiEft7oAQlhIs71xcSeuVg= +github.com/aws/aws-sdk-go-v2/service/sts v1.42.1 h1:F/M5Y9I3nwr2IEpshZgh1GeHpOItExNM9L1euNuh/fk= +github.com/aws/aws-sdk-go-v2/service/sts v1.42.1/go.mod h1:mTNxImtovCOEEuD65mKW7DCsL+2gjEH+RPEAexAzAio= +github.com/aws/smithy-go v1.25.1 h1:J8ERsGSU7d+aCmdQur5Txg6bVoYelvQJgtZehD12GkI= +github.com/aws/smithy-go v1.25.1/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= From d34246de7d098d980c5eaeb7b71fd99fa8c7000f Mon Sep 17 00:00:00 2001 From: David Karlsson <35727626+dvdksn@users.noreply.github.com> Date: Wed, 13 May 2026 15:26:46 +0200 Subject: [PATCH 2/2] releaser: populate lab KVS ARN and CF function name in env.json Co-Authored-By: Claude Sonnet 4.6 --- hack/releaser/env.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hack/releaser/env.json b/hack/releaser/env.json index bcf1e1a3070a..a1e3821f5db4 100644 --- a/hack/releaser/env.json +++ b/hack/releaser/env.json @@ -7,8 +7,8 @@ "DOCS_S3_BUCKET": "labs-docs-docs.docker.com", "DOCS_CLOUDFRONT_ID": "E1MYDYF65FW3HG", "DOCS_LAMBDA_FUNCTION_REDIRECTS": "DockerDocsRedirectFunction-labs", - "DOCS_CLOUDFRONT_KVS_ARN": "", - "DOCS_CLOUDFRONT_FUNCTION_NAME": "" + "DOCS_CLOUDFRONT_KVS_ARN": "arn:aws:cloudfront::710015040892:key-value-store/cfbd85b1-0ea6-4f10-be98-5fb95932bb61", + "DOCS_CLOUDFRONT_FUNCTION_NAME": "docs-docker-com-redirects-labs" }, "refs/heads/main": { "HUGO_ENV": "production",