Skip to content

feat: complete iteration 0 RIE-free contract and tooling work - #5

Merged
Blind-Striker merged 30 commits into
masterfrom
feature/iteration0-aot-contract-tier
Aug 8, 2026
Merged

Blind-Striker merged 30 commits into
masterfrom
feature/iteration0-aot-contract-tier

Conversation

@Blind-Striker

@Blind-Striker Blind-Striker commented Jul 10, 2026

Copy link
Copy Markdown
Member

Summary

  • replace RIE-based coverage with Aspire and LocalStack-backed HTTP contract tests
  • add the file-based BadgeSmith CLI and migrate CI, Lambda build, ingestion, badge, and secret-seeding workflows
  • refresh .NET 10, Aspire, AWS, LocalStack, workflow actions, runners, Node.js, and CDK alignment
  • harden canonical HMAC authentication, upstream transport modes, test-result publishing, secret handling, and white-label URL behavior
  • separate production and LocalStack-only performance CDK apps
  • consolidate architecture, tooling, roadmap, performance, secret-safety, and agent guidance

Contract boundaries

  • Aspire Testing plus APIGatewayEmulator owns HTTP contract execution without Lambda RIE
  • LocalStack-backed tests use explicit Mock upstream mode; production and local-performance CDK artifacts use explicit Live mode
  • hosted CI builds and uploads the ARM64 Native AOT ZIP but does not execute that artifact as an AOT contract test
  • a future artifact smoke tier remains separate from this RIE-free contract scope
  • the badge action is remotely reusable; the test runner remains repository-local

Review remediation

  • restored warning-free Native AOT serializer compatibility
  • hard-cut canonical HMAC signing across API, tools, and tests
  • moved HMAC secrets out of process arguments and generated shell text
  • made optional test-report URLs fall back to the GitHub workflow run while preserving dorny or third-party HTTPS report targets
  • aligned transport exceptions with the opt-in fail-on-error policy
  • validated every secret mapping before AWS mutation, normalized identity fields, and enforced Secrets Manager name constraints
  • added explicit Live and Mock upstream contracts with HTTPS enforcement and fail-fast local configuration
  • refreshed action pins and fixed internal versus external action path ownership
  • addressed all human and Copilot review findings or documented the deliberate white-label HMAC trust boundary

Validation

  • local Release build: zero warnings and zero errors
  • local test suite: 437 passed, 0 failed, 0 skipped
  • targeted remediation tests: 74 passed
  • file-based CLI build, actionlint, Slopwatch, git diff check, production CDK synth, and local-performance CDK synth passed
  • hosted CI run 31254642321 passed build-and-test and ARM64 Native AOT ZIP build/upload on head ef216e9
  • no AWS deployment or release was performed

Review status

PR head is ef216e9. The branch is ready for final review and merge discussion.

- Add the Iteration 0 planning and research baseline: deep-dive code review findings,
  performance opportunities, roadmap wave mapping, AOT contract-tier design, execution
  handoff notes, and the initial Slopwatch baseline for pre-existing findings.
- Add contract-test infrastructure for local AWS-style execution, including shared
  Testcontainers setup, deterministic contract fixtures, HTTP client base URL overrides,
  and normalized override URL handling for WireMock-backed NuGet/GitHub flows.
- Expand active HTTP contract coverage across test-result ingestion, HMAC auth failure
  paths, test badges, redirects, NuGet package badges, GitHub package badges, upstream
  unauthorized/forbidden/not-found cases, missing GitHub secrets, routing, HEAD, CORS
  preflight, and response CORS headers.
- Make test-result contract data deterministic so repeated local and CI runs do not
  collide on run identifiers, timestamps, nonces, or stored DynamoDB state.
- Add and harden the k6 performance baseline tooling, including environment-driven
  configuration, Lambda response projection, RIE-safe validation, memory sampling via
  mstat export, and local smoke baseline capture.
- Replace the active RIE-based contract path with Aspire Testing plus
  APIGatewayEmulator, and move local benchmark execution to the LocalStack ZIP Lambda
  path with Function URL fallback where LocalStack Community API Gateway v2 support is
  insufficient.
- Record durable baseline evidence for the mock pre-iteration reference, final local
  LocalStack smoke, live direct API Gateway smoke, and live CloudFront comparison smoke;
  document that direct API Gateway is the Lambda/API baseline while CloudFront is only
  an edge-cache comparison.
- Update Aspire/agent handover notes so future work starts from the RIE-free contract
  and benchmark topology, with CloudWatch Lambda REPORT lines as the source of truth
  for Lambda duration, memory, and cold-start observations.
Squashes the W1.5 file-based tooling migration commits while preserving their intent:

- build: add file-based BadgeSmith tool foundation

- build: migrate lambda build script to file-based tool

- build: migrate test runner helper to file-based tool

- build: migrate badge update and ingestion tooling to C#

