Skip to content

Add AddBunApp for Bun-native apps#17416

Merged
davidfowl merged 9 commits into
mainfrom
davidfowl/crispy-winner
May 25, 2026
Merged

Add AddBunApp for Bun-native apps#17416
davidfowl merged 9 commits into
mainfrom
davidfowl/crispy-winner

Conversation

@davidfowl
Copy link
Copy Markdown
Contributor

@davidfowl davidfowl commented May 23, 2026

Description

Adds an AddBunApp extension on IDistributedApplicationBuilder to Aspire.Hosting.JavaScript, parallel to the existing AddNodeApp. Bun-native apps typically run a TypeScript or JavaScript file directly (bun server.ts) rather than going through a package.json script, so this API takes a resource name, an app directory, and the entry script path.

This complements #17382, which renamed the package-script publish API to reflect that package-script publishing now covers npm, pnpm, Yarn, and Bun. AddBunApp is the matching direct-entrypoint shape for Bun, the same way AddNodeApp is for Node.

User-facing usage

C# AppHost:

var builder = DistributedApplication.CreateBuilder(args);

builder.AddBunApp("api", "./api", "server.ts")
       .WithHttpEndpoint(env: "PORT")
       .WithExternalHttpEndpoints();

// Or via a package.json script:
builder.AddBunApp("api", "./api", "server.ts")
       .WithRunScript("start");

builder.Build().Run();

TypeScript AppHost:

import { createBuilder } from './.aspire/modules/aspire.mjs';

const builder = await createBuilder();

await builder
    .addBunApp("api", "./api", "server.ts")
    .withHttpEndpoint({ env: "PORT" })
    .withExternalHttpEndpoints();

await builder.build().run();

