# Fix Failing GitHub Actions Checks in an ASP.NET Core App

Yes. When your .NET build goes red, an agent reads the failed job's log, reruns the same dotnet test or format command, fixes the cause and opens a pull request.

[Run this on Rush](https://cloud.getrush.ai/run/fix-failing-ci/aspnet-core/), in a Project that has your repository.

## What the agent does

The agent reads the failure before the code. From the `workflow_run` event it runs `gh run view <run id> --log-failed` and names the workflow and step. In a repository like bitwarden/server that matters, because three workflows can go red for different reasons: `test.yml` runs `dotnet test ./test --configuration Debug` with a `trx` logger and Coverlet, then the same for `./bitwarden_license/test`; `build.yml` starts with a `Lint` job that runs `dotnet format --verify-no-changes` before it publishes each project; and `test-database.yml` starts the databases with Docker Compose, checks `dotnet ef migrations has-pending-model-changes` for MySQL, PostgreSQL and SQLite, runs the migrators and then tests `Infrastructure.IntegrationTest`. A formatting failure, a pending-model-changes failure and a failed xUnit fact each need a different fix, and the agent quotes the block that says which.

Then it matches the toolchain. `global.json` pins SDK 10.0.103 with `rollForward: latestFeature`, `Directory.Build.props` targets `net10.0` and sets xUnit 2.6.6, NSubstitute 5.1.0, AutoFixture 4.18.1 and Coverlet 6.0.0, and `test.yml` installs a Rust toolchain (1.97.1) before testing because a dependency builds native code. `test/Bitwarden.Tests.proj` is a Traversal project over every test project, so `dotnet test ./test` runs them all; the agent instead runs the one project the log names with a filter, such as `dotnet test test/Api.Test --configuration Debug --filter "FullyQualifiedName~CiphersControllerTests"`, so the failure is on record in seconds rather than after the whole suite.

With the failure reproduced it reads what the test covers. For the vault API that is `src/Api/Vault/Controllers/CiphersController.cs`, whose actions `Get`, `GetDetails`, `GetAll`, `Post`, `PostCreate`, `Put`, `PutAdmin` and the `organization-details` family are tested in `test/Api.Test/Vault/Controllers/CiphersControllerTests.cs` next to `SyncControllerTests.cs` and `FoldersControllerTests.cs`, with `SutProvider` and the `BitAutoData` attributes from `test/Common` building the controller and its substitutes. For identity it is `src/Identity/IdentityServer/RequestValidators/`, where `BaseRequestValidator`, `ResourceOwnerPasswordValidator`, `CustomTokenRequestValidator`, `DeviceValidator`, `TwoFactorAuthenticationValidator` and `WebAuthnGrantValidator` are covered by the unit tests in `test/Identity.Test/IdentityServer/` and by `test/Identity.IntegrationTest`, whose `IdentityServerTests.cs` and `RefreshTokenGrantTests.cs` drive the token endpoint through a `WebApplicationFactory` on an in-memory SQLite database as `test/INTEGRATION_TEST.md` describes. The agent reads the commit that broke the job too, because the fix belongs where that commit changed behavior.

The fix goes in `src/`. A test is changed only when the test is wrong, and the pull request says so; an AutoFixture customization is changed only when the generated data no longer matches the model. Before pushing, the agent runs the whole project it changed, then `dotnet format --verify-no-changes` on the solution, and when the change touched an Entity Framework model, `dotnet ef migrations has-pending-model-changes` for each provider the database workflow checks, so a green test job is not followed by a red lint or database job.

## Start it with one API call

`POST https://api.prix.dev/o/{org}/sessions`

```json
{
  "agent": "claude",
  "input": "The GitHub Actions workflow on this branch failed; the workflow_run event is at the end of this prompt. Read the failed job's log with gh run view <run id> --log-failed, name the workflow and step that failed (a dotnet test project, dotnet format, or a pending-model-changes check), and quote the failing test or diagnostic. Install the SDK that global.json names and run the failing test project alone with --configuration Debug and a --filter on the failing class first, so the failure is reproduced before any change. Fix the cause in src/ (change a test or an AutoFixture customization only if it is wrong, and say so), then rerun that project, run dotnet format --verify-no-changes, and if you touched an EF model run dotnet ef migrations has-pending-model-changes for each provider. Open a pull request against the failing branch that quotes the error it fixed.\n\nEvent: <workflow_run payload>",
  "resources": [
    {
      "url": "https://github.com/your-org/your-app"
    }
  ]
}
```

1. **Get an API key.** In the console, open Settings, then API keys, and create a key for your org. Send it in the Authorization header as a Bearer token.
2. **Send the request.** POST the body in request.json to https://api.prix.dev/o/{org}/sessions, with your repository as the resources URL. The run starts in its own cloud sandbox.
3. **Read what came back.** Follow the run on its live stream or wait for the run.completed webhook, then read the result and its trajectory.

## What comes back

A pull request against the failing branch, with the fix in the controller, validator or model the test covers and the workflow, step and quoted failure in the description. It shows the filtered test failing and then passing, then the whole project, then `dotnet format --verify-no-changes`, and lists every command the agent ran; the session's trajectory keeps each with its output. The test and build workflows rerun on the pull request.

When the failing step is `has-pending-model-changes`, the pull request adds the migration for each provider the workflow checks and the description names the model change that required it. When the failure comes from the `bitwarden_license` tests, the agent says whether it could run them in its sandbox. When there is no code cause, it opens nothing and its answer explains what the log shows.

A reviewer checks that a validator change still refuses what it refused before, that an edited test was really wrong, that no `[Fact]` was skipped, and that `global.json`, `Directory.Build.props` and the workflows are untouched.

## Run it on every failed .NET test run

Add an automation to the Project with this prompt and a `github` trigger on `workflow_run.failure`; each failed run of the `Testing` or `Build` workflow starts one run with the event under the prompt, and only work by owners, members and collaborators fires it. Or send GitHub's `workflow_run` webhook to your own server and send this request with `https://github.com/<owner>/<repo>/tree/<head_branch>` as the resource.

Exclude the agent's own branches so a failed fix does not trigger itself, keep each `workflow_run.id` with the `execution_id` to drop redeliveries, and use the `run.completed` webhook from Rush to post the pull request link on the contributor's pull request.

## Why run it on Rush?

A red .NET build in a repository with a test project per service is slow to chase on a laptop: the right SDK, a Rust toolchain for one native dependency, and a full `dotnet test ./test` that takes far longer than the one failing fact. The agent reads the log, runs only the failing project with a filter in its own sandbox, and widens to the whole project only once the fix is in.

What it hands back is checkable: the quoted failure, the trajectory with every `dotnet test` and `dotnet format` run and its output, and the workflows rerunning on the pull request. Failures on several branches each get their own run at the same time, and nothing merges without a reviewer.

## Frequently asked questions

### Can it reproduce a database integration test failure?

The unit and integration tests under `test/` use NSubstitute or an in-memory SQLite database, so those run in the sandbox as is. For `Infrastructure.IntegrationTest`, which the database workflow runs against SQL Server, MySQL, PostgreSQL and SQLite in Docker, the agent starts the providers it can and says in the pull request which ones it verified.

### Why does it install Rust for a .NET repository?

Because `test.yml` does: it sets up a Rust toolchain before `dotnet test`, so a dependency with a native component builds. The agent follows the workflow rather than guessing, and skips the step only when the failing project does not need it.

### Will it fix a format failure by editing .editorconfig?

No. It runs `dotnet format` on the changed files and leaves the configuration alone. A diff to `.editorconfig` or to the analyzer settings would be visible, and the prompt does not ask for one.

### What if the test is flaky rather than broken?

It runs the filtered test several times. If it passes and fails without a code change, the agent looks for shared state or ordering in the test and fixes that, or reports that it found none, rather than rerunning the workflow until it is green.
