Commit Graph

8 Commits

Author SHA1 Message Date
Austin Pickett
f6df13bac6 fix(update): keep never-pushed and unmerged branches pinned in source check
An empty ls-remote advertisement cannot tell "merged and deleted upstream"
from "never pushed". The source check now re-pins a missing branch to main
only when the local branch was once published (remote-tracking ref or a
configured upstream) and git cherry finds no commits missing from main.
Otherwise it keeps the branch and reports branch-local-only.

Diagnosis from #105053 by @0xalydev and #105055 by @kokhlo, which targeted
the Electron healer since moved into hermes_cli/source_check.py.

Fixes #105042
2026-09-28 21:02:35 -04:00
ethernet
3351ec0967 test(source-check): pin that an unpublished main record follows the branch
The refusal matrix no longer carries ("main", "missing"). State the
intended behaviour at the source-check level instead: a 404 for
releases/channels/main.json yields no error, probes the configured
branch exactly as a published source-branch channel would, and leaves
the Desktop branch setting untouched.
2026-09-24 16:17:35 -04:00
ethernet
364bff76e4 test(source-check): drop the unpublished-main case from channel refusals
1dd9a9955d made a missing releases/channels/main.json resolve to the
main branch on purpose (main IS the source branch; its record can only
add a retirement), and pinned that in
test_source_channel_integration.py. The older refusal matrix in
test_source_check.py still expected `release-unavailable` for
("main", "missing") and failed with `fetch-failed` on the Python lane.
The case contradicts the intended behaviour; stable/canary/preview
refusals stay covered.
2026-09-24 16:17:35 -04:00
ethernet
6ba45b300c fix(update-check): authenticate api.github.com calls and name the branch-tip failure
The passive source check moved into hermes_cli/source_check.py during the
pm/ rewrite, and with it the GitHub calls left the desktop — but the four
main fixes that lived on the desktop side (gh-CLI token fallback
c61a11474b, anonymous retry e79ba2d7f2, rate-limit headers
c7d4d32800, failure copy 66a13703b3) did not follow. `_request` sent no
Authorization, so every client behind one NAT/VPN exit shared the anonymous
60/hour budget, and `_branch_tip` collapsed every failure into "Could not
resolve the remote branch tip." — a 403 rate limit read as a Hermes bug.

hermes_cli/github_api.py owns the credential ladder (GITHUB_TOKEN, GH_TOKEN,
`gh auth token` cached per process, anonymous; a 401 on a token retries
anonymously) and the failure copy (rate limit with reset time and the
GITHUB_TOKEN remedy, 5xx as GitHub trouble, else the status/transport
error). `_branch_tip` returns that reason and check_for_updates puts it in
the message.

apps/desktop/electron/github-api-auth.ts had no caller left (the desktop no
longer talks to api.github.com) — removed with its test; the behaviour now
lives where the request is made.
2026-09-21 18:56:56 -04:00
ethernet
d0ae1413cc test: fix the pm-clean python backlog clusters
- tui_gateway/test_protocol: import hermes_bootstrap before the MagicMock
  sys.modules window (PM activation reads the real install root at boot).
- test_source_check serves R2 records over loopback, so it opts out of the
  local source-branch channel stub (real_release_channels).
- browser_use_cli: discovery/install tests target the PM seams (python_tool /
  ensure_python_tool) instead of the retired shutil.which/uvx/managed-bin path.
- test_update_stage: reset tempfile's cached tempdir so TMPDIR is observed.
- test_update_finish: the selected interpreter is a symlink to the relocatable
  build; a copied binary cannot find its stdlib.
- drop test_desktop_half_installed_get_windows (node-deps.mjs owns npm ci).
2026-09-20 10:20:01 -04:00
ethernet
b37acb8389 feat(release): dynamic R2-owned channels and preview retirement (rounds 1-2)
Checkpoint before round-3 reduction (two-tier retirement derived from
product identity). Includes:

- R2 channel protocol (release_channels.py, channel-protocol.ts): records,
  builds, manifests, retired channels with pinned destinationHead and
  receiverProtocol; fail-closed readers in both languages
- One shared native manifest/feed writer (scripts/bundles/channel_artifacts.py)
- Scoped/disposable R2 publication, fork isolation before credential
  access, canary bootstrap verification of its own promoted outputs
- Channel source CLI: typed SourceTarget, source-channel resolution,
  retirement downgrade refusal
- Desktop channel resolver/strategy, install-stamp/build-stamp receiver
  ownership (stable-owned S/T candidates), single-flight updater operation
- Cross-package retirement machinery (receiver/host/preservation/
  compatibility/connections/dialog/discovery, backup_migration strict
  snapshots with retained-link inventory, empty-dir preservation,
  connection-collision resolution, URL-credential rejection)
- Native install harness (tests/install/channel-retirement-*) and
  install-e2e retirement jobs
- checkout-source.test.ts transport shim now covers build_opener().open
  (was silently hitting the real network in CI)

Removed secondary certification protocol (channel_qualification.py) per
approved round-2 plan. All focused suites green at checkpoint; native
cross-package journeys unverified (to be deleted in round 3).
2026-09-14 10:26:36 -04:00
ethernet
3a707117c5 fix(cli): accept BOM-prefixed catalog and runtime metadata 2026-09-13 18:21:59 -04:00
ethernet
cfebdfd466 Own passive source update checks in Python
Use the exact target root and profile for branch, release, and cache decisions. Keep the desktop as a transport and handoff adapter. Remove the competing TypeScript checker and switch the banner, dashboard, and updater count consumers.

Preserve fork origins, unknown counts, publication checks, old-probe recovery, and official SSH branch healing through public HTTPS. Keep the historical unstamped-root policy unchanged.
2026-09-12 19:03:26 -04:00