**Related issue:** #47725 moved the script but didn't update the workflow # Checklist for submitter - [x] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. N/A - CI-only change, no user-visible impact. - [x] Input data is properly validated, `SELECT *` is avoided, SQL injection is prevented (using placeholders for values in statements), JS inline code is prevented especially for url redirects, and untrusted data interpolated into shell scripts/commands is validated against shell metacharacters. - [x] Timeouts are implemented and retries are limited to avoid infinite loops ## Testing - [x] QA'd all new/changed functionality manually **How this was tested:** 1. Confirmed `uninstall-fleetd-windows.ps1` does not exist at the old path (`it-and-security/lib/windows/scripts/`) on `main` -- reproduces the `CommandNotFoundException`. 2. Confirmed the file exists at the new path (`docs/solutions/windows/scripts/`). 3. Ran sparse-checkout simulations locally: old path yields no script file, new path successfully pulls it. 4. Compared old vs new script -- the new version adds an MDM unenrollment step that is a no-op in E2E (no MDM enrolled), so behavior is equivalent. 5. Triggered the full E2E agent workflow on this PR branch to verify all 32 Windows jobs pass the "Uninstall Orbit" step. ## Root cause PR #47725 ("Fix unenroll Windows instructions", merged June 19) moved `uninstall-fleetd-windows.ps1` from `it-and-security/lib/windows/scripts/` to `docs/solutions/windows/scripts/` as part of merging the "turn off MDM" and "uninstall fleetd" scripts into one. However, `.github/workflows/e2e-agent.yml` was not updated to reflect the new path. This broke all 32 Windows E2E jobs (windows-2025 and windows-11-arm, all channel/update combinations) at the "Uninstall Orbit" step. The nightly run has been failing for 2 consecutive cycles (June 20 and 21), exhausting all 4 retry attempts each time. ## Fix Update the sparse-checkout path and PowerShell run command in `e2e-agent.yml` to the new location. ## Note: inconsistent uninstall script locations After #47725, the uninstall scripts are now in different directories per OS: | OS | Uninstall script location | |---|---| | macOS | `it-and-security/lib/macos/scripts/uninstall-fleetd-macos.sh` | | Linux | `it-and-security/lib/linux/scripts/uninstall-fleetd-linux.sh` | | Windows | `docs/solutions/windows/scripts/uninstall-fleetd-windows.ps1` | macOS and Linux remain in `it-and-security/lib/` (Fleet's dogfooding GitOps config). Windows was moved to `docs/solutions/` (user-facing documentation). This inconsistency may warrant a follow-up to decide on a canonical location.
Github Actions
Fleet uses Github Actions for continuous integration (CI). This document describes best practices and at patterns for writing and maintaining Fleet's Github Actions workflows.
Bash
By default, Github Actions sets the shell to bash -e for linux and MacOS runners. To help write
safer bash scripts in run jobs and avoid common issues, override the default by adding the following
to the workflow file
defaults:
run:
# fail-fast using bash -eo pipefail. See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#exit-codes-and-error-action-preference
shell: bash
By specifying the default shell to bash, some extra flags are set. The option pipefail changes
the behaviour when using the pipe | operator such that if any command in a pipeline fails, that
commands return code will be used a the return code for the whole pipeline. Consider the following
example in test-go.yaml
- name: Run Go Tests
run: |
# omitted ...
make test-go 2>&1 | tee /tmp/gotest.log
If the pipefail option was not set, this job would always succeed because tee would always
return success. This is not the intended behavior. Instead, we want the job to fail if make test-go fails.
Concurrency
Github Action runners are limited. If a lot of workflows are queued, they will wait in pending until a runner becomes available. This has caused issue in the past where workflows take an excessively long time to start. To help with this issue, use the following in workflows
# This allows a subsequently queued workflow run to interrupt previous runs
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id}}
cancel-in-progress: true
When a workflow is triggered via a pull request, it will cancel previous running workflows for that
pull request. This is especially useful when changes are pushed to a pull request frequently.
Manually triggered workflows, workflows that run on a schedule, and workflows triggered by pushes to
main are unaffected.