Skip to content

feat(gmail): migrate Gmail integration from private repo#323

Merged
TheRealAgentK merged 1 commit into
masterfrom
feat/322/migrate-gmail-from-private
May 13, 2026
Merged

feat(gmail): migrate Gmail integration from private repo#323
TheRealAgentK merged 1 commit into
masterfrom
feat/322/migrate-gmail-from-private

Conversation

@TheRealAgentK
Copy link
Copy Markdown
Collaborator

@TheRealAgentK TheRealAgentK commented May 12, 2026

Closes #322

Summary

Migrates the Gmail integration from the private Autohive-AI/integrations repo to the public autohive-integrations repo.

Security / safety / secrets review

Reviewed before migration — clean:

Concern Result
Hardcoded secrets / API keys / tokens None
Internal URLs (autohive.com, dash, qa) None
Customer / employee names None
Trade secrets / proprietary business logic None — straight Gmail API wrapper
OAuth client IDs/secrets None — uses platform OAuth (token injected at runtime)
Vendored SDK (integration.py) Old SDK 1.x copy — dropped; public uses autohive-integrations-sdk from PyPI
Legacy manual harness (test_gmail_integration.py) No secrets, but doesn't fit public pytest pattern — dropped

What's included

  • gmail/config.json — copied as-is
  • gmail/gmail.py — copied as-is (uses googleapiclient + bleach for HTML sanitisation)
  • gmail/icon.png — copied as-is
  • gmail/__init__.py — empty (matches public repo convention)
  • gmail/requirements.txt — kept at SDK ~=1.0.2 (migrate as-is; SDK 2.0 upgrade is a separate concern)
  • gmail/README.md — rewritten in the public repo style (modelled on google-calendar/README.md)
  • gmail/tests/{__init__.py,context.py,test_gmail.py} — copied placeholder structure
  • README.md — added Gmail entry near other Google integrations

Validation

$ python ../autohive-integrations-tooling/scripts/validate_integration.py gmail
⚠️ Validation passed with warnings
   - SDK version 1.0.2 is deprecated (acceptable; migrating as-is)
   - Potentially unused scopes (false positive — gmail.modify is used)

$ python ../autohive-integrations-tooling/scripts/check_code.py gmail
✅ CODE CHECK PASSED

Companion PRs

Migrates the Gmail integration from the private `integrations` repo to
the public `autohive-integrations` repo after a security/safety/secrets
review found no hardcoded secrets, internal URLs, customer references,
or proprietary business logic.

Drops legacy artefacts that don't belong in the public repo:
  * integration.py — vendored old SDK copy (public uses PyPI package)
  * test_gmail_integration.py — manual harness (replaced by tests/)

Includes 21 actions across messages, threads, drafts, and labels, with
HTML sanitisation via bleach and pagination on every list endpoint.

Closes #322
@github-actions
Copy link
Copy Markdown

🔍 Integration Validation Results

Commit: 4e0f3b8faa30cb512bc0b78cde2a6b074882d75a · feat(gmail): migrate Gmail integration from private repo
Updated: 2026-05-12T23:24:11Z

Changed directories: gmail

Check Result
Structure ⚠️ Passed with warnings
Code ⚠️ Passed with warnings
Tests ⚠️ Passed with warnings
README ✅ Passed
Version ✅ Passed
⚠️ Structure Check output
Validating 1 integration(s)...

============================================================
Integration: gmail
============================================================

Warnings (2):
  ⚠️ SDK version 1.0.2 is deprecated — upgrade to autohive-integrations-sdk~=1.1.1 or later
  ⚠️ Potentially unused scopes (please verify): https://www.googleapis.com/auth/gmail.modify

============================================================
SUMMARY
============================================================
Integrations validated: 1
Total errors: 0
Total warnings: 2

⚠️ Validation passed with warnings - please review
⚠️ Code Check output

[notice] A new release of pip is available: 26.0.1 -> 26.1.1
[notice] To update, run: pip install --upgrade pip
----------------------------------------
Checking: gmail
----------------------------------------

📦 Installing dependencies...

🐍 Checking Python syntax...
   ✅ Syntax OK

📥 Checking imports...
   ✅ Imports OK

📄 Checking JSON files...
   ✅ JSON files OK

🔍 Linting with ruff...
   ✅ Lint OK

🎨 Checking formatting with ruff...
   ✅ Formatting OK

🔒 Scanning for security issues with bandit...
   ✅ Security OK

🛡️ Checking dependencies for vulnerabilities with pip-audit...
   ✅ Dependencies OK