- refactor: complete hosted DI conversion for file-based tool

Also syncs the Slopwatch baseline after removing the standalone seeder project.
W1.7 Task 2: bump non-pinned PackageVersion entries to latest stable on NuGet.

Aspire / LocalStack.Aspire.Hosting / Aspire.Hosting.AWS pins from Task 1 (4cbc96b) preserved unchanged. Microsoft.Extensions.* and System.Text.Json kept on 10.x stable (10.0.9). No xUnit / BenchmarkDotNet prereleases taken.

Version table (old -> new):

  Amazon.JSII.Analyzers                       1.121.0          -> 1.138.0

  Meziantou.Analyzer                         2.0.264          -> 3.0.122

  Microsoft.CodeAnalysis.BannedApiAnalyzers   4.14.0           -> 5.6.0

  Microsoft.CodeAnalysis.NetAnalyzers         10.0.101         -> 10.0.301

  Microsoft.VisualStudio.Threading.Analyzers  17.14.15         -> 18.7.23

  SonarAnalyzer.CSharp                       10.17.0.131074   -> 10.28.0.143324

  xunit.analyzers                            1.26.0           -> 1.27.0

  AWSSDK.Core                                4.0.100.1        -> 4.0.100.3

  AWSSDK.DynamoDBv2                          4.0.10.4         -> 4.0.101.1

  AWSSDK.SecretsManager                      4.0.4.1          -> 4.0.100.3

  Amazon.CDK.Lib                             2.233.0          -> 2.261.0

  Amazon.Lambda.APIGatewayEvents             2.7.3            -> 3.0.0

  Amazon.Lambda.Core                         2.8.0            -> 3.1.1

  Amazon.Lambda.RuntimeSupport               1.14.1           -> 2.1.2

  Amazon.Lambda.Serialization.SystemTextJson 2.4.4            -> 3.0.0

  Amazon.Lambda.TestUtilities                3.0.1            -> 4.1.0

  AWSSDK.Extensions.NETCore.Setup            4.0.3.17         -> 4.0.100.3

  Microsoft.Extensions.Hosting               10.0.8           -> 10.0.9

  Microsoft.Extensions.Http                  10.0.8           -> 10.0.9

  Microsoft.Extensions.Caching.Memory        10.0.1           -> 10.0.9

  Microsoft.Extensions.Logging.Console       10.0.1           -> 10.0.9

  Microsoft.SourceLink.GitHub                8.0.0            -> 10.0.300

  System.Text.Json                           10.0.1           -> 10.0.9

  OpenTelemetry.Api                          1.14.0           -> 1.16.0

  OpenTelemetry.Instrumentation.AspNetCore   1.14.0           -> 1.16.0

  OpenTelemetry.Instrumentation.Runtime      1.15.1           -> 1.16.0

  CliWrap                                    3.6.0            -> 3.10.2

  Constructs                                 10.4.4           -> 10.6.0

  NuGet.Versioning                           7.0.1            -> 7.6.0

  ZLinq                                     1.5.4            -> 1.5.6

  Microsoft.NET.Test.Sdk                     18.0.1           -> 18.7.0

  Testcontainers                             4.12.0           -> 4.13.0

  Testcontainers.LocalStack                  4.12.0           -> 4.13.0

  xunit.v3                                   3.2.1            -> 3.2.2

  xunit.v3.runner.console                    3.2.1            -> 3.2.2

Unchanged (Task 1 pins preserved):

  Aspire.Hosting.AppHost     13.4.6

  Aspire.Hosting.AWS         13.3.1

  Aspire.Hosting.Testing     13.4.6

  LocalStack.Aspire.Hosting  13.4.0

  LocalStack.Client          2.0.0 (already latest stable)

  LocalStack.Client.Extensions 2.0.0 (already latest stable)

  Roslynator.Analyzers / CodeAnalysis / Formatting 4.15.0 (already latest)

  SecurityCodeScan.VS2019   5.6.7 (already latest)

  Spectre.Console.Cli(.Extensions.DependencyInjection|.Testing) 0.55.0 / 0.26.0 (latest)

  BenchmarkDotNet           0.15.8 (already latest)

  OneOf / OneOf.SourceGenerator 3.0.271 (already latest)

  Moq                       4.20.72 (already latest)

  xunit.runner.visualstudio  3.1.5 (already latest)

Compile fix: SonarAnalyzer 10.28 promotes S5332 (HTTP usage) to error. The CDK local-performance stack uses 'http://localstack:4566' as the LocalStack container endpoint inside the Docker network (HTTP-only by design). Added a scoped #pragma warning disable/restore S5332 at the call site with an explanatory comment; no behavior change.

Verification: dotnet restore + dotnet build BadgeSmith.sln -c Release (0 warn / 0 err); dotnet build tools/badgesmith.cs (ok); dotnet test Category=Unit (315 passed); dotnet test Category=Functional (28 passed, Docker available); slopwatch analyze clean.
@Blind-Striker

