Skip to content
76 changes: 76 additions & 0 deletions docs/platforms/dotnet/common/configuration/msbuild.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ However, we generally recommend the following:

You do not need to separately install Sentry CLI on your build server, as it is already provided by the Sentry NuGet package.

- If building inside a **Docker container**, use a [BuildKit secret](https://docs.docker.com/build/building/secrets/) to pass the auth token securely.
See [Building with Docker](#building-with-docker) below for a complete example.

## Configuration

In addition to authentication, you must configure your Sentry organization and project slugs.
Expand Down Expand Up @@ -259,3 +262,76 @@ them, be very careful that their values are not committed to source control or a
A more secure approach is to set authentication via environment variable or `~/.sentryclirc` file,

</Alert>

## Building with Docker

When building inside a Docker container, there are two things to handle: passing the auth token securely, and avoiding errors in multi-stage builds.

### Passing the Auth Token

Use Docker BuildKit's `--secret` flag to pass the auth token at build time. Unlike `ARG`/`ENV`, BuildKit secrets are never written to any image layer and do not appear in `docker history`.

Pass the secret when building the image:

```bash
docker build --secret id=sentry_auth_token,env=SENTRY_AUTH_TOKEN .
```

In your Dockerfile, add a [syntax directive](https://docs.docker.com/reference/dockerfile/#syntax) at the top, then mount the secret for the `RUN` instruction that performs the build:

```dockerfile
# syntax=docker/dockerfile:1

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Bug: The documentation overstates that # syntax=docker/dockerfile:1 "ensures" support for the env= option. This is not guaranteed for users with stale, cached Docker frontend images.
Severity: LOW

Suggested Fix

To improve accuracy, pin the Dockerfile syntax to a specific version that supports the env= feature, such as # syntax=docker/dockerfile:1.10. Alternatively, rephrase the documentation to clarify that docker/dockerfile:1 points to the latest stable version 1 syntax and that modern Docker installations are required for the env= feature to be available.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.

Location: docs/platforms/dotnet/common/configuration/msbuild.mdx#L283

Potential issue: The documentation states that using the `# syntax=docker/dockerfile:1`
directive "ensures" the Docker frontend supports the `env=` option for secrets. However,
`docker/dockerfile:1` is a floating tag. A user with a stale, cached version of this
image from before v1.10 (which introduced `env=`) could experience a build failure.
While this scenario is unlikely in practice, as most users will pull a recent version of
the image, the documentation's claim is technically inaccurate and could be misleading
in rare edge cases.

Also affects:

  • docs/platforms/dotnet/common/configuration/msbuild.mdx:312~312

...
RUN --mount=type=secret,id=sentry_auth_token,env=SENTRY_AUTH_TOKEN \
dotnet build "MyWebApp.csproj" --no-restore -c Release
```

The `env=` option (available since Dockerfile syntax v1.10) exposes the secret as the `SENTRY_AUTH_TOKEN` environment variable for the duration of that `RUN` instruction only — exactly what the Sentry CLI needs — without persisting it to a layer. The `# syntax=` directive ensures Docker uses a frontend that supports `env=`, regardless of the Docker Engine version.

<Alert>

BuildKit is enabled by default in Docker 23.0 and later. For older versions, set `DOCKER_BUILDKIT=1` in your environment before running `docker build`.

</Alert>

### Multi-Stage Dockerfiles

If your Dockerfile has separate stages for `dotnet build` and `dotnet publish` (a common pattern for ASP.NET Core apps), Sentry CLI only needs to run during the **build** stage, where the auth token is mounted.

By default, `dotnet publish` runs its own implicit build. That would invoke Sentry CLI again — and because the auth token is deliberately scoped to the build stage's `RUN` (so it never reaches the publish stage or the final image), the second run would fail. Pass `--no-build --no-restore` so `dotnet publish` reuses the build stage's output instead of recompiling, plus `-p:UseSentryCLI=false` as an extra safeguard:

```dockerfile
RUN dotnet publish "MyWebApp.csproj" -c Release -o /app/publish --no-build --no-restore -p:UseAppHost=false -p:UseSentryCLI=false

@Flash0ver Flash0ver Jul 9, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

note: technically, --no-build also implicitly sets the --no-restore flag, but I personally also prefer explicitness

```

### Complete Example

The following is a complete multi-stage Dockerfile for an ASP.NET Core app. It assumes `<SentryOrg>`, `<SentryProject>`, `<SentryUploadSymbols>`, and `<SentryUploadSources>` are configured in your `.csproj` or `Directory.Build.props`.

```dockerfile
# syntax=docker/dockerfile:1
# Build: docker build --secret id=sentry_auth_token,env=SENTRY_AUTH_TOKEN .
FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS base
WORKDIR /app
EXPOSE 8080

FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /src
COPY ["MyWebApp.csproj", "./"]
RUN dotnet restore "MyWebApp.csproj"
COPY . .

# The secret is available only for this RUN instruction and is never written to a layer.
# Sentry CLI runs here and uploads debug symbols as part of the build.
RUN --mount=type=secret,id=sentry_auth_token,env=SENTRY_AUTH_TOKEN \
dotnet build "MyWebApp.csproj" --no-restore -c Release

# Reuse the build output; --no-build avoids recompiling, which would re-run Sentry CLI without the auth token.
FROM build AS publish
RUN dotnet publish "MyWebApp.csproj" -c Release -o /app/publish --no-build --no-restore -p:UseAppHost=false -p:UseSentryCLI=false

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "MyWebApp.dll"]
```
Loading