Commit Graph

27 Commits

Author SHA1 Message Date
Eugeniusz Gilewski 64dd865912 fix(deps): repair Google transitive security floors (#72108)
Google API and authentication packages permit vulnerable httplib2 and pyasn1
transitives, while the Workspace and Google Chat runtime installers previously
treated any importable version as sufficient. Existing environments could
therefore remain vulnerable after the project dependency pins were repaired.

Carry the fixed versions through the Google and Vertex extras, lazy feature
requirements, lockfile, and both runtime installers. Route the documented
Google Chat installation path through its maintained secure requirements
instead of an unconstrained direct pip command.

Detect stale distributions, install only unsatisfied requirements, and verify
the result before continuing. Behavioral tests cover those repair invariants
without freezing manifests, lockfiles, or complete package sets.

Related #72108
Extracted from #72840
Co-authored-by: Teknium <127238744+teknium1@users.noreply.github.com>
2026-07-31 23:18:38 -07:00
Yorkstone Supplies (sycamoregroupltd) 37e42808e7 fix(security): pin httplib2==0.32.0 in setup.py REQUIRED_PACKAGES (GHSA-j5g9-f88f-gfj3)
The previous fix (904ade32b) pinned httplib2==0.32.0 in pyproject.toml's
google extra and tools/lazy_deps.py's skill.google_workspace, but missed
a third install path: skills/productivity/google-workspace/scripts/setup.py
REQUIRED_PACKAGES. A user following the --install-deps path could still
resolve httplib2 via unpinned ranges.

This commit:
1. Exact-pins all four Google packages in REQUIRED_PACKAGES to match
   pyproject.toml and lazy_deps.py contracts exactly.
2. Adds a focused regression test that parses setup.py's REQUIRED_PACKAGES
   via AST and asserts every pin matches the other two install paths.

Changelog: fix(security), test(security)
2026-07-31 22:28:21 -07:00
teknium1 75e0d52034 fix(windows): sweep remaining bare read_text/write_text sites + linter rule
AST-driven pass over every Path.read_text()/write_text() without an
explicit encoding= across non-test code: 71 sites in 34 files
(skills_hub, hermes_cli/main+profiles+service_manager+container_boot,
mem0/hindsight/honcho plugins, achievements dashboard, release/CI
scripts, productivity+comfyui skill helpers, agent/*). Verified zero
positional-encoding collisions before insertion; per-file compile()
check after.

Adds a check-windows-footguns rule flagging bare single-line
read_text/write_text (multi-line forms stay covered by the AST guard
test from #38985). Together with the salvaged contributor commits this
retires the ~169-site bare file-I/O class (#37423's long tail).
2026-07-24 17:10:39 -07:00
Stoltemberg c89481db5e fix: add explicit UTF-8 encoding to all subprocess text=True calls (#53428)
On Windows with Chinese locale (GBK), subprocess.run(text=True) without
explicit encoding causes UnicodeDecodeError crashes. This fix adds
encoding='utf-8', errors='replace' to all subprocess.run() and
subprocess.Popen() calls that use text=True across 76 non-test Python files.

Fixes #53428 (master tracker for Windows GBK locale crash).

Note: credential_pool.py and electron changes excluded per reviewer request —
those will be submitted as separate focused PRs.
2026-07-24 11:45:57 -07:00
ethernet d84e11af4d
rip out brew + pip/PyPI wheel support (#68217)
Removes Homebrew and PyPI wheel/sdist as Hermes distribution paths while
preserving the supported source, Docker, and Nix workflows.

Changes:
- Removes the Homebrew formula, PyPI publish workflow, sdist manifest
  (MANIFEST.in), and wheel/sdist release-attachment logic from scripts/release.py.
- Keeps setuptools metadata and entry points required by editable installs
  and Docker/Nix builds, but adds a setup.py guard that rejects wheel/sdist
  builds outside a sealed Nix derivation (HERMES_NIX_BUILD=1).
- Removes pip/Homebrew install detection, PyPI update checks, the pip
  self-update path, the deprecation-banner state, the postinstall subcommand,
  wheel data-directory fallbacks in agent/i18n.py and hermes_constants.py,
  and the ACP Registry manifest/version-lockstep release logic.
- Adds /nix/store/ path detection so `nix run` / `nix profile install`
  installs (which don't set HERMES_MANAGED) are correctly identified as
  "nix" rather than falling through to "git"/"unknown".
- Retired install-method values ("pip", "homebrew") in existing
  .install_method stamps (both code-scoped and home-scoped) are ignored by
  the allowlist reader and fall through to "unknown" instead of resurrecting
  a retired enum value.
- Updates Nix packaging to ship bare runtime data (locales, optional-mcps)
  through store symlinks and wrapper env vars instead of wheel data-files.
- Removes the ACP Registry manifest/icon and their version-lockstep tests.
- Deletes or rewrites packaging, pip-update, Homebrew, and ACP Registry
  tests; adds parametrized coverage for the packaging build guard covering
  BOTH sdist and wheel paths (the guards live in separate cmdclass entries
  — a passing sdist test proves nothing about the wheel path).
- Updates installation/platform documentation and related user-facing copy.
- Adjusts the supply-chain scan so deleted install-hook files do not trigger
  a finding, while additions or modifications still require the existing
  ci-reviewed label gate.

Supported installation paths (unchanged):
- git installer (install.sh)
- Docker
- Nix/NixOS
- editable development installs (uv sync, uv pip install -e ., pip install -e .)
2026-07-22 16:51:01 -04:00
Ben Barclay 7c00ffd92c
fix(google-workspace): fall back to uv when venv has no pip (#39516)
The Hermes Docker image's venv is built with `uv sync`, which does not
bootstrap pip into the venv. When the google-workspace setup script needs
to install its deps and the running interpreter has no pip,
`sys.executable -m pip install` dead-ends with "No module named pip"
(reported via Discord support).

install_deps() now falls back to `uv pip install --python <interpreter>`
when the pip path fails and uv is on PATH. uv installs into the exact
interpreter the script is running under without needing pip present, so
the pip-less venv self-heals (e.g. a dep evicted on image update, or a
build without the [google]/[all] extra). On environments with neither
pip nor uv, the [google] extra hint is printed as before.

Verified E2E against nousresearch/hermes-agent:latest: under the venv
python with a missing dep, --install-deps now prints "Dependencies
installed." and exits 0 instead of failing.

Adds TestInstallDeps regression coverage: pip path, uv fallback,
uv-not-consulted-when-pip-works control, and both no-installer-available
and uv-also-fails failure cases.
2026-06-05 13:30:02 +10:00
Donovan Yohan 8bd00607dc fix(google-workspace): handle Gmail header casing case-insensitively
Normalize Gmail API message header names to lowercase before lookup so
gmail get/search/reply populate to/subject/from regardless of the casing
the message was stored with. Emit conventional MIME header casing
(To/Subject/Cc/From) on send and reply.

Fixes #34806

Co-authored-by: Donovan Yohan <donovan-yohan@users.noreply.github.com>
2026-05-30 02:38:18 -07:00
Zyrixtrex 87c6edc1d0 fix(skills): add timeout to Google OAuth urlopen calls 2026-05-19 00:11:44 -07:00
kshitij 5fba236644
chore: ruff auto-fix PLR6201 resweep — tuple → set in membership tests (#27355)
Six days after #23937 (608 fixes) the codebase had accumulated 241 new
PLR6201 violations. Same mechanical `x in (...)` → `x in {...}` fix,
same zero-risk profile: set lookup is O(1) vs O(n) for tuple and the
two are semantically equivalent for hashable scalar membership tests.

All 241 instances fixed via `ruff check --select PLR6201 --fix
--unsafe-fixes`, zero remaining. Every changed value is a hashable
scalar (str/int/None/enum/signal); no risk of unhashable runtime
errors. No behavior change.

Test plan:
- 119 files changed, +244/-244 (net zero) — exactly one-line edits
- `ruff check` clean afterward
- Compile checks pass on the largest touched files (cli.py, run_agent.py,
  gateway/run.py, gateway/platforms/discord.py, model_tools.py)
- Subset broad test run on tests/gateway/ tests/hermes_cli/ tests/agent/
  tests/tools/: 18187 passed, 59 pre-existing failures (verified against
  origin/main with the same shape — identical failure count, identical
  category — all xdist test-order flakes unrelated to this change)

Follows the same template as PR #23937 ([tracker: #23972](https://github.com/NousResearch/hermes-agent/issues/23972)).
2026-05-17 02:29:41 -07:00
Teknium e43d2fe520
feat(google-workspace): Drive write ops + Docs/Sheets create/append (#21895)
Expand the google-workspace skill beyond read-only access to Drive and
Docs. Sheets already had full scope — just adds the missing create verb.

New subcommands:
- drive get        : metadata for a single file
- drive upload     : upload a local file (auto MIME detection)
- drive download   : download or export (Docs/Sheets/Slides export to pdf/csv/pdf by default)
- drive create-folder
- drive share      : user/group/domain/anyone + reader/writer/etc.
- drive delete     : default trashes (reversible); --permanent skips the trash
- sheets create    : new spreadsheet with optional first-tab name
- docs create      : new doc, optional initial body
- docs append      : append text at end of an existing doc

Scope changes:
- drive.readonly     -> drive
- documents.readonly -> documents

Existing users with old tokens will hit the existing partial-scope
warning path (AUTHENTICATED (partial) ...) — the troubleshooting table
now points them at $GSETUP --revoke + redo steps 3-5 to pick up the
write scopes.
2026-05-08 07:27:32 -07:00
Teknium 83c23e8861 fix(google-workspace): cleanup for --check-live salvage
Small follow-ups on top of #19643:
- check_auth() takes quiet kwarg to suppress its AUTHENTICATED print
  when called from check_auth_live(), so the final status line reflects
  the live-call outcome only.
- Drop redundant _ensure_deps() call in check_auth_live() (check_auth()
  already calls it).
- Add AUTHOR_MAP entry for ygd58 so release attribution script works.
2026-05-08 04:50:43 -07:00
ygd58 617ac0535b fix: correct docstring syntax error in check_auth_live 2026-05-08 04:50:43 -07:00
ygd58 5fa493a2ca fix(google-workspace): detect disabled_client in --check and add --check-live
setup.py --check only validated token shape/expiry but did not detect
when Google had disabled the OAuth client or account. Users got
AUTHENTICATED even when actual API calls failed with disabled_client.

Changes:
- Catch disabled_client and invalid_client in check_auth() refresh
  path with actionable guidance (check Cloud Console, check account
  status, do not retry)
- Add check_auth_live() that performs a real Calendar API call to
  detect disabled_client errors that survive token refresh
- Add --check-live CLI flag backed by check_auth_live()

Fixes #19570
2026-05-08 04:50:43 -07:00
xiahu88988 898ccfd667 fix(skills): honor scope query from Google OAuth redirect URL
Parse scope from the raw callback URL before stripping the auth code so Flow.fetch_token matches user-granted scopes. Add regression test for dual-scope callbacks.

Made-with: Cursor
2026-04-26 21:08:19 -07:00
Teknium 13038dc747 fix(skills): ship google-workspace deps as [google] extra; make setup.py 3.9-parseable
Closes #13626.

Two follow-ups on top of the _hermes_home helper from @jerome-benoit's #12729:

1. Declare a [google] optional extra in pyproject.toml
   (google-api-python-client, google-auth-oauthlib, google-auth-httplib2) and
   include it in [all]. Packagers (Nix flake, Homebrew) now ship the deps by
   default, so `setup.py --check` does not need to shell out to pip at
   runtime — the imports succeed and install_deps() is never reached.
   This fixes the Nix breakage where pip/ensurepip are stripped.

2. Add `from __future__ import annotations` to setup.py so the PEP 604
   `str | None` annotation parses on Python 3.9 (macOS system python).
   Previously system python3 SyntaxError'd before any code ran.

install_deps() error message now also points users at the extra instead of
just the raw pip command.
2026-04-24 16:45:27 -07:00
Jérôme Benoit c34d3f4807 fix(skills): factor HERMES_HOME resolution into shared _hermes_home helper
The three google-workspace scripts (setup.py, google_api.py, gws_bridge.py)
each had their own way of resolving HERMES_HOME:

- setup.py imported hermes_constants (crashes outside Hermes process)
- google_api.py used os.getenv inline (no strip, no empty handling)
- gws_bridge.py defined its own local get_hermes_home() (duplicate)

Extract the common logic into _hermes_home.py which:
- Delegates to hermes_constants when available (profile support, etc.)
- Falls back to os.getenv with .strip() + empty-as-unset handling
- Provides display_hermes_home() with ~/ shortening for profiles

All three scripts now import from _hermes_home instead of duplicating.

7 regression tests cover the fallback path: env var override, default
~/.hermes, empty env var, display shortening, profile paths, and
custom non-home paths.

Closes #12722
2026-04-24 16:45:27 -07:00
LeonSGP43 daef0519e9 fix(google-workspace): normalize authorized user token writes 2026-04-16 04:22:16 -07:00
Misturi dedc4600dd fix(skills): handle missing fields in Google Workspace token file gracefully instead of crashing with KeyError 2026-04-15 03:45:09 -07:00
Teknium b24e5ee4b0
feat(google-workspace): add --from flag for custom sender display name (#9931)
Adds --from flag to gmail send and gmail reply commands, allowing agents
to customize the From header display name when sharing the same email
account. Usage: --from '"Agent Name" <user@example.com>'

Also syncs repo google_api.py with the deployed standalone implementation
(replaces outdated gws_bridge thin wrapper), adds dedicated docs page
under Features > Skills, and updates sidebar navigation.

Requested by community user @Maxime44.
2026-04-14 16:55:34 -07:00
Teknium e9168f917e fix: handle HTTP errors gracefully in gws_bridge token refresh
Instead of crashing with a raw urllib traceback on refresh failure,
print a clean error message and suggest re-running setup.py.
2026-04-09 14:28:35 -07:00
Teknium 73eb59db8d fix: follow-up fixes for google-workspace gws migration
- Fix npm package name: @anthropic -> @googleworkspace/cli
- Add Homebrew install option
- Fix calendar_list to respect --start/--end args (uses raw Calendar
  API for date ranges, +agenda helper for default 7-day view)
- Improve check_auth partial scope output (list missing scopes)
- Add output format documentation with key JSON shapes
- Use npm install in troubleshooting (no Rust toolchain needed)

Follow-up to cherry-picked PR #6713
2026-04-09 14:28:35 -07:00
spideystreet 127b4caf0d feat(skills): migrate google-workspace to gws CLI backend
Migrate the google-workspace skill from custom Python API wrappers
(google-api-python-client) to Google's official Rust CLI gws
(googleworkspace/cli). Add gws_bridge.py for headless-compatible
token refresh. Fix partial OAuth scope handling.

Co-authored-by: spideystreet <dhicham.pro@gmail.com>
Cherry-picked from PR #6713
2026-04-09 14:28:35 -07:00
Zainan Victor Zhou 83df001d01 fix: allow google-workspace skill scripts to run directly
- fall back to adding the repo root to sys.path when hermes_constants is not importable
- fixes direct execution of setup.py and google_api.py from the repo checkout
- keeps the upstream PR scoped to the google-workspace compatibility fix
2026-04-06 16:50:07 -07:00
kshitijk4poor 5359921199 refactor: simplify scope validation helpers in google workspace scripts
Fix double file read bug in google_api.py _missing_scopes(), consolidate
redundant _normalize_scope_values into callers, merge duplicate except blocks.
2026-04-03 17:49:18 -07:00
kshitijk4poor 37e2ef6c3f fix: protect profile-scoped google workspace oauth tokens 2026-04-03 17:49:18 -07:00
teknium1 4524cddc72 fix: persist google oauth pkce for headless auth
Store the pending OAuth state and code verifier between --auth-url and --auth-code so the manual headless flow can reuse Flow.fetch_token() without disabling PKCE.
2026-03-14 22:11:34 -07:00
teknium1 669e4d0297 add experimental google workspace command center skill 2026-02-26 14:29:51 -08:00