diff --git a/.github/workflows/winget-publish.yml b/.github/workflows/winget-publish.yml index 1023c342b..3466bb62f 100644 --- a/.github/workflows/winget-publish.yml +++ b/.github/workflows/winget-publish.yml @@ -32,13 +32,23 @@ # # ── Required secret ────────────────────────────────────────────────── # `WINGET_TOKEN` — a **classic** Personal Access Token with the -# `public_repo` scope (fine-grained tokens that can fork + push to -# microsoft/winget-pkgs also work). The default `GITHUB_TOKEN` CANNOT +# `public_repo` AND `workflow` scopes. The default `GITHUB_TOKEN` CANNOT # be used: it has no permission to fork an external repo or push the # manifest branch. Create it under the maintainer account that owns the # winget-pkgs fork (the same account that hand-submitted PR # microsoft/winget-pkgs#378294 for v0.5.102), then add it at # Settings → Secrets and variables → Actions → New repository secret. +# +# Why `workflow` too (field failure 2026-10-03, v0.6.43): the fork sync +# below fast-forwards githubrobbi/winget-pkgs over whatever upstream +# merged since the last release. Whenever that span touches a file +# under `.github/workflows/` — which microsoft/winget-pkgs does every +# few weeks — GitHub rejects the fast-forward for a PAT without the +# `workflow` scope ("refusing to allow a Personal Access Token to +# create or update workflow"). The fork then stays stale and komac +# fails with the misleading `CreateRef` permissions error. A classic +# PAT's scopes can be edited in place at https://github.com/settings/tokens +# (no rotation needed). name: 📦 WinGet Publish @@ -122,13 +132,19 @@ jobs: # winget-pkgs moves constantly and nothing else ever pushes to the # fork. Syncing here makes the submission self-healing. # - # `continue-on-error`: a sync hiccup must not block the submission — - # if the fork happens to be current, komac proceeds fine regardless. - # The `||` fallback keeps the step green while still surfacing the - # reason in the log. + # Second field failure 2026-10-03 (v0.6.43): the sync itself was + # refused — upstream had merged a `.github/workflows/` change and + # GitHub will not let a PAT without the `workflow` scope fast-forward + # over it. The step was `continue-on-error` with a `||` warning, so + # the refusal scrolled past as a warning, the fork stayed 81 commits + # behind, and komac failed with the same misleading `CreateRef` + # message as in August. This step therefore FAILS HARD now, with + # the real cause, whenever the fork is not at upstream's HEAD after + # the sync: komac cannot succeed from a stale base, so letting it + # try only buries the diagnosis. A fork that was already current + # never reaches the sync call. - name: Sync winget-pkgs fork with upstream if: steps.token.outputs.present == 'true' - continue-on-error: true env: GH_TOKEN: ${{ secrets.WINGET_TOKEN }} FORK_USER: githubrobbi @@ -137,16 +153,31 @@ jobs: set -uo pipefail before="$(gh api "repos/${FORK_USER}/winget-pkgs/commits/master" --jq .sha 2>/dev/null || echo unknown)" upstream="$(gh api repos/microsoft/winget-pkgs/commits/master --jq .sha 2>/dev/null || echo unknown)" - if [[ "$before" == "$upstream" && "$before" != unknown ]]; then + if [[ "$upstream" == unknown ]]; then + echo "::error title=Fork sync failed::Cannot read microsoft/winget-pkgs master with WINGET_TOKEN." + exit 1 + fi + if [[ "$before" == "$upstream" ]]; then echo "Fork already in sync at ${before}." exit 0 fi echo "Fork ${before} behind upstream ${upstream} — fast-forwarding." - gh api -X POST "repos/${FORK_USER}/winget-pkgs/merge-upstream" \ - -f branch=master --jq '.message' \ - || echo "::warning title=Fork sync failed::Could not fast-forward ${FORK_USER}/winget-pkgs; komac may fail to create its manifest branch." + if ! sync_out="$(gh api -X POST "repos/${FORK_USER}/winget-pkgs/merge-upstream" -f branch=master 2>&1)"; then + echo "$sync_out" + if grep -q "refusing to allow a Personal Access Token to create or update workflow" <<<"$sync_out"; then + echo "::error title=WINGET_TOKEN lacks the workflow scope::Upstream winget-pkgs changed a .github/workflows file and GitHub refuses to fast-forward the fork with a PAT that lacks the \`workflow\` scope. Fix: edit the classic PAT at https://github.com/settings/tokens to add \`workflow\` (no rotation needed), or sync once by hand with a token that has it: gh api -X POST repos/${FORK_USER}/winget-pkgs/merge-upstream -f branch=master — then re-run this workflow for ${{ inputs.release-tag }}." + else + echo "::error title=Fork sync failed::Could not fast-forward ${FORK_USER}/winget-pkgs (see output above). komac cannot cut its manifest branch from a stale fork, so the submission stops here." + fi + exit 1 + fi + echo "$sync_out" | jq -r '.message' 2>/dev/null || echo "$sync_out" after="$(gh api "repos/${FORK_USER}/winget-pkgs/commits/master" --jq .sha 2>/dev/null || echo unknown)" echo "Fork now at ${after} (upstream ${upstream})." + if [[ "$after" != "$upstream" ]]; then + echo "::error title=Fork still behind upstream::${FORK_USER}/winget-pkgs is at ${after}, upstream is ${upstream}. komac would fail with a misleading CreateRef permissions error; sync the fork and re-run." + exit 1 + fi - name: Submit manifest to winget-pkgs if: steps.token.outputs.present == 'true' diff --git a/.github/workflows/winget-token-expiry-check.yml b/.github/workflows/winget-token-expiry-check.yml index 528e47162..a38016de9 100644 --- a/.github/workflows/winget-token-expiry-check.yml +++ b/.github/workflows/winget-token-expiry-check.yml @@ -4,7 +4,7 @@ # ───────────────────────────────────────────────────────────────────────────── # winget-token-expiry-check — weekly heads-up before WINGET_TOKEN dies. # -# `winget-publish.yml` needs a classic PAT (`WINGET_TOKEN`, `public_repo` +# `winget-publish.yml` needs a classic PAT (`WINGET_TOKEN`, `public_repo` + `workflow` # scope) to fork + push to microsoft/winget-pkgs. When that PAT expires # the release-triggered WinGet submission fails — and because it runs on # the `release: released` event (not the PR path), nobody sees the red X @@ -174,9 +174,27 @@ jobs: || fail "cannot read microsoft/winget-pkgs master" [[ -n "${upstream:-}" ]] || fail "upstream master SHA came back empty" + # Scope check (field failure 2026-10-03, v0.6.43): the fork sync + # is refused outright whenever upstream's pending commits touch + # `.github/workflows/` and the PAT lacks the `workflow` scope — + # a condition that comes and goes with upstream's activity, so + # the sync-then-branch probe below can pass one week and the + # release fail the next. Reading the scopes is deterministic. + scopes="$(gh api -i user 2>/dev/null | grep -i '^x-oauth-scopes:' | cut -d: -f2- | tr -d ' \r')" + if [[ -n "$scopes" ]] && ! grep -qw workflow <<<"$scopes"; then + fail "WINGET_TOKEN lacks the workflow scope (has: ${scopes}); the fork sync is refused whenever microsoft/winget-pkgs changes a workflow file. Edit the classic PAT at https://github.com/settings/tokens to add workflow." + fi + # Fast-forward the fork, mirroring what the publish workflow does. - gh api -X POST "repos/${FORK_USER}/winget-pkgs/merge-upstream" \ - -f branch=master >/dev/null 2>&1 || true + if ! sync_out="$(gh api -X POST "repos/${FORK_USER}/winget-pkgs/merge-upstream" -f branch=master 2>&1)"; then + if grep -q "refusing to allow a Personal Access Token to create or update workflow" <<<"$sync_out"; then + fail "fork sync refused: WINGET_TOKEN lacks the workflow scope and upstream has pending workflow changes" + fi + fail "fork sync failed: ${sync_out}" + fi + fork_head="$(gh api "repos/${FORK_USER}/winget-pkgs/commits/master" --jq .sha 2>/dev/null || true)" + [[ "$fork_head" == "$upstream" ]] \ + || fail "fork still behind after sync (fork ${fork_head:-?}, upstream ${upstream})" # The real test: create the kind of ref komac creates, then remove # it. A unique name keeps concurrent runs from colliding. @@ -277,11 +295,11 @@ jobs: `Check, in this order, before assuming the token is at fault:`, `1. Does the fork \`githubrobbi/winget-pkgs\` still exist and is it writable?`, `2. Is it far behind \`microsoft/winget-pkgs\`? (Publishing self-heals this, but a failing sync will not.)`, - `3. Only then suspect the token — and note the action requires a **classic** PAT; fine-grained PATs are unsupported and cannot open the cross-fork PR.`, + `3. Only then suspect the token — and note the action requires a **classic** PAT with the \`public_repo\` **and** \`workflow\` scopes; without \`workflow\` the fork sync is refused whenever upstream touched a workflow file, and fine-grained PATs are unsupported (they cannot open the cross-fork PR).`, ``, ] : []), `### How to rotate`, - `1. Create a new **classic** PAT at https://github.com/settings/tokens — scope \`public_repo\` only, ~1-year expiry.`, + `1. Create a new **classic** PAT at https://github.com/settings/tokens — scopes \`public_repo\` + \`workflow\`, ~1-year expiry.`, `2. \`gh secret set WINGET_TOKEN --repo ${owner}/${repo}\` and paste it.`, `3. Run the **🔑 WinGet Token Expiry Check** workflow manually (\`workflow_dispatch\`) to confirm healthy — it will auto-close this issue.`, ``, diff --git a/CHANGELOG.md b/CHANGELOG.md index 70a37deb7..12730d876 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.6.44] - 2026-10-03 + +### Added + +- cli: make --benchmark measure output production; -v shows the rows + +### Changed + +- daemon: never force a tier change on memory pressure + +### Fixed + +- client: report the client's own deadline as Timeout, never as a warm-up retry +- daemon: surface search timeouts as errors and cancel the orphaned scan +- daemon: log the per-tick USN refresh at debug, not info + ## [0.6.43] - 2026-10-03 ### Added @@ -2880,7 +2896,8 @@ thin clients over a unified `uffsd` process. ### Fixed - Various MFT parsing edge cases -[Unreleased]: https://github.com/skyllc-ai/UltraFastFileSearch/compare/v0.6.43...HEAD +[Unreleased]: https://github.com/skyllc-ai/UltraFastFileSearch/compare/v0.6.44...HEAD +[0.6.44]: https://github.com/skyllc-ai/UltraFastFileSearch/compare/v0.6.43...v0.6.44 [0.6.43]: https://github.com/skyllc-ai/UltraFastFileSearch/compare/v0.6.42...v0.6.43 [0.6.42]: https://github.com/skyllc-ai/UltraFastFileSearch/compare/v0.6.41...v0.6.42 [0.6.41]: https://github.com/skyllc-ai/UltraFastFileSearch/compare/v0.6.40...v0.6.41 diff --git a/Cargo.lock b/Cargo.lock index 98e53a39b..d5f381c6f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4329,7 +4329,7 @@ checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" [[package]] name = "uffs-bench" -version = "0.6.43" +version = "0.6.44" dependencies = [ "chrono", "clap", @@ -4346,7 +4346,7 @@ dependencies = [ [[package]] name = "uffs-broker" -version = "0.6.43" +version = "0.6.44" dependencies = [ "anyhow", "serde", @@ -4365,14 +4365,14 @@ dependencies = [ [[package]] name = "uffs-broker-protocol" -version = "0.6.43" +version = "0.6.44" dependencies = [ "thiserror 2.0.21", ] [[package]] name = "uffs-ci-pipeline" -version = "0.6.43" +version = "0.6.44" dependencies = [ "anyhow", "chrono", @@ -4391,7 +4391,7 @@ dependencies = [ [[package]] name = "uffs-cli" -version = "0.6.43" +version = "0.6.44" dependencies = [ "anyhow", "assert_cmd", @@ -4414,7 +4414,7 @@ dependencies = [ [[package]] name = "uffs-client" -version = "0.6.43" +version = "0.6.44" dependencies = [ "dirs-next", "libc", @@ -4434,7 +4434,7 @@ dependencies = [ [[package]] name = "uffs-core" -version = "0.6.43" +version = "0.6.44" dependencies = [ "anyhow", "bytemuck", @@ -4465,7 +4465,7 @@ dependencies = [ [[package]] name = "uffs-daemon" -version = "0.6.43" +version = "0.6.44" dependencies = [ "anyhow", "clap", @@ -4498,7 +4498,7 @@ dependencies = [ [[package]] name = "uffs-diag" -version = "0.6.43" +version = "0.6.44" dependencies = [ "anyhow", "chrono", @@ -4513,7 +4513,7 @@ dependencies = [ [[package]] name = "uffs-fetch" -version = "0.6.43" +version = "0.6.44" dependencies = [ "anyhow", "hex", @@ -4524,7 +4524,7 @@ dependencies = [ [[package]] name = "uffs-format" -version = "0.6.43" +version = "0.6.44" dependencies = [ "chrono", "itoa", @@ -4535,7 +4535,7 @@ dependencies = [ [[package]] name = "uffs-gen-hooks" -version = "0.6.43" +version = "0.6.44" dependencies = [ "anyhow", "clap", @@ -4547,7 +4547,7 @@ dependencies = [ [[package]] name = "uffs-gen-workflow" -version = "0.6.43" +version = "0.6.44" dependencies = [ "anyhow", "clap", @@ -4560,7 +4560,7 @@ dependencies = [ [[package]] name = "uffs-manifest-audit" -version = "0.6.43" +version = "0.6.44" dependencies = [ "anyhow", "clap", @@ -4572,7 +4572,7 @@ dependencies = [ [[package]] name = "uffs-mcp" -version = "0.6.43" +version = "0.6.44" dependencies = [ "anyhow", "axum", @@ -4596,7 +4596,7 @@ dependencies = [ [[package]] name = "uffs-mft" -version = "0.6.43" +version = "0.6.44" dependencies = [ "anyhow", "bitflags", @@ -4637,14 +4637,14 @@ dependencies = [ [[package]] name = "uffs-polars" -version = "0.6.43" +version = "0.6.44" dependencies = [ "polars", ] [[package]] name = "uffs-security" -version = "0.6.43" +version = "0.6.44" dependencies = [ "aes-gcm", "dirs-next", @@ -4659,22 +4659,22 @@ dependencies = [ [[package]] name = "uffs-statusfmt" -version = "0.6.43" +version = "0.6.44" [[package]] name = "uffs-text" -version = "0.6.43" +version = "0.6.44" dependencies = [ "bytemuck", ] [[package]] name = "uffs-time" -version = "0.6.43" +version = "0.6.44" [[package]] name = "uffs-update" -version = "0.6.43" +version = "0.6.44" dependencies = [ "anyhow", "dirs-next", @@ -4691,11 +4691,11 @@ dependencies = [ [[package]] name = "uffs-version" -version = "0.6.43" +version = "0.6.44" [[package]] name = "uffs-vss-requestor" -version = "0.6.43" +version = "0.6.44" dependencies = [ "anyhow", "cc", @@ -4707,7 +4707,7 @@ dependencies = [ [[package]] name = "uffs-watchdog" -version = "0.6.43" +version = "0.6.44" dependencies = [ "anyhow", "dirs-next", @@ -4716,7 +4716,7 @@ dependencies = [ [[package]] name = "uffs-winsvc" -version = "0.6.43" +version = "0.6.44" dependencies = [ "anyhow", "windows", diff --git a/Cargo.toml b/Cargo.toml index 19384d67a..617852806 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -68,7 +68,7 @@ members = [ # Workspace Package Metadata (inherited by all crates) # ───────────────────────────────────────────────────────────────────────────── [workspace.package] -version = "0.6.43" +version = "0.6.44" edition = "2024" # No `rust-version` claim: the workspace is structurally nightly-only. # `crates/uffs-polars` enables `polars/nightly` unconditionally, which @@ -135,36 +135,36 @@ publish = false # proposed-plan output for 12 days because `release-plz update` # failed at `cargo package` with this very error. See # `release-automation-baseline.md` §10 for the diagnostic trail. -uffs-polars = { path = "crates/uffs-polars", version = "0.6.43" } -uffs-security = { path = "crates/uffs-security", version = "0.6.43" } -uffs-text = { path = "crates/uffs-text", version = "0.6.43" } -uffs-time = { path = "crates/uffs-time", version = "0.6.43" } -uffs-version = { path = "crates/uffs-version", version = "0.6.43" } -uffs-statusfmt = { path = "crates/uffs-statusfmt", version = "0.6.43" } -uffs-mft = { path = "crates/uffs-mft", version = "0.6.43" } -uffs-format = { path = "crates/uffs-format", version = "0.6.43" } -uffs-core = { path = "crates/uffs-core", version = "0.6.43" } -uffs-client = { path = "crates/uffs-client", version = "0.6.43" } +uffs-polars = { path = "crates/uffs-polars", version = "0.6.44" } +uffs-security = { path = "crates/uffs-security", version = "0.6.44" } +uffs-text = { path = "crates/uffs-text", version = "0.6.44" } +uffs-time = { path = "crates/uffs-time", version = "0.6.44" } +uffs-version = { path = "crates/uffs-version", version = "0.6.44" } +uffs-statusfmt = { path = "crates/uffs-statusfmt", version = "0.6.44" } +uffs-mft = { path = "crates/uffs-mft", version = "0.6.44" } +uffs-format = { path = "crates/uffs-format", version = "0.6.44" } +uffs-core = { path = "crates/uffs-core", version = "0.6.44" } +uffs-client = { path = "crates/uffs-client", version = "0.6.44" } # `uffs-broker-protocol` carries the wire-protocol types shared between # `uffs-broker` (the elevated handle vendor, Windows-only binary) and # `uffs-daemon::broker_client` (the handle consumer). Pure-logic # Layer-0 lib — cross-platform tests run on every CI lane. Added in # F5 (issue #205) so neither side duplicates `BROKER_PIPE_NAME` / # wire-format byte literals. -uffs-broker-protocol = { path = "crates/uffs-broker-protocol", version = "0.6.43" } +uffs-broker-protocol = { path = "crates/uffs-broker-protocol", version = "0.6.44" } # `uffs-winsvc` — native Windows service control (SCM query/start/stop) + # the non-connecting broker-pipe readiness probe. Layer-0 leaf: its only # dependency is the `windows` crate (windows-target), with non-Windows # stubs so cross-platform consumers (uffs-update, uffs-cli) compile. # Single source of truth for the `sc`/SCM mechanics previously duplicated # across uffs-broker, uffs-update, and uffs-cli. -uffs-winsvc = { path = "crates/uffs-winsvc", version = "0.6.43" } +uffs-winsvc = { path = "crates/uffs-winsvc", version = "0.6.44" } # `uffs-fetch` — hardened release-asset transport (blocking reqwest + # rustls with retry/timeout/byte-cap, plus `SHA256SUMS` verification), # extracted from `uffs-update` as a small public lib so external products # can reuse it. Cross-platform pure-logic leaf; keeps the HTTP/TLS stack # out of the lean `uffs` CLI exactly as before. -uffs-fetch = { path = "crates/uffs-fetch", version = "0.6.43" } +uffs-fetch = { path = "crates/uffs-fetch", version = "0.6.44" } # NOTE: no `uffs-broker` workspace dependency alias on purpose — # `uffs-broker` is a binary-only crate (the only `[lib]` it carries is # this protocol module's now-extracted sibling); no other workspace diff --git a/crates/uffs-cli/Cargo.toml b/crates/uffs-cli/Cargo.toml index babad84e3..0e458b314 100644 --- a/crates/uffs-cli/Cargo.toml +++ b/crates/uffs-cli/Cargo.toml @@ -70,7 +70,7 @@ path = "src/main.rs" # by the release bump) is required for `cargo package` validation — see # root `Cargo.toml`'s [workspace.dependencies] note for the full # rationale (R6 of `release-automation-plan.md`). -uffs-client = { path = "../uffs-client", version = "0.6.43", default-features = false } +uffs-client = { path = "../uffs-client", version = "0.6.44", default-features = false } # Canonical CSV / parity / legacy-footer writer. Direct dep (not a # re-export chain through `uffs-client`) so the CLI and the daemon @@ -79,7 +79,7 @@ uffs-client = { path = "../uffs-client", version = "0.6.43", default-features = # by the release bump) is required for `cargo package` validation — see # root `Cargo.toml`'s [workspace.dependencies] note for the full # rationale (R6 of `release-automation-plan.md`). -uffs-format = { path = "../uffs-format", version = "0.6.43" } +uffs-format = { path = "../uffs-format", version = "0.6.44" } # Typed drive-letter newtype. Direct dep so the CLI command signatures # (`daemon_load`, `daemon_tiering`, etc.) name `DriveLetter` natively