Behavior

  • Defaults the Dockerfile build and runtime stages to oven/bun:1 (configurable via WithDockerfileBaseImage). Multi-stage build, bun install with a build-cache mount, USER bun (uid 1000 on the official image), NODE_ENV=production, and ENTRYPOINT ["bun", scriptPath].
  • Production-only dependencies in the runtime image: a dedicated prod-deps stage runs bun install --frozen-lockfile --production, the runtime stage copies node_modules from prod-deps and the application source from the build context (COPY . .). This mirrors the pattern in Bun's official Docker guide (https://bun.com/guides/ecosystem/docker) and ensures devDependencies do not leak into the final image.
  • .dockerignore is emitted alongside generated Dockerfiles using BuildKit's per-Dockerfile convention (<dockerfile-name>.dockerignore), keeping generated artifacts out of the user's source tree. To override, drop a .dockerignore at the build context root (next to package.json); Aspire skips/removes the generated sibling so BuildKit honors the user's file. See https://docs.docker.com/build/concepts/context/#filename-and-location.
  • WithBunDefaults wires up WithOtlpExporter, WithRequiredCommand("bun", "https://bun.sh/docs/installation"), NODE_ENV (Bun honors NODE_ENV — see https://bun.com/docs/runtime/env), and certificate trust. Certificate trust uses Bun's Node compatibility surface: Append scope maps to NODE_EXTRA_CA_CERTS and Override / System scopes set NODE_OPTIONS=--use-openssl-ca. Known limitation: Bun 1.3.10 and 1.3.14 still reject Aspire's injected self-signed localhost certificate for outgoing HTTPS requests with UNABLE_TO_VERIFY_LEAF_SIGNATURE, while curl --cacert and Node.js with NODE_EXTRA_CA_CERTS accept the same certificate. This dependency is tracked in Track Bun custom CA support for HTTPS OTLP export to Aspire Dashboard #17455.
  • Auto-applies WithBun() when a package.json exists in the app directory (parallel to AddNodeApp auto-applying WithNpm()).
  • OnBeforeStart swaps the run-mode command to the configured package manager when WithRunScript is set, so a user-selected manager (WithYarn, WithPnpm, …) is respected in run mode.

Supporting changes in core publishing

To keep generated artifacts contained to generated Dockerfile locations, this PR introduces a small additive API on DockerfileBuildAnnotation:

  • New string? BuildContextIgnoreContent { get; set; } property — when set, Aspire emits a per-Dockerfile <dockerfile-name>.dockerignore sibling next to generated Dockerfiles.
  • New EmitDockerfileArtifactsAsync(DockerfileFactoryContext context, string? dockerfilePath = null) method — materializes the generated Dockerfile, optionally copies it to the caller-provided output path, and writes/removes generated sibling files as needed. If the build context root already contains a user-authored .dockerignore, Aspire removes stale siblings only when their content matches the configured generated content, preserving user-authored per-Dockerfile overrides.

The emission is wired into direct image builds/DCP builds via DockerfileHelper, and copied publish outputs for manifest, Docker Compose, Kubernetes, and Azure publishers all call the same artifact-emission method with their destination Dockerfile path.

Validation

Unit + functional tests in tests/Aspire.Hosting.JavaScript.Tests:

  • AddBunAppTests (15 tests): manifest shape, Dockerfile generation with and without package.json, custom base image override, per-Dockerfile .dockerignore emission, stale generated sibling cleanup when a user-authored .dockerignore appears, package-manager auto-config, run script, command, argument validation, and certificate-trust callback wiring for Append and Override scopes.
  • BunFunctionalTests (2 tests, gated by [RequiresTools(["bun"])]): in-process Aspire app spins up two BunAppResource instances - direct file execution and WithRunScript("start") - against the real bun runtime, uses HTTP health checks for readiness, and verifies the served payloads.
  • Full Aspire.Hosting.JavaScript.Tests (157 tests), Aspire.Hosting.Docker.Tests (96 passed / 1 Windows-only skipped), DockerfileBuildAnnotation-focused tests (11 tests), and affected publisher builds pass.

Live end-to-end with the locally-built CLI against playground/AspireWithBun (TypeScript AppHost):

  • aspire run: both bunapp and bunscript resources report Running + Healthy; curl returns the expected payloads (Hello from bun! / Hello from bun script!).
  • aspire publish with addDockerComposeEnvironment("compose"): emits docker-compose.yaml, per-resource Dockerfiles using oven/bun:1, and aspire-output/bunapp.Dockerfile.dockerignore / aspire-output/bunscript.Dockerfile.dockerignore next to them. The user's BunFrontend/ directory is left clean — no .dockerignore is created in source.
  • aspire do --list-steps: pipeline step discovery succeeds for the playground.
  • aspire do build: builds both Bun images successfully. With a deliberately polluted local BunFrontend/node_modules/ms@99.0.0, the resulting image still contains ms@2.1.3 from prod-deps and no chalk devDependency, confirming the generated ignore is honored by the direct build path.
  • User-override path: after creating a BunFrontend/.dockerignore, re-running publish removes/skips Aspire-generated siblings so the user's file wins. User-authored per-Dockerfile siblings are preserved.
  • HTTPS certificate trust investigation: Aspire correctly injects NODE_EXTRA_CA_CERTS/NODE_OPTIONS, and Dashboard OTLP over HTTPS accepts the injected certificate with curl --cacert and Node.js. Bun 1.3.10 and 1.3.14 still fail the same request with UNABLE_TO_VERIFY_LEAF_SIGNATURE; follow-up issue Track Bun custom CA support for HTTPS OTLP export to Aspire Dashboard #17455 tracks the Bun dependency before adding a Bun-to-Dashboard HTTPS OTLP E2E test.

Checklist

  • Is this feature complete?
    • Yes. Ready to ship.
    • No. Follow-up changes expected.
  • Are you including unit tests for the changes and scenario tests if relevant?
    • Yes
    • No
  • Did you add public API?
    • Yes
      • If yes, did you have an API Review for it?
        • Yes
        • No
      • Did you add <remarks /> and <code /> elements on your triple slash comments?
        • Yes
        • No
    • No
  • Does the change make any security assumptions or guarantees?
    • Yes
      • If yes, have you done a threat model and had a security review?
        • Yes
        • No
    • No
  • Does the change require an update in our Aspire docs?
    • Yes
      • Link to aspire-docs issue:
    • No

- Add AddBunApp(name, appDirectory, scriptPath) and BunAppResource to
  Aspire.Hosting.JavaScript, parallel to AddNodeApp.
- Default Dockerfile uses oven/bun:1 for build and runtime stages with
  multi-stage build, bun install cache mount, USER bun, and ENTRYPOINT
  ["bun", scriptPath].
- WithBunDefaults wires OtlpExporter, RequiredCommand check, and
  NODE_ENV. Intentionally omits the Node cert-trust env hooks because
  Bun's CA story differs.
- AddBunApp auto-applies WithBun() when package.json is present.
- 11 unit tests in AddBunAppTests.cs and 2 real-bun functional tests
  in BunFunctionalTests.cs (gated by [RequiresTools(["bun"])]).
- TypeScript AppHost playground at playground/AspireWithBun exercises
  the API end-to-end with both direct file and WithRunScript('start')
  resources and a Docker Compose publish target.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 23, 2026 17:29
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 23, 2026

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 17416

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 17416"

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds first-class Bun support to Aspire.Hosting.JavaScript by introducing a new AddBunApp builder extension (parallel to AddNodeApp) and a corresponding BunAppResource, including Dockerfile generation defaults and coverage via unit + functional tests plus a TypeScript playground.

Changes:

  • Add AddBunApp and WithBunDefaults to model Bun-native “direct entry script” apps and generate publish-time Dockerfiles targeting oven/bun:1.
  • Introduce BunAppResource and validate behavior via new unit tests and Bun-gated functional tests.
  • Add a new TypeScript AppHost playground (playground/AspireWithBun) demonstrating run + publish flows.
Show a summary per file
File Description
tests/Aspire.Hosting.JavaScript.Tests/BunFunctionalTests.cs Adds Bun-gated functional tests validating direct execution vs package-script execution.
tests/Aspire.Hosting.JavaScript.Tests/BunAppFixture.cs Test fixture that boots two Bun resources and waits for readiness via HTTP probes.
tests/Aspire.Hosting.JavaScript.Tests/AddBunAppTests.cs Adds unit tests covering manifest shape, Dockerfile generation, package manager auto-detection, and argument validation.
src/Aspire.Hosting.JavaScript/JavaScriptHostingExtensions.cs Implements AddBunApp, Bun defaults, run-script behavior, and Bun Dockerfile generation.
src/Aspire.Hosting.JavaScript/BunAppResource.cs Introduces the new Bun resource type for the application model.
playground/AspireWithBun/tsconfig.json TypeScript config for the Bun playground AppHost.
playground/AspireWithBun/README.md Documents how to run the Bun playground and what to expect.
playground/AspireWithBun/package.json Declares deps/scripts for the TypeScript AppHost playground.
playground/AspireWithBun/package-lock.json Locks the playground npm dependencies.
playground/AspireWithBun/BunFrontend/server.ts Minimal Bun HTTP server used by the playground scenario.
playground/AspireWithBun/BunFrontend/package.json Defines the start script used by the package-script path.
playground/AspireWithBun/aspire.config.json Declares the TypeScript AppHost entrypoint and required packages.
playground/AspireWithBun/apphost.mts TypeScript AppHost exercising addBunApp for both direct and script-based execution.

Copilot's findings

Files not reviewed (1)
  • playground/AspireWithBun/package-lock.json: Language not supported
  • Files reviewed: 12/13 changed files
  • Comments generated: 1

Comment thread src/Aspire.Hosting.JavaScript/JavaScriptHostingExtensions.cs
@github-actions
Copy link
Copy Markdown
Contributor

Re-running the failed jobs in the CI workflow for this pull request because 1 job was identified as retry-safe transient failures in the CI run attempt.
GitHub was asked to rerun all failed jobs for that attempt, and the rerun is being tracked in the rerun attempt.
The job links below point to the failed attempt jobs that matched the retry-safe transient failure rules.

Matched test failure patterns (1 test)
  • Aspire.Cli.EndToEnd.Tests.KubernetesDeployBasicApiServiceTests.DeployK8sBasicApiService — Unable to access container registry during publish

Switch the AddBunApp runtime stage to Bun's recommended Dockerfile pattern
so that devDependencies are excluded from the final image and add
NODE_EXTRA_CA_CERTS / NODE_OPTIONS=--use-openssl-ca wiring so Bun apps
honor Aspire certificate trust configuration.

Dockerfile changes:
- Runtime stage now copies node_modules from the prod-deps stage and the
  application source from the build context (`COPY . .`), rather than
  copying /app wholesale from the build stage. Docker COPY --from has
  merge semantics that left dev dependencies in place after overlay.
- Emit a default .dockerignore next to the resource working directory
  (skipped when the user already has one) so `COPY . .` does not pull
  in node_modules, .aspire, aspire-output, dotenv files, etc.

Certificate trust:
- WithBunDefaults now calls WithCertificateTrustConfiguration. Append
  scope maps to NODE_EXTRA_CA_CERTS (supported in Bun 1.3+). Override
  and System scopes set NODE_OPTIONS=--use-openssl-ca so Bun uses the
  bundled / OS trust store.

Playground:
- BunFrontend now declares a prod dependency (`ms`) and a dev
  dependency (`chalk`) so the published image can be inspected to
  confirm dev deps are pruned.
- Commit the generated .dockerignore and bun.lock so `aspire publish`
  produces a build-context-safe image out of the box.

Tests:
- Update VerifyDockerfile snapshot to the new runtime layout.
- Add unit tests for the Append and Override cert-trust scopes.
- All 13 AddBunAppTests pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions
Copy link
Copy Markdown
Contributor

Re-running the failed jobs in the CI workflow for this pull request because 1 job was identified as retry-safe transient failures in the CI run attempt.
GitHub was asked to rerun all failed jobs for that attempt, and the rerun is being tracked in the rerun attempt.
The job links below point to the failed attempt jobs that matched the retry-safe transient failure rules.

…r-Dockerfile convention

Generated .dockerignore now lives next to the published Dockerfile in aspire-output/
as <resource>.Dockerfile.dockerignore (BuildKit per-Dockerfile ignore convention),
instead of being written into the user's source tree. This keeps generated artifacts
contained to aspire-output/ and leaves the user's package.json directory clean.

When the build context root already contains a user-authored .dockerignore, Aspire
skips emitting the per-Dockerfile sibling so the user's file is honored — BuildKit
gives per-Dockerfile ignore files precedence, so emitting both would silently
shadow a user override.

Changes:
- Add public BuildContextIgnoreContent property and EmitBuildContextIgnoreAsync
  method on DockerfileBuildAnnotation. The annotation already gates this API
  under [Experimental("ASPIREDOCKERFILEBUILDER001")].
- Call EmitBuildContextIgnoreAsync from ManifestPublishingContext and
  DockerComposePublishingContext after copying the Dockerfile to the output path.
- AddBunApp sets the default content on the annotation instead of writing into
  the source tree.
- Remove the previously committed playground/AspireWithBun/BunFrontend/.dockerignore
  so the playground exercises the default (no user file) path.
- Add unit tests covering default emission and user-override skip behavior.

Verified end-to-end with the playground:
- aspire publish emits bunapp.Dockerfile.dockerignore next to bunapp.Dockerfile.
- docker build honors the per-Dockerfile ignore (devDependencies excluded;
  user-polluted node_modules/ in BunFrontend not copied into the image).
- Re-publishing with a user-authored BunFrontend/.dockerignore does NOT write
  the per-Dockerfile sibling.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Ensure Bun's generated Docker ignore content is honored anywhere Aspire builds or publishes generated Dockerfiles:
- Emit the per-Dockerfile ignore next to materialized factory Dockerfiles for direct image builds and DCP build paths.
- Emit the copied-output sibling from Azure and Kubernetes publishers as well as manifest and Docker Compose.
- Remove stale copied-output siblings when a user-authored context-root .dockerignore is added later, so BuildKit does not keep shadowing the user's file.
- Avoid accumulating duplicate Docker Compose deployment target annotations when pipeline steps are resolved repeatedly.
- Use separate startup and readiness timeout budgets in the Bun functional test fixture.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add DockerfileBuildAnnotation.EmitDockerfileArtifactsAsync so callers provide a DockerfileFactoryContext and an optional destination Dockerfile path, and the annotation owns materializing the generated Dockerfile plus companion files such as the BuildKit per-Dockerfile .dockerignore.

Publishers now use the same method when copying generated Dockerfiles to output paths, while direct build paths use it without a destination path. This keeps the artifact emission flow future-proof as more generated Dockerfile companion files are added.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Member

@mitchdenny mitchdenny left a comment

Choose a reason for hiding this comment

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

Reviewed the PR. The Bun integration works end-to-end (aspire run + aspire publish + docker build all succeed, see the testing report comment below). A few concrete issues to consider:

  1. Flaky test pattern in BunAppFixture.WaitReadyStateAsync (single-shot HTTP probe with no retry).
  2. EmitDockerfileArtifactsAsync uses StringComparison.Ordinal to compare filesystem paths — case-insensitive FSes (Windows / default macOS) can trigger File.Copy from a file to itself.
  3. EmitBuildContextIgnoreAsync silently deletes any pre-existing <dockerfile>.dockerignore sibling when a context-root .dockerignore appears — including one the user authored themselves.
  4. In run-mode container image builds (ResourceContainerImageManager), the generated sibling .dockerignore is written next to the materialized Dockerfile in the user's source tree.

Inline comments below.

Comment thread tests/Aspire.Hosting.JavaScript.Tests/BunAppFixture.cs Outdated
Comment thread src/Aspire.Hosting/ApplicationModel/DockerfileBuildAnnotation.cs Outdated
Comment thread src/Aspire.Hosting/ApplicationModel/DockerfileBuildAnnotation.cs
Comment thread src/Aspire.Hosting/Utils/DockerfileHelper.cs
@mitchdenny
Copy link
Copy Markdown
Member

🧪 PR Testing Report

Smoke-tested the PR build end-to-end on macOS arm64 (Bun 1.3.14 + Docker Desktop).

CLI version verified: 13.4.0-pr.17416.gd5dd6606 matches PR head d5dd6606.

Scenarios

# Scenario Result
1 Dogfood CLI install (get-aspire-cli-pr.sh 17416 …) + --version match
2 aspire run on a temp copy of playground/AspireWithBun — both bunapp (bun server.ts) and bunscript (bun run start) reach up, endpoints return the expected greetings, aspire stop shuts cleanly
3 aspire publish emits bunapp.Dockerfile, bunscript.Dockerfile, sibling *.Dockerfile.dockerignore, and docker-compose.yaml; user BunFrontend/ tree is not polluted
4 DOCKER_BUILDKIT=1 docker build -f aspire-output/bunapp.Dockerfile … BunFrontend/ produces a working image; container responds Hello from bun!; prod-deps correctly ships only runtime deps (ms@2.1.3); USER bun, ENV NODE_ENV=production, ENTRYPOINT ["bun","server.ts"] all set

Notable observations

  • The TypeScript binding (addBunApp in apphost.mts) generated correctly from [AspireExport] and worked first try.
  • BuildKit picked up bunapp.Dockerfile.dockerignore as a sibling even though the build context is a sibling directory (BunFrontend/) rather than aspire-output/ — confirming the per-Dockerfile ignore convention works as the doc claims.
  • --frozen-lockfile is automatically added to bun install when bun.lock is present in the context — nice touch.
  • In the run-mode describe, Append-scope cert trust shows up correctly: NODE_EXTRA_CA_CERTS=/var/folders/.../bunapp-nxttmpwt/cert.pem and NODE_ENV=development (matching the dev environment).

Suggested follow-up: ACA deployment via live e2e

Local docker build exercises the build stage and docker run exercises the runtime stage, but neither validates that the generated Dockerfile + dockerignore flow round-trips through the Aspire.Hosting.Azure publishing path that this PR also refactored (EmitDockerfileArtifactsAsync in AzurePublishingContext.cs). The Compose dedup change in DockerComposeEnvironmentResource.AddOrReplaceDeploymentTargetAnnotation is similarly only exercised indirectly here.

Before merging, it would be worth piggy-backing on the existing live ACA e2e tests (the same suite that deploys other PublishAsDockerFile resources to Azure Container Apps) to deploy a Bun app, since that path:

  • exercises AzurePublishingContext.EmitDockerfileArtifactsAsync with the new sibling-dockerignore emission against a real Bicep + ACA deployment,
  • verifies the oven/bun:1 image actually pulls and runs on ACA's container runtime (which differs subtly from local Docker Desktop), and
  • exercises the new AddOrReplaceDeploymentTargetAnnotation path during the compose-resource phase that runs before Azure deployment.

Adding an ACA scenario for AddBunApp (parallel to the existing AddNodeApp ACA coverage, if any) would also catch any future regressions in the multi-stage Bun Dockerfile (e.g. USER bun ownership issues with mounted volumes).

Test artifacts

All evidence captured in transcript. Temp workspace cleaned up; built image and container removed.

- Use HTTP health checks and resource health waits in Bun functional tests instead of single-shot HTTP probes.
- Compare Dockerfile artifact paths with a platform-aware filesystem comparison.
- Preserve user-authored per-Dockerfile .dockerignore siblings when a context-root .dockerignore exists, only deleting siblings that match Aspire-generated content.
- Ignore generated *.Dockerfile.dockerignore siblings in Bun build contexts.
- Add focused Dockerfile artifact tests for these behaviors.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@davidfowl
Copy link
Copy Markdown
Contributor Author

Replying to #17416 (review):

Thanks, this is the generated PR overview and does not require a code change. I left it as-is.

@davidfowl
Copy link
Copy Markdown
Contributor Author

Replying to #17416 (review):

Accepted items 1-3 and partially accepted item 4. I added health-based readiness, platform-aware path comparison, preservation of user-authored per-Dockerfile ignore siblings, and focused coverage; for item 4, the AddBunApp generated Dockerfile is materialized outside the source tree, and I also added *.Dockerfile.dockerignore to the Bun build-context ignore defaults.

Remove the Docker Compose-only deployment target annotation replacement helper. Other deployment target preparers append annotations directly today, so this avoids making Docker Compose special in this PR.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@mitchdenny
Copy link
Copy Markdown
Member

Re-reviewed the two follow-up commits (f01cfb8e3, d6d86bb40). All three actionable findings from my earlier review are addressed cleanly:

# Finding Status
1 Flaky single-shot HTTP probe in BunAppFixture.WaitReadyStateAsync ✅ Now WaitForResourceHealthyAsync in parallel with WithHttpHealthCheck("/") wired up — proper readiness signal instead of racing the first GET.
2 StringComparison.Ordinal on filesystem paths in EmitDockerfileArtifactsAsync ✅ New PathEquals helper that uses OrdinalIgnoreCase on Windows/macOS and Ordinal on Linux. Test coverage added (EmitDockerfileArtifactsAsync_SkipsCopyWhenOutputPathCasingDiffersOnCaseInsensitiveFileSystem).
3 Silent deletion of user-authored sibling .dockerignore IsGeneratedBuildContextIgnoreAsync now compares the existing sibling against the content Aspire would generate and only deletes on an exact match. Both behaviors covered (…RemovesAspireOwnedPerDockerfileIgnoreWhenContextRootIgnoreExists and …PreservesUserPerDockerfileIgnoreWhenContextRootIgnoreExists). XML doc rewritten to match the new semantics.

The Compose AddOrReplaceDeploymentTargetAnnotation dedup helper was reverted in d6d86bb40 — "Keep Docker Compose deployment target behavior consistent". Reasonable scope-tightening since that drive-by wasn't required by the Bun work; happy to see it pulled out of this PR.

One small extra: adding *.Dockerfile.dockerignore to the Node defaults' baked-in .dockerignore is a nice defense-in-depth against any stray sibling file ending up in a future build context.

Finding #4 (run-mode source-tree pollution) — note, not blocking

My fourth finding was about DockerfileHelper.cs:35 writing the per-Dockerfile .dockerignore next to the user's source Dockerfile during run-mode container builds. DockerfileHelper.cs is not modified in these commits, so the sibling file is still written into the user's source tree during run-mode. However, with finding #3 now properly distinguishing generated vs. user content, the worst-case impact (clobbering a hand-written sibling) is gone. The remaining concern is purely cosmetic — an extra file appearing in git status. Worth a follow-up issue but not a merge blocker.

CI

The failing Tests / Hosting.DotnetTool / Hosting.DotnetTool (windows-latest) job exits with -1073741502 (Windows STATUS_DLL_INIT_FAILED) which looks like an infrastructure / hang-dump situation, and Final Test Results is reporting digest-mismatch on log-artifact downloads — neither appears related to this PR. A rerun would confirm.

LGTM to merge after CI is green. The ACA live-deployment suggestion from the previous testing report still stands as good follow-up validation but isn't a blocker.

Replace inline string and contains assertions for generated manifest, Dockerfile, and dockerignore content with Verify snapshots so changes are reviewed as full artifacts.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Record that Bun 1.3.10 and 1.3.14 currently reject Aspire's injected self-signed localhost certificate for outgoing HTTPS requests even though curl and Node accept the same certificate. Link the tracking issue from the certificate trust comments.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions
Copy link
Copy Markdown
Contributor

CLI E2E Tests unknown — 96 passed, 0 failed, 5 unknown (commit e30d577)

View all recordings
Status Test Recording
AddPackageInteractiveWhileAppHostRunningDetached ▶️ View recording
AddPackageWhileAppHostRunningDetached ▶️ View recording
AgentCommands_AllHelpOutputs_AreCorrect ▶️ View recording
AgentInitCommand_DefaultSelection_InstallsDefaultSkills ▶️ View recording
AgentInitCommand_MigratesDeprecatedConfig ▶️ View recording
AgentMcpListStructuredLogsFromStarterAppCore ▶️ View recording
AllPublishMethodsBuildDockerImages ▶️ View recording
AspireAddPackageVersionToDirectoryPackagesProps ▶️ View recording
AspireInitSingleFileAppHostRunsViaDotnetRunAppHost ▶️ View recording
AspireInitWithExistingAppHostDirRecreatesMissingNuGetConfigAndPreservesFiles ▶️ View recording
AspireInitWithSolutionFileGeneratesAppHostThatBuildsAgainstChannelHive ▶️ View recording
AspireStartUpdatesStaleTypeScriptAppHostPath ▶️ View recording
AspireUpdateRemovesAppHostPackageVersionFromDirectoryPackagesProps ▶️ View recording
AspireUpdateRemovesOrphanAppHostPackageVersionWhenSdkAlreadyCurrent ▶️ View recording
Banner_DisplayedOnFirstRun ▶️ View recording
Banner_DisplayedWithExplicitFlag ▶️ View recording
Banner_NotDisplayedWithNoLogoFlag ▶️ View recording
CertificatesClean_RemovesCertificates ▶️ View recording
CertificatesTrust_WithNoCert_CreatesAndTrustsCertificate ▶️ View recording
CertificatesTrust_WithUntrustedCert_TrustsCertificate ▶️ View recording
ConfigSetGet_CreatesNestedJsonFormat ▶️ View recording
CreateAndRunAspireStarterProject ▶️ View recording
CreateAndRunAspireStarterProjectWithBundle ▶️ View recording
CreateAndRunEmptyAppHostProject ▶️ View recording
CreateAndRunJavaEmptyAppHostProject ▶️ View recording
CreateAndRunJsReactProject ▶️ View recording
CreateAndRunPythonReactProject ▶️ View recording
CreateAndRunTypeScriptEmptyAppHostProject ▶️ View recording
CreateAndRunTypeScriptStarterProject ▶️ View recording
CreateJavaAppHostWithViteApp ▶️ View recording
CreateTypeScriptAppHostWithViteApp_UsesConfiguredToolchain ▶️ View recording
DashboardRunWithAgentMcpCore ▶️ View recording
DashboardRunWithOtelTracesReturnsNoTracesCore ▶️ View recording
DeployK8sBasicApiService ▶️ View recording
DeployK8sWithExternalHelmChart ▶️ View recording
DeployK8sWithGarnet ▶️ View recording
DeployK8sWithMongoDB ▶️ View recording
DeployK8sWithMySql ▶️ View recording
DeployK8sWithPostgres ▶️ View recording
DeployK8sWithRabbitMQ ▶️ View recording
DeployK8sWithRedis ▶️ View recording
DeployK8sWithSqlServer ▶️ View recording
DeployK8sWithValkey ▶️ View recording
DeployTypeScriptAppToKubernetes ▶️ View recording
DescribeCommandResolvesReplicaNames ▶️ View recording
DescribeCommandShowsRunningResources ▶️ View recording
DetachFormatJsonProducesValidJson ▶️ View recording
DetachFormatJsonProducesValidJsonWhenRestartingExistingInstance ▶️ View recording
DoListStepsShowsPipelineSteps ▶️ View recording
DocsCommand_RendersInteractiveMarkdownFromLocalSource ▶️ View recording
DoctorCommand_DetectsDeprecatedAgentConfig ▶️ View recording
DoctorCommand_TypeScriptAppHostReportsMissingConfiguredToolchain ▶️ View recording
DoctorCommand_WithSslCertDir_ShowsTrusted ▶️ View recording
DoctorCommand_WithoutSslCertDir_ShowsPartiallyTrusted ▶️ View recording
GeneratedAspireDevScript_StartsWatchMode_WithConfiguredToolchain ▶️ View recording
GlobalMigration_HandlesCommentsAndTrailingCommas ▶️ View recording
GlobalMigration_HandlesMalformedLegacyJson ▶️ View recording
GlobalMigration_PreservesAllValueTypes ▶️ View recording
GlobalMigration_SkipsWhenNewConfigExists ▶️ View recording
GlobalSettings_MigratedFromLegacyFormat ▶️ View recording
InitTypeScriptAppHost_AugmentsExistingViteRepoAtRoot ▶️ View recording
InteractiveCSharpInitCreatesExpectedFiles ▶️ View recording
InvalidAppHostPathWithComments_IsHealedOnRun ▶️ View recording
JavaScriptHostingApisRunFromTypeScriptAppHost ▶️ View recording
LatestCliCanStartStableChannelAppHost ▶️ View recording
LatestCliCanStartStableChannelTypeScriptAppHost ▶️ View recording
LegacySettingsMigration_AdjustsRelativeAppHostPath ▶️ View recording
LogLevelTrace_ProducesTraceEntriesInCliLogFile ▶️ View recording
LogsCommandShowsResourceLogs ▶️ View recording
OtelLogsReturnsStructuredLogsFromStarterApp ▶️ View recording
OtelLogsReturnsStructuredLogsFromStarterAppIsolated ▶️ View recording
PsCommandListsRunningAppHost ▶️ View recording
PsFormatJsonOutputsOnlyJsonToStdout ▶️ View recording
PublishJavaScriptPatternsGeneratesExpectedDockerComposeArtifacts ▶️ View recording
PublishWithConfigureEnvFileUpdatesEnvOutput ▶️ View recording
PublishWithDockerComposeServiceCallbackSucceeds ▶️ View recording
PublishWithoutOutputPathUsesAppHostDirectoryDefault ▶️ View recording
ResourceCommand_FailedExecution_DisplaysAppHostLogPathAndLogContainsEntries ▶️ View recording
ResourceCommand_FailsWhenInteractionServiceIsRequired ▶️ View recording
ResourceCommand_SetAndDeleteParameterUpdatesDescribeOutput ▶️ View recording
RestoreGeneratesSdkFiles ▶️ View recording
RestoreGeneratesSdkFiles_WithConfiguredToolchain ▶️ View recording
RestoreRefreshesGeneratedSdkAfterAddingIntegration ▶️ View recording
RestoreSupportsConfigOnlyHelperPackageAndCrossPackageTypes ▶️ View recording
RunFromParentDirectory_UsesExistingConfigNearAppHost ▶️ View recording
RunPublishFailureScenarioAsync ▶️ View recording
RunReportsSyntaxErrorsForDotNetAppHost ▶️ View recording
RunReportsSyntaxErrorsForTypeScriptAppHost ▶️ View recording
SecretCrudOnDotNetAppHost ▶️ View recording
SecretCrudOnTypeScriptAppHost ▶️ View recording
StagingChannel_ConfigureAndVerifySettings_ThenSwitchChannels ▶️ View recording
StartAndWaitForTypeScriptSqlServerAppHostWithNativeAssets ▶️ View recording
StartReportsSyntaxErrorsForDotNetAppHost ▶️ View recording
StartReportsSyntaxErrorsForTypeScriptAppHost ▶️ View recording
StopAllAppHostsFromAppHostDirectory ▶️ View recording
StopJavaPolyglotAppHostUsingApphostDirectory ▶️ View recording
StopNonInteractiveSingleAppHost ▶️ View recording
StopTypeScriptPolyglotAppHostUsingApphostDirectory ▶️ View recording
StopWithNoRunningAppHostExitsSuccessfully ▶️ View recording
UnAwaitedChainsCompileWithAutoResolvePromises ▶️ View recording
UpdateProjectChannelToStable_TypeScript_PicksUpStablePackages ▶️ View recording

📹 Recordings uploaded automatically from CI run #26377256994

@davidfowl davidfowl merged commit d170676 into main May 25, 2026
616 of 619 checks passed
@github-actions github-actions Bot added this to the 13.4 milestone May 25, 2026
@aspire-repo-bot
Copy link
Copy Markdown
Contributor

✅ No documentation update needed.

Documentation changes are needed (docs_required: new_public_type, pr_body_has_user_facing_section) but the automated PR creation tool failed with an infrastructure error (safeoutputs create_pull_request could not find commits in the _repos/aspire.dev subdirectory).

Prepared changes (commit e3c3e34 on branch add-bun-app-docs in _repos/aspire.dev):

  • Updated src/frontend/src/content/docs/integrations/frameworks/javascript.mdx to add BunAppResource to the resource types list and a new "Add Bun application" section documenting AddBunApp / addBunApp, WithRunScript, publish defaults (oven/bun:1, prod-deps stage, .dockerignore sibling), and certificate trust behavior.

A manual docs PR targeting release/13.4 on microsoft/aspire.dev is required to cover the new AddBunApp API.

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.

3 participants