Publishers crash or silently drop resources when references cross resource boundaries
Nobody has claimed this yet.
- Dominant language
- C#
- Stars
- 6.3k
- Forks
- 991
- Avg merge
- 2d 12h
- Merged PRs (30d)
- 201
Description
## Problem
Publishers crash or silently drop resources when references cross resource boundaries. This affects **all** compute environment implementations:
- **Docker Compose** (`DockerComposeInfrastructure`)
- **Azure Container Apps** (`AzureContainerAppsInfrastructure`)
- **Azure App Service**
- **Kubernetes**
- **Any 3rd-party implementation** that follows the same `BeforeStart` + `GetComputeResources` + `ResourceMapping` pattern
The root pattern is broken and needs to change.
### Root cause
All publishers follow the same pattern:
1. Subscribe to `BeforeStartEvent`
2. Iterate `GetComputeResources()` (which filters out build-only, excluded, cross-environment resources)
3. Build a `ResourceMapping` dictionary from only those filtered resources
4. Resolve environment variables — which can reference ANY resource, including filtered ones
5. 💥 `KeyNotFoundException` when a callback references a resource not in the mapping
`GetComputeResources()` makes a premature decision about which resources matter. It conflates "should this resource be deployed" with "should this resource exist in the resolution graph." These are different questions.
### Affected publishers
| Publisher | Mapping | Crash site |
|-----------|---------|------------|
| Docker Compose | `DockerComposeEnvironmentResource.ResourceMapping` | `DockerComposeServiceResourceExtensions.ProcessValueAsync:22` |
| Azure Container Apps | `ContainerAppEnvironmentContext._containerApps` | `BaseContainerAppContext:227` |
| Azure App Service | Similar pattern | Similar crash |
| Kubernetes | Similar pattern | Similar crash |
| 3rd-party | Anyone using `GetComputeResources()` | Same |
### Scenario 1: Build-only container referenced by another resource
A JavaScript app without a `PublishAs*` method is build-only. When another resource references it, the publisher crashes.
```csharp
var frontend = builder.AddViteApp("frontend", "./frontend")
.WithHttpEndpoint(name: "http", targetPort: 3000);
builder.AddContainer("api", "apiimage")
.WithReference(frontend.GetEndpoint("http"));
```
**Result**: `KeyNotFoundException` during `publish-compose` step.
### Scenario 2: Excluded resource referenced by another resource
```csharp
var excluded = builder.AddContainer("auth", "authimage")
.WithHttpEndpoint(name: "http", targetPort: 8080)
.ExcludeFromManifest();
builder.AddContainer("api", "apiimage")
.WithReference(excluded.GetEndpoint("http"));
```
**Result**: `KeyNotFoundException` — excluded resource not in mapping.
### Scenario 3: Cross-environment resource referenced
```csharp
var compose1 = builder.AddDockerComposeEnvironment("compose1");
var compose2 = builder.AddDockerComposeEnvironment("compose2");
var db = builder.AddContainer("db", "postgres")
.WithHttpEndpoint(name: "http", targetPort: 5432)
.WithComputeEnvironment(compose2);
builder.AddContainer("api", "apiimage")
.WithComputeEnvironment(compose1)
.WithReference(db.GetEndpoint("http"));
```
**Result**: `KeyNotFoundException` — `db` not in `compose1`'s mapping.
### Scenario 4: Build-only container with no consumer (silent omission)
```csharp
// User forgot .PublishAsStaticWebsite()
builder.AddViteApp("frontend", "./frontend")
.WithExternalHttpEndpoints();
builder.AddContainer("api", "apiimage");
```
**Result**: `PIPELINE SUCCEEDED` ✅ but `frontend` is silently missing from output. No error.
### Proposed fix
**Dependent on #11787** — infrastructure processing runs in `BeforeStartEvent`, which is too early.
We need to change the pattern that all publishers follow:
1. **Move infrastructure processing from `BeforeStart` into pipeline steps** — proper ordering, other subscribers can add annotations first
2. **Build the full resource mapping** — ALL resources get registered (endpoints only), not just compute resources. References never crash.
3. **Separate "resolvable" from "deployable"** — all resources are resolvable (in the mapping), only compute resources are deployable (get `DeploymentTargetAnnotation`, appear in output)
4. **Validate the resource graph** — after resolution, check for invalid states:
- Build-only resource not consumed and not explicitly excluded → error with actionable message
- Excluded resource referenced by a deployable resource → error with actionable message
5. **Update all publishers** — Docker Compose first, then replicate to ACA, App Service, K8s
6. **Document the pattern** for 3rd-party implementors
### Test cases
4 test cases on branch `davidfowl/fix-resource-exclusion` in `DockerComposeResourceExclusionTests.cs`:
- `ReferencedResourceExcludedFromPublish_ShouldNotCrash`
- `ReferencedResourceTargetingDifferentEnvironment_ShouldNotCrash`
- `ReferencedBuildOnlyContainer_ShouldNotCrash`
- `UnreferencedBuildOnlyContainer_ShouldFailWithClearError`
### Related
- Depends on: #11787 (BeforeStartEvent is too early for infrastructure processing)
- JavaScript pits of failure: https://aspire.dev/deployment/javascript-apps/#pits-of-failure
- Branch with WIP fix + tests: `davidfowl/fix-resource-exclusion`
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with DockerComposeResourceExclusionTests.cs on the davidfowl/fix-resource-exclusion branch and inspect the BeforeStart, GetComputeResources, and ResourceMapping paths described in the issue. Compare the Docker Compose behavior with the Azure Container Apps, Azure App Service, and Kubernetes publisher patterns, keeping #11787 in view. Done means the named scenarios no longer crash or silently omit resources, with clear validation and corresponding publisher coverage.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- azure, csharp, docker-compose, kubernetes
- Domain
- cloud, devops, infrastructure
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100