Copy link
Copy Markdown
Member Author

Pipeline validation result:

  • build-and-test: passed (350 tests)
  • continuous-deployment: failed during the ARM64 Native AOT publish
  • Root cause: Amazon.Lambda.Serialization.SystemTextJson 3.0.0 emits IL3053 AOT analysis warnings, which are blocking under the repository warnings-as-errors policy

Failed job: https://github.com/localstack-dotnet/badge-smith/actions/runs/29073897324/job/86302264987

The PR remains draft until this AOT compatibility issue and the listed review follow-ups are resolved.

- restore Native AOT serializer compatibility
- harden HMAC and white-label tooling contracts
- secure GitHub Actions and ARM artifact generation
- correct Aspire source-navigation guidance

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot wasn't able to review this pull request because it exceeds the maximum number of lines (20,000). Try reducing the number of changed lines and requesting a review from Copilot again.

@Blind-Striker
Blind-Striker marked this pull request as ready for review August 7, 2026 13:02
@Blind-Striker Blind-Striker self-assigned this Aug 7, 2026
Comment thread .github/workflows/update-test-badge/action.yml
Comment thread .github/workflows/update-test-badge/README.md
Comment thread build/BadgeSmith.CDK.LocalPerformance/Program.cs
Comment thread build/BadgeSmith.CDK/README.md Outdated

Do not use `--all` for production synth, diff, or deploy commands.

## Local performance app

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

this section is not relevant to this cdk app anymore move it to relevant one

@@ -0,0 +1,200 @@
---

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

delete all handover-prompts except for the template

Comment thread src/BadgeSmith.Host/Program.cs Outdated
}

var secretMappingConfigPath = Path.GetFullPath(Path.Combine(builder.AppHostDirectory, "..", "..", "tools", "organization-pat-mapping.json"));
if (File.Exists(secretMappingConfigPath))

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

this a a reason for throwing exception, without this system wouldnt work

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 152 out of 155 changed files in this pull request and generated 1 comment.

Suppressed comments (6)

tools/Commands/BadgeUpdateCommand.cs:87

  • Transport failures do not follow the advertised non-failing default. DNS, TLS, connection, and timeout failures throw here before settings.FailOnError is checked, so the global exception handler returns a nonzero exit even without --fail-on-error. Handle transport exceptions here (while preserving caller cancellation) and apply the same opt-in failure policy used for non-success HTTP responses.
    tools/Commands/BadgeUpdateCommand.cs:56
  • test_url_html is documented and declared optional, but omitting it serializes url_html as an empty string. TestResultsService.TryValidateTestPayload rejects any non-absolute UrlHtml (src/BadgeSmith.Api/Features/TestResults/TestResultsService.cs:162-167), so the default action invocation receives HTTP 400 and silently skips the badge update. Fall back to the workflow-run URL when this optional input is blank (and validate a supplied value).
    tools/Infrastructure/OrgSecretSeeder.cs:56
  • Each entry is validated only immediately before it is written. If a later entry is malformed, earlier Secrets Manager and DynamoDB mutations have already happened, leaving a partially applied configuration. Normalize all entries before entering the write loop so invalid configuration fails without any AWS mutation.
    tools/Infrastructure/OrgSecretSeeder.cs:101
  • These values are lowercased but not trimmed. A nonblank config value such as " test-org " passes validation and then produces a Secrets Manager name containing spaces (invalid in AWS) and DynamoDB keys that do not match runtime lookups. Trim each field before lowercasing it.
    src/BadgeSmith.Api/Features/TestResults/Handlers/TestResultIngestionHandler.cs:208
  • This broad catch now suppresses unexpected serialization/AOT failures without logging them. The outer HandleAsync catch already logs unexpected exceptions and returns a safe generic 500, so let non-JsonException failures propagate there; otherwise production parse failures become invisible to diagnostics.
    tests/BadgeSmith.Api.Tests/README.md:11
  • This states that the AOT artifact smoke tier is still future work, which conflicts with the PR title claiming the AOT contract tier is complete. The Aspire fixture exercises the project through APIGatewayEmulator, while CI only builds/uploads the Native AOT ZIP; no added test executes that artifact. Either add the artifact smoke coverage or rename/re-scope the PR so it does not claim completion of the AOT tier.

Comment thread tools/Commands/TestIngestCommand.cs Outdated
Comment on lines +101 to +103
[CommandOption("--secret")]
[Description("HMAC shared secret.")]
public string Secret { get; init; } = "";
@Blind-Striker Blind-Striker changed the title feat: complete iteration 0 AOT contract tier feat: complete iteration 0 RIE-free contract and tooling work Aug 8, 2026
@Blind-Striker
Blind-Striker merged commit 2b147de into master Aug 8, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants