diff --git a/src/infra/docs-lambda-changelog-scrubber/Program.cs b/src/infra/docs-lambda-changelog-scrubber/Program.cs index 58370a8bc3..c49d84c498 100644 --- a/src/infra/docs-lambda-changelog-scrubber/Program.cs +++ b/src/infra/docs-lambda-changelog-scrubber/Program.cs @@ -181,7 +181,7 @@ async Task CopyPassThrough(IAmazonS3 s3Client, string sourceBucket, string key, async Task ScrubContent(string key, string content, ILambdaContext context) { - var isBundlePath = key.Contains("/bundles/", StringComparison.OrdinalIgnoreCase); + var isBundlePath = key.Contains("/bundle/", StringComparison.OrdinalIgnoreCase); if (isBundlePath) return await ScrubBundle(content, context); diff --git a/src/infra/docs-lambda-changelog-scrubber/README.md b/src/infra/docs-lambda-changelog-scrubber/README.md index 9e22be860d..6ade40a790 100644 --- a/src/infra/docs-lambda-changelog-scrubber/README.md +++ b/src/infra/docs-lambda-changelog-scrubber/README.md @@ -37,6 +37,6 @@ The `bootstrap` binary should be available under: ## Scrubbing logic -- **Bundle files** (`{product}/bundles/*.yaml`): `LinkAllowlistSanitizer.TryApplyBundle` scrubs `prs`/`issues` lists -- **Changelog entries** (`{product}/changelogs/*.yaml`): `LinkAllowlistSanitizer.TryApplyChangelogEntry` scrubs `prs`, `issues`, `description`, `impact`, `action` +- **Bundle files** (`{product}/bundle/*.yaml`): `LinkAllowlistSanitizer.TryApplyBundle` scrubs `prs`/`issues` lists +- **Changelog entries** (`{product}/changelog/*.yaml`): `LinkAllowlistSanitizer.TryApplyChangelogEntry` scrubs `prs`, `issues`, `description`, `impact`, `action` - The allowlist is built once at cold start from the embedded `assembler.yml` via `BuildAllowReposFromAssembler` diff --git a/src/services/Elastic.Changelog/Uploading/ChangelogUploadService.cs b/src/services/Elastic.Changelog/Uploading/ChangelogUploadService.cs index 2c7f1bc838..0852dc9c87 100644 --- a/src/services/Elastic.Changelog/Uploading/ChangelogUploadService.cs +++ b/src/services/Elastic.Changelog/Uploading/ChangelogUploadService.cs @@ -133,7 +133,7 @@ internal IReadOnlyList DiscoverUploadTargets(IDiagnosticsCollector continue; } - var s3Key = $"{product}/changelogs/{fileName}"; + var s3Key = $"{product}/changelog/{fileName}"; targets.Add(new UploadTarget(filePath, s3Key)); } } @@ -200,7 +200,7 @@ internal IReadOnlyList DiscoverBundleUploadTargets(IDiagnosticsCol continue; } - var s3Key = $"{product}/bundles/{fileName}"; + var s3Key = $"{product}/bundle/{fileName}"; targets.Add(new UploadTarget(filePath, s3Key)); } } diff --git a/tests/Elastic.Changelog.Tests/Changelogs/LinkAllowlistSanitizerTests.cs b/tests/Elastic.Changelog.Tests/Changelogs/LinkAllowlistSanitizerTests.cs index b3cb5cc2a8..d93d7e5e05 100644 --- a/tests/Elastic.Changelog.Tests/Changelogs/LinkAllowlistSanitizerTests.cs +++ b/tests/Elastic.Changelog.Tests/Changelogs/LinkAllowlistSanitizerTests.cs @@ -534,7 +534,7 @@ public void TryApplyChangelogEntry_NullFields_PreservesNulls() public void TryApplyChangelogEntry_BarePrNumberWithoutDefaultRepo_KeptWithWarning() { // The scrubber Lambda calls TryApplyChangelogEntry with defaultRepo=null because per-entry - // YAMLs uploaded under {product}/changelogs/*.yaml carry no embedded repo context. A bare + // YAMLs uploaded under {product}/changelog/*.yaml carry no embedded repo context. A bare // numeric PR ref ("155500") must be tolerated rather than failing the whole entry — the // reference carries no repo identity so it cannot leak a private link, and downstream // rendering supplies the owner/repo from runtime context. diff --git a/tests/Elastic.Changelog.Tests/Uploading/ChangelogUploadServiceTests.cs b/tests/Elastic.Changelog.Tests/Uploading/ChangelogUploadServiceTests.cs index 90528f4b64..6a6fe8f7c5 100644 --- a/tests/Elastic.Changelog.Tests/Uploading/ChangelogUploadServiceTests.cs +++ b/tests/Elastic.Changelog.Tests/Uploading/ChangelogUploadServiceTests.cs @@ -65,7 +65,7 @@ public void DiscoverUploadTargets_SingleProduct_MapsToCorrectS3Key() targets.Should().HaveCount(1); targets[0].LocalPath.Should().Be(path); - targets[0].S3Key.Should().Be("elasticsearch/changelogs/entry.yaml"); + targets[0].S3Key.Should().Be("elasticsearch/changelog/entry.yaml"); _collector.Errors.Should().Be(0); } @@ -88,8 +88,8 @@ public void DiscoverUploadTargets_MultipleProducts_CreatesTargetPerProduct() var targets = _service.DiscoverUploadTargets(_collector, _changelogDir); targets.Should().HaveCount(2); - targets.Should().Contain(t => t.S3Key == "elasticsearch/changelogs/fix.yaml"); - targets.Should().Contain(t => t.S3Key == "kibana/changelogs/fix.yaml"); + targets.Should().Contain(t => t.S3Key == "elasticsearch/changelog/fix.yaml"); + targets.Should().Contain(t => t.S3Key == "kibana/changelog/fix.yaml"); } [Fact] @@ -154,8 +154,8 @@ public void DiscoverUploadTargets_MixedValidAndInvalidProducts_FiltersCorrectly( var targets = _service.DiscoverUploadTargets(_collector, _changelogDir); targets.Should().HaveCount(2); - targets.Should().Contain(t => t.S3Key == "elasticsearch/changelogs/mixed.yaml"); - targets.Should().Contain(t => t.S3Key == "kibana/changelogs/mixed.yaml"); + targets.Should().Contain(t => t.S3Key == "elasticsearch/changelog/mixed.yaml"); + targets.Should().Contain(t => t.S3Key == "kibana/changelog/mixed.yaml"); _collector.Warnings.Should().BeGreaterThan(0); } @@ -184,8 +184,8 @@ public void DiscoverUploadTargets_MultipleFiles_DiscoversBoth() var targets = _service.DiscoverUploadTargets(_collector, _changelogDir); targets.Should().HaveCount(2); - targets.Should().Contain(t => t.S3Key == "elasticsearch/changelogs/first.yaml"); - targets.Should().Contain(t => t.S3Key == "kibana/changelogs/second.yaml"); + targets.Should().Contain(t => t.S3Key == "elasticsearch/changelog/first.yaml"); + targets.Should().Contain(t => t.S3Key == "kibana/changelog/second.yaml"); } [Fact] @@ -205,8 +205,8 @@ public void DiscoverUploadTargets_ProductWithHyphensAndUnderscores_Accepted() var targets = _service.DiscoverUploadTargets(_collector, _changelogDir); targets.Should().HaveCount(2); - targets.Should().Contain(t => t.S3Key == "elastic-agent/changelogs/hyphen.yaml"); - targets.Should().Contain(t => t.S3Key == "cloud_hosted/changelogs/hyphen.yaml"); + targets.Should().Contain(t => t.S3Key == "elastic-agent/changelog/hyphen.yaml"); + targets.Should().Contain(t => t.S3Key == "cloud_hosted/changelog/hyphen.yaml"); _collector.Errors.Should().Be(0); _collector.Warnings.Should().Be(0); } @@ -245,7 +245,7 @@ public async Task Upload_WithValidChangelogs_UploadsToS3() _collector.Errors.Should().Be(0); A.CallTo(() => _s3Client.PutObjectAsync( - A.That.Matches(r => r.Key == "elasticsearch/changelogs/entry.yaml" && r.BucketName == "test-bucket"), + A.That.Matches(r => r.Key == "elasticsearch/changelog/entry.yaml" && r.BucketName == "test-bucket"), A._ )).MustHaveHappenedOnceExactly(); } @@ -375,7 +375,7 @@ public async Task Upload_BundleArtifactType_UploadsToS3() _collector.Errors.Should().Be(0); A.CallTo(() => _s3Client.PutObjectAsync( - A.That.Matches(r => r.Key == "elasticsearch/bundles/elasticsearch-9.2.0.yaml" && r.BucketName == "test-bucket"), + A.That.Matches(r => r.Key == "elasticsearch/bundle/elasticsearch-9.2.0.yaml" && r.BucketName == "test-bucket"), A._ )).MustHaveHappenedOnceExactly(); } @@ -405,7 +405,7 @@ public void DiscoverBundleUploadTargets_MapsToCorrectS3Key() var targets = _service.DiscoverBundleUploadTargets(_collector, bundleDir); targets.Should().HaveCount(1); - targets[0].S3Key.Should().Be("elasticsearch/bundles/elasticsearch-9.2.0.yaml"); + targets[0].S3Key.Should().Be("elasticsearch/bundle/elasticsearch-9.2.0.yaml"); _collector.Errors.Should().Be(0); } @@ -436,8 +436,8 @@ public void DiscoverBundleUploadTargets_MultipleProducts_CreatesTargetPerProduct var targets = _service.DiscoverBundleUploadTargets(_collector, bundleDir); targets.Should().HaveCount(2); - targets.Should().Contain(t => t.S3Key == "elasticsearch/bundles/stack-9.2.0.yaml"); - targets.Should().Contain(t => t.S3Key == "kibana/bundles/stack-9.2.0.yaml"); + targets.Should().Contain(t => t.S3Key == "elasticsearch/bundle/stack-9.2.0.yaml"); + targets.Should().Contain(t => t.S3Key == "kibana/bundle/stack-9.2.0.yaml"); } [Fact] diff --git a/tests/Elastic.Documentation.Integrations.Tests/S3/S3IncrementalUploaderTests.cs b/tests/Elastic.Documentation.Integrations.Tests/S3/S3IncrementalUploaderTests.cs index 604628e433..eb019a97b7 100644 --- a/tests/Elastic.Documentation.Integrations.Tests/S3/S3IncrementalUploaderTests.cs +++ b/tests/Elastic.Documentation.Integrations.Tests/S3/S3IncrementalUploaderTests.cs @@ -42,14 +42,14 @@ public async Task Upload_NewFile_UploadsSuccessfully() var uploader = CreateUploader(); var ct = TestContext.Current.CancellationToken; - var result = await uploader.Upload([new UploadTarget(path, "elasticsearch/changelogs/entry.yaml")], ct); + var result = await uploader.Upload([new UploadTarget(path, "elasticsearch/changelog/entry.yaml")], ct); result.Uploaded.Should().Be(1); result.Skipped.Should().Be(0); result.Failed.Should().Be(0); A.CallTo(() => _s3Client.PutObjectAsync( - A.That.Matches(r => r.Key == "elasticsearch/changelogs/entry.yaml" && r.BucketName == BucketName), + A.That.Matches(r => r.Key == "elasticsearch/changelog/entry.yaml" && r.BucketName == BucketName), A._ )).MustHaveHappenedOnceExactly(); } @@ -67,7 +67,7 @@ public async Task Upload_UnchangedFile_SkipsUpload() var uploader = CreateUploader(); var ct = TestContext.Current.CancellationToken; - var result = await uploader.Upload([new UploadTarget(path, "kibana/changelogs/entry.yaml")], ct); + var result = await uploader.Upload([new UploadTarget(path, "kibana/changelog/entry.yaml")], ct); result.Uploaded.Should().Be(0); result.Skipped.Should().Be(1); @@ -91,7 +91,7 @@ public async Task Upload_ChangedFile_UploadsNewVersion() var uploader = CreateUploader(); var ct = TestContext.Current.CancellationToken; - var result = await uploader.Upload([new UploadTarget(path, "elasticsearch/changelogs/entry.yaml")], ct); + var result = await uploader.Upload([new UploadTarget(path, "elasticsearch/changelog/entry.yaml")], ct); result.Uploaded.Should().Be(1); result.Skipped.Should().Be(0); @@ -112,7 +112,7 @@ public async Task Upload_S3PutFails_CountsAsFailure() var uploader = CreateUploader(); var ct = TestContext.Current.CancellationToken; - var result = await uploader.Upload([new UploadTarget(path, "elasticsearch/changelogs/entry.yaml")], ct); + var result = await uploader.Upload([new UploadTarget(path, "elasticsearch/changelog/entry.yaml")], ct); result.Uploaded.Should().Be(0); result.Skipped.Should().Be(0); @@ -129,12 +129,12 @@ public async Task Upload_MixedTargets_ReportsCorrectCounts() var unchangedEtag = Convert.ToHexStringLower(MD5.HashData("unchanged"u8.ToArray())); A.CallTo(() => _s3Client.GetObjectMetadataAsync( - A.That.Matches(r => r.Key == "es/changelogs/new.yaml"), + A.That.Matches(r => r.Key == "es/changelog/new.yaml"), A._ )).Throws(new AmazonS3Exception("Not Found") { StatusCode = HttpStatusCode.NotFound }); A.CallTo(() => _s3Client.GetObjectMetadataAsync( - A.That.Matches(r => r.Key == "es/changelogs/unchanged.yaml"), + A.That.Matches(r => r.Key == "es/changelog/unchanged.yaml"), A._ )).Returns(new GetObjectMetadataResponse { ETag = $"\"{unchangedEtag}\"" }); @@ -144,8 +144,8 @@ public async Task Upload_MixedTargets_ReportsCorrectCounts() var uploader = CreateUploader(); var ct = TestContext.Current.CancellationToken; var result = await uploader.Upload([ - new UploadTarget(newPath, "es/changelogs/new.yaml"), - new UploadTarget(unchangedPath, "es/changelogs/unchanged.yaml") + new UploadTarget(newPath, "es/changelog/new.yaml"), + new UploadTarget(unchangedPath, "es/changelog/unchanged.yaml") ], ct); result.Uploaded.Should().Be(1);