🔗 Checking config-code sync...
   ⚠️  Action 'send_email': parameter 'subject' defined in input_schema but never accessed in code
   ⚠️  Action 'send_email': parameter 'body' defined in input_schema but never accessed in code
   ⚠️  Action 'send_email': parameter 'body_format' defined in input_schema but never accessed in code
   ⚠️  Action 'send_email': parameter 'cc' defined in input_schema but never accessed in code
   ⚠️  Action 'send_email': parameter 'to' defined in input_schema but never accessed in code
   ⚠️  Action 'send_email': parameter 'files' defined in input_schema but never accessed in code
   ⚠️  Action 'reply_to_thread': parameter 'cc' is optional in schema but accessed with inputs["cc"] (will raise KeyError if not provided)
   ⚠️  Action 'reply_to_thread': parameter 'to' is optional in schema but accessed with inputs["to"] (will raise KeyError if not provided)
   ⚠️  Action 'read_inbox': parameter 'scope' is required in schema but accessed with inputs.get() (safe for missing)
   ⚠️  Action 'read_inbox': parameter 'pageToken' is optional in schema but accessed with inputs["pageToken"] (will raise KeyError if not provided)
   ⚠️  Action 'read_all_mail': parameter 'scope' is required in schema but accessed with inputs.get() (safe for missing)
   ⚠️  Action 'read_all_mail': parameter 'pageToken' is optional in schema but accessed with inputs["pageToken"] (will raise KeyError if not provided)
   ⚠️  Action 'list_labels': parameter 'label_type' is optional in schema but accessed with inputs["label_type"] (will raise KeyError if not provided)
   ⚠️  Action 'list_emails_by_label': parameter 'maxResults' is optional in schema but accessed with inputs["maxResults"] (will raise KeyError if not provided)
   ⚠️  Action 'list_emails_by_label': parameter 'pageToken' is optional in schema but accessed with inputs["pageToken"] (will raise KeyError if not provided)
   ⚠️  Action 'create_label': parameter 'backgroundColor' is optional in schema but accessed with inputs["backgroundColor"] (will raise KeyError if not provided)
   ⚠️  Action 'create_label': parameter 'textColor' is optional in schema but accessed with inputs["textColor"] (will raise KeyError if not provided)
   ⚠️  Action 'create_draft': parameter 'from' accessed in code but not defined in input_schema
   ⚠️  Action 'create_draft': parameter 'files' defined in input_schema but never accessed in code
   ⚠️  Action 'create_draft': parameter 'cc' defined in input_schema but never accessed in code
   ⚠️  Action 'create_draft': parameter 'bcc' defined in input_schema but never accessed in code
   ⚠️  Action 'create_draft': parameter 'body_format' defined in input_schema but never accessed in code
   ⚠️  Action 'create_draft': parameter 'body' defined in input_schema but never accessed in code
   ⚠️  Action 'create_draft': parameter 'subject' is optional in schema but accessed with inputs["subject"] (will raise KeyError if not provided)
   ⚠️  Action 'create_draft': parameter 'to' is optional in schema but accessed with inputs["to"] (will raise KeyError if not provided)
   ⚠️  Action 'update_draft': parameter 'from' accessed in code but not defined in input_schema
   ⚠️  Action 'update_draft': parameter 'files' defined in input_schema but never accessed in code
   ⚠️  Action 'update_draft': parameter 'cc' defined in input_schema but never accessed in code
   ⚠️  Action 'update_draft': parameter 'to' defined in input_schema but never accessed in code
   ⚠️  Action 'update_draft': parameter 'subject' defined in input_schema but never accessed in code
   ⚠️  Action 'update_draft': parameter 'bcc' defined in input_schema but never accessed in code
   ⚠️  Action 'update_draft': parameter 'body' defined in input_schema but never accessed in code
   ⚠️  Action 'update_draft': parameter 'body_format' defined in input_schema but never accessed in code
   ⚠️  Action 'list_drafts': parameter 'maxResults' is optional in schema but accessed with inputs["maxResults"] (will raise KeyError if not provided)
   ⚠️  Action 'list_drafts': parameter 'includeSpamTrash' is optional in schema but accessed with inputs["includeSpamTrash"] (will raise KeyError if not provided)
   ⚠️  Action 'list_drafts': parameter 'q' is optional in schema but accessed with inputs["q"] (will raise KeyError if not provided)
   ⚠️  Action 'list_drafts': parameter 'pageToken' is optional in schema but accessed with inputs["pageToken"] (will raise KeyError if not provided)
   ✅ Config-code sync OK

🔄 Checking fetch patterns...
   ✅ Fetch patterns OK

========================================
✅ CODE CHECK PASSED
========================================
⚠️ Tests Check output
⚠️  No unit tests (test_*_unit.py) found in: gmail
⚠️  No unit tests to run
✅ README Check output
========================================
✅ README CHECK PASSED
========================================
✅ Version Check output
✅ gmail: New integration with version 0.1.0

========================================
✅ VERSION CHECK PASSED
========================================

Comment thread gmail/tests/context.py
import sys

sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
from gmail import gmail # noqa: F401
Comment thread gmail/tests/test_gmail.py
@@ -0,0 +1,6 @@
import context # noqa: F401
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4e0f3b8faa

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread gmail/gmail.py
Comment on lines +476 to +483
# Handle CC recipients if present
if "cc" in inputs:
if isinstance(inputs["cc"], list):
message["cc"] = ", ".join(inputs["cc"])
else:
message["cc"] = inputs["cc"]

message["subject"] = inputs["subject"]
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Add BCC handling for new sends

When users send a new email, the implementation copies only to and cc into the MIME message and then immediately sets the subject, so any BCC support advertised in gmail/README.md/the root README is unavailable for send_email (and direct callers passing bcc would silently drop those recipients). Draft creation/update already handles bcc, so mirror that logic here and expose the field in this action's schema.

Useful? React with 👍 / 👎.

Comment thread gmail/gmail.py
Comment on lines +848 to +851
return parsedate_to_datetime(email["date"])
except Exception:
# Fallback: use the email ID as a rough ordering mechanism
return email["id"]
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep thread sort keys comparable

If a thread contains one message with a parseable Date header and another with a missing or malformed Date, this fallback returns a string while the successful path returns a datetime; Python 3 cannot compare those key types, so thread_emails.sort(...) raises and the whole get_thread_emails action returns an error for that thread. Use a single comparable key type for both paths, such as a tuple with a parse-success flag and timestamp/id.

Useful? React with 👍 / 👎.

@TheRealAgentK
Copy link
Copy Markdown
Collaborator Author

Please ignore all the warnings in this PR - this is a 1:1 migration and will be fixed up in a subsequent PR.

@TheRealAgentK TheRealAgentK merged commit 438d0e1 into master May 13, 2026
4 checks passed
@TheRealAgentK TheRealAgentK deleted the feat/322/migrate-gmail-from-private branch May 13, 2026 00:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(gmail): migrate Gmail integration from private repo

2 participants